arch-riscv: Implement Zcmp instructions (#1432)

1. Implement Zcmp(cm.push, cm.pop, cm.popret, cm.popretz, cm.mva01s,
cm.mvsa01) instructions

2. The Zcd instructions overlap the Zcmp and Zcmt instruction. This
option is used to enable/disable Zcd extension, implies enable Zcmp/Zcmt
extension. If Zcd is enable, the Zcmp and Zcmt is disabled. Otherwise,
Zcmp and Zcmt is enabled.

Spec: https://github.com/riscv/riscv-isa-manual/blob/main/src/zc.adoc
This commit is contained in:
Bobby R. Bruce
2024-10-18 05:33:55 -07:00
committed by GitHub
16 changed files with 1096 additions and 54 deletions

View File

@@ -114,6 +114,13 @@ class RiscvISA(BaseISA):
enable_Zicbom_fs = Param.Bool(True, "Enable Zicbom extension in FS mode")
enable_Zicboz_fs = Param.Bool(True, "Enable Zicboz extension in FS mode")
enable_Zcd = Param.Bool(
True,
"Enable Zcd extensions. "
"Set the option to false implies the Zcmp and Zcmt is enable as "
"c.fsdsp is overlap with them."
"Refs: https://github.com/riscv/riscv-isa-manual/blob/main/src/zc.adoc",
)
wfi_resume_on_pending = Param.Bool(
False,

View File

@@ -44,6 +44,7 @@ Decoder::Decoder(const RiscvDecoderParams &p) : InstDecoder(p, &machInst)
ISA *isa = dynamic_cast<ISA*>(p.isa);
vlen = isa->getVecLenInBits();
elen = isa->getVecElemLenInBits();
_enableZcd = isa->enableZcd();
reset();
}
@@ -127,6 +128,7 @@ Decoder::decode(PCStateBase &_next_pc)
emi.vtype8 = next_pc.vtype() & 0xff;
emi.vill = next_pc.vtype().vill;
emi.rv_type = static_cast<int>(next_pc.rvType());
emi.enable_zcd = _enableZcd;
return decode(emi, next_pc.instAddr());
}

View File

@@ -62,6 +62,7 @@ class Decoder : public InstDecoder
uint32_t vlen;
uint32_t elen;
bool _enableZcd;
virtual StaticInstPtr decodeInst(ExtMachInst mach_inst);

View File

@@ -34,3 +34,4 @@ Source('mem.cc', tags='riscv isa')
Source('standard.cc', tags='riscv isa')
Source('static_inst.cc', tags='riscv isa')
Source('vector.cc', tags='riscv isa')
Source('zcmp.cc', tags='riscv isa')

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2024 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "arch/riscv/insts/zcmp.hh"
#include <string>
#include "arch/riscv/regs/int.hh"
#include "arch/riscv/utility.hh"
namespace gem5
{
namespace RiscvISA
{
CmMacroInst::CmMacroInst(
const char* mnem, ExtMachInst machInst, OpClass opClass)
: RiscvMacroInst(mnem, machInst, opClass), rlist(machInst.rlist)
{
}
// Ref: https://github.com/riscv-software-src/riscv-isa-sim/blob/f7d0dba60/
// riscv/decode.h#L168
uint64_t
CmMacroInst::stackAdj() const
{
uint64_t stack_adj_base = 0;
switch (machInst.rlist) {
case 15:
stack_adj_base += 16;
[[fallthrough]];
case 14:
if (machInst.rv_type == RV64) {
stack_adj_base += 16;
}
[[fallthrough]];
case 13:
case 12:
stack_adj_base += 16;
[[fallthrough]];
case 11:
case 10:
if (machInst.rv_type == RV64) {
stack_adj_base += 16;
}
[[fallthrough]];
case 9:
case 8:
stack_adj_base += 16;
[[fallthrough]];
case 7:
case 6:
if (machInst.rv_type == RV64) {
stack_adj_base += 16;
}
[[fallthrough]];
case 5:
case 4:
stack_adj_base += 16;
break;
}
return stack_adj_base + machInst.spimm * 16;
}
std::string
CmMacroInst::getRlistStr() const
{
std::string s = "";
switch (machInst.rlist) {
case 15:
s = csprintf("{%s, %s-%s}", registerName(ReturnAddrReg),
registerName(int_reg::S0),
registerName(PushPopRegList[0]));
break;
case 14:
case 13:
case 12:
case 11:
case 10:
case 9:
case 8:
case 7:
case 6:
s = csprintf("{%s, %s-%s}", registerName(ReturnAddrReg),
registerName(int_reg::S0),
registerName(PushPopRegList[16-machInst.rlist]));
break;
case 5:
s = csprintf("{%s, %s}", registerName(ReturnAddrReg),
registerName(int_reg::S0));
break;
case 4:
s = csprintf("{%s}", registerName(ReturnAddrReg));
break;
default:
break;
}
return s;
}
} // namespace RiscvISA
} // namespace gem5

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2024 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_RISCV_INSTS_ZCMP_HH__
#define __ARCH_RISCV_INSTS_ZCMP_HH__
#include <string>
#include "arch/riscv/insts/static_inst.hh"
#include "cpu/static_inst.hh"
namespace gem5
{
namespace RiscvISA
{
class CmMacroInst : public RiscvMacroInst
{
public:
CmMacroInst(const char* mnem, ExtMachInst machInst, OpClass opClass);
protected:
using RiscvMacroInst::RiscvMacroInst;
uint64_t stackAdj() const;
std::string getRlistStr() const;
uint64_t rlist;
};
} // namespace RiscvISA
} // namespace gem5
#endif // __ARCH_RISCV_INSTS_ZCMP_HH__

