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  }