#include "Valu.h" #include "verilated.h" #include "tester.hpp" #include struct alu_testcase { std::string name; // Inputs uint32_t A, B; uint8_t op; // Outputs uint32_t O; std::optional overflow, zero; std::optional max_cycles; }; void test_op(Valu *valu, Tester *tester, alu_testcase test) { Tester subtester(tester, test.name); // assign inputs valu->op = test.op; valu->A = test.A; valu->B = test.B; valu->eval(); char o_name[100]; if (test.O < 0x100) snprintf(o_name, sizeof o_name, "O == 0x%02x", test.O); if (test.O < 0x10000) snprintf(o_name, sizeof o_name, "O == 0x%04x", test.O); else snprintf(o_name, sizeof o_name, "O == 0x%08x", test.O); subtester.assert_eq(o_name, valu->O, test.O); if (test.overflow.has_value()) { if (*test.overflow) subtester.assert_eq("overflow flag set", valu->Fflow, 1); else subtester.assert_eq("no overflow flag", valu->Fflow, 0); } if (test.zero.has_value()) { if (*test.zero) subtester.assert_eq("zero flag set", valu->Fzero, 1); else subtester.assert_eq("no zero flag", valu->Fzero, 0); } } int main(int argc, char **argv) { VerilatedContext *vctx = new VerilatedContext; Valu *valu = new Valu(vctx); Tester alu_t("alu"); { Tester add_t(&alu_t, "add", true); test_op(valu, &add_t, { .name = "0x2137+0x1234", .A = 0x2137, .B = 0x1234, .op = 0b000, .O = 0x336b, .overflow = false, }); test_op(valu, &add_t, { .name = "0x09+0x10", .A = 0x09, .B = 0x10, .op = 0b000, .O = 0x19, .overflow = false, }); test_op(valu, &add_t, { .name = "0x5555+0x5555", .A = 0x5555, .B = 0x5555, .op = 0b000, .O = 0xaaaa, .overflow = false, }); test_op(valu, &add_t, { .name = "0xfffffffe+0x1", .A = 0xfffffffe, .B = 0x1, .op = 0b000, .O = 0xffffffff, .overflow = false, .zero = false, }); test_op(valu, &add_t, { .name = "0xffffffff+0x1", .A = 0xffffffff, .B = 0x1, .op = 0b000, .O = 0x0, .overflow = true, .zero = true, }); test_op(valu, &add_t, { .name = "0xffffffff+0x2", .A = 0xffffffff, .B = 0x2, .op = 0b000, .O = 0x1, .overflow = true, .zero = false, }); test_op(valu, &add_t, { .name = "0x0+0x0", .A = 0x0, .B = 0x0, .op = 0b000, .O = 0x0, .overflow = false, .zero = true, }); } { Tester sub_t(&alu_t, "sub", true); test_op(valu, &sub_t, { .name = "0x2137-0x0420", .A = 0x2137, .B = 0x0420, .op = 0b001, .O = 0x1d17, .overflow = false, }); test_op(valu, &sub_t, { .name = "0x0-0x1", .A = 0x0, .B = 0x1, .op = 0b001, .O = 0xffffffff, .overflow = true, }); test_op(valu, &sub_t, { .name = "0x100-0x0200", .A = 0x100, .B = 0x200, .op = 0b001, .O = 0xffffff00, .overflow = true, }); test_op(valu, &sub_t, { .name = "0x21-0x9", .A = 0x21, .B = 0x9, .op = 0b001, .O = 0x18, .overflow = false, .zero = false, }); test_op(valu, &sub_t, { .name = "0x20-0x20", .A = 0x20, .B = 0x20, .op = 0b001, .O = 0x0, .overflow = false, .zero = true, }); } { Tester bitwise_t(&alu_t, "bitwise", true); // 0x3 = 0b0011, 0x5 = 0b0101 test_op(valu, &bitwise_t, { .name = "0x3&0x5", .A = 0x3, .B = 0x5, .op = 0b100, .O = 0x1, .zero = false, }); test_op(valu, &bitwise_t, { .name = "0x3|0x5", .A = 0x3, .B = 0x5, .op = 0b101, .O = 0x7, .zero = false, }); test_op(valu, &bitwise_t, { .name = "0x3^0x5", .A = 0x3, .B = 0x5, .op = 0b110, .O = 0x6, .zero = false, }); test_op(valu, &bitwise_t, { .name = "~0xa5a5a5a5", .A = 0xa5a5a5a5, .B = 0x0, .op = 0b111, .O = 0x5a5a5a5a, .zero = false, }); test_op(valu, &bitwise_t, { .name = "~0xffffffff", .A = 0xffffffff, .B = 0x0, .op = 0b111, .O = 0x0, .zero = true, }); } }