Skip to content

Commit

Permalink
Merge pull request #16 from Alignof/feature/Zicntr
Browse files Browse the repository at this point in the history
Implement Zicntr extenstion
  • Loading branch information
Alignof committed Aug 13, 2024
2 parents da85a53 + 6a305e3 commit 29b906d
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 0 deletions.
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,
RDTIME,
RDINSTRET,
}

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

0 comments on commit 29b906d

Please sign in to comment.