VicturalMachine(2)javscript code the stack from the machineDefinition stack When we call the function, we need to pointer to protocal the stack from original stack pointer frame pointer Difintion in CPU class length - 1 make sure index from 0, another minus one because we need 2 bytes to store the bits word class CPU { constructor(memory){ this.registerNames = [ 'sp','fp' ] // ... this.setRegister('sp',this.getRegister('sp').length - 1 - 1) this.setRegister('fp',this.getRegister('fp'.length - 1 -1)) } // ... } Difintion in instructions set const PSH_LIT = 0x17 const PSH_REG = 0x18 Implement pop and push case PSH_LIT: { const value = this.fetch16() this.push(value) return } case PSH_REG: { const registerIndex = this.fetchRegisterIndex() this.push(this.registers.getUint16(registerIndex)) return } case POP: { const registerIndex = this.fetchRegisterIndex() const value = this.pop() this.registers.setUint16(registerIndex,value) return } Test the push and pop writeBytes[i++] = MOVE_LIT_REG writeBytes[i++] = 0x51 writeBytes[i++] = 0x51 writeBytes[i++] = R1 writeBytes[i++] = MOVE_LIT_REG writeBytes[i++] = 0x42 writeBytes[i++] = 0x42 writeBytes[i++] = R2 writeBytes[i++] = PSH_REG writeBytes[i++] = R1 writeBytes[i++] = PSH_REG writeBytes[i++] = R2 writeBytes[i++] = POP writeBytes[i++] = R1 writeBytes[i++] = POP writeBytes[i++] = R2 cpu.debug() cpu.viewMemoryAt(cpu.getRegister('ip')) /** 0xffff-1 為記憶體開頭 而往下還有7個字節因此減6 (從0開始) **/ cpu.viewMemoryAt(0xffff - 1 - 6) const rl = readline.createInterface({ input: process.stdin, output:process.stdout }) rl.on('line',()=>{ cpu.step() cpu.debug() cpu.viewMemoryAt(cpu.getRegister('ip')) cpu.viewMemoryAt(0xffff - 1 - 6) }) CAL and RET Definition of the instruction const CAL_LIT = 0x5e const CAL_REG = 0x5f const RET = 0x60 Implement the function of instruction CAL function case CAL_LIT: { const address = this.fetch16() this.pushState() this.setRegister('fp',this.getRegister('sp')) this.stackFrameSize = 0 this.setRegister('ip',address) return } case CAL_REG: { const registerIndex = this.fetchRegisterIndex() const address = this.registers.getUint16(registerIndex) this.pushState() this.setRegister('ip',address) return } push state function pushState(){ this.push(this.getRegister('r1')) this.push(this.getRegister('r2')) this.push(this.getRegister('r3')) this.push(this.getRegister('r4')) this.push(this.getRegister('r5')) this.push(this.getRegister('r6')) this.push(this.getRegister('r7')) this.push(this.getRegister('r8')) this.push(this.getRegister('ip')) this.push(this.stackFrameSize + 2) //last item } RET function case RET: { this.popState() return } pop state pop state is inverse of the push state beacause the stack is FILO popState(){ const framePointerAddress = this.getRegister('fp') this.setRegister('sp',framePointerAddress) this.stackFrameSize = this.pop() // get the last item which is stackFrameSize size const stackFrameSize = this.stackFrameSize this.setRegister('ip', this.pop()) this.setRegister('r8', this.pop()) this.setRegister('r7', this.pop()) this.setRegister('r6', this.pop()) this.setRegister('r5', this.pop()) this.setRegister('r4', this.pop()) this.setRegister('r3', this.pop()) this.setRegister('r2', this.pop()) this.setRegister('r1', this.pop()) const nArgs = this.pop() for(let i = 0;i < nArgs;i++){ this.pop() } this.setRegister('fp',framePointerAddress + stackFrameSize) } Change the View Memory function to check the more address in memory viewMemoryAt(address,n = 8) { // 0x0f01: 0x04 0x05 0xA3 0xFE 0x13 0x0D 0x44 0x0F const nextNBytes = Array.from({length: n}, (_, i) => this.memory.getUint8(address + i) ).map(v => `0x${v.toString(16).padStart(2, '0')}`); console.log(`0x${address.toString(16).padStart(4, '0')}: ${nextNBytes.join(' ')}`); } TEST the CAL and RET # define the subfunction started address const subroutineAddress = 0x3000 let i = 0 writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x33 writeBytes[i++] = 0x33 writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x22 writeBytes[i++] = 0x22 writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x11 writeBytes[i++] = 0x11 writeBytes[i++] = MOVE_LIT_REG writeBytes[i++] = 0x12 writeBytes[i++] = 0x34 writeBytes[i++] = R1 writeBytes[i++] = MOVE_LIT_REG writeBytes[i++] = 0x56 writeBytes[i++] = 0x78 writeBytes[i++] = R4 writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x00 writeBytes[i++] = 0x00 writeBytes[i++] = CAL_LIT writeBytes[i++] = (subroutineAddress & 0xff00) >> 8 writeBytes[i++] = (subroutineAddress & 0x00ff) writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x44 writeBytes[i++] = 0x44 i = subroutineAddress writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x01 writeBytes[i++] = 0x02 writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x03 writeBytes[i++] = 0x04 writeBytes[i++] = PSH_LIT writeBytes[i++] = 0x05 writeBytes[i++] = 0x06 writeBytes[i++] = MOVE_LIT_REG writeBytes[i++] = 0x07 writeBytes[i++] = 0x08 writeBytes[i++] = R1 writeBytes[i++] = MOVE_LIT_REG writeBytes[i++] = 0x09 writeBytes[i++] = 0x0A writeBytes[i++] = R8 writeBytes[i++] = RET cpu.debug() // ... /** 0xffff-1 為記憶體開頭 而往下還有44個字節因此減42 (從0開始) **/ cpu.viewMemoryAt(0xffff - 1 - 42,44) // ... rl.on('line',()=>{ // ... cpu.viewMemoryAt(0xffff - 1 - 42,44) })