Simulating Memory in verilog - Page 1
Forum section: electronics / general

author: Rainwater
author_rank: Regular Contributor
timestamp: February 24, 2024, 01:21:31 am
content: IDE environment and tool chain I using can be found byfollowing this tutorial hereIt is based on OSS-CAD-Suite toolchain 2023-02-10 version and the Lushay Code plugin.FPGA chip: GW1NR-9Im just learning the verilog language and after following their tutorials and asic-world.com's readings, I want to write a fully configurable UART module so I can practice the grammar and syntax of the language. I want to include a pair of FIFO buffers so I wrote a memory module based on the ssram blocks in the chip I got. All that went well, just a few lines of code, so I got to thinking about how to stack the ssram blocks together into an array to make a adjustable size memory module. Simulations went well and I wrote the FIFO module. again, everything was great until it was not.I quickly discovered some unexpected behavior, in simulation. I traced the errors to the module which I use as a wrapper for the memory, to add chip select features.I little more detail about the design I chose. The basic memory module is wrapped in a module that will disable the clk and set the dataOut to high impedance when CS goes LOW. Doing this allowed me to share a common DataOut bus of wires in between all memory modules within the memory_array saving resources and maybe a little bit of power. When a read request is made, the DataOut will be valid on the next clock cycle.but when I play with the CS port, Memory becomes available on the same clock cycle it is requested. Another set of eyes would be greatly appreciated in helping me see where I have made a mistake. I'm 99% sure data is not normally available on the same cycle it is requested. But if it is, this is great news to me.Below is the minimal code needed to recreate the unexpected behavior and the test bench output. attached is the test bench.shadow_ram.vCode:// basic ssram semi-dual port 4bits wide 16 words deep max.// datasheet: UG285E.pdf Page 55// URL: http://cdn.gowinsemi.com.cn/UG285E.pdfmodule ssram16dp(input wire clk,input wire w_re,input wire[3:0] raddress,input wire[3:0] waddress,input wire[3:0] dataIn,output reg [3:0] dataOut);reg[3:0] ram [15:0];always @(posedge clk) beginif( w_re == 1 ) beginram <= dataIn;end else begindataOut <= ram;endendendmodule// ssram wrapper with high impedance dataOut and clk disable on chip select HIGH.module ssram16dp_zstate(input wire clk,input wire w_re,input wire[3:0] raddress,input wire[3:0] waddress,input wire[3:0] dataIn,output wire[3:0] dataOut,input wire cs);wire sram_clk;wire [3:0] sram_dataOut;ssram16dp sram(.clk( sram_clk ),.w_re( w_re ),.raddress( raddress ),.waddress( waddress ),.dataIn( dataIn ),.dataOut( sram_dataOut ));assign sram_clk = cs & clk;assign dataOut = cs ? sram_dataOut : 4'bzzzz;endmodule/* This module stack the basic blocks together in columns and rows to provide custom width anddepth. Increasing the width will be simple as each column module will provide data for its sectionof output bits. Increasing the rows or depth will require the use of a multiplexer to select whichram blocks will be accessed. A chip select option that disables the clock input, should savepower, the high impedance dataOut allows all banks to share a data buss.*/module ssram16dp_array #(parameter width = 4,parameter depth = 16)(clk,w_re,raddress,waddress,dataIn,dataOut);localparam array_width = width / 4;localparam array_depth = depth / 16;localparam address_width = $clog2(depth);input wire clk;input wire w_re;input wire [address_width:0] raddress;input wire [address_width:0] waddress;input wire [width-1:0] dataIn;output wire [width-1:0] dataOut;reg [array_depth-1:0] chip_select;genvar a, b;generatefor( a = 0; a < array_depth; a = a + 1 ) beginfor( b = 0; b < array_width; b = b + 1 ) beginssram16dp_zstate memory_array(.clk( clk ),.w_re( w_re ),.raddress( raddress[3:0] ),.waddress( waddress[3:0] ),.dataIn( dataIn [3+b*4 : b*4] ),.dataOut( dataOut[3+b*4 : b*4] ),.cs( chip_select ));endendendgenerateinteger i;always @( raddress or waddress or w_re ) beginfor( i = 0; i < array_depth; i = i + 1 ) begincase ( w_re )1: chip_select <= ( waddress[address_width:4] == i ) ? 1 : 0;0: chip_select <= ( raddress[address_width:4] == i ) ? 1 : 0;endcaseendendendmoduleTest outputCode:Starting FPGA ToolchainStarting Testbench with iVerilogFinished TestbenchStarting Testbench with iVerilogVCD info: dumpfile UUT.vcd opened for output.starting testWriting1 cs:1w_re:zDataIn: zwaddy: zDataOut: xraddy: z3 cs:1w_re:1DataIn: 0waddy: 0DataOut: xraddy: z5 cs:1w_re:1DataIn: 1waddy: 1DataOut: xraddy: z7 cs:1w_re:1DataIn: 2waddy: 2DataOut: xraddy: z9 cs:1w_re:1DataIn: 3waddy: 3DataOut: xraddy: z11 cs:1w_re:1DataIn: 4waddy: 4DataOut: xraddy: z13 cs:1w_re:1DataIn: 5waddy: 5DataOut: xraddy: z15 cs:1w_re:1DataIn: 6waddy: 6DataOut: xraddy: z17 cs:1w_re:1DataIn: 7waddy: 7DataOut: xraddy: z19 cs:1w_re:1DataIn: 8waddy: 8DataOut: xraddy: z21 cs:1w_re:1DataIn: 9waddy: 9DataOut: xraddy: z23 cs:1w_re:1DataIn: 10waddy: 10DataOut: xraddy: z25 cs:1w_re:1DataIn: 11waddy: 11DataOut: xraddy: z27 cs:1w_re:1DataIn: 12waddy: 12DataOut: xraddy: z29 cs:1w_re:1DataIn: 13waddy: 13DataOut: xraddy: z31 cs:1w_re:1DataIn: 14waddy: 14DataOut: xraddy: z33 cs:1w_re:1DataIn: 15waddy: 15DataOut: xraddy: z35 cs:1w_re:1DataIn: 15waddy: 15DataOut: xraddy: zreading37 cs:1w_re:0DataIn: zwaddy: zDataOut: xraddy: 039 cs:1w_re:0DataIn: zwaddy: zDataOut: 0raddy: 141 cs:1w_re:0DataIn: zwaddy: zDataOut: 1raddy: 243 cs:1w_re:0DataIn: zwaddy: zDataOut: 2raddy: 345 cs:1w_re:0DataIn: zwaddy: zDataOut: 3raddy: 447 cs:1w_re:0DataIn: zwaddy: zDataOut: 4raddy: 549 cs:1w_re:0DataIn: zwaddy: zDataOut: 5raddy: 651 cs:1w_re:0DataIn: zwaddy: zDataOut: 6raddy: 753 cs:1w_re:0DataIn: zwaddy: zDataOut: 7raddy: 855 cs:1w_re:0DataIn: zwaddy: zDataOut: 8raddy: 957 cs:1w_re:0DataIn: zwaddy: zDataOut: 9raddy: 1059 cs:1w_re:0DataIn: zwaddy: zDataOut: 10raddy: 1161 cs:1w_re:0DataIn: zwaddy: zDataOut: 11raddy: 1263 cs:1w_re:0DataIn: zwaddy: zDataOut: 12raddy: 1365 cs:1w_re:0DataIn: zwaddy: zDataOut: 13raddy: 1467 cs:1w_re:0DataIn: zwaddy: zDataOut: 14raddy: 15intermitted cs69 cs:1w_re:0DataIn: zwaddy: zDataOut: 15raddy: 1571 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 073 cs:1w_re:0DataIn: zwaddy: zDataOut: 1raddy: 175 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 277 cs:1w_re:0DataIn: zwaddy: zDataOut: 3raddy: 379 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 481 cs:1w_re:0DataIn: zwaddy: zDataOut: 5raddy: 583 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 685 cs:1w_re:0DataIn: zwaddy: zDataOut: 7raddy: 787 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 889 cs:1w_re:0DataIn: zwaddy: zDataOut: 9raddy: 991 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 1093 cs:1w_re:0DataIn: zwaddy: zDataOut: 11raddy: 1195 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 1297 cs:1w_re:0DataIn: zwaddy: zDataOut: 13raddy: 1399 cs:0w_re:0DataIn: zwaddy: zDataOut: zraddy: 14101 cs:1w_re:0DataIn: zwaddy: zDataOut: 15raddy: 15103 cs:1w_re:0DataIn: zwaddy: zDataOut: 15raddy: 15reading105 cs:1w_re:0DataIn: zwaddy: zDataOut: 15raddy: 0107 cs:1w_re:0DataIn: zwaddy: zDataOut: 0raddy: 1109 cs:1w_re:0DataIn: zwaddy: zDataOut: 1raddy: 2111 cs:1w_re:0DataIn: zwaddy: zDataOut: 2raddy: 3113 cs:1w_re:0DataIn: zwaddy: zDataOut: 3raddy: 4115 cs:1w_re:0DataIn: zwaddy: zDataOut: 4raddy: 5117 cs:1w_re:0DataIn: zwaddy: zDataOut: 5raddy: 6119 cs:1w_re:0DataIn: zwaddy: zDataOut: 6raddy: 7121 cs:1w_re:0DataIn: zwaddy: zDataOut: 7raddy: 8123 cs:1w_re:0DataIn: zwaddy: zDataOut: 8raddy: 9125 cs:1w_re:0DataIn: zwaddy: zDataOut: 9raddy: 10127 cs:1w_re:0DataIn: zwaddy: zDataOut: 10raddy: 11129 cs:1w_re:0DataIn: zwaddy: zDataOut: 11raddy: 12131 cs:1w_re:0DataIn: zwaddy: zDataOut: 12raddy: 13133 cs:1w_re:0DataIn: zwaddy: zDataOut: 13raddy: 14135 cs:1w_re:0DataIn: zwaddy: zDataOut: 14raddy: 15Test finished Properlyc:\Users\\Desktop\fpga_projects\Tang_Nano_9K_blink\src\uart\shadow_ram\ssram16dp_zstate_tb.v:124: $finish called at 137 (1s)137 cs:1w_re:0DataIn: zwaddy: zDataOut: 15raddy: 15Finished TestbenchToolchain Completed

