Author Topic: RAM timing problems (SOLVED)  (Read 2616 times)

0 Members and 1 Guest are viewing this topic.

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
RAM timing problems (SOLVED)
« on: April 05, 2022, 01:39:25 pm »
I have just started using Block RAM in my FPGA project, and so far I've been able to implement it in a crude way however I am not getting the results I expect. I have a fixed size block RAM which I am writing data to synchronously each clock cycle, and then reading out that data continuously on the next clock cycles. The RAM has 8 bit wide input and 1 bit output. I have added a delay between read and write, giving at least 2 cycles for each. Despite this, the RAM is behaving with uncertainty in output state, viewing the output on the oscilloscope shows that the RAM will not behave consistently and doesn't reflect the data I am storing in it. I have attached my source code below in case anyone is able to spot an obvious flaw in my implementation

Code: [Select]
module LaserControl (
input data_in,
input comms_clk,
input execute,
input clk_in,
input in_a,
input in_b,
output reg ld_out);

// Variable and memory constants
parameter  bit  USE_NEG_EDGE  = 1 ;
parameter N_BITS = 16;            // Total number of bits supported by the incoming register
parameter N_DATA_BITS = 12;        // How many bits of data can be recived in one block
parameter MAX_RAM = 4095;
parameter VRAM_BANK2 = 4095; // Start address for bank 2 of vram

// Control constants
parameter SET_PIXEL_OFFSET = 1;
parameter SET_PIXEL_PERIOD = 5;
parameter SET_SCAN_LINE_LIMIT = 6;
parameter STORE_PIXEL_PACKET = 2;   // Memory address is automatically incremented
parameter RESET_ADDRESS = 3;
parameter UPDATE_VRAM = 4;
parameter BLANK_BEAM = 7;

reg       reset             = 1 ; // since you do not have a reset, we are artificially making preset to on.
reg       enable_laser      = 0 ; // A reg to block the laser from coming on.
reg       laser_out         = 0 ;
reg       debug_mode        = 1 ; // 1 = display test pattern, 0 = display pattern from VRAM
reg [4:0] function_pos      = 0 ; // Create a program position pointer which can serve 32 states.
reg [4:0] ram_state = 0 ; // Store the state of RAM operation
reg [4:0] ram_readout_state = 0 ;


reg        reg_data_in       = 0 ; // Register inputs
reg        reg_comms_clk     = 0 ;
reg        reg_execute       = 0 ;
reg        reg_in_a          = 0 ;
reg        reg_in_b          = 0 ;
reg        sync_in           = 0 ;

  // Internal registers for keeping track of state
reg [N_DATA_BITS-1:0] max_pixel_count   = 50;
reg [N_DATA_BITS-1:0] pixel_offset      = 40;   // how many pixels to delay the output laser pulses
reg [N_DATA_BITS-1:0] pixel_count       = 0 ;
reg [N_DATA_BITS-1:0] pixel_period      = 50 ;      // Period of the pixel clock (1 = period of main clock, 2 = 1/2 of main clock, etc..
reg [N_DATA_BITS-1:0] pixel_period_timer_reg = 0;
reg                   sync_in_dly       = 0 ;


  // communcations
reg                     comms_clk_dly     = 0 ;
reg                     shift_bit_in      = 0 ;
reg [N_BITS-1:0]        command_packet    = 0 ;
reg [2:0]               command_reg       = 0 ;
reg [N_DATA_BITS-1:0]   data_reg          = 0 ;
reg [N_DATA_BITS-1:0]   data_reg_reversed = 0 ;

wire sync_pos_trigger = sync_in && !sync_in_dly ;
wire sync_neg_trigger = !sync_in && sync_in_dly ;
wire sync_trigger_on  = USE_NEG_EDGE ? sync_neg_trigger  : sync_pos_trigger ; // Use a parameter or reg to select the trigger edge.

// Video memory (can store up to 4095 pixels based on the current 12 bit address size)
reg writeEnable = 0; // Write enable for the VRAM
reg [7:0] dataWord = 0; // Data word to write to VRAM
reg VRAM_out = 0; // The output bit of the VRAM
reg [12:0] VRAM_raddress = 0; // Read address for the VRAM
reg [8:0] VRAM_waddress = 0; // Write address for the VRAM
reg [12:0] VRAM_offset   = 0; // Offset address for VRAM (for reading bank 1 or bank 2)

