func TestAdd(t *testing.T) { doTest(t, `set a, 0xffff add a, 1`, cpu.Encode(cpu.SET, 0, 0x20), cpu.Encode(cpu.ADD, 0, 0x22), ) }
func TestSub(t *testing.T) { doTest(t, `set a, 0 sub a, 1`, cpu.Encode(cpu.SET, 0x0, 0x21), cpu.Encode(cpu.SUB, 0x0, 0x22), ) }
func TestAsr(t *testing.T) { doTest(t, `SET A, 10 ASR A, 1`, cpu.Encode(cpu.SET, 0, 0x2b), cpu.Encode(cpu.ASR, 0, 0x22), ) }
// buildInstruction compiles the given instruction. func (a *assembler) buildInstruction(nodes []parser.Node) (err error) { name := nodes[0].(*parser.Name) if name.Data == "dat" { return a.buildData(nodes) } op, ok := opcodes[name.Data] if !ok { return NewBuildError( a.ast.Files[name.File()], name.Line(), name.Col(), "Unknown instruction: %s", name.Data, ) } if len(nodes)-1 != op.argc { return NewBuildError( a.ast.Files[name.File()], name.Line(), name.Col(), "Invalid argument count for %q. Want %d", name.Data, op.argc, ) } var va, vb cpu.Word var argv []cpu.Word var symbols []parser.Node symbols = append(symbols, name) switch op.argc { case 2: va, err = a.buildOperand(&argv, &symbols, nodes[1].(*parser.Expression).Children()[0], true) if err != nil { return } vb, err = a.buildOperand(&argv, &symbols, nodes[2].(*parser.Expression).Children()[0], false) case 1: va, err = a.buildOperand(&argv, &symbols, nodes[1].(*parser.Expression).Children()[0], false) } if err != nil { return } if op.ext { a.code = append(a.code, cpu.Encode(cpu.EXT, op.code, va)) } else { a.code = append(a.code, cpu.Encode(op.code, va, vb)) } a.debug.Emit(symbols...) a.code = append(a.code, argv...) return }
func TestEQU(t *testing.T) { doTest(t, `equ SomeValue, 16 equ AnotherValue, 'A' set a, SomeValue add a, AnotherValue `, cpu.Encode(cpu.SET, 0, 0x31), // set a, 16 cpu.Encode(cpu.ADD, 0, 0x1f), // add a, 'A' cpu.Word('A'), ) }
func TestSet(t *testing.T) { doTest(t, `set a, 0x30`, cpu.Encode(cpu.SET, 0, 0x1f), 0x30, ) }
func TestJsr(t *testing.T) { doTest(t, ` set a, 0xffff jsr my_sub exit :my_sub add a, 1 set pc, pop `, cpu.Encode(cpu.SET, 0, 0x20), cpu.Encode(cpu.EXT, cpu.JSR, 0x1f), 0x4, cpu.Encode(cpu.EXT, cpu.EXIT, 0), cpu.Encode(cpu.ADD, 0, 0x22), cpu.Encode(cpu.SET, 0x1c, 0x18), ) }
func TestHwi(t *testing.T) { doTest(t, ` set a,1 set b, 0x100 hwi 0 set a, [0x100] exit `, cpu.Encode(cpu.SET, 0, 0x22), cpu.Encode(cpu.SET, 1, 0x1f), 0x100, cpu.Encode(cpu.EXT, cpu.HWI, 0x21), cpu.Encode(cpu.SET, 0, 0x1e), 0x100, cpu.Encode(cpu.EXT, cpu.EXIT, 0), ) }
func TestDat(t *testing.T) { doTest(t, `:end set pc, end :dat dat 0x170, "Hello, universe", 0 `, cpu.Encode(cpu.SET, 0x1c, 0x21), 0x170, 'H', 'e', 'l', 'l', 'o', ',', ' ', 'u', 'n', 'i', 'v', 'e', 'r', 's', 'e', 0, ) }
func TestNestedIf(t *testing.T) { doTest(t, `SET A, 0 IFG A, 1 IFG A, 2 IFE A, 0 SET A, 4 SET [100], A `, cpu.Encode(cpu.SET, 0, 0x21), cpu.Encode(cpu.IFG, 0, 0x22), cpu.Encode(cpu.IFG, 0, 0x23), cpu.Encode(cpu.IFE, 0, 0x21), cpu.Encode(cpu.SET, 0, 0x25), cpu.Encode(cpu.SET, 0x1e, 0), 100, ) }
func TestIntRfi(t *testing.T) { doTest(t, ` ias my_handler int 0xbeef set a, b exit :my_handler set b, a add b, 1 rfi a `, cpu.Encode(cpu.EXT, cpu.IAS, 0x1f), 0x6, cpu.Encode(cpu.EXT, cpu.INT, 0x1f), 0xbeef, cpu.Encode(cpu.SET, 0, 1), cpu.Encode(cpu.EXT, cpu.EXIT, 0), cpu.Encode(cpu.SET, 1, 0), cpu.Encode(cpu.ADD, 1, 0x22), cpu.Encode(cpu.EXT, cpu.RFI, 0), ) }
func TestFunc(t *testing.T) { doTest(t, `def main equ LoopLimit, 16 set i, 0 ife i, LoopLimit return add i, 1 end `, cpu.Encode(cpu.SET, 0x18, 6), // set push, i cpu.Encode(cpu.SET, 6, 0x21), // set i, 0 cpu.Encode(cpu.IFE, 6, 0x31), // ife i, 16 cpu.Encode(cpu.SET, 0x1c, 0x1f), // set pc, $__main_epilog 0x6, cpu.Encode(cpu.ADD, 6, 0x22), // add i, 1 cpu.Encode(cpu.SET, 6, 0x18), // $__main_epilog: set i, pop cpu.Encode(cpu.SET, 0x1c, 0x18), // set pc, pop ) }
func TestSetIndexExpr(t *testing.T) { test(t, "test/asm/set_index_expr", []cpu.Word{ cpu.Encode(cpu.SET, 0x00, 0x11), 0xff, }) }
func TestSetIndex(t *testing.T) { test(t, "test/asm/set_index", []cpu.Word{ cpu.Encode(cpu.SET, 0x08, 0x09), }) }
func TestSet(t *testing.T) { test(t, "test/asm/set", []cpu.Word{ cpu.Encode(cpu.SET, 0x00, 0x01), }) }
func TestSetIndexNextWord(t *testing.T) { test(t, "test/asm/set_index_next_word", []cpu.Word{ cpu.Encode(cpu.SET, 0x00, 0x1e), 0xfffe, }) }
func TestSetPushPop(t *testing.T) { test(t, "test/asm/set_pushpop", []cpu.Word{ cpu.Encode(cpu.SET, 0x18, 0x03), cpu.Encode(cpu.SET, 0x03, 0x18), }) }
// Ensure Read/Write roundtrip is the identity function. func TestIdentity(t *testing.T) { var w bytes.Buffer code := []cpu.Word{ cpu.Encode(cpu.SET, 0, 0x1f), 0xffff, cpu.Encode(cpu.ADD, 0, 0x22), cpu.Encode(cpu.MUL, 0, 0x22), cpu.Encode(cpu.SET, 1, 0), } var dbg asm.DebugInfo dbg.Files = []asm.FileInfo{{"a.dasm", 0}} dbg.Functions = []asm.FuncInfo{{"main", 0, 5, 0, 4}} dbg.SourceMapping = make([]asm.SourceInfo, 5) a := New(code, &dbg) a.Update(0, nil) a.Update(2, nil) a.Update(3, nil) a.Update(4, nil) a.UpdateCost(2, 5) err := Write(a, &w) if err != nil { t.Fatalf("Write: %v", err) } b, err := Read(&w) if err != nil { t.Fatalf("Read: %v", err) } if len(a.Files) != len(b.Files) { t.Fatalf("len(a.Files) != len(b.Files)") } for i := range a.Files { if a.Files[i].Name != b.Files[i].Name { t.Fatalf("a.Files[i].Name != b.Files[i].Name") } if a.Files[i].StartAddr != b.Files[i].StartAddr { t.Fatalf("a.Files[i].Start != b.Files[i].Start") } } if len(a.Functions) != len(b.Functions) { t.Fatalf("len(a.Functions) != len(b.Functions)") } for i := range a.Functions { if a.Functions[i].StartAddr != b.Functions[i].StartAddr { t.Fatalf("a.Functions[i].StartAddr != b.Functions[i].StartAddr") } if a.Functions[i].EndAddr != b.Functions[i].EndAddr { t.Fatalf("a.Functions[i].EndAddr != b.Functions[i].EndAddr") } if a.Functions[i].StartLine != b.Functions[i].StartLine { t.Fatalf("a.Functions[i].StartLine != b.Functions[i].StartLine") } if a.Functions[i].EndLine != b.Functions[i].EndLine { t.Fatalf("a.Functions[i].EndLine != b.Functions[i].EndLine") } if a.Functions[i].Name != b.Functions[i].Name { t.Fatalf("a.Functions[i].Name != b.Functions[i].Name") } } if len(a.Data) != len(b.Data) { t.Fatalf("len(a.Data) != len(b.Data)") } for pc, va := range a.Data { vb := b.Data[pc] if va.Count != vb.Count { t.Fatalf("va.Count != vb.Count") } if va.File != vb.File { t.Fatalf("va.File != vb.File") } if va.Line != vb.Line { t.Fatalf("va.Line != vb.Line") } if va.Col != vb.Col { t.Fatalf("va.Col != vb.Col") } if va.Data != vb.Data { t.Fatalf("va.Data != vb.Data") } if va.Penalty != vb.Penalty { t.Fatalf("va.Penalty != vb.Penalty") } if va.Cost() != vb.Cost() { t.Fatalf("va.Cost() != vb.Cost()") } } }