Skip to content

Commit

Permalink
vm: implement diagnostic dump, slight api change for image slice.
Browse files Browse the repository at this point in the history
cmd/retro: implement dump, force output flush on exit.
  • Loading branch information
db47h committed Aug 9, 2016
1 parent b24591c commit cca8c64
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 19 deletions.
22 changes: 15 additions & 7 deletions cmd/retro/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var shrink = flag.Bool("shrink", true, "When saving, don't save unused cells")
var size = flag.Int("size", 50000, "image size in cells")
var rawIO = flag.Bool("raw", true, "enable raw terminal IO")
var debug = flag.Bool("debug", false, "enable debug diagnostics")
var dump = flag.Bool("dump", false, "dump stacks and image upon exit, for ngarotest.py")

func port1Handler(i *vm.Instance, v, port vm.Cell) error {
if v != 1 {
Expand Down Expand Up @@ -67,8 +68,13 @@ func main() {
var err error
var proc *vm.Instance

// catch and log errors during run
stdout := bufio.NewWriter(os.Stdout)
output := vm.NewVT100Terminal(stdout, stdout.Flush, consoleSize(os.Stdout))

// catch and log errors
defer func() {
output.Flush()

if err == nil {
return
}
Expand Down Expand Up @@ -99,13 +105,10 @@ func main() {
}
}

output := bufio.NewWriter(os.Stdout)
outTerm := vm.NewVT100Terminal(output, output.Flush, consoleSize(os.Stdout))

// default options
var opts = []vm.Option{
vm.Shrink(*shrink),
vm.Output(outTerm),
vm.Output(output),
}

if rawtty {
Expand All @@ -115,7 +118,7 @@ func main() {
opts = append(opts,
vm.Input(os.Stdin),
vm.BindWaitHandler(1, port1Handler),
vm.BindWaitHandler(2, port2Handler(outTerm)))
vm.BindWaitHandler(2, port2Handler(output)))
} else {
// If not raw tty, buffer stdin, but do not check further if the i/o is
// a terminal or not. The standard VT100 behavior is sufficient here.
Expand All @@ -140,8 +143,13 @@ func main() {
if err != nil {
return
}

if err = proc.Run(); err == io.EOF {
err = nil
}
if *dump {
err = proc.Dump(output)
if err != nil {
return
}
}
}
21 changes: 11 additions & 10 deletions vm/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ import (
// Image encapsulates a VM's memory
type Image []Cell

// Load loads an image from file fileName. The image size will be the largest of
// (file cells + 1024) and minSize parameter.
func Load(fileName string, minSize int) (Image, error) {
// Load loads an image from file fileName. The returned slice should have its
// length equal to the number of cells in the file and its capacity equal to the
// maximum of the requested capacity and the image file size + 1024 free cells.
// When using this slice to create a new VM, New will get the lenght to track
// the image file size and expand the slice to its full capacity.
func Load(fileName string, capacity int) (Image, error) {
f, err := os.Open(fileName)
if err != nil {
return nil, err
Expand All @@ -44,15 +47,13 @@ func Load(fileName string, minSize int) (Image, error) {
if sz > int64((^uint(0))>>1) { // MaxInt
return nil, fmt.Errorf("Load %v: file too large", fileName)
}
var t Cell
sz /= int64(unsafe.Sizeof(t))
fileCells := sz
fileCells := int(sz / int64(unsafe.Sizeof(Cell(0))))
// make sure there are at least 1024 free cells at the end of the image
sz += 1024
if int64(minSize) > fileCells {
sz = int64(minSize)
imgCells := fileCells + 1024
if capacity > imgCells {
imgCells = capacity
}
i := make(Image, sz)
i := make(Image, fileCells, imgCells)
err = binary.Read(f, binary.LittleEndian, i[:fileCells])
if err != nil {
return nil, err
Expand Down
49 changes: 47 additions & 2 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package vm
import (
"io"
"os"
"strconv"
)

// Cell is the raw type stored in a memory location.
Expand All @@ -35,6 +36,7 @@ type Instance struct {
PC int // Program Counter (aka. Instruction Pointer)
Image Image // Memory image
Ports []Cell // I/O ports
fileCells int
sp int
rsp int
data []Cell
Expand Down Expand Up @@ -169,7 +171,10 @@ func (i *Instance) SetOptions(opts ...Option) error {
// New creates a new Ngaro Virtual Machine instance.
//
// The image parameter is the Cell array used as memory by the VM. Usually
// loaded from file with the Load function.
// loaded from file with the Load function. Note that New expects the lenght of
// the slice to be the actual image file size (in Cells) and its capacity set to
// the run-time image size, so New will expand the slice to its full capacity
// before using it.
//
// The imageFile parameter is the fileName that will be used to dump the
// contents of the memory image. It does not have to exist or even be writable
Expand All @@ -181,14 +186,15 @@ func New(image Image, imageFile string, opts ...Option) (*Instance, error) {
PC: 0,
sp: -1,
rsp: -1,
Image: image,
Image: image[:cap(image)],
Ports: make([]Cell, portCount),
inH: make(map[Cell]InHandler),
outH: make(map[Cell]OutHandler),
waitH: make(map[Cell]WaitHandler),
imageFile: imageFile,
files: make(map[Cell]*os.File),
fid: 1,
fileCells: len(image),
}

// default Wait Handlers
Expand Down Expand Up @@ -232,3 +238,42 @@ func (i *Instance) Address() []Cell {
func (i *Instance) InstructionCount() int64 {
return i.insCount
}

type errWriter struct {
w io.Writer
err error
}

func (w *errWriter) Write(p []byte) (n int, err error) {
if w.err != nil {
return 0, w.err
}
n, err = w.w.Write(p)
if err != nil {
w.err = err
}
return n, err
}

func (w *errWriter) dumpSlice(a []Cell) error {
l := len(a) - 1
if l >= 0 {
for i := 0; i < l; i++ {
io.WriteString(w, strconv.Itoa(int(a[i])))
w.Write([]byte{' '})
}
io.WriteString(w, strconv.Itoa(int(a[l])))
}
return w.err
}

// Dump dumps the virtual machine stacks and image to the specified io.Writer.
func (i *Instance) Dump(w io.Writer) error {
ew := &errWriter{w: w}
ew.Write([]byte{'\x1C'})
ew.dumpSlice(i.data[:i.sp+1])
ew.Write([]byte{'\x1D'})
ew.dumpSlice(i.address[:i.rsp+1])
ew.Write([]byte{'\x1D'})
return ew.dumpSlice(i.Image[:i.fileCells])
}

0 comments on commit cca8c64

Please sign in to comment.