Added keyboard controller

This commit is contained in:
Will Angenent 2018-05-09 15:41:20 +01:00
parent 7d64938630
commit 389773cb1d
5 changed files with 300 additions and 1 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/hajimehoshi/ebiten/ebitenutil"
"mos6502go/cpu"
"mos6502go/keyboard"
"mos6502go/mmu"
"mos6502go/vid"
)
@ -49,6 +50,7 @@ func checkResetKeys() {
}
func update(screen *ebiten.Image) error {
keyboard.Poll()
checkResetKeys()
cpu.Run(&cpuState, *showInstructions, nil, *disableBell, 1024000/60)
@ -67,6 +69,9 @@ func main() {
cpuState.Memory = memory
cpuState.PageTable = &memory.PageTable
cpuState.Init()
keyboard.Init()
reset()
var err error

View File

@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"mos6502go/cpu"
"mos6502go/keyboard"
"mos6502go/mmu"
"mos6502go/utils"
)
@ -88,6 +89,8 @@ func main() {
breakAddress = &foo
}
keyboard.Init()
cpu.Run(&s, *showInstructions, breakAddress, false, 0)
fmt.Printf("Finished running %s\n\n", rom)
}

View File

@ -2,6 +2,7 @@ package cpu
import (
"fmt"
"mos6502go/keyboard"
"mos6502go/mmu"
"os"
)
@ -131,6 +132,23 @@ func pop16(s *State) uint16 {
func readMemory(s *State, address uint16) uint8 {
if (address >= 0xc000) && (address < 0xc100) {
if (address == mmu.KEYBOARD) || (address == mmu.STROBE) {
keyBoardData, strobe := keyboard.Read()
if address == mmu.KEYBOARD {
return keyBoardData
} else {
keyboard.ResetStrobe()
return strobe
}
} else if address == mmu.RDCXROM {
// using external slot ROM not implemented
return 0
} else if address == mmu.RD80VID {
// using 80-column display mode not implemented
return 0
}
fmt.Printf("TODO read %04x\n", address)
return 0
}
@ -166,7 +184,9 @@ func writeMemory(s *State, address uint16, value uint8) {
}
if address >= 0xc000 {
if address == mmu.CLRCXROM {
if address == mmu.STROBE {
keyboard.ResetStrobe()
} else if address == mmu.CLRCXROM {
mmu.MapFirstHalfOfIO(s.Memory)
} else if address == mmu.SETCXROM {
mmu.MapSecondHalfOfIO(s.Memory)

254
keyboard/keyboard.go Normal file
View File

@ -0,0 +1,254 @@
package keyboard
import (
"github.com/hajimehoshi/ebiten"
)
var ebitenAsciiMap map[ebiten.Key]uint8
var shiftMap map[uint8]uint8
var controlMap map[uint8]uint8
var keyBoardData uint8
var strobe uint8
var previousKeysPressed map[uint8]bool
func Init() {
keyBoardData = 0
strobe = 0
ebitenAsciiMap = make(map[ebiten.Key]uint8)
shiftMap = make(map[uint8]uint8)
controlMap = make(map[uint8]uint8)
previousKeysPressed = make(map[uint8]bool)
ebitenAsciiMap[ebiten.KeyLeft] = 8
ebitenAsciiMap[ebiten.KeyTab] = 9
ebitenAsciiMap[ebiten.KeyDown] = 10
ebitenAsciiMap[ebiten.KeyUp] = 11
ebitenAsciiMap[ebiten.KeyEnter] = 13
ebitenAsciiMap[ebiten.KeyRight] = 21
ebitenAsciiMap[ebiten.KeyEscape] = 27
ebitenAsciiMap[ebiten.KeyDelete] = 127
ebitenAsciiMap[ebiten.Key0] = '0'
ebitenAsciiMap[ebiten.Key1] = '1'
ebitenAsciiMap[ebiten.Key2] = '2'
ebitenAsciiMap[ebiten.Key3] = '3'
ebitenAsciiMap[ebiten.Key4] = '4'
ebitenAsciiMap[ebiten.Key5] = '5'
ebitenAsciiMap[ebiten.Key6] = '6'
ebitenAsciiMap[ebiten.Key7] = '7'
ebitenAsciiMap[ebiten.Key8] = '8'
ebitenAsciiMap[ebiten.Key9] = '9'
ebitenAsciiMap[ebiten.KeyA] = 'a'
ebitenAsciiMap[ebiten.KeyB] = 'b'
ebitenAsciiMap[ebiten.KeyC] = 'c'
ebitenAsciiMap[ebiten.KeyD] = 'd'
ebitenAsciiMap[ebiten.KeyE] = 'e'
ebitenAsciiMap[ebiten.KeyF] = 'f'
ebitenAsciiMap[ebiten.KeyG] = 'g'
ebitenAsciiMap[ebiten.KeyH] = 'h'
ebitenAsciiMap[ebiten.KeyI] = 'i'
ebitenAsciiMap[ebiten.KeyJ] = 'j'
ebitenAsciiMap[ebiten.KeyK] = 'k'
ebitenAsciiMap[ebiten.KeyL] = 'l'
ebitenAsciiMap[ebiten.KeyM] = 'm'
ebitenAsciiMap[ebiten.KeyN] = 'n'
ebitenAsciiMap[ebiten.KeyO] = 'o'
ebitenAsciiMap[ebiten.KeyP] = 'p'
ebitenAsciiMap[ebiten.KeyQ] = 'q'
ebitenAsciiMap[ebiten.KeyR] = 'r'
ebitenAsciiMap[ebiten.KeyS] = 's'
ebitenAsciiMap[ebiten.KeyT] = 't'
ebitenAsciiMap[ebiten.KeyU] = 'u'
ebitenAsciiMap[ebiten.KeyV] = 'v'
ebitenAsciiMap[ebiten.KeyW] = 'w'
ebitenAsciiMap[ebiten.KeyX] = 'x'
ebitenAsciiMap[ebiten.KeyY] = 'y'
ebitenAsciiMap[ebiten.KeyZ] = 'z'
ebitenAsciiMap[ebiten.KeyApostrophe] = '\''
ebitenAsciiMap[ebiten.KeyBackslash] = '\\'
ebitenAsciiMap[ebiten.KeyComma] = ','
ebitenAsciiMap[ebiten.KeyEqual] = '='
ebitenAsciiMap[ebiten.KeyGraveAccent] = '`'
ebitenAsciiMap[ebiten.KeyLeftBracket] = '['
ebitenAsciiMap[ebiten.KeyMinus] = '-'
ebitenAsciiMap[ebiten.KeyPeriod] = '.'
ebitenAsciiMap[ebiten.KeyRightBracket] = ']'
ebitenAsciiMap[ebiten.KeySemicolon] = ';'
ebitenAsciiMap[ebiten.KeySlash] = '/'
ebitenAsciiMap[ebiten.KeySpace] = ' '
shiftMap['1'] = '!'
shiftMap['2'] = '@'
shiftMap['3'] = '#'
shiftMap['4'] = '$'
shiftMap['5'] = '%'
shiftMap['6'] = '^'
shiftMap['7'] = '&'
shiftMap['8'] = '*'
shiftMap['9'] = '('
shiftMap['0'] = ')'
shiftMap['-'] = '_'
shiftMap['='] = '+'
shiftMap['a'] = 'A'
shiftMap['b'] = 'B'
shiftMap['c'] = 'C'
shiftMap['d'] = 'D'
shiftMap['e'] = 'E'
shiftMap['f'] = 'F'
shiftMap['g'] = 'G'
shiftMap['h'] = 'H'
shiftMap['i'] = 'I'
shiftMap['j'] = 'J'
shiftMap['k'] = 'K'
shiftMap['l'] = 'L'
shiftMap['m'] = 'M'
shiftMap['n'] = 'N'
shiftMap['o'] = 'O'
shiftMap['p'] = 'P'
shiftMap['q'] = 'Q'
shiftMap['r'] = 'R'
shiftMap['s'] = 'S'
shiftMap['t'] = 'T'
shiftMap['u'] = 'U'
shiftMap['v'] = 'V'
shiftMap['w'] = 'W'
shiftMap['x'] = 'X'
shiftMap['y'] = 'Y'
shiftMap['z'] = 'Z'
shiftMap[','] = '<'
shiftMap['.'] = '>'
shiftMap['/'] = '?'
shiftMap['`'] = '~'
shiftMap['['] = '{'
shiftMap[']'] = '}'
shiftMap[';'] = ':'
shiftMap['\''] = '"'
shiftMap['\\'] = '|'
shiftMap[' '] = ' '
controlMap['A'] = 'A' - 0x40
controlMap['B'] = 'B' - 0x40
controlMap['C'] = 'C' - 0x40
controlMap['D'] = 'D' - 0x40
controlMap['E'] = 'E' - 0x40
controlMap['F'] = 'F' - 0x40
controlMap['G'] = 'G' - 0x40
controlMap['H'] = 'H' - 0x40
controlMap['I'] = 'I' - 0x40
controlMap['J'] = 'J' - 0x40
controlMap['K'] = 'K' - 0x40
controlMap['L'] = 'L' - 0x40
controlMap['M'] = 'M' - 0x40
controlMap['N'] = 'N' - 0x40
controlMap['O'] = 'O' - 0x40
controlMap['P'] = 'P' - 0x40
controlMap['Q'] = 'Q' - 0x40
controlMap['R'] = 'R' - 0x40
controlMap['S'] = 'S' - 0x40
controlMap['T'] = 'T' - 0x40
controlMap['U'] = 'U' - 0x40
controlMap['V'] = 'V' - 0x40
controlMap['W'] = 'W' - 0x40
controlMap['X'] = 'X' - 0x40
controlMap['Y'] = 'Y' - 0x40
controlMap['Z'] = 'Z' - 0x40
controlMap[']'] = 0x5d
controlMap['`'] = 0x60
controlMap['a'] = 'a' - 0x60
controlMap['b'] = 'b' - 0x60
controlMap['c'] = 'c' - 0x60
controlMap['d'] = 'd' - 0x60
controlMap['e'] = 'e' - 0x60
controlMap['f'] = 'f' - 0x60
controlMap['g'] = 'g' - 0x60
controlMap['h'] = 'h' - 0x60
controlMap['i'] = 'i' - 0x60
controlMap['j'] = 'j' - 0x60
controlMap['k'] = 'k' - 0x60
controlMap['l'] = 'l' - 0x60
controlMap['m'] = 'm' - 0x60
controlMap['n'] = 'n' - 0x60
controlMap['o'] = 'o' - 0x60
controlMap['p'] = 'p' - 0x60
controlMap['q'] = 'q' - 0x60
controlMap['r'] = 'r' - 0x60
controlMap['s'] = 's' - 0x60
controlMap['t'] = 't' - 0x60
controlMap['u'] = 'u' - 0x60
controlMap['v'] = 'v' - 0x60
controlMap['w'] = 'w' - 0x60
controlMap['x'] = 'x' - 0x60
controlMap['y'] = 'y' - 0x60
controlMap['z'] = 'z' - 0x60
controlMap['}'] = 0x5d
controlMap['~'] = 0x60
}
// Poll queries ebiten's keyboard state and transforms that into apple //e
// values in $c000 and $c010
func Poll() {
allKeysPressed := make(map[uint8]bool)
newKeysPressed := make(map[uint8]bool)
for k, v := range ebitenAsciiMap {
if ebiten.IsKeyPressed(k) {
allKeysPressed[v] = true
_, present := previousKeysPressed[v]
if !present {
newKeysPressed[v] = true
}
}
}
previousKeysPressed = allKeysPressed
if len(allKeysPressed) == 0 {
// No keys are pressed, clear the strobe and return
strobe = keyBoardData & 0x7f
return
} else if len(newKeysPressed) == 0 {
// No new keys pressed, do nothing
return
} else if len(newKeysPressed) > 1 {
// More than one new keys pressed, do nothing
return
}
// Implicit else, one new key has been pressed
keys := []uint8{}
for k := range newKeysPressed {
keys = append(keys, k)
}
key := keys[0]
if ebiten.IsKeyPressed(ebiten.KeyShift) {
shiftedKey, present := shiftMap[key]
if present {
key = shiftedKey
}
}
if ebiten.IsKeyPressed(ebiten.KeyControl) {
controlKey, present := controlMap[key]
if present {
key = controlKey
}
}
keyBoardData = key | 0x80
strobe = keyBoardData
return
}
func Read() (uint8, uint8) {
return keyBoardData, strobe
}
func ResetStrobe() {
keyBoardData &= 0x7f
}

View File

@ -30,6 +30,23 @@ const (
CLRALTCH = 0xC00E // use alternate character set ROM
SETALTCH = 0xC00F
STROBE = 0xC010 // strobe (unlatch) keyboard data
RDLCBNK2 = 0xC011 // reading from LC bank $Dx 2
RDLCRAM = 0xC012 // reading from LC RAM
RDRAMRD = 0xC013 // reading from auxilliary 48K
RDRAMWR = 0xC014 // writing to auxilliary 48K
RDCXROM = 0xC015 // using external slot ROM
RDAUXZP = 0xC016 // using auxilliary ZP, stack, & LC
RDC3ROM = 0xC017 // using external slot C3 ROM
RD80COL = 0xC018 // using 80-column memory mapping
RDVBLBAR = 0xC019 // not VBL (VBL signal low)
RDTEXT = 0xC01A // using text mode
RDMIXED = 0xC01B // using mixed mode
RDPAGE2 = 0xC01C // using text/graphics page2
RDHIRES = 0xC01D // using Hi-res graphics mode
RDALTCH = 0xC01E // using alternate character set ROM
RD80VID = 0xC01F // using 80-column display mode
)
type PhysicalMemory struct {