ELF byte streaming now works with a fixed sized array

This commit is contained in:
JetSetIlly 2023-09-07 11:35:11 +01:00
parent 7de45d3d25
commit a921130414
4 changed files with 103 additions and 35 deletions

View file

@ -219,19 +219,20 @@ func (cart *Elf) Reset() {
func (cart *Elf) reset() {
// stream bytes rather than injecting them into the VCS as they arrive. we
// can't currently accomodate this if the ROM requires bus stuffing of data
cart.mem.streaming = !cart.mem.busStuff
cart.mem.stream.active = !cart.mem.busStuff
// initialise ROM for the VCS
if cart.mem.streaming {
cart.mem.stream = append(cart.mem.stream, streamEntry{
if cart.mem.stream.active {
cart.mem.stream.push(streamEntry{
addr: 0x1ffc,
data: 0x00,
})
cart.mem.stream = append(cart.mem.stream, streamEntry{
cart.mem.stream.push(streamEntry{
addr: 0x1ffd,
data: 0x10,
})
cart.mem.drain = true
cart.mem.strongarm.nextRomAddress = 0x1000
cart.mem.stream.startDrain()
} else {
cart.mem.setStrongArmFunction(vcsEmulationInit)
}
@ -247,17 +248,13 @@ func (cart *Elf) reset() {
// Access implements the mapper.CartMapper interface.
func (cart *Elf) Access(addr uint16, _ bool) (uint8, uint8, error) {
if cart.mem.streaming {
if addr == cart.mem.stream[0].addr&memorymap.CartridgeBits {
if !cart.mem.drain {
cart.runARM()
}
cart.mem.gpio.data[DATA_ODR] = cart.mem.stream[0].data
cart.mem.stream = cart.mem.stream[1:]
if len(cart.mem.stream) < 10 {
cart.mem.drain = false
}
if cart.mem.stream.active {
if !cart.mem.stream.drain {
cart.runARM()
}
if addr == cart.mem.stream.peekAddr()&memorymap.CartridgeBits {
e := cart.mem.stream.pull()
cart.mem.gpio.data[DATA_ODR] = e.data
}
}
cart.mem.busStuffDelay = true
@ -285,7 +282,7 @@ func (cart *Elf) Patch(_ int, _ uint8) error {
}
func (cart *Elf) runARM() bool {
if cart.mem.drain {
if cart.mem.stream.drain {
return true
}
@ -332,7 +329,7 @@ func (cart *Elf) AccessPassive(addr uint16, data uint8) {
cart.mem.gpio.data[ADDR_IDR+1] = uint8(addr >> 8)
// check that strongarm is set and panic if not (see WARNING comment above)
if !cart.mem.streaming {
if !cart.mem.stream.active {
if cart.mem.strongarm.running.function == nil {
panic("ELF ROMs do not handle non strongarm reading of the GPIO")
}
@ -349,7 +346,7 @@ func (cart *Elf) AccessPassive(addr uint16, data uint8) {
cart.runARM()
// check that strongarm is set and panic if not (see WARNING comment above)
if !cart.mem.streaming {
if !cart.mem.stream.active {
if cart.mem.strongarm.running.function == nil {
panic("ELF ROMs do not handle non strongarm reading of the GPIO")
}

View file

@ -152,14 +152,7 @@ type elfMemory struct {
yield coprocessor.CoProcYield
// byte stream support
streaming bool
stream []streamEntry
drain bool
}
type streamEntry struct {
addr uint16
data uint8
stream stream
}
func newElfMemory() *elfMemory {
@ -754,13 +747,12 @@ func (mem *elfMemory) MapAddress(addr uint32, write bool) (*[]byte, uint32) {
if f.support {
mem.runStrongArmFunction(f.function)
} else {
if mem.streaming {
if mem.stream.active {
mem.setStrongArmFunction(f.function)
for mem.strongarm.running.function != nil {
mem.strongarm.running.function(mem)
}
if len(mem.stream) >= 1000 {
mem.drain = true
if mem.stream.drain {
mem.arm.Interrupt()
}
} else {

View file

@ -0,0 +1,79 @@
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package elf
import "fmt"
type streamEntry struct {
addr uint16
data uint8
}
func (s streamEntry) String() string {
return fmt.Sprintf("%04x=%02x", s.addr, s.data)
}
type stream struct {
active bool
stream [1000]streamEntry
ptr int
drain bool
drainPtr int
drainTop int
}
func (s *stream) startDrain() {
s.drain = true
s.drainTop = s.ptr
s.drainPtr = 0
}
func (s *stream) push(e streamEntry) {
s.stream[s.ptr] = e
s.ptr++
// the stream can be pushed to even if the drain has started. this can
// happen when the pushBoundary has been reached but there are still bytes
// to be pushed from the current strongarm function
if s.drain {
s.drainTop = s.ptr
} else {
// the pushBoundary prevents out-of-bounds errors in the event of an
// instruction pushing more bytes than are available. a sufficiently
// high boundary value means that the drain will start before the next
// strongarm function is reached but allowing the current function to
// complete
const pushBoundary = 10
if s.ptr >= len(s.stream)-pushBoundary {
s.startDrain()
}
}
}
func (s *stream) pull() streamEntry {
e := s.stream[s.drainPtr]
s.drainPtr++
if s.drainPtr >= s.drainTop {
s.drain = false
s.ptr = 0
}
return e
}
func (s *stream) peekAddr() uint16 {
return s.stream[s.drainPtr].addr
}

View file

@ -75,8 +75,8 @@ func (mem *elfMemory) setNextRomAddress(addr uint16) {
}
func (mem *elfMemory) injectRomByte(v uint8) bool {
if mem.streaming {
mem.stream = append(mem.stream, streamEntry{
if mem.stream.active {
mem.stream.push(streamEntry{
addr: mem.strongarm.nextRomAddress,
data: v,
})
@ -99,7 +99,7 @@ func (mem *elfMemory) injectRomByte(v uint8) bool {
}
func (mem *elfMemory) yieldDataBus(addr uint16) bool {
if mem.streaming {
if mem.stream.active {
return true
}
@ -115,7 +115,7 @@ func (mem *elfMemory) yieldDataBus(addr uint16) bool {
}
func (mem *elfMemory) yieldDataBusToStack() bool {
if mem.streaming {
if mem.stream.active {
return true
}
@ -208,7 +208,7 @@ func vcsSta3(mem *elfMemory) {
// uint8_t snoopDataBus(uint16_t address)
func snoopDataBus(mem *elfMemory) {
if mem.streaming {
if mem.stream.active {
mem.endStrongArmFunction()
return
}