View
6.022
Download
0
Category
Tags:
Preview:
DESCRIPTION
A code-heavy exploration of leveraging Go to build virtual machines
Citation preview
GoLightlyBuilding VM-based language runtimes in Go
Eleanor McHugh
http://golightly.games-with-brains.net
1Friday, 15 October 2010
portrait of an artist...
physics major
embedded systems
dynamic languages
dns provisioning
network scaling
questionable taste in music
http://feyeleanor.tel
Eleanor McHugh
2Friday, 15 October 2010
today’s menu
an overview of golightly
a crash course in go programming
application virtualisation & soft machines
3Friday, 15 October 2010
caveat lector
danger! we’re entering strange territory
our map is missing major landmarks
and will be riddled with inaccuracies
so please tread carefully
try not to disturb the local wildlife
and don’t be put off by the pages of code
4Friday, 15 October 2010
golightlyagnostic heterogenous virtualisation networks
5Friday, 15 October 2010
go...a systems language by google
productivity, performance, concurrency
lighter than Java, safer than C
6Friday, 15 October 2010
...lightlyclean abstractions
geared to performance
non-viral open source license
7Friday, 15 October 2010
inspirationprocessor design
sensor and control networks
field-programmable gate arrays
8Friday, 15 October 2010
perspirationiterative empirical development
explore -> implement -> test -> benchmark
evolve towards elegance
9Friday, 15 October 2010
principlesdecoupling improves scalability
coherence simplifies organisation
optimisations are application specific
10Friday, 15 October 2010
agnosticno blessed programming languages
flexible platform abstractions
write once, run everywhere it matters
11Friday, 15 October 2010
heterogeneousa system comprises many components
components may differ in purpose and design
but they cooperate to solve problems
12Friday, 15 October 2010
virtualisationdesign discrete Turing machines
implement these machines in software
compile programs to run on them
13Friday, 15 October 2010
networksmachines cooperate by sending messages
machine states can be serialised as messages
messages transcend process and host boundaries
14Friday, 15 October 2010
goa crash course
15Friday, 15 October 2010
behind the hype
a statically-typed compiled language
class-free object-orientation
nominal type declaration
structural type inference
garbage collection
concurrency via communication (CSP)
16Friday, 15 October 2010
an elegant tool
the safety of a static type system
the feel of a dynamic runtime
the performance of a compiled language
no dependence on runtime libraries
17Friday, 15 October 2010
nominal types
primitive (boolean, numeric, pointer)
aggregate (array, slice, map, struct)
functional (closure, channel)
all types can underpin user-defined types
methods are declared on user-defined types
types can be embedded in struct types
18Friday, 15 October 2010
package Integer
type Int int
func (i *Int) Add(x int) {*i += Int(x)
}
type Buffer []Int
func (b Buffer) Clone() Buffer {s := make(Buffer, len(b))copy(s, b)return s
}
func (b Buffer) Swap(i, j int) {b[i], b[j] = b[j], b[i]
}
func (b Buffer) Move(i, n int) {if n > len(b) - i {
n = len(b) - i}segment_to_move := b[:i].Clone()copy(b, b[i:i + n])copy(b[n:i + n], segment_to_move)
}
package mainimport “Integer”
func main() {i := Integer.Buffer{0, 1, 2, 3, 4, 5}b := i.Clone()b.Swap(1, 2)b.Move(3, 2)b[0].Add(3)println(“b[0:2] = {”, b[0], “,”, b[1], “}”)
}
produces:b[0:2] = { 6, 4 }
19Friday, 15 October 2010
package Vectorimport . “Integer”
type Vector struct {Buffer
}
func (v *Vector) Clone() Vector {return Vector{v.Buffer.Clone()}
}
func (v *Vector) Slice(i, j int) Buffer {return v.Buffer[i:j]
}
func (v *Vector) Replace(o interface{}) {switch o := o.(type) {case Vector:
v = ocase Buffer:
v.Buffer = o}
}
package mainimport “Integer”
func main() {i := Vector{Buffer{0, 1, 2, 3, 4, 5}}b := i.Clone()b.Swap(1, 2)b.Move(3, 2)s := b.Slice(0, 2)s[0].Add(3)b.Replace(s)println(“b[0:2] = {”, b.Buffer[0], “,”, b.Buffer[1], “}”)
}
produces:b[0:2] = { 6, 4 }
20Friday, 15 October 2010
structural types
interfaces define method sets
they can be embedded within each other
but do not implement methods
a type can implement many interfaces
type inference determines which if any
all types implement the blank interface
21Friday, 15 October 2010
package main
type Adder interface { Add(j int) Subtract(j int) Result() interface{}}
type IntAdder []intfunc (i IntAdder) Add(j int) { i[0] += i[j]}func (i IntAdder) Subtract(j int) { i[0] -= i[j]}func (i IntAdder) Result() interface{} { return i[0]}
type FloatAdder []floatfunc (f FloatAdder) Add(j int) { f[0] += f[j]}func (f FloatAdder) Subtract(j int) { f[0] -= f[j]}func (f FloatAdder) Result() interface{} { return f[0]}
type Calculator struct { Adder}
func main() {c := Calculator{}c.Adder = IntAdder{0, 1, 2, 3, 4, 5}c.Add(1) c.Add(2)c.Subtract(3)println("c.Result() =", c.Result().(int))
c.Adder = FloatAdder{0.0, 1.1, 2.2, 3.3, 4.4, 5.5}c.Add(1)c.Add(2)c.Subtract(3)println("c.Result() =", c.Result())
}
produces:c.Result() = 0c.Result() = (0x10f94,0x34800000)
22Friday, 15 October 2010
dynamic typing
type assertions
type switches
runtime reflection
23Friday, 15 October 2010
package generaliseimport "fmt"import . "reflect"
func Allocate(i interface{}, limit... int) (n interface{}) {switch v := NewValue(i).(type) {case *SliceValue:
l := v.Cap()if len(limit) > 0 { l = limit[0] }t := v.Type().(*SliceType)n = MakeSlice(t, l, l).Interface()
case *MapValue:n = MakeMap(v.Type().(*MapType)).Interface()
}return
}
func SwapSlices(i interface{}, d, s, n int) {if v, ok := NewValue(i).(*SliceValue); ok {
source := v.Slice(s, s + n)destination := v.Slice(d, d + n)temp := NewValue(Allocate(i, n)).(*SliceValue)ArrayCopy(temp, destination)ArrayCopy(destination, source)ArrayCopy(source, temp)
}}
func Duplicate(i interface{}) (clone interface{}) {if clone = Allocate(i); clone != nil {
switch clone := NewValue(clone).(type) {case *SliceValue:
s := NewValue(i).(*SliceValue)ArrayCopy(clone, s)
case *MapValue:m := NewValue(i).(*MapValue)for _, k := range m.Keys() {
clone.SetElem(k, m.Elem(k))}
}}return
}
24Friday, 15 October 2010
package mainimport . “generalise”
func main() {error_text := “panic caused by”defer func() {
if x := recover(); x != nil {fmt.Println(error_text, x)
}}()
s1 := []int{0, 1, 2, 3, 4, 5}fmt.Println("s1 =", s1)s2 := Duplicate(s1)fmt.Println("s2 =", s2, "Duplicate(s1)")SwapSlices(s2, 0, 3, 3)fmt.Println("s2 =", s2, "SwapSlices(s2, 0, 3, 3)")s3 := Allocate(s1, 1)fmt.Println("s3 =", s3, "Allocate(s1, 1)")
m := map[int] int{1: 1, 2: 2, 3: 3, 0: 0, 4: 4, 5: 5}fmt.Println("m =", m)n := Allocate(m)fmt.Println("n =", n, "Allocate(m)")SwapSlices(m, 0, 3, 3)
}
produces:s1 = [0 1 2 3 4 5]s2 = [0 1 2 3 4 5] Duplicate(s1)s2 = [3 4 5 0 1 2] SwapSlices(s2, 0, 3, 3)s3 = [0] Allocate(s1, 1)m = map[3:3 0:0 1:1 4:4 5:5 2:2]n = map[]panic caused by map[3:3 0:0 1:1 4:4 5:5 2:2]
25Friday, 15 October 2010
goroutines
concurrent threads of control
launched by the go statement
which returns immediately
each may be a function call or method call
and can communicate via channels
26Friday, 15 October 2010
channels
link concurrently executing functions
support sending and/or receiving
only accept items of a specified type
synchronous channels are unbuffered
asynchronous channels are buffered
27Friday, 15 October 2010
package generaliseimport . "reflect"
type Results chan interface{}
type SignalSource func(status chan bool)func (s SignalSource) Pipeline() {
done := make(chan bool)defer close(done)go s(done)<-done
}
func (s SignalSource) Multiplex(count int) {done := make(chan bool)defer close(done)go s(done)for i := 0; i < count; i++ {
<- done}
}
type Iteration func(k, x interface{})func (i Iteration) apply(k, v interface{}, c chan bool) {
go func() {i(k, v)c <- true
}()}
func (f Iteration) Each(c interface{}) {switch c := NewValue(c).(type) {case *SliceValue:
count := c.Len()SignalSource(func(done chan bool) {
for i := 0; i < count; i++ {f.apply(i, c.Elem(i).Interface(), done)
}}).Multiplex(count)
case *MapValue:SignalSource(func(done chan bool) {
for _, k := range c.Keys() {f.apply(k, c.Elem(k).Interface(), done)
}}).Multiplex(c.Len())
}}
type Combination func(x, y interface{}) interface{} func (f Combination) Reduce(c, s interface{}) (r Results) {
r = make(Results)go func() {
Iteration(func(k, x interface{}) {s = f(s, x)
}).Each(c)r <- s
}()return
}
28Friday, 15 October 2010
type Transformation func(x interface{}) interface{} func (t Transformation) GetValue(x interface{}) Value {
return NewValue(t(x))}
func (t Transformation) Map(c interface{}) interface{} {switch n := NewValue(Allocate(c)).(type) {case *SliceValue:
SignalSource(func(done chan bool) {Iteration(func(k, x interface{}) {
n.Elem(k.(int)).SetValue(t.GetValue(x))}).Each(c)done <- true
}).Pipeline()return n.Interface()
case *MapValue:SignalSource(func(done chan bool) {
Iteration(func(k, x interface{}) {n.SetElem(NewValue(k), t.GetValue(x))
}).Each(c)done <- true
}).Pipeline()return n.Interface()
}return Duplicate(c)
}
package mainimport “fmt”import . “generalise”
var adder Combination = func(x, y interface{}) interface{} { return x.(int) + y.(int)}
var multiplier Transformation = func(x interface{}) interface{} { return x.(int) * 2}
func main() {s := []int{0, 1, 2, 3, 4, 5}fmt.Println("s =", s)fmt.Println("sum s =", (<- adder.Reduce(s, 0)).(int))
c := multiplier.Map(s)fmt.Println("c =", c)fmt.Println("sum c =", (<- adder.Reduce(c, 0)).(int))
}
produces:s = [0 1 2 3 4 5]sum s = 15c = [0 2 4 6 8 10]sum c = 30
29Friday, 15 October 2010
tooling
gotest is a testing framework
which also supports benchmarking
gofmt standardises code layout
godoc formats and serves documentation
goinstall is an automatic package installer
cgo integrates C code with go
30Friday, 15 October 2010
software machinesapplication virtualisation 101
31Friday, 15 October 2010
system clocksynchronising components
32Friday, 15 October 2010
package clockimport "syscall"
type Clock struct {Period int64Count chan int64Control chan boolactive bool
}
func (c *Clock) Start() {if !c.active {
go func() {c.active = truefor i := int64(0); ; i++ {
select {case status := <- c.Control:
c.active = statusdefault:
if c.active {c.Count <- i
}syscall.Sleep(c.Period)
}}
}()}
}
package mainimport . “clock”
func main() {c := Clock{1000, make(chan int64), make(chan bool), false}c.Start()
for i := 0; i < 3; i++ {println("pulse value", <-c.Count, "from clock")
}
println("disabling clock")c.Control <- falsesyscall.Sleep(1000000)println("restarting clock")c.Control <- trueprintln("pulse value", <-c.Count, "from clock")
}
produces:pulse value 0 from clockpulse value 1 from clockpulse value 2 from clockdisabling clockrestarting clockpulse value 106 from clock
33Friday, 15 October 2010
instruction setspecifying operation sequences
34Friday, 15 October 2010
package instructionsimport "fmt"
type Operation func(o []int)
type Executable interface {Opcode() intOperands() []intExecute(op Operation)
}
const INVALID_OPCODE = -1
type Instruction []intfunc (i Instruction) Opcode() int {
if len(i) == 0 {return INVALID_OPCODE
}return i[0]
}
func (i Instruction) Operands() []int {if len(i) < 2 {
return []int{}}return i[1:]
}
func (i Instruction) Execute(op Operation) {op(i.Operands())
}
type Assembler struct {opcodes map[string] intnames map[int] string
}
func NewAssember(names... string) (a Assembler) {a = Assembler{ make(map[string] int), make(map[int] string) }a.Define(names...)return
}
func (a Assembler) Assemble(name string, params... int)(i Instruction) {
i = make(Instruction, len(params) + 1) if opcode, ok := a.opcodes[name]; ok { i[0] = opcode } else { i[0] = INVALID_OPCODE } copy(i[1:], params) return }
35Friday, 15 October 2010
func (a Assembler) Define(names... string) {for _, name := range names {
a.opcodes[name] = len(a.names)a.names[len(a.names)] = name
}}
func (a Assembler) Disassemble(e Executable) (s string) {if name, ok := a.names[e.Opcode()]; ok {
s = nameif params := e.Operands(); len(params) > 0 {
s = fmt.Sprintf("%v\t%v", s, params[0])for _, v := range params[1:] {
s = fmt.Sprintf("%v, %v", s, v)}
}} else {
s = "unknown"}return
}
type Program []Executablefunc (p Program) Disassemble(a Assembler) {
for _, v := range p {fmt.Println(a.Disassemble(v))
}}
package mainimport . “instructions”
func main() {a := NewAssembler("noop", "load", "store")p := Program{ a.Assemble("noop"),
a.Assemble("load", 1),a.Assemble("store", 1, 2),a.Assemble("invalid", 3, 4, 5) }
p.Disassemble(a)for _, v := range p {
if len(v.Operands()) == 2 {v.Execute(func(o []int) {
o[0] += o[1]})println("op =", v.Opcode(), "result =", v.Operands()[0])
}}
}
produces:noopload!! 1store! 1, 2unknownop = 2 result = 3
36Friday, 15 October 2010
CISCsemantically rich instructions
complex memory addressing modes
compact binary code
37Friday, 15 October 2010
RISCseparate IO and data processing
register-to-register instructions
load/store memory access
38Friday, 15 October 2010
VLIWmultiple operations per instruction
compiler statically determines parallelism
simplifies control logic
39Friday, 15 October 2010
memorystoring data and instructions
40Friday, 15 October 2010
subtletiesvon Neumann
Harvard
indirection bits
41Friday, 15 October 2010
package memoryimport "fmt"import . "reflect"import "unsafe"
var _BYTE_SLICE = Typeof([]byte(nil))var _SLICE_TYPE = Typeof(SliceHeader{})
func Data(addr unsafe.Pointer) []byte {return unsafe.Unreflect(_BYTE_SLICE, addr).([]byte)
}
func Resize(h *SliceHeader, d, m int) {h.Len /= dh.Len *= m
}
func Serialise(i interface{}) []byte {switch i := NewValue(i).(type) {case *SliceValue:
h := Header(unsafe.Pointer(i.Addr()))t := i.Type().(*SliceType)Resize(&h, 1, int(t.Elem().Size()))return Data(unsafe.Pointer(&h))
}return nil
}
func Overwrite(i interface{}, b []byte) interface{} {switch i := NewValue(i).(type) {case *SliceValue:
h := Header(unsafe.Pointer(&b))t := i.Type().(*SliceType)Resize(&h, int(t.Elem().Size()), 1)return unsafe.Unreflect(t, unsafe.Pointer(&h))
}return nil
}
42Friday, 15 October 2010
package mainimport “fmt”import . "memory"
type Memory []int
func main() { m := make(Memory, 2) fmt.Println("m (cells) =", len(m), "of", cap(m), ":", m) b := Serialise(m) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)
n := Overwrite(m, []byte{0, 0, 0, 1, 0, 0, 0, 1}).(Memory) fmt.Println("n (cells) =", len(n), "of", cap(n), ":", n)
b = Serialise(n) fmt.Println("b (bytes) =", len(b), "of", cap(b), ":", b)}
produces:m (cells) = 2 of 2 : [0 0]b (bytes) = 8 of 2 : [0 0 0 0 0 0 0 0]n (cells) = 2 of 8 : [16777216 16777216]b (bytes) = 8 of 8 : [0 0 0 1 0 0 0 1]
43Friday, 15 October 2010
processor coretying it all together
44Friday, 15 October 2010
package processorimport . “instructions”import . “memory”
const PROCESSOR_READY = 0const PROCESSOR_BUSY = 1const CALL_STACK_UNDERFLOW = 2const CALL_STACK_OVERFLOW = 4const ILLEGAL_OPERATION = 8const INVALID_ADDRESS = 16
type Processor interface {! Run(p []Executable)}
type Core struct {Ticks! ! intRunning! boolPC, Flags! intCS! ! []intM! ! MemoryOP! ! Executable
}
func NewCore(CSSize, MSize int) ProcessorCore {return Core{
CS: make([]int, 0, Calls)},M: make(Memory, MSize),
}}
func (p *Core) Reset() {p.Running = falsep.Flags = PROCESSOR_READY
}
func (c *Core) RunExclusive(p []Executable, f func()) {defer func() {
c.Running = falseif x := recover(); x != nil {
c.Flags &= x.(int)}
}()if c.Running {
panic(PROCESSOR_BUSY)}c.Running = truefor c.PC = 0; c.Running; {
c.LoadInstruction(p)f()c.Ticks++
}}
func (c *Core) LoadInstruction(program []Executable) {if c.PC >= len(program) {
panic(PROCESSOR_READY)}c.Executable = program[c.PC]c.PC++
}
45Friday, 15 October 2010
package processor
func (c *Core) Goto(addr int) {! c.PC = addr}
func (c *Core) Call(addr int) {if top := len(c.CS); top < cap(c.CS) - 1 {
c.CS = c.CS[:top + 1]c.CS[top] = c.PCc.PC = addr
} else {panic(CALL_STACK_OVERFLOW)
}}
func (c *Core) TailCall(addr int) {! c.CS[len(c.CS) - 1] = c.PC! c.PC = addr}
func (c *Core) Return() {! if top := len(c.CS); top > 0 {! ! c.PC, c.CS = c.CS[top - 1], c.CS[:top]! } else {! ! panic(CALL_STACK_UNDERFLOW)! }}
46Friday, 15 October 2010
package mainimport . “processor”import . “instructions”
const (CALL = iotaGOTOMOVERETURN
)
var dispatcher = func() {switch c.Opcode() {case CALL:
c.Execute(func(o []int) { c.Call(o[0]) })case GOTO:
c.Execute(func(o []int) { c.Goto(o[0]) })case MOVE:
c.Execute(func(o []int) { c.Goto(c.PC + o[0]) })case RETURN:
c.Execute(func(o []int) { c.Return() })default:
panic(ILLEGAL_OPERATION)}
}
func main() {c := NewCore(10, 8)p := []Executable{
Instruction{CALL, 2},Instruction{GOTO, 5},Instruction{MOVE, 2},Instruction{RETURN},Instruction{MOVE, -1},
}c.RunExclusive(p, dispatcher)fmt.Println("Instructions Executed:", c.Ticks)fmt.Println("PC =", c.PC)if c.Flags | PROCESSOR_READY == PROCESSOR_READY {
fmt.Println("Core Ready")} else {
fmt.Println("Core Error:", c.Flags)}
}
produces:top = 0cap(c.CS) -1 = 9Instructions Executed: 2PC = 5Core Ready
47Friday, 15 October 2010
accumulator machine1-operand instructions
data from memory combined with accumulator
result stored in accumulator
48Friday, 15 October 2010
package accmachineimport . “processor”import . “memory”
const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD
)
type AccMachine struct {! Core! AC! ! ! ! int}
func NewAccMachine(CSSize, MSize int) *AccMachine {! return &AccMachine{NewCore(CSSize, MSize), 0}}
func (a *AccMachine) Run(program []Executable) {a.RunExclusive(program, func() {
switch a.Opcode() {case CONSTANT:
a.Execute(func(o []int) {a.AC = o[0]
})case LOAD_VALUE:
a.Execute(func(o []int) {a.AC = a.M[o[0]]
})case STORE_VALUE:
a.Execute(func(o []int) {a.M[o[0]] = a.AC
})case ADD:
a.Execute(func(o []int) {a.AC += a.M[o[0]]
})default:
panic(ILLEGAL_OPERATION)}
})}
49Friday, 15 October 2010
package mainimport . “accmachine”import . “instructions”
func main() {a := NewAccMachine(10, 8)p := []Executable{
Instruction{CONSTANT, 27},Instruction{STORE_VALUE, 0},Instruction{CONSTANT, 13},Instruction{STORE_VALUE, 1},Instruction{CONSTANT, 10},Instruction{ADD, 1},Instruction{ADD, 0},Instruction{STORE_VALUE, 2},
}a.Run(p)fmt.Println("accumulated value =", a.AC)
}
produces:accumulated value = 50
50Friday, 15 October 2010
stack machine0-operand instructions
data popped from stack
results pushed on stack
51Friday, 15 October 2010
package smachineimport . “processor”
func (s *StackMachine) Run(program []Executable) {s.RunExclusive(program, func() {
switch s.Opcode() {case CONSTANT:
s.Execute(func(o []int) {s.Push(o[0])
})case PUSH_VALUE:
s.Execute(func(o []int) {s.Push(s.M[o[0]])
})case POP_VALUE:
s.Execute(func(o []int) {s.Pop(s.M[o[0]])
})case ADD:
s.Execute(func(o []int) {l := len(s.DS)s.DS[l - 2] += s.DS[l - 1]s.DS = s.DS[:l - 1]
})default:
panic(ILLEGAL_OPERATION)}
})}
type StackMachine struct {CoreDS! []int
}
func (s *StackMachine) Push(v int) {top := len(s.DS)s.DS, s.DS[top] = s.DS[:top + 1], v
}
func (s *StackMachine) Pop(addr int) {top := len(s.DS) - 1s.M[addr], s.DS = s.DS[top], s.DS[:top]
}
const (CONSTANT = iotaPUSH_VALUEPOP_VALUEADD
)
func NewStackM(CSSize, DSSize, MSize int) *StackMachine {return &StackMachine{
DS: make([]int, 0, DSSize),Core: NewCore(CSSize, MSize),
}}
52Friday, 15 October 2010
package mainimport . “smachine”import . “instructions”
func main() {s := NewStackM(10, 10, 8)p := []Executable{
Instruction{CONSTANT, 27},Instruction{CONSTANT, 13},Instruction{CONSTANT, 10},Instruction{ADD},Instruction{ADD},
}s.Run(p)fmt.Println("data stack =", s.DS)
}
produces:registers = [50 13 10 0 0 0 0 0 0 0]
53Friday, 15 October 2010
register machinemulti-operand instructions
data read from memory into registers
operator combines registers and stores
54Friday, 15 October 2010
package rmachineimport . “processor”
func (r *RegisterMachine) Run(program []Executable) {! r.RunExclusive(program, func() {! ! switch r.Opcode() {! ! case CONSTANT:! ! ! r.Execute(func(o []int) {! ! ! ! r.R[o[0]] = o[1]! ! ! })! ! case LOAD_VALUE:! ! ! r.Execute(func(o []int) {! ! ! ! r.R[o[0]] = r.M[o[1]]! ! ! })! ! case STORE_VALUE:! ! ! r.Execute(func(o []int) {! ! ! ! r.M[o[0]] = r.R[o[1]]! ! ! })! ! case ADD:! ! ! r.Execute(func(o []int) {! ! ! ! r.R[o[0]] += r.R[o[1]]! ! ! })! ! default:! ! ! panic(ILLEGAL_OPERATION)! ! }! })}
type RegisterMachine struct {! Core! R! ! Memory}
const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD
)
func NewRMachine(CSSize, RSize, MSize int) *RegisterMachine {return &RegisterMachine{
NewCore(CSSize, MSize),make([]int, RSize)
}}
55Friday, 15 October 2010
package mainimport . “rmachine”import . “instructions”
func main() {r := NewRMachine(10, 10, 8)p := []Executable{
Instruction{CONSTANT, 0, 27},Instruction{CONSTANT, 1, 13},Instruction{CONSTANT, 2, 10},Instruction{ADD, 0, 1},Instruction{ADD, 0, 2},
}r.Run(p)fmt.Println("registers =", r.R)
}
produces:registers = [50 13 10 0 0 0 0 0 0 0]
56Friday, 15 October 2010
transport triggeringregister machine architecture
exposes internal buses and components
operations are side-effects of internal writes
57Friday, 15 October 2010
vector machinemulti-operand instructions
data vectors read from memory into registers
operations combine registers
58Friday, 15 October 2010
package vmachineimport . “processor”
func (v *VectorMachine) Run(program []Executable) {v.RunExclusive(program, func() {
switch v.Opcode() {case CONSTANT:
v.Execute(func(o []int) { v.Load(o[0], o[1:]) })case LOAD_VALUE:
v.Execute(func(o []int) {v.Load(o[0], v.M[o[1]:o[1] + o[2]])
})case STORE_VALUE:
v.Execute(func(o []int) {copy(v.M[o[0]:], v.R[o[1]])
})case ADD:
v.Execute(func(o []int) {a, b := v.R[o[0]], v.R[o[1]]if len(a) < len(b) {
for i, x := range a { a[i] = x + b[i] }} else {
for i, x := range b { a[i] += x }}
})! ! default:! ! ! panic(ILLEGAL_OPERATION)! ! }! })}
type VectorMachine struct {! Core! R! ! []Memory}
func (v *VectorMachine) Load(r int, m Memory) {! v.R[r] = make(Memory, len(m))! copy(v.R[r], m)}
func NewVMachine(CSSize, RSize, MSize int) *VectorMachine {! return &VectorMachine{
NewCore(CSSize, MSize),make([]Memory, RSize)
}}
const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD
)
59Friday, 15 October 2010
package mainimport . “vmachine”import . “instructions”
func main() {r := NewVMachine(10, 10, 8)p := []Executable{
Instruction{CONSTANT, 0, 27},Instruction{CONSTANT, 1, 13},Instruction{CONSTANT, 2, 10},Instruction{ADD, 0, 1},Instruction{ADD, 0, 2},
}r.Run(p)fmt.Println("registers =", r.R)
}
produces:vectors = [[50 50 50] [13 10 27] [10 27 13] [] [] [] [] [] [] []]
60Friday, 15 October 2010
superscalarmultiple execution units
processor caching
out-of-order execution
61Friday, 15 October 2010
close to the machineinterrupts
transport buses
peripheral drivers
62Friday, 15 October 2010
finding out more
http://golightly.games-with-brains.net
http://github.com/feyeleanor/GoLightly
twitter://#golightly
wikipedia
63Friday, 15 October 2010
Recommended