Skip to content

Commit

Permalink
[wip] add cli tester
Browse files Browse the repository at this point in the history
  • Loading branch information
chanmix51 committed Mar 28, 2024
1 parent e428496 commit 6759695
Show file tree
Hide file tree
Showing 10 changed files with 493 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ resolver = "2"

members = [
"soft65c02_lib"
]
, "soft65c02_tester"]

[workspace.package]
authors = ["greg <[email protected]>"]
Expand Down
5 changes: 4 additions & 1 deletion soft65c02_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
[package]
name = "soft65c02_lib"
version = "1.0.0-alpha2"
edition = "2021"
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
10 changes: 5 additions & 5 deletions soft65c02_lib/src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
//! command pointer: 16 bit address register stack pointer: 8 bits at page 0x0100, set at 0xff at
//! start.
//!
//! The way the BREAK bit works is a bit puzzling but a quick read at (this forum
//! post)[http://forum.6502.org/viewtopic.php?f=8&t=3111] explains this bit is only aimed at being
//! saved in the stack to determine if it is a hard or soft interrupt in the interrupt service
//! routine (see [documentation](http://6502.org/tutorials/interrupts.html)).
//!
//! The way the BREAK bit works is a bit puzzling but a quick read of (this forum
//! post)[http://forum.6502.org/viewtopic.php?f=8&t=3111] explains that this bit is only aimed at
//! being saved in the stack to determine if it is a hard or soft interrupt in the interrupt
//! service routine (see [documentation](http://6502.org/tutorials/interrupts.html)).
use super::memory::MemoryStack as Memory;
use super::memory::{AddressableIO, MemoryError};
use rand::random;
Expand Down
16 changes: 16 additions & 0 deletions soft65c02_tester/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "soft65c02_tester"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.81"
hex = "0.4.3"
pest = "2.7.8"
pest_derive = "2.7.8"
soft65c02_lib = { path = "../soft65c02_lib" }
72 changes: 72 additions & 0 deletions soft65c02_tester/rules.pest
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
WHITESPACE = _{ " " }
COMMENT = _{ "//" ~ ANY* }
sentence = _{ SOI ~ instruction | COMMENT ~ EOI }

instruction = { registers_instruction |
memory_instruction |
run_instruction |
help_instruction |
disassemble_instruction |
assert_instruction |
reset_instruction }

reset_instruction = { ^"reset" ~ reset_memory_target | reset_registers_target | reset_all_target }
reset_memory_target = { ^"memory" }
reset_registers_target = { ^"registers" }
reset_all_target = { ^"all" }

registers_instruction = { ^"registers" ~ registers_action }
registers_action = _{ registers_show | registers_flush }
registers_flush = { ^"flush" }
registers_show = { ^"show" }

memory_instruction = { ^"memory" ~ memory_action }
memory_action = _{ memory_show | memory_load | memory_write | ^"sub " ~ memory_sub_action }
memory_show = { ^"show" ~ memory_address ~ size_parameter }
memory_load = { ^"load" ~ memory_address ~ filename }
memory_write = { ^"write" ~ memory_address ~ ^"0x(" ~ bytes ~ ")" }

memory_sub_action = _{ memory_sub_list | memory_sub_add }
memory_sub_list = { ^"list" }
memory_sub_add = { ^"add" ~ memory_address ~ memory_sub_name }
memory_sub_name = { ASCII_ALPHANUMERIC+ }

run_instruction = { ^"run" ~ (memory_address)? ~ (run_until_condition)? }
run_until_condition = { ^"until" ~ boolean_condition }

disassemble_instruction = {
^"disassemble" ~ memory_address ~ size_parameter
| ^"disassemble" ~ size_parameter }

assert_instruction = { ^"assert" ~ boolean_condition ~ "$$" ~ description ~ "$$"}

help_instruction = { help_registers | help_memory | help_run | help_disassemble | help_assert | help_global }
help_registers = { ^"help registers" }
help_memory = { ^"help memory" }
help_run = { ^"help run" }
help_disassemble = { ^"help disassemble" }
help_assert = { ^"help assert" }
help_global = { ^"help" }

boolean_condition = { boolean | operation }

boolean = { ^"true" | ^"false" }
operation = { operation16 | operation8 }
operation16 = _{ location16 ~ operator ~ value16 }
operation8 = _{ location8 ~ operator ~ value8 }

location16 = _{ register16 }
location8 = _{ memory_address | register8 }

memory_address = { "#0x" ~ ASCII_HEX_DIGIT{4} }
register16 = { "CP" }
register8 = { "A" | "X" | "Y" | "S" }
value16 = { "0x" ~ ASCII_HEX_DIGIT{4} }
value8 = { "0x" ~ ASCII_HEX_DIGIT{2} | "0b" ~ ASCII_BIN_DIGIT{8} }
bytes = @{ ASCII_HEX_DIGIT{2} ~ ("," ~ ASCII_HEX_DIGIT{2})* }
size_parameter = { ASCII_DIGIT+ }

