superscalar: fetch 64 bits (#2013)

This commit is contained in:
Côme 2024-04-08 09:25:39 +00:00 committed by GitHub
parent c6f81d74c4
commit ec44b22920
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 235 additions and 221 deletions

View file

@ -147,7 +147,7 @@ module cva6_icache
// latch this in case we have to stall later on
// make sure this is 32bit aligned
assign vaddr_d = (dreq_o.ready & dreq_i.req) ? dreq_i.vaddr : vaddr_q;
assign areq_o.fetch_vaddr = {vaddr_q[CVA6Cfg.VLEN-1:2], 2'b0};
assign areq_o.fetch_vaddr = (vaddr_q >> CVA6Cfg.FETCH_ALIGN_BITS) << CVA6Cfg.FETCH_ALIGN_BITS;
// split virtual address into index and offset to address cache arrays
assign cl_index = vaddr_d[CVA6Cfg.ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH];
@ -155,7 +155,7 @@ module cva6_icache
if (CVA6Cfg.NOCType == config_pkg::NOC_TYPE_AXI4_ATOP) begin : gen_axi_offset
// if we generate a noncacheable access, the word will be at offset 0 or 4 in the cl coming from memory
assign cl_offset_d = ( dreq_o.ready & dreq_i.req) ? {dreq_i.vaddr[ICACHE_OFFSET_WIDTH-1:2], 2'b0} :
assign cl_offset_d = ( dreq_o.ready & dreq_i.req) ? (dreq_i.vaddr >> CVA6Cfg.FETCH_ALIGN_BITS) << CVA6Cfg.FETCH_ALIGN_BITS :
( paddr_is_nc & mem_data_req_o ) ? {{ICACHE_OFFSET_WIDTH-1{1'b0}}, cl_offset_q[2]}<<2 : // needed since we transfer 32bit over a 64bit AXI bus in this case
cl_offset_q;
// request word address instead of cl address in case of NC access

View file

@ -371,7 +371,9 @@ module frontend
end
// 1. Default assignment
if (if_ready) begin
npc_d = {fetch_address[CVA6Cfg.VLEN-1:2], 2'b0} + 'h4;
npc_d = {
fetch_address[CVA6Cfg.VLEN-1:CVA6Cfg.FETCH_ALIGN_BITS] + 1, {CVA6Cfg.FETCH_ALIGN_BITS{1'b0}}
};
end
// 2. Replay instruction fetch
if (replay) begin

View file

@ -209,8 +209,8 @@ ariane_pkg::FETCH_FIFO_DEPTH
// shift the inputs
for (genvar i = 0; i < CVA6Cfg.INSTR_PER_FETCH; i++) begin : gen_fifo_input_select
/* verilator lint_off WIDTH */
assign instr_data_in[i].instr = instr[i+idx_is_q];
assign instr_data_in[i].cf = cf[i+idx_is_q];
assign instr_data_in[i].instr = instr[CVA6Cfg.INSTR_PER_FETCH+i-idx_is_q];
assign instr_data_in[i].cf = cf[CVA6Cfg.INSTR_PER_FETCH+i-idx_is_q];
assign instr_data_in[i].ex = exception_i; // exceptions hold for the whole fetch packet
assign instr_data_in[i].ex_vaddr = exception_addr_i;
if (CVA6Cfg.RVH) begin : gen_hyp_ex_with_C

View file

@ -171,6 +171,8 @@ package ariane_pkg;
// leave as is (fails with >8 entries and wider fetch width)
localparam int unsigned FETCH_FIFO_DEPTH = 4;
localparam int unsigned SUPERSCALAR = cva6_config_pkg::CVA6ConfigSuperscalarEn;
typedef enum logic [2:0] {
NoCF, // No control flow prediction
Branch, // Branch

View file

@ -128,9 +128,10 @@ package build_config_pkg;
cfg.FETCH_USER_EN = CVA6Cfg.FetchUserEn;
cfg.AXI_USER_EN = CVA6Cfg.DataUserEn | CVA6Cfg.FetchUserEn;
cfg.FETCH_WIDTH = 32;
cfg.INSTR_PER_FETCH = CVA6Cfg.RVC == 1'b1 ? (cfg.FETCH_WIDTH / 16) : 1;
cfg.LOG2_INSTR_PER_FETCH = CVA6Cfg.RVC == 1'b1 ? $clog2(cfg.INSTR_PER_FETCH) : 1;
cfg.FETCH_WIDTH = 32 << ariane_pkg::SUPERSCALAR;
cfg.FETCH_ALIGN_BITS = $clog2(cfg.FETCH_WIDTH / 8);
cfg.INSTR_PER_FETCH = cfg.FETCH_WIDTH / (CVA6Cfg.RVC ? 16 : 32);
cfg.LOG2_INSTR_PER_FETCH = cfg.INSTR_PER_FETCH > 1 ? $clog2(cfg.INSTR_PER_FETCH) : 1;
cfg.ModeW = (CVA6Cfg.XLEN == 32) ? 1 : 4;
cfg.ASIDW = (CVA6Cfg.XLEN == 32) ? 9 : 16;

View file

@ -273,6 +273,7 @@ package config_pkg;
bit AXI_USER_EN;
int unsigned FETCH_WIDTH;
int unsigned FETCH_ALIGN_BITS;
int unsigned INSTR_PER_FETCH;
int unsigned LOG2_INSTR_PER_FETCH;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 1;
localparam CVA6ConfigNrScoreboardEntries = 4;

View file

@ -47,6 +47,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 2;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 1;
localparam CVA6ConfigNrScoreboardEntries = 4;

View file

@ -47,6 +47,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 2;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 1;
localparam CVA6ConfigNrScoreboardEntries = 4;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 2;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 1;
localparam CVA6ConfigNrScoreboardEntries = 4;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;
localparam CVA6ConfigNrLoadBufEntries = 2;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -55,6 +55,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 2;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -48,6 +48,7 @@ package cva6_config_pkg;
localparam CVA6ConfigWtDcacheWbufDepth = 8;
localparam CVA6ConfigSuperscalarEn = 0;
localparam CVA6ConfigNrCommitPorts = 1;
localparam CVA6ConfigNrScoreboardEntries = 8;

View file

@ -11,15 +11,14 @@
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
// Description: Instruction Re-aligner
//
// This module takes 32-bit aligned cache blocks and extracts the instructions.
// As we are supporting the compressed instruction set extension in a 32 bit instruction word
// This module takes cache blocks and extracts the instructions.
// As we are supporting the compressed instruction set extension, in a 32 bit instruction word
// are up to 2 compressed instructions.
// Furthermore those instructions can be arbitrarily interleaved which makes it possible to fetch
// only the lower part of a 32 bit instruction.
// Furthermore we need to handle the case if we want to start fetching from an unaligned
// instruction e.g. a branch.
module instr_realign
import ariane_pkg::*;
#(
@ -47,7 +46,7 @@ module instr_realign
output logic [CVA6Cfg.INSTR_PER_FETCH-1:0][31:0] instr_o
);
// as a maximum we support a fetch width of 64-bit, hence there can be 4 compressed instructions
logic [3:0] instr_is_compressed;
logic [CVA6Cfg.INSTR_PER_FETCH-1:0] instr_is_compressed;
for (genvar i = 0; i < CVA6Cfg.INSTR_PER_FETCH; i++) begin
// LSB != 2'b11
@ -71,8 +70,8 @@ module instr_realign
unaligned_instr_d = data_i[31:16];
valid_o[0] = valid_i;
instr_o[0] = (unaligned_q) ? {data_i[15:0], unaligned_instr_q} : data_i[31:0];
addr_o[0] = (unaligned_q) ? unaligned_address_q : address_i;
instr_o[0] = unaligned_q ? {data_i[15:0], unaligned_instr_q} : data_i[31:0];
addr_o[0] = unaligned_q ? unaligned_address_q : address_i;
valid_o[1] = 1'b0;
instr_o[1] = '0;
@ -113,237 +112,231 @@ module instr_realign
end
end
end
// TODO(zarubaf): Fix 64 bit CVA6Cfg.FETCH_WIDTH, maybe generalize to arbitrary fetch width
end else if (CVA6Cfg.FETCH_WIDTH == 64) begin : realign_bp_64
initial begin
$error("Not propperly implemented");
end
always_comb begin : re_align
unaligned_d = unaligned_q;
unaligned_d = 1'b0;
unaligned_address_d = unaligned_address_q;
unaligned_instr_d = unaligned_instr_q;
unaligned_instr_d = unaligned_instr_q;
valid_o = '0;
valid_o[0] = valid_i;
valid_o = '0;
instr_o[0] = '0;
addr_o[0] = '0;
instr_o[1] = '0;
addr_o[1] = '0;
instr_o[2] = '0;
addr_o[2] = '0;
instr_o[3] = {16'b0, data_i[63:48]};
addr_o[3] = {address_i[riscv::VLEN-1:3], 3'b110};
instr_o[0] = data_i[31:0];
addr_o[0] = address_i;
instr_o[1] = '0;
addr_o[1] = {address_i[CVA6Cfg.VLEN-1:3], 3'b010};
instr_o[2] = {16'b0, data_i[47:32]};
addr_o[2] = {address_i[CVA6Cfg.VLEN-1:3], 3'b100};
instr_o[3] = {16'b0, data_i[63:48]};
addr_o[3] = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
// last instruction was unaligned
if (unaligned_q) begin
instr_o[0] = {data_i[15:0], unaligned_instr_q};
addr_o[0] = unaligned_address_q;
// for 64 bit there exist the following options:
// 64 32 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | I | U | -> again unaligned
// | * | C | I | U | -> aligned
// | * | I | C | U | -> aligned
// | I | C | C | U | -> again unaligned
// | * | C | C | C | U | -> aligned
// Legend: C = compressed, I = 32 bit instruction, U = unaligned upper half
// * = don't care
if (instr_is_compressed[1]) begin
instr_o[1] = {16'b0, data_i[31:16]};
valid_o[1] = valid_i;
if (instr_is_compressed[2]) begin
if (instr_is_compressed[3]) begin
unaligned_d = 1'b0;
valid_o[3] = valid_i;
end else begin
// continues to be unaligned
end
end else begin
unaligned_d = 1'b0;
instr_o[2] = data_i[63:32];
valid_o[2] = valid_i;
end
// instruction 1 is not compressed
end else begin
instr_o[1] = data_i[47:16];
valid_o[1] = valid_i;
addr_o[2] = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
if (instr_is_compressed[2]) begin
unaligned_d = 1'b0;
instr_o[2] = {16'b0, data_i[63:48]};
valid_o[2] = valid_i;
end else begin
// continues to be unaligned
end
end
end else if (instr_is_compressed[0]) begin // instruction zero is RVC
// 64 32 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | I | C | -> again unaligned
// | * | C | I | C | -> aligned
// | * | I | C | C | -> aligned
// | I | C | C | C | -> again unaligned
// | * | C | C | C | C | -> aligned
if (instr_is_compressed[1]) begin
instr_o[1] = {16'b0, data_i[31:16]};
valid_o[1] = valid_i;
if (instr_is_compressed[2]) begin
valid_o[2] = valid_i;
if (instr_is_compressed[3]) begin
valid_o[3] = valid_i;
end else begin
// this instruction is unaligned
unaligned_d = 1'b1;
unaligned_instr_d = data_i[63:48];
unaligned_address_d = addr_o[3];
end
end else begin
instr_o[2] = data_i[63:32];
valid_o[2] = valid_i;
end
// instruction 1 is not compressed -> check slot 3
end else begin
instr_o[1] = data_i[47:16];
valid_o[1] = valid_i;
addr_o[2] = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
if (instr_is_compressed[3]) begin
instr_o[2] = data_i[63:48];
valid_o[2] = valid_i;
end else begin
unaligned_d = 1'b1;
unaligned_instr_d = data_i[63:48];
unaligned_address_d = addr_o[2];
end
end
// Full instruction in slot zero
// 64 32 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | C | I |
// | * | C | C | I |
// | * | I | I |
end else begin
addr_o[1] = {address_i[CVA6Cfg.VLEN-1:3], 3'b100};
if (instr_is_compressed[2]) begin
instr_o[1] = {16'b0, data_i[47:32]};
valid_o[1] = valid_i;
addr_o[2] = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
if (instr_is_compressed[3]) begin
// | * | C | C | I |
valid_o[2] = valid_i;
addr_o[2] = {16'b0, data_i[63:48]};
end else begin
// this instruction is unaligned
unaligned_d = 1'b1;
unaligned_instr_d = data_i[63:48];
unaligned_address_d = addr_o[2];
end
end else begin
// two regular instructions back-to-back
instr_o[1] = data_i[63:32];
valid_o[1] = valid_i;
end
end
// --------------------------
// Unaligned fetch
// --------------------------
// Address was not 64 bit aligned
case (address_i[2:1])
// this means the previouse instruction was either compressed or unaligned
// in any case we don't ccare
2'b01: begin
// 64 32 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | I | x -> again unaligned
// | * | C | I | x -> aligned
// | * | I | C | x -> aligned
// | I | C | C | x -> again unaligned
// | * | C | C | C | x -> aligned
addr_o[0] = {address_i[CVA6Cfg.VLEN-1:3], 3'b010};
2'b00: begin
valid_o[0] = valid_i;
valid_o[1] = valid_i;
if (instr_is_compressed[1]) begin
instr_o[0] = {16'b0, data_i[31:16]};
valid_o[0] = valid_i;
unaligned_d = unaligned_q;
// last instruction was unaligned
// TODO how are jumps + unaligned managed?
if (unaligned_q) begin
// for 64 bit there exist the following options:
// 64 48 32 16 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | I | U | -> again unaligned
// | * | C | I | U | -> aligned
// | * | I | C | U | -> aligned
// | I | C | C | U | -> again unaligned
// | * | C | C | C | U | -> aligned
// Legend: C = compressed, I = 32 bit instruction, U = unaligned upper half
instr_o[0] = {data_i[15:0], unaligned_instr_q};
addr_o[0] = unaligned_address_q;
instr_o[1] = data_i[47:16];
addr_o[1] = {address_i[riscv::VLEN-1:3], 3'b010};
if (instr_is_compressed[1]) begin
instr_o[2] = data_i[63:32];
addr_o[2] = {address_i[riscv::VLEN-1:3], 3'b100};
valid_o[2] = valid_i;
if (instr_is_compressed[2]) begin
if (instr_is_compressed[3]) begin
unaligned_d = 1'b0;
valid_o[3] = valid_i;
end else begin
unaligned_instr_d = instr_o[3];
unaligned_address_d = addr_o[3];
end
end else begin
unaligned_d = 1'b0;
valid_o[2] = valid_i;
end
end else begin
instr_o[2] = instr_o[3];
addr_o[2] = addr_o[3];
if (instr_is_compressed[3]) begin
unaligned_d = 1'b0;
valid_o[2] = valid_i;
end else begin
unaligned_instr_d = instr_o[3];
unaligned_address_d = addr_o[3];
end
end
end else begin
instr_o[0] = data_i[31:0];
addr_o[0] = address_i;
if (instr_is_compressed[0]) begin
instr_o[1] = data_i[47:16];
addr_o[1] = {address_i[riscv::VLEN-1:3], 3'b010};
// 64 48 32 16 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | I | C | -> again unaligned
// | * | C | I | C | -> aligned
// | * | I | C | C | -> aligned
// | I | C | C | C | -> again unaligned
// | * | C | C | C | C | -> aligned
if (instr_is_compressed[1]) begin
instr_o[2] = data_i[63:32];
addr_o[2] = {address_i[riscv::VLEN-1:3], 3'b100};
valid_o[2] = valid_i;
if (instr_is_compressed[2]) begin
if (instr_is_compressed[3]) begin
valid_o[3] = valid_i;
end else begin
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[3];
unaligned_address_d = addr_o[3];
end
end
end else begin
instr_o[2] = instr_o[3];
addr_o[2] = addr_o[3];
if (instr_is_compressed[3]) begin
valid_o[2] = valid_i;
end else begin
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[3];
unaligned_address_d = addr_o[3];
end
end
end else begin
// 64 32 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | C | I |
// | * | C | C | I |
// | * | I | I |
instr_o[1] = data_i[63:32];
addr_o[1] = {address_i[riscv::VLEN-1:3], 3'b100};
instr_o[2] = instr_o[3];
addr_o[2] = addr_o[3];
if (instr_is_compressed[2]) begin
if (instr_is_compressed[3]) begin
valid_o[2] = valid_i;
end else begin
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[3];
unaligned_address_d = addr_o[3];
end
end
end
end
end
// this means the previous instruction was either compressed or unaligned
// in any case we don't care
// TODO input is actually right-shifted so the code below is wrong
2'b01: begin
// 64 48 32 16 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | I | -> again unaligned
// | * | C | I | -> aligned
// | * | I | C | -> aligned
// | I | C | C | -> again unaligned
// | * | C | C | C | -> aligned
// 000 110 100 010 <- unaligned address
instr_o[0] = data_i[31:0];
addr_o[0] = {address_i[riscv::VLEN-1:3], 3'b010};
valid_o[0] = valid_i;
instr_o[2] = data_i[63:32];
addr_o[2] = {address_i[riscv::VLEN-1:3], 3'b110};
if (instr_is_compressed[0]) begin
instr_o[1] = data_i[47:16];
addr_o[1] = {address_i[riscv::VLEN-1:3], 3'b100};
valid_o[1] = valid_i;
if (instr_is_compressed[1]) begin
if (instr_is_compressed[2]) begin
valid_o[2] = valid_i;
end else begin
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[2];
unaligned_address_d = addr_o[2];
end
end
end else begin
instr_o[1] = instr_o[2];
addr_o[1] = addr_o[2];
if (instr_is_compressed[2]) begin
valid_o[1] = valid_i;
instr_o[1] = {16'b0, data_i[47:32]};
addr_o[1] = {address_i[CVA6Cfg.VLEN-1:3], 3'b100};
if (instr_is_compressed[3]) begin
instr_o[2] = {16'b0, data_i[63:48]};
addr_o[2] = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
valid_o[2] = valid_i;
end else begin
// this instruction is unaligned
unaligned_d = 1'b1;
unaligned_instr_d = data_i[63:48];
unaligned_address_d = addr_o[3];
end
end else begin
instr_o[1] = data_i[63:32];
addr_o[1] = {address_i[CVA6Cfg.VLEN-1:3], 3'b100};
valid_o[1] = valid_i;
end
// instruction 1 is not compressed -> check slot 3
end else begin
instr_o[0] = data_i[47:16];
valid_o[0] = valid_i;
addr_o[1] = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
if (instr_is_compressed[3]) begin
instr_o[1] = data_i[63:48];
valid_o[1] = valid_i;
end else begin
unaligned_d = 1'b1;
unaligned_instr_d = data_i[63:48];
unaligned_address_d = addr_o[1];
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[2];
unaligned_address_d = addr_o[2];
end
end
end
2'b10: begin
valid_o = '0;
// 64 32 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | I | C | * | <- unaligned
// | C | C | * | <- aligned
// | I | * | <- aligned
if (instr_is_compressed[2]) begin
valid_o[0] = valid_i;
instr_o[0] = data_i[47:32];
// second instruction is also compressed
if (instr_is_compressed[3]) begin
// 64 48 32 16 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | * | I | C | <- unaligned
// | * | C | C | <- aligned
// | * | I | <- aligned
// 1000 110 100 <- unaligned address
instr_o[0] = data_i[31:0];
addr_o[0] = {address_i[riscv::VLEN-1:3], 3'b100};
valid_o[0] = valid_i;
instr_o[1] = data_i[47:16];
addr_o[1] = {address_i[riscv::VLEN-1:3], 3'b110};
if (instr_is_compressed[0]) begin
if (instr_is_compressed[1]) begin
valid_o[1] = valid_i;
instr_o[1] = data_i[63:48];
// regular instruction -> unaligned
end else begin
unaligned_d = 1'b1;
unaligned_address_d = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
unaligned_instr_d = data_i[63:48];
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[1];
unaligned_address_d = addr_o[1];
end
// instruction is a regular instruction
end else begin
valid_o[0] = valid_i;
instr_o[0] = data_i[63:32];
addr_o[0] = address_i;
end
end
// we started to fetch on a unaligned boundary with a whole instruction -> wait until we've
// received the next instruction
2'b11: begin
valid_o = '0;
if (!instr_is_compressed[3]) begin
unaligned_d = 1'b1;
unaligned_address_d = {address_i[CVA6Cfg.VLEN-1:3], 3'b110};
unaligned_instr_d = data_i[63:48];
// 64 48 32 16 0
// | 3 | 2 | 1 | 0 | <- instruction slot
// | * | I | <- unaligned
// | * | C | <- aligned
// 1000 110 <- unaligned address
instr_o[0] = data_i[31:0];
addr_o[0] = {address_i[riscv::VLEN-1:3], 3'b110};
if (instr_is_compressed[0]) begin
valid_o[0] = valid_i;
end else begin
valid_o[3] = valid_i;
unaligned_d = 1'b1;
unaligned_instr_d = instr_o[0];
unaligned_address_d = addr_o[0];
end
end
endcase