图: 普通寄存器电路图
图: 带读写控制寄存器电路图
图:带读写控制寄存器时序图
一般来讲,一个模块的interface到内部reg之间,需要的信号为地址信号addr,读写使能信号(分开),byte_strobe字节选通信号,读写数据信号(分开)。
module apb4_slave #( parameter ADDRWIDTH = 12)
( input wire PCLK, input wire PRESETn, input wire PSEL, input wire[ADDRWIDTH -1:0] PADDR, input wire PENABLE, input wire PWRITE, input wire[31:0] PWDATA, input wire[3:0] PSTRB, input wire[3:0] ECOREVNUM, output wire[31:0] PRDATA, output wire PREADY, output wire PSLVERR
);
wire [ADDRWIDTH-1:0] reg_addr; wire reg_read_en; wire reg_write_en; wire [3:0] reg_byte_strobe; wire [31:0] reg_wdata; wire [31:0] reg_rdata;
apb4_slave #(.ADDRWIDTH (ADDRWIDTH))
u_apb_slave_interface(
.pclk (PCLK),
.presetn (PRESETn),
.psel (PSEL),
.paddr (PADDR),
.penable (PENABLE),
.pwrite (PWRITE),
.pwdata (PWDATA),
.pstrb (PSTRB),
.prdata (PRDATA),
.pready (PREADY),
.pslverr (PSLVERR),
.addr (reg_addr),
.read_en (reg_read_en),
.write_en (reg_write_en),
.byte_strobe (reg_byte_strobe),
.wdata (reg_wdata),
.tdata (reg_rdata)
);
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