1. 目的及意义
CPU、存储、总线、外设看起来很平常,但是在构建系统时,并非可以很容易获取;
IP:
组件标准化、复用很有意义;
IP需要一定的业界水准;
IP精心设计,需要能够支持不同设计需求,因而要具备一定的可配置性;;
需要配备完整的验证方案、集成流程和文档;
千层之台起于累土,本博将基于组件,构建一个完整系统,从RTL到GDS的例子。
2. 设计与实现
头文件:
// ============================================================================
// Copy Right Chip, All Rights Reserved
//
// File: dp_sram_model_define.v
//
// Description:
// top tb of dp_sram_model.v
//
// Relation:
//
// Revision:
// v0.0: Initial version: debug memory?
// Chip,2015/6/6.
//
// ============================================================================
// ----------------------------------------------------------------------------
// 1. for design
// ----------------------------------------------------------------------------
`define ADDR_WIDTH 4
`define DATA_WIDTH 8
// ----------------------------------------------------------------------------
// 2. for sim
// ----------------------------------------------------------------------------
// `timescale 1ns/1ps
`define CLK_CYC 20
`define SIM_TIME 3000
参数化有利于信息管理和设计可配置。
设计文件:
// ============================================================================
// Copy Right Chip, All Rights Reserved
//
// File: dp_sram_model.v
//
// Description:
// dual port sram sim model
//
// Relation:
//
// Revision:
// v0.0: Initial version: function,format,parameter.
// Chip,2015/6/6.
// ToDo:
// 1. sync/async;
// 2. rst;
// 3. initial for fastsim;
// 4. bit mask;
// 5. deal with r/w confilct;
// 6. single port/two port;
// 7. write through;
// 8. more real just like fundry IP does;
//
// ============================================================================
// ----------------------------------------------------------------------------
// 1. include
// ----------------------------------------------------------------------------
`include "dp_sram_model_define.v"
// ----------------------------------------------------------------------------
// 2. port
// ----------------------------------------------------------------------------
module dp_sram_model
( // glb sig
input rst_n,
input clk,
// rd port
input rd,
input [`ADDR_WIDTH-1:0] rd_addr,
output [`DATA_WIDTH-1:0] rd_data,
// wr port
input wr,
input [`ADDR_WIDTH-1:0] wr_addr,
input [`DATA_WIDTH-1:0] wr_data
);
// ----------------------------------------------------------------------------
// 3. wire/reg
// ----------------------------------------------------------------------------
parameter num_units = 2 << (`ADDR_WIDTH-1); // NOTEME: 2^`ADDR_WIDTH, ^ is xor;
reg [`DATA_WIDTH-1:0] mem [num_units-1:0];// NOTEME: 1, unit width; 2,num of units;
// ----------------------------------------------------------------------------
// 4. main logic
// ----------------------------------------------------------------------------
// rd
assign rd_data = rd ? mem[rd_addr] : `DATA_WIDTH'bz; // FIXME: preserve? wr through?
// wr
always @( posedge clk ) // FIXME: com logic?
if ( wr )
mem[wr_addr] = wr_data;
else;
endmodule
// ============================================================================
// File End
// ============================================================================
3. 测试和验证
testbench:
// ============================================================================
// Copy Right Chip, All Rights Reserved
//
// File: dp_ram_model_tb.v
//
// Description:
// top tb of dp_sram_model.v
//
// Relation:
//
// Revision:
// v0.0: Initial version;
// Chip,2015/6/6.
// ToDo: for gen test data and auto check
//
// ============================================================================
// ----------------------------------------------------------------------------
// 1. include
// ----------------------------------------------------------------------------
`include "dp_sram_model_define.v"
// ----------------------------------------------------------------------------
// 2. port
// ----------------------------------------------------------------------------
module dp_sram_model_tb;
// ----------------------------------------------------------------------------
// 3. wire/reg
// ----------------------------------------------------------------------------
// port connections
reg rst_n;
reg clk;
reg rd;
reg [`ADDR_WIDTH-1:0] rd_addr;
wire [`DATA_WIDTH-1:0] rd_data;
reg wr;
reg [`ADDR_WIDTH-1:0] wr_addr;
reg [`DATA_WIDTH-1:0] wr_data;
// test data
//integer i;
parameter num_units = 2 << (`ADDR_WIDTH-1);
reg [`DATA_WIDTH-1:0] test_data [num_units-1:0];
// ----------------------------------------------------------------------------
// 4. DUT
// ----------------------------------------------------------------------------
dp_sram_model u_dp_sram_model
(
.rst_n ( rst_n ),
.clk ( clk ),
.rd ( rd ),
.rd_addr ( rd_addr ),
.rd_data ( rd_data ),
.wr ( wr ),
.wr_addr ( wr_addr ),
.wr_data ( wr_data )
);
// ----------------------------------------------------------------------------
// 5. tasks
// ----------------------------------------------------------------------------
// FIXME cnt
// init
task dp_sram_init;
begin // NOTEME: begin-end is necessary in task
@( posedge clk ) $display("\nVVVVVV: init");
// initi X
#`CLK_CYC wr = 0; wr_addr = 0; wr_data = 0;
rd = 0; rd_addr = 0; rst_n = 0;
#(`CLK_CYC/2) rst_n = 1;
end
endtask
// wr task
task dp_sram_wr;
input [`ADDR_WIDTH-1:0] addr;
input [`DATA_WIDTH-1:0] data;
begin // NOTEME: posedge clk, 1 unit before clk rise
@( posedge clk ) $display("\nVVVVVV: wr");
#(`CLK_CYC-1) wr_addr = addr; wr_data = data;
#`CLK_CYC wr = 1;
#`CLK_CYC wr = 0; wr_data = 0;
end
endtask
// rd task
task dp_sram_rd;
input [`ADDR_WIDTH-1:0] addr;
// output [7:0] data;
begin
@( posedge clk ) $display("\nVVVVVV: rd");
#(`CLK_CYC-1) rd_addr = addr;
#`CLK_CYC rd = 1;
// #1 data = rd_data;
#`CLK_CYC rd = 0;
end
endtask
// ----------------------------------------------------------------------------
// 6. stimulus
// ----------------------------------------------------------------------------
// rst,not used
// clk
initial begin
#`CLK_CYC;
#`CLK_CYC clk = 1'b0;
forever #(`CLK_CYC/2) clk = !clk; // NOTEME: without delay, sim go to dead loop!
end
// generate test data
/*
genvar i; //integer i;
for ( i=0; i<=num_units; i=i+1 )
test_data[i] <= `DATA_WIDTH'h0f + i<<4;
*/
// rd/wr, FIXME: replace with task?
initial begin
// init
dp_sram_init();
// wr
dp_sram_wr(`ADDR_WIDTH'h1,`DATA_WIDTH'h1f);
dp_sram_wr(`ADDR_WIDTH'h2,`DATA_WIDTH'h2f);
dp_sram_wr(`ADDR_WIDTH'h3,`DATA_WIDTH'h3f);
dp_sram_wr(`ADDR_WIDTH'h4,`DATA_WIDTH'h4f);
dp_sram_wr(`ADDR_WIDTH'h5,`DATA_WIDTH'h5f);
dp_sram_wr(`ADDR_WIDTH'h6,`DATA_WIDTH'h6f);
dp_sram_wr(`ADDR_WIDTH'h7,`DATA_WIDTH'h7f);
dp_sram_wr(`ADDR_WIDTH'h8,`DATA_WIDTH'h8f);
dp_sram_wr(`ADDR_WIDTH'h9,`DATA_WIDTH'h9f);
dp_sram_wr(`ADDR_WIDTH'ha,`DATA_WIDTH'haf);
dp_sram_wr(`ADDR_WIDTH'hb,`DATA_WIDTH'hbf);
dp_sram_wr(`ADDR_WIDTH'hc,`DATA_WIDTH'hcf);
dp_sram_wr(`ADDR_WIDTH'hd,`DATA_WIDTH'hdf);
dp_sram_wr(`ADDR_WIDTH'he,`DATA_WIDTH'hef);
dp_sram_wr(`ADDR_WIDTH'hf,`DATA_WIDTH'hff);
dp_sram_wr(`ADDR_WIDTH'h0,`DATA_WIDTH'h0f);
// rd
dp_sram_rd(`ADDR_WIDTH'hf);
dp_sram_rd(`ADDR_WIDTH'he);
dp_sram_rd(`ADDR_WIDTH'hd);
dp_sram_rd(`ADDR_WIDTH'hc);
dp_sram_rd(`ADDR_WIDTH'hb); // FIXME: 'dp_sram_rd' is not a function name.
dp_sram_rd(`ADDR_WIDTH'ha);
dp_sram_rd(`ADDR_WIDTH'h9);
dp_sram_rd(`ADDR_WIDTH'h8);
dp_sram_rd(`ADDR_WIDTH'h7);
dp_sram_rd(`ADDR_WIDTH'h6);
dp_sram_rd(`ADDR_WIDTH'h5);
dp_sram_rd(`ADDR_WIDTH'h4);
dp_sram_rd(`ADDR_WIDTH'h3);
dp_sram_rd(`ADDR_WIDTH'h2);
dp_sram_rd(`ADDR_WIDTH'h1);
dp_sram_rd(`ADDR_WIDTH'h0);
// FIXME: check ?
end
// ----------------------------------------------------------------------------
// 7. output/check
// ----------------------------------------------------------------------------
// monitor
/*
initial begin
@(posedge clk)
$monitor("clk=%b, rd=%b, rd_addr=%h, rd_data=%h; wr=%b, wr_addr=%h, wr_data=%h",
clk,rd,rd_addr,rd_data,wr,wr_addr,wr_data);
end
*/
// vcd
initial begin
$dumpfile("dp_sram_model_tb.vcd");
$dumpvars(0,"dp_sram_model_tb");
end
// fsdb
/*
initial begin
$fsdbDumpfile("dp_sram_model_tb.vcd");
$fsdbDumpvars(0,"dp_sram_model_tb");
end
*/
// overtime finish
initial begin
$display("\nVVVVVV: Simulation Start");
#`SIM_TIME $display("\nVVVVVV: End");
#10 $finish(0);
end
endmodule
// ============================================================================
// File End
// ============================================================================
4. 后记
目前只是实现了一个dual port memory model,后续完善项目见设计文件文件头说明。
经验之谈,但一家之言;持续更新,欢迎探讨。