Note: This project is under active development and is not yet feature-complete.
TURBO/64 BBS is a Commodore 64 BBS written in C for the Oscar64 compiler. It targets native .prg output for real hardware (including C64 Ultimate) and VICE emulation.
Current status: v0.3.0 — login/registration, terminal translation (PETSCII, ANSI/CP437, ASCII), bulletin boards, door programs (run external Oscar64 plug-ins), Punter and Zmodem file transfers, and the "Configure" editor are working.
Not working: Private mail, SysOp chat, polls/voting, and lots more remain stubbed.
Not a developer? Download
TURBO64-<ver>.d81from the latest GitHub release, mount it on your C64 Ultimate or in Vice, and jump straight to First-Time Setup below.
💬 Join the community on Discord — for support, feature ideas, or just to chat C64 BBSing.
Hardware / emulator
- Commodore 64 with SwiftLink/ACIA cartridge at $DE00, or C64 Ultimate (C64U) with built-in ACIA, or VICE x64sc with tcpser modem bridge
- Two .D81 disk images — one for the BBS, one blank one for message boards (device 9)
- 16 MB REU required for the message boards and some other features. The C64 Ultimate has one built in, and VICE can be configured with one. The BBS boots and lets you log in without a REU, but reading and posting messages need it. This will probably be a hard-check in the future.
Developer Build host (macOS / Linux)
oscar64compiler —bash tools/install-oscar64.shc1541from VICE package (disk assembly)c64udeploy tool for C64U —bash tools/install-c64u.shtcpserfor VICE modem emulation — macOS:brew install tcpser
make all # compile BOOT and CONFIGURE PRGs
make disk # assemble TURBO64-<ver>.d81 from build output + data/
make disk-with-users # same, but fetches live user database from C64U firstOutput: build/c64/BOOT-<ver>.prg, build/c64/CONFIGURE-<ver>.prg, build/c64/TURBO64-<ver>.d81
See tools/README.md for the full reference.
On the C64, mount TURBO64-<ver>.D81 on device 8 and load CONFIGURE:
LOAD "CONFIGURE-0.3.0",8
RUN
From the CONFIGURE main menu, choose I — INIT FILES.
Creates:
USR LOG— user database (100 slots, 30 bytes/record)USR PROF— extended user profiles (100 slots, 86 bytes/record)CALLERS— callers log, seeded with one SYSOP entry so the WFC screen has something to display
Record 1 is always the SysOp account — handle SYSOP, password PASS, access level 5. Change it!
CONFIGURE → C — CONFIG → 1 SETTINGS:
| Key | Default | Notes |
|---|---|---|
BBSNAME |
A NEW T/64 BBS |
BBS name shown at login |
BBSCITY |
SOMEWHERE, CA |
Location string |
SYSOPNAME |
JOE SYSOP |
Displayed on BBS |
NEWUSERLVL |
1 |
Access level for new registrants (0–4) |
ALLOWNEW |
1 |
Allow self-registration |
SYSOPSTAT |
|
Default message when users try and chat |
PROMPTCUR |
ON |
Animated prompt cursor |
CONFIGURE → C - CONFIG → 2 DEVICES:
| Key | Default | Notes |
|---|---|---|
DEV_SYSTEM |
8 |
Device for boot PRG, config, and gfiles |
DEV_MSGS |
9 |
Device for message boards (separate drive recommended) |
DEV_FILES |
8 |
Device for upload/download areas |
DEV_DOORS |
8 |
Device for door programs |
CONFIGURE → C → 5 MODEM TYPE: AUTO (DETECT), VICE, U64.
CONFIGURE → C → 2 BAUD RATE: 300, 1200, 2400, 9600, 19200, or 38400.
Changes are saved to the config SEQ file immediately.
If configured in DEVICES, the BBS reads message boards from a separate disk on DEV_MSGS (default device 9). Two options:
Format a blank .D81 and mount it on C64U device 9. Then in CONFIGURE → M — MSG AREAS → C — CREATE, add boards. Each board needs a title, read level, and write level. The BOARDS DIR REL file and per-board index files are created automatically on first post.
Then mount BOARDS-<ver>.D81 on C64U device 9.
⚠️ The message index format uses 63-byte REL records.
Outside CONFIGURE, on the C64:
LOAD "BOOT-0.3.0",8
RUN
Expected startup output:
TURBO/64 BBS V0.3.0
LOADING SETUP...
BBS: <your bbs name>
SYSOP: <your name>
INIT MODEM...
ACIA STATUS: $10
DSR: INACTIVE
CHECKING REU...
REU: 16 MB
CHECKING USR LOG...
USR LOG: OK
CHECKING FOR REAL TIME CLOCK...
If USR LOG: NOT FOUND or USR LOG: EMPTY appears, return to CONFIGURE and run Init Files.
data/config is the template bundled into every disk build:
BBS_NAME=A NEW T/64 BBS
BBS_CITY=SOMEWHERE, CA
SYSOP_NAME=JOE SYSOP
NEW_USER_LEVEL=1
MIN_CALL_TIME=5
MAX_CALL_TIME=60
DEV_SYSTEM=8
DEV_MSGS=9
DEV_FILES=8
DEV_DOORS=8
MODEM_INIT=ATZ
BAUD_RATE=38400
MODEM_TIMEOUT=255
ALLOW_NEW_USERS=1
ALLOW_UPLOADS=1
Device values can include a drive number and CBM DOS init string: 8, 8;0:, or 8;0:;CD:BBS. The BBS sends the init string to the drive at startup.
| Level | Name | Description |
|---|---|---|
| 0 | Deleted | Banned / deleted account |
| 1 | New | Unvalidated new user (default for registrants) |
| 2 | User | Standard validated user |
| 3 | Power | Power user |
| 4 | Co-SysOp | Co-SysOp |
| 5 | SysOp | Full access; cannot be deleted |
The SysOp account (ID 1) is created by Init Files at level 5. Adjust NEW_USER_LEVEL to control what level new registrants receive.
Each level also carries daily usage limits and capability flags, edited in CONFIGURE → Access Levels:
- CALLS/DAY — maximum logins allowed per day for the level.
- MINS/DAY — maximum online minutes per day. Enforced live: a time-left banner and a per-second countdown show during the session (see the
%TLMCI code), and the caller is warned and disconnected when the limit is reached. Levels with the T flag are exempt. - FLAGS — capability bits, shown in the editor as a row of letters (a
-means that flag is off, e.g.APSJU---):
| Letter | Flag | Grants |
|---|---|---|
A |
POST_ANON | post messages anonymously |
P |
PAGE_SYSOP | page the SysOp for chat |
S |
SEND_MAIL | send private mail |
J |
JOIN_POLLS | vote in polls |
U |
UPLOAD | upload files |
T |
NO_TIME_LIMIT | exempt from MINS/DAY |
C |
NO_CALL_LIMIT | exempt from CALLS/DAY |
Y |
SYSOP | full SysOp / Co-SysOp access |
These rows live in the ACCESS SEQ file on the system disk, one comma-delimited line per level:
level,name,calls_per_day,mins_per_day,flags
flags is the decimal sum of the bit values (A=1, P=2, S=4, J=8, U=16, T=32, C=64, Y=128). Edit it through CONFIGURE rather than by hand. Overriding the name field there also changes the label shown for that level throughout the BBS.
CONFIGURE MAIN MENU
I — INIT BBS Initialize USR LOG, USR PROF, and CALLERS
U — USER MGMT List, delete, reset passwords
M — MSG AREAS Create/edit/delete message boards
F — FILE AREAS Create/edit upload/download areas
V — VOTE MGMT Create/edit polls (stub)
D — DOOR PROGRAMS Register/edit/delete door programs (see Door Programs below)
C — CONFIG OPTIONS Edit BBS name, devices, baud rate
S — STATISTICS Show user/area counts (basic)
Q — QUIT
Doors are external programs the BBS loads and runs during a call — games,
utilities, info screens. A door is a separate Oscar64 .prg built to load at
$9700; the BBS hands it a small SDK (print, read input, display a file, caller
info) and reloads itself when the door exits. They're configured in CONFIGURE
and run from the ! (DOOR PROGRAMS) entry on the main menu, or automatically
at login.
The release disk bundles an example door, FORTUNE (FORTUNE.PRG), so you
can try the system without writing any code.
-
Boot CONFIGURE and choose
D— DOOR PROGRAMS, thenC(Create). Fill in:Field Value Notes TITLE FORTUNEshown in the door menu FILENAME FORTUNEthe bundled FORTUNE.PRGon the diskDEVICE 8device the door PRG lives on (the release disk is device 8) DRIVE 0CMD KEY Fthe key that runs it from the menu MIN LEVEL 0minimum access level ENABLED Ymust be Y to appear RUN AT LOGIN NYruns it automatically after loginSave. (Confirm
DEV_DOORS=8under CONFIG OPTIONS so the BBS reads the door table from the same drive — on a single-drive setup that's device 8.) -
Run the BBS and log in. At the main menu press
!(DOOR PROGRAMS) — you should see[F] FORTUNE. PressFto run it: it greets you, shows a fortune, and returns to the menu on a keypress.
The door table (your registrations) is created by CONFIGURE and lives on the disk; it persists between boots of the same disk. Re-assembling a fresh disk starts with no doors registered — re-register, or see
tools/README.md(--seed-doors) to carry the table across rebuilds.
See devkit/README.md — the dev kit ships an SDK header
and a one-file build (make door DOOR=<name>). Doors get ~10 KB and a small
versioned API; the guide covers the authoring contract and constraints.
Manage boards in CONFIGURE → M — MSG BOARDS (List, Create, Edit, Delete).
Creating a board. Create asks only for a title, then drops you into the board editor where you set everything else. (Cancelling the editor right after creating discards the new board.)
Per-board settings (board editor). Press the reverse-video hotkey to change a field:
| Key | Field | Meaning |
|---|---|---|
T |
TITLE | Board name (max 16 chars) |
L |
LIST ORD | Display order in the BBS (lower sorts first; ties break by id) |
R |
READ | Min access level to read (0–5) |
W |
WRITE | Min access level to post (0–5) |
A |
ANON | Allow anonymous posts (Y/N) |
N |
NET | Networked area (Y/N); when on, set G NET TAG |
O/X |
SUBOP | Assign / clear a SubOp by handle |
M |
MAX MSG | Per-board message limit (DEFAULT = use the system default) |
D |
MAX DAYS | Age-prune limit in days (OFF = no age pruning) |
Press S to save, C to cancel.
Size and age limits. Two independent limits keep a board from growing without
bound (compile-time defaults in include/bbs/config.h):
- Message count. A board's
MAX MSGcaps how many messages it keeps.DEFAULT(0) usesCFG_MSG_LIMIT_DEFAULT= 100. When a board passes its limit, the oldest messages are auto-pruned (soft-deleted) in batches ofCFG_MSG_PRUNE_BATCH= 10. There is also a hard ceiling ofCFG_MSG_MAX_PER_BOARD= 200 messages per board — posting beyond it fails. - Age.
MAX DAYSsoft-deletes messages older than N days. The default isCFG_MSG_AGE_DEFAULT= 0 = OFF (no age pruning) until a SysOp sets a day count on the board.
So out of the box a board keeps ~100 messages (auto-pruning the oldest above that, hard stop at 200) with no age limit. Pruning is automatic at runtime; there is no manual compact/prune step in CONFIGURE.
TURBO/64 supports two transfer protocols through the F (FILES) entry on the main menu. Files are organised into areas, each with its own device, upload permission level, and listing. When you press D or U, the BBS prompts PROTOCOL: (P)UNTER (Z)MODEM (ENTER=CANCEL):.
Punter (P) — the native C64 BBS protocol. If you're calling with CCGMS, CGTerm, or another C64 terminal, use Punter. It is compiled directly into the OVL_FILES overlay so there is no extra disk load. The implementation sends one 256-byte block at a time with a simple checksum-and-ACK handshake.
Zmodem (Z) — better for PC-side clients (SyncTerm, PuTTY with Zmodem support, etc.). The BBS swaps in the OVL_ZMODEM overlay (~3.4 KB) for the transfer, then reloads OVL_FILES to continue. Uses ZHEX headers, ZCRCG streaming in 255-byte blocks, CRC-16, and the standard five-ZDLE cancel sequence.
| Key | Action |
|---|---|
L |
List files in the current area |
A |
List all areas |
+ / - |
Next / previous area |
1–9 |
Jump to area by number |
D |
Download a file (prompts for protocol) |
U |
Upload a file (prompts for protocol) |
Q |
Quit back to main menu |
CONFIGURE → F — FILE AREAS → C (Create). Each area has:
| Field | Notes |
|---|---|
| NAME | Area title shown to callers |
| DEVICE | CBM device the files live on (typically 8 or 9) |
| DRIVE | CBM drive number (usually 0) |
| DL LEVEL | Minimum access level to download |
| UL LEVEL | Minimum access level to upload |
Files are stored as ordinary PRG/SEQ entries on the configured device — no special index. Uploaded files appear immediately for download.
Uflag in CONFIGURE → Access Levels enables uploading for that level. Without it,Uis refused even ifUL LEVELpasses.ALLOW_UPLOADSin CONFIG OPTIONS is a global on/off switch; the access flag is checked on top of it.- Downloads are gated only by
DL LEVEL— no per-level flag is required.
- No file size in Zmodem ZFILE header. CBM DOS does not expose file size before reading, so the ZFILE header sends the filename only. Most Zmodem clients handle this gracefully (they show
?for size and rely on ZEOF to terminate). - No Zmodem resume. CBM DOS sequential files cannot seek; a receiver-requested ZRPOS will abort the transfer rather than rewind the file.
- 255-byte disk reads.
disk_readis limited to 255 bytes per call; both protocol implementations use back-to-back reads so throughput is unaffected, but each IEC operation is a separate bus transaction at 1541/1571/1581 speed.
Files on TURBO64-<ver>.d81 (device 8, system device):
| Filename | Type | Description |
|---|---|---|
boot-<ver> |
PRG | BBS runtime |
configure-<ver> |
PRG | SysOp editor |
ovl_msgs |
PRG | Bulletin-board overlay |
ovl_wfc |
PRG | WFC (waiting-for-call) overlay |
ovl_boot |
PRG | Boot/login overlay |
ovl_doors |
PRG | Door programs overlay |
ovl_files |
PRG | File-area overlay (browse, list, D/U) |
ovl_zmodem |
PRG | Zmodem transfer overlay |
fortune |
PRG | Example door (FORTUNE) |
config |
SEQ | BBS configuration (key=value) |
access |
SEQ | Access levels (6 lines, one per level 0–5) |
usr log |
REL | User database (30 bytes/record, 100 slots) |
usr prof |
REL | Extended user profiles (86 bytes/record, 100 slots) |
usr day |
REL | Per-user daily counters (8 bytes/record, 100 slots) |
callers |
SEQ | Callers log (fixed-width lines) |
status |
SEQ | SysOp status line |
syscnt |
SEQ | System call counters |
g.login |
SEQ | Login art — generic fallback |
g.login 0 |
SEQ | Login art — PETSCII |
g.login 1 80 |
SEQ | Login art — ANSI/CP437 80-col |
g.login 2 80 |
SEQ | Login art — ASCII 80-col |
g.newuser |
SEQ | New user screen — generic fallback |
g.term |
SEQ | Terminal selection menu |
m.doors |
SEQ | Door programs menu body |
m.files |
SEQ | File areas menu body |
m.main |
SEQ | Main menu body — generic fallback |
m.main 1 80 |
SEQ | Main menu body — ANSI/CP437 80-col |
m.msgs |
SEQ | Messages menu body — generic fallback |
m.msgs 1 80 |
SEQ | Messages menu body — ANSI/CP437 80-col |
m.read |
SEQ | Read-message display — generic fallback |
p.doors |
SEQ | Door programs menu prompt |
p.files |
SEQ | File areas menu prompt |
p.main |
SEQ | Main menu prompt — generic fallback |
p.main 1 80 |
SEQ | Main menu prompt — ANSI/CP437 80-col |
p.msgs |
SEQ | Messages menu prompt |
p.read |
SEQ | Read-message prompt — generic fallback |
p.read 1 80 |
SEQ | Read-message prompt — ANSI/CP437 80-col |
Files on BOARDS-<ver>.d81 (device 9, message device):
| Filename | Type | Description |
|---|---|---|
boards |
REL | Board directory (44 bytes/record; CFG_MAX_BOARDS boards, default 20) |
b<n>.idx |
REL | Message index for board N (63 bytes/record, up to 200 msgs) |
b<n>.txt |
SEQ | Message body text for board N |
usr ptr |
REL | Per-user last-read pointers (CFG_MAX_BOARDS × 2 bytes/record, 100 slots) |
Display files follow the pattern <prefix>.<name> [<mode>] [<width>]:
- prefix —
g= gfile (display page),m= menu body,p= prompt - mode —
0=PETSCII,1=ANSI/CP437,2=ASCII, - width —
40or80; omit to match any width
BOOT tries the most specific match first:
<prefix>.<name> <mode> <width> → <prefix>.<name> <mode> → <prefix>.<name> <width> → <prefix>.<name>
A p.<name> file replaces the built-in COMMAND: prompt for that menu. If absent, the built-in text is used.
Display files support inline color codes using |XX or \XX (two-digit decimal 00–15). Both forms are identical — \ is provided as a C64-native alias because the standard C64 keyboard has no | key: the £ key produces CHR$(92) = ASCII backslash. Codes are translated to the appropriate PETSCII or ANSI escape for each caller's terminal; ASCII callers receive no color output.
| Code | Color | Code | Color |
|---|---|---|---|
|00 |
Black | |08 |
Orange |
|01 |
White | |09 |
Brown |
|02 |
Red | |10 |
Light Red |
|03 |
Cyan | |11 |
Dark Gray |
|04 |
Purple | |12 |
Medium Gray |
|05 |
Green | |13 |
Light Green |
|06 |
Blue | |14 |
Light Blue |
|07 |
Yellow | |15 |
Light Gray |
|16 |
Reverse on | |17 |
Reverse off |
Color resets to white-on-black at the end of each display file. \|17 (reverse off) is emitted automatically at reset; you only need it mid-file to cancel an earlier \|16.
Authoring on a C64: prefer the
\XXform — the£key types it directly. The|form is handy when authoring on a PC. A more C64-keyboard-friendly color scheme is on the roadmap.
| Token | Replaced with | Active in |
|---|---|---|
%SN |
Configured BBS (system) name | g.term (connect screen) |
%SO |
Configured SysOp name | g.term (connect screen) |
%BN |
Current board name (trimmed) | p.msgs, p.read |
%MN |
Current message number | p.read only |
%TL |
Caller's time left today (e.g. 10m; unlim if the level is time-exempt) |
Any display/prompt file (g.*, m.*, p.*) |
Tokens not yet set expand to an empty string. The time-left value (%TL) is recomputed from the live MINS/DAY state each time a file is shown. On PETSCII it is uppercased (10M / UNLIM) so it stays readable in the graphics charset. Example p.main:
|01(%TL LEFT) |03CMD|07?|04:
Example p.read:
|05MSG#|03%MN |05IN |03%BN
|03CMD|07?|04:
The local C64 screen mirrors the caller's session, with a status bar showing handle, access level, time online, and action keys. The view adapts to the caller's terminal type.
The caller's output is rendered directly on the C64's 40-column text screen using the C64 character ROM. A five-row panel (rows 20–24) shows user details and quick-action keys.
The spy is locked to the uppercase/graphics charset for the entire session — it does not follow callers who switch to lowercase/text. This keeps PETSCII art and the status panel rendering correctly, but means mixed-case text (e.g. a message body) appears as graphics glyphs on the spy. ANSI/ASCII callers are unaffected since they use the 80-column view below.
The VIC-II has no hardware 80-column mode, so TURBO/64 renders a software 80-column display into a hi-res bitmap using a custom 4×6-pixel font — 80 columns on a stock C64. This mode is automatic when an REU is detected at boot and the caller is 80-column; without an REU it falls back to the 40-column spy.
Internals: VIC switches to hi-res bitmap mode (bank 3, bitmap at $E000 under KERNAL ROM, colour RAM at $C000). A small ANSI parser in the overlay interprets printable text, CR/LF, cursor positioning (ESC[H/ESC[r;cH/ESC[A–D), screen clear (ESC[2J), and SGR colours (mapped to the VIC palette), rendering into the bitmap. Caller content occupies rows 0–23; row 24 is a reverse-video status bar (handle · access level · time · action keys) that stays visible and ticks once per second.
| Key | Action |
|---|---|
| F2 | Drop the current caller (works from anywhere) |
| F1 | SysOp chat (scaffolded, not yet wired) |
| F3 | Change access level (scaffolded, not yet wired) |
- REU required. No REU → 80-column callers shown on 40-column spy (clipped to 40 columns).
- ANSI/ASCII only. PETSCII callers always use the 40-column spy — the bitmap parser doesn't speak PETSCII.
- Approximate font. 4×6 font covers ASCII
0x20–0x7E. CP437 box-drawing chars map to+ - | #; fine graphics are lost. - Two colours per cell. One foreground colour per 8×8 cell (two chars), so adjacent differently-coloured characters share the rightmost colour. Background is always black.
- Scroll pacing. Shifting ~7 KB of bitmap per scroll; noticeably slower on a stock 1 MHz C64, snappy on C64U. Caller output is not delayed — only the spy rendering slows.
- Bottom row. Status bar occupies row 24; the caller's row 25 is not shown.
Note: The 80-column soft view is functional but not extensively tested with complex ANSI art. Help appreciated!
USR LOG: NOT FOUND on boot
Run CONFIGURE → I Init Files. The REL file was never created.
USR LOG: EMPTY on boot
Record 1 (SysOp) is missing. Run Init Files again.
ERROR: MODEM INIT FAILED
ACIA not detected at $DE00. On C64U, verify ACIA/SwiftLink is enabled. In VICE, verify tools/deploy-vice.sh launched with -acia1 flags.
VICE: telnet connection refused
tcpser may not have started. Check that deploy-vice.sh output shows tcpser launched.
Double-echo characters in terminal
The BBS sends IAC WILL ECHO; your terminal client should suppress local echo. Use a proper telnet client (not raw TCP).
Garbled characters (PETSCII/ANSI) BOOT auto-detects terminal type via backspace probe. Use a terminal that responds to backspace (PETSCII: C64 terminal; ANSI: SyncTerm, PuTTY). If detection fails, BBS falls back to ASCII.
M from main menu says NO BOARDS
Device 9 is not mounted or has no boards configured. Mount BOARDS-<ver>.D81 on device 9 and verify DEV_MSGS=9 in config. If the disk is blank, use CONFIGURE → M — MSG AREAS to create at least one board.
The following features return a placeholder message:
- Private mail
- SysOp chat / page
- Polls and votes
- Last caller display
- System info
- Grafitti wall
- Preferences (can't edit)
- Help
- Local chat
- 80 column (ANSI) view message viewer
- WFC F Keys (local login, log viewer, etc.)
- Spy F Keys (Chat, Change Access Level)
- Adapt message area to 80 cols if user selects that mode
Data structures and CONFIGURE admin modules for all of the above are in place.
Things I'd love for TURBO/64 to do:
- Message networking (like Image3 - should D8 be compatible? Not Fidonet)
- Embedded scriping / modding support - let sysops customize the hell out of it
- External strings to easy editing
- A more C64-keyboard-friendly markup scheme for gfiles. Colors currently use
|XX/\XX(the\form is already C64-typeable via the£key), but the|prefix isn't on the C64 keyboard. A dedicated single-key or%-style color scheme would make on-C64 authoring easier and keep color markup consistent with the%-prefixed MCI codes.
TURBO/64 is an active project and contributions of all kinds are welcome — you do not need to be a C programmer to help.
Can you wrangle a C codebase targeting a 1MHz 6502 while having genuine opinions about which C64 BBS software had the best message base? Do you understand why fitting a feature into a 10 KB overlay segment is a satisfying constraint rather than an annoying one? We could use you.
The stubbed features listed above are the priority. Each one has its data layer and CONFIGURE admin UI in place; what is missing is the caller-facing session logic inside src/features/. If you want to pick up a feature, open an issue first to avoid duplication.
Good entry points: src/features/mail.c, src/features/vote.c, src/features/callers.c — all are thin stubs waiting to be wired up on the same pattern as src/features/bulletin.c.
Technical chops:
- Solid C experience — not "I got it to compile with enough casts"
- Understands the 6502 memory model: zero page, bank switching, why you care about what goes where
- Knows what IEC bus timing means in practice and why CBM DOS REL files are both brilliant and painful
- Can read a linker map and understand why the overlay boundary moved four times in a week
- Bonus: familiarity with oscar64, PETSCII terminal emulation, or CBM DOS internals
- Bonus: experience with modem/ACIA programming or serial protocol implementation
Cultural fit:
- Either lived through the C64 scene OR has become genuinely and unironically obsessed with it
- Understands why PETSCII is not just "ASCII but weird" and has feelings about it
- Gets that the 40-column display is a design constraint worth respecting, not working around
- Has opinions about which 1581 partition scheme was least terrible
- Will not suggest porting it to a Raspberry Pi
The BBS runs on a constrained 6502 with a 37 KB core region and a 10.5 KB overlay zone for the message module. Contributions that reduce code size, tighten the overlay boundary, or improve IEC bus throughput are extremely valuable. Familiarity with oscar64 pragmas (#pragma code, #pragma overlay, #pragma region) and CBM DOS REL files is a plus.
The BBS ships with bare-bones gfiles. What it needs:
- PETSCII art (
g.login 0,g.newuser 0,m.main 0,m.msgs 0,p.msgs 0, etc.) — 40-column PETSCII using pipe/backslash color codes (|NNor\NN) - ANSI/CP437 art (mode
1, optionally1 80for 80-column) — classic BBS ANSI with the same color code system - ASCII variants (mode
3) — plain text for terminals that strip color - Menu prompt files (
p.*) — the one-or-two-line prompts shown at each menu; small but high-impact
Files live in data/gfiles/ and are assembled directly onto the disk image by make disk. No build tools required — edit, copy to the D81, and test live.
Are you an old-school ANSi artist? Younger and inexplicably drawn to this era and aesthetic? Do you need one more goddamn thing to do? Consider spending some of your valuable free time on this — compensated by nothing more than the unyielding appreciation of the people who enjoy this kind of thing. Gotta be a few of us around, right?
Style guide:
- Authentic C64/Compunet-era aesthetic — PETSCII character graphics, the C64's native 40-column canvas, and the distinct visual language that came out of the early European and North American C64 scene
- Work within the C64's 16-color palette; the classic cyan-on-blue, or white-on-black with colored highlights are right at home here — lean into the limitations, don't fight them
- Logo screens and headers built from PETSCII block and graphic characters — the kind of thing that looked like it took three days on a real machine, because it did
- ANSI/CP437 variants (for mode
1) should feel like they belong on a 1990 warez dist site, not a modern retro tribute — if it could have shipped on a C64 BBS in 1991, you're in the right place - Group shoutouts, greetz, and handle tags are not only acceptable, they are strongly encouraged
Real-hardware and emulator coverage is critical. Specifically needed:
- SD2IEC — the BBS uses CBM DOS REL files; SD2IEC REL support has known edge cases. Reports of what works and what does not are very helpful.
- VICE — regression testing after each feature addition;
tools/deploy-vice.shmakes this fast. - Real 1541/1571/1581 — timing and IEC bus behaviour differs from emulation and the C64U's built-in drive.
- Terminal clients — SyncTerm, PuTTY, netcat, and real C64 terminals over a nullmodem or SwiftLink.
File issues on GitHub with hardware/firmware versions, a description of what you did, and the exact error or unexpected behaviour.
Prefer to talk it through? Join the TURBO/64 Discord for support, feature ideas, and general C64 BBS chatter.





