Created
October 15, 2023 06:35
-
-
Save narskidan/2d880fe27510e0c90f75680bfee86b29 to your computer and use it in GitHub Desktop.
Pancho triggering my autism
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MEMORY_SIZE = 1_000_000; | |
type Memory = any[] | |
type registerName = 'stackPointer' | |
| 'instructionPointer' | |
| 'returnValue' | |
| 'general'; | |
interface Processor { | |
halted: boolean; | |
stack: string[]; | |
code: string[]; | |
memory: Memory; | |
registers: { | |
stackPointer: number, | |
instructionPointer: number, | |
returnValue?: any, | |
general?: any, | |
general2?: any, | |
temporary?: any | |
temporary2?: any, | |
temporary3?: any | |
}; | |
} | |
// inc, cmp, goto, Label, syscall, mov, hlt, push, pop | |
class Processor { | |
constructor(code: string[], memory: Memory) { | |
// replace labels with memory locations... | |
// very ugly code | |
const labels = code | |
.map((e, i) => [i, e]) | |
.filter(([i, e]) => | |
(e as string).trim().startsWith('label') | |
); | |
for (let i = 0; i < code.length; i++) { | |
const jumps = ['je', 'jmp', 'jlt', 'jgt', 'jne']; | |
if (jumps.some(jmp => code[i].startsWith(jmp))) { | |
const [jmp, label] = code[i].split(' '); | |
const labelObj = labels.find(([index, l]) => (l as string).endsWith(label)); | |
if (labelObj === undefined) { | |
throw new Error('Code jumps to non-existent label'); | |
} | |
const memoryLocation = labelObj[0]; | |
const translatedJump = `${jmp} ${memoryLocation}`; | |
code[i] = translatedJump; | |
} | |
} | |
this.halted = false; | |
this.code = code; | |
this.memory = memory; | |
this.registers = { | |
stackPointer: this.code.length, // should be after program ends | |
instructionPointer: 0, | |
} | |
this.code.forEach((e, i) => { | |
this.memory[i] = e; | |
}); | |
} | |
exe(): void { | |
while (!this.halted) { | |
const ip = this.registers.instructionPointer | |
this.registers | |
const [instruction, ...args] = this.memory[ip].split(' '); | |
if (instruction === 'mov') { | |
const [register, value] = args; | |
this.mov(register, value); | |
} if (instruction === 'inc') { | |
const [register] = args; | |
this.inc(register); | |
} if (instruction === 'dec') { | |
const [register] = args; | |
this.dec(register); | |
} if (instruction === 'hlt') { | |
this.hlt(); | |
} if (instruction === 'cmp') { | |
const [register1, register2] = args; | |
this.cmp(register1, register2); | |
} if (instruction === 'jmp') { | |
const [memoryLocation] = args; | |
this.jmp(memoryLocation) | |
} if (instruction === 'je') { | |
const [memoryLocation] = args; | |
this.je(memoryLocation) | |
} if (instruction === 'push') { | |
const [register] = args; | |
this.push(register); | |
} if (instruction === 'pop') { | |
const [register] = args; | |
this.pop(register); | |
} | |
this.registers.instructionPointer++; | |
} | |
} | |
hlt(): void { | |
this.halted = true; | |
} | |
mov(register: registerName, value: any): void { | |
this.registers[register] = parseInt(value); | |
} | |
inc(register: registerName): void { | |
this.registers[register]++; | |
} | |
dec(register: registerName): void { | |
this.registers[register]--; | |
} | |
cmp(registerName1: registerName, registerName2: registerName) { | |
const register1 = parseInt(this.registers[registerName1]); | |
const register2 = parseInt(this.registers[registerName2]); | |
if (register1 < -5 || register2 < -5) { | |
throw new Error('just exiting...') | |
} | |
if (register1 > register2) { | |
this.registers.temporary = 2; | |
} | |
if (register1 < register2) { | |
this.registers.temporary = 0; | |
} | |
if (register1 === register2) { | |
this.registers.temporary = 1; | |
} | |
} | |
je(memoryLocation: string): void { | |
if (this.registers.temporary === 1) { | |
this.registers.instructionPointer = parseInt(memoryLocation); | |
} | |
} | |
jmp(memoryLocation: string): void { | |
this.registers.instructionPointer = parseInt(memoryLocation); | |
} | |
push(register: registerName): void { | |
this.memory[this.registers.stackPointer++] = parseInt(this.registers[register]); | |
} | |
pop(register: registerName): void { | |
this.registers.stackPointer--; | |
this.registers[register] = parseInt(this.memory[this.registers.stackPointer]) | |
} | |
} | |
const code: string[] = [ | |
"jmp Main", | |
"label AddFunction", | |
"pop general", // 2 | |
"pop temporary2", // 3 | |
"mov temporary3 0", // 0 | |
"label Loop", | |
"cmp temporary2 temporary3", | |
"je ExitLoop", | |
"inc general", | |
"dec temporary2", | |
"jmp Loop", | |
"label ExitLoop", | |
// exit our function | |
"pop temporary2", | |
"inc temporary2", | |
"inc temporary2", | |
"inc temporary2", | |
"inc temporary2", | |
"inc temporary2", | |
"push temporary2", | |
"pop instructionPointer", | |
"label Main", | |
"push instructionPointer", | |
"mov general 12", | |
"push general", | |
"mov general 21", | |
"push general", | |
"jmp AddFunction", | |
"hlt" | |
]; | |
const ram: Memory = new Array(MEMORY_SIZE); | |
const cpu: Processor = new Processor(code, ram); | |
cpu.exe() | |
console.log(cpu.registers.general) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Pancho was talking about stacks, leading to a discussion about the role of the stack during function calls, leading to us beginning to implement an ISA where we manually use the stack for function calls