[SOLVED] need help: bidirectional data bus and memory model (Verilog)

Status
Not open for further replies.

jlon

Newbie level 4
Joined
Jul 16, 2010
Messages
6
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Location
Denver
Activity points
1,332
As part of a larger project, I am trying to model a memory subsystem and am having trouble. It's a static async SRAM with an 8-bit bidirectional IO port.

The SRAMs are loading their images from the input files properly. The values when the 'A' (CPU) side is writing are being saved in the SRAM, I think. But when I enable the SRAM for output, it doesn't drive the stored values onto the bus, so the testbench (which simulates a CPU for now) cannot retrieve memory contents. I've stared at this and tried many (wrong) things for a few days now, and I'm stumped.

If I comment out the instantiation of the SRAMs and just drive outputB_r directly, bus_data shows its values. But when I include the SRAMs and don't drive outputB_r with register assignment, I get nothing.

Can anyone set me straight?

Complete code follows:
Code:
`timescale 1ns/100ps

module sram45C_test;
	reg bus_oeA;				// CPU-driven bus enable
	reg bus_oeB;				// CPU-driven bus enable
	reg sram_oe_;				// CPU-driven SRAM enable
	reg [15:0] addr;			// CPU-driven address
	//-------------------------------------------------------------------------
	wire [15:0] outputA;	
		reg [15:0] outputA_r; 	// used to drive outputA when A is writing
	wire [15:0] outputB;
		reg [15:0] outputB_r; 	// used to drive outputB when B is writing
	wire [15:0] bus_data;		// data from other devices shows up here
	reg [15:0] bus_r;			//drives 'bus_data' based on what side is enabled
	//-------------------------------------------------------------------------
	// create a bidirectional bus; either 'A' or 'B' drives
	always @ (outputA or outputB or bus_oeA or bus_oeB)
	begin
		case ({bus_oeB, bus_oeA})
			{1'b0, 1'b1}: bus_r = outputA;
			{1'b1, 1'b0}: bus_r = outputB;
		default: bus_r = 16'bz;
		endcase
	end
	assign bus_data = (bus_oeA | bus_oeB) ? bus_r : 16'bz;
	//-------------------------------------------------------------------------

	// create two SRAMS
	sram45C_mod #(.BANK(0)) sram0 (
		.addr(addr), .data(bus_data[7:0]),
		.ce1_(1'b0), .ce2(1'b1), .oe_(sram_oe_), .we_(~sram_oe_) );
	sram45C_mod #(.BANK(1)) sram1 (
		.addr(addr), .data(bus_data[15:8]),
		.ce1_(1'b0), .ce2(1'b1), .oe_(sram_oe_), .we_(~sram_oe_) );

	//-------------------------------------------------------------------------
	assign outputA = ( bus_oeA & ~bus_oeB) ? outputA_r : 16'bz;
	assign outputB = (~bus_oeA &  bus_oeB) ? outputB_r : 16'bz;
	
	initial begin
		$monitor("%6d addr %4h  outA %4h  bus_data %4h  outB %4h",
			$time, addr, outputA, bus_data, outputB);
	
		$display(""); $display("side 'A' sending (CPU storing value)");
		sram_oe_ = 1'b1; bus_oeA = 1'b1; bus_oeB = 1'b0;

		addr = 16'h0006;
		outputA_r = 16'hA5f4;
		#100;
		addr = 16'h0007;
		outputA_r = 16'h1749;
		#100;
		
		$display(""); $display("side 'B' sending (CPU loading value)");
		sram_oe_ = 1'b0; bus_oeA = 1'b0; bus_oeB = 1'b1;		
		
		addr = 16'h0007;
		//outputB_r = 16'h1234;  // see if this value shows on bus with SRAM not connected
		#100;
		addr = 16'h0006;
		//outputB_r = 16'h3465;  // see if this value shows on bus with SRAM not connected
		#100;
		addr = 16'h0020;
		#100;
		addr = 16'h0021;
		#100;
		addr = 16'h0022;
		#100;
		addr = 16'h0023;
		#100;

		$display(""); $display("bus disabled, everything HiZ");
		bus_oeA = 1'b0; bus_oeB = 1'b0;
		addr = 16'h1111;
		#100;
		$display("");
		$finish();
	end
	//-------------------------------------------------------------------------
	
endmodule

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

module sram45C_mod (addr, data, ce1_, ce2, oe_, we_);
	// Modeled after Cypress CY62128EV30, using ISSI 64LV6416L's Verilog as a starter.
	parameter BANK = 0;
	input ce1_, ce2, oe_, we_;
	input [15:0] addr;
	inout [7:0] data;				// bidirectional data
	//-------------------------------------------------------------------------
	reg  [7:0] mem [0:65535];
	//-------------------------------------------------------------------------
	wire [7:0] data_out;
	//-------------------------------------------------------------------------
	integer k;
	initial begin
		if (BANK == 0)	$readmemh("input\\ROM_0.img", mem);
		else 			$readmemh("input\\ROM_1.img", mem);
		for (k = 16'h0010; k < 16'h0030; k = k+ 1)
			$display("        sram[%1d] mem[%4h] = %2H", BANK, k, mem[k]);
		$display("");
	end
	//-------------------------------------------------------------------------
	wire w_en = (~ce1_ & ce2 & ~we_ &  oe_);
	wire r_en = (~ce1_ & ce2 &  we_ & ~oe_);

	assign #45 data = (r_en) ? data_out : 8'hz;
	assign data_out = mem[addr];
	
	always @ ( addr ) begin // diagnostic only
		#1; $display("        %6d addr sram[%1d] mem[%4h] = %2h   w_en %b r_en %b",
			$time, BANK, addr, mem[addr], w_en, r_en);
	end

	always @ ( data or data_out ) begin // diagnostic only
	#1; $display("        %6d data %4h data_out %4h   w_en %b r_en %b",
		$time, data, data_out, w_en, r_en);
	end
	
	always @ ( addr or w_en ) begin // actual 'write' block, with diagnostic printout
		if (w_en) begin
			#45 mem[addr] = data;
			#1; $display("        %6d stor sram[%1d] mem[%4h] = %2h  w_en %b r_en %b",
				$time, BANK, addr, mem[addr], w_en, r_en);
		end
	end
endmodule
 

An easy way to debug this is to change the memory array to be 8 bit (reg [7:0] mem
Write only once to address 0 and then you can see the memory being written / read in any simple waveform viewer.
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…