From 66d2f25802549de79a07983e5895d1faa95c846c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Thu, 18 Jul 2024 23:33:32 +0200 Subject: [PATCH] Add a macro for binary ops and use it for ADD2, SUB2, MUL2 and DIV2 --- coco-core/src/lib.rs | 82 +++++++++++++++++++++++---------- coco-core/src/opcodes.rs | 22 ++++++++- coco-ui/vendor/coco_ui_bg.wasm | Bin 47963 -> 48192 bytes 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/coco-core/src/lib.rs b/coco-core/src/lib.rs index b0229fa..5f21ff8 100644 --- a/coco-core/src/lib.rs +++ b/coco-core/src/lib.rs @@ -5,9 +5,11 @@ use core::cmp; use core::fmt; mod stack; +use opcodes::short_mode; use stack::Stack; pub mod opcodes; +use opcodes::FLAG_SHORT; /// The trait to implement for COCO virtual machines. pub trait Machine { @@ -20,6 +22,22 @@ pub trait Ports { const BASE: u8; } +macro_rules! binary_op { + ($self:ident, $flags:ident, $f:expr) => { + if short_mode($flags) { + let b = $self.stack.pop_short(); + let a = $self.stack.pop_short(); + let f: fn(u16, u16) -> u16 = $f; + $self.stack.push_short(f(a, b)) + } else { + let b = $self.stack.pop_byte(); + let a = $self.stack.pop_byte(); + let f: fn(u8, u8) -> u8 = $f; + $self.stack.push_byte(f(a, b)) + } + }; +} + /// COCO-8 CPU. #[derive(Debug)] pub struct Cpu { @@ -65,10 +83,14 @@ impl Cpu { opcodes::DEI => self.op_dei(machine), opcodes::DEO => self.op_deo(machine), opcodes::DEO2 => self.op_deo2(machine), - opcodes::ADD => self.op_add(), - opcodes::SUB => self.op_sub(), - opcodes::MUL => self.op_mul(), - opcodes::DIV => self.op_div(), + opcodes::ADD => self.op_add::<0x00>(), + opcodes::ADD2 => self.op_add::(), + opcodes::SUB => self.op_sub::<0x00>(), + opcodes::SUB2 => self.op_sub::(), + opcodes::MUL => self.op_mul::<0x00>(), + opcodes::MUL2 => self.op_mul::(), + opcodes::DIV => self.op_div::<0x00>(), + opcodes::DIV2 => self.op_div::(), opcodes::PUSH => self.op_push(), opcodes::PUSH2 => self.op_push2(), _ => {} @@ -179,35 +201,23 @@ impl Cpu { } #[inline] - fn op_add(&mut self) { - let b = self.stack.pop_byte(); - let a = self.stack.pop_byte(); - let value = a.wrapping_add(b); - self.stack.push_byte(value); + fn op_add(&mut self) { + binary_op!(self, FLAGS, |a, b| a.wrapping_add(b)) } #[inline] - fn op_sub(&mut self) { - let b = self.stack.pop_byte(); - let a = self.stack.pop_byte(); - let value = a.wrapping_sub(b); - self.stack.push_byte(value); + fn op_sub(&mut self) { + binary_op!(self, FLAGS, |a, b| a.wrapping_sub(b)) } #[inline] - fn op_mul(&mut self) { - let b = self.stack.pop_byte(); - let a = self.stack.pop_byte(); - let value = a.wrapping_mul(b); - self.stack.push_byte(value); + fn op_mul(&mut self) { + binary_op!(self, FLAGS, |a, b| a.wrapping_mul(b)) } #[inline] - fn op_div(&mut self) { - let b = self.stack.pop_byte(); - let a = self.stack.pop_byte(); - let value = a.wrapping_div(b); - self.stack.push_byte(value); + fn op_div(&mut self) { + binary_op!(self, FLAGS, |a, b| a.wrapping_div(b)) } } @@ -384,6 +394,18 @@ mod tests { assert_eq!(cpu.stack.byte_at(0), 0xad); } + #[test] + fn add2_opcode() { + let rom = rom_from(&[PUSH2, 0xab, 0xcd, PUSH2, 0x11, 0x11, ADD2, BRK]); + let mut cpu = Cpu::new(&rom); + + let pc = cpu.run(0x100, &mut AnyMachine {}); + + assert_eq!(pc, 0x108); + assert_eq!(cpu.stack.len(), 2); + assert_eq!(cpu.stack.short_at(0), 0xbcde); + } + #[test] fn sub_opcode() { let rom = rom_from(&[PUSH, 0xab, PUSH, 0x02, SUB, BRK]); @@ -396,6 +418,18 @@ mod tests { assert_eq!(cpu.stack.byte_at(0), 0xa9); } + #[test] + fn sub2_opcode() { + let rom = rom_from(&[PUSH2, 0xab, 0xcd, PUSH2, 0x11, 0x11, SUB2, BRK]); + let mut cpu = Cpu::new(&rom); + + let pc = cpu.run(0x100, &mut AnyMachine {}); + + assert_eq!(pc, 0x108); + assert_eq!(cpu.stack.len(), 2); + assert_eq!(cpu.stack.short_at(0), 0x9abc); + } + #[test] fn mul_opcode() { let rom = rom_from(&[PUSH, 0x03, PUSH, 0x02, MUL, BRK]); diff --git a/coco-core/src/opcodes.rs b/coco-core/src/opcodes.rs index 64d3321..5c409e0 100644 --- a/coco-core/src/opcodes.rs +++ b/coco-core/src/opcodes.rs @@ -4,10 +4,30 @@ pub const DUP: u8 = 0x06; pub const DUP2: u8 = 0x26; pub const DEI: u8 = 0x16; pub const DEO: u8 = 0x17; +pub const DEO2: u8 = 0x37; pub const ADD: u8 = 0x18; +pub const ADD2: u8 = 0x38; pub const SUB: u8 = 0x19; +pub const SUB2: u8 = 0x39; pub const MUL: u8 = 0x1a; +pub const MUL2: u8 = 0x3a; pub const DIV: u8 = 0x1b; -pub const DEO2: u8 = 0x37; +pub const DIV2: u8 = 0x3b; pub const PUSH: u8 = 0x80; pub const PUSH2: u8 = 0xa0; + +pub const FLAG_SHORT: u8 = 0b0010_0000; +pub const FLAG_RET: u8 = 0b0100_0000; +pub const FLAG_KEEP: u8 = 0b1000_0000; + +pub fn short_mode(opcode: u8) -> bool { + (opcode & FLAG_SHORT) == FLAG_SHORT +} + +pub fn ret_mode(opcode: u8) -> bool { + (opcode & FLAG_RET) == FLAG_RET +} + +pub fn keep_mode(opcode: u8) -> bool { + (opcode & FLAG_KEEP) == FLAG_KEEP +} diff --git a/coco-ui/vendor/coco_ui_bg.wasm b/coco-ui/vendor/coco_ui_bg.wasm index ff821a68f5747ed0399f46eeb19d2745732ed523..5d533af9280732527261241941a1d2741eb62308 100644 GIT binary patch delta 782 zcma)4&2G~`5Z+m@w`uLf+fo$KD(*Umw$N7mMEocyP8W&t2B;DTEO96@7FC4AflDGI zA#u%w2jC4V?F$s{+~5Kncmp^Ahe}~LRcb?fU?uO&d^_`bzS;fqlOF!22OErXs<+sX z(lKp?!pldg0{4hmB7 zLXyic$XNuwnBq+^uq*9;av0#avkWy{jzg$oJ8l5S-S|e6i&l|T^`se>by+4cF>QFa`5>FA4x{Yk??!HnvYYLUZ?SFGvHQ)$vX+gJ zb+U|=%w#Joy~%l2yirQ*d=^a1j6lEwB9H(ZJ0}-64?=(y!Gy3l7`PSK9UBJ z0wB%9t-zqq*wDnH$jHMxS;1P8k$bY0wanzTHXK1pi~`9DtO_6!u7;BvD8iz^D$vB} z_@A*bOP7H`pb8<)!3~vEf=GiES}`yvFgo%VDzZ=BU~Lx4E?|tJfmwk;fn7ixA;ykr zNP-f(BS#s?AQqrej9Fm271&WtwnZ@+XbOhOY#`Tz+zuwPkX_C?`M8ao9}9|t9ApK| zKq;V3MTlNScAz_e0ieX_%F7HilpVxTV9Z0-!8Ccct<~gfwr-o%9rLvr