-
Notifications
You must be signed in to change notification settings - Fork 0
/
assem.js
90 lines (73 loc) · 2.58 KB
/
assem.js
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
'use strict';
const codes = require('./codes');
const err = require('./err');
const widths = {
none: 1, accum: 1,
immed: 2, zero: 2, zerox: 2, zeroy: 2, rela: 2, indrx: 2, indry: 2,
abs: 3, absx: 3, absy: 3, indr: 3,
};
const assem = {
program: (lexed) =>
lexed.map((line) => assem.program_line(line)),
program_line: (line, errors) => {
const decoded = assem.decode_line(line);
switch (typeof decoded) {
case 'string':
err.log(decoded, line.lineno);
break;
case 'object':
decoded.width = decoded.width || 0;
return {...line, ...decoded};
}
return {...line, width: 0};
},
decode_line: (line) => {
if (!line.codename) {
return undefined;
}
const code_set = codes[line.codename];
if (line.codename == 'ORG') {
return {value: assem.value(line.arg_data)};
} else if (line.arg_type == 'list') {
const list = line.arg_data.map((v) => assem.value(v));
const elemsize = line.codename == 'DW' ? 2 : 1;
return {value: list, width: elemsize * list.length};
} else if (!code_set) {
return `unknown opcode or directive: ${line.codename}`;
}
const arg_type = code_set.rela ? 'rela' : line.arg_type;
const code = code_set[arg_type];
const value = assem.value(line.arg_data);
// 1:1 lexing -> assembly works for many things
if (code) {
return {code, value, width: widths[arg_type]};
}
// Handle addr -> zero|abs, addrx -> zerox|absx, etc.
if (/^addr/.test(arg_type)) {
const zero_type = arg_type.replace('addr', 'zero');
const abs_type = arg_type.replace('addr', 'abs');
if (value === undefined) {
return `could not determine width: ${line.arg_data}`;
}
const alt_type = (value < 0x100 && code_set[zero_type]) ?
zero_type : abs_type;
const code = code_set[alt_type];
if (code) {
return {code, value, width: widths[alt_type]};
}
}
return `unsupported parameter type for ${line.code}: ${arg_type}`;
},
value: (value) => {
switch (value[0]) {
case '$':
return parseInt(value.substr(1), 16);
case '%':
return parseInt(value.substr(1), 2);
default:
const num = parseInt(value);
return num ? num : value;
}
},
};
module.exports = assem;