View File

@@ -260,7 +260,7 @@ RegClass ccRegClass(CCRegClass, CCRegClassName, 0, debug::IntRegs);
ISA::ISA(const Params &p) : BaseISA(p, "riscv"),
_rvType(p.riscv_type), enableRvv(p.enable_rvv), vlen(p.vlen), elen(p.elen),
_privilegeModeSet(p.privilege_mode_set),
_wfiResumeOnPending(p.wfi_resume_on_pending)
_wfiResumeOnPending(p.wfi_resume_on_pending), _enableZcd(p.enable_Zcd)
{
_regClasses.push_back(&intRegClass);
_regClasses.push_back(&floatRegClass);

View File

@@ -108,6 +108,14 @@ class ISA : public BaseISA
*/
const bool _wfiResumeOnPending;
/**
* Enable Zcd extensions.
* Set the option to false implies the Zcmp and Zcmt is enable as c.fsdsp
* is overlap with them.
* Refs: https://github.com/riscv/riscv-isa-manual/blob/main/src/zc.adoc
*/
bool _enableZcd;
public:
using Params = RiscvISAParams;
@@ -184,6 +192,8 @@ class ISA : public BaseISA
bool resumeOnPending() { return _wfiResumeOnPending; }
bool enableZcd() { return _enableZcd; }
virtual Addr getFaultHandlerAddr(
RegIndex idx, uint64_t cause, bool intr) const;
};

View File

@@ -34,6 +34,7 @@
// Bitfield definitions.
//
def bitfield RVTYPE rv_type;
def bitfield ENABLE_ZCD enable_zcd;
def bitfield QUADRANT <1:0>;
def bitfield OPCODE5 <6:2>;
@@ -103,10 +104,13 @@ def bitfield CFUNCT1 <12>;
def bitfield CFUNCT1BIT6 <6>;
def bitfield CFUNCT2HIGH <11:10>;
def bitfield CFUNCT2LOW <6:5>;
def bitfield CFUNCT2MID <9:8>;
def bitfield RC1 <11:7>;
def bitfield RC2 <6:2>;
def bitfield RP1 <9:7>;
def bitfield RP2 <4:2>;
def bitfield R1S <9:7>;
def bitfield R2S <4:2>;
def bitfield FC1 <11:7>;
def bitfield FC2 <6:2>;
def bitfield FP2 <4:2>;

View File

