134 lines
3.2 KiB
Go
134 lines
3.2 KiB
Go
package creature
|
|
|
|
type Machine struct {
|
|
Program []int
|
|
stack []int
|
|
block []int
|
|
counter int
|
|
pointer int
|
|
}
|
|
|
|
// Execute starts execution at the address specified by offset. The machine will
|
|
// run until a HALT instruction is encountered, or the end of program memory is
|
|
// reached.
|
|
func (machine *Machine) Execute (offset int) {
|
|
machine.counter = offset
|
|
|
|
for {
|
|
switch machine.instruction() {
|
|
case 0x0:
|
|
// PUSH
|
|
// push the next word in program memory onto the stack
|
|
machine.counter ++
|
|
machine.Push(machine.instruction())
|
|
|
|
case 0x1:
|
|
// POP
|
|
// pop the top word off of the stack, and discard it
|
|
machine.Pop()
|
|
|
|
case 0x2:
|
|
// LOAD
|
|
// push the word at an address onto the stack
|
|
machine.Push(machine.Peek(machine.Pop()))
|
|
|
|
case 0x3:
|
|
// STOR
|
|
// store a word at an address
|
|
machine.Poke(machine.Pop(), machine.Pop())
|
|
|
|
case 0x4:
|
|
// ADD
|
|
// adds the last two words on the stack
|
|
machine.Push(machine.Pop() + machine.Pop())
|
|
|
|
case 0x5:
|
|
// SUB
|
|
// subtracts the second to last word on the stack from
|
|
// the last word on the stack
|
|
machine.Push(machine.Pop() - machine.Pop())
|
|
|
|
case 0x6:
|
|
// MUL
|
|
// multiplies the last two words on the stack
|
|
machine.Push(machine.Pop() * machine.Pop())
|
|
|
|
case 0x7:
|
|
// DIV
|
|
// divides the last word on the stack by the second to
|
|
// last word on the stack
|
|
machine.Push(machine.Pop() / machine.Pop())
|
|
|
|
case 0x8:
|
|
// EQU
|
|
// checks if the last two words on the stack are equal
|
|
|
|
case 0x9:
|
|
case 0xa:
|
|
case 0xb:
|
|
case 0xc:
|
|
case 0xd:
|
|
case 0xe:
|
|
case 0xf:
|
|
}
|
|
machine.counter ++
|
|
}
|
|
}
|
|
|
|
// Instruction returns the current instruction in program memory.
|
|
func (machine *Machine) instruction () (instruction int) {
|
|
instruction = machine.Program[machine.counter]
|
|
return
|
|
}
|
|
|
|
// reallocateStack changes the size of the stack to something reasonable. This
|
|
// should be called then the stack pointer is really small compared to the
|
|
// actual stack size, or the stack pointer is bigger than the stack.
|
|
func (machine *Machine) reallocateStack () {
|
|
reallocatedStack := make([]int, machine.pointer * 3 / 2)
|
|
copy(reallocatedStack, machine.stack)
|
|
machine.stack = reallocatedStack
|
|
}
|
|
|
|
// Push pushes a word onto the stack, increasing the stack pointer and
|
|
// reallocating the stack if necessary.
|
|
func (machine *Machine) Push (word int) {
|
|
machine.pointer ++
|
|
if len(machine.stack) <= machine.pointer {
|
|
machine.reallocateStack()
|
|
}
|
|
}
|
|
|
|
// Pop pops the last word off of the stack, and returns it, decreasing the stack
|
|
// pointer and reallocating the stack if necessary.
|
|
func (machine *Machine) Pop () (word int) {
|
|
word = machine.stack[machine.pointer]
|
|
machine.pointer --
|
|
|
|
if machine.pointer < len(machine.stack) / 3 {
|
|
machine.reallocateStack()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Peek returns the word at address in the block
|
|
func (machine *Machine) Peek (address int) (word int) {
|
|
if address < len(machine.block) {
|
|
word = machine.block[address]
|
|
}
|
|
return
|
|
}
|
|
|
|
// Poke sets the value at address in the block to word
|
|
func (machine *Machine) Poke (address int, word int) {
|
|
if address >= len(machine.block) {
|
|
reallocatedBlock := make([]int, address * 3 / 2)
|
|
copy(reallocatedBlock, machine.block)
|
|
machine.block = reallocatedBlock
|
|
}
|
|
}
|
|
|
|
// Milk milks the stack machine
|
|
func (machine *Machine) Milk () {}
|