]> Witch of Git - jade-mouse/commitdiff
Implement instruction execution develop
authorCassie Jones <code@witchoflight.com>
Wed, 22 Jan 2020 06:41:59 +0000 (01:41 -0500)
committerCassie Jones <code@witchoflight.com>
Wed, 22 Jan 2020 06:41:59 +0000 (01:41 -0500)
toolchain/src/cpu.rs
toolchain/src/cpu/test.rs
toolchain/src/inst.rs
toolchain/src/inst/test.rs

index 232617ce5d03312b3c0c2fce1fb74cd912acbaa2..18a9a3032ce0a94950dc0cce162a77c43dc1f25d 100644 (file)
@@ -1,11 +1,11 @@
-use crate::inst::{Inst, Reg};
+use crate::inst::{Addr, Cond, Half, Inst, LdSt, Op1, Op2, OpC, Reg, Size};
 use std::ops::{Index, IndexMut};
 
 #[cfg(test)]
 mod test;
 
 struct RegFile {
-    values: [u8; 4],
+    values: [u16; 4],
 }
 
 pub struct Cpu {
@@ -25,7 +25,7 @@ impl Cpu {
         }
     }
 
-    pub fn reg(&self, reg: Reg) -> u8 {
+    pub fn reg(&self, reg: Reg) -> u16 {
         self.reg[reg]
     }
 
@@ -39,15 +39,125 @@ impl Cpu {
 
     pub fn run_inst(&mut self, inst: &Inst) {
         match *inst {
-            Inst::Move(dst, src) => self.reg[dst] = self.reg[src],
-            _ => todo!(),
+            Inst::Halt | Inst::Nope => (),
+            Inst::Alu2(rd, op, r2) => {
+                self.reg[rd] = match op {
+                    Op2::Add => self.reg[rd].wrapping_add(self.reg[r2]),
+                    Op2::Sub => self.reg[rd].wrapping_sub(self.reg[r2]),
+                    Op2::AddPc => self.pc.wrapping_add(self.reg[r2]),
+                    Op2::And => self.reg[rd] & self.reg[r2],
+                    Op2::Or => self.reg[rd] | self.reg[r2],
+                    Op2::Xor => self.reg[rd] ^ self.reg[r2],
+                }
+            }
+            Inst::Jalr(r) => std::mem::swap(&mut self.pc, &mut self.reg[r]),
+            Inst::Move(rd, r2) => self.reg[rd] = self.reg[r2],
+            Inst::Alu1(rd, op) => {
+                self.reg[rd] = match op {
+                    Op1::Inc => self.reg[rd].wrapping_add(1),
+                    Op1::Dec => self.reg[rd].wrapping_sub(1),
+                    Op1::Neg => 0u16.wrapping_sub(self.reg[rd]), // negate :)
+                    Op1::Compl => !self.reg[rd],
+                }
+            }
+            Inst::Mem(LdSt::Ld, r, addr) => {
+                if let Addr::Extended {
+                    base,
+                    stack: true,
+                    size,
+                    ..
+                } = addr
+                {
+                    self.reg[base] = self.reg[base].wrapping_sub(size.bytes());
+                }
+                let (addr0, size) = self.eval_addr(addr);
+                self.reg[r] = self.load(addr0, size);
+            }
+            Inst::Mem(LdSt::St, r, addr) => {
+                let (addr0, size) = self.eval_addr(addr);
+                self.store(addr0, size, self.reg[r]);
+                if let Addr::Extended {
+                    base,
+                    stack: true,
+                    size,
+                    ..
+                } = addr
+                {
+                    self.reg[base] = self.reg[base].wrapping_add(size.bytes());
+                }
+            }
+            Inst::Branch(cond, offset) => {
+                if self.eval_cond(cond) {
+                    self.pc = self.pc.offset(offset);
+                }
+            }
+            Inst::JumpI(offset) => self.pc = self.pc.offset(offset),
+            Inst::AddI(rd, i) => self.reg[rd] = self.reg[rd].offset(i),
+            Inst::AluCompact(rd, op, i) => {
+                self.reg[rd] = match op {
+                    OpC::Lsl => self.reg[rd] << i.get(),
+                    OpC::Lsr => self.reg[rd] >> i.get(),
+                    OpC::Asr => (self.reg[rd] as i16 >> i.get()) as u16,
+                    OpC::Rol => self.reg[rd].rotate_left(i.get() as u32),
+                    OpC::Clr => self.reg[rd] & !(1 << i.get()),
+                    OpC::Set => self.reg[rd] | (1 << i.get()),
+                    OpC::Tog => self.reg[rd] ^ (1 << i.get()),
+                    OpC::Ext => self.reg[rd] & (1 << i.get()),
+                }
+            }
+            Inst::LdImm(Half::Low, rd, i) => self.reg[rd] = self.reg[rd] & 0xFF00 | i as u16,
+            Inst::LdImm(Half::High, rd, i) => {
+                self.reg[rd] = self.reg[rd] & 0x00FF | (i as u16) << 8
+            }
+        }
+    }
+
+    fn eval_addr(&self, addr: Addr) -> (u16, Size) {
+        match addr {
+            Addr::Fixed(i) => (i.get() * 2, Size::Word),
+            Addr::Reg(r) => (self.reg[r], Size::Word),
+            Addr::Extended {
+                base, size, offset, ..
+            } => (self.reg[base].offset(offset), size),
+        }
+    }
+
+    fn load(&self, addr: u16, size: Size) -> u16 {
+        match size {
+            Size::Byte => self.memory[addr as usize] as u16,
+            Size::Word => u16::from_le_bytes([
+                self.memory[addr as usize],
+                self.memory[addr.wrapping_add(1) as usize],
+            ]),
+        }
+    }
+
+    fn store(&mut self, addr: u16, size: Size, value: u16) {
+        match size {
+            Size::Byte => self.memory[addr as usize] = value as u8,
+            Size::Word => {
+                let [b0, b1] = value.to_le_bytes();
+                self.memory[addr as usize] = b0;
+                self.memory[addr.wrapping_add(1) as usize] = b1;
+            }
+        }
+    }
+
+    fn eval_cond(&self, cond: Cond) -> bool {
+        match cond {
+            Cond::Eql(a, b) => self.reg[a] == self.reg[b],
+            Cond::Neq(a, b) => self.reg[a] != self.reg[b],
+            Cond::Test(a, b) => self.reg[a] & self.reg[b] != 0,
+            Cond::TestNot(a, b) => self.reg[a] & self.reg[b] == 0,
+            Cond::Lt(a, b) => (self.reg[a] as i16) < self.reg[b] as i16,
+            Cond::Ult(a, b) => self.reg[a] < self.reg[b],
         }
     }
 }
 
 impl Index<Reg> for RegFile {
-    type Output = u8;
-    fn index(&self, index: Reg) -> &u8 {
+    type Output = u16;
+    fn index(&self, index: Reg) -> &Self::Output {
         match index {
             Reg::R0 => &self.values[0],
             Reg::R1 => &self.values[1],
@@ -58,7 +168,7 @@ impl Index<Reg> for RegFile {
 }
 
 impl IndexMut<Reg> for RegFile {
-    fn index_mut(&mut self, index: Reg) -> &mut u8 {
+    fn index_mut(&mut self, index: Reg) -> &mut Self::Output {
         match index {
             Reg::R0 => &mut self.values[0],
             Reg::R1 => &mut self.values[1],
@@ -89,3 +199,13 @@ impl std::fmt::Debug for Cpu {
             .finish()
     }
 }
+
+trait OffsetExt {
+    fn offset(&self, x: impl Into<i32>) -> Self;
+}
+
+impl OffsetExt for u16 {
+    fn offset(&self, x: impl Into<i32>) -> Self {
+        self.wrapping_add(x.into() as u16)
+    }
+}
index 50573541a605782520fb8d7012cac7598f7f6487..d707ec61e9f44cda6acda30d3107105d477506ae 100644 (file)
@@ -1,11 +1,11 @@
 use super::*;
-use crate::inst::{Inst, Reg};
+use crate::inst::{Inst, Reg, Half};
 use proptest::prelude::*;
 
 fn cpu() -> impl Strategy<Value = Cpu> {
     (
         0..1024u16,
-        [any::<u8>(); 4],
+        [any::<u16>(); 4],
         prop::collection::vec(any::<u8>(), 0..1024),
     )
         .prop_map(|(pc, reg, memory)| Cpu {
@@ -35,4 +35,22 @@ proptest! {
         prop_assert_eq!(val, cpu.reg(src));
         prop_assert_eq!(val, cpu.reg(dst));
     }
+
+    #[test]
+    fn run_jalr(mut cpu in cpu(), r in reg()) {
+        let inst = Inst::Jalr(r);
+        let dest = cpu.reg(r);
+        let pc0 = cpu.pc;
+        cpu.run_inst(&inst);
+        prop_assert_eq!(pc0, cpu.reg(r));
+        prop_assert_eq!(dest, cpu.pc);
+    }
+
+    #[test]
+    fn run_imm_lohi(mut cpu in cpu(), r in reg(), val: u16) {
+        let [b0, b1] = val.to_le_bytes();
+        cpu.run_inst(&Inst::LdImm(Half::Low, r, b0));
+        cpu.run_inst(&Inst::LdImm(Half::High, r, b1));
+        prop_assert_eq!(val, cpu.reg(r));
+    }
 }
index 130afc9f924952772058a84d31ba5c843aeb0b89..1f6fcdd47af1c493e391381efc2872f180ac80dc 100644 (file)
@@ -154,3 +154,46 @@ impl PartialEq for Cond {
         }
     }
 }
+
+impl Size {
+    pub fn bytes(&self) -> u16 {
+        match *self {
+            Size::Byte => 1,
+            Size::Word => 2,
+        }
+    }
+}
+
+impl U4 {
+    pub fn get(&self) -> usize {
+        self.0 as usize
+    }
+}
+
+impl U7 {
+    pub fn get(&self) -> u16 {
+        self.0 as u16
+    }
+}
+
+impl I5 {
+    pub fn get(&self) -> i8 {
+        self.0
+    }
+}
+
+impl Into<i32> for I5 {
+    fn into(self) -> i32 {
+        self.0 as i32
+    }
+}
+
+impl Into<i32> for I7 {
+    fn into(self) -> i32 {
+        self.0 as i32
+    }
+}
+
+/*
+pub struct I5(#[cfg_attr(test, proptest(strategy = "-16..=15i8"))] i8);
+*/
index efe1b5ed3c172e13dc0976a8527dd54296552d85..95aafdb85fb907a800db753daaab7a40ca860316 100644 (file)
@@ -1,4 +1,4 @@
-use super::{Cond, Decode, Encode, Inst, Reg};
+use super::{Decode, Encode, Inst, Reg};
 use proptest::prelude::*;
 use std::{fmt::Debug, io::Cursor};