1#![allow(clippy::module_name_repetitions)]
7
8use crate::inst::{InstSet, Op};
9use std::{
10 collections::BTreeMap,
11 fmt::{Debug, Display, Formatter, Result as FmtResult},
12 io::{stdin, stdout, BufReader, Read, Write},
13 str::FromStr,
14};
15
16#[allow(clippy::needless_pass_by_value, clippy::enum_glob_use)]
19pub mod arith;
20
21#[allow(clippy::needless_pass_by_value, clippy::enum_glob_use)]
24pub mod io;
25
26#[allow(clippy::needless_pass_by_value, clippy::enum_glob_use)]
29pub mod mov;
30
31#[allow(clippy::needless_pass_by_value, clippy::enum_glob_use)]
34pub mod cmp;
35
36#[allow(clippy::needless_pass_by_value, clippy::enum_glob_use)]
39pub mod bitman;
40
41#[allow(clippy::enum_glob_use)]
42mod error;
43
44mod memory;
45
46mod debug;
47
48#[allow(clippy::enum_glob_use)]
49mod inst;
50
51pub use error::{RtError, RtResult, Source};
52
53pub use memory::Memory;
54
55pub use inst::{ExecFunc, ExecInst};
56
57pub use debug::DebugInfo;
58
59pub struct Io {
63 pub read: BufReader<Box<dyn Read + Send + Sync>>,
64 pub write: Box<dyn Write + Send + Sync>,
65}
66
67#[macro_export]
82macro_rules! make_io {
83 () => {
84 $crate::exec::Io::default()
85 };
86 ($read:expr, $write:expr) => {{
87 $crate::exec::Io {
88 read: std::io::BufReader::new(Box::new($read)),
89 write: Box::new($write),
90 }
91 }};
92}
93
94impl Debug for Io {
95 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
96 f.write_str("<struct Io>")
97 }
98}
99
100impl Default for Io {
101 fn default() -> Self {
102 Self {
103 read: BufReader::new(Box::new(stdin())),
104 write: Box::new(stdout()),
105 }
106 }
107}
108
109#[derive(Debug, Default)]
111pub struct Context {
112 pub cmp: bool,
113 pub mar: usize,
114 pub acc: usize,
115 pub ix: usize,
116 pub flow_override_reg: bool,
117 pub mem: Memory,
118 pub ret: usize,
119 pub gprs: [usize; 30],
120 pub end: bool,
121 pub io: Io,
122}
123
124impl Context {
125 pub fn new(mem: Memory) -> Self {
126 Self {
127 mem,
128 ..Self::default()
129 }
130 }
131
132 pub fn with_io(mem: Memory, io: Io) -> Self {
133 Self {
134 mem,
135 io,
136 ..Self::default()
137 }
138 }
139
140 #[inline]
141 pub fn override_flow_control(&mut self) {
142 self.flow_override_reg = true;
143 }
144
145 #[inline]
148 pub fn get_mut_register(&mut self, op: &Op) -> &mut usize {
149 match op {
150 Op::Acc => &mut self.acc,
151 Op::Ix => &mut self.ix,
152 Op::Ar => &mut self.ret,
153 Op::Gpr(x) => &mut self.gprs[*x],
154 _ => unreachable!(),
155 }
156 }
157
158 #[inline]
161 pub fn get_register(&self, op: &Op) -> usize {
162 match op {
163 Op::Acc => self.acc,
164 Op::Ix => self.ix,
165 Op::Ar => self.ret,
166 Op::Gpr(x) => self.gprs[*x],
167 _ => unreachable!(),
168 }
169 }
170
171 #[inline]
194 pub fn read(&self, op: &Op) -> RtResult<usize> {
195 match op {
196 &Op::Literal(val) => Ok(val),
197 Op::Addr(addr) => self.mem.get(addr).copied(),
198 Op::Indirect(op) if op.is_usizeable() => {
199 let addr = self.read(op)?;
200 self.mem.get(&addr).copied()
201 }
202 reg if reg.is_register() => Ok(self.get_register(reg)),
203 _ => unreachable!(),
204 }
205 }
206
207 pub fn as_address(&self, op: &Op) -> RtResult<usize> {
210 match op {
211 &Op::Addr(addr) => Ok(addr),
212 Op::Indirect(op) if op.is_read_write() => self.read(op),
213 _ => unreachable!(),
214 }
215 }
216
217 #[inline]
241 pub fn modify(&mut self, op: &Op, f: impl Fn(&mut usize)) -> RtResult {
242 match op {
243 Op::Addr(x) => f(self.mem.get_mut(x)?),
244 Op::Indirect(op) if op.is_usizeable() => {
245 let addr = self.read(op)?;
246 f(self.mem.get_mut(&addr)?);
247 }
248 op if op.is_register() => f(self.get_mut_register(op)),
249 _ => unreachable!(),
250 }
251
252 Ok(())
253 }
254}
255
256impl Display for Context {
257 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
258 f.write_str("Context {\n")?;
259 writeln!(f, "{:>6}: {}", "mar", self.mar)?;
260 writeln!(f, "{:>6}: {}", "acc", self.acc)?;
261 writeln!(f, "{:>6}: {}", "ix", self.ix)?;
262 writeln!(f, "{:>6}: {}", "cmp", self.cmp)?;
263 write!(f, "{:>6}: [", "gprs")?;
264
265 for (idx, val) in self.gprs.iter().enumerate() {
266 if idx == self.gprs.len() - 1 {
267 writeln!(f, "r{idx} = {val}]")?;
268 } else {
269 write!(f, "r{idx} = {val}, ")?;
270 }
271 }
272
273 writeln!(f, "{:>6}: Memory {{", "mem")?;
274
275 for (addr, entry) in &self.mem {
276 writeln!(f, "{addr:>8}: {entry},")?;
277 }
278
279 writeln!(f, "{:>6}}}", "")?;
280
281 f.write_str("}")
282 }
283}
284
285pub type ExTree = BTreeMap<usize, ExecInst>;
287
288pub struct Executor {
290 pub debug_info: DebugInfo,
291 pub source: Source,
292 pub prog: ExTree,
293 pub ctx: Context,
294 count: u64,
295}
296
297pub enum Status {
299 Complete,
301 Continue,
303 Error(RtError),
305}
306
307impl Executor {
308 pub fn new(
309 source: impl Into<Source>,
310 prog: ExTree,
311 ctx: Context,
312 debug_info: DebugInfo,
313 ) -> Self {
314 Self {
315 debug_info,
316 source: source.into(),
317 prog,
318 ctx,
319 count: 0,
320 }
321 }
322
323 pub fn step<T>(&mut self) -> Status
330 where
331 T: InstSet,
332 <T as FromStr>::Err: Display,
333 {
334 if self.ctx.mar == self.prog.len() || self.ctx.end {
335 Status::Complete
336 } else {
337 self.count += 1;
338
339 let inst = if let Some(inst) = self.prog.get(&self.ctx.mar) {
340 inst
341 } else {
342 panic!("Unable to fetch instruction. Please report this as a bug with full debug logs attached.")
343 };
344
345 trace!(
346 "Executing instruction {} {}",
347 T::from_id(inst.id).unwrap_or_else(|msg| panic!("{msg}")),
348 inst.op
349 );
350
351 match (inst.func)(&mut self.ctx, &inst.op) {
352 Ok(()) => {
353 if self.ctx.flow_override_reg {
354 self.ctx.flow_override_reg = false;
355 } else {
356 self.ctx.mar += 1;
357 }
358
359 Status::Continue
360 }
361 Err(e) => Status::Error(e),
362 }
363 }
364 }
365
366 pub fn exec<T>(&mut self)
367 where
368 T: InstSet,
369 <T as FromStr>::Err: Display,
370 {
371 #[allow(clippy::needless_continue)]
372 let err = loop {
373 match self.step::<T>() {
374 Status::Complete => break None,
375 Status::Continue => continue,
376 Status::Error(e) => break Some(e),
377 }
378 };
379
380 if let Some(e) = err {
381 self.source
382 .handle_err(&mut self.ctx.io.write, &e, self.ctx.mar)
383 .unwrap();
384 } else {
385 info!("Total instructions executed: {}", self.count);
386 }
387 }
388
389 pub fn display_with_opcodes<T>(&self) -> Result<String, <T as FromStr>::Err>
390 where
391 T: InstSet,
392 <T as FromStr>::Err: Display,
393 {
394 use std::fmt::Write;
395
396 let mut s = String::new();
397
398 s.reserve(self.prog.len() * 15);
399
400 writeln!(s, "Executor {{").unwrap();
401
402 for (addr, ExecInst { id, op, .. }) in &self.prog {
403 writeln!(s, "{addr:>6}: {func} {op}", func = T::from_id(*id)?).unwrap();
404 }
405
406 s.push('}');
407
408 Ok(s)
409 }
410}
411
412impl Display for Executor {
413 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
414 f.write_str("Executor {")?;
415 for (addr, ExecInst { op, .. }) in &self.prog {
416 writeln!(f, "{addr:>6}: {op}")?;
417 }
418 f.write_str("}")
419 }
420}
421
422impl Debug for Executor {
423 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
424 f.debug_struct("Executor")
425 .field("source", &self.source)
426 .field(
427 "prog",
428 &self
429 .prog
430 .iter()
431 .map(|(addr, ExecInst { op, .. })| (addr, op))
432 .collect::<Vec<_>>(),
433 )
434 .field("ctx", &self.ctx)
435 .field("count", &self.count)
436 .finish_non_exhaustive()
437 }
438}
439
440#[cfg(test)]
441mod tests {
442 use super::*;
443
444 #[test]
445 fn ensure_send_sync() {
446 fn assert_send_sync<T: Send + Sync>() {}
447 assert_send_sync::<Executor>();
448 }
449
450 #[test]
451 fn exec() {
452 let prog =
453 [
455 (0, ExecInst::new(0, arith::inc, "202".into())),
456 (1, ExecInst::new(0, arith::add, "203,201".into())),
457 (2, ExecInst::new(0, cmp::cmp, "203,204".into())),
458 (3, ExecInst::new(0, cmp::jpn, "0".into())),
459 (4, ExecInst::new(0, mov::ldd, "202".into())),
460 (5, ExecInst::new(0, io::end, "".into())),
461 ].into();
462
463 let mem = [(200, 0), (201, 5), (202, 0), (203, 0), (204, 15)].into();
464
465 let mut exec = Executor::new(
466 "None",
467 prog,
468 Context::new(Memory::new(mem)),
469 DebugInfo::default(),
470 );
471
472 exec.exec::<crate::parse::DefaultSet>();
473
474 assert_eq!(exec.ctx.acc, 3);
475 }
476}