mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-01-30 05:34:27 +00:00
Videx Videoterm 80 columns card support. Videx Soft Video Switch support
This commit is contained in:
parent
f34b3da510
commit
dfb8b1ffb2
@ -26,6 +26,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||
- ThunderClock Plus real time clock
|
||||
- Apple //e 80 columns with 64Kb extra RAM and optional RGB modes
|
||||
- No Slot Clock based on the DS1216
|
||||
- Videx Videoterm 80 column card with the Videx Soft Video Switch (Apple ][+ only)
|
||||
- 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
|
||||
@ -35,7 +36,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||
|
||||
- Graphic modes:
|
||||
- Text 40 columns
|
||||
- Text 80 columns (Apple //e only)
|
||||
- Text 80 columns (Apple //e and Videx VideoTerm)
|
||||
- Low-Resolution graphics
|
||||
- Double-Width Low-Resolution graphics (Apple //e only)
|
||||
- High-Resolution graphics
|
||||
@ -231,6 +232,8 @@ Only valid on SDL mode
|
||||
dump to the console the sofswitch registrations
|
||||
-vidHDSlot int
|
||||
slot for the VidHD card, only for //e models. -1 for none (default 2)
|
||||
-videxCardSlot int
|
||||
slot for the Videx Videoterm 80 columns card. For pre-2e models. -1 for none (default 3)
|
||||
|
||||
|
||||
```
|
||||
|
@ -15,6 +15,7 @@ type Apple2 struct {
|
||||
io *ioC0Page
|
||||
cg *CharacterGenerator
|
||||
cards [8]Card
|
||||
softVideoSwitch *SoftVideoSwitch
|
||||
isApple2e bool
|
||||
commandChannel chan int
|
||||
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
||||
@ -53,7 +54,7 @@ func (a *Apple2) Run() {
|
||||
for i := 0; i < cpuSpinLoops; i++ {
|
||||
// Conditional tracing
|
||||
//pc, _ := a.cpu.GetPCAndSP()
|
||||
//a.cpu.SetTrace(pc >= 0x300 && pc <= 0x400)
|
||||
//a.cpu.SetTrace((pc >= 0xc300 && pc <= 0xc400) || (pc >= 0xc800 && pc <= 0xce00))
|
||||
|
||||
// Execution
|
||||
a.cpu.ExecuteInstruction()
|
||||
|
@ -158,6 +158,13 @@ func (a *Apple2) AddMouseCard(slot int) {
|
||||
a.insertCard(NewCardMouse(), slot)
|
||||
}
|
||||
|
||||
// AddVidexCard inserts a Videx card
|
||||
func (a *Apple2) AddVidexCard(slot int) {
|
||||
c := NewCardVidex()
|
||||
a.insertCard(c, slot)
|
||||
a.softVideoSwitch = NewSoftVideoSwitch(c)
|
||||
}
|
||||
|
||||
// AddRGBCard inserts an RBG option to the Apple IIe 80 col 64KB card
|
||||
func (a *Apple2) AddRGBCard() {
|
||||
setupRGBCard(a)
|
||||
|
@ -82,6 +82,10 @@ func MainApple() *Apple2 {
|
||||
"mouseCardSlot",
|
||||
4,
|
||||
"slot for the Mouse card. -1 for none")
|
||||
videxCardSlot := flag.Int(
|
||||
"videxCardSlot",
|
||||
3,
|
||||
"slot for the Videx Videoterm 80 columns card. For pre-2e models. -1 for none")
|
||||
nsc := flag.Int(
|
||||
"nsc",
|
||||
-1,
|
||||
@ -204,11 +208,17 @@ func MainApple() *Apple2 {
|
||||
}
|
||||
charGenMap = charGenColumnsMapBase64a
|
||||
*vidHDCardSlot = -1
|
||||
*videxCardSlot = -1 // The videx firmware crashes the BASE64A, probably by use of ANN0
|
||||
|
||||
default:
|
||||
panic("Model not supported")
|
||||
}
|
||||
|
||||
if a.isApple2e {
|
||||
// Videx not used on Apple IIe
|
||||
*videxCardSlot = -1
|
||||
}
|
||||
|
||||
a.cpu.SetTrace(*traceCPU)
|
||||
|
||||
// Load ROM if not loaded already
|
||||
@ -249,6 +259,9 @@ func MainApple() *Apple2 {
|
||||
if *mouseCardSlot > 0 {
|
||||
a.AddMouseCard(*mouseCardSlot)
|
||||
}
|
||||
if *videxCardSlot > 0 {
|
||||
a.AddVidexCard(*videxCardSlot)
|
||||
}
|
||||
|
||||
if *smartPortImage != "" {
|
||||
err := a.AddSmartPortDisk(5, *smartPortImage, *traceHD)
|
||||
|
18
cardBase.go
18
cardBase.go
@ -1,6 +1,8 @@
|
||||
package izapple2
|
||||
|
||||
import "github.com/ivanizag/izapple2/storage"
|
||||
import (
|
||||
"github.com/ivanizag/izapple2/storage"
|
||||
)
|
||||
|
||||
// Card represents an Apple II card to be inserted in a slot
|
||||
type Card interface {
|
||||
@ -15,9 +17,9 @@ type Card interface {
|
||||
type cardBase struct {
|
||||
a *Apple2
|
||||
name string
|
||||
romCsxx *memoryRangeROM
|
||||
romC8xx *memoryRangeROM
|
||||
romCxxx *memoryRangeROM
|
||||
romCsxx memoryHandler
|
||||
romC8xx memoryHandler
|
||||
romCxxx memoryHandler
|
||||
|
||||
slot int
|
||||
_ssr [16]softSwitchR
|
||||
@ -54,8 +56,14 @@ func (c *cardBase) loadRom(data []uint8) {
|
||||
if len(data) == 0x100 {
|
||||
// Just 256 bytes in Cs00
|
||||
c.romCsxx = newMemoryRangeROM(0, data, "Slot ROM")
|
||||
} else if len(data) == 0x400 {
|
||||
// The file has C800 to CBFF for ROM
|
||||
// The 256 bytes in Cx00 are copied from the last page in C800-CBFF
|
||||
// Used on the Videx 80 columns card
|
||||
c.romCsxx = newMemoryRangeROM(0, data[0x300:], "Slot ROM")
|
||||
c.romC8xx = newMemoryRangeROM(0xc800, data, "Slot C8 ROM")
|
||||
} else if len(data) == 0x800 {
|
||||
// The file has C800 to C8FF
|
||||
// The file has C800 to CFFF
|
||||
// The 256 bytes in Cx00 are copied from the first page in C800
|
||||
c.romCsxx = newMemoryRangeROM(0, data, "Slot ROM")
|
||||
c.romC8xx = newMemoryRangeROM(0xc800, data, "Slot C8 ROM")
|
||||
|
@ -6,6 +6,10 @@ from controlled speed to max speed the emulator can do.
|
||||
Note: It ends up not being useful for Total Replay as loading from HD is already
|
||||
very fast. HD blocks are loaded directly on the emulated RAM.
|
||||
|
||||
Note that it doesn't intefere with the Apple IIe 80 columns in slot 3. It doesn't
|
||||
have ROM or slot specific sofswitches.
|
||||
|
||||
|
||||
See:
|
||||
https://github.com/a2-4am/4cade/blob/master/src/hw.accel.a
|
||||
http://www.a2heaven.com/webshop/resources/pdf_document/18/82/c.pdf
|
||||
@ -26,15 +30,9 @@ type CardFastChip struct {
|
||||
func NewCardFastChip() *CardFastChip {
|
||||
var c CardFastChip
|
||||
c.name = "FASTChip IIe Card - limited"
|
||||
c.loadRom(buildFastChipRom())
|
||||
return &c
|
||||
}
|
||||
|
||||
func buildFastChipRom() []uint8 {
|
||||
data := make([]uint8, 256)
|
||||
return data
|
||||
}
|
||||
|
||||
const (
|
||||
fastChipUnlockToken = 0x6a
|
||||
fastChipUnlockRepeats = 4
|
||||
|
@ -28,7 +28,7 @@ func (c *CardLogger) assign(a *Apple2, slot int) {
|
||||
return 0
|
||||
}, "LOGGERR")
|
||||
c.addCardSoftSwitchW(i, func(_ *ioC0Page, value uint8) {
|
||||
fmt.Printf("[cardLogger] Write access to softswith 0x%x for slot %v, value 0x%v.\n", iCopy, slot, value)
|
||||
fmt.Printf("[cardLogger] Write access to softswith 0x%x for slot %v, value 0x%02x.\n", iCopy, slot, value)
|
||||
}, "LOGGERW")
|
||||
}
|
||||
|
||||
|
163
cardVidex.go
Normal file
163
cardVidex.go
Normal file
@ -0,0 +1,163 @@
|
||||
package izapple2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/ivanizag/izapple2/component"
|
||||
"github.com/ivanizag/izapple2/storage"
|
||||
)
|
||||
|
||||
/*
|
||||
Videx 80 columns card for the Apple II+
|
||||
|
||||
See:
|
||||
https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/80%20Column%20Cards/Videx%20Videoterm/Manuals/Videx%20Videoterm%20-%20Installation%20and%20Operation%20Manual.pdf
|
||||
http://bitsavers.trailing-edge.com/components/motorola/_dataSheets/6845.pdf
|
||||
https://glasstty.com/?p=660
|
||||
|
||||
*/
|
||||
|
||||
// CardVidex represents a Videx compatible 80 column card
|
||||
type CardVidex struct {
|
||||
cardBase
|
||||
mc6845 component.MC6845
|
||||
sramPage uint8
|
||||
sram [0x800]uint8
|
||||
upperROM memoryHandler
|
||||
charGen []uint8
|
||||
}
|
||||
|
||||
// NewCardVidex creates a new CardVidex
|
||||
func NewCardVidex() *CardVidex {
|
||||
var c CardVidex
|
||||
c.name = "Videx 80 col Card"
|
||||
|
||||
// The C800 area has ROM and RAM
|
||||
c.loadRomFromResource("<internal>/Videx Videoterm ROM 2.4.bin")
|
||||
c.upperROM = c.romC8xx
|
||||
c.romC8xx = &c
|
||||
|
||||
// The resource should be internal and never fail
|
||||
c.loadCharacterMap("<internal>/80ColumnP110.BIN")
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *CardVidex) loadCharacterMap(filename string) error {
|
||||
bytes, _, err := storage.LoadResource(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
size := len(bytes)
|
||||
if size < 0x800 {
|
||||
return errors.New("Character ROM size not supported for Videx")
|
||||
}
|
||||
c.charGen = bytes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CardVidex) assign(a *Apple2, slot int) {
|
||||
for i := uint8(0x0); i <= 0xf; i++ {
|
||||
// Bit 0 goes to the RS pin of the MC6548. It controls
|
||||
// whether a register is being accesed or the contents
|
||||
// of the register is being accessed
|
||||
rsPin := (i & 1) == 1
|
||||
|
||||
// Bits 2 and 3 determine which page will be selected
|
||||
sramPage := i >> 2
|
||||
|
||||
ssName := fmt.Sprintf("VIDEXPAGE%v", sramPage)
|
||||
if rsPin {
|
||||
ssName += "REG"
|
||||
} else {
|
||||
ssName += "ADDRESS"
|
||||
}
|
||||
|
||||
c.addCardSoftSwitchR(i, func(*ioC0Page) uint8 {
|
||||
c.sramPage = sramPage
|
||||
return c.mc6845.Read(rsPin)
|
||||
}, ssName+"R")
|
||||
c.addCardSoftSwitchW(i, func(_ *ioC0Page, value uint8) {
|
||||
c.sramPage = sramPage
|
||||
c.mc6845.Write(rsPin, value)
|
||||
}, ssName+"W")
|
||||
}
|
||||
|
||||
c.cardBase.assign(a, slot)
|
||||
}
|
||||
|
||||
const videxRomLimit = uint16(0xcc00)
|
||||
const videxSramLimit = uint16(0xce00)
|
||||
const videxSramMask = uint16(0x01ff)
|
||||
|
||||
func (c *CardVidex) peek(address uint16) uint8 {
|
||||
if address < videxRomLimit {
|
||||
return c.upperROM.peek(address)
|
||||
} else if address < videxSramLimit {
|
||||
return c.sram[address&videxSramMask+uint16(c.sramPage)*0x200]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *CardVidex) poke(address uint16, value uint8) {
|
||||
if address >= videxRomLimit && address < videxSramLimit {
|
||||
c.sram[address&videxSramMask+uint16(c.sramPage)*0x200] = value
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CardVidex) setBase(base uint16) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
const (
|
||||
videxCharWidth = uint8(8)
|
||||
)
|
||||
|
||||
func (c *CardVidex) buildImage(light color.Color) *image.RGBA {
|
||||
params := c.mc6845.ImageData()
|
||||
width, height := params.DisplayedWidthHeight(videxCharWidth)
|
||||
if (width == 0) || (height == 0) {
|
||||
// No image available
|
||||
size := image.Rect(0, 0, 3, 3)
|
||||
img := image.NewRGBA(size)
|
||||
img.Set(1, 1, color.White)
|
||||
return img
|
||||
}
|
||||
|
||||
size := image.Rect(0, 0, width, height)
|
||||
img := image.NewRGBA(size)
|
||||
|
||||
params.IterateScreen(func(address uint16, charLine uint8,
|
||||
cursor bool, displayEnable bool,
|
||||
column uint8, y int) {
|
||||
|
||||
bits := uint8(0)
|
||||
if displayEnable {
|
||||
char := c.sram[address&0x7ff]
|
||||
bits = c.charGen[(uint16(char&0x7f)<<4)+uint16(charLine)]
|
||||
if cursor {
|
||||
bits = ^bits
|
||||
}
|
||||
if char >= 128 {
|
||||
bits = ^bits
|
||||
}
|
||||
}
|
||||
|
||||
x := int(column) * int(videxCharWidth)
|
||||
|
||||
for i := 0; i < int(videxCharWidth); i++ {
|
||||
pixel := (bits & 0x80) != 0
|
||||
if pixel {
|
||||
img.Set(x, y, light)
|
||||
} else {
|
||||
img.Set(x, y, color.Black)
|
||||
}
|
||||
bits <<= 1
|
||||
x++
|
||||
}
|
||||
})
|
||||
|
||||
return img
|
||||
}
|
105
component/mc6845.go
Normal file
105
component/mc6845.go
Normal file
@ -0,0 +1,105 @@
|
||||
package component
|
||||
|
||||
/*
|
||||
MC6845 CRT Controller
|
||||
See:
|
||||
Motorola MC6845 datasheet
|
||||
|
||||
Pins:
|
||||
RW, RS, D0-D7: Read() and Write()
|
||||
MA0-13, RA04, CURSOR, DE: MC6845RasterCallBack()
|
||||
*/
|
||||
|
||||
type MC6845 struct {
|
||||
reg [18]uint8 // Internal registers R0 to R17
|
||||
sel uint8 // Selected address register AR
|
||||
}
|
||||
|
||||
func (m *MC6845) Read(rs bool) uint8 {
|
||||
if !rs {
|
||||
// AR is not readable
|
||||
return 0x00
|
||||
} else if m.sel >= 14 && m.sel <= 17 {
|
||||
// Only R14 to R17 are readable
|
||||
// Should we mask R14 and R16?
|
||||
return m.reg[m.sel]
|
||||
}
|
||||
return 0x00
|
||||
}
|
||||
|
||||
func (m *MC6845) Write(rs bool, value uint8) {
|
||||
if !rs {
|
||||
// AR is 5 bits
|
||||
// What happens if AR > 17 ?
|
||||
m.sel = value & 0x1f
|
||||
} else if m.sel <= 15 {
|
||||
// R0 to R15 are writable
|
||||
m.reg[m.sel] = value
|
||||
//fmt.Printf("Set %v to %v\n", m.sel, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MC6845) ImageData() MC6845ImageData {
|
||||
var data MC6845ImageData
|
||||
|
||||
data.firstChar = uint16(m.reg[12]&0x3f)<<8 + uint16(m.reg[13])
|
||||
data.charLines = (m.reg[9] + 1) & 0x1f
|
||||
data.columns = m.reg[1]
|
||||
data.lines = m.reg[6] & 0x7f
|
||||
data.adjustLines = m.reg[5] & 0x1f
|
||||
|
||||
data.cursorPos = uint16(m.reg[14]&0x3f)<<8 + uint16(m.reg[15])
|
||||
data.cursorStart = m.reg[10] & 0x1f
|
||||
data.cursorEnd = m.reg[11] & 0x1f
|
||||
// cursor mode is on bits 6 and 5 of R10
|
||||
return data
|
||||
}
|
||||
|
||||
type MC6845ImageData struct {
|
||||
firstChar uint16 // 14 bits, address of the firt char on the first line
|
||||
charLines uint8 // 5 bits, lines par character
|
||||
columns uint8 // 8 bits, chars per line
|
||||
lines uint8 // 7 bits, char lines per screen
|
||||
adjustLines uint8 // 5 bits, extra blank lines
|
||||
|
||||
cursorPos uint16 // 14 bits, address? of the cursor position
|
||||
cursorStart uint8 // 5 bits, cursor starting char row
|
||||
cursorEnd uint8 // 5 bits, cursos ending char row
|
||||
// cursor mode
|
||||
|
||||
}
|
||||
|
||||
func (data *MC6845ImageData) DisplayedWidthHeight(charWidth uint8) (int, int) {
|
||||
return int(data.columns) * int(charWidth),
|
||||
int(data.lines)*int(data.charLines) + int(data.adjustLines)
|
||||
}
|
||||
|
||||
type MC6845RasterCallBack func(address uint16, charLine uint8, // Lookup in char ROM
|
||||
cursor bool, displayEnable bool, // Modifiers
|
||||
column uint8, y int) // Position in screen
|
||||
|
||||
func (data *MC6845ImageData) IterateScreen(callBack MC6845RasterCallBack) {
|
||||
lineAddress := data.firstChar
|
||||
y := 0
|
||||
var address uint16
|
||||
for line := uint8(0); line < data.lines; line++ {
|
||||
for charLine := uint8(0); charLine < data.charLines; charLine++ {
|
||||
address = lineAddress // Back to the first char of the line
|
||||
for column := uint8(0); column < data.columns; column++ {
|
||||
isCursor := (address == data.cursorPos) &&
|
||||
(charLine >= data.cursorStart) &&
|
||||
(charLine <= data.cursorEnd)
|
||||
callBack(address, charLine, isCursor, true, column, y)
|
||||
address = (address + 1) & 0x3fff // 14 bits
|
||||
}
|
||||
y++
|
||||
}
|
||||
lineAddress = address
|
||||
}
|
||||
for adjust := uint8(0); adjust <= data.adjustLines; adjust++ {
|
||||
for column := uint8(0); column < data.columns; column++ {
|
||||
callBack(0, 0, false, false, column, y) // lines with display not enabled
|
||||
}
|
||||
y++
|
||||
}
|
||||
}
|
@ -149,6 +149,10 @@ func (p *ioC0Page) poke(address uint16, value uint8) {
|
||||
ss(p, value)
|
||||
}
|
||||
|
||||
func (p *ioC0Page) setBase(_ uint16) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
func ssFromBool(value bool) uint8 {
|
||||
if value {
|
||||
return ssOn
|
||||
|
@ -70,6 +70,7 @@ const (
|
||||
type memoryHandler interface {
|
||||
peek(uint16) uint8
|
||||
poke(uint16, uint8)
|
||||
setBase(uint16)
|
||||
}
|
||||
|
||||
func newMemoryManager(a *Apple2) *memoryManager {
|
||||
|
@ -8,8 +8,6 @@ type memoryRange struct {
|
||||
base uint16
|
||||
data []uint8
|
||||
name string
|
||||
address string
|
||||
//basePtr uintptr
|
||||
}
|
||||
|
||||
type memoryRangeROM struct {
|
||||
@ -23,7 +21,6 @@ func newMemoryRange(base uint16, data []uint8, name string) *memoryRange {
|
||||
m.setBase(base)
|
||||
|
||||
m.name = name
|
||||
m.address = fmt.Sprintf("%p", &m)
|
||||
return &m
|
||||
}
|
||||
|
||||
@ -31,30 +28,16 @@ func newMemoryRangeROM(base uint16, data []uint8, name string) *memoryRangeROM {
|
||||
var m memoryRangeROM
|
||||
m.base = base
|
||||
m.data = data
|
||||
m.setBase(base)
|
||||
|
||||
m.name = name
|
||||
m.address = fmt.Sprintf("%p", &m)
|
||||
return &m
|
||||
}
|
||||
|
||||
func (m *memoryRange) setBase(base uint16) {
|
||||
m.base = base
|
||||
//p := unsafe.Pointer(&m.data[0])
|
||||
//m.basePtr = (uintptr)(p) - (uintptr)(base)
|
||||
}
|
||||
|
||||
func (m *memoryRange) peek(address uint16) uint8 {
|
||||
// Safe version:
|
||||
return m.data[address-m.base]
|
||||
|
||||
// Really overkill
|
||||
// go-vet warns the caching of basePtr
|
||||
// This wouldn't have a warning
|
||||
// indexp := unsafe.Pointer((uintptr)(unsafe.Pointer(&m.data[0])) - (uintptr)(m.base) + uintptr(address))
|
||||
// But it makes sense to precalculate that
|
||||
//indexp := unsafe.Pointer(m.basePtr + uintptr(address))
|
||||
//return *(*uint8)(indexp)
|
||||
}
|
||||
|
||||
func (m *memoryRange) poke(address uint16, value uint8) {
|
||||
@ -72,12 +55,12 @@ func (m *memoryRangeROM) poke(address uint16, value uint8) {
|
||||
func identifyMemory(m memoryHandler) string {
|
||||
ram, ok := m.(*memoryRange)
|
||||
if ok {
|
||||
return fmt.Sprintf("RAM 0x%04x %s at %s", ram.base, ram.name, ram.address)
|
||||
return fmt.Sprintf("RAM 0x%04x %s", ram.base, ram.name)
|
||||
}
|
||||
|
||||
rom, ok := m.(*memoryRangeROM)
|
||||
if ok {
|
||||
return fmt.Sprintf("ROM 0x%04x %s at %s", rom.base, ram.name, rom.address)
|
||||
return fmt.Sprintf("ROM 0x%04x %s", rom.base, ram.name)
|
||||
}
|
||||
|
||||
return ("Unknown memory")
|
||||
|
@ -138,6 +138,10 @@ func (nsc *noSlotClockDS1216) poke(address uint16, value uint8) {
|
||||
nsc.memory.poke(address, value)
|
||||
}
|
||||
|
||||
func (nsc *noSlotClockDS1216) setBase(base uint16) {
|
||||
nsc.memory.setBase(base)
|
||||
}
|
||||
|
||||
func (nsc *noSlotClockDS1216) loadTime() {
|
||||
now := time.Now()
|
||||
|
||||
|
@ -19,7 +19,21 @@ var Assets = func() http.FileSystem {
|
||||
fs := vfsgen۰FS{
|
||||
"/": &vfsgen۰DirInfo{
|
||||
name: "/",
|
||||
modTime: time.Date(2021, 1, 25, 17, 41, 15, 529030569, time.UTC),
|
||||
modTime: time.Date(2021, 3, 14, 16, 59, 4, 46831383, time.UTC),
|
||||
},
|
||||
"/80ColumnP109.BIN": &vfsgen۰CompressedFileInfo{
|
||||
name: "80ColumnP109.BIN",
|
||||
modTime: time.Date(2021, 3, 7, 21, 7, 53, 641037891, time.UTC),
|
||||
uncompressedSize: 1024,
|
||||
|
||||
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x93\x5f\x68\x1c\xd5\x17\xc7\xef\xee\xce\xbd\xb3\x3b\x6d\x93\x25\x69\x7e\x6c\xfb\x53\x7a\x71\xd3\x92\x95\x88\x41\x8c\x5e\x1f\x0c\x42\x1f\x9c\xac\x0b\x0d\xf8\x2e\x83\x4f\x77\x8a\x82\xbe\xc8\x80\xc4\x6c\x68\x37\x86\xd8\x95\x2b\x52\xd8\x55\x06\x02\x4d\x21\x37\x64\xc3\xa8\x2f\xd7\x92\x81\x79\x49\x99\x3b\xb1\xf4\xa2\x4f\x45\x1b\xfa\xe0\x9f\xc4\x87\x7a\xfb\x52\x06\x75\x53\x99\xf1\xd5\xb7\xf3\x3d\x1c\xee\x39\xe7\x73\xbe\x37\x14\xa8\x91\xca\x19\x3d\xc7\x67\x7c\x81\x7c\x62\x62\x12\xaf\xd9\x21\x31\x1b\xd5\xad\xb5\xc6\x68\xbf\x1d\x85\x57\xe2\xfe\x72\x74\xb8\xd6\x18\x55\x0f\xe9\x16\x07\x3e\x41\xad\x1b\x32\xaf\xd0\x06\xaf\xa9\x22\x1f\xeb\xd4\x1d\x7c\x3b\xfe\xf5\x12\x26\xf1\x00\x44\xd5\xc7\xd3\xd5\x48\x7e\xa2\x8a\xfc\x47\xb9\xac\xac\x90\x98\xf3\xaf\xf9\xc4\x0c\x7e\xca\x9e\xb5\x2c\xca\x90\x8c\x58\x71\x1e\xdb\x8d\x25\x5f\x40\xea\x7c\xb8\xf0\xf6\x99\xd3\xe5\xb1\x71\x70\x22\x3a\x01\x00\x00\x99\xfe\x7f\xb9\x76\x06\x94\xa3\x72\xa6\x7d\x01\x6f\x9e\xbf\x4f\xa0\x46\x3e\x81\xb8\x9e\xdc\x9c\xbc\x2f\x0c\x56\xf2\x85\x81\x49\x1c\x0a\x88\xaf\x26\xdb\x29\xe2\xf9\xac\xc2\xa8\x2d\x8a\x52\x7f\x39\xe2\x23\xfd\x76\xc4\xc1\x22\x31\xfa\xcb\x91\x13\x0a\x54\x29\xfa\x02\x39\x3c\xb2\x79\xfb\xa8\xa0\xfe\x1e\xcc\x44\xf4\xa8\xa0\x1e\x39\xbb\xc2\xc0\x6e\x72\x2c\x8c\x50\x18\x72\x81\x35\x79\x57\x9e\x52\x88\x03\x5f\x18\x4e\xa5\x2d\xd7\x83\x03\xf9\x31\x7b\x51\xdf\x76\x3f\x60\xcf\xeb\x69\x77\xc8\xde\xd0\x6f\xba\x43\x76\x59\x7f\x24\x4f\xb2\xa7\xf4\x3b\xee\x23\x36\xa2\x4f\xbb\x43\xb6\x9b\xe7\xaf\x07\xe3\x59\x33\x23\x6b\x76\x20\x8c\xea\x9f\xfc\x92\x2f\x8c\x90\x40\xad\x0f\x08\x6c\xd5\x13\x32\x1f\xe9\xe7\xdc\x21\xeb\xea\x07\xee\x90\xcd\xe9\x9f\xdd\x21\x3b\xab\x7e\xd8\xcd\x8b\x6c\x7c\x21\xc1\xb5\x64\x1d\x50\x17\xec\xd5\x99\x0e\xfe\xd7\x9a\x48\xf0\x40\xf6\xf4\x2f\xbf\xb7\xc2\x38\x9f\xca\x27\x70\xb3\x55\x4f\xf2\xf8\x98\xc0\x90\xc0\xbd\x3a\x7b\xeb\x80\xc0\xda\x76\x8a\x42\x82\x5c\xd8\x58\xf2\x09\xc2\x2f\x24\xfc\x54\x8e\x24\xc7\x71\x32\x0b\x73\x18\x1b\xf5\xd5\x1e\xbe\x90\xac\x03\x5c\x4b\x82\xfa\xf4\xfe\x93\xf7\x0c\xc2\x6a\xa2\xfb\xe4\x2e\x9e\xd8\x77\x3e\x9b\x22\x81\xde\x15\x06\x5f\xc7\x6e\x12\x47\x0b\x2c\x75\x42\x02\xbb\xa9\x61\x59\xb5\x77\x53\x63\x91\x20\xbb\xd9\x6c\x36\x7d\x62\x50\xcb\xb2\x2c\x5f\x94\x9c\x4f\x3d\xb3\x97\x51\xef\x7a\x30\x07\xde\x2c\x37\x4a\x96\x75\x2a\x45\x57\x67\x37\xbf\x6d\x47\x1b\xb3\x53\x3b\x1e\x74\xac\xec\xfa\x4d\x7a\xd9\xc6\x17\x13\x1a\x40\x1f\x7c\xc7\x4a\x3e\xb8\xb3\xe3\x99\x8e\xbd\x9d\x22\xfc\xdb\x7e\x66\x45\x53\x19\xb4\x35\x2e\x1b\x86\x7a\x96\x1e\xe1\xc6\x92\x7d\x20\x50\x96\x2f\xa9\x09\xba\x57\x0f\x4a\x3e\x81\x83\x14\xca\x85\x20\x3b\x7f\xab\x9e\xd0\x6e\x0a\x9d\xdc\xba\xb4\xd2\x96\x81\x32\x43\x62\x56\xaa\xaa\x22\xbf\x52\xe5\xcc\xa2\x7f\xb4\x46\x62\xf9\xb5\xaa\xf0\xe3\x57\x89\xe9\x13\xd3\x91\xdf\xa8\x0a\x2f\x3c\xfd\xaf\x68\x15\xe4\x7f\xee\x6f\xaf\xd9\x3d\xbb\xbc\x32\x7b\x8b\x52\x4a\x37\x29\xfd\x62\xab\x67\xaf\x65\xeb\x6e\x5e\x4b\x11\x9d\xb2\x17\xaa\xbc\xda\x21\x2b\xaf\x70\xb3\xf3\xd2\xca\xcb\x18\xc4\x35\xe6\xd1\x8d\x59\xfd\xcc\xea\xc0\x43\x72\x55\x9f\xbd\x07\x8a\x7a\x62\x1e\xdf\x03\x45\x35\x37\xf0\x50\x1f\x14\x03\x84\xed\x18\xbf\x2f\x79\x1b\x3f\x4e\xb0\x1d\xcb\x2f\xf5\x43\xd9\x55\xd0\xc6\x13\x09\x95\xd7\xd5\x58\xe6\xc3\x8b\x49\x00\xc3\x0c\x4c\x08\xee\x54\xda\x5d\x0f\xa9\x32\xb6\xe3\x75\x70\xcd\x43\xb7\x0e\x0f\x0f\x7d\x50\xd8\xf1\x4c\x0e\x3a\x93\x21\x81\x9d\xf3\x74\x93\x6e\x51\x87\xee\x12\xb3\x5a\xde\xf6\x50\xf4\x80\x15\x7a\xf8\x46\xcc\x97\xf0\x51\x12\x0a\x43\xa3\xa3\xd7\xd9\xf7\xee\xb9\x5a\x67\x92\xdd\x1d\x80\x48\x7e\xae\x46\xa7\xab\x51\xf6\x41\xff\x92\x57\x74\x69\xba\x1a\x11\xe7\xdc\x3f\x01\x00\x00\xff\xff\x98\xef\x4f\xd7\x00\x04\x00\x00"),
|
||||
},
|
||||
"/80ColumnP110.BIN": &vfsgen۰CompressedFileInfo{
|
||||
name: "80ColumnP110.BIN",
|
||||
modTime: time.Date(2021, 3, 14, 15, 10, 13, 458446698, time.UTC),
|
||||
uncompressedSize: 2048,
|
||||
|
||||
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x95\x3f\x6b\xdb\x4e\x18\xc7\x0f\x71\x98\x1b\x44\xf2\x60\x32\xdc\x20\xc2\x21\x34\x98\x1f\xbf\xc1\x53\x30\x45\x88\xe3\xe1\x08\xa6\x43\x31\x21\x43\x86\x0c\xc6\x53\xc6\x4e\xc5\x14\x23\x84\xe8\x10\x42\x07\x23\x32\x15\x9a\xa1\x63\x5e\x44\xc9\xd4\xd7\x91\xa1\x63\x06\x8f\x9e\xac\xa2\xab\x7d\xf7\xe8\x48\xfa\xe0\x21\x1f\x7d\xef\xbe\x77\xcf\x1f\x29\x2c\x88\xb6\x6d\xff\xf9\xa8\xb5\xf1\xf6\x92\xbf\x7f\xbd\xbd\xa5\x3d\xc4\x9e\x9f\xd7\xcf\x0f\x9b\x38\x4a\x0e\x8b\xd7\xeb\xcd\xfa\xa7\x10\xe2\xc0\x55\x55\x3d\x6c\x24\xc0\x81\x6f\x6f\x67\xaa\x20\xfa\xa6\x7a\x7a\x58\x13\xfd\x63\x55\xad\x86\xc9\xc9\xd0\xf3\x1c\x5e\x86\xc3\x98\xf0\xe9\x6f\xce\x8f\xc2\x0c\x0e\x21\x04\x31\xdf\xc7\x71\xa0\x1f\xbf\xb6\xe7\x8d\xb0\xfb\x83\x67\xc7\x81\xbe\x0d\xbc\xb6\x81\x7f\x1b\xe8\x61\xf9\xb7\x81\xff\x36\xf0\x6f\x03\xbd\x0d\x74\x1a\xb2\x0b\x26\x1d\x9f\x9d\x0d\x33\xaa\x67\x59\x99\x95\x99\x7f\x24\x8a\x69\x3e\x5c\xb9\xf2\xb3\xc5\xfd\x0d\xfc\x7f\xf1\xd5\xb1\x9a\xcd\x16\xf7\xb7\x9f\x88\xbf\x00\xea\x17\x83\x52\x0a\x5c\x7b\xd8\x58\x70\xce\xc5\xd8\x31\x34\x97\x93\xcb\x86\x6c\x01\xd8\x01\x84\x77\xee\x79\x96\x61\x4e\x4c\xfa\x7c\x22\x2e\x40\xe9\xca\xf1\xc4\xdc\x35\x3f\xcc\xc4\xe7\x33\xe9\xaa\x52\x38\xce\x31\x4a\x94\xf6\x96\x25\x17\x49\x84\xb9\x63\x1e\x9f\x64\x25\xe7\x5e\xd7\xab\x88\xea\xa7\x4a\xaf\x90\x70\x69\x2f\xa0\x88\x3f\xe6\x54\xcf\x11\x8b\x88\x2f\x7b\x77\x27\xd7\xdf\x33\xc9\x77\x20\xe7\x72\xc0\x7a\xe9\xf7\x0a\x30\x97\x03\x39\x67\x34\x9f\x18\x18\x10\xfe\xf6\x78\xaf\xfd\xf9\x32\x43\x2c\x11\x1d\xaf\x10\xbb\x9f\xe3\x24\xd5\x5a\xa7\xee\x75\x65\x4b\x83\x88\x66\x49\xf2\xd7\x4b\x4d\xeb\x65\x59\xd3\xfd\x1f\x30\x3d\x75\x8c\xf6\x38\x7f\x5e\x62\xa7\xd2\xfb\x1f\x71\xce\x39\xe9\x0f\x9a\xe9\xec\xc6\xf8\xf5\xda\x86\x3f\xaf\xfe\xf5\xd8\xd4\x75\xed\xd7\x2f\x2e\xde\x9f\x13\xff\x89\xa9\xeb\x9a\xf8\x75\xc9\xd1\xfb\x75\xfa\x9d\x79\xd7\xd3\xa7\xe4\xbc\x1c\x75\x4e\xfb\xbb\x03\x1b\x34\x1f\xa4\xfd\xac\x6b\x63\x46\x23\x20\x5c\xd7\xcd\xa3\xf1\x6c\x46\x30\x32\x75\x8f\xa9\xdf\xce\xce\xeb\xce\x71\x31\xee\xc2\xcf\x67\xa5\x15\x08\x1e\x79\x7d\xd0\x85\xd7\x45\xf2\xdf\x6b\xaf\xb9\x33\x94\x12\x02\x71\xcb\x57\x5f\x3e\x3b\xd2\xdd\xf8\x92\xfe\xdb\x0a\x68\xef\x1f\x45\x05\x22\x16\x3d\xbd\x24\xf3\x94\xa4\x6a\xa9\xc8\xbc\xb3\xc8\x4e\xb8\xab\x90\xd6\xd7\x0b\xda\x7f\x11\x7c\x81\x39\xeb\x06\x80\x67\xd2\xad\x3f\xbf\x9a\x5f\x9d\x3b\x5d\x06\xf3\xc2\xd8\x4b\xd3\x34\x0d\xe1\xeb\x34\x4d\xd3\xde\xfd\x68\x7f\x6c\x87\xbb\x11\x70\x6c\xf3\x89\x7c\x45\xaf\x17\x74\x3e\x18\x2b\x74\x1e\x91\x7a\x40\x01\x00\xf4\xdf\x89\x31\x86\xcc\x8f\x9d\x80\x11\xf4\x98\xf6\x9f\x31\xcc\x64\x86\xe1\x7a\xf5\xe4\xb8\xe4\x52\xf9\xf9\x8e\x41\x8c\x05\xf9\x5e\x76\xb5\xa2\xf5\xea\x44\x20\xdf\xcf\x79\x13\x33\x1a\xd9\xb4\xb1\xbf\x3d\x7e\xff\x13\x00\x00\xff\xff\xf1\x70\x46\x09\x00\x08\x00\x00"),
|
||||
},
|
||||
"/Apple IIe Video Enhanced - 342-0265-A - 2732.bin": &vfsgen۰CompressedFileInfo{
|
||||
name: "Apple IIe Video Enhanced - 342-0265-A - 2732.bin",
|
||||
@ -133,6 +147,13 @@ var Assets = func() http.FileSystem {
|
||||
|
||||
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"),
|
||||
},
|
||||
"/Videx Videoterm ROM 2.4.bin": &vfsgen۰CompressedFileInfo{
|
||||
name: "Videx Videoterm ROM 2.4.bin",
|
||||
modTime: time.Date(2021, 3, 7, 20, 59, 17, 80032721, time.UTC),
|
||||
uncompressedSize: 1024,
|
||||
|
||||
compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\x92\x51\x68\x1c\x45\x1c\xc6\x27\x77\x3b\xbb\x77\x4b\x93\x9e\x49\xa4\x07\x5a\x32\xa6\x2d\xf5\xf0\xd4\xb4\x18\x3d\xf1\xc5\x87\x82\x9b\x63\x69\xcf\x37\x83\x45\x46\x84\x76\x23\x04\xcd\xdb\xe1\x3c\x24\x2a\x49\xd3\xea\xc8\x4a\x28\x44\x34\x70\x1e\x06\x33\x21\x8b\x9b\xf8\xd2\x08\x81\xd1\xfa\xb0\xff\x4d\x73\x99\x82\x2f\xa5\x08\x79\xaa\x69\xc0\xb2\x29\x04\x0f\x46\x13\xd9\x13\xf7\xe9\xbf\xcc\x37\xcc\xff\xfb\x7d\x5f\xc0\xac\x52\x1b\x86\x92\x67\xc4\x10\x67\x16\xd7\x96\x40\x5c\x9b\xe4\x5d\x68\xa2\x1b\x3c\x94\x1b\xdf\x46\x7c\x55\xee\xee\x14\xd4\x3e\x1f\x95\x34\xd0\x56\x29\x97\xe4\xc9\xdc\x21\x19\xfc\x9b\x5c\x3f\xf4\x96\xbc\x65\x8f\x92\xbb\xd1\x83\x8b\x2a\xf3\xe0\x52\x80\x64\xe1\x80\x5c\x8e\xfc\xa4\x5c\x90\x45\x0a\x9f\xa9\x8c\xb8\x0f\x1f\x2b\x3b\xd0\xd6\xc8\xeb\x5c\x5b\xe1\x1f\x4e\xa0\x2d\xdb\xf6\xfc\x01\x08\xfd\xa7\xca\xef\xc9\xa1\x7e\x08\x93\x1e\x90\x2a\x23\x14\xdc\xf7\x73\xa5\x6d\x65\x88\xdf\xf3\xc4\x29\x4d\x72\x66\x7a\x15\xfa\x51\xed\x9d\x17\x07\x51\xf1\x24\xca\xed\xe4\x10\x42\x88\x33\x73\xf1\xcc\x96\xc6\x89\xc9\x35\x26\x46\xbc\x78\x7a\x8b\x61\x3f\xcb\x19\x0e\x98\x49\xae\xc7\xe2\x38\x0f\x65\xc0\x30\xd4\xc2\xbe\x71\x66\xf0\x55\x29\x7a\x78\x28\x05\x1a\xd7\xe9\x0f\x1d\x91\x90\x0b\x4f\x2e\x09\x70\xd6\x1f\x6f\x3a\x74\x6f\x85\x61\xd1\x20\x13\x71\x24\x6b\x7e\x9b\x8a\x97\x38\xb3\xa8\x38\xaf\xda\x0d\xd9\x9c\x8a\xd5\x3f\xc1\x90\x9c\x55\x07\x74\x85\x61\x59\xf3\xb1\x43\x42\xf0\x56\x18\x26\x13\xf1\x23\x86\xcb\x75\xa3\x60\xfd\xf7\x94\x97\x2a\x02\x8d\x1d\x62\xc5\xc4\x80\x06\xf2\xc6\x10\x14\xfd\x24\x3c\x45\xae\xc2\x7c\xb2\x2b\x10\x67\x98\x6b\xbc\x94\xf4\xb6\x18\x2e\x2c\x88\x4b\xbc\xa3\x4f\xe6\x5a\x1a\xbb\x46\xdc\xa1\xef\xe5\xa7\x60\x55\x5d\x15\x39\xfe\x96\x54\x6f\xc3\x9a\x7a\x53\x1c\x3e\xaf\xd3\x50\x28\x67\xe6\xc5\xba\xe1\x6e\x46\xe4\x6c\xfc\x48\xa7\x37\xa1\xe8\x57\x5b\xe9\x64\x8e\x19\xa5\xc9\x34\xb3\xde\x58\x74\x77\xbc\x77\x4c\x1f\x4b\xc7\x8e\x65\x71\x82\x58\x71\x03\x11\x03\xc2\x9b\xf0\xa3\xea\x11\x5d\xdd\xda\x52\x02\x42\xf5\x8d\x9b\x8f\xdc\xb3\x10\x68\xcc\xdb\x86\x6d\x8f\xb7\x8d\x71\x6d\x3a\xd5\x6a\xb5\xca\xb5\xe1\xd9\xb6\x6d\x73\x66\x50\xe8\x56\x66\x67\x7f\x9a\x9f\x82\x46\xd8\x82\x6b\x7e\xae\xc3\x6f\x1d\x1c\x5a\x9c\xe8\x5b\x73\xe8\x0f\x0b\x8f\xfb\xfe\xff\xae\xf4\xf4\x55\x50\x3f\x2b\xce\x8f\x33\xc3\xe9\x60\x77\xec\xd2\xb1\xe5\x8d\x50\x7a\x55\x6f\x99\xda\x69\x03\xaa\xde\xfb\x0e\x19\x8d\xbd\x10\x2f\xa0\x3b\x7e\x76\x01\x6d\x51\x47\xfc\x45\x1a\xc0\x47\x65\xda\x48\x4b\x19\x9e\x7b\x2a\x2e\x19\x49\xd6\xbd\x06\x5e\xe5\x21\x29\x4d\x3a\x2d\x66\xa5\x67\x59\xf5\xa4\x07\xc5\x30\xcb\x35\x0e\xda\x29\xfb\x34\x7b\xd7\x88\x3d\xde\xc6\x34\x40\x12\xe6\xd4\xf1\x72\x41\xa6\x5d\xd4\xf0\x69\x92\x2d\x17\x24\x5d\x5a\x3f\xb7\x49\xf6\x23\x72\x21\x82\x56\x98\x03\xf0\x0d\xb8\xa3\xf6\xdc\xfd\x68\xaf\xbc\x79\xf4\xe1\xb9\x8a\x5f\xbc\x55\x7b\xae\xeb\x93\x27\xfa\x9f\x1e\x74\x51\x2a\x2b\x4d\x36\x11\x25\xdf\x43\x13\x51\x40\x49\x3e\x40\xd2\xf6\xb3\xe4\x72\xd4\x44\xf4\xcb\x67\x2b\xb7\xf8\xd1\xb6\x33\x3d\x7c\xc3\x99\x77\x16\x87\x67\x86\x9b\xb7\xbf\xa8\x1b\x4e\xad\x20\xce\x4f\x57\x66\x5e\x15\xd6\xf4\xcb\x33\xaf\x10\x14\x15\xfd\x0f\xbc\xef\x86\x93\x81\xd9\xa0\x6e\xc2\x6c\x72\xe2\x1e\xca\x24\xbd\x23\xe4\x1e\xca\xa8\xd7\x82\xba\xf9\x15\xca\x84\x59\xf2\x67\x2c\xa6\xc8\x01\xa4\x9b\x7d\x9d\xec\x03\x57\xd8\x21\x5d\xe0\xc1\x4d\xd5\x9b\xf6\x6c\x34\x0e\xf1\x46\x8a\x68\x03\x6d\xe5\xa7\x78\xdd\x54\x39\x72\x21\x6a\xa0\xcf\xeb\xe6\x4f\xbb\xbb\xbb\x0b\xa8\x4b\xa0\xe9\xd3\x81\xc6\xd3\x67\xdc\x17\x22\x6f\x45\x5b\x85\xdc\x4a\xdd\x94\x3b\x7e\xd7\x3c\x59\x8d\xc8\x76\x2c\x26\x49\x03\x02\x86\x1f\xbe\xe1\xff\x36\x36\x50\xf4\xef\xd2\xca\xc4\x1a\x43\xce\x95\x5f\x7f\xf9\xf9\xe8\xf6\xde\xbf\x01\x00\x00\xff\xff\x28\xbb\xe3\xbb\x00\x04\x00\x00"),
|
||||
},
|
||||
"/dos33.dsk": &vfsgen۰CompressedFileInfo{
|
||||
name: "dos33.dsk",
|
||||
modTime: time.Date(2021, 1, 23, 23, 12, 20, 701418936, time.UTC),
|
||||
@ -142,6 +163,8 @@ var Assets = func() http.FileSystem {
|
||||
},
|
||||
}
|
||||
fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
|
||||
fs["/80ColumnP109.BIN"].(os.FileInfo),
|
||||
fs["/80ColumnP110.BIN"].(os.FileInfo),
|
||||
fs["/Apple IIe Video Enhanced - 342-0265-A - 2732.bin"].(os.FileInfo),
|
||||
fs["/Apple IIe Video Unenhanced - 342-0133-A - 2732.bin"].(os.FileInfo),
|
||||
fs["/Apple2_Plus.rom"].(os.FileInfo),
|
||||
@ -158,6 +181,7 @@ var Assets = func() http.FileSystem {
|
||||
fs["/DISK2.rom"].(os.FileInfo),
|
||||
fs["/MemoryExpansionCard-341-0344a.bin"].(os.FileInfo),
|
||||
fs["/ThunderclockPlusROM.bin"].(os.FileInfo),
|
||||
fs["/Videx Videoterm ROM 2.4.bin"].(os.FileInfo),
|
||||
fs["/dos33.dsk"].(os.FileInfo),
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,9 @@ func snapshotByMode(vs VideoSource, videoMode uint16, screenMode int) *image.RGB
|
||||
case VideoSHR:
|
||||
snap = snapshotSuperHiRes(vs)
|
||||
applyNTSCFilter = false
|
||||
case VideoVidex:
|
||||
snap = vs.GetCardImage(lightColor)
|
||||
applyNTSCFilter = false
|
||||
}
|
||||
|
||||
if applyNTSCFilter {
|
||||
|
@ -71,6 +71,8 @@ func VideoModeName(vs VideoSource) string {
|
||||
name = "RGB160"
|
||||
case VideoSHR:
|
||||
name = "SHR"
|
||||
case VideoVidex:
|
||||
name = "VIDEX"
|
||||
default:
|
||||
name = "Unknown video mode"
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package screen
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -128,6 +130,11 @@ func (ts *TestScenario) GetSuperVideoMemory() []uint8 {
|
||||
return ts.SVideoPage
|
||||
}
|
||||
|
||||
// GetCardImage returns an image provided by a card, like the videx card
|
||||
func (ts *TestScenario) GetCardImage(light color.Color) *image.RGBA {
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildImageName(name string, screenMode int, altSet bool) string {
|
||||
var screenName string
|
||||
switch screenMode {
|
||||
|
@ -1,5 +1,10 @@
|
||||
package screen
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// Base Video Modes
|
||||
const (
|
||||
VideoBaseMask uint16 = 0x1f
|
||||
@ -14,6 +19,7 @@ const (
|
||||
VideoRGBMix uint16 = 0x12
|
||||
VideoRGB160 uint16 = 0x13
|
||||
VideoSHR uint16 = 0x14
|
||||
VideoVidex uint16 = 0x15
|
||||
)
|
||||
|
||||
// Mix text video mdes modifiers
|
||||
@ -43,4 +49,6 @@ type VideoSource interface {
|
||||
GetCharacterPixel(char uint8, rowInChar int, colInChar int, isAltText bool, isFlashedFrame bool) bool
|
||||
// GetSuperVideoMemory returns a slice to the SHR video memory
|
||||
GetSuperVideoMemory() []uint8
|
||||
// GetCardImage returns an image provided by a card, like the videx card
|
||||
GetCardImage(light color.Color) *image.RGBA
|
||||
}
|
||||
|
44
softVideoSwitch.go
Normal file
44
softVideoSwitch.go
Normal file
@ -0,0 +1,44 @@
|
||||
package izapple2
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
/*
|
||||
Videx Soft Video Switch
|
||||
|
||||
See:
|
||||
https://archive.org/details/videx-soft-video-switch
|
||||
|
||||
*/
|
||||
|
||||
// SoftVideoSwitch represents a Videx soft video switch
|
||||
type SoftVideoSwitch struct {
|
||||
card *CardVidex
|
||||
}
|
||||
|
||||
// NewSoftVideoSwitch creates a new SoftVideoSwitch
|
||||
func NewSoftVideoSwitch(card *CardVidex) *SoftVideoSwitch {
|
||||
var vs SoftVideoSwitch
|
||||
vs.card = card
|
||||
return &vs
|
||||
}
|
||||
|
||||
func (vs *SoftVideoSwitch) isActive() bool {
|
||||
if vs == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
isTextMode := vs.card.a.io.isSoftSwitchActive(ioFlagText)
|
||||
ann0 := vs.card.a.io.isSoftSwitchActive(ioFlagAnnunciator0)
|
||||
return isTextMode && ann0
|
||||
}
|
||||
|
||||
func (vs *SoftVideoSwitch) BuildAlternateImage(light color.Color) *image.RGBA {
|
||||
return vs.card.buildImage(light)
|
||||
}
|
||||
|
||||
func (a *Apple2) SoftVideoSwitch() *SoftVideoSwitch {
|
||||
return a.softVideoSwitch
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
package izapple2
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/ivanizag/izapple2/screen"
|
||||
)
|
||||
|
||||
@ -23,6 +26,7 @@ func (a *Apple2) GetCurrentVideoMode() uint16 {
|
||||
isStore80Active := a.mmu.store80Active
|
||||
isDoubleResMode := !isTextMode && is80Columns && !a.io.isSoftSwitchActive(ioFlagAnnunciator3)
|
||||
isSuperHighResMode := a.io.isSoftSwitchActive(ioDataNewVideo)
|
||||
isVidex := a.softVideoSwitch.isActive()
|
||||
|
||||
isRGBCard := a.io.isSoftSwitchActive(ioFlagRGBCardActive)
|
||||
rgbFlag1 := a.io.isSoftSwitchActive(ioFlag1RGBCard)
|
||||
@ -39,6 +43,9 @@ func (a *Apple2) GetCurrentVideoMode() uint16 {
|
||||
if isSuperHighResMode {
|
||||
mode = screen.VideoSHR
|
||||
isMixMode = false
|
||||
} else if isVidex {
|
||||
mode = screen.VideoVidex
|
||||
isMixMode = false
|
||||
} else if isTextMode {
|
||||
if is80Columns {
|
||||
mode = screen.VideoText80
|
||||
@ -137,6 +144,11 @@ func (a *Apple2) GetCharacterPixel(char uint8, rowInChar int, colInChar int, isA
|
||||
return pixel
|
||||
}
|
||||
|
||||
// GetCardImage returns an image provided by a card, like the videx card
|
||||
func (a *Apple2) GetCardImage(light color.Color) *image.RGBA {
|
||||
return a.softVideoSwitch.BuildAlternateImage(light)
|
||||
}
|
||||
|
||||
// DumpTextModeAnsi returns the text mode contents using ANSI escape codes for reverse and flash
|
||||
func DumpTextModeAnsi(a *Apple2) string {
|
||||
is80Columns := a.io.isSoftSwitchActive(ioFlag80Col)
|
||||
|
Loading…
x
Reference in New Issue
Block a user