@@ -54,23 +54,25 @@ decode QUADRANT default Unknown::unknown() {
Rp2 = rvSext(sp + imm);
}}, uint64_t);
format CompressedLoad {
0x1: c_fld({{
offset = CIMM3 << 3 | CIMM2 << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
0x1: decode ENABLE_ZCD {
0x1: c_fld({{
offset = CIMM3 << 3 | CIMM2 << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
// Mutating any floating point register changes the FS bit
// of the STATUS CSR.
status.fs = FPUStatus::DIRTY;
xc->setMiscReg(MISCREG_STATUS, status);
// Mutating any floating point register changes the FS bit
// of the STATUS CSR.
status.fs = FPUStatus::DIRTY;
xc->setMiscReg(MISCREG_STATUS, status);
Fp2_bits = Mem;
}}, {{
EA = rvSext(Rp1 + offset);
}});
Fp2_bits = Mem;
}}, {{
EA = rvSext(Rp1 + offset);
}});
}
0x2: c_lw({{
offset = CIMM2<1:1> << 2 |
CIMM3 << 3 |
@@ -152,18 +154,20 @@ decode QUADRANT default Unknown::unknown() {
}
}
format CompressedStore {
0x5: c_fsd({{
offset = CIMM3 << 3 | CIMM2 << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
0x5: decode ENABLE_ZCD {
0x1: c_fsd({{
offset = CIMM3 << 3 | CIMM2 << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
Mem = Fp2_bits;
}}, {{
EA = rvSext(Rp1 + offset);
}});
Mem = Fp2_bits;
}}, {{
EA = rvSext(Rp1 + offset);
}});
}
0x6: c_sw({{
offset = CIMM2<1:1> << 2 |
CIMM3 << 3 |
@@ -381,23 +385,25 @@ decode QUADRANT default Unknown::unknown() {
Rc1 = rvSext(Rc1 << imm);
}}, uint64_t);
format CompressedLoad {
0x1: c_fldsp({{
offset = CIMM5<4:3> << 3 |
CIMM1 << 5 |
CIMM5<2:0> << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
0x1: decode ENABLE_ZCD {
0x1: c_fldsp({{
offset = CIMM5<4:3> << 3 |
CIMM1 << 5 |
CIMM5<2:0> << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
status.fs = FPUStatus::DIRTY;
xc->setMiscReg(MISCREG_STATUS, status);
status.fs = FPUStatus::DIRTY;
xc->setMiscReg(MISCREG_STATUS, status);
Fc1_bits = Mem;
}}, {{
EA = rvSext(sp + offset);
}});
Fc1_bits = Mem;
}}, {{
EA = rvSext(sp + offset);
}});
}
0x2: c_lwsp({{
offset = CIMM5<4:2> << 2 |
CIMM1 << 5 |
@@ -480,19 +486,35 @@ decode QUADRANT default Unknown::unknown() {
}
}
format CompressedStore {
0x5: c_fsdsp({{
offset = CIMM6<5:3> << 3 |
CIMM6<2:0> << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
0x5: decode ENABLE_ZCD {
0x0: decode CFUNCT6LOW3 {
0x3: decode CFUNCT2LOW {
0x1: CmMvsa01::cm_mvsa01();
0x3: CmMva01s::cm_mva01s();
}
0x6: decode CFUNCT2MID {
0x0: CmPush::cm_push();
0x2: CmPop::cm_pop();
}
0x7: decode CFUNCT2MID {
0x0: CmPop::cm_popretz(is_ret=True, has_a0=True);
0x2: CmPop::cm_popret(is_ret=True);
}
}
0x1: c_fsdsp({{
offset = CIMM6<5:3> << 3 |
CIMM6<2:0> << 6;
}}, {{
STATUS status = xc->readMiscReg(MISCREG_STATUS);
if (status.fs == FPUStatus::OFF)
return std::make_shared<IllegalInstFault>("FPU is off",
machInst);
Mem_ud = Fc2_bits;
}}, {{
EA = rvSext(sp + offset);
}});
Mem_ud = Fc2_bits;
}}, {{
EA = rvSext(sp + offset);
}});
}
0x6: c_swsp({{
offset = CIMM6<5:2> << 2 |
CIMM6<1:0> << 6;

View File

@@ -40,6 +40,7 @@
##include "vector_conf.isa"
##include "vector_arith.isa"
##include "vector_mem.isa"
##include "zcmp.isa"
// Include formats for nonstandard extensions
##include "compressed.isa"

View File

@@ -0,0 +1,782 @@
// -*- mode:c++ -*-
// Copyright (c) 2015 RISC-V Foundation
// Copyright (c) 2016 The University of Virginia
// Copyright (c) 2024 Google LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Cmpush template.
def template CmPushDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst);
protected:
using %(base_class)s::%(base_class)s;
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
}};
def template CmPushConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst) :
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
StaticInstPtr cur_inst = nullptr;
if (rlist < 4) {
cur_inst = new Unknown(machInst);
cur_inst->setFlag(IsMicroop);
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
} else {
int start_reg = 0;
if (rlist != 15) {
start_reg = (16-rlist);
}
int offset = 0;
for (int i = start_reg; i < PushPopRegList.size(); i++) {
offset -= rvSelect(4, 8);
if (machInst.rv_type == RV32) {
cur_inst = new %(class_name)s32MicroInst(
machInst, PushPopRegList[i], offset);
} else {
cur_inst = new %(class_name)s64MicroInst(
machInst, PushPopRegList[i], offset);
}
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
}
cur_inst = new %(class_name)sSpAdjMicroInst(machInst, -stackAdj());
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
}
microops.front()->setFirstMicroop();
microops.back()->setLastMicroop();
}
}};
def template CmPushExecute {{
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << getRlistStr() << ", " << (int64_t)-stackAdj();
return ss.str();
}
}};
def template CmStoreMicroDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst, RegId push_reg, int64_t offset);
Fault execute(ExecContext *, trace::InstRecord *) const override;
Fault initiateAcc(ExecContext *, trace::InstRecord *) const override;
Fault completeAcc(
Packet *, ExecContext *, trace::InstRecord *) const override;
std::string generateDisassembly(
Addr, const loader::SymbolTable *) const override;
protected:
using %(base_class)s::%(base_class)s;
private:
%(reg_idx_arr_decl)s;
int64_t offset;
Request::Flags memAccessFlags;
};
}};
def template CmStoreMicroConstructor {{
%(class_name)s::%(class_name)s(
ExtMachInst machInst, RegId push_reg, int64_t offset)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
offset(offset)
{
%(set_reg_idx_arr)s;
%(constructor)s;
}
}};
def template CmStoreMicroExecute {{
Fault
%(class_name)s::execute(
ExecContext *xc, trace::InstRecord *traceData) const
{
Addr EA;
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
%(memacc_code)s;
{
Fault fault =
writeMemAtomicLE(xc, traceData, Mem, EA, memAccessFlags,
nullptr);
if (fault != NoFault)
return fault;
}
%(op_wb)s;
return NoFault;
}
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(1)) << ", " <<
offset << '(' << registerName(srcRegIdx(0)) << ')';
return ss.str();
}
}};
def template CmStoreMicroInitiateAcc {{
Fault
%(class_name)s::initiateAcc(ExecContext *xc,
trace::InstRecord *traceData) const
{
Addr EA;
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
%(memacc_code)s;
{
Fault fault = writeMemTimingLE(xc, traceData, Mem, EA,
memAccessFlags, nullptr);
if (fault != NoFault)
return fault;
}
%(op_wb)s;
return NoFault;
}
}};
def template CmStoreMicroCompleteAcc {{
Fault
%(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
trace::InstRecord *traceData) const
{
return NoFault;
}
}};
def template SpAdjMicroDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst, int64_t adj);
protected:
using %(base_class)s::%(base_class)s;
Fault execute(ExecContext *, trace::InstRecord *) const override;
std::string generateDisassembly(
Addr, const loader::SymbolTable *) const override;
private:
%(reg_idx_arr_decl)s;
int64_t adj;
};
}};
def template SpAdjMicroConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst, int64_t adj)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s), adj(adj)
{
%(set_reg_idx_arr)s;
%(constructor)s;
}
}};
def template SpAdjMicroExecute {{
Fault
%(class_name)s::execute(
ExecContext *xc, trace::InstRecord *traceData) const
{
%(op_decl)s;
%(op_rd)s;
%(code)s;
%(op_wb)s;
return NoFault;
}
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ' '
<< registerName(srcRegIdx(0)) << ' ' << adj;
return ss.str();
}
}};
// Cmpop decode template.
def template CmPopDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst);
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
protected:
using %(base_class)s::%(base_class)s;
};
}};
def template CmPopConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst) :
%(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
StaticInstPtr cur_inst = nullptr;
if (rlist < 4) {
cur_inst = new Unknown(machInst);
cur_inst->setFlag(IsMicroop);
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
} else {
int start_reg = 0;
if (rlist != 15) {
start_reg = (16-rlist);
}
int offset = stackAdj();
for (int i = start_reg; i < PushPopRegList.size(); i++) {
offset -= rvSelect(4, 8);
if (machInst.rv_type == RV32) {
cur_inst = new %(class_name)s32MicroInst(
machInst, PushPopRegList[i], offset);
} else {
cur_inst = new %(class_name)s64MicroInst(
machInst, PushPopRegList[i], offset);
}
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
}
cur_inst = new %(class_name)sSpAdjMicroInst(machInst, stackAdj());
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
%(move_a0_desc)s;
%(return_desc)s;
}
microops.front()->setFirstMicroop();
microops.back()->setLastMicroop();
}
}};
def template CmPopExecute {{
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << getRlistStr() << ", " << stackAdj();
return ss.str();
}
}};
def template CmLoadMicroDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst, RegId pop_reg, int64_t offset);
Fault execute(ExecContext *, trace::InstRecord *) const override;
Fault initiateAcc(ExecContext *, trace::InstRecord *) const override;
Fault completeAcc(
Packet *, ExecContext *, trace::InstRecord *) const override;
std::string generateDisassembly(
Addr, const loader::SymbolTable *) const override;
protected:
using %(base_class)s::%(base_class)s;
private:
%(reg_idx_arr_decl)s;
int64_t offset;
Request::Flags memAccessFlags;
};
}};
def template CmLoadMicroConstructor {{
%(class_name)s::%(class_name)s(
ExtMachInst machInst, RegId pop_reg, int64_t offset)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
offset(offset)
{
%(set_reg_idx_arr)s;
%(constructor)s;
}
}};
def template CmLoadMicroExecute {{
Fault
%(class_name)s::execute(
ExecContext *xc, trace::InstRecord *traceData) const
{
Addr EA;
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
{
Fault fault =
readMemAtomicLE(xc, traceData, EA, Mem, memAccessFlags);
if (fault != NoFault)
return fault;
}
%(memacc_code)s;
%(op_wb)s;
return NoFault;
}
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
offset << '(' << registerName(srcRegIdx(0)) << ')';
return ss.str();
}
}};
def template CmLoadMicroInitiateAcc {{
Fault
%(class_name)s::initiateAcc(ExecContext *xc,
trace::InstRecord *traceData) const
{
Addr EA;
%(op_src_decl)s;
%(op_rd)s;
%(ea_code)s;
return initiateMemRead(xc, traceData, EA, Mem, memAccessFlags);
}
}};
def template CmLoadMicroCompleteAcc {{
Fault
%(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
trace::InstRecord *traceData) const
{
%(op_decl)s;
%(op_rd)s;
getMemLE(pkt, Mem, traceData);
%(memacc_code)s;
%(op_wb)s;
return NoFault;
}
}};
def template CmRetMicroDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
/// Constructor.
%(class_name)s(ExtMachInst machInst);
protected:
using %(base_class)s::%(base_class)s;
Fault execute(ExecContext *, trace::InstRecord *) const override;
std::string
generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
std::unique_ptr<PCStateBase> branchTarget(
ThreadContext *tc) const override;
using StaticInst::branchTarget;
private:
%(reg_idx_arr_decl)s;
};
}};
def template CmRetMicroConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
%(set_reg_idx_arr)s;
%(constructor)s;
}
}};
def template CmRetMicroExecute {{
Fault
%(class_name)s::execute(
ExecContext *xc, trace::InstRecord *traceData) const
{
%(op_decl)s;
%(op_rd)s;
%(code)s;
%(op_wb)s;
return NoFault;
}
std::unique_ptr<PCStateBase>
%(class_name)s::branchTarget(ThreadContext *tc) const
{
PCStateBase *pc_ptr = tc->pcState().clone();
pc_ptr->as<PCState>().set(rvSext(tc->getReg(srcRegIdx(0)) & ~0x1));
return std::unique_ptr<PCStateBase>{pc_ptr};
}
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(0));
return ss.str();
}
}};
// Cmmvsa01 decode template
def template CmMvDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst);
protected:
using %(base_class)s::%(base_class)s;
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
}};
def template CmMvsa01Constructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
StaticInstPtr cur_inst;
cur_inst = new %(class_name)sMvMicroInst(
machInst, int_reg::A0, StackRegs[machInst.r1s]);
microops.emplace_back(cur_inst);
cur_inst = new %(class_name)sMvMicroInst(
machInst, int_reg::A1, StackRegs[machInst.r2s]);
microops.emplace_back(cur_inst);
microops.front()->setFirstMicroop();
microops.back()->setLastMicroop();
}
}};
def template CmMva01sConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
StaticInstPtr cur_inst;
cur_inst = new %(class_name)sMvMicroInst(
machInst, StackRegs[machInst.r1s], int_reg::A0);
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
cur_inst = new %(class_name)sMvMicroInst(
machInst, StackRegs[machInst.r2s], int_reg::A1);
cur_inst->setDelayedCommit();
microops.emplace_back(cur_inst);
microops.front()->setFirstMicroop();
microops.back()->setLastMicroop();
}
}};
def template CmMvExecute {{
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(StackRegs[machInst.r1s])
<< ", " << registerName(StackRegs[machInst.r2s]);
return ss.str();
}
}};
def template CmMvMicroDeclare {{
class %(class_name)s : public %(base_class)s
{
public:
%(class_name)s(ExtMachInst machInst, RegId push_reg, RegId pop_reg);
protected:
using %(base_class)s::%(base_class)s;
Fault execute(ExecContext *, trace::InstRecord *) const override;
std::string generateDisassembly(
Addr, const loader::SymbolTable *) const override;
private:
%(reg_idx_arr_decl)s;
};
}};
def template CmMvMicroConstructor {{
%(class_name)s::%(class_name)s(
ExtMachInst machInst, RegId push_reg, RegId pop_reg)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
%(set_reg_idx_arr)s;
%(constructor)s;
}
}};
def template CmMvMicroExecute {{
Fault
%(class_name)s::execute(
ExecContext *xc, trace::InstRecord *traceData) const
{
%(op_decl)s;
%(op_rd)s;
%(code)s;
%(op_wb)s;
return NoFault;
}
std::string
%(class_name)s::generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ' '
<< registerName(srcRegIdx(0));
return ss.str();
}
}};
def format CmPush(*flags) {{
code = ''
macro_iop = InstObjParams(name, Name, 'CmMacroInst', code, flags)
header_output = CmPushDeclare.subst(macro_iop)
decoder_output = CmPushConstructor.subst(macro_iop)
exec_output = CmPushExecute.subst(macro_iop)
decode_block = BasicDecode.subst(macro_iop)
memacc_code = 'Mem_sw = CmPushReg_sw;'
ea_code = 'EA = rvSext(sp + offset);'
micro32_iop = InstObjParams('lw', f'{Name}32MicroInst', 'RiscvMicroInst',
{'ea_code': ea_code, 'memacc_code': memacc_code},
flags)
mem_flags = [getAlignFlag(micro32_iop)]
s = '\n\tmemAccessFlags = ' + '|'.join(mem_flags) + ';'
micro32_iop.constructor += s
header_output += CmStoreMicroDeclare.subst(micro32_iop)
decoder_output += CmStoreMicroConstructor.subst(micro32_iop)
exec_output += CmStoreMicroExecute.subst(micro32_iop) \
+ CmStoreMicroInitiateAcc.subst(micro32_iop) \
+ CmStoreMicroCompleteAcc.subst(micro32_iop)
memacc_code = 'Mem = CmPushReg;'
ea_code = 'EA = rvSext(sp + offset);'
micro64_iop = InstObjParams('ld', f'{Name}64MicroInst', 'RiscvMicroInst',
{'ea_code': ea_code, 'memacc_code': memacc_code},
flags)
mem_flags = [getAlignFlag(micro64_iop)]
s = '\n\tmemAccessFlags = ' + '|'.join(mem_flags) + ';'
micro64_iop.constructor += s
header_output += CmStoreMicroDeclare.subst(micro64_iop)
decoder_output += CmStoreMicroConstructor.subst(micro64_iop)
exec_output += CmStoreMicroExecute.subst(micro64_iop) \
+ CmStoreMicroInitiateAcc.subst(micro64_iop) \
+ CmStoreMicroCompleteAcc.subst(micro64_iop)
code = 'spd = rvSext(sp + adj);'
sp_adj_iop = InstObjParams('addi', f'{Name}SpAdjMicroInst',
'RiscvMicroInst', code, flags)
header_output += SpAdjMicroDeclare.subst(sp_adj_iop)
decoder_output += SpAdjMicroConstructor.subst(sp_adj_iop)
exec_output += SpAdjMicroExecute.subst(sp_adj_iop)
}};
def format CmPop(is_ret=False, has_a0=False, *flags) {{
code = ''
flags = []
has_a0 = eval(has_a0)
is_ret = eval(is_ret)
move_a0_desc = ''
return_desc = ''
if has_a0:
move_a0_desc = rf'''
cur_inst = new {Name}MvMicroInst(
machInst, ReturnValueReg, int_reg::Zero);
microops.emplace_back(cur_inst);
'''
if is_ret:
return_desc = rf'''
cur_inst = new {Name}RetMicroInst(machInst);
microops.emplace_back(cur_inst);
'''
macro_iop = InstObjParams(name, Name, 'CmMacroInst',
{'code': code, 'move_a0_desc': move_a0_desc,
'return_desc': return_desc},
flags)
header_output = CmPopDeclare.subst(macro_iop)
decoder_output = CmPopConstructor.subst(macro_iop)
exec_output = CmPopExecute.subst(macro_iop)
decode_block = BasicDecode.subst(macro_iop)
memacc_code = 'CmPopReg_sw = Mem_sw;'
ea_code = 'EA = rvSext(sp + offset);'
micro32_iop = InstObjParams('lw', f'{Name}32MicroInst', 'RiscvMicroInst',
{'ea_code': ea_code, 'memacc_code': memacc_code},
flags)
mem_flags = [getAlignFlag(micro32_iop)]
s = '\n\tmemAccessFlags = ' + '|'.join(mem_flags) + ';'
micro32_iop.constructor += s
header_output += CmLoadMicroDeclare.subst(micro32_iop)
decoder_output += CmLoadMicroConstructor.subst(micro32_iop)
exec_output += CmLoadMicroExecute.subst(micro32_iop) \
+ CmLoadMicroInitiateAcc.subst(micro32_iop) \
+ CmLoadMicroCompleteAcc.subst(micro32_iop)
memacc_code = 'CmPopReg = Mem;'
ea_code = 'EA = rvSext(sp + offset);'
micro64_iop = InstObjParams('ld', f'{Name}64MicroInst', 'RiscvMicroInst',
{'ea_code': ea_code, 'memacc_code': memacc_code},
flags)
mem_flags = [getAlignFlag(micro64_iop)]
s = '\n\tmemAccessFlags = ' + '|'.join(mem_flags) + ';'
micro64_iop.constructor += s
header_output += CmLoadMicroDeclare.subst(micro64_iop)
decoder_output += CmLoadMicroConstructor.subst(micro64_iop)
exec_output += CmLoadMicroExecute.subst(micro64_iop) \
+ CmLoadMicroInitiateAcc.subst(micro64_iop) \
+ CmLoadMicroCompleteAcc.subst(micro64_iop)
code = 'spd = rvSext(sp + adj);'
sp_adj_iop = InstObjParams('addi', f'{Name}SpAdjMicroInst',
'RiscvMicroInst', code, flags)
header_output += SpAdjMicroDeclare.subst(sp_adj_iop)
decoder_output += SpAdjMicroConstructor.subst(sp_adj_iop)
exec_output += SpAdjMicroExecute.subst(sp_adj_iop)
if has_a0:
code = 'CmPopReg = CmPushReg;'
has_a0_iop = InstObjParams('mv', f'{Name}MvMicroInst',
'RiscvMicroInst', code, flags)
header_output += CmMvMicroDeclare.subst(has_a0_iop)
decoder_output += CmMvMicroConstructor.subst(has_a0_iop)
exec_output += CmMvMicroExecute.subst(has_a0_iop)
if is_ret:
code = 'NPC = rvSext(ra & (~0x1));'
ret_flags = ['IsIndirectControl', 'IsUncondControl', 'IsReturn']
is_ret_iop = InstObjParams('jr', f'{Name}RetMicroInst',
'RiscvMicroInst', code, ret_flags)
header_output += CmRetMicroDeclare.subst(is_ret_iop)
decoder_output += CmRetMicroConstructor.subst(is_ret_iop)
exec_output += CmRetMicroExecute.subst(is_ret_iop)
}};
def format CmMvsa01() {{
code = ''
flags = []
iop = InstObjParams(name, Name, 'RiscvMacroInst', code, flags)
header_output = CmMvDeclare.subst(iop)
decoder_output = CmMvsa01Constructor.subst(iop)
exec_output = CmMvExecute.subst(iop)
decode_block = BasicDecode.subst(iop)
code = 'CmPopReg = CmPushReg;'
micro_iop = InstObjParams('mv', f'{Name}MvMicroInst', 'RiscvMicroInst',
code, flags)
header_output += CmMvMicroDeclare.subst(micro_iop)
decoder_output += CmMvMicroConstructor.subst(micro_iop)
exec_output += CmMvMicroExecute.subst(micro_iop)
}};
def format CmMva01s() {{
code = ''
flags = []
iop = InstObjParams(name, Name, 'RiscvMacroInst', code, flags)
header_output = CmMvDeclare.subst(iop)
decoder_output = CmMva01sConstructor.subst(iop)
exec_output = CmMvExecute.subst(iop)
decode_block = BasicDecode.subst(iop)
code = 'CmPopReg = CmPushReg;'
micro_iop = InstObjParams('mv', f'{Name}MvMicroInst', 'RiscvMicroInst',
code, flags)
header_output += CmMvMicroDeclare.subst(micro_iop)
decoder_output += CmMvMicroConstructor.subst(micro_iop)
exec_output += CmMvMicroExecute.subst(micro_iop)
}};

View File

@@ -55,6 +55,7 @@ output header {{
#include "arch/riscv/insts/static_inst.hh"
#include "arch/riscv/insts/unknown.hh"
#include "arch/riscv/insts/vector.hh"
#include "arch/riscv/insts/zcmp.hh"
#include "arch/riscv/interrupts.hh"
#include "cpu/static_inst.hh"
#include "mem/packet.hh"

View File

@@ -70,10 +70,14 @@ def operands {{
'Rp2': IntReg('ud', 'RP2 + 8', 'IsInteger', 3),
'ra': IntReg('ud', 'ReturnAddrReg', 'IsInteger', 1),
'sp': IntReg('ud', 'StackPointerReg', 'IsInteger', 2),
'spd': IntReg('ud', 'StackPointerReg', 'IsInteger', 1),
'a0': IntReg('ud', '10', 'IsInteger', 1),
'a1': IntReg('ud', '11', 'IsInteger', 2),
'CmPushReg': IntReg('ud', 'push_reg', 'IsInteger', 3),
'CmPopReg': IntReg('ud', 'pop_reg', 'IsInteger', 1),
'Fd': FloatRegOp('df', 'FD', 'IsFloating', 1),
'Fd_bits': FloatRegOp('ud', 'FD', 'IsFloating', 1),
'Fs1': FloatRegOp('df', 'FS1', 'IsFloating', 2),

View File

@@ -149,6 +149,18 @@ inline constexpr RegId ArgumentRegs[] = {
int_reg::A4, int_reg::A5, int_reg::A6, int_reg::A7
};
const std::vector<RegId> PushPopRegList = {
int_reg::S11, int_reg::S10, int_reg::S9, int_reg::S8,
int_reg::S7, int_reg::S6, int_reg::S5, int_reg::S4,
int_reg::S3, int_reg::S2, int_reg::S1, int_reg::S0,
int_reg::Ra
};
inline constexpr RegId StackRegs[] = {
int_reg::S0, int_reg::S1, int_reg::S2, int_reg::S3,
int_reg::S4, int_reg::S5, int_reg::S6, int_reg::S7,
};
} // namespace RiscvISA
} // namespace gem5

View File

@@ -58,6 +58,7 @@ BitUnion64(ExtMachInst)
// Decoder state
Bitfield<63, 62> rv_type;
Bitfield<61> compressed;
Bitfield<60> enable_zcd;
// More bits for vector extension
Bitfield<57, 41> vl; // [0, 2**16]
Bitfield<40> vill;
@@ -126,6 +127,8 @@ BitUnion64(ExtMachInst)
Bitfield< 6, 2> rc2;
Bitfield< 9, 7> rp1;
Bitfield< 4, 2> rp2;
Bitfield< 9, 7> r1s;
Bitfield< 4, 2> r2s;
Bitfield<11, 7> fc1;
Bitfield< 6, 2> fc2;
Bitfield< 4, 2> fp2;
@@ -144,6 +147,8 @@ BitUnion64(ExtMachInst)
Bitfield<12, 10> cimm3;
Bitfield< 6, 5> cimm2;
Bitfield<12> cimm1;
Bitfield< 7, 4> rlist;
Bitfield< 3, 2> spimm;
// Pseudo instructions
Bitfield<31, 25> m5func;
// vector