Skip to content

Instantly share code, notes, and snippets.

@narskidan
Created October 15, 2023 06:35
Show Gist options
  • Save narskidan/2d880fe27510e0c90f75680bfee86b29 to your computer and use it in GitHub Desktop.
Save narskidan/2d880fe27510e0c90f75680bfee86b29 to your computer and use it in GitHub Desktop.
Pancho triggering my autism
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)
@narskidan
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment