36877ecffd/vm/gonga/ngaro.go

User picture

Commiter: Charles Childers

Author: Charles Childers

Revision: 36877ecffd


File Size: 4.3 KB

(March 12, 2010 23:46 UTC) About 2 years ago

fix for stack depth query in gonga (thanks yiyus)

 
Show/hide line numbers
// 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
	allows to launch new cores writing 1 to the port 13. The
	new core will start running the same (shared) image
	from the address at the top of the stack. Cores communicate
	writing and id to port 1 (to receive) and 2 (to send). To
	remove a channel write its id to ports 1 and 2 and wait.

	Some useful words:

	: :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 )

	Example:

	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

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

	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 (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)
		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
}