1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
use std::io::{Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use types::*;
use instructions::*;

/// Represents the outcome of a program run;
/// a halt (graceful termination) or a 
/// fault (hardware error), or a state of continuation,
/// in which the computer can keep running.

#[derive(PartialEq, Debug, Clone)]
pub enum Outcome {
    /// The program halted successfully.
    Halt,
    /// The program caused a problem and broke the machine.
    Fault(String),
    /// The program can continue running.
    Continue
}

/// Represents the state of a machine, including its registers, its memory,
/// its I/O Read and Write, and its program. 
/// 
/// The associated lifetime `'mach`
/// represents the life of the machine; its I/O connections must live at 
/// least that long.
pub struct Machine<'mach> {
    /// The amount of memory the machine can use, at maximum.
    max_words: usize,
    /// The eight general purpouse registers, used for program operation.
    registers: [Word; 8],
    /// The stack pointer
    sp: Word,
    /// The base pointer
    bp: Word,
    /// The instruction pointer. Note that this is a pointer into the program vector, not
    /// the machine's data memory! It indexes a vector and does NOT advance by bytes or words.
    ip: usize,
    /// Memory used by the machine
    memory: Vec<Word>,
    /// Program code for the machine
    program: Program,
    /// A reader to get input for the machine
    input: &'mach mut Read,
    /// A writer into which to put output from the machine
    output: &'mach mut Write
}

impl <'mach> Machine <'mach> {
    /// Create a new Machine connected to the given I/O ports.
    pub fn new(max_words: usize, input: &'mach mut Read, output: &'mach mut Write) -> Self {
        Self {
            max_words: max_words,
            registers: [0; 8],
            // Both SP and BP start at the top of memory; the stack grows downwards.
            sp: (max_words - 1) as u64,
            bp: (max_words - 1) as u64,
            ip: 0,
            memory: Vec::with_capacity(max_words),
            program: vec![Instruction::Illegal],
            input: input,
            output: output,
        }
    }

    /// Load a program into the machine
    /// This resets the instruction pointer.
    pub fn load_program(&mut self, new: Vec<Instruction>) {
        self.program = new;
        self.ip = 0;
    }

    /// Borrow out the machine's internal memory for examination.
    /// When it's borrowed out, the machine can't run.
    pub fn get_memory(&self) -> &[Word] { &self.memory }

    /// Replace the machine's memory with the given vector.
    pub fn load_memory(&mut self, new: Vec<Word>) { self.memory = new; }

    /// Advance to the next instruction (i.e., increment IP). This can cause a Fault, if IP ends up off the end.
    pub fn next_instr(&mut self) -> Outcome {
        self.ip += 1;
        if self.ip >= self.program.len() {
            Outcome::Fault(format!("IP beyond program length. IP = {}, length = {}", self.ip, self.program.len()))
        } else {
            Outcome::Continue
        }
    }
    
    /// Write the given word value to the given address.
    /// If it's a Literal, this will emit a Fault;
    /// otherwise it's a Continue.
    pub fn write_addr(&mut self, a: Address, v: Word) -> Outcome {
        use self::Address::*;
        match a {
            Literal(l) => { Outcome::Fault(
                    format!("Tried to write {} to literal {}.", v, l)) },
            RegAbs(r) => { self.write_register(r, v); Outcome::Continue  },
            MemAbs(l) => { self.write_memory(l, v) },
            MemReg(r) => {
                let location = self.read_register(r); 
                self.write_memory(location, v) 
            }
        }
    }

    /// Read a word from the given address.
    pub fn read_addr(&self, a: Address) -> Word {
        use self::Address::*;
        match a {
            Literal(v) => { v },
            RegAbs(r) => { self.read_register(r) },
            MemAbs(l) => { self.read_memory(l) },
            MemReg(r) => { self.read_memory(self.read_register(r)) }
        }
    }

    /// Read a value from a register
    fn read_register(&self, r: Register) -> Word {
        match r {
            Register::R0 => {self.registers[0]},
            Register::R1 => {self.registers[1]},
            Register::R2 => {self.registers[2]},
            Register::R3 => {self.registers[3]},
            Register::R4 => {self.registers[4]},
            Register::R5 => {self.registers[5]},
            Register::R6 => {self.registers[6]},
            Register::R7 => {self.registers[7]},
            Register::SP => {self.sp},
            Register::BP => {self.bp},
        }
    }

    /// Write a value into a register
    fn write_register(&mut self, r: Register, v: Word) {
        match r {
            Register::R0 => {self.registers[0] = v;},
            Register::R1 => {self.registers[1] = v;},
            Register::R2 => {self.registers[2] = v;},
            Register::R3 => {self.registers[3] = v;},
            Register::R4 => {self.registers[4] = v;},
            Register::R5 => {self.registers[5] = v;},
            Register::R6 => {self.registers[6] = v;},
            Register::R7 => {self.registers[7] = v;},
            Register::SP => {self.sp = v;},
            Register::BP => {self.bp = v;},
        }
    }

    /// Write the provided value (v) into the provided memory address.
    /// If this is off the end of the provided memory, fault.
    fn write_memory(&mut self, l: Word, v: Word) -> Outcome {
        let l = l as usize;
        // Memory must be at least the right length
        if l > self.max_words { return Outcome::Fault(
                format!("Tried to write out of available memory: {}", l)); }
        // OK, within the provided memory. Resize if needed.
        if l > self.memory.len() { self.memory.resize(l+1 as usize, 0); }
        self.memory[l] = v;
        Outcome::Continue
    }
    
    /// Read a Word from the provided memory address.
    /// If this address is outsize of the provided memory, this returns 0.
    fn read_memory(&self, l: Word) -> Word {
        let l = l as usize;
        // If it falls outside memory, just give back the default
        if l > self.max_words { 0 }
        else if l > self.memory.len() { 0 }
        else { self.memory[l] }
    }

    fn absolute_jump(&mut self, l: JumpLocation) -> Outcome {
        if l < self.program.len() {
            self.ip = l;
            Outcome::Continue 
            }
        else { 
        Outcome::Fault(
            format!("Attempt to jump to {} would overrun program of length {}.", l, self.program.len())) 
        }
    }

    pub fn execute_next(&mut self) -> Outcome {
        use Instruction::*;
        // This index operation is safe because next_instr faults if IP goes over the 
        // end of the vector
        match self.program[self.ip] {
            NoOp => { self.ins_no_op() },   
            Zero(a) => { self.ins_zero(a) },         
            Move(a, b) => { self.ins_move(a, b) },
            Output(a) => { self.ins_output(a) },
            Input(a) => { self.ins_input(a) },
            Add(a, b) => { self.ins_generic_scalar(a, b, |va, vb| va.wrapping_add(vb)) },
            Sub(a, b) => { self.ins_generic_scalar(a, b, |va, vb| va.wrapping_sub(vb)) },
            Jump(a) => { self.ins_jump(a) },
            JumpIfZero(a, b) => { self.ins_generic_jump_single(a, b, |v| v == 0) },
            JumpNotZero(a, b) => { self.ins_generic_jump_single(a, b, |v| v != 0) },
            Push(a) => { self.ins_push(a) },
            Pop(a) => { self.ins_pop(a) },
            Halt => { self.ins_halt() },
            Illegal => { Outcome::Fault("Illegal instruction encountered.".into()) },
        }
    }

    /// Execute instructions until a Halt or Fault occurs.
    /// _BEWARE: This may run forever!_
    pub fn run(&mut self) -> Outcome {
        loop {
            match self.execute_next() {
                Outcome::Continue => { },
                other => { return other; }
            }
        }
    }

    /// Execute at most the given number of instructions, also stopping on a Halt or Fault condition.
    /// Returns the Outcome of the last instruction and the number of instructions executed.
    pub fn run_for(&mut self, cycles: u64) -> (Outcome, u64) {
        let mut instructions_remaining = cycles;
        while instructions_remaining > 0 {
            match self.execute_next() {
                Outcome::Continue => { instructions_remaining -= 1; },
                other => { return (other, cycles - instructions_remaining); }
            }
        }
        (Outcome::Continue, cycles - instructions_remaining)
    }

    /// Execute a NoOp instruction
    fn ins_no_op(&mut self) -> Outcome {
        self.next_instr()
    }

    /// Execute a Halt instruction
    fn ins_halt(&mut self) -> Outcome { Outcome::Halt }
    
    /// Execute a Move instruction
    fn ins_move(&mut self, a: Address, b: Address) -> Outcome {
        let v = self.read_addr(a);
        match self.write_addr(b, v) {
            Outcome::Continue => { self.next_instr() },
            o => o
       }
    }
    
    /// Execute a Zero instruction
    fn ins_zero(&mut self, a: Address) -> Outcome {
        match self.write_addr(a, 0) {
            Outcome::Continue => { self.next_instr() },
            o => o
       }
    }
    
    /// Execute an Output instruction
    fn ins_output(&mut self, a: Address) -> Outcome {
        let v = self.read_addr(a);
        match self.output.write_u64::<BigEndian>(v) {
            Ok(_) => { self.next_instr() }
            Err(e) => { Outcome::Fault(format!("Failed to write on output instruction: {}.", e)) }
        }
    }

    /// Execute an Input instruction
    fn ins_input(&mut self, a: Address) -> Outcome {
        match self.input.read_u64::<BigEndian>() {
            Ok(v) => {
                match self.write_addr(a, v) {
                    Outcome::Continue => { self.next_instr() },
                    o => o
                }
            },
            Err(e) => { 
            Outcome::Fault(format!("Failed to read on input instruction: {}.", e))
            }
        }
    }

    /// Execute any 2-register scalar instruction
    fn ins_generic_scalar<F: FnOnce(Word, Word) -> Word>(&mut self, a: Address, b: Address, f: F) -> Outcome {
        let value_a = self.read_addr(a);
        let value_b = self.read_addr(b);
        match self.write_addr(a, f(value_a, value_b)) {
            Outcome::Continue => { self.next_instr() },
            other => other
        }
    }

    /// Execute an unconditional jump
    fn ins_jump(&mut self, a: Address) -> Outcome {
        let addr = self.read_addr(a) as JumpLocation;
        self.absolute_jump(addr)
    }

    /// Execute any one-operand jump
    fn ins_generic_jump_single<F: FnOnce(Word) -> bool>(&mut self, a: Address, b: Address, f: F) -> Outcome {
        let value_a = self.read_addr(a) as JumpLocation;
        let value_b = self.read_addr(b);
        if f(value_b) {
            self.absolute_jump(value_a)
        } else {
            self.next_instr()
        }
    }

    /// Execute a push instruction. Causes a fault if the stack has overrun the available
    /// memory.
    fn ins_push(&mut self, a: Address) -> Outcome {
        let val = self.read_addr(a);
        // Scope for mutable borrow
        self.sp -= 1;
        if self.sp <= 0 { Outcome::Fault("Stack has overrun available memory!".into()) }
        else {
            // Copy out of immutable ref to self to satisfy borrow checker
            let location = self.sp; 
            self.write_memory(location, val);
            self.next_instr()
         }
    }

    /// Execute a pop instruction. If the stack is empty, this does not fault, but sets the target to
    /// zero.
    fn ins_pop(&mut self, a: Address) -> Outcome {
        let val = if self.sp >= self.bp {
            self.sp = self.bp;
            0 
        } else {
            self.read_memory(self.sp)
        };
        self.sp += 1;

        match self.write_addr(a, val) {
            Outcome::Continue => { self.next_instr() },
            other => other
        }
    }
}