-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpu.js
127 lines (113 loc) · 3.69 KB
/
cpu.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
127
const createMemory = require("./createMemory")
const instructions = require("./instructions")
class CPU {
constructor(memory) {
this.memory = memory
// prettier-ignore
this.registerNames = [
'ip', 'acc',
'r1', 'r2', 'r3', 'r4',
'r5', 'r6', 'r7', 'r8'
]
this.registers = createMemory(this.registerNames.length * 2)
this.registerMap = this.registerNames.reduce((map, name, i) => {
map[name] = i * 2
return map
}, {})
}
debug() {
this.registerNames.forEach((name) => {
console.log(
`${name}: 0x${this.getRegister(name).toString(16).padStart(4, "0")}`
)
})
console.log()
}
viewMemoryAt(address) {
const nextEightBytes = Array.from({ length: 8 }, (_, i) =>
this.memory.getUint8(address + i)
).map((v) => `0x${v.toString(16).padStart(2, "0")}`)
console.log(
`0x${address.toString(16).padStart(4, "0")}: ${nextEightBytes.join(" ")}`
)
}
getRegister(name) {
if (!(name in this.registerMap)) {
throw new Error(`getRegister: No such register '${name}'`)
}
return this.registers.getUint16(this.registerMap[name])
}
setRegister(name, value) {
if (!(name in this.registerMap)) {
throw new Error(`getRegister: No such register '${name}'`)
}
return this.registers.setUint16(this.registerMap[name], value)
}
fetch() {
const nextInstructionAddress = this.getRegister("ip")
const instruction = this.memory.getUint8(nextInstructionAddress)
this.setRegister("ip", nextInstructionAddress + 1)
return instruction
}
fetch16() {
const nextInstructionAddress = this.getRegister("ip")
const instruction = this.memory.getUint16(nextInstructionAddress)
this.setRegister("ip", nextInstructionAddress + 2)
return instruction
}
execute(instruction) {
switch (instruction) {
// Move literal into register
case instructions.MOV_LIT_REG: {
const literal = this.fetch16()
const register = (this.fetch() % this.registerNames.length) * 2
this.registers.setUint16(register, literal)
return
}
// Move register to register
case instructions.MOV_REG_REG: {
const registerFrom = (this.fetch() % this.registerNames.length) * 2
const registerTo = (this.fetch() % this.registerNames.length) * 2
const value = this.registers.getUint16(registerFrom)
this.registers.setUint16(registerTo, value)
return
}
case instructions.MOV_REG_MEM: {
const registerFrom = (this.fetch() % this.registerNames.length) * 2
const address = this.fetch16()
const value = this.registers.getUint16(registerFrom)
this.memory.setUint16(address, value)
return
}
case instructions.MOV_MEM_REG: {
const address = this.fetch16()
const value = this.memory.getUint16(address)
const registerTo = (this.fetch() % this.registerNames.length) * 2
this.registers.setUint16(registerTo, value)
return
}
// Add register to register
case instructions.ADD_REG_REG: {
const r1 = this.fetch()
const r2 = this.fetch()
const registerValue1 = this.registers.getUint16(r1 * 2)
const registerValue2 = this.registers.getUint16(r2 * 2)
this.setRegister("acc", registerValue1 + registerValue2)
return
}
case instructions.JMP_NOT_EQ: {
const value = this.fetch16()
const address = this.fetch16()
if (value != this.getRegister("acc")) {
this.setRegister("ip", address)
}
return
}
}
}
step() {
const instruction = this.fetch()
return this.execute(instruction)
}
}
module.exports = CPU