From f652ff6669e6a9aef51dd60f497b31098efb528a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 25 Sep 2020 00:39:10 +0200 Subject: [PATCH] dump sreg, add new ops --- Cargo.lock | 1 + asm/src/instr/op.rs | 3 +- asm/src/parse/parse_op.rs | 7 ++ runtime/Cargo.toml | 1 + runtime/src/exec/mod.rs | 195 +++++++++++++++++++++++++++++++------- runtime/src/frame.rs | 35 +++++++ runtime/src/run_thread.rs | 2 +- 7 files changed, 209 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb2af1d..89a1407 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,6 +146,7 @@ dependencies = [ "anyhow", "asm", "log", + "num-traits", "thiserror", ] diff --git a/asm/src/instr/op.rs b/asm/src/instr/op.rs index 2f624cf..7ca52a3 100644 --- a/asm/src/instr/op.rs +++ b/asm/src/instr/op.rs @@ -61,7 +61,8 @@ pub enum Op { Sub(Wr, Rd), Mul(Wr, Rd), Div(Wr, Rd), - Mod(Wr, /*rem*/Wr, Rd), + Mod(Wr, Rd), + DivRem(Wr, /*rem*/Wr, Rd), // /// Bitwise And(Wr, Rd), diff --git a/asm/src/parse/parse_op.rs b/asm/src/parse/parse_op.rs index 535a4f6..dba3154 100644 --- a/asm/src/parse/parse_op.rs +++ b/asm/src/parse/parse_op.rs @@ -131,6 +131,13 @@ pub fn parse_op(keyword: &str, far : bool, mut arg_tokens: impl Iterator { HLOp::L(Op::Mod( + parse_wr(arg_tokens.next())?, + parse_rd(arg_tokens.next())? + )) + } + + "divr" => { + HLOp::L(Op::DivRem( parse_wr(arg_tokens.next())?, parse_wr(arg_tokens.next())?, parse_rd(arg_tokens.next())? diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 8b39578..3321d8b 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -11,3 +11,4 @@ asm = { path = "../asm" } thiserror = "1.0.20" anyhow = "1.0.32" log = "0.4.11" +num-traits = "0.2.12" diff --git a/runtime/src/exec/mod.rs b/runtime/src/exec/mod.rs index f529286..e5684d3 100644 --- a/runtime/src/exec/mod.rs +++ b/runtime/src/exec/mod.rs @@ -3,6 +3,8 @@ use asm::instr::{Op, Cond}; use crate::fault::Fault; use crate::frame::StackFrame; use asm::data::literal::{Value, is_positive, is_negative, Addr}; +use std::ops::{Rem, BitXor, Shl}; +use num_traits::PrimInt; pub type CyclesSpent = usize; @@ -12,6 +14,7 @@ pub struct EvalRes { } impl RunThread { + // TODO unit tests pub fn eval_op(&mut self) -> Result { let mut cycles = 1; let mut advance = 1; @@ -19,6 +22,8 @@ impl RunThread { let mut frame = &mut self.frame; let op = self.program.read(frame.pc); + + debug!("------------------------"); debug!("{} | {:?}", frame.pc, op); /* Operations can be given different execution times when run in slow mode. */ @@ -144,72 +149,196 @@ impl RunThread { frame.status.clear(); let mut a = frame.read(dst.as_rd())?; let mut b = frame.read(*src)?; - - let val = a.wrapping_add(b); + let (val, ov) = if let Some(v) = a.checked_add(b) { + (v, false) + } else { + (a.wrapping_add(b), true) + }; frame.status.zero = (val == 0); frame.status.positive = is_positive(val); frame.status.negative = is_negative(val); - frame.status.overflow = b > Value::MAX - a; // TODO check - // TODO carry? + frame.status.overflow = ov; frame.write(*dst, val)?; } Op::Sub(dst, src) => { frame.status.clear(); let mut a = frame.read(dst.as_rd())?; let mut b = frame.read(*src)?; - - let val = a.wrapping_sub(b); + let (val, ov) = if let Some(v) = a.checked_sub(b) { + (v, false) + } else { + (a.wrapping_sub(b), true) + }; frame.status.zero = (val == 0); frame.status.positive = is_positive(val); frame.status.negative = is_negative(val); - frame.status.overflow = b > a; - // TODO carry? + frame.status.overflow = ov; frame.write(*dst, val)?; } Op::Mul(dst, src) => { frame.status.clear(); let mut a = frame.read(dst.as_rd())?; let mut b = frame.read(*src)?; - - let val = a.wrapping_mul(b); + let (val, ov) = if let Some(v) = a.checked_mul(b) { + (v, false) + } else { + (a.wrapping_mul(b), true) + }; frame.status.zero = (val == 0); frame.status.positive = is_positive(val); frame.status.negative = is_negative(val); - //frame.status.overflow = b > a; // TODO detect overflow + frame.status.overflow = ov; frame.write(*dst, val)?; } - Op::Div(_, _) => { - unimplemented!() + Op::Div(dst, src) => { + frame.status.clear(); + let mut a = frame.read(dst.as_rd())?; + let mut b = frame.read(*src)?; + if b == 0 { + frame.status.overflow = true; + // TODO ? + } else { + let (val, ov) = if let Some(v) = a.checked_div(b) { + (v, false) + } else { + (a.wrapping_div(b), true) + }; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.status.overflow = ov; + frame.write(*dst, val)?; + } } - Op::Mod(_, _, _) => { - unimplemented!() + Op::Mod(dst, src) => { + frame.status.clear(); + let mut a = frame.read(dst.as_rd())?; + let mut b = frame.read(*src)?; + if b == 0 { + frame.status.overflow = true; + // TODO ? + } else { + let (val, ov) = if let Some(v) = a.checked_rem(b) { + (v, false) + } else { + (a.wrapping_rem(b), true) + }; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.status.overflow = ov; + frame.write(*dst, val)?; + } } - Op::And(_, _) => { - unimplemented!() + Op::DivRem(dst, remptr, src) => { + frame.status.clear(); + let mut a = frame.read(dst.as_rd())?; + let mut b = frame.read(*src)?; + if b == 0 { + frame.status.overflow = true; + // TODO ? + } else { + let (val, rem, ov) = if let Some(v) = a.checked_div(b) { + (v, a.rem(b), false) + } else { + (a.wrapping_div(b), a.wrapping_rem(b), true) + }; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.status.overflow = ov; + frame.write(*dst, val)?; + frame.write(*remptr, rem)?; + } } - Op::Or(_, _) => { - unimplemented!() + Op::And(dst, src) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*src)?; + val &= b; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Xor(_, _) => { - unimplemented!() + Op::Or(dst, src) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*src)?; + val |= b; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Cpl(_) => { - unimplemented!() + Op::Xor(dst, src) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*src)?; + val ^= b; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; + } + Op::Cpl(dst) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + val = !val; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Rol(_, _) => { - unimplemented!() + Op::Rol(dst, num) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*num)?; + val = val.rotate_left(b as u32); // FIXME check overflow + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Ror(_, _) => { - unimplemented!() + Op::Ror(dst, num) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*num)?; + val = val.rotate_right(b as u32); // FIXME check overflow + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Lsl(_, _) => { - unimplemented!() + Op::Lsl(dst, num) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*num)?; + val = val << b; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Lsr(_, _) => { - unimplemented!() + Op::Lsr(dst, num) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*num)?; + val = val >> b; + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } - Op::Asr(_, _) => { - unimplemented!() + Op::Asr(dst, num) => { + frame.status.clear(); + let mut val = frame.read(dst.as_rd())?; + let mut b = frame.read(*num)?; + val = val.signed_shr(b as u32); // FIXME check overflow + frame.status.zero = (val == 0); + frame.status.positive = is_positive(val); + frame.status.negative = is_negative(val); + frame.write(*dst, val)?; } } diff --git a/runtime/src/frame.rs b/runtime/src/frame.rs index dea8922..f4fae0c 100644 --- a/runtime/src/frame.rs +++ b/runtime/src/frame.rs @@ -2,6 +2,8 @@ use asm::data::literal::{Addr, Value}; use asm::data::{Rd, SrcDisp, Register, Wr, DstDisp}; use crate::fault::Fault; use asm::instr::Cond; +use std::fmt::{Display, Formatter, Write}; +use std::fmt; pub const REG_COUNT: usize = 8; @@ -25,6 +27,39 @@ pub struct StatusFlags { pub carry: bool, } +impl Display for StatusFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str("[")?; + if self.equal { + f.write_str(" E")?; + } + if self.zero { + f.write_str(" Z")?; + } + if self.lower { + f.write_str(" L")?; + } + if self.greater { + f.write_str(" G")?; + } + if self.positive { + f.write_str(" P")?; + } + if self.negative { + f.write_str(" N")?; + } + if self.overflow { + f.write_str(" V")?; + } + if self.carry { + f.write_str(" C")?; + } + f.write_str(" ]")?; + + Ok(()) + } +} + impl StatusFlags { pub fn clear(&mut self) { *self = Self::default(); diff --git a/runtime/src/run_thread.rs b/runtime/src/run_thread.rs index 5af6851..40386c5 100644 --- a/runtime/src/run_thread.rs +++ b/runtime/src/run_thread.rs @@ -52,7 +52,7 @@ impl RunThread { cycles, advance }) => { std::thread::sleep(CYCLE_TIME * (cycles as u32)); - debug!("PC += {}", advance); + debug!("Step {}; Status = {}", advance, self.frame.status); self.frame.pc.advance(advance); } Err(e) => {