mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-19 03:44:46 -04:00
Add support for Superscalar with ZCMP, ZCMT and CVXIF. ZCMP decoder, ZCMT decoder and CVXIF interface driver are using port 0. Standard RVC and 32 bits instruction can take port 0 or 1.
133 lines
5.3 KiB
Systemverilog
133 lines
5.3 KiB
Systemverilog
// Licensed under the Solderpad Hardware Licence, Version 2.1 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
|
//
|
|
// Author: Farhan Ali Shah, 10xEngineers
|
|
// Date: 15.11.2024
|
|
// Description: ZCMT extension in the CVA6 core targeting the 32-bit embedded-class platforms (CV32A60x).
|
|
// ZCMT is a code-size reduction feature that utilizes compressed table jump instructions (cm.jt and cm.jalt) to
|
|
//reduce code size for embedded systems
|
|
//
|
|
module zcmt_decoder #(
|
|
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
|
parameter type dcache_req_i_t = logic,
|
|
parameter type dcache_req_o_t = logic,
|
|
parameter type jvt_t = logic,
|
|
parameter type branchpredict_sbe_t = logic
|
|
) (
|
|
// Subsystem Clock - SUBSYSTEM
|
|
input logic clk_i,
|
|
// Asynchronous reset active low - SUBSYSTEM
|
|
input logic rst_ni,
|
|
// Instruction input - compressed_decoder
|
|
input logic [ 31:0] instr_i,
|
|
// current PC - FRONTEND
|
|
input logic [CVA6Cfg.VLEN-1:0] pc_i,
|
|
// Intruction is of ZCMT extension - compressed_decoder
|
|
input logic is_zcmt_instr_i,
|
|
// Instruction is illegal - compressed_decoder
|
|
input logic illegal_instr_i,
|
|
// Instruction is compressed - compressed_decoder
|
|
input logic is_compressed_i,
|
|
// JVT struct input - CSR
|
|
input jvt_t jvt_i,
|
|
// Data cache request output - CACHE
|
|
input dcache_req_o_t req_port_i,
|
|
// Instruction out - cvxif_compressed_if_driver
|
|
output logic [ 31:0] instr_o,
|
|
// Instruction is illegal out - cvxif_compressed_if_driver
|
|
output logic illegal_instr_o,
|
|
// Instruction is compressed out - cvxif_compressed_if_driver
|
|
output logic is_compressed_o,
|
|
// Fetch stall - cvxif_compressed_if_driver
|
|
output logic fetch_stall_o,
|
|
// Data cache request input - CACHE
|
|
output dcache_req_i_t req_port_o,
|
|
// jump_address
|
|
output logic [CVA6Cfg.XLEN-1:0] jump_address_o
|
|
);
|
|
|
|
// FSM States
|
|
enum logic {
|
|
IDLE, // if ZCMT instruction then request sent to fetch the entry from jump table
|
|
TABLE_JUMP // Check the valid data from jump table and Calculate the offset for jump and create jal instruction
|
|
}
|
|
state_d, state_q;
|
|
// Temporary registers
|
|
// Physical address: jvt + (index <<2)
|
|
logic [CVA6Cfg.VLEN-1:0] table_address;
|
|
|
|
always_comb begin
|
|
state_d = state_q;
|
|
illegal_instr_o = 1'b0;
|
|
is_compressed_o = is_zcmt_instr_i || is_compressed_i;
|
|
fetch_stall_o = '0;
|
|
jump_address_o = '0;
|
|
|
|
// cache request port
|
|
req_port_o.data_wdata = '0;
|
|
req_port_o.data_wuser = '0;
|
|
req_port_o.data_req = 1'b0;
|
|
req_port_o.data_we = 1'b0;
|
|
req_port_o.data_be = '0;
|
|
req_port_o.data_size = 2'b10;
|
|
req_port_o.data_id = 1'b1;
|
|
req_port_o.kill_req = 1'b0;
|
|
req_port_o.tag_valid = 1'b1;
|
|
|
|
unique case (state_q)
|
|
IDLE: begin
|
|
fetch_stall_o = 1'b0;
|
|
if (is_zcmt_instr_i) begin
|
|
if (CVA6Cfg.XLEN == 32) begin //It is only target for 32 bit targets in cva6 with No MMU
|
|
table_address = {jvt_i.base, 6'b000000} + {24'h0, instr_i[7:2], 2'b00};
|
|
req_port_o.address_index = table_address[9:0];
|
|
req_port_o.address_tag = table_address[CVA6Cfg.VLEN-1:10]; // No MMU support
|
|
state_d = TABLE_JUMP;
|
|
req_port_o.data_req = 1'b1;
|
|
fetch_stall_o = 1'b1;
|
|
end else illegal_instr_o = 1'b1;
|
|
// Condition may be extented for 64 bits embedded targets with No MMU
|
|
end else begin
|
|
illegal_instr_o = illegal_instr_i;
|
|
instr_o = instr_i;
|
|
state_d = IDLE;
|
|
end
|
|
end
|
|
TABLE_JUMP: begin
|
|
if (req_port_i.data_rvalid) begin
|
|
// save the PC relative Xlen table jump address
|
|
jump_address_o = $unsigned($signed(req_port_i.data_rdata) - $signed(pc_i));
|
|
if (instr_i[9:2] < 32) begin // jal pc_offset, x0 for no return stack
|
|
instr_o = {
|
|
20'h0, 5'h0, riscv::OpcodeJal
|
|
}; // immidiate assigned here (0) will be overwrite in decode stage with jump_address_o
|
|
end else if ((instr_i[9:2] >= 32) & (instr_i[9:2] <= 255)) begin //- jal pc_offset, x1 for return stack
|
|
instr_o = {
|
|
20'h0, 5'h1, riscv::OpcodeJal
|
|
}; // immidiate assigned here (0) will be overwrite in decode stage with jump_address_o
|
|
end else begin
|
|
illegal_instr_o = 1'b1;
|
|
instr_o = instr_i;
|
|
end
|
|
state_d = IDLE;
|
|
end else begin
|
|
state_d = TABLE_JUMP;
|
|
end
|
|
end
|
|
default: begin
|
|
state_d = IDLE;
|
|
end
|
|
endcase
|
|
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
|
|
endmodule
|