use vast::util::file::read_to_string; use vast::v17::ast::*; macro_rules! check { ($res:expr, $exp:expr) => { assert!( $res == $exp, "\n\nresult:\n{}\nexpected:\n{}\n\n", $res, $exp ); }; } #[test] fn test_expr_str() { let expr = Expr::new_str("multiply"); let exp = r#""multiply""#.to_string(); let res = expr.to_string(); check!(res, exp); } #[test] fn test_expr_ulit_bin() { let expr = Expr::new_ulit_bin(4, "1000"); let exp = "4'b1000".to_string(); let res = expr.to_string(); check!(res, exp); } #[test] fn test_expr_ulit_hex() { let expr = Expr::new_ulit_hex(8, "ff"); let exp = "8'hff".to_string(); let res = expr.to_string(); check!(res, exp); } #[test] fn test_expr_ulit_dec() { let expr = Expr::new_ulit_dec(16, "78"); let exp = "16'd78".to_string(); let res = expr.to_string(); check!(res, exp); } #[test] fn test_expr_logor() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ulit_dec(1, "1"); let logor = Expr::new_logical_or(lhs, rhs); let res = logor.to_string(); let exp = "a || 1'd1".to_string(); check!(res, exp); } #[test] fn test_expr_logand() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ulit_dec(1, "1"); let logand = Expr::new_logical_and(lhs, rhs); let res = logand.to_string(); let exp = "a && 1'd1".to_string(); check!(res, exp); } #[test] fn test_expr_add() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ulit_dec(8, "1"); let add = Expr::new_add(lhs, rhs); let res = add.to_string(); let exp = "a + 8'd1".to_string(); check!(res, exp); } #[test] fn test_expr_gt() { let lhs = Expr::new_ref("mask"); let rhs = Expr::new_ulit_dec(32, "1"); let gt = Expr::new_gt(lhs, rhs); let res = gt.to_string(); let exp = "mask > 32'd1".to_string(); check!(res, exp); } #[test] fn test_expr_lt() { let lhs = Expr::new_ref("mask"); let rhs = Expr::new_ulit_dec(32, "1"); let lt = Expr::new_lt(lhs, rhs); let res = lt.to_string(); let exp = "mask < 32'd1".to_string(); check!(res, exp); } #[test] fn test_expr_geq() { let lhs = Expr::new_ref("mask"); let rhs = Expr::new_ulit_dec(32, "1"); let geq = Expr::new_geq(lhs, rhs); let res = geq.to_string(); let exp = "mask >= 32'd1".to_string(); check!(res, exp); } #[test] fn test_expr_leq() { let lhs = Expr::new_ref("mask"); let rhs = Expr::new_ulit_dec(32, "1"); let leq = Expr::new_leq(lhs, rhs); let res = leq.to_string(); let exp = "mask <= 32'd1".to_string(); check!(res, exp); } #[test] fn test_expr_eq() { let lhs = Expr::new_ref("z"); let rhs = Expr::new_ulit_dec(8, "1"); let eq = Expr::new_eq(lhs, rhs); let res = eq.to_string(); let exp = "z == 8'd1".to_string(); check!(res, exp); } #[test] fn test_expr_neq() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ref("b"); let neq = Expr::new_neq(lhs, rhs); let res = neq.to_string(); let exp = "a != b".to_string(); check!(res, exp); } #[test] fn test_expr_mul() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ref("b"); let mul = Expr::new_mul(lhs, rhs); let res = mul.to_string(); let exp = "a * b".to_string(); check!(res, exp); } #[test] fn test_expr_int() { let expr = Expr::Int(3); let res = expr.to_string(); let exp = "3".to_string(); check!(res, exp); } #[test] fn test_expr_mux() { let cond = Expr::new_eq(Expr::new_ref("a"), Expr::new_ref("b")); let tru = Expr::new_ref("a"); let fal = Expr::new_ref("b"); let mux = Expr::new_mux(cond, tru, fal); let res = mux.to_string(); let exp = "a == b ? a : b".to_string(); check!(res, exp); } #[test] fn test_expr_slice() { let hi = Expr::new_int(7); let lo = Expr::new_int(0); let slice = Expr::new_slice("a", hi, lo); let res = slice.to_string(); let exp = "a[7:0]".to_string(); check!(res, exp); } #[test] fn test_expr_index_slice() { let lo = Expr::new_int(0); let slice = Expr::new_index_slice("a", lo, 8); let res = slice.to_string(); let exp = "a[0 +: 8]".to_string(); check!(res, exp); } #[test] fn test_expr_index_slice_var() { let lo = Expr::new_mul(Expr::new_ref("x"), Expr::new_int(32)); let slice = Expr::new_index_slice("a", lo, 32); let res = slice.to_string(); let exp = "a[x * 32 +: 32]".to_string(); check!(res, exp); } #[test] fn test_expr_bit() { let bit = Expr::new_index_bit("a", 9); let res = bit.to_string(); let exp = "a[9]".to_string(); check!(res, exp); } #[test] fn test_expr_ipath() { let path = Expr::new_ipath("cpu.alu.a"); let res = path.to_string(); let exp = "cpu.alu.a".to_string(); check!(res, exp); } #[test] fn test_expr_ipath_with_index() { let path = Expr::new_ipath_with_index("cpu.mem", "addr"); let res = path.to_string(); let exp = "cpu.mem[addr]".to_string(); check!(res, exp); } #[test] fn test_expr_return() { let ret = Sequential::new_return(Expr::new_ref("y")); let res = ret.to_string(); let exp = "return y;".to_string(); check!(res, exp); } #[test] fn test_expr_call() { let params: Vec = vec![Expr::new_ref("a"), Expr::new_ref("b")]; let call = Expr::new_call("func", params); let res = call.to_string(); let exp = "func(a, b)".to_string(); check!(res, exp); } #[test] fn test_attr_val() { let mut attr = Attribute::default(); attr.add_val("full_case"); let exp = "(*full_case*)".to_string(); let res = attr.to_string(); check!(res, exp); } #[test] fn test_attr_stmt() { let mut attr = Attribute::default(); attr.add_stmt("x", "3"); let exp = "(*x = \"3\"*)".to_string(); let res = attr.to_string(); check!(res, exp); } #[test] fn test_decl_logic_width_32() { let logic = Decl::Logic("foo".to_string(), Ty::Width(32)); let res = logic.to_string(); let exp = "logic [31:0] foo".to_string(); check!(res, exp); } #[test] fn test_decl_logic_width_1() { let logic = Decl::Logic("foo".to_string(), Ty::Width(1)); let res = logic.to_string(); let exp = "logic foo".to_string(); check!(res, exp); } #[test] fn test_decl_int() { let int = Decl::Int("a".to_string(), Ty::Int); let res = int.to_string(); let exp = "int a".to_string(); check!(res, exp); } #[test] fn test_decl_param_uint() { let param = Decl::new_param_uint("width", 3); let res = param.to_string(); let exp = "parameter int width = 32'd3".to_string(); check!(res, exp); } #[test] fn test_event_ty_posedge() { let event = EventTy::Posedge; let res = event.to_string(); let exp = "posedge".to_string(); check!(res, exp); } #[test] fn test_event_ty_negedge() { let event = EventTy::Negedge; let res = event.to_string(); let exp = "negedge".to_string(); check!(res, exp); } #[test] fn test_case_branch() { let mut branch = CaseBranch::new(Expr::new_ulit_dec(32, "0")); branch.add_seq(Sequential::new_display("branch 0")); let res = branch.to_string(); let exp = r#"32'd0 : begin $display("branch 0"); end"#; check!(res, exp); } #[test] fn test_case_default() { let mut default = CaseDefault::default(); default.add_seq(Sequential::new_display("default branch")); let res = default.to_string(); let exp = r#"default : begin $display("default branch"); end"#; check!(res, exp); } #[test] fn test_seq_event_posedge_clock() { let event = Sequential::Event(EventTy::Posedge, Expr::Ref("clock".to_string())); let res = event.to_string(); let exp = "posedge clock".to_string(); check!(res, exp); } #[test] fn test_seq_error() { let err = Sequential::new_error("this is an error"); let res = err.to_string(); let exp = r#"$error("this is an error");"#; check!(res, exp); } #[test] fn test_seq_display() { let res = Sequential::new_display("this is a message").to_string(); let exp = r#"$display("this is a message");"#; check!(res, exp); } #[test] fn test_seq_assert() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ref("b"); let expr = Expr::new_eq(lhs, rhs); let assert = Sequential::new_assert(expr); let res = assert.to_string(); let exp = "assert(a == b)".to_string(); check!(res, exp); } #[test] fn test_seq_assert_with_error() { let lhs = Expr::new_ref("a"); let rhs = Expr::new_ref("b"); let expr = Expr::new_eq(lhs, rhs); let err = Sequential::new_error("some error"); let assert = Sequential::new_assert_with_else(expr, err); let res = assert.to_string(); let exp = r#"assert(a == b) else $error("some error");"#; check!(res, exp); } #[test] fn test_seq_assign_blk_ref() { let lexpr = Expr::new_ref("a"); let rexpr = Expr::new_ulit_bin(2, "10"); let assign = Sequential::new_blk_assign(lexpr, rexpr); let res = assign.to_string(); let exp = "a = 2'b10;".to_string(); check!(res, exp); } #[test] fn test_seq_assign_non_blk_ref() { let lexpr = Expr::new_ref("y"); let rexpr = Expr::new_ref("a"); let assign = Sequential::new_nonblk_assign(lexpr, rexpr); let res = assign.to_string(); let exp = "y <= a;".to_string(); check!(res, exp); } #[test] fn test_seq_if() { let cond = Expr::new_ref("reset"); let y = Expr::new_ref("y"); let a = Expr::new_ref("a"); let seq = Sequential::new_nonblk_assign(y, a); let mut ifelse = SequentialIfElse::new(cond); ifelse.add_seq(seq); let exp = r#"if(reset) begin y <= a; end"#; let res = ifelse.to_string(); check!(res, exp); } #[test] fn test_seq_if_else() { let c0 = Expr::new_ref("reset"); let y = Expr::new_ref("y"); let a = Expr::new_ref("a"); let val = Expr::new_int(0); let s0 = Sequential::new_nonblk_assign(y.clone(), val); let s1 = Sequential::new_nonblk_assign(y, a); let mut i0 = SequentialIfElse::new(c0); let mut else_s = SequentialIfElse::default(); i0.add_seq(s0); else_s.add_seq(s1); i0.set_else(else_s); let exp = r#"if(reset) begin y <= 0; end else begin y <= a; end"#; let res = i0.to_string(); check!(res, exp); } #[test] fn test_seq_if_else_if() { let c0 = Expr::new_ref("reset"); let c1 = Expr::new_ref("en"); let y = Expr::new_ref("y"); let a = Expr::new_ref("a"); let val = Expr::new_int(0); let s0 = Sequential::new_nonblk_assign(y.clone(), val); let s1 = Sequential::new_nonblk_assign(y, a); let mut tbr = SequentialIfElse::new(c0); let mut fbr = SequentialIfElse::new(c1); tbr.add_seq(s0); fbr.add_seq(s1); tbr.set_else(fbr); let exp = r#"if(reset) begin y <= 0; end else if(en) begin y <= a; end"#; let res = tbr.to_string(); check!(res, exp); } #[test] fn test_sequential_if_else_if_unique() { let c0 = Expr::new_ref("reset"); let c1 = Expr::new_ref("en"); let y = Expr::new_ref("y"); let a = Expr::new_ref("a"); let val = Expr::new_int(0); let s0 = Sequential::new_nonblk_assign(y.clone(), val); let s1 = Sequential::new_nonblk_assign(y, a); let mut i0 = SequentialIfElse::new(c0); let mut i1 = SequentialIfElse::new(c1); i0.add_seq(s0); i1.add_seq(s1); i0.set_else(i1); i0.set_unique(); let exp = r#"unique if(reset) begin y <= 0; end else if(en) begin y <= a; end"#; let res = i0.to_string(); check!(res, exp); } #[test] fn test_port_input_width_1() { let input = Port::Input(Decl::Logic("foo".to_string(), Ty::Width(1))); let res = input.to_string(); let exp = "input logic foo".to_string(); check!(res, exp); } #[test] fn test_module_simple() { let mut module = Module::new("foo"); module.add_input("a", 32); let res = module.to_string(); let exp = r#"module foo ( input logic [31:0] a ); endmodule "#; check!(res, exp); } #[test] fn test_module_empty() { let exp = read_to_string("regression/v17/module_empty.v"); let res = Module::new("empty").to_string(); check!(res, exp); } #[test] fn test_module_with_import_function() { let exp = read_to_string("regression/v17/module_with_import_function.v"); let mut func = Function::new("foo", Ty::Void); func.add_input_int("a"); func.add_input_int("b"); func.import(); let mut main = Module::new("main"); main.add_decl(Decl::new_int("x")); main.add_decl(Decl::from(func)); let mut comb = ParallelProcess::new_always_comb(); comb.add_seq(Sequential::SeqExpr(Expr::new_call( "foo", vec![Expr::new_int(2), Expr::new_ref("x")], ))); let res = main.add_process(comb).to_string(); check!(res, exp); } #[test] fn test_module_attribute() { let exp = read_to_string("regression/v17/module_attribute.v"); let mut attr = Attribute::default(); attr.add_stmt("use", "yes"); let mut module = Module::new("attribute"); module.set_attr(attr); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_one_input() { let exp = read_to_string("regression/v17/module_one_input.v"); let mut module = Module::new("one_input"); module.add_input("a", 5); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_four_inputs() { let exp = read_to_string("regression/v17/module_four_inputs.v"); let mut module = Module::new("four_inputs"); module.add_input("a", 2); module.add_input("b", 7); module.add_input("c", 4); module.add_input("d", 1); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_instances() { let exp = read_to_string("regression/v17/module_with_instances.v"); let mut i0 = Instance::new("i0", "prim"); let mut i1 = Instance::new("i1", "prim"); let mut i2 = Instance::new("i2", "prim"); let e0 = Expr::new_ulit_hex(4, "0"); let e1 = Expr::new_ulit_hex(4, "8"); let e2 = Expr::new_ulit_hex(4, "f"); i1.add_param_str("name", "multiply"); i2.add_param_uint("WIDTH", 3); i0.connect("port_a", e0); i1.connect("port_a", e1); i2.connect("port_a", e2); let mut module = Module::new("module_with_instances"); module.add_instance(i0); module.add_instance(i1); module.add_instance(i2); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_function() { let exp = read_to_string("regression/v17/module_with_function.v"); let lhs = Expr::new_ref("value"); let rhs = Expr::new_ulit_hex(32, "badc0ffe"); let expr = Expr::new_eq(lhs, rhs); let err = Sequential::new_error("good coffee"); let assert = Sequential::new_assert_with_else(expr, err); let mut func = Function::new("check", Ty::Void); func.add_input("value", 32); func.add_stmt(assert); let mut module = Module::new("module_with_function"); module.add_function(func); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_function_add_one() { let exp = read_to_string("regression/v17/module_with_function_add_one.v"); let var_res = Expr::new_ref("res"); let var_val = Expr::new_ref("val"); let con_one = Expr::new_ulit_bin(1, "1"); let add_expr = Expr::new_add(var_val, con_one); let mut func = Function::new("add_one", Ty::Int); func.add_input("val", 32); func.add_logic("res", 32); func.add_stmt(Sequential::new_blk_assign(var_res.clone(), add_expr)); func.add_stmt(Sequential::new_return(var_res)); let mut module = Module::new("module_with_function_add_one"); module.add_function(func); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_always_comb() { let exp = read_to_string("regression/v17/module_with_always_comb.v"); let mut always = ParallelProcess::new_always_comb(); always.add_seq(Sequential::new_display("hello world")); let stmt = Stmt::from(always); let mut module = Module::new("module_with_always_comb"); module.add_stmt(stmt); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_always_ff() { let exp = read_to_string("regression/v17/module_with_always_ff.v"); let event = Sequential::Event(EventTy::Posedge, Expr::Ref("clock".to_string())); let mut always = ParallelProcess::new_always_ff(); always.add_seq(Sequential::new_display("hello sync world")); always.set_event(event); let stmt = Stmt::from(always); let mut module = Module::new("module_with_always_ff"); module.add_stmt(stmt); module.add_input("clock", 1); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_initial() { let exp = read_to_string("regression/v17/module_with_initial.v"); let mut initial = ParallelProcess::new_initial(); initial.add_seq(Sequential::new_display("initial")); let stmt = Stmt::from(initial); let mut module = Module::new("module_with_initial"); module.add_stmt(stmt); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_final() { let exp = read_to_string("regression/v17/module_with_final.v"); let mut fnal = ParallelProcess::new_final(); fnal.add_seq(Sequential::new_display("final")); let stmt = Stmt::from(fnal); let mut module = Module::new("module_with_final"); module.add_stmt(stmt); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_case() { let exp = read_to_string("regression/v17/module_with_case.v"); let mut nop = CaseBranch::new(Expr::new_ulit_dec(5, "0")); nop.add_seq(Sequential::new_display("nop")); let mut add = CaseBranch::new(Expr::new_ulit_dec(5, "1")); add.add_seq(Sequential::new_display("add")); let mut sub = CaseBranch::new(Expr::new_ulit_dec(5, "2")); sub.add_seq(Sequential::new_display("sub")); let mut invalid = CaseDefault::default(); invalid.add_seq(Sequential::new_display("invalid")); let mut case = Case::new(Expr::new_ref("opcode")); case.add_branch(nop); case.add_branch(add); case.add_branch(sub); case.set_default(invalid); let mut always = ParallelProcess::new_always_comb(); always.add_case(case); let stmt = Stmt::from(always); let mut module = Module::new("module_with_case"); module.add_input("opcode", 5); module.add_stmt(stmt); let res = module.to_string(); check!(res, exp); } #[test] fn test_module_with_nested_case() { let exp = read_to_string("regression/v17/module_with_nested_case.v"); let mut id_0 = CaseBranch::new(Expr::new_ulit_dec(1, "0")); id_0.add_seq(Sequential::new_display("id 0")); let mut id_1 = CaseBranch::new(Expr::new_ulit_dec(1, "1")); id_1.add_seq(Sequential::new_display("id 1")); let mut case_id = Case::new(Expr::new_ref("id")); case_id.add_branch(id_0); case_id.add_branch(id_1); let mut opcode_0 = CaseBranch::new(Expr::new_ulit_dec(1, "0")); opcode_0.add_case(case_id); let mut opcode_1 = CaseBranch::new(Expr::new_ulit_dec(1, "1")); opcode_1.add_seq(Sequential::new_display("invalid")); let mut case_opcode = Case::new(Expr::new_ref("opcode")); case_opcode.add_branch(opcode_0); case_opcode.add_branch(opcode_1); let mut always = ParallelProcess::new_always_comb(); always.add_case(case_opcode); let mut module = Module::new("module_with_nested_case"); module.add_input("opcode", 1); module.add_input("id", 1); let stmt = Stmt::from(always); module.add_stmt(stmt); let res = module.to_string(); check!(res, exp); }