diff --git a/README.md b/README.md index da3985f..4d9b587 100644 --- a/README.md +++ b/README.md @@ -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 "") + -consoleCardSlot int + slot for the host console card. -1 for none (default -1) -disk string file to load on the first disk drive (default "/dos33.dsk") -disk2Slot int diff --git a/apple2Setup.go b/apple2Setup.go index 9375dd2..d60f4cf 100644 --- a/apple2Setup.go +++ b/apple2Setup.go @@ -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 diff --git a/apple2main.go b/apple2main.go index ba1d488..6207de8 100644 --- a/apple2main.go +++ b/apple2main.go @@ -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, - "/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 { diff --git a/cardInOut.go b/cardInOut.go index e4b90ae..847c161 100644 --- a/cardInOut.go +++ b/cardInOut.go @@ -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