2e06a9e52d/vm/gonga/ngaro.go
Commiter: Charles Childers
Author: Charles Childers
Revision: 2e06a9e52d
File Size: 6.85 KB
(March 13, 2010 23:09 UTC) About 2 years ago
sync against gonga hg repo
// Original Ngaro Virtual Machine and Uki framework:
// Copyright (C) 2008, 2009, 2010 Charles Childers
// Go port
// Copyright 2009, 2010 JGL
// Public Domain or LICENSE file
/*
Ngaro virtual machines.
Ngaro is a portable virtual machine / emulator for a dual
stack processor and various I/O devices. The instruction set
is concise (31 core instructions), and the basic I/O devices
are kept minimal. For more information see
http://github.com/crcx/ngaro
Communication with the virtual machine is done through
int chanels for input (port 1) and output (port 2). The
port 4 can be used to save the current image to a file,
while port 5 is used to get information about the virtual
machine.
In addition to normal ngaro features, this Go version
adds concurrency, floating point and direct IO support.
Concurrency vocabulary:
: :go ( a- ) 1 13 out wait ; ( start new core with ip set to a )
: go ( "- ) ' :go ; ( parse a word and run it on a new core )
: ->c ( xy- ) 2 out wait ; ( send x to channel y )
: c-> ( x-y ) 1 out wait 1 in ; ( receive y from channel x )
: delchan ( x- ) dup 1 out 2 out wait ; ( delete channel )
Floating poing vocabulary:
-2000
dup : fpush [ 5 + , ] ; dup : fpop [ 6 + , ] ;
dup : f>jump [ 10 + , ] ; dup : f<jump [ 11 + , ] ;
dup : f!jump [ 12 + , ] ; dup : f=jump [ 13 + , ] ;
dup : f+ [ 16 + , ] ; dup : f- [ 17 + , ] ;
dup : f* [ 18 + , ] ; dup : f/ [ 19 + , ] ;
drop
Direct IO vocabulary:
-1100 dup : >int? ( a-xf ) [ 28 + , ] ; : . ( x- ) [ 29 + , ] ;
-1200 dup : >float? ( a-xf ) [ 28 + , ] ; : f. ( x- ) [ 29 + , ] ;
-1300 dup : <accept ( ca- ) [ 28 + , ] ; : $. ( a- ) [ 29 + , ] ;
Direct IO usage:
: tib<accept ( c- )
dup 32 = whitespace @ and if drop -1 then tib <accept ;
: (accept)
dup tib<accept
32 =if ( ugly way to know if this is the listen loop )
tib >int? if .data rdrop listen ;then drop
tib >float? if .data rdrop listen ;then drop
then ;
' (accept) is accept
Example of a concurrent program:
create ch1 ( It is not needed to create channels, but a )
create ch2 ( good way to get a semi-random new id )
: odd ( - ) 1 repeat dup ch1 ->c 2 + again ;
: even ( - ) 2 repeat dup ch2 ->c 2 + again ;
go odd
go even
ch1 c-> . ch1 c-> . ch1 c-> . ( prints: 1 3 5 )
ch2 c-> . ch2 c-> . ch2 c-> . ( prints: 2 4 6 )
ch1 delchan ( clean up )
ch2 delchan
Usage from go: See gonga.go
*/
package ngaro
import (
"fmt"
"strconv"
"unsafe"
)
const (
// Instruction set
Nop = iota
Lit
Dup
Drop
Swap
Push
Pop
Call
Jump
Return
GtJump
LtJump
NeJump
EqJump
Fetch
Store
Add
Sub
Mul
Dinod
And
Or
Xor
ShL
ShR
ZeroExit
Inc
Dec
In
Out
Wait
FP = -2000
IOint = -1100
IOfloat = -1200
IOstring = -1300
stackDepth = 100
chanBuffer = 128
nports = 64
)
type NgaroVM struct {
img []int
dump string
channel map[int]chan int
Input *Input
Output
EndOk chan bool
}
func ftoi(f float) int { return *(*int)(unsafe.Pointer(&f)) }
func itof(i int) float { return *(*float)(unsafe.Pointer(&i)) }
func (vm *NgaroVM) core(ip int) {
var port [nports]int
var sp, rsp int
var tos int
var data, addr [stackDepth + 2]int
sp = 2 // to avoid underflows
for ; ip < len(vm.img); ip++ {
switch vm.img[ip] {
case Nop:
case Lit:
sp++
ip++
data[sp] = vm.img[ip]
case Dup:
sp++
data[sp] = tos
case Drop:
sp--
case Swap:
data[sp], data[sp-1] = data[sp-1], tos
case Push:
rsp++
addr[rsp] = tos
sp--
case Pop:
sp++
data[sp] = addr[rsp]
rsp--
case Call:
ip++
rsp++
addr[rsp] = ip
ip = vm.img[ip] - 1
case Jump:
ip++
ip = vm.img[ip] - 1
case Return:
ip = addr[rsp]
rsp--
case GtJump:
ip++
if data[sp-1] > tos {
ip = vm.img[ip] - 1
}
sp = sp - 2
case LtJump:
ip++
if data[sp-1] < tos {
ip = vm.img[ip] - 1
}
sp = sp - 2
case NeJump:
ip++
if data[sp-1] != tos {
ip = vm.img[ip] - 1
}
sp = sp - 2
case EqJump:
ip++
if data[sp-1] == tos {
ip = vm.img[ip] - 1
}
sp = sp - 2
case Fetch:
data[sp] = vm.img[tos]
case Store:
vm.img[tos] = data[sp-1]
sp = sp - 2
case Add:
data[sp-1] += tos
sp--
case Sub:
data[sp-1] -= tos
sp--
case Mul:
data[sp-1] *= tos
sp--
case Dinod:
data[sp] = data[sp-1] / tos
data[sp-1] = data[sp-1] % tos
case And:
data[sp-1] &= tos
sp--
case Or:
data[sp-1] |= tos
sp--
case Xor:
data[sp-1] ^= tos
sp--
case ShL:
data[sp-1] <<= uint(tos)
sp--
case ShR:
data[sp-1] >>= uint(tos)
sp--
case ZeroExit:
if tos == 0 {
sp--
ip = addr[rsp]
rsp--
}
case Inc:
data[sp]++
case Dec:
data[sp]--
case In:
data[sp] = port[tos]
port[tos] = 0
case Out:
port[0] = 0
port[tos] = data[sp-1]
sp = sp - 2
case Wait:
sp -= vm.wait(&port, tos, sp-2, rsp)
case FP + GtJump:
ip++
if itof(data[sp-1]) > itof(tos) {
ip = vm.img[ip] - 1
}
sp = sp - 2
case FP + LtJump:
ip++
if itof(data[sp-1]) < itof(tos) {
ip = vm.img[ip] - 1
}
sp = sp - 2
case FP + Add:
data[sp-1] = ftoi(itof(data[sp-1]) + itof(tos))
sp--
case FP + Sub:
data[sp-1] = ftoi(itof(data[sp-1]) - itof(tos))
sp--
case FP + Mul:
data[sp-1] = ftoi(itof(data[sp-1]) * itof(tos))
sp--
case FP + Dinod:
data[sp-1] = ftoi(itof(data[sp-1]) / itof(tos))
sp--
case IOint + In:
a := readA(vm.img, tos)
sp++
if i, err := strconv.Atoi(a); err != nil {
data[sp] = 0
} else {
data[sp-1] = i
data[sp] = -1
}
case IOint + Out:
fmt.Fprint(vm.Output, tos)
sp--
case IOfloat + In:
a := readA(vm.img, tos)
sp++
if f, err := strconv.Atof(a); err != nil {
data[sp] = 0
} else {
data[sp-1] = ftoi(f)
data[sp] = -1
}
case IOfloat + Out:
fmt.Fprint(vm.Output, itof(tos))
sp--
case IOstring + In: // Accept
var c [1]byte
var cont func() bool
if data[sp-1] == -1 {
cont = func() bool { return c[0] != ' ' && c[0] != '\n' && c[0] != '\t' }
} else {
cont = func() bool { return c[0] != byte(data[sp-1]) }
}
_, err := vm.Input.Read(c[0:])
// Skip leading white-space
for data[sp-1] == -1 && (c[0] == ' ' || c[0] == '\n' || c[0] == '\t') {
vm.Input.Read(c[0:])
}
a := tos
for ; err == nil && cont(); _, err = vm.Input.Read(c[0:]) {
vm.img[a] = int(c[0])
a++
}
vm.img[a] = 0
sp -= 2
case IOstring + Out:
for i := tos; i < len(vm.img); i++ {
if vm.img[i] == 0 {
break
}
fmt.Fprintf(vm.Output, "%c", byte(vm.img[i]))
}
sp--
default:
rsp++
addr[rsp] = ip
ip = vm.img[ip] - 1
}
// to avoid segfaults:
if sp < 2 {
sp = 2
}
tos = data[sp]
}
}
func NewVM(img []int, dump string, in *Input, out Output) *NgaroVM {
vm := NgaroVM{
dump: dump,
channel: make(map[int]chan int),
Input: in,
Output: out,
EndOk: make(chan bool),
img: img,
}
go vm.core(0)
return &vm
} |