tdo

Dicing the onion
git clone git@abtrout.com:tdo.git
Log | Files | Refs | README

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 }