forked from lilyball/dcpu16
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
114 lines (110 loc) · 2.89 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
package main
import (
"flag"
"fmt"
"github.com/kballard/dcpu16/dcpu"
"github.com/kballard/dcpu16/dcpu/core"
"github.com/kballard/termbox-go"
"io/ioutil"
"os"
)
var requestedRate dcpu.ClockRate = dcpu.DefaultClockRate
var printRate *bool = flag.Bool("printRate", false, "Print the effective clock rate at termination")
var screenRefreshRate dcpu.ClockRate = dcpu.DefaultScreenRefreshRate
var littleEndian *bool = flag.Bool("littleEndian", false, "Interpret the input file as little endian")
func main() {
// command-line flags
flag.Var(&requestedRate, "rate", "Clock rate to run the machine at")
flag.Var(&screenRefreshRate, "screenRefreshRate", "Clock rate to refresh the screen at")
// update usage
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s [flags] program\n", os.Args[0])
flag.PrintDefaults()
}
flag.Parse()
if flag.NArg() != 1 {
flag.Usage()
os.Exit(2)
}
program := flag.Arg(0)
data, err := ioutil.ReadFile(program)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// Interpret the file as Words
words := make([]core.Word, len(data)/2)
for i := 0; i < len(data)/2; i++ {
b1, b2 := core.Word(data[i*2]), core.Word(data[i*2+1])
var w core.Word
if *littleEndian {
w = b2<<8 + b1
} else {
w = b1<<8 + b2
}
words[i] = w
}
// Set up a machine
machine := new(dcpu.Machine)
machine.Video.RefreshRate = screenRefreshRate
if err := machine.State.LoadProgram(words, 0); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if err := machine.Start(requestedRate); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// convert termbox event polling into a channel
events := make(chan termbox.Event)
go func() {
for {
events <- termbox.PollEvent()
}
}()
var effectiveRate dcpu.ClockRate
printErr := func(err error) {
fmt.Fprintln(os.Stderr, err)
machine.State.Ram.DumpMemory(os.Stderr, []int{int(machine.State.PC())})
os.Exit(1)
}
// now wait for keyboard events
loop:
for {
select {
case evt := <-events:
if evt.Type == termbox.EventKey {
if evt.Key == termbox.KeyCtrlC {
effectiveRate = machine.EffectiveClockRate()
if err := machine.Stop(); err != nil {
printErr(err)
}
break loop
}
// else pass it to the keyboard
if evt.Ch == 0 {
// it's a key constant
key := evt.Key
if r, ok := keymapTermboxKeyToRune[key]; ok {
machine.Keyboard.RegisterKeyTyped(r)
} else if k, ok := keymapTermboxKeyToKey[key]; ok {
machine.Keyboard.RegisterKeyPressed(k)
machine.Keyboard.RegisterKeyReleased(k)
}
} else {
ch := evt.Ch
if r, ok := keymapRuneToRune[evt.Ch]; ok {
ch = r
}
machine.Keyboard.RegisterKeyTyped(ch)
}
}
case err := <-machine.ErrorC:
machine.Stop() // unlike HasError(), ErrorC doesn't shut down the machine
printErr(err)
}
}
if *printRate {
fmt.Printf("Effective clock rate: %s\n", effectiveRate)
}
}