Support for text mode rendering

This commit is contained in:
Ivan Izaguirre 2019-04-21 21:04:02 +02:00
parent 016e1ea875
commit 2cd3ed3a48
9 changed files with 192 additions and 10 deletions

View File

@ -89,7 +89,7 @@ func ansiCursorUp(steps int) {
fmt.Printf("\033[%vA", steps)
}
func (fe *ansiConsoleFrontend) textModeGoRoutine() {
func (fe *ansiConsoleFrontend) textModeGoRoutineFast() {
fe.extraLineFeeds = make(chan int, 100)
fmt.Printf(strings.Repeat("\n", 26))
@ -112,7 +112,7 @@ func (fe *ansiConsoleFrontend) textModeGoRoutine() {
// See "Understand the Apple II", page 5-10
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchExtActive(ioFlagAltChar)
isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchActive(ioFlagAltChar)
var i, j, h, c uint8
// Top, middle and botton screen
for i = 0; i < 120; i = i + 40 {
@ -139,6 +139,52 @@ func (fe *ansiConsoleFrontend) textModeGoRoutine() {
}
}
func (fe *ansiConsoleFrontend) textModeGoRoutine() {
fe.extraLineFeeds = make(chan int, 100)
fmt.Printf(strings.Repeat("\n", 26))
for {
if fe.textUpdated {
fe.textUpdated = false
// Go up
ansiCursorUp(26)
done := false
for !done {
select {
case lineFeeds := <-fe.extraLineFeeds:
ansiCursorUp(lineFeeds)
default:
done = true
}
}
pageIndex := 0
if fe.apple2.io.isSoftSwitchActive(ioFlagSecondPage) {
pageIndex = 1
}
isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchActive(ioFlagAltChar)
fmt.Println(strings.Repeat("#", 44))
for line := 0; line < 24; line++ {
text := ""
for col := 0; col < 40; col++ {
value := getTextChar(fe.apple2, col, line, pageIndex)
text += textMemoryByteToString(value, isAltText)
}
fmt.Printf("# %v #\n", text)
}
fmt.Println(strings.Repeat("#", 44))
if fe.stdinKeyboard {
fmt.Print("\033[KLine: ")
}
saveSnapshot(fe.apple2)
}
time.Sleep(refreshDelayMs * time.Millisecond)
}
}
func textMemoryByteToString(value uint8, isAltCharSet bool) string {
// See https://en.wikipedia.org/wiki/Apple_II_character_set
// Supports the new lowercase characters in the Apple2e

View File

@ -11,6 +11,7 @@ type Apple2 struct {
cpu *core6502.State
mmu *memoryManager
io *ioC0Page
cg *CharacterGenerator
cards []cardBase
isApple2e bool
panicSS bool
@ -18,11 +19,14 @@ type Apple2 struct {
}
// NewApple2 instantiates an apple2
func NewApple2(romFile string, panicSS bool) *Apple2 {
func NewApple2(romFile string, charRomFile string, panicSS bool) *Apple2 {
var a Apple2
a.mmu = newMemoryManager(&a)
a.cpu = core6502.NewNMOS6502(a.mmu)
a.loadRom(romFile)
if charRomFile != "" {
a.cg = NewCharacterGenerator(charRomFile)
}
a.mmu.resetPaging()
a.panicSS = panicSS

View File

@ -48,7 +48,13 @@ func (cg *CharacterGenerator) load(filename string) {
buf.Read(cg.data)
}
func (cg *CharacterGenerator) dumpChar(char uint8) {
func (cg *CharacterGenerator) getPixel(char uint8, row int, column int) bool {
bits := cg.data[int(char)*8+row]
bit := bits >> (uint(6 - column)) & 1
return bit == 1
}
func (cg *CharacterGenerator) dumpCharFast(char uint8) {
base := int(char) * 8
fmt.Printf("Char: %v\n---------\n", char)
for i := 0; i < 8; i++ {
@ -66,6 +72,23 @@ func (cg *CharacterGenerator) dumpChar(char uint8) {
fmt.Println("---------")
}
func (cg *CharacterGenerator) dumpChar(char uint8) {
fmt.Printf("Char: %v\n---------\n", char)
for row := 0; row < 8; row++ {
fmt.Print("|")
for col := 0; col < 7; col++ {
if cg.getPixel(char, row, col) {
fmt.Print("#")
} else {
fmt.Print(" ")
}
}
fmt.Println("|")
}
fmt.Println("---------")
}
// Dump to sdtout all the character maps
func (cg *CharacterGenerator) Dump() {
for i := 0; i < 256; i++ {
cg.dumpChar(uint8(i))

View File

@ -15,7 +15,7 @@ type ioC0Page struct {
type softSwitchR func(io *ioC0Page) uint8
type softSwitchW func(io *ioC0Page, value uint8)
// KeyboardProvider declares the keyboard implementation requitements
// KeyboardProvider declares the keyboard implementation requirements
type KeyboardProvider interface {
GetKey(strobe bool) (key uint8, ok bool)
}
@ -61,7 +61,7 @@ func (p *ioC0Page) addSoftSwitchW(address uint8, ss softSwitchW) {
p.softSwitchesW[address] = ss
}
func (p *ioC0Page) isSoftSwitchExtActive(ioFlag uint8) bool {
func (p *ioC0Page) isSoftSwitchActive(ioFlag uint8) bool {
return (p.softSwitchesData[ioFlag] & ssOn) == ssOn
}
@ -81,6 +81,10 @@ func (p *ioC0Page) Peek(address uint8) uint8 {
return ss(p)
}
func (p *ioC0Page) internalPeek(address uint8) uint8 {
return 0
}
func (p *ioC0Page) Poke(address uint8, value uint8) {
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
ss := p.softSwitchesW[address]

View File

@ -19,6 +19,7 @@ type memoryManager struct {
type memoryPage interface {
Peek(uint8) uint8
Poke(uint8, uint8)
internalPeek(uint8) uint8
}
const (
@ -36,6 +37,12 @@ func (mmu *memoryManager) Peek(address uint16) uint8 {
return mmu.activeMemory[hi].Peek(lo)
}
func (mmu *memoryManager) internalPeek(address uint16) uint8 {
hi := uint8(address >> 8)
lo := uint8(address)
return mmu.activeMemory[hi].internalPeek(lo)
}
// Poke sets the data at the given address
func (mmu *memoryManager) Poke(address uint16, value uint8) {
if address == ioC8Off {
@ -55,7 +62,7 @@ func (mmu *memoryManager) setPage(index uint8, page memoryPage) {
// When 0xcfff is accessed the card expansion rom is unassigned
func (mmu *memoryManager) resetSlotExpansionRoms() {
if mmu.apple2.io.isSoftSwitchExtActive(ioFlagIntCxRom) {
if mmu.apple2.io.isSoftSwitchActive(ioFlagIntCxRom) {
// Ignore if the Apple2 shadow ROM is active
return
}

94
apple2/screen.go Normal file
View File

@ -0,0 +1,94 @@
package apple2
import (
"fmt"
"image"
"image/color"
"image/png"
"os"
)
func snapshot(a *Apple2) image.Image {
isTextMode := a.io.isSoftSwitchActive(ioFlagGraphics)
is80ColMode := a.io.isSoftSwitchActive(ioFlag80Col)
pageIndex := 0
if a.io.isSoftSwitchActive(ioFlagSecondPage) {
pageIndex = 1
}
if isTextMode && !is80ColMode {
//Text mode
return snapshotTextMode(a, pageIndex)
}
fmt.Printf("t: %v, 8: %v\n", isTextMode, is80ColMode)
return nil
//panic("Screen mode not supported")
}
func saveSnapshot(a *Apple2) {
img := snapshot(a)
if img == nil {
return
}
f, err := os.Create("snapshot.png")
if err != nil {
panic(err)
}
defer f.Close()
fmt.Println("Saving snapshot")
png.Encode(f, img)
}
const (
charWidth = 7
charHeight = 8
textColumns = 40
textLines = 24
textPage1Address = uint16(0x400)
textPage2Address = uint16(0x400)
)
func getTextChar(a *Apple2, col int, line int, page int) uint8 {
address := textPage1Address
if page == 1 {
address = textPage2Address
}
// See "Understand the Apple II", page 5-10
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
section := line / 8 // Top, middle and bottom
eigth := line % 8
address += uint16(section*40 + eigth*0x80 + col)
return a.mmu.internalPeek(address)
}
func snapshotTextMode(a *Apple2, page int) image.Image {
width := textColumns * charWidth
height := textLines * charHeight
size := image.Rect(0, 0, width, height)
bwPalette := []color.Color{color.Black, color.White}
img := image.NewPaletted(size, bwPalette)
for x := 0; x < width; x++ {
for y := 0; y < height; y++ {
//yRev := height - y
line := y / charHeight
col := x / charWidth
rowInChar := y % charHeight
colInChar := x % charWidth
char := getTextChar(a, col, line, page)
pixel := a.cg.getPixel(char, rowInChar, colInChar)
color := uint8(0)
if pixel {
color = 1
}
img.SetColorIndex(x, y, color)
}
}
return img
}

View File

@ -60,7 +60,7 @@ func softSwitchIntCxRomOff(io *ioC0Page) {
}
func softSwitchSlotC3RomOn(io *ioC0Page) {
if io.isSoftSwitchExtActive(ioFlagIntCxRom) {
if io.isSoftSwitchActive(ioFlagIntCxRom) {
return // Ignore if allt the Apple2 shadow ROM is active
}
// TODO restore the slot 3 ROM
@ -69,7 +69,7 @@ func softSwitchSlotC3RomOn(io *ioC0Page) {
}
func softSwitchSlotC3RomOff(io *ioC0Page) {
if io.isSoftSwitchExtActive(ioFlagIntCxRom) {
if io.isSoftSwitchActive(ioFlagIntCxRom) {
return // Ignore if allt the Apple2 shadow ROM is active
}
mmu := io.apple2.mmu

View File

@ -10,6 +10,10 @@ func (p *unassignedPage) Peek(address uint8) uint8 {
return 0xdd
}
func (p *unassignedPage) internalPeek(address uint8) uint8 {
return 0xdd
}
func (p *unassignedPage) Poke(address uint8, value uint8) {
//fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
//panic(address)

View File

@ -53,7 +53,7 @@ func main() {
}
log := false
a := apple2.NewApple2(*romFile, *panicSS)
a := apple2.NewApple2(*romFile, *charRomFile, *panicSS)
a.AddDisk2(*disk2RomFile, *diskImage)
if *useSdl {
apple2sdl.SDLRun(a)