mirror of
https://github.com/zellyn/goapple2.git
synced 2024-12-26 16:29:22 +00:00
shiny resize, language card impl
This commit is contained in:
parent
e8e766c0c7
commit
998569cee1
@ -1,6 +1,7 @@
|
|||||||
package cards
|
package cards
|
||||||
|
|
||||||
type Card interface {
|
type Card interface {
|
||||||
|
Init() // Give the card a chance to initialize
|
||||||
String() string // The name of the card, for debug/display purposes
|
String() string // The name of the card, for debug/display purposes
|
||||||
Read16(address byte) byte // Read from the $C0(8+slot)X addresses
|
Read16(address byte) byte // Read from the $C0(8+slot)X addresses
|
||||||
Write16(address byte, value byte) // Write to the $C0(8+slot)X addresses
|
Write16(address byte, value byte) // Write to the $C0(8+slot)X addresses
|
||||||
|
@ -58,6 +58,9 @@ func (dc *DiskCard) String() string {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dc *DiskCard) Init() {
|
||||||
|
}
|
||||||
|
|
||||||
func (dc *DiskCard) Slot() byte {
|
func (dc *DiskCard) Slot() byte {
|
||||||
return dc.slot
|
return dc.slot
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FirmwareCard struct {
|
type FirmwareCard struct {
|
||||||
name string
|
name string
|
||||||
rom [12288]byte
|
rom [12288]byte
|
||||||
cm CardManager
|
cm CardManager
|
||||||
slot byte
|
slot byte
|
||||||
slotbit byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFirmwareCard(rom []byte, name string, slot byte, cm CardManager) (*FirmwareCard, error) {
|
func NewFirmwareCard(rom []byte, name string, slot byte, cm CardManager) (*FirmwareCard, error) {
|
||||||
if len(rom) != 12288 {
|
if len(rom) != 12288 {
|
||||||
return nil, fmt.Errorf("Wrong size ROM: expected 12288, got %d", len(rom))
|
return nil, fmt.Errorf("Wrong size ROM: expected 12288, got %d", len(rom))
|
||||||
}
|
}
|
||||||
fc := &FirmwareCard{name: name, cm: cm, slot: slot, slotbit: 1 << slot}
|
fc := &FirmwareCard{name: name, cm: cm, slot: slot}
|
||||||
copy(fc.rom[:], rom)
|
copy(fc.rom[:], rom)
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
@ -25,6 +24,9 @@ func (fc *FirmwareCard) String() string {
|
|||||||
return fmt.Sprintf("%s (slot %d)", fc.name, fc.slot)
|
return fmt.Sprintf("%s (slot %d)", fc.name, fc.slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fc *FirmwareCard) Init() {
|
||||||
|
}
|
||||||
|
|
||||||
func (fc *FirmwareCard) Slot() byte {
|
func (fc *FirmwareCard) Slot() byte {
|
||||||
return fc.slot
|
return fc.slot
|
||||||
}
|
}
|
||||||
@ -36,10 +38,10 @@ func (fc *FirmwareCard) ROMDisabled() {
|
|||||||
func (fc *FirmwareCard) handleAccess(address byte) {
|
func (fc *FirmwareCard) handleAccess(address byte) {
|
||||||
if address%2 == 1 {
|
if address%2 == 1 {
|
||||||
// Card off
|
// Card off
|
||||||
fc.cm.HandleROM(false, fc.slotbit)
|
fc.cm.HandleROM(false, fc.slot)
|
||||||
} else {
|
} else {
|
||||||
// Card on
|
// Card on
|
||||||
fc.cm.HandleROM(true, fc.slotbit)
|
fc.cm.HandleROM(true, fc.slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
142
cards/language.go
Normal file
142
cards/language.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package cards
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LanguageCard struct {
|
||||||
|
name string
|
||||||
|
rom [12288]byte
|
||||||
|
ram [16384]byte
|
||||||
|
cm CardManager
|
||||||
|
slot byte
|
||||||
|
slotbit byte
|
||||||
|
bank int // 1 = bank 1, 0 = bank 2
|
||||||
|
ramread bool
|
||||||
|
ramwrite bool
|
||||||
|
readcount int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLanguageCard(rom []byte, name string, slot byte, cm CardManager) (*LanguageCard, error) {
|
||||||
|
if len(rom) != 12288 {
|
||||||
|
return nil, fmt.Errorf("Wrong size ROM: expected 12288, got %d", len(rom))
|
||||||
|
}
|
||||||
|
lc := &LanguageCard{
|
||||||
|
name: name,
|
||||||
|
cm: cm,
|
||||||
|
slot: slot,
|
||||||
|
slotbit: 1 << slot,
|
||||||
|
bank: 0,
|
||||||
|
ramread: false,
|
||||||
|
ramwrite: true,
|
||||||
|
readcount: 0,
|
||||||
|
}
|
||||||
|
copy(lc.rom[:], rom)
|
||||||
|
return lc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) String() string {
|
||||||
|
return fmt.Sprintf("%s (slot %d)", lc.name, lc.slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init: language card should always handle D000-FFFF accessess, since
|
||||||
|
// it contains either RAM or ROM.
|
||||||
|
func (lc *LanguageCard) Init() {
|
||||||
|
lc.cm.Handle12k(true, lc.slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Slot() byte {
|
||||||
|
return lc.slot
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) ROMDisabled() {
|
||||||
|
// Language card doesn't have a $C(8-F)xx ROM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) handleAccess(address byte, write bool) {
|
||||||
|
if write {
|
||||||
|
lc.readcount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
address &^= 4
|
||||||
|
switch address &^ 8 {
|
||||||
|
case 0:
|
||||||
|
lc.ramread = true
|
||||||
|
lc.ramwrite = false
|
||||||
|
lc.readcount = 0
|
||||||
|
case 1:
|
||||||
|
lc.ramread = false
|
||||||
|
if lc.readcount > 0 {
|
||||||
|
lc.ramwrite = true
|
||||||
|
}
|
||||||
|
if !write {
|
||||||
|
lc.readcount++
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
lc.ramread = false
|
||||||
|
lc.ramwrite = false
|
||||||
|
lc.readcount = 0
|
||||||
|
case 3:
|
||||||
|
lc.ramread = true
|
||||||
|
if lc.readcount > 0 {
|
||||||
|
lc.ramwrite = true
|
||||||
|
}
|
||||||
|
if !write {
|
||||||
|
lc.readcount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lc.bank = int((address & 8) >> 3)
|
||||||
|
// fmt.Printf("ramread: %v, ramwrite: %v, bank: %d, readcount: %d\n", lc.ramread, lc.ramwrite, lc.bank, lc.readcount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Read16(address byte) byte {
|
||||||
|
// fmt.Printf("Read to %02xd: ", address)
|
||||||
|
lc.handleAccess(address, false)
|
||||||
|
return lc.cm.EmptyRead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Write16(address byte, value byte) {
|
||||||
|
// fmt.Printf("Write to %02xd: ", address)
|
||||||
|
lc.handleAccess(address, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) ramOffset(address uint16) uint16 {
|
||||||
|
if address < 0xE000 {
|
||||||
|
return address - 0xD000 + 0x1000*uint16(lc.bank)
|
||||||
|
}
|
||||||
|
return address - 0xE000 + 0x2000
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Read(address uint16) byte {
|
||||||
|
// fmt.Printf("Read from %04x\n", address)
|
||||||
|
if address < 0xD000 {
|
||||||
|
panic(fmt.Sprintf("%s got read to $%04X (<$D000)", lc.String(), address))
|
||||||
|
}
|
||||||
|
if lc.ramread {
|
||||||
|
return lc.ram[lc.ramOffset(address)]
|
||||||
|
}
|
||||||
|
return lc.rom[address-0xD000]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Write(address uint16, value byte) {
|
||||||
|
// fmt.Printf("Write to %04x\n", address)
|
||||||
|
if lc.ramwrite {
|
||||||
|
lc.ram[lc.ramOffset(address)] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Read256(address byte) byte {
|
||||||
|
return lc.cm.EmptyRead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Write256(address byte, value byte) {
|
||||||
|
// Language is ROM: do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) WantTicker() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LanguageCard) Tick() {
|
||||||
|
// do nothing
|
||||||
|
}
|
@ -95,6 +95,7 @@ func (a2 *Apple2) AddCard(card cards.Card) error {
|
|||||||
a2.cardTickerMask |= slotbit
|
a2.cardTickerMask |= slotbit
|
||||||
}
|
}
|
||||||
a2.cards[slot] = card
|
a2.cards[slot] = card
|
||||||
|
card.Init()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +214,7 @@ func (a2 *Apple2) Read(address uint16) byte {
|
|||||||
if address&0xF000 == 0xC000 {
|
if address&0xF000 == 0xC000 {
|
||||||
return a2.handleC00X(address, 0, false)
|
return a2.handleC00X(address, 0, false)
|
||||||
}
|
}
|
||||||
if address >= 0xD000 && a2.cardRomMask > 0 {
|
if address >= 0xD000 && a2.card12kMask > 0 {
|
||||||
if a2.card12kConflict {
|
if a2.card12kConflict {
|
||||||
panic(fmt.Sprintf("More than one card trying to provide 12K ROM: Mask=$%02X", a2.card12kMask))
|
panic(fmt.Sprintf("More than one card trying to provide 12K ROM: Mask=$%02X", a2.card12kMask))
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ func (a2 *Apple2) Write(address uint16, value byte) {
|
|||||||
// fmt.Printf("Write to 0x46: PC==$%04X\n", a2.cpu.PC())
|
// fmt.Printf("Write to 0x46: PC==$%04X\n", a2.cpu.PC())
|
||||||
// }
|
// }
|
||||||
if address >= 0xD000 {
|
if address >= 0xD000 {
|
||||||
if a2.cardRomMask > 0 {
|
if a2.card12kMask > 0 {
|
||||||
if a2.card12kConflict {
|
if a2.card12kConflict {
|
||||||
panic(fmt.Sprintf("More than one card trying to provide 12K ROM: Mask=$%02X", a2.card12kMask))
|
panic(fmt.Sprintf("More than one card trying to provide 12K ROM: Mask=$%02X", a2.card12kMask))
|
||||||
}
|
}
|
||||||
@ -344,9 +345,9 @@ func (a2 *Apple2) HandleROM(onOff bool, slot byte) {
|
|||||||
|
|
||||||
func (a2 *Apple2) Handle12k(onOff bool, slot byte) {
|
func (a2 *Apple2) Handle12k(onOff bool, slot byte) {
|
||||||
if onOff {
|
if onOff {
|
||||||
a2.card12kMask |= slot
|
a2.card12kMask |= (1 << slot)
|
||||||
} else {
|
} else {
|
||||||
a2.card12kMask &^= slot
|
a2.card12kMask &^= (1 << slot)
|
||||||
}
|
}
|
||||||
a2.card12kConflict = a2.card12kMask&(a2.card12kMask-1) > 0
|
a2.card12kConflict = a2.card12kMask&(a2.card12kMask-1) > 0
|
||||||
if !onOff && !a2.card12kConflict && a2.card12kMask > 0 {
|
if !onOff && !a2.card12kConflict && a2.card12kMask > 0 {
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
|
||||||
"golang.org/x/exp/shiny/driver"
|
"golang.org/x/exp/shiny/driver"
|
||||||
@ -18,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"github.com/zellyn/goapple2"
|
"github.com/zellyn/goapple2"
|
||||||
"github.com/zellyn/goapple2/cards"
|
"github.com/zellyn/goapple2/cards"
|
||||||
|
"github.com/zellyn/goapple2/disk"
|
||||||
"github.com/zellyn/goapple2/util"
|
"github.com/zellyn/goapple2/util"
|
||||||
"github.com/zellyn/goapple2/videoscan"
|
"github.com/zellyn/goapple2/videoscan"
|
||||||
)
|
)
|
||||||
@ -39,17 +39,17 @@ const (
|
|||||||
func RunEmulator(s screen.Screen) {
|
func RunEmulator(s screen.Screen) {
|
||||||
rom := util.ReadRomOrDie("../data/roms/apple2+.rom", 12288)
|
rom := util.ReadRomOrDie("../data/roms/apple2+.rom", 12288)
|
||||||
charRom := util.ReadSmallCharacterRomOrDie("../data/roms/apple2-chars.rom")
|
charRom := util.ReadSmallCharacterRomOrDie("../data/roms/apple2-chars.rom")
|
||||||
intBasicRom := util.ReadRomOrDie("../data/roms/apple2.rom", 12288)
|
// intBasicRom := util.ReadRomOrDie("../data/roms/apple2.rom", 12288)
|
||||||
util.ReadRomOrDie("../data/roms/Apple Disk II 16 Sector Interface Card ROM P5 - 341-0027.bin", 256)
|
util.ReadRomOrDie("../data/roms/Apple Disk II 16 Sector Interface Card ROM P5 - 341-0027.bin", 256)
|
||||||
|
|
||||||
eventChan := make(chan (interface{}))
|
eventChan := make(chan (interface{}))
|
||||||
w, err := s.NewWindow(&screen.NewWindowOptions{Width: SCREEN_WIDTH, Height: SCREEN_HEIGHT})
|
w, err := s.NewWindow(&screen.NewWindowOptions{Width: SCREEN_WIDTH * 2, Height: SCREEN_HEIGHT * 2})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer w.Release()
|
defer w.Release()
|
||||||
|
|
||||||
winSize := image.Point{SCREEN_WIDTH, SCREEN_HEIGHT}
|
winSize := image.Point{SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2}
|
||||||
b, err := s.NewBuffer(winSize)
|
b, err := s.NewBuffer(winSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -59,37 +59,48 @@ func RunEmulator(s screen.Screen) {
|
|||||||
var a2 *goapple2.Apple2
|
var a2 *goapple2.Apple2
|
||||||
oncePerFrame := func() {
|
oncePerFrame := func() {
|
||||||
a2.Done = a2.Done || ProcessEvents(a2, w, eventChan)
|
a2.Done = a2.Done || ProcessEvents(a2, w, eventChan)
|
||||||
runtime.Gosched()
|
|
||||||
}
|
}
|
||||||
plotter := ShinyPlotter{w, b, oncePerFrame}
|
plotter := ShinyPlotter{w, b, oncePerFrame}
|
||||||
a2 = goapple2.NewApple2(plotter, rom, charRom)
|
a2 = goapple2.NewApple2(plotter, rom, charRom)
|
||||||
|
|
||||||
firmwareCard, err := cards.NewFirmwareCard(intBasicRom, "Intbasic Firmware Card", 0, a2)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := a2.AddCard(firmwareCard); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
diskCardRom := util.ReadRomOrDie("../data/roms/Apple Disk II 16 Sector Interface Card ROM P5 - 341-0027.bin", 256)
|
firmwareCard, err := cards.NewFirmwareCard(intBasicRom, "Intbasic Firmware Card", 0, a2)
|
||||||
diskCard, err := cards.NewDiskCard(diskCardRom, 6, a2)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := a2.AddCard(diskCard); err != nil {
|
if err := a2.AddCard(firmwareCard); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
languageCard, err := cards.NewLanguageCard(rom, "Language Card", 0, a2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := a2.AddCard(languageCard); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diskCardRom := util.ReadRomOrDie("../data/roms/Apple Disk II 16 Sector Interface Card ROM P5 - 341-0027.bin", 256)
|
||||||
|
diskCard, err := cards.NewDiskCard(diskCardRom, 6, a2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := a2.AddCard(diskCard); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
// disk1, err := disk.DiskFromFile("../data/disks/spedtest.dsk", 0)
|
// disk1, err := disk.DiskFromFile("../data/disks/spedtest.dsk", 0)
|
||||||
// disk1, err := disk.DiskFromFile("../data/disks/dung_beetles.dsk", 0)
|
// disk1, err := disk.DiskFromFile("../data/disks/dung_beetles.dsk", 0)
|
||||||
// disk1, err := disk.DiskFromFile("../data/disks/chivalry.dsk", 0)
|
// disk1, err := disk.DiskFromFile("../data/disks/chivalry.dsk", 0)
|
||||||
// disk1, err := disk.DiskFromFile("../data/disks/wavynavy.dsk", 0)
|
// disk1, err := disk.DiskFromFile("../data/disks/wavynavy.dsk", 0)
|
||||||
// if err != nil {
|
disk1, err := disk.DiskFromFile("/Users/zellyn/Documents/a2-disks/disks/Rescue_Raiders_1.2.dsk", 0)
|
||||||
// log.Fatal(err)
|
// disk1, err := disk.DiskFromFile("/Users/zellyn/Development/go/src/github.com/zellyn/a2audit/floatbus/floatbus.dsk", 0)
|
||||||
// }
|
// disk1, err := disk.DiskFromFile("/Users/zellyn/Development/go/src/github.com/zellyn/a2audit/audit/audit.dsk", 0)
|
||||||
// diskCard.LoadDisk(disk1, 0)
|
// disk1, err := disk.DiskFromFile("/Users/zellyn/Development/go/src/github.com/zellyn/diskii/lib/supermon/testdata/chacha20.dsk", 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
diskCard.LoadDisk(disk1, 0)
|
||||||
|
|
||||||
steps := *steplimit
|
steps := *steplimit
|
||||||
|
|
||||||
@ -119,7 +130,7 @@ func RunEmulator(s screen.Screen) {
|
|||||||
|
|
||||||
a2.AddPCAction(0xBDAF, goapple2.PCAction{Type: goapple2.ActionDiskStatus})
|
a2.AddPCAction(0xBDAF, goapple2.PCAction{Type: goapple2.ActionDiskStatus})
|
||||||
|
|
||||||
a2.AddPCAction(0xBDAF, goapple2.PCAction{Type: goapple2.ActionTrace, String: "on",
|
a2.AddPCAction(0x6000, goapple2.PCAction{Type: goapple2.ActionTrace, String: "on",
|
||||||
Delay: 70})
|
Delay: 70})
|
||||||
|
|
||||||
a2.AddPCAction(
|
a2.AddPCAction(
|
||||||
@ -129,7 +140,9 @@ func RunEmulator(s screen.Screen) {
|
|||||||
0xBDAF, goapple2.PCAction{Type: goapple2.ActionDumpMem, String: "0xBDAF-goa2.bin", Delay: 68})
|
0xBDAF, goapple2.PCAction{Type: goapple2.ActionDumpMem, String: "0xBDAF-goa2.bin", Delay: 68})
|
||||||
*/
|
*/
|
||||||
|
|
||||||
go typeProgram(a2)
|
// a2.AddPCAction(0x6000, goapple2.PCAction{Type: goapple2.ActionTrace, String: "on"})
|
||||||
|
|
||||||
|
// go typeProgram(a2)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@ -143,7 +156,6 @@ func RunEmulator(s screen.Screen) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// runtime.Gosched() // So the keyboard-reading goroutines can run
|
|
||||||
if steps > 0 {
|
if steps > 0 {
|
||||||
steps--
|
steps--
|
||||||
if steps == 0 {
|
if steps == 0 {
|
||||||
@ -156,7 +168,12 @@ func RunEmulator(s screen.Screen) {
|
|||||||
|
|
||||||
func plot(x, y int, c color.RGBA, b screen.Buffer) {
|
func plot(x, y int, c color.RGBA, b screen.Buffer) {
|
||||||
rgba := b.RGBA()
|
rgba := b.RGBA()
|
||||||
rgba.SetRGBA(x+BORDER_W, y+BORDER_H, c)
|
xx := (x + BORDER_W) * 2
|
||||||
|
yy := (y + BORDER_H) * 2
|
||||||
|
rgba.SetRGBA(xx, yy, c)
|
||||||
|
rgba.SetRGBA(xx+1, yy, c)
|
||||||
|
rgba.SetRGBA(xx, yy+1, c)
|
||||||
|
rgba.SetRGBA(xx+1, yy+1, c)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
x = x + BORDER_W
|
x = x + BORDER_W
|
||||||
|
Loading…
Reference in New Issue
Block a user