-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmod.rs
More file actions
180 lines (150 loc) · 4.6 KB
/
mod.rs
File metadata and controls
180 lines (150 loc) · 4.6 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use crate::comparison::Comparison;
use crate::state::{State};
use crate::text::Serializable;
/// Wrapper for a program (as a list of instructions)
pub struct InstructionVec {
pub instructions: Vec<Box<dyn Instruction>>
}
/// Trait that defines an executable instruction
pub trait Instruction: StringRepr {
fn exec(&self, state: &mut State);
}
/// Forces (most) instructions to have a defined string representation
// TODO: Implement this for the two special cases below
pub trait StringRepr {
fn command_name(&self) -> String;
fn to_string(&self) -> String;
}
/// Serialization functions for Instructions
impl <T> Serializable for T where T: Instruction {
fn to_string(&self) -> String {
self.to_string()
}
fn dump(&self) {
println!("{}", self.to_string())
}
}
/// Serialization functions for Instruction Vector Wrappers
impl Serializable for InstructionVec {
fn to_string(&self) -> String {
let mut res = String::new();
for inst in self.instructions.iter() {
res.push_str(inst.to_string().as_str());
res.push('\n');
}
res
}
fn dump(&self) {
for inst in self.instructions.iter() {
println!("{}", inst.to_string().as_str());
}
}
}
/// Automatically generates single operand instructions
macro_rules! make_single_operand_instruction {
( $( $name:ident, $argtype:ident ), * ) => {
$(
#[derive(Debug, Clone, Copy)]
pub struct $name {
operand: $argtype,
}
impl $name {
pub fn operand(&self) -> usize {
self.operand as usize
}
pub fn new(op: $argtype) -> $name {
$name {
operand: op
}
}
}
impl StringRepr for $name {
fn command_name(&self) -> String {
stringify!($name).to_string().to_uppercase()
}
fn to_string(&self) -> String {
format!("{} {}", self.command_name(), self.operand())
}
}
)*
};
}
// Modules hold the concrete implementation of the instructions
// i.e. fn exec(...)
pub mod load;
pub mod store;
pub mod add;
pub mod sub;
pub mod mult;
pub mod div;
pub mod jmp;
pub mod end;
make_single_operand_instruction![
/*
* Non-prefixed operations use the value of the register specified in the operand
* C-prefixed operations load/add/subtract/... a hard-coded constant to/from the accumulator
* IND-prefixed operations use the value of a referenced register (register -> register -> value)
*/
/* Load values on to the accumulator (r0) */
Load, usize,
CLoad, u128,
IndLoad, usize,
/* Store the value that the accumulator currently holds */
Store, usize,
IndStore, usize,
/* ADD Functions */
Add, usize,
CAdd, u128,
IndAdd, usize,
/* SUB Functions */
Sub, usize,
CSub, u128,
IndSub, usize,
/* MULT Functions */
Mult, usize,
CMult, u128,
IndMult, usize,
/* DIV Functions */
Div, usize,
CDiv, u128,
IndDiv, usize,
/* JMP Instruction */
Jmp, usize
];
/* END instruction */
// This is the only instruction with no arguments: no point in defining a macro for it
pub struct End {}
/* Conditional Jump Instrunction */
// IF r0?value THEN GOTO jmp_address
pub struct CondJmp {
comparison: Comparison,
value: u128,
jmp_address: usize,
}
impl InstructionVec {
/// Executes the instruction at `index` on the machine defined by `state`
pub fn exec_instruction(&self, index: usize, state: &mut State) {
self.instructions.get(index).unwrap().exec(state)
}
/// Pushes `instruction` on to the `InstructionVec`
pub fn push_instruction<T>(&mut self, instruction: T) where T: Instruction + 'static {
self.instructions.push(Box::new(instruction));
}
/// Returned the boxed instruction at `index`
pub fn get_boxed_instruction(&self, index: usize) -> &Box<dyn Instruction> {
self.instructions.get(index).unwrap()
}
/// Empty InstructionVec constructor
pub fn new() -> InstructionVec {
InstructionVec { instructions: Vec::new() }
}
}
/// Pushes a list of instructions onto an InstructionVec
#[macro_export]
macro_rules! ivec_push_multiple {
( $vec:ident, $($act:expr), * ) => {
$(
$vec.push_instruction($act);
)*
};
}