-
Notifications
You must be signed in to change notification settings - Fork 0
/
assembler.js
128 lines (109 loc) · 3.45 KB
/
assembler.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
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
"use strict";
export class Assembler {
constructor() {
this.memAddress = 0;
this.labels = {};
}
getMemAddress() {
return this.memAddress;
}
setMemAddress(value) {
this.memAddress = value;
}
incrementMemAddress(byValue = 1) {
this.memAddress += byValue;
}
getLabel(key) {
return this.labels[key];
}
setLabel(key, value) {
this.labels[key] = value;
}
assemble(code) {
this.setMemAddress(0);
code = code.replace(/:/g, "\n");
let lines = code.split('\n').filter(line => line.trim()); //filter out empty lines
let finalCode = "v2.0 raw\n";
lines.forEach(line => {
line = line.split(/;|#/)[0];
line = line.trim();
if (line.length === 0) return; // skip lines with only comments
let [opCode, operand, data] = line.split(/, |,| |:/).map(line => {
line = line.replace("(", "");
line = line.replace(")", "");
return line;
});
let firstChar = Assembler.hex(InstructionMap[opCode], "end");
// this.incrementMemAddress();
let restOfString = this.makeOperand(opCode, operand, data);
//console.log(restOfString,"\n");
if (operand === undefined && data === undefined) return;
if (restOfString !== undefined && restOfString.length === 1) { // one byte
finalCode += firstChar[0] + restOfString + " ";
this.incrementMemAddress();
}
else {
if (restOfString !== undefined && firstChar !== undefined) { // two bytes
finalCode += firstChar[0] + restOfString[0] + restOfString.substring(restOfString.indexOf(" ")) + " ";
this.incrementMemAddress(2);
}
else if (opCode === "JMP") { // two bytes, JMP
finalCode += firstChar[0] + "0 " + Assembler.hex(this.getLabel(operand)) + " ";
this.incrementMemAddress(2);
}
else { // two bytes, JNE, JEQ...
finalCode += firstChar[0]+(operand[1]*4).toString(16)+ " " + Assembler.hex(this.getLabel(data)) + " ";
// added the second bit to jump opcode for example jne - 9 and R3 - c ==> 9c
this.incrementMemAddress(2);
}
}
//console.log(restOfString," ",restOfString.substring(restOfString.indexOf(" ")));
});
return finalCode.slice(0,-1); // remove last appended space
}
makeOperand(opCode, operand, data) {
// this.incrementMemAddress();
if (data !== undefined && data[0] == 'R') {
return (((operand[1]) & 0b11) << 2 | ((((data[1]) & 0b11) << 0) & 0xff)).toString(16);
}
else {
if (!isNaN(parseInt(data))) {
return (operand[1] * 4).toString(16) + ' ' + data.slice(-2);
}
else {
// this.incrementMemAddress(-1);
if (data === undefined)
this.setLabel(opCode, this.getMemAddress());
else
this.setLabel(opCode, this.getMemAddress());
//at this section the label is the opcode not the data
}
}
}
/**
* Converts DEC to HEX
* @param {Number} value Value to convert
* @param {String} pad Text padding. Default "start"
*/
static hex(value, pad = "start") {
if (value !== undefined) return pad === "start" ? value.toString(16).padStart(2, '0') : value.toString(16).padEnd(2, '0');
}
}
const InstructionMap = {
"AND": 0x00,
"OR": 0x01,
"ADD": 0x02,
"SUB": 0x03,
"LW": 0x04,
"SW": 0x05,
"MOV": 0x06,
"INP": 0x07,
"JEQ": 0x08,
"JNE": 0x09,
"JGT": 0xa,
"JLT": 0xb,
"LW": 0xc,
"SW": 0xd,
"LI": 0xe,
"JMP": 0xf,
}