pub const REGISTERS_COUNT: usize = 32;
use std::cmp;
use std::cmp::PartialEq;
use std::fmt;
use std::num::FpCategory;
use crate::{
bus::{Bus, DRAM_BASE},
csr::*,
devices::{
uart::UART_IRQ,
virtio::{Virtio, VIRTIO_IRQ},
},
exception::Exception,
interrupt::Interrupt,
memory::MEMORY_SIZE,
};
const SP: usize = 2;
const PAGE_SIZE: usize = 4096;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Mode {
User = 0b00,
Supervisor = 0b01,
Machine = 0b11,
Debug,
}
impl Mode {
pub fn require(&self, require: Mode) -> Result<(), Exception> {
match require {
Mode::User => {
if self == &Mode::Machine || self == &Mode::Supervisor || self == &Mode::User {
return Ok(());
}
Err(Exception::IllegalInstruction(String::from(format!(
"this should be called in {:#?} mode but called in {:#?} mode",
require, self
))))
}
Mode::Supervisor => {
if self == &Mode::Machine || self == &Mode::Supervisor {
return Ok(());
}
Err(Exception::IllegalInstruction(String::from(format!(
"this should be called in {:#?} mode but called in {:#?} mode",
require, self
))))
}
Mode::Machine => {
if self == &Mode::Machine {
return Ok(());
}
Err(Exception::IllegalInstruction(String::from(format!(
"this should be called in {:#?} mode but called in {:#?} mode",
require, self
))))
}
_ => Err(Exception::IllegalInstruction(String::from(format!(
"this should be called in {:#?} mode but called in {:#?} mode",
require, self
)))),
}
}
}
#[derive(Debug)]
pub struct XRegisters {
xregs: [i64; REGISTERS_COUNT],
}
impl XRegisters {
pub fn new() -> Self {
let mut xregs = [0; REGISTERS_COUNT];
xregs[SP] = MEMORY_SIZE as i64 + DRAM_BASE as i64;
Self { xregs }
}
pub fn read(&self, index: usize) -> i64 {
self.xregs[index]
}
pub fn write(&mut self, index: usize, value: i64) {
if index != 0 {
self.xregs[index] = value;
}
}
}
impl fmt::Display for XRegisters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut output = String::from("");
for i in (0..REGISTERS_COUNT).step_by(4) {
output = format!(
"{}\n{}",
output,
format!(
"x{:02}={:>#18x} x{:02}={:>#18x} x{:02}={:>#18x} x{:02}={:>#18x}",
i,
self.read(i),
i + 1,
self.read(i + 1),
i + 2,
self.read(i + 2),
i + 3,
self.read(i + 3)
)
);
}
output.remove(0);
write!(f, "{}", output)
}
}
#[derive(Debug)]
pub struct FRegisters {
fregs: [f64; REGISTERS_COUNT],
}
impl FRegisters {
pub fn new() -> Self {
Self {
fregs: [0.0; REGISTERS_COUNT],
}
}
pub fn read(&self, index: usize) -> f64 {
self.fregs[index]
}
pub fn write(&mut self, index: usize, value: f64) {
self.fregs[index] = value;
}
}
impl fmt::Display for FRegisters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut output = String::from("");
for i in (0..REGISTERS_COUNT).step_by(4) {
output = format!(
"{}\n{}",
output,
format!(
"f{:02}={:>width$.prec$} f{:02}={:>width$.prec$} f{:02}={:>width$.prec$} f{:02}={:>width$.prec$}",
i,
self.read(i),
i + 1,
self.read(i + 1),
i + 2,
self.read(i + 2),
i + 3,
self.read(i + 3),
width=18,
prec=8,
)
);
}
output.remove(0);
write!(f, "{}", output)
}
}
pub struct Cpu {
pub xregs: XRegisters,
pub fregs: FRegisters,
pub pc: usize,
pub state: State,
pub mode: Mode,
pub bus: Bus,
pub enable_paging: bool,
pub page_table: usize,
pub debug: bool,
}
impl Cpu {
pub fn new() -> Cpu {
Cpu {
xregs: XRegisters::new(),
fregs: FRegisters::new(),
pc: 0,
state: State::new(),
mode: Mode::Machine,
bus: Bus::new(),
enable_paging: false,
page_table: 0,
debug: false,
}
}
pub fn reset(&mut self) {
self.pc = 0;
self.state.reset();
for i in 0..REGISTERS_COUNT {
self.xregs.write(i, 0);
self.fregs.write(i, 0.0);
}
}
pub fn timer_increment(&mut self) {
self.bus.clint.increment();
}
pub fn check_interrupt(&mut self) -> Option<Interrupt> {
match self.mode {
Mode::Machine => {
if (self.state.read(MSTATUS) >> 3) & 1 == 0 {
return None;
}
}
Mode::Supervisor => {
if (self.state.read(SSTATUS) >> 1) & 1 == 0 {
return None;
}
}
Mode::User => {
if self.state.read(USTATUS) & 1 == 0 {
return None;
}
}
_ => {}
}
if self.bus.clint.is_interrupting() {
match self.mode {
Mode::Machine => return Some(Interrupt::MachineSoftwareInterrupt),
Mode::Supervisor => return Some(Interrupt::SupervisorSoftwareInterrupt),
Mode::User => return Some(Interrupt::UserSoftwareInterrupt),
_ => return Some(Interrupt::MachineSoftwareInterrupt),
}
}
let irq;
if self.bus.uart.is_interrupting() {
irq = UART_IRQ;
} else if self.bus.virtio.is_interrupting() {
Virtio::disk_access(self);
irq = VIRTIO_IRQ;
} else {
return None;
}
match self.mode {
Mode::Machine => Some(Interrupt::MachineExternalInterrupt(irq)),
Mode::Supervisor => Some(Interrupt::SupervisorExternalInterrupt(irq)),
Mode::User => Some(Interrupt::UserExternalInterrupt(irq)),
_ => Some(Interrupt::MachineExternalInterrupt(irq)),
}
}
pub fn translate(&mut self, addr: usize) -> Result<usize, Exception> {
if !self.enable_paging {
return Ok(addr);
}
let levels = 3;
let vpn = [
(addr >> 12) & 0x1ff,
(addr >> 21) & 0x1ff,
(addr >> 30) & 0x1ff,
];
let mut a = self.page_table;
let mut i: i32 = levels - 1;
let mut pte;
loop {
pte = self.bus.read64(a + vpn[i as usize] * 8)?;
let v = pte & 1;
let r = (pte >> 1) & 1;
let w = (pte >> 2) & 1;
let x = (pte >> 3) & 1;
if v == 0 || (r == 0 && w == 1) {
return Err(Exception::InstructionPageFault);
}
if r == 1 || x == 1 {
break;
}
i -= 1;
let ppn = (pte >> 10) & 0x0fff_ffff_ffff;
a = ppn as usize * PAGE_SIZE;
if i < 0 {
return Err(Exception::InstructionPageFault);
}
}
let offset = addr & 0xfff;
return Ok(if i > 0 {
let ppn = [
((pte >> 10) & 0x1ff) as usize,
((pte >> 19) & 0x1ff) as usize,
((pte >> 28) & 0x03ff_ffff) as usize,
];
(ppn[2] << 30) | (ppn[1] << 21) | (vpn[0] << 12) | offset
} else {
let ppn = (pte >> 10) & 0x0fff_ffff_ffff;
(ppn << 12) as usize | offset
});
}
pub fn read8(&mut self, v_addr: usize) -> Result<u8, Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.read8(p_addr)
}
pub fn read16(&mut self, v_addr: usize) -> Result<u16, Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.read16(p_addr)
}
pub fn read32(&mut self, v_addr: usize) -> Result<u32, Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.read32(p_addr)
}
pub fn read64(&mut self, v_addr: usize) -> Result<u64, Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.read64(p_addr)
}
pub fn write8(&mut self, v_addr: usize, val: u8) -> Result<(), Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.write8(p_addr, val)
}
pub fn write16(&mut self, v_addr: usize, val: u16) -> Result<(), Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.write16(p_addr, val)
}
pub fn write32(&mut self, v_addr: usize, val: u32) -> Result<(), Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.write32(p_addr, val)
}
pub fn write64(&mut self, v_addr: usize, val: u64) -> Result<(), Exception> {
let p_addr = self.translate(v_addr)?;
self.bus.write64(p_addr, val)
}
pub fn fetch(&mut self) -> Result<u32, Exception> {
self.read32(self.pc)
}
pub fn execute(&mut self, inst: u32) -> Result<(), Exception> {
let opcode = inst & 0x0000007f;
let rd = ((inst & 0x00000f80) >> 7) as usize;
let rs1 = ((inst & 0x000f8000) >> 15) as usize;
let rs2 = ((inst & 0x01f00000) >> 20) as usize;
let funct3 = (inst & 0x00007000) >> 12;
let funct7 = (inst & 0xfe000000) >> 25;
match opcode {
0x03 => {
let offset = (match inst & 0x80000000 {
0x80000000 => 0xfffff800,
_ => 0,
} | ((inst >> 20) & 0x000007ff)) as i32 as i64;
let addr = self.xregs.read(rs1).wrapping_add(offset) as usize;
match funct3 {
0x0 => {
let val = (self.read8(addr)? as i8) as i64;
self.xregs.write(rd, val);
}
0x1 => {
let val = (self.read16(addr)? as i16) as i64;
self.xregs.write(rd, val);
}
0x2 => {
let val = (self.read32(addr)? as i32) as i64;
self.xregs.write(rd, val);
}
0x3 => {
let val = self.read64(addr)? as i64;
self.xregs.write(rd, val);
}
0x4 => {
let val = (self.read8(addr)? as i64) & 0xff;
self.xregs.write(rd, val);
}
0x5 => {
let val = (self.read16(addr)? as i64) & 0xffff;
self.xregs.write(rd, val);
}
0x6 => {
let val = (self.read32(addr)? as i64) & 0xffffffff;
self.xregs.write(rd, val);
}
_ => {}
}
}
0x07 => {
let offset = ((inst & 0xfff00000) as u64) >> 20;
let addr = (self.xregs.read(rs1) + offset as i64) as usize;
match funct3 {
0x2 => {
let val = f64::from_bits(self.read64(addr)? as u64);
self.fregs.write(rd, val);
}
0x3 => {
let val = f64::from_bits(self.read64(addr)?);
self.fregs.write(rd, val);
}
_ => {}
}
}
0x0F => {
match funct3 {
0x0 => {}
0x1 => {}
_ => {}
}
}
0x13 => {
let imm = (((inst & 0xfff00000) as i32) as i64) >> 20;
let shamt = (inst & 0x03f00000) >> 20;
let funct6 = funct7 >> 1;
match funct3 {
0x0 => self.xregs.write(rd, self.xregs.read(rs1).wrapping_add(imm)),
0x1 => self
.xregs
.write(rd, ((self.xregs.read(rs1) as u64) << shamt) as i64),
0x2 => self
.xregs
.write(rd, if self.xregs.read(rs1) < imm { 1 } else { 0 }),
0x3 => {
self.xregs.write(
rd,
if (self.xregs.read(rs1) as u64) < (imm as u64) {
1
} else {
0
},
);
}
0x4 => self.xregs.write(rd, self.xregs.read(rs1) ^ imm),
0x5 => {
match funct6 {
0x00 => self
.xregs
.write(rd, ((self.xregs.read(rs1) as u64) >> shamt) as i64),
0x10 => self.xregs.write(rd, self.xregs.read(rs1) >> shamt),
_ => {}
}
}
0x6 => self.xregs.write(rd, self.xregs.read(rs1) | imm),
0x7 => self.xregs.write(rd, self.xregs.read(rs1) & imm),
_ => {}
}
}
0x17 => {
let imm = ((inst & 0xfffff000) as i32) as i64;
self.xregs.write(rd, (self.pc as i64) + imm - 4);
}
0x1B => {
let imm = (((inst & 0xfff00000) as i32) as i64) >> 20;
let shamt = imm & 0x1f;
match funct3 {
0x0 => {
self.xregs.write(
rd,
(((self.xregs.read(rs1).wrapping_add(imm)) & 0xffffffff) as i32) as i64,
);
}
0x1 => self.xregs.write(
rd,
(((self.xregs.read(rs1) << shamt) & 0xffffffff) as i32) as i64,
),
0x5 => {
match funct7 {
0x00 => {
self.xregs.write(
rd,
(((self.xregs.read(rs1) as u32) >> shamt) as i32) as i64,
)
}
0x20 => self
.xregs
.write(rd, ((self.xregs.read(rs1) as i32) >> shamt) as i64),
_ => {}
}
}
_ => {}
}
}
0x23 => {
let offset = (
match inst & 0x80000000 {
0x80000000 => 0xfffff800,
_ => 0
} |
((inst & 0xfe000000) >> 20) |
((inst & 0x00000f80) >> 7)
) as i32 as i64;
let addr = (self.xregs.read(rs1) + offset) as usize;
match funct3 {
0x0 => self.write8(addr, self.xregs.read(rs2) as u8)?,
0x1 => self.write16(addr, self.xregs.read(rs2) as u16)?,
0x2 => self.write32(addr, self.xregs.read(rs2) as u32)?,
0x3 => {
self.write64(addr, self.xregs.read(rs2) as u64)?;
}
_ => {}
}
}
0x27 => {
let imm11_5 = (((inst & 0xfe000000) as i32) as i64) >> 25;
let imm4_0 = ((inst & 0x00000f80) >> 7) as u64;
let offset = (((imm11_5 << 5) as u64) | imm4_0) as i64;
let addr = (self.xregs.read(rs1) + offset) as usize;
match funct3 {
0x2 => self
.bus
.write32(addr, (self.fregs.read(rs2) as f32).to_bits())?,
0x3 => self.write64(addr, self.fregs.read(rs2).to_bits())?,
_ => {}
}
}
0x2F => {
let funct5 = (funct7 & 0b1111100) >> 2;
let _aq = (funct7 & 0b0000010) >> 1;
let _rl = funct7 & 0b0000001;
match (funct3, funct5) {
(0x2, 0x00) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.write32(
self.xregs.read(rs1) as usize,
(t.wrapping_add(self.xregs.read(rs2) as i32)) as u32,
)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x00) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.write64(
self.xregs.read(rs1) as usize,
t.wrapping_add(self.xregs.read(rs2)) as u64,
)?;
self.xregs.write(rd, t);
}
(0x2, 0x01) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.bus
.write32(self.xregs.read(rs1) as usize, self.xregs.read(rs2) as u32)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x01) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.bus
.write64(self.xregs.read(rs1) as usize, self.xregs.read(rs2) as u64)?;
self.xregs.write(rd, t);
}
(0x2, 0x02) => {
let addr = self.read32(self.xregs.read(rs1) as usize)?;
self.xregs.write(rd, addr as i32 as i64);
}
(0x3, 0x02) => {
let addr = self.read32(self.xregs.read(rs1) as usize)?;
self.xregs.write(rd, addr as i64);
}
(0x2, 0x03) => {
let addr = self.read32(self.xregs.read(rs1) as usize)?;
let src = self.read32(self.xregs.read(rs2) as usize)?;
self.xregs.write(rd, 0);
self.bus.write32(addr as usize, src as u32)?;
}
(0x3, 0x03) => {
let addr = self.read32(self.xregs.read(rs1) as usize)?;
let src = self.read32(self.xregs.read(rs2) as usize)?;
self.xregs.write(rd, 0);
self.bus.write64(addr as usize, src as u64)?;
}
(0x2, 0x04) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.write32(
self.xregs.read(rs1) as usize,
(t ^ (self.xregs.read(rs2) as i32)) as u32,
)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x04) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.write64(
self.xregs.read(rs1) as usize,
(t ^ self.xregs.read(rs2)) as u64,
)?;
self.xregs.write(rd, t);
}
(0x2, 0x08) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.write32(
self.xregs.read(rs1) as usize,
(t | (self.xregs.read(rs2) as i32)) as u32,
)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x08) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.write64(
self.xregs.read(rs1) as usize,
(t | self.xregs.read(rs2)) as u64,
)?;
self.xregs.write(rd, t);
}
(0x2, 0x0c) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.write32(
self.xregs.read(rs1) as usize,
(t & (self.xregs.read(rs2) as i32)) as u32,
)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x0c) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.write64(
self.xregs.read(rs1) as usize,
(t & self.xregs.read(rs1)) as u64,
)?;
self.xregs.write(rd, t);
}
(0x2, 0x10) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.write32(
self.xregs.read(rs1) as usize,
cmp::min(t, self.xregs.read(rs2) as i32) as u32,
)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x10) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.write64(
self.xregs.read(rs1) as usize,
cmp::min(t, self.xregs.read(rs2)) as u64,
)?;
self.xregs.write(rd, t);
}
(0x2, 0x14) => {
let t = self.read32(self.xregs.read(rs1) as usize)? as i32;
self.write32(
self.xregs.read(rs1) as usize,
cmp::max(t, self.xregs.read(rs2) as i32) as u32,
)?;
self.xregs.write(rd, t as i64);
}
(0x3, 0x14) => {
let t = self.read64(self.xregs.read(rs1) as usize)? as i64;
self.write64(
self.xregs.read(rs1) as usize,
cmp::max(t, self.xregs.read(rs2)) as u64,
)?;
self.xregs.write(rd, t);
}
(0x2, 0x18) => {
let t = self.read32(self.xregs.read(rs1) as usize)?;
self.write32(
self.xregs.read(rs1) as usize,
cmp::min(t, self.xregs.read(rs2) as u32),
)?;
self.xregs.write(rd, (t as i32) as i64);
}
(0x3, 0x18) => {
let t = self.read64(self.xregs.read(rs1) as usize)?;
self.write64(
self.xregs.read(rs1) as usize,
cmp::min(t, self.xregs.read(rs2) as u64),
)?;
self.xregs.write(rd, t as i64);
}
(0x2, 0x1c) => {
let t = self.read32(self.xregs.read(rs1) as usize)?;
self.write32(
self.xregs.read(rs1) as usize,
cmp::max(t, self.xregs.read(rs2) as u32),
)?;
self.xregs.write(rd, (t as i32) as i64);
}
(0x3, 0x1c) => {
let t = self.read64(self.xregs.read(rs1) as usize)?;
self.write64(
self.xregs.read(rs1) as usize,
cmp::max(t, self.xregs.read(rs2) as u64),
)?;
self.xregs.write(rd, t as i64);
}
_ => {}
}
}
0x33 => {
let shamt = ((self.xregs.read(rs2) & 0x3f) as u64) as u32;
match (funct3, funct7) {
(0x0, 0x00) => self
.xregs
.write(rd, self.xregs.read(rs1).wrapping_add(self.xregs.read(rs2))),
(0x0, 0x01) => self
.xregs
.write(rd, self.xregs.read(rs1).wrapping_mul(self.xregs.read(rs2))),
(0x0, 0x20) => self
.xregs
.write(rd, self.xregs.read(rs1).wrapping_sub(self.xregs.read(rs2))),
(0x1, 0x00) => self
.xregs
.write(rd, self.xregs.read(rs1).wrapping_shl(shamt)),
(0x1, 0x01) => {
self.xregs.write(
rd,
((self.xregs.read(rs1) as i128)
.wrapping_mul(self.xregs.read(rs2) as i128)
>> 64) as i64,
);
}
(0x2, 0x00) => self.xregs.write(
rd,
if self.xregs.read(rs1) < self.xregs.read(rs2) {
1
} else {
0
},
),
(0x2, 0x01) => {
self.xregs.write(
rd,
((self.xregs.read(rs1) as u128)
.wrapping_mul((self.xregs.read(rs2) as u64) as u128)
>> 64) as i64,
);
}
(0x3, 0x00) => {
self.xregs.write(
rd,
if (self.xregs.read(rs1) as u64) < (self.xregs.read(rs2) as u64) {
1
} else {
0
},
);
}
(0x3, 0x01) => {
self.xregs.write(
rd,
(((self.xregs.read(rs1) as u64) as u128)
.wrapping_mul((self.xregs.read(rs2) as u64) as u128)
>> 64) as i128 as i64,
);
}
(0x4, 0x00) => self
.xregs
.write(rd, self.xregs.read(rs1) ^ self.xregs.read(rs2)),
(0x4, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => {
self.state.write_bit(FCSR, 3, true);
-1
}
_ => self.xregs.read(rs1).wrapping_div(self.xregs.read(rs2)),
},
);
}
(0x5, 0x00) => self
.xregs
.write(rd, ((self.xregs.read(rs1) as u64) >> shamt) as i64),
(0x5, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => {
self.state.write_bit(FCSR, 3, true);
-1
}
_ => {
let dividend = self.xregs.read(rs1) as u64;
let divisor = self.xregs.read(rs2) as u64;
dividend.wrapping_div(divisor) as i64
}
},
);
}
(0x5, 0x20) => self.xregs.write(rd, self.xregs.read(rs1) >> shamt),
(0x6, 0x00) => self
.xregs
.write(rd, self.xregs.read(rs1) | self.xregs.read(rs2)),
(0x6, 0x01) => self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => self.xregs.read(rs1),
_ => self.xregs.read(rs1).wrapping_rem(self.xregs.read(rs2)),
},
),
(0x7, 0x00) => self
.xregs
.write(rd, self.xregs.read(rs1) & self.xregs.read(rs2)),
(0x7, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => self.xregs.read(rs1),
_ => {
let dividend = self.xregs.read(rs1) as u64;
let divisor = self.xregs.read(rs2) as u64;
dividend.wrapping_rem(divisor) as i64
}
},
);
}
_ => {}
};
}
0x37 => {
self.xregs.write(rd, ((inst & 0xfffff000) as i32) as i64);
}
0x3B => {
let shamt = (self.xregs.read(rs2) & 0x1f) as u32;
match (funct3, funct7) {
(0x0, 0x00) => {
self.xregs.write(
rd,
((self.xregs.read(rs1).wrapping_add(self.xregs.read(rs2))) as i32)
as i64,
);
}
(0x0, 0x01) => {
let n1 = self.xregs.read(rs1) as i32;
let n2 = self.xregs.read(rs2) as i32;
let result = n1.wrapping_mul(n2);
self.xregs.write(rd, result as i64);
}
(0x0, 0x20) => {
self.xregs.write(
rd,
((self.xregs.read(rs1).wrapping_sub(self.xregs.read(rs2))) as i32)
as i64,
);
}
(0x1, 0x00) => self
.xregs
.write(rd, (((self.xregs.read(rs1) as u32) << shamt) as i32) as i64),
(0x4, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => {
self.state.write_bit(FCSR, 3, true);
-1
}
_ => {
let dividend = self.xregs.read(rs1) as i32;
let divisor = self.xregs.read(rs2) as i32;
dividend.wrapping_div(divisor) as i64
}
},
);
}
(0x5, 0x00) => self
.xregs
.write(rd, (((self.xregs.read(rs1) as u32) >> shamt) as i32) as i64),
(0x5, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => {
self.state.write_bit(FCSR, 3, true);
-1
}
_ => {
let dividend = self.xregs.read(rs1) as u32;
let divisor = self.xregs.read(rs2) as u32;
(dividend.wrapping_div(divisor) as i32) as i64
}
},
);
}
(0x5, 0x20) => self
.xregs
.write(rd, ((self.xregs.read(rs1) as i32) >> (shamt as i32)) as i64),
(0x6, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => self.xregs.read(rs1),
_ => {
let dividend = self.xregs.read(rs1) as i32;
let divisor = self.xregs.read(rs2) as i32;
dividend.wrapping_rem(divisor) as i64
}
},
);
}
(0x7, 0x01) => {
self.xregs.write(
rd,
match self.xregs.read(rs2) {
0 => self.xregs.read(rs1),
_ => {
let dividend = self.xregs.read(rs1) as u64 as u32;
let divisor = self.xregs.read(rs2) as u64 as u32;
dividend.wrapping_rem(divisor) as i32 as i64
}
},
);
}
_ => {}
}
}
0x43 => {
let rs3 = ((inst & 0xf8000000) >> 27) as usize;
let funct2 = (inst & 0x03000000) >> 25;
match funct2 {
0x0 => {
self.fregs.write(
rd,
(self.fregs.read(rs1) as f32)
.mul_add(self.fregs.read(rs2) as f32, self.fregs.read(rs3) as f32)
as f64,
);
}
0x1 => self.fregs.write(
rd,
self.fregs
.read(rs1)
.mul_add(self.fregs.read(rs2), self.fregs.read(rs3)),
),
_ => {}
}
}
0x47 => {
let rs3 = ((inst & 0xf8000000) >> 27) as usize;
let funct2 = (inst & 0x03000000) >> 25;
match funct2 {
0x0 => {
self.fregs.write(
rd,
(self.fregs.read(rs1) as f32)
.mul_add(self.fregs.read(rs2) as f32, -self.fregs.read(rs3) as f32)
as f64,
);
}
0x1 => self.fregs.write(
rd,
self.fregs
.read(rs1)
.mul_add(self.fregs.read(rs2), -self.fregs.read(rs3)),
),
_ => {}
}
}
0x4B => {
let rs3 = ((inst & 0xf8000000) >> 27) as usize;
let funct2 = (inst & 0x03000000) >> 25;
match funct2 {
0x0 => {
self.fregs.write(
rd,
(-self.fregs.read(rs1) as f32)
.mul_add(self.fregs.read(rs2) as f32, self.fregs.read(rs3) as f32)
as f64,
);
}
0x1 => self.fregs.write(
rd,
(-self.fregs.read(rs1)).mul_add(self.fregs.read(rs2), self.fregs.read(rs3)),
),
_ => {}
}
}
0x4F => {
let rs3 = ((inst & 0xf8000000) >> 27) as usize;
let funct2 = (inst & 0x03000000) >> 25;
match funct2 {
0x0 => {
self.fregs.write(
rd,
(-self.fregs.read(rs1) as f32)
.mul_add(self.fregs.read(rs2) as f32, -self.fregs.read(rs3) as f32)
as f64,
);
}
0x1 => self.fregs.write(
rd,
(-self.fregs.read(rs1))
.mul_add(self.fregs.read(rs2), -self.fregs.read(rs3)),
),
_ => {}
}
}
0x53 => {
match self.state.read_bits(FCSR, 5..8) {
0b000 => {}
0b001 => {}
0b010 => {}
0b011 => {}
0b100 => {}
0b111 => {}
_ => {
return Err(Exception::IllegalInstruction(String::from(
"frm is set to an invalid value (101–110)",
)));
}
}
match funct7 {
0x00 => {
self.fregs.write(
rd,
(self.fregs.read(rs1) as f32 + self.fregs.read(rs2) as f32) as f64,
)
}
0x01 => self
.fregs
.write(rd, self.fregs.read(rs1) + self.fregs.read(rs2)),
0x04 => {
self.fregs.write(
rd,
(self.fregs.read(rs1) as f32 - self.fregs.read(rs2) as f32) as f64,
)
}
0x05 => self
.fregs
.write(rd, self.fregs.read(rs1) - self.fregs.read(rs2)),
0x08 => {
self.fregs.write(
rd,
(self.fregs.read(rs1) as f32 * self.fregs.read(rs2) as f32) as f64,
)
}
0x09 => self
.fregs
.write(rd, self.fregs.read(rs1) * self.fregs.read(rs2)),
0x0c => {
self.fregs.write(
rd,
(self.fregs.read(rs1) as f32 / self.fregs.read(rs2) as f32) as f64,
)
}
0x0d => self
.fregs
.write(rd, self.fregs.read(rs1) / self.fregs.read(rs2)),
0x10 => {
match funct3 {
0x0 => self
.fregs
.write(rd, self.fregs.read(rs1).copysign(self.fregs.read(rs2))),
0x1 => self
.fregs
.write(rd, self.fregs.read(rs1).copysign(-self.fregs.read(rs2))),
0x2 => {
let sign1 = (self.fregs.read(rs1) as f32).to_bits() & 0x80000000;
let sign2 = (self.fregs.read(rs2) as f32).to_bits() & 0x80000000;
let other = (self.fregs.read(rs1) as f32).to_bits() & 0x7fffffff;
self.fregs
.write(rd, f32::from_bits((sign1 ^ sign2) | other) as f64);
}
_ => {}
}
}
0x11 => {
match funct3 {
0x0 => self
.fregs
.write(rd, self.fregs.read(rs1).copysign(self.fregs.read(rs2))),
0x1 => self
.fregs
.write(rd, self.fregs.read(rs1).copysign(-self.fregs.read(rs2))),
0x2 => {
let sign1 = self.fregs.read(rs1).to_bits() & 0x80000000_00000000;
let sign2 = self.fregs.read(rs2).to_bits() & 0x80000000_00000000;
let other = self.fregs.read(rs1).to_bits() & 0x7fffffff_ffffffff;
self.fregs
.write(rd, f64::from_bits((sign1 ^ sign2) | other));
}
_ => {}
}
}
0x14 => {
match funct3 {
0x0 => self
.fregs
.write(rd, self.fregs.read(rs1).min(self.fregs.read(rs2))),
0x1 => self
.fregs
.write(rd, self.fregs.read(rs1).max(self.fregs.read(rs2))),
_ => {}
}
}
0x15 => {
match funct3 {
0x0 => self
.fregs
.write(rd, self.fregs.read(rs1).min(self.fregs.read(rs2))),
0x1 => self
.fregs
.write(rd, self.fregs.read(rs1).max(self.fregs.read(rs2))),
_ => {}
}
}
0x20 => self.fregs.write(rd, self.fregs.read(rs1)),
0x21 => self.fregs.write(rd, (self.fregs.read(rs1) as f32) as f64),
0x2c => self
.fregs
.write(rd, (self.fregs.read(rs1) as f32).sqrt() as f64),
0x2d => self.fregs.write(rd, self.fregs.read(rs1).sqrt()),
0x50 => {
match funct3 {
0x0 => self.xregs.write(
rd,
if self.fregs.read(rs1) <= self.fregs.read(rs2) {
1
} else {
0
},
),
0x1 => self.xregs.write(
rd,
if self.fregs.read(rs1) < self.fregs.read(rs2) {
1
} else {
0
},
),
0x2 => self.xregs.write(
rd,
if self.fregs.read(rs1) == self.fregs.read(rs2) {
1
} else {
0
},
),
_ => {}
}
}
0x51 => {
match funct3 {
0x0 => self.xregs.write(
rd,
if self.fregs.read(rs1) <= self.fregs.read(rs2) {
1
} else {
0
},
),
0x1 => self.xregs.write(
rd,
if self.fregs.read(rs1) < self.fregs.read(rs2) {
1
} else {
0
},
),
0x2 => self.xregs.write(
rd,
if self.fregs.read(rs1) == self.fregs.read(rs2) {
1
} else {
0
},
),
_ => {}
}
}
0x60 => {
match rs2 {
0x0 => self
.xregs
.write(rd, ((self.fregs.read(rs1) as f32).round() as i32) as i64),
0x1 => self.xregs.write(
rd,
(((self.fregs.read(rs1) as f32).round() as u32) as i32) as i64,
),
0x2 => self
.xregs
.write(rd, (self.fregs.read(rs1) as f32).round() as i64),
0x3 => self
.xregs
.write(rd, ((self.fregs.read(rs1) as f32).round() as u64) as i64),
_ => {}
}
}
0x61 => {
match rs2 {
0x0 => self
.xregs
.write(rd, (self.fregs.read(rs1).round() as i32) as i64),
0x1 => self
.xregs
.write(rd, ((self.fregs.read(rs1).round() as u32) as i32) as i64),
0x2 => self.xregs.write(rd, self.fregs.read(rs1).round() as i64),
0x3 => self
.xregs
.write(rd, (self.fregs.read(rs1).round() as u64) as i64),
_ => {}
}
}
0x68 => {
match rs2 {
0x0 => self
.fregs
.write(rd, ((self.xregs.read(rs1) as i32) as f32) as f64),
0x1 => self
.fregs
.write(rd, ((self.xregs.read(rs1) as u32) as f32) as f64),
0x2 => self.fregs.write(rd, (self.xregs.read(rs1) as f32) as f64),
0x3 => self
.fregs
.write(rd, ((self.xregs.read(rs1) as u64) as f32) as f64),
_ => {}
}
}
0x69 => {
match rs2 {
0x0 => self.fregs.write(rd, (self.xregs.read(rs1) as i32) as f64),
0x1 => self.fregs.write(rd, (self.xregs.read(rs1) as u32) as f64),
0x2 => self.fregs.write(rd, self.xregs.read(rs1) as f64),
0x3 => self.fregs.write(rd, (self.xregs.read(rs1) as u64) as f64),
_ => {}
}
}
0x70 => {
match funct3 {
0x0 => self.xregs.write(rd, (self.fregs.read(rs1) as i32) as i64),
0x1 => {
let f = self.fregs.read(rs1);
match f.classify() {
FpCategory::Infinite => {
self.xregs
.write(rd, if f.is_sign_negative() { 0 } else { 7 });
}
FpCategory::Normal => {
self.xregs
.write(rd, if f.is_sign_negative() { 1 } else { 6 });
}
FpCategory::Subnormal => {
self.xregs
.write(rd, if f.is_sign_negative() { 2 } else { 5 });
}
FpCategory::Zero => {
self.xregs
.write(rd, if f.is_sign_negative() { 3 } else { 4 });
}
FpCategory::Nan => self.xregs.write(rd, 9),
}
}
_ => {}
}
}
0x71 => {
match funct3 {
0x0 => self.xregs.write(rd, self.fregs.read(rs1) as i64),
0x1 => {
let f = self.fregs.read(rs1);
match f.classify() {
FpCategory::Infinite => {
self.xregs
.write(rd, if f.is_sign_negative() { 0 } else { 7 });
}
FpCategory::Normal => {
self.xregs
.write(rd, if f.is_sign_negative() { 1 } else { 6 });
}
FpCategory::Subnormal => {
self.xregs
.write(rd, if f.is_sign_negative() { 2 } else { 5 });
}
FpCategory::Zero => {
self.xregs
.write(rd, if f.is_sign_negative() { 3 } else { 4 });
}
FpCategory::Nan => self.xregs.write(rd, 9),
}
}
_ => {}
}
}
0x78 => self
.fregs
.write(rd, ((self.xregs.read(rs1) as i32) as f32) as f64),
0x79 => self.fregs.write(rd, self.xregs.read(rs1) as f64),
_ => {}
}
}
0x63 => {
let imm12 = (((inst & 0x80000000) as i32) as i64) >> 31;
let imm10_5 = ((inst & 0x7e000000) >> 25) as u64;
let imm4_1 = ((inst & 0x00000f00) >> 8) as u64;
let imm11 = ((inst & 0x00000080) >> 7) as u64;
let offset =
((imm12 << 12) as u64 | (imm11 << 11) | (imm10_5 << 5) | (imm4_1 << 1)) as i64;
match funct3 {
0x0 => {
if self.xregs.read(rs1) == self.xregs.read(rs2) {
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
}
0x1 => {
if self.xregs.read(rs1) != self.xregs.read(rs2) {
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
}
0x4 => {
if self.xregs.read(rs1) < self.xregs.read(rs2) {
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
}
0x5 => {
if self.xregs.read(rs1) >= self.xregs.read(rs2) {
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
}
0x6 => {
if (self.xregs.read(rs1) as u64) < (self.xregs.read(rs2) as u64) {
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
}
0x7 => {
if (self.xregs.read(rs1) as u64) >= (self.xregs.read(rs2) as u64) {
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
}
_ => {}
}
}
0x67 => {
let t = self.pc as i64;
let imm = (((inst & 0xfff00000) as i32) as i64) >> 20;
let target = (self.xregs.read(rs1).wrapping_add(imm)) & !1;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
self.xregs.write(rd, t);
}
0x6F => {
self.xregs.write(rd, self.pc as i64);
let imm20 = (((inst & 0x80000000) as i32) as i64) >> 31;
let imm10_1 = ((inst & 0x7fe00000) >> 21) as u64;
let imm11 = ((inst & 0x100000) >> 20) as u64;
let imm19_12 = ((inst & 0xff000) >> 12) as u64;
let offset =
((imm20 << 20) as u64 | (imm19_12 << 12) | (imm11 << 11) | (imm10_1 << 1))
as i64;
let target = (self.pc as i64) + offset - 4;
if target % 4 != 0 {
return Err(Exception::InstructionAddressMisaligned);
}
self.pc = target as usize;
}
0x73 => {
let csr_addr = ((inst & 0xfff00000) >> 20) as u16;
match funct3 {
0x0 => {
match (rs2, funct7) {
(0x0, 0x0) => {
match self.mode {
Mode::User => {
return Err(Exception::EnvironmentCallFromUMode);
}
Mode::Supervisor => {
return Err(Exception::EnvironmentCallFromSMode);
}
Mode::Machine => {
return Err(Exception::EnvironmentCallFromMMode);
}
_ => {}
}
}
(0x1, 0x0) => {
return Err(Exception::Breakpoint);
}
(0x2, 0x0) => {
dbg!("uret: not implemented yet. pc {}", self.pc);
}
(0x2, 0x8) => {
self.mode.require(Mode::Supervisor)?;
self.pc = self.state.read(SEPC) as usize;
self.mode = match self.state.read_bit(SSTATUS, 8) {
false => Mode::User,
true => Mode::Supervisor,
};
self.state
.write_bit(SSTATUS, 1, self.state.read_bit(SSTATUS, 5));
self.state.write_bit(SSTATUS, 5, true);
self.state.write_bit(SSTATUS, 8, false);
}
(0x2, 0x18) => {
self.mode.require(Mode::Machine)?;
self.pc = self.state.read(MEPC) as usize;
self.mode = match self.state.read_bits(MSTATUS, 11..13) {
0b00 => Mode::User,
0b01 => Mode::Supervisor,
0b11 => Mode::Machine,
_ => Mode::Debug,
};
self.state
.write_bit(MSTATUS, 3, self.state.read_bit(MSTATUS, 7));
self.state.write_bit(MSTATUS, 7, true);
self.state.write_bits(MSTATUS, 11..13, 0b00);
}
(0x5, 0x8) => {}
(_, 0x9) => {}
(_, 0x11) => {}
(_, 0x51) => {}
_ => {}
}
}
0x1 => {
let t = self.state.read(csr_addr);
self.state.write(csr_addr, self.xregs.read(rs1));
self.xregs.write(rd, t);
if csr_addr == SATP {
self.page_table = self.state.read_bits(SATP, ..44) as usize * PAGE_SIZE;
let mode = self.state.read_bits(SATP, 60..);
if mode == 8 {
self.enable_paging = true;
} else {
self.enable_paging = false;
}
}
}
0x2 => {
self.xregs.write(rd, self.state.read(csr_addr));
self.state
.write(csr_addr, self.xregs.read(rd) | self.xregs.read(rs1));
}
0x3 => {
self.xregs.write(rd, self.state.read(csr_addr));
self.state
.write(csr_addr, self.xregs.read(rd) & (!self.xregs.read(rs1)));
}
0x5 => {
let uimm = rs1 as u64 as i64;
self.xregs.write(rd, self.state.read(csr_addr));
self.state.write(csr_addr, uimm);
if csr_addr == SATP {
self.page_table = self.state.read_bits(SATP, ..44) as usize * PAGE_SIZE;
let mode = self.state.read_bits(SATP, 60..);
if mode == 8 {
self.enable_paging = true;
} else {
self.enable_paging = false;
}
}
}
0x6 => {
let uimm = rs1 as u64 as i64;
self.xregs.write(rd, self.state.read(csr_addr));
self.state.write(csr_addr, self.xregs.read(rd) | uimm);
}
0x7 => {
let uimm = rs1 as u64 as i64;
self.xregs.write(rd, self.state.read(csr_addr));
self.state.write(csr_addr, self.xregs.read(rd) & (!uimm));
}
_ => {}
}
}
_ => {
return Err(Exception::IllegalInstruction(String::from(
"instruction not found",
)));
}
}
Ok(())
}
}