author: BrianHG
author_rank: Super Contributor
timestamp: February 24, 2024, 04:27:10 am
content: Here are a few things I have written which you may just read/use/learn and experiment with:A few different FIFOs I've played with:(There are 4 different FIFOs modules I have written in this 1 source code, only the last one called 'module BHG_FIFO_Xword_FWFT' would probably be of interest to you. The first one is a configurable nasty sequential bucket shifter I created for insane FMAX speeds.)https://github.com/BrianHGinc/BrianHG-DDR3-Controller/blob/main/BrianHG_DDR3/BrianHG_DDR3_FIFOs.svA simple synchronous UART for full duplex high speed RS232 with PCs: (MCU's UARTS typically work without the bi-dir sync requirement, but they implement it anyways)https://www.eevblog.com/forum/fpga/verilog-rs232-uart-and-rs232-debugger-source-code-and-educational-tutorial/Note that they are written in SystemVerilog.If you want to see simple simulation examples for some other tiny projects, look here:https://www.eevblog.com/forum/fpga/verilog-floating-point-clock-divider-release/https://www.eevblog.com/forum/fpga/bhg_i2c_init_rs232_debugger-an-i2c-initializer-with-integrated-rs232-debugger/

author: Rainwater
author_rank: Regular Contributor
timestamp: February 24, 2024, 03:13:35 pm
content: After some sleep and studying the waveform I think I have figured out what is happening. The error only occurs 1 clock cycle after changing CS.CS HIGH to LOWThe previous write request(w_re=HIGH) will be completed.The previous read request(w_re=LOW) gets canceled.CS LOW to HIGHA write request will complete.A read request will start.This lead me to review my basic memory module, who's timing does NOT matching the timing diagrams in the datasheet. my major error is I assumed the timing of the memory, and did not check the datasheet.5 minutes later....Great news, data is available at the rising clock edge. Yeppy for me!!!My errors, Gonna toss this up to being green.1) so the data sheet says that the memory is "asynchronous" meaning it can read and write at the same time.2) it samples on the negative clock edge.my ssram16db module always block should look like thisCode:always @(negedge clk) beginif( w_re == 1 )ram <= dataIn;dataOut <= ram;endwham bam thank you ma'am. it works.Totally doesnt work on the chip.Simulation looks good tho.Got it figured out. just had to read EVERY sentence in the datasheet regarding the timing. The following produces a result that matches the datasheet timing diagram.Code:assign dataOut = ram;always @( posedge clk )beginif( w_re == 1 )ram <= dataIn;