use crate::register::{Register,Register32,RegisterWidth};
use crate::{variant,Variant};
pub struct Core<R: Register> {
registers: [R; 32],
pub pc: R
}
impl<R: Register + Default + Copy + Clone> Core<R> {
pub fn new(address: R::Unsigned) -> Self {
Self {
registers: [Default::default(); 32],
pc: R::from_unsigned(address)
}
}
pub fn step(&mut self) {
self.pc = self.pc.add_unsigned(R::zero_extended_byte(4))
}
#[inline(always)]
pub fn get(&self, index: usize) -> R {
self.registers[index]
}
#[inline(always)]
pub fn set(&mut self, index: usize, register: R) {
if index > 0 {
self.registers[index] = register
}
}
pub fn execute(&mut self, instruction: [u8; 4], mmu: &mut dyn Mmu<R>) -> Result<(), DecodeError> {
let opcode = instruction[0] & 0x7F;
let funct3 = (instruction[1] & 0x70) >> 4;
let funct7 = (instruction[3] & 0xFE) >> 1;
match (opcode, funct3, funct7) {
(0b0110011, 0b000, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).add_unsigned(self.get(source2)));
Ok(self.step())
},
(0b0111011, 0b000, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, R::sign_extended_word(Register32(self.get(source1).word()).add_unsigned(Register32(self.get(source2).word())).word()));
Ok(self.step())
},
(0b0110011, 0b000, 0b0100000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).sub_unsigned(self.get(source2)));
Ok(self.step())
},
(0b0111011, 0b000, 0b0100000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, R::sign_extended_word(Register32(self.get(source1).word()).sub_unsigned(Register32(self.get(source2).word())).word()));
Ok(self.step())
},
(0b0110011, 0b010, _) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, if self.get(source1).lt_signed(self.get(source2)) { R::zero_extended_byte(1) } else { R::zero_extended_byte(0) });
Ok(self.step())
},
(0b0110011, 0b011, _) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, if self.get(source1).lt_unsigned(self.get(source2)) { R::zero_extended_byte(1) } else { R::zero_extended_byte(0) });
Ok(self.step())
},
(0b0010011, 0b000, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).add_signed(immediate));
Ok(self.step())
},
(0b0011011, 0b000, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, R::sign_extended_word(Register32(self.get(source).word()).add_signed(immediate).word()));
Ok(self.step())
},
(0b0010011, 0b010, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, if self.get(source).lt_signed(immediate) { R::zero_extended_byte(1) } else { R::zero_extended_byte(0) });
Ok(self.step())
},
(0b0010011, 0b011, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, if self.get(source).lt_unsigned(immediate) { R::zero_extended_byte(1) } else { R::zero_extended_byte(0) });
Ok(self.step())
},
(0b0110011, 0b100, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).xor(self.get(source2)));
Ok(self.step())
},
(0b0110011, 0b110, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).or(self.get(source2)));
Ok(self.step())
},
(0b0110011, 0b111, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).and(self.get(source2)));
Ok(self.step())
},
(0b0010011, 0b100, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).xor(immediate));
Ok(self.step())
},
(0b0010011, 0b110, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).or(immediate));
Ok(self.step())
},
(0b0010011, 0b111, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).and(immediate));
Ok(self.step())
},
(0b0110011, 0b001, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).shl(self.get(source2)));
Ok(self.step())
},
(0b0111011, 0b001, 0b0000000) if R::WIDTH != RegisterWidth::Bits32 => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, R::sign_extended_word(Register32(self.get(source1).word()).shl(Register32(self.get(source2).word())).word()));
Ok(self.step())
},
(0b0110011, 0b101, 0b0000000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).shr(self.get(source2)));
Ok(self.step())
},
(0b0111011, 0b101, 0b0000000) if R::WIDTH != RegisterWidth::Bits32 => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, R::sign_extended_word(Register32(self.get(source1).word()).shr(Register32(self.get(source2).word())).word()));
Ok(self.step())
},
(0b0110011, 0b101, 0b0100000) => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, self.get(source1).sha(self.get(source2)));
Ok(self.step())
},
(0b0111011, 0b101, 0b0100000) if R::WIDTH != RegisterWidth::Bits32 => {
let variant::R { destination, source1, source2 } = Variant::decode(instruction);
self.set(destination, R::sign_extended_word(Register32(self.get(source1).word()).sha(Register32(self.get(source2).word())).word()));
Ok(self.step())
},
(0b0010011, 0b001, _) => {
let variant::I::<R> { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).shl(immediate.and(R::zero_extended_byte(0x0E))));
Ok(self.step())
},
(0b0011011, 0b001, _) if R::WIDTH != RegisterWidth::Bits32 => {
let variant::I::<R> { destination, source, immediate } = Variant::decode(instruction);
if immediate.byte() & 0x20 != 0 {
Err(DecodeError::ShiftWordReservedBit)
} else {
self.set(destination, R::sign_extended_word(Register32(self.get(source).word()).shl(Register32(immediate.word()).and(Register32::zero_extended_byte(0x0E))).word()));
Ok(self.step())
}
},
(0b0010011, 0b101, _) if instruction[3] & 0x40 == 0 => {
let variant::I::<R> { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).shr(immediate.and(R::zero_extended_byte(0x0E))));
Ok(self.step())
},
(0b0011011, 0b101, _) if instruction[3] & 0x40 == 0 && R::WIDTH != RegisterWidth::Bits32 => {
let variant::I::<R> { destination, source, immediate } = Variant::decode(instruction);
if immediate.byte() & 0x20 != 0 {
Err(DecodeError::ShiftWordReservedBit)
} else {
self.set(destination, R::sign_extended_word(Register32(self.get(source).word()).shr(Register32(immediate.word()).and(Register32::zero_extended_byte(0x0E))).word()));
Ok(self.step())
}
},
(0b0010011, 0b101, _) if instruction[3] & 0x40 != 0 => {
let variant::I::<R> { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, self.get(source).sha(immediate.and(R::zero_extended_byte(0x0E))));
Ok(self.step())
},
(0b0011011, 0b101, _) if instruction[3] & 0x40 != 0 && R::WIDTH != RegisterWidth::Bits32 => {
let variant::I::<R> { destination, source, immediate } = Variant::decode(instruction);
if immediate.byte() & 0x20 != 0 {
Err(DecodeError::ShiftWordReservedBit)
} else {
self.set(destination, R::sign_extended_word(Register32(self.get(source).word()).sha(Register32(immediate.word()).and(Register32::zero_extended_byte(0x0E))).word()));
Ok(self.step())
}
},
(0b0110111, _, _) => {
let variant::U { destination, immediate } = Variant::decode(instruction);
self.set(destination, immediate);
Ok(self.step())
},
(0b0010111, _, _) => {
let variant::U { destination, immediate } = Variant::decode(instruction);
self.set(destination, self.pc.add_signed(immediate));
Ok(self.step())
},
(0b0000011, 0b000, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, R::sign_extended_byte(mmu.get(self.get(source).add_signed(immediate).unsigned())));
Ok(self.step())
},
(0b0000011, 0b100, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
self.set(destination, R::zero_extended_byte(mmu.get(self.get(source).add_signed(immediate).unsigned())));
Ok(self.step())
},
(0b0000011, 0b001, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
let address = self.get(source).add_signed(immediate);
self.set(destination, R::sign_extended_half([mmu.get(address.unsigned()), mmu.get(address.append(1))]));
Ok(self.step())
},
(0b0000011, 0b101, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
let address = self.get(source).add_signed(immediate);
self.set(destination, R::zero_extended_half([mmu.get(address.unsigned()), mmu.get(address.append(1))]));
Ok(self.step())
},
(0b0000011, 0b010, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
let address = self.get(source).add_signed(immediate);
self.set(destination, R::sign_extended_word([
mmu.get(address.unsigned()),
mmu.get(address.append(1)),
mmu.get(address.append(2)),
mmu.get(address.append(3))
]));
Ok(self.step())
},
(0b0000011, 0b110, _) if R::WIDTH != RegisterWidth::Bits32 => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
let address = self.get(source).add_signed(immediate);
self.set(destination, R::zero_extended_word([
mmu.get(address.unsigned()),
mmu.get(address.append(1)),
mmu.get(address.append(2)),
mmu.get(address.append(3))
]));
Ok(self.step())
},
(0b0000011, 0b011, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
let address = self.get(source).add_signed(immediate);
self.set(destination, R::sign_extended_double([
mmu.get(address.unsigned()),
mmu.get(address.append(1)),
mmu.get(address.append(2)),
mmu.get(address.append(3)),
mmu.get(address.append(4)),
mmu.get(address.append(5)),
mmu.get(address.append(6)),
mmu.get(address.append(7))
]));
Ok(self.step())
},
(0b0100011, 0b000, _) => {
let variant::S { source1, source2, immediate } = Variant::decode(instruction);
let address = self.get(source1).add_signed(immediate);
mmu.set(address.unsigned(), self.get(source2).byte());
Ok(self.step())
},
(0b0100011, 0b001, _) => {
let variant::S { source1, source2, immediate } = Variant::decode(instruction);
let address = self.get(source1).add_signed(immediate);
let half = self.get(source2).half();
mmu.set(address.unsigned(), half[0]);
mmu.set(address.append(1), half[1]);
Ok(self.step())
},
(0b0100011, 0b010, _) => {
let variant::S { source1, source2, immediate } = Variant::decode(instruction);
let address = self.get(source1).add_signed(immediate);
let word = self.get(source2).word();
mmu.set(address.unsigned(), word[0]);
mmu.set(address.append(1), word[1]);
mmu.set(address.append(2), word[2]);
mmu.set(address.append(3), word[3]);
Ok(self.step())
},
(0b1101111, _, _) => {
let variant::J { destination, immediate } = Variant::decode(instruction);
self.set(destination, self.pc.add_unsigned(R::zero_extended_byte(4)));
Ok(self.pc = self.pc.add_signed(immediate))
},
(0b1100111, 0b000, _) => {
let variant::I { destination, source, immediate } = Variant::decode(instruction);
let to_set = self.get(source).add_signed(immediate);
self.set(destination, self.pc.add_unsigned(R::zero_extended_byte(4)));
Ok(self.pc = to_set)
},
(0b1100011, 0b000, _) => {
let variant::B { source1, source2, immediate } = Variant::decode(instruction);
Ok(if self.get(source1).eq(self.get(source2)) { self.pc = self.pc.add_signed(immediate) } else { self.step() })
},
(0b1100011, 0b001, _) => {
let variant::B { source1, source2, immediate } = Variant::decode(instruction);
Ok(if self.get(source1).neq(self.get(source2)) { self.pc = self.pc.add_signed(immediate) } else { self.step() })
},
(0b1100011, 0b100, _) => {
let variant::B { source1, source2, immediate } = Variant::decode(instruction);
Ok(if self.get(source1).lt_signed(self.get(source2)) { self.pc = self.pc.add_signed(immediate) } else { self.step() })
},
(0b1100011, 0b110, _) => {
let variant::B { source1, source2, immediate } = Variant::decode(instruction);
Ok(if self.get(source1).lt_unsigned(self.get(source2)) { self.pc = self.pc.add_signed(immediate) } else { self.step() })
},
(0b1100011, 0b101, _) => {
let variant::B { source1, source2, immediate } = Variant::decode(instruction);
Ok(if self.get(source1).gte_signed(self.get(source2)) { self.pc = self.pc.add_signed(immediate) } else { self.step() })
},
(0b1100011, 0b111, _) => {
let variant::B { source1, source2, immediate } = Variant::decode(instruction);
Ok(if self.get(source1).gte_unsigned(self.get(source2)) { self.pc = self.pc.add_signed(immediate) } else { self.step() })
},
(opcode, funct3, funct7) => Err(DecodeError::UnknownInstruction(opcode, funct3, funct7))
}
}
}
pub trait Mmu<R: Register> {
fn get(&self, address: R::Unsigned) -> u8;
fn set(&mut self, address: R::Unsigned, value: u8);
}
pub enum DecodeError {
UnknownInstruction(u8, u8, u8),
ShiftWordReservedBit
}
impl std::fmt::Debug for DecodeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnknownInstruction(opcode, funct3, funct7) => write!(f, "UnknownInstruction(opcode: {:#b}, funct3: {:#b}, funct7: {:#b})", opcode, funct3, funct7),
Self::ShiftWordReservedBit => write!(f, "Shift *W instruction was used with immediate[5] set. This bit is reserved.")
}
}
}