mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-21 18:29:45 +00:00
Observers on memory pages. Text memory is now regular RAM with an observer
This commit is contained in:
parent
590dfb5cec
commit
ac73b8823c
@ -21,12 +21,23 @@ type ansiConsoleFrontend struct {
|
||||
mmu *memoryManager
|
||||
keyChannel chan uint8
|
||||
extraLineFeeds chan int
|
||||
textUpdated bool
|
||||
}
|
||||
|
||||
func newAnsiConsoleFrontend(mmu *memoryManager) ansiConsoleFrontend {
|
||||
func newAnsiConsoleFrontend(mmu *memoryManager) *ansiConsoleFrontend {
|
||||
var fe ansiConsoleFrontend
|
||||
fe.mmu = mmu
|
||||
return fe
|
||||
fe.subscribeToTextPages()
|
||||
return &fe
|
||||
}
|
||||
|
||||
func (fe *ansiConsoleFrontend) subscribeToTextPages() {
|
||||
observer := func(_ uint8, _ bool) {
|
||||
fe.textUpdated = true
|
||||
}
|
||||
for i := 0x04; i < 0x08; i++ {
|
||||
fe.mmu.physicalMainRAM[i].observer = observer
|
||||
}
|
||||
}
|
||||
|
||||
const refreshDelayMs = 100
|
||||
@ -37,7 +48,8 @@ func (fe *ansiConsoleFrontend) getKey() (key uint8, ok bool) {
|
||||
for {
|
||||
byte, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
c <- byte
|
||||
}
|
||||
@ -67,12 +79,13 @@ func ansiCursorUp(steps int) {
|
||||
fmt.Printf("\033[%vA", steps)
|
||||
}
|
||||
|
||||
func (fe *ansiConsoleFrontend) textModeGoRoutine(tp *textPages) {
|
||||
func (fe *ansiConsoleFrontend) textModeGoRoutine() {
|
||||
fe.extraLineFeeds = make(chan int, 100)
|
||||
|
||||
fmt.Printf(strings.Repeat("\n", 26))
|
||||
for {
|
||||
if tp.strobe() {
|
||||
if fe.textUpdated {
|
||||
fe.textUpdated = false
|
||||
// Go up
|
||||
ansiCursorUp(26)
|
||||
done := false
|
||||
@ -90,16 +103,17 @@ func (fe *ansiConsoleFrontend) textModeGoRoutine(tp *textPages) {
|
||||
// See "Understand the Apple II", page 5-10
|
||||
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
|
||||
isAltText := fe.mmu.isApple2e && fe.mmu.ioPage.isSoftSwitchExtActive(ioFlagAltChar)
|
||||
var i, j, h uint8
|
||||
var i, j, h, c uint8
|
||||
// Top, middle and botton screen
|
||||
for i = 0; i < 120; i = i + 40 {
|
||||
// Memory pages
|
||||
for _, p := range tp.pages {
|
||||
for j = 0x04; j < 0x08; j++ {
|
||||
p := fe.mmu.physicalMainRAM[j]
|
||||
// The two half pages
|
||||
for _, h = range []uint8{0, 128} {
|
||||
line := ""
|
||||
for j = i + h; j < i+h+40; j++ {
|
||||
line += textMemoryByteToString(p.Peek(j), isAltText)
|
||||
for c = i + h; c < i+h+40; c++ {
|
||||
line += textMemoryByteToString(p.internalPeek(c), isAltText)
|
||||
}
|
||||
fmt.Printf("# %v #\n", line)
|
||||
}
|
||||
|
@ -10,8 +10,8 @@ func Run(romFile string, log bool) {
|
||||
s.Mem = mmu
|
||||
|
||||
fe := newAnsiConsoleFrontend(mmu)
|
||||
mmu.ioPage.setKeyboardProvider(&fe)
|
||||
go fe.textModeGoRoutine(mmu.textPages1)
|
||||
mmu.ioPage.setKeyboardProvider(fe)
|
||||
go fe.textModeGoRoutine()
|
||||
|
||||
// Start the processor
|
||||
core6502.Reset(&s)
|
||||
|
@ -18,8 +18,7 @@ type memoryManager struct {
|
||||
unassignedExpansionROM []unassignedPage // 0xc000 to 0xcfff
|
||||
ioPage *ioC0Page // 0xc000 to 0xc080
|
||||
isApple2e bool
|
||||
textPages1 *textPages // 0x0400 to 0x07ff
|
||||
activeSlow int // Slot that has the addressing 0xc800 to 0ccfff
|
||||
activeSlot int // Slot that has the addressing 0xc800 to 0ccfff
|
||||
}
|
||||
|
||||
const (
|
||||
@ -87,14 +86,6 @@ func newAddressSpace(romImage string) *memoryManager {
|
||||
m.SetPage(page, p)
|
||||
}
|
||||
|
||||
// Replace RAM in the TEXT1 area.
|
||||
// TODO: treat as normal ram. Add is dirty in all RAM pages
|
||||
var t textPages
|
||||
mmu.textPages1 = &t
|
||||
for i := 0; i < 4; i++ {
|
||||
m.SetPage(uint8(4+i), &(t.pages[i]))
|
||||
}
|
||||
|
||||
return &mmu
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,36 @@
|
||||
package apple2
|
||||
|
||||
type rxmPage struct {
|
||||
data [256]uint8
|
||||
observer func(address uint8, isWrite bool)
|
||||
}
|
||||
|
||||
type ramPage struct {
|
||||
data [256]uint8
|
||||
rxmPage
|
||||
}
|
||||
|
||||
type romPage struct {
|
||||
data [256]uint8
|
||||
rxmPage
|
||||
}
|
||||
|
||||
func (p *ramPage) Peek(address uint8) uint8 {
|
||||
func (p *rxmPage) Peek(address uint8) uint8 {
|
||||
p.touch(address, false)
|
||||
return p.data[address]
|
||||
}
|
||||
|
||||
func (p *ramPage) Poke(address uint8, value uint8) {
|
||||
func (p *rxmPage) internalPeek(address uint8) uint8 {
|
||||
return p.data[address]
|
||||
}
|
||||
|
||||
func (p *rxmPage) Poke(address uint8, value uint8) {
|
||||
p.touch(address, true)
|
||||
p.data[address] = value
|
||||
}
|
||||
|
||||
func (p *romPage) Peek(address uint8) uint8 {
|
||||
return p.data[address]
|
||||
func (p *rxmPage) touch(address uint8, isWrite bool) {
|
||||
if p.observer != nil {
|
||||
p.observer(address, isWrite)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *romPage) Poke(address uint8, value uint8) {
|
||||
|
@ -1,48 +0,0 @@
|
||||
package apple2
|
||||
|
||||
type textPages struct {
|
||||
pages [4]textPage
|
||||
}
|
||||
|
||||
type textPage struct {
|
||||
dirty bool
|
||||
data [256]uint8
|
||||
}
|
||||
|
||||
func (p *textPage) Peek(address uint8) uint8 {
|
||||
return p.data[address]
|
||||
}
|
||||
|
||||
func (p *textPage) Poke(address uint8, value uint8) {
|
||||
p.data[address] = value
|
||||
// Note: we could avoid setting dirty on the 16 blocks of 8 hidden bytes
|
||||
p.dirty = true
|
||||
}
|
||||
|
||||
func (tp *textPages) read(column uint8, line uint8) uint8 {
|
||||
page, address := tp.charAddress(column, line)
|
||||
return tp.pages[page].Peek(address)
|
||||
}
|
||||
|
||||
func (tp *textPages) write(column uint8, line uint8, value uint8) {
|
||||
page, address := tp.charAddress(column, line)
|
||||
tp.pages[page].Poke(address, value)
|
||||
}
|
||||
|
||||
func (tp *textPages) charAddress(column uint8, line uint8) (page uint8, address uint8) {
|
||||
page = (line % 8) / 2
|
||||
address = column + (line/8)*40 + (line%2)*128
|
||||
return
|
||||
}
|
||||
|
||||
func (tp *textPages) strobe() bool {
|
||||
// Thread safe. May just mark more dirties than needed.
|
||||
dirty := false
|
||||
for i := 0; i < 4; i++ {
|
||||
if tp.pages[i].dirty {
|
||||
dirty = true
|
||||
tp.pages[i].dirty = false
|
||||
}
|
||||
}
|
||||
return dirty
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package apple2
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCharAddress(t *testing.T) {
|
||||
var tp textPages
|
||||
|
||||
mappings := [][]uint8{
|
||||
// column, line, page, address
|
||||
{0, 0, 0, 0},
|
||||
{0, 1, 0, 0x80},
|
||||
{0, 2, 1, 0x00},
|
||||
{0, 23, 3, 0xD0},
|
||||
}
|
||||
|
||||
for _, v := range mappings {
|
||||
page, address := tp.charAddress(v[0], v[1])
|
||||
if page != v[2] || address != v[3] {
|
||||
t.Errorf("Error on charAddress for (%v, %v) (%v:%02x) <> (%v:%02x)",
|
||||
v[0], v[1], v[2], v[3], page, address)
|
||||
}
|
||||
}
|
||||
}
|
4
main.go
4
main.go
@ -4,8 +4,8 @@ import "go6502/apple2"
|
||||
|
||||
func main() {
|
||||
//romFile := "apple2/romdumps/Apple2.rom"
|
||||
//romFile := "apple2/romdumps/Apple2_Plus.rom"
|
||||
romFile := "apple2/romdumps/Apple2e.rom"
|
||||
romFile := "apple2/romdumps/Apple2_Plus.rom"
|
||||
//romFile := "apple2/romdumps/Apple2e.rom"
|
||||
|
||||
log := false
|
||||
apple2.Run(romFile, log)
|
||||
|
Loading…
Reference in New Issue
Block a user