├── .gitignore ├── LICENSE ├── README.md ├── assembler ├── asm.go └── asm_test.go ├── devices ├── console │ └── console.go └── keyboard │ └── keyboard.go ├── drivers ├── console │ └── console_drv.go ├── devices.go └── keyboard │ └── keyboard_drv.go ├── utils └── deque │ └── deque.go └── von ├── cpu.go ├── device.go └── mem.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 七牛云 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arch 2 | 3 | TODO 4 | -------------------------------------------------------------------------------- /assembler/asm.go: -------------------------------------------------------------------------------- 1 | package assembler 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "strings" 7 | 8 | "github.com/qiniu/arch/von" 9 | ) 10 | 11 | type Builder struct { 12 | data *bytes.Buffer 13 | undefLabels map[string]*labelRef 14 | defLabels map[string]int64 15 | } 16 | 17 | type labelRef struct { 18 | data []int 19 | } 20 | 21 | func New(buf *bytes.Buffer) *Builder { 22 | if buf == nil { 23 | buf = new(bytes.Buffer) 24 | } 25 | return &Builder{ 26 | data: buf, 27 | undefLabels: make(map[string]*labelRef), 28 | defLabels: make(map[string]int64), 29 | } 30 | } 31 | 32 | func (p *Builder) Bytes() []byte { 33 | n := len(p.undefLabels) 34 | if n > 0 { 35 | labels := make([]string, 0, n) 36 | for label, _ := range p.undefLabels { 37 | labels = append(labels, label) 38 | } 39 | panic("Undefined labels: " + strings.Join(labels, ", ")) 40 | } 41 | return p.data.Bytes() 42 | } 43 | 44 | func (p *Builder) Add() *Builder { 45 | p.writeU16(von.ADD) 46 | return p 47 | } 48 | 49 | func (p *Builder) Sub() *Builder { 50 | p.writeU16(von.SUB) 51 | return p 52 | } 53 | 54 | func (p *Builder) Mul() *Builder { 55 | p.writeU16(von.MUL) 56 | return p 57 | } 58 | 59 | func (p *Builder) Div() *Builder { 60 | p.writeU16(von.DIV) 61 | return p 62 | } 63 | 64 | func (p *Builder) Mod() *Builder { 65 | p.writeU16(von.MOD) 66 | return p 67 | } 68 | 69 | func (p *Builder) Neg() *Builder { 70 | p.writeU16(von.NEG) 71 | return p 72 | } 73 | 74 | func (p *Builder) LessThanInt() *Builder { 75 | p.writeU16(von.LTI) 76 | return p 77 | } 78 | 79 | func (p *Builder) LessThanString() *Builder { 80 | p.writeU16(von.LTS) 81 | return p 82 | } 83 | 84 | func (p *Builder) EqualInt() *Builder { 85 | p.writeU16(von.EQI) 86 | return p 87 | } 88 | 89 | func (p *Builder) EqualString() *Builder { 90 | p.writeU16(von.EQS) 91 | return p 92 | } 93 | 94 | func (p *Builder) Not() *Builder { 95 | p.writeU16(von.NOT) 96 | return p 97 | } 98 | 99 | func (p *Builder) Concat() *Builder { 100 | p.writeU16(von.CONCAT) 101 | return p 102 | } 103 | 104 | func (p *Builder) Index() *Builder { 105 | p.writeU16(von.INDEX) 106 | return p 107 | } 108 | 109 | func (p *Builder) String() *Builder { 110 | p.writeU16(von.STRING) 111 | return p 112 | } 113 | 114 | func (p *Builder) Alloc() *Builder { 115 | p.writeU16(von.ALLOC) 116 | return p 117 | } 118 | 119 | func (p *Builder) Read(port uint16) *Builder { 120 | p.writeU16(von.READ) 121 | p.writeU16(port) 122 | return p 123 | } 124 | 125 | func (p *Builder) Write(port uint16) *Builder { 126 | p.writeU16(von.WRITE) 127 | p.writeU16(port) 128 | return p 129 | } 130 | 131 | func (p *Builder) PushInt(v int64) *Builder { 132 | p.writeU16(von.PUSHI) 133 | p.writeI64(v) 134 | return p 135 | } 136 | 137 | func (p *Builder) PushString(v string) *Builder { 138 | p.writeU16(von.PUSHS) 139 | p.writeU16(uint16(len(v))) 140 | p.data.WriteString(v) 141 | return p 142 | } 143 | 144 | func (p *Builder) PushArg(index int16) *Builder { 145 | p.writeU16(von.PUSHA) 146 | p.writeU16(uint16(index)) 147 | return p 148 | } 149 | 150 | func (p *Builder) SetArg(index int16) *Builder { 151 | p.writeU16(von.SETA) 152 | p.writeU16(uint16(index)) 153 | return p 154 | } 155 | 156 | func (p *Builder) Ret(narg int) *Builder { 157 | p.writeU16(von.RET) 158 | p.writeU16(uint16(narg)) 159 | return p 160 | } 161 | 162 | func (p *Builder) Jmp(name string) *Builder { 163 | return p.goLabel(von.JMP, name) 164 | } 165 | 166 | func (p *Builder) JZ(name string) *Builder { 167 | return p.goLabel(von.JZ, name) 168 | } 169 | 170 | func (p *Builder) Call(name string) *Builder { 171 | return p.goLabel(von.CALL, name) 172 | } 173 | 174 | func (p *Builder) Label(name string) *Builder { 175 | if _, ok := p.defLabels[name]; ok { 176 | panic("Redefine label: " + name) 177 | } 178 | pc := p.data.Len() 179 | if lref, ok := p.undefLabels[name]; ok { 180 | b := p.data.Bytes() 181 | for _, off := range lref.data { 182 | binary.LittleEndian.PutUint64(b[off:], uint64(pc-(off-2))) 183 | } 184 | delete(p.undefLabels, name) 185 | } 186 | p.defLabels[name] = int64(pc) 187 | return p 188 | } 189 | 190 | func (p *Builder) goLabel(op uint16, name string) *Builder { 191 | p.writeU16(op) 192 | if pc, ok := p.defLabels[name]; ok { 193 | base := int64(p.data.Len() - 2) 194 | p.writeI64(pc - base) 195 | } else { 196 | lref := p.reqUndefLabel(name) 197 | lref.data = append(lref.data, p.data.Len()) 198 | p.writeI64(0) 199 | } 200 | return p 201 | } 202 | 203 | func (p *Builder) reqUndefLabel(name string) *labelRef { 204 | if lref, ok := p.undefLabels[name]; ok { 205 | return lref 206 | } 207 | lref := new(labelRef) 208 | p.undefLabels[name] = lref 209 | return lref 210 | } 211 | 212 | func (p *Builder) Halt() *Builder { 213 | p.writeU16(von.HALT) 214 | return p 215 | } 216 | 217 | func (p *Builder) writeU16(v uint16) { 218 | var buf [2]byte 219 | binary.LittleEndian.PutUint16(buf[:], v) 220 | p.data.Write(buf[:]) 221 | } 222 | 223 | func (p *Builder) writeI64(v int64) { 224 | var buf [8]byte 225 | binary.LittleEndian.PutUint64(buf[:], uint64(v)) 226 | p.data.Write(buf[:]) 227 | } 228 | -------------------------------------------------------------------------------- /assembler/asm_test.go: -------------------------------------------------------------------------------- 1 | package assembler 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/qiniu/arch/devices/console" 7 | "github.com/qiniu/arch/devices/keyboard" 8 | "github.com/qiniu/arch/drivers" 9 | "github.com/qiniu/arch/von" 10 | 11 | con "github.com/qiniu/arch/drivers/console" 12 | kb "github.com/qiniu/arch/drivers/keyboard" 13 | ) 14 | 15 | type shortMem struct { 16 | b []byte 17 | } 18 | 19 | func newShortMem(b []byte) *shortMem { 20 | code := make([]byte, von.PageSize) 21 | copy(code, b) 22 | return &shortMem{code} 23 | } 24 | 25 | func (p *shortMem) OnPageMiss(ipage int64) ([]byte, error) { 26 | if ipage > 0 { 27 | panic("out of range") 28 | } 29 | return p.b, nil 30 | } 31 | 32 | var ( 33 | theKeyboard *keyboard.Device 34 | ) 35 | 36 | func run(b *Builder) *von.CPU { 37 | b.Halt() 38 | code := b.Bytes() 39 | mem := von.NewMemory(newShortMem(code)) 40 | cpu := von.NewCPU(mem) 41 | devKeyboard := theKeyboard 42 | if devKeyboard == nil { 43 | devKeyboard = keyboard.New() 44 | } 45 | cpu.AddDevice(drivers.KEYBOARD, devKeyboard) 46 | cpu.AddDevice(drivers.CONSOLE, console.New()) 47 | cpu.Run(0) 48 | return cpu 49 | } 50 | 51 | func notEq(ret interface{}, v string) bool { 52 | return string(ret.([]byte)) != v 53 | } 54 | 55 | func TestInt(t *testing.T) { 56 | asm := New(nil) 57 | asm.PushInt(2). 58 | PushInt(3). 59 | Mul() 60 | ret := run(asm).Top(1) 61 | if ret != int64(6) { 62 | t.Fatal("TestInt:", ret) 63 | } 64 | } 65 | 66 | func TestString(t *testing.T) { 67 | asm := New(nil) 68 | asm.PushString("Hello, "). 69 | PushString("World"). 70 | Concat() 71 | ret := run(asm).Top(1) 72 | if notEq(ret, "Hello, World") { 73 | t.Fatal("TestString:", ret) 74 | } 75 | } 76 | 77 | func TestJZ_true(t *testing.T) { 78 | asm := New(nil) 79 | asm.PushString("Hello"). 80 | PushString("World"). 81 | LessThanString(). 82 | JZ("else"). 83 | PushString("true"). 84 | Halt(). 85 | Label("else"). 86 | PushString("false") 87 | ret := run(asm).Top(1) 88 | if notEq(ret, "true") { 89 | t.Fatal("TestJZ_true:", ret) 90 | } 91 | } 92 | 93 | func TestJZ_false(t *testing.T) { 94 | asm := New(nil) 95 | asm.PushInt(3). 96 | PushInt(2). 97 | LessThanInt(). 98 | JZ("else"). 99 | PushString("true"). 100 | Halt(). 101 | Label("else"). 102 | PushString("false") 103 | ret := run(asm).Top(1) 104 | if notEq(ret, "false") { 105 | t.Fatal("TestJZ_false:", ret) 106 | } 107 | } 108 | 109 | func TestProc(t *testing.T) { 110 | asm := New(nil) 111 | asm.PushInt(0). 112 | PushInt(2). 113 | PushInt(3). 114 | Call("sub"). 115 | Halt(). 116 | Label("sub"). 117 | PushArg(-2). 118 | PushArg(-1). 119 | Sub(). 120 | SetArg(-3). 121 | Ret(2) 122 | ret := run(asm).Top(1) 123 | if ret != int64(-1) { 124 | t.Fatal("TestProc:", ret) 125 | } 126 | } 127 | 128 | func TestKeyboardAndConsole(t *testing.T) { 129 | theKeyboard = keyboard.New() 130 | theKeyboard.KeyDown(kb.KeyShift). 131 | KeyPress(kb.KeyH). 132 | KeyUp(kb.KeyShift). 133 | KeyPress(kb.KeyE). 134 | KeyPress(kb.KeyL). 135 | KeyPress(kb.KeyL). 136 | KeyPress(kb.KeyO) 137 | 138 | asm := New(nil) 139 | asm.PushString(""). 140 | PushInt(128). 141 | Alloc(). // var2 = make([]byte, 128) 142 | PushArg(2). 143 | Read(drivers.KEYBOARD). // var3: nread int64 144 | PushInt(0). // var4: i int64 145 | PushInt(0). // var5: c byte 146 | PushInt(0). // var6: t byte 147 | PushInt(0). // var7: shift bool 148 | Label("loop"). 149 | PushArg(4). 150 | PushArg(3). 151 | LessThanInt(). // i < nread? 152 | JZ("done"). 153 | PushArg(2). 154 | PushArg(4). 155 | PushInt(1). 156 | Add(). 157 | Index(). 158 | SetArg(5). // c = var2[i+1] 159 | PushArg(2). 160 | PushArg(4). 161 | Index(). 162 | SetArg(6). // t = var2[i] 163 | PushArg(5). 164 | PushInt(int64(kb.KeyShift)). 165 | EqualInt(). // c == kb.KeyShift? 166 | JZ("normalkey"). 167 | PushArg(6). 168 | PushInt(kb.KEYDOWN). 169 | EqualInt(). 170 | SetArg(7). // shift = (t == kb.KEYDOWN) 171 | Jmp("continue"). 172 | Label("normalkey"). 173 | PushArg(6). 174 | PushInt(kb.KEYDOWN). 175 | EqualInt(). // t == kb.KEYDOWN? 176 | JZ("continue"). 177 | PushArg(1). 178 | PushArg(7). 179 | JZ("lowercase"). 180 | PushInt('A'). 181 | Jmp("lcend"). 182 | Label("lowercase"). 183 | PushInt('a'). 184 | Label("lcend"). // (shift ? 'A' : 'a') 185 | PushArg(5). 186 | Add(). 187 | PushInt(int64(kb.KeyA)). 188 | Sub(). 189 | String(). 190 | Concat(). 191 | SetArg(1). // var1 += string((shift ? 'A' : 'a') + c - kb.KeyA) 192 | Label("continue"). 193 | PushArg(4). 194 | PushInt(2). 195 | Add(). 196 | SetArg(4). // i += 2 197 | Jmp("loop"). 198 | Label("done"). 199 | PushString(string(con.PUTS)). 200 | PushArg(1). 201 | Concat(). 202 | PushString("\n"). 203 | Concat(). 204 | Write(drivers.CONSOLE). // 将 var1 通过 console 设备输出:PUTS var1+"\n" 205 | PushArg(1) 206 | ret := run(asm).Top(1) 207 | if notEq(ret, "Hello") { 208 | t.Fatal("TestKeyboardAndConsole:", ret) 209 | } 210 | } 211 | 212 | /* 213 | var1 := "" 214 | var2 := make([]byte, 128) 215 | nread := Read(drivers.KEYBOARD, var2) 216 | shift := false 217 | for i := 0; i < nread; i += 2 { 218 | c := var2[i+1] 219 | t := var2[i] 220 | if c == kb.KeyShift { 221 | shift = (t == kb.KEYDOWN) 222 | } else if t == kb.KEYDOWN { 223 | var1 += string((shift ? 'A' : 'a') + c - kb.KeyA) 224 | } 225 | } 226 | */ 227 | -------------------------------------------------------------------------------- /devices/console/console.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | 7 | "github.com/qiniu/arch/drivers/console" 8 | ) 9 | 10 | type Device struct { 11 | } 12 | 13 | func New() *Device { 14 | return &Device{} 15 | } 16 | 17 | func (p *Device) Read(b []byte) (int, error) { 18 | panic("can't read from console") 19 | } 20 | 21 | func (p *Device) Write(b []byte) (int, error) { 22 | switch b[0] { 23 | case console.PUTI: 24 | v := int64(binary.LittleEndian.Uint64(b[1:])) 25 | fmt.Print(v) 26 | return 9, nil 27 | case console.PUTS: 28 | fmt.Print(string(b[1:])) 29 | return len(b), nil 30 | default: 31 | panic("Device console: unknown instruction") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /devices/keyboard/keyboard.go: -------------------------------------------------------------------------------- 1 | package keyboard 2 | 3 | import ( 4 | "github.com/qiniu/arch/drivers/keyboard" 5 | "github.com/qiniu/arch/utils/deque" 6 | ) 7 | 8 | type Device struct { 9 | data *deque.Deque 10 | } 11 | 12 | type keyEvent struct { 13 | evType byte 14 | evData byte 15 | } 16 | 17 | func New() *Device { 18 | return &Device{ 19 | data: deque.New(), 20 | } 21 | } 22 | 23 | func (p *Device) Read(b []byte) (int, error) { 24 | n := len(b) / 2 25 | for i := 0; i < n; i++ { 26 | if v, ok := p.data.PopFront(); ok { 27 | o := v.(keyEvent) 28 | b[i<<1] = o.evType 29 | b[(i<<1)+1] = o.evData 30 | } else { 31 | return i * 2, nil 32 | } 33 | } 34 | return n * 2, nil 35 | } 36 | 37 | func (p *Device) Write(b []byte) (int, error) { 38 | panic("can't write to keyboard") 39 | } 40 | 41 | func (p *Device) KeyDown(key keyboard.Key) *Device { 42 | p.data.PushBack(keyEvent{ 43 | evType: keyboard.KEYDOWN, 44 | evData: byte(key), 45 | }) 46 | return p 47 | } 48 | 49 | func (p *Device) KeyUp(key keyboard.Key) *Device { 50 | p.data.PushBack(keyEvent{ 51 | evType: keyboard.KEYUP, 52 | evData: byte(key), 53 | }) 54 | return p 55 | } 56 | 57 | func (p *Device) KeyPress(key keyboard.Key) *Device { 58 | return p.KeyDown(key).KeyUp(key) 59 | } 60 | -------------------------------------------------------------------------------- /drivers/console/console_drv.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | const ( 4 | NOOP = iota 5 | PUTI 6 | PUTS 7 | ) 8 | -------------------------------------------------------------------------------- /drivers/devices.go: -------------------------------------------------------------------------------- 1 | package drivers 2 | 3 | const ( 4 | NIL = iota 5 | CONSOLE 6 | KEYBOARD 7 | ) 8 | -------------------------------------------------------------------------------- /drivers/keyboard/keyboard_drv.go: -------------------------------------------------------------------------------- 1 | package keyboard 2 | 3 | type Key int 4 | 5 | const ( 6 | Key0 Key = iota 7 | Key1 8 | Key2 9 | Key3 10 | Key4 11 | Key5 12 | Key6 13 | Key7 14 | Key8 15 | Key9 16 | KeyA 17 | KeyB 18 | KeyC 19 | KeyD 20 | KeyE 21 | KeyF 22 | KeyG 23 | KeyH 24 | KeyI 25 | KeyJ 26 | KeyK 27 | KeyL 28 | KeyM 29 | KeyN 30 | KeyO 31 | KeyP 32 | KeyQ 33 | KeyR 34 | KeyS 35 | KeyT 36 | KeyU 37 | KeyV 38 | KeyW 39 | KeyX 40 | KeyY 41 | KeyZ 42 | KeyAlt 43 | KeyApostrophe 44 | KeyBackslash 45 | KeyBackspace 46 | KeyCapsLock 47 | KeyComma 48 | KeyControl 49 | KeyDelete 50 | KeyDown 51 | KeyEnd 52 | KeyEnter 53 | KeyEqual 54 | KeyEscape 55 | KeyF1 56 | KeyF2 57 | KeyF3 58 | KeyF4 59 | KeyF5 60 | KeyF6 61 | KeyF7 62 | KeyF8 63 | KeyF9 64 | KeyF10 65 | KeyF11 66 | KeyF12 67 | KeyGraveAccent 68 | KeyHome 69 | KeyInsert 70 | KeyKP0 71 | KeyKP1 72 | KeyKP2 73 | KeyKP3 74 | KeyKP4 75 | KeyKP5 76 | KeyKP6 77 | KeyKP7 78 | KeyKP8 79 | KeyKP9 80 | KeyKPAdd 81 | KeyKPDecimal 82 | KeyKPDivide 83 | KeyKPEnter 84 | KeyKPEqual 85 | KeyKPMultiply 86 | KeyKPSubtract 87 | KeyLeft 88 | KeyLeftBracket 89 | KeyMenu 90 | KeyMinus 91 | KeyNumLock 92 | KeyPageDown 93 | KeyPageUp 94 | KeyPause 95 | KeyPeriod 96 | KeyPrintScreen 97 | KeyRight 98 | KeyRightBracket 99 | KeyScrollLock 100 | KeySemicolon 101 | KeyShift 102 | KeySlash 103 | KeySpace 104 | KeyTab 105 | KeyUp 106 | ) 107 | 108 | const ( 109 | NOOP = iota 110 | KEYDOWN 111 | KEYUP 112 | ) 113 | -------------------------------------------------------------------------------- /utils/deque/deque.go: -------------------------------------------------------------------------------- 1 | package deque 2 | 3 | import "container/list" 4 | 5 | // Deque implements an efficient double-ended queue. 6 | // 7 | // Internally it is composed of a doubly-linked list (list.List) of 8 | // blocks. Each block is a slice that holds 0 to blockLen items. The 9 | // Deque starts with one block. Blocks are added to the front and back 10 | // when the edge blocks fill up as items are pushed onto the 11 | // deque. Edge blocks are removed when blocks become empty as items 12 | // are popped off the Deque. 13 | // 14 | // Only the front and back blocks may contain less than blockLen items. 15 | // The first element in the Deque is d.blocks.Front().Value[d.frontIdx]. 16 | // The last element in the Deque is d.blocks.Back().Value[d.backIdx]. 17 | // 18 | // This approach is more efficient than using a standard doubly-linked 19 | // list for a queue because memory allocation is only required every 20 | // blockLen items, instead of for each pushed item. Conversely, fewer 21 | // memory deallocations are required when popping items. Bookkeeping 22 | // overhead per item is also reduced. 23 | type Deque struct { 24 | maxLen int 25 | blocks list.List 26 | frontIdx, backIdx int 27 | len int 28 | } 29 | 30 | // blockLen can be any value above 1. Raising the blockLen decreases 31 | // the average number of memory allocations per item, but increases 32 | // the amount of memory "wasted". Raising blockLen also doesn't 33 | // necessarily make Deque operations faster. 64 is used by Python's 34 | // deque and seems to be a sweet spot on the author's machine too. 35 | const blockLen = 64 36 | const blockCenter = (blockLen - 1) / 2 37 | 38 | type blockT []interface{} 39 | 40 | // New returns a new Deque instance. 41 | func New() *Deque { 42 | return NewWithMaxLen(0) 43 | } 44 | 45 | // New returns a new Deque instance which is limited to a certain 46 | // length. Pushes which cause the length to exceed the specified size 47 | // will cause an item to be dropped from the opposing side. 48 | // 49 | // A maxLen of 0 means that there is no maximum length limit in place. 50 | func NewWithMaxLen(maxLen int) *Deque { 51 | d := Deque{maxLen: maxLen} 52 | d.blocks.PushBack(newBlock()) 53 | d.recenter() 54 | return &d 55 | } 56 | 57 | func newBlock() blockT { 58 | return make(blockT, blockLen) 59 | } 60 | 61 | func (d *Deque) recenter() { 62 | // The indexes start crossed at the middle of the block so that 63 | // the first push on either side has both indexes pointing at the 64 | // first item. 65 | d.frontIdx = blockCenter + 1 66 | d.backIdx = blockCenter 67 | } 68 | 69 | // Len returns the number of items stored in the queue. 70 | func (d *Deque) Len() int { 71 | return d.len 72 | } 73 | 74 | // PushBack adds an item to the back of the queue. 75 | func (d *Deque) PushBack(item interface{}) { 76 | var block blockT 77 | if d.backIdx == blockLen-1 { 78 | // The current back block is full so add another. 79 | block = newBlock() 80 | d.blocks.PushBack(block) 81 | d.backIdx = -1 82 | } else { 83 | block = d.blocks.Back().Value.(blockT) 84 | } 85 | 86 | d.backIdx++ 87 | block[d.backIdx] = item 88 | d.len++ 89 | 90 | if d.maxLen > 0 && d.len > d.maxLen { 91 | d.PopFront() 92 | } 93 | } 94 | 95 | // PushFront adds an item to the front of the queue. 96 | func (d *Deque) PushFront(item interface{}) { 97 | var block blockT 98 | if d.frontIdx == 0 { 99 | // The current front block is full so add another. 100 | block = newBlock() 101 | d.blocks.PushFront(block) 102 | d.frontIdx = blockLen 103 | } else { 104 | block = d.blocks.Front().Value.(blockT) 105 | } 106 | 107 | d.frontIdx-- 108 | block[d.frontIdx] = item 109 | d.len++ 110 | 111 | if d.maxLen > 0 && d.len > d.maxLen { 112 | d.PopBack() 113 | } 114 | } 115 | 116 | // PopBack removes an item from the back of the queue and returns 117 | // it. The returned flag is true unless there were no items left in 118 | // the queue. 119 | func (d *Deque) PopBack() (interface{}, bool) { 120 | if d.len < 1 { 121 | return nil, false 122 | } 123 | 124 | elem := d.blocks.Back() 125 | block := elem.Value.(blockT) 126 | item := block[d.backIdx] 127 | block[d.backIdx] = nil 128 | d.backIdx-- 129 | d.len-- 130 | 131 | if d.backIdx == -1 { 132 | // The back block is now empty. 133 | if d.len == 0 { 134 | d.recenter() // Deque is empty so reset. 135 | } else { 136 | d.blocks.Remove(elem) 137 | d.backIdx = blockLen - 1 138 | } 139 | } 140 | 141 | return item, true 142 | } 143 | 144 | // PopFront removes an item from the front of the queue and returns 145 | // it. The returned flag is true unless there were no items left in 146 | // the queue. 147 | func (d *Deque) PopFront() (interface{}, bool) { 148 | if d.len < 1 { 149 | return nil, false 150 | } 151 | 152 | elem := d.blocks.Front() 153 | block := elem.Value.(blockT) 154 | item := block[d.frontIdx] 155 | block[d.frontIdx] = nil 156 | d.frontIdx++ 157 | d.len-- 158 | 159 | if d.frontIdx == blockLen { 160 | // The front block is now empty. 161 | if d.len == 0 { 162 | d.recenter() // Deque is empty so reset. 163 | } else { 164 | d.blocks.Remove(elem) 165 | d.frontIdx = 0 166 | } 167 | } 168 | 169 | return item, true 170 | } 171 | -------------------------------------------------------------------------------- /von/cpu.go: -------------------------------------------------------------------------------- 1 | package von 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | // 指令格式: 10 | // 函数调用格式: 11 | // push 12 | // push arg1 13 | // push arg2 14 | // ... 15 | // push argN 16 | // call procName 17 | // 函数实现格式: 18 | // pusha -2 ;取倒数第2个参数 19 | // pusha -1 ;取倒数第1个参数 20 | // ... 21 | // seta -3 ;将运算结果设置到倒数第3个参数 (可能就是返回值的位置) 22 | // ret 2 ;函数返回,将所有参数弹出去 (只留下返回值) 23 | // 24 | const ( 25 | NOOP = iota 26 | ADD // 加法 (arg1, arg2 int64) 27 | SUB // 减法 (arg1, arg2 int64) 28 | MUL // 乘法 (arg1, arg2 int64) 29 | DIV // 除法 (arg1, arg2 int64) 30 | MOD // 取余 (arg1, arg2 int64) 31 | NEG // 取负 (arg1 int64) 32 | LTI // 小于 (arg1, arg2 int64) 33 | LTS // 小于 (arg1, arg2 []byte) 34 | EQI // 等于 (arg1, arg2 int64) 35 | EQS // 等于 (arg1, arg2 []byte) 36 | NOT // 非 (arg1 int64) 37 | CONCAT // 字符串连接 (arg1, arg2 []byte) 38 | INDEX // 取字符 (s []byte, index int64) 39 | STRING // 字符转为字符串 (ch int64) 40 | ALLOC // 申请空间 (n int64) 41 | READ // 读取端口数据 (arg1 []byte) 42 | WRITE // 写端口数据 (arg1 []byte) 43 | PUSHI // 入栈 44 | PUSHS // 入栈 45 | PUSHA // 取参数入栈 46 | SETA // 修改参数 (arg1 interface{}) 47 | JMP // 跳转到 48 | JZ // 如果为假跳转到 49 | CALL // 调用函数 50 | RET // 返回 51 | HALT // 终止 52 | ) 53 | 54 | type CPU struct { 55 | mem *Memory 56 | devs map[int]Device 57 | stk []interface{} 58 | bp int 59 | } 60 | 61 | func NewCPU(mem *Memory) *CPU { 62 | devs := make(map[int]Device) 63 | return &CPU{mem: mem, devs: devs, bp: -1} 64 | } 65 | 66 | func (p *CPU) AddDevice(port int, dev Device) { 67 | p.devs[port] = dev 68 | } 69 | 70 | func (p *CPU) Run(pc int64) { 71 | mem := p.mem 72 | for { 73 | op := readU16(mem, pc) 74 | switch op { 75 | case ADD: 76 | v := p.pop().(int64) 77 | ret := p.top(1) 78 | *ret = (*ret).(int64) + v 79 | pc += 2 80 | debug("ADD:", p.stk) 81 | case SUB: 82 | v := p.pop().(int64) 83 | ret := p.top(1) 84 | *ret = (*ret).(int64) - v 85 | pc += 2 86 | debug("SUB:", p.stk) 87 | case MUL: 88 | v := p.pop().(int64) 89 | ret := p.top(1) 90 | *ret = (*ret).(int64) * v 91 | pc += 2 92 | debug("MUL:", p.stk) 93 | case DIV: 94 | v := p.pop().(int64) 95 | ret := p.top(1) 96 | *ret = (*ret).(int64) / v 97 | pc += 2 98 | debug("DIV:", p.stk) 99 | case MOD: 100 | v := p.pop().(int64) 101 | ret := p.top(1) 102 | *ret = (*ret).(int64) % v 103 | pc += 2 104 | debug("MOD:", p.stk) 105 | case NEG: 106 | ret := p.top(1) 107 | *ret = -(*ret).(int64) 108 | pc += 2 109 | debug("NEG:", p.stk) 110 | case LTI: 111 | v := p.pop().(int64) 112 | ret := p.top(1) 113 | *ret = fromBool((*ret).(int64) < v) 114 | pc += 2 115 | debug("LTI:", p.stk) 116 | case LTS: 117 | v := p.pop().([]byte) 118 | ret := p.top(1) 119 | *ret = fromBool(bytes.Compare((*ret).([]byte), v) < 0) 120 | pc += 2 121 | debug("LTS:", p.stk) 122 | case EQI: 123 | v := p.pop().(int64) 124 | ret := p.top(1) 125 | *ret = fromBool((*ret).(int64) == v) 126 | pc += 2 127 | debug("EQI:", p.stk) 128 | case EQS: 129 | v := p.pop().([]byte) 130 | ret := p.top(1) 131 | *ret = fromBool(bytes.Equal((*ret).([]byte), v)) 132 | pc += 2 133 | debug("EQS:", p.stk) 134 | case NOT: 135 | ret := p.top(1) 136 | *ret = not((*ret).(int64)) 137 | pc += 2 138 | debug("NOT:", p.stk) 139 | case CONCAT: 140 | v := p.pop().([]byte) 141 | ret := p.top(1) 142 | *ret = append((*ret).([]byte), v...) 143 | pc += 2 144 | debug("CONCAT:", p.stk) 145 | case INDEX: 146 | v := p.pop().(int64) 147 | ret := p.top(1) 148 | *ret = int64(((*ret).([]byte))[v]) 149 | pc += 2 150 | debug("INDEX:", p.stk) 151 | case STRING: 152 | ret := p.top(1) 153 | *ret = []byte(string(rune((*ret).(int64)))) 154 | pc += 2 155 | debug("STRING:", p.stk) 156 | case ALLOC: 157 | ret := p.top(1) 158 | *ret = make([]byte, (*ret).(int64)) 159 | pc += 2 160 | debug("ALLOC:", p.stk) 161 | case READ: 162 | port := readU16(mem, pc+2) 163 | buf := p.pop().([]byte) 164 | dev := p.devs[int(port)] 165 | n, err := dev.Read(buf) 166 | if err != nil { 167 | panic(err) 168 | } 169 | p.push(int64(n)) 170 | pc += 4 171 | debug("READ:", p.stk) 172 | case WRITE: 173 | port := readU16(mem, pc+2) 174 | buf := p.pop().([]byte) 175 | dev := p.devs[int(port)] 176 | n, err := dev.Write(buf) 177 | if err != nil { 178 | panic(err) 179 | } 180 | p.push(int64(n)) 181 | pc += 4 182 | debug("WRITE:", p.stk) 183 | case PUSHI: 184 | v := readI64(mem, pc+2) 185 | p.push(v) 186 | pc += 10 187 | debug("PUSHI:", p.stk) 188 | case PUSHS: 189 | n := readU16(mem, pc+2) 190 | v := readBytes(mem, pc+4, int(n)) 191 | p.push(v) 192 | pc += 4 + int64(n) 193 | debug("PUSHS:", p.stk) 194 | case PUSHA: 195 | index := readU16(mem, pc+2) 196 | p.push(p.arg(int16(index))) 197 | pc += 4 198 | debug("PUSHA:", p.stk, "BP:", p.bp) 199 | case SETA: 200 | index := readU16(mem, pc+2) 201 | v := p.pop() 202 | p.stk[p.bp+int(int16(index))] = v 203 | debug("SETA:", p.stk) 204 | pc += 4 205 | case JMP: 206 | delta := readI64(mem, pc+2) 207 | pc += delta 208 | debug("JMP") 209 | case JZ: 210 | delta := readI64(mem, pc+2) 211 | v := p.pop().(int64) 212 | if v == 0 { 213 | pc += delta 214 | } else { 215 | pc += 10 216 | } 217 | debug("JZ:", pc) 218 | case CALL: 219 | base := p.bp 220 | delta := readI64(mem, pc+2) 221 | p.bp = len(p.stk) 222 | p.push(&frame{pc: pc + 10, bp: base}) 223 | pc += delta 224 | debug("CALL:", p.stk) 225 | case RET: 226 | narg := readU16(mem, pc+2) 227 | f := p.arg(0).(*frame) 228 | p.stk = p.stk[:p.bp-int(narg)] 229 | p.bp = f.bp 230 | pc = f.pc 231 | debug("RET:", p.stk, "PC:", pc) 232 | case HALT: 233 | debug("HALT") 234 | return 235 | default: 236 | debug("Unknown instruction:", op) 237 | panic("Unknown instruction") 238 | } 239 | } 240 | } 241 | 242 | type frame struct { 243 | pc int64 244 | bp int 245 | } 246 | 247 | func (p *CPU) Top(index int) interface{} { 248 | last := len(p.stk) - index 249 | return p.stk[last] 250 | } 251 | 252 | func (p *CPU) arg(index int16) interface{} { 253 | return p.stk[p.bp+int(index)] 254 | } 255 | 256 | func (p *CPU) top(index int) *interface{} { 257 | last := len(p.stk) - index 258 | return &p.stk[last] 259 | } 260 | 261 | func (p *CPU) pop() (v interface{}) { 262 | last := len(p.stk) - 1 263 | v = p.stk[last] 264 | p.stk = p.stk[:last] 265 | return 266 | } 267 | 268 | func (p *CPU) push(v interface{}) { 269 | p.stk = append(p.stk, v) 270 | } 271 | 272 | func readU16(mem *Memory, off int64) (v uint16) { 273 | var buf [2]byte 274 | if _, err := mem.ReadAt(buf[:], off); err != nil { 275 | panic(err) 276 | } 277 | return binary.LittleEndian.Uint16(buf[:]) 278 | } 279 | 280 | func readI64(mem *Memory, off int64) (v int64) { 281 | var buf [8]byte 282 | if _, err := mem.ReadAt(buf[:], off); err != nil { 283 | panic(err) 284 | } 285 | return int64(binary.LittleEndian.Uint64(buf[:])) 286 | } 287 | 288 | func readBytes(mem *Memory, off int64, n int) (v []byte) { 289 | v = make([]byte, n) 290 | if _, err := mem.ReadAt(v, off); err != nil { 291 | panic(err) 292 | } 293 | return 294 | } 295 | 296 | func fromBool(b bool) int64 { 297 | if b { 298 | return 1 299 | } 300 | return 0 301 | } 302 | 303 | func not(b int64) int64 { 304 | if b == 0 { 305 | return 1 306 | } 307 | return 0 308 | } 309 | 310 | func debug(a ...interface{}) { 311 | if Debug { 312 | log.Println(a...) 313 | } 314 | } 315 | 316 | var ( 317 | Debug bool 318 | ) 319 | -------------------------------------------------------------------------------- /von/device.go: -------------------------------------------------------------------------------- 1 | package von 2 | 3 | type Device interface { 4 | Read(b []byte) (int, error) 5 | Write(b []byte) (int, error) 6 | } 7 | -------------------------------------------------------------------------------- /von/mem.go: -------------------------------------------------------------------------------- 1 | package von 2 | 3 | import "fmt" 4 | 5 | const PageSize = 1024 6 | 7 | type PageEvent interface { 8 | OnPageMiss(ipage int64) ([]byte, error) 9 | } 10 | 11 | type Memory struct { 12 | data map[int64][]byte 13 | ev PageEvent 14 | } 15 | 16 | func NewMemory(ev PageEvent) *Memory { 17 | data := make(map[int64][]byte) 18 | return &Memory{data, ev} 19 | } 20 | 21 | func (p *Memory) requirePage(ipage int64) []byte { 22 | page, ok := p.data[ipage] 23 | if !ok { 24 | newpage, err := p.ev.OnPageMiss(ipage) 25 | if err != nil { 26 | panic(err) 27 | } 28 | if len(newpage) != PageSize { 29 | panic(fmt.Errorf("OnPageMiss: len(newpage) != PageSize")) 30 | } 31 | p.data[ipage] = newpage 32 | return newpage 33 | } 34 | return page 35 | } 36 | 37 | func (p *Memory) ReadAt(b []byte, pos int64) (n int, err error) { 38 | ipage := pos / PageSize 39 | off := int(pos % PageSize) 40 | for { 41 | page := p.requirePage(ipage) 42 | readed := copy(b, page[off:]) 43 | n += readed 44 | if len(b) == readed { 45 | return 46 | } 47 | b = b[readed:] 48 | off = 0 49 | ipage++ 50 | } 51 | } 52 | --------------------------------------------------------------------------------