Changeset 81be6a759539aac15f78155a22b2c7e42cb70e12

User picture

Commiter: Charles Childers

Author: Charles Childers

Parent: 49a8127e04

(2010/03/12 20:49) Almost 2 years ago

update gonga (yiyus)

Affected files

Added vm/gonga/devs.go Download diff

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
package ngaro
8
9
import (
10
	"io"
11
	"bufio"
12
	"os"
13
	B "encoding/binary"
14
)
15
16
type Input struct {
17
	io.Reader
18
	Next *Input
19
}
20
21
type Output io.Writer
22
23
var ClearScreen func() = func() {}
24
25
func IncludeFile(filename string) io.Reader {
26
	r, err := os.Open(filename, os.O_RDONLY, 0)
27
	if err != nil {
28
		return nil
29
	}
30
	br := bufio.NewReader(r)
31
	return io.Reader(br)
32
}
33
34
func LoadDump(filename string, img []int, start int) int {
35
	r, err := os.Open(filename, os.O_RDONLY, 0)
36
	if err != nil {
37
		return 0
38
	}
39
	br := bufio.NewReader(r)
40
	var ui uint32
41
	var i int
42
	for i, _ = range img[start:] {
43
		if err := B.Read(br, B.LittleEndian, &ui); err != nil {
44
			break
45
		}
46
		img[i] = int(ui)
47
	}
48
	return i
49
}
50
51
func (vm *NgaroVM) WriteDump(filename string) {
52
	w, err := os.Open(filename, os.O_WRONLY|os.O_CREATE, 0666)
53
	if err != nil {
54
		return
55
	}
56
	for _, i := range vm.img {
57
		if err = B.Write(w, B.LittleEndian, uint32(i)); err != nil {
58
			break
59
		}
60
	}
61
}
62
63
func (vm *NgaroVM) Channel(id int) chan int {
64
	if c, ok := vm.channel[id]; ok {
65
		return c
66
	}
67
	vm.channel[id] = make(chan int)
68
	return vm.channel[id]
69
}
70
71
func readA(data []int, a int) string {
72
	var w int
73
	for w = a; w < len(data) && data[w] != 0; w++ {
74
	}
75
	return string(data[a:w])
76
}
77
78
func (vm *NgaroVM) wait(port *[nports]int, tos int, ip int) (spdec int) {
79
	var c [1]byte
80
	switch {
81
	case port[0] == 1:
82
		return
83
84
	case port[1] == 1: // Input
85
		if _, err := vm.Input.Read(c[0:]); err != nil {
86
			if err == os.EOF {
87
				vm.Input = vm.Input.Next
88
			} else {
89
				vm.EndOk <- false
90
				return
91
			}
92
		}
93
		port[1] = int(c[0])
94
95
	case port[1] > 1: // Receive from (or delete) channel
96
		if port[2] == port[1] {
97
			vm.channel[port[1]] = nil, false
98
			port[1] = 0
99
			port[2] = 0
100
		} else {
101
			port[1] = <-vm.Channel(port[1])
102
		}
103
104
	case port[2] == 1: // Output
105
		c[0] = byte(tos)
106
		if tos < 0 {
107
			ClearScreen()
108
		} else if _, err := vm.Output.Write(c[0:]); err != nil {
109
			vm.EndOk <- false
110
			return
111
		}
112
		port[2] = 0
113
		spdec = 1
114
115
	case port[2] > 1: // Send to channel
116
		vm.Channel(port[2]) <- tos
117
		port[2] = 0
118
		spdec = 1
119
120
	case port[4] != 0: // Files
121
		switch port[4] {
122
		case 1: // Write dump
123
			vm.WriteDump(vm.dump)
124
		case 2: // Include file
125
			if f := IncludeFile(readA(vm.img, tos)); f != nil {
126
				vm.Input = &Input{f, vm.Input}
127
			}
128
		}
129
		// TODO: -1 to -7 (file system)
130
		port[4] = 0
131
132
	case port[5] != 0: // Capabilities
133
		// TODO: case -8 (seconds from epoch)
134
		switch port[5] {
135
		case -1: // Image size
136
			port[5] = len(vm.img)
137
		case -5: // Stack depth
138
			port[5] = stackDepth
139
		case -6: // Address stack depth
140
			port[5] = stackDepth
141
		case -9: // Bye!
142
			vm.EndOk <- true
143
		default:
144
			port[5] = 0
145
		}
146
147
	// TODO: port[6] (canvas)
148
	// TODO: port[7] (mouse)
149
	// TODO: port[8] (sockets)
150
151
	case port[13] == 1:
152
		go vm.core(tos)
153
		port[13] = 0
154
		spdec = 1
155
	}
156
	port[0] = 1
157
	return
158
}

Added vm/gonga/gonga.go Download diff

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
	Gonga launchs a new ngaro image (retroForth by default). The
9
	vm exposes the function Channel(int id) to get a direct channel:
10
	any int can be used as channel id, but 0 is stdin and 1 is stdout.
11
	Gonga uses these functions in goroutinesthat read from stdin
12
	and write to stdout.
13
14
	When launching gonga it is posible to specify the image to
15
	load. Multiple images can be given (they will be concatenated)
16
	the special filename "-" means to load the default image.
17
18
	Usage:
19
		gonga [options] [image file(s)]
20
	Options:
21
		-s=50000: image size
22
		-d="": image dump file
23
*/
24
25
package main
26
27
import (
28
	"./ngaro"
29
	"flag"
30
	"fmt"
31
	"os"
32
)
33
34
var size = flag.Int("s", 50000, "image size")
35
var dump = flag.String("d", "retro.img", "image dump file")
36
var retroImage = [...]int{}
37
38
func main() {
39
	flag.Parse()
40
	ngaro.ClearScreen = func() { fmt.Printf("\033[2J\033[1;1H") }
41
42
	var img = make([]int, *size)
43
	if flag.NArg() == 0 {
44
		img = &retroImage
45
	}
46
	for i, n := 0, 0; i < flag.NArg(); i++ {
47
		if flag.Arg(i) == "-" {
48
			img = &retroImage
49
			img = img[0:cap(img)]
50
			n += len(retroImage)
51
		} else {
52
			n += ngaro.LoadDump(flag.Arg(i), img, n)
53
		}
54
	}
55
	input := &ngaro.Input{os.Stdin, nil}
56
	vm := ngaro.NewVM(img, *dump, input, os.Stdout)
57
58
	<-vm.EndOk
59
}

Added vm/gonga/Makefile Download diff

49a8127e04097067b5577155ad650a58b898387d81be6a759539aac15f78155a22b2c7e42cb70e12
1
include $(GOROOT)/src/Make.$(GOARCH)
2
3
TARG=ngaro
4
GOFILES=ngaro.go devs.go
5
6
gonga: ./$(TARG).a gonga.go
7
	$(GC) -o gonga.$O gonga.go
8
	$(LD) -o $@ gonga.$O
9
10
./$(TARG).a: ./_obj/$(TARG).a
11
	cp ./_obj/$(TARG).a .
12
13
include $(GOROOT)/src/Make.pkg

Added vm/gonga/ngaro.go Download diff

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
}