verilog源码积累:ram和axi slaver

这两个代码,用过,觉得不错。收下。

ram可以改写成可读可写的memory模型

主要是配合$readmemh,$fopen,$fdisplay

参考文档:

ram.v

`timescale 1ns / 1ps
//-----------------------------------------------------
// Design Name : ram_sp_sr_sw
// File Name   : ram_sp_sr_sw.v
// Function    : Synchronous read write RAM 
// Coder       : Deepak Kumar Tala
//-----------------------------------------------------
module ram_sp_sr_sw (
clk         , // Clock Input
address     , // Address Input
data        , // Data bi-directional
cs          , // Chip Select
we          , // Write Enable/Read Enable
oe            // Output Enable
); 

parameter DATA_WIDTH = 5 ;
parameter ADDR_WIDTH = 5 ;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;

//--------------Input Ports----------------------- 
input                  clk         ;
input [ADDR_WIDTH-1:0] address     ;
input                  cs          ;
input                  we          ;
input                  oe          ; 

//--------------Inout Ports----------------------- 
inout [DATA_WIDTH-1:0]  data       ;

//--------------Internal variables---------------- 
reg [DATA_WIDTH-1:0] data_out ;
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
reg                  oe_r;

//--------------Code Starts Here------------------ 

initial  $readmemh("ram_init.txt",mem); // initialize readback from a file

// Tri-State Buffer control 
// output : When we = 0, oe = 1, cs = 1
assign data = (cs && oe_r && !we) ? data_out : {DATA_WIDTH{1'bz}}; 

// Memory Write Block 
// Write Operation : When we = 1, cs = 1
always @ (posedge clk)
begin : MEM_WRITE
   if ( cs && we ) begin
       mem[address] = data;
   end
end

// Memory Read Block 
// Read Operation : When we = 0, oe = 1, cs = 1
always @ (posedge clk)
begin : MEM_READ
  if (cs && !we && oe) begin
    data_out = mem[address];
    oe_r = 1;
  end else begin
    oe_r = 0;
  end
end

endmodule // End of Module ram_sp_sr_sw

axi slaver.v

`timescale 1ns/10ps

module axi_slave
#(
parameter   AXI_ID_WIDTH = 4
)
(
        clk,
        rstn,

        // AXI write address channel
        i_awaddr,
        i_awid,
        i_awlen,
        i_awvalid,
        o_awready,

        // AXI write data channel
        i_wdata,
        i_wid,
        i_wstrb,
        i_wlast,
        i_wvalid,
        o_wready,
        o_bresp,
        o_bid,
        o_bvalid,
        i_bready,

        // AXI read address channel
        i_araddr,
        i_arid,
        i_arlen,
        i_arvalid,
        o_arready,

        // AXI read data channel
        o_rdata,
        o_rid,
        o_rresp,
        o_rlast,
        o_rvalid,
        i_rready
);

input           clk;
input           rstn;

// AXI write address channel
input   [31:0]  i_awaddr;
input   [AXI_ID_WIDTH-1:0]   i_awid;
input   [3:0]   i_awlen;
input           i_awvalid;
output          o_awready;

// AXI write data channel
input   [31:0]  i_wdata;
input   [AXI_ID_WIDTH-1:0]   i_wid;
input   [3:0]   i_wstrb;
input           i_wlast;
input           i_wvalid;
output          o_wready;
output  [AXI_ID_WIDTH-1:0]   o_bid;
output  [1:0]   o_bresp;
output          o_bvalid;
input           i_bready;

// AXI read address channel
input   [31:0]  i_araddr;
input   [AXI_ID_WIDTH-1:0]   i_arid;
input   [3:0]   i_arlen;
input           i_arvalid;
output          o_arready;

// AXI read data channel
output  [31:0]  o_rdata;
output  [AXI_ID_WIDTH-1:0]   o_rid;
output  [1:0]   o_rresp;
output          o_rlast;
output          o_rvalid;
input           i_rready;

parameter      ST_R_IDLE = 3'd0;
parameter      ST_R_PRE1 = 3'd1;
parameter      ST_R_PRE2 = 3'd2;
parameter      ST_R_PRE3 = 3'd3;
parameter      ST_R_READ = 3'd4;
parameter      ST_R_END  = 3'd5;

parameter      ST_W_IDLE  = 3'd0;
parameter      ST_W_PRE1  = 3'd1;
parameter      ST_W_PRE2  = 3'd2;
parameter      ST_W_PRE3  = 3'd3;
parameter      ST_W_WRITE = 3'd4;
parameter      ST_W_END   = 3'd5;

reg     [2:0]  r_cs;
reg     [2:0]  r_ns;
reg     [2:0]  w_cs;
reg     [2:0]  w_ns;

reg     [3:0]  rdcnt;
reg     [31:0] araddr;
reg     [3:0]  arlen;
reg     [AXI_ID_WIDTH-1:0]  arid;

reg     [3:0]  wdcnt;
reg     [31:0] awaddr;
reg     [3:0]  awlen;
reg     [AXI_ID_WIDTH-1:0]  awid;

reg     [5:0]  axi_wait_cnt_0;
reg     [5:0]  axi_wait_cnt_1;
reg     [5:0]  axi_wait_num_0;
reg     [5:0]  axi_wait_num_1;
reg     [31:0] rdn_num_0;
reg     [31:0] rdn_num_1;

reg     [31:0]  o_rdata;
reg     [31:0]  mem[63:0];

initial begin
    $mem_alloc();
end

