cva6/core/include/ariane_pkg.sv
2024-05-16 00:24:50 +02:00

798 lines
23 KiB
Systemverilog

/* 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_pkg.sv
* Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
* Date: 8.4.2017
*
* Description: Contains all the necessary defines for Ariane
* in one package.
*/
// this is needed to propagate the
// configuration in case Ariane is
// instantiated in OpenPiton
`ifdef PITON_ARIANE
`include "l15.tmp.h"
`endif
/// This package contains `functions` and global defines for CVA6.
/// *Note*: There are some parameters here as well which will eventually be
/// moved out to favour a fully parameterizable core.
package ariane_pkg;
// TODO: Slowly move those parameters to the new system.
localparam BITS_SATURATION_COUNTER = 2;
localparam ISSUE_WIDTH = 1;
// depth of store-buffers, this needs to be a power of two
localparam logic [2:0] DEPTH_SPEC = 'd4;
// if CVA6Cfg.DCacheType = cva6_config_pkg::WT
// we can use a small commit queue since we have a write buffer in the dcache
// we could in principle do without the commit queue in this case, but the timing degrades if we do that due
// to longer paths into the commit stage
// if CVA6Cfg.DCacheType = cva6_config_pkg::WB
// allocate more space for the commit buffer to be on the save side, this needs to be a power of two
localparam logic [2:0] DEPTH_COMMIT = 'd4;
// Transprecision float unit
localparam int unsigned LAT_COMP_FP32 = 'd2;
localparam int unsigned LAT_COMP_FP64 = 'd3;
localparam int unsigned LAT_COMP_FP16 = 'd1;
localparam int unsigned LAT_COMP_FP16ALT = 'd1;
localparam int unsigned LAT_COMP_FP8 = 'd1;
localparam int unsigned LAT_DIVSQRT = 'd2;
localparam int unsigned LAT_NONCOMP = 'd1;
localparam int unsigned LAT_CONV = 'd2;
localparam logic [31:0] OPENHWGROUP_MVENDORID = 32'h0602;
localparam logic [31:0] ARIANE_MARCHID = 32'd3;
// 32 registers
localparam REG_ADDR_SIZE = 5;
// Read ports for general purpose register files
localparam NR_RGPR_PORTS = 2;
// static debug hartinfo
// 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;
// amount of data count registers implemented
localparam logic [3:0] DataCount = 4'h2;
// 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
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;
localparam hartinfo_t DebugHartInfo = '{
zero1: '0,
nscratch: 2, // Debug module needs at least two scratch regs
zero0: '0,
dataaccess: 1'b1, // data registers are memory mapped in the debugger
datasize: DataCount,
dataaddr: DataAddr
};
// enables a commit log which matches spikes commit log format for easier trace comparison
localparam bit ENABLE_SPIKE_COMMIT_LOG = 1'b1;
// ------------- Dangerous -------------
// if set to zero a flush will not invalidate the cache-lines, in a single core environment
// where coherence is not necessary this can improve performance. This needs to be switched on
// when more than one core is in a system
localparam logic INVALIDATE_ON_FLUSH = 1'b1;
`ifdef SPIKE_TANDEM
// Spike still places 0 in TVAL for ENV_CALL_* exceptions.
// This may eventually go away when Spike starts to handle TVAL for *all* exceptions.
localparam bit ZERO_TVAL = 1'b1;
`else
localparam bit ZERO_TVAL = 1'b0;
`endif
// read mask for SSTATUS over MMSTATUS
function automatic logic [63:0] smode_status_read_mask(config_pkg::cva6_cfg_t Cfg);
return riscv::SSTATUS_UIE
| riscv::SSTATUS_SIE
| riscv::SSTATUS_SPIE
| riscv::SSTATUS_SPP
| riscv::SSTATUS_FS
| riscv::SSTATUS_XS
| riscv::SSTATUS_SUM
| riscv::SSTATUS_MXR
| riscv::SSTATUS_UPIE
| riscv::SSTATUS_SPIE
| riscv::SSTATUS_UXL
| riscv::sstatus_sd(Cfg.IS_XLEN64);
endfunction
localparam logic [63:0] SMODE_STATUS_WRITE_MASK = riscv::SSTATUS_SIE
| riscv::SSTATUS_SPIE
| riscv::SSTATUS_SPP
| riscv::SSTATUS_FS
| riscv::SSTATUS_SUM
| riscv::SSTATUS_MXR;
localparam logic [63:0] HSTATUS_WRITE_MASK = riscv::HSTATUS_VSBE
| riscv::HSTATUS_GVA
| riscv::HSTATUS_SPV
| riscv::HSTATUS_SPVP
| riscv::HSTATUS_HU
| riscv::HSTATUS_VTVM
| riscv::HSTATUS_VTW
| riscv::HSTATUS_VTSR;
// hypervisor delegable interrupts
function automatic logic [31:0] hs_deleg_interrupts(config_pkg::cva6_cfg_t Cfg);
return riscv::MIP_VSSIP | riscv::MIP_VSTIP | riscv::MIP_VSEIP;
endfunction
// virtual supervisor delegable interrupts
function automatic logic [31:0] vs_deleg_interrupts(config_pkg::cva6_cfg_t Cfg);
return riscv::MIP_VSSIP | riscv::MIP_VSTIP | riscv::MIP_VSEIP;
endfunction
// ---------------
// AXI
// ---------------
typedef enum logic {
SINGLE_REQ,
CACHE_LINE_REQ
} ad_req_t;
// ---------------
// Fetch Stage
// ---------------
// 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
Jump, // Jump to address from immediate
JumpR, // Jump to address from registers
Return // Return Address Prediction
} cf_t;
typedef struct packed {
logic valid;
logic taken;
} bht_prediction_t;
typedef struct packed {
logic valid;
logic [1:0] saturation_counter;
} bht_t;
typedef enum logic [3:0] {
NONE, // 0
LOAD, // 1
STORE, // 2
ALU, // 3
CTRL_FLOW, // 4
MULT, // 5
CSR, // 6
FPU, // 7
FPU_VEC, // 8
CVXIF, // 9
ACCEL // 10
} fu_t;
localparam EXC_OFF_RST = 8'h80;
localparam SupervisorIrq = 1;
localparam MachineIrq = 0;
// ---------------
// Cache config
// ---------------
// for usage in OpenPiton we have to propagate the openpiton L15 configuration from l15.h
`ifdef PITON_ARIANE
`ifndef CONFIG_L1I_CACHELINE_WIDTH
`define CONFIG_L1I_CACHELINE_WIDTH 128
`endif
`ifndef CONFIG_L1I_ASSOCIATIVITY
`define CONFIG_L1I_ASSOCIATIVITY 4
`endif
`ifndef CONFIG_L1I_SIZE
`define CONFIG_L1I_SIZE 16*1024
`endif
`ifndef CONFIG_L1D_CACHELINE_WIDTH
`define CONFIG_L1D_CACHELINE_WIDTH 128
`endif
`ifndef CONFIG_L1D_ASSOCIATIVITY
`define CONFIG_L1D_ASSOCIATIVITY 8
`endif
`ifndef CONFIG_L1D_SIZE
`define CONFIG_L1D_SIZE 32*1024
`endif
`ifndef L15_THREADID_WIDTH
`define L15_THREADID_WIDTH 3
`endif
// I$
localparam int unsigned ICACHE_LINE_WIDTH = `CONFIG_L1I_CACHELINE_WIDTH;
localparam int unsigned ICACHE_SET_ASSOC = `CONFIG_L1I_ASSOCIATIVITY;
localparam int unsigned ICACHE_INDEX_WIDTH = $clog2(`CONFIG_L1I_SIZE / ICACHE_SET_ASSOC);
localparam int unsigned ICACHE_TAG_WIDTH = riscv::PLEN - ICACHE_INDEX_WIDTH;
localparam int unsigned ICACHE_USER_LINE_WIDTH = (AXI_USER_WIDTH == 1) ? 4 : 128; // in bit
// D$
localparam int unsigned DCACHE_LINE_WIDTH = `CONFIG_L1D_CACHELINE_WIDTH;
localparam int unsigned DCACHE_SET_ASSOC = `CONFIG_L1D_ASSOCIATIVITY;
localparam int unsigned DCACHE_INDEX_WIDTH = $clog2(`CONFIG_L1D_SIZE / DCACHE_SET_ASSOC);
localparam int unsigned DCACHE_TAG_WIDTH = riscv::PLEN - DCACHE_INDEX_WIDTH;
localparam int unsigned DCACHE_USER_LINE_WIDTH = (AXI_USER_WIDTH == 1) ? 4 : 128; // in bit
localparam int unsigned DCACHE_USER_WIDTH = cva6_config_pkg::CVA6ConfigDataUserWidth;
localparam int unsigned MEM_TID_WIDTH = `L15_THREADID_WIDTH;
`endif
localparam int unsigned WT_DCACHE_WBUF_DEPTH = cva6_config_pkg::CVA6ConfigWtDcacheWbufDepth;
// ---------------
// EX Stage
// ---------------
typedef enum logic [7:0] { // basic ALU op
ADD,
SUB,
ADDW,
SUBW,
// logic operations
XORL,
ORL,
ANDL,
// shifts
SRA,
SRL,
SLL,
SRLW,
SLLW,
SRAW,
// comparisons
LTS,
LTU,
GES,
GEU,
EQ,
NE,
// jumps
JALR,
BRANCH,
// set lower than operations
SLTS,
SLTU,
// CSR functions
MRET,
SRET,
DRET,
ECALL,
WFI,
FENCE,
FENCE_I,
SFENCE_VMA,
HFENCE_VVMA,
HFENCE_GVMA,
CSR_WRITE,
CSR_READ,
CSR_SET,
CSR_CLEAR,
// LSU functions
LD,
SD,
LW,
LWU,
SW,
LH,
LHU,
SH,
LB,
SB,
LBU,
// Hypervisor Virtual-Machine Load and Store Instructions
HLV_B,
HLV_BU,
HLV_H,
HLV_HU,
HLVX_HU,
HLV_W,
HLVX_WU,
HSV_B,
HSV_H,
HSV_W,
HLV_WU,
HLV_D,
HSV_D,
// Atomic Memory Operations
AMO_LRW,
AMO_LRD,
AMO_SCW,
AMO_SCD,
AMO_SWAPW,
AMO_ADDW,
AMO_ANDW,
AMO_ORW,
AMO_XORW,
AMO_MAXW,
AMO_MAXWU,
AMO_MINW,
AMO_MINWU,
AMO_SWAPD,
AMO_ADDD,
AMO_ANDD,
AMO_ORD,
AMO_XORD,
AMO_MAXD,
AMO_MAXDU,
AMO_MIND,
AMO_MINDU,
// Multiplications
MUL,
MULH,
MULHU,
MULHSU,
MULW,
// Divisions
DIV,
DIVU,
DIVW,
DIVUW,
REM,
REMU,
REMW,
REMUW,
// Floating-Point Load and Store Instructions
FLD,
FLW,
FLH,
FLB,
FSD,
FSW,
FSH,
FSB,
// Floating-Point Computational Instructions
FADD,
FSUB,
FMUL,
FDIV,
FMIN_MAX,
FSQRT,
FMADD,
FMSUB,
FNMSUB,
FNMADD,
// Floating-Point Conversion and Move Instructions
FCVT_F2I,
FCVT_I2F,
FCVT_F2F,
FSGNJ,
FMV_F2X,
FMV_X2F,
// Floating-Point Compare Instructions
FCMP,
// Floating-Point Classify Instruction
FCLASS,
// Vectorial Floating-Point Instructions that don't directly map onto the scalar ones
VFMIN,
VFMAX,
VFSGNJ,
VFSGNJN,
VFSGNJX,
VFEQ,
VFNE,
VFLT,
VFGE,
VFLE,
VFGT,
VFCPKAB_S,
VFCPKCD_S,
VFCPKAB_D,
VFCPKCD_D,
// Offload Instructions to be directed into cv_x_if
OFFLOAD,
// Or-Combine and REV8
ORCB,
REV8,
// Bitwise Rotation
ROL,
ROLW,
ROR,
RORI,
RORIW,
RORW,
// Sign and Zero Extend
SEXTB,
SEXTH,
ZEXTH,
// Count population
CPOP,
CPOPW,
// Count Leading/Training Zeros
CLZ,
CLZW,
CTZ,
CTZW,
// Carry less multiplication Op's
CLMUL,
CLMULH,
CLMULR,
// Single bit instructions Op's
BCLR,
BCLRI,
BEXT,
BEXTI,
BINV,
BINVI,
BSET,
BSETI,
// Integer minimum/maximum
MAX,
MAXU,
MIN,
MINU,
// Shift with Add Unsigned Word and Unsigned Word Op's (Bitmanip)
SH1ADDUW,
SH2ADDUW,
SH3ADDUW,
ADDUW,
SLLIUW,
// Shift with Add (Bitmanip)
SH1ADD,
SH2ADD,
SH3ADD,
// Bitmanip Logical with negate op (Bitmanip)
ANDN,
ORN,
XNOR,
// Accelerator operations
ACCEL_OP,
ACCEL_OP_FS1,
ACCEL_OP_FD,
ACCEL_OP_LOAD,
ACCEL_OP_STORE,
// Zicond instruction
CZERO_EQZ,
CZERO_NEZ
} fu_op;
function automatic logic op_is_branch(input fu_op op);
unique case (op) inside
EQ, NE, LTS, GES, LTU, GEU: return 1'b1;
default: return 1'b0; // all other ops
endcase
endfunction
// -------------------------------
// Extract Src/Dst FP Reg from Op
// -------------------------------
// function used in instr_trace svh
// is_rs1_fpr function is kept to allow cva6 compilation with instr_trace feature
function automatic logic is_rs1_fpr(input fu_op op);
unique case (op) inside
[FMUL : FNMADD], // Computational Operations (except ADD/SUB)
FCVT_F2I, // Float-Int Casts
FCVT_F2F, // Float-Float Casts
FSGNJ, // Sign Injections
FMV_F2X, // FPR-GPR Moves
FCMP, // Comparisons
FCLASS, // Classifications
[VFMIN : VFCPKCD_D], // Additional Vectorial FP ops
ACCEL_OP_FS1:
return 1'b1; // Accelerator instructions
default: return 1'b0; // all other ops
endcase
endfunction
// function used in instr_trace svh
// is_rs2_fpr function is kept to allow cva6 compilation with instr_trace feature
function automatic logic is_rs2_fpr(input fu_op op);
unique case (op) inside
[FSD : FSB], // FP Stores
[FADD : FMIN_MAX], // Computational Operations (no sqrt)
[FMADD : FNMADD], // Fused Computational Operations
FCVT_F2F, // Vectorial F2F Conversions requrie target
[FSGNJ : FMV_F2X], // Sign Injections and moves mapped to SGNJ
FCMP, // Comparisons
[VFMIN : VFCPKCD_D]:
return 1'b1; // Additional Vectorial FP ops
default: return 1'b0; // all other ops
endcase
endfunction
// function used in instr_trace svh
// is_imm_fpr function is kept to allow cva6 compilation with instr_trace feature
// ternary operations encode the rs3 address in the imm field, also add/sub
function automatic logic is_imm_fpr(input fu_op op);
unique case (op) inside
[FADD : FSUB], // ADD/SUB need inputs as Operand B/C
[FMADD : FNMADD], // Fused Computational Operations
[VFCPKAB_S : VFCPKCD_D]:
return 1'b1; // Vectorial FP cast and pack ops
default: return 1'b0; // all other ops
endcase
endfunction
// function used in instr_trace svh
// is_rd_fpr function is kept to allow cva6 compilation with instr_trace feature
function automatic logic is_rd_fpr(input fu_op op);
unique case (op) inside
[FLD : FLB], // FP Loads
[FADD : FNMADD], // Computational Operations
FCVT_I2F, // Int-Float Casts
FCVT_F2F, // Float-Float Casts
FSGNJ, // Sign Injections
FMV_X2F, // GPR-FPR Moves
[VFMIN : VFSGNJX], // Vectorial MIN/MAX and SGNJ
[VFCPKAB_S : VFCPKCD_D], // Vectorial FP cast and pack ops
ACCEL_OP_FD:
return 1'b1; // Accelerator instructions
default: return 1'b0; // all other ops
endcase
endfunction
function automatic logic is_amo(fu_op op);
case (op) inside
[AMO_LRW : AMO_MINDU]: begin
return 1'b1;
end
default: return 1'b0;
endcase
endfunction
// -------------------
// Performance counter
// -------------------
localparam int unsigned MHPMCounterNum = 6;
// --------------------
// Atomics
// --------------------
typedef enum logic [3:0] {
AMO_NONE = 4'b0000,
AMO_LR = 4'b0001,
AMO_SC = 4'b0010,
AMO_SWAP = 4'b0011,
AMO_ADD = 4'b0100,
AMO_AND = 4'b0101,
AMO_OR = 4'b0110,
AMO_XOR = 4'b0111,
AMO_MAX = 4'b1000,
AMO_MAXU = 4'b1001,
AMO_MIN = 4'b1010,
AMO_MINU = 4'b1011,
AMO_CAS1 = 4'b1100, // unused, not part of riscv spec, but provided in OpenPiton
AMO_CAS2 = 4'b1101 // unused, not part of riscv spec, but provided in OpenPiton
} amo_t;
// Bits required for representation of physical address space as 4K pages
// (e.g. 27*4K == 39bit address space).
localparam PPN4K_WIDTH = 38;
typedef struct packed {
logic valid; // valid flag
logic is_4M; //
logic [20-1:0] vpn; //VPN (32bits) = 20bits + 12bits offset
logic [9-1:0] asid; //ASID length = 9 for Sv32 mmu
riscv::pte_sv32_t content;
} tlb_update_sv32_t;
typedef enum logic [1:0] {
FE_NONE,
FE_INSTR_ACCESS_FAULT,
FE_INSTR_PAGE_FAULT,
FE_INSTR_GUEST_PAGE_FAULT
} frontend_exception_t;
// AMO request going to cache. this request is unconditionally valid as soon
// as request goes high.
// Furthermore, those signals are kept stable until the response indicates
// completion by asserting ack.
typedef struct packed {
logic req; // this request is valid
amo_t amo_op; // atomic memory operation to perform
logic [1:0] size; // 2'b10 --> word operation, 2'b11 --> double word operation
logic [63:0] operand_a; // address
logic [63:0] operand_b; // data as layouted in the register
} amo_req_t;
// AMO response coming from cache.
typedef struct packed {
logic ack; // response is valid
logic [63:0] result; // sign-extended, result
} amo_resp_t;
localparam RVFI = cva6_config_pkg::CVA6ConfigRvfiTrace;
// ----------------------
// Arithmetic Functions
// ----------------------
function automatic logic [63:0] sext32to64(logic [31:0] operand);
return {{32{operand[31]}}, operand[31:0]};
endfunction
// ----------------------
// LSU Functions
// ----------------------
// generate byte enable mask
function automatic logic [7:0] be_gen(logic [2:0] addr, logic [1:0] size);
case (size)
2'b11: begin
return 8'b1111_1111;
end
2'b10: begin
case (addr[2:0])
3'b000: return 8'b0000_1111;
3'b001: return 8'b0001_1110;
3'b010: return 8'b0011_1100;
3'b011: return 8'b0111_1000;
3'b100: return 8'b1111_0000;
default: ; // Do nothing
endcase
end
2'b01: begin
case (addr[2:0])
3'b000: return 8'b0000_0011;
3'b001: return 8'b0000_0110;
3'b010: return 8'b0000_1100;
3'b011: return 8'b0001_1000;
3'b100: return 8'b0011_0000;
3'b101: return 8'b0110_0000;
3'b110: return 8'b1100_0000;
default: ; // Do nothing
endcase
end
2'b00: begin
case (addr[2:0])
3'b000: return 8'b0000_0001;
3'b001: return 8'b0000_0010;
3'b010: return 8'b0000_0100;
3'b011: return 8'b0000_1000;
3'b100: return 8'b0001_0000;
3'b101: return 8'b0010_0000;
3'b110: return 8'b0100_0000;
3'b111: return 8'b1000_0000;
endcase
end
endcase
return 8'b0;
endfunction
function automatic logic [3:0] be_gen_32(logic [1:0] addr, logic [1:0] size);
case (size)
2'b10: begin
return 4'b1111;
end
2'b01: begin
case (addr[1:0])
2'b00: return 4'b0011;
2'b01: return 4'b0110;
2'b10: return 4'b1100;
default: ; // Do nothing
endcase
end
2'b00: begin
case (addr[1:0])
2'b00: return 4'b0001;
2'b01: return 4'b0010;
2'b10: return 4'b0100;
2'b11: return 4'b1000;
endcase
end
default: return 4'b0;
endcase
return 4'b0;
endfunction
// ----------------------
// Extract Bytes from Op
// ----------------------
function automatic logic [1:0] extract_transfer_size(fu_op op);
case (op)
LD, HLV_D, SD, HSV_D, FLD, FSD,
AMO_LRD, AMO_SCD,
AMO_SWAPD, AMO_ADDD,
AMO_ANDD, AMO_ORD,
AMO_XORD, AMO_MAXD,
AMO_MAXDU, AMO_MIND,
AMO_MINDU: begin
return 2'b11;
end
LW, LWU, HLV_W, HLV_WU, HLVX_WU,
SW, HSV_W, FLW, FSW,
AMO_LRW, AMO_SCW,
AMO_SWAPW, AMO_ADDW,
AMO_ANDW, AMO_ORW,
AMO_XORW, AMO_MAXW,
AMO_MAXWU, AMO_MINW,
AMO_MINWU: begin
return 2'b10;
end
LH, LHU, HLV_H, HLV_HU, HLVX_HU, SH, HSV_H, FLH, FSH: return 2'b01;
LB, LBU, HLV_B, HLV_BU, SB, HSV_B, FLB, FSB: return 2'b00;
default: return 2'b11;
endcase
endfunction
// ----------------------
// MMU Functions
// ----------------------
// checks if final translation page size is 1G when H-extension is enabled
function automatic logic is_trans_1G(input logic s_st_enbl, input logic g_st_enbl,
input logic is_s_1G, input logic is_g_1G);
return (((is_s_1G && s_st_enbl) || !s_st_enbl) && ((is_g_1G && g_st_enbl) || !g_st_enbl));
endfunction : is_trans_1G
// checks if final translation page size is 2M when H-extension is enabled
function automatic logic is_trans_2M(input logic s_st_enbl, input logic g_st_enbl,
input logic is_s_1G, input logic is_s_2M,
input logic is_g_1G, input logic is_g_2M);
return (s_st_enbl && g_st_enbl) ?
((is_s_2M && (is_g_1G || is_g_2M)) || (is_g_2M && (is_s_1G || is_s_2M))) :
((is_s_2M && s_st_enbl) || (is_g_2M && g_st_enbl));
endfunction : is_trans_2M
// computes the paddr based on the page size, ppn and offset
function automatic logic [40:0] make_gpaddr(input logic s_st_enbl, input logic is_1G,
input logic is_2M, input logic [63:0] vaddr,
input riscv::pte_t pte);
logic [40:0] gpaddr;
if (s_st_enbl) begin
gpaddr = {pte.ppn[28:0], vaddr[11:0]};
// Giga page
if (is_1G) gpaddr[29:12] = vaddr[29:12];
// Mega page
if (is_2M) gpaddr[20:12] = vaddr[20:12];
end else begin
gpaddr = vaddr[40:0];
end
return gpaddr;
endfunction : make_gpaddr
// computes the final gppn based on the guest physical address
function automatic logic [28:0] make_gppn(input logic s_st_enbl, input logic is_1G,
input logic is_2M, input logic [28:0] vpn,
input riscv::pte_t pte);
logic [28:0] gppn;
if (s_st_enbl) begin
gppn = pte.ppn[28:0];
if (is_2M) gppn[8:0] = vpn[8:0];
if (is_1G) gppn[17:0] = vpn[17:0];
end else begin
gppn = vpn;
end
return gppn;
endfunction : make_gppn
endpackage