VRAM activeRAM ( .clock (clk_in),
.data (dataWord),
.rdaddress (VRAM_raddress),
.wraddress (VRAM_waddress),
.wren (writeEnable),
.q (VRAM_out));               // Current VRAM for outputing pixel data


// Reverse data on the input data register
assign data_reg_reversed[0] = data_reg[11];
assign data_reg_reversed[1] = data_reg[10];
assign data_reg_reversed[2] = data_reg[9];
assign data_reg_reversed[3] = data_reg[8];
assign data_reg_reversed[4] = data_reg[7];
assign data_reg_reversed[5] = data_reg[6];
assign data_reg_reversed[6] = data_reg[5];
assign data_reg_reversed[7] = data_reg[4];
assign data_reg_reversed[8] = data_reg[3];
assign data_reg_reversed[9] = data_reg[2];
assign data_reg_reversed[10] = data_reg[1];
assign data_reg_reversed[11] = data_reg[0];
 

// **************************************************
// Everything should run from the 25MHz clock.
// **************************************************
always @(posedge clk_in) begin

// Cleanly register FPGA inputs.
reg_data_in    <= data_in   ;
reg_comms_clk  <= comms_clk ;
reg_execute    <= execute   ;
reg_in_a       <= in_a      ;
reg_in_b       <= in_b      ;

// **************************************************
// During the reset condition, do these things.
// **************************************************
if (reset) begin

    reset        <= 0 ; // dispixel_period_timer_regable the reset.
    enable_laser <= 0 ; // Force laser off.
    ld_out       <= 0 ; // Force laser off.
    function_pos <= 0 ; // Clear the function position so that position 0 runs once the reset is released.

  end else begin
// **************************************************
// Once the reset condition has cleared, do these things.
// **************************************************

ld_out <= !(enable_laser && laser_out) ; // For now, always drive the laser output pin when these are high and !reset.
                                      // We will change this to a memory lookup when we create the 2048 pixel line memory



// **************************************************
// Communications
// **************************************************

  comms_clk_dly <= reg_comms_clk;
 
  // load a bit into the communications register every time the comms clock goes low to high
  shift_bit_in <= reg_comms_clk  && !comms_clk_dly;
  if ( shift_bit_in ) command_packet[N_BITS-1:0] <= { command_packet[N_BITS-2:0] , reg_data_in } ;

  // store results in the setting register bank
  if (reg_execute) begin
    command_reg <= command_packet[2:0];                         // Store the command op-code
    data_reg <= command_packet[N_BITS-1:N_BITS-N_DATA_BITS];    // Store the data
   
    case (command_reg)
     
      SET_PIXEL_OFFSET : begin // Set the pixel offset register     
        pixel_offset <= data_reg_reversed;
      end
         
      SET_PIXEL_PERIOD : begin // Set pixel period register
          pixel_period <= data_reg_reversed;
      end
         
      SET_SCAN_LINE_LIMIT : begin // Set scan line limit register
          max_pixel_count <= data_reg_reversed;
      end
         
      BLANK_BEAM : begin  // Blank or unblank the laser beam, also controls debug mode
          enable_laser <= data_reg_reversed[0];
          debug_mode <= data_reg_reversed[1];
      end
     
      STORE_PIXEL_PACKET : begin  // Store the pixels in the buffer RAM

if(ram_state == 0) ram_state <= 1; // Initiate store cycle

      end
     
      RESET_ADDRESS : begin // reset the buffer address for buffer memory access
          if (data_reg_reversed < MAX_RAM) VRAM_waddress <= data_reg_reversed;  // 0 will reset it to 0, otherwise the buffer address can be set to an arbitrary address location
          else VRAM_waddress <= 1'b0; 
      end
     
      UPDATE_VRAM : begin   // Switch active bank of VRAM by changing address offset
          if (VRAM_offset == 0) VRAM_offset <= VRAM_BANK2;
else VRAM_offset <= 0;
      end
     
    endcase
  end


// **************************************************
// Schmitt trigger
// **************************************************
        if (reg_in_a && reg_in_b) sync_in <= 1'b1; // Both high, so set.
  else if (!(reg_in_a || reg_in_b)) sync_in <= 1'b0; // Both low, so clear, otherwise, hold the last value.
 
  sync_in_dly <= sync_in;
  comms_clk_dly <= reg_comms_clk;
 
 
 
// **************************************************
// Begin Sequencer for controlling RAM
// **************************************************
 
case (ram_state)

default : ram_state <= 0; // Undefined state, reset back to 0

0 : begin // Do nothing
// Ready state
writeEnable <= 0;
end

1 : begin // Store data, setup RAM storage buffer register

writeEnable <= 1;
dataWord <= data_reg_reversed[7:0]; // Store 1 word into VRAM buffer
ram_state <= ram_state + 1'b1; // Go to next function state (on next clock cyle)

end

2 : begin // Clock in data to RAM

// Data word is clocked in, increment address
if ( VRAM_waddress < MAX_RAM ) VRAM_waddress <= VRAM_waddress + 1'b1;    // Increment buffer address
else VRAM_waddress <= 1'b0; // reset buffer address

ram_state <= 0; // reset state

end
endcase

// **************************************************
// Begin Sequencer driving for the laser output
// **************************************************
     case (function_pos)

        default : function_pos <= 0 ; // If an undefined position has been reached, goto position 0.

       0 : begin // This state begins after the reset has been released

            enable_laser <= 0 ; // Force laser off
            function_pos <= function_pos + 1'b1 ; // Go to next function (1).
       
           end

       1 : begin
         
            SET_laser_clock ( pixel_period, pixel_offset ); // setup the laser clock for a delay (pixel offset delay)

            if ( sync_trigger_on ) function_pos <= function_pos + 1'b1 ; // Goto next function when the sync_trigger goes from high to low
           
           end

       2 : begin
         
              RUN_laser_clock ( pixel_period );   // counting pixel offset delay

           end
           
       3 : begin
             
              enable_laser <= 1 ; // Force laser on
              SET_laser_clock ( pixel_period, max_pixel_count ); // Set the number of pixels to display in the scan line
              function_pos <= function_pos + 1'b1;  // Goto next function
               
          end
               
       4 : begin
         
              RUN_laser_clock ( pixel_period );   // counting laser output pixel clock
             
              if( debug_mode == 1 ) laser_out <= pixel_count[0];  // Laser is toggled based on the LSB of pixel counter
              else begin
 
case (ram_readout_state)

default : ram_readout_state <= 0; // Undefined state, reset back to 0

0 : begin // Wait 1 cycle for RAM ready
laser_out <= 1'b1;
ram_readout_state <= ram_readout_state + 1'b1;
end

1 : begin // Read out VRAM

laser_out <= VRAM_out;
ram_readout_state <= ram_readout_state + 1'b1;

end

2 : begin // Increment the address counter

laser_out <= 1'b1;
VRAM_raddress <= VRAM_raddress + 1'b1 ; // Increment the VRAM read address
ram_readout_state <= 1'b0;

end
endcase;

  end
             
           end
           
      5 : begin
            // Sweep finished
           
            // Turn laser on
            laser_out <= 1'b0;
VRAM_raddress <= VRAM_offset ;// reset the VRAM address
ram_readout_state <= 0;
            function_pos <= 1;    // Reset function counter
         
          end

      endcase
// **************************************************
// End Sequencer for driving the laser output
// **************************************************


  end // !reset
end // always @25 MHz clock.


// **************************************************
// TASKS - set laser pixel clock and address pointer.
// **************************************************
task SET_laser_clock(bit [N_DATA_BITS-1:0] period,bit [N_DATA_BITS-1:0] length);
  begin
    pixel_count <= length;
    pixel_period_timer_reg <= period;
  end
endtask

// **************************************************
// TASKS - run laser pixel timer and address pointer.
// **************************************************
task RUN_laser_clock(bit [N_DATA_BITS-1:0] period);
  begin
   
    if ( pixel_period_timer_reg != 0 ) pixel_period_timer_reg <= pixel_period_timer_reg - 1'b1 ; // decrement the pixel period count
    else begin
     
      pixel_period_timer_reg <= period;   // reset the period counter
   
      if (pixel_count !=0) pixel_count   <= pixel_count  - 1'b1  ; // Count down until 0
   else function_pos  <= function_pos + 1'b1  ; // Once 0, auto-increment the function_pos for the case statement.
    end
  end
endtask


endmodule

« Last Edit: October 04, 2022, 04:33:54 am by kpow8050 »
 

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4961
  • Country: au
    • send complaints here
