internal/vm: start playing with op executions

So far the pattern feels a tiny bit weird but also has been nice to work
with. As you can see, the op now contains it’s instruction execution func
which can be called directly from the op.
This commit is contained in:
Bradford Lamson-Scribner 2020-05-30 17:06:14 -06:00
parent 2bd748fccd
commit 8d6a0f8fd3
3 changed files with 131 additions and 35 deletions

49
internal/vm/exec_funcs.go Normal file
View File

@ -0,0 +1,49 @@
package vm
import "fmt"
func todo(a *Appleone, o op) error {
fmt.Println("implement me")
return nil
}
// interrupt, N Z C I D V
// push PC+2, push SR - - - 1 - -
func exec0x00(a *Appleone, o op) error {
// set processer status flag to BRK
a.cpu.ps = flagBreak
a.pushDWordToStack(a.cpu.pc + 1)
a.pushWordToStack(a.cpu.ps)
a.cpu.ps |= flagDisableInterrupts
a.cpu.pc = uint16(a.mem[0xFFFF])<<8 | uint16(a.mem[0xFFFE])
return nil
}
// pull SR, pull PC N Z C I D V
// from stack
func exec0x40(a *Appleone, o op) error {
a.cpu.ps = a.popStackWord()
a.cpu.pc = a.popStackDWord()
return nil
}
// M - 1 -> M N Z C I D V
// + + - - - -
func exec0xC6(a *Appleone, o op) error {
addr, err := o.getAddr(a)
if err != nil {
return err
}
b := a.mem[addr]
b--
a.mem[addr] = b
a.setZeroIfNeeded(b)
a.setNegativeIfOverflow(b)
return nil
}

View File

@ -2,7 +2,6 @@ package vm
import (
"errors"
"fmt"
)
// op represents an operation. It includes the name of the op, it's 8 bit hexidecimal
@ -34,37 +33,41 @@ func opByCode(b byte) (op, error) {
return o, nil
}
// interrupt, N Z C I D V
// push PC+2, push SR - - - 1 - -
func exec0x00(a *Appleone, o op) error {
// set processer status flag to BRK
a.cpu.ps = flagBreak
a.pushDWordToStack(a.cpu.pc + 1)
a.pushWordToStack(a.cpu.ps)
a.cpu.ps |= flagDisableInterrupts
a.cpu.pc = uint16(a.mem[0xFFFF])<<8 | uint16(a.mem[0xFFFE])
return nil
}
// pull SR, pull PC N Z C I D V
// from stack
func exec0x40(a *Appleone, o op) error {
a.cpu.ps = a.popStackWord()
a.cpu.pc = a.popStackDWord()
return nil
}
func exec0xC6(a *Appleone, o op) error {
fmt.Println("Implement me")
return nil
}
func todo(a *Appleone, o op) error {
fmt.Println("implement me")
return nil
func (o op) getAddr(a *Appleone) (uint16, error) {
switch o.addrMode {
// TODO: will these ever apply here?
// case accumulator:
//
// case implied:
//
case absolute:
return a.nextDWord(), nil
case absoluteXIndexed:
return a.nextDWord() + uint16(a.cpu.x), nil
case absoluteYIndexed:
return a.nextDWord() + uint16(a.cpu.y), nil
case immediate:
return a.cpu.pc - 1, nil
case indirect:
return uint16(a.nextWord()), nil
case indirectXIndexed:
addr := (uint16(a.nextWord()) + uint16(a.cpu.x)) & 0xFF
return a.littleEndianToUint16(a.mem[addr+1], a.mem[addr]), nil
case indirectYIndexed:
addr := uint16(a.nextWord())
val := a.littleEndianToUint16(a.mem[addr+1], a.mem[addr])
return val + uint16(a.cpu.y), nil
case relative:
return a.cpu.pc - 1, nil
case zeroPage:
return uint16(a.nextWord()) & 0xFF, nil
case zeroPageXIndexed:
return (uint16(a.nextWord()) + uint16(a.cpu.x)) & 0xFF, nil
case zeroPageYIndexed:
return (uint16(a.nextWord()) + uint16(a.cpu.y)) & 0xFF, nil
default:
return 0, errors.New("unkown addressing mode")
}
}
// opcodes represent all of the Apple 1 opcodes available. Each 8 bit opcode is mapped to a corresponding
@ -90,9 +93,9 @@ var opcodes = map[uint8]op{
// absolute DEC oper CE 3 6
// absolute,X DEC oper,X DE 3 7
0xC6: newOp("DEC", 0xC6, 2, zeroPage, exec0xC6),
0xD6: newOp("DEC", 0xD6, 2, zeroPageXIndexed, todo),
0xCE: newOp("DEC", 0xCE, 3, absolute, todo),
0xDE: newOp("DEC", 0xDE, 3, absoluteXIndexed, todo),
0xD6: newOp("DEC", 0xD6, 2, zeroPageXIndexed, exec0xC6),
0xCE: newOp("DEC", 0xCE, 3, absolute, exec0xC6),
0xDE: newOp("DEC", 0xDE, 3, absoluteXIndexed, exec0xC6),
// INC Increment Memory by One
// addressing assembler opc bytes cyles

View File

@ -36,6 +36,10 @@ func (a *Appleone) step() {
}
}
func (a *Appleone) littleEndianToUint16(big, little uint8) uint16 {
return uint16(a.mem[big])<<8 | uint16(a.mem[little])
}
// pushWordToStack pushes the given word (byte) into memory and sets the new stack pointer
func (a *Appleone) pushWordToStack(b byte) {
a.mem[StackBottom+uint16(a.cpu.sp)] = b
@ -62,3 +66,43 @@ func (a *Appleone) popStackDWord() uint16 {
h := a.popStackWord()
return (uint16(h) << 8) | uint16(l)
}
// nextWord returns the next byte in memory
func (a *Appleone) nextWord() uint8 {
return a.mem[a.cpu.pc-1]
}
// nextDWord returns the next two bytes (double word)
func (a *Appleone) nextDWord() uint16 {
return a.littleEndianToUint16(a.mem[a.cpu.pc-1], a.mem[a.cpu.pc-2])
}
func (a *Appleone) setZeroIfNeeded(word uint8) {
a.clearZero()
if word == 0 {
a.setZero()
}
}
func (a *Appleone) setZero() {
a.cpu.ps |= flagZero
}
func (a *Appleone) clearZero() {
a.cpu.sp &^= flagZero
}
func (a *Appleone) setNegativeIfOverflow(word uint8) {
a.clearNegative()
if word > 127 {
a.setNegative()
}
}
func (a *Appleone) setNegative() {
a.cpu.ps |= flagZero
}
func (a *Appleone) clearNegative() {
a.cpu.sp &^= flagZero
}