y86_lib/
executer.rs

1mod commands;
2mod instructions;
3mod print;
4use std::error::Error;
5use std::fs::File;
6use std::io::prelude::*;
7use std::io::stdin;
8
9use instructions::Instruction;
10use print::*;
11
12/// A state representing the Y86 program
13/// registers: a vector representing the registers
14/// condition_code: u8 representing the current set condition codes
15/// program_map: a vector holding the byte contents of the program
16/// program_size: u64, the size of the program memory
17/// program_counter: the program counter at all times, pointing to an address
18/// in memory
19pub struct State {
20    registers: Vec<u64>,
21    program_map: Vec<u8>,
22    condition_code: u8,
23    program_size: u64,
24    program_counter: u64,
25}
26
27impl State {
28    /// Creates a new state of the program from a machine code file
29    /// file_name: string representing the file name of a Y86 Machine code
30    /// file
31    pub fn new(file_name: String) -> Result<Self, Box<dyn Error>> {
32        let mut file = File::open(file_name)?;
33        let program_size = file.metadata()?.len();
34        let program_counter = 0;
35        let mut program_map = Vec::new();
36        file.read_to_end(&mut program_map)?;
37        Ok(State {
38            registers: vec![0; 16],
39            program_map,
40            program_size,
41            condition_code: 0,
42            program_counter,
43        })
44    }
45
46    /// Retrieve the value of a register
47    /// register_id: u8 representing the id of the register
48    pub fn get_register(&self, register_id: u8) -> u64 {
49        self.registers[register_id as usize]
50    }
51
52    /// sets the value of a register
53    /// register_id: u8 representing the id of the register
54    /// value: u64 representing the new value to put in the register
55    pub fn set_register(&mut self, register_id: u8, value: u64) {
56        self.registers[register_id as usize] = value;
57    }
58
59    /// Gets the current set condition codes
60    pub fn get_condition_code(&self) -> u8 {
61        self.condition_code
62    }
63
64    /// Sets the condition codes
65    /// value: u8 representing the new value
66    pub fn set_condition_code(&mut self, value: u8) {
67        self.condition_code = value;
68    }
69
70    /// Gets the program size
71    pub fn get_program_size(&self) -> u64 {
72        self.program_size
73    }
74
75    /// Reads a memory address in little-endian
76    /// address: u64 representing the address
77    /// Returns a Result, fails if memory is out of bounds
78    pub fn read_le(&self, address: u64) -> Result<u64, Box<dyn Error>> {
79        let mut res: u64 = 0;
80        for i in 0..8 {
81            res = (res << 8) | self.program_map[(address + 7 - i) as usize] as u64;
82        }
83        Ok(res)
84    }
85
86    /// Writes to memory address in little-endian
87    /// address: u64 representing the address
88    /// value: u64 representing the value to insert into memory
89    /// Returns a result, fails if memory is out of bounds
90    pub fn write_le(&mut self, address: u64, value: u64) -> Result<(), Box<dyn Error>> {
91        for i in 0..8 {
92            let val = ((value >> 8 * i) & 0xFF) as u8;
93            self.program_map[(address + i) as usize] = val;
94        }
95        Ok(())
96    }
97
98    /// Sets the value of the program counter
99    /// new_pc: u64 representing the new pc to set
100    pub fn set_pc(&mut self, new_pc: u64) {
101        self.program_counter = new_pc;
102    }
103
104    /// Gets the current PC
105    pub fn get_pc(&self) -> u64 {
106        self.program_counter
107    }
108
109
110    /// Reads a single byte in memory
111    /// address: u64 representing the address to the value to read
112    pub fn read_byte(&self, address: u64) -> u8 {
113        self.program_map[address as usize]
114    }
115}
116
117
118/// Generic function to debug a Y86 program
119/// file_name: String representing the name of a Y86 Machine code file
120pub fn debug(file_name: String) -> Result<(), Box<dyn Error>> {
121    let mut state = State::new(file_name.clone())?;
122    while state.read_byte(state.get_pc()) == 0 {
123        state.set_pc(state.get_pc() + 1);
124    }
125    println!(
126        "## Opened {:}, starting PC 0x{:x}",
127        file_name,
128        state.get_pc()
129    );
130
131    loop {
132        let mut instruction = Instruction::new(&state)?;
133        print_instruction(&instruction);
134        print!(">    ");
135        std::io::stdout().flush()?;
136        let mut buffer = String::new();
137        match stdin().read_line(&mut buffer) {
138            Ok(_) => (),
139            Err(_) => {
140                eprintln!("Could not parse input, please try again");
141                continue;
142            }
143        }
144        buffer = buffer.trim().to_string();
145        if buffer.starts_with("quit") {
146            break;
147        }
148        match commands::run(buffer, &mut instruction, &mut state) {
149            Ok(_) => (),
150            Err(e) => {
151                eprintln!("{:}", e);
152            }
153        }
154    }
155    Ok(())
156}