-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathassembler.c
166 lines (146 loc) · 5.86 KB
/
assembler.c
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
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <byteswap.h>
#include "command.h"
#include "token.h"
#include "util.h"
void print_inst(Instruction ins)
{
printf("Instruction: 0x%X | #%d:\n", ins.opcode, ins.arg_count);
for (int i = 0; i < ins.arg_count; i++) {
printf(" arg[%d]: %d, 0x%X\n", i, ins.args[i].literal, ins.args[i].value);
}
printf("\n");
}
void test() {
print_inst(token_parse_line("jmp 0"));
print_inst(token_parse_line("jmp 1293"));
print_inst(token_parse_line("ret "));
print_inst(token_parse_line(" ret"));
print_inst(token_parse_line("drw V0 VF 39"));
print_inst(token_parse_line("drw V0 VF 7"));
print_inst(token_parse_line("add I V2"));
print_inst(token_parse_line("mov Va [I] v9"));
}
OpcodeType line_to_instruction_type(char* line) {
Instruction ins = token_parse_line(line);
Command cmd = command_parse_opcode(ins.opcode);
// printf("Ins: %04X\n", ins.opcode);
// printf("Cmd: %04X\n\n", cmd.type);
return cmd.type;
}
void test_all_codes() {
assert(line_to_instruction_type("call 342") == 0x2FFF);
assert(line_to_instruction_type("cls") == 0x00E0);
assert(line_to_instruction_type("drw V1 V2 3") == 0xD01F);
assert(line_to_instruction_type("jmp 1000") == 0x1FFF);
assert(line_to_instruction_type("jmp0 3494") == 0xBFFF);
assert(line_to_instruction_type("mov V3 250") == 0x60FF);
assert(line_to_instruction_type("mov V1 V2") == 0x8010);
assert(line_to_instruction_type("mov V3 DT") == 0xF007);
assert(line_to_instruction_type("mov V2 K") == 0xF00A);
assert(line_to_instruction_type("mov V4 [I]") == 0xF065);
assert(line_to_instruction_type("mov I 496") == 0xAFFF);
assert(line_to_instruction_type("mov DT V7") == 0xF015);
assert(line_to_instruction_type("mov ST V8") == 0xF018);
assert(line_to_instruction_type("mov F V5") == 0xF029);
assert(line_to_instruction_type("mov B V9") == 0xF033);
assert(line_to_instruction_type("mov [I] Va") == 0xF055);
assert(line_to_instruction_type("rnd V0 13") == 0xC0FF);
assert(line_to_instruction_type("ret") == 0x00EE);
assert(line_to_instruction_type("se V9 131") == 0x30FF);
assert(line_to_instruction_type("se V3 V4") == 0x5010);
assert(line_to_instruction_type("sne V6 70") == 0x40FF);
assert(line_to_instruction_type("sne V6 V7") == 0x9010);
assert(line_to_instruction_type("skp Vb") == 0xE09E);
assert(line_to_instruction_type("sknp Ve") == 0xE0A1);
assert(line_to_instruction_type("add Vc 96") == 0x70FF);
assert(line_to_instruction_type("add Vd Ve") == 0x8014);
assert(line_to_instruction_type("add I V3") == 0xF01E);
assert(line_to_instruction_type("sub Vd V2") == 0x8015);
assert(line_to_instruction_type("subn V4 V3") == 0x8017);
assert(line_to_instruction_type("and V6 V6") == 0x8012);
assert(line_to_instruction_type("or V7 V5") == 0x8011);
assert(line_to_instruction_type("xor V8 V2") == 0x8013);
assert(line_to_instruction_type("shr V0") == 0x8016);
assert(line_to_instruction_type("shl V9") == 0x801E);
}
typedef struct {
uint16_t* items;
size_t count;
size_t capacity;
} Opcodes;
void set_fonts(uint8_t* binary) {
// fills memory with font data as described here http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#2.4
// copies to memory starting at 0x000
uint8_t font_data[] = {
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
0x20, 0x60, 0x20, 0x20, 0x70, // 1
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
};
memcpy(binary, font_data, sizeof(font_data));
}
int main(int argc, char** argv) {
test_all_codes();
if (argc < 3) {
printf("Usage: %s <input-asm> <output-bin>\n", argv[0]);
return 1;
}
String input = {0};
if (!util_read_file(argv[1], &input)) {
printf("Error: Could not read file: %s\n", argv[1]);
return 1;
}
Opcodes ops = {0};
CString_List lines = {0};
int line_idx = 0;
char* line = strtok(input.items, "\n");
while (line != NULL) {
Instruction ins = token_parse_line(line);
if (ins.opcode == 0) {
printf("Warning: Could not parse line: %d\n", line_idx);
} else {
uint16_t op = __bswap_16(ins.opcode); // swap endian-ness for big-endian in file
util_da_append(&ops, op);
}
util_da_append(&lines, line);
line = strtok(NULL, "\n");
line_idx++;
}
printf("\nParsed Lines:\n");
for (int i = 0; i < lines.count; i++) {
printf("%02d: %s\n", i, lines.items[i]);
}
printf("\nOpcodes:\n");
for (int i = 0; i < ops.count; i++) {
uint16_t op = __bswap_16(ops.items[i]); // swap endian-ness back for printing lol
printf("%04X\n", op);
}
// create binary with UTIL_INSTRUCTION_START offset
int bin_length = UTIL_INSTRUCTION_START + ops.count * 2;
uint8_t* binary = malloc(bin_length);
memset(binary, 0, UTIL_INSTRUCTION_START);
memcpy(binary + UTIL_INSTRUCTION_START, ops.items, ops.count * 2);
set_fonts(binary);
if (!util_write_file(argv[2], binary, bin_length)) {
printf("Error: Could not write file: %s\n", argv[2]);
return 1;
}
free(binary);
return 0;
}