arch-riscv: use sign-extend for all address generation (#1316)
In gem5, we use the same code base for RISC-V 32 and 64. However, if we need to allow modifiable XLEN control on CSR.mstatus in the future, we should follow the RISC-V ISA manual to sign-extend all the register results, including PC and GPR. If this feature implemented, the simulator needs to handle user-mode in RV32 but CSR.SATP sets to Sv39. In this case, 0x80000000 and 0xffffffff80000000 are different addresses in the 64-bit S-Mode perspective, but they are the same in the 32-bit U-Mode perspective. We should avoid this wrong behavior happening before we implement this feature. Thus, we need to sign-extend the results of all the addresses, including the PC and memory addresses, which currently use zero-extend. As specified in the RISC-V ISA manual, we use zero-extend in narrow XLEN mode for the physical address implemented in TLB. Changes based on spec: 1. Sign-extend narrow XLEN: https://github.com/riscv/riscv-isa-manual/blob/riscv-isa-release-b7a445a-2024-07-02/src/machine.adoc?plain=1#L567 2. Zero-extend physical address: https://github.com/riscv/riscv-isa-manual/blob/riscv-isa-release-b7a445a-2024-07-02/src/supervisor.adoc?plain=1#L1670 Signed-off-by: Yangyu Chen <cyy@cyyself.name>
This commit is contained in:
@@ -69,7 +69,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
|
||||
Fp2_bits = Mem;
|
||||
}}, {{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x2: c_lw({{
|
||||
offset = CIMM2<1:1> << 2 |
|
||||
@@ -78,7 +78,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, {{
|
||||
Rp2_sd = Mem_sw;
|
||||
}}, {{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x3: decode RVTYPE {
|
||||
0x0: c_flw({{
|
||||
@@ -97,7 +97,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
freg_t fd = freg(f32(Mem_uw));
|
||||
Fp2_bits = fd.v;
|
||||
}}, {{
|
||||
EA = (uint32_t)(Rp1_uw + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x1: c_ld({{
|
||||
offset = CIMM3 << 3 | CIMM2 << 6;
|
||||
@@ -115,7 +115,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, {{
|
||||
Rp2 = Mem_ub;
|
||||
}}, {{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x1: decode CFUNCT1BIT6 {
|
||||
0x0: c_lhu({{
|
||||
@@ -123,14 +123,14 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, {{
|
||||
Rp2 = Mem_uh;
|
||||
}}, {{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x1: c_lh({{
|
||||
offset = CIMM2<0:0> << 1;
|
||||
}}, {{
|
||||
Rp2_sd = Mem_sh;
|
||||
}}, {{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -140,14 +140,14 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, {{
|
||||
Mem_ub = Rp2_ub;
|
||||
}}, ea_code={{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x3: c_sh({{
|
||||
offset = (CIMM2<0:0> << 1);
|
||||
}}, {{
|
||||
Mem_uh = Rp2_uh;
|
||||
}}, ea_code={{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
|
||||
Mem = Fp2_bits;
|
||||
}}, {{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x6: c_sw({{
|
||||
offset = CIMM2<1:1> << 2 |
|
||||
@@ -171,7 +171,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, {{
|
||||
Mem_uw = Rp2_uw;
|
||||
}}, ea_code={{
|
||||
EA = rvZext(Rp1 + offset);
|
||||
EA = rvSext(Rp1 + offset);
|
||||
}});
|
||||
0x7: decode RVTYPE {
|
||||
0x0: c_fsw({{
|
||||
@@ -186,7 +186,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
|
||||
Mem_uw = unboxF32(boxF32(Fp2_bits));
|
||||
}}, {{
|
||||
EA = (uint32_t)(Rp1_uw + offset);
|
||||
EA = rvSext(Rp1_uw + offset);
|
||||
}});
|
||||
0x1: c_sd({{
|
||||
offset = CIMM3 << 3 | CIMM2 << 6;
|
||||
@@ -213,8 +213,8 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}});
|
||||
0x1: decode RVTYPE {
|
||||
0x0: CJOp::c_jal({{
|
||||
ra_sw = NPC_uw;
|
||||
NPC_uw = PC_uw + imm;
|
||||
ra = rvSext(NPC);
|
||||
NPC = rvSext(PC + imm);
|
||||
}}, IsDirectControl, IsUncondControl, IsCall);
|
||||
0x1: CIOp::c_addiw({{
|
||||
imm = sext<6>(CIMM5 | (CIMM1 << 5));
|
||||
@@ -349,18 +349,18 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}
|
||||
}
|
||||
0x5: CJOp::c_j({{
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
}}, IsDirectControl, IsUncondControl);
|
||||
format CBOp {
|
||||
0x6: c_beqz({{
|
||||
if (rvSext(Rp1) == 0)
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
else
|
||||
NPC = NPC;
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
0x7: c_bnez({{
|
||||
if (rvSext(Rp1) != 0)
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
else
|
||||
NPC = NPC;
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
@@ -396,7 +396,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
|
||||
Fc1_bits = Mem;
|
||||
}}, {{
|
||||
EA = rvZext(sp + offset);
|
||||
EA = rvSext(sp + offset);
|
||||
}});
|
||||
0x2: c_lwsp({{
|
||||
offset = CIMM5<4:2> << 2 |
|
||||
@@ -409,7 +409,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}
|
||||
Rc1_sw = Mem_sw;
|
||||
}}, {{
|
||||
EA = rvZext(sp + offset);
|
||||
EA = rvSext(sp + offset);
|
||||
}});
|
||||
0x3: decode RVTYPE {
|
||||
0x0: c_flwsp({{
|
||||
@@ -429,7 +429,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
fd = freg(f32(Mem_uw));
|
||||
Fc1_bits = fd.v;
|
||||
}}, {{
|
||||
EA = (uint32_t)(sp_uw + offset);
|
||||
EA = rvSext(sp_uw + offset);
|
||||
}});
|
||||
0x1: c_ldsp({{
|
||||
offset = CIMM5<4:3> << 3 |
|
||||
@@ -453,7 +453,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
return std::make_shared<IllegalInstFault>(
|
||||
"source reg x0", machInst);
|
||||
}
|
||||
NPC = rvZext(Rc1 & (~0x1));
|
||||
NPC = rvSext(Rc1 & (~0x1));
|
||||
}}, IsIndirectControl, IsUncondControl);
|
||||
default: CROp::c_mv({{
|
||||
// RC1 == 0 is HINT
|
||||
@@ -470,7 +470,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, IsSerializeAfter, IsNonSpeculative, No_OpClass);
|
||||
default: CJump::c_jalr({{
|
||||
ra = rvSext(NPC);
|
||||
NPC = rvZext(Rc1 & (~0x1));
|
||||
NPC = rvSext(Rc1 & (~0x1));
|
||||
}}, IsIndirectControl, IsUncondControl, IsCall);
|
||||
}
|
||||
default: CompressedROp::c_add({{
|
||||
@@ -491,7 +491,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
|
||||
Mem_ud = Fc2_bits;
|
||||
}}, {{
|
||||
EA = rvZext(sp + offset);
|
||||
EA = rvSext(sp + offset);
|
||||
}});
|
||||
0x6: c_swsp({{
|
||||
offset = CIMM6<5:2> << 2 |
|
||||
@@ -499,7 +499,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
}}, {{
|
||||
Mem_uw = Rc2_uw;
|
||||
}}, {{
|
||||
EA = rvZext(sp + offset);
|
||||
EA = rvSext(sp + offset);
|
||||
}});
|
||||
0x7: decode RVTYPE {
|
||||
0x0: c_fswsp({{
|
||||
@@ -513,7 +513,7 @@ decode QUADRANT default Unknown::unknown() {
|
||||
|
||||
Mem_uw = unboxF32(boxF32(Fc2_bits));
|
||||
}}, {{
|
||||
EA = (uint32_t)(sp_uw + offset);
|
||||
EA = rvSext(sp_uw + offset);
|
||||
}});
|
||||
0x1: c_sdsp({{
|
||||
offset = CIMM6<5:3> << 3 |
|
||||
@@ -4755,44 +4755,44 @@ decode QUADRANT default Unknown::unknown() {
|
||||
format BOp {
|
||||
0x0: beq({{
|
||||
if (rvSext(Rs1) == rvSext(Rs2)) {
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
} else {
|
||||
NPC = rvZext(NPC);
|
||||
NPC = rvSext(NPC);
|
||||
}
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
0x1: bne({{
|
||||
if (rvSext(Rs1) != rvSext(Rs2)) {
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
} else {
|
||||
NPC = rvZext(NPC);
|
||||
NPC = rvSext(NPC);
|
||||
}
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
0x4: blt({{
|
||||
if (rvSext(Rs1_sd) < rvSext(Rs2_sd)) {
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
} else {
|
||||
NPC = rvZext(NPC);
|
||||
NPC = rvSext(NPC);
|
||||
}
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
0x5: bge({{
|
||||
if (rvSext(Rs1_sd) >= rvSext(Rs2_sd)) {
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
} else {
|
||||
NPC = rvZext(NPC);
|
||||
NPC = rvSext(NPC);
|
||||
}
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
0x6: bltu({{
|
||||
if (rvZext(Rs1) < rvZext(Rs2)) {
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
} else {
|
||||
NPC = rvZext(NPC);
|
||||
NPC = rvSext(NPC);
|
||||
}
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
0x7: bgeu({{
|
||||
if (rvZext(Rs1) >= rvZext(Rs2)) {
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
} else {
|
||||
NPC = rvZext(NPC);
|
||||
NPC = rvSext(NPC);
|
||||
}
|
||||
}}, IsDirectControl, IsCondControl);
|
||||
}
|
||||
@@ -4801,13 +4801,13 @@ decode QUADRANT default Unknown::unknown() {
|
||||
0x19: decode FUNCT3 {
|
||||
0x0: Jump::jalr({{
|
||||
Rd = rvSext(NPC);
|
||||
NPC = rvZext((imm + Rs1) & (~0x1));
|
||||
NPC = rvSext((imm + Rs1) & (~0x1));
|
||||
}}, IsIndirectControl, IsUncondControl);
|
||||
}
|
||||
|
||||
0x1b: JOp::jal({{
|
||||
Rd = rvSext(NPC);
|
||||
NPC = rvZext(PC + imm);
|
||||
NPC = rvSext(PC + imm);
|
||||
}}, IsDirectControl, IsUncondControl);
|
||||
|
||||
0x1c: decode FUNCT3 {
|
||||
|
||||
@@ -429,7 +429,7 @@ def template AtomicMemOpRMWCompleteAcc {{
|
||||
// LR/SC/AMO decode formats
|
||||
|
||||
def format LoadReserved(memacc_code, postacc_code={{ }},
|
||||
ea_code={{EA = rvZext(Rs1);}}, mem_flags=[], inst_flags=[]) {{
|
||||
ea_code={{EA = rvSext(Rs1);}}, mem_flags=[], inst_flags=[]) {{
|
||||
macro_ea_code = ''
|
||||
macro_inst_flags = []
|
||||
macro_iop = InstObjParams(name, Name, 'LoadReserved', macro_ea_code,
|
||||
@@ -460,7 +460,7 @@ def format LoadReserved(memacc_code, postacc_code={{ }},
|
||||
}};
|
||||
|
||||
def format StoreCond(memacc_code, postacc_code={{ }},
|
||||
ea_code={{EA = rvZext(Rs1);}}, mem_flags=[], inst_flags=[]) {{
|
||||
ea_code={{EA = rvSext(Rs1);}}, mem_flags=[], inst_flags=[]) {{
|
||||
macro_ea_code = ''
|
||||
macro_inst_flags = []
|
||||
macro_iop = InstObjParams(name, Name, 'StoreCond', macro_ea_code,
|
||||
@@ -491,7 +491,7 @@ def format StoreCond(memacc_code, postacc_code={{ }},
|
||||
}};
|
||||
|
||||
def format AtomicMemOp(memacc_code, amoop_code, postacc_code={{ }},
|
||||
ea_code={{EA = rvZext(Rs1);}}, mem_flags=[], inst_flags=[]) {{
|
||||
ea_code={{EA = rvSext(Rs1);}}, mem_flags=[], inst_flags=[]) {{
|
||||
macro_ea_code = ''
|
||||
macro_inst_flags = []
|
||||
macro_iop = InstObjParams(name, Name, 'AtomicMemOp', macro_ea_code,
|
||||
|
||||
@@ -173,7 +173,7 @@ def template CJumpExecute {{
|
||||
%(class_name)s::branchTarget(ThreadContext *tc) const
|
||||
{
|
||||
PCStateBase *pc_ptr = tc->pcState().clone();
|
||||
pc_ptr->as<PCState>().set(rvZext(tc->getReg(srcRegIdx(0)) & ~0x1));
|
||||
pc_ptr->as<PCState>().set(rvSext(tc->getReg(srcRegIdx(0)) & ~0x1));
|
||||
return std::unique_ptr<PCStateBase>{pc_ptr};
|
||||
}
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ def template CacheBlockBasedStoreCompleteAcc {{
|
||||
}
|
||||
}};
|
||||
|
||||
def format Load(memacc_code, ea_code = {{EA = rvZext(Rs1 + offset);}},
|
||||
def format Load(memacc_code, ea_code={{EA = rvSext(Rs1 + offset);}},
|
||||
offset_code={{offset = sext<12>(IMM12);}},
|
||||
mem_flags=[], inst_flags=[]) {{
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
@@ -309,7 +309,7 @@ def format Load(memacc_code, ea_code = {{EA = rvZext(Rs1 + offset);}},
|
||||
inst_flags, 'Load', exec_template_base='Load')
|
||||
}};
|
||||
|
||||
def format Store(memacc_code, ea_code={{EA = rvZext(Rs1 + offset);}},
|
||||
def format Store(memacc_code, ea_code={{EA = rvSext(Rs1 + offset);}},
|
||||
offset_code={{offset = sext<12>(IMM5 | (IMM7 << 5));}},
|
||||
mem_flags=[], inst_flags=[]) {{
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
@@ -317,7 +317,7 @@ def format Store(memacc_code, ea_code={{EA = rvZext(Rs1 + offset);}},
|
||||
inst_flags, 'Store', exec_template_base='Store')
|
||||
}};
|
||||
|
||||
def format CBMOp(memacc_code, ea_code={{EA = rvZext(Rs1);}},
|
||||
def format CBMOp(memacc_code, ea_code={{EA = rvSext(Rs1);}},
|
||||
offset_code={{;}}, mem_flags=[], inst_flags=[]) {{
|
||||
(header_output, decoder_output, decode_block, exec_output) = \
|
||||
LoadStoreBase(name, Name, offset_code, ea_code, memacc_code, mem_flags,
|
||||
|
||||
@@ -199,7 +199,7 @@ def template BranchExecute {{
|
||||
{
|
||||
auto &rpc = branch_pc.as<RiscvISA::PCState>();
|
||||
std::unique_ptr<PCState> npc(dynamic_cast<PCState*>(rpc.clone()));
|
||||
npc->set(rvZext(rpc.pc() + imm));
|
||||
npc->set(rvSext(rpc.pc() + imm));
|
||||
return npc;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ def template JumpExecute {{
|
||||
{
|
||||
PCStateBase *pc_ptr = tc->pcState().clone();
|
||||
pc_ptr->as<PCState>().set(
|
||||
rvZext((tc->getReg(srcRegIdx(0)) + imm) & ~0x1));
|
||||
rvSext((tc->getReg(srcRegIdx(0)) + imm) & ~0x1));
|
||||
return std::unique_ptr<PCStateBase>{pc_ptr};
|
||||
}
|
||||
|
||||
|
||||
@@ -385,9 +385,16 @@ TLB::translate(const RequestPtr &req, ThreadContext *tc,
|
||||
if (fault == NoFault) {
|
||||
if (req->getFlags() & Request::PHYSICAL) {
|
||||
/**
|
||||
* we simply set the virtual address to physical address
|
||||
* we simply set the virtual address to physical address.
|
||||
*
|
||||
* For RV32, we follow what the specification said:
|
||||
* When mapping between narrower and wider addresses,
|
||||
* RISC-V zero-extends a narrower physical address to a
|
||||
* wider size.
|
||||
*/
|
||||
req->setPaddr(req->getVaddr());
|
||||
req->setPaddr(((ISA*) tc->getIsaPtr())->rvType() == RV32 ?
|
||||
bits(req->getVaddr(), 31, 0) :
|
||||
req->getVaddr());
|
||||
} else {
|
||||
fault = doTranslate(req, tc, translation, mode, delayed);
|
||||
}
|
||||
@@ -418,9 +425,20 @@ TLB::translate(const RequestPtr &req, ThreadContext *tc,
|
||||
|
||||
Process * p = tc->getProcessPtr();
|
||||
|
||||
Fault fault = p->pTable->translate(req);
|
||||
if (fault != NoFault)
|
||||
return fault;
|
||||
/*
|
||||
* In RV32 Linux, as vaddr >= 0x80000000 is legal in userspace
|
||||
* (except for COMPAT mode for RV32 Userspace in RV64 Linux), we
|
||||
* need to ignore the upper bits beyond 32 bits.
|
||||
*/
|
||||
Addr vaddr = ((ISA*) tc->getIsaPtr())->rvType() == RV32 ?
|
||||
bits(req->getVaddr(), 31, 0) :
|
||||
req->getVaddr();
|
||||
Addr paddr;
|
||||
|
||||
if (!p->pTable->translate(vaddr, paddr))
|
||||
return std::make_shared<GenericPageTableFault>(req->getVaddr());
|
||||
|
||||
req->setPaddr(paddr);
|
||||
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user