Skip to content

drexel-systems/Drexel-CPU

Repository files navigation

CS281 Virtual Dev Board

CS281 Virtual Development Board

A bare-metal RISC-V RV32IM emulated development platform for CS281 Systems Architecture at Drexel University. Built on Renode, it gives students a realistic hardware environment — GPIO, UART, timers, interrupts — without requiring physical hardware.

📄 CS281 Technical Reference Manual — memory map, peripheral registers, interrupt reference, boot sequence, and register quick reference. (Also available as CS281_TRM.docx for editing.)

CS281 Virtual Development Board


What's Here

hardware/               Shared platform definition (used by every lab)
  cs281_board.repl      Renode machine description (CPU, memory, peripherals)
  cs281_run.resc        Renode script — normal run
  cs281_debug.resc      Renode script — GDB debug session
  lib/
    cs281.ld            Linker script (ROM @ 0x20000000, RAM @ 0x40000000)
    startup.S           Reset handler: stack init, .data copy, .bss zero
    uart.S              uart_putchar / uart_puts / uart_getchar
    cs281.inc           Assembly register map (.equ definitions)
    cs281.h             C register map (for C labs)
  docs/
    CS281_TRM.docx      Technical Reference Manual / datasheet

lab1-blinky/            Lab 1: blink LED0 with busy-wait delay
  main.S
  Makefile
  .vscode/              Tasks, launch config, IntelliSense settings

lab2-blinky2/           Lab 2: blink LED0 with CLINT timer interrupt and WFI
  main.S
  Makefile
  .vscode/              Tasks, launch config, IntelliSense settings

lab3-arrays/            Lab 3: array operations (sum, min, max, reverse) in assembly
  main.S
  Makefile
  .vscode/              Tasks, launch config, IntelliSense settings

lab4a-timers-c/         Lab 4a: LiteX Timer interrupt in C (reference implementation)
  main.c
  Makefile
  .vscode/              Tasks, launch config, IntelliSense settings

lab4b-timers/           Lab 4b: LiteX Timer interrupt in assembly (student TODO)
  main.S
  Makefile
  .vscode/              Tasks, launch config, IntelliSense settings

lab5-gpio-input/        Lab 5: GPIO input interrupts — button presses toggle LEDs
  main.S
  Makefile
  .vscode/              Tasks, launch config, IntelliSense settings

Hardware

The CS281 board is a custom virtual platform defined in hardware/cs281_board.repl and emulated by Renode. It is not based on any real chip — it is designed specifically for this course so that the memory map, peripherals, and interrupt assignments are as clean and teachable as possible. Full register-level documentation is in the CS281 Technical Reference Manual.

Processor — RISC-V RV32IM + Zicsr running in machine mode (M-mode only). RV32I is the base 32-bit integer ISA; M adds hardware multiply and divide; Zicsr adds the CSR instructions needed for interrupt handling. There is no MMU, no OS, no privilege levels below M-mode — what you write runs directly on the (emulated) metal.

Memory — Two regions. ROM at 0x20000000 (256 KB) holds the program and read-only data and is loaded from the ELF at boot. RAM at 0x40000000 (512 KB) holds .data, .bss, the heap, and the stack (top at 0x40080000). The split between load address (ROM) and run address (RAM) for initialized data is handled by the linker script and the boot sequence in startup.S.

Peripherals — All peripherals are memory-mapped; reading or writing the right address controls the hardware directly. The board includes:

  • UART (0xe0001800) — LiteX UART connected to a telnet server on port 3456. Three registers: RXTX (read/write a byte), TXFULL (poll before writing), RXEMPTY (poll before reading).
  • LiteX Timer (0xe0002000) — A countdown timer with configurable load, auto-reload, and an IRQ on line 11. Useful for periodic interrupts without touching the CLINT. Important: the timer uses 8-bit CSR sub-registers — the 32-bit LOAD and RELOAD values are each split across four 8-bit registers at consecutive 4-byte addresses, written MSB first (offsets 0x00–0x0C for LOAD, 0x10–0x1C for RELOAD). Control registers: EN at 0x20, EV_PENDING at 0x3C (write 1 to clear), EV_ENABLE at 0x40 (write 1 to route to CPU line 11). See the TRM Section 6 for the complete register table and ISR pattern.
  • CLINT (0xe0005000) — The standard RISC-V Core-Level Interruptor. Provides MTIME (a 64-bit free-running counter at 100 MHz) and MTIMECMP (fires a machine timer interrupt on line 7 when MTIME ≥ MTIMECMP). Also provides MSIP (software interrupt on line 3).
  • GPIO Output (0xe0015000) — Four LEDs. Write a bitmask: bit 0 = LED0, bit 1 = LED1, bit 2 = LED2, bit 3 = LED3.
  • GPIO Input (0xe0015400) — Four inputs with an IRQ on line 12 triggered by rising edge of enabled pins. Bit 0 = BTN0, bit 1 = BTN1, bit 2 = DIP_SW0, bit 3 = DIP_SW1. Simulate from the Renode monitor: sysbus.gpio_in OnGPIO 0 True (press) / sysbus.gpio_in OnGPIO 0 False (release).
  • 7-Segment Display (0xe0004400) — Eight GPIO output bits, one per segment (a–g + decimal point). Write a bitmask to light individual segments; common digit patterns are defined in cs281.inc.
  • Buzzer (0xe0004000) — Single-bit GPIO output. Write 0x1 to activate, 0x0 to silence.

Interrupts — The CPU has three interrupt lines wired up. Line 3 (MSIP) and line 7 (MTIP) come from the CLINT; line 11 (MEIP) comes from the LiteX Timer; line 12 comes from GPIO Input. Enable a specific interrupt by setting the corresponding bit in mie, then set mstatus.MIE (bit 3) to open the global gate. Point mtvec at your trap handler before enabling anything.

Memory Region Address Size
ROM 0x20000000 256 KB
RAM 0x40000000 512 KB
UART 0xe0001800
LiteX Timer 0xe0002000
Buzzer 0xe0004000
7-Segment Display 0xe0004400
CLINT 0xe0005000
GPIO Output (LEDs) 0xe0015000
GPIO Input (BTN/DIP) 0xe0015400

→ See hardware/cs281_board.repl for the full Renode platform definition and hardware/docs/CS281_TRM.pdf for complete register documentation.

Prerequisites

Tool Notes
Renode 1.16+ — the emulator
RISC-V GNU Toolchain Provides riscv64-elf-as, riscv64-elf-ld, riscv64-elf-gdb
telnet For UART and monitor connections
VS Code (optional) .vscode/ configs are provided in each lab for convenience, but any editor works

See docs/setup.md for step-by-step installation instructions on macOS, Windows, and Linux.

Quick Start

cd lab1-blinky
make              # assemble and link → build/lab1.elf
make run          # launch Renode headless

In a second terminal:

make uart-connect # telnet to UART — see LED0 ON / LED0 OFF output

All Make Targets

Target Description
make / make all Build build/lab1.elf
make clean Remove build/
make run Run in Renode (headless)
make run-debug Run with GDB stub on :3333, CPU halted
make debug-attach Attach riscv64-elf-gdb (command-line)
make uart-connect telnet localhost 3456 — UART output
make monitor-connect telnet localhost 1234 — Renode monitor
make disasm Disassemble ELF to stdout

Renode Monitor Commands

Once connected via make monitor-connect:

pause                              # halt CPU
start                              # resume
cpu PC                             # show program counter
sysbus.gpio_led0 State             # read LED0 state (True/False)
sysbus.gpio_in OnGPIO 0 True       # BTN0 press  (rising edge → IRQ)
sysbus.gpio_in OnGPIO 0 False      # BTN0 release
sysbus.gpio_in OnGPIO 1 True       # BTN1 press
quit                               # exit Renode

Lab Progression

Lab Topic
Lab 1 (lab1-blinky) GPIO output, UART, software busy-wait delay
Lab 2 (lab2-blinky2) CLINT timer interrupt, mtvec, WFI, MTIMECMP
Lab 3 (lab3-arrays) Indexed memory access, loops, RISC-V calling convention
Lab 4a (lab4a-timers-c) LiteX Timer interrupt in C — read before Lab 4b
Lab 4b (lab4b-timers) LiteX Timer interrupt in assembly — student implementation
Lab 5 (lab5-gpio-input) GPIO input interrupts, rising-edge trigger, IRQ_PENDING

Architecture

  • CPU: RISC-V RV32IM + Zicsr (32-bit, integer multiply/divide, CSR instructions)
  • Emulator: Renode with LiteX-compatible peripheral models
  • Language: Assembly-first (C supported via same toolchain and linker script)
  • Debug: GDB stub in Renode + VS Code Native Debug extension (webfreak.debug, external server mode)

Experimental: CS281 Board UI

A terminal TUI that renders a virtual board — colored LEDs, a 7-segment display, DIP switches, a CPU status indicator, and a live UART output pane. Connects to Renode over TCP so you can interact with the hardware without touching the monitor prompt. Written in Go using the Charm ecosystem; cross-compiles to macOS, Linux, and Windows.

╭─────────────────────────────────────────────────────────────────────╮
│               CS281 Virtual Development Board                        │
│                         ◉  RUNNING                                  │
│─────────────────────────────────────────────────────────────────────│
│  INPUTS          │   7-SEG   │  LEDs         │  STATUS              │
│                  │           │               │                      │
│  [0] BTN0  mom   │   ───     │  ⬤ LED0 ○LED1 │  CPU  ● RUN         │
│  [1] BTN1  mom   │  █   █    │  ○ LED2 ○LED3 │                     │
│  [2] DIP0  ▽off  │   ───     │               │  ╔══════╗            │
│  [3] DIP1  ▽off  │  █   █    │               │  ║ RST  ║            │
│                  │   ───     │               │  ╚══════╝            │
│─────────────────────────────────────────────────────────────────────│
│  UART OUTPUT                                   ↑↓ / j k / scroll    │
│─────────────────────────────────────────────────────────────────────│
│  Main loop running...                                                │
│  . . . . [BTN0] LED0 ON . . . [BTN0] LED0 OFF . . .                │
│─────────────────────────────────────────────────────────────────────│
│  [0] BTN0  [1] BTN1  [2] DIP0  [3] DIP1                            │
│  [R] Reset     [P] Power Down      [Q] Quit                         │
╰─────────────────────────────────────────────────────────────────────╯

Power-up sequence — pressing P connects to Renode and runs a self-test animation: each LED cycles on/off, each DIP flips, and the 7-segment counts 0–9. UART output is buffered silently behind a "Testing Board..." banner, then streams live once the board reports POST OK. Press Esc to skip the self-test.

Reset — pressing R while running performs a soft reset: the CPU is paused, all GPIO inputs are cleared, the program counter is rewound to _start (0x20000000), and the CPU is resumed. The firmware re-runs its boot sequence without closing the Renode session.

CPU status — the STATUS panel shows ● RUN (green) or ○ HLT (amber) based on whether the program counter is advancing. Programs that halt or spin on wfi without activity for ~6 seconds are flagged as halted.

→ See experimental/ui/README.md for build instructions, keyboard controls, flags, and architecture details.


Drexel University — CS281 Systems Architecture

About

Emulated Drexel CPU for Systems Architecture Class

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors