Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Zicntr extenstion #16

Merged
merged 8 commits into from
Aug 13, 2024
Merged
12 changes: 12 additions & 0 deletions src/decode/inst_32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod a_extension;
mod base_i;
mod m_extension;
mod priv_extension;
mod zicntr_extension;
mod zicsr_extension;
mod zifencei_extension;

Expand Down Expand Up @@ -40,6 +41,7 @@ impl Decode for u32 {
self,
)?)),
Ok(Extensions::Zicsr) => Ok(OpcodeKind::Zicsr(zicsr_extension::parse_opcode(self)?)),
Ok(Extensions::Zicntr) => Ok(OpcodeKind::Zicntr(zicntr_extension::parse_opcode(self)?)),
Ok(Extensions::Priv) => Ok(OpcodeKind::Priv(priv_extension::parse_opcode(self)?)),
Ok(Extensions::C) => Err(DecodingError::Not32BitInst),
Err(decoding_err) => Err(decoding_err),
Expand All @@ -53,6 +55,7 @@ impl Decode for u32 {
OpcodeKind::A(opc) => Ok(a_extension::parse_rd(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rd(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rd(self, opc)),
OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_rd(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rd(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
}
Expand All @@ -65,6 +68,7 @@ impl Decode for u32 {
OpcodeKind::A(opc) => Ok(a_extension::parse_rs1(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rs1(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rs1(self, opc)),
OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_rs1(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rs1(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
}
Expand All @@ -77,6 +81,7 @@ impl Decode for u32 {
OpcodeKind::A(opc) => Ok(a_extension::parse_rs2(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rs2(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rs2(self, opc)),
OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_rs2(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rs2(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
}
Expand All @@ -89,6 +94,7 @@ impl Decode for u32 {
OpcodeKind::A(opc) => Ok(a_extension::parse_imm(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_imm(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_imm(self, opc)),
OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_imm(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_imm(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
}
Expand All @@ -104,6 +110,7 @@ impl DecodeUtil for u32 {
let opmap: u8 = u8::try_from(self.slice(6, 0)).unwrap();
let funct3: u8 = u8::try_from(self.slice(14, 12)).unwrap();
let funct7: u8 = u8::try_from(self.slice(31, 25)).unwrap();
let csr: u16 = u16::try_from(self.slice(31, 20)).unwrap();

match opmap {
0b000_1111 => Ok(Extensions::Zifencei),
Expand All @@ -122,6 +129,11 @@ impl DecodeUtil for u32 {
0b000_0000 => Ok(Extensions::BaseI),
_ => Ok(Extensions::Priv),
},
0b010 => match csr {
// csrrs rd, (cycle|time|instret), zero
0xc00..=0xc02 | 0xc80..=0xc82 => Ok(Extensions::Zicntr),
_ => Ok(Extensions::Zicsr),
},
_ => Ok(Extensions::Zicsr),
},
_ => Ok(Extensions::BaseI),
Expand Down
107 changes: 107 additions & 0 deletions src/decode/inst_32/zicntr_extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use super::super::{DecodeUtil, DecodingError};
use crate::instruction::zicntr_extension::ZicntrOpcode;

pub fn parse_opcode(inst: u32) -> Result<ZicntrOpcode, DecodingError> {
let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap();
let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap();
let csr_num: u16 = u16::try_from(inst.slice(31, 20)).unwrap();

match opmap {
0b111_0011 => match funct3 {
0b010 => match csr_num {
0xc00 => Ok(ZicntrOpcode::RDCYCLE),
0xc01 => Ok(ZicntrOpcode::RDTIME),
0xc02 => Ok(ZicntrOpcode::RDINSTRET),
0xc80 => Ok(ZicntrOpcode::RDCYCLE_H),
0xc81 => Ok(ZicntrOpcode::RDTIME_H),
0xc82 => Ok(ZicntrOpcode::RDINSTRET_H),
_ => Err(DecodingError::InvalidOpcode),
},
_ => Err(DecodingError::InvalidFunct3),
},
_ => Err(DecodingError::InvalidOpcode),
}
}

#[allow(clippy::unnecessary_wraps)]
pub fn parse_rd(inst: u32, opkind: &ZicntrOpcode) -> Option<usize> {
let rd: usize = inst.slice(11, 7) as usize;
match opkind {
ZicntrOpcode::RDCYCLE
| ZicntrOpcode::RDTIME
| ZicntrOpcode::RDINSTRET
| ZicntrOpcode::RDCYCLE_H
| ZicntrOpcode::RDTIME_H
| ZicntrOpcode::RDINSTRET_H => Some(rd),
}
}

#[allow(clippy::unnecessary_wraps)]
pub fn parse_rs1(_inst: u32, opkind: &ZicntrOpcode) -> Option<usize> {
match opkind {
ZicntrOpcode::RDCYCLE
| ZicntrOpcode::RDTIME
| ZicntrOpcode::RDINSTRET
| ZicntrOpcode::RDCYCLE_H
| ZicntrOpcode::RDTIME_H
| ZicntrOpcode::RDINSTRET_H => None,
}
}

#[allow(clippy::unnecessary_wraps)]
pub fn parse_rs2(_inst: u32, opkind: &ZicntrOpcode) -> Option<usize> {
match opkind {
ZicntrOpcode::RDCYCLE
| ZicntrOpcode::RDTIME
| ZicntrOpcode::RDINSTRET
| ZicntrOpcode::RDCYCLE_H
| ZicntrOpcode::RDTIME_H
| ZicntrOpcode::RDINSTRET_H => None,
}
}

#[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)]
pub fn parse_imm(_inst: u32, opkind: &ZicntrOpcode) -> Option<i32> {
match opkind {
ZicntrOpcode::RDCYCLE
| ZicntrOpcode::RDTIME
| ZicntrOpcode::RDINSTRET
| ZicntrOpcode::RDCYCLE_H
| ZicntrOpcode::RDTIME_H
| ZicntrOpcode::RDINSTRET_H => None,
}
}

#[cfg(test)]
#[allow(unused_variables)]
mod test_zicntr {
#[test]
#[allow(overflowing_literals)]
fn zicntr_decode_test() {
use super::*;
use crate::{Decode, Isa, OpcodeKind};

let test_32 = |inst_32: u32,
op: OpcodeKind,
rd: Option<usize>,
rs1: Option<usize>,
rs2: Option<usize>,
imm: Option<i32>| {
let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap();
assert!(matches!(&op_32, op));
assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd);
assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1);
assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2);
assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm);
};

test_32(
0b1100_0000_0001_0000_0010_0111_1111_0011,
OpcodeKind::Zicntr(ZicntrOpcode::RDTIME),
Some(15),
None,
None,
None,
)
}
}
15 changes: 15 additions & 0 deletions src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod base_i;
pub mod c_extension;
pub mod m_extension;
pub mod priv_extension;
pub mod zicntr_extension;
pub mod zicsr_extension;
pub mod zifencei_extension;

Expand All @@ -15,6 +16,7 @@ use base_i::BaseIOpcode;
use c_extension::COpcode;
use m_extension::MOpcode;
use priv_extension::PrivOpcode;
use zicntr_extension::ZicntrOpcode;
use zicsr_extension::ZicsrOpcode;
use zifencei_extension::ZifenceiOpcode;

Expand Down Expand Up @@ -194,6 +196,9 @@ impl Display for Instruction {
self.imm.unwrap(),
)
}
InstFormat::CSRcntrformat => {
write!(f, "{} {}", self.opc, reg2str(self.rd.unwrap()),)
}
InstFormat::Uncategorized => {
write!(
f,
Expand Down Expand Up @@ -378,6 +383,12 @@ pub enum InstFormat {
/// ```
CSRuiformat,

/// Zicntr extension format
/// ```ignore
/// rdtime rd
/// ```
CSRcntrformat,

/// M-extension instruction format
/// ```ignore
/// mul rd, rs1, rs2
Expand Down Expand Up @@ -428,6 +439,8 @@ pub enum OpcodeKind {
Zifencei(ZifenceiOpcode),
/// Control and Status Register Instructions
Zicsr(ZicsrOpcode),
/// Base Counters and Timers
Zicntr(ZicntrOpcode),
/// Privileged Instructions
Priv(PrivOpcode),
}
Expand All @@ -441,6 +454,7 @@ impl Display for OpcodeKind {
Self::C(opc) => write!(f, "{opc}"),
Self::Zifencei(opc) => write!(f, "{opc}"),
Self::Zicsr(opc) => write!(f, "{opc}"),
Self::Zicntr(opc) => write!(f, "{opc}"),
Self::Priv(opc) => write!(f, "{opc}"),
}
}
Expand All @@ -456,6 +470,7 @@ impl OpcodeKind {
Self::C(opc) => opc.get_format(),
Self::Zifencei(opc) => opc.get_format(),
Self::Zicsr(opc) => opc.get_format(),
Self::Zicntr(opc) => opc.get_format(),
Self::Priv(opc) => opc.get_format(),
}
}
Expand Down
47 changes: 47 additions & 0 deletions src/instruction/zicntr_extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! Zicntr extension Instruction.

use super::{InstFormat, Opcode};
use core::fmt::{self, Display, Formatter};

/// Insturctions in Zicntr Extension.
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
#[derive(Debug, PartialEq)]
pub enum ZicntrOpcode {
// For Rv32, these instructions indicate lower 32 bits.
// For Rv64, these instructions do not exist.
RDCYCLE_H,
RDTIME_H,
RDINSTRET_H,

// For Rv32, these instructions indicate upper 32 bits.
// For Rv64, these instructions can access the full 64-bit CSRs directly.
RDCYCLE,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [clippy] clippy::upper_case_acronyms reported by reviewdog 🐶
name RDCYCLE contains a capitalized acronym

RDTIME,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [clippy] clippy::upper_case_acronyms reported by reviewdog 🐶
name RDTIME contains a capitalized acronym

RDINSTRET,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [clippy] clippy::upper_case_acronyms reported by reviewdog 🐶
name RDINSTRET contains a capitalized acronym

}

impl Display for ZicntrOpcode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
ZicntrOpcode::RDCYCLE_H => write!(f, "rdcycleh"),
ZicntrOpcode::RDTIME_H => write!(f, "rdtimeh"),
ZicntrOpcode::RDINSTRET_H => write!(f, "rdinstreth"),
ZicntrOpcode::RDCYCLE => write!(f, "rdcycle"),
ZicntrOpcode::RDTIME => write!(f, "rdtime"),
ZicntrOpcode::RDINSTRET => write!(f, "rdinstret"),
}
}
}

impl Opcode for ZicntrOpcode {
fn get_format(&self) -> InstFormat {
match self {
ZicntrOpcode::RDCYCLE_H
| ZicntrOpcode::RDTIME_H
| ZicntrOpcode::RDINSTRET_H
| ZicntrOpcode::RDCYCLE
| ZicntrOpcode::RDTIME
| ZicntrOpcode::RDINSTRET => InstFormat::CSRcntrformat,
}
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ enum Extensions {
Zifencei,
/// Control and Status Register Instructions
Zicsr,
/// Base Counters and Timers
Zicntr,
/// Privileged Instructions
Priv,
}
Expand Down