tomtel.go (4647B)
1 package tdo 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "log" 8 "strings" 9 ) 10 11 type Tomtel struct { 12 // 8-bit registers 13 a uint8 // accumulator 14 b uint8 // operand 15 c uint8 // counter/offset 16 d, e uint8 // general purpose 17 f uint8 // flags 18 ptrC uint8 // for MV/MVI 19 // 32-bit registers 20 la, lb, lc, ld uint32 // general purpose 21 ptr uint32 // pointer to memory 22 pc uint32 // program counter 23 // Mutable memory 24 mem []byte 25 // Output buffer 26 outBuf *bytes.Buffer 27 } 28 29 func NewTomtel(code []byte) *Tomtel { 30 return &Tomtel{ 31 mem: code, 32 outBuf: &bytes.Buffer{}, 33 } 34 } 35 36 func (t *Tomtel) String() string { 37 var b strings.Builder 38 b.WriteString("Tomtel{") 39 b.WriteString(fmt.Sprintf("a=%d, ", t.a)) 40 b.WriteString(fmt.Sprintf("b=%d, ", t.b)) 41 b.WriteString(fmt.Sprintf("c=%d, ", t.c)) 42 b.WriteString(fmt.Sprintf("d=%d, ", t.d)) 43 b.WriteString(fmt.Sprintf("e=%d, ", t.e)) 44 b.WriteString(fmt.Sprintf("f=%d, ", t.f)) 45 b.WriteString(fmt.Sprintf("la=%d, ", t.la)) 46 b.WriteString(fmt.Sprintf("lb=%d, ", t.lb)) 47 b.WriteString(fmt.Sprintf("lc=%d, ", t.lc)) 48 b.WriteString(fmt.Sprintf("ld=%d, ", t.ld)) 49 b.WriteString(fmt.Sprintf("ptr=%d, ", t.ptr)) 50 b.WriteString(fmt.Sprintf("pc=%d, ", t.pc)) 51 b.WriteString(fmt.Sprintf("ptrC=%d", t.ptrC)) 52 b.WriteString("}") 53 return b.String() 54 } 55 56 func (t *Tomtel) Run() []byte { 57 for { 58 op := t.mem[t.pc] 59 t.pc += 1 60 61 switch op { 62 case 0xC2: // ADD a <- b 63 t.add() 64 case 0xE1: // APTR imm8 65 imm8 := t.mem[t.pc] 66 t.pc += 1 // advance for uint8 argument 67 t.aptr(imm8) 68 case 0xC1: // CMP 69 t.cmp() 70 case 0x01: // HALT 71 return t.outBuf.Bytes() 72 case 0x21: // JEZ imm32 73 imm32 := binary.LittleEndian.Uint32(t.mem[t.pc:]) 74 t.pc += 4 // advance for uint32 argument 75 t.jez(imm32) 76 case 0x22: // JNZ imm32 77 imm32 := binary.LittleEndian.Uint32(t.mem[t.pc:]) 78 t.pc += 4 // advance for uint32 argument 79 t.jnz(imm32) 80 case 0x02: // OUT a 81 t.out() 82 case 0xC3: // SUB a <- b 83 t.sub() 84 case 0xC4: // XOR a <- b 85 t.xor() 86 default: 87 if ok, dest, src := parseMv(op); ok { 88 t.mv(dest, src) 89 } else if ok, dest := parseMvi(op); ok { 90 imm8 := t.mem[t.pc] 91 t.pc += 1 // advance for uint8 argument 92 t.mvi(dest, imm8) 93 } else if ok, dest, src := parseMv32(op); ok { 94 t.mv32(dest, src) 95 } else if ok, dest := parseMvi32(op); ok { 96 imm32 := binary.LittleEndian.Uint32(t.mem[t.pc:]) 97 t.pc += 4 // advance for uint32 argument 98 t.mvi32(dest, imm32) 99 } else { 100 log.Fatalf("Non instruction byte %X at PC %d", op, t.pc-1) 101 } 102 } 103 } 104 } 105 106 func parseMv(op uint8) (bool, uint8, uint8) { 107 // 0b01DDDSSS 108 if op&uint8(0b11000000) != 0b01000000 { 109 return false, 0, 0 110 } else if op&uint8(0b00000111) == 0 { 111 return false, 0, 0 112 } 113 dest := (op & uint8(0b00111000)) >> 3 114 src := op & uint8(0b00000111) 115 return true, dest, src 116 } 117 118 func parseMvi(op uint8) (bool, uint8) { 119 // 0b01DDD000 120 if op&uint8(0b11000111) == 0b01000000 { 121 dest := op & uint8(0b00111000) >> 3 122 return true, dest 123 } 124 return false, 0 125 } 126 127 func parseMv32(op uint8) (bool, uint8, uint8) { 128 // 0b10DDDSSS 129 if op&uint8(0b11000000) != 0b10000000 { 130 return false, 0, 0 131 } else if op&uint8(0b00000111) == 0 { 132 return false, 0, 0 133 } 134 dest := (op & uint8(0b00111000)) >> 3 135 src := op & uint8(0b00000111) 136 return true, dest, src 137 } 138 139 func parseMvi32(op uint8) (bool, uint8) { 140 // 0b10DDD000 141 if op&uint8(0b11000111) == 0b10000000 { 142 dest := op & uint8(0b00111000) >> 3 143 return true, dest 144 } 145 return false, 0 146 } 147 148 func (t *Tomtel) add() { t.a = t.a + t.b } 149 150 func (t *Tomtel) aptr(imm8 uint8) { t.ptr += uint32(imm8) } 151 152 func (t *Tomtel) cmp() { 153 if t.a == t.b { 154 t.f = 0 155 } else { 156 t.f = 1 157 } 158 } 159 160 func (t *Tomtel) jez(imm32 uint32) { 161 if t.f == 0 { 162 t.pc = imm32 163 } 164 } 165 166 func (t *Tomtel) jnz(imm32 uint32) { 167 if t.f != 0 { 168 t.pc = imm32 169 } 170 } 171 172 func (t *Tomtel) mv(dest, src uint8) { 173 regs := []*uint8{&t.a, &t.b, &t.c, &t.d, &t.e, &t.f} 174 if dest == 7 { 175 t.mem[t.ptr+uint32(t.c)] = *regs[src-1] 176 } else if src == 7 { 177 *regs[dest-1] = t.mem[t.ptr+uint32(t.c)] 178 } else { 179 *regs[dest-1] = *regs[src-1] 180 } 181 } 182 183 func (t *Tomtel) mvi(dest, imm8 uint8) { 184 regs := []*uint8{&t.a, &t.b, &t.c, &t.d, &t.e, &t.f} 185 if dest == 7 { 186 t.mem[t.ptr+uint32(t.c)] = imm8 187 } else { 188 *regs[dest-1] = imm8 189 } 190 } 191 192 func (t *Tomtel) mv32(dest, src uint8) { 193 regs := []*uint32{&t.la, &t.lb, &t.lc, &t.ld, &t.ptr, &t.pc} 194 *regs[dest-1] = *regs[src-1] 195 } 196 197 func (t *Tomtel) mvi32(dest uint8, imm32 uint32) { 198 regs := []*uint32{&t.la, &t.lb, &t.lc, &t.ld, &t.ptr, &t.pc} 199 *regs[dest-1] = imm32 200 } 201 202 func (t *Tomtel) out() { t.outBuf.WriteByte(t.a) } 203 204 func (t *Tomtel) sub() { t.a -= t.b } 205 206 func (t *Tomtel) xor() { t.a ^= t.b }