func main() { // 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 := 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++ { w := core.Word(data[i*2])<<8 + core.Word(data[i*2+1]) words[i] = w } // Set up a machine machine := new(dcpu.Machine) 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) } var effectiveRate dcpu.ClockRate // now wait for the q key for { evt := termbox.PollEvent() if err := machine.HasError(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } 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) } break } } } if *printRate { fmt.Printf("Effective clock rate: %s\n", effectiveRate) } }
func (v *Video) UnmapFromMachine(offset core.Word, m *Machine) error { if v.addresses == nil { return errors.New("Video is not mapped to a machine") } if err := m.State.Ram.UnmapRegion(offset, core.Word(len(v.words))); err != nil { return err } v.addresses = nil return nil }
func (k *Keyboard) UnmapFromMachine(offset core.Word, m *Machine) error { if k.input == nil { return errors.New("Keyboard is not mapped to a machine") } if err := m.State.Ram.UnmapRegion(offset, core.Word(len(k.words))); err != nil { return err } close(k.input) k.input = nil return nil }
// PollKeys checks for any pending keys and stuffs them into the buffer func (k *Keyboard) PollKeys() { if k.words[k.offset] == 0 { // we have an open spot; check for a key select { case key := <-k.input: k.words[k.offset] = core.Word(key) k.offset = (k.offset + 1) % len(k.words) default: } } }
func (v *Video) MapToMachine(offset core.Word, m *Machine) error { if v.addresses != nil { return errors.New("Video is already mapped to a machine") } addresses := make(chan core.Word, 1) get := func(offset core.Word) core.Word { return v.words[offset] } set := func(offset, val core.Word) error { v.words[offset] = val addresses <- offset return nil } v.addresses = addresses return m.State.Ram.MapRegion(offset, core.Word(len(v.words)), get, set) }
func (v *Video) MapToMachine(offset core.Word, m *Machine) error { if v.mapped { return errors.New("Video is already mapped to a machine") } get := func(offset core.Word) core.Word { return v.words[offset] } set := func(offset, val core.Word) error { v.words[offset] = val v.handleChange(offset) return nil } if err := m.State.Ram.MapRegion(offset, core.Word(len(v.words)), get, set); err != nil { return err } v.mapped = true return nil }
func (k *Keyboard) MapToMachine(offset core.Word, m *Machine) error { if k.input != nil { return errors.New("Keyboard is already mapped to a machine") } k.input = make(chan rune, 1) k.offset = 0 for i := 0; i < 10; i++ { // zero out the words k.words[i] = 0 } get := func(offset core.Word) core.Word { return k.words[offset] } set := func(offset, val core.Word) error { k.words[offset] = val return nil } return m.State.Ram.MapRegion(offset, core.Word(len(k.words)), get, set) }
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) } }