operator = { ">=" | "<=" | "!=" | "=" | ">" | "<" }
filename = { "\"" ~ filechar+ ~ "\"" }
filechar = _{ ASCII_ALPHANUMERIC | "." | "_" | "/" }
description = { ((!"$$") ~ ANY)* }
117 changes: 117 additions & 0 deletions soft65c02_tester/source_boolex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use super::{Memory, Registers, AddressableIO};
use std::fmt;

#[derive(Debug)]
pub enum Source {
Accumulator,
RegisterX,
RegisterY,
RegisterS,
RegisterSP,
RegisterCP,
Memory(usize),
}

impl Source {
pub fn get_value(&self, registers: &Registers, memory: &Memory) -> usize {
match *self {
Source::Accumulator => registers.accumulator as usize,
Source::RegisterX => registers.register_x as usize,
Source::RegisterY => registers.register_y as usize,
Source::RegisterSP => registers.get_status_register() as usize,
Source::RegisterS => registers.stack_pointer as usize,
Source::Memory(addr) => memory.read(addr, 1).unwrap()[0] as usize,
Source::RegisterCP => registers.command_pointer as usize,
}
}
}

impl fmt::Display for Source {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Source::Accumulator => write!(f, "A"),
Source::RegisterX => write!(f, "X"),
Source::RegisterY => write!(f, "Y"),
Source::RegisterSP => write!(f, "SP"),
Source::RegisterS => write!(f, "S"),
Source::Memory(addr) => write!(f, "#0x{:04X}", addr),
Source::RegisterCP => write!(f, "CP"),
}
}
}

#[derive(Debug)]
pub enum BooleanExpression {
Equal(Source, usize),
GreaterOrEqual(Source, usize),
StrictlyGreater(Source, usize),
LesserOrEqual(Source, usize),
StrictlyLesser(Source, usize),
Different(Source, usize),
Value(bool),
And(Box<BooleanExpression>, Box<BooleanExpression>),
Or(Box<BooleanExpression>, Box<BooleanExpression>),
}

impl BooleanExpression {
pub fn solve(&self, registers: &Registers, memory: &Memory) -> bool {
match &*self {
BooleanExpression::Equal(source, val) => source.get_value(registers, memory) == *val,
BooleanExpression::GreaterOrEqual(source, val) => {
source.get_value(registers, memory) >= *val
}
BooleanExpression::StrictlyGreater(source, val) => {
source.get_value(registers, memory) > *val
}
BooleanExpression::LesserOrEqual(source, val) => {
source.get_value(registers, memory) <= *val
}
BooleanExpression::StrictlyLesser(source, val) => {
source.get_value(registers, memory) < *val
}
BooleanExpression::Different(source, val) => {
source.get_value(registers, memory) != *val
}
BooleanExpression::Value(val) => *val,
BooleanExpression::And(expr1, expr2) => {
expr1.solve(registers, memory) && expr2.solve(registers, memory)
}
BooleanExpression::Or(expr1, expr2) => {
expr1.solve(registers, memory) || expr2.solve(registers, memory)
}
}
}
}

impl fmt::Display for BooleanExpression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BooleanExpression::Equal(source, val) => write!(f, "{} = 0x{:X}", source, val),
BooleanExpression::GreaterOrEqual(source, val) => {
write!(f, "{} ≥ 0x{:X}", source, val)
}
BooleanExpression::StrictlyGreater(source, val) => {
write!(f, "{} > 0x{:X}", source, val)
}
BooleanExpression::LesserOrEqual(source, val) => {
write!(f, "{} ≤ 0x{:X}", source, val)
}
BooleanExpression::StrictlyLesser(source, val) => {
write!(f, "{} < 0x{:X}", source, val)
}
BooleanExpression::Different(source, val) => {
write!(f, "{} ≠ 0x{:X}", source, val)
}
BooleanExpression::Value(val) => {
write!(f, "{}", if *val { "true" } else { "false" })
}
BooleanExpression::And(expr1, expr2) => {
write!(f, "{} AND {}", expr1, expr2)
}
BooleanExpression::Or(expr1, expr2) => {
write!(f, "({} OR {})", expr1, expr2)
}
}
}
}

19 changes: 19 additions & 0 deletions soft65c02_tester/src/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use crate::until_condition::BooleanExpression;
#[derive(Debug)]
pub enum CliCommand {
Help(HelpCommand),
None,
}

#[derive(Debug)]
pub enum HelpCommand {
Global,
Registers,
Run,
}

#[derive(Debug)]
pub struct RunCommand {
pub stop_condition: BooleanExpression,
pub start_address: Option<usize>,
}
13 changes: 13 additions & 0 deletions soft65c02_tester/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mod commands;
mod pest_parser;
mod until_condition;

use anyhow::Result;

pub type AppResult<T> = anyhow::Result<T>;

fn main() -> Result<()> {
println!("Hello, world!");

Ok(())
}
Loading

0 comments on commit 6759695

Please sign in to comment.