Merge branch 'master' into apple2e

This commit is contained in:
Ivan Izaguirre 2019-10-19 22:56:02 +02:00
commit b1b9424aeb
6 changed files with 50 additions and 4 deletions

View File

@ -133,6 +133,8 @@ Only valid on SDL mode
emulate a green phosphor monitor instead of a NTSC color TV. Use F6 to toggle.
-panicss
panic if a not implemented softswitch is used
-profile
generate profile trace to analyse with pprof
-rom string
main rom file (default "<internal>/Apple2_Plus.rom")
-saturnCardSlot int

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/ivanizag/apple2/core6502"
"github.com/pkg/profile"
)
// Apple2 represents all the components and state of the emulated machine
@ -25,6 +26,7 @@ type Apple2 struct {
isColor bool
fastMode bool
fastRequestsCounter int
profile bool
}
const (
@ -37,6 +39,12 @@ const maxWaitDuration = 100 * time.Millisecond
// Run starts the Apple2 emulation
func (a *Apple2) Run() {
if a.profile {
// See the log with:
// go tool pprof --pdf ~/go/bin/apple2sdl /tmp/profile329536248/cpu.pprof > profile.pdf
defer profile.Start().Stop()
}
// Start the processor
a.cpu.Reset()
referenceTime := time.Now()
@ -50,6 +58,9 @@ func (a *Apple2) Run() {
for commandsPending {
select {
case command := <-a.commandChannel:
if command == CommandKill {
return
}
a.executeCommand(command)
default:
commandsPending = false
@ -73,6 +84,10 @@ func (a *Apple2) Run() {
}
}
func (a *Apple2) setProfile(value bool) {
a.profile = value
}
const (
// CommandToggleSpeed toggles cpu speed between full speed and actual Apple II speed
CommandToggleSpeed = iota + 1
@ -88,6 +103,8 @@ const (
CommandNextCharGenPage
// CommandToggleCPUTrace toggle tracing of CPU execution
CommandToggleCPUTrace
// CommandKill stops the cpu execution loop
CommandKill
)
// SendCommand enqueues a command to the emulator thread

View File

@ -88,6 +88,11 @@ func MainApple() *Apple2 {
"2plus",
"set base model. Models available 2plus, 2e, base64a",
)
profile := flag.Bool(
"profile",
false,
"generate profile trace to analyse with pprof",
)
flag.Parse()
var a *Apple2
@ -138,6 +143,7 @@ func MainApple() *Apple2 {
a.cpu.SetTrace(*traceCPU)
a.io.setTrace(*traceSS)
a.io.setPanicNotImplemented(*panicSS)
a.setProfile(*profile)
// Load ROM if not loaded already
if *romFile != "" {

View File

@ -43,6 +43,7 @@ func SDLRun(a *apple2.Apple2) {
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch t := event.(type) {
case *sdl.QuitEvent:
a.SendCommand(apple2.CommandKill)
running = false
case *sdl.KeyboardEvent:
//fmt.Printf("[%d ms] Keyboard\ttype:%d\tsym:%c\tmodifiers:%d\tstate:%d\trepeat:%d\n",

View File

@ -21,6 +21,7 @@ const (
sampleDurationCycles = 1000000 * apple2.CpuClockMhz / samplingHz
// each sample on the sound stream is 21.31 cpu cycles approx
maxOutOfSyncMs = 2000
decayLevel = 128
)
type sdlSpeaker struct {
@ -28,6 +29,7 @@ type sdlSpeaker struct {
pendingClicks []uint64
lastCycle uint64
lastState bool
lastLevel C.Uint8
}
/*
@ -40,6 +42,7 @@ func newSDLSpeaker() *sdlSpeaker {
var s sdlSpeaker
s.clickChannel = make(chan uint64, bufferSize)
s.pendingClicks = make([]uint64, 0, bufferSize)
s.lastLevel = decayLevel // Mid position to avoid starting clicks.
return &s
}
@ -55,6 +58,7 @@ func stateToLevel(state bool) C.Uint8 {
return 0
}
// SpeakerCallback is called to get more sound buffer data
//export SpeakerCallback
func SpeakerCallback(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
s := theSDLSpeaker
@ -90,7 +94,7 @@ func SpeakerCallback(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
// Build wave
var i, p int
level := stateToLevel(s.lastState)
level := s.lastLevel
for p = 0; p < len(s.pendingClicks); p++ {
cycle := s.pendingClicks[p]
if cycle < s.lastCycle {
@ -119,10 +123,26 @@ func SpeakerCallback(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
}
}
// If the buffer is empty lets decay the signal
if i == 0 {
for level != decayLevel && i < bufferSize {
if i%100 == 0 {
if level > decayLevel {
level--
} else {
level++
}
}
buf[i] = level
i++
}
}
// Complete the buffer if needed
for b := i; b < bufferSize; b++ {
buf[b] = level
}
s.lastLevel = level
// Remove processed clicks, store the rest for later
remainingClicks := len(s.pendingClicks) - p

View File

@ -33,7 +33,7 @@ const (
ioC8Off uint16 = 0xCFFF
)
func (mmu *memoryManager) access(address uint16, activeMemory [256]memoryHandler) memoryHandler {
func (mmu *memoryManager) access(address uint16, activeMemory *[256]memoryHandler) memoryHandler {
if address == ioC8Off {
mmu.resetSlotExpansionRoms()
}
@ -54,7 +54,7 @@ func (mmu *memoryManager) access(address uint16, activeMemory [256]memoryHandler
// Peek returns the data on the given address
func (mmu *memoryManager) Peek(address uint16) uint8 {
mh := mmu.access(address, mmu.activeMemoryRead)
mh := mmu.access(address, &mmu.activeMemoryRead)
if mh == nil {
return 0xf4 // Or some random number
}
@ -63,7 +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) {
mh := mmu.access(address, mmu.activeMemoryWrite)
mh := mmu.access(address, &mmu.activeMemoryWrite)
if mh == nil {
return
}