(原创)Altera 1-port ram 的wishbone slave接口写法和wishbone master BFM验证
Altera 1-port ram 的wishbone slave接口写法和wishbone master BFM验证
目标:aemb软硬件系统
在学习wishbone总线
现在的想法是:先做一个wishbone+altera ram的testbench
ToolsàMegaWizard Plug-In Manager…àcreat a new custom megafunction variation
Mem Init中选择No,leave it blank
生成altera_ram.v文件
// megafunction wizard: %RAM: 1-PORT%
// GENERATION: STANDARD
// VERSION: WM1.0
// MODULE: altsyncram
// ============================================================
// File Name: altera_ram.v
// Megafunction Name(s):
// altsyncram
//
// Simulation Library Files(s):
// altera_mf
// ============================================================
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
//
// 9.0 Build 132 02/25/2009 SJ Full Version
// ************************************************************
//Copyright (C) 1991-2009 Altera Corporation
//Your use of Altera Corporation's design tools, logic functions
//and other software and tools, and its AMPP partner logic
//functions, and any output files from any of the foregoing
//(including device programming or simulation files), and any
//associated documentation or information are expressly subject
//to the terms and conditions of the Altera Program License
//Subscription Agreement, Altera MegaCore Function License
//Agreement, or other applicable license agreement, including,
//without limitation, that your use is for the sole purpose of
//programming logic devices manufactured by Altera and sold by
//Altera or its authorized distributors. Please refer to the
//applicable agreement for further details.
// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module altera_ram (
aclr,
address,
byteena,
clock,
data,
wren,
q);
input aclr;
input [12:0] address;
input [3:0] byteena;
input clock;
input [31:0] data;
input wren;
output [31:0] q;
wire [31:0] sub_wire0;
wire [31:0] q = sub_wire0[31:0];
altsyncram altsyncram_component (
.wren_a (wren),
.aclr0 (aclr),
.clock0 (clock),
.byteena_a (byteena),
.address_a (address),
.data_a (data),
.q_a (sub_wire0),
.aclr1 (1'b0),
.address_b (1'b1),
.addressstall_a (1'b0),
.addressstall_b (1'b0),
.byteena_b (1'b1),
.clock1 (1'b1),
.clocken0 (1'b1),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.data_b (1'b1),
.eccstatus (),
.q_b (),
.rden_a (1'b1),
.rden_b (1'b1),
.wren_b (1'b0));
defparam
altsyncram_component.byte_size = 8,
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.intended_device_family = "Cyclone II",
altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.numwords_a = 8192,
altsyncram_component.operation_mode = "SINGLE_PORT",
altsyncram_component.outdata_aclr_a = "CLEAR0",
altsyncram_component.outdata_reg_a = "CLOCK0",
altsyncram_component.power_up_uninitialized = "FALSE",
altsyncram_component.widthad_a = 13,
altsyncram_component.width_a = 32,
altsyncram_component.width_byteena_a = 4;
endmodule
// ============================================================
// CNX file retrieval info
// ============================================================
// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
// Retrieval info: PRIVATE: AclrAddr NUMERIC "0"
// Retrieval info: PRIVATE: AclrByte NUMERIC "0"
// Retrieval info: PRIVATE: AclrData NUMERIC "0"
// Retrieval info: PRIVATE: AclrOutput NUMERIC "1"
// Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "1"
// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
// Retrieval info: PRIVATE: BlankMemory NUMERIC "1"
// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
// Retrieval info: PRIVATE: Clken NUMERIC "0"
// Retrieval info: PRIVATE: DataBusSeparated NUMERIC "1"
// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
// Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
// Retrieval info: PRIVATE: MIFfilename STRING ""
// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "8192"
// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3"
// Retrieval info: PRIVATE: RegAddr NUMERIC "1"
// Retrieval info: PRIVATE: RegData NUMERIC "1"
// Retrieval info: PRIVATE: RegOutput NUMERIC "1"
// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
// Retrieval info: PRIVATE: SingleClock NUMERIC "1"
// Retrieval info: PRIVATE: UseDQRAM NUMERIC "1"
// Retrieval info: PRIVATE: WRCONTROL_ACLR_A NUMERIC "0"
// Retrieval info: PRIVATE: WidthAddr NUMERIC "13"
// Retrieval info: PRIVATE: WidthData NUMERIC "32"
// Retrieval info: PRIVATE: rden NUMERIC "0"
// Retrieval info: CONSTANT: BYTE_SIZE NUMERIC "8"
// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS"
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
// Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO"
// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "8192"
// Retrieval info: CONSTANT: OPERATION_MODE STRING "SINGLE_PORT"
// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "CLEAR0"
// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0"
// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE"
// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "13"
// Retrieval info: CONSTANT: WIDTH_A NUMERIC "32"
// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "4"
// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT NODEFVAL aclr
// Retrieval info: USED_PORT: address 0 0 13 0 INPUT NODEFVAL address[12..0]
// Retrieval info: USED_PORT: byteena 0 0 4 0 INPUT NODEFVAL byteena[3..0]
// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
// Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL data[31..0]
// Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL q[31..0]
// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT NODEFVAL wren
// Retrieval info: CONNECT: @address_a 0 0 13 0 address 0 0 13 0
// Retrieval info: CONNECT: q 0 0 32 0 @q_a 0 0 32 0
// Retrieval info: CONNECT: @byteena_a 0 0 4 0 byteena 0 0 4 0
// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
// Retrieval info: CONNECT: @aclr0 0 0 0 0 aclr 0 0 0 0
// Retrieval info: CONNECT: @data_a 0 0 32 0 data 0 0 32 0
// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram.v TRUE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram.inc FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram.cmp FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram.bsf FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram_inst.v FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram_bb.v FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram_waveforms.html FALSE
// Retrieval info: GEN_FILE: TYPE_NORMAL altera_ram_wave*.jpg FALSE
// Retrieval info: LIB_FILE: altera_mf
编写altera_ram的slave接口文件,此处是根据orpXL工程中的接口写的,只不过在orpXL中是VHDL文件的。ram0_top.v文件
module ram0_top(
input clk_i,
input rst_i,
input wb_stb_i,
input wb_cyc_i,
output reg wb_ack_o,
input [31:0] wb_addr_i,
input [3:0] wb_sel_i,
input wb_we_i,
input [31:0] wb_data_i,
output [31:0] wb_data_o
);
// request signal
wire request;
// inputs to ram
wire [12:0] ram_address;
wire [31:0] ram_data;
wire [3:0] ram_byteena;
wire ram_wren;
// request signal's rising edge
reg request_delay;
wire request_rising_edge;
// ack signal
reg ram_ack;
// get request signal
assign request = wb_stb_i & wb_cyc_i;
// select data to on-chip ram only when request = '1'
// otherwise wren will be '0', so that no data will be
// written into onchip ram by mistake.
assign ram_address = (request == 1'b1)? wb_addr_i[14:2]:13'b0;
assign ram_data = (request == 1'b1)? wb_data_i:32'b0;
assign ram_byteena = (request == 1'b1)? wb_sel_i:4'b0;
assign ram_wren = (request == 1'b1)? wb_we_i:1'b0;
// [14:2] of 32-bit address input is connected to ram0,
// for the reason of 4 byte alignment of OR1200 processor.
// 8-bit char or 16-bit short int accesses are accomplished
// with the help of wb_sel_i (byteena) signal.
altera_ram ram0(
.aclr(rst_i),
.address(ram_address),
.byteena(ram_byteena),
.clock(clk_i),
.data(ram_data),
.wren(ram_wren),
.q(wb_data_o)
);
// get the rising edge of request signal
always @ (posedge clk_i)
begin
if(rst_i == 1)
request_delay <= 0;
else
request_delay <= request;
end
assign request_rising_edge = (request_delay ^ request) & request;
// generate a 1 cycle acknowledgement for each request rising edge
always @ (posedge clk_i)
begin
if (rst_i == 1)
ram_ack <= 0;
else if (request_rising_edge == 1)
ram_ack <= 1;
else
ram_ack <= 0;
end
// register wb_ack output, because onchip ram0 uses registered output
always @ (posedge clk_i)
begin
if (rst_i == 1)
wb_ack_o <= 0;
//else if(request == 1'b1)
// wb_ack_o <= 1;
else
wb_ack_o <= ram_ack;
end
endmodule
后记:其中这句
assign request_rising_edge = (request_delay ^ request) & request;
一开始把&错写成|了,浪费了时间。
wishbone master的BFM文件 wb_master_model.v文件
/////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE Master Model ////
//// ////
//// ////
//// Author: Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
/////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2001 Rudolf Usselmann ////
//// rudi@asics.ws ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer.////
//// ////
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
//// POSSIBILITY OF SUCH DAMAGE. ////
//// ////
/////////////////////////////////////////////////////////////////////
// CVS Log
//
// $Id: wb_mast_model.v,v 1.1.1.1 2001/07/26 08:22:36 rudi Exp $
//
// $Date: 2001/07/26 08:22:36 $
// $Revision: 1.1.1.1 $
// $Author: rudi $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: wb_mast_model.v,v $
// Revision 1.1.1.1 2001/07/26 08:22:36 rudi
// WISHBONE Simulation Models
//
//
//
//
//
//
/*
task mem_fill;
- Fills local burst read (rd_buf[]) and write(wr_buf[]) buffers with random values.
task wb_wr1( 32 bit address, 4 bit byte select, 32 bit write data);
- Performs a single WISHBONE write
task wb_wr4( 32 bit address, 4 bit byte select, integer delay,
32 bit data 1, 32 bit data 2, 32 bit data 3, 32 bit data 4);
- Performs 4 consecutive WISHBONE writes
- Strobe is deasserted between writes for 'delay' number of cycles
(This simulates wait state insertion ...)
task wb_wr_mult( 32 bit address, 4 bit byte select, integer delay,
integer count);
- Simular to wb_wr4, except it pwrforms "count" number of write cycles.
The data is taken from the internal wr_bub[] memory.
- Strobe is deasserted between writes for 'delay' number of cycles
(This simulates wait state insertion ...)
task wb_rmw( 32 bit address, 4 bit byte select, integer delay,
integer rcount, integer wcount);
- This task performs "rcount" read cycles, followed by wcount write cycles.
- read data is placed in to the internal rd_buf[] memory, write data is
taken from the internal wr_buf[] memory.
- Strobe is deasserted between writes for 'delay' number of cycles
(This simulates wait state insertion ...)
task wb_wmr( 32 bit address, 4 bit byte select, integer delay,
integer rcount, integer wcount);
- This task performs "wcount" write cycles, followed by "rcount" read cycles.
- read data is placed in to the internal rd_buf[] memory, write data is
taken from the internal wr_buf[] memory.
- Strobe is deasserted between writes for 'delay' number of cycles
(This simulates wait state insertion ...)
task wb_rd1( 32 bit address, 4 bit byte select, 32 bit read data);
- Performs a single WISHBONE write
task wb_rd4( 32 bit address, 4 bit byte select, integer delay,
32 bit data 1, 32 bit data 2, 32 bit data 3, 32 bit data 4);
- Performs 4 consecutive WISHBONE reads
- Strobe is deasserted between reads for 'delay' number of cycles
(This simulates wait state insertion ...)
task wb_rd_mult( 32 bit address, 4 bit byte select, integer delay,
integer count);
- Simular to wb_rd4, except it pwrforms "count" number of read cycles.
The data is read in to the internal rd_buf[] memory.
- Strobe is deasserted between reads for 'delay' number of cycles
(This simulates wait state insertion ...)
*/
//`include "wb_model_defines.v"
`timescale 1ns/100ps
module wb_mast(clk, rst, adr, din, dout, cyc, stb, sel, we, ack, err, rty);
input clk, rst;
output [31:0] adr;
input [31:0] din;
output [31:0] dout;
output cyc, stb;
output [3:0] sel;
output we;
input ack, err, rty;
////////////////////////////////////////////////////////////////////
//
// Local Wires
//
parameter mem_size = 4096;
reg [31:0] adr;
reg [31:0] dout;
reg cyc, stb;
reg [3:0] sel;
reg we;
reg [31:0] rd_mem[mem_size:0];
reg [31:0] wr_mem[mem_size:0];
integer rd_cnt;
integer wr_cnt;
////////////////////////////////////////////////////////////////////
//
// Memory Logic
//
initial
begin
adr = 32'hxxxx_xxxx;
dout = 32'hxxxx_xxxx;
cyc = 0;
stb = 0;
sel = 4'hx;
we = 1'hx;
rd_cnt = 0;
wr_cnt = 0;
#1;
$display("\nINFO: WISHBONE MASTER MODEL INSTANTIATED (%m)\n");
end
task mem_fill;
integer n;
begin
rd_cnt = 0;
wr_cnt = 0;
for(n=0;n<mem_size;n=n+1)
begin
rd_mem[n] = $random;
wr_mem[n] = $random;
end
end
endtask
////////////////////////////////////////////////////////////////////
//
// Write 1 Word Task
//
task wb_wr1;
input [31:0] a;
input [3:0] s;
input [31:0] d;
begin
@(posedge clk);
#1;
adr = a;
dout = d;
cyc = 1;
stb = 1;
we=1;
sel = s;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
#1;
cyc=0;
stb=0;
adr = 32'hxxxx_xxxx;
dout = 32'hxxxx_xxxx;
we = 1'hx;
sel = 4'hx;
end
endtask
////////////////////////////////////////////////////////////////////
//
// Write 4 Words Task
//
task wb_wr4;
input [31:0] a;
input [3:0] s;
input delay;
input [31:0] d1;
input [31:0] d2;
input [31:0] d3;
input [31:0] d4;
integer delay;
begin
@(posedge clk);
#1;
cyc = 1;
sel = s;
repeat(delay)
begin
@(posedge clk);
#1;
end
adr = a;
dout = d1;
stb = 1;
we=1;
while(~ack & ~err) @(posedge clk);
#2;
stb=0;
we=1'bx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
stb=1;
adr = a+4;
dout = d2;
we=1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
#2;
stb=0;
we=1'bx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
stb=1;
adr = a+8;
dout = d3;
we=1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
#2;
stb=0;
we=1'bx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
stb=1;
adr = a+12;
dout = d4;
we=1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
#1;
stb=0;
cyc=0;
adr = 32'hxxxx_xxxx;
dout = 32'hxxxx_xxxx;
we = 1'hx;
sel = 4'hx;
end
endtask
task wb_wr_mult;
input [31:0] a;
input [3:0] s;
input delay;
input count;
integer delay;
integer count;
integer n;
begin
@(posedge clk);
#1;
cyc = 1;
for(n=0;n<count;n=n+1)
begin
repeat(delay)
begin
@(posedge clk);
#1;
end
adr = a + (n*4);
dout = wr_mem[n + wr_cnt];
stb = 1;
we=1;
sel = s;
if(n!=0) @(posedge clk);
while(~ack & ~err) @(posedge clk);
#2;
stb=0;
we=1'bx;
sel = 4'hx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
end
cyc=0;
adr = 32'hxxxx_xxxx;
wr_cnt = wr_cnt + count;
end
endtask
task wb_rmw;
input [31:0] a;
input [3:0] s;
input delay;
input rcount;
input wcount;
integer delay;
integer rcount;
integer wcount;
integer n;
begin
@(posedge clk);
#1;
cyc = 1;
we = 1'bx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay) @(posedge clk);
#1;
we = 0;
sel = s;
for(n=0;n<rcount-1;n=n+1)
begin
adr = a + (n*4);
stb = 1;
while(~ack & ~err) @(posedge clk);
rd_mem[n + rd_cnt] = din;
//$display("Rd Mem[%0d]: %h", (n + rd_cnt), rd_mem[n + rd_cnt] );
#2;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
we = 0;
sel = s;
end
adr = a+(n*4);
stb = 1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
rd_mem[n + rd_cnt] = din;
//$display("Rd Mem[%0d]: %h", (n + rd_cnt), rd_mem[n + rd_cnt] );
#1;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
rd_cnt = rd_cnt + rcount;
for(n=0;n<wcount;n=n+1)
begin
repeat(delay)
begin
@(posedge clk);
#1;
end
adr = a + (n*4);
dout = wr_mem[n + wr_cnt];
stb = 1;
we=1;
sel = s;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
#2;
stb=0;
we=1'bx;
sel = 4'hx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
end
cyc=0;
stb=0;
we=1'bx;
sel = 4'hx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
wr_cnt = wr_cnt + wcount;
end
endtask
task wb_wmr;
input [31:0] a;
input [3:0] s;
input delay;
input rcount;
input wcount;
integer delay;
integer rcount;
integer wcount;
integer n;
begin
@(posedge clk);
#1;
cyc = 1;
we = 1'bx;
sel = 4'hx;
sel = s;
for(n=0;n<wcount;n=n+1)
begin
repeat(delay)
begin
@(posedge clk);
#1;
end
adr = a + (n*4);
dout = wr_mem[n + wr_cnt];
stb = 1;
we=1;
sel = s;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
#2;
stb=0;
we=1'bx;
sel = 4'hx;
dout = 32'hxxxx_xxxx;
adr = 32'hxxxx_xxxx;
end
wr_cnt = wr_cnt + wcount;
stb=0;
repeat(delay) @(posedge clk);
#1;
sel = s;
we = 0;
for(n=0;n<rcount-1;n=n+1)
begin
adr = a + (n*4);
stb = 1;
while(~ack & ~err) @(posedge clk);
rd_mem[n + rd_cnt] = din;
//$display("Rd Mem[%0d]: %h", (n + rd_cnt), rd_mem[n + rd_cnt] );
#2;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
we = 0;
sel = s;
end
adr = a+(n*4);
stb = 1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
rd_mem[n + rd_cnt] = din;
rd_cnt = rd_cnt + rcount;
//$display("Rd Mem[%0d]: %h", (n + rd_cnt), rd_mem[n + rd_cnt] );
#1;
cyc = 0;
stb = 0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
end
endtask
////////////////////////////////////////////////////////////////////
//
// Read 1 Word Task
//
task wb_rd1;
input [31:0] a;
input [3:0] s;
output [31:0] d;
begin
@(posedge clk);
#1;
adr = a;
cyc = 1;
stb = 1;
we = 0;
sel = s;
while(~ack & ~err) @(posedge clk);
d = din;
#1;
cyc=0;
stb=0;
adr = 32'hxxxx_xxxx;
dout = 32'hxxxx_xxxx;
we = 1'hx;
sel = 4'hx;
end
endtask
////////////////////////////////////////////////////////////////////
//
// Read 4 Words Task
//
task wb_rd4;
input [31:0] a;
input [3:0] s;
input delay;
output [31:0] d1;
output [31:0] d2;
output [31:0] d3;
output [31:0] d4;
integer delay;
begin
@(posedge clk);
#1;
cyc = 1;
we = 0;
sel = s;
repeat(delay) @(posedge clk);
adr = a;
stb = 1;
while(~ack & ~err) @(posedge clk);
d1 = din;
#2;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
we = 0;
sel = s;
adr = a+4;
stb = 1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
d2 = din;
#2;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
we = 0;
sel = s;
adr = a+8;
stb = 1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
d3 = din;
#2;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
we = 0;
sel = s;
adr = a+12;
stb = 1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
d4 = din;
#1;
stb=0;
cyc=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
end
endtask
task wb_rd_mult;
input [31:0] a;
input [3:0] s;
input delay;
input count;
integer delay;
integer count;
integer n;
begin
@(posedge clk);
#1;
cyc = 1;
we = 0;
sel = s;
repeat(delay) @(posedge clk);
for(n=0;n<count-1;n=n+1)
begin
adr = a + (n*4);
stb = 1;
while(~ack & ~err) @(posedge clk);
rd_mem[n + rd_cnt] = din;
#2;
stb=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
repeat(delay)
begin
@(posedge clk);
#1;
end
we = 0;
sel = s;
end
adr = a+(n*4);
stb = 1;
@(posedge clk);
while(~ack & ~err) @(posedge clk);
rd_mem[n + rd_cnt] = din;
#1;
stb=0;
cyc=0;
we = 1'hx;
sel = 4'hx;
adr = 32'hxxxx_xxxx;
rd_cnt = rd_cnt + count;
end
endtask
endmodule
写顶层模块wb_tb,直接从张老师给的例子中拷贝出来的,改了一下。wb_tb.v文件
`timescale 1ns/100ps
`define HALF_PERIOD 10
module wb_tb;
reg wb_clk;
reg wb_rst;
wire wb_stb;
wire wb_cyc;
wire wb_ack;
wire [3:0] wb_sel;
wire [31:0] wb_dat_to_ram;
wire [31:0] wb_dat_from_ram;
wire [31:0] wb_adr;
wire wb_we;
ram0_top ram0_inst(
.clk_i(wb_clk),
.rst_i(wb_rst),
.wb_stb_i(wb_stb),
.wb_cyc_i(wb_cyc),
.wb_data_i(wb_dat_to_ram),
.wb_data_o(wb_dat_from_ram),
.wb_addr_i(wb_adr),
.wb_we_i(wb_we),
.wb_ack_o(wb_ack),
.wb_sel_i(wb_sel)
);
/*
module wb_mast(clk, rst, adr, din, dout, cyc, stb, sel, we, ack, err, rty);
*/
wb_mast wb_mast_inst(
.clk(wb_clk),
.rst(wb_rst),
.adr(wb_adr),
.din(wb_dat_from_ram),
.dout(wb_dat_to_ram),
.cyc(wb_cyc),
.stb(wb_stb),
.sel(wb_sel),
.we(wb_we),
.ack(wb_ack),
.err(1'b0),
.rty(1'b0)
);
initial begin
wb_clk<=0;
end
always@(wb_clk)
begin
#`HALF_PERIOD wb_clk <= ~wb_clk;
end
reg [31:0] tmp_dat;
reg [31:0] d0,d1,d2,d3;
initial begin
wb_rst<=1;
#50 wb_rst<=0;
//write your test here!
@(posedge wb_clk);
wb_mast_inst.wb_wr1(32'h00,4'b1111,32'haa88);
wb_mast_inst.wb_rd1(32'h00,4'b1111,tmp_dat);
$display($time,,"readfrom %x, value = %x\n",32'h00,tmp_dat);
//adr,adr+4,adr+8,adr+12
wb_mast_inst.wb_wr4(32'h00,4'b1111,1,32'h01,32'h02,32'h03,32'h04);
wb_mast_inst.wb_rd4(32'h00,4'b1111,3,d0,d1,d2,d3);
$display($time,,"read4from %x, value = %x , %x , %x , %x\n",32'h05,d0,d1,d2,d3);
#100 $stop;
end
endmodule
仿真脚本文件 altera_ram_slave.do文件
vlib work
vmap work work
vlog *.v
vsim -L C:/altera/90/modelsim_ae/altera/verilog/220model -L C:/altera/90/modelsim_ae/altera/verilog/altera_mf work.wb_tb
add wave /wb_clk
add wave /wb_rst
add wave /wb_stb
add wave /wb_cyc
add wave /wb_ack
add wave /wb_sel
add wave -radix hex /wb_dat_to_ram
add wave -radix hex /wb_dat_from_ram
add wave -radix hex /wb_adr
add wave /wb_we
add wave -radix hex /wb_tb/ram0_inst/*
run -all
在dos窗口下切换到工作目录,运行
D:\aemb\or1200_wb_altram\wb_ram>vsim -do altera_ram_slave.do
或者在Modelsim 命令行窗口下换到工作目录,运行
VSIM(paused)>do altera_ram_slave.do
仿真结果