1#![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
22const OPCODE_JSR: u8 = 0x20;
25const OPCODE_RTI: u8 = 0x40;
26const OPCODE_RTS: u8 = 0x60;
27
28pub enum Cmd {
31 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 Goto(Option<u16>),
42 Next(u16),
43 RegRead,
44 RegWrite(Vec<RegOp>),
45 Return,
46 Step(u16),
47 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 Reset(bool),
58 Screen,
59 Stopwatch(bool),
60 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 command_parser: CommandParser,
96 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 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 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 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 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 Cmd::Reset(hard) => self.cmd_reset(hard),
169 Cmd::Screen => self.cmd_screen(),
170 Cmd::Stopwatch(reset) => self.cmd_stopwatch(reset),
171 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 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(®s, &instr, &mem[0..instr_len]))
270 }
271
272 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(®s, &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(®s, &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(®s, &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(®s, &instr, &mem[0..instr_len])
384 .as_str(),
385 );
386 Ok(buffer)
387 }
388
389 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 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 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 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 "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 "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 "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 "reset" => self.parse_reset(&mut tokens),
787 "screen" | "sc" => self.parse_screen(&mut tokens),
788 "stopwatch" | "sw" => self.parse_stopwatch(&mut tokens),
789 "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 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 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 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 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 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 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 "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 "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 "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 "reset" => CommandHelp::help_cmd("reset [<type>]", ""),
1147 "screen" | "sc" => CommandHelp::help_cmd("screen", "sc"),
1148 "stopwatch" | "sw" => CommandHelp::help_cmd("stopwatch [reset]", "sw"),
1149 "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}