Commit 7aabbac0 by sakundu

Updated Ariane SystemVerilog list

parent 8b29470d
// 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.
//
// Author: Matthias Baer <baermatt@student.ethz.ch>
// Author: Igor Loi <igor.loi@unibo.it>
// Author: Andreas Traber <atraber@student.ethz.ch>
// Author: Lukas Mueller <lukasmue@student.ethz.ch>
// Author: Florian Zaruba <zaruabf@iis.ee.ethz.ch>
//
// Date: 19.03.2017
// Description: Ariane ALU based on RI5CY's ALU
import ariane_pkg::*;
module alu (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input fu_data_t fu_data_i,
output logic [63:0] result_o,
output logic alu_branch_res_o
);
logic [63:0] operand_a_rev;
logic [31:0] operand_a_rev32;
logic [64:0] operand_b_neg;
logic [65:0] adder_result_ext_o;
logic less; // handles both signed and unsigned forms
// bit reverse operand_a for left shifts and bit counting
generate
genvar k;
for(k = 0; k < 64; k++)
assign operand_a_rev[k] = fu_data_i.operand_a[63-k];
for (k = 0; k < 32; k++)
assign operand_a_rev32[k] = fu_data_i.operand_a[31-k];
endgenerate
// ------
// Adder
// ------
logic adder_op_b_negate;
logic adder_z_flag;
logic [64:0] adder_in_a, adder_in_b;
logic [63:0] adder_result;
always_comb begin
adder_op_b_negate = 1'b0;
unique case (fu_data_i.operator)
// ADDER OPS
EQ, NE,
SUB, SUBW: adder_op_b_negate = 1'b1;
default: ;
endcase
end
// prepare operand a
assign adder_in_a = {fu_data_i.operand_a, 1'b1};
// prepare operand b
assign operand_b_neg = {fu_data_i.operand_b, 1'b0} ^ {65{adder_op_b_negate}};
assign adder_in_b = operand_b_neg ;
// actual adder
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
assign adder_result = adder_result_ext_o[64:1];
assign adder_z_flag = ~|adder_result;
// get the right branch comparison result
always_comb begin : branch_resolve
// set comparison by default
alu_branch_res_o = 1'b1;
case (fu_data_i.operator)
EQ: alu_branch_res_o = adder_z_flag;
NE: alu_branch_res_o = ~adder_z_flag;
LTS, LTU: alu_branch_res_o = less;
GES, GEU: alu_branch_res_o = ~less;
default: alu_branch_res_o = 1'b1;
endcase
end
// ---------
// Shifts
// ---------
// TODO: this can probably optimized significantly
logic shift_left; // should we shift left
logic shift_arithmetic;
logic [63:0] shift_amt; // amount of shift, to the right
logic [63:0] shift_op_a; // input of the shifter
logic [31:0] shift_op_a32; // input to the 32 bit shift operation
logic [63:0] shift_result;
logic [31:0] shift_result32;
logic [64:0] shift_right_result;
logic [32:0] shift_right_result32;
logic [63:0] shift_left_result;
logic [31:0] shift_left_result32;
assign shift_amt = fu_data_i.operand_b;
assign shift_left = (fu_data_i.operator == SLL) | (fu_data_i.operator == SLLW);
assign shift_arithmetic = (fu_data_i.operator == SRA) | (fu_data_i.operator == SRAW);
// right shifts, we let the synthesizer optimize this
logic [64:0] shift_op_a_64;
logic [32:0] shift_op_a_32;
// choose the bit reversed or the normal input for shift operand a
assign shift_op_a = shift_left ? operand_a_rev : fu_data_i.operand_a;
assign shift_op_a32 = shift_left ? operand_a_rev32 : fu_data_i.operand_a[31:0];
assign shift_op_a_64 = { shift_arithmetic & shift_op_a[63], shift_op_a};
assign shift_op_a_32 = { shift_arithmetic & shift_op_a[31], shift_op_a32};
assign shift_right_result = $unsigned($signed(shift_op_a_64) >>> shift_amt[5:0]);
assign shift_right_result32 = $unsigned($signed(shift_op_a_32) >>> shift_amt[4:0]);
// bit reverse the shift_right_result for left shifts
genvar j;
generate
for(j = 0; j < 64; j++)
assign shift_left_result[j] = shift_right_result[63-j];
for(j = 0; j < 32; j++)
assign shift_left_result32[j] = shift_right_result32[31-j];
endgenerate
assign shift_result = shift_left ? shift_left_result : shift_right_result[63:0];
assign shift_result32 = shift_left ? shift_left_result32 : shift_right_result32[31:0];
// ------------
// Comparisons
// ------------
always_comb begin
logic sgn;
sgn = 1'b0;
if ((fu_data_i.operator == SLTS) ||
(fu_data_i.operator == LTS) ||
(fu_data_i.operator == GES))
sgn = 1'b1;
less = ($signed({sgn & fu_data_i.operand_a[63], fu_data_i.operand_a}) < $signed({sgn & fu_data_i.operand_b[63], fu_data_i.operand_b}));
end
// -----------
// Result MUX
// -----------
always_comb begin
result_o = '0;
unique case (fu_data_i.operator)
// Standard Operations
ANDL: result_o = fu_data_i.operand_a & fu_data_i.operand_b;
ORL: result_o = fu_data_i.operand_a | fu_data_i.operand_b;
XORL: result_o = fu_data_i.operand_a ^ fu_data_i.operand_b;
// Adder Operations
ADD, SUB: result_o = adder_result;
// Add word: Ignore the upper bits and sign extend to 64 bit
ADDW, SUBW: result_o = {{32{adder_result[31]}}, adder_result[31:0]};
// Shift Operations
SLL,
SRL, SRA: result_o = shift_result;
// Shifts 32 bit
SLLW,
SRLW, SRAW: result_o = {{32{shift_result32[31]}}, shift_result32[31:0]};
// Comparison Operations
SLTS, SLTU: result_o = {63'b0, less};
default: ; // default case to suppress unique warning
endcase
end
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 15.09.2018
// Description: Combinatorial AMO unit
module amo_alu (
// AMO interface
input ariane_pkg::amo_t amo_op_i,
input logic [63:0] amo_operand_a_i,
input logic [63:0] amo_operand_b_i,
output logic [63:0] amo_result_o // result of atomic memory operation
);
logic [64:0] adder_sum;
logic [64:0] adder_operand_a, adder_operand_b;
assign adder_sum = adder_operand_a + adder_operand_b;
always_comb begin
adder_operand_a = $signed(amo_operand_a_i);
adder_operand_b = $signed(amo_operand_b_i);
amo_result_o = amo_operand_b_i;
unique case (amo_op_i)
// the default is to output operand_b
ariane_pkg::AMO_SC:;
ariane_pkg::AMO_SWAP:;
ariane_pkg::AMO_ADD: amo_result_o = adder_sum[63:0];
ariane_pkg::AMO_AND: amo_result_o = amo_operand_a_i & amo_operand_b_i;
ariane_pkg::AMO_OR: amo_result_o = amo_operand_a_i | amo_operand_b_i;
ariane_pkg::AMO_XOR: amo_result_o = amo_operand_a_i ^ amo_operand_b_i;
ariane_pkg::AMO_MAX: begin
adder_operand_b = -$signed(amo_operand_b_i);
amo_result_o = adder_sum[64] ? amo_operand_b_i : amo_operand_a_i;
end
ariane_pkg::AMO_MIN: begin
adder_operand_b = -$signed(amo_operand_b_i);
amo_result_o = adder_sum[64] ? amo_operand_a_i : amo_operand_b_i;
end
ariane_pkg::AMO_MAXU: begin
adder_operand_a = $unsigned(amo_operand_a_i);
adder_operand_b = -$unsigned(amo_operand_b_i);
amo_result_o = adder_sum[64] ? amo_operand_b_i : amo_operand_a_i;
end
ariane_pkg::AMO_MINU: begin
adder_operand_a = $unsigned(amo_operand_a_i);
adder_operand_b = -$unsigned(amo_operand_b_i);
amo_result_o = adder_sum[64] ? amo_operand_a_i : amo_operand_b_i;
end
default: amo_result_o = '0;
endcase
end
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 20.09.2018
// Description: Buffers AMO requests
// This unit buffers an atomic memory operations for the cache subsyste.
// Furthermore it handles interfacing with the commit stage
module amo_buffer (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // pipeline flush
input logic valid_i, // AMO is valid
output logic ready_o, // AMO unit is ready
input ariane_pkg::amo_t amo_op_i, // AMO Operation
input logic [63:0] paddr_i, // physical address of store which needs to be placed in the queue
input logic [63:0] data_i, // data which is placed in the queue
input logic [1:0] data_size_i, // type of request we are making (e.g.: bytes to write)
// D$
output ariane_pkg::amo_req_t amo_req_o, // request to cache subsytem
input ariane_pkg::amo_resp_t amo_resp_i, // response from cache subsystem
// Auxiliary signals
input logic amo_valid_commit_i, // We have a vaild AMO in the commit stage
input logic no_st_pending_i // there is currently no store pending anymore
);
logic flush_amo_buffer;
logic amo_valid;
typedef struct packed {
ariane_pkg::amo_t op;
logic [63:0] paddr;
logic [63:0] data;
logic [1:0] size;
} amo_op_t ;
amo_op_t amo_data_in, amo_data_out;
// validate this request as soon as all stores have drained and the AMO is in the commit stage
assign amo_req_o.req = no_st_pending_i & amo_valid_commit_i & amo_valid;
assign amo_req_o.amo_op = amo_data_out.op;
assign amo_req_o.size = amo_data_out.size;
assign amo_req_o.operand_a = amo_data_out.paddr;
assign amo_req_o.operand_b = amo_data_out.data;
assign amo_data_in.op = amo_op_i;
assign amo_data_in.data = data_i;
assign amo_data_in.paddr = paddr_i;
assign amo_data_in.size = data_size_i;
// only flush if we are currently not committing the AMO
// e.g.: it is not speculative anymore
assign flush_amo_buffer = flush_i & !amo_valid_commit_i;
fifo_v2 #(
.DEPTH ( 1 ),
.ALM_EMPTY_TH ( 0 ),
.ALM_FULL_TH ( 0 ),
.dtype ( amo_op_t )
) i_amo_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( flush_amo_buffer ),
.testmode_i ( 1'b0 ),
.full_o ( amo_valid ),
.empty_o ( ready_o ),
.alm_full_o ( ), // left open
.alm_empty_o ( ), // left open
.data_i ( amo_data_in ),
.push_i ( valid_i ),
.data_o ( amo_data_out ),
.pop_i ( amo_resp_i.ack )
);
endmodule
\ No newline at end of file
// 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.
//
// Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module apb_to_reg (
input logic clk_i,
input logic rst_ni,
input logic penable_i,
input logic pwrite_i,
input logic [31:0] paddr_i,
input logic psel_i,
input logic [31:0] pwdata_i,
output logic [31:0] prdata_o,
output logic pready_o,
output logic pslverr_o,
REG_BUS.out reg_o
);
always_comb begin
reg_o.addr = paddr_i;
reg_o.write = pwrite_i;
reg_o.wdata = pwdata_i;
reg_o.wstrb = '1;
reg_o.valid = psel_i & penable_i;
pready_o = reg_o.ready;
pslverr_o = reg_o.error;
prdata_o = reg_o.rdata;
end
endmodule
This source diff could not be displayed because it is too large. You can view the blob instead.
/* 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: ariane_axi_pkg.sv
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
* Date: 17.8.2018
*
* Description: Contains Ariane's AXI ports, does not contain user ports
*/
package ariane_axi;
// used in axi_adapter.sv
typedef enum logic { SINGLE_REQ, CACHE_LINE_REQ } ad_req_t;
// 4 is recommended by AXI standard, so lets stick to it, do not change
localparam IdWidth = 4;
localparam UserWidth = 1;
localparam AddrWidth = 64;
localparam DataWidth = 64;
localparam StrbWidth = DataWidth / 8;
typedef logic [IdWidth-1:0] id_t;
typedef logic [AddrWidth-1:0] addr_t;
typedef logic [DataWidth-1:0] data_t;
typedef logic [StrbWidth-1:0] strb_t;
typedef logic [UserWidth-1:0] user_t;
// AW Channel
typedef struct packed {
id_t id;
addr_t addr;
axi_pkg::len_t len;
axi_pkg::size_t size;
axi_pkg::burst_t burst;
logic lock;
axi_pkg::cache_t cache;
axi_pkg::prot_t prot;
axi_pkg::qos_t qos;
axi_pkg::region_t region;
axi_pkg::atop_t atop;
} aw_chan_t;
// W Channel
typedef struct packed {
data_t data;
strb_t strb;
logic last;
} w_chan_t;
// B Channel
typedef struct packed {
id_t id;
axi_pkg::resp_t resp;
} b_chan_t;
// AR Channel
typedef struct packed {
id_t id;
addr_t addr;
axi_pkg::len_t len;
axi_pkg::size_t size;
axi_pkg::burst_t burst;
logic lock;
axi_pkg::cache_t cache;
axi_pkg::prot_t prot;
axi_pkg::qos_t qos;
axi_pkg::region_t region;
} ar_chan_t;
// R Channel
typedef struct packed {
id_t id;
data_t data;
axi_pkg::resp_t resp;
logic last;
} r_chan_t;
typedef struct packed {
aw_chan_t aw;
logic aw_valid;
w_chan_t w;
logic w_valid;
logic b_ready;
ar_chan_t ar;
logic ar_valid;
logic r_ready;
} req_t;
typedef struct packed {
logic aw_ready;
logic ar_ready;
logic w_ready;
logic b_valid;
b_chan_t b;
logic r_valid;
r_chan_t r;
} resp_t;
endpackage
// 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.
//
// Engineer: Francesco Conti - f.conti@unibo.it
//
// Additional contributions by:
// Markus Wegmann - markus.wegmann@technokrat.ch
//
// Design Name: RISC-V register file
// Project Name: zero-riscy
// Language: SystemVerilog
//
// Description: Register file with 31 or 15x 32 bit wide registers.
// Register 0 is fixed to 0. This register file is based on
// flip flops.
//
module ariane_regfile #(
parameter int unsigned DATA_WIDTH = 32,
parameter int unsigned NR_READ_PORTS = 2,
parameter int unsigned NR_WRITE_PORTS = 2,
parameter bit ZERO_REG_ZERO = 0
)(
// clock and reset
input logic clk_i,
input logic rst_ni,
// disable clock gates for testing
input logic test_en_i,
// read port
input logic [NR_READ_PORTS-1:0][4:0] raddr_i,
output logic [NR_READ_PORTS-1:0][DATA_WIDTH-1:0] rdata_o,
// write port
input logic [NR_WRITE_PORTS-1:0][4:0] waddr_i,
input logic [NR_WRITE_PORTS-1:0][DATA_WIDTH-1:0] wdata_i,
input logic [NR_WRITE_PORTS-1:0] we_i
);
localparam ADDR_WIDTH = 5;
localparam NUM_WORDS = 2**ADDR_WIDTH;
logic [NUM_WORDS-1:0][DATA_WIDTH-1:0] mem;
logic [NR_WRITE_PORTS-1:0][NUM_WORDS-1:0] we_dec;
always_comb begin : we_decoder
for (int unsigned j = 0; j < NR_WRITE_PORTS; j++) begin
for (int unsigned i = 0; i < NUM_WORDS; i++) begin
if (waddr_i[j] == i)
we_dec[j][i] = we_i[j];
else
we_dec[j][i] = 1'b0;
end
end
end
// loop from 1 to NUM_WORDS-1 as R0 is nil
always_ff @(posedge clk_i, negedge rst_ni) begin : register_write_behavioral
if (~rst_ni) begin
mem <= '{default: '0};
end else begin
for (int unsigned j = 0; j < NR_WRITE_PORTS; j++) begin
for (int unsigned i = 0; i < NUM_WORDS; i++) begin
if (we_dec[j][i]) begin
mem[i] <= wdata_i[j];
end
end
if (ZERO_REG_ZERO) begin
mem[0] <= '0;
end
end
end
end
for (genvar i = 0; i < NR_READ_PORTS; i++) begin
assign rdata_o[i] = mem[raddr_i[i]];
end
endmodule
// Copyright 2014-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.
module axi2apb_wrap #(
parameter int unsigned AXI_ADDR_WIDTH = 32,
parameter int unsigned AXI_DATA_WIDTH = 32,
parameter int unsigned AXI_USER_WIDTH = 6,
parameter int unsigned AXI_ID_WIDTH = 6,
parameter int unsigned APB_ADDR_WIDTH = 32,
parameter int unsigned APB_DATA_WIDTH = 32
)(
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
AXI_BUS.Slave axi_slave,
APB_BUS.Master apb_master
);
// ----------------
// AXI2APB WRAPER
// ----------------
generate if (AXI_DATA_WIDTH == APB_DATA_WIDTH) begin
axi2apb #(
.AXI4_ADDRESS_WIDTH ( AXI_ADDR_WIDTH ),
.AXI4_RDATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI4_WDATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI4_ID_WIDTH ( AXI_ID_WIDTH ),
.AXI4_USER_WIDTH ( AXI_USER_WIDTH ),
.BUFF_DEPTH_SLAVE ( 2 ),
.APB_ADDR_WIDTH ( APB_ADDR_WIDTH )
) axi2apb_i (
.ACLK ( clk_i ),
.ARESETn ( rst_ni ),
.test_en_i ( test_en_i ),
.AWID_i ( axi_slave.aw_id ),
.AWADDR_i ( axi_slave.aw_addr ),
.AWLEN_i ( axi_slave.aw_len ),
.AWSIZE_i ( axi_slave.aw_size ),
.AWBURST_i ( axi_slave.aw_burst ),
.AWLOCK_i ( axi_slave.aw_lock ),
.AWCACHE_i ( axi_slave.aw_cache ),
.AWPROT_i ( axi_slave.aw_prot ),
.AWREGION_i ( axi_slave.aw_region ),
.AWUSER_i ( axi_slave.aw_user ),
.AWQOS_i ( axi_slave.aw_qos ),
.AWVALID_i ( axi_slave.aw_valid ),
.AWREADY_o ( axi_slave.aw_ready ),
.WDATA_i ( axi_slave.w_data ),
.WSTRB_i ( axi_slave.w_strb ),
.WLAST_i ( axi_slave.w_last ),
.WUSER_i ( axi_slave.w_user ),
.WVALID_i ( axi_slave.w_valid ),
.WREADY_o ( axi_slave.w_ready ),
.BID_o ( axi_slave.b_id ),
.BRESP_o ( axi_slave.b_resp ),
.BVALID_o ( axi_slave.b_valid ),
.BUSER_o ( axi_slave.b_user ),
.BREADY_i ( axi_slave.b_ready ),
.ARID_i ( axi_slave.ar_id ),
.ARADDR_i ( axi_slave.ar_addr ),
.ARLEN_i ( axi_slave.ar_len ),
.ARSIZE_i ( axi_slave.ar_size ),
.ARBURST_i ( axi_slave.ar_burst ),
.ARLOCK_i ( axi_slave.ar_lock ),
.ARCACHE_i ( axi_slave.ar_cache ),
.ARPROT_i ( axi_slave.ar_prot ),
.ARREGION_i ( axi_slave.ar_region ),
.ARUSER_i ( axi_slave.ar_user ),
.ARQOS_i ( axi_slave.ar_qos ),
.ARVALID_i ( axi_slave.ar_valid ),
.ARREADY_o ( axi_slave.ar_ready ),
.RID_o ( axi_slave.r_id ),
.RDATA_o ( axi_slave.r_data ),
.RRESP_o ( axi_slave.r_resp ),
.RLAST_o ( axi_slave.r_last ),
.RUSER_o ( axi_slave.r_user ),
.RVALID_o ( axi_slave.r_valid ),
.RREADY_i ( axi_slave.r_ready ),
.PENABLE ( apb_master.penable ),
.PWRITE ( apb_master.pwrite ),
.PADDR ( apb_master.paddr ),
.PSEL ( apb_master.psel ),
.PWDATA ( apb_master.pwdata ),
.PRDATA ( apb_master.prdata ),
.PREADY ( apb_master.pready ),
.PSLVERR ( apb_master.pslverr )
);
end else if (AXI_DATA_WIDTH == 64 && APB_DATA_WIDTH == 32) begin
axi2apb_64_32 #(
.AXI4_ADDRESS_WIDTH ( AXI_ADDR_WIDTH ),
.AXI4_RDATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI4_WDATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI4_ID_WIDTH ( AXI_ID_WIDTH ),
.AXI4_USER_WIDTH ( AXI_USER_WIDTH ),
.BUFF_DEPTH_SLAVE ( 2 ),
.APB_ADDR_WIDTH ( APB_ADDR_WIDTH )
) axi2apb_i (
.ACLK ( clk_i ),
.ARESETn ( rst_ni ),
.test_en_i ( test_en_i ),
.AWID_i ( axi_slave.aw_id ),
.AWADDR_i ( axi_slave.aw_addr ),
.AWLEN_i ( axi_slave.aw_len ),
.AWSIZE_i ( axi_slave.aw_size ),
.AWBURST_i ( axi_slave.aw_burst ),
.AWLOCK_i ( axi_slave.aw_lock ),
.AWCACHE_i ( axi_slave.aw_cache ),
.AWPROT_i ( axi_slave.aw_prot ),
.AWREGION_i ( axi_slave.aw_region ),
.AWUSER_i ( axi_slave.aw_user ),
.AWQOS_i ( axi_slave.aw_qos ),
.AWVALID_i ( axi_slave.aw_valid ),
.AWREADY_o ( axi_slave.aw_ready ),
.WDATA_i ( axi_slave.w_data ),
.WSTRB_i ( axi_slave.w_strb ),
.WLAST_i ( axi_slave.w_last ),
.WUSER_i ( axi_slave.w_user ),
.WVALID_i ( axi_slave.w_valid ),
.WREADY_o ( axi_slave.w_ready ),
.BID_o ( axi_slave.b_id ),
.BRESP_o ( axi_slave.b_resp ),
.BVALID_o ( axi_slave.b_valid ),
.BUSER_o ( axi_slave.b_user ),
.BREADY_i ( axi_slave.b_ready ),
.ARID_i ( axi_slave.ar_id ),
.ARADDR_i ( axi_slave.ar_addr ),
.ARLEN_i ( axi_slave.ar_len ),
.ARSIZE_i ( axi_slave.ar_size ),
.ARBURST_i ( axi_slave.ar_burst ),
.ARLOCK_i ( axi_slave.ar_lock ),
.ARCACHE_i ( axi_slave.ar_cache ),
.ARPROT_i ( axi_slave.ar_prot ),
.ARREGION_i ( axi_slave.ar_region ),
.ARUSER_i ( axi_slave.ar_user ),
.ARQOS_i ( axi_slave.ar_qos ),
.ARVALID_i ( axi_slave.ar_valid ),
.ARREADY_o ( axi_slave.ar_ready ),
.RID_o ( axi_slave.r_id ),
.RDATA_o ( axi_slave.r_data ),
.RRESP_o ( axi_slave.r_resp ),
.RLAST_o ( axi_slave.r_last ),
.RUSER_o ( axi_slave.r_user ),
.RVALID_o ( axi_slave.r_valid ),
.RREADY_i ( axi_slave.r_ready ),
.PENABLE ( apb_master.penable ),
.PWRITE ( apb_master.pwrite ),
.PADDR ( apb_master.paddr ),
.PSEL ( apb_master.psel ),
.PWDATA ( apb_master.pwdata ),
.PRDATA ( apb_master.prdata ),
.PREADY ( apb_master.pready ),
.PSLVERR ( apb_master.pslverr )
);
end
endgenerate
endmodule
// 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.
// Davide Rossi <davide.rossi@unibo.it>
module axi_ar_buffer #(
parameter int ID_WIDTH = -1,
parameter int ADDR_WIDTH = -1,
parameter int USER_WIDTH = -1,
parameter int BUFFER_DEPTH = -1
)(
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic slave_valid_i,
input logic [ADDR_WIDTH-1:0] slave_addr_i,
input logic [2:0] slave_prot_i,
input logic [3:0] slave_region_i,
input logic [7:0] slave_len_i,
input logic [2:0] slave_size_i,
input logic [1:0] slave_burst_i,
input logic slave_lock_i,
input logic [3:0] slave_cache_i,
input logic [3:0] slave_qos_i,
input logic [ID_WIDTH-1:0] slave_id_i,
input logic [USER_WIDTH-1:0] slave_user_i,
output logic slave_ready_o,
output logic master_valid_o,
output logic [ADDR_WIDTH-1:0] master_addr_o,
output logic [2:0] master_prot_o,
output logic [3:0] master_region_o,
output logic [7:0] master_len_o,
output logic [2:0] master_size_o,
output logic [1:0] master_burst_o,
output logic master_lock_o,
output logic [3:0] master_cache_o,
output logic [3:0] master_qos_o,
output logic [ID_WIDTH-1:0] master_id_o,
output logic [USER_WIDTH-1:0] master_user_o,
input logic master_ready_i
);
logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_in;
logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_out;
assign s_data_in = {slave_cache_i, slave_prot_i, slave_lock_i, slave_burst_i, slave_size_i, slave_len_i, slave_qos_i, slave_region_i, slave_addr_i, slave_user_i, slave_id_i} ;
assign {master_cache_o, master_prot_o, master_lock_o, master_burst_o, master_size_o, master_len_o, master_qos_o, master_region_o, master_addr_o, master_user_o, master_id_o} = s_data_out;
axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH)) i_axi_single_slice (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.testmode_i ( test_en_i ),
.valid_i ( slave_valid_i ),
.ready_o ( slave_ready_o ),
.data_i ( s_data_in ),
.ready_i ( master_ready_i ),
.valid_o ( master_valid_o ),
.data_o ( s_data_out )
);
endmodule
// 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.
// Davide Rossi <davide.rossi@unibo.it>
module axi_aw_buffer #(
parameter int ID_WIDTH = -1,
parameter int ADDR_WIDTH = -1,
parameter int USER_WIDTH = -1,
parameter int BUFFER_DEPTH = -1
)(
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic slave_valid_i,
input logic [ADDR_WIDTH-1:0] slave_addr_i,
input logic [2:0] slave_prot_i,
input logic [3:0] slave_region_i,
input logic [7:0] slave_len_i,
input logic [2:0] slave_size_i,
input logic [1:0] slave_burst_i,
input logic slave_lock_i,
input logic [3:0] slave_cache_i,
input logic [3:0] slave_qos_i,
input logic [ID_WIDTH-1:0] slave_id_i,
input logic [USER_WIDTH-1:0] slave_user_i,
output logic slave_ready_o,
output logic master_valid_o,
output logic [ADDR_WIDTH-1:0] master_addr_o,
output logic [2:0] master_prot_o,
output logic [3:0] master_region_o,
output logic [7:0] master_len_o,
output logic [2:0] master_size_o,
output logic [1:0] master_burst_o,
output logic master_lock_o,
output logic [3:0] master_cache_o,
output logic [3:0] master_qos_o,
output logic [ID_WIDTH-1:0] master_id_o,
output logic [USER_WIDTH-1:0] master_user_o,
input logic master_ready_i
);
logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_in;
logic [29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH-1:0] s_data_out;
assign s_data_in = {slave_cache_i, slave_prot_i, slave_lock_i, slave_burst_i, slave_size_i, slave_len_i, slave_qos_i, slave_region_i, slave_addr_i, slave_user_i, slave_id_i};
assign {master_cache_o, master_prot_o, master_lock_o, master_burst_o, master_size_o, master_len_o, master_qos_o, master_region_o, master_addr_o, master_user_o, master_id_o} = s_data_out;
axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(29+ADDR_WIDTH+USER_WIDTH+ID_WIDTH)) i_axi_single_slice (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.testmode_i ( test_en_i ),
.valid_i ( slave_valid_i ),
.ready_o ( slave_ready_o ),
.data_i ( s_data_in ),
.ready_i ( master_ready_i ),
.valid_o ( master_valid_o ),
.data_o ( s_data_out )
);
endmodule
// 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.
// Davide Rossi <davide.rossi@unibo.it>
module axi_b_buffer #(
parameter int ID_WIDTH = -1,
parameter int USER_WIDTH = -1,
parameter int BUFFER_DEPTH = -1
)(
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic slave_valid_i,
input logic [1:0] slave_resp_i,
input logic [ID_WIDTH-1:0] slave_id_i,
input logic [USER_WIDTH-1:0] slave_user_i,
output logic slave_ready_o,
output logic master_valid_o,
output logic [1:0] master_resp_o,
output logic [ID_WIDTH-1:0] master_id_o,
output logic [USER_WIDTH-1:0] master_user_o,
input logic master_ready_i
);
logic [2+USER_WIDTH+ID_WIDTH-1:0] s_data_in;
logic [2+USER_WIDTH+ID_WIDTH-1:0] s_data_out;
assign s_data_in = {slave_id_i, slave_user_i, slave_resp_i};
assign {master_id_o, master_user_o, master_resp_o} = s_data_out;
axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(2+USER_WIDTH+ID_WIDTH)) i_axi_single_slice (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.testmode_i ( test_en_i ),
.valid_i ( slave_valid_i ),
.ready_o ( slave_ready_o ),
.data_i ( s_data_in ),
.ready_i ( master_ready_i ),
.valid_o ( master_valid_o ),
.data_o ( s_data_out )
);
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 17/07/2017
// Description: AXI Lite compatible interface
//
module axi_lite_interface #(
parameter int unsigned AXI_ADDR_WIDTH = 64,
parameter int unsigned AXI_DATA_WIDTH = 64,
parameter int unsigned AXI_ID_WIDTH = 10
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input ariane_axi::req_t axi_req_i,
output ariane_axi::resp_t axi_resp_o,
output logic [AXI_ADDR_WIDTH-1:0] address_o,
output logic en_o, // transaction is valid
output logic we_o, // write
input logic [AXI_DATA_WIDTH-1:0] data_i, // data
output logic [AXI_DATA_WIDTH-1:0] data_o
);
// The RLAST signal is not required, and is considered asserted for every transfer on the read data channel.
enum logic [1:0] { IDLE, READ, WRITE, WRITE_B} CS, NS;
// save the trans id, we will need it for reflection otherwise we are not plug compatible to the AXI standard
logic [AXI_ID_WIDTH-1:0] trans_id_n, trans_id_q;
// address register
logic [AXI_ADDR_WIDTH-1:0] address_n, address_q;
// pass through read data on the read data channel
assign axi_resp_o.r.data = data_i;
// send back the transaction id we've latched
assign axi_resp_o.r.id = trans_id_q;
assign axi_resp_o.b.id = trans_id_q;
// set r_last to one as defined by the AXI4 - Lite standard
assign axi_resp_o.r.last = 1'b1;
// we do not support any errors so set response flag to all zeros
assign axi_resp_o.b.resp = 2'b0;
assign axi_resp_o.r.resp = 2'b0;
// output data which we want to write to the slave
assign data_o = axi_req_i.w.data;
// ------------------------
// AXI4-Lite State Machine
// ------------------------
always_comb begin
// default signal assignment
NS = CS;
address_n = address_q;
trans_id_n = trans_id_q;
// we'll answer a write request only if we got address and data
axi_resp_o.aw_ready = 1'b0;
axi_resp_o.w_ready = 1'b0;
axi_resp_o.b_valid = 1'b0;
axi_resp_o.ar_ready = 1'b1;
axi_resp_o.r_valid = 1'b0;
address_o = '0;
we_o = 1'b0;
en_o = 1'b0;
case (CS)
// we are ready to accept a new request
IDLE: begin
// we've git a valid write request, we also know that we have asserted the aw_ready
if (axi_req_i.aw_valid) begin
axi_resp_o.aw_ready = 1'b1;
// this costs performance but the interconnect does not obey the AXI standard
NS = WRITE;
// save address
address_n = axi_req_i.aw.addr;
// save the transaction id for reflection
trans_id_n = axi_req_i.aw.id;
// we've got a valid read request, we also know that we have asserted the ar_ready
end else if (axi_req_i.ar_valid) begin
NS = READ;
address_n = axi_req_i.ar.addr;
// also request the word from the memory-like interface
address_o = axi_req_i.ar.addr;
// save the transaction id for reflection
trans_id_n = axi_req_i.ar.id;
end
end
// We've got a read request at least one cycle earlier
// so data_i will already contain the data we'd like tor read
READ: begin
// enable the ram-like
en_o = 1'b1;
// we are not ready for another request here
axi_resp_o.ar_ready = 1'b0;
// further assert the correct address
address_o = address_q;
// the read is valid
axi_resp_o.r_valid = 1'b1;
// check if we got a valid r_ready and go back to IDLE
if (axi_req_i.r_ready)
NS = IDLE;
end
// We've got a write request at least one cycle earlier
// wait here for the data
WRITE: begin
if (axi_req_i.w_valid) begin
// we are not ready for another request here
axi_resp_o.ar_ready = 1'b0;
axi_resp_o.w_ready = 1'b1;
// use the latched address
address_o = address_q;
en_o = 1'b1;
we_o = 1'b1;
// close this request
NS = WRITE_B;
end
end
WRITE_B: begin
axi_resp_o.b_valid = 1'b1;
// we've already performed the write here so wait for the ready signal
if (axi_req_i.b_ready)
NS = IDLE;
end
default:;
endcase
end
// ------------------------
// Registers
// ------------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
CS <= IDLE;
address_q <= '0;
trans_id_q <= '0;
end else begin
CS <= NS;
address_q <= address_n;
trans_id_q <= trans_id_n;
end
end
// ------------------------
// Assertions
// ------------------------
// Listen for illegal transactions
//pragma translate_off
`ifndef VERILATOR
// check that burst length is just one
assert property (@(posedge clk_i) axi_req_i.ar_valid |-> ((axi_req_i.ar.len == 8'b0)))
else begin $error("AXI Lite does not support bursts larger than 1 or byte length unequal to the native bus size"); $stop(); end
// do the same for the write channel
assert property (@(posedge clk_i) axi_req_i.aw_valid |-> ((axi_req_i.aw.len == 8'b0)))
else begin $error("AXI Lite does not support bursts larger than 1 or byte length unequal to the native bus size"); $stop(); end
`endif
//pragma translate_on
endmodule
// 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.
//
// Description: Connects SV AXI interface to structs used by Ariane
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module axi_master_connect (
input ariane_axi::req_t axi_req_i,
output ariane_axi::resp_t axi_resp_o,
AXI_BUS.out master
);
assign master.aw_id = axi_req_i.aw.id;
assign master.aw_addr = axi_req_i.aw.addr;
assign master.aw_len = axi_req_i.aw.len;
assign master.aw_size = axi_req_i.aw.size;
assign master.aw_burst = axi_req_i.aw.burst;
assign master.aw_lock = axi_req_i.aw.lock;
assign master.aw_cache = axi_req_i.aw.cache;
assign master.aw_prot = axi_req_i.aw.prot;
assign master.aw_qos = axi_req_i.aw.qos;
assign master.aw_region = axi_req_i.aw.region;
assign master.aw_user = '0;
assign master.aw_valid = axi_req_i.aw_valid;
assign axi_resp_o.aw_ready = master.aw_ready;
assign master.w_data = axi_req_i.w.data;
assign master.w_strb = axi_req_i.w.strb;
assign master.w_last = axi_req_i.w.last;
assign master.w_user = '0;
assign master.w_valid = axi_req_i.w_valid;
assign axi_resp_o.w_ready = master.w_ready;
assign axi_resp_o.b.id = master.b_id;
assign axi_resp_o.b.resp = master.b_resp;
assign axi_resp_o.b_valid = master.b_valid;
assign master.b_ready = axi_req_i.b_ready;
assign master.ar_id = axi_req_i.ar.id;
assign master.ar_addr = axi_req_i.ar.addr;
assign master.ar_len = axi_req_i.ar.len;
assign master.ar_size = axi_req_i.ar.size;
assign master.ar_burst = axi_req_i.ar.burst;
assign master.ar_lock = axi_req_i.ar.lock;
assign master.ar_cache = axi_req_i.ar.cache;
assign master.ar_prot = axi_req_i.ar.prot;
assign master.ar_qos = axi_req_i.ar.qos;
assign master.ar_region = axi_req_i.ar.region;
assign master.ar_user = '0;
assign master.ar_valid = axi_req_i.ar_valid;
assign axi_resp_o.ar_ready = master.ar_ready;
assign axi_resp_o.r.id = master.r_id;
assign axi_resp_o.r.data = master.r_data;
assign axi_resp_o.r.resp = master.r_resp;
assign axi_resp_o.r.last = master.r_last;
assign axi_resp_o.r_valid = master.r_valid;
assign master.r_ready = axi_req_i.r_ready;
endmodule
// 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.
//
// Description: Connects SV AXI interface to structs used by Ariane
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module axi_master_connect_rev (
output ariane_axi::req_t axi_req_o,
input ariane_axi::resp_t axi_resp_i,
AXI_BUS.in master
);
assign axi_req_o.aw.atop = '0; // not supported at the moment
assign axi_req_o.aw.id = master.aw_id;
assign axi_req_o.aw.addr = master.aw_addr;
assign axi_req_o.aw.len = master.aw_len;
assign axi_req_o.aw.size = master.aw_size;
assign axi_req_o.aw.burst = master.aw_burst;
assign axi_req_o.aw.lock = master.aw_lock;
assign axi_req_o.aw.cache = master.aw_cache;
assign axi_req_o.aw.prot = master.aw_prot;
assign axi_req_o.aw.qos = master.aw_qos;
assign axi_req_o.aw.region = master.aw_region;
// assign = master.aw_user;
assign axi_req_o.aw_valid = master.aw_valid;
assign master.aw_ready = axi_resp_i.aw_ready;
assign axi_req_o.w.data = master.w_data;
assign axi_req_o.w.strb = master.w_strb;
assign axi_req_o.w.last = master.w_last;
// assign = master.w_user;
assign axi_req_o.w_valid = master.w_valid;
assign master.w_ready = axi_resp_i.w_ready;
assign master.b_id = axi_resp_i.b.id;
assign master.b_resp = axi_resp_i.b.resp;
assign master.b_valid = axi_resp_i.b_valid;
assign axi_req_o.b_ready = master.b_ready;
assign axi_req_o.ar.id = master.ar_id;
assign axi_req_o.ar.addr = master.ar_addr;
assign axi_req_o.ar.len = master.ar_len;
assign axi_req_o.ar.size = master.ar_size;
assign axi_req_o.ar.burst = master.ar_burst;
assign axi_req_o.ar.lock = master.ar_lock;
assign axi_req_o.ar.cache = master.ar_cache;
assign axi_req_o.ar.prot = master.ar_prot;
assign axi_req_o.ar.qos = master.ar_qos;
assign axi_req_o.ar.region = master.ar_region;
// assign = master.ar_user;
assign axi_req_o.ar_valid = master.ar_valid;
assign master.ar_ready = axi_resp_i.ar_ready;
assign master.r_id = axi_resp_i.r.id;
assign master.r_data = axi_resp_i.r.data;
assign master.r_resp = axi_resp_i.r.resp;
assign master.r_last = axi_resp_i.r.last;
assign master.r_valid = axi_resp_i.r_valid;
assign axi_req_o.r_ready = master.r_ready;
endmodule
// Copyright (c) 2014-2018 ETH Zurich, 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.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
package axi_pkg;
typedef logic [1:0] burst_t;
typedef logic [1:0] resp_t;
typedef logic [3:0] cache_t;
typedef logic [2:0] prot_t;
typedef logic [3:0] qos_t;
typedef logic [3:0] region_t;
typedef logic [7:0] len_t;
typedef logic [2:0] size_t;
typedef logic [5:0] atop_t; // atomic operations
typedef logic [3:0] nsaid_t; // non-secure address identifier
localparam BURST_FIXED = 2'b00;
localparam BURST_INCR = 2'b01;
localparam BURST_WRAP = 2'b10;
localparam RESP_OKAY = 2'b00;
localparam RESP_EXOKAY = 2'b01;
localparam RESP_SLVERR = 2'b10;
localparam RESP_DECERR = 2'b11;
localparam CACHE_BUFFERABLE = 4'b0001;
localparam CACHE_MODIFIABLE = 4'b0010;
localparam CACHE_RD_ALLOC = 4'b0100;
localparam CACHE_WR_ALLOC = 4'b1000;
// 4 is recommended by AXI standard, so lets stick to it, do not change
localparam IdWidth = 4;
localparam UserWidth = 1;
localparam AddrWidth = 64;
localparam DataWidth = 64;
localparam StrbWidth = DataWidth / 8;
typedef logic [IdWidth-1:0] id_t;
typedef logic [AddrWidth-1:0] addr_t;
typedef logic [DataWidth-1:0] data_t;
typedef logic [StrbWidth-1:0] strb_t;
typedef logic [UserWidth-1:0] user_t;
// AW Channel
typedef struct packed {
id_t id;
addr_t addr;
len_t len;
size_t size;
burst_t burst;
logic lock;
cache_t cache;
prot_t prot;
qos_t qos;
region_t region;
atop_t atop;
} aw_chan_t;
// W Channel
typedef struct packed {
data_t data;
strb_t strb;
logic last;
} w_chan_t;
// B Channel
typedef struct packed {
id_t id;
resp_t resp;
} b_chan_t;
// AR Channel
typedef struct packed {
id_t id;
addr_t addr;
len_t len;
size_t size;
burst_t burst;
logic lock;
cache_t cache;
prot_t prot;
qos_t qos;
region_t region;
} ar_chan_t;
// R Channel
typedef struct packed {
id_t id;
data_t data;
resp_t resp;
logic last;
} r_chan_t;
endpackage
// 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.
// Davide Rossi <davide.rossi@unibo.it>
module axi_r_buffer #(
parameter ID_WIDTH = 4,
parameter DATA_WIDTH = 64,
parameter USER_WIDTH = 6,
parameter BUFFER_DEPTH = 8,
parameter STRB_WIDTH = DATA_WIDTH/8 // DO NOT OVERRIDE
)(
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic slave_valid_i,
input logic [DATA_WIDTH-1:0] slave_data_i,
input logic [1:0] slave_resp_i,
input logic [USER_WIDTH-1:0] slave_user_i,
input logic [ID_WIDTH-1:0] slave_id_i,
input logic slave_last_i,
output logic slave_ready_o,
output logic master_valid_o,
output logic [DATA_WIDTH-1:0] master_data_o,
output logic [1:0] master_resp_o,
output logic [USER_WIDTH-1:0] master_user_o,
output logic [ID_WIDTH-1:0] master_id_o,
output logic master_last_o,
input logic master_ready_i
);
logic [2+DATA_WIDTH+USER_WIDTH+ID_WIDTH:0] s_data_in;
logic [2+DATA_WIDTH+USER_WIDTH+ID_WIDTH:0] s_data_out;
assign s_data_in = {slave_id_i, slave_user_i, slave_data_i, slave_resp_i, slave_last_i};
assign {master_id_o, master_user_o, master_data_o, master_resp_o, master_last_o} = s_data_out;
axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(3+DATA_WIDTH+USER_WIDTH+ID_WIDTH)) i_axi_single_slice (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.testmode_i ( test_en_i ),
.valid_i ( slave_valid_i ),
.ready_o ( slave_ready_o ),
.data_i ( s_data_in ),
.ready_i ( master_ready_i ),
.valid_o ( master_valid_o ),
.data_o ( s_data_out )
);
endmodule
// 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.
/// Wrapper for a generic fifo
module axi_single_slice #(
parameter int BUFFER_DEPTH = -1,
parameter int DATA_WIDTH = -1
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic testmode_i,
input logic valid_i,
output logic ready_o,
input logic [DATA_WIDTH-1:0] data_i,
input logic ready_i,
output logic valid_o,
output logic [DATA_WIDTH-1:0] data_o
);
logic full, empty;
assign ready_o = ~full;
assign valid_o = ~empty;
fifo #(
.FALL_THROUGH ( 1'b0 ),
.DATA_WIDTH ( DATA_WIDTH ),
.DEPTH ( BUFFER_DEPTH )
) i_fifo (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.threshold_o (), // NC
.testmode_i ( testmode_i ),
.full_o ( full ),
.empty_o ( empty ),
.data_i ( data_i ),
.push_i ( valid_i & ready_o ),
.data_o ( data_o ),
.pop_i ( ready_i & valid_o )
);
endmodule
// 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.
//
// Description: Connects SV AXI interface to structs used by Ariane
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module axi_slave_connect (
output ariane_axi::req_t axi_req_o,
input ariane_axi::resp_t axi_resp_i,
AXI_BUS.in slave
);
assign axi_req_o.aw.atop = '0; // not supported at the moment
assign axi_req_o.aw.id = slave.aw_id;
assign axi_req_o.aw.addr = slave.aw_addr;
assign axi_req_o.aw.len = slave.aw_len;
assign axi_req_o.aw.size = slave.aw_size;
assign axi_req_o.aw.burst = slave.aw_burst;
assign axi_req_o.aw.lock = slave.aw_lock;
assign axi_req_o.aw.cache = slave.aw_cache;
assign axi_req_o.aw.prot = slave.aw_prot;
assign axi_req_o.aw.qos = slave.aw_qos;
assign axi_req_o.aw.region = slave.aw_region;
// assign = slave.aw_user;
assign axi_req_o.aw_valid = slave.aw_valid;
assign slave.aw_ready = axi_resp_i.aw_ready;
assign axi_req_o.w.data = slave.w_data;
assign axi_req_o.w.strb = slave.w_strb;
assign axi_req_o.w.last = slave.w_last;
// assign = slave.w_user;
assign axi_req_o.w_valid = slave.w_valid;
assign slave.w_ready = axi_resp_i.w_ready;
assign slave.b_id = axi_resp_i.b.id;
assign slave.b_resp = axi_resp_i.b.resp;
assign slave.b_valid = axi_resp_i.b_valid;
assign slave.b_user = 1'b0;
assign axi_req_o.b_ready = slave.b_ready;
assign axi_req_o.ar.id = slave.ar_id;
assign axi_req_o.ar.addr = slave.ar_addr;
assign axi_req_o.ar.len = slave.ar_len;
assign axi_req_o.ar.size = slave.ar_size;
assign axi_req_o.ar.burst = slave.ar_burst;
assign axi_req_o.ar.lock = slave.ar_lock;
assign axi_req_o.ar.cache = slave.ar_cache;
assign axi_req_o.ar.prot = slave.ar_prot;
assign axi_req_o.ar.qos = slave.ar_qos;
assign axi_req_o.ar.region = slave.ar_region;
// assign = slave.ar_user;
assign axi_req_o.ar_valid = slave.ar_valid;
assign slave.ar_ready = axi_resp_i.ar_ready;
assign slave.r_id = axi_resp_i.r.id;
assign slave.r_data = axi_resp_i.r.data;
assign slave.r_resp = axi_resp_i.r.resp;
assign slave.r_last = axi_resp_i.r.last;
assign slave.r_valid = axi_resp_i.r_valid;
assign slave.r_user = 1'b0;
assign axi_req_o.r_ready = slave.r_ready;
endmodule
// 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.
//
// Description: Connects SV AXI interface to structs used by Ariane
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module axi_slave_connect_rev (
input ariane_axi::req_t axi_req_i,
output ariane_axi::resp_t axi_resp_o,
AXI_BUS.out slave
);
assign slave.aw_id = axi_req_i.aw.id;
assign slave.aw_addr = axi_req_i.aw.addr;
assign slave.aw_len = axi_req_i.aw.len;
assign slave.aw_size = axi_req_i.aw.size;
assign slave.aw_burst = axi_req_i.aw.burst;
assign slave.aw_lock = axi_req_i.aw.lock;
assign slave.aw_cache = axi_req_i.aw.cache;
assign slave.aw_prot = axi_req_i.aw.prot;
assign slave.aw_qos = axi_req_i.aw.qos;
assign slave.aw_region = axi_req_i.aw.region;
assign slave.aw_user = '0;
assign slave.aw_valid = axi_req_i.aw_valid;
assign axi_resp_o.aw_ready = slave.aw_ready;
assign slave.w_data = axi_req_i.w.data;
assign slave.w_strb = axi_req_i.w.strb;
assign slave.w_last = axi_req_i.w.last;
assign slave.w_user = '0;
assign slave.w_valid = axi_req_i.w_valid;
assign axi_resp_o.w_ready = slave.w_ready;
assign axi_resp_o.b.id = slave.b_id;
assign axi_resp_o.b.resp = slave.b_resp;
assign axi_resp_o.b_valid = slave.b_valid;
assign slave.b_ready = axi_req_i.b_ready;
assign slave.ar_id = axi_req_i.ar.id;
assign slave.ar_addr = axi_req_i.ar.addr;
assign slave.ar_len = axi_req_i.ar.len;
assign slave.ar_size = axi_req_i.ar.size;
assign slave.ar_burst = axi_req_i.ar.burst;
assign slave.ar_lock = axi_req_i.ar.lock;
assign slave.ar_cache = axi_req_i.ar.cache;
assign slave.ar_prot = axi_req_i.ar.prot;
assign slave.ar_qos = axi_req_i.ar.qos;
assign slave.ar_region = axi_req_i.ar.region;
assign slave.ar_user = '0;
assign slave.ar_valid = axi_req_i.ar_valid;
assign axi_resp_o.ar_ready = slave.ar_ready;
assign axi_resp_o.r.id = slave.r_id;
assign axi_resp_o.r.data = slave.r_data;
assign axi_resp_o.r.resp = slave.r_resp;
assign axi_resp_o.r.last = slave.r_last;
assign axi_resp_o.r_valid = slave.r_valid;
assign slave.r_ready = axi_req_i.r_ready;
endmodule
module axi_slice_wrap #(
parameter AXI_ADDR_WIDTH = 32,
parameter AXI_DATA_WIDTH = 64,
parameter AXI_USER_WIDTH = 6,
parameter AXI_ID_WIDTH = 3,
parameter SLICE_DEPTH = 2,
parameter AXI_STRB_WIDTH = AXI_DATA_WIDTH/8
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic test_en_i,
AXI_BUS.Slave axi_slave,
AXI_BUS.Master axi_master
);
axi_slice #(
.AXI_ADDR_WIDTH ( AXI_ADDR_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
.SLICE_DEPTH ( SLICE_DEPTH ),
.AXI_STRB_WIDTH ( AXI_STRB_WIDTH )
) i_axi_slice (
.axi_slave_aw_valid_i ( axi_slave.aw_valid ),
.axi_slave_aw_addr_i ( axi_slave.aw_addr ),
.axi_slave_aw_prot_i ( axi_slave.aw_prot ),
.axi_slave_aw_region_i ( axi_slave.aw_region ),
.axi_slave_aw_len_i ( axi_slave.aw_len ),
.axi_slave_aw_size_i ( axi_slave.aw_size ),
.axi_slave_aw_burst_i ( axi_slave.aw_burst ),
.axi_slave_aw_lock_i ( axi_slave.aw_lock ),
.axi_slave_aw_cache_i ( axi_slave.aw_cache ),
.axi_slave_aw_qos_i ( axi_slave.aw_qos ),
.axi_slave_aw_id_i ( axi_slave.aw_id ),
.axi_slave_aw_user_i ( axi_slave.aw_user ),
.axi_slave_aw_ready_o ( axi_slave.aw_ready ),
.axi_slave_ar_valid_i ( axi_slave.ar_valid ),
.axi_slave_ar_addr_i ( axi_slave.ar_addr ),
.axi_slave_ar_prot_i ( axi_slave.ar_prot ),
.axi_slave_ar_region_i ( axi_slave.ar_region ),
.axi_slave_ar_len_i ( axi_slave.ar_len ),
.axi_slave_ar_size_i ( axi_slave.ar_size ),
.axi_slave_ar_burst_i ( axi_slave.ar_burst ),
.axi_slave_ar_lock_i ( axi_slave.ar_lock ),
.axi_slave_ar_cache_i ( axi_slave.ar_cache ),
.axi_slave_ar_qos_i ( axi_slave.ar_qos ),
.axi_slave_ar_id_i ( axi_slave.ar_id ),
.axi_slave_ar_user_i ( axi_slave.ar_user ),
.axi_slave_ar_ready_o ( axi_slave.ar_ready ),
.axi_slave_w_valid_i ( axi_slave.w_valid ),
.axi_slave_w_data_i ( axi_slave.w_data ),
.axi_slave_w_strb_i ( axi_slave.w_strb ),
.axi_slave_w_user_i ( axi_slave.w_user ),
.axi_slave_w_last_i ( axi_slave.w_last ),
.axi_slave_w_ready_o ( axi_slave.w_ready ),
.axi_slave_r_valid_o ( axi_slave.r_valid ),
.axi_slave_r_data_o ( axi_slave.r_data ),
.axi_slave_r_resp_o ( axi_slave.r_resp ),
.axi_slave_r_last_o ( axi_slave.r_last ),
.axi_slave_r_id_o ( axi_slave.r_id ),
.axi_slave_r_user_o ( axi_slave.r_user ),
.axi_slave_r_ready_i ( axi_slave.r_ready ),
.axi_slave_b_valid_o ( axi_slave.b_valid ),
.axi_slave_b_resp_o ( axi_slave.b_resp ),
.axi_slave_b_id_o ( axi_slave.b_id ),
.axi_slave_b_user_o ( axi_slave.b_user ),
.axi_slave_b_ready_i ( axi_slave.b_ready ),
.axi_master_aw_valid_o ( axi_master.aw_valid ),
.axi_master_aw_addr_o ( axi_master.aw_addr ),
.axi_master_aw_prot_o ( axi_master.aw_prot ),
.axi_master_aw_region_o ( axi_master.aw_region ),
.axi_master_aw_len_o ( axi_master.aw_len ),
.axi_master_aw_size_o ( axi_master.aw_size ),
.axi_master_aw_burst_o ( axi_master.aw_burst ),
.axi_master_aw_lock_o ( axi_master.aw_lock ),
.axi_master_aw_cache_o ( axi_master.aw_cache ),
.axi_master_aw_qos_o ( axi_master.aw_qos ),
.axi_master_aw_id_o ( axi_master.aw_id ),
.axi_master_aw_user_o ( axi_master.aw_user ),
.axi_master_aw_ready_i ( axi_master.aw_ready ),
.axi_master_ar_valid_o ( axi_master.ar_valid ),
.axi_master_ar_addr_o ( axi_master.ar_addr ),
.axi_master_ar_prot_o ( axi_master.ar_prot ),
.axi_master_ar_region_o ( axi_master.ar_region ),
.axi_master_ar_len_o ( axi_master.ar_len ),
.axi_master_ar_size_o ( axi_master.ar_size ),
.axi_master_ar_burst_o ( axi_master.ar_burst ),
.axi_master_ar_lock_o ( axi_master.ar_lock ),
.axi_master_ar_cache_o ( axi_master.ar_cache ),
.axi_master_ar_qos_o ( axi_master.ar_qos ),
.axi_master_ar_id_o ( axi_master.ar_id ),
.axi_master_ar_user_o ( axi_master.ar_user ),
.axi_master_ar_ready_i ( axi_master.ar_ready ),
.axi_master_w_valid_o ( axi_master.w_valid ),
.axi_master_w_data_o ( axi_master.w_data ),
.axi_master_w_strb_o ( axi_master.w_strb ),
.axi_master_w_user_o ( axi_master.w_user ),
.axi_master_w_last_o ( axi_master.w_last ),
.axi_master_w_ready_i ( axi_master.w_ready ),
.axi_master_r_valid_i ( axi_master.r_valid ),
.axi_master_r_data_i ( axi_master.r_data ),
.axi_master_r_resp_i ( axi_master.r_resp ),
.axi_master_r_last_i ( axi_master.r_last ),
.axi_master_r_id_i ( axi_master.r_id ),
.axi_master_r_user_i ( axi_master.r_user ),
.axi_master_r_ready_o ( axi_master.r_ready ),
.axi_master_b_valid_i ( axi_master.b_valid ),
.axi_master_b_resp_i ( axi_master.b_resp ),
.axi_master_b_id_i ( axi_master.b_id ),
.axi_master_b_user_i ( axi_master.b_user ),
.axi_master_b_ready_o ( axi_master.b_ready ),
.*
);
endmodule
// 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.
// Davide Rossi <davide.rossi@unibo.it>
module axi_w_buffer #(
parameter int DATA_WIDTH = -1,
parameter int USER_WIDTH = -1,
parameter int BUFFER_DEPTH = -1,
parameter int STRB_WIDTH = DATA_WIDTH/8 // DO NOT OVERRIDE
)(
input logic clk_i,
input logic rst_ni,
input logic test_en_i,
input logic slave_valid_i,
input logic [DATA_WIDTH-1:0] slave_data_i,
input logic [STRB_WIDTH-1:0] slave_strb_i,
input logic [USER_WIDTH-1:0] slave_user_i,
input logic slave_last_i,
output logic slave_ready_o,
output logic master_valid_o,
output logic [DATA_WIDTH-1:0] master_data_o,
output logic [STRB_WIDTH-1:0] master_strb_o,
output logic [USER_WIDTH-1:0] master_user_o,
output logic master_last_o,
input logic master_ready_i
);
logic [DATA_WIDTH+STRB_WIDTH+USER_WIDTH:0] s_data_in;
logic [DATA_WIDTH+STRB_WIDTH+USER_WIDTH:0] s_data_out;
assign s_data_in = { slave_user_i, slave_strb_i, slave_data_i, slave_last_i };
assign { master_user_o, master_strb_o, master_data_o, master_last_o } = s_data_out;
axi_single_slice #(.BUFFER_DEPTH(BUFFER_DEPTH), .DATA_WIDTH(1+DATA_WIDTH+STRB_WIDTH+USER_WIDTH)) i_axi_single_slice (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.testmode_i ( test_en_i ),
.valid_i ( slave_valid_i ),
.ready_o ( slave_ready_o ),
.data_i ( s_data_in ),
.ready_i ( master_ready_i ),
.valid_o ( master_valid_o ),
.data_o ( s_data_out )
);
endmodule
//Copyright (C) 2018 to present,
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 2.0 (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-2.0. 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.//
// Author: Florian Zaruba, ETH Zurich
// Date: 08.02.2018
// Migrated: Luis Vitorio Cargnini, IEEE
// Date: 09.06.2018
// branch history table - 2 bit saturation counter
module bht #(
parameter int unsigned NR_ENTRIES = 1024
)(
input logic clk_i,
input logic rst_ni,
input logic flush_i,
input logic debug_mode_i,
input logic [63:0] vpc_i,
input ariane_pkg::bht_update_t bht_update_i,
output ariane_pkg::bht_prediction_t bht_prediction_o
);
localparam OFFSET = 2; // we are using compressed instructions so do not use the lower 2 bits for prediction
localparam ANTIALIAS_BITS = 8;
// number of bits we should use for prediction
localparam PREDICTION_BITS = $clog2(NR_ENTRIES) + OFFSET;
struct packed {
logic valid;
logic [1:0] saturation_counter;
} bht_d[NR_ENTRIES-1:0], bht_q[NR_ENTRIES-1:0];
logic [$clog2(NR_ENTRIES)-1:0] index, update_pc;
logic [1:0] saturation_counter;
assign index = vpc_i[PREDICTION_BITS - 1:OFFSET];
assign update_pc = bht_update_i.pc[PREDICTION_BITS - 1:OFFSET];
// prediction assignment
assign bht_prediction_o.valid = bht_q[index].valid;
assign bht_prediction_o.taken = bht_q[index].saturation_counter == 2'b10;
assign bht_prediction_o.strongly_taken = (bht_q[index].saturation_counter == 2'b11);
always_comb begin : update_bht
bht_d = bht_q;
saturation_counter = bht_q[update_pc].saturation_counter;
if (bht_update_i.valid && !debug_mode_i) begin
bht_d[update_pc].valid = 1'b1;
if (saturation_counter == 2'b11) begin
// we can safely decrease it
if (~bht_update_i.taken)
bht_d[update_pc].saturation_counter = saturation_counter - 1;
// then check if it saturated in the negative regime e.g.: branch not taken
end else if (saturation_counter == 2'b00) begin
// we can safely increase it
if (bht_update_i.taken)
bht_d[update_pc].saturation_counter = saturation_counter + 1;
end else begin // otherwise we are not in any boundaries and can decrease or increase it
if (bht_update_i.taken)
bht_d[update_pc].saturation_counter = saturation_counter + 1;
else
bht_d[update_pc].saturation_counter = saturation_counter - 1;
end
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
for (int unsigned i = 0; i < NR_ENTRIES; i++)
bht_q[i] <= '0;
end else begin
// evict all entries
if (flush_i) begin
for (int i = 0; i < NR_ENTRIES; i++) begin
bht_q[i].valid <= 1'b0;
bht_q[i].saturation_counter <= 2'b10;
end
end else begin
bht_q <= bht_d;
end
end
end
endmodule
/* 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: $filename.v
*
* Description: Auto-generated bootrom
*/
// Auto-generated code
module bootrom (
input logic clk_i,
input logic req_i,
input logic [63:0] addr_i,
output logic [63:0] rdata_o
);
localparam int RomSize = 226;
const logic [RomSize-1:0][63:0] mem = {
64'h00006874_6469772d,
64'h6f692d67_65720074,
64'h66696873_2d676572,
64'h00737470_75727265,
64'h746e6900_746e6572,
64'h61702d74_70757272,
64'h65746e69_00646565,
64'h70732d74_6e657272,
64'h75630076_65646e2c,
64'h76637369_72007974,
64'h69726f69_72702d78,
64'h616d2c76_63736972,
64'h0073656d_616e2d67,
64'h65720064_65646e65,
64'h7478652d_73747075,
64'h72726574_6e690073,
64'h65676e61_7200656c,
64'h646e6168_702c7875,
64'h6e696c00_72656c6c,
64'h6f72746e_6f632d74,
64'h70757272_65746e69,
64'h00736c6c_65632d74,
64'h70757272_65746e69,
64'h23007469_6c70732d,
64'h626c7400_65707974,
64'h2d756d6d_00617369,
64'h2c766373_69720073,
64'h75746174_73006765,
64'h72006570_79745f65,
64'h63697665_64007963,
64'h6e657571_6572662d,
64'h6b636f6c_63007963,
64'h6e657571_6572662d,
64'h65736162_656d6974,
64'h006c6564_6f6d0065,
64'h6c626974_61706d6f,
64'h6300736c_6c65632d,
64'h657a6973_2300736c,
64'h6c65632d_73736572,
64'h64646123_09000000,
64'h02000000_02000000,
64'h02000000_04000000,
64'h2e010000_04000000,
64'h03000000_02000000,
64'h24010000_04000000,
64'h03000000_01000000,
64'h19010000_04000000,
64'h03000000_02000000,
64'h08010000_04000000,
64'h03000000_00c20100,
64'hfa000000_04000000,
64'h03000000_80f0fa02,
64'h3f000000_04000000,
64'h03000000_00100000,
64'h00000000_00000010,
64'h00000000_5b000000,
64'h10000000_03000000,
64'h00303537_3631736e,
64'h1b000000_08000000,
64'h03000000_00000030,
64'h30303030_30303140,
64'h74726175_01000000,
64'h02000000_006c6f72,
64'h746e6f63_d2000000,
64'h08000000_03000000,
64'h00100000_00000000,
64'h00000000_00000000,
64'h5b000000_10000000,
64'h03000000_ffff0000,
64'h01000000_be000000,
64'h08000000_03000000,
64'h00333130_2d677562,
64'h65642c76_63736972,
64'h1b000000_10000000,
64'h03000000_00003040,
64'h72656c6c_6f72746e,
64'h6f632d67_75626564,
64'h01000000_02000000,
64'h02000000_af000000,
64'h04000000_03000000,
64'h02000000_a9000000,
64'h04000000_03000000,
64'h02000000_ef000000,
64'h04000000_03000000,
64'h07000000_dc000000,
64'h04000000_03000000,
64'h00000004_00000000,
64'h0000000c_00000000,
64'h5b000000_10000000,
64'h03000000_09000000,
64'h01000000_0b000000,
64'h01000000_be000000,
64'h10000000_03000000,
64'h94000000_00000000,
64'h03000000_00000030,
64'h63696c70_2c766373,
64'h69720030_2e302e31,
64'h2d63696c_702c6576,
64'h69666973_1b000000,
64'h1e000000_03000000,
64'h01000000_83000000,
64'h04000000_03000000,
64'h00000000_00000000,
64'h04000000_03000000,
64'h00000000_30303030,
64'h30306340_72656c6c,
64'h6f72746e_6f632d74,
64'h70757272_65746e69,
64'h01000000_02000000,
64'h006c6f72_746e6f63,
64'hd2000000_08000000,
64'h03000000_00000c00,
64'h00000000_00000002,
64'h00000000_5b000000,
64'h10000000_03000000,
64'h07000000_01000000,
64'h03000000_01000000,
64'hbe000000_10000000,
64'h03000000_00000000,
64'h30746e69_6c632c76,
64'h63736972_1b000000,
64'h0d000000_03000000,
64'h00000030_30303030,
64'h30324074_6e696c63,
64'h01000000_b7000000,
64'h00000000_03000000,
64'h00007375_622d656c,
64'h706d6973_00636f73,
64'h2d657261_622d656e,
64'h61697261_2c687465,
64'h1b000000_1f000000,
64'h03000000_02000000,
64'h0f000000_04000000,
64'h03000000_02000000,
64'h00000000_04000000,
64'h03000000_00636f73,
64'h01000000_02000000,
64'h00008001_00000000,
64'h00000080_00000000,
64'h5b000000_10000000,
64'h03000000_00007972,
64'h6f6d656d_4f000000,
64'h07000000_03000000,
64'h00303030_30303030,
64'h38407972_6f6d656d,
64'h01000000_02000000,
64'h02000000_02000000,
64'h01000000_af000000,
64'h04000000_03000000,
64'h01000000_a9000000,
64'h04000000_03000000,
64'h00006374_6e692d75,
64'h70632c76_63736972,
64'h1b000000_0f000000,
64'h03000000_94000000,
64'h00000000_03000000,
64'h01000000_83000000,
64'h04000000_03000000,
64'h00000000_72656c6c,
64'h6f72746e_6f632d74,
64'h70757272_65746e69,
64'h01000000_79000000,
64'h00000000_03000000,
64'h00003933_76732c76,
64'h63736972_70000000,
64'h0b000000_03000000,
64'h00007573_63616d69,
64'h34367672_66000000,
64'h0b000000_03000000,
64'h00000076_63736972,
64'h00656e61_69726120,
64'h2c687465_1b000000,
64'h12000000_03000000,
64'h00000000_79616b6f,
64'h5f000000_05000000,
64'h03000000_00000000,
64'h5b000000_04000000,
64'h03000000_00757063,
64'h4f000000_04000000,
64'h03000000_80f0fa02,
64'h3f000000_04000000,
64'h03000000_00000030,
64'h40757063_01000000,
64'h00800000_2c000000,
64'h04000000_03000000,
64'h00000000_0f000000,
64'h04000000_03000000,
64'h01000000_00000000,
64'h04000000_03000000,
64'h00000000_73757063,
64'h01000000_00657261,
64'h622d656e_61697261,
64'h2c687465_26000000,
64'h10000000_03000000,
64'h00766564_2d657261,
64'h622d656e_61697261,
64'h2c687465_1b000000,
64'h14000000_03000000,
64'h02000000_0f000000,
64'h04000000_03000000,
64'h02000000_00000000,
64'h04000000_03000000,
64'h00000000_01000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h1c050000_3b010000,
64'h00000000_10000000,
64'h11000000_28000000,
64'h54050000_38000000,
64'h8f060000_edfe0dd0,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_0000bff5,
64'h10500073_03c58593,
64'h00000597_f1402573,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00000000_00000000,
64'h00008402_07458593,
64'h00000597_f1402573,
64'h01f41413_0010041b
};
logic [$clog2(RomSize)-1:0] addr_q;
always_ff @(posedge clk_i) begin
if (req_i) begin
addr_q <= addr_i[$clog2(RomSize)-1+3:3];
end
end
// this prevents spurious Xes from propagating into
// the speculative fetch stage of the core
assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0;
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 09.05.2017
// Description: Branch target calculation and comparison
import ariane_pkg::*;
module branch_unit (
input fu_data_t fu_data_i,
input logic [63:0] pc_i, // PC of instruction
input logic is_compressed_instr_i,
input logic fu_valid_i, // any functional unit is valid, check that there is no accidental mis-predict
input logic branch_valid_i,
input logic branch_comp_res_i, // branch comparison result from ALU
output logic [63:0] branch_result_o,
input branchpredict_sbe_t branch_predict_i, // this is the address we predicted
output branchpredict_t resolved_branch_o, // this is the actual address we are targeting
output logic resolve_branch_o, // to ID to clear that we resolved the branch and we can
// accept new entries to the scoreboard
output exception_t branch_exception_o // branch exception out
);
logic [63:0] target_address;
logic [63:0] next_pc;
// here we handle the various possibilities of mis-predicts
always_comb begin : mispredict_handler
// set the jump base, for JALR we need to look at the register, for all other control flow instructions we can take the current PC
automatic logic [63:0] jump_base;
jump_base = (fu_data_i.operator == JALR) ? fu_data_i.operand_a : pc_i;
resolve_branch_o = 1'b0;
resolved_branch_o.target_address = 64'b0;
resolved_branch_o.is_taken = 1'b0;
resolved_branch_o.valid = branch_valid_i;
resolved_branch_o.is_mispredict = 1'b0;
resolved_branch_o.clear = 1'b0;
resolved_branch_o.cf_type = branch_predict_i.cf_type;
// calculate next PC, depending on whether the instruction is compressed or not this may be different
next_pc = pc_i + ((is_compressed_instr_i) ? 64'h2 : 64'h4);
// calculate target address simple 64 bit addition
target_address = $unsigned($signed(jump_base) + $signed(fu_data_i.imm));
// on a JALR we are supposed to reset the LSB to 0 (according to the specification)
if (fu_data_i.operator == JALR)
target_address[0] = 1'b0;
// if we need to put the branch target address in a destination register, output it here to WB
branch_result_o = next_pc;
// save PC - we need this to get the target row in the branch target buffer
// we play this trick with the branch instruction which wraps a word boundary:
// /---------- Place the prediction on this PC
// \/
// ____________________________________________________
// |branch [15:0] | branch[31:16] | compressed 1[15:0] |
// |____________________________________________________
// This will relief the pre-fetcher to re-fetch partially fetched unaligned branch instructions e.g.:
// we don't have a back arch between the pre-fetcher and decoder/instruction FIFO.
resolved_branch_o.pc = (is_compressed_instr_i || pc_i[1] == 1'b0) ? pc_i : ({pc_i[63:2], 2'b0} + 64'h4);
if (branch_valid_i) begin
// write target address which goes to pc gen
resolved_branch_o.target_address = (branch_comp_res_i) ? target_address : next_pc;
resolved_branch_o.is_taken = branch_comp_res_i;
// we've detected a branch in ID with the following parameters
// we mis-predicted e.g.: the predicted address is unequal to the actual address
if (target_address[0] == 1'b0) begin
// we've got a valid branch prediction
if (branch_predict_i.valid) begin
// if the outcome doesn't match we've got a mis-predict
if (branch_predict_i.predict_taken != branch_comp_res_i) begin
resolved_branch_o.is_mispredict = 1'b1;
end
// check if the address of the predict taken branch is correct
if (branch_predict_i.predict_taken && target_address != branch_predict_i.predict_address) begin
resolved_branch_o.is_mispredict = 1'b1;
end
// branch-prediction didn't do anything (e.g.: it fetched PC + 2/4), so if this branch is taken
// we also have a mis-predict
end else begin
if (branch_comp_res_i) begin
resolved_branch_o.is_mispredict = 1'b1;
end
end
end
// to resolve the branch in ID
resolve_branch_o = 1'b1;
// the other case would be that this instruction was no branch but branch prediction thought that it was one
// this is essentially also a mis-predict
end else if (fu_valid_i && branch_predict_i.valid && branch_predict_i.predict_taken) begin
// re-set the branch to the next PC
resolved_branch_o.is_mispredict = 1'b1;
resolved_branch_o.target_address = next_pc;
// clear this entry so that we are not constantly mis-predicting
resolved_branch_o.clear = 1'b1;
resolved_branch_o.valid = 1'b1;
resolve_branch_o = 1'b1;
end
end
// use ALU exception signal for storing instruction fetch exceptions if
// the target address is not aligned to a 2 byte boundary
always_comb begin : exception_handling
branch_exception_o.cause = riscv::INSTR_ADDR_MISALIGNED;
branch_exception_o.valid = 1'b0;
branch_exception_o.tval = pc_i;
// only throw exception if this is indeed a branch
if (branch_valid_i && target_address[0] != 1'b0)
branch_exception_o.valid = 1'b1;
end
endmodule
//Copyright (C) 2018 to present,
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 2.0 (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-2.0. 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 08.02.2018
// Migrated: Luis Vitorio Cargnini, IEEE
// Date: 09.06.2018
// ------------------------------
// Branch Prediction
// ------------------------------
// branch target buffer
module btb #(
parameter int NR_ENTRIES = 8
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the btb
input logic debug_mode_i,
input logic [63:0] vpc_i, // virtual PC from IF stage
input ariane_pkg::btb_update_t btb_update_i, // update btb with this information
output ariane_pkg::btb_prediction_t btb_prediction_o // prediction from btb
);
// number of bits which are not used for indexing
localparam OFFSET = 1; // we are using compressed instructions so do use the lower 2 bits for prediction
localparam ANTIALIAS_BITS = 8;
// number of bits we should use for prediction
localparam PREDICTION_BITS = $clog2(NR_ENTRIES) + OFFSET;
// typedef for all branch target entries
// we may want to try to put a tag field that fills the rest of the PC in-order to mitigate aliasing effects
ariane_pkg::btb_prediction_t btb_d [NR_ENTRIES-1:0], btb_q [NR_ENTRIES-1:0];
logic [$clog2(NR_ENTRIES)-1:0] index, update_pc;
assign index = vpc_i[PREDICTION_BITS - 1:OFFSET];
assign update_pc = btb_update_i.pc[PREDICTION_BITS - 1:OFFSET];
// output matching prediction
assign btb_prediction_o = btb_q[index];
// -------------------------
// Update Branch Prediction
// -------------------------
// update on a mis-predict
always_comb begin : update_branch_predict
btb_d = btb_q;
if (btb_update_i.valid && !debug_mode_i) begin
btb_d[update_pc].valid = 1'b1;
// the target address is simply updated
btb_d[update_pc].target_address = btb_update_i.target_address;
// check if we should invalidate this entry, this happens in case we predicted a branch
// where actually none-is (aliasing)
if (btb_update_i.clear) begin
btb_d[update_pc].valid = 1'b0;
end
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
// Bias the branches to be taken upon first arrival
for (int i = 0; i < NR_ENTRIES; i++)
btb_q[i] <= '{default: 0};
end else begin
// evict all entries
if (flush_i) begin
for (int i = 0; i < NR_ENTRIES; i++) begin
btb_q[i].valid <= 1'b0;
end
end else begin
btb_q <= btb_d;
end
end
end
endmodule
// 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.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A two-phase clock domain crossing.
///
/// CONSTRAINT: Requires max_delay of min_period(src_clk_i, dst_clk_i) through
/// the paths async_req, async_ack, async_data.
/* verilator lint_off DECLFILENAME */
module cdc_2phase #(
parameter type T = logic
)(
input logic src_rst_ni,
input logic src_clk_i,
input T src_data_i,
input logic src_valid_i,
output logic src_ready_o,
input logic dst_rst_ni,
input logic dst_clk_i,
output T dst_data_o,
output logic dst_valid_o,
input logic dst_ready_i
);
// Asynchronous handshake signals.
(* dont_touch = "true" *) logic async_req;
(* dont_touch = "true" *) logic async_ack;
(* dont_touch = "true" *) T async_data;
// The sender in the source domain.
cdc_2phase_src #(.T(T)) i_src (
.rst_ni ( src_rst_ni ),
.clk_i ( src_clk_i ),
.data_i ( src_data_i ),
.valid_i ( src_valid_i ),
.ready_o ( src_ready_o ),
.async_req_o ( async_req ),
.async_ack_i ( async_ack ),
.async_data_o ( async_data )
);
// The receiver in the destination domain.
cdc_2phase_dst #(.T(T)) i_dst (
.rst_ni ( dst_rst_ni ),
.clk_i ( dst_clk_i ),
.data_o ( dst_data_o ),
.valid_o ( dst_valid_o ),
.ready_i ( dst_ready_i ),
.async_req_i ( async_req ),
.async_ack_o ( async_ack ),
.async_data_i ( async_data )
);
endmodule
/// Half of the two-phase clock domain crossing located in the source domain.
module cdc_2phase_src #(
parameter type T = logic
)(
input logic rst_ni,
input logic clk_i,
input T data_i,
input logic valid_i,
output logic ready_o,
output logic async_req_o,
input logic async_ack_i,
output T async_data_o
);
(* dont_touch = "true" *)
logic req_src_q, ack_src_q, ack_q;
(* dont_touch = "true" *)
T data_src_q;
// The req_src and data_src registers change when a new data item is accepted.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
req_src_q <= 0;
data_src_q <= '0;
end else if (valid_i && ready_o) begin
req_src_q <= ~req_src_q;
data_src_q <= data_i;
end
end
// The ack_src and ack registers act as synchronization stages.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ack_src_q <= 0;
ack_q <= 0;
end else begin
ack_src_q <= async_ack_i;
ack_q <= ack_src_q;
end
end
// Output assignments.
assign ready_o = (req_src_q == ack_q);
assign async_req_o = req_src_q;
assign async_data_o = data_src_q;
endmodule
/// Half of the two-phase clock domain crossing located in the destination
/// domain.
module cdc_2phase_dst #(
parameter type T = logic
)(
input logic rst_ni,
input logic clk_i,
output T data_o,
output logic valid_o,
input logic ready_i,
input logic async_req_i,
output logic async_ack_o,
input T async_data_i
);
(* dont_touch = "true" *)
(* async_reg = "true" *)
logic req_dst_q, req_q0, req_q1, ack_dst_q;
(* dont_touch = "true" *)
T data_dst_q;
// The ack_dst register changes when a new data item is accepted.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
ack_dst_q <= 0;
end else if (valid_o && ready_i) begin
ack_dst_q <= ~ack_dst_q;
end
end
// The data_dst register changes when a new data item is presented. This is
// indicated by the async_req line changing levels.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
data_dst_q <= '0;
end else if (req_q0 != req_q1 && !valid_o) begin
data_dst_q <= async_data_i;
end
end
// The req_dst and req registers act as synchronization stages.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
req_dst_q <= 0;
req_q0 <= 0;
req_q1 <= 0;
end else begin
req_dst_q <= async_req_i;
req_q0 <= req_dst_q;
req_q1 <= req_q0;
end
end
// Output assignments.
assign valid_o = (ack_dst_q != req_q1);
assign data_o = data_dst_q;
assign async_ack_o = ack_dst_q;
endmodule
/* verilator lint_on DECLFILENAME */
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 15/07/2017
// Description: A RISC-V privilege spec 1.11 (WIP) compatible CLINT (core local interrupt controller)
//
// Platforms provide a real-time counter, exposed as a memory-mapped machine-mode register, mtime. mtime must run at
// constant frequency, and the platform must provide a mechanism for determining the timebase of mtime (device tree).
module clint #(
parameter int unsigned AXI_ADDR_WIDTH = 64,
parameter int unsigned AXI_DATA_WIDTH = 64,
parameter int unsigned AXI_ID_WIDTH = 10,
parameter int unsigned NR_CORES = 1 // Number of cores therefore also the number of timecmp registers and timer interrupts
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic testmode_i,
input ariane_axi::req_t axi_req_i,
output ariane_axi::resp_t axi_resp_o,
input logic rtc_i, // Real-time clock in (usually 32.768 kHz)
output logic [NR_CORES-1:0] timer_irq_o, // Timer interrupts
output logic [NR_CORES-1:0] ipi_o // software interrupt (a.k.a inter-process-interrupt)
);
// register offset
localparam logic [15:0] MSIP_BASE = 16'h0;
localparam logic [15:0] MTIMECMP_BASE = 16'h4000;
localparam logic [15:0] MTIME_BASE = 16'hbff8;
localparam AddrSelWidth = (NR_CORES == 1) ? 1 : $clog2(NR_CORES);
// signals from AXI 4 Lite
logic [AXI_ADDR_WIDTH-1:0] address;
logic en;
logic we;
logic [63:0] wdata;
logic [63:0] rdata;
// bit 11 and 10 are determining the address offset
logic [15:0] register_address;
assign register_address = address[15:0];
// actual registers
logic [63:0] mtime_n, mtime_q;
logic [NR_CORES-1:0][63:0] mtimecmp_n, mtimecmp_q;
logic [NR_CORES-1:0] msip_n, msip_q;
// increase the timer
logic increase_timer;
// -----------------------------
// AXI Interface Logic
// -----------------------------
axi_lite_interface #(
.AXI_ADDR_WIDTH ( AXI_ADDR_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
) axi_lite_interface_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.axi_req_i ( axi_req_i ),
.axi_resp_o ( axi_resp_o ),
.address_o ( address ),
.en_o ( en ),
.we_o ( we ),
.data_i ( rdata ),
.data_o ( wdata )
);
// -----------------------------
// Register Update Logic
// -----------------------------
// APB register write logic
always_comb begin
mtime_n = mtime_q;
mtimecmp_n = mtimecmp_q;
msip_n = msip_q;
// RTC says we should increase the timer
if (increase_timer)
mtime_n = mtime_q + 1;
// written from APB bus - gets priority
if (en && we) begin
case (register_address) inside
[MSIP_BASE:MSIP_BASE+8*NR_CORES]: begin
msip_n[$unsigned(address[AddrSelWidth-1+3:3])] = wdata[0];
end
[MTIMECMP_BASE:MTIMECMP_BASE+8*NR_CORES]: begin
mtimecmp_n[$unsigned(address[AddrSelWidth-1+3:3])] = wdata;
end
MTIME_BASE: begin
mtime_n = wdata;
end
default:;
endcase
end
end
// APB register read logic
always_comb begin
rdata = 'b0;
if (en && !we) begin
case (register_address) inside
[MSIP_BASE:MSIP_BASE+8*NR_CORES]: begin
rdata = msip_q[$unsigned(address[AddrSelWidth-1+3:3])];
end
[MTIMECMP_BASE:MTIMECMP_BASE+8*NR_CORES]: begin
rdata = mtimecmp_q[$unsigned(address[AddrSelWidth-1+3:3])];
end
MTIME_BASE: begin
rdata = mtime_q;
end
default:;
endcase
end
end
// -----------------------------
// IRQ Generation
// -----------------------------
// The mtime register has a 64-bit precision on all RV32, RV64, and RV128 systems. Platforms provide a 64-bit
// memory-mapped machine-mode timer compare register (mtimecmp), which causes a timer interrupt to be posted when the
// mtime register contains a value greater than or equal (mtime >= mtimecmp) to the value in the mtimecmp register.
// The interrupt remains posted until it is cleared by writing the mtimecmp register. The interrupt will only be taken
// if interrupts are enabled and the MTIE bit is set in the mie register.
always_comb begin : irq_gen
// check that the mtime cmp register is set to a meaningful value
for (int unsigned i = 0; i < NR_CORES; i++) begin
if (mtime_q >= mtimecmp_q[i]) begin
timer_irq_o[i] = 1'b1;
end else begin
timer_irq_o[i] = 1'b0;
end
end
end
// -----------------------------
// RTC time tracking facilities
// -----------------------------
// 1. Put the RTC input through a classic two stage edge-triggered synchronizer to filter out any
// metastability effects (or at least make them unlikely :-))
sync_wedge i_sync_edge (
.clk_i,
.rst_ni,
.en_i ( ~testmode_i ),
.serial_i ( rtc_i ),
.r_edge_o ( increase_timer ),
.f_edge_o ( ), // left open
.serial_o ( ) // left open
);
// Registers
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
mtime_q <= 64'b0;
mtimecmp_q <= 'b0;
msip_q <= '0;
end else begin
mtime_q <= mtime_n;
mtimecmp_q <= mtimecmp_n;
msip_q <= msip_n;
end
end
assign ipi_o = msip_q;
// -------------
// Assertions
// --------------
//pragma translate_off
`ifndef VERILATOR
// Static assertion check for appropriate bus width
initial begin
assert (AXI_DATA_WIDTH == 64) else $fatal("Timer needs to interface with a 64 bit bus, everything else is not supported");
end
`endif
//pragma translate_on
endmodule
// 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.
module cluster_clock_inverter
(
input logic clk_i,
output logic clk_o
);
assign clk_o = ~clk_i;
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 08.05.2017
// Description: Flush controller
import ariane_pkg::*;
module controller (
input logic clk_i,
input logic rst_ni,
output logic set_pc_commit_o, // Set PC om PC Gen
output logic flush_if_o, // Flush the IF stage
output logic flush_unissued_instr_o, // Flush un-issued instructions of the scoreboard
output logic flush_id_o, // Flush ID stage
output logic flush_ex_o, // Flush EX stage
output logic flush_icache_o, // Flush ICache
output logic flush_dcache_o, // Flush DCache
input logic flush_dcache_ack_i, // Acknowledge the whole DCache Flush
output logic flush_tlb_o, // Flush TLBs
input logic halt_csr_i, // Halt request from CSR (WFI instruction)
output logic halt_o, // Halt signal to commit stage
input logic eret_i, // Return from exception
input logic ex_valid_i, // We got an exception, flush the pipeline
input logic set_debug_pc_i, // set the debug pc from CSR
input branchpredict_t resolved_branch_i, // We got a resolved branch, check if we need to flush the front-end
input logic flush_csr_i, // We got an instruction which altered the CSR, flush the pipeline
input logic fence_i_i, // fence.i in
input logic fence_i, // fence in
input logic sfence_vma_i, // We got an instruction to flush the TLBs and pipeline
input logic flush_commit_i // Flush request from commit stage
);
// active fence - high if we are currently flushing the dcache
logic fence_active_d, fence_active_q;
logic flush_dcache;
// ------------
// Flush CTRL
// ------------
always_comb begin : flush_ctrl
fence_active_d = fence_active_q;
set_pc_commit_o = 1'b0;
flush_if_o = 1'b0;
flush_unissued_instr_o = 1'b0;
flush_id_o = 1'b0;
flush_ex_o = 1'b0;
flush_dcache = 1'b0;
flush_icache_o = 1'b0;
flush_tlb_o = 1'b0;
// ------------
// Mis-predict
// ------------
// flush on mispredict
if (resolved_branch_i.is_mispredict) begin
// flush only un-issued instructions
flush_unissued_instr_o = 1'b1;
// and if stage
flush_if_o = 1'b1;
end
// ---------------------------------
// FENCE
// ---------------------------------
if (fence_i) begin
// this can be seen as a CSR instruction with side-effect
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
flush_dcache = 1'b1;
fence_active_d = 1'b1;
end
// ---------------------------------
// FENCE.I
// ---------------------------------
if (fence_i_i) begin
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
flush_icache_o = 1'b1;
flush_dcache = 1'b1;
fence_active_d = 1'b1;
end
// wait for the acknowledge here
if (flush_dcache_ack_i && fence_active_q) begin
fence_active_d = 1'b0;
// keep the flush dcache signal high as long as we didn't get the acknowledge from the cache
end else if (fence_active_q) begin
flush_dcache = 1'b1;
end
// ---------------------------------
// SFENCE.VMA
// ---------------------------------
if (sfence_vma_i) begin
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
flush_tlb_o = 1'b1;
end
// Set PC to commit stage and flush pipleine
if (flush_csr_i || flush_commit_i) begin
set_pc_commit_o = 1'b1;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
// ---------------------------------
// 1. Exception
// 2. Return from exception
// ---------------------------------
if (ex_valid_i || eret_i || set_debug_pc_i) begin
// don't flush pcgen as we want to take the exception: Flush PCGen is not a flush signal
// for the PC Gen stage but instead tells it to take the PC we gave it
set_pc_commit_o = 1'b0;
flush_if_o = 1'b1;
flush_unissued_instr_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
end
// ----------------------
// Halt Logic
// ----------------------
always_comb begin
// halt the core if the fence is active
halt_o = halt_csr_i || fence_active_q;
end
// ----------------------
// Registers
// ----------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
fence_active_q <= 1'b0;
flush_dcache_o <= 1'b0;
end else begin
fence_active_q <= fence_active_d;
// register on the flush signal, this signal might be critical
flush_dcache_o <= flush_dcache;
end
end
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 05.05.2017
// Description: Buffer to hold CSR address, this acts like a functional unit
// to the scoreboard.
import ariane_pkg::*;
module csr_buffer (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i,
input fu_data_t fu_data_i,
output logic csr_ready_o, // FU is ready e.g. not busy
input logic csr_valid_i, // Input is valid
output logic [63:0] csr_result_o,
input logic csr_commit_i, // commit the pending CSR OP
// to CSR file
output logic [11:0] csr_addr_o // CSR address to commit stage
);
// this is a single entry store buffer for the address of the CSR
// which we are going to need in the commit stage
struct packed {
logic [11:0] csr_address;
logic valid;
} csr_reg_n, csr_reg_q;
// control logic, scoreboard signals
assign csr_result_o = fu_data_i.operand_a;
assign csr_addr_o = csr_reg_q.csr_address;
// write logic
always_comb begin : write
csr_reg_n = csr_reg_q;
// by default we are ready
csr_ready_o = 1'b1;
// if we have a valid uncomiited csr req or are just getting one WITHOUT a commit in, we are not ready
if ((csr_reg_q.valid || csr_valid_i) && ~csr_commit_i)
csr_ready_o = 1'b0;
// if we got a valid from the scoreboard
// store the CSR address
if (csr_valid_i) begin
csr_reg_n.csr_address = fu_data_i.operand_b[11:0];
csr_reg_n.valid = 1'b1;
end
// if we get a commit and no new valid instruction -> clear the valid bit
if (csr_commit_i && ~csr_valid_i) begin
csr_reg_n.valid = 1'b0;
end
// clear the buffer if we flushed
if (flush_i)
csr_reg_n.valid = 1'b0;
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
csr_reg_q <= '{default: 0};
end else begin
csr_reg_q <= csr_reg_n;
end
end
endmodule
/* 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: $filename.v
*
* Description: Auto-generated bootrom
*/
// Auto-generated code
module debug_rom (
input logic clk_i,
input logic req_i,
input logic [63:0] addr_i,
output logic [63:0] rdata_o
);
localparam int RomSize = 19;
const logic [RomSize-1:0][63:0] mem = {
64'h00000000_7b200073,
64'h7b302573_7b202473,
64'h10852423_f1402473,
64'ha85ff06f_7b302573,
64'h7b202473_10052223,
64'h00100073_7b302573,
64'h10052623_00c51513,
64'h00c55513_00000517,
64'h7b351073_fd5ff06f,
64'hfa041ce3_00247413,
64'h40044403_00a40433,
64'hf1402473_02041c63,
64'h00147413_40044403,
64'h00a40433_10852023,
64'hf1402473_00c51513,
64'h00c55513_00000517,
64'h7b351073_7b241073,
64'h0ff0000f_04c0006f,
64'h07c0006f_00c0006f
};
logic [$clog2(RomSize)-1:0] addr_q;
always_ff @(posedge clk_i) begin
if (req_i) begin
addr_q <= addr_i[$clog2(RomSize)-1+3:3];
end
end
// this prevents spurious Xes from propagating into
// the speculative fetch stage of the core
assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0;
endmodule
/* 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_pkg.sv
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
* Date: 30.6.2018
*
* Description: Debug-module package, contains common system definitions.
*
*/
package dm;
localparam logic [3:0] DbgVersion013 = 4'h2;
// size of program buffer in junks of 32-bit words
localparam logic [4:0] ProgBufSize = 5'h8;
// TODO(zarubaf) This is hard-coded to two at the moment
// amount of data count registers implemented
localparam logic [3:0] DataCount = 4'h2;
// address to which a hart should jump when it was requested to halt
localparam logic [63:0] HaltAddress = 64'h800;
localparam logic [63:0] ResumeAddress = HaltAddress + 4;
localparam logic [63:0] ExceptionAddress = HaltAddress + 8;
// address where data0-15 is shadowed or if shadowed in a CSR
// address of the first CSR used for shadowing the data
localparam logic [11:0] DataAddr = 12'h380; // we are aligned with Rocket here
// debug registers
typedef enum logic [7:0] {
Data0 = 8'h04,
Data1 = 8'h05,
Data2 = 8'h06,
Data3 = 8'h07,
Data4 = 8'h08,
Data5 = 8'h09,
Data6 = 8'h0A,
Data7 = 8'h0B,
Data8 = 8'h0C,
Data9 = 8'h0D,
Data10 = 8'h0E,
Data11 = 8'h0F,
DMControl = 8'h10,
DMStatus = 8'h11, // r/o
Hartinfo = 8'h12,
HaltSum1 = 8'h13,
HAWindowSel = 8'h14,
HAWindow = 8'h15,
AbstractCS = 8'h16,
Command = 8'h17,
AbstractAuto = 8'h18,
DevTreeAddr0 = 8'h19,
DevTreeAddr1 = 8'h1A,
DevTreeAddr2 = 8'h1B,
DevTreeAddr3 = 8'h1C,
NextDM = 8'h1D,
ProgBuf0 = 8'h20,
ProgBuf15 = 8'h2F,
AuthData = 8'h30,
HaltSum2 = 8'h34,
HaltSum3 = 8'h35,
SBAddress3 = 8'h37,
SBCS = 8'h38,
SBAddress0 = 8'h39,
SBAddress1 = 8'h3A,
SBAddress2 = 8'h3B,
SBData0 = 8'h3C,
SBData1 = 8'h3D,
SBData2 = 8'h3E,
SBData3 = 8'h3F,
HaltSum0 = 8'h40
} dm_csr_t;
// debug causes
localparam logic [2:0] CauseBreakpoint = 3'h1;
localparam logic [2:0] CauseTrigger = 3'h2;
localparam logic [2:0] CauseRequest = 3'h3;
localparam logic [2:0] CauseSingleStep = 3'h4;
typedef struct packed {
logic [31:23] zero1;
logic impebreak;
logic [21:20] zero0;
logic allhavereset;
logic anyhavereset;
logic allresumeack;
logic anyresumeack;
logic allnonexistent;
logic anynonexistent;
logic allunavail;
logic anyunavail;
logic allrunning;
logic anyrunning;
logic allhalted;
logic anyhalted;
logic authenticated;
logic authbusy;
logic hasresethaltreq;
logic devtreevalid;
logic [3:0] version;
} dmstatus_t;
typedef struct packed {
logic haltreq;
logic resumereq;
logic hartreset;
logic ackhavereset;
logic zero1;
logic hasel;
logic [25:16] hartsello;
logic [15:6] hartselhi;
logic [5:4] zero0;
logic setresethaltreq;
logic clrresethaltreq;
logic ndmreset;
logic dmactive;
} dmcontrol_t;
typedef struct packed {
logic [31:24] zero1;
logic [23:20] nscratch;
logic [19:17] zero0;
logic dataaccess;
logic [15:12] datasize;
logic [11:0] dataaddr;
} hartinfo_t;
typedef enum logic [2:0] { CmdErrNone, CmdErrBusy, CmdErrNotSupported,
CmdErrorException, CmdErrorHaltResume,
CmdErrorBus, CmdErrorOther = 7
} cmderr_t;
typedef struct packed {
logic [31:29] zero3;
logic [28:24] progbufsize;
logic [23:13] zero2;
logic busy;
logic zero1;
cmderr_t cmderr;
logic [7:4] zero0;
logic [3:0] datacount;
} abstractcs_t;
typedef enum logic [7:0] {
AccessRegister = 8'h0,
QuickAccess = 8'h1,
AccessMemory = 8'h2
} cmd_t;
typedef struct packed {
cmd_t cmdtype;
logic [23:0] control;
} command_t;
typedef struct packed {
logic [31:16] autoexecprogbuf;
logic [15:12] zero0;
logic [11:0] autoexecdata;
} abstractauto_t;
typedef struct packed {
logic zero1;
logic [22:20] aarsize;
logic zero0;
logic postexec;
logic transfer;
logic write;
logic [15:0] regno;
} ac_ar_cmd_t;
// DTM
typedef enum logic [1:0] {
DTM_NOP = 2'h0,
DTM_READ = 2'h1,
DTM_WRITE = 2'h2
} dtm_op_t;
typedef struct packed {
logic [31:29] sbversion;
logic [28:23] zero0;
logic sbbusyerror;
logic sbbusy;
logic sbreadonaddr;
logic [19:17] sbaccess;
logic sbautoincrement;
logic sbreadondata;
logic [14:12] sberror;
logic [11:5] sbasize;
logic sbaccess128;
logic sbaccess64;
logic sbaccess32;
logic sbaccess16;
logic sbaccess8;
} sbcs_t;
localparam logic[1:0] DTM_SUCCESS = 2'h0;
typedef struct packed {
logic [6:0] addr;
dtm_op_t op;
logic [31:0] data;
} dmi_req_t;
typedef struct packed {
logic [31:0] data;
logic [1:0] resp;
} dmi_resp_t;
endpackage
/* 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
/* 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: axi_riscv_debug_module.sv
* Author: Andreas Traber <atraber@iis.ee.ethz.ch>
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
*
* Description: Clock domain crossings for JTAG to DMI very heavily based
* on previous work by Andreas Traber for the PULP project.
* This is mainly a wrapper around the existing CDCs.
*/
module dmi_cdc (
// JTAG side (master side)
input logic tck_i,
input logic trst_ni,
input dm::dmi_req_t jtag_dmi_req_i,
output logic jtag_dmi_ready_o,
input logic jtag_dmi_valid_i,
output dm::dmi_resp_t jtag_dmi_resp_o,
output logic jtag_dmi_valid_o,
input logic jtag_dmi_ready_i,
// core side (slave side)
input logic clk_i,
input logic rst_ni,
output dm::dmi_req_t core_dmi_req_o,
output logic core_dmi_valid_o,
input logic core_dmi_ready_i,
input dm::dmi_resp_t core_dmi_resp_i,
output logic core_dmi_ready_o,
input logic core_dmi_valid_i
);
cdc_2phase #(.T(dm::dmi_req_t)) i_cdc_req (
.src_rst_ni ( trst_ni ),
.src_clk_i ( tck_i ),
.src_data_i ( jtag_dmi_req_i ),
.src_valid_i ( jtag_dmi_valid_i ),
.src_ready_o ( jtag_dmi_ready_o ),
.dst_rst_ni ( rst_ni ),
.dst_clk_i ( clk_i ),
.dst_data_o ( core_dmi_req_o ),
.dst_valid_o ( core_dmi_valid_o ),
.dst_ready_i ( core_dmi_ready_i )
);
cdc_2phase #(.T(dm::dmi_resp_t)) i_cdc_resp (
.src_rst_ni ( rst_ni ),
.src_clk_i ( clk_i ),
.src_data_i ( core_dmi_resp_i ),
.src_valid_i ( core_dmi_valid_i ),
.src_ready_o ( core_dmi_ready_o ),
.dst_rst_ni ( trst_ni ),
.dst_clk_i ( tck_i ),
.dst_data_o ( jtag_dmi_resp_o ),
.dst_valid_o ( jtag_dmi_valid_o ),
.dst_ready_i ( jtag_dmi_ready_i )
);
endmodule
/* 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: axi_riscv_debug_module.sv
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
* Date: 19.7.2018
*
* Description: JTAG DMI (debug module interface)
*
*/
module dmi_jtag (
input logic clk_i, // DMI Clock
input logic rst_ni, // Asynchronous reset active low
input logic testmode_i,
output logic dmi_rst_no, // hard reset
output dm::dmi_req_t dmi_req_o,
output logic dmi_req_valid_o,
input logic dmi_req_ready_i,
input dm::dmi_resp_t dmi_resp_i,
output logic dmi_resp_ready_o,
input logic dmi_resp_valid_i,
input logic tck_i, // JTAG test clock pad
input logic tms_i, // JTAG test mode select pad
input logic trst_ni, // JTAG test reset pad
input logic td_i, // JTAG test data input pad
output logic td_o, // JTAG test data output pad
output logic tdo_oe_o // Data out output enable
);
assign dmi_rst_no = rst_ni;
logic test_logic_reset;
logic shift_dr;
logic update_dr;
logic capture_dr;
logic dmi_access;
logic dtmcs_select;
logic dmi_reset;
logic dmi_tdi;
logic dmi_tdo;
dm::dmi_req_t dmi_req;
logic dmi_req_ready;
logic dmi_req_valid;
dm::dmi_resp_t dmi_resp;
logic dmi_resp_valid;
logic dmi_resp_ready;
typedef struct packed {
logic [6:0] address;
logic [31:0] data;
logic [1:0] op;
} dmi_t;
typedef enum logic [1:0] {
DMINoError = 2'h0, DMIReservedError = 2'h1,
DMIOPFailed = 2'h2, DMIBusy = 2'h3
} dmi_error_t;
enum logic [2:0] { Idle, Read, WaitReadValid, Write, WaitWriteValid } state_d, state_q;
logic [$bits(dmi_t)-1:0] dr_d, dr_q;
logic [6:0] address_d, address_q;
logic [31:0] data_d, data_q;
dmi_t dmi;
assign dmi = dmi_t'(dr_q);
assign dmi_req.addr = address_q;
assign dmi_req.data = data_q;
assign dmi_req.op = (state_q == Write) ? dm::DTM_WRITE : dm::DTM_READ;
// we'will always be ready to accept the data we requested
assign dmi_resp_ready = 1'b1;
logic error_dmi_busy;
dmi_error_t error_d, error_q;
always_comb begin
error_dmi_busy = 1'b0;
// default assignments
state_d = state_q;
address_d = address_q;
data_d = data_q;
error_d = error_q;
dmi_req_valid = 1'b0;
case (state_q)
Idle: begin
// make sure that no error is sticky
if (dmi_access && update_dr && (error_q == DMINoError)) begin
// save address and value
address_d = dmi.address;
data_d = dmi.data;
if (dm::dtm_op_t'(dmi.op) == dm::DTM_READ) begin
state_d = Read;
end else if (dm::dtm_op_t'(dmi.op) == dm::DTM_WRITE) begin
state_d = Write;
end
// else this is a nop and we can stay here
end
end
Read: begin
dmi_req_valid = 1'b1;
if (dmi_req_ready) begin
state_d = WaitReadValid;
end
end
WaitReadValid: begin
// load data into register and shift out
if (dmi_resp_valid) begin
data_d = dmi_resp.data;
state_d = Idle;
end
end
Write: begin
dmi_req_valid = 1'b1;
// got a valid answer go back to idle
if (dmi_req_ready) begin
state_d = Idle;
end
end
WaitWriteValid: begin
// just wait for idle here
if (dmi_resp_valid) begin
state_d = Idle;
end
end
endcase
// update_dr means we got another request but we didn't finish
// the one in progress, this state is sticky
if (update_dr && state_q != Idle) begin
error_dmi_busy = 1'b1;
end
// if capture_dr goes high while we are in the read state
// or in the corresponding wait state we are not giving back a valid word
// -> throw an error
if (capture_dr && state_q inside {Read, WaitReadValid}) begin
error_dmi_busy = 1'b1;
end
if (error_dmi_busy) begin
error_d = DMIBusy;
end
// clear sticky error flag
if (dmi_reset && dtmcs_select) begin
error_d = DMINoError;
end
end
// shift register
assign dmi_tdo = dr_q[0];
always_comb begin
dr_d = dr_q;
if (capture_dr) begin
if (dmi_access) begin
if (error_q == DMINoError && !error_dmi_busy) begin
dr_d = {address_q, data_q, DMINoError};
// DMI was busy, report an error
end else if (error_q == DMIBusy || error_dmi_busy) begin
dr_d = {address_q, data_q, DMIBusy};
end
end
end
if (shift_dr) begin
if (dmi_access) dr_d = {dmi_tdi, dr_q[$bits(dr_q)-1:1]};
end
if (test_logic_reset) begin
dr_d = '0;
end
end
always_ff @(posedge tck_i or negedge trst_ni) begin
if (~trst_ni) begin
dr_q <= '0;
state_q <= Idle;
address_q <= '0;
data_q <= '0;
error_q <= DMINoError;
end else begin
dr_q <= dr_d;
state_q <= state_d;
address_q <= address_d;
data_q <= data_d;
error_q <= error_d;
end
end
// ---------
// TAP
// ---------
dmi_jtag_tap #(
.IrLength (5)
) i_dmi_jtag_tap (
.tck_i,
.tms_i,
.trst_ni,
.td_i,
.td_o,
.tdo_oe_o,
.testmode_i ( testmode_i ),
.test_logic_reset_o ( test_logic_reset ),
.shift_dr_o ( shift_dr ),
.update_dr_o ( update_dr ),
.capture_dr_o ( capture_dr ),
.dmi_access_o ( dmi_access ),
.dtmcs_select_o ( dtmcs_select ),
.dmi_reset_o ( dmi_reset ),
.dmi_error_i ( error_q ),
.dmi_tdi_o ( dmi_tdi ),
.dmi_tdo_i ( dmi_tdo )
);
// ---------
// CDC
// ---------
dmi_cdc i_dmi_cdc (
// JTAG side (master side)
.tck_i,
.trst_ni,
.jtag_dmi_req_i ( dmi_req ),
.jtag_dmi_ready_o ( dmi_req_ready ),
.jtag_dmi_valid_i ( dmi_req_valid ),
.jtag_dmi_resp_o ( dmi_resp ),
.jtag_dmi_valid_o ( dmi_resp_valid ),
.jtag_dmi_ready_i ( dmi_resp_ready ),
// core side
.clk_i,
.rst_ni,
.core_dmi_req_o ( dmi_req_o ),
.core_dmi_valid_o ( dmi_req_valid_o ),
.core_dmi_ready_i ( dmi_req_ready_i ),
.core_dmi_resp_i ( dmi_resp_i ),
.core_dmi_ready_o ( dmi_resp_ready_o ),
.core_dmi_valid_i ( dmi_resp_valid_i )
);
endmodule
// 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.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
/* verilator lint_off DECLFILENAME */
module fifo #(
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
parameter int unsigned THRESHOLD = 1, // fill count until when to assert threshold_o
parameter type dtype = logic [DATA_WIDTH-1:0]
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic testmode_i, // test_mode to bypass clock gating
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic threshold_o, // the FIFO is above the specified threshold
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
fifo_v2 #(
.FALL_THROUGH ( FALL_THROUGH ),
.DATA_WIDTH ( DATA_WIDTH ),
.DEPTH ( DEPTH ),
.ALM_FULL_TH ( THRESHOLD ),
.dtype ( dtype )
) impl (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( flush_i ),
.testmode_i ( testmode_i ),
.full_o ( full_o ),
.empty_o ( empty_o ),
.alm_full_o ( threshold_o ),
.alm_empty_o ( ),
.data_i ( data_i ),
.push_i ( push_i ),
.data_o ( data_o ),
.pop_i ( pop_i )
);
endmodule
/* verilator lint_on DECLFILENAME */
// 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.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module fifo_v2 #(
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
parameter int unsigned ALM_EMPTY_TH = 1, // almost empty threshold (when to assert alm_empty_o)
parameter int unsigned ALM_FULL_TH = 1, // almost full threshold (when to assert alm_full_o)
parameter type dtype = logic [DATA_WIDTH-1:0],
// DO NOT OVERWRITE THIS PARAMETER
parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic testmode_i, // test_mode to bypass clock gating
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic alm_full_o, // FIFO fillstate >= the specified threshold
output logic alm_empty_o, // FIFO fillstate <= the specified threshold
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
logic [ADDR_DEPTH-1:0] usage;
// generate threshold parameters
if (DEPTH == 0) begin
assign alm_full_o = 1'b0; // that signal does not make any sense in a FIFO of depth 0
assign alm_empty_o = 1'b0; // that signal does not make any sense in a FIFO of depth 0
end else begin
assign alm_full_o = (usage >= ALM_FULL_TH[ADDR_DEPTH-1:0]);
assign alm_empty_o = (usage <= ALM_EMPTY_TH[ADDR_DEPTH-1:0]);
end
fifo_v3 #(
.FALL_THROUGH ( FALL_THROUGH ),
.DATA_WIDTH ( DATA_WIDTH ),
.DEPTH ( DEPTH ),
.dtype ( dtype )
) i_fifo_v3 (
.clk_i,
.rst_ni,
.flush_i,
.testmode_i,
.full_o,
.empty_o,
.usage_o (usage),
.data_i,
.push_i,
.data_o,
.pop_i
);
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (ALM_FULL_TH <= DEPTH) else $error("ALM_FULL_TH can't be larger than the DEPTH.");
assert (ALM_EMPTY_TH <= DEPTH) else $error("ALM_EMPTY_TH can't be larger than the DEPTH.");
end
`endif
// pragma translate_on
endmodule // fifo_v2
// 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.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module fifo_v3 #(
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
parameter type dtype = logic [DATA_WIDTH-1:0],
// DO NOT OVERWRITE THIS PARAMETER
parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic testmode_i, // test_mode to bypass clock gating
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic [ADDR_DEPTH-1:0] usage_o, // fill pointer
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
// local parameter
// FIFO depth - handle the case of pass-through, synthesizer will do constant propagation
localparam int unsigned FIFO_DEPTH = (DEPTH > 0) ? DEPTH : 1;
// clock gating control
logic gate_clock;
// pointer to the read and write section of the queue
logic [ADDR_DEPTH - 1:0] read_pointer_n, read_pointer_q, write_pointer_n, write_pointer_q;
// keep a counter to keep track of the current queue status
logic [ADDR_DEPTH:0] status_cnt_n, status_cnt_q; // this integer will be truncated by the synthesis tool
// actual memory
dtype [FIFO_DEPTH - 1:0] mem_n, mem_q;
assign usage_o = status_cnt_q[ADDR_DEPTH-1:0];
if (DEPTH == 0) begin
assign empty_o = ~push_i;
assign full_o = ~pop_i;
end else begin
assign full_o = (status_cnt_q == FIFO_DEPTH[ADDR_DEPTH:0]);
assign empty_o = (status_cnt_q == 0) & ~(FALL_THROUGH & push_i);
end
// status flags
// read and write queue logic
always_comb begin : read_write_comb
// default assignment
read_pointer_n = read_pointer_q;
write_pointer_n = write_pointer_q;
status_cnt_n = status_cnt_q;
data_o = (DEPTH == 0) ? data_i : mem_q[read_pointer_q];
mem_n = mem_q;
gate_clock = 1'b1;
// push a new element to the queue
if (push_i && ~full_o) begin
// push the data onto the queue
mem_n[write_pointer_q] = data_i;
// un-gate the clock, we want to write something
gate_clock = 1'b0;
// increment the write counter
if (write_pointer_q == FIFO_DEPTH[ADDR_DEPTH-1:0] - 1)
write_pointer_n = '0;
else
write_pointer_n = write_pointer_q + 1;
// increment the overall counter
status_cnt_n = status_cnt_q + 1;
end
if (pop_i && ~empty_o) begin
// read from the queue is a default assignment
// but increment the read pointer...
if (read_pointer_n == FIFO_DEPTH[ADDR_DEPTH-1:0] - 1)
read_pointer_n = '0;
else
read_pointer_n = read_pointer_q + 1;
// ... and decrement the overall count
status_cnt_n = status_cnt_q - 1;
end
// keep the count pointer stable if we push and pop at the same time
if (push_i && pop_i && ~full_o && ~empty_o)
status_cnt_n = status_cnt_q;
// FIFO is in pass through mode -> do not change the pointers
if (FALL_THROUGH && (status_cnt_q == 0) && push_i && pop_i) begin
data_o = data_i;
status_cnt_n = status_cnt_q;
read_pointer_n = read_pointer_q;
write_pointer_n = write_pointer_q;
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
read_pointer_q <= '0;
write_pointer_q <= '0;
status_cnt_q <= '0;
end else begin
if (flush_i) begin
read_pointer_q <= '0;
write_pointer_q <= '0;
status_cnt_q <= '0;
end else begin
read_pointer_q <= read_pointer_n;
write_pointer_q <= write_pointer_n;
status_cnt_q <= status_cnt_n;
end
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
mem_q <= '0;
end else if (!gate_clock) begin
mem_q <= mem_n;
end
end
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (DEPTH > 0) else $error("DEPTH must be greater than 0.");
end
full_write : assert property(
@(posedge clk_i) disable iff (~rst_ni) (full_o |-> ~push_i))
else $fatal (1, "Trying to push new data although the FIFO is full.");
empty_read : assert property(
@(posedge clk_i) disable iff (~rst_ni) (empty_o |-> ~pop_i))
else $fatal (1, "Trying to pop data although the FIFO is empty.");
`endif
// pragma translate_on
endmodule // fifo_v3
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 15.04.2017
// Description: Description: Instruction decode, contains the logic for decode,
// issue and read operands.
import ariane_pkg::*;
module id_stage (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i,
// from IF
input frontend_fetch_t fetch_entry_i,
input logic fetch_entry_valid_i,
output logic decoded_instr_ack_o, // acknowledge the instruction (fetch entry)
// to ID
output scoreboard_entry_t issue_entry_o, // a decoded instruction
output logic issue_entry_valid_o, // issue entry is valid
output logic is_ctrl_flow_o, // the instruction we issue is a ctrl flow instructions
input logic issue_instr_ack_i, // issue stage acknowledged sampling of instructions
// from CSR file
input riscv::priv_lvl_t priv_lvl_i, // current privilege level
input riscv::xs_t fs_i, // floating point extension status
input logic [2:0] frm_i, // floating-point dynamic rounding mode
input logic debug_mode_i, // we are in debug mode
input logic tvm_i,
input logic tw_i,
input logic tsr_i
);
// register stage
struct packed {
logic valid;
scoreboard_entry_t sbe;
logic is_ctrl_flow;
} issue_n, issue_q;
logic is_control_flow_instr;
scoreboard_entry_t decoded_instruction;
fetch_entry_t fetch_entry;
logic is_illegal;
logic [31:0] instruction;
logic is_compressed;
logic fetch_ack_i;
logic fetch_entry_valid;
// ---------------------------------------------------------
// 1. Re-align instructions
// ---------------------------------------------------------
instr_realigner instr_realigner_i (
.fetch_entry_i ( fetch_entry_i ),
.fetch_entry_valid_i ( fetch_entry_valid_i ),
.fetch_ack_o ( decoded_instr_ack_o ),
.fetch_entry_o ( fetch_entry ),
.fetch_entry_valid_o ( fetch_entry_valid ),
.fetch_ack_i ( fetch_ack_i ),
.*
);
// ---------------------------------------------------------
// 2. Check if they are compressed and expand in case they are
// ---------------------------------------------------------
compressed_decoder compressed_decoder_i (
.instr_i ( fetch_entry.instruction ),
.instr_o ( instruction ),
.illegal_instr_o ( is_illegal ),
.is_compressed_o ( is_compressed )
);
// ---------------------------------------------------------
// 3. Decode and emit instruction to issue stage
// ---------------------------------------------------------
decoder decoder_i (
.pc_i ( fetch_entry.address ),
.is_compressed_i ( is_compressed ),
.compressed_instr_i ( fetch_entry.instruction[15:0] ),
.instruction_i ( instruction ),
.branch_predict_i ( fetch_entry.branch_predict ),
.is_illegal_i ( is_illegal ),
.ex_i ( fetch_entry.ex ),
.instruction_o ( decoded_instruction ),
.is_control_flow_instr_o ( is_control_flow_instr ),
.fs_i,
.frm_i,
.*
);
// ------------------
// Pipeline Register
// ------------------
assign issue_entry_o = issue_q.sbe;
assign issue_entry_valid_o = issue_q.valid;
assign is_ctrl_flow_o = issue_q.is_ctrl_flow;
always_comb begin
issue_n = issue_q;
fetch_ack_i = 1'b0;
// Clear the valid flag if issue has acknowledged the instruction
if (issue_instr_ack_i)
issue_n.valid = 1'b0;
// if we have a space in the register and the fetch is valid, go get it
// or the issue stage is currently acknowledging an instruction, which means that we will have space
// for a new instruction
if ((!issue_q.valid || issue_instr_ack_i) && fetch_entry_valid) begin
fetch_ack_i = 1'b1;
issue_n = {1'b1, decoded_instruction, is_control_flow_instr};
end
// invalidate the pipeline register on a flush
if (flush_i)
issue_n.valid = 1'b0;
end
// -------------------------
// Registers (ID <-> Issue)
// -------------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
issue_q <= '0;
end else begin
issue_q <= issue_n;
end
end
endmodule
//Copyright (C) 2018 to present,
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 2.0 (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-2.0. 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.
// Author: Florian Zaruba, ETH Zurich
// Date: 08.02.2018
// Migrated: Luis Vitorio Cargnini, IEEE
// Date: 09.06.2018
// ------------------------------
// Instruction Scanner
// ------------------------------
module instr_scan (
input logic [31:0] instr_i, // expect aligned instruction, compressed or not
output logic is_rvc_o,
output logic rvi_return_o,
output logic rvi_call_o,
output logic rvi_branch_o,
output logic rvi_jalr_o,
output logic rvi_jump_o,
output logic [63:0] rvi_imm_o,
output logic rvc_branch_o,
output logic rvc_jump_o,
output logic rvc_jr_o,
output logic rvc_return_o,
output logic rvc_jalr_o,
output logic rvc_call_o,
output logic [63:0] rvc_imm_o
);
assign is_rvc_o = (instr_i[1:0] != 2'b11);
// check that rs1 is either x1 or x5 and that rs1 is not x1 or x5, TODO: check the fact about bit 7
assign rvi_return_o = rvi_jalr_o & ~instr_i[7] & ~instr_i[19] & ~instr_i[18] & ~instr_i[16] & instr_i[15];
assign rvi_call_o = (rvi_jalr_o | rvi_jump_o) & instr_i[7]; // TODO: check that this captures calls
// differentiates between JAL and BRANCH opcode, JALR comes from BHT
assign rvi_imm_o = (instr_i[3]) ? ariane_pkg::uj_imm(instr_i) : ariane_pkg::sb_imm(instr_i);
assign rvi_branch_o = (instr_i[6:0] == riscv::OpcodeBranch) ? 1'b1 : 1'b0;
assign rvi_jalr_o = (instr_i[6:0] == riscv::OpcodeJalr) ? 1'b1 : 1'b0;
assign rvi_jump_o = (instr_i[6:0] == riscv::OpcodeJal) ? 1'b1 : 1'b0;
// opcode JAL
assign rvc_jump_o = (instr_i[15:13] == riscv::OpcodeC1J) & is_rvc_o & (instr_i[1:0] == riscv::OpcodeC1);
// always links to register 0
assign rvc_jr_o = (instr_i[15:13] == riscv::OpcodeC2JalrMvAdd)
& ~instr_i[12]
& (instr_i[6:2] == 5'b00000)
& (instr_i[1:0] == riscv::OpcodeC2)
& is_rvc_o;
assign rvc_branch_o = ((instr_i[15:13] == riscv::OpcodeC1Beqz) | (instr_i[15:13] == riscv::OpcodeC1Bnez))
& (instr_i[1:0] == riscv::OpcodeC1)
& is_rvc_o;
// check that rs1 is x1 or x5
assign rvc_return_o = ~instr_i[11] & ~instr_i[10] & ~instr_i[8] & instr_i[7] & rvc_jr_o ;
// always links to register 1 e.g.: it is a jump
assign rvc_jalr_o = (instr_i[15:13] == riscv::OpcodeC2JalrMvAdd)
& instr_i[12]
& (instr_i[6:2] == 5'b00000) & is_rvc_o;
assign rvc_call_o = rvc_jalr_o;
// // differentiates between JAL and BRANCH opcode, JALR comes from BHT
assign rvc_imm_o = (instr_i[14]) ? {{56{instr_i[12]}}, instr_i[6:5], instr_i[2], instr_i[11:10], instr_i[4:3], 1'b0}
: {{53{instr_i[12]}}, instr_i[8], instr_i[10:9], instr_i[6], instr_i[7], instr_i[2], instr_i[11], instr_i[5:3], 1'b0};
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Interface
import ariane_pkg::*;
`ifndef INSTR_TRACER_IF_SV
`define INSTR_TRACER_IF_SV
interface instruction_tracer_if (
input clk
);
logic rstn;
logic flush_unissued;
logic flush;
// Decode
logic [31:0] instruction;
logic fetch_valid;
logic fetch_ack;
// Issue stage
logic issue_ack; // issue acknowledged
scoreboard_entry_t issue_sbe; // issue scoreboard entry
// WB stage
logic [1:0][4:0] waddr;
logic [1:0][63:0] wdata;
logic [1:0] we_gpr;
logic [1:0] we_fpr;
// commit stage
scoreboard_entry_t [1:0] commit_instr; // commit instruction
logic [1:0] commit_ack;
// address translation
// stores
logic st_valid;
logic [63:0] st_paddr;
// loads
logic ld_valid;
logic ld_kill;
logic [63:0] ld_paddr;
// misprediction
branchpredict_t resolve_branch;
// exceptions
exception_t exception;
// current privilege level
riscv::priv_lvl_t priv_lvl;
logic debug_mode;
// the tracer just has a passive interface we do not drive anything with it
//pragma translate_off
clocking pck @(posedge clk);
input rstn, flush_unissued, flush, instruction, fetch_valid, fetch_ack, issue_ack, issue_sbe, waddr,
st_valid, st_paddr, ld_valid, ld_kill, ld_paddr, resolve_branch,
wdata, we_gpr, we_fpr, commit_instr, commit_ack, exception, priv_lvl, debug_mode;
endclocking
//pragma translate_on
endinterface
`endif
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 16.05.2017
// Description: Instruction Tracer Package
package instruction_tracer_pkg;
import ariane_pkg::*;
//pragma translate_off
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "instruction_tracer_defines.svh"
`include "instruction_trace_item.svh"
`include "exception_trace_item.svh"
`include "instruction_tracer.svh"
//pragma translate_on
endpackage
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 21.05.2017
// Description: Issue stage dispatches instructions to the FUs and keeps track of them
// in a scoreboard like data-structure.
import ariane_pkg::*;
module issue_stage #(
parameter int unsigned NR_ENTRIES = 8,
parameter int unsigned NR_WB_PORTS = 4,
parameter int unsigned NR_COMMIT_PORTS = 2
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
output logic sb_full_o,
input logic flush_unissued_instr_i,
input logic flush_i,
// from ISSUE
input scoreboard_entry_t decoded_instr_i,
input logic decoded_instr_valid_i,
input logic is_ctrl_flow_i,
output logic decoded_instr_ack_o,
// to EX
output fu_data_t fu_data_o,
output logic [63:0] pc_o,
output logic is_compressed_instr_o,
input logic flu_ready_i,
output logic alu_valid_o,
// ex just resolved our predicted branch, we are ready to accept new requests
input logic resolve_branch_i,
input logic lsu_ready_i,
output logic lsu_valid_o,
// branch prediction
output logic branch_valid_o, // use branch prediction unit
output branchpredict_sbe_t branch_predict_o, // Branch predict Out
output logic mult_valid_o,
input logic fpu_ready_i,
output logic fpu_valid_o,
output logic [1:0] fpu_fmt_o, // FP fmt field from instr.
output logic [2:0] fpu_rm_o, // FP rm field from instr.
output logic csr_valid_o,
// write back port
input logic [NR_WB_PORTS-1:0][TRANS_ID_BITS-1:0] trans_id_i,
input branchpredict_t resolved_branch_i,
input logic [NR_WB_PORTS-1:0][63:0] wbdata_i,
input exception_t [NR_WB_PORTS-1:0] ex_ex_i, // exception from execute stage
input logic [NR_WB_PORTS-1:0] wb_valid_i,
// commit port
input logic [NR_COMMIT_PORTS-1:0][4:0] waddr_i,
input logic [NR_COMMIT_PORTS-1:0][63:0] wdata_i,
input logic [NR_COMMIT_PORTS-1:0] we_gpr_i,
input logic [NR_COMMIT_PORTS-1:0] we_fpr_i,
output scoreboard_entry_t [NR_COMMIT_PORTS-1:0] commit_instr_o,
input logic [NR_COMMIT_PORTS-1:0] commit_ack_i
);
// ---------------------------------------------------
// Scoreboard (SB) <-> Issue and Read Operands (IRO)
// ---------------------------------------------------
fu_t [2**REG_ADDR_SIZE:0] rd_clobber_gpr_sb_iro;
fu_t [2**REG_ADDR_SIZE:0] rd_clobber_fpr_sb_iro;
logic [REG_ADDR_SIZE-1:0] rs1_iro_sb;
logic [63:0] rs1_sb_iro;
logic rs1_valid_sb_iro;
logic [REG_ADDR_SIZE-1:0] rs2_iro_sb;
logic [63:0] rs2_sb_iro;
logic rs2_valid_iro_sb;
logic [REG_ADDR_SIZE-1:0] rs3_iro_sb;
logic [FLEN-1:0] rs3_sb_iro;
logic rs3_valid_iro_sb;
scoreboard_entry_t issue_instr_rename_sb;
logic issue_instr_valid_rename_sb;
logic issue_ack_sb_rename;
scoreboard_entry_t issue_instr_sb_iro;
logic issue_instr_valid_sb_iro;
logic issue_ack_iro_sb;
// ---------------------------------------------------------
// 1. Re-name
// ---------------------------------------------------------
re_name i_re_name (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.flush_i ( flush_i ),
.flush_unissied_instr_i ( flush_unissued_instr_i ),
.issue_instr_i ( decoded_instr_i ),
.issue_instr_valid_i ( decoded_instr_valid_i ),
.issue_ack_o ( decoded_instr_ack_o ),
.issue_instr_o ( issue_instr_rename_sb ),
.issue_instr_valid_o ( issue_instr_valid_rename_sb ),
.issue_ack_i ( issue_ack_sb_rename )
);
// ---------------------------------------------------------
// 2. Manage instructions in a scoreboard
// ---------------------------------------------------------
scoreboard #(
.NR_ENTRIES (NR_ENTRIES ),
.NR_WB_PORTS(NR_WB_PORTS)
) i_scoreboard (
.sb_full_o ( sb_full_o ),
.unresolved_branch_i ( 1'b0 ),
.rd_clobber_gpr_o ( rd_clobber_gpr_sb_iro ),
.rd_clobber_fpr_o ( rd_clobber_fpr_sb_iro ),
.rs1_i ( rs1_iro_sb ),
.rs1_o ( rs1_sb_iro ),
.rs1_valid_o ( rs1_valid_sb_iro ),
.rs2_i ( rs2_iro_sb ),
.rs2_o ( rs2_sb_iro ),
.rs2_valid_o ( rs2_valid_iro_sb ),
.rs3_i ( rs3_iro_sb ),
.rs3_o ( rs3_sb_iro ),
.rs3_valid_o ( rs3_valid_iro_sb ),
.decoded_instr_i ( issue_instr_rename_sb ),
.decoded_instr_valid_i ( issue_instr_valid_rename_sb ),
.decoded_instr_ack_o ( issue_ack_sb_rename ),
.issue_instr_o ( issue_instr_sb_iro ),
.issue_instr_valid_o ( issue_instr_valid_sb_iro ),
.issue_ack_i ( issue_ack_iro_sb ),
.resolved_branch_i ( resolved_branch_i ),
.trans_id_i ( trans_id_i ),
.wbdata_i ( wbdata_i ),
.ex_i ( ex_ex_i ),
.*
);
// ---------------------------------------------------------
// 3. Issue instruction and read operand, also commit
// ---------------------------------------------------------
issue_read_operands i_issue_read_operands (
.flush_i ( flush_unissued_instr_i ),
.issue_instr_i ( issue_instr_sb_iro ),
.issue_instr_valid_i ( issue_instr_valid_sb_iro ),
.issue_ack_o ( issue_ack_iro_sb ),
.fu_data_o ( fu_data_o ),
.flu_ready_i ( flu_ready_i ),
.rs1_o ( rs1_iro_sb ),
.rs1_i ( rs1_sb_iro ),
.rs1_valid_i ( rs1_valid_sb_iro ),
.rs2_o ( rs2_iro_sb ),
.rs2_i ( rs2_sb_iro ),
.rs2_valid_i ( rs2_valid_iro_sb ),
.rs3_o ( rs3_iro_sb ),
.rs3_i ( rs3_sb_iro ),
.rs3_valid_i ( rs3_valid_iro_sb ),
.rd_clobber_gpr_i ( rd_clobber_gpr_sb_iro ),
.rd_clobber_fpr_i ( rd_clobber_fpr_sb_iro ),
.alu_valid_o ( alu_valid_o ),
.branch_valid_o ( branch_valid_o ),
.csr_valid_o ( csr_valid_o ),
.mult_valid_o ( mult_valid_o ),
.*
);
endmodule
// 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.
// Author: Igor Loi - University of Bologna
// Author: Florian Zaruba, ETH Zurich
// Date: 12.11.2017
// Description: 8-bit LFSR
// --------------
// 8-bit LFSR
// --------------
//
// Description: Shift register
//
module lfsr_8bit #(
parameter logic [7:0] SEED = 8'b0,
parameter int unsigned WIDTH = 8
)(
input logic clk_i,
input logic rst_ni,
input logic en_i,
output logic [WIDTH-1:0] refill_way_oh,
output logic [$clog2(WIDTH)-1:0] refill_way_bin
);
localparam int unsigned LOG_WIDTH = $clog2(WIDTH);
logic [7:0] shift_d, shift_q;
always_comb begin
automatic logic shift_in;
shift_in = !(shift_q[7] ^ shift_q[3] ^ shift_q[2] ^ shift_q[1]);
shift_d = shift_q;
if (en_i)
shift_d = {shift_q[6:0], shift_in};
// output assignment
refill_way_oh = 'b0;
refill_way_oh[shift_q[LOG_WIDTH-1:0]] = 1'b1;
refill_way_bin = shift_q;
end
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
if(~rst_ni) begin
shift_q <= SEED;
end else begin
shift_q <= shift_d;
end
end
//pragma translate_off
initial begin
assert (WIDTH <= 8) else $fatal(1, "WIDTH needs to be less than 8 because of the 8-bit LFSR");
end
//pragma translate_on
endmodule
import ariane_pkg::*;
module mult (
input logic clk_i,
input logic rst_ni,
input logic flush_i,
input fu_data_t fu_data_i,
input logic mult_valid_i,
output logic [63:0] result_o,
output logic mult_valid_o,
output logic mult_ready_o,
output logic [TRANS_ID_BITS-1:0] mult_trans_id_o
);
logic mul_valid;
logic div_valid;
logic div_ready_i; // receiver of division result is able to accept the result
logic [TRANS_ID_BITS-1:0] mul_trans_id;
logic [TRANS_ID_BITS-1:0] div_trans_id;
logic [63:0] mul_result;
logic [63:0] div_result;
logic div_valid_op;
logic mul_valid_op;
// Input Arbitration
assign mul_valid_op = ~flush_i && mult_valid_i && (fu_data_i.operator inside { MUL, MULH, MULHU, MULHSU, MULW });
assign div_valid_op = ~flush_i && mult_valid_i && (fu_data_i.operator inside { DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW });
// ---------------------
// Output Arbitration
// ---------------------
// we give precedence to multiplication as the divider supports stalling and the multiplier is
// just a dumb pipelined multiplier
assign div_ready_i = (mul_valid) ? 1'b0 : 1'b1;
assign mult_trans_id_o = (mul_valid) ? mul_trans_id : div_trans_id;
assign result_o = (mul_valid) ? mul_result : div_result;
assign mult_valid_o = div_valid | mul_valid;
// mult_ready_o = division as the multiplication will unconditionally be ready to accept new requests
// ---------------------
// Multiplication
// ---------------------
multiplier i_multiplier (
.clk_i,
.rst_ni,
.trans_id_i ( fu_data_i.trans_id ),
.operator_i ( fu_data_i.operator ),
.operand_a_i ( fu_data_i.operand_a ),
.operand_b_i ( fu_data_i.operand_b ),
.result_o ( mul_result ),
.mult_valid_i ( mul_valid_op ),
.mult_valid_o ( mul_valid ),
.mult_trans_id_o ( mul_trans_id ),
.mult_ready_o ( ) // this unit is unconditionally ready
);
// ---------------------
// Division
// ---------------------
logic [63:0] operand_b, operand_a; // input operands after input MUX (input silencing, word operations or full inputs)
logic [63:0] result; // result before result mux
logic div_signed; // signed or unsigned division
logic rem; // is it a reminder (or not a reminder e.g.: a division)
logic word_op_d, word_op_q; // save whether the operation was signed or not
// is this a signed op?
assign div_signed = fu_data_i.operator inside {DIV, DIVW, REM, REMW};
// is this a modulo?
assign rem = fu_data_i.operator inside {REM, REMU, REMW, REMUW};
// prepare the input operands and control divider
always_comb begin
// silence the inputs
operand_a = '0;
operand_b = '0;
// control signals
word_op_d = word_op_q;
// we've go a new division operation
if (mult_valid_i && fu_data_i.operator inside {DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW}) begin
// is this a word operation?
if (fu_data_i.operator inside {DIVW, DIVUW, REMW, REMUW}) begin
// yes so check if we should sign extend this is only done for a signed operation
if (div_signed) begin
operand_a = sext32(fu_data_i.operand_a[31:0]);
operand_b = sext32(fu_data_i.operand_b[31:0]);
end else begin
operand_a = fu_data_i.operand_a[31:0];
operand_b = fu_data_i.operand_b[31:0];
end
// save whether we want sign extend the result or not, this is done for all word operations
word_op_d = 1'b1;
end else begin
// regular op
operand_a = fu_data_i.operand_a;
operand_b = fu_data_i.operand_b;
word_op_d = 1'b0;
end
end
end
// ---------------------
// Serial Divider
// ---------------------
serdiv #(
.WIDTH ( 64 )
) i_div (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.id_i ( fu_data_i.trans_id ),
.op_a_i ( operand_a ),
.op_b_i ( operand_b ),
.opcode_i ( {rem, div_signed} ), // 00: udiv, 10: urem, 01: div, 11: rem
.in_vld_i ( div_valid_op ),
.in_rdy_o ( mult_ready_o ),
.flush_i ( flush_i ),
.out_vld_o ( div_valid ),
.out_rdy_i ( div_ready_i ),
.id_o ( div_trans_id ),
.res_o ( result )
);
// Result multiplexer
// if it was a signed word operation the bit will be set and the result will be sign extended accordingly
assign div_result = (word_op_q) ? sext32(result) : result;
// ---------------------
// Registers
// ---------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if(~rst_ni) begin
word_op_q <= '0;
end else begin
word_op_q <= word_op_d;
end
end
endmodule
// 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.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
//
// Description: Multiplication Unit with one pipeline register
// This unit relies on retiming features of the synthesizer
//
import ariane_pkg::*;
module multiplier (
input logic clk_i,
input logic rst_ni,
input logic [TRANS_ID_BITS-1:0] trans_id_i,
input logic mult_valid_i,
input fu_op operator_i,
input logic [63:0] operand_a_i,
input logic [63:0] operand_b_i,
output logic [63:0] result_o,
output logic mult_valid_o,
output logic mult_ready_o,
output logic [TRANS_ID_BITS-1:0] mult_trans_id_o
);
// Pipeline register
logic [TRANS_ID_BITS-1:0] trans_id_q;
logic mult_valid_q;
fu_op operator_d, operator_q;
logic [127:0] mult_result_d, mult_result_q;
// control registers
logic sign_a, sign_b;
logic mult_valid;
// control signals
assign mult_valid_o = mult_valid_q;
assign mult_trans_id_o = trans_id_q;
assign mult_ready_o = 1'b1;
assign mult_valid = mult_valid_i && (operator_i inside {MUL, MULH, MULHU, MULHSU, MULW});
// datapath
logic [127:0] mult_result;
assign mult_result = $signed({operand_a_i[63] & sign_a, operand_a_i}) * $signed({operand_b_i[63] & sign_b, operand_b_i});
// Sign Select MUX
always_comb begin
sign_a = 1'b0;
sign_b = 1'b0;
// signed multiplication
if (operator_i == MULH) begin
sign_a = 1'b1;
sign_b = 1'b1;
// signed - unsigned multiplication
end else if (operator_i == MULHSU) begin
sign_a = 1'b1;
// unsigned multiplication
end else begin
sign_a = 1'b0;
sign_b = 1'b0;
end
end
// single stage version
assign mult_result_d = $signed({operand_a_i[63] & sign_a, operand_a_i}) *
$signed({operand_b_i[63] & sign_b, operand_b_i});
assign operator_d = operator_i;
always_comb begin : p_selmux
unique case (operator_q)
MULH, MULHU, MULHSU: result_o = mult_result_q[127:64];
MULW: result_o = sext32(mult_result_q[31:0]);
// MUL performs an XLEN-bit×XLEN-bit multiplication and places the lower XLEN bits in the destination register
default: result_o = mult_result_q[63:0];// including MUL
endcase
end
// -----------------------
// Output pipeline register
// -----------------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
mult_valid_q <= '0;
trans_id_q <= '0;
operator_q <= MUL;
mult_result_q <= '0;
end else begin
// Input silencing
trans_id_q <= trans_id_i;
// Output Register
mult_valid_q <= mult_valid;
operator_q <= operator_d;
mult_result_q <= mult_result_d;
end
end
endmodule
// 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 06.10.2017
// Description: Performance counters
import ariane_pkg::*;
module perf_counters #(
int unsigned NR_EXTERNAL_COUNTERS = 1
)(
input logic clk_i,
input logic rst_ni,
input logic debug_mode_i, // debug mode
// SRAM like interface
input logic [4:0] addr_i, // read/write address (up to 29 aux counters possible in riscv encoding.h)
input logic we_i, // write enable
input logic [63:0] data_i, // data to write
output logic [63:0] data_o, // data to read
// from commit stage
input scoreboard_entry_t [NR_COMMIT_PORTS-1:0] commit_instr_i, // the instruction we want to commit
input logic [NR_COMMIT_PORTS-1:0] commit_ack_i, // acknowledge that we are indeed committing
// from L1 caches
input logic l1_icache_miss_i,
input logic l1_dcache_miss_i,
// from MMU
input logic itlb_miss_i,
input logic dtlb_miss_i,
// from issue stage
input logic sb_full_i,
// from frontend
input logic if_empty_i,
// from PC Gen
input exception_t ex_i,
input logic eret_i,
input branchpredict_t resolved_branch_i
);
logic [riscv::CSR_IF_EMPTY[4:0] : riscv::CSR_L1_ICACHE_MISS[4:0]][63:0] perf_counter_d, perf_counter_q;
always_comb begin : perf_counters
perf_counter_d = perf_counter_q;
data_o = 'b0;
// don't increment counters in debug mode
if (!debug_mode_i) begin
// ------------------------------
// Update Performance Counters
// ------------------------------
if (l1_icache_miss_i)
perf_counter_d[riscv::CSR_L1_ICACHE_MISS[4:0]] = perf_counter_q[riscv::CSR_L1_ICACHE_MISS[4:0]] + 1'b1;
if (l1_dcache_miss_i)
perf_counter_d[riscv::CSR_L1_DCACHE_MISS[4:0]] = perf_counter_q[riscv::CSR_L1_DCACHE_MISS[4:0]] + 1'b1;
if (itlb_miss_i)
perf_counter_d[riscv::CSR_ITLB_MISS[4:0]] = perf_counter_q[riscv::CSR_ITLB_MISS[4:0]] + 1'b1;
if (dtlb_miss_i)
perf_counter_d[riscv::CSR_DTLB_MISS[4:0]] = perf_counter_q[riscv::CSR_DTLB_MISS[4:0]] + 1'b1;
// instruction related perf counters
for (int unsigned i = 0; i < NR_COMMIT_PORTS-1; i++) begin
if (commit_ack_i[i]) begin
if (commit_instr_i[i].fu == LOAD)
perf_counter_d[riscv::CSR_LOAD[4:0]] = perf_counter_q[riscv::CSR_LOAD[4:0]] + 1'b1;
if (commit_instr_i[i].fu == STORE)
perf_counter_d[riscv::CSR_STORE[4:0]] = perf_counter_q[riscv::CSR_STORE[4:0]] + 1'b1;
if (commit_instr_i[i].fu == CTRL_FLOW)
perf_counter_d[riscv::CSR_BRANCH_JUMP[4:0]] = perf_counter_q[riscv::CSR_BRANCH_JUMP[4:0]] + 1'b1;
// The standard software calling convention uses register x1 to hold the return address on a call
// the unconditional jump is decoded as ADD op
if (commit_instr_i[i].fu == CTRL_FLOW && commit_instr_i[i].op == '0 && commit_instr_i[i].rd == 'b1)
perf_counter_d[riscv::CSR_CALL[4:0]] = perf_counter_q[riscv::CSR_CALL[4:0]] + 1'b1;
// Return from call
if (commit_instr_i[i].op == JALR && commit_instr_i[i].rs1 == 'b1)
perf_counter_d[riscv::CSR_RET[4:0]] = perf_counter_q[riscv::CSR_RET[4:0]] + 1'b1;
end
end
if (ex_i.valid)
perf_counter_d[riscv::CSR_EXCEPTION[4:0]] = perf_counter_q[riscv::CSR_EXCEPTION[4:0]] + 1'b1;
if (eret_i)
perf_counter_d[riscv::CSR_EXCEPTION_RET[4:0]] = perf_counter_q[riscv::CSR_EXCEPTION_RET[4:0]] + 1'b1;
if (resolved_branch_i.valid && resolved_branch_i.is_mispredict)
perf_counter_d[riscv::CSR_MIS_PREDICT[4:0]] = perf_counter_q[riscv::CSR_MIS_PREDICT[4:0]] + 1'b1;
if (sb_full_i) begin
perf_counter_d[riscv::CSR_SB_FULL[4:0]] = perf_counter_q[riscv::CSR_SB_FULL[4:0]] + 1'b1;
end
if (if_empty_i) begin
perf_counter_d[riscv::CSR_IF_EMPTY[4:0]] = perf_counter_q[riscv::CSR_IF_EMPTY[4:0]] + 1'b1;
end
end
// write after read
data_o = perf_counter_q[addr_i];
if (we_i) begin
perf_counter_d[addr_i] = data_i;
end
end
// ----------------
// Registers
// ----------------
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
perf_counter_q <= '0;
end else begin
perf_counter_q <= perf_counter_d;
end
end
endmodule
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment