Metadata-Version: 2.4
Name: scoreboarding
Version: 0.3.0
Summary: Pure-Python cycle-exact simulator of Thornton's Scoreboarding (CDC 6600) in-order dynamic scheduling, with structural, WAR, and WAW hazard detection and per-instruction traces for computer architecture education.
Project-URL: Homepage, https://github.com/amaar-mc/scoreboarding
Project-URL: Repository, https://github.com/amaar-mc/scoreboarding
Project-URL: Issues, https://github.com/amaar-mc/scoreboarding/issues
Project-URL: Changelog, https://github.com/amaar-mc/scoreboarding/blob/main/CHANGELOG.md
Author: Amaar Chughtai
License: MIT License
        
        Copyright (c) 2026 Amaar Chughtai
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: cdc-6600,computer-architecture,cpu-simulator,education,hazards,in-order,instruction-scheduling,pipeline,pipelined,scoreboarding,simulation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Education
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.10
Provides-Extra: dev
Requires-Dist: hatchling>=1.25; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# scoreboarding

<p align="center">
  <img src="assets/logo.png" alt="scoreboarding logo" width="160">
</p>

Pure-Python cycle-exact simulator of Thornton's **Scoreboarding** algorithm,
as implemented in the CDC 6600 (1964). Designed for computer architecture
education: readable source, zero runtime dependencies, and per-instruction
cycle-number traces.

i built this because the algorithm only really clicked once i could watch each
hazard clear one cycle at a time.

---

## What is Scoreboarding?

Scoreboarding is an **in-order issue, out-of-order execution** dynamic
scheduling technique. The processor issues instructions one at a time
(program order), but lets them read operands and execute independently once
their hazards clear. A central scoreboard -- three tables -- tracks every
in-flight instruction and enforces the classic CDC 6600 hazard rules without
any register renaming.

### The Four Stages

| Stage | What happens | Hazard checked |
|---|---|---|
| **Issue** | Assign instruction to a free FU | Structural (no free FU of the kind) + WAW (another active insn writes same dest) |
| **Read Operands** | Read both source registers | RAW (stall until producing FU has written result) |
| **Execute** | Occupy the FU for its full latency | -- |
| **Write Result** | Commit result to register file, free FU | WAR (stall until every earlier reader has read its operand) |

### Three Tracking Tables

1. **Instruction Status** -- per-instruction cycle stamps (Issue / ReadOperands / ExecuteComplete / WriteResult).
2. **Functional Unit Status** -- per-FU: busy flag, op, destination (Fi), sources (Fj, Fk), producing FUs (Qj, Qk), ready flags (Rj, Rk).
3. **Register Result Status** -- which FU will next write each register (None once written).

### Pipelined vs unpipelined functional units

Each `FunctionalUnit` declares whether its execute stage is `pipelined`.

- **Unpipelined** (`pipelined=False`, the classic CDC 6600 default): the unit is a
  structural hazard for its entire lifetime. It stays busy from Issue through Write
  Result, so a same-kind successor cannot issue to it until the occupying
  instruction has written its result. This is the original scoreboard behaviour.
- **Pipelined** (`pipelined=True`): the unit frees its issue slot as soon as the
  occupying instruction has read its operands and entered the execute pipeline. A
  same-kind successor can then issue the next cycle while the deep execute pipeline
  still carries the earlier result. The structural stall is shorter; RAW, WAR, and
  WAW hazards are unaffected.

For example, two independent back-to-back multiplies on a single `latency=4`
multiply unit:

| | Unpipelined | Pipelined |
|---|---|---|
| MULT #1 issue / write | 1 / 7 | 1 / 7 |
| MULT #2 issue / write | 7 / 13 | 2 / 8 |
| Total cycles | 13 | 8 |

The pipelined unit issues the second multiply at cycle 2 (right after the first
reads operands) instead of waiting until cycle 7 for the first to write back.

### How it differs from Tomasulo

| | Scoreboarding | Tomasulo |
|---|---|---|
| Issue order | In order | In order |
| Execution order | Out of order | Out of order |
| WAW handling | Stall Issue | Register renaming (RS tags) |
| WAR handling | Stall Write Result | Eliminated by renaming |
| RAW handling | Stall Read Operands | Stall in RS until CDB broadcast |
| Register renaming | No | Yes (via reservation stations) |
| Broadcast mechanism | Central scoreboard | Common Data Bus |

