P
pallav
Guest
Hi all,
I'm playing around with a very simple DRAM module in Verilog.
According to my fictitious specification, I have the following:
"Any type of memory can be added. The memory should expect an enable
input when the cache system requests a read/write. Once the memory has
performed the operation, and driven the necessary output ports, it
asserts done."
Based on that, my code fro the memory module is below.
The question I have is regarding data. Currently its: assign data =
(rwb) ? DRAM[addr] : 32'bz.
Should this be made to say assign data = (en & rwb) ? DRAM[addr] :
32'bz;
Similarly, should the writing to DRAM be made to say
always @(posedge ph1)
if (en & ~rwb)
DRAM[addr] <= {byte3, byte2, byte1, byte0};
I'm wondering a scenario where en was low and rwb/addr changed. Then
I'd be incorrectly writing or changing the data port. My question is
it the responsibility of the DRAM module to ensure this doesn't
happen, or is it the responsibility of the block sending the signal to
ensure rwb/addr don't change if en is deasserted.
Which would be the preferred way? Thanks for any help.
Kind regards,
--------------------------------------------------------------------------------
`timescale 1ns / 1ps
`define DRAM_TEST_PROGRAM "../tests/mult.bin"
`define MEMSYS_INSTR_PROGRAM "../tests/mult.bin"
`define MEMSYS_DATA_PROGRAM "../tests/fib.bin"
/*
* Generic DRAM module. Data width is 32 bits and big-endian (address
is MSB
* byte) is assumed.
*
* SIZE = 2^{ADDRIDX}.
*/
module dram #(parameter SIZE = 8192, parameter ADDRIDX = 13)
(input ph1, ph2, reset, // non-overlapping clocks/reset
input [ADDRIDX-1:0] addr, // address
inout [31:0] data, // bi-directional data
input [3:0] bytemask, // byte enable mask
input rwb, en, // read/write bar, memory enable
output done); // memory operation complete
reg [31:0] DRAM[SIZE-1:0];
// assign bytes of data to write depending upon bytemask.
wire [7:0] byte3, byte2, byte1, byte0;
assign byte0 = bytemask[0] ? data[7:0] : DRAM[addr][7:0];
assign byte1 = bytemask[1] ? data[15:8] : DRAM[addr][15:8];
assign byte2 = bytemask[2] ? data[23:16] : DRAM[addr][23:16];
assign byte3 = bytemask[3] ? data[31:24] : DRAM[addr][31:24];
// if reading drive data on bus; otherwise bus is high impedance.
assign data = (rwb) ? DRAM[addr] : 32'bz;
// for memory op, simulate 2 cycle delay by creating a 3 state FSM,
enable
// done when we reach state 3.
wire [1:0] state;
reg [1:0] nextstate;
dflopr #(2) dramstate(.ph1(ph1), .ph2(ph2), .reset(reset), .d
(nextstate), .q(state));
assign done = state[1];
always @(*)
case (state)
2'b00:
if (en)
nextstate <= 2'b01;
else
nextstate <= 2'b00;
2'b01:
if (en)
nextstate <= 2'b10;
else
nextstate <= 2'b00;
default:
nextstate <= 2'b00;
endcase
// write to memory (rwb = 0)
always @(posedge ph1)
if (~rwb)
DRAM[addr] <= {byte3, byte2, byte1, byte0};
// for DRAM testing only
`ifdef DRAM_TEST
initial
begin
$readmemh(`DRAM_TEST_PROGRAM, DRAM);
$display($time, ": Memory initialized with ",
`DRAM_TEST_PROGRAM, ".");
end
`endif
// for MEMSYS testing only
`ifdef MEMSYS_TEST
initial
begin
$readmemh(`MEMSYS_INSTR_PROGRAM, DRAM, 'h100);
$display($time, ": Memory initialized at 0x%h with ", 13'h100,
`MEMSYS_INSTR_PROGRAM, ".");
$readmemh(`MEMSYS_DATA_PROGRAM, DRAM, 'h200);
$display($time, ": Memory initialized at 0x%h with ", 13'h200,
`MEMSYS_DATA_PROGRAM, ".");
end
`endif
endmodule // dram
I'm playing around with a very simple DRAM module in Verilog.
According to my fictitious specification, I have the following:
"Any type of memory can be added. The memory should expect an enable
input when the cache system requests a read/write. Once the memory has
performed the operation, and driven the necessary output ports, it
asserts done."
Based on that, my code fro the memory module is below.
The question I have is regarding data. Currently its: assign data =
(rwb) ? DRAM[addr] : 32'bz.
Should this be made to say assign data = (en & rwb) ? DRAM[addr] :
32'bz;
Similarly, should the writing to DRAM be made to say
always @(posedge ph1)
if (en & ~rwb)
DRAM[addr] <= {byte3, byte2, byte1, byte0};
I'm wondering a scenario where en was low and rwb/addr changed. Then
I'd be incorrectly writing or changing the data port. My question is
it the responsibility of the DRAM module to ensure this doesn't
happen, or is it the responsibility of the block sending the signal to
ensure rwb/addr don't change if en is deasserted.
Which would be the preferred way? Thanks for any help.
Kind regards,
--------------------------------------------------------------------------------
`timescale 1ns / 1ps
`define DRAM_TEST_PROGRAM "../tests/mult.bin"
`define MEMSYS_INSTR_PROGRAM "../tests/mult.bin"
`define MEMSYS_DATA_PROGRAM "../tests/fib.bin"
/*
* Generic DRAM module. Data width is 32 bits and big-endian (address
is MSB
* byte) is assumed.
*
* SIZE = 2^{ADDRIDX}.
*/
module dram #(parameter SIZE = 8192, parameter ADDRIDX = 13)
(input ph1, ph2, reset, // non-overlapping clocks/reset
input [ADDRIDX-1:0] addr, // address
inout [31:0] data, // bi-directional data
input [3:0] bytemask, // byte enable mask
input rwb, en, // read/write bar, memory enable
output done); // memory operation complete
reg [31:0] DRAM[SIZE-1:0];
// assign bytes of data to write depending upon bytemask.
wire [7:0] byte3, byte2, byte1, byte0;
assign byte0 = bytemask[0] ? data[7:0] : DRAM[addr][7:0];
assign byte1 = bytemask[1] ? data[15:8] : DRAM[addr][15:8];
assign byte2 = bytemask[2] ? data[23:16] : DRAM[addr][23:16];
assign byte3 = bytemask[3] ? data[31:24] : DRAM[addr][31:24];
// if reading drive data on bus; otherwise bus is high impedance.
assign data = (rwb) ? DRAM[addr] : 32'bz;
// for memory op, simulate 2 cycle delay by creating a 3 state FSM,
enable
// done when we reach state 3.
wire [1:0] state;
reg [1:0] nextstate;
dflopr #(2) dramstate(.ph1(ph1), .ph2(ph2), .reset(reset), .d
(nextstate), .q(state));
assign done = state[1];
always @(*)
case (state)
2'b00:
if (en)
nextstate <= 2'b01;
else
nextstate <= 2'b00;
2'b01:
if (en)
nextstate <= 2'b10;
else
nextstate <= 2'b00;
default:
nextstate <= 2'b00;
endcase
// write to memory (rwb = 0)
always @(posedge ph1)
if (~rwb)
DRAM[addr] <= {byte3, byte2, byte1, byte0};
// for DRAM testing only
`ifdef DRAM_TEST
initial
begin
$readmemh(`DRAM_TEST_PROGRAM, DRAM);
$display($time, ": Memory initialized with ",
`DRAM_TEST_PROGRAM, ".");
end
`endif
// for MEMSYS testing only
`ifdef MEMSYS_TEST
initial
begin
$readmemh(`MEMSYS_INSTR_PROGRAM, DRAM, 'h100);
$display($time, ": Memory initialized at 0x%h with ", 13'h100,
`MEMSYS_INSTR_PROGRAM, ".");
$readmemh(`MEMSYS_DATA_PROGRAM, DRAM, 'h200);
$display($time, ": Memory initialized at 0x%h with ", 13'h200,
`MEMSYS_DATA_PROGRAM, ".");
end
`endif
endmodule // dram