blob: c97f9565ae99c9c55d744809d009c835d02f54cf [file] [log] [blame]
/* 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 #(
parameter int unsigned BusWidth = 32
) (
input logic clk_i, // Clock
input logic rst_ni,
input logic dmactive_i, // synchronous reset active low
output logic master_req_o,
output logic [BusWidth-1:0] master_add_o,
output logic master_we_o,
output logic [BusWidth-1:0] master_wdata_o,
output logic [BusWidth/8-1:0] master_be_o,
input logic master_gnt_i,
input logic master_r_valid_i,
input logic [BusWidth-1:0] master_r_rdata_i,
input logic [BusWidth-1:0] sbaddress_i,
input logic sbaddress_write_valid_i,
// control signals in
input logic sbreadonaddr_i,
output logic [BusWidth-1:0] sbaddress_o,
input logic sbautoincrement_i,
input logic [2:0] sbaccess_i,
// data in
input logic sbreadondata_i,
input logic [BusWidth-1:0] sbdata_i,
input logic sbdata_read_valid_i,
input logic sbdata_write_valid_i,
// read data out
output logic [BusWidth-1: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
);
typedef enum logic [2:0] { Idle, Read, Write, WaitRead, WaitWrite } state_e;
state_e state_d, state_q;
logic [BusWidth-1:0] address;
logic req;
logic gnt;
logic we;
logic [BusWidth/8-1:0] be;
logic [$clog2(BusWidth/8)-1:0] be_idx;
assign sbbusy_o = logic'(state_q != Idle);
always_comb begin : p_fsm
req = 1'b0;
address = sbaddress_i;
we = 1'b0;
be = '0;
be_idx = sbaddress_i[$clog2(BusWidth/8)-1:0];
sberror_o = '0;
sberror_valid_o = 1'b0;
sbaddress_o = sbaddress_i;
state_d = state_q;
unique 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
unique case (sbaccess_i)
3'b000: begin
be[be_idx] = '1;
end
3'b001: begin
be[int'({be_idx[$high(be_idx):1], 1'b0}) +: 2] = '1;
end
3'b010: begin
if (BusWidth == 32'd64) be[int'({be_idx[$high(be_idx)], 2'h0}) +: 4] = '1;
else be = '1;
end
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 + (32'h1 << sbaccess_i);
end
end
WaitWrite: begin
if (sbdata_valid_o) begin
state_d = Idle;
// auto-increment address
if (sbautoincrement_i) sbaddress_o = sbaddress_i + (32'h1 << sbaccess_i);
end
end
default: state_d = Idle; // catch parasitic state
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 = 3'd3;
end
// further error handling should go here ...
end
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
state_q <= Idle;
end else begin
state_q <= state_d;
end
end
assign master_req_o = req;
assign master_add_o = address[BusWidth-1:0];
assign master_we_o = we;
assign master_wdata_o = sbdata_i[BusWidth-1:0];
assign master_be_o = be[BusWidth/8-1:0];
assign gnt = master_gnt_i;
assign sbdata_valid_o = master_r_valid_i;
assign sbdata_o = master_r_rdata_i[BusWidth-1:0];
//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 : dm_sba