SDCC-MDF
Microcontroller Development Framework for SDCC — build, flash & debug MCS-51 (8051), STM8, Z80 and MOS6502 projects directly from VS Code.
Highlights
- 🧩 Board Manager — 149 built-in MCUs covering every SDCC port, in a manufacturer tree with search; add / edit / duplicate / delete your own (stored globally, survives updates)
- 📁 Project editor — visual
sdcc-project.json editing, project clock override in Hz, native browse dialogs for source/include/library/component paths, ${…} variable picker, live validation, multi-root workspaces, import from PlatformIO / Code::Blocks / Eclipse / Keil µVision
- ⚙️ Build — C and assembly (
sdas<port>), linked crt0* first → .ihx → .hex → .bin; errors in the Problems panel with Go to Error; Release / Debug modes; the success toast quotes the fresh memory usage and carries a Flash button (0.29.3, the avr-mdf pattern) and a Memory button that reveals the Memory view with the fresh report (0.29.8, the esp8266-idf pattern); every tool line is self-anchored — cd /d <project root> && … runs with each compile/link/flash command, so a drifting terminal can no longer break relative paths (0.29.4)
- 🚀 Zero-setup debugging — F5 offers Build & Debug on an unbuilt project, the debug records write themselves into
launch.json, the IntelliSense config restores itself; simulator (ucsim) and hardware (any GDB server) in one flow
- 🔧 Toolchain health at a glance — the Development Tools view (its own dockable tab since 0.28.11) lists every utility the SDCC install ships, in category groups with live found-counts and missing markers
- 📊 Memory report — area bars, 16×16 IRAM map, symbol sizes, build history — and a one-line usage quote in the build-success notification (
Flash 181/8192B (2%) · RAM 10/128B (8%), 0.29.3) plus a Memory button opening the report (0.29.8)
- ⚡ Flash — configurable upload tool with 40+
${…} variables, or one-click flash recipes (stcgal / stm8flash / avrdude / wchisp / minipro / flashrom / pk2cmd / picprog)
- 📡 Serial Monitor — cross-platform (no native modules), talks to real ports and to the simulated UART; one ▶ Start / ■ Stop button, the status-bar Monitor ⇄ Stop Monitor toggle, auto-opens after flash
- ✅ tasks.json —
SDCC: Build / Flash / Clean write themselves into .vscode/tasks.json (merge-only, silent) so Ctrl+Shift+B and Tasks: Run Task work out of the box
Requirements
- SDCC 4.2+ — auto-detected (setting →
SDCC_HOME → PATH → standard locations)
- Optional: a flash tool (see recipes) and a serial port
Quick start
- Install the SDCC toolchain.
- Create New Project (sidebar) → name → board → pick a fresh folder.
- Write code in
src/main.c → Build (Ctrl+Alt+B).
- Press F5 — on an unbuilt project the Build & Debug button switches the mode, builds and starts the simulator. Set a breakpoint in
main(); enable the Hardware Debug card to debug on the chip instead.
- Pick a flash recipe and Flash (
Ctrl+Alt+F).
Installation
From a release .vsix: Extension panel → ⋯ → Install from VSIX…, or
code --install-extension sdcc-mdf-0.29.8.vsix.
| View |
What it gives you |
| Project & Commands |
Create / Import project, live config status, the MCU row — click it and the SDCC Project Editor opens (0.28.15) — & sources overview, Actions (Build / Flash / Clean / Disassembly — now also the whole linked image via uCsim dc, 0.29.1 — the load itself verified and path-proof since 0.29.2), Device (Option Bytes…, EEPROM upload/download, Chip Erase — 0.29.0), Port |
| Development Tools |
the former 🔧 Toolchain group, its own dockable tab since 0.28.11 — sdcc version, core rows and the full utilities listing in category groups with found-counts, the toolchain picker |
| Memory |
the memory report — Overview / IRAM / Symbols / History tabs |
| Serial Monitor |
port/baud, ▶ Start / ■ Stop, timestamps & autoscroll checkboxes in the toolbar, 🧹 clear in the view title, send line; Ctrl+Alt+M reveals it wherever it is docked |
| SDCC Reference |
the curated libc + port-header reference (0.29.0, re-verified entry-by-entry against the toolchain includes in 0.29.9) — 8051 SFRs, the FULL register sets of the Z180 (61 rows: 48 SFRs + 12 vectors + Z180_IO_BASE) and Rabbit r2k (94 registers) transcribed verbatim from the real headers (0.29.11), the honest "port · no header" leaf rows for z80/stm8, the libc functions incl. the C23 stdbit/stdckdint/stdcountof modules; inline Insert #include / Details buttons |
Every view is a draggable tab; dragged out of the sidebar it introduces itself with the extension's name — "Project & Commands (SDCC-MDF)", "Development Tools (SDCC-MDF)", … — so a tab landing in the Panel or the Secondary Side Bar is never anonymous (the contextualTitle, the ESP8266-IDF pattern).
Notes:
- The status-bar items (Build / Flash / Clean / Monitor / port / mode) appear once one of the views is opened and stay for the session; commands work from the palette at all times.
- The project tree's MCU row (
MCU: <board>) is a shortcut since 0.28.15: a single click opens the SDCC Project Editor page with the project settings — the MCU itself is changed on the editor's General → Board list (searchable, the current one in bold). Since 0.29.10 the row's tooltip carries the board's characteristics (name · -m target · flash/IRAM/XRAM/heap · clock · memory model), and the Board field's hint line shows the characteristics of the selected MCU — the avr-mdf boardInfo pattern (Beken BK2461 · -mmcs51 · flash 8KB · IRAM 256B · XRAM 512B · 16 MHz · small model).
- The 🔧 Device group (0.29.0) drives the chip through the project's own upload tool: Option Bytes (STM8 0x4800 — ROP/UBC/WDG_SW/HSI trim, read/write via stm8flash, honest hex fallback otherwise), EEPROM upload/download, Chip Erase (avrdude/flashrom/wchisp/picprog; tools without a standalone erase say so). After flash also write EEPROM (Project Editor → Upload) writes an EEPROM image after every successful flash.
- A view dragged out of the sidebar (e.g. into a closed Panel) can be brought home: SDCC: Return Views to the Sidebar in the palette, or right-click the view's header → Reset View Location.
- Selecting a folder that is not an SDCC project is refused with an actionable error — the Open Another Folder button reopens the picker.
tasks.json
When a project becomes active (restored at startup, selected, created, imported) the extension makes sure the workspace folder's .vscode/tasks.json carries the three SDCC-MDF tasks — SDCC: Build (the default build task: Ctrl+Shift+B), SDCC: Flash, SDCC: Clean. They run the extension's own commands — the same build Ctrl+Alt+B runs, with the SDCC terminal and the Problems panel — through the contributed sdcc task type. Merge-only and add-if-missing: your own entries and formatting are never touched; sdcc.autoGenerateTasks (default on) gates the automatic flow, SDCC: Regenerate tasks.json re-runs the merge and reports.
Serial Monitor
The toolbar is the classic serial-monitor row, the ESP8266-IDF layout: ● state · port · baud on the left, and — pinned to the RIGHT edge (since 0.28.14) — [✓ timestamps] [✓ autoscroll] · ▶ Start, the way esp8266-idf's own monitor rides its controls right. One button is the whole session — ▶ Start connects, and once data flows it becomes the error-red ■ Stop. The timestamps and autoscroll checkboxes sit right before it; their state is what you see, the whole label clicks, and both persist across windows. Clearing moved to the view's title bar — the 🧹 $(clear-all) icon next to the port re-scan (or Ctrl+L inside the view).
The same toggle lives in the status bar: $(terminal) Monitor starts (it reveals the view and connects — to a running ucsim virtual COM first, then to the port the toolbar shows, then sdcc.comPort), and a live session turns it into the error-red $(debug-stop) Monitor — click to stop. SDCC: Start Monitor / SDCC: Stop Monitor in the palette do the same.
Debugging
Simulator-first debugging on ucsim — mcs51 (incl. DS390/DS400), z80 (incl. Z80N/ZX Next), stm8, pdk13–16, rabbit, 6502, tlcs90, … The debug adapter speaks ucsim's console protocol and reads SDCC's .cdb symbols directly. Register parsing is full on mcs51/z80/stm8; pdk/tlcs90 show A/F/SP only (0.29.5).
- Press F5. On an unbuilt project the Build & Debug button builds (a Debug build writes the
.cdb) and starts the simulator; with launch.json records pick an SDCC-MDF: … entry in the Run-and-Debug selector. The program runs to main() and stops.
- Editor breakpoints land on executable lines (gdb-style slide included); step in/over/out at C level; hover variables in the Run view; edit memory through the Hex Editor; raw
! commands go to the Debug Console (! dump iram 0 15).
- Firmware UART I/O without hardware: open the Serial Monitor (
Ctrl+Alt+M) and pick ucsim uartN · virtual COM — the monitor follows the session by itself; firmware output lands in the monitor, sends land in the UART RX.
- Passthrough — the PC's COM port as the MCU's UART: launch the Simulator + host COM port (passthrough) variant; the host port comes from
"simUartPort" in launch.json, else sdcc.debug.simUartPort, else (since 0.28.11) the workspace port (sdcc.comPort — the one you flash through), so the variant never silently degrades into the virtual COM. The debug console names the port it took. Pin the mode with "simUart" in launch.json: "monitor" (virtual COM) / "host" (passthrough) / "off" / "auto".
Hardware debugging
Debug on the chip: the session attaches to any GDB server speaking the standard Remote Serial Protocol — OpenOCD, st-util, J-Link GDB Server, pyOCD, QEMU, or your own stub.
- Project Editor → Hardware Debug card: pick a preset, set host/port, optionally the server command (the extension launches it, streams its output, stops it at session end) and flash before attach.
- Build in Debug mode and flash once.
- Start from the Run-and-Debug dropdown: SDCC-MDF: Hardware (attach to GDB server) — the record is auto-written to launch.json. F5 keeps the simulator.
Honest limits: flat-memory targets only (STM8, Z80/Z180/SM83/ez80 — MCS-51's paged spaces stay on the simulator); Step Over degrades to instruction stepping over RSP; register layout comes from the server's target.xml.
Project layout
my-project/
├─ sdcc-project.json # the project file (visual editor: ✎ in the tree)
├─ src/ # .c and .s/.S/.asm sources (recursively)
├─ include/ lib/ components/ # optional
└─ build/ # output: obj/**, firmware.ihx/.hex/.bin/.map/.mem/.cdb
Minimal sdcc-project.json:
{
"name": "blink",
"board": "generic-8051",
"sources": ["src"],
"build": { "output_dir": "build", "output_name": "firmware" }
}
Per-source flags: build.flags, build.src_flags, build.asm_flags. Hooks: pre_build, post_link, post_build, pre_upload, post_upload. Boards can live in the project (.sdcc/boards/), a shared folder (sdcc.boardsDir), or globally.
Variables
Hooks, upload tool/args and output_dir/output_name support 40+ variables: ${workspaceFolder}, ${project.name}, ${outputIhx}/${outputHex}/${outputBin}, ${board.mcu}/${board.target}/${board.fcpu}, ${config:any.setting}, ${env:NAME} — unresolved ones stay literal instead of silently emptying.
Coming from another IDE?
SDCC: Import Project from Other IDE… understands five formats now (0.29.0): PlatformIO (platformio.ini), Code::Blocks (.cbp), Eclipse CDT (.cproject), Keil µVision (.uvprojx) and Makefile (MCU/MMCU + -mmcu/-m<port> scan, TARGET, -I/-D, AVRDUDE_*) — it writes a draft sdcc-project.json in place (nothing moves) and opens the Project Editor with a summary:
- PlatformIO (
platformio.ini), Code::Blocks (.cbp), Eclipse CDT (.cproject)
- Keil µVision (
.uvprojx / .uvproj) — device → board mapping, include paths, defines, A51 assembly; ARM devices are refused with a clear message (SDCC has no ARM backend)
Settings
| Setting |
Default |
Description |
sdcc.path |
"" |
sdcc executable; empty = auto-detect |
sdcc.boardsDir |
"" |
extra board JSON folder (priority: project → this → global → built-in) |
sdcc.comPort |
"" |
serial port |
sdcc.shellPath |
"" |
Windows shell override (auto-detected otherwise) |
sdcc.reuseTerminal |
true |
reuse the SDCC terminal |
sdcc.saveSettingsToWorkspace |
true |
save port etc. to workspace settings |
sdcc.autoHexBin |
true |
also produce .hex/.bin after build |
sdcc.postBuildAction |
none |
flash = flash right after a successful build |
sdcc.buildMode |
release |
debug adds --debug + DEBUG |
sdcc.externalSdkPath |
"" |
external SDK folder (lib/*.lib, components/<sub>/); relative → resolved against the project root |
sdcc.debug.stopOnEntry |
true |
run to main() on F5 |
sdcc.debug.simPath |
"" |
explicit ucsim simulator executable |
sdcc.debug.clockFromBoard |
true |
feed the board's f_cpu to the simulator |
sdcc.debug.cpu |
"" |
override the simulator CPU model |
sdcc.debug.simUart |
auto |
simulated UART wiring: monitor / host / off / auto |
sdcc.debug.simUartPort |
"" |
PC COM port for host passthrough (e.g. COM3); the Simulator + host COM port variant falls back to sdcc.comPort when empty |
sdcc.autoGenerateTasks |
true |
merge the three SDCC-MDF tasks into .vscode/tasks.json when a project becomes active (add-if-missing, silent) |
sdcc.debug.syncLaunchJson |
true |
merge the debug records into launch.json automatically |
sdcc.intellisense.autoConfig |
true |
add the SDCC IntelliSense configuration when missing |
sdcc.monitorAutoOpen |
true |
open the Serial Monitor after a successful flash |
sdcc.monitorBaud |
115200 |
default Serial Monitor baud rate |
sdcc.monitorEol |
lf |
send-line terminator: lf / cr / crlf / none |
sdcc.monitorTimestamps |
false |
prefix received lines with a timestamp |
sdcc.memory.thresholdWarning |
85 |
area turns yellow at this % |
sdcc.memory.historyLimit |
50 |
builds kept in the History tab |
Supported shells: PowerShell, cmd, bash, sh, zsh, fish, dash, ksh, csh, tcsh, WSL — anything else gets a one-time actionable warning.
License
MIT © Dzantemir