instruction.go (2638B)
1 package asm 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "regexp" 8 "strconv" 9 "strings" 10 ) 11 12 type Instruction struct { 13 Opcode Opcode 14 RegA, RegB, RegC Register 15 Value uint32 16 } 17 18 func NewInstruction(in string) *Instruction { 19 parsingRe := regexp.MustCompile(`[a-zA-Z0-9']+`) 20 input := parsingRe.FindAllString(in, -1) 21 cnt := len(input) 22 if cnt == 0 { 23 log.Fatal("invalid input - array cannot be empty") 24 } 25 opcode := NewOpcode(strings.ToUpper(input[0])) 26 instr := Instruction{Opcode: opcode} 27 errmsg := fmt.Sprintf("invalid number of operands for opcode %s", input[0]) 28 29 switch opcode { 30 case CMOV, ARRI, ARRA, ADD, MUL, DIV, NOTA: 31 if cnt != 4 { 32 log.Fatal(errmsg) 33 } 34 instr.RegA = NewRegister(input[1]) 35 instr.RegB = NewRegister(input[2]) 36 instr.RegC = NewRegister(input[3]) 37 case HALT: // no operands 38 case ALLO, LOAD: 39 if cnt != 3 { 40 log.Fatal(errmsg) 41 } 42 instr.RegB = NewRegister(input[1]) 43 instr.RegC = NewRegister(input[2]) 44 case ABAN, OUTP, INP: 45 if cnt != 2 { 46 log.Fatal(errmsg) 47 } 48 instr.RegC = NewRegister(input[1]) 49 case ORTH: 50 if cnt != 3 { 51 log.Fatal(errmsg) 52 } 53 instr.RegA = NewRegister(input[1]) 54 instr.Value = parseValue(input[2]) 55 } 56 57 return &instr 58 } 59 60 func parseValue(s string) uint32 { 61 var val uint32 62 if strings.ContainsRune(s, '\'') { 63 s = strings.Trim(s, "'") 64 if len(s) != 1 { 65 log.Fatalf("invalid character value '%s'", s) 66 } 67 val = uint32(s[0]) 68 } else { 69 if v, err := strconv.ParseUint(s, 10, 32); err != nil { 70 log.Fatal(err) 71 } else { 72 val = uint32(v) 73 } 74 } 75 return val 76 } 77 78 //@todo make some kind of polymorphism for different opcodes 79 func (i *Instruction) Pack() uint32 { 80 const valueMask uint32 = 0x1FFFFFF 81 var ret uint32 = uint32(i.Opcode) << 28 82 if i.Opcode == ORTH { 83 var v uint32 = i.Value & valueMask 84 var r1 uint32 = uint32(i.RegA) << 25 85 ret = ret | r1 | v 86 } else { 87 var r1 uint32 = uint32(i.RegA) << 6 88 var r2 uint32 = uint32(i.RegB) << 3 89 var r3 uint32 = uint32(i.RegC) 90 ret = ret | r1 | r2 | r3 91 } 92 return ret 93 } 94 95 func (i *Instruction) String() string { 96 var buf bytes.Buffer 97 buf.WriteString(i.Opcode.String()) 98 buf.WriteString(" ") 99 100 switch i.Opcode { 101 case CMOV, ARRI, ARRA, ADD, MUL, DIV, NOTA: 102 dumpRegisters(&buf, i.RegA, i.RegB, i.RegC) 103 case HALT: 104 // no operands 105 case ALLO, LOAD: 106 dumpRegisters(&buf, i.RegB, i.RegC) 107 case ABAN, OUTP, INP: 108 dumpRegisters(&buf, i.RegC) 109 case ORTH: 110 dumpRegisters(&buf, i.RegA) 111 buf.WriteString(strconv.Itoa(int(i.Value))) 112 } 113 114 return buf.String() 115 } 116 117 func dumpRegisters(buf *bytes.Buffer, regs ...Register) { 118 for _, reg := range regs { 119 buf.WriteString(reg.String()) 120 buf.WriteString(" ") 121 } 122 }