Skip to content

Commit

Permalink
vm: implement custom port handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
db47h committed Aug 3, 2016
1 parent ed94b36 commit 5964457
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 139 deletions.
38 changes: 29 additions & 9 deletions cmd/retro/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,35 @@ import (
"github.com/pkg/errors"
)

var fileName = flag.String("image", "retroImage", "Use `filename` as the image to load")
var withFile = flag.String("with", "", "Add `filename` to the input stack")
var shrink = flag.Bool("shrink", true, "When saving, don't save unused cells")
var size = flag.Int("size", 50000, "image size in cells")
var debug = flag.Bool("debug", false, "enable debug diagnostics")

func main() {
// check exit condition
var err error
var proc *vm.Instance
defer func() {
if err != nil {
err = errors.Cause(err)
fmt.Fprintf(os.Stderr, "%+v\n", err)
if err == nil {
return
}
if !*debug {
fmt.Fprintf(os.Stderr, "\n%v\n", err)
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "\n%+#v\n", err)
if proc != nil {
if proc.PC < len(proc.Image) {
fmt.Fprintf(os.Stderr, "PC: %v (%v), Stack: %v, Ret: %v\n", proc.PC, proc.Image[proc.PC], proc.Data(), proc.Address())
} else {
fmt.Fprintf(os.Stderr, "PC: %v, Stack: %v\nRet: %v\n", proc.PC, proc.Data(), proc.Address())
}
}
os.Exit(1)
}()

var fileName = flag.String("image", "retroImage", "Use `filename` as the image to load")
var withFile = flag.String("with", "", "Add `filename` to the input stack")
var shrink = flag.Bool("shrink", true, "When saving, don't save unused cells")
var size = flag.Int("size", 50000, "image size in cells")
flag.Parse()

var interactive bool
Expand All @@ -52,10 +66,16 @@ func main() {
}

// default options
output := bufio.NewWriter(os.Stdout)
var opts = []vm.Option{
vm.Shrink(*shrink),
// buffered io is faster
vm.Output(bufio.NewWriter(os.Stdout)),
vm.Output(output),
// handle Flush events
vm.OutHandler(3, func(vm.Cell) (vm.Cell, error) {
output.Flush()
return 0, nil
}),
}

// buffer input if not interactive
Expand All @@ -79,7 +99,7 @@ func main() {
if err != nil {
return
}
proc, err := vm.New(img, *fileName, opts...)
proc, err = vm.New(img, *fileName, opts...)
if err != nil {
return
}
Expand Down
70 changes: 59 additions & 11 deletions vm/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,43 @@ package vm

import "github.com/pkg/errors"

type opcode Cell

// ngaro Virtual Machine Opcodes.
const (
OpNop opcode = iota
OpLit
OpDup
OpDrop
OpSwap
OpPush
OpPop
OpLoop
OpJump
OpReturn
OpGtJump
OpLtJump
OpNeJump
OpEqJump
OpFetch
OpStore
OpAdd
OpSub
OpMul
OpDimod
OpAnd
OpOr
OpXor
OpShl
OpShr
OpZeroExit
OpInc
OpDec
OpIn
OpOut
OpWait
)

// Push pushes the argument on top of the data stack.
func (i *Instance) Push(v Cell) {
i.sp++
Expand Down Expand Up @@ -53,7 +90,11 @@ func (i *Instance) Rpop() Cell {
func (i *Instance) Run(toPC int) (err error) {
defer func() {
if e := recover(); e != nil {
err = errors.Errorf("%v", e)
var ok bool
if err, ok = e.(error); !ok {
panic(e)
}
err = errors.Wrap(err, "VM abort")
}
}()
i.insCount = 0
Expand Down Expand Up @@ -186,26 +227,33 @@ func (i *Instance) Run(toPC int) (err error) {
i.PC++
case OpIn:
port := i.data[i.sp]
i.data[i.sp], i.ports[port] = i.ports[port], 0
v := i.ports[port]
if h := i.inH[int(port)]; h != nil {
v, err = h(v)
if err != nil {
return err
}
}
i.data[i.sp], i.ports[port] = v, 0
i.PC++
case OpOut:
port := i.data[i.sp]
i.ports[port] = i.data[i.sp-1]
i.sp -= 2
if port == 3 {
if o, ok := i.output.(Flusher); ok {
o.Flush()
v := i.data[i.sp-1]
if h := i.outH[int(port)]; h != nil {
v, err = h(v)
if err != nil {
return err
}
}
i.ports[port] = v
i.sp -= 2
i.PC++
case OpWait:
err = i.ioWait()
switch err.(type) {
case nil:
i.PC++
default:
if err != nil {
return err
}
i.PC++
default:
i.rsp++
i.address[i.rsp], i.PC = Cell(i.PC), int(op)
Expand Down
Loading

0 comments on commit 5964457

Please sign in to comment.