Skip to content

docs: add dungeon-master-nochip to the family #137

docs: add dungeon-master-nochip to the family

docs: add dungeon-master-nochip to the family #137

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
PYTHON_VERSION: "3.12"
jobs:
lint:
name: Format and lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install ruff
run: pipx install ruff==0.16.3
- name: Check formatting
run: ruff format --check .
- name: Lint
run: ruff check --output-format=github .
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm
- name: Install the formatter
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Check that every JSON and YAML file is formatted
run: pnpm run format:check
# The workflows are the one thing here nothing else checks, and a mistake
# in them is only visible once a run has already gone wrong. The archive
# is verified by digest before anything in it runs, for the same reason
# every document this project reads is.
- name: Check the workflows themselves
run: |
curl -fsSL -o actionlint.tar.gz \
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c -
tar -xzf actionlint.tar.gz actionlint
./actionlint -color
rm -f actionlint actionlint.tar.gz
shell: bash
env:
ACTIONLINT_VERSION: "1.7.12"
ACTIONLINT_SHA256: "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8"
- name: Lint the shell scripts
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
shellcheck --severity=style --shell=bash scripts/*.sh
types:
name: Types
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install the type checker
run: pipx install mypy==1.14.1
# Strict, with every optional error class the version offers. A processor
# core is masked integers, flag bits and addressing modes end to end, and a
# width crossing a boundary it should not is exactly what this catches. The
# settings live in pyproject.toml so a local run and this one agree.
- name: Every annotation has to hold
run: mypy
test:
name: Tests on Python ${{ matrix.python }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python: ["3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python }}
- name: Install coverage
run: python -m pip install --disable-pip-version-check coverage==7.6.10
- name: Run every test file, under coverage
run: |
python -m coverage erase
status=0
while IFS= read -r file; do
echo "::group::${file}"
python -m coverage run -a "${file}" || status=1
echo "::endgroup::"
done < <(find mos65xx conformance -name '*.test.py' | sort)
exit "${status}"
shell: bash
- name: Coverage must be total
run: python -m coverage report
# No document is redistributable, so none is here and this checks nothing
# on a runner. It says so rather than reporting a pass: the value is that
# somebody running it with the documents on disk gets a real answer, and
# that a run without them cannot be mistaken for one.
- name: Every quoted sentence, against the document it came from
run: python -m conformance.quotes
# Uninstrumented, and deliberately after the coverage run rather than
# inside it. A coverage tracer costs about ten times what the model does, so
# a throughput check under one measures the tracer.
- name: The model has not become several times slower
run: python -m conformance.speed
# Opt-in, and silent when nothing is there. A transistor level simulation
# of the die answers what no data sheet states and no recording carries,
# but it is somebody else's work under their own licence, so a copy belongs
# on the machine that runs it rather than in this repository or this job.
- name: The model against a simulation of the die, when one is present
run: python -m conformance.netlist
conformance:
name: Conformance against SingleStepTests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
# One key for every suite, taken from the file that pins them all, so the
# two jobs that need them share one entry rather than filling the cache
# with the same gigabytes twice.
- name: Cache the suites
id: cache
uses: actions/cache@v6
with:
path: ~/.cache/conformance-suites
key: suites-${{ hashFiles('conformance/suites.json') }}
- name: Fetch the suite
if: steps.cache.outputs.cache-hit != 'true'
run: python -m conformance.fetch ~/.cache/conformance-suites
# A pull request runs a tenth of each suite for a quick answer. A push to
# main runs every case, because the number of them is what the claim of
# conformance rests on, and the claim covers every part rather than one.
- name: Run every suite
run: |
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
limit=1000
else
limit=0
fi
status=0
while read -r suite model; do
echo "::group::${suite} as a ${model}"
python -m conformance.singlestep \
"${HOME}/.cache/conformance-suites/${suite}" "${limit}" --model "${model}" || status=1
echo "::endgroup::"
done <<'SUITES'
65816/65816/v1 65816
6502/6502/v1 6502
nes6502/nes6502/v1 2a03
synertek65c02/synertek65c02/v1 65c02
rockwell65c02/rockwell65c02/v1 r65c02
wdc65c02/wdc65c02/v1 w65c02
SUITES
exit "${status}"
shell: bash
cycles:
name: Cycle for cycle against SingleStepTests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
# One key for every suite, taken from the file that pins them all, so the
# two jobs that need them share one entry rather than filling the cache
# with the same gigabytes twice.
- name: Cache the suites
id: cache
uses: actions/cache@v6
with:
path: ~/.cache/conformance-suites
key: suites-${{ hashFiles('conformance/suites.json') }}
- name: Fetch the suite
if: steps.cache.outputs.cache-hit != 'true'
run: python -m conformance.fetch ~/.cache/conformance-suites
# Every cycle of an eight-bit part is a bus cycle, so this compares timing
# and side effects at once: address, value, and read against write, in
# order. On the 65816 it also compares eight output pins per cycle, and the
# cycles where the part drives no valid address at all.
- name: Compare the bus, cycle by cycle
run: |
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
limit=1000
else
limit=0
fi
status=0
while read -r suite model; do
echo "::group::${suite} as a ${model}"
python -m conformance.cycles \
"${HOME}/.cache/conformance-suites/${suite}" "${limit}" --model "${model}" || status=1
echo "::endgroup::"
done <<'SUITES'
65816/65816/v1 65816
6502/6502/v1 6502
nes6502/nes6502/v1 2a03
synertek65c02/synertek65c02/v1 65c02
rockwell65c02/rockwell65c02/v1 r65c02
wdc65c02/wdc65c02/v1 w65c02
SUITES
exit "${status}"
shell: bash