⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dramcon_sim.v

📁 各种基本单元的verilog模块.对初学者很有帮助的.
💻 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 + -