一个简易的(不完整的)APB4 slave的可以没有PREADY和PSLVERR,这两个信号都被赋予常数,以及没有PPROT。
两种不同类型的寄存器:
图: 普通寄存器电路图
图: 带读写控制寄存器电路图
图:带读写控制寄存器时序图
一般来讲,一个模块的interface到内部reg之间,需要的信号为地址信号addr,读写使能信号(分开),byte_strobe字节选通信号,读写数据信号(分开)。
interface spec:
寄存器表:
部分代码:
1 module apb4_slave #( 2 parameter ADDRWIDTH = 12) 3 ( 4 input wire PCLK, 5 input wire PRESETn, 6 7 input wire PSEL, 8 input wire[ADDRWIDTH -1:0] PADDR, 9 input wire PENABLE,10 input wire PWRITE,11 input wire[31:0] PWDATA,12 input wire[3:0] PSTRB,13 14 input wire[3:0] ECOREVNUM,15 16 output wire[31:0] PRDATA,17 output wire PREADY,18 output wire PSLVERR19 );20 21 wire [ADDRWIDTH-1:0] reg_addr;22 wire reg_read_en;23 wire reg_write_en;24 wire [3:0] reg_byte_strobe;25 wire [31:0] reg_wdata;26 wire [31:0] reg_rdata;27 28 apb4_slave #(.ADDRWIDTH (ADDRWIDTH))29 u_apb_slave_interface(30 .pclk (PCLK),31 .presetn (PRESETn),32 33 .psel (PSEL),34 .paddr (PADDR),35 .penable (PENABLE),36 .pwrite (PWRITE),37 .pwdata (PWDATA),38 .pstrb (PSTRB),39 40 .prdata (PRDATA),41 .pready (PREADY),42 .pslverr (PSLVERR),43 44 .addr (reg_addr),45 .read_en (reg_read_en),46 .write_en (reg_write_en),47 .byte_strobe (reg_byte_strobe),48 .wdata (reg_wdata),49 .tdata (reg_rdata)50 51 );
u_apb_slave_interfacef #( parameter ADDRWIDTH = 12)( // IO declaration input wire pclk, input wire presetn, // apb interface input input wire psel, input wire[ADDRWIDTH-1:0] paddr, input wire penable, input wire pwite, input wire[31:0] pwdata, input wire[3:0] pstrb, // apb interface output output wire[31:0] prdata, output wire pready, // Register interface output wire[ADDRWIDTH-1:0] addr, output wire read_en, output wire write_en, output wire[3:0] byte_pstrb, output wire[31:0] wdata, output wire[31:0] rdata);assign pready = 1'b1;assign pslverr = 1'b0;assign addr = paddr;assign read_en = psel & (~pwrite); // 当pwrite为0,psel为1的时候,才读assign write_en = psel & (~penable) & pwrite; // 在PCLK中,第一拍为psel有效,penable为低,第二拍才是psel和penable同时有效;assign byte_pstrb = pstrb;assign wdata = pwdata;assign prdata = rdata;
module apb4_slave_reg #( parameter ADDRWIDTH = 12)( input wire pclk, input wire presetn, input wire[ADDRWIDTH-1:0] addr, input wire read_en, input wire write_en, input wire[3:0] byte_pstrb, input wire[31:0] wdata, input wire ecorevnum, output wire[31:0] rdata);localparam ARM_CMSDK_APB4_EG_SLAVE_PID4 = 32'h00000004; // 12'hFD0;localparam ARM_CMSDK_APB4_EG_SLAVE_PID5 = 32'h00000000; // 12'hFD4;localparam ARM_CMSDK_APB4_EG_SLAVE_PID6 = 32'h00000000; // 12'hFD8;localparam ARM_CMSDK_APB4_EG_SLAVE_PID7 = 32'h00000000; // 12'hFDC;localparam ARM_CMSDK_APB4_EG_SLAVE_PID0 = 32'h00000019; // 12'hFE0;localparam ARM_CMSDK_APB4_EG_SLAVE_PID1 = 32'h000000B8; // 12'hFE4;localparam ARM_CMSDK_APB4_EG_SLAVE_PID2 = 32'h0000001B; // 12'hFE8;localparam ARM_CMSDK_APB4_EG_SLAVE_PID3 = 32'h00000000; // 12'hFEC;wire [3:0] wr_sel;// 取地址的高10位出来,why?// 地址是32为对其的,末尾都是0(0000)、4(0100)、8(1000)、C(1100)循环的,低两位都是一样的,只有高10位不一样assign wr_sel[0] = ((addr[(ADDRWIDTH-1):2]==10'b0000000000)&(write_en)) ? 1'b1: 1'b0;assign wr_sel[1] = ((addr[(ADDRWIDTH-1):2]==10'b0000000001)&(write_en)) ? 1'b1: 1'b0;assign wr_sel[2] = ((addr[(ADDRWIDTH-1):2]==10'b0000000010)&(write_en)) ? 1'b1: 1'b0;assign wr_sel[3] = ((addr[(ADDRWIDTH-1):2]==10'b0000000011)&(write_en)) ? 1'b1: 1'b0; // write_en = psel & (~penable) & pwrite; 时序要求在penable为高这一拍把数据写下去,所以要在其前一拍判断是否要写。// 寄存器的写操作// Data register: data0always @(posedge pclk or negedge presetn) begin if (~presetn) begin data0 <= { 32{ 1'b0}}; end else if (wr_sel[0]) begin if (byte_strobe[0]) data0[ 7:0] <= wdata[7:0]; if (byte_strobe[1]) data0[15:8] <= wdata[15:8]; if (byte_strobe[2]) data0[23:16] <= wdata[23:16]; if (byte_strobe[3]) data0[31:24] <= wdata[31:24]; endend// Data register: data1always @(posedge pclk or negedge presetn) begin if (~presetn) begin data1 <= { 32{ 1'b0}}; end else if (wr_sel[1]) begin if (byte_strobe[0]) data1[ 7:0] <= wdata[7:0]; if (byte_strobe[1]) data1[15:8] <= wdata[15:8]; if (byte_strobe[2]) data1[23:16] <= wdata[23:16]; if (byte_strobe[3]) data1[31:24] <= wdata[31:24]; endend// Data register: data2always @(posedge pclk or negedge presetn) begin if (~presetn) begin data2 <= { 32{ 1'b0}}; end else if (wr_sel[2]) begin if (byte_strobe[0]) data2[ 7:0] <= wdata[7:0]; if (byte_strobe[1]) data2[15:8] <= wdata[15:8]; if (byte_strobe[2]) data2[23:16] <= wdata[23:16]; if (byte_strobe[3]) data2[31:24] <= wdata[31:24]; endend// Data register: data3always @(posedge pclk or negedge presetn) begin if (~presetn) begin data3 <= { 32{ 1'b0}}; end else if (wr_sel[1]) begin if (byte_strobe[0]) data3[ 7:0] <= wdata[7:0]; if (byte_strobe[1]) data3[15:8] <= wdata[15:8]; if (byte_strobe[2]) data3[23:16] <= wdata[23:16]; if (byte_strobe[3]) data3[31:24] <= wdata[31:24]; endend// 寄存器的读操作always @(read_en or addr or data0 or data1 or data2 or data3 or ecorevnum) begin case (read_en) 1'b1: begin if (addr[11:4] == 8'h00) begin // 判断为RW类型的寄存器 case (addr[3:2]) 2'b00: rdata = data0; 2'b01: rdata = data1; 2'b10: rdata = data2; 2'b11: rdata = data3; default: rdata = { 32{ 1'bx}}; endcase end else if (addr[11:6] == 6'h3F) begin // 判断为RO类型的寄存器 case(addr[5:2]) 4'b0100:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID4; 4'b0101:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID5; 4'b0110:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID6; 4'b0111:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID7; 4'b1000:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID0; 4'b1001:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID1; 4'b1010:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID2; 4'b1011:rdata = {ARM_CMSDK_APB4_EG_SLAVE_PID3[31:0],ecorevnum[3:0],4'h0}; default: rdata = { 32{ 1'bx}}; endcase end else begin rdata = { 32{ 1'b0}}; end end 1'b0: begin rdata = { 32{ 1'b0}}; end default: rdata = { 32{ 1'bx}}; endcaseend endmodule