Card to bridge PR# and IN# to the host terminal

This commit is contained in:
Ivan Izaguirre 2021-01-24 16:56:06 +01:00
parent 89881a8466
commit 8b50ae1500
4 changed files with 122 additions and 104 deletions

View File

@ -24,11 +24,14 @@ Portable emulator of an Apple II+ or //e. Written in Go.
- 1Mb Memory Expansion Card (slinky)
- RAMWorks style expansion Card (up to 16MB additional) (Apple //e only)
- ThunderClock Plus real time clock
- Bootable Smartport / ProDOS card
- Apple //e 80 columns with 64Kb extra RAM and optional RGB modes
- No Slot Clock based on the DS1216
- Useful cards not emulating a real card
- Bootable Smartport / ProDOS card
- VidHd, limited to the ROM signature and SHR as used by Total Replay, only for //e models with 128Kb
- FASTChip, limited to what Total Replay needs to set and clear fast mode
- No Slot Clock based on the DS1216
- Host console card. Maps the host STDIN and STDOUT to PR# and IN#
- Graphic modes:
- Text 40 columns
- Text 80 columns (Apple //e only)
@ -164,6 +167,8 @@ Only valid on SDL mode
```terminal
-charRom string
rom file for the character generator (default "<default>")
-consoleCardSlot int
slot for the host console card. -1 for none (default -1)
-disk string
file to load on the first disk drive (default "<internal>/dos33.dsk")
-disk2Slot int

View File

@ -149,10 +149,8 @@ func (a *Apple2) AddMemoryExpansionCard(slot int) {
}
// AddThunderClockPlusCard inserts a ThunderClock Plus clock card
func (a *Apple2) AddThunderClockPlusCard(slot int, romFile string) error {
c := NewCardThunderClockPlus()
a.insertCard(c, slot)
return nil
func (a *Apple2) AddThunderClockPlusCard(slot int) {
a.insertCard(NewCardThunderClockPlus(), slot)
}
// AddRGBCard inserts an RBG option to the Apple IIe 80 col 64KB card

View File

@ -75,6 +75,10 @@ func MainApple() *Apple2 {
"thunderClockCardSlot",
4,
"slot for the ThunderClock Plus card. -1 for none")
consoleCardSlot := flag.Int(
"consoleCardSlot",
-1,
"slot for the host console card. -1 for none")
nsc := flag.Int(
"nsc",
-1,
@ -235,15 +239,14 @@ func MainApple() *Apple2 {
a.AddMemoryExpansionCard(*memoryExpansionCardSlot)
}
if *thunderClockCardSlot > 0 {
err := a.AddThunderClockPlusCard(*thunderClockCardSlot,
"<internal>/ThunderclockPlusROM.bin")
if err != nil {
panic(err)
}
a.AddThunderClockPlusCard(*thunderClockCardSlot)
}
if *vidHDCardSlot >= 0 {
a.AddVidHD(*vidHDCardSlot)
}
if *consoleCardSlot >= 0 {
a.AddCardInOut(*consoleCardSlot)
}
if *smartPortImage != "" {
err := a.AddSmartPortDisk(5, *smartPortImage, *traceHD)
@ -294,7 +297,6 @@ func MainApple() *Apple2 {
}
// a.AddRomX()
// a.AddCardInOut(2)
// a.AddCardLogger(4)
if *dumpChars {

View File

@ -1,7 +1,9 @@
package izapple2
import (
"bufio"
"fmt"
"os"
)
/*
@ -11,12 +13,15 @@ See:
"Apple II Monitors peeled."
http://mysite.du.edu/~etuttle/math/acia.htm
PR#n stores Cn00 in CSWL and CSWH
IN#n stores Cn00 in KSWL and KSWH
*/
// CardInOut is an experimental card to bridge with the host
// CardInOut is an experimental card to bridge with the host console
type CardInOut struct {
cardBase
i int
reader *bufio.Reader
}
// NewCardInOut creates CardInOut
@ -27,129 +32,137 @@ func NewCardInOut() *CardInOut {
}
func (c *CardInOut) assign(a *Apple2, slot int) {
for i := uint8(0x0); i <= 0xf; i++ {
iCopy := i
c.addCardSoftSwitchR(i, func(*ioC0Page) uint8 {
value := []uint8{0xc1, 0xc1, 0x93, 0x0}[c.i%4]
c.i++
fmt.Printf("[cardInOut] Read access to softswith 0x%x for slot %v, value %x.\n", iCopy, slot, value)
//return 0x41 + 0x80
return []uint8{0x41, 0x41, 0x13}[i%3] + 0x80
}, "INOUTR")
c.addCardSoftSwitchW(i, func(_ *ioC0Page, value uint8) {
fmt.Printf("[cardInOut] Write access to softswith 0x%x for slot %v, value 0x%x.\n", iCopy, slot, value)
}, "INOUTW")
}
c.addCardSoftSwitchR(0, func(*ioC0Page) uint8 {
if c.reader == nil {
c.reader = bufio.NewReader(os.Stdin)
}
value, err := c.reader.ReadByte()
in := true
out := false
if err != nil {
panic(err)
}
value += 0x80
if value&0x7f == 10 {
value = 13 + 0x80
}
//fmt.Printf("[cardInOut] Read access to softswith 0x%x for slot %v, value %x.\n", 0, slot, value)
return value
}, "INOUTR")
c.addCardSoftSwitchW(1, func(_ *ioC0Page, value uint8) {
//fmt.Printf("[cardInOut] Write access to softswith 0x%x for slot %v, value 0x%x: %v, %v.\n", 1, slot, value, value&0x7f, string(value&0x7f))
if value&0x7f == 13 {
fmt.Printf("\n")
} else {
fmt.Printf("%v", string(value&0x7f))
}
}, "INOUTW")
data := [256]uint8{
// Register
0xA9, 0xC2,
0x85, 0x37,
0x85, 0x39,
0xA9, 0x10,
0x85, 0x36,
0xA9, 0x15,
0x85, 0x38,
0x60, 0xEA,
0x4c, 0x40, 0xc2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// Out char
0x8D, 0xA1, 0xC0,
0x60, 0xEA,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Get char
0x91, 0x28,
0xAD, 0xA0, 0xC0,
0x60,
0x48, 0xA5, 0x38, 0xD0, 0x12, 0xA9, 0xC2, 0xC5,
0x39, 0xD0, 0x0C, 0xAD, 0x50, 0x00, 0x85, 0x38,
0x68, 0x91, 0x28, 0xAD, 0xA0, 0xC0, 0x60, 0x68,
0x8D, 0xA1, 0xC0, 0x60,
}
if !out {
// NOP the CSWL,H change
for _, v := range []uint8{2, 3, 8, 9} {
data[v] = 0xEA
}
}
c.romCsxx = newMemoryRangeROM(0xC200, data[:], "InOUt card")
if !in {
// NOP the KSWL,H change
for _, v := range []uint8{4, 5, 12, 13} {
data[v] = 0xEA
}
}
// Fix slot dependant addresses
data[0x02] = uint8(0xc0 + slot)
data[0x46] = uint8(0xc0 + slot)
data[0x54] = uint8(0x80 + slot<<4)
data[0x59] = uint8(0x81 + slot<<4)
c.romCsxx = newMemoryRangeROM(0xC200, data[0:255], "InOUt card")
if slot != 2 {
// To make it work on other slots, patch C2, A0 and A1
panic("Assert failed. Only slot 2 supported for the InOut card")
}
c.cardBase.assign(a, slot)
}
/*
The ROM code was assembled using https://www.masswerk.at/6502/assembler.html
We will have $Cn00 as the entry point for CSWL/H. But before doing
anything we have to check that we are not in $Cn00 because of an IN#.
To da that we check id KSWL/H is $Cn00, it is it we wif it to INEntry.
src:
BASL = $28
CSWL = $36
CSWH = $37
KSWL = $38
KSWH = $39
* = $C200
Register:
Entry:
JMP SkipHeader
* = $C240
SkipHeader:
PHA
LDA *KSWL
BNE PREntry
LDA #$C2
STA *CSWH
STA *KSWH
LDA #$10
STA *CSWL
LDA #$15
CMP *KSWH
BNE PREntry
FixKSWL:
LDA <INEntry
STA *KSWL
RTS
NOP
OutChar:
STA $C0A1
RTS
NOP
GetChar:
INEntry:
PLA
STA (BASL),Y
LDA $C0A0
RTS
PREntry:
PLA
STA $C0A1
RTS
assembled as:
Listing:
pass 2
0000 BASL = 0028
0000 CSWL = 0036
0000 CSWH = 0037
0000 KSWL = 0038
0000 KSWH = 0039
* = $C200
C200 REGIST
C200 LDA #$C2 A9 C2
C202 STA *CSWH 85 37
C204 STA *KSWH 85 39
C206 LDA #$10 A9 10
C208 STA *CSWL 85 36
C20A LDA #$15 A9 15
C20C STA *KSWL 85 38
C20E RTS 60
C20F NOP EA
C210 OUTCHA
C210 STA $C0A1 8D A1 C0
C213 RTS 60
C214 NOP EA
C215 GETCHA
C215 STA (BASL),Y 91 28
C217 LDA $C0A0 AD A0 C0
C21A RTS
* = $C200
C200 ENTRY:
C200 JMP SKIPHE 4C 40 C2
object code:
A9 C2 85 37 85 39 A9 10
85 36 A9 15 85 38 60 EA
8D A1 C0 60 EA 91 28 AD
A0 C0 60
* = $C240
C240 SKIPHE
C240 PHA 48
C241 LDA *KSWL A5 38
C243 BNE PRENTR D0 12
C245 LDA #$C2 A9 C2
C247 CMP *KSWH C5 39
C249 BNE PRENTR D0 0C
C24B FIXKSW
C24B LDA <INENTR AD 50 00
C24E STA *KSWL 85 38
C250 INENTR
C250 PLA 68
C251 STA (BASL),Y 91 28
C253 LDA $C0A0 AD A0 C0
C256 RTS 60
C257 PRENTR
C257 PLA 68
C258 STA $C0A1 8D A1 C0
C25B RTS 60
done.
Object Code:
c200:
4C 40 C2
c240:
48 A5 38 D0 12
A9 C2 C5 39 D0 0C AD 50
00 85 38 68 91 28 AD A0
C0 60 68 8D A1 C0 60
*/