mirror of
https://github.com/bradford-hamilton/apple-1.git
synced 2024-05-31 14:41:29 +00:00
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:
parent
2bd748fccd
commit
8d6a0f8fd3
49
internal/vm/exec_funcs.go
Normal file
49
internal/vm/exec_funcs.go
Normal 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
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// op represents an operation. It includes the name of the op, it's 8 bit hexidecimal
|
// 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
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// interrupt, N Z C I D V
|
func (o op) getAddr(a *Appleone) (uint16, error) {
|
||||||
// push PC+2, push SR - - - 1 - -
|
switch o.addrMode {
|
||||||
func exec0x00(a *Appleone, o op) error {
|
// TODO: will these ever apply here?
|
||||||
// set processer status flag to BRK
|
// case accumulator:
|
||||||
a.cpu.ps = flagBreak
|
//
|
||||||
|
// case implied:
|
||||||
a.pushDWordToStack(a.cpu.pc + 1)
|
//
|
||||||
a.pushWordToStack(a.cpu.ps)
|
case absolute:
|
||||||
|
return a.nextDWord(), nil
|
||||||
a.cpu.ps |= flagDisableInterrupts
|
case absoluteXIndexed:
|
||||||
a.cpu.pc = uint16(a.mem[0xFFFF])<<8 | uint16(a.mem[0xFFFE])
|
return a.nextDWord() + uint16(a.cpu.x), nil
|
||||||
|
case absoluteYIndexed:
|
||||||
return nil
|
return a.nextDWord() + uint16(a.cpu.y), nil
|
||||||
}
|
case immediate:
|
||||||
|
return a.cpu.pc - 1, nil
|
||||||
// pull SR, pull PC N Z C I D V
|
case indirect:
|
||||||
// from stack
|
return uint16(a.nextWord()), nil
|
||||||
func exec0x40(a *Appleone, o op) error {
|
case indirectXIndexed:
|
||||||
a.cpu.ps = a.popStackWord()
|
addr := (uint16(a.nextWord()) + uint16(a.cpu.x)) & 0xFF
|
||||||
a.cpu.pc = a.popStackDWord()
|
return a.littleEndianToUint16(a.mem[addr+1], a.mem[addr]), nil
|
||||||
return nil
|
case indirectYIndexed:
|
||||||
}
|
addr := uint16(a.nextWord())
|
||||||
|
val := a.littleEndianToUint16(a.mem[addr+1], a.mem[addr])
|
||||||
func exec0xC6(a *Appleone, o op) error {
|
return val + uint16(a.cpu.y), nil
|
||||||
fmt.Println("Implement me")
|
case relative:
|
||||||
return nil
|
return a.cpu.pc - 1, nil
|
||||||
}
|
case zeroPage:
|
||||||
|
return uint16(a.nextWord()) & 0xFF, nil
|
||||||
func todo(a *Appleone, o op) error {
|
case zeroPageXIndexed:
|
||||||
fmt.Println("implement me")
|
return (uint16(a.nextWord()) + uint16(a.cpu.x)) & 0xFF, nil
|
||||||
return 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
|
// 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 DEC oper CE 3 6
|
||||||
// absolute,X DEC oper,X DE 3 7
|
// absolute,X DEC oper,X DE 3 7
|
||||||
0xC6: newOp("DEC", 0xC6, 2, zeroPage, exec0xC6),
|
0xC6: newOp("DEC", 0xC6, 2, zeroPage, exec0xC6),
|
||||||
0xD6: newOp("DEC", 0xD6, 2, zeroPageXIndexed, todo),
|
0xD6: newOp("DEC", 0xD6, 2, zeroPageXIndexed, exec0xC6),
|
||||||
0xCE: newOp("DEC", 0xCE, 3, absolute, todo),
|
0xCE: newOp("DEC", 0xCE, 3, absolute, exec0xC6),
|
||||||
0xDE: newOp("DEC", 0xDE, 3, absoluteXIndexed, todo),
|
0xDE: newOp("DEC", 0xDE, 3, absoluteXIndexed, exec0xC6),
|
||||||
|
|
||||||
// INC Increment Memory by One
|
// INC Increment Memory by One
|
||||||
// addressing assembler opc bytes cyles
|
// addressing assembler opc bytes cyles
|
||||||
|
|
|
@ -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
|
// pushWordToStack pushes the given word (byte) into memory and sets the new stack pointer
|
||||||
func (a *Appleone) pushWordToStack(b byte) {
|
func (a *Appleone) pushWordToStack(b byte) {
|
||||||
a.mem[StackBottom+uint16(a.cpu.sp)] = b
|
a.mem[StackBottom+uint16(a.cpu.sp)] = b
|
||||||
|
@ -62,3 +66,43 @@ func (a *Appleone) popStackDWord() uint16 {
|
||||||
h := a.popStackWord()
|
h := a.popStackWord()
|
||||||
return (uint16(h) << 8) | uint16(l)
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user