# 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 <pkgs+top>` →
`xelab -L uvm` → `xsim -R -testplusarg UVM_TESTNAME=<test>`.

## 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`.
