RAMWorks card support for up to 16MB RAM
This commit is contained in:
parent
ede3b65257
commit
65f013e9b3
24
README.md
24
README.md
|
@ -19,7 +19,8 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||||
- DiskII controller
|
- DiskII controller
|
||||||
- 16Kb Language Card
|
- 16Kb Language Card
|
||||||
- 256Kb Saturn RAM
|
- 256Kb Saturn RAM
|
||||||
- 1Mb Memory Expansion Card
|
- 1Mb Memory Expansion Card (slinky)
|
||||||
|
- RAMWorks style expansion Card (up to 16MB additional) (Apple //e only)
|
||||||
- ThunderClock Plus real time clock
|
- ThunderClock Plus real time clock
|
||||||
- Bootable hard disk card
|
- Bootable hard disk card
|
||||||
- Apple //e 80 columns with 64Kb extra RAM and optional RGB modes
|
- Apple //e 80 columns with 64Kb extra RAM and optional RGB modes
|
||||||
|
@ -34,8 +35,9 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||||
- Double-Width High-Resolution graphics (Apple //e only)
|
- Double-Width High-Resolution graphics (Apple //e only)
|
||||||
- Super High Resolution (VidHD only)
|
- Super High Resolution (VidHD only)
|
||||||
- Mixed mode
|
- Mixed mode
|
||||||
- RGB card text 40 columns with 16 colors for foreground and background
|
- RGB card text 40 columns with 16 colors for foreground and background (mixable)
|
||||||
- RGB card mode 11, mono 560x192
|
- RGB card mode 11, mono 560x192
|
||||||
|
- RGB card mode 12, ntsc 160*192
|
||||||
- RGB card mode 13, ntsc 140*192 (regular DHGR)
|
- RGB card mode 13, ntsc 140*192 (regular DHGR)
|
||||||
- RGB card mode 14, mix of modes 11 and 13 on the fly
|
- RGB card mode 14, mix of modes 11 and 13 on the fly
|
||||||
- Displays:
|
- Displays:
|
||||||
|
@ -61,7 +63,7 @@ No installation required. [Download](https://github.com/ivanizag/apple2/releases
|
||||||
|
|
||||||
Execute without parameters to have an emulated Apple //e Enhanced with 128kb booting DOS 3.3 ready to run Applesoft:
|
Execute without parameters to have an emulated Apple //e Enhanced with 128kb booting DOS 3.3 ready to run Applesoft:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
casa@servidor:~$ ./apple2sdl
|
casa@servidor:~$ ./apple2sdl
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ casa@servidor:~$ ./apple2sdl
|
||||||
|
|
||||||
Download a DSK or WOZ file or use an URL ([Asimov](https://www.apple.asimov.net/images/) is an excellent source) with the `-disk` parameter:
|
Download a DSK or WOZ file or use an URL ([Asimov](https://www.apple.asimov.net/images/) is an excellent source) with the `-disk` parameter:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
casa@servidor:~$ ./apple2sdl -disk "https://www.apple.asimov.net/images/games/action/karateka/karateka (includes intro).dsk"
|
casa@servidor:~$ ./apple2sdl -disk "https://www.apple.asimov.net/images/games/action/karateka/karateka (includes intro).dsk"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -82,7 +84,7 @@ casa@servidor:~$ ./apple2sdl -disk "https://www.apple.asimov.net/images/games/ac
|
||||||
Download the excellent [Total Replay](https://archive.org/details/TotalReplay) compilation by
|
Download the excellent [Total Replay](https://archive.org/details/TotalReplay) compilation by
|
||||||
[a2-4am](https://github.com/a2-4am/4cade). Run it with the `-hd` parameter:
|
[a2-4am](https://github.com/a2-4am/4cade). Run it with the `-hd` parameter:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
casa@servidor:~$ ./apple2sdl -hd "Total Replay v3.0.2mg"
|
casa@servidor:~$ ./apple2sdl -hd "Total Replay v3.0.2mg"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -94,7 +96,7 @@ Displays super hi-res box art as seen with the VidHD card.
|
||||||
|
|
||||||
To run text mode right on the terminal without the SDL2 dependency, use `apple2console`. It runs on the console using ANSI escape codes. Input is sent to the emulated Apple II one line at a time:
|
To run text mode right on the terminal without the SDL2 dependency, use `apple2console`. It runs on the console using ANSI escape codes. Input is sent to the emulated Apple II one line at a time:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
casa@servidor:~$ ./apple2console -model 2plus
|
casa@servidor:~$ ./apple2console -model 2plus
|
||||||
|
|
||||||
############################################
|
############################################
|
||||||
|
@ -145,7 +147,7 @@ Only valid on SDL mode
|
||||||
|
|
||||||
### Command line options
|
### Command line options
|
||||||
|
|
||||||
``` shell
|
```terminal
|
||||||
-charRom string
|
-charRom string
|
||||||
rom file for the character generator (default "<default>")
|
rom file for the character generator (default "<default>")
|
||||||
-disk string
|
-disk string
|
||||||
|
@ -180,6 +182,8 @@ Only valid on SDL mode
|
||||||
panic if a not implemented softswitch is used
|
panic if a not implemented softswitch is used
|
||||||
-profile
|
-profile
|
||||||
generate profile trace to analyse with pprof
|
generate profile trace to analyse with pprof
|
||||||
|
-ramworks int
|
||||||
|
memory to use with RAMWorks card, 0 for no card, max is 16384 (default 8192)
|
||||||
-rgb
|
-rgb
|
||||||
emulate the RGB modes of the 80col RGB card for DHGR (default true)
|
emulate the RGB modes of the 80col RGB card for DHGR (default true)
|
||||||
-rom string
|
-rom string
|
||||||
|
@ -212,7 +216,7 @@ The only dependency is having a working Go installation on any platform.
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
go get github.com/ivanizag/apple2/apple2console
|
go get github.com/ivanizag/apple2/apple2console
|
||||||
go build github.com/ivanizag/apple2/apple2console
|
go build github.com/ivanizag/apple2/apple2console
|
||||||
```
|
```
|
||||||
|
@ -223,7 +227,7 @@ Besides having a working Go installation, install the SDL2 developer files. Vali
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
go get github.com/ivanizag/apple2/apple2sdl
|
go get github.com/ivanizag/apple2/apple2sdl
|
||||||
go build github.com/ivanizag/apple2/apple2sdl
|
go build github.com/ivanizag/apple2/apple2sdl
|
||||||
```
|
```
|
||||||
|
@ -232,7 +236,7 @@ go build github.com/ivanizag/apple2/apple2sdl
|
||||||
|
|
||||||
To create executables for Linux and Windows without installing Go, SDL2 or the Windows cross compilation toosl, run:
|
To create executables for Linux and Windows without installing Go, SDL2 or the Windows cross compilation toosl, run:
|
||||||
|
|
||||||
``` shell
|
``` terminal
|
||||||
cd docker
|
cd docker
|
||||||
./build.sh
|
./build.sh
|
||||||
```
|
```
|
||||||
|
|
|
@ -24,7 +24,7 @@ func newApple2e() *Apple2 {
|
||||||
a.mmu = newMemoryManager(&a)
|
a.mmu = newMemoryManager(&a)
|
||||||
a.cpu = core6502.NewNMOS6502(a.mmu)
|
a.cpu = core6502.NewNMOS6502(a.mmu)
|
||||||
a.io = newIoC0Page(&a)
|
a.io = newIoC0Page(&a)
|
||||||
a.mmu.InitRAMalt()
|
a.mmu.initExtendedRAM(1)
|
||||||
addApple2SoftSwitches(a.io)
|
addApple2SoftSwitches(a.io)
|
||||||
addApple2ESoftSwitches(a.io)
|
addApple2ESoftSwitches(a.io)
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ func newApple2eEnhanced() *Apple2 {
|
||||||
a.mmu = newMemoryManager(&a)
|
a.mmu = newMemoryManager(&a)
|
||||||
a.cpu = core6502.NewCMOS65c02(a.mmu)
|
a.cpu = core6502.NewCMOS65c02(a.mmu)
|
||||||
a.io = newIoC0Page(&a)
|
a.io = newIoC0Page(&a)
|
||||||
a.mmu.InitRAMalt()
|
a.mmu.initExtendedRAM(1)
|
||||||
addApple2SoftSwitches(a.io)
|
addApple2SoftSwitches(a.io)
|
||||||
addApple2ESoftSwitches(a.io)
|
addApple2ESoftSwitches(a.io)
|
||||||
|
|
||||||
|
@ -194,6 +194,10 @@ func (a *Apple2) AddRGBCard() {
|
||||||
setupRGBCard(a)
|
setupRGBCard(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Apple2) AddRAMWorks(banks int) {
|
||||||
|
setupRAMWorksCard(a, banks)
|
||||||
|
}
|
||||||
|
|
||||||
// AddCardLogger inserts a fake card that logs accesses
|
// AddCardLogger inserts a fake card that logs accesses
|
||||||
func (a *Apple2) AddCardLogger(slot int) {
|
func (a *Apple2) AddCardLogger(slot int) {
|
||||||
a.insertCard(&cardLogger{}, slot)
|
a.insertCard(&cardLogger{}, slot)
|
||||||
|
|
|
@ -69,6 +69,10 @@ func MainApple() *Apple2 {
|
||||||
"memoryExpSlot",
|
"memoryExpSlot",
|
||||||
4,
|
4,
|
||||||
"slot for the Memory Expansion card with 1GB. -1 for none")
|
"slot for the Memory Expansion card with 1GB. -1 for none")
|
||||||
|
ramWorksKb := flag.Int(
|
||||||
|
"ramworks",
|
||||||
|
8192,
|
||||||
|
"memory to use with RAMWorks card, 0 for no card, max is 16384")
|
||||||
thunderClockCardSlot := flag.Int(
|
thunderClockCardSlot := flag.Int(
|
||||||
"thunderClockCardSlot",
|
"thunderClockCardSlot",
|
||||||
5,
|
5,
|
||||||
|
@ -253,6 +257,13 @@ func MainApple() *Apple2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *ramWorksKb != 0 {
|
||||||
|
if *ramWorksKb%64 != 0 {
|
||||||
|
panic("Ramworks size must be a multiple of 64")
|
||||||
|
}
|
||||||
|
a.AddRAMWorks(*ramWorksKb / 64)
|
||||||
|
}
|
||||||
|
|
||||||
if *rgbCard {
|
if *rgbCard {
|
||||||
a.AddRGBCard()
|
a.AddRGBCard()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ Modes by RGB flags 1 and 2:
|
||||||
0-0: 560*192 mono
|
0-0: 560*192 mono
|
||||||
1-1: 140*192 ntsc
|
1-1: 140*192 ntsc
|
||||||
0-1: Mixed mode
|
0-1: Mixed mode
|
||||||
1-0: 160*192 ntsc (not supported)
|
1-0: 160*192 ntsc
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package apple2
|
||||||
|
|
||||||
|
/*
|
||||||
|
RAMWorks style card on the Apple IIe aus slot.
|
||||||
|
https://patents.google.com/patent/US4601018
|
||||||
|
https://ae.applearchives.com/apple_e/ramworks_iii/ramworks_iii_basic_manual_1.pdf
|
||||||
|
|
||||||
|
Diagnostics disks:
|
||||||
|
https://ae.applearchives.com/apple_e/ramworks_iii/ramworks_diagnostics.zip
|
||||||
|
|
||||||
|
It's is like the extra 64kb on an Apple IIe 80col 64kb card, but with up to 256 banks
|
||||||
|
*/
|
||||||
|
|
||||||
|
func setupRAMWorksCard(a *Apple2, banks int) {
|
||||||
|
a.mmu.initExtendedRAM(banks)
|
||||||
|
|
||||||
|
ssr := func(_ *ioC0Page) uint8 {
|
||||||
|
return a.mmu.extendedRAMBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
ssw := func(_ *ioC0Page, value uint8) {
|
||||||
|
a.mmu.setExtendedRAMActiveBlock(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not have a slot assigned
|
||||||
|
a.io.addSoftSwitchR(0x71, ssr, "RAMWORKSR")
|
||||||
|
a.io.addSoftSwitchR(0x73, ssr, "RAMWORKSR")
|
||||||
|
a.io.addSoftSwitchR(0x75, ssr, "RAMWORKSR")
|
||||||
|
a.io.addSoftSwitchR(0x77, ssr, "RAMWORKSR")
|
||||||
|
a.io.addSoftSwitchW(0x71, ssw, "RAMWORKSW")
|
||||||
|
a.io.addSoftSwitchW(0x73, ssw, "RAMWORKSW")
|
||||||
|
a.io.addSoftSwitchW(0x75, ssw, "RAMWORKSW")
|
||||||
|
a.io.addSoftSwitchW(0x77, ssw, "RAMWORKSW")
|
||||||
|
}
|
|
@ -114,7 +114,7 @@ func (c *cardSaturn) ssAction(ss uint8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cardSaturn) applyState() {
|
func (c *cardSaturn) applyState() {
|
||||||
c.a.mmu.setLanguageRAMBlock(c.activeBlock)
|
c.a.mmu.setLanguageRAMActiveBlock(c.activeBlock)
|
||||||
c.a.mmu.setLanguageRAM(c.readState, c.writeState == lcWriteEnabled, c.altBank)
|
c.a.mmu.setLanguageRAM(c.readState, c.writeState == lcWriteEnabled, c.altBank)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,23 @@ type memoryManager struct {
|
||||||
apple2 *Apple2
|
apple2 *Apple2
|
||||||
|
|
||||||
// Main RAM area: 0x0000 to 0xbfff
|
// Main RAM area: 0x0000 to 0xbfff
|
||||||
physicalMainRAM *memoryRange // 0x0000 to 0xbfff, Up to 48 Kb
|
physicalMainRAM *memoryRange // 0x0000 to 0xbfff, Up to 48 Kb
|
||||||
physicalMainRAMAlt *memoryRange // 0x0000 to 0xbfff, Up to 48 Kb. Additional
|
|
||||||
|
|
||||||
// Slots area: 0xc000 to 0xcfff
|
// Slots area: 0xc000 to 0xcfff
|
||||||
cardsROM [8]memoryHandler //0xcs00 to 0xcsff. 256 bytes for each card
|
cardsROM [8]memoryHandler //0xcs00 to 0xcSff. 256 bytes for each card
|
||||||
cardsROMExtra [8]memoryHandler // 0xc800 to 0xcfff. 2048 bytes for each card
|
cardsROMExtra [8]memoryHandler // 0xc800 to 0xcfff. 2048 bytes for each card
|
||||||
physicalROMe memoryHandler // 0xc100 to 0xcfff, Zero or 4kb in the Apple2e
|
physicalROMe memoryHandler // 0xc100 to 0xcfff, Zero or 4kb in the Apple2e
|
||||||
|
|
||||||
// Upper area: 0xd000 to 0xffff
|
// Upper area ROM: 0xd000 to 0xffff
|
||||||
physicalROM [4]memoryHandler // 0xd000 to 0xffff, 12 Kb. Up to four banks
|
physicalROM [4]memoryHandler // 0xd000 to 0xffff, 12 Kb. Up to four
|
||||||
physicalDRAM []memoryHandler // 0xd000 to 0xdfff, 4KB. Up to 8 banks.
|
|
||||||
physicalDAltRAM []memoryHandler // 0xd000 to 0xdfff, 4KB. Up to 8 banks.
|
// Language card upper area RAM: 0xd000 to 0xffff. One bank for regular LC cards, up to 8 with Saturn
|
||||||
physicalEFRAM []memoryHandler // 0xe000 to 0xffff, 8KB. Up to 8 banks.
|
physicalLangRAM []*memoryRange // 0xd000 to 0xffff, 12KB. Up to 8 banks.
|
||||||
|
physicalLangAltRAM []*memoryRange // 0xd000 to 0xdfff, 4KB. Up to 8 banks.
|
||||||
|
|
||||||
|
// Extended RAM: 0x0000 to 0xffff (with 4Kb moved from 0xc000 to 0xd000 alt). One bank for extended Apple 2e card, up to 256 with RamWorks
|
||||||
|
physicalExtRAM []*memoryRange // 0x0000 to 0xffff. 60Kb, 0xc000 to 0xcfff not used. Up to 256 banks
|
||||||
|
physicalExtAltRAM []*memoryRange // 0xd000 to 0xdfff, 4Kb. Up to 256 banks.
|
||||||
|
|
||||||
// Configuration switches, Language cards
|
// Configuration switches, Language cards
|
||||||
lcSelectedBlock uint8 // Language card block selected. Usually, allways 0. But Saturn has 8
|
lcSelectedBlock uint8 // Language card block selected. Usually, allways 0. But Saturn has 8
|
||||||
|
@ -40,6 +44,7 @@ type memoryManager struct {
|
||||||
slotC3ROMActive bool // Apple2e slot 3 ROM shadow
|
slotC3ROMActive bool // Apple2e slot 3 ROM shadow
|
||||||
intCxROMActive bool // Apple2e slots internal ROM shadow
|
intCxROMActive bool // Apple2e slots internal ROM shadow
|
||||||
activeSlot uint8 // Active slot owner of 0xc800 to 0xcfff
|
activeSlot uint8 // Active slot owner of 0xc800 to 0xcfff
|
||||||
|
extendedRAMBlock uint8 // Block used for entended memory for RAMWorks cards
|
||||||
|
|
||||||
// Configuration switches, Base64A
|
// Configuration switches, Base64A
|
||||||
romPage uint8 // Active ROM page
|
romPage uint8 // Active ROM page
|
||||||
|
@ -97,23 +102,35 @@ func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
||||||
return mmu.cardsROMExtra[mmu.activeSlot]
|
return mmu.cardsROMExtra[mmu.activeSlot]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) accessLCArea(address uint16) memoryHandler {
|
func (mmu *memoryManager) accessUpperRAMArea(address uint16) memoryHandler {
|
||||||
block := mmu.lcSelectedBlock
|
|
||||||
if mmu.altZeroPage {
|
if mmu.altZeroPage {
|
||||||
block = 1
|
// Use extended RAM
|
||||||
}
|
block := mmu.extendedRAMBlock
|
||||||
if address <= addressLimitDArea {
|
if mmu.lcAltBank && address <= addressLimitDArea {
|
||||||
if mmu.lcAltBank {
|
return mmu.physicalExtAltRAM[block]
|
||||||
return mmu.physicalDAltRAM[block]
|
|
||||||
}
|
}
|
||||||
return mmu.physicalDRAM[block]
|
return mmu.physicalExtRAM[mmu.extendedRAMBlock]
|
||||||
}
|
}
|
||||||
return mmu.physicalEFRAM[block]
|
|
||||||
|
// Use language card
|
||||||
|
block := mmu.lcSelectedBlock
|
||||||
|
if mmu.lcAltBank && address <= addressLimitDArea {
|
||||||
|
return mmu.physicalLangAltRAM[block]
|
||||||
|
}
|
||||||
|
return mmu.physicalLangRAM[block]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) getPhysicalMainRAM(alt bool) *memoryRange {
|
func (mmu *memoryManager) getPhysicalMainRAM(ext bool) memoryHandler {
|
||||||
if alt {
|
if ext {
|
||||||
return mmu.physicalMainRAMAlt
|
return mmu.physicalExtRAM[mmu.extendedRAMBlock]
|
||||||
|
}
|
||||||
|
return mmu.physicalMainRAM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mmu *memoryManager) getVideoRAM(ext bool) *memoryRange {
|
||||||
|
if ext {
|
||||||
|
// The video memory uses the first extended RAM block, even with RAMWorks
|
||||||
|
return mmu.physicalExtRAM[0]
|
||||||
}
|
}
|
||||||
return mmu.physicalMainRAM
|
return mmu.physicalMainRAM
|
||||||
}
|
}
|
||||||
|
@ -142,7 +159,7 @@ func (mmu *memoryManager) accessRead(address uint16) memoryHandler {
|
||||||
return mmu.accessCArea(address)
|
return mmu.accessCArea(address)
|
||||||
}
|
}
|
||||||
if mmu.lcActiveRead {
|
if mmu.lcActiveRead {
|
||||||
return mmu.accessLCArea(address)
|
return mmu.accessUpperRAMArea(address)
|
||||||
}
|
}
|
||||||
return mmu.physicalROM[mmu.romPage]
|
return mmu.physicalROM[mmu.romPage]
|
||||||
}
|
}
|
||||||
|
@ -171,7 +188,7 @@ func (mmu *memoryManager) accessWrite(address uint16) memoryHandler {
|
||||||
return mmu.accessCArea(address)
|
return mmu.accessCArea(address)
|
||||||
}
|
}
|
||||||
if mmu.lcActiveWrite {
|
if mmu.lcActiveWrite {
|
||||||
return mmu.accessLCArea(address)
|
return mmu.accessUpperRAMArea(address)
|
||||||
}
|
}
|
||||||
return mmu.physicalROM[mmu.romPage]
|
return mmu.physicalROM[mmu.romPage]
|
||||||
}
|
}
|
||||||
|
@ -205,19 +222,24 @@ func (mmu *memoryManager) setCardROMExtra(slot int, mh memoryHandler) {
|
||||||
mmu.cardsROMExtra[slot] = mh
|
mmu.cardsROMExtra[slot] = mh
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) initLanguageRAM(groups int) {
|
func (mmu *memoryManager) initLanguageRAM(groups uint8) {
|
||||||
mmu.physicalDRAM = make([]memoryHandler, groups)
|
// Apple II+ language card or Saturn (up to 8 groups)
|
||||||
mmu.physicalDAltRAM = make([]memoryHandler, groups)
|
mmu.physicalLangRAM = make([]*memoryRange, groups)
|
||||||
mmu.physicalEFRAM = make([]memoryHandler, groups)
|
mmu.physicalLangAltRAM = make([]*memoryRange, groups)
|
||||||
for i := 0; i < groups; i++ {
|
for i := uint8(0); i < groups; i++ {
|
||||||
mmu.physicalDRAM[i] = newMemoryRange(0xd000, make([]uint8, 0x1000))
|
mmu.physicalLangRAM[i] = newMemoryRange(0xd000, make([]uint8, 0x3000))
|
||||||
mmu.physicalDAltRAM[i] = newMemoryRange(0xd000, make([]uint8, 0x1000))
|
mmu.physicalLangAltRAM[i] = newMemoryRange(0xd000, make([]uint8, 0x1000))
|
||||||
mmu.physicalEFRAM[i] = newMemoryRange(0xe000, make([]uint8, 0x2000))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) InitRAMalt() {
|
func (mmu *memoryManager) initExtendedRAM(groups int) {
|
||||||
mmu.physicalMainRAMAlt = newMemoryRange(0, make([]uint8, 0xc000))
|
// Apple IIe 80 col card with 64Kb style RAM or RAMWorks (up to 256 banks)
|
||||||
|
mmu.physicalExtRAM = make([]*memoryRange, groups)
|
||||||
|
mmu.physicalExtAltRAM = make([]*memoryRange, groups)
|
||||||
|
for i := 0; i < groups; i++ {
|
||||||
|
mmu.physicalExtRAM[i] = newMemoryRange(0, make([]uint8, 0x10000))
|
||||||
|
mmu.physicalExtAltRAM[i] = newMemoryRange(0xd000, make([]uint8, 0x1000))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory configuration
|
// Memory configuration
|
||||||
|
@ -235,11 +257,19 @@ func (mmu *memoryManager) setLanguageRAM(readActive bool, writeActive bool, altB
|
||||||
mmu.lcAltBank = altBank
|
mmu.lcAltBank = altBank
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) setLanguageRAMBlock(block uint8) {
|
func (mmu *memoryManager) setLanguageRAMActiveBlock(block uint8) {
|
||||||
block = block % uint8(len(mmu.physicalDRAM))
|
block = block % uint8(len(mmu.physicalLangRAM))
|
||||||
mmu.lcSelectedBlock = block
|
mmu.lcSelectedBlock = block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mmu *memoryManager) setExtendedRAMActiveBlock(block uint8) {
|
||||||
|
if int(block) >= len(mmu.physicalExtRAM) {
|
||||||
|
// How does the real hardware reacts?
|
||||||
|
block = 0
|
||||||
|
}
|
||||||
|
mmu.extendedRAMBlock = block
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: complete save and load
|
// TODO: complete save and load
|
||||||
func (mmu *memoryManager) save(w io.Writer) error {
|
func (mmu *memoryManager) save(w io.Writer) error {
|
||||||
err := mmu.physicalMainRAM.save(w)
|
err := mmu.physicalMainRAM.save(w)
|
||||||
|
|
|
@ -31,7 +31,7 @@ func getHiResLine(a *Apple2, line int, isSecondPage bool, auxMem bool) []uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
address += getHiResLineOffset(line)
|
address += getHiResLineOffset(line)
|
||||||
return a.mmu.getPhysicalMainRAM(auxMem).subRange(address, address+hiResLineBytes)
|
return a.mmu.getVideoRAM(auxMem).subRange(address, address+hiResLineBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotHiResModeMono(a *Apple2, isSecondPage bool, light color.Color) *image.RGBA {
|
func snapshotHiResModeMono(a *Apple2, isSecondPage bool, light color.Color) *image.RGBA {
|
||||||
|
|
|
@ -24,8 +24,10 @@ func snapshotSuperHiResMode(a *Apple2) *image.RGBA {
|
||||||
size := image.Rect(0, 0, shrWidth, shrHeight)
|
size := image.Rect(0, 0, shrWidth, shrHeight)
|
||||||
img := image.NewRGBA(size)
|
img := image.NewRGBA(size)
|
||||||
|
|
||||||
|
videoRAM := a.mmu.getVideoRAM(true)
|
||||||
|
|
||||||
// Load the palettes
|
// Load the palettes
|
||||||
paletteMem := a.mmu.physicalMainRAMAlt.subRange(shrColorPalettesAddress, shrColorPalettesAddressEnd)
|
paletteMem := videoRAM.subRange(shrColorPalettesAddress, shrColorPalettesAddressEnd)
|
||||||
colors := make([]color.Color, palettesCount)
|
colors := make([]color.Color, palettesCount)
|
||||||
iMem := 0
|
iMem := 0
|
||||||
for i := 0; i < palettesCount; i++ {
|
for i := 0; i < palettesCount; i++ {
|
||||||
|
@ -46,13 +48,13 @@ func snapshotSuperHiResMode(a *Apple2) *image.RGBA {
|
||||||
|
|
||||||
// Build the lines
|
// Build the lines
|
||||||
for y := 0; y < shrHeight; y++ {
|
for y := 0; y < shrHeight; y++ {
|
||||||
controlByte := a.mmu.physicalMainRAMAlt.peek(shrScanLineControlAddress + uint16(y))
|
controlByte := videoRAM.peek(shrScanLineControlAddress + uint16(y))
|
||||||
is640Wide := (controlByte & 0x80) != 0
|
is640Wide := (controlByte & 0x80) != 0
|
||||||
isColorFill := (controlByte & 0x20) != 0
|
isColorFill := (controlByte & 0x20) != 0
|
||||||
paletteIndex := (controlByte & 0x0f) << 4
|
paletteIndex := (controlByte & 0x0f) << 4
|
||||||
|
|
||||||
lineAddress := shrPixelDataAddress + uint16(shrWidthBytes*y)
|
lineAddress := shrPixelDataAddress + uint16(shrWidthBytes*y)
|
||||||
lineBytes := a.mmu.physicalMainRAMAlt.subRange(lineAddress, uint16(lineAddress+shrWidthBytes))
|
lineBytes := videoRAM.subRange(lineAddress, uint16(lineAddress+shrWidthBytes))
|
||||||
|
|
||||||
if is640Wide {
|
if is640Wide {
|
||||||
// Line is 640 pixels, two bits per pixel
|
// Line is 640 pixels, two bits per pixel
|
||||||
|
|
|
@ -20,7 +20,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func snapshotText40Mode(a *Apple2, isSecondPage bool, light color.Color) *image.RGBA {
|
func snapshotText40Mode(a *Apple2, isSecondPage bool, light color.Color) *image.RGBA {
|
||||||
text := getTextFromMemory(a.mmu.physicalMainRAM, isSecondPage)
|
text := getTextFromMemory(a.mmu.getVideoRAM(false), isSecondPage)
|
||||||
return renderTextMode(a, text, nil /*colorMap*/, light)
|
return renderTextMode(a, text, nil /*colorMap*/, light)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,13 +30,13 @@ func snapshotText80Mode(a *Apple2, isSecondPage bool, light color.Color) *image.
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotText40RGBMode(a *Apple2, isSecondPage bool) *image.RGBA {
|
func snapshotText40RGBMode(a *Apple2, isSecondPage bool) *image.RGBA {
|
||||||
text := getTextFromMemory(a.mmu.physicalMainRAM, isSecondPage)
|
text := getTextFromMemory(a.mmu.getVideoRAM(false), isSecondPage)
|
||||||
colorMap := getTextFromMemory(a.mmu.physicalMainRAMAlt, isSecondPage)
|
colorMap := getTextFromMemory(a.mmu.getVideoRAM(true), isSecondPage)
|
||||||
return renderTextMode(a, text, colorMap, nil)
|
return renderTextMode(a, text, colorMap, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotText40RGBModeColors(a *Apple2, isSecondPage bool) *image.RGBA {
|
func snapshotText40RGBModeColors(a *Apple2, isSecondPage bool) *image.RGBA {
|
||||||
colorMap := getTextFromMemory(a.mmu.physicalMainRAMAlt, isSecondPage)
|
colorMap := getTextFromMemory(a.mmu.getVideoRAM(true), isSecondPage)
|
||||||
return renderTextMode(a, nil /*text*/, colorMap, nil)
|
return renderTextMode(a, nil /*text*/, colorMap, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ func getTextCharOffset(col int, line int) uint16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getText80FromMemory(a *Apple2, isSecondPage bool) []uint8 {
|
func getText80FromMemory(a *Apple2, isSecondPage bool) []uint8 {
|
||||||
text40Columns := getTextFromMemory(a.mmu.physicalMainRAM, isSecondPage)
|
text40Columns := getTextFromMemory(a.mmu.getVideoRAM(false), isSecondPage)
|
||||||
text40ColumnsAlt := getTextFromMemory(a.mmu.physicalMainRAMAlt, isSecondPage)
|
text40ColumnsAlt := getTextFromMemory(a.mmu.getVideoRAM(true), isSecondPage)
|
||||||
|
|
||||||
// Merge the two 40 cols to return 80 cols
|
// Merge the two 40 cols to return 80 cols
|
||||||
text80Columns := make([]uint8, 2*len(text40Columns))
|
text80Columns := make([]uint8, 2*len(text40Columns))
|
||||||
|
@ -165,7 +165,7 @@ func DumpTextModeAnsi(a *Apple2) string {
|
||||||
if is80Columns {
|
if is80Columns {
|
||||||
text = getText80FromMemory(a, isSecondPage)
|
text = getText80FromMemory(a, isSecondPage)
|
||||||
} else {
|
} else {
|
||||||
text = getTextFromMemory(a.mmu.physicalMainRAM, isSecondPage)
|
text = getTextFromMemory(a.mmu.getVideoRAM(false), isSecondPage)
|
||||||
}
|
}
|
||||||
columns := len(text) / textLines
|
columns := len(text) / textLines
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue