📄 sramcon_sim.v
字号:
/*********************************************************/
// MODULE: SRAM/ROM Controller simulation
//
// FILE NAME: sramcon_sim.v
// VERSION: 1.0
// DATE: January 1, 1999
// AUTHOR: Bob Zeidman, Zeidman Consulting
//
// CODE TYPE: Simulation
//
// DESCRIPTION: This module provides stimuli for simulating
// an SRAM/ROM memory controller. It uses an SRAM model and
// performs a number of writes and reads to the model,
// 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 WR_COUNT 1 // Number of write cycles needed
`define RD_COUNT 4 // Number of read cycles needed
`define CLK_HPERIOD 50 // Clock half period
// Clock period
`define CLK_PERIOD CLK_HPERIOD*2
`define WR_PERIOD 70 // Write access time of memory
// Should be between
// (WR_COUNT-1)*CLK_PERIOD and
// WR_COUNT*CLK_PERIOD
`define RD_PERIOD 350 // Read access time of memory
// (RD_COUNT-1)*CLK_PERIOD and
// RD_COUNT*CLK_PERIOD
`define DWIDTH 8 // Data bus width
`define ADEPTH 256 // Memory depth
`define AWIDTH 8 // Number of bits needed to
// address memory
// TOP MODULE
module sramcon_sim();
// INPUTS
// OUTPUTS
// INOUTS
// SIGNAL DECLARATIONS
reg clock;
reg reset;
reg as;
reg rw;
wire out_en;
wire write_en;
wire ack;
reg [`DWIDTH-1:0] data_out; // Data out of processor
wire [`DWIDTH-1:0] data; // Data bus
reg [`AWIDTH-1:0] address; // Address bus
integer cyc_count; // Count cycles to determine
// if the access has taken
// too long
reg [`AWIDTH:0] addr_count; // Address counter
reg [`DWIDTH-1:0] data_patt; // Data pattern holder
// PARAMETERS
// ASSIGN STATEMENTS
assign data = (as & rw) ? 8'hzz : data_out;
// MAIN CODE
// Instantiate the controller
sram_control Sram_control(
.clock(clock),
.reset_n(~reset),
.as_n(~as),
.rw(rw),
.out_en(out_en),
.write_en(write_en),
.ack(ack));
// Instantiate an SRAM
sram Sram(
.rd(out_en),
.wr(write_en),
.address(address),
.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 ((out_en === 1'b0) && (write_en === 1'b0) &&
(ack === 1'b0))
$display ("Reset is working");
else begin
$display("\nERROR at time %0t:", $time);
$display("Reset is not working");
$display(" out_en = %b", out_en);
$display(" write_en = %b", write_en);
$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[`AWIDTH] === 0) begin
// Write to memory
writemem(addr_count[`AWIDTH-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[`AWIDTH] === 0) begin
// Read from memory
readmem(addr_count[`AWIDTH-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 > (`RD_COUNT + `WR_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 [`AWIDTH-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 <= 0; // Set up a write access
as <= 1; // Assert address strobe
address <= write_addr; // Set up the address
data_out <= write_data; // Set up the data
// Wait for the acknowledge
@(posedge clock);
while (~ack) begin
// Increment the cycle count
cyc_count = cyc_count + 1;
@(posedge clock);
end
as <= 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 [`AWIDTH-1:0] read_addr; // Memory address
input [`DWIDTH-1:0] expected; // Expected read data
// OUTPUTS
// INOUTS
// TASK CODE
begin
cyc_count = 0; // Initialize the cycle count
// Wait for the rising clock edge
@(posedge clock);
rw <= 1; // Set up a read access
as <= 1; // Assert address strobe
address <= read_addr; // Set up the address
// 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 !== expected) begin
$display("\nERROR at time %0t:", $time);
$display("Controller is not working");
$display(" data written = %h", expected);
$display(" data read = %h\n", data);
// Use $stop for debugging
$stop;
end
as <= 0; // Deassert address strobe
@(posedge clock); // Wait one clock cycle
end
endtask // readmem
endmodule // sramcon_sim
// SUBMODULE
// SRAM memory model
module sram(
data,
address,
rd,
wr);
// INPUTS
input [`AWIDTH-1:0] address; // Memory address
input rd; // Read input
input wr; // Write input
// OUTPUTS
// INOUTS
inout [`DWIDTH-1:0] data; // Data lines
// SIGNAL DECLARATIONS
wire [`AWIDTH-1:0] address;
wire rd;
wire wr;
wire [`DWIDTH-1:0] data;
reg [`DWIDTH-1:0] mem[`ADEPTH-1:0]; // Stored data
time rd_time; // Time of the most recent change
// of the rd inputwire [63:0] rd_dtime; // rd_time delayed by `RD_PERIOD
// time units
time wr_time; // Time of the most recent change
// of the wr inputwire [63:0] wr_dtime; // wr_time delayed by `WD_PERIOD
// time units
reg oe; // Output enable - this signal is
// asserted after the minimum rd
// pulse time
reg we; // Write enable - this signal is
// asserted after the minimum wr
// pulse time
// PARAMETERS
// ASSIGN STATEMENTS
assign #`RD_PERIOD rd_dtime = rd_time;
assign #`WR_PERIOD wr_dtime = wr_time;
// Output the data if the rd signal is asserted
// and the oe is asserted, which means that
// we met the minimum rd pulse time
assign data = (oe & rd) ? mem[address] : 8'hzz;
// MAIN CODE
initial begin
oe = 0;
we = 0;
wr_time = 0;
rd_time = 0;
end
// Look for the beginning of the write access
always @(posedge wr) begin
wr_time = $time; // Save the time of the most
// recent rising edge of wr
we = 0;
end
always @(wr_dtime) begin
if (wr_time === wr_dtime) begin
// If this is true, the last rising edge of wr
// was exactly `WR_PERIOD time units ago, so
// assert the write enable
we = 1;
end
end
// Look for the end of the write access
always @(negedge wr) begin
if (we) begin
// Write the data if the write enable is asserted
// which means we met the minimum wr pulse time
mem[address] <= data;
end
we = 0; // Turn off the write enable
end
// Look for the beginning of the read access
always @(posedge rd) begin
rd_time = $time; // Save the time of the most
// recent rising edge of rd
oe = 0;
end
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 output enable
oe = 1;
end
end
// Look for the end of the read access
always @(negedge rd) begin
oe = 0; // Turn off the output enable
end
endmodule // sram
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -