monistode_emulator/
stack_processor.rs

1use monistode_binutils::{Architecture, Executable};
2
3use crate::tightly_packed_array;
4
5use super::{
6    arithmetic,
7    common::{Processor, ProcessorContinue},
8    flag_register::{implement_flag_register, FlagRegister, ProcessorFlags},
9    memory::Memory,
10    memory::{two_byte_memory, TwoByteMemory},
11    stack::{two_byte_stack, Stack, TwoByteStack},
12    system,
13};
14use num_derive::FromPrimitive;
15use num_traits::FromPrimitive;
16use std::{fs::File, io::Read};
17use ux::u6;
18
19#[derive(Debug, FromPrimitive)]
20enum Opcode {
21    Halt = 0b000000,
22    Load = 0b000001,
23    LoadFr = 0b000010,
24    LoadMem = 0b100000,
25    Store = 0b000100,
26    StoreImm = 0b100001,
27    StoreFr = 0b000101,
28    Swap = 0b000110,
29    Dup = 0b000111,
30    Dup2 = 0b001000,
31    Mov = 0b100010,
32    Push = 0b001001,
33    PushFr = 0b001010,
34    Pop = 0b001100,
35    PopFr = 0b001101,
36    Add = 0b001110,
37    Sub = 0b001111,
38    Mul = 0b010000,
39    Div = 0b10001,
40    And = 0b010010,
41    Or = 0b010011,
42    Xor = 0b010100,
43    Not = 0b010101,
44    LshImm = 0b100011,
45    RshImm = 0b100100,
46    CallImm = 0b100101,
47    Call = 0b010110,
48    Ret = 0b010111,
49    Cmpe = 0b011000,
50    CmpeImm = 0b100110,
51    Cmpb = 0b011001,
52    CmpbImm = 0b100111,
53    Jmp = 0b011010,
54    JmpImm = 0b101000,
55    Jc = 0b011011,
56    JcImm = 0b101001,
57    In = 0b101010,
58    Out = 0b101011,
59    Nop = 0b011100,
60}
61
62macro_rules! to_bool {
63    ($value:expr) => {{
64        if $value {
65            0b1111111111111111
66        } else {
67            0b0000000000000000
68        }
69    }};
70}
71
72macro_rules! with_immediate {
73    ($processor:ident, $op:expr) => {{
74        let immediate = $processor.load_immediate();
75        $op(immediate);
76        ProcessorContinue::KeepRunning
77    }};
78}
79
80macro_rules! arithmetic {
81    ($processor:ident, $op:expr) => {{
82        let a = $processor.register_stack().pop();
83        let b = $processor.register_stack().pop();
84        let result = $op(&mut $processor.registers.fr, a, b);
85        $processor.register_stack().push(result);
86        ProcessorContinue::KeepRunning
87    }};
88}
89
90macro_rules! arithmetic_imm {
91    ($processor:ident, $op:expr) => {
92        with_immediate!($processor, |immediate| {
93            let stack_value = $processor.register_stack().pop();
94            let result = $op(&mut $processor.registers.fr, immediate, stack_value);
95            $processor.register_stack().push(result);
96            ProcessorContinue::KeepRunning
97        })
98    };
99}
100
101implement_flag_register!(StackProcessorFlagRegister(u16));
102
103pub struct StackProcessorRegisters {
104    pub pc: u16,
105    pub fr: StackProcessorFlagRegister,
106    pub tos: u16,
107    pub sp: u16,
108}
109
110pub struct StackProcessor {
111    pub text_memory: Memory<u6>,
112    pub data_memory: Memory<u8>,
113    pub registers: StackProcessorRegisters,
114}
115
116impl StackProcessor {
117    pub fn new() -> StackProcessor {
118        StackProcessor {
119            text_memory: Memory::new(u6::new(0), 65536),
120            data_memory: Memory::new(0, 65536),
121            registers: StackProcessorRegisters {
122                pc: 0,
123                fr: StackProcessorFlagRegister::new(),
124                tos: 256,
125                sp: 1024,
126            },
127        }
128    }
129
130    pub fn load_from_bytes(&mut self, bytes: &[u8]) {
131        self.text_memory
132            .load_binary(&bytes.iter().map(|x| u6::new(*x)).collect::<Vec<_>>());
133    }
134
135    pub fn load_text_binary_file(&mut self, binary: &str) {
136        let mut file = File::open(binary).expect("File not found");
137        let mut buffer = Vec::new();
138        file.read_to_end(&mut buffer).expect("Could not read file");
139        self.text_memory
140            .load_binary(&buffer.iter().map(|x| u6::new(*x)).collect::<Vec<_>>());
141    }
142
143    two_byte_stack!(register_stack[tos: u16] -> u8, based on data_memory, growing downward);
144    two_byte_stack!(memory_stack[sp: u16] -> u8, based on data_memory);
145    two_byte_memory!(two_byte_data_memory: data_memory[u16] -> 2 * u8);
146
147    #[inline]
148    fn load_immediate(&mut self) -> u16 {
149        let low = self.text_memory[(self.registers.pc.wrapping_add(2)) as usize];
150        let middle = self.text_memory[(self.registers.pc.wrapping_add(1)) as usize];
151        let high = self.text_memory[self.registers.pc as usize];
152        self.registers.pc = self.registers.pc.wrapping_add(3);
153        (u16::from(high)) << 12 | (u16::from(middle)) << 6 | u16::from(low)
154    }
155}
156
157impl Processor<u6, u16, u16, u16> for StackProcessor {
158    fn next(&mut self) -> u6 {
159        let instruction = self.text_memory[self.registers.pc as usize];
160        self.registers.pc = self.registers.pc.wrapping_add(1);
161        instruction
162    }
163    fn at_pc_plus(&self, offset: u16) -> u6 {
164        self.text_memory[self.registers.pc.wrapping_add(offset) as usize]
165    }
166    fn pc(&self) -> u16 {
167        self.registers.pc
168    }
169
170    fn peek_stack(&mut self, n: u8) -> u16 {
171        self.register_stack().peek_down_by(n * 2)
172    }
173
174    fn run_command<T, U>(&mut self, output: T, input: U) -> ProcessorContinue
175    where
176        T: Fn(u16, u16),
177        U: Fn(u16) -> u16,
178    {
179        let next_instruction = self.next();
180        let next_instruction_as_enum = match Opcode::from_u8(next_instruction.into()) {
181            Some(opcode) => opcode,
182            None => {
183                return ProcessorContinue::Error;
184            }
185        };
186
187        match next_instruction_as_enum {
188            Opcode::Halt => system::halt(),
189            Opcode::Load => {
190                let address = self.register_stack().pop();
191                let result = self.two_byte_data_memory().read(address);
192                self.register_stack().push(result);
193                ProcessorContinue::KeepRunning
194            }
195            Opcode::LoadFr => {
196                let result = self.registers.fr.0;
197                self.register_stack().push(result);
198                ProcessorContinue::KeepRunning
199            }
200            Opcode::LoadMem => with_immediate!(self, |address| {
201                let source = self.two_byte_data_memory().read(address);
202                self.register_stack().push(source);
203            }),
204            Opcode::Store => {
205                let source = self.register_stack().pop();
206                let address = self.register_stack().pop();
207                self.two_byte_data_memory().write(address, source);
208                ProcessorContinue::KeepRunning
209            }
210            Opcode::StoreFr => {
211                let source = self.registers.fr.0;
212                let address = self.register_stack().pop();
213                self.two_byte_data_memory().write(address, source);
214                ProcessorContinue::KeepRunning
215            }
216            Opcode::StoreImm => with_immediate!(self, |source| {
217                let address = self.register_stack().pop();
218                self.two_byte_data_memory().write(address, source);
219            }),
220            Opcode::Mov => with_immediate!(self, |immediate| self.register_stack().push(immediate)),
221            Opcode::Push => {
222                let source = self.register_stack().pop();
223                self.memory_stack().push(source);
224                ProcessorContinue::KeepRunning
225            }
226            Opcode::PushFr => {
227                let source = self.registers.fr.0;
228                self.memory_stack().push(source);
229                ProcessorContinue::KeepRunning
230            }
231            Opcode::Pop => {
232                let source = self.memory_stack().pop();
233                self.register_stack().push(source);
234                ProcessorContinue::KeepRunning
235            }
236            Opcode::PopFr => {
237                let source = self.memory_stack().pop();
238                self.registers.fr.0 = source;
239                ProcessorContinue::KeepRunning
240            }
241            Opcode::Dup => {
242                let source = self.register_stack().pop();
243                self.register_stack().push(source);
244                self.register_stack().push(source);
245                ProcessorContinue::KeepRunning
246            }
247            Opcode::Dup2 => {
248                let source1 = self.register_stack().pop();
249                let source2 = self.register_stack().pop();
250                self.register_stack().push(source2);
251                self.register_stack().push(source1);
252                self.register_stack().push(source2);
253                ProcessorContinue::KeepRunning
254            }
255            // The arithmetic operations push the result onto the register stack
256            Opcode::Add => arithmetic!(self, arithmetic::add),
257            Opcode::Sub => arithmetic!(self, arithmetic::sub),
258            Opcode::Mul => arithmetic!(self, arithmetic::mul),
259            Opcode::Div => arithmetic!(self, arithmetic::div),
260            Opcode::And => arithmetic!(self, arithmetic::and),
261            Opcode::Or => arithmetic!(self, arithmetic::or),
262            Opcode::Xor => arithmetic!(self, arithmetic::xor),
263            Opcode::Not => {
264                let source = self.register_stack().pop();
265                let result = arithmetic::not(&mut self.registers.fr, source);
266                self.register_stack().push(result);
267                ProcessorContinue::KeepRunning
268            }
269            Opcode::LshImm => arithmetic_imm!(self, |fr, a, b| arithmetic::shl(fr, b, a)),
270            Opcode::RshImm => arithmetic_imm!(self, |fr, a, b| arithmetic::shr(fr, b, a)),
271            Opcode::Swap => {
272                let source1 = self.register_stack().pop();
273                let source2 = self.register_stack().pop();
274                self.register_stack().push(source1);
275                self.register_stack().push(source2);
276                ProcessorContinue::KeepRunning
277            }
278            Opcode::Cmpe => arithmetic!(self, |_, a, b| to_bool!(a == b)),
279            Opcode::CmpeImm => arithmetic_imm!(self, |_, immediate, stack_value| to_bool!(
280                immediate == stack_value
281            )),
282            Opcode::Cmpb => arithmetic!(self, |_, a, b| to_bool!(a > b)),
283            Opcode::CmpbImm => arithmetic_imm!(self, |_, immediate, stack_value| to_bool!(
284                immediate > stack_value
285            )),
286            Opcode::Jmp => {
287                self.registers.pc = self.register_stack().pop().wrapping_add(self.registers.pc);
288                ProcessorContinue::KeepRunning
289            }
290            Opcode::JmpImm => with_immediate!(self, |target: u16| self.registers.pc =
291                target.wrapping_add(self.registers.pc)),
292            Opcode::Jc => {
293                if self.register_stack().pop() == 0b1111111111111111 {
294                    self.registers.pc = self.register_stack().pop().wrapping_add(self.registers.pc);
295                }
296                ProcessorContinue::KeepRunning
297            }
298            Opcode::JcImm => with_immediate!(self, |destination: u16| {
299                if self.register_stack().pop() == 0b1111111111111111 {
300                    self.registers.pc = destination.wrapping_add(self.registers.pc);
301                }
302                ProcessorContinue::KeepRunning
303            }),
304            Opcode::Call => {
305                let current_pc = self.registers.pc;
306                self.memory_stack().push(current_pc);
307                self.registers.pc = self.register_stack().pop().wrapping_add(self.registers.pc);
308                ProcessorContinue::KeepRunning
309            }
310            Opcode::CallImm => with_immediate!(self, |target: u16| {
311                let current_pc = self.registers.pc;
312                self.memory_stack().push(current_pc);
313                self.registers.pc = target.wrapping_add(self.registers.pc);
314            }),
315            Opcode::Ret => {
316                self.registers.pc = self.memory_stack().pop();
317                ProcessorContinue::KeepRunning
318            }
319            Opcode::Nop => ProcessorContinue::KeepRunning,
320            Opcode::Out => with_immediate!(self, |port| output(port, self.register_stack().pop())),
321            Opcode::In => with_immediate!(self, |port| {
322                self.register_stack().push(input(port));
323            }),
324        }
325    }
326
327    fn load_executable(&mut self, executable: &Executable) -> Result<(), String> {
328        // if !executable.header.harvard {
329        //     return Err("Executable is not harvard architecture".to_string());
330        // }
331        if !matches!(executable.architecture(), Architecture::Stack) {
332            return Err("Executable is not stack architecture".to_string());
333        }
334        for segment in executable.segments() {
335            if segment.flags.executable {
336                let array = tightly_packed_array::TightlyPackedArray::new(segment.data.clone(), 6);
337                // TODO why copy
338                for i in 0..segment.address_space_size {
339                    self.text_memory[(segment.address_space_start + i) as usize] =
340                        u6::new(array.at(i as usize));
341                }
342            } else if segment.flags.readable {
343                for i in 0..segment.address_space_size {
344                    self.data_memory[(segment.address_space_start + i) as usize] =
345                        segment.serialize().1[i as usize];
346                }
347            }
348        }
349        self.registers.pc = executable.entry_point() as u16;
350        Ok(())
351    }
352}