前面分析了AHB总线协议。接下来分析APB总线协议。
(一) APB总线接口:
PCLK APB总线时钟。
PRESETn APB总线复位。低有效。
PADDR 地址总线。
PSELx 从设备选择。
PENABLE APB传输选通。
PWRITE 高为写传输,低为读。
PRDATA 读数据总线。
PWDATA 写数据总线。
接口信号定义如下:
1 interface apb_slv_intf #( 2 parameter AW = 32, 3 DW = 32 4 ) ( 5 input logic PCLK, 6 input logic PRESETn 7 ); 8 logic PSEL; 9 logic PENABLE; 10 logic [AW-1:0] PADDR; 11 logic PWRITE; 12 logic [DW-1:0] PWDATA; 13 14 logic [DW-1:0] PRDATA; 15 16 17 modport m ( 18 input PRDATA, 19 output PSEL, PENABLE, PADDR, PWRITE, PWDATA 20 ); 21 22 modport s ( 23 input PSEL, PENABLE, PADDR, PWRITE, PWDATA, 24 output PRDATA 25 ); 26 27 endinterface: apb_slv_intf
(二) APB总线时序图:
写传输
读传输
注意在PENABLE信号有效后从设备需要给出有效数据/读取有效数据。
(三) AHB总线到APB总线转换桥
1 module ahb2apb_bridge #( 2 parameter AHB_AW = 32, 3 AHB_DW = 32, 4 APB_AW = 32, 5 APB_DW = 32, 6 NSLV = 16 7 ) ( 8 input logic HCLK, 9 input logic HRESETn, 10 input logic PCLK, 11 input logic PRESETn, 12 ahb_slv_intf.s ahb, 13 apb_slv_intf.m apbv[NSLV] 14 ); 15 16 logic ahb_work; 17 logic apb_work; 18 19 genvar i; 20 21 typedef enum logic [1:0] { 22 AHB_IDLE = 2'b00, 23 AHB_WRITE = 2'b01, 24 AHB_READ = 2'b10, 25 AHB_WAIT = 2'b11 26 } ahb_state_e; 27 28 // Signal of AHB Domain 29 struct { 30 logic work; 31 logic [AHB_AW-1:0] addr; 32 logic [AHB_DW-1:0] data; 33 logic write; 34 ahb_state_e cstate, nstate; 35 } ahbd; 36 37 typedef enum logic [1:0] { 38 APB_IDLE = 2'b00, 39 APB_WRITE = 2'b01, 40 APB_READ = 2'b10 41 } apb_state_e; 42 43 // Signal of APB Domain 44 struct { 45 logic work; 46 logic [APB_DW-1:0] data[NSLV]; 47 logic PSEL[NSLV]; 48 logic PENABLE[NSLV]; 49 apb_state_e cstate, nstate; 50 } apbd; 51 52 53 // AHB Control Logic 54 always_comb begin 55 case (ahbd.cstate) 56 AHB_IDLE: begin 57 if (ahb.HSEL && ahb.HTRANS == HTRANS_NONSEQ) begin 58 if (ahb.HWRITE) 59 ahbd.nstate = AHB_WRITE; 60 else 61 ahbd.nstate = AHB_READ; 62 end 63 else 64 ahbd.nstate = AHB_IDLE; 65 end 66 AHB_WRITE: begin 67 if (apbd.work) 68 ahbd.nstate = AHB_WAIT; 69 else 70 ahbd.nstate = AHB_WRITE; 71 end 72 AHB_READ: begin 73 if (apbd.work) 74 ahbd.nstate = AHB_WAIT; 75 else 76 ahbd.nstate = AHB_READ; 77 end 78 AHB_WAIT: begin 79 if (!apbd.work) 80 ahbd.nstate = AHB_IDLE; 81 else 82 ahbd.nstate = AHB_WAIT; 83 end 84 default: ahbd.nstate = AHB_IDLE; 85 endcase 86 end 87 88 always_ff @(posedge HCLK or negedge HRESETn) begin 89 if (!HRESETn) 90 ahbd.cstate <= AHB_IDLE; 91 else 92 ahbd.cstate <= ahbd.nstate; 93 end 94 95 always_ff @(posedge HCLK or negedge HRESETn) begin 96 if (!HRESETn) begin 97 ahbd.work <= 1'b0; 98 ahbd.addr <= '0; 99 ahbd.data <= '0; 100 ahbd.write <= 1'b0; 101 ahb.HREADY <= 1'b1; 102 ahb.HRDATA[APB_DW-1:0] <= '0; 103 end 104 else begin 105 case (ahbd.cstate) 106 AHB_IDLE: begin 107 if (ahb.HSEL && ahb.HTRANS == HTRANS_NONSEQ) begin 108 ahbd.addr <= ahb.HADDR; 109 ahbd.write <= ahb.HWRITE; 110 ahb.HREADY <= 1'b0; 111 end 112 else begin 113 ahbd.addr <= '0; 114 ahbd.write <= 1'b0; 115 ahb.HREADY <= 1'b1; 116 end 117 ahbd.work <= 1'b0; 118 ahbd.data <= '0; 119 ahb.HRDATA[APB_DW-1:0] <= apbd.data[ahbd.addr[AHB_AW-5:AHB_AW-8]]; 120 end 121 AHB_WRITE: begin 122 ahb.HREADY <= 1'b0; 123 ahbd.work <= 1'b1; 124 ahbd.data <= ahb.HWDATA; 125 ahb.HRDATA[APB_DW-1:0] <= '0; 126 end 127 AHB_READ: begin 128 ahbd.work <= 1'b1; 129 ahbd.data <= '0; 130 ahb.HREADY <= 1'b0; 131 ahb.HRDATA[APB_DW-1:0] <= '0; 132 end 133 AHB_WAIT: begin 134 ahbd.work <= 1'b0; 135 ahb.HREADY <= 1'b0; 136 ahb.HRDATA[APB_DW-1:0] <= '0; 137 end 138 endcase 139 end 140 end 141 142 assign ahb.HRESP = HRESP_OKAY; 143 // assign ahb.HRDATA[AHB_DW-1:APB_DW] = '0; 144 145 146 // APB Control Logic 147 always_comb begin 148 case (apbd.cstate) 149 APB_IDLE: begin 150 if (ahbd.work) begin 151 if (ahbd.write) 152 apbd.nstate = APB_WRITE; 153 else 154 apbd.nstate = APB_READ; 155 end 156 else 157 apbd.nstate = APB_IDLE; 158 end 159 APB_WRITE: apbd.nstate = APB_IDLE; 160 APB_READ: apbd.nstate = APB_IDLE; 161 default: apbd.nstate = APB_IDLE; 162 endcase 163 end 164 165 always_ff @(posedge PCLK or negedge PRESETn) begin 166 if (!PRESETn) 167 apbd.cstate <= APB_IDLE; 168 else 169 apbd.cstate <= apbd.nstate; 170 end 171 172 always_ff @(posedge PCLK or negedge PRESETn) begin 173 if (!PRESETn) begin 174 apbd.work <= 1'b0; 175 for (int j = 0; j < NSLV; j++) begin 176 apbd.PSEL[j] <= 1'b0; 177 apbd.PENABLE[j] <= 1'b0; 178 end 179 end 180 else begin 181 case (apbd.cstate) 182 APB_IDLE: begin 183 if (ahbd.work) begin 184 apbd.work <= 1'b1; 185 for (int j = 0; j < NSLV; j++) 186 apbd.PSEL[j] <= (ahbd.addr[AHB_AW-5:AHB_AW-8] == j) ? 1'b1 : 1'b0; 187 end 188 else begin 189 apbd.work <= 1'b0; 190 for (int j = 0; j < NSLV; j++) 191 apbd.PSEL[j] <= 1'b0; 192 end 193 for (int j = 0; j < NSLV; j++) 194 apbd.PENABLE[j] <= 1'b0; 195 end 196 APB_WRITE: begin 197 apbd.work <= 1'b1; 198 for (int j = 0; j < NSLV; j++) 199 apbd.PENABLE[j] <= (ahbd.addr[AHB_AW-5:AHB_AW-8] == j) ? 1'b1 : 1'b0; 200 end 201 APB_READ: begin 202 apbd.work <= 1'b1; 203 for (int j = 0; j < NSLV; j++) 204 apbd.PENABLE[j] <= (ahbd.addr[AHB_AW-5:AHB_AW-8] == j) ? 1'b1 : 1'b0; 205 end 206 endcase 207 end 208 end 209 210 generate 211 for (i = 0; i < NSLV; i++) begin: apbv_loop 212 assign apbv[i].PADDR = {4'h0, ahbd.addr[APB_AW-4-1:0]}; 213 assign apbv[i].PWRITE = ahbd.write; 214 assign apbv[i].PWDATA = ahbd.data[APB_DW-1:0]; 215 assign apbd.data[i] = apbv[i].PRDATA; 216 assign apbv[i].PSEL = apbd.PSEL[i]; 217 assign apbv[i].PENABLE = apbd.PENABLE[i]; 218 end 219 endgenerate 220 221 endmodule: ahb2apb_bridge