/* 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