mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 21:27:10 -04:00
superscalar: fetch 64 bits (#2013)
This commit is contained in:
parent
c6f81d74c4
commit
ec44b22920
22 changed files with 235 additions and 221 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 1;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 4;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 2;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 1;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 4;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 2;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 1;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 4;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 2;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 1;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 4;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
localparam CVA6ConfigNrLoadBufEntries = 2;
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 2;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ package cva6_config_pkg;
|
|||
|
||||
localparam CVA6ConfigWtDcacheWbufDepth = 8;
|
||||
|
||||
localparam CVA6ConfigSuperscalarEn = 0;
|
||||
localparam CVA6ConfigNrCommitPorts = 1;
|
||||
localparam CVA6ConfigNrScoreboardEntries = 8;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue