mirror of
https://github.com/freewilll/apple2-go.git
synced 2024-12-22 04:29:28 +00:00
Added keyboard controller
This commit is contained in:
parent
7d64938630
commit
389773cb1d
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
22
cpu/cpu.go
22
cpu/cpu.go
@ -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
254
keyboard/keyboard.go
Normal 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
|
||||
}
|
17
mmu/mmu.go
17
mmu/mmu.go
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user