Permalink
Browse files

Add flags to control the clock rate

Define a new flag -rate to set the clock rate for the machine.
Define a new flag -printRate to print the effective clock rate when the
machine is done.
  • Loading branch information...
1 parent 28ef149 commit 78ec5b5ed87ee1d540e338ea9e295a97db8f4d55 @kballard committed Apr 13, 2012
Showing with 70 additions and 19 deletions.
  1. +49 −15 dcpu/machine.go
  2. +21 −4 main.go
View
@@ -4,6 +4,8 @@ import (
"errors"
"fmt"
"github.com/kballard/dcpu16/dcpu/core"
+ "io"
+ "strings"
"time"
)
@@ -25,11 +27,11 @@ func (err *MachineError) Error() string {
return fmt.Sprintf("machine error occurred; PC: %#x (%v)", err.PC, err.UnderlyingError)
}
-const DefaultClockRate = time.Microsecond * 10
+const DefaultClockRate ClockRate = 100000 // 100KHz
// Start boots up the machine, with a clock rate of 1 / period
// 10MHz would be expressed as (Microsecond / 10)
-func (m *Machine) Start(period time.Duration) error {
+func (m *Machine) Start(rate ClockRate) error {
if m.stopped != nil {
return errors.New("Machine has already started")
}
@@ -47,7 +49,7 @@ func (m *Machine) Start(period time.Duration) error {
m.cycleCount = 0
m.startTime = time.Now()
go func() {
- ticker := time.NewTicker(period)
+ ticker := time.NewTicker(rate.ToDuration())
scanrate := time.NewTicker(time.Second / 60) // 60Hz
var stoperr error
loop:
@@ -89,26 +91,58 @@ func (m *Machine) Stop() error {
return err
}
-// EffectiveClockRate returns the current observed rate that the machine
-// is running at, as an average since the last Start()
-func (m *Machine) EffectiveClockRate() uint {
- duration := time.Since(m.startTime)
- cycles := m.cycleCount
- return uint(float64(cycles) / duration.Seconds())
-}
+// ClockRate represents the clock rate of the machine
+type ClockRate int64
-func ClockRateToString(rate uint) string {
+func (c ClockRate) String() string {
+ rate := int64(c)
suffix := "Hz"
- if rate > 1e6 {
+ if rate >= 1e6 {
rate /= 1e6
- suffix = "Mhz"
- } else if rate > 1e3 {
+ suffix = "MHz"
+ } else if rate >= 1e3 {
rate /= 1e3
- suffix = "Khz"
+ suffix = "KHz"
}
return fmt.Sprintf("%d%s", rate, suffix)
}
+func (c *ClockRate) Set(str string) error {
+ var rate int64
+ var suffix string
+ if n, err := fmt.Sscanf(str, "%d%s", &rate, &suffix); err != nil && !(n == 1 && err == io.EOF) {
+ return err
+ }
+ if rate <= 0 {
+ return errors.New("clock rate must be positive")
+ }
+ switch strings.ToLower(suffix) {
+ case "mhz":
+ rate *= 1e6
+ case "khz":
+ rate *= 1e3
+ case "hz", "":
+ default:
+ return errors.New(fmt.Sprintf("unknown suffix %#v", suffix))
+ }
+ *c = ClockRate(rate)
+ return nil
+}
+
+// ToDuration converts the ClockRate to a time.Duration that represents
+// the period of one clock cycle
+func (c ClockRate) ToDuration() time.Duration {
+ return time.Second / time.Duration(c)
+}
+
+// EffectiveClockRate returns the current observed rate that the machine
+// is running at, as an average since the last Start()
+func (m *Machine) EffectiveClockRate() ClockRate {
+ duration := time.Since(m.startTime)
+ cycles := m.cycleCount
+ return ClockRate(float64(cycles) / duration.Seconds())
+}
+
// If the machine has already halted due to an error, that error is returned.
// Otherwise, nil is returned.
// If the machine has not started, an error is returned.
View
25 main.go
@@ -1,6 +1,7 @@
package main
import (
+ "flag"
"fmt"
"github.com/kballard/dcpu16/dcpu"
"github.com/kballard/dcpu16/dcpu/core"
@@ -9,12 +10,23 @@ import (
"os"
)
+var requestedRate dcpu.ClockRate = dcpu.DefaultClockRate
+var printRate *bool = flag.Bool("printRate", false, "Print the effective clock rate at termination")
+
func main() {
- if len(os.Args) != 2 {
- fmt.Fprintf(os.Stderr, "usage: %s program\n", os.Args[0])
+ // command-line flags
+ flag.Var(&requestedRate, "rate", "Clock rate to run the machine 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 := os.Args[1]
+ program := flag.Arg(0)
data, err := ioutil.ReadFile(program)
if err != nil {
fmt.Fprintln(os.Stderr, err)
@@ -33,10 +45,11 @@ func main() {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
- if err := machine.Start(dcpu.DefaultClockRate); err != nil {
+ if err := machine.Start(requestedRate); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
+ var effectiveRate dcpu.ClockRate
// now wait for the q key
for {
evt := termbox.PollEvent()
@@ -46,6 +59,7 @@ func main() {
}
if evt.Type == termbox.EventKey {
if evt.Key == termbox.KeyCtrlC || (evt.Mod == 0 && evt.Ch == 'q') {
+ effectiveRate = machine.EffectiveClockRate()
if err := machine.Stop(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
@@ -54,4 +68,7 @@ func main() {
}
}
}
+ if *printRate {
+ fmt.Printf("Effective clock rate: %s\n", effectiveRate)
+ }
}

0 comments on commit 78ec5b5

Please sign in to comment.