package riscvemu import ( "bytes" "errors" "fmt" "os/exec" "strings" "testing" ) // assemble_llvm assembles RISC-V source code with the installed system LLVM // compiler and returns the raw bytes from the resulting .text section. func assemble_llvm(source string) ([]byte, error) { // echo 'nop' | clang --target=riscv32 -march=rv32i -x assembler - -c -o - | llvm-objcopy - /dev/null --dump-section .text=/dev/stdout | xxd cmd := exec.Command(`/bin/bash`, `-c`, `/usr/bin/clang --target=riscv32 -march=rv32i -x assembler - -c -o - | /usr/bin/llvm-objcopy - /dev/null --dump-section .text=/dev/stdout`) cmd.Stdin = strings.NewReader(source) so_buff := bytes.Buffer{} cmd.Stdout = &so_buff err := cmd.Wait() if err != nil { return nil, err } return so_buff.Bytes(), nil } func runUntilEbreak(c *CPUState, expect_insns int) error { for i := 0; i < expect_insns-1; i++ { err := c.Step() if err != nil { return err } } err := c.Step() if err != nil { if eb := (ErrBreak{}); errors.As(err, &eb) { return nil // Successfully got EBREAK precisely when wanted } return err // Some other real error } return fmt.Errorf("Expected EBREAK at instruction count %d, but got %v", expect_insns, err) } func TestBreak(t *testing.T) { env := NewVirtualEEI() // ebreak _, err := env.WriteAt([]byte{0x73, 0x00, 0x10, 0x00}, 0) if err != nil { t.Fatal(err) } c := NewCPU(&env) err = c.Step() if err == nil { t.Fatal("expected ErrBreak, got ") } if eb := (ErrBreak{}); !errors.As(err, &eb) { t.Fatalf("expected ErrBreak, got %#v", err) } } func TestAdd(t *testing.T) { env := NewVirtualEEI() // li a0, 0xffff // ebreak _, err := env.WriteAt([]byte{0x37, 0xc5, 0xad, 0xde, 0x13, 0x05, 0xf5, 0xee, 0x73, 0x00, 0x10, 0x00}, 0) if err != nil { t.Fatal(err) } c := NewCPU(&env) err = runUntilEbreak(&c, 3) if err != nil { t.Error(err) } // Check that we managed to load into the register if c.Registers[10] != 0xdeadbeef { t.Errorf("expected register a0 (x10) to contain 0xdeadbeef, got %#v", c.Registers[10]) } }