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
|
use core::panic;
use crate::interpreter::{MemAddress, StackAddress};
use crate::opcodes::OpCode;
#[derive(Debug)]
pub struct Instruction {
pub opcode: OpCode,
pub in_operands: Vec<Operand>,
pub out_operands: Vec<Operand>,
}
enum Nybble {
High,
Low,
}
#[derive(PartialEq, Debug, Clone)]
pub enum Operand {
Constant(i32),
PopStack,
FrameIndirect(StackAddress),
MemIndirect(MemAddress),
MemRamIndirect(MemAddress),
}
impl Instruction {
pub fn read<'a, I>(bytes: &mut I) -> Result<(Instruction, u32), u32>
where
I: IntoIterator<Item = &'a u8> + Copy
{
let mut bytes = bytes.into_iter().enumerate().peekable();
let instruction_length = {
let first_byte = *bytes.peek().unwrap().1;
match first_byte >> 6 {
0b00 | 0b01 => 1,
0b10 => 2,
0b11 => 4,
_ => unreachable!()
}
};
let mask = match instruction_length {
1 => 0,
2 => 0x8000,
4 => 0xC0000000,
_ => panic!("Invalid opcode byte array"),
};
let instruction_bytes = (0..4-instruction_length).into_iter().map(|_n| 0).chain(
(0..instruction_length).into_iter().map(|_n| *bytes.next().unwrap().1)
).collect::<Vec<_>>();
let opcode_num = u32::from_be_bytes(instruction_bytes.clone().try_into().unwrap()) & !mask;
println!("instruction length: {instruction_length}, number: 0x{opcode_num:x}, bytes: {instruction_bytes:?}");
let opcode = OpCode::get_from_code(opcode_num);
if let None = opcode {
return Err(opcode_num);
}
let opcode = opcode.unwrap();
let input_operand_count = OpCode::get_input_arg_count(opcode.clone());
let output_operand_count = OpCode::get_output_arg_count(opcode.clone());
let operand_count = input_operand_count + output_operand_count;
let operand_bytes = (operand_count + 1) / 2;
let skip_last_half = operand_bytes != operand_count / 2;
let operand_bytes = (0..operand_bytes).into_iter().map(|_n| *bytes.next().unwrap().1);
let halfbytes : Vec<_> = operand_bytes.flat_map(|byte| vec![(byte, Nybble::Low), (byte, Nybble::High)]).collect();
// Just ensure other borrows to the byte array have closed by rebinding it
// This verifies we're at the operand data position
let mut data_bytes = bytes;
let mut operands : Vec<Operand> = halfbytes.iter().map(|(byte, nybble)| {
let value = match nybble {
Nybble::High => byte >> 4,
Nybble::Low => byte & 0x0f,
};
match value {
0 => Operand::Constant(0),
1 => Operand::Constant(i8::from_be_bytes([*data_bytes.next().unwrap().1]) as i32),
2 => Operand::Constant(i16::from_be_bytes([*data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1]) as i32),
3 => Operand::Constant(i32::from_be_bytes([*data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
4 => panic!("Invalid operand addressing mode: {value:x}"),
5 => Operand::MemIndirect(u32::from_be_bytes([0, 0, 0, *data_bytes.next().unwrap().1])),
6 => Operand::MemIndirect(u32::from_be_bytes([0, 0, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
7 => Operand::MemIndirect(u32::from_be_bytes([*data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
8 => Operand::PopStack,
9 => Operand::FrameIndirect(u32::from_be_bytes([0, 0, 0, *data_bytes.next().unwrap().1])),
0xa => Operand::FrameIndirect(u32::from_be_bytes([0, 0, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
0xb => Operand::FrameIndirect(u32::from_be_bytes([*data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
0xc => panic!("Invalid operand addressing mode: {value:x}"),
0xd => Operand::MemRamIndirect(u32::from_be_bytes([0, 0, 0, *data_bytes.next().unwrap().1])),
0xe => Operand::MemRamIndirect(u32::from_be_bytes([0, 0, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
0xf => Operand::MemRamIndirect(u32::from_be_bytes([*data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1, *data_bytes.next().unwrap().1])),
_ => unreachable!()
}
}).collect();
// Should only trim it off if it was all 0
if skip_last_half && operands.len() > 0 {
assert!(*operands.last().unwrap() == Operand::Constant(0));
operands.remove(operands.len() - 1);
}
let in_operands = operands[0..input_operand_count].try_into().unwrap();
let out_operands = operands[input_operand_count..].try_into().unwrap();
// Return instruction along with the number of bytes we've read
Ok((Instruction {
opcode,
in_operands,
out_operands,
}, data_bytes.peek().unwrap().0 as u32))
}
}
|