github.com/jflude/taocp@v0.0.0-20240210234939-99f2a91af3c2/mix/computer.go (about) 1 2 // Package mix simulates the MIX 1009 computer as described in 3 // Donald Knuth's "The Art of Computer Programming" (third edition). 4 package mix 5 6 import ( 7 "io" 8 "log" 9 ) 10 11 const ( 12 // The registers of the MIX 1009 CPU. 13 A = iota 14 I1 15 I2 16 I3 17 I4 18 I5 19 I6 20 X 21 J 22 // Z 23 24 // Less, Equal and Greater are the possible values taken by the 25 // computer's comparison indicator. 26 Less = -1 27 Equal = 0 28 Greater = 1 29 30 // MemorySize is the number of memory cells in a regular MIX computer. 31 MemorySize = 4000 32 mBase = MemorySize - 1 33 ) 34 35 type Computer struct { 36 Overflow bool 37 Comparison int 38 Elapsed, Idle int64 39 Reg [10]Word 40 Contents []Word 41 attributes []attribute 42 Devices []Peripheral 43 busyUntil []int64 44 bind *Binding 45 m, next int 46 ctrl, halted bool 47 Tracer io.WriteCloser 48 Trigger int 49 lastDevMask uint 50 lastIdle int64 51 Interrupts bool 52 lastTick int64 53 pending priority 54 BootFrom int 55 } 56 57 type attribute struct { 58 lockUntil int64 59 } 60 61 func NewComputer() *Computer { 62 return &Computer{ 63 Contents: make([]Word, 2*MemorySize-1), 64 attributes: make([]attribute, 2*MemorySize-1), 65 Devices: make([]Peripheral, DeviceCount), 66 busyUntil: make([]int64, DeviceCount), 67 BootFrom: CardReaderUnit, 68 Trigger: 32, 69 } 70 } 71 72 func (c *Computer) Bind(b *Binding) error { 73 var err error 74 for i := range c.Devices { 75 if err2 := c.unbindDevice(i); err2 != nil { 76 if err == nil { 77 err = err2 78 } else { 79 log.Println("error:", err2) 80 } 81 } 82 } 83 c.bind = b 84 return err 85 } 86 87 func (c *Computer) Shutdown() error { 88 return c.Bind(nil) 89 } 90 91 func (c *Computer) validAddress(address int) bool { 92 if c.ctrl { 93 return address > -MemorySize && address < MemorySize 94 } else { 95 return address >= 0 && address < MemorySize 96 } 97 } 98 99 func (c *Computer) checkAddress(m int) { 100 if !c.validAddress(m) { 101 panic(ErrInvalidAddress) 102 } 103 } 104 105 func (c *Computer) zeroContents() { 106 for i := range c.Contents { 107 c.Contents[i] = 0 108 } 109 } 110 111 func (c *Computer) unlockContents() { 112 for i := range c.attributes { 113 c.attributes[i].lockUntil = 0 114 } 115 } 116 117 func (c *Computer) lockContents(m, n int, until int64) { 118 for i := m; i < n; i++ { 119 c.attributes[i].lockUntil = until 120 } 121 } 122 123 func (c *Computer) checkInterlock(m, n int) { 124 if m == n { 125 if c.attributes[mBase+m].lockUntil > c.Elapsed { 126 panic(ErrContentsInterlock) 127 } 128 } else { 129 for i := mBase + m; i < mBase+n; i++ { 130 if c.attributes[i].lockUntil > c.Elapsed { 131 panic(ErrContentsInterlock) 132 } 133 } 134 } 135 }