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
use std::fmt;
use crate::bytecode::instruction::Instruction;
use crate::bytecode::opcode::{
SuperCode,
misc::{self, move_subcode::DecodedMove},
index::{self, DecodedIndex},
comparison::{self, DecodedComparison},
arithmetic::{self, DecodedArithmetic},
};
use crate::bytecode::operand::{
FromDestination, FromSource,
RawRegister, Global,
WildDestination,
InstructionPointer, FunctionKey
};
pub fn disassemble_instruction(f: &mut fmt::Formatter, instruction: Instruction) -> fmt::Result {
match SuperCode::from(instruction) {
SuperCode::Misc => {
let subcode = misc::Subcode::from(instruction);
match subcode {
misc::Subcode::Jump => {
use misc::jump_subcode::Reason;
match Reason::from(instruction) {
Reason::Special => {
use misc::jump_subcode::Special;
match Special::from(instruction) {
Special::NoOp => write!(f, "nop"),
Special::Return => write!(f, "ret"),
_ => unimplemented!(),
}
}
Reason::Always => {
let instruction_pointer = InstructionPointer::from_both_operands(instruction);
write!(f, "jmp {instruction_pointer:<8}")
}
Reason::IfFalse => {
use misc::jump_subcode::ConditionType;
let instruction_pointer = InstructionPointer::from_both_operands(instruction);
let condition_type = ConditionType::from(instruction);
let condition: WildDestination<RawRegister> = match condition_type {
ConditionType::Register => RawRegister::from_destination(instruction).into(),
ConditionType::Global => Global::from_destination(instruction).into(),
};
write!(f, "jmp {instruction_pointer:<8} if !{condition}")
}
Reason::IfTrue => {
use misc::jump_subcode::ConditionType;
let instruction_pointer = InstructionPointer::from_both_operands(instruction);
let condition_type = ConditionType::from(instruction);
let condition: WildDestination<RawRegister> = match condition_type {
ConditionType::Register => RawRegister::from_destination(instruction).into(),
ConditionType::Global => Global::from_destination(instruction).into(),
};
write!(f, "jmp {instruction_pointer:<8} if {condition}")
}
}
}
misc::Subcode::Move => {
let DecodedMove { destination, source } = misc::move_subcode::decode(instruction);
write!(f, "mov {destination} = {source}")
}
misc::Subcode::Call => {
use misc::call_subcode::ArgCount;
let arg_count = ArgCount::from(instruction);
let arg_start = RawRegister::from_second(instruction);
let dest = RawRegister::from_destination(instruction);
let function = FunctionKey::from_first(instruction);
match arg_count {
ArgCount(0) => write!(f, "call {dest} = {function}()"),
ArgCount(1) => write!(f, "call {dest} = {function}({arg_start})"),
ArgCount(count) => {
let last = RawRegister(arg_start.0 + count - 1);
write!(f, "call {dest} = {function}({arg_start}...{last})")
}
}
}
misc::Subcode::Interrupt => unimplemented!(),
}
}
SuperCode::Index => {
let DecodedIndex { index_on, destination, source, index } = index::decode(instruction);
match index_on {
index::On::Destination => write!(f, "idx {destination}[{index}] = {source}"),
index::On::Source => write!(f, "idx {destination} = {source}[{index}]"),
}
}
SuperCode::Comparison => {
use comparison::Sources;
let DecodedComparison { subcode, destination, sources } = comparison::decode(instruction);
let subcode_op_str = subcode.op_str();
match sources {
Sources::FirstIsWild(first, second) =>
write!(f, "{subcode:<4} {destination} = {first} {subcode_op_str} {second}"),
Sources::SecondIsWild(first, second) =>
write!(f, "{subcode:<4} {destination} = {first} {subcode_op_str} {second}"),
}
}
SuperCode::Arithmetic => {
use arithmetic::Sources;
let DecodedArithmetic { subcode, destination, sources } = arithmetic::decode(instruction);
let subcode_op_str = subcode.op_str();
match sources {
Sources::FirstIsWild(first, second) =>
write!(f, "{subcode:<4} {destination} = {first} {subcode_op_str} {second}"),
Sources::SecondIsWild(first, second) =>
write!(f, "{subcode:<4} {destination} = {first} {subcode_op_str} {second}"),
}
}
}
}