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