See the sibling package [tomasulo](https://github.com/amaar-mc/tomasulo) for the
Tomasulo out-of-order scheduler with register renaming.

---

## Install

```bash
# From source (until PyPI release):
git clone https://github.com/amaar-mc/scoreboarding
cd scoreboarding
uv pip install -e ".[dev]"
```

---

## Usage

### Python API

```python
from scoreboarding import FunctionalUnit, Instruction, run, render_trace

fus = [
    FunctionalUnit(name="Load1", kind="load", latency=2,  pipelined=False),
    FunctionalUnit(name="Mult1", kind="mult", latency=10, pipelined=False),
    FunctionalUnit(name="Add1",  kind="add",  latency=2,  pipelined=False),
    FunctionalUnit(name="Div1",  kind="div",  latency=40, pipelined=False),
]

program = [
    Instruction(op="LD",   dest="F6",  src1="R2", src2=""),
    Instruction(op="LD",   dest="F2",  src1="R3", src2=""),
    Instruction(op="MULT", dest="F0",  src1="F2", src2="F4"),
    Instruction(op="SUB",  dest="F8",  src1="F6", src2="F2"),
    Instruction(op="DIV",  dest="F10", src1="F0", src2="F6"),
    Instruction(op="ADD",  dest="F6",  src1="F8", src2="F2"),
]

trace = run(program, functional_units=fus)
print(render_trace(trace))
```

### Example timing table

```
+---------------------+-------+---------+----------+-------------+
| Instruction         | Issue | ReadOps | ExecComp | WriteResult |
+---------------------+-------+---------+----------+-------------+
| LD F6, R2           |     1 |       1 |        2 |           3 |
| LD F2, R3           |     3 |       3 |        4 |           5 |
| MULT F0, F2, F4     |     4 |       5 |       14 |          15 |
| SUB F8, F6, F2      |     4 |       5 |        6 |           7 |
| DIV F10, F0, F6     |     5 |      15 |       54 |          55 |
| ADD F6, F8, F2      |     8 |       8 |        9 |          16 |
+---------------------+-------+---------+----------+-------------+
Total cycles: 16
```

### Per-cycle snapshots

Pass `capture_snapshots=True` to `run()` to capture scoreboard state after every
cycle, then render any `CycleSnapshot` with `render_snapshot()`:

```python
from scoreboarding import render_snapshot

trace = run(program, functional_units=fus, capture_snapshots=True)
print(render_snapshot(trace.snapshots[0]))
```

```
-- Cycle 1 --
Instruction status
  #  Issue  ReadOps  ExecComp  WriteResult
  -  -----  -------  --------  -----------
  0  1      -        -         -
  1  -      -        -         -
  2  -      -        -         -
  3  -      -        -         -
  4  -      -        -         -
  5  -      -        -         -

Functional unit status
  FU     Busy  Op  Fi  Fj  Fk  Qj  Qk  Rj   Rk   ExecStart
  -----  ----  --  --  --  --  --  --  ---  ---  ---------
  Add1   no    -   -   -   -   -   -   no   no   -
  Div1   no    -   -   -   -   -   -   no   no   -
  Load1  yes   LD  F6  R2  -   -   -   yes  yes  -
  Mult1  no    -   -   -   -   -   -   no   no   -

Register result status
  Register  Producer
  --------  --------
  F6        Load1
```

`render_trace()` renders the summary timing table; `render_snapshot()` renders
the full three-table scoreboard state for a single cycle.

### CLI

```bash
# Use the bundled example:
scoreboarding examples/classic.txt

# Enable per-cycle snapshots:
scoreboarding --snapshots examples/classic.txt

# Read from stdin:
cat examples/classic.txt | scoreboarding -
```

`--snapshots` prints the instruction-status, functional-unit-status, and
register-result-status tables after every cycle, so a stall can be traced back
to the exact scoreboard entry holding it up.

Program file format:

```
# Comments start with #
# FU <name> <kind> <latency> [pipelined|unpipelined]   (default: unpipelined)
FU Load1 load 2
FU Mult1 mult 10 pipelined
FU Add1  add  2
FU Div1  div  40 unpipelined

LD   F6, R2
LD   F2, R3
MULT F0, F2, F4
SUB  F8, F6, F2
DIV  F10, F0, F6
ADD  F6, F8, F2
```

---

## Development

```bash
uv run pytest -q
uv run ruff check .
uv run mypy src
uv build
```

CI runs on Python 3.10, 3.11, 3.12, 3.13 via GitHub Actions.

---

## License

MIT -- see [LICENSE](LICENSE).
