1use crate::{Instruction, InstructionHandler, VMState, DDR, DSR, KBDR, KBSR, OPERATING_SYSTEM, VM};
2use std::io::{Error as IOError, Read, Result as IOResult, Write};
3use std::marker::PhantomData;
4
5#[cfg(all(target_os = "windows", not(feature = "disable-crlf-compat-windows")))]
6use crate::crlf_helper::CrlfToLf;
7
8pub struct IOStreamHandler<R: Read, W: Write> {
10 phantom_r: PhantomData<R>,
11 phantom_w: PhantomData<W>,
12}
13
14impl<R: Read, W: Write> InstructionHandler for IOStreamHandler<R, W> {
15 type Context = (R, W);
16 type Err = IOError;
17
18 fn create_vm(initial_context: Self::Context) -> VM<Self> {
19 let mut vm = VM {
20 state: Default::default(),
21 context: initial_context,
22 };
23 vm.load_u8(OPERATING_SYSTEM);
24 vm
25 }
26
27 fn process_instruction(
28 vm_state: &mut VMState,
29 context: &mut Self::Context,
30 instruction: Instruction,
31 ) -> IOResult<()> {
32 macro_rules! reg {
33 ($num:expr) => {
34 vm_state.register[$num as usize]
35 };
36 }
37
38 macro_rules! zero_if_eq {
39 ($addr:expr, $data:expr, $state:expr) => {
40 if $addr == $data {
41 vm_state.mem[$state] = 0;
42 }
52 };
53 }
54
55 let input = &mut context.0;
56
57 #[cfg(all(target_os = "windows", not(feature = "disable-crlf-compat-windows")))]
58 let input = CrlfToLf(input); let mut in_stream = input.bytes();
61
62 macro_rules! handle_input {
63 ($addr:expr) => {
64 if $addr == KBSR {
65 if let Some(result) = in_stream.next() {
66 vm_state.mem[KBSR] |= 0b1000_0000_0000_0000;
67 vm_state.mem[KBDR] = u16::from(result.unwrap());
68 }
69 }
70 };
71 }
72
73 macro_rules! handle_output {
74 ($addr:expr) => {
75 if $addr == DDR {
76 context.1.write_all(&[vm_state.mem[DDR] as u8])?;
77 vm_state.mem[DSR] |= 0b1000_0000_0000_0000;
78 }
79 };
80 }
81
82 #[cfg(feature = "instruction-trace")]
83 eprintln!("[DEBUG] {:?}", instruction);
84
85 match instruction {
86 Instruction::ADD { dst, src1, src2 } => {
87 reg!(dst) = reg!(src1).wrapping_add(reg!(src2));
88 vm_state.update_condition(dst as usize);
89 }
90 Instruction::ADDi { dst, src, immd } => {
91 reg!(dst) = reg!(src).wrapping_add(immd);
92 vm_state.update_condition(dst as usize);
93 }
94 Instruction::AND { dst, src1, src2 } => {
95 reg!(dst) = reg!(src1) & reg!(src2);
96 vm_state.update_condition(dst as usize);
97 }
98 Instruction::ANDi { dst, src, immd } => {
99 reg!(dst) = reg!(src) & immd;
100 vm_state.update_condition(dst as usize);
101 }
102 Instruction::BR { cond, offset } => {
103 if cond.satisfies(&vm_state.condition) {
104 vm_state.pc = vm_state.pc.wrapping_add(offset as u16);
105 }
106 }
107 Instruction::JMP { base } => {
108 vm_state.pc = reg!(base) as u16;
109 }
110 Instruction::JSR { offset } => {
111 reg!(7) = vm_state.pc as i16;
112 vm_state.pc = vm_state.pc.wrapping_add(offset as u16);
113 }
114 Instruction::JSRR { base } => {
115 reg!(7) = vm_state.pc as i16;
116 vm_state.pc = reg!(base) as u16;
117 }
118 Instruction::LD { dst, offset } => {
119 let addr = (vm_state.pc.wrapping_add(offset as u16)) as usize;
120 handle_input!(addr);
121
122 reg!(dst) = vm_state.mem[addr] as i16;
123 vm_state.update_condition(dst as usize);
124 zero_if_eq!(addr, KBDR, KBSR);
125 }
126 Instruction::LDI { dst, offset } => {
127 let addr =
128 vm_state.mem[(vm_state.pc.wrapping_add(offset as u16)) as usize] as usize;
129 handle_input!(addr);
130
131 reg!(dst) = vm_state.mem[addr] as i16;
132 vm_state.update_condition(dst as usize);
133 zero_if_eq!(addr, KBDR, KBSR);
134 }
135 Instruction::LDR { dst, base, offset } => {
136 let addr = (reg!(base) as u16).wrapping_add(offset as u16) as usize;
137 handle_input!(addr);
138
139 reg!(dst) = vm_state.mem[addr] as i16;
140 vm_state.update_condition(dst as usize);
141 zero_if_eq!(addr, KBDR, KBSR);
142 }
143 Instruction::LEA { dst, offset } => {
144 reg!(dst) = (vm_state.pc as i16).wrapping_add(offset);
145 vm_state.update_condition(dst as usize);
146 }
147 Instruction::NOT { dst, src } => {
148 reg!(dst) = !reg!(src);
149 vm_state.update_condition(dst as usize);
150 }
151 Instruction::RTI => {
152 context.1.write_fmt(format_args!(
153 "*** lc3-rs notification ***
154lc3-rs does not support interrupts, but RTI instruction is being executed from address x{:04X}.
155Please check your program if this is not intended.
156*** End lc3-rs notification ***",
157 vm_state.pc - 1
158 ))?;
159 }
160 Instruction::ST { src, offset } => {
161 let addr = (vm_state.pc.wrapping_add(offset as u16)) as usize;
162 vm_state.mem[addr] = reg!(src) as u16;
163 zero_if_eq!(addr, DDR, DSR);
164
165 handle_output!(addr);
166 }
167 Instruction::STI { src, offset } => {
168 let addr =
169 vm_state.mem[(vm_state.pc.wrapping_add(offset as u16)) as usize] as usize;
170 vm_state.mem[addr] = reg!(src) as u16;
171 zero_if_eq!(addr, DDR, DSR);
172
173 handle_output!(addr);
174 }
175 Instruction::STR { src, base, offset } => {
176 let addr = (reg!(base) as u16).wrapping_add(offset as u16) as usize;
177 vm_state.mem[addr] = reg!(src) as u16;
178 zero_if_eq!(addr, DDR, DSR);
179
180 handle_output!(addr);
181 }
182 Instruction::RESERVED => {
183 context.1.write_fmt(format_args!(
184 "*** lc3-rs notification ***
185A RESERVED instruction(0b1101) is being executed from address x{:04X}.
186Please check your program if this is not intended.
187*** End lc3-rs notification ***",
188 vm_state.pc - 1
189 ))?;
190 }
191 Instruction::TRAP { vect } => {
192 reg!(7) = vm_state.pc as i16;
193 vm_state.pc = vm_state.mem[(vect as u16) as usize];
194 }
195 }
196 Ok(())
197 }
198}