Project Full coverage report
Current view: Cores-VeeR-EL2—Cores-VeeR-EL2—design—lib—ahb_to_axi4.sv Coverage Hit Total
Test Date: 08-11-2024 Toggle 83.6% 46 55
Test: all Branch 100.0% 23 23

            Line data    Source code
       1              : // SPDX-License-Identifier: Apache-2.0
       2              : // Copyright 2020 Western Digital Corporation or its affiliates.
       3              : //
       4              : // Licensed under the Apache License, Version 2.0 (the "License");
       5              : // you may not use this file except in compliance with the License.
       6              : // You may obtain a copy of the License at
       7              : //
       8              : // http://www.apache.org/licenses/LICENSE-2.0
       9              : //
      10              : // Unless required by applicable law or agreed to in writing, software
      11              : // distributed under the License is distributed on an "AS IS" BASIS,
      12              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13              : // See the License for the specific language governing permissions and
      14              : // limitations under the License.
      15              : //********************************************************************************
      16              : // $Id$
      17              : //
      18              : // Owner:
      19              : // Function: AHB to AXI4 Bridge
      20              : // Comments:
      21              : //
      22              : //********************************************************************************
      23              : module ahb_to_axi4
      24              : import el2_pkg::*;
      25              : #(
      26              :    TAG = 1,
      27              :    `include "el2_param.vh"
      28              : )
      29              : //   ,TAG  = 1)
      30              : (
      31     31200563 :    input                   clk,
      32           34 :    input                   rst_l,
      33              :    /* verilator coverage_off */
      34              :    input                   scan_mode,
      35              :    /* verilator coverage_on */
      36           22 :    input                   bus_clk_en,
      37            0 :    input                   clk_override,
      38              : 
      39              :    // AXI signals
      40              :    // AXI Write Channels
      41          402 :    output logic            axi_awvalid,
      42          420 :    input  logic            axi_awready,
      43              :    /* exclude signals that are tied to constant value in this file */
      44              :    /*verilator coverage_off*/
      45              :    output logic [TAG-1:0]  axi_awid,
      46              :    /*verilator coverage_on*/
      47           14 :    output logic [31:0]     axi_awaddr,
      48            0 :    output logic [2:0]      axi_awsize,
      49              :    /* exclude signals that are tied to constant value in this file */
      50              :    /*verilator coverage_off*/
      51              :    output logic [2:0]      axi_awprot,
      52              :    output logic [7:0]      axi_awlen,
      53              :    output logic [1:0]      axi_awburst,
      54              :    /*verilator coverage_on*/
      55              : 
      56          402 :    output logic            axi_wvalid,
      57          324 :    input  logic            axi_wready,
      58           89 :    output logic [63:0]     axi_wdata,
      59           14 :    output logic [7:0]      axi_wstrb,
      60              :    /* exclude signals that are tied to constant value in this file */
      61              :    /*verilator coverage_off*/
      62              :    output logic            axi_wlast,
      63              :    /*verilator coverage_on*/
      64              : 
      65          302 :    input  logic            axi_bvalid,
      66              :    /* exclude signals that are tied to constant value in this file */
      67              :    /*verilator coverage_off*/
      68              :    output logic            axi_bready,
      69              :    /*verilator coverage_on*/
      70            2 :    input  logic [1:0]      axi_bresp,
      71              :    /* Exclude unused AXI rid since it has no equivalent in AHB */
      72              :    /*verilator coverage_off*/
      73              :    input  logic [TAG-1:0]  axi_bid,
      74              :    /*verilator coverage_on*/
      75              : 
      76              :    // AXI Read Channels
      77          202 :    output logic            axi_arvalid,
      78          222 :    input  logic            axi_arready,
      79              :    /* exclude signals that are tied to constant value in this file */
      80              :    /*verilator coverage_off*/
      81              :    output logic [TAG-1:0]  axi_arid,
      82              :    /*verilator coverage_on*/
      83           14 :    output logic [31:0]     axi_araddr,
      84            0 :    output logic [2:0]      axi_arsize,
      85              :    /* exclude signals that are tied to constant value in this file */
      86              :    /*verilator coverage_off*/
      87              :    output logic [2:0]      axi_arprot,
      88              :    output logic [7:0]      axi_arlen,
      89              :    output logic [1:0]      axi_arburst,
      90              :    /*verilator coverage_on*/
      91              : 
      92          200 :    input  logic            axi_rvalid,
      93              :    /* exclude signals that are tied to constant value in this file */
      94              :    /*verilator coverage_off*/
      95              :    output logic            axi_rready,
      96              :    /*verilator coverage_on*/
      97              :    /* Exclude unused AXI rid since it has no equivalent in AHB */
      98              :    /*verilator coverage_off*/
      99              :    input  logic [TAG-1:0]  axi_rid,
     100              :    /*verilator coverage_on*/
     101           38 :    input  logic [63:0]     axi_rdata,
     102            2 :    input  logic [1:0]      axi_rresp,
     103              : 
     104              :    // AHB-Lite signals
     105            2 :    input logic [31:0]      ahb_haddr,     // ahb bus address
     106              :    // Exclude input signals that are unused in this file (their AXI equivalents
     107              :    // are tied to constants)
     108              :    /*verilator coverage_off*/
     109              :    input logic [2:0]       ahb_hburst,    // tied to 0
     110              :    input logic             ahb_hmastlock, // tied to 0
     111              :    input logic [3:0]       ahb_hprot,     // tied to 4'b0011
     112              :    /*verilator coverage_on*/
     113            0 :    input logic [2:0]       ahb_hsize,     // size of bus transaction (possible values 0,1,2,3)
     114          606 :    input logic [1:0]       ahb_htrans,    // Transaction type (possible values 0,2 only right now)
     115            1 :    input logic             ahb_hwrite,    // ahb bus write
     116           87 :    input logic [63:0]      ahb_hwdata,    // ahb bus write data
     117           22 :    input logic             ahb_hsel,      // this slave was selected
     118           22 :    input logic             ahb_hreadyin,  // previous hready was accepted or not
     119              : 
     120           38 :    output logic [63:0]      ahb_hrdata,      // ahb bus read data
     121          225 :    output logic             ahb_hreadyout,   // slave ready to accept transaction
     122            0 :    output logic             ahb_hresp        // slave response (high indicates erro)
     123              : 
     124              : );
     125              : 
     126            2 :    logic [7:0]       master_wstrb;
     127              : 
     128              :  typedef enum logic [1:0] {   IDLE   = 2'b00,    // Nothing in the buffer. No commands yet recieved
     129              :                               WR     = 2'b01,    // Write Command recieved
     130              :                               RD     = 2'b10,    // Read Command recieved
     131              :                               PEND   = 2'b11     // Waiting on Read Data from core
     132              :                             } state_t;
     133          223 :    state_t      buf_state, buf_nxtstate;
     134          806 :    logic        buf_state_en;
     135              : 
     136              :    // Buffer signals (one entry buffer)
     137            0 :    logic                    buf_read_error_in, buf_read_error;
     138           38 :    logic [63:0]             buf_rdata;
     139              : 
     140          225 :    logic                    ahb_hready;
     141          235 :    logic                    ahb_hready_q;
     142          606 :    logic [1:0]              ahb_htrans_in, ahb_htrans_q;
     143            0 :    logic [2:0]              ahb_hsize_q;
     144            9 :    logic                    ahb_hwrite_q;
     145           14 :    logic [31:0]             ahb_haddr_q;
     146            0 :    logic                    ahb_hresp_q;
     147              : 
     148              :     //Miscellaneous signals
     149            0 :    logic                    ahb_addr_in_dccm, ahb_addr_in_iccm, ahb_addr_in_pic;
     150           14 :    logic                    ahb_addr_in_dccm_region_nc, ahb_addr_in_iccm_region_nc, ahb_addr_in_pic_region_nc;
     151              :    // signals needed for the read data coming back from the core and to block any further commands as AHB is a blocking bus
     152          200 :    logic                    buf_rdata_en;
     153              : 
     154          200 :    logic                    ahb_addr_clk_en, buf_rdata_clk_en;
     155          200 :    logic                    bus_clk, ahb_addr_clk, buf_rdata_clk;
     156              :    // Command buffer is the holding station where we convert to AXI and send to core
     157          602 :    logic                    cmdbuf_wr_en, cmdbuf_rst;
     158          202 :    logic                    cmdbuf_full;
     159            9 :    logic                    cmdbuf_vld, cmdbuf_write;
     160           14 :    logic [1:0]              cmdbuf_size;
     161           14 :    logic [7:0]              cmdbuf_wstrb;
     162           14 :    logic [31:0]             cmdbuf_addr;
     163           89 :    logic [63:0]             cmdbuf_wdata;
     164              : 
     165              : // FSM to control the bus states and when to block the hready and load the command buffer
     166           22 :    always_comb begin
     167           22 :       buf_nxtstate      = IDLE;
     168           22 :       buf_state_en      = 1'b0;
     169           22 :       buf_rdata_en      = 1'b0;              // signal to load the buffer when the core sends read data back
     170           22 :       buf_read_error_in = 1'b0;              // signal indicating that an error came back with the read from the core
     171           22 :       cmdbuf_wr_en      = 1'b0;              // all clear from the gasket to load the buffer with the command for reads, command/dat for writes
     172           22 :       case (buf_state)
     173      8874995 :          IDLE: begin  // No commands recieved
     174      8874995 :                   buf_nxtstate      = ahb_hwrite ? WR : RD;
     175      8874995 :                   buf_state_en      = ahb_hready & ahb_htrans[1] & ahb_hsel;                 // only transition on a valid hrtans
     176              :           end
     177         2210 :          WR: begin // Write command recieved last cycle
     178         2210 :                   buf_nxtstate      = (ahb_hresp | (ahb_htrans[1:0] == 2'b0) | ~ahb_hsel) ? IDLE : ahb_hwrite  ? WR : RD;
     179         2210 :                   buf_state_en      = (~cmdbuf_full | ahb_hresp) ;
     180         2210 :                   cmdbuf_wr_en      = ~cmdbuf_full & ~(ahb_hresp | ((ahb_htrans[1:0] == 2'b01) & ahb_hsel));   // Dont send command to the buffer in case of an error or when the master is not ready with the data now.
     181              :          end
     182          606 :          RD: begin // Read command recieved last cycle.
     183          606 :                  buf_nxtstate      = ahb_hresp ? IDLE :PEND;                                       // If error go to idle, else wait for read data
     184          606 :                  buf_state_en      = (~cmdbuf_full | ahb_hresp);                                   // only when command can go, or if its an error
     185          606 :                  cmdbuf_wr_en      = ~ahb_hresp & ~cmdbuf_full;                                    // send command only when no error
     186              :          end
     187         4248 :          PEND: begin // Read Command has been sent. Waiting on Data.
     188         4248 :                  buf_nxtstate      = IDLE;                                                          // go back for next command and present data next cycle
     189         4248 :                  buf_state_en      = axi_rvalid & ~cmdbuf_write;                                    // read data is back
     190         4248 :                  buf_rdata_en      = buf_state_en;                                                  // buffer the read data coming back from core
     191         4248 :                  buf_read_error_in = buf_state_en & |axi_rresp[1:0];                                // buffer error flag if return has Error ( ECC )
     192              :          end
     193              :      endcase
     194              :    end // always_comb begin
     195              : 
     196              :     rvdffs_fpga #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk));
     197              : 
     198              :    assign master_wstrb[7:0]   = ({8{ahb_hsize_q[2:0] == 3'b0}}  & (8'b1    << ahb_haddr_q[2:0])) |
     199              :                                 ({8{ahb_hsize_q[2:0] == 3'b1}}  & (8'b11   << ahb_haddr_q[2:0])) |
     200              :                                 ({8{ahb_hsize_q[2:0] == 3'b10}} & (8'b1111 << ahb_haddr_q[2:0])) |
     201              :                                 ({8{ahb_hsize_q[2:0] == 3'b11}} & 8'b1111_1111);
     202              : 
     203              :    // AHB signals
     204              :    assign ahb_hreadyout       = ahb_hresp ? (ahb_hresp_q & ~ahb_hready_q) :
     205              :                                          ((~cmdbuf_full | (buf_state == IDLE)) & ~(buf_state == RD | buf_state == PEND)  & ~buf_read_error);
     206              : 
     207              :    assign ahb_hready          = ahb_hreadyout & ahb_hreadyin;
     208              :    assign ahb_htrans_in[1:0]  = {2{ahb_hsel}} & ahb_htrans[1:0];
     209              :    assign ahb_hrdata[63:0]    = buf_rdata[63:0];
     210              :    assign ahb_hresp        = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE)  &
     211              : 
     212              :                              ((~(ahb_addr_in_dccm | ahb_addr_in_iccm)) |                                                                                   // request not for ICCM or DCCM
     213              :                              ((ahb_addr_in_iccm | (ahb_addr_in_dccm &  ahb_hwrite_q)) & ~((ahb_hsize_q[1:0] == 2'b10) | (ahb_hsize_q[1:0] == 2'b11))) |    // ICCM Rd/Wr OR DCCM Wr not the right size
     214              :                              ((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0])   |                                                                             // HW size but unaligned
     215              :                              ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) |                                                                          // W size but unaligned
     216              :                              ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) |                                                                        // DW size but unaligned
     217              :                              buf_read_error |                                                                                                              // Read ECC error
     218              :                              (ahb_hresp_q & ~ahb_hready_q);
     219              : 
     220              :    // Buffer signals - needed for the read data and ECC error response
     221              :    rvdff_fpga  #(.WIDTH(64)) buf_rdata_ff     (.din(axi_rdata[63:0]),   .dout(buf_rdata[63:0]), .clk(buf_rdata_clk), .clken(buf_rdata_clk_en), .rawclk(clk), .*);
     222              :    rvdff_fpga  #(.WIDTH(1))  buf_read_error_ff(.din(buf_read_error_in), .dout(buf_read_error),  .clk(bus_clk),       .clken(bus_clk_en),       .rawclk(clk), .*);          // buf_read_error will be high only one cycle
     223              : 
     224              :    // All the Master signals are captured before presenting it to the command buffer. We check for Hresp before sending it to the cmd buffer.
     225              :    rvdff_fpga #(.WIDTH(1))  hresp_ff  (.din(ahb_hresp),          .dout(ahb_hresp_q),       .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     226              :    rvdff_fpga #(.WIDTH(1))  hready_ff (.din(ahb_hready),         .dout(ahb_hready_q),      .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     227              :    rvdff_fpga #(.WIDTH(2))  htrans_ff (.din(ahb_htrans_in[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     228              :    rvdff_fpga #(.WIDTH(3))  hsize_ff  (.din(ahb_hsize[2:0]),     .dout(ahb_hsize_q[2:0]),  .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     229              :    rvdff_fpga #(.WIDTH(1))  hwrite_ff (.din(ahb_hwrite),         .dout(ahb_hwrite_q),      .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     230              :    rvdff_fpga #(.WIDTH(32)) haddr_ff  (.din(ahb_haddr[31:0]),    .dout(ahb_haddr_q[31:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     231              : 
     232              :    // Address check  dccm
     233              :    rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
     234              :                   .CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck (
     235              :       .addr(ahb_haddr_q[31:0]),
     236              :       .in_range(ahb_addr_in_dccm),
     237              :       .in_region(ahb_addr_in_dccm_region_nc)
     238              :    );
     239              : 
     240              :    // Address check  iccm
     241              :    if (pt.ICCM_ENABLE == 1) begin: GenICCM
     242              :       rvrangecheck #(.CCM_SADR(pt.ICCM_SADR),
     243              :                      .CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck (
     244              :          .addr(ahb_haddr_q[31:0]),
     245              :          .in_range(ahb_addr_in_iccm),
     246              :          .in_region(ahb_addr_in_iccm_region_nc)
     247              :       );
     248              :    end else begin: GenNoICCM
     249              :       assign ahb_addr_in_iccm = '0;
     250              :       assign ahb_addr_in_iccm_region_nc = '0;
     251              :    end
     252              : 
     253              :    // PIC memory address check
     254              :    rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR),
     255              :                   .CCM_SIZE(pt.PIC_SIZE)) addr_pic_rangecheck (
     256              :       .addr(ahb_haddr_q[31:0]),
     257              :       .in_range(ahb_addr_in_pic),
     258              :       .in_region(ahb_addr_in_pic_region_nc)
     259              :    );
     260              : 
     261              :    // Command Buffer - Holding for the commands to be sent for the AXI. It will be converted to the AXI signals.
     262              :    assign cmdbuf_rst         = (((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en) | (ahb_hresp & ~cmdbuf_write);
     263              :    assign cmdbuf_full        = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)));
     264              : 
     265              :    rvdffsc_fpga #(.WIDTH(1))  cmdbuf_vldff      (.din(1'b1),              .dout(cmdbuf_vld),         .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     266              :    rvdffs_fpga  #(.WIDTH(1))  cmdbuf_writeff    (.din(ahb_hwrite_q),      .dout(cmdbuf_write),       .en(cmdbuf_wr_en),                     .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     267              :    rvdffs_fpga  #(.WIDTH(2))  cmdbuf_sizeff     (.din(ahb_hsize_q[1:0]),  .dout(cmdbuf_size[1:0]),   .en(cmdbuf_wr_en),                     .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     268              :    rvdffs_fpga  #(.WIDTH(8))  cmdbuf_wstrbff    (.din(master_wstrb[7:0]), .dout(cmdbuf_wstrb[7:0]),  .en(cmdbuf_wr_en),                     .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     269              :    rvdffe       #(.WIDTH(32)) cmdbuf_addrff     (.din(ahb_haddr_q[31:0]), .dout(cmdbuf_addr[31:0]),  .en(cmdbuf_wr_en & bus_clk_en),        .clk(clk), .*);
     270              :    rvdffe       #(.WIDTH(64)) cmdbuf_wdataff    (.din(ahb_hwdata[63:0]),  .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en & bus_clk_en),        .clk(clk), .*);
     271              : 
     272              :    // AXI Write Command Channel
     273              :    assign axi_awvalid           = cmdbuf_vld & cmdbuf_write;
     274              :    assign axi_awid[TAG-1:0]     = '0;
     275              :    assign axi_awaddr[31:0]      = cmdbuf_addr[31:0];
     276              :    assign axi_awsize[2:0]       = {1'b0, cmdbuf_size[1:0]};
     277              :    assign axi_awprot[2:0]       = 3'b0;
     278              :    assign axi_awlen[7:0]        = '0;
     279              :    assign axi_awburst[1:0]      = 2'b01;
     280              :    // AXI Write Data Channel - This is tied to the command channel as we only write the command buffer once we have the data.
     281              :    assign axi_wvalid            = cmdbuf_vld & cmdbuf_write;
     282              :    assign axi_wdata[63:0]       = cmdbuf_wdata[63:0];
     283              :    assign axi_wstrb[7:0]        = cmdbuf_wstrb[7:0];
     284              :    assign axi_wlast             = 1'b1;
     285              :   // AXI Write Response - Always ready. AHB does not require a write response.
     286              :    assign axi_bready            = 1'b1;
     287              :    // AXI Read Channels
     288              :    assign axi_arvalid           = cmdbuf_vld & ~cmdbuf_write;
     289              :    assign axi_arid[TAG-1:0]     = '0;
     290              :    assign axi_araddr[31:0]      = cmdbuf_addr[31:0];
     291              :    assign axi_arsize[2:0]       = {1'b0, cmdbuf_size[1:0]};
     292              :    assign axi_arprot            = 3'b0;
     293              :    assign axi_arlen[7:0]        = '0;
     294              :    assign axi_arburst[1:0]      = 2'b01;
     295              :    // AXI Read Response Channel - Always ready as AHB reads are blocking and the the buffer is available for the read coming back always.
     296              :    assign axi_rready            = 1'b1;
     297              : 
     298              :    // Clock header logic
     299              :    assign ahb_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]);
     300              :    assign buf_rdata_clk_en    = bus_clk_en & buf_rdata_en;
     301              : 
     302              : `ifdef RV_FPGA_OPTIMIZE
     303              :    assign bus_clk = 1'b0;
     304              :    assign ahb_addr_clk = 1'b0;
     305              :    assign buf_rdata_clk = 1'b0;
     306              : `else
     307              :    rvclkhdr bus_cgc       (.en(bus_clk_en),       .l1clk(bus_clk),       .*);
     308              :    rvclkhdr ahb_addr_cgc  (.en(ahb_addr_clk_en),  .l1clk(ahb_addr_clk),  .*);
     309              :    rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*);
     310              : `endif
     311              : 
     312              : `ifdef RV_ASSERT_ON
     313              :    property ahb_error_protocol;
     314              :       @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
     315              :    endproperty
     316              :    assert_ahb_error_protocol: assert property (ahb_error_protocol) else
     317              :       $display("Bus Error with hReady isn't preceded with Bus Error without hready");
     318              : 
     319              : `endif
     320              : 
     321              : endmodule // ahb_to_axi4