1use super::Node;
2use core::{Program, Port, Instruction, Source, Register};
3use core::Port::*;
4use core::Instruction::*;
5use core::Source::*;
6use core::Register::*;
7use core::IoRegister::*;
8use io::IoBusView;
9
10#[derive(Debug)]
12pub struct DamagedExecutionNode;
13
14impl Node for DamagedExecutionNode {}
15
16#[derive(Debug, PartialEq, Eq)]
18pub enum Mode {
19 Idle,
20 Run,
21 Read,
22 Wrte,
23}
24
25use self::Mode::*;
26
27#[derive(Debug)]
61pub struct BasicExecutionNode {
62 program: Program,
63 pc: isize,
64 mode: Mode,
65 acc: isize,
66 bak: isize,
67 last: Option<Port>,
68}
69
70impl BasicExecutionNode {
71 pub fn new() -> BasicExecutionNode {
73 BasicExecutionNode {
74 program: Program::new(),
75 pc: 0,
76 mode: Idle,
77 acc: 0,
78 bak: 0,
79 last: None,
80 }
81 }
82
83 pub fn with_program(program: Program) -> BasicExecutionNode {
85 let mut node = BasicExecutionNode::new();
86 node.set_program(program);
87 node
88 }
89
90 pub fn set_program(&mut self, program: Program) {
92 self.program = program;
93 }
94
95 pub fn get_mode(&self) -> &Mode {
96 &self.mode
97 }
98
99 fn inc_pc(&mut self) {
101 self.pc += 1;
102 if self.pc >= self.program.len() as isize {
103 self.pc = 0;
104 }
105 }
106
107 fn set_pc(&mut self, pc: isize) {
109 if pc < 0 {
110 self.pc = 0;
111 } else if pc as usize > self.program.len() {
112 self.pc = self.program.len() as isize - 1;
113 } else {
114 self.pc = pc;
115 }
116 }
117
118 fn fetch(&mut self) -> Option<Instruction> {
120 self.program.get(self.pc as usize).map(|&i| i)
121 }
122
123 fn eval(&mut self, instruction: Instruction, io: &mut IoBusView) {
125 match instruction {
126 Nop => (),
127 Mov(src, dst) => if let Some(val) = self.read(io, src) {
128 let value = clamp_value(val);
129 self.write(io, dst, value);
130 },
131 Swp => {
132 let tmp = self.bak;
133 self.bak = self.acc;
134 self.acc = tmp;
135 },
136 Sav => self.bak = self.acc,
137 Add(src) => if let Some(val) = self.read(io, src) {
138 self.acc += val;
139 },
140 Sub(src) => if let Some(val) = self.read(io, src) {
141 self.acc -= val;
142 },
143 Neg => self.acc = -self.acc,
144 Jmp(pc) => self.set_pc(pc),
145 Jez(pc) => if self.acc == 0 {
146 self.set_pc(pc);
147 },
148 Jnz(pc) => if self.acc != 0 {
149 self.set_pc(pc);
150 },
151 Jgz(pc) => if self.acc > 0 {
152 self.set_pc(pc);
153 },
154 Jlz(pc) => if self.acc < 0 {
155 self.set_pc(pc);
156 },
157 Jro(src) => if let Some(off) = self.read(io, src) {
158 let pc = self.pc + off;
159 self.set_pc(pc);
160 },
161 }
162 }
163
164 fn read(&mut self, io: &mut IoBusView, src: Source) -> Option<isize> {
166 let val = match src {
167 VAL(val) => Some(val),
168 REG(ACC) => Some(self.acc),
169 REG(NIL) => Some(0),
170 REG(IO(DIR(port))) => io.read(port),
171 REG(IO(ANY)) => io.read(LEFT)
172 .or_else(|| io.read(RIGHT))
173 .or_else(|| io.read(UP))
174 .or_else(|| io.read(DOWN)),
175 REG(IO(LAST)) => match self.last {
176 Some(port) => io.read(port),
177 None => Some(0),
178 },
179 };
180
181 val.or_else(|| {
182 self.mode = Read;
183 None
184 })
185 }
186
187 fn write(&mut self, io: &mut IoBusView, dst: Register, value: isize) {
189 match dst {
190 ACC => self.acc = value,
191 NIL => (),
192 IO(reg) => {
193 match reg {
194 DIR(port) => io.write(port, value),
195 ANY => {
196 io.write(UP, value);
197 io.write(DOWN, value);
198 io.write(LEFT, value);
199 io.write(RIGHT, value);
200 },
201 LAST => if let Some(port) = self.last {
202 io.write(port, value);
203 }
204 }
205 self.mode = Wrte;
206 }
207 }
208 }
209}
210
211impl Node for BasicExecutionNode {
212 fn step(&mut self, io: &mut IoBusView) {
214 if self.mode != Wrte {
215 if let Some(instruction) = self.fetch() {
216 self.mode = Run;
217 self.eval(instruction, io);
218 if self.mode == Run {
219 self.inc_pc();
220 }
221 }
222 }
223 }
224
225 fn sync(&mut self, io: &mut IoBusView) {
229 if self.mode == Wrte {
230 if !io.is_blocked() {
231 self.mode = Run;
232 self.inc_pc();
233 }
234 }
235 }
236
237 fn is_stalled(&self) -> bool {
239 self.mode != Run
240 }
241}
242
243
244fn clamp_value(value: isize) -> isize {
246 if value > 999 {
247 999
248 } else if value < -999 {
249 -999
250 } else {
251 value
252 }
253}
254
255#[test]
256fn test_clamp_value() {
257 assert_eq!(clamp_value(1000), 999);
258 assert_eq!(clamp_value(999), 999);
259 assert_eq!(clamp_value(998), 998);
260
261 assert_eq!(clamp_value(-1000), -999);
262 assert_eq!(clamp_value(-999), -999);
263 assert_eq!(clamp_value(-998), -998);
264}