riscvemu/cpu_test.go

92 lines
2.0 KiB
Go

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 <nil>")
}
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])
}
}