# Calc1 UVM Verification Environment A complete, self-checking UVM environment for the **Calc1** calculator DUT, built on top of the lecture skeleton (Vežbe 5–11). It drives real stimulus, reconstructs transactions, checks them against a golden reference model and collects functional coverage. ``` calc_verif_top (dut + interface + clock/reset) └── uvm_test_top (test_base → test_simple / test_sanity / test_random / test_corner / test_no_sub …) └── calc_env ├── calc_agent │ ├── calc_sequencer ← sequences (calc_*_seq) │ ├── calc_driver → drives req{1..4}_cmd/data │ └── calc_monitor ← samples pins, functional coverage └── calc_scoreboard ← reference model + checking ``` ## DUT recap (functional spec — Vežba 5) | Command | cmd | Result | |---------|-----|--------| | NOP | `0000` | none | | ADD | `0001` | `op1 + op2` | | SUB | `0010` | `op1 - op2` | | SHL | `0101` | `op1 << op2[4:0]` (zero fill) | | SHR | `0110` | `op1 >> op2[4:0]` (zero fill) | | invalid | other | error | * **Protocol:** `cmd` + `op1` are driven in one cycle, `op2` in the next; the response appears `≥3` cycles later. Only one operation may be outstanding per port; the 4 ports are independent. * **Response (`out_respX`):** `00` none, `01` success (data on `out_dataX`), `10` overflow/underflow/invalid, `11` unused. * **Reset:** active-high on all 7 lines, held ≥7 cycles, inputs 0 during reset. ## What was implemented (on top of the skeleton) * **`Agent/calc_seq_item.sv`** – transaction: `port, cmd, op1, op2, delay` (rand) + observed `resp, result`; `calc_cmd_e` / `calc_resp_e` enums; command distribution constraints; `convert2string`. * **`Agent/calc_driver.sv`** – two-cycle request protocol, per-port selection, waits for reset release and for the port's response before completing an item (bidirectional non-pipelined model, Vežba 6). Uses non-blocking drives to stay race-free against the monitor. * **`Agent/calc_monitor.sv`** – one collector thread per port reconstructs each request/response pair, broadcasts it on the analysis port and samples the **functional coverage** model (cmd, port, resp, operand corners, cmd×port and cmd×resp crosses — Vežba 11). * **`calc_scoreboard.sv`** – embedded **reference model / predictor** computes the expected `resp`/`data` per spec and compares against the DUT; counts pass/fail and reports them (Vežba 10). * **`Configurations/calc_config.sv`** – `is_active`, `checks_enable`, `coverage_enable`; pushed to mon/scbd by the env. * **Sequences (`Sequences/`)** – `calc_simple_seq` (random N), and in `calc_seq_lib.sv`: `single`, `same_port`, `diff_port`, `alu` (ALU1 only), `shift` (ALU2 only), `shift_amounts`, `corner` (overflow/underflow/equal), `invalid`, and `clean` (guaranteed spec-conformant). * **Tests (`test_lib.sv`)** – `test_sanity`, `test_random`, `test_corner`, `test_no_sub` (factory override demo, Vežba 9) plus the original `test_simple` / `test_simple_2`. * **`calc_verif_top.sv`** – fixed reset to be spec-compliant (all-ones, ≥7 cycles) and added an optional `+WAVES` dump. ## How to run **Cadence Xcelium** (lab tool, paths in `v10_run.f`): ```sh cd code/vezba10 xrun -f v10_run.f # default: test_sanity xrun -f v10_run.f +UVM_TESTNAME=test_corner # pick another test xrun -f v10_run.f +UVM_TESTNAME=test_random +UVM_VERBOSITY=UVM_HIGH ``` **QuestaSim / ModelSim:** ```sh cd code/vezba10 vsim -do run.do # default: test_sanity vsim -do "set TEST test_corner; do run.do" ``` **Vivado / xsim (batch, terminal-only)** — verified on Vivado 2022.2: ```sh cd code/vezba10 make # compile + elaborate + run test_sanity make TEST=test_corner make TEST=test_random VERB=UVM_HIGH make WAVES=1 # also dump calc.vcd make clean # override tool path: make VIVADO=/tools/Xilinx/Vivado/2022.2 ``` Equivalent without `make`: ```sh ./run_vivado.sh # default test_sanity ./run_vivado.sh test_corner ``` Both wrap the raw flow `xvlog dut/*.v` → `xvlog --sv -L uvm ` → `xelab -L uvm` → `xsim -R -testplusarg UVM_TESTNAME=`. ## Expected results The scoreboard models the **specification** (golden model). Running it on the provided RTL (verified on Vivado 2022.2) gives: * **`test_sanity` → 36/36 pass, 0 UVM_ERRORs.** It drives directed *known-good* vectors (verified against the DUT) covering every port and command, so it proves the environment / reference model has **no false positives**. * **`test_corner` / `test_random` / `test_simple` / `test_simple_2` → the scoreboard flags real DUT defects** and the run still terminates cleanly (driver/monitor use a bounded response wait, so a non-responding port is reported, never hung on). The defects this DUT exhibits: * ADD overflow / SUB underflow are **not** reported (`resp` stays `01`, wrapped data returned) and **invalid** commands execute instead of erroring — root cause: `error_found` tied to `0` in `dut/calc_top.v:90`. * **Port 4 ADD/SUB never responds** — `dut/priority.v:73-76` only asserts the ALU1 valid for port 4 when `local_error_found` (which is 0). The environment times out and reports it instead of deadlocking. * **Data-dependent arithmetic errors** in the adder/shifter (e.g. `0x08EA14DC + 0x036BA248` gives `0x0C55D724` instead of `0x0C55B724`). * **Shift by 0** returns `0` instead of the operand. * **`test_no_sub`** demonstrates a factory override (a transaction subtype that never issues SUB) applied across the whole environment. All of the above was confirmed by actually building and simulating the environment in Vivado xsim; `test_sanity` is green and the bug-finding tests report the defects above while always reaching `$finish`.