From 2a37db9e3b6deb9c0a13fe77f19cd6d58f44f85d Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Sat, 11 Jan 2020 17:31:19 -0500 Subject: [PATCH] Add decoding with proptest round-trip test --- toolchain/Cargo.lock | 421 +++++++++++++++++++ toolchain/Cargo.toml | 4 + toolchain/proptest-regressions/inst/test.txt | 9 + toolchain/src/inst.rs | 34 +- toolchain/src/inst/decode.rs | 120 +++++- toolchain/src/inst/encode.rs | 14 +- toolchain/src/inst/parse.rs | 14 +- toolchain/src/inst/test.rs | 15 +- 8 files changed, 607 insertions(+), 24 deletions(-) create mode 100644 toolchain/proptest-regressions/inst/test.txt diff --git a/toolchain/Cargo.lock b/toolchain/Cargo.lock index 130066f..5f129a4 100644 --- a/toolchain/Cargo.lock +++ b/toolchain/Cargo.lock @@ -9,12 +9,98 @@ dependencies = [ "nodrop", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "bit-set" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" + +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" +dependencies = [ + "ppv-lite86", +] + [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "lexical-core" version = "0.4.6" @@ -28,6 +114,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" + [[package]] name = "memchr" version = "2.3.0" @@ -51,6 +143,253 @@ dependencies = [ "version_check", ] +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg 1.0.0", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proptest" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" +dependencies = [ + "bit-set", + "bitflags", + "byteorder", + "lazy_static", + "num-traits", + "quick-error", + "rand 0.6.5", + "rand_chacha 0.1.1", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", +] + +[[package]] +name = "proptest-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d31edb17edac73aeacc947bd61462dda15220584268896a58e12f053d767f15b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha 0.2.1", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +dependencies = [ + "c2-chacha", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "regex-syntax" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +dependencies = [ + "winapi", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -60,6 +399,18 @@ dependencies = [ "semver", ] +[[package]] +name = "rusty-fork" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.2" @@ -87,15 +438,85 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand 0.7.3", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "toolchain" version = "0.1.0" dependencies = [ "nom", + "proptest", + "proptest-derive", ] +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/toolchain/Cargo.toml b/toolchain/Cargo.toml index c06dcab..54029fc 100644 --- a/toolchain/Cargo.toml +++ b/toolchain/Cargo.toml @@ -8,3 +8,7 @@ edition = "2018" [dependencies] nom = "5.1.0" + +[dev-dependencies] +proptest = "0.9.4" +proptest-derive = "0.1.0" diff --git a/toolchain/proptest-regressions/inst/test.txt b/toolchain/proptest-regressions/inst/test.txt new file mode 100644 index 0000000..03111a6 --- /dev/null +++ b/toolchain/proptest-regressions/inst/test.txt @@ -0,0 +1,9 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc ecdd893edc935d8d4eb2eb12057b49f81f30d7211ffe3821f199f895e6c1dfb3 # shrinks to inst = LdD(D1, Reg(U3(0)), false) +cc a7153639ea7f091987410d362c4639c35081fc2ecccf65bb9971a8570ae230d9 # shrinks to inst = Jump(OffImm(0)) +cc 316327f54ddfe6fb212d24b80e401bea293a0c836cba642afafe92df51f0480f # shrinks to inst = Swap(Reg(U3(0))) diff --git a/toolchain/src/inst.rs b/toolchain/src/inst.rs index 15c793a..eddfd34 100644 --- a/toolchain/src/inst.rs +++ b/toolchain/src/inst.rs @@ -4,7 +4,11 @@ pub mod parse; #[cfg(test)] pub mod test; +#[cfg(test)] +use proptest_derive::Arbitrary; + #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum Op1 { Zero, @@ -18,6 +22,7 @@ pub enum Op1 { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum OpR { Add, @@ -31,6 +36,7 @@ pub enum OpR { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum OpI3 { Rol, @@ -44,6 +50,7 @@ pub enum OpI3 { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] #[repr(u8)] pub enum Data { D1, @@ -51,19 +58,24 @@ pub enum Data { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub enum Special { Data(Data), Code, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub struct Reg(U3); #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct U3(u8); +#[cfg_attr(test, derive(Arbitrary))] +pub struct U3(#[cfg_attr(test, proptest(strategy = "0..=7u8"))] u8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct AddImm(i8); +#[cfg_attr(test, derive(Arbitrary))] +pub struct AddImm(#[cfg_attr(test, proptest(strategy = "-64..=127i8"))] i8); #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] pub enum AluI { And(u8), Ior(u8), @@ -73,12 +85,20 @@ pub enum AluI { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] +pub enum Target { + Abs, + Off, + OffImm(i8), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(Arbitrary))] +#[cfg_attr(test, proptest(no_params))] pub enum Inst { Trap, - JAbs, - CAbs, - JOff, - COff, + Jump(Target), + Call(Target), Swap(Reg), GetR(Reg), SetR(Reg), @@ -91,8 +111,6 @@ pub enum Inst { StD(Data, Reg, bool), AluI(AluI), BEzI(i8), - JOfI(i8), - COfI(i8), } impl Reg { diff --git a/toolchain/src/inst/decode.rs b/toolchain/src/inst/decode.rs index cb9b6a4..6875cb9 100644 --- a/toolchain/src/inst/decode.rs +++ b/toolchain/src/inst/decode.rs @@ -1,5 +1,123 @@ +use super::{AddImm, AluI, Data, Inst, Op1, OpI3, OpR, Reg, Special, Target, U3}; use std::io::{self, Read}; pub trait Decode: Sized { - fn decode(reader: &mut impl Read) -> io::Result>; + fn decode(reader: &mut impl Read) -> io::Result; +} + +fn reg(x: u8) -> Reg { + Reg::new(x & 0x7).unwrap() +} + +fn special(x: u8) -> io::Result { + match x { + 0b000 => Ok(Special::Data(Data::D1)), + 0b001 => Ok(Special::Data(Data::D2)), + 0b010 => Ok(Special::Code), + 0b011 => Err(io::Error::new( + io::ErrorKind::Other, + "Reserved special register", + )), + _ => Err(io::Error::new( + io::ErrorKind::Other, + "Invalid special register", + )), + } +} + +fn op1(x: u8) -> Op1 { + match x { + 0b000 => Op1::Zero, + 0b001 => Op1::Lsl1, + 0b010 => Op1::Lsr1, + 0b011 => Op1::Asr1, + 0b100 => Op1::Incr, + 0b101 => Op1::Decr, + 0b110 => Op1::Comp, + 0b111 => Op1::Negt, + _ => unreachable!(), + } +} + +fn op_r(x: u8) -> OpR { + match x & 7 { + 0b000 => OpR::Add, + 0b001 => OpR::Sub, + 0b010 => OpR::And, + 0b011 => OpR::Ior, + 0b100 => OpR::Xor, + 0b101 => OpR::Lsl, + 0b110 => OpR::Lsr, + 0b111 => OpR::Asr, + _ => unreachable!(), + } +} + +fn flag(x: u8) -> bool { + x & 2 != 0 +} + +fn op_compact(x: u8) -> OpI3 { + match (x >> 3) & 7 { + 0b000 => OpI3::Rol, + 0b001 => OpI3::Lsl, + 0b010 => OpI3::Lsr, + 0b011 => OpI3::Asr, + 0b100 => OpI3::Clr, + 0b101 => OpI3::Set, + 0b110 => OpI3::Tog, + 0b111 => OpI3::Ext, + _ => unreachable!(), + } +} + +impl Decode for Inst { + fn decode(reader: &mut impl Read) -> io::Result { + use Data::*; + let mut op_byte = [0]; + reader.read_exact(&mut op_byte)?; + Ok(match (op_byte[0] >> 3, op_byte[0] & 7) { + (0b0000_0, 0..=2) => Inst::Trap, + (0b0000_0, 0b100) => Inst::Jump(Target::Abs), + (0b0000_0, 0b101) => Inst::Call(Target::Abs), + (0b0000_0, 0b110) => Inst::Jump(Target::Off), + (0b0000_0, 0b111) => Inst::Call(Target::Off), + (0b0000_1, r) => Inst::Swap(reg(r)), + (0b0001_0, r) => Inst::GetR(reg(r)), + (0b0001_1, r) => Inst::SetR(reg(r)), + (0b0010_0, s) => Inst::Get(special(s)?), + (0b0010_1, s) => Inst::Set(special(s)?), + (0b0011_0, o) => Inst::Alu1(op1(o)), + (0b0011_1, r) => Inst::IsLt(reg(r)), + (o @ 0b0100_0..=0b0111_1, r) => Inst::AluR(op_r(o), reg(r)), + (o @ 0b1000_0, r) | (o @ 0b1001_0, r) => Inst::LdD(D1, reg(r), flag(o)), + (o @ 0b1000_1, r) | (o @ 0b1001_1, r) => Inst::StD(D1, reg(r), flag(o)), + (o @ 0b1010_0, r) | (o @ 0b1011_0, r) => Inst::LdD(D2, reg(r), flag(o)), + (o @ 0b1010_1, r) | (o @ 0b1011_1, r) => Inst::StD(D2, reg(r), flag(o)), + (0b1111_0..=0b1111_1, _) => { + let mut imm_byte = [0]; + reader.read_exact(&mut imm_byte)?; + let imm = imm_byte[0]; + match op_byte[0] & 0xf { + 0b0000 => Inst::AluI(AluI::And(imm)), + 0b0001 => Inst::AluI(AluI::Ior(imm)), + 0b0010 => Inst::AluI(AluI::Xor(imm)), + 0b0011 => match imm >> 6 { + 0b00 | 0b01 | 0b11 => Inst::AluI(AluI::Add(AddImm::new(imm as i8).unwrap())), + 0b10 => { + let imm3 = U3::new(imm & 7).unwrap(); + Inst::AluI(AluI::Compact(op_compact(imm), imm3)) + } + _ => unreachable!(), + }, + 0b0100 => Inst::BEzI(imm as i8), + 0b0101 => Inst::Trap, /* reserved branch */ + 0b0110 => Inst::Jump(Target::OffImm(imm as i8)), + 0b0111 => Inst::Call(Target::OffImm(imm as i8)), + _ => Inst::Trap, /* reserved with immediate */ + } + } + _ => Inst::Trap, + }) + } } diff --git a/toolchain/src/inst/encode.rs b/toolchain/src/inst/encode.rs index ffa9614..f23c53a 100644 --- a/toolchain/src/inst/encode.rs +++ b/toolchain/src/inst/encode.rs @@ -1,4 +1,4 @@ -use super::{AluI, Data, Inst, Reg, Special, U3}; +use super::{AluI, Data, Inst, Reg, Special, Target, U3}; use std::io::{self, Write}; pub trait Encode { @@ -21,10 +21,10 @@ impl Encode for Inst { fn encode(&self, writer: &mut impl Write) -> io::Result<()> { match *self { Inst::Trap => writer.write(&[0x00])?, - Inst::JAbs => writer.write(&[0x04])?, - Inst::CAbs => writer.write(&[0x05])?, - Inst::JOff => writer.write(&[0x06])?, - Inst::COff => writer.write(&[0x07])?, + Inst::Jump(Target::Abs) => writer.write(&[0x04])?, + Inst::Call(Target::Abs) => writer.write(&[0x05])?, + Inst::Jump(Target::Off) => writer.write(&[0x06])?, + Inst::Call(Target::Off) => writer.write(&[0x07])?, Inst::Swap(r) => writer.write(&[0x08 | reg(r)])?, Inst::GetR(r) => writer.write(&[0x10 | reg(r)])?, Inst::SetR(r) => writer.write(&[0x18 | reg(r)])?, @@ -47,8 +47,8 @@ impl Encode for Inst { AluI::Compact(op, imm) => writer.write(&[0xf3, 0x80 | (op as u8) << 3 | imm.0])?, }, Inst::BEzI(off) => writer.write(&[0xf4, off as u8])?, - Inst::JOfI(off) => writer.write(&[0xf6, off as u8])?, - Inst::COfI(off) => writer.write(&[0xf7, off as u8])?, + Inst::Jump(Target::OffImm(off)) => writer.write(&[0xf6, off as u8])?, + Inst::Call(Target::OffImm(off)) => writer.write(&[0xf7, off as u8])?, }; Ok(()) } diff --git a/toolchain/src/inst/parse.rs b/toolchain/src/inst/parse.rs index f6899ec..858a6bc 100644 --- a/toolchain/src/inst/parse.rs +++ b/toolchain/src/inst/parse.rs @@ -1,4 +1,4 @@ -use super::{AddImm, AluI, Data, Inst, Op1, OpI3, OpR, Reg, Special, U3}; +use super::{AddImm, AluI, Data, Inst, Op1, OpI3, OpR, Reg, Special, Target, U3}; use nom::{ branch::alt, bytes::complete::tag_no_case, @@ -29,10 +29,10 @@ fn inst<'s>() -> impl Fn(&'s str) -> IResult<&'s str, Inst> { alt(( box_alt(( fixed("trap", Inst::Trap), - fixed("JABS", Inst::JAbs), - fixed("CABS", Inst::CAbs), - fixed("JOFF", Inst::JOff), - fixed("COFF", Inst::COff), + fixed("JABS", Inst::Jump(Target::Abs)), + fixed("CABS", Inst::Call(Target::Abs)), + fixed("JOFF", Inst::Jump(Target::Off)), + fixed("COFF", Inst::Call(Target::Off)), )), box_alt(( with_reg("SWAP", |r| Inst::Swap(r)), @@ -90,8 +90,8 @@ fn inst<'s>() -> impl Fn(&'s str) -> IResult<&'s str, Inst> { )), box_alt(( with_off("BEZI", |off| Inst::BEzI(off)), - with_off("JOFI", |off| Inst::JOfI(off)), - with_off("COFI", |off| Inst::COfI(off)), + with_off("JOFI", |off| Inst::Jump(Target::OffImm(off))), + with_off("COFI", |off| Inst::Call(Target::OffImm(off))), )), )) } diff --git a/toolchain/src/inst/test.rs b/toolchain/src/inst/test.rs index 4fcc054..71fb2ab 100644 --- a/toolchain/src/inst/test.rs +++ b/toolchain/src/inst/test.rs @@ -1,6 +1,19 @@ -use super::{encode::Encode, parse}; +use super::{decode::Decode, encode::Encode, parse, Inst}; +use proptest::prelude::*; use std::io::Cursor; +proptest! { + #[test] + fn roundtrip(inst: Inst) { + let mut buf = [0, 0]; + let mut cursor = Cursor::new(&mut buf[..]); + inst.encode(&mut cursor).expect("to encode"); + cursor.set_position(0); + let decoded = Inst::decode(&mut cursor).expect("to decode"); + prop_assert_eq!(inst, decoded); + } +} + fn display(buf: &[u8]) -> String { match buf.len() { 1 => format!("{:04b}_{:04b}", buf[0] >> 4, buf[0] & 0xf), -- 2.43.2