init
This commit is contained in:
+114
@@ -0,0 +1,114 @@
|
||||
package vm
|
||||
|
||||
import "testing"
|
||||
|
||||
type testBus struct {
|
||||
in map[uint16]int32
|
||||
out map[uint16]int32
|
||||
}
|
||||
|
||||
func (b *testBus) In(p uint16) int32 { return b.in[p] }
|
||||
func (b *testBus) Out(p uint16, v int32) { b.out[p] = v }
|
||||
|
||||
func run(t *testing.T, src string, budget int) (*CPU, *testBus) {
|
||||
t.Helper()
|
||||
prog, err := Assemble(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, err := New(prog, 256)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := &testBus{in: map[uint16]int32{5: 42}, out: map[uint16]int32{}}
|
||||
c.Run(b, budget)
|
||||
return c, b
|
||||
}
|
||||
|
||||
func TestSumLoop(t *testing.T) {
|
||||
c, b := run(t, `
|
||||
ldi r0, 0 ; sum
|
||||
ldi r1, 1 ; i
|
||||
ldi r2, 11
|
||||
loop:
|
||||
add r0, r1
|
||||
addi r1, 1
|
||||
blt r1, r2, loop
|
||||
out 7, r0
|
||||
halt
|
||||
`, 1000)
|
||||
if c.Status != Halted || b.out[7] != 55 {
|
||||
t.Fatalf("status=%v out=%d", c.Status, b.out[7])
|
||||
}
|
||||
}
|
||||
|
||||
func TestLiCallStackMemory(t *testing.T) {
|
||||
c, b := run(t, `
|
||||
li r0, 0x12345678
|
||||
call double
|
||||
stw r0, [sp-8] ; below current sp
|
||||
ldw r3, [sp-8]
|
||||
in r4, 5
|
||||
add r3, r4
|
||||
out 1, r3
|
||||
halt
|
||||
double:
|
||||
add r0, r0
|
||||
ret
|
||||
`, 1000)
|
||||
want := int32(0x12345678)*2 + 42
|
||||
if c.Status != Halted || b.out[1] != want {
|
||||
t.Fatalf("status=%v fault=%q out=%x want %x", c.Status, c.Fault, b.out[1], want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestYieldAndBudget(t *testing.T) {
|
||||
prog, _ := Assemble("l: addi r0, 1\n jmp l")
|
||||
c, _ := New(prog, 64)
|
||||
b := &testBus{}
|
||||
if used := c.Run(b, 100); used != 100 || c.Status != Running {
|
||||
t.Fatalf("used=%d status=%v", used, c.Status)
|
||||
}
|
||||
r0 := c.R[0]
|
||||
c.Run(b, 100)
|
||||
if c.R[0] != r0+50 {
|
||||
t.Fatalf("did not resume: %d -> %d", r0, c.R[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFaults(t *testing.T) {
|
||||
c, _ := run(t, "ldi r0, 1\n ldi r1, 0\n div r0, r1", 100)
|
||||
if c.Status != Faulted {
|
||||
t.Fatal("expected div fault")
|
||||
}
|
||||
c, _ = run(t, "ldi r1, 300\n ldw r0, [r1]", 100)
|
||||
if c.Status != Faulted {
|
||||
t.Fatal("expected memory fault")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateRoundTrip(t *testing.T) {
|
||||
c, _ := run(t, "ldi r0, 9\n stb r0, [r1+3]\n yield\n ldi r0, 1", 100)
|
||||
d, _ := New(c.Prog, 256)
|
||||
if err := d.UnmarshalState(c.MarshalState()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.R != c.R || d.PC != c.PC || d.RAM[3] != 9 || d.Status != Yielded {
|
||||
t.Fatal("state mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssemblerCaseInsensitiveDirectives(t *testing.T) {
|
||||
// LI expands to two instructions; label distances must agree in any case.
|
||||
lower, err := Assemble(".equ K 5\n li r1, 0x12345\n jmp end\n nop\nend: halt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
upper, err := Assemble(".EQU K 5\n LI r1, 0x12345\n JMP end\n NOP\nend: HALT")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(lower) != string(upper) {
|
||||
t.Fatal("upper- and lower-case source assembled differently")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user