zinc64_debug/
debugger.rs

1// This file is part of zinc64.
2// Copyright (c) 2016-2019 Sebastian Jastrzebski. All rights reserved.
3// Licensed under the GPLv3. See LICENSE file in the project root for full license text.
4
5#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
6
7use std::io;
8use std::io::{BufRead, BufReader, BufWriter, Cursor, Error, ErrorKind, Write};
9use std::net::{SocketAddr, TcpListener, TcpStream};
10use std::sync::mpsc;
11use std::u16;
12use std::u8;
13
14use bit_field::BitField;
15use byteorder::{BigEndian, ReadBytesExt};
16use zinc64_emu::cpu::Instruction;
17
18use super::charset;
19use super::disassembler::Disassembler;
20use super::{Command, Output, RegData, RegOp};
21
22// SPEC: Vice -> Alt-H -> help -> [Enter]
23
24const OPCODE_JSR: u8 = 0x20;
25const OPCODE_RTI: u8 = 0x40;
26const OPCODE_RTS: u8 = 0x60;
27
28// TODO debugger: print triggered breakpoint
29
30pub enum Cmd {
31    // Breakpoint
32    BpCondition(u16, String),
33    BpDisable(Option<u16>),
34    BpDelete(Option<u16>),
35    BpEnable(Option<u16>),
36    BpIgnore(u16, u16),
37    BpList,
38    BpSet(u16),
39    BpUntil(u16),
40    // Debugger
41    Goto(Option<u16>),
42    Next(u16),
43    RegRead,
44    RegWrite(Vec<RegOp>),
45    Return,
46    Step(u16),
47    // Memory
48    Compare(u16, u16, u16),
49    Disassemble(Option<u16>, Option<u16>),
50    Fill(u16, u16, Vec<u8>),
51    Hunt(u16, u16, Vec<u8>),
52    Memory(Option<u16>, Option<u16>),
53    MemChar(Option<u16>),
54    Move(u16, u16, u16),
55    Petscii(u16, Option<u16>),
56    // System
57    Reset(bool),
58    Screen,
59    Stopwatch(bool),
60    // Monitor
61    Exit,
62    Help(Option<String>),
63    Quit,
64    Radix(Option<u16>),
65}
66
67pub struct Debugger {
68    command_tx: mpsc::Sender<Command>,
69}
70
71impl Debugger {
72    pub fn new(command_tx: mpsc::Sender<Command>) -> Self {
73        Self { command_tx }
74    }
75
76    pub fn start(&self, addr: SocketAddr) -> io::Result<()> {
77        let listener = TcpListener::bind(addr)?;
78        for stream in listener.incoming() {
79            if let Ok(stream) = stream {
80                let mut conn = Connection::build(self.command_tx.clone(), &stream).unwrap();
81                match conn.handle() {
82                    Ok(_) => info!(target: "debugger", "Connection closed"),
83                    Err(error) => {
84                        error!(target: "debugger", "Connection failed, error - {}", error)
85                    }
86                }
87            }
88        }
89        Ok(())
90    }
91}
92
93struct Connection {
94    // Dependencies
95    command_parser: CommandParser,
96    // I/O
97    reader: BufReader<TcpStream>,
98    writer: BufWriter<TcpStream>,
99    command_tx: mpsc::Sender<Command>,
100    response_rx: mpsc::Receiver<Output>,
101    response_tx: mpsc::Sender<Output>,
102    // Runtime State
103    regs: Option<RegData>,
104    running: bool,
105}
106
107impl Connection {
108    pub fn build(command_tx: mpsc::Sender<Command>, stream: &TcpStream) -> io::Result<Self> {
109        let reader = BufReader::new(stream.try_clone()?);
110        let writer = BufWriter::new(stream.try_clone()?);
111        let (response_tx, response_rx) = mpsc::channel::<Output>();
112        let conn = Self {
113            command_parser: CommandParser::new(),
114            reader,
115            writer,
116            command_tx,
117            response_rx,
118            response_tx,
119            regs: None,
120            running: true,
121        };
122        Ok(conn)
123    }
124
125    pub fn handle(&mut self) -> io::Result<()> {
126        let tx = self.response_tx.clone();
127        self.execute_unit_cmd(Command::Attach(tx))?;
128        while self.running {
129            self.regs = Some(self.read_regs()?);
130            self.write_prompt()?;
131            let mut input = String::new();
132            self.reader.read_line(&mut input)?;
133            self.handle_request(&input)?;
134        }
135        self.command_tx.send(Command::Detach).unwrap();
136        self.writer.flush()?;
137        Ok(())
138    }
139
140    fn handle_command(&mut self, command: Cmd) -> io::Result<()> {
141        let result = match command {
142            // Breakpoint
143            Cmd::BpCondition(index, condition) => self.cmd_bp_condition(index, condition),
144            Cmd::BpDisable(index) => self.cmd_bp_disable(index),
145            Cmd::BpDelete(index) => self.cmd_bp_delete(index),
146            Cmd::BpEnable(index) => self.cmd_bp_enable(index),
147            Cmd::BpIgnore(index, count) => self.cmd_bp_ignore(index, count),
148            Cmd::BpList => self.cmd_bp_list(),
149            Cmd::BpSet(address) => self.cmd_bp_set(address),
150            Cmd::BpUntil(address) => self.cmd_bp_until(address),
151            // Debugger
152            Cmd::Goto(address) => self.cmd_goto(address),
153            Cmd::Next(count) => self.cmd_next(count),
154            Cmd::RegRead => self.cmd_reg_read(),
155            Cmd::RegWrite(ops) => self.cmd_reg_write(ops),
156            Cmd::Return => self.cmd_return(),
157            Cmd::Step(count) => self.cmd_step(count),
158            // Memory
159            Cmd::Compare(start, end, target) => self.cmd_compare(start, end, target),
160            Cmd::Disassemble(start, end) => self.cmd_disassemble(start, end),
161            Cmd::Fill(start, end, data) => self.cmd_fill(start, end, &data),
162            Cmd::Hunt(start, end, data) => self.cmd_hunt(start, end, &data),
163            Cmd::Memory(start, end) => self.cmd_memory(start, end),
164            Cmd::MemChar(address) => self.cmd_memchar(address),
165            Cmd::Move(start, end, target) => self.cmd_move(start, end, target),
166            Cmd::Petscii(start, end) => self.cmd_petscii(start, end),
167            // System
168            Cmd::Reset(hard) => self.cmd_reset(hard),
169            Cmd::Screen => self.cmd_screen(),
170            Cmd::Stopwatch(reset) => self.cmd_stopwatch(reset),
171            // Monitor
172            Cmd::Exit => self.cmd_exit(),
173            Cmd::Quit => self.cmd_quit(),
174            Cmd::Radix(radix) => self.cmd_radix(radix),
175            Cmd::Help(command) => CommandHelp::help(command),
176        };
177        let output = result.unwrap_or_else(|e| format!("Error: {}\n", e));
178        self.writer.write_all(output.as_bytes())
179    }
180
181    fn handle_request(&mut self, input: &str) -> io::Result<()> {
182        match self.command_parser.parse(input) {
183            Ok(command) => self.handle_command(command),
184            Err(error) => self.writer.write_all(format!("{}\n", error).as_bytes()),
185        }
186    }
187
188    fn read_mem(&mut self, start: u16, end: u16) -> io::Result<Vec<u8>> {
189        match self.execute_emu(Command::MemRead(start, end))? {
190            Output::Buffer(data) => Ok(data),
191            Output::Error(error) => Err(Error::new(ErrorKind::Other, error)),
192            _ => Err(Error::new(ErrorKind::Other, "Invalid debugger result")),
193        }
194    }
195
196    fn read_regs(&mut self) -> io::Result<RegData> {
197        match self.execute_emu(Command::RegRead)? {
198            Output::Registers(regs) => Ok(regs),
199            Output::Error(error) => Err(Error::new(ErrorKind::Other, error)),
200            _ => Err(Error::new(ErrorKind::Other, "Invalid debugger result")),
201        }
202    }
203
204    fn write_prompt(&mut self) -> io::Result<()> {
205        let pc = self.regs.as_ref().map_or(0, |r| r.pc);
206        write!(self.writer, "${:04x}> ", pc)?;
207        self.writer.flush()
208    }
209
210    // -- Commands
211
212    // -- Breakpoint
213
214    fn cmd_bp_condition(&mut self, index: u16, condition: String) -> io::Result<String> {
215        let command = Command::BpCondition(index, condition, self.command_parser.get_radix());
216        self.execute_text_cmd(command)
217    }
218
219    fn cmd_bp_disable(&mut self, index: Option<u16>) -> io::Result<String> {
220        if let Some(index) = index {
221            self.execute_unit_cmd(Command::BpDisable(index))
222        } else {
223            self.execute_unit_cmd(Command::BpDisableAll)?;
224            Ok("Set all breakpoints to state: disabled\n".to_string())
225        }
226    }
227
228    fn cmd_bp_delete(&mut self, index: Option<u16>) -> io::Result<String> {
229        if let Some(index) = index {
230            self.execute_unit_cmd(Command::BpRemove(index))
231        } else {
232            self.execute_unit_cmd(Command::BpClear)?;
233            Ok("Deleted all breakpoints\n".to_string())
234        }
235    }
236
237    fn cmd_bp_enable(&mut self, index: Option<u16>) -> io::Result<String> {
238        if let Some(index) = index {
239            self.execute_unit_cmd(Command::BpEnable(index))
240        } else {
241            self.execute_unit_cmd(Command::BpEnableAll)?;
242            Ok("Set all breakpoints to state: enabled\n".to_string())
243        }
244    }
245
246    fn cmd_bp_ignore(&mut self, index: u16, count: u16) -> io::Result<String> {
247        self.execute_unit_cmd(Command::BpIgnore(index, count))?;
248        Ok(format!(
249            "Ignoring the next {} hits of breakpoint {}\n",
250            count, index
251        ))
252    }
253
254    fn cmd_bp_list(&mut self) -> io::Result<String> {
255        self.execute_text_cmd(Command::BpList)
256    }
257
258    fn cmd_bp_set(&mut self, address: u16) -> io::Result<String> {
259        self.execute_text_cmd(Command::BpSet(address, false))
260    }
261
262    fn cmd_bp_until(&mut self, address: u16) -> io::Result<String> {
263        self.execute_text_cmd(Command::BpSet(address, true))?;
264        self.execute_unit_cmd(Command::Continue)?;
265        let regs = self.read_regs()?;
266        let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(10))?;
267        let dis = Disassembler::new(mem.clone(), regs.pc);
268        let (instr, instr_len) = dis.disassemble(regs.pc);
269        Ok(self.format_instr(&regs, &instr, &mem[0..instr_len]))
270    }
271
272    // -- Debugger
273
274    fn cmd_goto(&mut self, address: Option<u16>) -> io::Result<String> {
275        if let Some(address) = address {
276            self.execute_unit_cmd(Command::RegWrite(vec![RegOp::SetPC(address)]))?;
277        }
278        self.execute_unit_cmd(Command::Continue)?;
279        let regs = self.read_regs()?;
280        let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(10))?;
281        let dis = Disassembler::new(mem.clone(), regs.pc);
282        let (instr, instr_len) = dis.disassemble(regs.pc);
283        Ok(self.format_instr(&regs, &instr, &mem[0..instr_len]))
284    }
285
286    fn cmd_next(&mut self, count: u16) -> io::Result<String> {
287        let mut bp_hit = 0;
288        for _i in 0..count {
289            let regs = self.read_regs()?;
290            let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(1))?;
291            let opcode = mem[0];
292            if opcode == OPCODE_JSR {
293                let target = regs.pc.wrapping_add(3);
294                loop {
295                    let regs = self.read_regs()?;
296                    if regs.pc == target {
297                        break;
298                    }
299                    bp_hit = self.execute_num_cmd(Command::Step)?;
300                    if bp_hit > 0 {
301                        break;
302                    }
303                }
304            } else {
305                bp_hit = self.execute_num_cmd(Command::Step)?;
306                if bp_hit > 0 {
307                    break;
308                }
309            }
310        }
311        let mut buffer = String::new();
312        if bp_hit > 0 {
313            buffer.push_str("Stopped on breakpoint\n");
314        }
315        let regs = self.read_regs()?;
316        let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(10))?;
317        let dis = Disassembler::new(mem.clone(), regs.pc);
318        let (instr, instr_len) = dis.disassemble(regs.pc);
319        buffer.push_str(
320            self.format_instr(&regs, &instr, &mem[0..instr_len])
321                .as_str(),
322        );
323        Ok(buffer)
324    }
325
326    fn cmd_reg_read(&mut self) -> io::Result<String> {
327        let regs = self.read_regs()?;
328        Ok(self.format_regs(regs))
329    }
330
331    fn cmd_reg_write(&mut self, ops: Vec<RegOp>) -> io::Result<String> {
332        self.execute_unit_cmd(Command::RegWrite(ops))?;
333        let regs = self.read_regs()?;
334        Ok(self.format_regs(regs))
335    }
336
337    fn cmd_return(&mut self) -> io::Result<String> {
338        let mut bp_hit = 0;
339        loop {
340            let regs = self.read_regs()?;
341            let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(1))?;
342            let opcode = mem[0];
343            if opcode == OPCODE_RTS || opcode == OPCODE_RTI {
344                break;
345            }
346            bp_hit = self.execute_num_cmd(Command::Step)?;
347            if bp_hit > 0 {
348                break;
349            }
350        }
351        let mut buffer = String::new();
352        if bp_hit > 0 {
353            buffer.push_str("Stopped on breakpoint\n");
354        }
355        let regs = self.read_regs()?;
356        let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(10))?;
357        let dis = Disassembler::new(mem.clone(), regs.pc);
358        let (instr, instr_len) = dis.disassemble(regs.pc);
359        buffer.push_str(
360            self.format_instr(&regs, &instr, &mem[0..instr_len])
361                .as_str(),
362        );
363        Ok(buffer)
364    }
365
366    fn cmd_step(&mut self, count: u16) -> io::Result<String> {
367        let mut bp_hit = 0;
368        for _i in 0..count {
369            bp_hit = self.execute_num_cmd(Command::Step)?;
370            if bp_hit > 0 {
371                break;
372            }
373        }
374        let mut buffer = String::new();
375        if bp_hit > 0 {
376            buffer.push_str("Stopped on breakpoint\n");
377        }
378        let regs = self.read_regs()?;
379        let mem = self.read_mem(regs.pc, regs.pc.wrapping_add(10))?;
380        let dis = Disassembler::new(mem.clone(), regs.pc);
381        let (instr, instr_len) = dis.disassemble(regs.pc);
382        buffer.push_str(
383            self.format_instr(&regs, &instr, &mem[0..instr_len])
384                .as_str(),
385        );
386        Ok(buffer)
387    }
388
389    // -- Memory
390
391    fn cmd_compare(&mut self, start: u16, end: u16, target: u16) -> io::Result<String> {
392        let source_data = self.read_mem(start, end)?;
393        let target_end = target.wrapping_add(target + source_data.len() as u16);
394        let target_data = self.read_mem(target, target_end)?;
395        let mut buffer = String::new();
396        for i in 0..source_data.len() {
397            let source = source_data[i];
398            let dest = target_data[i];
399            if source != dest {
400                let s = format!(
401                    "${:04x} ${:04x}: {:02x} {:02x}\n",
402                    start.wrapping_add(i as u16),
403                    target.wrapping_add(i as u16),
404                    source,
405                    dest
406                );
407                buffer.push_str(s.as_str());
408            }
409        }
410        Ok(buffer)
411    }
412
413    fn cmd_disassemble(&mut self, start: Option<u16>, end: Option<u16>) -> io::Result<String> {
414        let start = start.unwrap_or_else(|| self.regs.as_ref().map(|r| r.pc).unwrap_or(0));
415        let end = end.unwrap_or(start + 96);
416        let data = self.read_mem(start, end + 10)?;
417        let dis = Disassembler::new(data, start);
418        let mut buffer = String::new();
419        let mut address = start;
420        while address < end {
421            let (instr, instr_len) = dis.disassemble(address);
422            let mut instr_bytes = String::new();
423            for i in 0..instr_len as u16 {
424                let byte = dis.read_byte(address + i);
425                instr_bytes.push_str(format!("{:02x} ", byte).as_str());
426            }
427            let instr_text = format!("{}", instr);
428            buffer.push_str(
429                format!("${:04x}  {:12} {}\n", address, instr_bytes, instr_text).as_str(),
430            );
431            address = address.wrapping_add(instr_len as u16);
432        }
433        Ok(buffer)
434    }
435
436    fn cmd_fill(&mut self, start: u16, end: u16, data: &[u8]) -> io::Result<String> {
437        let mut address = start;
438        while address < end {
439            self.execute_unit_cmd(Command::MemWrite(address, data.to_vec()))?;
440            address = address.wrapping_add(data.len() as u16);
441        }
442        Ok(String::new())
443    }
444
445    fn cmd_hunt(&mut self, start: u16, end: u16, search: &[u8]) -> io::Result<String> {
446        let data = self.read_mem(start, end)?;
447        let mut buffer = String::new();
448        for (i, value) in data.iter().enumerate() {
449            let mut found = true;
450            for item in search {
451                if *value != *item {
452                    found = false;
453                    break;
454                }
455            }
456            if found {
457                buffer.push_str(format!("{:04x}\n", start.wrapping_add(i as u16)).as_str());
458            }
459        }
460        Ok(buffer)
461    }
462
463    fn cmd_memory(&mut self, start: Option<u16>, end: Option<u16>) -> io::Result<String> {
464        let start = start.unwrap_or_else(|| self.regs.as_ref().map(|r| r.pc).unwrap_or(0));
465        let data = self.read_mem(start, end.unwrap_or(start + 96))?;
466        let mut buffer = String::new();
467        let mut address = start;
468        let mut counter = 0;
469        for value in data {
470            if counter % 12 == 0 {
471                buffer.push_str(format!("${:04x} ", address).as_str());
472                address = address.wrapping_add(12);
473            }
474            if counter % 4 == 0 {
475                buffer.push(' ');
476            }
477            buffer.push_str(format!(" {:02x}", value).as_str());
478            counter += 1;
479            if counter % 12 == 0 {
480                buffer.push('\n');
481            }
482        }
483        if counter % 12 != 0 {
484            buffer.push('\n');
485        }
486        Ok(buffer)
487    }
488
489    fn cmd_memchar(&mut self, address: Option<u16>) -> io::Result<String> {
490        let address = address.unwrap_or_else(|| self.regs.as_ref().map(|r| r.pc).unwrap_or(0));
491        let data = self.read_mem(address, address.wrapping_add(8))?;
492        let mut buffer = String::new();
493        for value in data {
494            let mut s = String::new();
495            s.push_str(format!("${:04x} ", address).as_str());
496            for i in 0..8 {
497                let bit = if value.get_bit(7 - i) { "." } else { "*" };
498                s.push_str(bit);
499            }
500            buffer.push_str(format!("{}\n", s).as_str());
501        }
502        Ok(buffer)
503    }
504
505    fn cmd_move(&mut self, start: u16, end: u16, target: u16) -> io::Result<String> {
506        let data = self.read_mem(start, end)?;
507        self.execute_unit_cmd(Command::MemWrite(target, data))
508    }
509
510    fn cmd_petscii(&mut self, start: u16, end: Option<u16>) -> io::Result<String> {
511        let data = self.read_mem(start, end.unwrap_or_else(|| start.wrapping_add(400)))?;
512        let mut buffer = String::new();
513        let mut counter = 0;
514        for value in data {
515            let ascii = match charset::pet_to_ascii(value) {
516                0 => 46,
517                v => v,
518            };
519            buffer.push(char::from(ascii));
520            counter += 1;
521            if counter % 40 == 0 {
522                buffer.push('\n');
523            }
524        }
525        if counter % 40 != 0 {
526            buffer.push('\n');
527        }
528        Ok(buffer)
529    }
530
531    // -- System
532
533    fn cmd_quit(&mut self) -> io::Result<String> {
534        self.running = false;
535        self.execute_unit_cmd(Command::SysQuit)
536    }
537
538    fn cmd_reset(&mut self, hard: bool) -> io::Result<String> {
539        self.execute_unit_cmd(Command::SysReset(hard))
540    }
541
542    fn cmd_screen(&mut self) -> io::Result<String> {
543        let vm_base = self.execute_num_cmd(Command::SysScreen)?;
544        let data = self.read_mem(vm_base, vm_base.wrapping_add(1000))?;
545        let mut buffer = String::new();
546        let mut counter = 0;
547        buffer.push_str(format!("Displaying 40x25 screen at ${:04x}\n", vm_base).as_str());
548        for value in data {
549            let ascii = match charset::screen_code_to_ascii(value) {
550                0 => 46,
551                v => v,
552            };
553            buffer.push(char::from(ascii));
554            counter += 1;
555            if counter % 40 == 0 {
556                buffer.push('\n');
557            }
558        }
559        if counter % 40 != 0 {
560            buffer.push('\n');
561        }
562        Ok(buffer)
563    }
564
565    fn cmd_stopwatch(&mut self, reset: bool) -> io::Result<String> {
566        let result = self.execute_buffer_cmd(Command::SysStopwatch(reset))?;
567        let mut rdr = Cursor::new(result);
568        let clock = rdr.read_u64::<BigEndian>()?;
569        Ok(format!("Clock: {}", clock))
570    }
571
572    // -- Monitor
573
574    fn cmd_exit(&mut self) -> io::Result<String> {
575        self.running = false;
576        Ok(String::new())
577    }
578
579    fn cmd_radix(&mut self, radix: Option<u16>) -> io::Result<String> {
580        if let Some(radix) = radix {
581            self.command_parser.set_radix(radix as u32);
582        }
583        let result = format!("Set radix to {}\n", self.command_parser.get_radix());
584        Ok(result)
585    }
586
587    // -- Helpers
588
589    fn execute_emu(&mut self, command: Command) -> io::Result<Output> {
590        self.command_tx.send(command).unwrap();
591        self.response_rx
592            .recv()
593            .map_err(|error| Error::new(ErrorKind::Other, error))
594    }
595
596    fn execute_buffer_cmd(&mut self, command: Command) -> io::Result<Vec<u8>> {
597        match self.execute_emu(command)? {
598            Output::Buffer(buffer) => Ok(buffer),
599            Output::Error(error) => Err(Error::new(ErrorKind::Other, error)),
600            _ => Err(Error::new(ErrorKind::Other, "Invalid debugger result")),
601        }
602    }
603
604    fn execute_num_cmd(&mut self, command: Command) -> io::Result<u16> {
605        match self.execute_emu(command)? {
606            Output::Number(num) => Ok(num),
607            Output::Error(error) => Err(Error::new(ErrorKind::Other, error)),
608            _ => Err(Error::new(ErrorKind::Other, "Invalid debugger result")),
609        }
610    }
611
612    fn execute_text_cmd(&mut self, command: Command) -> io::Result<String> {
613        match self.execute_emu(command)? {
614            Output::Text(text) => Ok(text),
615            Output::Error(error) => Err(Error::new(ErrorKind::Other, error)),
616            _ => Err(Error::new(ErrorKind::Other, "Invalid debugger result")),
617        }
618    }
619
620    fn execute_unit_cmd(&mut self, command: Command) -> io::Result<String> {
621        match self.execute_emu(command)? {
622            Output::Unit => Ok(String::new()),
623            Output::Error(error) => Err(Error::new(ErrorKind::Other, error)),
624            _ => Err(Error::new(ErrorKind::Other, "Invalid debugger result")),
625        }
626    }
627
628    fn format_instr(&self, regs: &RegData, instr: &Instruction, instr_bytes: &[u8]) -> String {
629        let mut buffer = String::new();
630        let mut instr_bytes2 = String::new();
631        for byte in instr_bytes {
632            instr_bytes2.push_str(format!("{:02x} ", byte).as_str());
633        }
634        buffer.push_str(
635            format!(
636                "${:04x}: {:12} {:16} A:{:02x} X:{:02x} Y:{:02x} SP:{:02x} {}{}{}{}{}{}{}  {}\n",
637                regs.pc,
638                instr_bytes2,
639                format!("{}", instr),
640                regs.a,
641                regs.x,
642                regs.y,
643                regs.sp,
644                if (regs.p & CpuFlag::Negative as u8) != 0 {
645                    "N"
646                } else {
647                    "n"
648                },
649                if (regs.p & CpuFlag::Overflow as u8) != 0 {
650                    "V"
651                } else {
652                    "v"
653                },
654                if (regs.p & CpuFlag::Decimal as u8) != 0 {
655                    "B"
656                } else {
657                    "b"
658                },
659                if (regs.p & CpuFlag::Decimal as u8) != 0 {
660                    "D"
661                } else {
662                    "d"
663                },
664                if (regs.p & CpuFlag::IntDisable as u8) != 0 {
665                    "I"
666                } else {
667                    "i"
668                },
669                if (regs.p & CpuFlag::Zero as u8) != 0 {
670                    "Z"
671                } else {
672                    "z"
673                },
674                if (regs.p & CpuFlag::Carry as u8) != 0 {
675                    "C"
676                } else {
677                    "c"
678                },
679                regs.clock,
680            )
681            .as_str(),
682        );
683        buffer
684    }
685
686    fn format_regs(&self, regs: RegData) -> String {
687        let mut buffer = String::new();
688        buffer.push_str("PC   A  X  Y  SP 00 01 NV-BDIZC\n");
689        buffer.push_str(
690            format!(
691                "{:04x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {}{}1{}{}{}{}{}\n",
692                regs.pc,
693                regs.a,
694                regs.x,
695                regs.y,
696                regs.sp,
697                regs.port_00,
698                regs.port_01,
699                if (regs.p & CpuFlag::Negative as u8) != 0 {
700                    "1"
701                } else {
702                    "0"
703                },
704                if (regs.p & CpuFlag::Overflow as u8) != 0 {
705                    "1"
706                } else {
707                    "0"
708                },
709                if (regs.p & CpuFlag::Break as u8) != 0 {
710                    "1"
711                } else {
712                    "0"
713                },
714                if (regs.p & CpuFlag::Decimal as u8) != 0 {
715                    "1"
716                } else {
717                    "0"
718                },
719                if (regs.p & CpuFlag::IntDisable as u8) != 0 {
720                    "1"
721                } else {
722                    "0"
723                },
724                if (regs.p & CpuFlag::Zero as u8) != 0 {
725                    "1"
726                } else {
727                    "0"
728                },
729                if (regs.p & CpuFlag::Carry as u8) != 0 {
730                    "1"
731                } else {
732                    "0"
733                }
734            )
735            .as_str(),
736        );
737        buffer
738    }
739}
740
741struct CommandParser {
742    radix: u32,
743}
744
745impl CommandParser {
746    pub fn new() -> Self {
747        Self { radix: 16 }
748    }
749
750    pub fn get_radix(&self) -> u32 {
751        self.radix
752    }
753
754    pub fn set_radix(&mut self, radix: u32) {
755        self.radix = radix;
756    }
757
758    pub fn parse(&self, input: &str) -> Result<Cmd, String> {
759        let mut tokens = input.split_whitespace();
760        if let Some(command) = tokens.next() {
761            match command.to_lowercase().as_str() {
762                // Breakpoint
763                "break" | "bk" => self.parse_break(&mut tokens),
764                "condition" | "cond" => self.parse_condition(&mut tokens),
765                "enable" | "en" => self.parse_enable(&mut tokens),
766                "delete" | "del" => self.parse_delete(&mut tokens),
767                "disable" | "dis" => self.parse_disable(&mut tokens),
768                "ignore" => self.parse_ignore(&mut tokens),
769                "until" | "un" => self.parse_until(&mut tokens),
770                // Debugger
771                "goto" | "g" => self.parse_goto(&mut tokens),
772                "next" | "n" => self.parse_next(&mut tokens),
773                "registers" | "r" => self.parse_registers(&mut tokens),
774                "return" | "ret" => self.parse_return(&mut tokens),
775                "step" | "z" => self.parse_step(&mut tokens),
776                // Memory
777                "compare" | "c" => self.parse_compare(&mut tokens),
778                "disass" | "d" => self.parse_disassemble(&mut tokens),
779                "fill" | "f" => self.parse_fill(&mut tokens),
780                "hunt" | "h" => self.parse_hunt(&mut tokens),
781                "mem" | "m" => self.parse_memory(&mut tokens),
782                "memchar" | "mc" => self.parse_mem_char(&mut tokens),
783                "move" | "t" => self.parse_move(&mut tokens),
784                "i" => self.parse_petscii(&mut tokens),
785                // System
786                "reset" => self.parse_reset(&mut tokens),
787                "screen" | "sc" => self.parse_screen(&mut tokens),
788                "stopwatch" | "sw" => self.parse_stopwatch(&mut tokens),
789                // Monitor
790                "exit" | "x" => self.parse_exit(&mut tokens),
791                "help" | "?" => self.parse_help(&mut tokens),
792                "quit" => self.parse_quit(&mut tokens),
793                "radix" => self.parse_radix(&mut tokens),
794                _ => Err(format!("Invalid command {}", input)),
795            }
796        } else {
797            Err(format!("Invalid command {}", input))
798        }
799    }
800
801    // -- Breakpoint
802
803    fn parse_break(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
804        let address = self.parse_num_maybe(tokens.next())?;
805        self.ensure_eos(tokens)?;
806        match address {
807            Some(address) => Ok(Cmd::BpSet(address)),
808            None => Ok(Cmd::BpList),
809        }
810    }
811
812    fn parse_condition(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
813        let index = self.parse_num(tokens.next())?;
814        self.ensure_keyword("if", tokens)?;
815        let expr = tokens.next();
816        self.ensure_eos(tokens)?;
817        if let Some(expr) = expr {
818            Ok(Cmd::BpCondition(index, expr.to_string()))
819        } else {
820            Err("Missing expression".to_string())
821        }
822    }
823
824    fn parse_delete(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
825        let index = self.parse_num_maybe(tokens.next())?;
826        self.ensure_eos(tokens)?;
827        Ok(Cmd::BpDelete(index))
828    }
829
830    fn parse_disable(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
831        let index = self.parse_num_maybe(tokens.next())?;
832        self.ensure_eos(tokens)?;
833        Ok(Cmd::BpDisable(index))
834    }
835
836    fn parse_enable(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
837        let index = self.parse_num_maybe(tokens.next())?;
838        self.ensure_eos(tokens)?;
839        Ok(Cmd::BpEnable(index))
840    }
841
842    fn parse_ignore(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
843        let index = self.parse_num(tokens.next())?;
844        let count = self.parse_num_maybe(tokens.next())?;
845        self.ensure_eos(tokens)?;
846        Ok(Cmd::BpIgnore(index, count.unwrap_or(1)))
847    }
848
849    fn parse_until(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
850        let address = self.parse_num_maybe(tokens.next())?;
851        self.ensure_eos(tokens)?;
852        match address {
853            Some(address) => Ok(Cmd::BpUntil(address)),
854            None => Ok(Cmd::BpList),
855        }
856    }
857
858    // -- Debugger
859
860    fn parse_goto(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
861        let address = self.parse_num_maybe(tokens.next())?;
862        self.ensure_eos(tokens)?;
863        Ok(Cmd::Goto(address))
864    }
865
866    fn parse_next(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
867        let count = self.parse_num_maybe(tokens.next())?;
868        self.ensure_eos(tokens)?;
869        Ok(Cmd::Next(count.unwrap_or(1)))
870    }
871
872    fn parse_registers(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
873        let mut ops = Vec::new();
874        while let Some(op) = self.parse_reg_op(tokens)? {
875            ops.push(op);
876            if !self.parse_reg_sep(tokens)? {
877                break;
878            }
879        }
880        if ops.is_empty() {
881            Ok(Cmd::RegRead)
882        } else {
883            Ok(Cmd::RegWrite(ops))
884        }
885    }
886
887    fn parse_reg_op(
888        &self,
889        tokens: &mut dyn Iterator<Item = &str>,
890    ) -> Result<Option<RegOp>, String> {
891        if let (Some(name), Some(op), Some(value)) = (tokens.next(), tokens.next(), tokens.next()) {
892            match op.trim() {
893                "=" => {
894                    let reg = RegName::from(name.trim())?;
895                    let op = match reg {
896                        RegName::A => RegOp::SetA(self.parse_byte(value.trim())?),
897                        RegName::X => RegOp::SetX(self.parse_byte(value.trim())?),
898                        RegName::Y => RegOp::SetY(self.parse_byte(value.trim())?),
899                        RegName::P => RegOp::SetP(self.parse_byte(value.trim())?),
900                        RegName::SP => RegOp::SetSP(self.parse_byte(value.trim())?),
901                        RegName::PC => RegOp::SetPC(self.parse_word(value.trim())?),
902                    };
903                    Ok(Some(op))
904                }
905                _ => Err(format!("invalid operator {}", op)),
906            }
907        } else {
908            Ok(None)
909        }
910    }
911
912    fn parse_reg_sep(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<bool, String> {
913        if let Some(sep) = tokens.next() {
914            match sep.trim() {
915                "," => Ok(true),
916                _ => Err(format!("invalid token {}", sep)),
917            }
918        } else {
919            Ok(false)
920        }
921    }
922
923    fn parse_return(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
924        self.ensure_eos(tokens)?;
925        Ok(Cmd::Return)
926    }
927
928    fn parse_step(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
929        let count = self.parse_num_maybe(tokens.next())?;
930        self.ensure_eos(tokens)?;
931        Ok(Cmd::Step(count.unwrap_or(1)))
932    }
933
934    // -- Memory
935
936    fn parse_compare(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
937        let start = self.parse_num(tokens.next())?;
938        let end = self.parse_num(tokens.next())?;
939        let target = self.parse_num(tokens.next())?;
940        self.ensure_eos(tokens)?;
941        Ok(Cmd::Compare(start, end, target))
942    }
943
944    fn parse_disassemble(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
945        let start = self.parse_num_maybe(tokens.next())?;
946        let end = self.parse_num_maybe(tokens.next())?;
947        self.ensure_eos(tokens)?;
948        Ok(Cmd::Disassemble(start, end))
949    }
950
951    fn parse_fill(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
952        let start = self.parse_num(tokens.next())?;
953        let end = self.parse_num(tokens.next())?;
954        let mut data: Vec<u8> = Vec::new();
955        for token in tokens {
956            if token.contains(',') {
957                for value in token.split(',') {
958                    data.push(self.parse_byte(value)?);
959                }
960            } else {
961                data.push(self.parse_byte(token)?)
962            }
963        }
964        if !data.is_empty() {
965            Ok(Cmd::Fill(start, end, data))
966        } else {
967            Err("Missing data".to_string())
968        }
969    }
970
971    fn parse_hunt(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
972        let start = self.parse_num(tokens.next())?;
973        let end = self.parse_num(tokens.next())?;
974        let mut data: Vec<u8> = Vec::new();
975        for token in tokens {
976            if token.contains(',') {
977                for value in token.split(',') {
978                    data.push(self.parse_byte(value)?);
979                }
980            } else {
981                data.push(self.parse_byte(token)?)
982            }
983        }
984        if !data.is_empty() {
985            Ok(Cmd::Hunt(start, end, data))
986        } else {
987            Err("Missing data".to_string())
988        }
989    }
990
991    fn parse_memory(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
992        let start = self.parse_num_maybe(tokens.next())?;
993        let end = self.parse_num_maybe(tokens.next())?;
994        self.ensure_eos(tokens)?;
995        Ok(Cmd::Memory(start, end))
996    }
997
998    fn parse_mem_char(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
999        let address = self.parse_num_maybe(tokens.next())?;
1000        self.ensure_eos(tokens)?;
1001        Ok(Cmd::MemChar(address))
1002    }
1003
1004    fn parse_move(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1005        let start = self.parse_num(tokens.next())?;
1006        let end = self.parse_num(tokens.next())?;
1007        let target = self.parse_num(tokens.next())?;
1008        self.ensure_eos(tokens)?;
1009        Ok(Cmd::Move(start, end, target))
1010    }
1011
1012    fn parse_petscii(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1013        let start = self.parse_num(tokens.next())?;
1014        let end = self.parse_num_maybe(tokens.next())?;
1015        self.ensure_eos(tokens)?;
1016        Ok(Cmd::Petscii(start, end))
1017    }
1018
1019    // -- System
1020
1021    fn parse_reset(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1022        let mode = self.parse_num_maybe(tokens.next())?;
1023        self.ensure_eos(tokens)?;
1024        Ok(Cmd::Reset(mode.unwrap_or(0) == 1))
1025    }
1026
1027    fn parse_screen(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1028        self.ensure_eos(tokens)?;
1029        Ok(Cmd::Screen)
1030    }
1031
1032    fn parse_stopwatch(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1033        let reset = if let Some(token) = tokens.next() {
1034            token == "reset"
1035        } else {
1036            false
1037        };
1038        Ok(Cmd::Stopwatch(reset))
1039    }
1040
1041    // -- Monitor
1042
1043    fn parse_help(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1044        let command = tokens.next().map(|s| s.to_string());
1045        self.ensure_eos(tokens)?;
1046        Ok(Cmd::Help(command))
1047    }
1048
1049    fn parse_exit(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1050        self.ensure_eos(tokens)?;
1051        Ok(Cmd::Exit)
1052    }
1053
1054    fn parse_quit(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1055        self.ensure_eos(tokens)?;
1056        Ok(Cmd::Quit)
1057    }
1058
1059    fn parse_radix(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<Cmd, String> {
1060        let radix = self.parse_num_maybe(tokens.next())?;
1061        self.ensure_eos(tokens)?;
1062        Ok(Cmd::Radix(radix))
1063    }
1064
1065    // -- Helpers
1066
1067    fn ensure_eos(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<(), String> {
1068        match tokens.next() {
1069            Some(token) => Err(format!("Unexpected token {}", token)),
1070            None => Ok(()),
1071        }
1072    }
1073
1074    fn ensure_keyword(
1075        &self,
1076        keyword: &str,
1077        tokens: &mut dyn Iterator<Item = &str>,
1078    ) -> Result<(), String> {
1079        match tokens.next() {
1080            Some(token) if token.to_string().to_lowercase() == keyword => Ok(()),
1081            _ => Err(format!("Missing keyword {}", keyword)),
1082        }
1083    }
1084
1085    fn parse_byte(&self, value: &str) -> Result<u8, String> {
1086        u8::from_str_radix(value, self.radix).map_err(|_| format!("Invalid number {}", value))
1087    }
1088
1089    fn parse_num(&self, input: Option<&str>) -> Result<u16, String> {
1090        if let Some(value) = input {
1091            u16::from_str_radix(value, self.radix).map_err(|_| format!("Invalid number {}", value))
1092        } else {
1093            Err("missing argument".to_string())
1094        }
1095    }
1096
1097    fn parse_num_maybe(&self, input: Option<&str>) -> Result<Option<u16>, String> {
1098        if let Some(value) = input {
1099            let result = u16::from_str_radix(value, self.radix)
1100                .map_err(|_| format!("Invalid number {}", value))?;
1101            Ok(Some(result))
1102        } else {
1103            Ok(None)
1104        }
1105    }
1106
1107    fn parse_word(&self, value: &str) -> Result<u16, String> {
1108        u16::from_str_radix(value, self.radix).map_err(|_| format!("Invalid number {}", value))
1109    }
1110}
1111
1112struct CommandHelp;
1113
1114impl CommandHelp {
1115    pub fn help(command: Option<String>) -> io::Result<String> {
1116        if let Some(command) = command {
1117            match command.trim().to_lowercase().as_str() {
1118                // Breakpoint
1119                "break" | "bk" => CommandHelp::help_cmd("break [address]", "bk"),
1120                "condition" | "cond" => {
1121                    CommandHelp::help_cmd("condition <index> if <cond_exp>", "cond")
1122                }
1123                "enable" | "en" => CommandHelp::help_cmd("enable [<index>]", "en"),
1124                "delete" | "del" => CommandHelp::help_cmd("delete [<index>]", "del"),
1125                "disable" | "dis" => CommandHelp::help_cmd("disable [<index>]", "dis"),
1126                "ignore" => CommandHelp::help_cmd("ignore <index> [<count>]", ""),
1127                "until" | "un" => CommandHelp::help_cmd("until <address>", "un"),
1128                // Debugger
1129                "goto" | "g" => CommandHelp::help_cmd("goto <address>", "g"),
1130                "next" | "n" => CommandHelp::help_cmd("next [<count>]", "n"),
1131                "registers" | "r" => {
1132                    CommandHelp::help_cmd("registers [<reg> = <num>[, <reg> = <num>]*]", "r")
1133                }
1134                "return" | "ret" => CommandHelp::help_cmd("return", "ret"),
1135                "step" | "z" => CommandHelp::help_cmd("step [<count>]", "z"),
1136                // Memory
1137                "compare" | "c" => CommandHelp::help_cmd("compare", "c"),
1138                "disass" | "d" => CommandHelp::help_cmd("disass [<address> [<address>]]", "d"),
1139                "fill" | "f" => CommandHelp::help_cmd("fill <address> <address> <data_list>", "f"),
1140                "hunt" | "h" => CommandHelp::help_cmd("hunt <address> <address> <data_list>", "h"),
1141                "mem" | "m" => CommandHelp::help_cmd("mem [<address> [<address>]]", "m"),
1142                "memchar" | "mc" => CommandHelp::help_cmd("memchar [<address>]", "mc"),
1143                "move" | "t" => CommandHelp::help_cmd("move <address> <address> <address>", "t"),
1144                "petscii" | "i" => CommandHelp::help_cmd("petscii <address> [<address>]", "i"),
1145                // System
1146                "reset" => CommandHelp::help_cmd("reset [<type>]", ""),
1147                "screen" | "sc" => CommandHelp::help_cmd("screen", "sc"),
1148                "stopwatch" | "sw" => CommandHelp::help_cmd("stopwatch [reset]", "sw"),
1149                // Monitor
1150                "exit" | "x" => CommandHelp::help_cmd("exit", "x"),
1151                "help" | "?" => CommandHelp::help_cmd("help", "?"),
1152                "quit" => CommandHelp::help_cmd("quit", ""),
1153                "radix" => CommandHelp::help_cmd("radix <num>", ""),
1154                _ => Err(Error::new(
1155                    ErrorKind::Other,
1156                    format!("Invalid command {}", command),
1157                )),
1158            }
1159        } else {
1160            CommandHelp::help_star()
1161        }
1162    }
1163
1164    fn help_cmd(syntax: &str, short: &str) -> io::Result<String> {
1165        let abbr_line = if short.is_empty() {
1166            String::new()
1167        } else {
1168            format!("Shortname: {}\n", short)
1169        };
1170        let result = format!("Syntax: {}\n{}", syntax, abbr_line);
1171        Ok(result)
1172    }
1173
1174    fn help_star() -> io::Result<String> {
1175        let mut buffer = String::new();
1176        buffer.push_str("* Breakpoint *\n");
1177        buffer.push_str("break (bk)\n");
1178        buffer.push_str("condition (cond)\n");
1179        buffer.push_str("enable (en)\n");
1180        buffer.push_str("delete (del)\n");
1181        buffer.push_str("disable (dis)\n");
1182        buffer.push_str("ignore\n");
1183        buffer.push_str("until (un)\n");
1184        buffer.push_str("\n");
1185        buffer.push_str("* Debug *\n");
1186        buffer.push_str("goto (g)\n");
1187        buffer.push_str("next (n)\n");
1188        buffer.push_str("registers (r)\n");
1189        buffer.push_str("return (ret)\n");
1190        buffer.push_str("step (z)\n");
1191        buffer.push_str("\n");
1192        buffer.push_str("* Memory *\n");
1193        buffer.push_str("compare (c)\n");
1194        buffer.push_str("disass (d)\n");
1195        buffer.push_str("fill (f)\n");
1196        buffer.push_str("hunt (h)\n");
1197        buffer.push_str("mem (m)\n");
1198        buffer.push_str("memchar (mc)\n");
1199        buffer.push_str("move (t)\n");
1200        buffer.push_str("petscii (i)\n");
1201        buffer.push_str("\n");
1202        buffer.push_str("* System *\n");
1203        buffer.push_str("reset\n");
1204        buffer.push_str("screen (sc)\n");
1205        buffer.push_str("stopwatch (sw)\n");
1206        buffer.push_str("\n");
1207        buffer.push_str("* Monitor *\n");
1208        buffer.push_str("exit (x)\n");
1209        buffer.push_str("help (?)\n");
1210        buffer.push_str("quit\n");
1211        buffer.push_str("radix\n");
1212        buffer.push_str("\n");
1213        Ok(buffer)
1214    }
1215}
1216
1217enum CpuFlag {
1218    Carry = 1,
1219    Zero = 1 << 1,
1220    IntDisable = 1 << 2,
1221    Decimal = 1 << 3,
1222    Break = 1 << 4,
1223    Overflow = 1 << 6,
1224    Negative = 1 << 7,
1225}
1226
1227enum RegName {
1228    A,
1229    X,
1230    Y,
1231    P,
1232    SP,
1233    PC,
1234}
1235
1236impl RegName {
1237    pub fn from(name: &str) -> Result<RegName, String> {
1238        match name {
1239            "a" | "A" => Ok(RegName::A),
1240            "x" | "X" => Ok(RegName::X),
1241            "y" | "Y" => Ok(RegName::Y),
1242            "p" | "P" => Ok(RegName::P),
1243            "sp" | "SP" => Ok(RegName::SP),
1244            "pc" | "PC" => Ok(RegName::PC),
1245            _ => Err(format!("invalid register {}", name)),
1246        }
1247    }
1248}