Refactoring
This commit is contained in:
Generated
+1
@@ -5,6 +5,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/vcore/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/vemu/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/vasm/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
Generated
+139
@@ -61,12 +61,39 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.8.0"
|
||||
@@ -294,6 +321,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
@@ -315,6 +351,12 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -345,6 +387,15 @@ dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.5"
|
||||
@@ -530,6 +581,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
@@ -755,6 +812,12 @@ version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
@@ -786,6 +849,49 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
dependencies = [
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
|
||||
dependencies = [
|
||||
"maplit",
|
||||
"pest",
|
||||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pixels"
|
||||
version = "0.9.0"
|
||||
@@ -945,6 +1051,18 @@ version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.6"
|
||||
@@ -1044,6 +1162,18 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
|
||||
[[package]]
|
||||
name = "ultraviolet"
|
||||
version = "0.8.1"
|
||||
@@ -1065,6 +1195,15 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "vasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"vcore",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcore"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -3,4 +3,5 @@ resolver = "2"
|
||||
members = [
|
||||
"vcore",
|
||||
"vemu",
|
||||
"vasm"
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "vasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vcore = { path = "../vcore" }
|
||||
pest = "2.1.3"
|
||||
pest_derive = "2.1.0"
|
||||
@@ -0,0 +1,11 @@
|
||||
extern crate pest;
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
mod parse_error;
|
||||
mod vasm_line;
|
||||
mod vasm_parser;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
use vcore::opcodes::InvalidOpcode;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ParseError<'a>(pub &'a str);
|
||||
|
||||
impl<'a> From<InvalidOpcode> for ParseError<'a> {
|
||||
fn from(_: InvalidOpcode) -> Self {
|
||||
Self("Invalid opcode")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
WHITESPACE = _{ " " | "\t" }
|
||||
|
||||
// A comment will start with a semicolon and go to the end of the line. Actually everything is parsed
|
||||
// line by line, so anything that starts with a semicolon is a comment:
|
||||
COMMENT = _{ ";" ~ ANY* ~ EOI }
|
||||
|
||||
// Numbers are more complicated. We'll support three formats:
|
||||
// - Decimal numbers like 42
|
||||
// - Hexadecimal like 0x2a
|
||||
// - Binary like 0b00101010
|
||||
// - Decimal zero needs its own pattern: it's not a decimal because
|
||||
// it starts with a 0, but it has to be matched after hex and bin
|
||||
// because otherwise any "0x" will parse as "decimal 0 followed
|
||||
// by unparseable x"
|
||||
dec_number = @{ ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
|
||||
neg_number = ${ "-" ~ dec_number }
|
||||
hex_number = ${ "0x" ~ ASCII_HEX_DIGIT+ }
|
||||
bin_number = ${ "0b" ~ ASCII_BIN_DIGIT+ }
|
||||
dec_zero = @{ "0" }
|
||||
number = { dec_number | hex_number | bin_number | dec_zero | neg_number }
|
||||
|
||||
// A label can be any sequence of C-identifier-y characters, as long as it doesn't start with
|
||||
// a digit:
|
||||
label_char = { ASCII_ALPHA_LOWER | ASCII_ALPHA_UPPER | "_" }
|
||||
label = @{ label_char ~ (label_char | ASCII_DIGIT | "$")* }
|
||||
|
||||
// To make relative jumps easier, we'll also allow an '@' at the start of a label, and interpret
|
||||
// that as meaning "relative to the first byte of this instruction:"
|
||||
relative_label = ${ "@" ~ label }
|
||||
|
||||
// We'll also have a special form, $+nnn (and $-nnn) which is the first byte of the an earlier or later line:
|
||||
absolute_line_offset = { "$" ~ sign ~ dec_number }
|
||||
|
||||
// And the relative form of that, @+nnn and @-nnn:
|
||||
relative_line_offset = { "@" ~ sign ~ dec_number }
|
||||
|
||||
opcode = @{ ASCII_ALPHA_LOWER+ } // TODO: replace with actual list
|
||||
|
||||
// The assembler will support some directives:
|
||||
// - .org to set the current address
|
||||
// - .db to embed some data
|
||||
// - .equ to define some constants
|
||||
directive = { ".org" | ".db" | ".equ" }
|
||||
|
||||
// The .equ directive isn't much use without the ability to have expressions based on
|
||||
// symbols, so, a quick arithmetic expression parser:
|
||||
sign = { "+" | "-" }
|
||||
term_op = { "/" | "*" | "%" }
|
||||
expr = { term ~ (sign ~ term)* }
|
||||
term = { fact ~ (term_op ~ fact)* }
|
||||
fact = { ("(" ~ expr ~ ")") | (number | relative_line_offset | relative_label | absolute_line_offset | label) }
|
||||
|
||||
// Likewise, .db would get tedious quick without a string syntax, so, let's define one of those. An escape
|
||||
// sequence is a backslash followed by certain other characters:
|
||||
escape = @{ "\\" ~ ("t" | "r" | "n" | "0" | "\\" | "\"") }
|
||||
|
||||
// And a string is a quoted sequence of escapes or other characters:
|
||||
string_inner = ${ !("\"" | "\\") ~ ANY | escape }
|
||||
string = ${ "\"" ~ string_inner* ~ "\"" }
|
||||
|
||||
// Parsing a line
|
||||
// Normally an assembly line will be a sequence of "label, opcode, argument, comment."
|
||||
// However, most of these elements are optional. An opcode is only required if an
|
||||
// argument exists. Comments are already handled by the COMMENT pattern
|
||||
|
||||
|
||||
// Some sub-patterns for the portions of a line:
|
||||
label_group = { label ~ ":" }
|
||||
argument_group = { expr | string }
|
||||
|
||||
// An opcode might be an actual opcode, or a directive
|
||||
instruction_group = { (opcode | directive) ~ argument_group? }
|
||||
|
||||
// Finally the entire pattern for an assembly line:
|
||||
line = { SOI ~ label_group? ~ instruction_group? ~ EOI }
|
||||
@@ -0,0 +1,61 @@
|
||||
use vcore::opcodes::Opcode;
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum Directive { Db, Equ, Org }
|
||||
|
||||
impl From<&str> for Directive {
|
||||
fn from(value: &str) -> Self {
|
||||
use Directive::*;
|
||||
match value {
|
||||
".db" => Db,
|
||||
".equ" => Equ,
|
||||
".org" => Org,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub struct VASMLine<'a> {
|
||||
label: Option<&'a str>,
|
||||
opcode: Option<Opcode>,
|
||||
directive: Option<Directive>
|
||||
}
|
||||
|
||||
impl<'a> VASMLine<'a> {
|
||||
pub fn blank() -> VASMLine<'a> {
|
||||
VASMLine {
|
||||
label: None,
|
||||
opcode: None,
|
||||
directive: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_opcode(opcode: Opcode) -> VASMLine<'a> {
|
||||
Self::blank().with_opcode(opcode)
|
||||
}
|
||||
|
||||
pub fn with_opcode(self, opcode: Opcode) -> VASMLine<'a> {
|
||||
VASMLine {
|
||||
label: self.label,
|
||||
opcode: Some(opcode),
|
||||
directive: self.directive
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_directive(self, directive: Directive) -> VASMLine<'a> {
|
||||
VASMLine {
|
||||
label: self.label,
|
||||
opcode: self.opcode,
|
||||
directive: Some(directive)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_label(self, label: &'a str) -> Self {
|
||||
VASMLine {
|
||||
label: Some(label),
|
||||
opcode: self.opcode,
|
||||
directive: self.directive
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use vcore::opcodes::Opcode;
|
||||
|
||||
use crate::parse_error::ParseError;
|
||||
use crate::vasm_line::{Directive, VASMLine};
|
||||
|
||||
use pest::{Parser};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "vasm.pest"]
|
||||
struct VASMParser;
|
||||
|
||||
fn parse_vasm_line(line: &str) -> Result<VASMLine, ParseError<'_>> {
|
||||
let mut pairs = VASMParser::parse(Rule::line, line)
|
||||
.map_err(|_| ParseError("Failed to parse line"))?
|
||||
.next()
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.peekable();
|
||||
|
||||
let mut vasm_line = VASMLine::blank();
|
||||
|
||||
if let Some(label_group) = pairs.next_if(|pair| pair.as_rule() == Rule::label_group) {
|
||||
let label = label_group.into_inner().next().unwrap();
|
||||
vasm_line = vasm_line.with_label(label.as_str())
|
||||
}
|
||||
|
||||
if let Some(instruction_group) = pairs.next_if(|pair| pair.as_rule() == Rule::instruction_group) {
|
||||
let instruction_field = instruction_group.into_inner().next().unwrap();
|
||||
vasm_line = match instruction_field.as_rule() {
|
||||
Rule::opcode => vasm_line.with_opcode(Opcode::try_from(instruction_field.as_str())?),
|
||||
Rule::directive => vasm_line.with_directive(Directive::from(instruction_field.as_str())),
|
||||
_ => unreachable!()
|
||||
}
|
||||
// something something argument here
|
||||
}
|
||||
|
||||
Ok(vasm_line)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
assert_eq!(parse_vasm_line("add"), Ok(VASMLine::for_opcode(Opcode::Add)));
|
||||
assert_eq!(parse_vasm_line("sub"), Ok(VASMLine::for_opcode(Opcode::Sub)));
|
||||
assert_eq!(parse_vasm_line("blah"), Err(ParseError("Invalid opcode")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_labels() {
|
||||
assert_eq!(parse_vasm_line("foo: add"), Ok(VASMLine::for_opcode(Opcode::Add).with_label("foo")));
|
||||
assert_eq!(parse_vasm_line("bar:"), Ok(VASMLine::blank().with_label("bar")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_directives() {
|
||||
assert_eq!(parse_vasm_line("foo: .equ"), Ok(VASMLine::blank().with_label("foo").with_directive(Directive::Equ)));
|
||||
assert_eq!(parse_vasm_line(".db"), Ok(VASMLine::blank().with_directive(Directive::Db)));
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -154,8 +154,8 @@ impl CPU {
|
||||
Opcode::Store => self.memory.poke8(x, y.to_bytes()[0]),
|
||||
Opcode::Storew => self.memory.poke24(x, y),
|
||||
Opcode::Setsdp => {
|
||||
self.dp = x.into();
|
||||
self.sp = y.into()
|
||||
self.dp = x;
|
||||
self.sp = y
|
||||
}
|
||||
Opcode::Brz => {
|
||||
if y == 0 {
|
||||
@@ -195,7 +195,7 @@ impl CPU {
|
||||
self.push_data(x);
|
||||
self.push_data(z)
|
||||
}
|
||||
Opcode::Jmp => return self.pop_data().into(),
|
||||
Opcode::Jmp => return self.pop_data(),
|
||||
Opcode::Jmpr => {
|
||||
let x = i32::from(self.pop_data());
|
||||
return self.pc + x;
|
||||
@@ -203,9 +203,9 @@ impl CPU {
|
||||
Opcode::Call => {
|
||||
let x = self.pop_data();
|
||||
self.push_call(self.pc + instruction.length as i32);
|
||||
return x.into();
|
||||
return x;
|
||||
}
|
||||
Opcode::Ret => return self.pop_call().into(),
|
||||
Opcode::Ret => return self.pop_call(),
|
||||
Opcode::Hlt => self.halted = true,
|
||||
Opcode::Load => {
|
||||
let x = self.pop_data();
|
||||
@@ -217,7 +217,7 @@ impl CPU {
|
||||
}
|
||||
Opcode::Inton => self.int_enabled = true,
|
||||
Opcode::Intoff => self.int_enabled = false,
|
||||
Opcode::Setiv => self.iv = self.pop_data().into(),
|
||||
Opcode::Setiv => self.iv = self.pop_data(),
|
||||
Opcode::Sdp => {
|
||||
self.push_data(self.sp);
|
||||
self.push_data(self.dp + 3) // The +3 accounts for the word we're about to push
|
||||
|
||||
@@ -163,6 +163,60 @@ impl TryFrom<u8> for Opcode {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Opcode {
|
||||
type Error = InvalidOpcode;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
use Opcode::*;
|
||||
Ok(match value {
|
||||
"nop" => Nop,
|
||||
"add" => Add,
|
||||
"sub" => Sub,
|
||||
"mul" => Mul,
|
||||
"div" => Div,
|
||||
"mod" => Mod,
|
||||
"rand" => Rand,
|
||||
"and" => And,
|
||||
"or" => Or,
|
||||
"xor" => Xor,
|
||||
"not" => Not,
|
||||
"gt" => Gt,
|
||||
"lt" => Lt,
|
||||
"agt" => Agt,
|
||||
"alt" => Alt,
|
||||
"lshift" => Lshift,
|
||||
"rshift" => Rshift,
|
||||
"arshift" => Arshift,
|
||||
"pop" => Pop,
|
||||
"dup" => Dup,
|
||||
"swap" => Swap,
|
||||
"pick" => Pick,
|
||||
"rot" => Rot,
|
||||
"jmp" => Jmp,
|
||||
"jmpr" => Jmpr,
|
||||
"call" => Call,
|
||||
"ret" => Ret,
|
||||
"brz" => Brz,
|
||||
"brnz" => Brnz,
|
||||
"hlt" => Hlt,
|
||||
"load" => Load,
|
||||
"loadw" => Loadw,
|
||||
"store" => Store,
|
||||
"storew" => Storew,
|
||||
"inton" => Inton,
|
||||
"intoff" => Intoff,
|
||||
"setiv" => Setiv,
|
||||
"sdp" => Sdp,
|
||||
"setsdp" => Setsdp,
|
||||
"pushr" => Pushr,
|
||||
"popr" => Popr,
|
||||
"peekr" => Peekr,
|
||||
"debug" => Debug,
|
||||
_ => return Err(InvalidOpcode(255))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
assert_eq!(Opcode::try_from(18), Ok(Opcode::Pop));
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
// 128k, the amount of memory in a standard Vulcan machine
|
||||
pub const MEM_SIZE: u32 = 128 * 1024;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, Ord)]
|
||||
#[derive(Debug, Copy, Clone, Eq)]
|
||||
pub struct Word(u32);
|
||||
|
||||
impl Word {
|
||||
@@ -10,9 +10,9 @@ impl Word {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use vulcan_emu::Word;
|
||||
/// use vcore::word::Word;
|
||||
///
|
||||
/// assert_eq!(Word::from_bytes([0x01, 0x02, 0x03]) == 0x010203);
|
||||
/// assert!(Word::from_bytes([0x01, 0x02, 0x03]) == 0x030201);
|
||||
/// ```
|
||||
pub fn from_bytes(bytes: [u8; 3]) -> Self {
|
||||
let [a, b, c] = bytes;
|
||||
@@ -24,9 +24,9 @@ impl Word {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use vulcan_emu::Word;
|
||||
/// use vcore::word::Word;
|
||||
///
|
||||
/// assert_eq!(Word::from(0x010203).to_bytes(), [0x01, 0x02, 0x03]);
|
||||
/// assert_eq!(Word::from(0x010203).to_bytes(), [0x03, 0x02, 0x01]);
|
||||
/// ```
|
||||
pub fn to_bytes(self) -> [u8; 3] {
|
||||
let [a, b, c, _] = self.0.to_le_bytes();
|
||||
|
||||
+5
-9
@@ -211,7 +211,7 @@ fn draw_paletted_low_text<P: PeekPoke>(machine: &P, reg: DisplayRegisters, frame
|
||||
let char_byte = machine.peek(reg.font + (char_idx << 3) + char_row);
|
||||
|
||||
let color_addr = addr + (reg.width * reg.height);
|
||||
let color_byte = machine.peek(Word::from(color_addr));
|
||||
let color_byte = machine.peek(color_addr);
|
||||
let (fg_color_idx, bg_color_idx) = (color_byte & 0xf, color_byte >> 4);
|
||||
|
||||
let fg_color = machine.peek(reg.palette + fg_color_idx);
|
||||
@@ -231,10 +231,8 @@ fn draw_direct_low_gfx<P: PeekPoke>(machine: &P, reg: DisplayRegisters, frame: &
|
||||
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||
let (display_row, display_col) = (i / 640, i % 640);
|
||||
|
||||
if display_row >= (240 - 64 * 3)
|
||||
&& display_row < (240 + 64 * 3)
|
||||
&& display_col >= (320 - 64 * 3)
|
||||
&& display_col < (320 + 64 * 3)
|
||||
if ((240 - 64 * 3)..(240 + 64 * 3)).contains(&display_row)
|
||||
&& ((320 - 64 * 3)..(320 + 64 * 3)).contains(&display_col)
|
||||
{
|
||||
let (vulcan_row, vulcan_col) = (
|
||||
Word::from((display_row - (240 - 64 * 3)) / 3),
|
||||
@@ -253,10 +251,8 @@ fn draw_paletted_low_gfx<P: PeekPoke>(machine: &P, reg: DisplayRegisters, frame:
|
||||
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||
let (display_row, display_col) = (i / 640, i % 640);
|
||||
|
||||
if display_row >= (240 - 64 * 3)
|
||||
&& display_row < (240 + 64 * 3)
|
||||
&& display_col >= (320 - 64 * 3)
|
||||
&& display_col < (320 + 64 * 3)
|
||||
if ((240 - 64 * 3)..(240 + 64 * 3)).contains(&display_row)
|
||||
&& ((320 - 64 * 3)..(320 + 64 * 3)).contains(&display_col)
|
||||
{
|
||||
let (vulcan_row, vulcan_col) = (
|
||||
Word::from((display_row - (240 - 64 * 3)) / 3),
|
||||
|
||||
+2
-2
@@ -59,10 +59,10 @@ fn window_loop(event_loop: EventLoop<()>, window: Window, mut pixels: Pixels, mu
|
||||
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
|
||||
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Resized(newSize),
|
||||
event: WindowEvent::Resized(new_size),
|
||||
window_id
|
||||
} if window_id == window.id() => {
|
||||
pixels.resize_surface(newSize.width, newSize.height);
|
||||
pixels.resize_surface(new_size.width, new_size.height);
|
||||
}
|
||||
|
||||
Event::MainEventsCleared => {
|
||||
|
||||
Reference in New Issue
Block a user