-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
207 lines (150 loc) · 3.51 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package main
import (
"flag"
"io/ioutil"
"runtime"
"sync"
"github.com/moshenahmias/gopherboy/audio"
"github.com/moshenahmias/gopherboy/config"
"github.com/moshenahmias/gopherboy/cpu"
"github.com/moshenahmias/gopherboy/display"
"github.com/moshenahmias/gopherboy/game"
"github.com/moshenahmias/gopherboy/joypad"
"github.com/moshenahmias/gopherboy/memory"
"github.com/moshenahmias/gopherboy/ui"
"github.com/sirupsen/logrus"
)
func main() {
// set logging level
logrus.SetLevel(logrus.InfoLevel)
// init command-line arguments
argROM := flag.String("rom", "", "Path to game ROM")
argBIOS := flag.String("bios", "", "Path to boot ROM")
argSettings := flag.String("settings", config.DefaultSettingsFile, "Path to settings file")
// parse command-line arguments
flag.Parse()
// validate rom file arg
if len(*argROM) == 0 {
flag.PrintDefaults()
return
}
// load settings
settings, err := config.LoadSettings(*argSettings)
if err != nil {
logrus.Error(err)
return
}
// run
if err := run(*argROM, *argBIOS, settings); err != nil {
logrus.Error(err)
}
}
func run(romFile, biosFile string, settings *config.Settings) error {
runtime.LockOSThread()
// init ui
if err := ui.Initialize(); err != nil {
return err
}
defer ui.Close()
// create input listener
input := ui.NewInput(settings.JoypadMapping)
// create and show the window
window, err := ui.NewWindow(
"gopherboy",
int(settings.Scale),
settings.Color_0,
settings.Color_1,
settings.Color_2,
settings.Color_3)
if err != nil {
return err
}
defer window.Close()
var sound ui.Sound
if settings.SoundDevice >= 0 {
if err := sound.Initialize(int(settings.SoundDevice)); err != nil {
return err
}
defer sound.Close()
}
// load bios (if available)
var biosData []byte
if len(biosFile) > 0 {
var err error
// load bios from file
biosData, err = ioutil.ReadFile(biosFile)
if err != nil {
return err
}
}
soundMute := false
// restart loop
for quit := false; !quit; {
// set sound mute state
sound.Mute(soundMute)
// create mmu
mmu := memory.NewMMU()
// TODO: map missing IO registers to FF00-FF7F
if err := mmu.Map(memory.NewRAM(make([]byte, 128), 0xFF00), 0xFF00, 0xFF7F); err != nil {
return err
}
// create cpu core
core, err := cpu.NewCore(mmu)
if err != nil {
return err
}
// create and map the joyp register
joyp := joypad.NewJOYP(core, input)
// create gpu
gpu, err := display.NewGPU(mmu, window, core, settings.Fps)
if err != nil {
return err
}
// create apu
_, err = audio.NewAPU(core, mmu, &sound)
if err != nil {
return err
}
// load cartridg
cartridge, err := game.NewCartridge(romFile, core)
if err != nil {
return err
}
// assemble everything
gameboy, err := NewGameboy(cartridge, mmu, core, biosData, joyp, gpu)
if err != nil {
return err
}
// start the game
var wg sync.WaitGroup
wg.Add(1)
go func() {
if err := gameboy.Start(); err != nil {
logrus.Error(err)
input.Stop()
}
wg.Done()
}()
// wait for keyboard events
keyEvent := input.WaitForKeyEvents()
for keyEvent == ui.ControlEventPause || keyEvent == ui.ControlEventMute {
// pause
if keyEvent == ui.ControlEventPause {
gameboy.Pause()
}
// mute
if keyEvent == ui.ControlEventMute {
soundMute = !soundMute
sound.Mute(soundMute)
}
keyEvent = input.WaitForKeyEvents()
}
// quit
quit = keyEvent == ui.ControlEventQuit
// stop cpu
gameboy.Stop()
wg.Wait()
}
// bye
return nil
}