gdritter repos dlxvm / dd94c86
git-ified DLX simulator Getty Ritter 6 years ago
25 changed file(s) with 612 addition(s) and 0 deletion(s). Collapse all Expand all
1 from sys import stdin, argv
2
3 result = []
4 ARITH = {
5 'add': 0x20,
6 'and': 0x24,
7 'or': 0x25,
8 'seq': 0x28,
9 'sle': 0x2c,
10 'sll': 0x04,
11 'slt': 0x2a,
12 'sne': 0x29,
13 'sra': 0x07,
14 'srl': 0x06,
15 'sub': 0x22,
16 'xor': 0x26,
17 'nul': 0x00
18 }
19
20 OP = {
21 'addi': 0x08,
22 'andi': 0x0c,
23 'beqz': 0x04,
24 'bnez': 0x05,
25 'j': 0x02,
26 'jal': 0x03,
27 'jalr': 0x13,
28 'jr': 0x12,
29 'lhi': 0x0f,
30 'lw': 0x23,
31 'ori': 0x0d,
32 'seqi': 0x18,
33 'slei': 0x1c,
34 'slli': 0x14,
35 'slti': 0x1a,
36 'snei': 0x19,
37 'srai': 0x17,
38 'srli': 0x16,
39 'subi': 0x0a,
40 'sw': 0x2b,
41 'xori': 0x0e,
42 'halt': 0x30,
43 'pln': 0x31
44 }
45
46 BYTE = 0xff
47
48 for line in stdin.readlines():
49 op, *rest = line.split()
50 if op in ARITH:
51 opcode = 0
52 funct = ARITH[op]
53 type = 'R'
54 else:
55 opcode = OP[op]
56 if op in ('j', 'jal'):
57 type = 'J'
58 else:
59 type = 'I'
60
61 if type == 'R':
62 rs, rt, rd = map(int, rest)
63 result.append(opcode << 26 |
64 rs << 21 |
65 rt << 16 |
66 rd << 11 |
67 funct)
68 elif type == 'I':
69 rs, rt, immed = map(int, rest)
70 result.append(opcode << 26 |
71 rs << 21 |
72 rt << 16 |
73 (immed & 0xffff))
74 else:
75 addr = int(rest[0])
76 result.append(opcode << 26 |
77 (addr & 0x3ffffff))
78
79 with open(argv[1], 'wb') as f:
80 for instr in result:
81 f.write(bytes([instr >> 0x18,
82 (instr >> 0x10) & BYTE,
83 (instr >> 0x08) & BYTE,
84 instr & BYTE]))
Binary diff not shown
1 ori 0 1 1
2 ori 0 2 5
3 add 1 2 1
4 subi 2 2 1
5 slt 2 3 0
6 bnez 3 0 -3
7 pln 1 0 0
8 halt 0 0 0
Binary diff not shown
1 ori 0 1 10
2 pln 1 0 0
3 beqz 0 0 -2
4 pln 0 0 0
5 halt 0 0 0
Binary diff not shown
1 ori 0 0 1
2 addi 1 1 1
3 pln 1 0 0
4 j -2
5 halt 0 0 0
Binary diff not shown
1 ori 1 1 5
2 sw 0 1 0
3 subi 1 1 1
4 pln 1 0 0
5 bnez 1 0 -3
6 lw 1 2 0
7 pln 2 0 0
8 bnez 1 0 -2
9 halt 0 0 0
Binary diff not shown
1 ori 1 1 5
2 ori 2 2 1
3 sw 0 1 0
4 subi 1 1 1
5 pln 1 0 0
6 bnez 1 0 -4
7 ori 0 2 5
8 lw 1 2 0
9 subi 2 2 1
10 pln 2 0 0
11 bnez 1 0 -3
12 pln 2 0 0
13 halt 0 0 0
Binary diff not shown
1 ori 1 1 10
2 sw 0 1 0
3 lw 0 2 0
4 addi 1 3 1
5 addi 1 4 1
6 addi 1 5 1
7 pln 2 0 0
8 halt 0 0 0
Binary diff not shown
1 ori 1 1 1
2 add 1 1 2
3 add 1 1 3
4 add 1 1 4
5 pln 1 0 0
6 halt 0 0 0
Binary diff not shown
1 ori 1 1 1
2 add 1 1 2
3 add 1 2 3
4 and 1 2 4
5 pln 1 0 0
6 pln 2 0 0
7 pln 3 0 0
8 halt 0 0 0
Binary diff not shown
1 ori 0 1 9
2 sw 0 1 10
3 ori 0 2 2
4 lw 2 5 8
5 pln 5 0 0
6 halt 0 0 0
Binary diff not shown
1 ori 1 1 8
2 bnez 1 0 1
3 pln 0 0 0
4 pln 1 0 0
5 halt 0 0 0
Binary diff not shown
1 ori 1 1 1
2 add 1 1 1
3 add 1 1 1
4 add 1 1 1
5 pln 1 0 0
6 halt 0 0 0
1 import instr;
2
3 import std.array;
4 import std.stdio;
5 import std.string;
6
7 class CPU {
8 public:
9 uint[32] registers;
10 uint[4096] memory;
11 uint[] program;
12 uint pc, cycles;
13 bool running;
14
15 this(uint[] p) {
16 pc = 0;
17 registers[] = 0;
18 memory[] = 0;
19 running = true;
20
21 program = p;
22 }
23
24 void tick() {
25 if (pc < program.length) {
26 Instr i = Instr.decode(program[pc]);
27 i.compute(this);
28 } else {
29 running = false;
30 }
31 pc++;
32 }
33
34 void run() {
35 while (running) {
36 tick();
37 }
38 }
39
40 /* Stop the program. */
41 void halt() {
42 writefln("HALTING PROGRAM.");
43 running = false;
44 }
45
46 /* Print all the registers at this state. */
47 void print_registers() {
48 writef(" registers([");
49 for (uint i = 0; i < 32; i++) {
50 if (i != 0)
51 writef(", ");
52
53 writef("%x", registers[i]);
54 }
55 writefln("])");
56 }
57
58 /* Print the value of a register. */
59 void print_line(uint x) {
60 printf("PROGRAM OUTPUT: %d\n", x);
61 }
62 }
63
64 void main(string[] args) {
65 if (args.length < 2) {
66 writefln("Usage: %s [file]", args[0]);
67 return;
68 }
69 writefln("Opening %s", args[1]);
70 auto f = File(args[1], "r");
71 uint psize = cast(uint)f.size >> 2;
72 uint[] program;
73 program.length = psize;
74 uint i = 0;
75
76 foreach(ubyte[] buffer; f.byChunk(4)) {
77 uint word = buffer[3] |
78 buffer[2] << 0x08 |
79 buffer[1] << 0x10 |
80 buffer[0] << 0x18;
81 program[i] = word;
82 i ++;
83 }
84 CPU cpu = new CPU(program);
85 writefln("Executing program...");
86 (new CPU(program)).run();
87 writefln("");
88 }
1 module instr;
2
3 /* Reference on the DLX instruction set---mostly a subset
4 of MIPS with slightly different semantics---can be
5 found at
6 http://www.csee.umbc.edu/courses/undergraduate/411/spring96/dlx.html
7 */
8
9 import std.string;
10 import std.stdio;
11 import cpu;
12
13 /* the full list of DLX opcodes; the only one missing is
14 the arithmetic opcode, which is always 0x00. */
15 enum Opcode {
16 addi = 0x08,
17 andi = 0x0c,
18 beqz = 0x04,
19 bnez = 0x05,
20 j = 0x02,
21 jal = 0x03,
22 jalr = 0x13,
23 jr = 0x12,
24 lhi = 0x0f,
25 lw = 0x23,
26 ori = 0x0d,
27 seqi = 0x18,
28 slei = 0x1c,
29 slli = 0x14,
30 slti = 0x1a,
31 snei = 0x19,
32 srai = 0x17,
33 srli = 0x16,
34 subi = 0x0a,
35 sw = 0x2b,
36 xori = 0x0e,
37 halt = 0x30, /* These two are not part of the instruction */
38 pln = 0x31, /* set but were added to make debugging easier. */
39 }
40
41 /* These are the arithmetic 'opcodes', which are found to
42 the far right in an arithmetic instruction. */
43 enum Func {
44 add = 0x20,
45 and = 0x24,
46 or = 0x25,
47 seq = 0x28,
48 sle = 0x2c,
49 sll = 0x04,
50 slt = 0x2a,
51 sne = 0x29,
52 sra = 0x07,
53 srl = 0x06,
54 sub = 0x22,
55 xor = 0x26,
56 nul = 0x00,
57 }
58
59 /* The masks to extract the individual portions of
60 the bytecode instructions. */
61 enum Masks {
62 opcode = 0b11111100000000000000000000000000,
63 rs = 0b00000011111000000000000000000000,
64 rt = 0b00000000000111110000000000000000,
65 rd = 0b00000000000000001111100000000000,
66 shamt = 0b00000000000000000000011111000000,
67 funct = 0b00000000000000000000000000111111,
68 immed = 0b00000000000000001111111111111111,
69 addr = 0b00000011111111111111111111111111,
70 }
71
72 /* A set of related functions to extract and shift
73 * the relevant pieces of an instruction. */
74 ubyte extract_opcode(uint instr) {
75 return (Masks.opcode & instr) >> 26;
76 }
77
78 ubyte extract_rs(uint instr) {
79 return (Masks.rs & instr) >> 21;
80 }
81
82 ubyte extract_rt(uint instr) {
83 return (Masks.rt & instr) >> 16;
84 }
85
86 ubyte extract_rd(uint instr) {
87 return (Masks.rd & instr) >> 11;
88 }
89
90 ubyte extract_shamt(uint instr) {
91 return (Masks.shamt & instr) >> 6;
92 }
93
94 ubyte extract_funct(uint instr) {
95 return (Masks.funct & instr);
96 }
97
98 ushort extract_immed(uint instr) {
99 return (Masks.immed & instr);
100 }
101
102 uint extract_addr(uint instr) {
103 return (Masks.addr & instr);
104 }
105
106 /* Ensure the sign still exists.*/
107 short extend(ushort x) {
108 return cast(short)x;
109 }
110
111 int addr_extend(uint address) {
112 uint na = address & 0x1fffffff;
113 na |= (address & 0x20000000) << 6;
114 return cast(int)na;
115 }
116
117
118 /* The structs representing the parts of instructions;
119 one for each of the three types. */
120 struct R_Type {
121 ubyte opcode, rs, rt, rd, shamt, funct;
122 };
123
124 struct I_Type {
125 ubyte opcode, rs, rt;
126 ushort immediate;
127 };
128
129 struct J_Type {
130 ubyte opcode;
131 uint address;
132 };
133
134 /* An Instr consists of a single flag to tell the type of the
135 * instruction, and a payload that is a union whose initialized
136 * member corresponds to the type. Each member of the payload
137 * is a struct mirroring the constituents of that MIPS
138 * instruction type. */
139 struct Instr {
140 static r_string = "R(op:0x%x, rs:0x%x, rt:0x%x, rd:0x%x, shamt:0x%x, funct:0x%x)";
141 static i_string = "I(op:0x%x, rs:0x%x, rt:0x%x, immediate:0x%x)";
142 static j_string = "J(op:0x%x, addr:0x%x)";
143
144 enum Type : short { R, I, J };
145 Type type;
146
147 union {
148 R_Type r_instr;
149 I_Type i_instr;
150 J_Type j_instr;
151 };
152
153 /* Unless specified otherwise, an instruction takes 2 cycles to
154 complete. */
155 uint time = 2u;
156
157 static Instr decode(uint raw_instruction) {
158 ubyte op = extract_opcode(raw_instruction);
159 Instr result;
160
161 writefln("opcode: %02x\n", op);
162 if (op == 0x00) {
163 result.type = Type.R;
164 with (result.r_instr) {
165 opcode = op;
166 rs = extract_rs(raw_instruction);
167 rt = extract_rt(raw_instruction);
168 rd = extract_rd(raw_instruction);
169 shamt = extract_shamt(raw_instruction);
170 funct = extract_funct(raw_instruction);
171 }
172
173 } else if (op == Opcode.j || op == Opcode.jal) {
174 result.type = Type.J;
175 with (result.j_instr) {
176 opcode = op;
177 address = extract_addr(raw_instruction);
178 }
179
180 } else {
181 result.type = Type.I;
182 with (result.i_instr) {
183 opcode = op;
184 rs = extract_rs(raw_instruction);
185 rt = extract_rt(raw_instruction);
186 immediate = extract_immed(raw_instruction);
187 }
188 }
189
190 return result;
191 }
192
193 /* Perform the action indicated by this instruction. Has
194 access to the CPU (which also contains memory to be
195 used. */
196 uint compute(CPU cpu) {
197 writefln("Executing %s\n", this.toString());
198 switch (type) {
199 case Type.R:
200 with(r_instr) {
201 uint vs = cpu.registers[rs];
202 uint vt = cpu.registers[rt];
203 switch (funct) {
204 case Func.add:
205 cpu.registers[rd] = vs + vt;
206 break;
207 case Func.and:
208 cpu.registers[rd] = vs & vt;
209 break;
210 case Func.or:
211 cpu.registers[rd] = vs | vt;
212 break;
213 case Func.seq:
214 cpu.registers[rd] = (vs == vt ? 1u : 0u);
215 break;
216 case Func.sle:
217 cpu.registers[rd] = (vs <= vt ? 1u : 0u);
218 break;
219 case Func.sll:
220 cpu.registers[rd] = vs << (vt % 8);
221 break;
222 case Func.slt:
223 cpu.registers[rd] = (vs < vt ? 1u : 0u);
224 break;
225 case Func.sne:
226 cpu.registers[rd] = (vs != vt ? 1u : 0u);
227 break;
228 case Func.sra:
229 cpu.registers[rd] = vs >> (vt % 8);
230 break;
231 case Func.srl:
232 cpu.registers[rd] = vs >> (vt % 8);
233 break;
234 case Func.sub:
235 cpu.registers[rd] = vs - vt;
236 break;
237 case Func.xor:
238 cpu.registers[rd] = rs ^ rt;
239 break;
240 default:
241 throw new Exception("Unknown funct: %d".format(funct));
242 }
243 return cpu.registers[rd];
244 }
245 break;
246
247 case Type.J:
248 switch (j_instr.opcode) {
249 case Opcode.j:
250 cpu.pc += addr_extend(j_instr.address) - 1;
251 break;
252 case Opcode.jal:
253 cpu.registers[31] = cpu.pc + 4;
254 cpu.pc += addr_extend(j_instr.address) - 1;
255 break;
256 default:
257 throw new Exception("Unknown opcode for J-type: %d".format(j_instr.opcode));
258 }
259 break;
260
261 case Type.I:
262 with (i_instr) {
263 uint vs = cpu.registers[rs];
264 uint eimm = extend(immediate);
265 switch (opcode) {
266 case Opcode.addi:
267 cpu.registers[rt] = vs + eimm;
268 break;
269 case Opcode.andi:
270 cpu.registers[rt] = vs & eimm;
271 break;
272 case Opcode.beqz:
273 cpu.pc += (vs == 0 ? eimm : 0);
274 break;
275 case Opcode.bnez:
276 cpu.pc += (vs != 0 ? eimm : 0);
277 break;
278 case Opcode.jalr:
279 cpu.registers[31] = cpu.pc + 4;
280 cpu.pc = vs - 1;
281 break;
282 case Opcode.jr:
283 cpu.pc = vs - 1;
284 break;
285 case Opcode.lhi:
286 cpu.registers[rt] = immediate << 16;
287 break;
288 case Opcode.lw:
289 cpu.registers[rt] = cpu.memory[vs + eimm];
290 break;
291 case Opcode.ori:
292 cpu.registers[rt] = vs | eimm;
293 break;
294 case Opcode.seqi:
295 cpu.registers[rt] = (vs == eimm ? 1 : 0);
296 break;
297 case Opcode.slei:
298 cpu.registers[rt] = (vs <= eimm ? 1 : 0);
299 break;
300 case Opcode.slli:
301 cpu.registers[rt] = vs << (immediate % 8);
302 break;
303 case Opcode.slti:
304 cpu.registers[rt] = (vs < eimm ? 1 : 0);
305 break;
306 case Opcode.snei:
307 cpu.registers[rt] = (vs != eimm ? 1 : 0);
308 break;
309 case Opcode.srai:
310 cpu.registers[rt] = vs >> (immediate % 8);
311 break;
312 case Opcode.srli:
313 cpu.registers[rt] = vs >> (immediate % 8);
314 break;
315 case Opcode.subi:
316 cpu.registers[rt] = vs - eimm;
317 break;
318 case Opcode.sw:
319 cpu.memory[vs + eimm] = cpu.registers[rt];
320 break;
321 case Opcode.xori:
322 cpu.registers[rt] = vs ^ immediate;
323 break;
324 case Opcode.pln:
325 cpu.print_line(vs);
326 break;
327 case Opcode.halt:
328 cpu.halt();
329 break;
330 default:
331 throw new Exception("Unknown opcode in %s".format(this.toString()));
332 }
333 return cpu.registers[rt];
334 }
335 break;
336 default:
337 throw new Exception("Unknown type: %d".format(type));
338 break;
339 }
340 return 0u;
341 }
342
343 string toString() {
344 switch(type) {
345 case Type.R:
346 with(r_instr) {
347 return r_string.format(opcode, rs, rt, rd, shamt, funct);
348 }
349 case Type.I:
350 with (i_instr) {
351 return i_string.format(opcode, rs, rt, immediate);
352 }
353 case Type.J:
354 with (j_instr) {
355 return j_string.format(opcode, address);
356 }
357 default:
358 return "UNKNOWN";
359 }
360 }
361 }