Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/pm100/db65
Browse files Browse the repository at this point in the history
  • Loading branch information
pm100 committed Jan 3, 2024
2 parents 2386af1 + 7dc0c2d commit b726ce5
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2021"
anyhow = "1.0.75"
bitflags = "2.4.1"
clap = {version="4.4.11", features=["derive"]}
evalexpr = "11.3.0"
hex = "0.4.3"
once_cell = "1.19.0"
rustyline = {version="13.0.0", features=["with-file-history"]}
Expand Down
14 changes: 12 additions & 2 deletions src/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ the same functionality as the cli shell.
*/

use anyhow::{anyhow, bail, Result};
use evalexpr::Value;
use std::{
collections::HashMap,
fs::File,
io::{BufRead, BufReader},
path::Path,
};

use crate::{cpu::Cpu, execute::StopReason, loader};
use crate::{cpu::Cpu, execute::StopReason, expr::DB65Context, loader};
pub struct Debugger {
symbols: HashMap<String, u16>,
pub(crate) symbols: HashMap<String, u16>,
pub break_points: HashMap<u16, BreakPoint>,
pub(crate) watch_points: HashMap<u16, WatchPoint>,
pub(crate) next_bp: Option<u16>,
Expand All @@ -27,6 +28,7 @@ pub struct Debugger {
pub(crate) enable_mem_check: bool,
load_name: String,
pub(crate) run_done: bool,
pub(crate) expr_context: DB65Context,
}
#[derive(Debug)]
pub(crate) enum FrameType {
Expand Down Expand Up @@ -74,6 +76,7 @@ impl Debugger {
next_bp: None,
load_name: String::new(),
run_done: false,
expr_context: DB65Context::new(),
}
}
pub fn delete_breakpoint(&mut self, id_opt: Option<&String>) -> Result<()> {
Expand Down Expand Up @@ -175,6 +178,12 @@ impl Debugger {
}
}
}
self.expr_context.symbols.clear();
for (k, v) in &self.symbols {
self.expr_context
.symbols
.insert(k.clone(), Value::Int(*v as i64));
}
Ok(())
}
pub fn get_symbols(&self, filter: Option<&String>) -> Result<Vec<(String, u16)>> {
Expand Down Expand Up @@ -252,6 +261,7 @@ impl Debugger {
Cpu::push_arg(arg)
}
self.stack_frames.clear();
self.run_done = true;
self.execute(0) // 0 = forever
}
pub fn get_chunk(&self, addr: u16, mut len: u16) -> Result<Vec<u8>> {
Expand Down
118 changes: 118 additions & 0 deletions src/expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
Evaluates arbitrary address expressions
Any shell command tha expects an address can be given an expression instead.
An expression starts with '=' and is followed by a valid evalexpr expression.
It may need to be quoted to avoid shell expansion and clap confusuion.
The regsisters are variables called ac, xr, yr, sp, pc
All symbols are available as variables
You can deference a pointer using '@(<ptr>)'
the expr command evaluates an expression and prints the result
so you can do
dis =pc
mem =xr+0x20
mem .ptr // no need for expression, symbols just work anyway
mem =@(.ptr) // deference a pointer
mem '=@(.ptr + 0x20)' // do math on a pointer
mem =@(.ptr + (0x20*xr)) // more math
*/

use crate::{cpu::Cpu, debugger::Debugger};
use anyhow::{anyhow, Result};
use evalexpr::{eval_int_with_context, Context, EvalexprResult, Value};
use std::{collections::HashMap, ops::RangeInclusive};

pub struct DB65Context {
pub symbols: HashMap<String, Value>,
ac: Value,
xr: Value,
yr: Value,
sp: Value,
pc: Value,
}

impl DB65Context {
pub fn new() -> Self {
Self {
symbols: HashMap::new(),
ac: Value::Int(0),
xr: Value::Int(0),
yr: Value::Int(0),
sp: Value::Int(0),
pc: Value::Int(0),
}
}
pub fn reload(&mut self) {
self.ac = Value::Int(Cpu::read_ac() as i64);
self.xr = Value::Int(Cpu::read_xr() as i64);
self.yr = Value::Int(Cpu::read_yr() as i64);
self.sp = Value::Int(Cpu::read_sp() as i64);
self.pc = Value::Int(Cpu::read_pc() as i64);
}
}
impl Context for DB65Context {
fn get_value(&self, key: &str) -> Option<&Value> {
match key {
"ac" => Some(&self.ac),
"xr" => Some(&self.xr),
"yr" => Some(&self.yr),
"sp" => Some(&self.sp),
"pc" => Some(&self.pc),
_ => self.symbols.get(key),
}
}
fn call_function(&self, key: &str, arg: &Value) -> EvalexprResult<Value> {
match key {
"@" => {
let arg = arg.as_int()?;
if arg > u16::MAX as i64 {
return Err(evalexpr::EvalexprError::WrongFunctionArgumentAmount {
expected: RangeInclusive::new(0, 0xffff),
actual: arg as usize,
});
}
let word = Cpu::read_word(arg as u16);
Ok(evalexpr::Value::Int(word as i64))
}
"@b" => {
let arg = arg.as_int()?;
if arg > u16::MAX as i64 {
return Err(evalexpr::EvalexprError::WrongFunctionArgumentAmount {
expected: RangeInclusive::new(0, 0xffff),
actual: arg as usize,
});
}
let byte = Cpu::read_byte(arg as u16);
Ok(evalexpr::Value::Int(byte as i64))
}

_ => Err(evalexpr::EvalexprError::FunctionIdentifierNotFound(
key.to_string(),
)),
}
}
fn are_builtin_functions_disabled(&self) -> bool {
false
}
fn set_builtin_functions_disabled(&mut self, _disabled: bool) -> EvalexprResult<()> {
Err(evalexpr::EvalexprError::CustomMessage(
"builtin functions are not supported".to_string(),
))
}
}
impl Debugger {
pub fn evaluate(&mut self, expr: &str) -> Result<u16> {
// reload register values
self.expr_context.reload();
eval_int_with_context(expr, &mut self.expr_context)
.map_err(|e| anyhow!(e))
.map(|v| v as u16)
}
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ mod cpu;
mod debugger;
mod dis;
mod execute;
mod expr;
mod loader;
mod paravirt;
mod shell;
mod syntax;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
Expand Down
23 changes: 20 additions & 3 deletions src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,12 @@ impl Shell {
match matches.subcommand() {
Some(("break", args)) => {
let addr = args.get_one::<String>("address").unwrap();
let addr = &self.expand_expr(&addr)?;
self.debugger.set_break(addr, false)?;
}
Some(("watch", args)) => {
let addr = args.get_one::<String>("address").unwrap();
let addr = &self.expand_expr(&addr)?;
let read = *args.get_one::<bool>("read").unwrap();
let write = *args.get_one::<bool>("write").unwrap();
let rw = if read && write {
Expand Down Expand Up @@ -165,6 +167,7 @@ impl Shell {

Some(("memory", args)) => {
let addr_str = args.get_one::<String>("address").unwrap();
let addr_str = &self.expand_expr(&addr_str)?;
let addr = self.debugger.convert_addr(addr_str)?;
let chunk = self.debugger.get_chunk(addr, 48)?;
self.mem_dump(addr, &chunk);
Expand Down Expand Up @@ -225,7 +228,8 @@ impl Shell {

Some(("dis", args)) => {
let mut addr = if let Some(addr_str) = args.get_one::<String>("address") {
self.debugger.convert_addr(addr_str)?
let addr_str = self.expand_expr(&addr_str)?;
self.debugger.convert_addr(&addr_str)?
} else {
let mut a = self.current_dis_addr;
if a == 0 {
Expand Down Expand Up @@ -253,7 +257,8 @@ impl Shell {
}
Some(("print", args)) => {
let addr_str = args.get_one::<String>("address").unwrap();
let addr = self.debugger.convert_addr(addr_str)?;
let addr_str = self.expand_expr(&addr_str)?;
let addr = self.debugger.convert_addr(&addr_str)?;
self.print(addr, args)?;
}
Some(("enable", args)) => {
Expand All @@ -262,6 +267,11 @@ impl Shell {
self.debugger
.enable_stack_check(*args.get_one::<bool>("stackcheck").unwrap());
}
Some(("expr", args)) => {
let expr = args.get_one::<String>("expression").unwrap();
let ans = self.expand_expr(expr)?;
println!("{:}", ans);
}
Some(("finish", _)) => {
if !self.debugger.run_done {
bail!("program not running");
Expand All @@ -275,7 +285,14 @@ impl Shell {

Ok(false)
}

fn expand_expr(&mut self, exp: &str) -> Result<String> {
if let Some(exp) = exp.strip_prefix("=") {
let res = self.debugger.evaluate(exp)?;
Ok(format!("${:04x}", res))
} else {
Ok(exp.to_string())
}
}
fn print(&self, addr: u16, args: &ArgMatches) -> Result<()> {
if *args.get_one::<bool>("asstring").unwrap() {
let mut addr = addr;
Expand Down
6 changes: 6 additions & 0 deletions src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,10 @@ pub fn syntax() -> Command {
.about("run till current function returns")
.help_template(APPLET_TEMPLATE),
)
.subcommand(
Command::new("expr")
.arg(arg!(<expression> "expression to evaluate"))
.about("run till current function returns")
.help_template(APPLET_TEMPLATE),
)
}

0 comments on commit b726ce5

Please sign in to comment.