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
use enum_primitive::FromPrimitive;
use faucon_asm::{opcode::OperandSize, MemoryAccess, MemorySpace, Operand};
use super::{Cpu, CpuFlag};
pub fn parse_memory_access(cpu: &Cpu, mem: Operand) -> Option<(MemorySpace, u32)> {
if let Operand::Memory(mem) = mem {
match mem {
MemoryAccess::Reg { space, base } => Some((space, cpu.registers[base])),
MemoryAccess::RegReg {
space,
base,
offset,
scale,
} => Some((
space,
cpu.registers[base] + cpu.registers[offset] * scale as u32,
)),
MemoryAccess::RegImm {
space,
base,
offset,
} => Some((space, cpu.registers[base] + offset)),
}
} else {
None
}
}
pub fn parse_flag(flag: Operand) -> Option<CpuFlag> {
if let Operand::Flag(imm) = flag {
Some(CpuFlag::from_u8(imm).unwrap())
} else {
None
}
}
pub fn get_value(cpu: &Cpu, size: OperandSize, source: Operand) -> u32 {
match source {
Operand::Register(reg) => match size {
OperandSize::EightBit => cpu.registers[reg] & 0xFF,
OperandSize::SixteenBit => cpu.registers[reg] & 0xFFFF,
OperandSize::ThirtyTwoBit | OperandSize::Unsized => cpu.registers[reg],
},
Operand::Immediate(imm) => imm as u32,
Operand::UnsignedImmediate(imm) => imm,
Operand::Memory(_) => read_mem(cpu, size, source),
_ => panic!("The operand doesn't represent an extractable value"),
}
}
pub fn write_reg(cpu: &mut Cpu, size: OperandSize, destination: Operand, source: Operand) {
let value = get_value(cpu, size, source);
match size {
OperandSize::EightBit => cpu.registers[destination] &= !0xFF | value,
OperandSize::SixteenBit => cpu.registers[destination] &= !0xFFFF | value,
OperandSize::ThirtyTwoBit | OperandSize::Unsized => {
cpu.registers[destination] &= !0xFFFFFFFF | value;
}
}
}
pub fn write_value_to_reg(cpu: &mut Cpu, size: OperandSize, destination: Operand, source: u32) {
match size {
OperandSize::EightBit => cpu.registers[destination] &= !0xFF | (source & 0xFF),
OperandSize::SixteenBit => cpu.registers[destination] &= !0xFFFF | (source & 0xFFFF),
OperandSize::ThirtyTwoBit | OperandSize::Unsized => {
cpu.registers[destination] &= !0xFFFFFFFF | source
}
}
}
pub fn read_mem(cpu: &Cpu, size: OperandSize, source: Operand) -> u32 {
let (space, address) = parse_memory_access(cpu, source).unwrap();
match space {
MemorySpace::Io => read_imem(cpu, address),
MemorySpace::DMem => read_dmem(cpu, size, address),
}
}
pub fn write_mem(cpu: &mut Cpu, size: OperandSize, source: Operand, destination: Operand) {
let (space, address) = parse_memory_access(cpu, destination).unwrap();
match space {
MemorySpace::Io => panic!("Unsupported IMem write access attempted"),
MemorySpace::DMem => write_dmem(cpu, size, address, get_value(cpu, size, source)),
};
}
fn read_imem(cpu: &Cpu, address: u32) -> u32 {
cpu.memory.read_code_addr(address as u16)
}
fn read_dmem(cpu: &Cpu, size: OperandSize, address: u32) -> u32 {
match size {
OperandSize::EightBit => cpu.memory.read_data_byte(address) as u32,
OperandSize::SixteenBit => cpu.memory.read_data_halfword(address) as u32,
OperandSize::ThirtyTwoBit | OperandSize::Unsized => cpu.memory.read_data_word(address),
}
}
fn write_dmem(cpu: &mut Cpu, size: OperandSize, address: u32, value: u32) {
match size {
OperandSize::EightBit => cpu.memory.write_data_byte(address, value as u8),
OperandSize::SixteenBit => cpu.memory.write_data_halfword(address, value as u16),
OperandSize::ThirtyTwoBit | OperandSize::Unsized => {
cpu.memory.write_data_word(address, value)
}
}
}