📄 dramcon_sim.v
字号:
/*********************************************************/
// MODULE: DRAM Controller simulation
//
// FILE NAME: dramcon_sim.v
// VERSION: 1.0
// DATE: January 1, 1999
// AUTHOR: Bob Zeidman, Zeidman Consulting
//
// CODE TYPE: Simulation
//
// DESCRIPTION: This module provides stimuli for simulating
// a DRAM memory controller. It uses a DRAM memory model and
// performs a number of writes and reads, including
// back-to-back reads and writes. It also checks the reset
// function.
//
/*********************************************************/
// DEFINES
`define DEL 1 // Clock-to-output delay. Zero
// time delays can be confusing
// and sometimes cause problems.
`define DEL2 2 // Longer clock-to-output delay.
`define ACC_COUNT 4 // Maximum number of cycles needed
// to access memory
`define CLK_HPERIOD 50 // Clock half period
// Clock period
`define CLK_PERIOD CLK_HPERIOD*2
`define WR_PERIOD 70 // Write access time of memory
// from assertion of CAS
`define RD_PERIOD 120 // Read access time of memory
// from assertion of CAS
`define AOUT 4 // Address bit width to DRAM
`define AIN 2*`AOUT // Address bit width from processor
`define DWIDTH 8 // Data width of DRAM
`define DDEPTH 256 // Data depth of DRAM
// TOP MODULE
module dramcon_sim();
// INPUTS
// OUTPUTS
// INOUTS
// SIGNAL DECLARATIONS
reg clock;
reg reset;
reg [`AIN-1:0] addr_in;
reg as;
reg rw;
wire we_n;
wire ras_n;
wire cas_n;
wire ack;
wire [`AOUT-1:0] addr_out;
reg [`DWIDTH-1:0] data_out; // Data out of processor
wire [`DWIDTH-1:0] data; // Data bus
reg [`AIN:0] addr_count; // Address counter
reg [`DWIDTH-1:0] data_patt; // Data pattern holder
integer cyc_count; // Count cycles to determine
// if the access has taken
// too long
// PARAMETERS
// ASSIGN STATEMENTS
assign data = (as & we_n) ? 8'hzz : data_out;
// MAIN CODE
// Instantiate the controller
dram_control Dram_control(
.clock(clock),
.reset_n(~reset),
.as_n(~as),
.addr_in(addr_in),
.addr_out(addr_out),
.rw(rw),
.we_n(we_n),
.ras_n(ras_n),
.cas_n(cas_n),
.ack(ack));
// Instantiate a DRAM
dram Dram(
.ras(~ras_n),
.cas(~cas_n),
.we(~we_n),
.address(addr_out),
.data(data));
// Generate the clock
always #`CLK_HPERIOD clock = ~clock;
// Simulate
initial begin
// Initialize inputs
clock = 1;
reset = 0;
as = 0;
// Test the reset signal
#`DEL;
// Assert the reset signal
reset = 1;
// Wait for the outputs to change asynchronously
#`DEL
#`DEL
// Test outputs
if ((ras_n === 1'b1) && (cas_n === 1'b1) &&
(ack === 1'b0))
$display ("Reset is working");
else begin
$display("\nERROR at time %0t:", $time);
$display("Reset is not working");
$display(" ras_n = %b", ras_n);
$display(" cas_n = %b", cas_n);
$display(" ack = %b\n", ack);
// Use $stop for debugging
$stop;
end
// Deassert the reset signal
reset = 0;
// Initialize the address counter
addr_count = 0;
// Initialize the data pattern to be written
data_patt = `DWIDTH'h1;
// Write a series of values to memory
while (addr_count[`AIN] === 0) begin
// Write to memory
writemem(addr_count[`AIN-1:0], data_patt);
// Increment the address counter
addr_count <= addr_count + 1;
// Shift the data pattern
data_patt <= (data_patt << 1);
data_patt[0] <= data_patt[`DWIDTH-1];
// Wait for the data pattern to change
#`DEL;
end
// Initialize the address counter
addr_count = 0;
// Initialize the data pattern to be read
data_patt = `DWIDTH'h1;
// Verify the values that were written
while (addr_count[`AIN] === 0) begin
// Read from memory
readmem(addr_count[`AIN-1:0], data_patt);
// Increment the address counter
addr_count <= addr_count + 1;
// Shift the data pattern
data_patt <= (data_patt << 1);
data_patt[0] <= data_patt[`DWIDTH-1];
// Wait for the data pattern to change
#`DEL;
end
$display("\nSimulation complete - no errors\n");
$finish;
end
// Check the number of cycles for each access
always @(posedge clock) begin
// Check whether an access is taking too long
if (cyc_count > 3*`ACC_COUNT) begin
$display("\nERROR at time %0t:", $time);
if (rw)
$display("Read access took to long\n");
else
$display("Write access took to long\n");
// Use $stop for debugging
$stop;
end
end
// TASKS
// Write data to memory
task writemem;
// INPUTS
input [`AIN-1:0] write_addr; // Memory address
input [`DWIDTH-1:0] write_data; // Data to write to memory
// OUTPUTS
// INOUTS
// TASK CODE
begin
cyc_count = 0; // Initialize the cycle count
// Wait for the rising clock edge
@(posedge clock);
rw <= #`DEL 0; // Set up a write access
// Set up the address
addr_in <= #`DEL write_addr;
// Set up the data to be written
data_out <= #`DEL write_data;
as <= #`DEL2 1; // Assert address strobe
// Wait for the acknowledge
@(posedge clock);
while (~ack) begin
// Increment the cycle count
cyc_count = cyc_count + 1;
@(posedge clock);
end
as <= #`DEL 0; // Deassert address strobe
@(posedge clock); // Wait one clock cycle
end
endtask // writemem
// Read data from memory and check its value
task readmem;
// INPUTS
input [`AIN-1:0] read_addr; // Memory address
input [`DWIDTH-1:0] exp_data; // Expected read data
// OUTPUTS
// INOUTS
// TASK CODE
begin
cyc_count = 0; // Initialize the cycle count
// Wait for the rising clock edge
@(posedge clock);
rw <= #`DEL 1; // Set up a read access
// Set up the address
addr_in <= #`DEL read_addr;
as <= #`DEL2 1; // Assert address strobe
// Wait for the acknowledge
@(posedge clock);
while (~ack) begin
// Increment the cycle count
cyc_count = cyc_count + 1;
@(posedge clock);
end
// Did we find the expected data?
if (data !== exp_data) begin
$display("\nERROR at time %0t:", $time);
$display("Controller is not working");
$display(" data written = %h", exp_data);
$display(" data read = %h\n", data);
// Use $stop for debugging
$stop;
end
as <= #`DEL 0; // Deassert address strobe
@(posedge clock); // Wait one clock cycle
end
endtask // readmem
endmodule // dramcon_sim
// SUBMODULE
// DRAM memory model
module dram(
ras,
cas,
we,
address,
data);
// INPUTS
input ras; // Row address strobe
input cas; // Column address strobe
input we; // Write enable input
input [`AOUT-1:0] address; // Address input to DRAM
// OUTPUTS
// INOUTS
inout [`DWIDTH-1:0] data; // Data lines
// SIGNAL DECLARATIONS
wire ras;
wire cas;
wire we;
wire [`DWIDTH-1:0] data;
reg [`DWIDTH-1:0] mem[`DDEPTH-1:0]; // Stored data
reg [`AIN-1:0] mem_addr; // Memory address
time rd_time; // Time of the most recent change of
// the rd input
wire [63:0] rd_dtime; // rd_time delayed by `RD_PERIOD
// time units
time wr_time; // Time of the most recent change of
// the wr input
wire [63:0] wr_dtime; // wr_time delayed by `WD_PERIOD
// time units
reg oen; // Internal output enable - this
// signal is asserted after the
// minimum CAS time for a read
reg wen; // Internal write enable - this
// signal is asserted after the
// minimum CAS time for a write
// PARAMETERS
// ASSIGN STATEMENTS
assign #`RD_PERIOD rd_dtime = rd_time;
assign #`WR_PERIOD wr_dtime = wr_time;
// Output the data if the we signal is high and the oe is
// asserted, which means that we met the minimum CAS time
// for a read
assign data = (oen & ~we) ? mem[address] : 8'hzz;
// MAIN CODE
initial begin
oen = 0;
wen = 0;
wr_time = 0;
rd_time = 0;
end
// Look for the RAS rising edge for the row address
always @(posedge ras) begin
mem_addr[`AIN-1:`AOUT] <= #`DEL address;
end
// Look for the CAS rising edge for the column address
always @(posedge cas) begin
mem_addr[`AOUT-1:0] <= #`DEL address;
end
// Look for the beginning of the access
always @(posedge cas) begin
if (we) begin
// This is a write
wr_time = $time; // Save the time of the most
// recent rising edge of wr
wen = 0; // Deassert internal write enable
end
else begin
// This is a read
rd_time = $time; // Save the time of the most
// recent rising edge of rd
oen = 0; // Deassert internal read enable
end
end
// Determine whether to assert the internal write enable
always @(wr_dtime) begin
if (wr_time === wr_dtime) begin
// If this is true, the last rising edge of CAS
// was exactly `WR_PERIOD time units ago, so
// assert the internal write enable
wen = 1;
end
end
// Determine whether to assert the internal read enable
always @(rd_dtime) begin
if (rd_time === rd_dtime) begin
// If this is true, the last rising edge of rd
// was exactly `RD_PERIOD time units ago, so
// assert the internal output enable
oen = 1;
end
end
// Look for the end of the access
always @(negedge cas) begin
if (wen & we) begin
// Write the data if the write enable is asserted
// which means we met the minimum wr pulse time
mem[mem_addr] <= #`DEL data;
end
wen = 0; // Turn off the internal write enable
oen = 0; // Turn off the internal output enable
end
endmodule // dram
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -