Week: 12
Points: 20
Time: ~5 hours
Deliverable: toolchain/compiler/compiler.py (multi-file) + Pong end-to-end + custom program + diary/week-12.md
What you ship
toolchain/compiler/compiler.py— multi-file driverbuild/vm/Pong/— three VM files from compiling the Pong directorybuild/bin/pong.bin— linked Pong binarycompiler/week-12/MyProgram.vl— your own VirtusLang program (Lab 12.4)build/vm/MyProgram/MyProgram.vm— compiled outputdiary/week-12.md
Lab 12.1: Write the multi-file compiler driver
Extend toolchain/compiler/compiler.py to handle directories:
#!/usr/bin/env python3
"""compiler.py -- VirtusLang multi-file compiler."""
import sys
from pathlib import Path
from tokenizer import Tokenizer
from parser import Parser
from codegen import CodeGen
def compile_file(src_path: Path, out_dir: Path):
source = src_path.read_text()
tok = Tokenizer(source)
tree = Parser(tok).parse_class()
gen = CodeGen()
gen.compile_class(tree)
out_path = out_dir / src_path.with_suffix('.vm').name
out_path.write_text('\n'.join(gen.output) + '\n')
print(f" {src_path.name} -> {out_path.name} ({len(gen.output)} VM lines)")
def main():
if len(sys.argv) < 2:
print("Usage: compiler.py <source.vl | source-dir> [-o output-dir]")
sys.exit(1)
src = Path(sys.argv[1])
out_dir = Path(sys.argv[sys.argv.index('-o') + 1]) if '-o' in sys.argv else (
src.parent if src.is_file() else src
)
out_dir.mkdir(parents=True, exist_ok=True)
sources = sorted(src.glob('*.vl')) if src.is_dir() else [src]
print(f"Compiling {len(sources)} file(s) -> {out_dir}/")
for s in sources:
compile_file(s, out_dir)
if __name__ == '__main__':
main()
Verify by compiling a two-class directory and confirming that two .vm files are produced.
Lab 12.2: Compile and link Pong
A three-class Pong program is provided in compiler/week-12/Pong/:
Pong/Main.vl— entry point; creates PongGame and calls runPong/PongGame.vl— game logic; uses Screen, Output, Keyboard, GamePadPong/Ball.vl— ball object; uses Math.abs, Screen.drawRectangle
Run the full pipeline:
# Step 1: Compile all three classes
python3 toolchain/compiler/compiler.py compiler/week-12/Pong/ -o build/vm/Pong/
# Step 2: Translate each VM file to assembly
mkdir -p build/asm/Pong
for f in build/vm/Pong/*.vm; do
python3 toolchain/vm-translator/translator.py "$f" \
-o "build/asm/Pong/$(basename ${f%.vm}.s)"
done
# Step 3: Assemble each .s file
mkdir -p build/obj/Pong
for f in build/asm/Pong/*.s; do
python3 toolchain/assembler/asm.py "$f" \
-o "build/obj/Pong/$(basename ${f%.s}.vof)"
done
# Step 4: Link with Virtus OS stubs
python3 toolchain/linker/linker.py \
build/obj/Pong/*.vof \
virtus-os/*.vof \
-o build/bin/pong.bin
sha256sum build/bin/pong.bin
Record the SHA-256 hash in diary/week-12.md.
Lab 12.3: Spot-check PongGame.vm
Open build/vm/Pong/PongGame.vm and locate the code generated for one method of your choice. Verify:
- Each method call to an OS service uses the correct argument count from
OS_SIGNATURES - Object construction uses
call Memory.alloc 1+pop pointer 0 - Method calls on objects push
pointer 0before the explicit arguments
Write a two-paragraph spot-check in diary/week-12.md. Paragraph 1: which method you chose and why. Paragraph 2: what you found and whether it matched your expectation.
Lab 12.4: Write your own VirtusLang program
Write a VirtusLang program of your own design. Requirements:
- At least one class with at least one method
- At least one
whileloop - At least one OS call (any of:
Output.printInt,Output.printString,Screen.drawPixel,Keyboard.readChar) - The program must produce visible output when simulated
Create compiler/week-12/MyProgram.vl, compile it, run it through the full pipeline, and capture the simulation output.
In diary/week-12.md, answer the three Week 12 reflection prompts:
- Does the order of files in the directory affect correctness? When could it matter?
- What was the first thing that did not work when you compiled and ran your program? Describe the debugging steps and root cause.
- Your program calls one OS service. What would happen if the Virtus OS changed the argument count of that service without recompiling your program? Design a mechanism that would catch this mismatch at link time.
Lab 12.5: HDMI or UART output path
For students on the hardware path (Tang Primer 25K with HDMI extension):
# Flash the Pong bitstream
openFPGALoader -b tangprimer25k build/bin/pong.bin
Verify that HDMI output shows the Pong frame. Record the binary size and instruction count in diary/week-12.md.
For students on the UART-only path: redirect Screen.drawPixel to a UART escape sequence. Verify that the character-art Pong representation renders correctly over UART.
Grading
| Component | Points |
|---|---|
compiler.py: handles directory input, produces one VM per .vl |
4 |
| Pong compile + link: three VM files produced, binary built | 5 |
build/bin/pong.bin SHA-256 recorded in diary |
2 |
Spot-check PongGame.vm: two paragraphs, specific evidence |
3 |
| Lab 12.4: own program compiles + runs + produces output | 4 |
| Diary: debugging narrative for Lab 12.4 program | 2 |