Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[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.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top