always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        rdn_num_0 <= 32'd0;
        rdn_num_1 <= 32'd0;
    end else begin
        rdn_num_0 <= $random;
        rdn_num_1 <= $random;
    end
end

always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        axi_wait_cnt_0 <= 6'd0;
        axi_wait_num_0 <= 6'd8;
    end else if (i_arvalid & o_arready) begin
        axi_wait_cnt_0 <= 6'd0;
        axi_wait_num_0 <= rdn_num_0[5:0];
    end else if (i_arvalid & !o_arready) begin
        if (axi_wait_cnt_0==axi_wait_num_0) begin
            axi_wait_cnt_0 <= 5'd0;
        end else begin
            axi_wait_cnt_0 <= axi_wait_cnt_0 + 1'b1;
        end
    end
end

always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        axi_wait_cnt_1 <= 6'd0;
        axi_wait_num_1 <= 6'd8;
    end else if (i_awvalid & o_awready) begin
        axi_wait_cnt_1 <= 6'd0;
        axi_wait_num_1 <= rdn_num_1[5:0];
    end else if (i_awvalid & !o_awready) begin
        if (axi_wait_cnt_1==axi_wait_num_1) begin
            axi_wait_cnt_1 <= 5'd0;
        end else begin
            axi_wait_cnt_1 <= axi_wait_cnt_1 + 1'b1;
        end
    end
end

//------------------------------------------------------------------------------------------------
`ifdef AXI_BUSY
assign o_arready = (r_cs==ST_R_IDLE) & (axi_wait_cnt_0==axi_wait_num_0);
`else
assign o_arready = (r_cs==ST_R_IDLE);
`endif

assign o_rresp   = 2'b00;
assign o_rvalid  = (r_cs==ST_R_READ);
assign o_rlast   = o_rvalid & (rdcnt==arlen);
assign o_rid     = arid;

always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        r_cs <= ST_R_IDLE;
    end else begin
        r_cs <= r_ns;
    end
end

always@(*) begin

    r_ns = r_cs;

    case (r_cs)
        ST_R_IDLE : r_ns = (i_arvalid & o_arready) ? ST_R_PRE1 : r_cs;
        ST_R_PRE1 : r_ns = ST_R_PRE2;
        ST_R_PRE2 : r_ns = ST_R_PRE3;
        ST_R_PRE3 : r_ns = ST_R_READ;
        ST_R_READ : r_ns = (o_rvalid & i_rready & rdcnt==arlen) ? ST_R_END : r_cs;
        ST_R_END  : r_ns = ST_R_IDLE;
    endcase
end


always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        rdcnt <= 4'd0;
    end else if (o_rvalid & i_rready) begin
        if (rdcnt==arlen) begin
            rdcnt <= 4'd0;
        end else begin
            rdcnt <= rdcnt + 1'b1;
        end
    end
end

always@(posedge clk) begin
    if (i_arvalid & o_arready) begin
        araddr <= i_araddr;
    arlen  <= i_arlen;
        arid   <= i_arid;
    end
end

always@(posedge clk) begin
    if ((r_cs==ST_R_PRE3) || (r_cs==ST_R_READ)) begin
        $mem_read(araddr,o_rdata);
        araddr <= araddr + 4;
    end
end

//------------------------------------------------------------------------------------------------
always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        w_cs <= ST_W_IDLE;
    end else begin
        w_cs <= w_ns;
    end
end

always@(*) begin

    w_ns = w_cs;

    case (w_cs)
        ST_W_IDLE  : w_ns = (i_awvalid & o_awready) ? ST_W_PRE1 : w_cs;
        ST_W_PRE1  : w_ns = ST_W_PRE2;
        ST_W_PRE2  : w_ns = ST_W_PRE3;
        ST_W_PRE3  : w_ns = ST_W_WRITE;
        ST_W_WRITE : w_ns = (i_wvalid & o_wready & wdcnt==awlen) ? ST_W_END : w_cs;
        ST_W_END   : w_ns = (o_bvalid & i_bready) ? ST_W_IDLE : w_cs;
    endcase
end

always@(posedge clk or negedge rstn) begin
    if (!rstn) begin
        wdcnt <= 4'd0;
    end else if (i_wvalid & o_wready) begin
        if (wdcnt==awlen) begin
            wdcnt <= 4'd0;
        end else begin
            wdcnt <= wdcnt + 1'b1;
        end
    end
end

always@(posedge clk) begin
    if (i_awvalid & o_awready) begin
        awaddr <= i_awaddr;
    awlen  <= i_awlen;;
        awid   <= i_awid;
    end
end

always@(posedge clk) begin
  integer t;
    if (i_wvalid & o_wready) begin
        $mem_write(awaddr,i_wstrb,i_wdata);
        awaddr <= awaddr + 4;
    end
end

// for error checking
always@(posedge clk) begin
    if (i_wvalid & o_wready) begin
        if (wdcnt==awlen & !i_wlast) begin
            $display("[FAIL]: awlen does not match with wlast");
            $finish;
        end
        if (wdcnt!=awlen & i_wlast) begin
            $display("[FAIL]: awlen does not match with wlast");
            $finish;
        end
    end
end

`ifdef AXI_BUSY
assign o_awready = (w_cs==ST_W_IDLE) & (axi_wait_cnt_1==axi_wait_num_1);
`else
assign o_awready = (w_cs==ST_W_IDLE);
`endif

assign o_wready  = (w_cs==ST_W_WRITE);
assign o_bresp   = 2'b00;
assign o_bid     = awid;
assign o_bvalid  = (w_cs==ST_W_END);

endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值