Re: RAM timing problems
« Reply #1 on: April 05, 2022, 01:49:04 pm »
Not showing the ram module when you say the problem is with recovering data from it...  look into my crystal ball.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #2 on: April 05, 2022, 02:35:16 pm »
Since you are not showing you ram instantiation, we cannot help.
Notes
a) The data written in ram takes 2 clock to changes.
b) When reading ram, depending on settings, the data output is usually delayed 2 clocks behind the sent in read address.  IE, Clock cycle 1 latches the read address and passes it to the memory array.  Clock cycle 2 latches the read data from the memory array and sends it to the rest of your HDL code.

You can also prepare and set a .mif (memory initialization file) which presets the ram at powerup.
(note when using a .mif, modelsim wants a copy of the .mif file in your main project simulation folder.)
« Last Edit: April 05, 2022, 02:38:51 pm by BrianHG »
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #3 on: April 05, 2022, 11:52:04 pm »
Sorry guys, my bad for not including the RAM instantiation :-[. Here it is below (generated using the MegaFunction wizard)

Code: [Select]
module VRAM (
clock,
data,
rdaddress,
wraddress,
wren,
q);

input   clock;
input [7:0]  data;
input [12:0]  rdaddress;
input [9:0]  wraddress;
input   wren;
output [0:0]  q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
tri1   clock;
tri0   wren;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_on
`endif

wire [0:0] sub_wire0;
wire [0:0] q = sub_wire0[0:0];

altsyncram altsyncram_component (
.address_a (wraddress),
.clock0 (clock),
.data_a (data),
.wren_a (wren),
.address_b (rdaddress),
.q_b (sub_wire0),
.aclr0 (1'b0),
.aclr1 (1'b0),
.addressstall_a (1'b0),
.addressstall_b (1'b0),
.byteena_a (1'b1),
.byteena_b (1'b1),
.clock1 (1'b1),
.clocken0 (1'b1),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.data_b (1'b1),
.eccstatus (),
.q_a (),
.rden_a (1'b1),
.rden_b (1'b1),
.wren_b (1'b0));
defparam
altsyncram_component.address_reg_b = "CLOCK0",
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_input_b = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.clock_enable_output_b = "BYPASS",
altsyncram_component.intended_device_family = "Cyclone II",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.numwords_a = 1024,
altsyncram_component.numwords_b = 8192,
altsyncram_component.operation_mode = "DUAL_PORT",
altsyncram_component.outdata_aclr_b = "NONE",
altsyncram_component.outdata_reg_b = "CLOCK0",
altsyncram_component.power_up_uninitialized = "FALSE",
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
altsyncram_component.widthad_a = 10,
altsyncram_component.widthad_b = 13,
altsyncram_component.width_a = 8,
altsyncram_component.width_b = 1,
altsyncram_component.width_byteena_a = 1;


endmodule
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #4 on: April 06, 2022, 12:25:52 am »
Take a look at these 2 files, add the lines in red:


setup_lc.do:

Quote
transcript on
if {[file exists work]} {
   vdel -lib work -all
}
vlib work
vmap work work
vlog -sv -work work {VRAM.v}
vlog -sv -work work {LaserControl_v2.sv}
vlog -sv -work work {LaserControl_v2_tb.sv}

# Make Cyclone Megafunctions and PLL available.
vsim -t 1ns -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L work -voptargs="+acc"  LaserControl_v2_tb


add  wave /LaserControl_v2_tb/*


do run_lc.do

run_lc.do:

Quote
vlog -sv -work work {VRAM.v}
vlog -sv -work work {LaserControl_v2.sv}
vlog -sv -work work {LaserControl_v2_tb.sv}

restart -force
run -all

wave cursor active
wave refresh
wave zoom range 0ns 1000ns
view signals

This is assuming that the file you listed above is called 'VRAM.v'.
Also, the VRAM.V file needs to be in the same folder as all your other source files.
Adding the correct 2 red lines means modelsim setup .do batch files should work.
The part in green, ' -L cycloneive_ver ' may need to be changed as it tells modelsim to look for Altera's Cyclone IV-E functions, though altsyncram should be backwards/forwards compatible with Cyclone II.
« Last Edit: April 06, 2022, 12:35:13 am by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #5 on: April 06, 2022, 12:31:58 am »
Note that once you got your sim working, and you added all the new nets to your waveform, you will discover a few minor logic bombs in your code.
From there, see what you can fix before we dive deeper into solutions.
Also, I recommend in Quartus making a dummy initialization file for the dualport ram, so you will have dummy contents at powerup to help see what is going on.
« Last Edit: April 06, 2022, 12:33:48 am by BrianHG »
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #6 on: September 17, 2022, 12:10:38 pm »
Hi BrianHG, sorry for the long delay - things came up that prevented me working on this project. I have come back to it now and my first attempt is to get the ModelSim running, however it seems that its not able to instantiate the VRAM module. The error message is shown below

# Loading work.LaserControl_tb
# Loading work.LaserControl
# Loading work.VRAM
# ** Error: (vsim-3033) VRAM.sv(50): Instantiation of 'altsyncram' failed. The design unit was not found.
#
#         Region: /LaserControl_tb/UUT/activeRAM
#         Searched libraries:
#             C:/Users/Keith/Documents/Electronic projects/UV laser lithography/LaserControl_v5/work
# Error loading design

Wondering what would cause this error. All the modules are present in the working directory. I have attached the run_lc.do inside the .zip folder in case you need to look at that

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #7 on: September 17, 2022, 01:44:44 pm »
You forgot to add to your setup_lc.do:

Quote
if {[file exists work]} {
   vdel -lib work -all
}
vlib work
vmap work work
vlog -sv -work work {vram.sv}
vlog -sv -work work {LaserControl.sv}
vlog -sv -work work {LaserControl_tb.sv}

# Make Cyclone Megafunctions and PLL available.
vsim -t 1ns -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L work -voptargs="+acc"  LaserControl_tb


add  wave /LaserControl_tb/*


do run_lc.do

When adding an entire new module, you do need to rerun the setup_lc.do, or, re-run the 'vsim ' command line.

Note that in your run_lc.do, it is common practice to make sure that the 'vlog -sv -work work {LaserControl_tb.sv}' is the last one in the list of 'vlog's.  However it still seems to work.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #8 on: September 18, 2022, 12:01:08 am »
That has solved the problem!

After a bit of messing about with various errors I managed to get it to compile this far. Essentially it seems to be giving an error about continuous and procedural assignments. I'm not really sure what this refers to or how to fix it?

# Loading altera_mf_ver.ALTERA_MF_MEMORY_INITIALIZATION
# ** Error: (vsim-3838) LaserControl.sv(92): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(91): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(90): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(89): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(88): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(87): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(86): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(85): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(84): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(83): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(82): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# ** Error: (vsim-3838) LaserControl.sv(81): Variable '/LaserControl_tb/UUT/data_reg_reversed' written by continuous and procedural assignments. See LaserControl.sv(58).
#
#         Region: /LaserControl_tb/UUT
# Error loading design
# Error: Error loading design
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #9 on: September 18, 2022, 12:10:39 am »
Well, read the line numbers with the errors.

Something register written by continuous at line 58 has also simultaneously procedural assignments on lines 81 through 92.

You can define an assignment at one or the other, but not both.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #10 on: September 18, 2022, 12:46:52 am »
I modified the data_reg_reversed to a wire and the error goes away. I get a new error instead it shows

Error (10028): Can't resolve multiple constant drivers for net "data_reg_reversed[0]" at lasercontrol.sv(81)

Essentially I cannot see what is wrong with this, it is only defined once in the code. Ideally all that is required of these lines is to reverse the data in a register. My assumption is that it would be easier to do on the FPGA side, rather than change the arduino code side. I would prefer this occurs in logic, rather than sequential way too


// Reverse data on the input data register
assign data_reg_reversed[0] = data_reg[11];
assign data_reg_reversed[1] = data_reg[10];
assign data_reg_reversed[2] = data_reg[9];
assign data_reg_reversed[3] = data_reg[8];
assign data_reg_reversed[4] = data_reg[7];
assign data_reg_reversed[5] = data_reg[6];
assign data_reg_reversed[6] = data_reg[5];
assign data_reg_reversed[7] = data_reg[4];
assign data_reg_reversed[8] = data_reg[3];
assign data_reg_reversed[9] = data_reg[2];
assign data_reg_reversed[10] = data_reg[1];
assign data_reg_reversed[11] = data_reg[0];
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #11 on: September 18, 2022, 01:02:37 am »
Line 58:

reg [N_DATA_BITS-1:0]   data_reg_reversed = 0 ;

You cannot assign a fixed 0, and then assign a new value, it is not being used as clocked logic register which can change values.  In fact, what you have there is actually a wire which you are assigning to another register.  You should define it as:

wire [N_DATA_BITS-1:0]   data_reg_reversed;

Though, the 'reg' without the =0 should still work.  It is just better to comprehend how you are using the net name 'data_reg_reversed'.
 
The following users thanked this post: kpow8050

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #12 on: September 18, 2022, 01:16:26 am »
Line 58:

reg [N_DATA_BITS-1:0]   data_reg_reversed = 0 ;

You cannot assign a fixed 0, and then assign a new value, it is not being used as clocked logic register which can change values.  In fact, what you have there is actually a wire which you are assigning to another register.  You should define it as:

wire [N_DATA_BITS-1:0]   data_reg_reversed;

Though, the 'reg' without the =0 should still work.  It is just better to comprehend how you are using the net name 'data_reg_reversed'.

Perfect. That fixed it! I don't know how I missed that, I must still be stuck in my sequential programming mode :P
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #13 on: September 18, 2022, 01:26:17 am »
I'm not sure, but if you are only using the reversed data, why not change this line 135:

  if ( shift_bit_in ) command_packet[N_BITS-1:0] <= { command_packet[N_BITS-2:0] , reg_data_in } ;

to:

  if ( shift_bit_in ) command_packet[N_BITS-1:0] <= { reg_data_in, command_packet[N_BITS-1:1] } ;

Though your data comes in reverse, you would carefully need to modify lines 139 & 140 as the location of the data and command is reversed as well as the command ID name/numbers.

Anyways, what you have is fine.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #14 on: September 18, 2022, 03:55:57 am »
Makes sense. I think I will stick with what I have for now.

Now that I am debugging the memory problem, I have decided to create a memory initialization file (.mif) to initialize the contents of the RAM to a defined state. I added the following line into the defparam section of the VRAM.sv file to load the memory contents (attached in the .zip is the .mif file)
 
"altsyncram_component.init_file = "LaserControl.mif";"

I setup the test bench so that the ld_out will output the contents of memory starting from address 0 and incrementing every time the pixel counter goes up. Currently there is no output from the ld_out, however there should be 0, 1, 0, 1 etc output based on the memory contents I have given it. I'm wondering if there is a way to check if the RAM was initialized properly? Either way the code is not working how I would expect.

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8090
  • Country: ca
Re: RAM timing problems
« Reply #15 on: September 18, 2022, 05:04:28 am »
Since you have the .mif set to 8 bits and the output set to 1bit, shouldn't the output go:

0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1...

Remember, you can specify the 'layout' of the .mif file to match the A input port, or the B output port.
But, since you set the .mif to 8 bit, I assume you have the layout on port A.

If you want 0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0..., you will need to make the first address 0 byte = 8'h55, (or 8'hAA, I don't remember the output bit addressing order.), and all other bytes = 0.
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #16 on: September 19, 2022, 03:20:31 am »
I was under the impression that it would assume the port A format. But in any case wouldn't the output still result in 0,1,0,1... if it were defined as 8 bit or 1 bit, since when reading from the 1 bit output port each address increment effectively covers each bit in the 1 byte word. Maybe I should just stick with a symmetrical memory structure since i'm not really sure how this is working underneath. I could go with 8 bit in 8 bit out and have a counter to keep track of address and bit number on the output. When I test the design on the real hardware the memory seems to be corrupt or something, because it causes the device to lock up or get into an undefined state whenever I switch it into the memory reading mode. Debugging so far has not revealed the bug to me so I will need to continue to dig deeper on this. Worst case scenario I may go with an external static RAM chip as I'm pretty familiar with how to get those working
 

Offline kpow8050Topic starter

  • Regular Contributor
  • *
  • Posts: 57
  • Country: au
Re: RAM timing problems
« Reply #17 on: October 04, 2022, 04:31:55 am »
I have solved the timing issues with the block RAM on the FPGA. Just thought I would post an image of a successful PCB exposure that I did with this device. There is still a few things that need to be tweaked and unknown issues such as distortion at the end of scan lines (not sure if its from the laser or due to packets of data being lost or both). But this project is a success.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf