Support the ThunderClock Plus card. Partial mulation of the microPD1990AC integrated circuit.
This commit is contained in:
parent
3d21387d47
commit
00e4476e86
|
@ -12,7 +12,8 @@ Portable emulator of an Apple II+. Written in Go.
|
|||
- Emulated extension cards:
|
||||
- DiskII controller
|
||||
- 16Kb Language Card
|
||||
- 256Kb Saturn RAM Card
|
||||
- 256Kb Saturn RAM
|
||||
- ThunderClock Plus real time clock
|
||||
- Graphic modes:
|
||||
- Text, Lores and Hires
|
||||
- Displays:
|
||||
|
@ -40,7 +41,7 @@ casa@servidor:~$ ./apple2sdl
|
|||
![DOS 3.3 started](doc/dos33.png)
|
||||
|
||||
### Play games
|
||||
Download an DSK file locally or use the a link ([Asimov](https://www.apple.asimov.net/images/) is an excellent source) with the `-disk` parameter:
|
||||
Download a DSK file locally or use an URL ([Asimov](https://www.apple.asimov.net/images/) is an excellent source) with the `-disk` parameter:
|
||||
```
|
||||
casa@servidor:~$ ./apple2sdl -disk "https://www.apple.asimov.net/images/games/action/karateka/karateka (includes intro).dsk"
|
||||
```
|
||||
|
@ -88,7 +89,7 @@ Line:
|
|||
- F6: Toggle between NTSC color TV and green phosphor monochrome monitor
|
||||
- F7: Save current state to disk
|
||||
- F8: Restore state from disk
|
||||
- F10: Cycle character generator codepages. Only if the character generator ROM has more than one 2Kb pages.
|
||||
- F10: Cycle character generator codepages. Only if the character generator ROM has more than one 2Kb page.
|
||||
- F12: Save a screen snapshot to a file `snapshot.png`
|
||||
|
||||
Only valid on SDL mode
|
||||
|
@ -122,6 +123,8 @@ Only valid on SDL mode
|
|||
main rom file (default "<internal>/Apple2_Plus.rom")
|
||||
-saturnCardSlot int
|
||||
slot for the 256kb Saturn card. -1 for none (default -1)
|
||||
-thunderClockCardSlot int
|
||||
slot for the ThunderClock Plus card. -1 for none (default 5)
|
||||
-traceCpu
|
||||
dump to the console the CPU execution
|
||||
-traceSS
|
||||
|
|
|
@ -87,6 +87,13 @@ func (a *Apple2) AddSaturnCard(slot int) {
|
|||
a.insertCard(&cardSaturn{}, slot)
|
||||
}
|
||||
|
||||
// AddThunderClockPlusCard inserts a ThunderClock Plus clock card
|
||||
func (a *Apple2) AddThunderClockPlusCard(slot int, romFile string) {
|
||||
var c cardThunderClockPlus
|
||||
c.loadRom(romFile)
|
||||
a.insertCard(&c, slot)
|
||||
}
|
||||
|
||||
// AddCardLogger inserts a fake card that logs accesses
|
||||
func (a *Apple2) AddCardLogger(slot int) {
|
||||
a.insertCard(&cardLogger{}, slot)
|
||||
|
|
|
@ -39,6 +39,10 @@ func MainApple() *Apple2 {
|
|||
"saturnCardSlot",
|
||||
-1,
|
||||
"slot for the 256kb Saturn card. -1 for none")
|
||||
thunderClockCardSlot := flag.Int(
|
||||
"thunderClockCardSlot",
|
||||
5,
|
||||
"slot for the ThunderClock Plus card. -1 for none")
|
||||
mono := flag.Bool(
|
||||
"mono",
|
||||
false,
|
||||
|
@ -49,7 +53,6 @@ func MainApple() *Apple2 {
|
|||
true,
|
||||
"set fast mode when the disks are spinning",
|
||||
)
|
||||
|
||||
panicSS := flag.Bool(
|
||||
"panicss",
|
||||
false,
|
||||
|
@ -94,6 +97,9 @@ func MainApple() *Apple2 {
|
|||
if *saturnCardSlot >= 0 {
|
||||
a.AddSaturnCard(*saturnCardSlot)
|
||||
}
|
||||
if *thunderClockCardSlot > 0 {
|
||||
a.AddThunderClockPlusCard(*thunderClockCardSlot, "<internal>/ThunderclockPlusROM.bin")
|
||||
}
|
||||
if *disk2Slot >= 0 {
|
||||
a.AddDisk2(*disk2Slot, *disk2RomFile, *diskImage)
|
||||
}
|
||||
|
|
Binary file not shown.
23
cardBase.go
23
cardBase.go
|
@ -11,11 +11,12 @@ type card interface {
|
|||
}
|
||||
|
||||
type cardBase struct {
|
||||
a *Apple2
|
||||
rom *memoryRange
|
||||
slot int
|
||||
ssr [16]softSwitchR
|
||||
ssw [16]softSwitchW
|
||||
a *Apple2
|
||||
rom *memoryRange
|
||||
romExtra *memoryRange
|
||||
slot int
|
||||
ssr [16]softSwitchR
|
||||
ssw [16]softSwitchW
|
||||
}
|
||||
|
||||
func (c *cardBase) loadRom(filename string) {
|
||||
|
@ -23,7 +24,12 @@ func (c *cardBase) loadRom(filename string) {
|
|||
panic("Rom must be loaded before inserting the card in the slot")
|
||||
}
|
||||
data := loadResource(filename)
|
||||
c.rom = newMemoryRange(0, data)
|
||||
if len(data) >= 0x100 {
|
||||
c.rom = newMemoryRange(0, data)
|
||||
}
|
||||
if len(data) >= 0x800 {
|
||||
c.romExtra = newMemoryRange(0, data)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cardBase) assign(a *Apple2, slot int) {
|
||||
|
@ -34,6 +40,11 @@ func (c *cardBase) assign(a *Apple2, slot int) {
|
|||
a.mmu.setPagesRead(uint8(0xc0+slot), uint8(0xc0+slot), c.rom)
|
||||
}
|
||||
|
||||
if slot != 0 && c.romExtra != nil {
|
||||
c.romExtra.base = uint16(0xc800)
|
||||
a.mmu.prepareCardExtraRom(slot, c.romExtra)
|
||||
}
|
||||
|
||||
for i := 0; i < 0x10; i++ {
|
||||
a.io.addSoftSwitchR(uint8(0xC80+slot*0x10+i), c.ssr[i])
|
||||
a.io.addSoftSwitchW(uint8(0xC80+slot*0x10+i), c.ssw[i])
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package apple2
|
||||
|
||||
/*
|
||||
ThunderClock`, real time clock card.
|
||||
|
||||
See:
|
||||
https://ia800706.us.archive.org/22/items/ThunderClock_Plus/ThunderClock_Plus.pdf
|
||||
https://prodos8.com/docs/technote/01/
|
||||
https://www.semiee.com/file/backup/NEC-D1990.pdf
|
||||
|
||||
|
||||
uPD1990AC hookup:
|
||||
bit 0 = data in
|
||||
bit 1 = CLK
|
||||
bit 2 = STB
|
||||
bit 3 = C0
|
||||
bit 4 = C1
|
||||
bit 5 = C2
|
||||
bit 7 = data out
|
||||
*/
|
||||
|
||||
type cardThunderClockPlus struct {
|
||||
microPD1990ac
|
||||
cardBase
|
||||
}
|
||||
|
||||
func (c *cardThunderClockPlus) assign(a *Apple2, slot int) {
|
||||
c.ssr[0] = func(*ioC0Page) uint8 {
|
||||
bit := c.microPD1990ac.out()
|
||||
// Get the next data bit from uPD1990AC on the MSB
|
||||
if bit {
|
||||
return 0x80
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
c.ssw[0] = func(_ *ioC0Page, value uint8) {
|
||||
dataIn := (value & 0x01) == 1
|
||||
clock := ((value >> 1) & 0x01) == 1
|
||||
strobe := ((value >> 2) & 0x01) == 1
|
||||
command := (value >> 3) & 0x07
|
||||
/* fmt.Printf("[cardThunderClock] dataIn %v, clock %v, strobe %v, command %v.\n",
|
||||
dataIn, clock, strobe, command) */
|
||||
|
||||
c.microPD1990ac.in(clock, strobe, command, dataIn)
|
||||
}
|
||||
|
||||
c.cardBase.assign(a, slot)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package apple2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
@ -14,9 +15,13 @@ type memoryManager struct {
|
|||
activeMemoryWrite [256]memoryHandler
|
||||
|
||||
// Pages prepared to be paged in and out
|
||||
physicalMainRAM *memoryRange // 0x0000 to 0xbfff, Up to 48 Kb
|
||||
physicalROM *memoryRange // 0xd000 to 0xffff, 12 Kb
|
||||
physicalROMe *memoryRange // 0xc000 to 0xcfff, Zero or 4bk in the Apple2e
|
||||
physicalMainRAM *memoryRange // 0x0000 to 0xbfff, Up to 48 Kb
|
||||
physicalROM memoryHandler // 0xd000 to 0xffff, 12 Kb
|
||||
physicalROMe memoryHandler // 0xc000 to 0xcfff, Zero or 4bk in the Apple2e
|
||||
|
||||
// Pages prapared for optional card ROM banks
|
||||
activeSlot uint8
|
||||
cardsROMExtra [8]memoryHandler // 0xc800 to 0xcfff. for each card
|
||||
}
|
||||
|
||||
type memoryHandler interface {
|
||||
|
@ -28,14 +33,28 @@ const (
|
|||
ioC8Off uint16 = 0xCFFF
|
||||
)
|
||||
|
||||
// Peek returns the data on the given address
|
||||
func (mmu *memoryManager) Peek(address uint16) uint8 {
|
||||
func (mmu *memoryManager) access(address uint16, activeMemory [256]memoryHandler) memoryHandler {
|
||||
if address == ioC8Off {
|
||||
mmu.resetSlotExpansionRoms()
|
||||
}
|
||||
|
||||
hi := uint8(address >> 8)
|
||||
mh := mmu.activeMemoryRead[hi]
|
||||
if hi >= 0xC1 && hi <= 0xC7 {
|
||||
slot := hi - 0xC0
|
||||
if slot != mmu.activeSlot {
|
||||
mmu.activateCardRomExtra(slot)
|
||||
}
|
||||
}
|
||||
mh := activeMemory[hi]
|
||||
if mh == nil {
|
||||
return nil
|
||||
}
|
||||
return mh
|
||||
}
|
||||
|
||||
// Peek returns the data on the given address
|
||||
func (mmu *memoryManager) Peek(address uint16) uint8 {
|
||||
mh := mmu.access(address, mmu.activeMemoryRead)
|
||||
if mh == nil {
|
||||
return 0xf4 // Or some random number
|
||||
}
|
||||
|
@ -44,11 +63,7 @@ func (mmu *memoryManager) Peek(address uint16) uint8 {
|
|||
|
||||
// Poke sets the data at the given address
|
||||
func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
||||
if address == ioC8Off {
|
||||
mmu.resetSlotExpansionRoms()
|
||||
}
|
||||
hi := uint8(address >> 8)
|
||||
mh := mmu.activeMemoryWrite[hi]
|
||||
mh := mmu.access(address, mmu.activeMemoryWrite)
|
||||
if mh == nil {
|
||||
return
|
||||
}
|
||||
|
@ -82,15 +97,29 @@ func (mmu *memoryManager) setPagesWrite(begin uint8, end uint8, mh memoryHandler
|
|||
}
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) prepareCardExtraRom(slot int, mh memoryHandler) {
|
||||
mmu.cardsROMExtra[slot] = mh
|
||||
}
|
||||
|
||||
// When 0xcfff is accessed the card expansion rom is unassigned
|
||||
func (mmu *memoryManager) resetSlotExpansionRoms() {
|
||||
if mmu.apple2.io.isSoftSwitchActive(ioFlagIntCxRom) {
|
||||
// Ignore if the Apple2 shadow ROM is active
|
||||
return
|
||||
}
|
||||
mmu.activeSlot = 0
|
||||
mmu.setPagesRead(0xc8, 0xcf, nil)
|
||||
}
|
||||
|
||||
// When a card base ROM is accesed the extra rom is assigned if available
|
||||
func (mmu *memoryManager) activateCardRomExtra(slot uint8) {
|
||||
//fmt.Printf("Activate slot %v\n", slot)
|
||||
if mmu.cardsROMExtra[slot] != nil {
|
||||
mmu.setPagesRead(0xC8, 0xCF, mmu.cardsROMExtra[slot])
|
||||
}
|
||||
mmu.activeSlot = slot
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) resetRomPaging() {
|
||||
// Assign the first 12kb of ROM from 0xd000 to 0xffff
|
||||
mmu.setPagesRead(0xd0, 0xff, mmu.physicalROM)
|
||||
|
@ -114,9 +143,14 @@ func newMemoryManager(a *Apple2) *memoryManager {
|
|||
|
||||
func (mmu *memoryManager) save(w io.Writer) {
|
||||
mmu.physicalMainRAM.save(w)
|
||||
binary.Write(w, binary.BigEndian, mmu.activeSlot)
|
||||
|
||||
}
|
||||
|
||||
func (mmu *memoryManager) load(r io.Reader) {
|
||||
mmu.physicalMainRAM.load(r)
|
||||
binary.Read(r, binary.BigEndian, &mmu.activeSlot)
|
||||
mmu.activateCardRomExtra(mmu.activeSlot)
|
||||
|
||||
mmu.resetBaseRamPaging()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
package apple2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
microPD1990ac Serial I/O Calendar Clock IC
|
||||
See:
|
||||
https://www.semiee.com/file/backup/NEC-D1990.pdf
|
||||
|
||||
Used by the ThunderClock+ real time clock card.
|
||||
|
||||
The 40 bit register has 5 bytes (10 nibbles):
|
||||
byte 4:
|
||||
month, binary from 1 to 12
|
||||
day of week, BCD 0 to 6
|
||||
byte 3: day of month, BCD 1 to 31
|
||||
byte 2: hour, BCD 0 to 23
|
||||
byte 1: minute, BCD 0 to 59
|
||||
byte 0: seconds, BCD 0 to 59
|
||||
|
||||
*/
|
||||
|
||||
type microPD1990ac struct {
|
||||
clock bool // CLK state
|
||||
strobe bool // STB state
|
||||
command uint8 // C0, C1, C2 command. From 0 to 7
|
||||
register uint64 // 40 bit shift register
|
||||
}
|
||||
|
||||
const (
|
||||
mpd1990commandRegHold = 0
|
||||
mpd1990commandRegShift = 1
|
||||
mpd1990commandTimeSet = 2
|
||||
mpd1990commandTimeRead = 3
|
||||
)
|
||||
|
||||
func (m *microPD1990ac) in(clock bool, strobe bool, command uint8, dataIn bool) {
|
||||
// Detect signal raise
|
||||
clockRaise := clock && !m.clock
|
||||
strobeRaise := strobe && !m.strobe
|
||||
|
||||
// Update signal status
|
||||
m.clock = clock
|
||||
m.strobe = strobe
|
||||
|
||||
// On strobe raise, update command and execute if needed
|
||||
if strobeRaise {
|
||||
m.command = command
|
||||
|
||||
switch m.command {
|
||||
case mpd1990commandRegShift:
|
||||
// Nothing to do
|
||||
case mpd1990commandTimeRead:
|
||||
m.loadTime()
|
||||
default:
|
||||
panic(fmt.Sprintf("PD1990ac command %v not implemented.", m.command))
|
||||
}
|
||||
}
|
||||
|
||||
// On clock raise, with shift enable, shift the register
|
||||
if clockRaise && m.command == mpd1990commandRegShift {
|
||||
// Rotate right the 40 bits of the shift register
|
||||
lsb := m.register & 1
|
||||
m.register >>= 1
|
||||
m.register += lsb << 39
|
||||
}
|
||||
}
|
||||
|
||||
func (m *microPD1990ac) out() bool {
|
||||
if m.command == mpd1990commandRegHold {
|
||||
panic("Output on RegHold should be a 1Hz signal. Not implemented.")
|
||||
}
|
||||
|
||||
if m.command == mpd1990commandTimeRead {
|
||||
panic("Output on RegHold should be a 512Hz signal with LSB. Not implemented.")
|
||||
}
|
||||
|
||||
// Return the LSB of the register shift
|
||||
return (m.register & 1) == 1
|
||||
}
|
||||
|
||||
func (m *microPD1990ac) loadTime() {
|
||||
now := time.Now()
|
||||
|
||||
var register uint64
|
||||
|
||||
register = uint64(now.Month())
|
||||
register <<= 4
|
||||
register += uint64(now.Weekday())
|
||||
|
||||
day := uint64(now.Day())
|
||||
register <<= 4
|
||||
register += day / 10
|
||||
register <<= 4
|
||||
register += day % 10
|
||||
|
||||
hour := uint64(now.Hour())
|
||||
register <<= 4
|
||||
register += hour / 10
|
||||
register <<= 4
|
||||
register += hour % 10
|
||||
|
||||
minute := uint64(now.Minute())
|
||||
register <<= 4
|
||||
register += minute / 10
|
||||
register <<= 4
|
||||
register += minute % 10
|
||||
|
||||
second := uint64(now.Second())
|
||||
register <<= 4
|
||||
register += second / 10
|
||||
register <<= 4
|
||||
register += second % 10
|
||||
|
||||
m.register = register
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// To generate the resources put the files on a "files" subdirectory and run main
|
||||
// To generate the resources put the files on a "files" subdirectory and run "go run generate.go"
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ var Assets = func() http.FileSystem {
|
|||
fs := vfsgen۰FS{
|
||||
"/": &vfsgen۰DirInfo{
|
||||
name: "/",
|
||||
modTime: time.Date(2019, 6, 9, 16, 41, 30, 66545749, time.UTC),
|
||||
modTime: time.Date(2019, 9, 24, 22, 1, 11, 324155917, time.UTC),
|
||||
},
|
||||
"/Apple2_Plus.rom": &vfsgen۰CompressedFileInfo{
|
||||
name: "Apple2_Plus.rom",
|
||||
|
@ -91,6 +91,13 @@ var Assets = func() http.FileSystem {
|
|||
|
||||
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x5a\xa4\xb0\x80\x61\x11\x73\x9b\x4d\x17\x97\x8a\xcd\x07\x01\x56\x1b\xcf\xff\x9a\x75\x1b\x38\xbc\x2e\xfc\x9e\x31\x37\x8c\xf9\xc4\x0b\x81\xa7\x0a\x11\xff\x77\xed\x65\x60\xe4\xe2\xe2\xe2\x6a\xd5\x5e\xb5\xb7\xef\xc0\xde\x9e\x03\x7b\xbb\x0e\xec\xed\x3c\xb0\x20\x60\x6f\xc3\x81\x19\x9a\xcc\x5c\xac\xda\xab\xf6\x36\x1e\x58\x19\xa6\xb0\xe2\x4f\x87\xc0\xeb\x56\xb5\x56\xdb\x56\xc7\x95\x1c\xad\xea\x12\x1c\x7b\x7b\x0e\x08\xfc\xf6\xbc\x7a\xe1\x3b\x98\x71\x72\xd5\x85\xcf\xaf\x20\xac\x69\x1f\x38\x35\x26\xdc\xf7\x5c\xfb\x41\xf5\xc2\xcd\x05\xcc\xad\x0e\x60\x51\xad\x56\x1b\x30\xad\x6a\xd3\x71\xe1\x8d\xc6\x51\xdb\x0b\xfb\x96\x3a\x1c\x75\xbc\xb0\x63\xc3\xf6\x05\x61\x2d\x36\x7b\x40\x52\x91\xd7\x98\x96\xd8\x74\xcc\x64\x60\xbe\xf0\x0e\x59\x64\xa2\xda\x89\x0b\xef\x61\xdc\x0b\xed\x0b\x18\x16\x85\x9d\x32\xf8\xbd\x51\x2d\x8e\x81\x59\x0b\x84\x41\xf2\xef\x9e\xa9\x3f\xb3\x5d\x6a\x7b\x96\x81\x63\x99\xf6\x84\xdb\x3e\x8c\x1c\x0c\x20\x00\x08\x00\x00\xff\xff\xf6\x44\x71\xce\x00\x01\x00\x00"),
|
||||
},
|
||||
"/ThunderclockPlusROM.bin": &vfsgen۰CompressedFileInfo{
|
||||
name: "ThunderclockPlusROM.bin",
|
||||
modTime: time.Date(2019, 9, 24, 21, 55, 17, 674069636, time.UTC),
|
||||
uncompressedSize: 2048,
|
||||
|
||||
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x52\xc1\x6b\x23\x55\x1c\x9e\x4e\x67\x3a\xcd\xd8\x6e\x97\x76\x29\x51\x56\xfc\x95\xee\x4a\xb3\x14\x9b\x83\xae\x03\x96\xc5\xb8\x4d\x7d\x29\xd3\x74\x48\x13\xdd\x95\x25\xe4\xe0\xe1\x99\x93\x07\x0f\xb9\xa8\x39\xb8\xb0\x04\x02\x3d\x78\x48\x0a\x81\x61\x5c\xcb\xbc\x92\x66\x83\x2b\xec\xa4\x18\x8c\x20\xd8\xf7\xe6\x90\x77\xf0\x20\x82\xcb\x1e\xf6\x60\x7b\x90\x57\xb5\xec\x20\x48\x65\xd2\x52\x2f\xfe\x07\xf6\x3b\x7c\x6f\xbe\x99\xef\xf7\xfd\x3e\x86\x37\x5a\x9a\x9b\xbf\x75\xfc\xa1\x6a\xb4\x87\xa2\xde\x68\x09\x55\x50\x0d\xed\x1c\xf7\xe1\x85\x3d\x8c\x77\xab\x81\xa6\xeb\xba\x5e\x2d\x69\x18\x63\x17\x6f\x46\x14\x34\x57\x6b\x96\xb4\x56\xa0\xc5\x3e\x45\xd6\x05\xef\xcb\xeb\x5c\x79\xfa\xba\xd0\xc9\xe8\x5d\xc3\xd8\x98\x36\x2d\x4a\x9e\xbb\x7b\x9d\xe4\x1b\x9e\x42\xf4\x86\xa1\x10\xa9\x61\xa8\x98\x5e\x15\x77\xe8\xcb\xe2\x16\x5d\x14\x59\x7a\x43\x58\x74\x56\x98\x34\x2f\xde\xa3\x33\x62\x85\x5e\x13\x19\x07\xe8\xbc\xc8\x38\x73\xf4\x15\x61\x3a\x71\xba\x20\x96\x5b\x81\x86\xba\x9e\x42\x67\x44\x82\xe6\xc5\x05\x1c\x7b\x49\x37\xf6\x87\xc2\xc0\x3c\x9f\xc5\xc6\x7e\x22\x0e\x74\xfa\xe2\xe5\xed\x6e\xd5\x37\x15\xbf\x61\xa8\xe6\x02\x25\x00\x8f\x18\x19\x0d\x69\xa6\xe1\x29\xe6\x02\xad\xc0\x23\xc6\x9f\x61\x3a\x2e\xa6\x28\x88\xa5\xd8\x04\xf4\x99\x90\xc3\x62\x5a\x74\xe3\x35\xe8\xb3\x8f\x0d\x0d\x91\x48\xc3\x18\x81\x3e\x43\x8f\x8d\x11\xfe\x2c\xfc\x38\x82\xa1\xcf\x4e\xd4\xc5\x30\xe1\xab\x5d\x8c\x6b\x08\x63\x52\x45\x9b\xad\x40\x6b\x96\xb4\xae\x37\xfc\x8b\xa1\xf1\xb1\x17\x0d\x4d\x68\xf4\x4d\x3e\x5c\x2f\xf7\xb0\x8b\xb7\xf1\x5c\x01\x93\xe8\x59\x8d\xd3\x64\xaa\xc7\x65\x22\x0d\xf2\x0f\x43\x39\x3e\x90\x5d\x43\x15\x0a\x9d\xe5\x79\x5b\xc2\x54\x8f\x2b\x7b\xc6\xbe\x8e\x6a\x8e\x04\x5b\x0c\xc3\x16\x6b\x06\x5a\xc7\x50\xf9\x35\xf2\x00\x5c\x86\x6d\x05\x9f\xbe\xbf\x27\x34\xf2\x06\xb8\x8c\xff\x46\xec\xaa\x2a\x77\xfe\xf0\xc5\xf3\xe0\xb2\x3d\x7e\x44\x24\x64\xab\xf0\x80\x9d\x39\xf9\xef\xe6\x26\xc3\xdb\x58\xd7\xdd\x8a\xae\xa3\x56\xa0\x75\x0d\xd5\xb1\xe9\x62\x5b\x76\x9c\x8a\x23\x81\xcb\x3a\x5f\xf8\x7b\xe0\x32\x6a\xf3\x23\xec\x76\xbe\xfd\x57\xc0\xfd\x41\x06\x3c\x64\xf6\x70\x28\xf8\xf0\xd9\xfe\x08\xd9\x0d\x2b\x99\xb1\xd3\x8e\xf4\xaa\x50\xe8\x0d\x6e\xd9\x89\x9d\x31\x99\xda\x5c\x26\xf1\xc1\xa5\x01\x79\x67\x5c\x8e\x4d\x8c\x83\x4c\x27\xe3\xb2\x6d\x51\x89\x2b\x64\x92\x47\xe8\x54\x7c\x3a\x30\xf6\x27\x7f\x72\xc6\x10\x1c\xb3\xd8\x44\xb8\x2b\x36\x01\x5b\xcc\xb9\x04\x0f\x59\x0d\x5c\x46\x56\xc1\x65\x15\x97\x54\xc1\x65\xe6\x15\x2a\xc6\x23\xf1\x48\xb9\x21\xc9\xbf\x16\x48\x93\x1f\x11\x9b\x1f\xd6\xcb\xbd\x88\x52\x2f\xf7\xe0\x07\x96\x1a\x9c\x8c\x21\x84\x71\x01\x11\xa5\xe1\x8d\x10\xa9\xe1\xa9\x9d\x72\x4f\xff\xc4\x53\x31\x8a\x0d\x85\x6e\xb9\x5e\xee\xa5\x42\xc2\x45\xf4\xd8\x1b\xe1\x4f\x70\xd7\x53\xa3\xc5\x62\xb1\x58\x38\xf9\x35\xe1\x20\x58\x3e\x46\x60\xfa\x18\xa5\x02\x30\x7d\xc7\x86\x0f\x4e\xc8\x8e\x42\xc1\x6f\x05\x5a\x38\xf9\x33\xb6\xbf\x61\xfc\xef\x7b\xfc\x2f\x73\x81\xa2\x0d\x15\x2c\x5f\x0c\xc3\x6d\x1f\xeb\xfc\xb0\xe0\x58\xa1\x7b\x8e\x6b\x4e\x34\x7c\x58\x72\xa6\x06\xd6\xa0\xd0\x2c\x69\x04\xea\xe5\xde\xc1\xc1\x41\xea\xbf\x4e\xc6\x9f\x14\xde\x7f\x7a\xe5\xfe\xa5\xcf\xb3\x3f\x7e\xf4\xe7\xab\x5f\x2b\x9f\x2d\x7d\x3f\xbf\x78\xc7\xbc\x3c\xb6\x9e\x4b\xc3\xea\x5a\x1a\xb2\xb9\x24\xbc\x9b\x5c\x82\x2c\xca\xc1\x72\x26\x05\xeb\x89\x2c\x24\x33\x19\x58\x49\xa4\x61\x39\xf9\x16\xac\x26\x32\x90\xb0\x32\xb0\x9a\xb8\x0d\x2b\xb9\x34\xac\xe4\x4c\x48\xe4\xde\x86\xf5\xa4\x05\x6b\x37\xb3\x90\x5e\x7b\x07\x96\x92\x37\xa1\xd5\x6e\xb7\xa5\x01\xd9\xf6\x77\xc7\xe7\x38\xc7\x39\xfe\xb7\xf8\x27\x00\x00\xff\xff\xe3\xc4\x99\x1b\x00\x08\x00\x00"),
|
||||
},
|
||||
"/dos33.dsk": &vfsgen۰CompressedFileInfo{
|
||||
name: "dos33.dsk",
|
||||
modTime: time.Date(2019, 6, 7, 16, 50, 59, 550488426, time.UTC),
|
||||
|
@ -110,6 +117,7 @@ var Assets = func() http.FileSystem {
|
|||
fs["/BASE64A_F8.BIN"].(os.FileInfo),
|
||||
fs["/BASE64A_ROM7_CharGen.BIN"].(os.FileInfo),
|
||||
fs["/DISK2.rom"].(os.FileInfo),
|
||||
fs["/ThunderclockPlusROM.bin"].(os.FileInfo),
|
||||
fs["/dos33.dsk"].(os.FileInfo),
|
||||
}
|
||||
|
||||
|
@ -134,7 +142,7 @@ func (fs vfsgen۰FS) Open(path string) (http.File, error) {
|
|||
}
|
||||
return &vfsgen۰CompressedFile{
|
||||
vfsgen۰CompressedFileInfo: f,
|
||||
gr: gr,
|
||||
gr: gr,
|
||||
}, nil
|
||||
case *vfsgen۰DirInfo:
|
||||
return &vfsgen۰Dir{
|
||||
|
|
Loading…
Reference in New Issue