Swyftcard support (#13)

This commit is contained in:
Iván Izaguirre 2022-03-08 20:11:26 +01:00 committed by GitHub
parent fe15ce8c93
commit 1e32421c86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 223 additions and 12 deletions

View File

@ -191,6 +191,12 @@ func (a *Apple2) AddVidexCard(slot int) {
a.softVideoSwitch = NewSoftVideoSwitch(c)
}
// AddSwyftCard inserts a Swyft card in slot 3
func (a *Apple2) AddSwyftCard() {
c := NewCardSwyft()
a.insertCard(c, 3)
}
// AddRGBCard inserts an RBG option to the Apple IIe 80 col 64KB card
func (a *Apple2) AddRGBCard() {
setupRGBCard(a)

View File

@ -35,3 +35,7 @@ func (at *apple2Tester) run() {
func (at *apple2Tester) getText() string {
return screen.RenderTextModeString(at.a, false, false, false, at.a.isApple2e)
}
func (at *apple2Tester) getText80() string {
return screen.RenderTextModeString(at.a, true, false, false, at.a.isApple2e)
}

View File

@ -18,7 +18,7 @@ func MainApple() *Apple2 {
"slot for the disk driver. -1 for none.")
diskImage := flag.String(
"disk",
"<internal>/dos33.dsk",
defaultInternal,
"file to load on the first disk drive")
diskBImage := flag.String(
"diskb",
@ -84,6 +84,10 @@ func MainApple() *Apple2 {
"videxCardSlot",
3,
"slot for the Videx Videoterm 80 columns card. For pre-2e models. -1 for none")
swyftCard := flag.Bool(
"swyftCard",
false,
"activate a Swyft Card in slot 3. Load the tutorial disk if none provided")
nsc := flag.Int(
"nsc",
-1,
@ -169,6 +173,15 @@ func MainApple() *Apple2 {
}
}
// Resolve what is the default disk to use if not specified
if diskImageFinal == defaultInternal {
if *swyftCard {
diskImageFinal = "<internal>/SwyftWare_-_SwyftCard_Tutorial.woz"
} else {
diskImageFinal = "<internal>/dos33.dsk"
}
}
a := newApple2()
a.setup(*cpuClock, *fastDisk)
a.io.setTrace(*traceSS)
@ -232,6 +245,12 @@ func MainApple() *Apple2 {
if *videxCardSlot > 0 {
a.AddVidexCard(*videxCardSlot)
}
if *swyftCard {
if !a.isApple2e {
panic("SwyftCard available only on Apple IIe or better")
}
a.AddSwyftCard()
}
if *smartPortImage != "" {
err := a.AddSmartPortDisk(5, *smartPortImage, *traceHD)
@ -354,7 +373,7 @@ func initModel(a *Apple2, model string, romFile string, charRomFile string) {
panic("Model not supported")
}
// Load ROM if not loaded already
// Load ROM
if romFile != "" {
err := a.LoadRom(romFile)
if err != nil {
@ -362,7 +381,7 @@ func initModel(a *Apple2, model string, romFile string, charRomFile string) {
}
}
// Load character generator if it loaded already
// Load character generator
cg, err := newCharacterGenerator(charRomFile, charGenMap, a.isApple2e)
if err != nil {
panic(err)

View File

@ -114,6 +114,16 @@ func (c *cardBase) addCardSoftSwitchW(address uint8, ss softSwitchW, name string
c._sswName[address] = name
}
func (c *cardBase) addCardSoftSwitchRW(address uint8, ss softSwitchR, name string) {
c._ssr[address] = ss
c._ssrName[address] = name
c._ssw[address] = func(p *ioC0Page, _ uint8) {
ss(p)
}
c._sswName[address] = name
}
type softSwitches func(io *ioC0Page, address uint8, data uint8, write bool) uint8
func (c *cardBase) addCardSoftSwitches(sss softSwitches, name string) {

133
cardSwyft.go Normal file
View File

@ -0,0 +1,133 @@
package izapple2
/*
Swyft card for Apple IIe
See:
https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Other/IAI%20SwyftCard/
*/
/*
"SwyftCard Hardware Theory of Operation". SwyftCard manual, page 98:
The SwyftCard is a plug-in card for the Apple /Ie that operates in
slot 3. The card contains three integrated circuits which provide a
power-on reset circuit, storage for the SwyftCard program, and control
signals for the card. The card operates by asserting the Apple IIe bus
signal INH' which disables the built-in ROM and enables the SwyftCard
ROM. This permits the SwyftCard program to take over the system at
power-on and run the SwyftCard program. (Please refer to the
schematic.)
The lM311 voltage comparator is connected to provide the power-on
reset function. When the Apple lie is first turned on, the power-on
reset circuit resets the PAL, turning on the SwyftCard and disabling
the Apple IIe internal ROM. The power-on reset circuit must be
provided because the existing Apple IIe reset function is used by
many Apple lie programs for a "warm start": if Apple lie reset always
started the SwyftCard, other programs could not use the "warm start."
The 27128 PROM is used to store the SwyftCard program. The PROM
contains 16384 bytes which are mapped into the address space
$DOOO - $FFFF. Since the address space is only 12 Kbytes, there are
two 4 Kbyte sections of the PROM mapped into the address space
$DOOO-$DFFF.
The card is controlled by the PAL. When the SwyftCard is active, the
PAL asserts the INH' signal, enables the PROM, and bank switches
the $DOOO-$DFFF address space. The card is controlled by two soft
switches. The soft switches are controlled by accessing the following
memory locations with either a read or a write operation.
$COBO - SwyftCard active, Bank 1
$COB1 - SwyftCard inactive, Bank 1
$COB2 - SwyftCard active, Bank 2
When the power-on reset circuit asserts the RES signal on Pin 3 of the
PAL, the SwyftCard is made active in Bank 1. Accessing location
$COB1 deactivates the SwyftCard for normal Apple IIe operation.
The INH' line is driven by a tri-state driver, so if another card in the
Apple /Ie asserts the IINH' signal there will not be a bus contention.
However, there will be a bus contention on the data bus if another card
attempts to control the bus while the SwyftCard is active.
*/
// CardSwyft represents a Swyft card
type CardSwyft struct {
cardBase
bank2 bool
rom []uint8
}
// NewCardSwyft creates a new CardSwyft
func NewCardSwyft() *CardSwyft {
var c CardSwyft
c.name = "SwyftCard"
// The Cx00 rom is not used. The card is expected to be installed in
// slot 3 of an Apple IIe with the 80 column firmware already present.
return &c
}
func (c *CardSwyft) assign(a *Apple2, slot int) {
// Load main ROM replacement
data, _, err := LoadResource("<internal>/SwyftCard ROM.bin")
if err != nil {
// The resource should be internal and never fail
panic(err)
}
c.rom = data
c.addCardSoftSwitchRW(0, func(*ioC0Page) uint8 {
a.mmu.inhibitROM(c)
c.bank2 = false
return 0x55
}, "SWYFTONBANK1")
c.addCardSoftSwitchRW(1, func(*ioC0Page) uint8 {
a.mmu.inhibitROM(nil)
c.bank2 = false
return 0x55
}, "SWYFTOFFBANK1")
c.addCardSoftSwitchRW(2, func(*ioC0Page) uint8 {
a.mmu.inhibitROM(c)
c.bank2 = true
return 0x55
}, "SWYFTONBANK2")
c.cardBase.assign(a, slot)
a.mmu.inhibitROM(c)
}
func (c *CardSwyft) translateAddress(address uint16) uint16 {
/*
The four 4k sections of the 16k ROM image are mapped:
D000-DFFF (page 1)
D000-DFFF (page 2)
E000-EFFF
F000-FFFF
*/
if address >= 0xE000 {
return address - 0xE000 + 0x2000
}
if !c.bank2 {
return address - 0xD000
}
return address - 0xD000 + 0x1000
}
func (c *CardSwyft) peek(address uint16) uint8 {
return c.rom[c.translateAddress(address)]
}
func (c *CardSwyft) poke(address uint16, value uint8) {
// Nothing
}
func (c *CardSwyft) setBase(base uint16) {
// Nothing
}

26
cardSwyft_test.go Normal file
View File

@ -0,0 +1,26 @@
package izapple2
import (
"strings"
"testing"
)
func TestSwyftTutorial(t *testing.T) {
at := makeApple2Tester("2e")
at.a.AddSwyftCard()
err := at.a.AddDisk2(6, "<internal>/SwyftWare_-_SwyftCard_Tutorial.woz", "", nil)
if err != nil {
panic(err)
}
at.terminateCondition = func(a *Apple2) bool {
return a.cpu.GetCycles() > 10_000_000
}
at.run()
text := at.getText80()
if !strings.Contains(text, "HOW TO USE SWYFTCARD") {
t.Errorf("Expected 'HOW TO USE SWYFTCARD', got '%s'", text)
}
}

View File

@ -33,15 +33,16 @@ type memoryManager struct {
lcAltBank bool // Alternate
// Configuration switches, Apple //e
altZeroPage bool // Use extra RAM from 0x0000 to 0x01ff. And additional language card block
altMainRAMActiveRead bool // Use extra RAM from 0x0200 to 0xbfff for read
altMainRAMActiveWrite bool // Use extra RAM from 0x0200 to 0xbfff for write
store80Active bool // Special pagination for text and graphics areas
slotC3ROMActive bool // Apple2e slot 3 ROM shadow
intCxROMActive bool // Apple2e slots internal ROM shadow
intC8ROMActive bool // C8Rom associated to the internal slot 3. Softswitch not directly accessible. See UtA2e 5-28
activeSlot uint8 // Active slot owner of 0xc800 to 0xcfff
extendedRAMBlock uint8 // Block used for entended memory for RAMWorks cards
altZeroPage bool // Use extra RAM from 0x0000 to 0x01ff. And additional language card block
altMainRAMActiveRead bool // Use extra RAM from 0x0200 to 0xbfff for read
altMainRAMActiveWrite bool // Use extra RAM from 0x0200 to 0xbfff for write
store80Active bool // Special pagination for text and graphics areas
slotC3ROMActive bool // Apple2e slot 3 ROM shadow
intCxROMActive bool // Apple2e slots internal ROM shadow
intC8ROMActive bool // C8Rom associated to the internal slot 3. Softswitch not directly accessible. See UtA2e 5-28
activeSlot uint8 // Active slot owner of 0xc800 to 0xcfff
extendedRAMBlock uint8 // Block used for entended memory for RAMWorks cards
mainROMinhibited memoryHandler // Alternative ROM from 0xd000 to 0xffff provided by a card with the INH signal.
// Configuration switches, Base64A
romPage uint8 // Active ROM page
@ -151,6 +152,12 @@ func (mmu *memoryManager) getVideoRAM(ext bool) *memoryRange {
return mmu.physicalMainRAM
}
func (mmu *memoryManager) inhibitROM(replacement memoryHandler) {
// If a card INH the ROM, it replaces the ROM and the LC RAM
mmu.mainROMinhibited = replacement
mmu.lastAddressPage = invalidAddressPage // Invalidate cache
}
func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
if address <= addressLimitZero {
return mmu.getPhysicalMainRAM(mmu.altZeroPage)
@ -175,6 +182,9 @@ func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
if address <= addressLimitSlotsExtra {
return mmu.accessCArea(address)
}
if mmu.mainROMinhibited != nil {
return mmu.mainROMinhibited
}
if mmu.lcActiveRead {
return mmu.accessUpperRAMArea(address)
}
@ -205,6 +215,9 @@ func (mmu *memoryManager) accessWrite(address uint16) memoryHandler {
if address <= addressLimitSlotsExtra {
return mmu.accessCArea(address)
}
if mmu.mainROMinhibited != nil {
return mmu.mainROMinhibited
}
if mmu.lcActiveWrite {
return mmu.accessUpperRAMArea(address)
}

BIN
resources/SwyftCard ROM.bin Normal file

Binary file not shown.

Binary file not shown.