mirror of
https://github.com/romychs/Ocean-240.2-Emulator.git
synced 2026-04-21 11:03:21 +03:00
fix cpu timings, fix irq for keyboard handling, fix cursor keys
This commit is contained in:
parent
a74841b048
commit
18df702750
8
go.mod
8
go.mod
@ -5,7 +5,10 @@ go 1.25
|
|||||||
require (
|
require (
|
||||||
fyne.io/fyne/v2 v2.7.3
|
fyne.io/fyne/v2 v2.7.3
|
||||||
github.com/PaesslerAG/gval v1.2.4
|
github.com/PaesslerAG/gval v1.2.4
|
||||||
|
github.com/PaesslerAG/jsonpath v0.1.0
|
||||||
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
|
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
|
||||||
|
github.com/loov/hrtime v1.0.4
|
||||||
|
github.com/shopspring/decimal v1.3.1
|
||||||
github.com/sirupsen/logrus v1.9.4
|
github.com/sirupsen/logrus v1.9.4
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
@ -29,12 +32,12 @@ require (
|
|||||||
github.com/hack-pad/safejs v0.1.0 // indirect
|
github.com/hack-pad/safejs v0.1.0 // indirect
|
||||||
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
|
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
|
||||||
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect
|
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||||
github.com/rymdport/portal v0.4.2 // indirect
|
github.com/rymdport/portal v0.4.2 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
|
||||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
|
||||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
|
||||||
github.com/stretchr/testify v1.11.1 // indirect
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
@ -43,4 +46,5 @@ require (
|
|||||||
golang.org/x/net v0.35.0 // indirect
|
golang.org/x/net v0.35.0 // indirect
|
||||||
golang.org/x/sys v0.30.0 // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
golang.org/x/text v0.22.0 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
17
go.sum
17
go.sum
@ -49,18 +49,27 @@ github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wH
|
|||||||
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
||||||
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
|
||||||
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/loov/hrtime v1.0.4 h1:K0wPQBsd9mWer2Sx8zIfpyAlF4ckZovtkEMUR/l9wpU=
|
||||||
|
github.com/loov/hrtime v1.0.4/go.mod h1:VbIwDNS2gYTRoo0RjQFdqdDlBjJLXrkDIOgoA7Jvupk=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
|
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
|
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
|
||||||
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||||
@ -84,7 +93,7 @@ golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
151
main.go
151
main.go
@ -9,16 +9,19 @@ import (
|
|||||||
"okemu/debug"
|
"okemu/debug"
|
||||||
"okemu/debug/listener"
|
"okemu/debug/listener"
|
||||||
"okemu/logger"
|
"okemu/logger"
|
||||||
"okemu/nanotime"
|
|
||||||
"okemu/okean240"
|
"okemu/okean240"
|
||||||
"okemu/z80/dis"
|
"okemu/z80/dis"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"runtime/pprof"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
//log "github.com/sirupsen/logrus"
|
"github.com/loov/hrtime"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Version = "v1.0.0"
|
var Version = "v1.0.0"
|
||||||
@ -41,6 +44,21 @@ func main() {
|
|||||||
|
|
||||||
fmt.Printf("Starting Ocean-240.2 emulator %s build at %s\n", Version, BuildTime)
|
fmt.Printf("Starting Ocean-240.2 emulator %s build at %s\n", Version, BuildTime)
|
||||||
|
|
||||||
|
f, err := os.Create("okemu.prof")
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Can not create prof file", err)
|
||||||
|
}
|
||||||
|
defer func(f *os.File) {
|
||||||
|
err := f.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Can not close prof file", err)
|
||||||
|
}
|
||||||
|
}(f)
|
||||||
|
if err := pprof.StartCPUProfile(f); err != nil {
|
||||||
|
log.Warn("Can not start CPU profiling", err)
|
||||||
|
}
|
||||||
|
defer pprof.StopCPUProfile()
|
||||||
|
|
||||||
// Create a context that can be cancelled
|
// Create a context that can be cancelled
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -68,7 +86,7 @@ func main() {
|
|||||||
w, raster, label := mainWindow(computer, conf)
|
w, raster, label := mainWindow(computer, conf)
|
||||||
|
|
||||||
go emulator(ctx, computer)
|
go emulator(ctx, computer)
|
||||||
// go timerClock(ctx, computer)
|
go timerClock(ctx, computer)
|
||||||
go screen(ctx, computer, raster, label)
|
go screen(ctx, computer, raster, label)
|
||||||
|
|
||||||
if conf.Debugger.Enabled {
|
if conf.Debugger.Enabled {
|
||||||
@ -86,9 +104,9 @@ func screen(ctx context.Context, computer *okean240.ComputerType, raster *canvas
|
|||||||
frame := 0
|
frame := 0
|
||||||
var pre uint64 = 0
|
var pre uint64 = 0
|
||||||
var preTim uint64 = 0
|
var preTim uint64 = 0
|
||||||
var freq float64 = 0
|
var cpuFreq float64 = 0
|
||||||
var freqTim float64 = 0
|
var timerFreq float64 = 0
|
||||||
timeStart := time.Now()
|
timeStart := hrtime.Now()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -98,30 +116,21 @@ func screen(ctx context.Context, computer *okean240.ComputerType, raster *canvas
|
|||||||
fyne.Do(func() {
|
fyne.Do(func() {
|
||||||
// status for every 50 frames
|
// status for every 50 frames
|
||||||
if frame%50 == 0 {
|
if frame%50 == 0 {
|
||||||
timeElapsed := time.Since(timeStart)
|
timeElapsed := hrtime.Since(timeStart)
|
||||||
period := float64(timeElapsed.Nanoseconds()) / 1_000_000.0
|
period := float64(timeElapsed.Nanoseconds()) / 1_000_000.0
|
||||||
|
|
||||||
freq = math.Round(float64(computer.Cycles()-pre)/period) / 1000.0
|
//cpuFreq = math.Round(float64(computer.Cycles()-pre)/period) / 1000.0
|
||||||
freqTim = math.Round(float64(timerTicks.Load()-preTim)/period) / 1000.0
|
cpuFreq = math.Round(float64(cpuTicks.Load()-pre)/period) / 1000.0
|
||||||
label.SetText(formatLabel(computer, freq, freqTim))
|
timerFreq = math.Round(float64(timerTicks.Load()-preTim)/period) / 1000.0
|
||||||
|
label.SetText(formatLabel(computer, cpuFreq, timerFreq))
|
||||||
|
|
||||||
// adjust cpu clock
|
adjustTimers(cpuFreq, timerFreq)
|
||||||
if freq > 2.55 && cpuClkPeriod.Load() < defaultCpuClkPeriod+40 {
|
|
||||||
cpuClkPeriod.Add(1)
|
|
||||||
} else if freq < 2.45 && cpuClkPeriod.Load() > defaultCpuClkPeriod-40 {
|
|
||||||
cpuClkPeriod.Add(-1)
|
|
||||||
}
|
|
||||||
// adjust timer clock
|
|
||||||
if freqTim > 1.53 && timerClkPeriod.Load() < defaultTimerClkPeriod+20 {
|
|
||||||
timerClkPeriod.Add(1)
|
|
||||||
} else if freqTim < 1.47 && timerClkPeriod.Load() > defaultTimerClkPeriod-20 {
|
|
||||||
timerClkPeriod.Add(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Debugf("Cpu clk period: %d, Timer clock period: %d, period: %1.3f", cpuClkPeriod.Load(), timerClkPeriod.Load(), period)
|
//log.Debugf("Cpu clk period: %d, Timer clock period: %d, period: %1.3f", cpuClkPeriod.Load(), timerClkPeriod.Load(), period)
|
||||||
pre = computer.Cycles()
|
//pre = computer.Cycles()
|
||||||
|
pre = cpuTicks.Load()
|
||||||
preTim = timerTicks.Load()
|
preTim = timerTicks.Load()
|
||||||
timeStart = time.Now()
|
timeStart = hrtime.Now()
|
||||||
}
|
}
|
||||||
raster.Refresh()
|
raster.Refresh()
|
||||||
})
|
})
|
||||||
@ -131,63 +140,92 @@ func screen(ctx context.Context, computer *okean240.ComputerType, raster *canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func adjustTimers(cpuFreq float64, timerFreq float64) {
|
||||||
|
// adjust cpu clock
|
||||||
|
if cpuFreq > 2.55 && cpuClkPeriod.Load() < defaultCpuClkPeriod+defaultCpuClkPeriod/2 {
|
||||||
|
cpuClkPeriod.Add(1)
|
||||||
|
// cpuTicker.Reset(time.Duration(cpuClkPeriod.Load()))
|
||||||
|
} else if cpuFreq < 2.45 && cpuClkPeriod.Load() > 3 {
|
||||||
|
cpuClkPeriod.Add(-2)
|
||||||
|
// cpuTicker.Reset(time.Duration(cpuClkPeriod.Load()))
|
||||||
|
}
|
||||||
|
// adjust timerClock clock
|
||||||
|
if timerFreq > 1.53 && timerClkPeriod.Load() < defaultTimerClkPeriod+defaultTimerClkPeriod/2 {
|
||||||
|
timerClkPeriod.Add(1)
|
||||||
|
//timerTicker.Reset(time.Duration(timerClkPeriod.Load()))
|
||||||
|
} else if timerFreq < 1.47 && timerClkPeriod.Load() > 3 {
|
||||||
|
timerClkPeriod.Add(-2)
|
||||||
|
//timerTicker.Reset(time.Duration(timerClkPeriod.Load()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func formatLabel(computer *okean240.ComputerType, freq float64, freqTim float64) string {
|
func formatLabel(computer *okean240.ComputerType, freq float64, freqTim float64) string {
|
||||||
return fmt.Sprintf("Screen size: %dx%d | Fcpu: %1.2fMHz | Ftmr: %1.2fMHz | Debugger: %s", computer.ScreenWidth(), computer.ScreenHeight(), freq, freqTim, computer.DebuggerState())
|
return fmt.Sprintf("Screen size: %dx%d | Fcpu: %1.3fMHz | Ftmr: %1.3fMHz | Debugger: %s", computer.ScreenWidth(), computer.ScreenHeight(), freq, freqTim, computer.DebuggerState())
|
||||||
}
|
}
|
||||||
|
|
||||||
var timerTicks atomic.Uint64
|
var timerTicks atomic.Uint64
|
||||||
|
|
||||||
const defaultTimerClkPeriod = 564 // = 1_000_000_000 / 1_607_900 // period in nanos for 1.5MHz frequency
|
const defaultTimerClkPeriod = 430 // = 1_000_000_000 / 1_607_900 // period in nanos for 1.5MHz frequency
|
||||||
const defaultCpuClkPeriod = 221 // = 1_000_000_000 / 2_770_000 // period in nanos for 2.5MHz frequency
|
const defaultCpuClkPeriod = 311 // = 1_000_000_000 / 2_770_000 // period in nanos for 2.5MHz frequency
|
||||||
|
|
||||||
var timerClkPeriod atomic.Int64 // = 1_000_000_000 / 1_607_900 // period in nanos for 1.5MHz frequency
|
var timerClkPeriod atomic.Int64 // = 1_000_000_000 / 1_607_900 // period in nanos for 1.5MHz frequency
|
||||||
var cpuClkPeriod atomic.Int64 // = 1_000_000_000 / 2_770_000 // period in nanos for 2.5MHz frequency
|
var cpuClkPeriod atomic.Int64 // = 1_000_000_000 / 2_770_000 // period in nanos for 2.5MHz frequency
|
||||||
|
|
||||||
func emulator(ctx context.Context, computer *okean240.ComputerType) {
|
//var timerTicker *time.Ticker
|
||||||
ticker := time.NewTicker(133 * time.Nanosecond)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
cpuClkPeriod.Store(defaultCpuClkPeriod)
|
//var cpuTicker *time.Ticker
|
||||||
|
|
||||||
|
func timerClock(ctx context.Context, computer *okean240.ComputerType) {
|
||||||
timerClkPeriod.Store(defaultTimerClkPeriod)
|
timerClkPeriod.Store(defaultTimerClkPeriod)
|
||||||
|
timeStart := hrtime.Now()
|
||||||
|
for {
|
||||||
|
elapsed := hrtime.Since(timeStart)
|
||||||
|
if int64(elapsed) > timerClkPeriod.Load() {
|
||||||
|
timeStart = hrtime.Now()
|
||||||
|
computer.TimerClk()
|
||||||
|
timerTicks.Add(1)
|
||||||
|
runtime.Gosched()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cpuTicks := uint64(0)
|
}
|
||||||
|
|
||||||
|
var cpuTicks atomic.Uint64
|
||||||
|
|
||||||
|
func emulator(ctx context.Context, computer *okean240.ComputerType) {
|
||||||
|
cpuClkPeriod.Store(defaultCpuClkPeriod)
|
||||||
|
//cpuTicker = time.NewTicker(time.Duration(cpuClkPeriod.Load()) * time.Nanosecond)
|
||||||
|
//defer cpuTicker.Stop()
|
||||||
|
|
||||||
|
cpuTicks.Store(0) // := uint64(0)
|
||||||
nextTick := uint64(0)
|
nextTick := uint64(0)
|
||||||
|
|
||||||
cpuTStart := nanotime.Now()
|
|
||||||
tmrTStart := cpuTStart
|
|
||||||
|
|
||||||
var bp uint16
|
var bp uint16
|
||||||
var bpType byte
|
var bpType byte
|
||||||
|
timeStart := hrtime.Now()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
//select {
|
||||||
case <-ticker.C:
|
//case <-cpuTicker.C:
|
||||||
tmrElapsed := nanotime.Since(tmrTStart)
|
|
||||||
// TIMER CLK
|
|
||||||
if tmrElapsed.Nanoseconds() >= timerClkPeriod.Load() {
|
|
||||||
computer.TimerClk()
|
|
||||||
timerTicks.Add(1)
|
|
||||||
tmrTStart = nanotime.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPU
|
// CPU
|
||||||
cpuElapsed := nanotime.Since(cpuTStart)
|
elapsed := hrtime.Since(timeStart)
|
||||||
if cpuElapsed.Nanoseconds() >= cpuClkPeriod.Load() {
|
if int64(elapsed) >= cpuClkPeriod.Load() {
|
||||||
cpuTicks++
|
timeStart = hrtime.Now()
|
||||||
bp = 0
|
bp = 0
|
||||||
bpType = 0
|
bpType = 0
|
||||||
|
|
||||||
|
// 2.5MHz frequency
|
||||||
|
cpuTicks.Add(1)
|
||||||
if fullSpeed.Load() {
|
if fullSpeed.Load() {
|
||||||
// Max frequency
|
// Max frequency
|
||||||
_, bp, bpType = computer.Do()
|
_, bp, bpType = computer.Do()
|
||||||
} else {
|
} else if cpuTicks.Load() >= nextTick {
|
||||||
// 2.5MHz frequency
|
|
||||||
if cpuTicks >= nextTick {
|
|
||||||
var t uint32
|
var t uint32
|
||||||
t, bp, bpType = computer.Do()
|
t, bp, bpType = computer.Do()
|
||||||
nextTick += uint64(t)
|
nextTick = cpuTicks.Load() + uint64(t)
|
||||||
}
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Breakpoint hit
|
// Breakpoint hit
|
||||||
if bp > 0 || bpType != 0 {
|
if bp > 0 || bpType != 0 {
|
||||||
listener.BreakpointHit(bp, bpType)
|
listener.BreakpointHit(bp, bpType)
|
||||||
@ -196,11 +234,10 @@ func emulator(ctx context.Context, computer *okean240.ComputerType) {
|
|||||||
computer.Reset()
|
computer.Reset()
|
||||||
needReset = false
|
needReset = false
|
||||||
}
|
}
|
||||||
cpuTStart = nanotime.Now()
|
|
||||||
}
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
//case <-ctx.Done():
|
||||||
|
// return
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import (
|
|||||||
"okemu/z80/c99"
|
"okemu/z80/c99"
|
||||||
//"okemu/z80/js"
|
//"okemu/z80/js"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,6 +49,7 @@ type ComputerType struct {
|
|||||||
//
|
//
|
||||||
debugger *debug.Debugger
|
debugger *debug.Debugger
|
||||||
config *config.OkEmuConfig
|
config *config.OkEmuConfig
|
||||||
|
kbAck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
@ -62,20 +62,20 @@ const VRAMBlock1 = 7
|
|||||||
const VidVsuBit = 0x80
|
const VidVsuBit = 0x80
|
||||||
const VidColorBit = 0x40
|
const VidColorBit = 0x40
|
||||||
|
|
||||||
type ComputerInterface interface {
|
//type ComputerInterface interface {
|
||||||
Run()
|
// Run()
|
||||||
Reset()
|
// Reset()
|
||||||
GetPixel(x uint16, y uint16) color.RGBA
|
// GetPixel(x uint16, y uint16) color.RGBA
|
||||||
Do() uint64
|
// Do() uint64
|
||||||
TimerClk()
|
// TimerClk()
|
||||||
PutKey(key *fyne.KeyEvent)
|
// PutKey(key *fyne.KeyEvent)
|
||||||
PutRune(key rune)
|
// PutRune(key rune)
|
||||||
PutCtrlKey(shortcut fyne.Shortcut)
|
// PutCtrlKey(shortcut fyne.Shortcut)
|
||||||
SaveFloppy()
|
// SaveFloppy()
|
||||||
LoadFloppy()
|
// LoadFloppy()
|
||||||
CPUState() *z80.CPU
|
// CPUState() *z80.CPU
|
||||||
SetCPUState(state *z80.CPU)
|
// SetCPUState(state *z80.CPU)
|
||||||
}
|
//}
|
||||||
|
|
||||||
func (c *ComputerType) GetCPUState() *z80.CPU {
|
func (c *ComputerType) GetCPUState() *z80.CPU {
|
||||||
return c.cpu.GetState()
|
return c.cpu.GetState()
|
||||||
@ -120,6 +120,7 @@ func NewComputer(cfg *config.OkEmuConfig, deb *debug.Debugger) *ComputerType {
|
|||||||
//c.aOffset = 0x100
|
//c.aOffset = 0x100
|
||||||
|
|
||||||
c.pit = pit.New()
|
c.pit = pit.New()
|
||||||
|
c.kbAck = false
|
||||||
c.usart = usart.New()
|
c.usart = usart.New()
|
||||||
c.pic = pic.New()
|
c.pic = pic.New()
|
||||||
c.fdc = fdc.NewFDC(cfg)
|
c.fdc = fdc.NewFDC(cfg)
|
||||||
@ -223,10 +224,14 @@ func (c *ComputerType) GetPixel(x uint16, y uint16) color.RGBA {
|
|||||||
// Color 256x256 mode
|
// Color 256x256 mode
|
||||||
addr = ((x & 0xf8) << 6) | y
|
addr = ((x & 0xf8) << 6) | y
|
||||||
|
|
||||||
cl := (c.vRAM.memory[(addr-offset)&0x3fff] >> (x & 0x07)) & 1
|
a1 := (addr - offset) & 0x3fff
|
||||||
cl |= ((c.vRAM.memory[(addr+0x100-offset)&0x3fff] >> (x & 0x07)) & 1) << 1
|
a2 := (a1 + 0x100) & 0x3fff
|
||||||
|
|
||||||
|
cl := (c.vRAM.memory[a1] >> (x & 0x07)) & 1
|
||||||
|
cl |= ((c.vRAM.memory[a2] >> (x & 0x07)) & 1) << 1
|
||||||
if cl == 0 {
|
if cl == 0 {
|
||||||
resColor = BgColorPalette[c.bgColor]
|
resColor = BgColorPalette[c.bgColor]
|
||||||
|
resColor = ColorPalette[c.palette][cl]
|
||||||
} else {
|
} else {
|
||||||
resColor = ColorPalette[c.palette][cl]
|
resColor = ColorPalette[c.palette][cl]
|
||||||
}
|
}
|
||||||
|
|||||||
20
okean240/computer_test.go
Normal file
20
okean240/computer_test.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package okean240
|
||||||
|
|
||||||
|
func calculateVAddress(x uint16, y uint16) (uint16, uint16) {
|
||||||
|
|
||||||
|
var offset uint16
|
||||||
|
if (c.vShift != 0) && (y > 255-uint16(c.vShift)) {
|
||||||
|
offset = 0x100
|
||||||
|
} else {
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
y += uint16(c.vShift) & 0x00ff
|
||||||
|
x += uint16(c.hShift-7) & 0x00ff
|
||||||
|
|
||||||
|
// Color 256x256 mode
|
||||||
|
addr = ((x & 0xf8) << 6) | y
|
||||||
|
|
||||||
|
a1 := (addr - offset) & 0x3fff
|
||||||
|
a2 := (addr + 0x100 - offset) & 0x3fff
|
||||||
|
|
||||||
|
}
|
||||||
@ -57,7 +57,7 @@ const KbdDd78pa = 0x40
|
|||||||
const KbdDd78pb = 0x41
|
const KbdDd78pb = 0x41
|
||||||
|
|
||||||
// KBD_DD78PC Port C - [PC7:5],[KBD_ACK],[PC3:0]
|
// KBD_DD78PC Port C - [PC7:5],[KBD_ACK],[PC3:0]
|
||||||
//const KBD_DD78PC = 0x42
|
const KbdDd78pc = 0x42
|
||||||
|
|
||||||
// KBD_DD78CTR Control port
|
// KBD_DD78CTR Control port
|
||||||
// Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
|
// Configure: [1][ma1,ma0][0-aO|1-aI],[0-chO,1-chI],[mb],[0-bO|1-bI],[0-clO,1-clI]
|
||||||
|
|||||||
@ -14,7 +14,12 @@ func (c *ComputerType) IORead(port uint16) byte {
|
|||||||
switch port & 0x00ff {
|
switch port & 0x00ff {
|
||||||
case PicDd75a:
|
case PicDd75a:
|
||||||
// PIO xx59, get IRR register
|
// PIO xx59, get IRR register
|
||||||
return c.pic.IRR()
|
irr := c.pic.IRR()
|
||||||
|
// if irq from keyboard and no ACK applied, re-fire
|
||||||
|
if irr&0x10 != 0 && !c.kbAck {
|
||||||
|
c.pic.SetIRQ(RstKbdNo)
|
||||||
|
}
|
||||||
|
return irr
|
||||||
case PicDd75b:
|
case PicDd75b:
|
||||||
return c.pic.CSW()
|
return c.pic.CSW()
|
||||||
case UartDd72rr:
|
case UartDd72rr:
|
||||||
@ -110,6 +115,14 @@ func (c *ComputerType) IOWrite(port uint16, val byte) {
|
|||||||
c.fdc.SetSectorNo(val)
|
c.fdc.SetSectorNo(val)
|
||||||
case Floppy:
|
case Floppy:
|
||||||
c.fdc.SetFloppy(val)
|
c.fdc.SetFloppy(val)
|
||||||
|
|
||||||
|
case KbdDd78pc:
|
||||||
|
if val&0x80 != 0 {
|
||||||
|
c.kbAck = true
|
||||||
|
} else {
|
||||||
|
//c.kbAck = false
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//log.Debugf("OUT to Unknown port (%x), %x", bp, val)
|
//log.Debugf("OUT to Unknown port (%x), %x", bp, val)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ func (c *ComputerType) PutKey(key *fyne.KeyEvent) {
|
|||||||
//log.Debugf("PutKey keyName: %s", key.Name)
|
//log.Debugf("PutKey keyName: %s", key.Name)
|
||||||
c.ioPorts[KbdDd78pa] = code
|
c.ioPorts[KbdDd78pa] = code
|
||||||
c.pic.SetIRQ(RstKbdNo)
|
c.pic.SetIRQ(RstKbdNo)
|
||||||
|
c.kbAck = false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -21,6 +22,7 @@ func (c *ComputerType) PutRune(key rune) {
|
|||||||
|
|
||||||
c.ioPorts[KbdDd78pa] = byte(key & 0xff)
|
c.ioPorts[KbdDd78pa] = byte(key & 0xff)
|
||||||
c.pic.SetIRQ(RstKbdNo)
|
c.pic.SetIRQ(RstKbdNo)
|
||||||
|
c.kbAck = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -39,6 +41,7 @@ func (c *ComputerType) PutRune(key rune) {
|
|||||||
func (c *ComputerType) PutCtrlKey(key byte) {
|
func (c *ComputerType) PutCtrlKey(key byte) {
|
||||||
c.ioPorts[KbdDd78pa] = key
|
c.ioPorts[KbdDd78pa] = key
|
||||||
c.pic.SetIRQ(RstKbdNo)
|
c.pic.SetIRQ(RstKbdNo)
|
||||||
|
c.kbAck = false
|
||||||
//c.ioPorts[PIC_DD75RS] |= Rst1Mask
|
//c.ioPorts[PIC_DD75RS] |= Rst1Mask
|
||||||
c.ioPorts[KbdDd78pb] &= 0x1f | 0x20
|
c.ioPorts[KbdDd78pb] &= 0x1f | 0x20
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,6 @@ package pic
|
|||||||
By Romych, 2025.03.05
|
By Romych, 2025.03.05
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
type I8259 struct {
|
type I8259 struct {
|
||||||
irr byte
|
irr byte
|
||||||
csw byte
|
csw byte
|
||||||
@ -42,12 +40,11 @@ func (c *I8259) IRR() byte {
|
|||||||
return irr
|
return irr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *I8259) SetIRQ(irq byte) {
|
func (c *I8259) ResetIRQ(irq byte) {
|
||||||
if irq < 8 {
|
c.irr &= ^(byte(1) << (irq & 0x07))
|
||||||
c.irr |= 1 << irq
|
|
||||||
} else {
|
|
||||||
log.Warnf("SetIRQ out of range [0..7]: %d", irq)
|
|
||||||
}
|
}
|
||||||
|
func (c *I8259) SetIRQ(irq byte) {
|
||||||
|
c.irr |= 1 << (irq & 0x07)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *I8259) CSW() byte {
|
func (c *I8259) CSW() byte {
|
||||||
|
|||||||
@ -9,10 +9,10 @@ var RemapCmdKey = map[fyne.KeyName]byte{
|
|||||||
fyne.KeyBackspace: 0x08,
|
fyne.KeyBackspace: 0x08,
|
||||||
fyne.KeyInsert: 0x00,
|
fyne.KeyInsert: 0x00,
|
||||||
fyne.KeyDelete: 0x08,
|
fyne.KeyDelete: 0x08,
|
||||||
fyne.KeyRight: 0x18,
|
fyne.KeyRight: 0x84, //0x18,
|
||||||
fyne.KeyLeft: 0x08,
|
fyne.KeyLeft: 0x93, //0x08,
|
||||||
fyne.KeyDown: 0x0A,
|
fyne.KeyDown: 0x0A,
|
||||||
fyne.KeyUp: 0x19,
|
fyne.KeyUp: 0x85, //0x19,
|
||||||
fyne.KeyPageUp: 0x00,
|
fyne.KeyPageUp: 0x00,
|
||||||
fyne.KeyPageDown: 0x00,
|
fyne.KeyPageDown: 0x00,
|
||||||
fyne.KeyHome: 0x0C,
|
fyne.KeyHome: 0x0C,
|
||||||
|
|||||||
@ -2,6 +2,8 @@ logFile: okemu.log
|
|||||||
logLevel: info
|
logLevel: info
|
||||||
monitorFile: rom/MON_r8_9c6c6546.bin
|
monitorFile: rom/MON_r8_9c6c6546.bin
|
||||||
cpmFile: rom/CPM_r8_bc0695e4.bin
|
cpmFile: rom/CPM_r8_bc0695e4.bin
|
||||||
|
#monitorFile: rom/MON_r5.bin
|
||||||
|
#cpmFile: rom/CPM_r5.bin
|
||||||
fdc:
|
fdc:
|
||||||
- autoLoad: true
|
- autoLoad: true
|
||||||
autoSave: true
|
autoSave: true
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user