golightlya customisable virtual machine written in GoEleanor McHughhttp://slides.games-with-brains.net/Thursday, 30 May 13
portrait of an artist...physics majorembedded controllerssoftware reliabilitydynamic languagesnetwork scalingquestionable ...
go...small, safety-conscious systems languageconcurrency, closures & garbage collectionconsistently fast compilationThursd...
...lightlyagnostic virtual machine networksapplication performance mattersnon-viral open source licenseThursday, 30 May 13
agnosticno blessed programming languagesflexible platform abstractionswrite once, run everywhere it mattersThursday, 30 May...
heterogeneousa system comprises many componentscomponents may differ in purpose and designbut they cooperate to solve prob...
networksmachines cooperate by sending messagesmachine states can be serialised as messagesmessages transcend process and h...
inspirationhardware designsensor and control networksfield-programmable gate arraysThursday, 30 May 13
virtual machineemulate an existing systemsimulate an imagined systemhave dynamic control of system stateThursday, 30 May 13
stack-based lambda calculus processorthreaded value cells in a von neumann memoryall operations are expressions are values...
stack-based processorthreaded word definitions in a von neumann memorywords thread primitives, word pointers and dataforthT...
stack-based processor with instruction setharvard memory separates code and dataclass loaders convert bytecode to machine ...
linux kernel hypervisorintel X86 virtualisation with hardware executionQEMU virtual machine runs in user spacekvmThursday,...
hello worldThursday, 30 May 13
package mainimport "fmt"const(HELLO string = "hello"WORLD string = "world")func main() {fmt.Println(HELLO, WORLD)}Thursday...
user-defined typeThursday, 30 May 13
package Integertype Int intfunc (i *Int) Add(x int) {*i += Int(x)}Thursday, 30 May 13
package Integertype Buffer []Intfunc (b Buffer) Eq(o Buffer) (r bool) {if len(b) == len(o) {for i := len(b) - 1; i > 0; i-...
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].A...
package Integerimport "testing"func TestSwap(t *testing.T) {i := Buffer{0, 1, 2, 3, 4, 5}b := i.Clone()b.Swap(1, 2)if !b[1...
embeddingThursday, 30 May 13
package Vectorimport . "Integer"type Vector struct {Buffer}func (v *Vector) Clone() Vector {return Vector{v.Buffer.Clone()...
package Integerimport "testing"func TestVectorSwap(t *testing.T) {i := Vector{Buffer{0, 1, 2, 3, 4, 5}}v := i.Clone()v.Swa...
package integerimport "testing"func BenchmarkVectorClone6(b *testing.B) {v := Vector{Buffer{0, 1, 2, 3, 4, 5}}for i := 0; ...
$ go test -test.bench="Benchmark"PASSinteger.BenchmarkVectorSwap 200000000 8 ns/opinteger.BenchmarkVectorClone6 10000000 3...
inferenceThursday, 30 May 13
package addertype Adder interface {Add(j int)Subtract(j int)Result() interface{}}type Calculator interface {AdderReset()}t...
package addertype IAdder []intfunc (i IAdder) Add(j int) {i[0] += i[j]}func (i IAdder) Subtract(j int) {i[0] -= i[j]}func ...
package adderimport "testing"func TestIAdder(t *testing.T) {error := "Result %v != %v"i := IAdder{0, 1, 2}i.Add(1)if i.Res...
package adderimport "testing"func TestIAdder(t *testing.T) {error := "Result %v != %v"i := IAdder{0, 1, 2}i.Add(1)if i.Res...
package addertype FAdder []float32func (f FAdder) Add(j int) {f[0] += f[j]}func (f FAdder) Subtract(j int) {f[0] -= f[j]}fu...
package adderimport "testing"func TestFAdder(t *testing.T) {error := "Result %v != %v"f := FAdder{0.0, 1.0, 2.0}f.Add(1)if...
package adderimport "testing"func TestAddingMachine(t *testing.T) {error := "Result %v != %v"a := &AddingMachine{ Adder: F...
concurrencyThursday, 30 May 13
goroutinesconcurrent execution stacksinitialised with a closurescheduled automatically by the runtimeThursday, 30 May 13
package mainimport "fmt"func main() {var c chan intc = make(chan int)go func() {for {fmt.Print(<-c)}}()for {select {case c...
package mainimport "fmt"func main() {var c chan intc = make(chan int, 16)go func() {for {fmt.Print(<-c)}}()go func() {sele...
package map_reducetype SignalSource func(status chan bool)func Wait(s SignalSource) {done := make(chan bool)defer close(do...
package map_reducetype Iteration func(k, x interface{})func (i Iteration) apply(k, v interface{}, c chan bool) {go func() ...
package map_reducefunc Each(c interface{}, f Iteration) {switch c := c.(type) {case []int: WaitCount(len(c), func(done cha...
package map_reducetype Results chan interface{}type Combination func(x, y interface{}) interface{}func (f Combination) Red...
package map_reducetype Transformation func(x interface{}) interface{}func (t Transformation) GetValue(x interface{}) inter...
func Map(c interface{}, t Transformation) (n interface{}) {var i Iterationswitch c := c.(type) {case []int: m := make([]in...
package mainimport "fmt"import . "map_reduce"func main() {m := "%v = %v, sum = %vn"s := []int{0, 1, 2, 3, 4, 5}sum := func...
software machinesThursday, 30 May 13
synchronisationThursday, 30 May 13
package clockimport "syscall"type Clock struct {Period int64Count chan int64Control chan boolactive bool}Thursday, 30 May 13
package clockimport "syscall"func (c *Clock) Start() {if !c.active {go func() {c.active = truefor i := int64(0); ; i++ {se...
package mainimport . "clock"func main() {c := Clock{1000, make(chan int64), make(chan bool), false}c.Start()for i := 0; i ...
OSX 10.6.2 Intel Atom 270 @ 1.6GHz:pulse value 0 from clockpulse value 1 from clockpulse value 2 from clockdisabling clock...
instruction setThursday, 30 May 13
operationsCISCRISCVLIWThursday, 30 May 13
package instructionsimport "fmt"type Operation func(o []int)type Executable interface {Opcode() intOperands() []intExecute...
package instructionstype Instruction []intfunc (i Instruction) Opcode() int {if len(i) == 0 {return INVALID_OPCODE}return ...
package instructionstype Assembler struct {opcodes map[string] intnames map[int] string}func NewAssember(names... string) ...
package instructionsfunc (a Assembler) Assemble(name string, params... int) (i Instruction) {i = make(Instruction, len(par...
package instructionsimport "fmt"func (a Assembler) Disassemble(e Executable) (s string) {if name, ok := a.names[e.Opcode()...
package mainimport . "instructions"func main() {a := NewAssembler("noop", "load", "store")p := Program{ a.Assemble("noop")...
produces:noopload 1store 1, 2unknownop = 2 result = 3Thursday, 30 May 13
processor coreThursday, 30 May 13
package processorimport . "instructions"const PROCESSOR_READY = 0const PROCESSOR_BUSY = 1const CALL_STACK_UNDERFLOW = 2con...
package processorimport . "instructions"func NewCore(CSS, MSS int, I chan Executable) *Core {return &Core{CS:make([]int, C...
package processorfunc (c *Core) Call(addr int) {top := len(c.CS)if top >= cap(c.CS) - 1 { panic(CALL_STACK_OVERFLOW) }c.CS...
package processorimport . "instructions"func (c *Core) Run(p []Executable, dispatchers... func(c *Core)) {defer func() {c....
package processorimport . "instructions"func (c *Core) BusyLoop(p []Executable, dispatchers... func(c *Core)) {select {cas...
package processorimport . "instructions"func (c *Core) RunExclusive(p []Executable, tracers... func(c *Core)) {defer func(...
package mainimport . "processor"import . "instructions"const( CALL = iotaGOTOMOVERETURN)c := NewCore(10, 8, nil)var dispat...
func main() {p := []Executable{ Instruction{ CALL, 2 },Instruction{ GOTO, 5 },Instruction{ MOVE, 2 },Instruction{ RETURN }...
accumulator machine1-operand instructionsdata from memory combined with accumulatorresult stored in accumulatorThursday, 3...
package accmachineimport . "processor"const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD)type AccMachine struct {CoreAC int}fu...
package accmachineimport . "processor"func (a *AccMachine) Run(program []Executable) {a.RunExclusive(program, func() {swit...
package mainimport . "accmachine"import . "instructions"func main() {a := NewAccMachine(10, 8, nil)p := []Executable{ Inst...
stack machine0-operand instructionsdata popped from stackresults pushed on stackThursday, 30 May 13
package smachineimport . "processor"const (CONSTANT = iotaPUSH_VALUEPOP_VALUEADD)type StackMachine struct {CoreDS []int}fu...
package smachineimport . "processor"func (s *StackMachine) Push(v int) {top := len(s.DS)s.DS, s.DS[top] = s.DS[:top + 1], ...
package smachineimport . "processor"func (s *StackMachine) Run(program []Executable) {s.RunExclusive(program, func() {swit...
package mainimport . "smachine"import . "instructions"func main() {s := NewStackM(10, 10, 8, nil)p := []Executable{ Instru...
register machinemulti-operand instructionsdata read from memory into registersoperator combines registers and storesThursd...
package rmachineimport . "processor"const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD)type RMachine struct {CoreR []int}func ...
package rmachineimport . "processor"func (r *RMachine) Run(program []Executable) {r.RunExclusive(program, func() {switch r...
package mainimport . "rmachine"import . "instructions"func main() {r := NewRMachine(10, 10, 8, nil)p := []Executable{ Inst...
vector machinemulti-operand instructionsdata vectors read from memory into registersoperations combine registersThursday, ...
package vmachineimport . "processor"const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD)type VMachine struct {CoreR [][]int}fun...
package vmachineimport . "processor"func (v *VMachine) Load(r int, m []int) {v.R[r] = make([]int, len(m))copy(v.R[r], m)}T...
package vmachineimport . "processor"func (v *VMachine) Run(program []Executable) {v.RunExclusive(program, func() {switch v...
package mainimport . "vmachine"import . "instructions"func main() {r := NewVMachine(10, 10, 8, nil)p := []Executable{ Inst...
related projectsgospeedraw - slices - lists - chains - sexpwendigoThursday, 30 May 13
related projectsgospeedtypelibwendigoThursday, 30 May 13
finding out morehttp://golang.org/twitter://#golanghttp://slides.games-with-brains.net/http://github.com/feyeleanor/wikiped...
Upcoming SlideShare
Loading in …5
×

GoLightly - a customisable virtual machine written in Go

1,882 views

Published on

A brief overview of the Go programming language and how it might be used to build a simple customisable virtual machine. This is a reduced and updated version of my previous Go virtual machine talks with many code examples.

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,882
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
0
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

GoLightly - a customisable virtual machine written in Go

  1. 1. golightlya customisable virtual machine written in GoEleanor McHughhttp://slides.games-with-brains.net/Thursday, 30 May 13
  2. 2. portrait of an artist...physics majorembedded controllerssoftware reliabilitydynamic languagesnetwork scalingquestionable taste in musichttp://github.com/feyeleanorEleanor McHughThursday, 30 May 13
  3. 3. go...small, safety-conscious systems languageconcurrency, closures & garbage collectionconsistently fast compilationThursday, 30 May 13
  4. 4. ...lightlyagnostic virtual machine networksapplication performance mattersnon-viral open source licenseThursday, 30 May 13
  5. 5. agnosticno blessed programming languagesflexible platform abstractionswrite once, run everywhere it mattersThursday, 30 May 13
  6. 6. heterogeneousa system comprises many componentscomponents may differ in purpose and designbut they cooperate to solve problemsThursday, 30 May 13
  7. 7. networksmachines cooperate by sending messagesmachine states can be serialised as messagesmessages transcend process and host boundariesThursday, 30 May 13
  8. 8. inspirationhardware designsensor and control networksfield-programmable gate arraysThursday, 30 May 13
  9. 9. virtual machineemulate an existing systemsimulate an imagined systemhave dynamic control of system stateThursday, 30 May 13
  10. 10. stack-based lambda calculus processorthreaded value cells in a von neumann memoryall operations are expressions are valueslispThursday, 30 May 13
  11. 11. stack-based processorthreaded word definitions in a von neumann memorywords thread primitives, word pointers and dataforthThursday, 30 May 13
  12. 12. stack-based processor with instruction setharvard memory separates code and dataclass loaders convert bytecode to machine statejvmThursday, 30 May 13
  13. 13. linux kernel hypervisorintel X86 virtualisation with hardware executionQEMU virtual machine runs in user spacekvmThursday, 30 May 13
  14. 14. hello worldThursday, 30 May 13
  15. 15. package mainimport "fmt"const(HELLO string = "hello"WORLD string = "world")func main() {fmt.Println(HELLO, WORLD)}Thursday, 30 May 13
  16. 16. user-defined typeThursday, 30 May 13
  17. 17. package Integertype Int intfunc (i *Int) Add(x int) {*i += Int(x)}Thursday, 30 May 13
  18. 18. package Integertype Buffer []Intfunc (b Buffer) Eq(o Buffer) (r bool) {if len(b) == len(o) {for i := len(b) - 1; i > 0; i-- {if b[i] != o[i] {return}}r = true}return}func (b Buffer) Swap(i, j int) {b[i], b[j] = b[j], b[i]}func (b Buffer) Clone() Buffer {s := make(Buffer, len(b))copy(s, b)return s}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)}Thursday, 30 May 13
  19. 19. 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[:2] = {", b[0], ",", b[1], "}")}produces:b[0:2] = { 6, 4 }Thursday, 30 May 13
  20. 20. package Integerimport "testing"func TestSwap(t *testing.T) {i := Buffer{0, 1, 2, 3, 4, 5}b := i.Clone()b.Swap(1, 2)if !b[1:3].Eq(Buffer{2, 1}) {t.Fatalf("b[:5] = %v", b)}}func TestMove(t *testing.T) {i := Buffer{0, 1, 2, 3, 4, 5}b := i.Clone()b.Move(3, 2)if !b.Eq(Buffer{3, 4, 0, 1, 2, 5}) {t.Fatalf("b[:5] = %v", b)}}func TestAdd(t *testing.T) {i := Buffer{0, 1, 2, 3, 4, 5}b := i.Clone()b[0].Add(3)if b[0] != i[0] + 3 {t.Fatalf("b[:5] = %v", b)}}Thursday, 30 May 13
  21. 21. embeddingThursday, 30 May 13
  22. 22. 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]}Thursday, 30 May 13
  23. 23. package Integerimport "testing"func TestVectorSwap(t *testing.T) {i := Vector{Buffer{0, 1, 2, 3, 4, 5}}v := i.Clone()v.Swap(1, 2)r := Vector{Buffer{0, 2, 1, 3, 4, 5}}switch {case !v.Match(&r):fallthroughcase !v.Buffer.Match(r.Buffer):t.Fatalf("b[:5] = %v", v)}}Thursday, 30 May 13
  24. 24. package integerimport "testing"func BenchmarkVectorClone6(b *testing.B) {v := Vector{Buffer{0, 1, 2, 3, 4, 5}}for i := 0; i < b.N; i++ {_ = v.Clone()}}func BenchmarkVectorSwap(b *testing.B) {b.StopTimer()v := Vector{Buffer{0, 1, 2, 3, 4, 5}}b.StartTimer()for i := 0; i < b.N; i++ {v.Swap(1, 2)}}Thursday, 30 May 13
  25. 25. $ go test -test.bench="Benchmark"PASSinteger.BenchmarkVectorSwap 200000000 8 ns/opinteger.BenchmarkVectorClone6 10000000 300 ns/opThursday, 30 May 13
  26. 26. inferenceThursday, 30 May 13
  27. 27. package addertype Adder interface {Add(j int)Subtract(j int)Result() interface{}}type Calculator interface {AdderReset()}type AddingMachine struct {Memory interface{}Adder}Thursday, 30 May 13
  28. 28. package addertype IAdder []intfunc (i IAdder) Add(j int) {i[0] += i[j]}func (i IAdder) Subtract(j int) {i[0] -= i[j]}func (i IAdder) Result() interface{} {return i[0]}func (i IAdder) Reset() {i[0] = *new(int)}Thursday, 30 May 13
  29. 29. package adderimport "testing"func TestIAdder(t *testing.T) {error := "Result %v != %v"i := IAdder{0, 1, 2}i.Add(1)if i.Result().(int) != 1 { t.Fatalf(error, i.Result(), 1) }i.Subtract(2)if i.Result().(int) != -1 { t.Fatalf(error, i.Result()), -1 }var r Calculator = IAdder{-1, 1, 2}for n, v := range r.(IAdder) {if i[n] != v { t.Fatalf("Adder %v should be %v", i, r) }}r.Reset()if r.Result().(int) != *new(int) {t.Fatalf(error, r.Result(), *new(int))}}Thursday, 30 May 13
  30. 30. package adderimport "testing"func TestIAdder(t *testing.T) {error := "Result %v != %v"i := IAdder{0, 1, 2}i.Add(1)if i.Result() != 1 { t.Fatalf(error, i.Result(), 1) }i.Subtract(2)if i.Result() != -1 { t.Fatalf(error, i.Result()), -1 }var r Calculator = IAdder{-1, 1, 2}for n, v := range r.(IAdder) {if i[n] != v { t.Fatalf("Adder %v should be %v", i, r) }}r.Reset()if r.Result() != *new(int) {t.Fatalf(error, r.Result(), *new(int))}}Thursday, 30 May 13
  31. 31. package addertype FAdder []float32func (f FAdder) Add(j int) {f[0] += f[j]}func (f FAdder) Subtract(j int) {f[0] -= f[j]}func (f FAdder) Result() interface{} {return f[0]}func (f FAdder) Reset() {f[0] = *new(float32)}Thursday, 30 May 13
  32. 32. package adderimport "testing"func TestFAdder(t *testing.T) {error := "Result %v != %v"f := FAdder{0.0, 1.0, 2.0}f.Add(1)if f.Result() != 1.0 { t.Fatalf(error, f.Result(), 1.0) }f.Subtract(2)if i.Result() != -1.0 { t.Fatalf(error, i.Result()), -1.0 }var r Calculator = FAdder{-1.0, 1.0, 2.0}for n, v := range r.(FAdder) {if f[n] != v { t.Fatalf("Adder %v should be %v", f, r) }}r.Reset()if r.Result() != *new(float32) {t.Fatalf(error, r.Result(), *new(float32))}}Thursday, 30 May 13
  33. 33. package adderimport "testing"func TestAddingMachine(t *testing.T) {error := "Result %v != %v"a := &AddingMachine{ Adder: FAdder{0.0, 1.0, 2.0} }a.Add(1)if f, ok := a.Result().(float32); !ok {t.Fatal("Result should be a float32")} else if f != 1.0 {t.Fatalf(error, a.Result(), 1.0)}a.Subtract(2)if a.Result().(float32) != -1.0 { t.Fatalf(error, a.Result(), -1.0) }r := FAdder{-1.0, 1.0, 2.0}for n, v := range a.Adder.(FAdder) {if r[n] != v { t.Fatalf("Adder %v should be %v", a, r) }}}Thursday, 30 May 13
  34. 34. concurrencyThursday, 30 May 13
  35. 35. goroutinesconcurrent execution stacksinitialised with a closurescheduled automatically by the runtimeThursday, 30 May 13
  36. 36. package mainimport "fmt"func main() {var c chan intc = make(chan int)go func() {for {fmt.Print(<-c)}}()for {select {case c <- 0:case c <- 1:}}} produces:01100111010110...Thursday, 30 May 13
  37. 37. package mainimport "fmt"func main() {var c chan intc = make(chan int, 16)go func() {for {fmt.Print(<-c)}}()go func() {select {case c <- 0:case c <- 1:}}()for {}}produces:01100111010110...Thursday, 30 May 13
  38. 38. package map_reducetype SignalSource func(status chan bool)func Wait(s SignalSource) {done := make(chan bool)defer close(done)go s(done)<-done}func WaitCount(count int, s SignalSource) {done := make(chan bool)defer close(done)go s(done)for i := 0; i < count; i++ {<- done}}Thursday, 30 May 13
  39. 39. package map_reducetype Iteration func(k, x interface{})func (i Iteration) apply(k, v interface{}, c chan bool) {go func() {i(k, v)c <- true}()}Thursday, 30 May 13
  40. 40. package map_reducefunc Each(c interface{}, f Iteration) {switch c := c.(type) {case []int: WaitCount(len(c), func(done chan bool) {for i, v := range c {f.apply(i, v, done)}})case map[int] int: WaitCount(len(c), func(done chan bool) {for k, v := range c {f.apply(k, v, done)}})}}Thursday, 30 May 13
  41. 41. package map_reducetype Results chan interface{}type Combination func(x, y interface{}) interface{}func (f Combination) Reduce(c, s interface{}) (r Results) {r = make(Results)go func() {Each(c, func(k, x interface{}) {s = f(s, x)})r <- s}()return}Thursday, 30 May 13
  42. 42. package map_reducetype Transformation func(x interface{}) interface{}func (t Transformation) GetValue(x interface{}) interface{} {return t(x)}Thursday, 30 May 13
  43. 43. func Map(c interface{}, t Transformation) (n interface{}) {var i Iterationswitch c := c.(type) {case []int: m := make([]int, len(c))i = func(k, x interface{}) { m[k] = t.GetValue(x) }n = mcase map[int] int: m := make(map[int] int)i = func(k, x interface{}) { m[k] = t.GetValue(x) }n = m}if i != nil {Wait(func(done chan bool) {Each(c, i)done <- true})}return}Thursday, 30 May 13
  44. 44. package mainimport "fmt"import . "map_reduce"func main() {m := "%v = %v, sum = %vn"s := []int{0, 1, 2, 3, 4, 5}sum := func(x, y interface{}) interface{} { return x.(int) + y.(int) }d := Map(s, func(x interface{}) interface{} { return x.(int) * 2 })x := <- Combination(sum).Reduce(s, 0)fmt.Printf("s", s, x)x = <- Combination(sum).Reduce(d, 0)fmt.Printf("d", d, x)}produces:s = [0 1 2 3 4 5], sum = 15c = [0 2 4 6 8 10], sum = 30Thursday, 30 May 13
  45. 45. software machinesThursday, 30 May 13
  46. 46. synchronisationThursday, 30 May 13
  47. 47. package clockimport "syscall"type Clock struct {Period int64Count chan int64Control chan boolactive bool}Thursday, 30 May 13
  48. 48. package clockimport "syscall"func (c *Clock) Start() {if !c.active {go func() {c.active = truefor i := int64(0); ; i++ {select {case c.active = <- c.Control:default:if c.active {c.Count <- i}syscall.Sleep(c.Period)}}}()}}Thursday, 30 May 13
  49. 49. 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")}Thursday, 30 May 13
  50. 50. OSX 10.6.2 Intel Atom 270 @ 1.6GHz:pulse value 0 from clockpulse value 1 from clockpulse value 2 from clockdisabling clockrestarting clockpulse value 106 from clockOSX 10.6.7 Intel Core 2 Duo @ 2.4GHz:pulse value 0 from clockpulse value 1 from clockpulse value 2 from clockdisabling clockrestarting clockpulse value 154 from clockThursday, 30 May 13
  51. 51. instruction setThursday, 30 May 13
  52. 52. operationsCISCRISCVLIWThursday, 30 May 13
  53. 53. package instructionsimport "fmt"type Operation func(o []int)type Executable interface {Opcode() intOperands() []intExecute(op Operation)}const INVALID_OPCODE = -1type Program []Executablefunc (p Program) Disassemble(a Assembler) {for _, v := range p {fmt.Println(a.Disassemble(v))}}Thursday, 30 May 13
  54. 54. package instructionstype 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())}Thursday, 30 May 13
  55. 55. package instructionstype Assembler struct {opcodes map[string] intnames map[int] string}func NewAssember(names... string) (a Assembler) {a = Assembler{opcodes: make(map[string] int),names:make(map[int] string),}a.Define(names...)return}func (a Assembler) Define(names... string) {for _, name := range names {a.opcodes[name] = len(a.names)a.names[len(a.names)] = name}}Thursday, 30 May 13
  56. 56. package instructionsfunc (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}Thursday, 30 May 13
  57. 57. package instructionsimport "fmt"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("%vt%v", s, params[0])for _, v := range params[1:] {s = fmt.Sprintf("%v, %v", s, v)}}} else {s = "unknown"}return}Thursday, 30 May 13
  58. 58. 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])}}}Thursday, 30 May 13
  59. 59. produces:noopload 1store 1, 2unknownop = 2 result = 3Thursday, 30 May 13
  60. 60. processor coreThursday, 30 May 13
  61. 61. package processorimport . "instructions"const PROCESSOR_READY = 0const PROCESSOR_BUSY = 1const CALL_STACK_UNDERFLOW = 2const CALL_STACK_OVERFLOW = 4const ILLEGAL_OPERATION = 8const INVALID_ADDRESS = 16type Processor interface {Run(p []Executable)}type Core struct {Running boolPC, Flags, Ticks intCS, M []intOP Executable "Loaded OpCode"I chan Executable "Interrupts"}Thursday, 30 May 13
  62. 62. package processorimport . "instructions"func NewCore(CSS, MSS int, I chan Executable) *Core {return &Core{CS:make([]int, CSS)},M: make([]int, MSS),I: I,}}func (c *Core) Reset() {c.Running = falsec.Flags = PROCESSOR_READY}func (c *Core) Goto(addr int) {c.PC = addr}Thursday, 30 May 13
  63. 63. package processorfunc (c *Core) Call(addr int) {top := len(c.CS)if top >= cap(c.CS) - 1 { panic(CALL_STACK_OVERFLOW) }c.CS = c.CS[:top + 1]c.CS[top] = c.PCc.PC = addr}func (c *Core) TailCall(addr int) {c.CS[len(c.CS) - 1] = c.PCc.PC = addr}func (c *Core) Return() {top := len(c.CS)if top == 0 { panic(CALL_STACK_UNDERFLOW) }c.PC, c.CS = c.CS[top - 1], c.CS[:top]}Thursday, 30 May 13
  64. 64. package processorimport . "instructions"func (c *Core) Run(p []Executable, dispatchers... func(c *Core)) {defer func() {c.Running = falseif x := recover(); x != nil { c.Flags &= x.(int) }}()switch {case c.Running: panic(PROCESSOR_BUSY)case len(dispatchers) == 0: panic(PROCESSOR_READY)default:c.Running = truec.BusyLoop(dispatchers...)}}func (c *Core) LoadInstruction(program []Executable) {if c.PC >= len(program) { panic(PROCESSOR_READY) }c.Executable = program[c.PC]c.PC++}Thursday, 30 May 13
  65. 65. package processorimport . "instructions"func (c *Core) BusyLoop(p []Executable, dispatchers... func(c *Core)) {select {case interrupt <- c.I:op, pc := c.OP, c.PCfor c.PC = 0; c.Running; c.Ticks++ {for _, f := range dispatchers { f(c) }c.LoadInstruction(p)}c.OP, c.PC = op, pcdefault:for c.PC = 0; c.Running; c.Ticks++ {c.LoadInstruction(p)for _, f := range dispatchers { f(c) }}}}Thursday, 30 May 13
  66. 66. package processorimport . "instructions"func (c *Core) RunExclusive(p []Executable, tracers... func(c *Core)) {defer func() {c.Running = falseif x := recover(); x != nil { c.Flags &= x.(int) }}()if c.Running { panic(PROCESSOR_BUSY) }case len(dispatchers) == 0: panic(PROCESSOR_READY)c.Running = truefor c.PC = 0; c.Running; c.Ticks++ {c.LoadInstruction(p)for _, f := range tracers { f(c) }}}Thursday, 30 May 13
  67. 67. package mainimport . "processor"import . "instructions"const( CALL = iotaGOTOMOVERETURN)c := NewCore(10, 8, nil)var dispatcher = func(c *Core) {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)}}Thursday, 30 May 13
  68. 68. func main() {p := []Executable{ Instruction{ CALL, 2 },Instruction{ GOTO, 5 },Instruction{ MOVE, 2 },Instruction{ RETURN },Instruction{ MOVE, -1 } }c.RunExclusive(p, dispatcher)fmt.Printf("Instructions Executed: %vnPC = %vn", c.Ticks, c.PC)if c.Flags | PROCESSOR_READY == PROCESSOR_READY {fmt.Println("Core Ready")} else {fmt.Println("Core Error:", c.Flags)}}produces:Instructions Executed: 2PC = 5Core ReadyThursday, 30 May 13
  69. 69. accumulator machine1-operand instructionsdata from memory combined with accumulatorresult stored in accumulatorThursday, 30 May 13
  70. 70. package accmachineimport . "processor"const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD)type AccMachine struct {CoreAC int}func NewAccMachine(CSSize, MSize int, I chan Executable) *AccMachine {return &AccMachine{ Core: NewCore(CSSize, MSize, I) }}Thursday, 30 May 13
  71. 71. package accmachineimport . "processor"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)}})}Thursday, 30 May 13
  72. 72. package mainimport . "accmachine"import . "instructions"func main() {a := NewAccMachine(10, 8, nil)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 = 50Thursday, 30 May 13
  73. 73. stack machine0-operand instructionsdata popped from stackresults pushed on stackThursday, 30 May 13
  74. 74. package smachineimport . "processor"const (CONSTANT = iotaPUSH_VALUEPOP_VALUEADD)type StackMachine struct {CoreDS []int}func NewStackM(CSSize, DSSize, MSize int, I chan Executable) *StackMachine {return &StackMachine{DS: make([]int, 0, DSSize),Core: NewCore(CSSize, MSize, I) }}Thursday, 30 May 13
  75. 75. package smachineimport . "processor"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]}Thursday, 30 May 13
  76. 76. 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)}})}Thursday, 30 May 13
  77. 77. package mainimport . "smachine"import . "instructions"func main() {s := NewStackM(10, 10, 8, nil)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]Thursday, 30 May 13
  78. 78. register machinemulti-operand instructionsdata read from memory into registersoperator combines registers and storesThursday, 30 May 13
  79. 79. package rmachineimport . "processor"const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD)type RMachine struct {CoreR []int}func NewRMachine(CSSize, RSize, MSize int, I chan Executable) *RMachine {return &RMachine{ Core: NewCore(CSSize, MSize, I),R: make([]int, RSize) }}Thursday, 30 May 13
  80. 80. package rmachineimport . "processor"func (r *RMachine) 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)}})}Thursday, 30 May 13
  81. 81. package mainimport . "rmachine"import . "instructions"func main() {r := NewRMachine(10, 10, 8, nil)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]Thursday, 30 May 13
  82. 82. vector machinemulti-operand instructionsdata vectors read from memory into registersoperations combine registersThursday, 30 May 13
  83. 83. package vmachineimport . "processor"const (CONSTANT = iotaLOAD_VALUESTORE_VALUEADD)type VMachine struct {CoreR [][]int}func NewVMachine(CSSize, RSize, MSize int, I chan Executable) *VMachine {return &VectorMachine{ Core: NewCore(CSSize, MSize),make([][]int, RSize) }}Thursday, 30 May 13
  84. 84. package vmachineimport . "processor"func (v *VMachine) Load(r int, m []int) {v.R[r] = make([]int, len(m))copy(v.R[r], m)}Thursday, 30 May 13
  85. 85. package vmachineimport . "processor"func (v *VMachine) Run(program []Executable) {v.RunExclusive(program, func() {switch v.Opcode() {case CONSTANT: v.Execute(func(o []int) { v.Load(o[0], o[1:]) })case STORE_VALUE: v.Execute(func(o []int) { copy(v.M[o[0]:], v.R[o[1]]) })case LOAD_VALUE: v.Execute(func(o []int) {v.Load(o[0], v.M[o[1]:o[1] + o[2]])})case ADD: v.Execute(func(o []int) {a, b := v.R[o[0]], v.R[o[1]]count := len(a)if len(b) < len(a) { count := len(b) }for ; count > 0; count-- { a[i] += b[i] }})default: panic(ILLEGAL_OPERATION)}})}Thursday, 30 May 13
  86. 86. package mainimport . "vmachine"import . "instructions"func main() {r := NewVMachine(10, 10, 8, nil)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] [] [] [] [] [] [] []]Thursday, 30 May 13
  87. 87. related projectsgospeedraw - slices - lists - chains - sexpwendigoThursday, 30 May 13
  88. 88. related projectsgospeedtypelibwendigoThursday, 30 May 13
  89. 89. finding out morehttp://golang.org/twitter://#golanghttp://slides.games-with-brains.net/http://github.com/feyeleanor/wikipedia or googleThursday, 30 May 13

×