81be6a7595/vm/gonga/ngaro.go

49a8127e04097067b5577155ad650a58b898387d81be6a759539aac15f78155a22b2c7e42cb70e12
1
// Original Ngaro Virtual Machine and Uki framework:
2
//	Copyright (C) 2008, 2009, 2010 Charles Childers
3
// Go port
4
//	Copyright 2009, 2010 JGL
5
// Public Domain or LICENSE file
6
7
/*
8
	Ngaro virtual machines.
9
10
	Ngaro is a portable virtual machine / emulator for a dual
11
	stack processor and various I/O devices. The instruction set
12
	is concise (31 core instructions), and the basic I/O devices
13
	are kept minimal. For more information see
14
		http://github.com/crcx/ngaro
15
16
	Communication with the virtual machine is done through
17
	int chanels for input (port 1) and output (port 2). The
18
	port 4 can be used to save the current image to a file,
19
	while port 5 is used to get information about the virtual
20
	machine.
21
22
	In addition to normal ngaro features, this Go version
23
	allows to launch new cores writing 1 to the port 13. The
24
	new core will start running the same (shared) image
25
	from the address at the top of the stack. Cores communicate
26
	writing and id to port 1 (to receive) and 2 (to send). To
27
	remove a channel write its id to ports 1 and 2 and wait.
28
29
	Some useful words:
30
31
	: :go ( a- ) 1 13 out wait ; ( start new core with ip set to a )
32
	: go ( "-  ) ' :go ; ( parse a word and run it on a new core )
33
	: ->c ( xy- ) 2 out wait ; ( send x to channel y )
34
	: c-> ( x-y ) 1 out wait 1 in ; ( receive y from channel x )
35
	: delchan ( x- ) dup 1 out 2 out wait ; ( delete channel )
36
37
	Example:
38
39
	create ch1 ( It is not needed to create channels, but a )
40
	create ch2 ( good way to get a semi-random new id )
41
	: odd ( - ) 1 repeat dup ch1 ->c 2 + again ;
42
	: even ( - ) 2 repeat dup ch2 ->c 2 + again ;
43
	go odd
44
	go even
45
	ch1 c-> . ch1 c-> . ch1 c-> . ( prints: 1 3 5 )
46
	ch2 c-> . ch2 c-> . ch2 c-> . ( prints: 2 4 6 )
47
	ch1 delchan ( clean up )
48
	ch2 delchan
49
50
	Usage from go: See gonga.go
51
52
*/
53
54
package ngaro
55
56
const (
57
	// Instruction set
58
	Nop = iota
59
	Lit
60
	Dup
61
	Drop
62
	Swap
63
	Push
64
	Pop
65
	Call
66
	Jump
67
	Return
68
	GtJump
69
	LtJump
70
	NeJump
71
	EqJump
72
	Fetch
73
	Store
74
	Add
75
	Sub
76
	Mul
77
	Dinod
78
	And
79
	Or
80
	Xor
81
	ShL
82
	ShR
83
	ZeroExit
84
	Inc
85
	Dec
86
	In
87
	Out
88
	Wait
89
90
	stackDepth = 100
91
	chanBuffer = 128
92
	nports     = 64
93
)
94
95
type NgaroVM struct {
96
	img     []int
97
	dump    string
98
	channel map[int]chan int
99
	Input *Input
100
	Output
101
	EndOk chan bool
102
}
103
104
func (vm *NgaroVM) core(ip int) {
105
	var port [nports]int
106
	var sp, rsp int
107
	var tos int
108
	var data, addr [stackDepth + 2]int
109
	sp = 2 // to avoid underflows
110
	for ; ip < len(vm.img); ip++ {
111
		switch vm.img[ip] {
112
		case Nop:
113
		case Lit:
114
			sp++
115
			ip++
116
			data[sp] = vm.img[ip]
117
		case Dup:
118
			sp++
119
			data[sp] = tos
120
		case Drop:
121
			sp--
122
		case Swap:
123
			data[sp], data[sp-1] = data[sp-1], tos
124
		case Push:
125
			rsp++
126
			addr[rsp] = tos
127
			sp--
128
		case Pop:
129
			sp++
130
			data[sp] = addr[rsp]
131
			rsp--
132
		case Call:
133
			ip++
134
			rsp++
135
			addr[rsp] = ip
136
			ip = vm.img[ip] - 1
137
		case Jump:
138
			ip++
139
			ip = vm.img[ip] - 1
140
		case Return:
141
			ip = addr[rsp]
142
			rsp--
143
		case GtJump:
144
			ip++
145
			if data[sp-1] > tos {
146
				ip = vm.img[ip] - 1
147
			}
148
			sp = sp - 2
149
		case LtJump:
150
			ip++
151
			if data[sp-1] < tos {
152
				ip = vm.img[ip] - 1
153
			}
154
			sp = sp - 2
155
		case NeJump:
156
			ip++
157
			if data[sp-1] != tos {
158
				ip = vm.img[ip] - 1
159
			}
160
			sp = sp - 2
161
		case EqJump:
162
			ip++
163
			if data[sp-1] == tos {
164
				ip = vm.img[ip] - 1
165
			}
166
			sp = sp - 2
167
		case Fetch:
168
			data[sp] = vm.img[tos]
169
		case Store:
170
			vm.img[tos] = data[sp-1]
171
			sp = sp - 2
172
		case Add:
173
			data[sp-1] += tos
174
			sp--
175
		case Sub:
176
			data[sp-1] -= tos
177
			sp--
178
		case Mul:
179
			data[sp-1] *= tos
180
			sp--
181
		case Dinod:
182
			data[sp] = data[sp-1] / tos
183
			data[sp-1] = data[sp-1] % tos
184
		case And:
185
			data[sp-1] &= tos
186
			sp--
187
		case Or:
188
			data[sp-1] |= tos
189
			sp--
190
		case Xor:
191
			data[sp-1] ^= tos
192
			sp--
193
		case ShL:
194
			data[sp-1] <<= uint(tos)
195
			sp--
196
		case ShR:
197
			data[sp-1] >>= uint(tos)
198
			sp--
199
		case ZeroExit:
200
			if tos == 0 {
201
				sp--
202
				ip = addr[rsp]
203
				rsp--
204
			}
205
		case Inc:
206
			data[sp]++
207
		case Dec:
208
			data[sp]--
209
		case In:
210
			data[sp] = port[tos]
211
			port[tos] = 0
212
		case Out:
213
			port[0] = 0
214
			port[tos] = data[sp-1]
215
			sp = sp - 2
216
		case Wait:
217
			sp -= vm.wait(&port, tos, ip)
218
		default:
219
			rsp++
220
			addr[rsp] = ip
221
			ip = vm.img[ip] - 1
222
		}
223
		// to avoid segfaults:
224
		if sp < 2 {
225
			sp = 2
226
		}
227
		tos = data[sp]
228
	}
229
}
230
231
func NewVM(img []int, dump string, in *Input, out Output) *NgaroVM {
232
	vm := NgaroVM{
233
		dump:    dump,
234
		channel: make(map[int]chan int),
235
		Input:   in,
236
		Output:  out,
237
		EndOk:   make(chan bool),
238
		img:     img,
239
	}
240
	go vm.core(0)
241
	return &vm
242
}