dm_sba.sv 5.93 KB
Newer Older
sakundu committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/* Copyright 2018 ETH Zurich and University of Bologna.
 * Copyright and related rights are licensed under the Solderpad Hardware
 * License, Version 0.51 (the “License”); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
 * or agreed to in writing, software, hardware and materials distributed under
 * this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * File:   dm_sba.sv
 * Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
 * Date:   1.8.2018
 *
 * Description: System Bus Access Module
 *
 */

module dm_sba (
    input  logic          clk_i,       // Clock
    input  logic          rst_ni,
    input  logic          dmactive_i,  // synchronous reset active low
    // AXI port
    output ariane_axi::req_t  axi_req_o,
    input  ariane_axi::resp_t axi_resp_i,

    input  logic [63:0]   sbaddress_i,
    input  logic          sbaddress_write_valid_i,
    // control signals in
    input  logic          sbreadonaddr_i,
    output logic [63:0]   sbaddress_o,
    input  logic          sbautoincrement_i,
    input  logic [2:0]    sbaccess_i,
    // data in
    input  logic          sbreadondata_i,
    input  logic [63:0]   sbdata_i,
    input  logic          sbdata_read_valid_i,
    input  logic          sbdata_write_valid_i,
    // read data out
    output logic [63:0]   sbdata_o,
    output logic          sbdata_valid_o,
    // control signals
    output logic          sbbusy_o,
    output logic          sberror_valid_o, // bus error occurred
    output logic [2:0]    sberror_o // bus error occurred
);

    enum logic [2:0] { Idle, Read, Write, WaitRead, WaitWrite } state_d, state_q;

    logic [63:0]      address;
    logic             req;
    logic             gnt;
    logic             we;
    logic [7:0]       be;

    assign sbbusy_o = (state_q != Idle) ? 1'b1 : 1'b0;

    always_comb begin
        req     = 1'b0;
        address = sbaddress_i;
        we      = 1'b0;
        be      = '0;

        sberror_o       = '0;
        sberror_valid_o = 1'b0;
        sbaddress_o     = sbaddress_i;

        state_d = state_q;

        case (state_q)
            Idle: begin
                // debugger requested a read
                if (sbaddress_write_valid_i && sbreadonaddr_i)  state_d = Read;
                // debugger requested a write
                if (sbdata_write_valid_i) state_d = Write;
                // perform another read
                if (sbdata_read_valid_i && sbreadondata_i) state_d = Read;
            end

            Read: begin
                req = 1'b1;
                if (gnt) state_d = WaitRead;
            end

            Write: begin
                req = 1'b1;
                we  = 1'b1;
                // generate byte enable mask
                case (sbaccess_i)
                    3'b000: be[ sbaddress_i[2:0]] = '1;
                    3'b001: be[{sbaddress_i[2:1], 1'b0} +: 2] = '1;
                    3'b010: be[{sbaddress_i[2:2], 2'b0} +: 4] = '1;
                    3'b011: be = '1;
                    default:;
                endcase
                if (gnt) state_d = WaitWrite;
            end

            WaitRead: begin
                if (sbdata_valid_o) begin
                    state_d = Idle;
                    // auto-increment address
                    if (sbautoincrement_i) sbaddress_o = sbaddress_i + (1 << sbaccess_i);
                end
            end

            WaitWrite: begin
                if (sbdata_valid_o) begin
                    state_d = Idle;
                    // auto-increment address
                    if (sbautoincrement_i) sbaddress_o = sbaddress_i + (1 << sbaccess_i);
                end
            end
        endcase
        // handle error case
        if (sbaccess_i > 3 && state_q != Idle) begin
            req             = 1'b0;
            state_d         = Idle;
            sberror_valid_o = 1'b1;
            sberror_o       = 'd3;
        end
        // further error handling should go here ...
    end

    always_ff @(posedge clk_i or negedge rst_ni) begin
        if (~rst_ni) begin
            state_q <= Idle;
        end else begin
            state_q <= state_d;
        end
    end


    axi_adapter #(
        .DATA_WIDTH            ( 64                        )
    ) i_axi_master (
        .clk_i                 ( clk_i                     ),
        .rst_ni                ( rst_ni                    ),
        .req_i                 ( req                       ),
        .type_i                ( ariane_axi::SINGLE_REQ    ),
        .gnt_o                 ( gnt                       ),
        .gnt_id_o              (                           ),
        .addr_i                ( address                   ),
        .we_i                  ( we                        ),
        .wdata_i               ( sbdata_i                  ),
        .be_i                  ( be                        ),
        .size_i                ( sbaccess_i[1:0]           ),
        .id_i                  ( '0                        ),
        .valid_o               ( sbdata_valid_o            ),
        .rdata_o               ( sbdata_o                  ),
        .id_o                  (                           ),
        .critical_word_o       (                           ), // not needed here
        .critical_word_valid_o (                           ), // not needed here
        .axi_req_o,
        .axi_resp_i
    );


    //pragma translate_off
    `ifndef VERILATOR
        // maybe bump severity to $error if not handled at runtime
        dm_sba_access_size: assert property(@(posedge  clk_i) disable iff (dmactive_i !== 1'b0) (state_d != Idle) |-> (sbaccess_i < 4)) else $warning ("accesses > 8 byte not supported at the moment");
    `endif
    //pragma translate_on

endmodule