一个简易的(不完整的)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 PSLVERR 19 ); 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: data0 always @(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]; end end // Data register: data1 always @(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]; end end // Data register: data2 always @(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]; end end // Data register: data3 always @(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]; end end // 寄存器的读操作 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}}; endcase end endmodule