VicturalMachine(2)
the stack from the machine
Definition 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)
})