Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>SDCC-MDFNew to Visual Studio Code? Get it now.
SDCC-MDF

SDCC-MDF

Dzantemir

|
4 installs
| (0) | Free
Microcontroller Development Framework — build & flash SDCC projects for MCS-51 (8051), STM8, Z80 and MOS6502 from VS Code
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

SDCC-MDF

Microcontroller Development Framework for SDCC — build & flash MCS-51 (8051), STM8, Z80 and MOS6502 projects directly from VS Code.

version license SDCC VS Code platform changelog


Highlights

  • 🧩 Board Manager — add / edit / duplicate / delete MCU definitions; stored globally, available in every project
  • 📁 Project editor (Webview) — sdcc-project.json with visual UI, multi-root workspace support, validated on save
  • ⚙️ Build — per-source .c → build/obj/** (mirroring source tree, no collisions) → main() first → .ihx → .hex (packihx) → .bin (makebin)
  • ⚡ Flash — configurable upload tool with variable expansion (${outputHex}, ${config:comPort}, ${board.mcu}, ${board.target}, ${env:…}, …)
  • 🪝 Hooks — pre_build / post_link / post_build / pre_upload / post_upload with cwd and continue_on_error; a ${…} picker in the editor inserts any of the 40+ variables at the cursor (grouped, searchable, with tooltips)
  • 📚 Libraries + components — prebuilt *.lib (linked as-is) and source libraries (compiled → sdar -rc → linked) — ESP8266-IDF components/ pattern, manual §3.2.4/§3.2.5
  • 🔌 Serial port auto-detection — Windows SerialPort.GetPortNames, Linux/macOS /dev scan
  • 🛠 Toolchain picker — auto-detects PATH / SDCC_HOME / standard install dirs, with native folder picker; companion tools (makebin, packihx, sdar) found next to sdcc
  • 🐚 Windows shell pinning — auto-detects your shell (PowerShell / cmd / bash / WSL) and pins it to the terminal so quoting and exit-code markers always match — no more "Syntax error in filename"
  • ⚠️ Auto-warning for unrecognized shells (v0.11.2) — Nushell / elvish / xonsh users get a one-time actionable hint instead of a silent build hang

Verified against the official SDCC 4.4.1 Compiler User Guide — target flags (§3.3.1), memory models per port (§3.3.6–§3.3.12), compile/link flow (§3.2.3), packihx/makebin (§3.2.2, §2.9).

Requirements

  • SDCC 4.0+ (4.4.1 recommended) — sdcc on PATH, or set SDCC: Path in Settings, or run SDCC: Select Toolchain Path
  • A flash tool for your target: stm8flash (STM8 via ST-Link), stcgal (STC89 USB/serial bootloader), ezp/nmflash (MCS-51) — configured per-project via upload.tool and upload.args

Quick start

  1. Install SDCC, make sure sdcc is on PATH (or run SDCC: Select Toolchain Path).
  2. Run SDCC: Create New Project → enter name → pick a board → Create Project Here (native folder picker). The starter folders (src/, include/, lib/, components/) and src/main.c open automatically.
  3. SDCC: Build (Ctrl+Alt+B) → configure upload in sdcc-project.json → SDCC: Flash (Ctrl+Alt+F).

Installation

From the VS Code Marketplace

  1. Open Extensions (Ctrl+Shift+X / Cmd+Shift+X).
  2. Search for SDCC-MDF.
  3. Click Install.

From a .vsix (offline / pre-release)

  1. Get sdcc-mdf-0.11.2.vsix.
  2. Extensions → ⋯ → Install from VSIX… → pick the file. — or — code --install-extension sdcc-mdf-0.11.2.vsix

Features

Board Manager (SDCC: Manage Boards)

A page to add / edit / duplicate / delete MCU definitions: target (all SDCC ports), memory model (filtered per target), IRAM / XRAM / Code / Heap / Stack sizes, f_cpu, extra flags, upload max size. Boards are stored globally in ~/.sdcc-mdf/boards (update-safe — survives extension updates, uninstalls/reinstalls and profile switches; boards still living in the legacy globalStorage are rescued automatically on activation); a project can keep its own .sdcc/boards/ overrides that shadow globals for the same id.

Backup: the Export / Import buttons (SVG icons) in the Board Manager's Boards header toolbar (own row under the title; + New upsized as the primary action and a soft separator splits it from the backup pair) (or the commands SDCC: Export User Boards (backup) / SDCC: Import Boards from Backup…). Export copies the whole home boards folder into a timestamped folder anywhere you choose; Import merges .json board files from any folder back (existing files are only overwritten when the imported copy is strictly newer — an import can never roll back newer edits; the list refreshes right after, no reopen needed).

Single board: the 📤 Export button (first in the save bar, next to Open JSON / Duplicate / Delete / Save) writes the currently open board — exactly as shown in the form — to any .json file you pick. It never touches ~/.sdcc-mdf/boards: share one MCU config, keep a copy, or drop the file into another project's .sdcc/boards/. Works for built-in and unsaved boards too; an invalid form is reported, not exported.

Ships with: Generic 8051, STC89C52RC, Beken BK2461, STM8S103F3, STM8S105K4, Generic Z80.

Project management (ESP8266-IDF pattern)

sdcc-project.json-based projects with a visual editor (Webview), multi-root workspace support. The Board field is select-only: the ▾ button opens a native-<select>-style dropdown — it drops under the Board input, exactly as wide as the input, listing all known MCUs with the current one shown in bold; the height is resizable by dragging the bottom edge, the width stays locked to the field. Free text is not allowed, so a board id is always a valid existing definition (add missing MCUs via the Board Manager). Create New Project: enter name → pick board → Create Project Here — a native folder picker; you CREATE a new empty folder anywhere, it is added to the workspace and src/main.c opens automatically.

The extension never grabs a workspace folder on its own — the project picker always shows a QuickPick annotated with the detected state (✓ valid / ⚠ warnings / ✗ errors / not an SDCC project). The config file is validated (schema, path safety, board, sources, hooks): the tree shows live status, build/flash/clean are blocked on errors, and SDCC: Show Project Problems prints the full report. The active project survives VS Code restarts (subfolder projects included).

Build

Auto-saves unsaved editors, compiles each .c into build/obj/** (mirroring the source tree — no basename collisions), links main() first into build/<name>.ihx, then generates .hex via packihx and .bin via makebin (buffer sized from the ihx — works for STM8's 0x8000+ layout). Verified against SDCC 4.2.0 / 4.4.1.

On failure you do not scroll the terminal: the failing command is replayed hidden once, its stderr parsed, and the first diagnostic lines appear right in the failure notification — with a Go to Error button that opens the exact file:line when one is parseable (the ASCII subst alias path is translated back to the real project path first). Assembler (?ASxxxx-Error…) and linker (?ASlink-Error…) failures show their text without a jump target.

Extra flags: build.flags (compile + link) and build.src_flags (compile-only) — PlatformIO-style. sdcc.buildMode = debug adds --debug (SDCC emits .sym/.rst debug info — manual §3.8) and defines DEBUG (inherited by library components). Flip the mode with the Release / Debug status-bar item or the Release / Debug segmented control in the Project Editor's Build card — the two always stay in sync (switching either one updates the other immediately); no need to open Settings.

build.output_dir and build.output_name support the variable table too (with ${…} buttons in the Project Editor): "output_dir": "build/${config:buildMode}" keeps debug and release artifacts apart. Build, Flash, Clean and hooks all resolve the same expanded paths.

Hooks

pre_build, post_link, post_build, pre_upload, post_upload command hooks with optional cwd and continue_on_error, editable in the Project Editor (PlatformIO extra_scripts pre:/post: equivalent). Hook commands, args and cwd support the full variable table below.

In the Project Editor, every hook field, the upload tool / args, and output_dir / output_name have a ${…} button that opens a searchable, grouped variable picker — hover a variable for its description in the detail bar, click to insert it at the cursor. ${env:NAME} / ${config:SETTING} insert with the placeholder selected, so you just type over it. The picker opens to the LEFT of the button, like a flyout: its top-right corner sits at the button's top-left corner when it opens down (or its bottom-right corner at the button's bottom-left corner when it opens up), always with a small horizontal gap — never flush against the button and never glued to the window edges; when space is tight the list scrolls inside. It is resizable (drag the bottom-right corner; the size persists for the session). Both menus hide automatically when the editor window is resized or the page scrolls.

Variables

Hooks (command / args / cwd), the upload tool and args, and build.output_dir / build.output_name support 40+ variables. ${config:comPort} resolves sdcc.comPort; ${env:NAME} reads any environment variable; ${config:any.setting} reads any VS Code setting (short keys resolve in the sdcc.* namespace first). Unresolved ${env:…} / ${config:…} stay literal — you see them in the failing command instead of a silent empty string.

Group Variable Value
Project ${workspaceFolder} project root
${workspaceFolderBasename} project folder name
${project.name} name from sdcc-project.json
Outputs ${outputDir} build/ (resolved)
${outputObjDir} build/obj/
${outputName} firmware name, no extension
${outputIhx} · ${outputHex} · ${outputBin} build/firmware.ihx/.hex/.bin
${outputMap} · ${outputMem} linker .map / .mem report
${outputLst} .lst listing of the main() source
Board ${board.mcu} e.g. stm8s103f3
${board.target} SDCC target: mcs51 / stm8 / z80 / …
${board.name} · ${board.cpu} board display name / CPU
${board.fcpu} build.f_cpu from the board definition
${board.memoryModel} small / medium / large
${board.iramSize} · ${board.xramSize} · ${board.codeSize} memory sizes
${board.uploadMaxSize} · ${board.uploadMaxRamSize} upload limits
Toolchain ${toolchain.sdcc} · ${toolchain.dir} sdcc path / its folder
${toolchain.version} detected SDCC version
${toolchain.packihx} · ${toolchain.makebin} · ${toolchain.sdar} companion tools
Git ${git:hash} · ${git:branch} short hash / branch ('' outside a repo)
Date & time ${date} · ${time} · ${datetime} · ${unixtime} filename-safe (colons → -)
System ${pathSeparator} · ${userHome} \ vs / · home dir
Config ${config:comPort} · ${config:buildMode} sdcc.comPort / sdcc.buildMode
${config:any.setting} any VS Code setting (sdcc.* namespace first)
${env:NAME} any environment variable

Examples — version-stamped backup and multi-target flashing:

"build": { "hooks": { "post_build": [
  { "command": "cp", "args": ["${outputHex}", "release/${project.name}_${git:hash}_${date}.hex"] }
] } }
"upload": {
  "tool": "${board.target}.bat",
  "args": ["-p", "${config:comPort}", "-f", "${outputHex}"]
}

Libraries + components

A project has four separate top-level folders: src/, include/, lib/, components/.

kind what where config entry
Prebuilt a ready .lib linked as-is (§3.2.4) lib/ libraries: ["lib"] (folder → scanned for *.lib); add "vendor/foo.lib" for a single file
Source library a folder of .c → compiled → sdar -rc → linked (§3.2.5) components/<name>/ components: ["components"] (each subfolder is one library); add a JSON object for a lib elsewhere

The build is config-driven: a libraries[] / components[] entry that is a folder name is scanned; a .lib file path or JSON object is linked/compiled directly. No hardcoded scan — the entries ARE the scan list. Library include dirs are automatically visible to app code (#include "stm8s.h" just works).

External SDK folder (sdcc.externalSdkPath)

An optional shared root for vendor SDKs that live outside the project — scanned the same way: <externalSdkPath>/lib/*.lib (prebuilt) and <externalSdkPath>/components/<subfolder>/ (source). Also editable in the Project Editor (External SDK folder block).

Flash + serial ports

Configurable upload tool with variable expansion — the tool itself and every arg support the full variable table (${outputIhx}, ${outputBin}, ${outputHex}, ${config:comPort}, ${board.mcu}, ${board.target}, ${env:…}, …). Serial port auto-detection: Linux/macOS /dev scan (ttyUSB/ttyACM/ttyS/cu.usbserial/cu.usbmodem), Windows SerialPort.GetPortNames.

Toolchain selection

SDCC: Select Toolchain Path shows all auto-detected sdcc locations (PATH / SDCC_HOME / standard install dirs) and offers native browse dialogs for the executable or folder (validated: sdcc or bin/sdcc inside). Companion tools (makebin, packihx, sdar) are found next to sdcc.

IntelliSense (C/C++ extension)

SDCC: Configure IntelliSense (C/C++) generates/refreshes one configuration named SDCC in .vscode/c_cpp_properties.json: project include dirs, component include dirs, SDCC's own header roots (<sdcc>/include, <sdcc>/include/<cpu>, non-free tree) and the project + board defines — no more red squiggles for 8051.h / stm8s.h / your include/. Paths inside the project are written as ${workspaceFolder}/… (portable); a hand-written c_cpp_properties.json is never clobbered — only the SDCC entry is touched. New projects get it automatically on creation.

Status bar + tree view

Status bar (Build / Flash / Clean / toolchain / port / build mode) and a tree view with all commands. Colored sidebar icons (charts.* theme colors): Build — green, Flash — blue, Clean — red, boards — purple, libraries — blue, components — cyan, sources/hooks — orange, folders — yellow.

Busy indicator (v0.13.23, ESP8266-IDF-style): while Build / Clean / Flash runs, a spinning ⟳ SDCC: <command> item with a live elapsed timer ((3s) → (1m 05s)) appears leftmost in the status bar, warns with the theme's warning background, explains in its tooltip that all commands are locked until it finishes, and focuses the build terminal on click. When a command completes, its button flashes the result for 4 seconds — ✓ Build OK / ✗ Build Failed, ✓ Flash OK / ✗ Flash Failed, ✓ Clean OK / ✗ Clean Failed — before reverting to the idle label.

Project layout

my-sdcc-project/
  src/             ← application sources        (proj.sources  → "src")
  include/         ← application headers        (proj.includes  → "include")
  lib/             ← prebuilt *.lib             (proj.libraries → "lib")      — linked as-is (§3.2.4)
  components/      ← source libraries          (proj.components→ "components") — compiled → sdar → linked (§3.2.5)
  sdcc-project.json
  .vscode/

Every textarea in the Project Editor shows its default folder name by default (Sources → src, Includes → include, Libraries → lib, Components → components). The build is config-driven: libraries[] and components[] entries are folder names (scanned) or .lib paths / JSON objects (linked directly). No hardcoded scan — the entries ARE the scan list.

sdcc-project.json

{
  "name": "blink",
  "board": "generic-8051",
  "sources": ["src"],
  "includes": ["include"],
  "defines": ["F_CPU=16000000UL"],
  "libraries": ["lib"],
  "components": ["components"],
  "build": {
    "output_dir": "build",
    "output_name": "firmware",
    "hooks": {
      "post_build": [
        { "command": "echo", "args": ["done"], "continue_on_error": true }
      ]
    }
  },
  "upload": {
    "tool": "stm8flash",
    "args": ["-c", "stlinkv2", "-p", "stm8s103f3", "-w", "${outputHex}"]
  }
}

Source rules

  • a string — a folder (scanned recursively for *.c) or a single file
  • { "path": "src", "pattern": "**/*.c" }
  • { "path": "src", "files": ["main.c", "utils.c"] }
  • { "exclude": ["src/test/**"] }

Vendor SDK guide (e.g. ST StdPeriph for STM8)

Two ways to attach the SDK:

Option A — as a JSON object in components (when the SDK lives outside components/):

{
  "name": "stm8s-app",
  "board": "stm8s103f3",
  "sources": ["src"],
  "includes": ["include"],
  "defines": ["STM8S103", "USE_STDPERIPH_DRIVER"],
  "libraries": ["lib"],
  "components": [
    "components",
    {
      "name": "stm8s_stdperiph",
      "path": "vendor/STM8S_StdPeriph_Lib/Libraries/STM8S_StdPeriph_Driver",
      "pattern": "src/**/*.c",
      "includes": ["inc", "../CMSIS/STM8S"],
      "defines": ["STM8S103"]
    }
  ]
}

Option B — as a subfolder of components/: copy the SDK under components/stm8s_stdperiph/ so the default components entry scans it automatically. Make sure the layout is components/stm8s_stdperiph/*.c + components/stm8s_stdperiph/inc/ (the inc/ folder is auto-added).

What happens on build (manual §3.2.4/§3.2.5):

  1. every SDK source is compiled into build/obj/libs/stm8s_stdperiph/**.rel with the SDK's include dirs (inc, ../CMSIS/… — resolved relative to the SDK folder) and defines, using the same target/memory model as the app;
  2. sdar -rc build/stm8s_stdperiph.lib archives them;
  3. the app is linked with the library after its own objects.

Notes for the ST SDK specifically:

  • copy stm8s_conf.h from Utilities/STM8S_StdPeriph_Templates/ into your src/ and enable the peripherals you use;
  • USE_STDPERIPH_DRIVER + the device define (STM8S103) must be set (project defines — they propagate to library compilation);
  • the SDK headers are automatically available to your code (#include "stm8s.h" just works);
  • a prebuilt .lib can be linked without recompiling: drop it into lib/ or add "vendor/my.lib" to libraries.

Coming from PlatformIO?

platformio.ini sdcc-project.json
board = stm8s003f3 "board": "stm8s103f3" (Board Manager id)
board_build.f_cpu = 16000000ul board definition build.f_cpu (Board Manager) or defines: ["F_CPU=16000000UL"]
build_flags = --opt-code-size "build": { "flags": ["--opt-code-size"] } (compile + link)
build_src_flags = --opt-code-size "build": { "src_flags": ["--opt-code-size"] } (compile only)
upload_command = flash -c stlinkv2 -w $BUILD_DIR\\firmware.hex "upload": { "tool": "flash", "args": ["-c","stlinkv2","-w","${outputHex}"] }
extra_scripts = pre:use_stm8dce.py "build": { "hooks": { "pre_build": ["python use_stm8dce.py"] } }
extra_scripts = post_build.py "build": { "hooks": { "post_build": ["python post_build.py ${outputBin}"] } } (e.g. CRC)
build_src_filter = -<**/*.asm> sources exclude rules: {"exclude":["**/*.asm"]}

Settings

Setting Default Description
sdcc.path "" Path to sdcc executable; empty = auto-detect
sdcc.boardsDir "" Additional folder with board definition JSON files. Boards from it override built-in ones with the same id (priority: project .sdcc/boards/ → this folder → global boards dir → built-in boards/)
sdcc.comPort "" Serial port used by ${config:comPort}
sdcc.shellPath "" Windows terminal shell override. Leave empty to auto-detect: terminal.integrated.automationProfile.windows → terminal.integrated.defaultProfile.windows (recognizes "Command Prompt" / "PowerShell" / "pwsh" / "Git Bash" / "WSL") → powershell.exe. The detected shell is pinned to the terminal so quoting and exit-code markers always match — no more "Syntax error in filename"
sdcc.reuseTerminal true Reuse the SDCC terminal between runs
sdcc.saveSettingsToWorkspace true Save port etc. to workspace settings
sdcc.autoHexBin true Generate .hex/.bin after build when tools are available
sdcc.postBuildAction none flash = run flash automatically after a successful build
sdcc.buildMode release debug adds --debug to compile & link flags (SDCC emits .sym/.rst debug info — manual §3.8) and defines DEBUG (inherited by library components). Exposed as ${config:buildMode}
sdcc.externalSdkPath "" External SDK folder — scanned for lib/*.lib (prebuilt) and components/<subfolder>/ (source), in addition to the project's own lib/ and components/. Also editable in the Project Editor (External SDK folder block)

Shell support & auto-warning

The extension supports the shells it can actually drive with quoting and exit-code markers: PowerShell (5.1 and 7+), cmd.exe, bash, sh, zsh, fish, dash, ksh, csh, tcsh, WSL. On Linux/macOS the system $SHELL is used directly (no detection, no pinning — VS Code opens the terminal with whatever shell it would use anyway).

If the resolved shell is not one of these (e.g. Nushell, elvish, xonsh, ion), a one-time information message per session shows:

SDCC: Detected shell "nu.exe" is not officially supported. Build/flash commands may fail with quoting or exit-code markers. Set "sdcc.shellPath" to override.

with the buttons Configure shell (opens Settings filtered by sdcc.shellPath) and Ignore.

The warning fires at most once per VS Code session — getUserShell() is called many times per build via shellKind(), so without a latch the user would drown in popups. It is suppressed when sdcc.shellPath is set explicitly (you took control, no nudge).

The trade-off is intentional: supporting every shell on Earth is overkill, but a silent build failure (PowerShell syntax sent to a nushell terminal → no marker file → build hangs for 30 minutes) is worse than a one-time actionable hint.

Publishing

This extension ships as a ready-to-install .vsix. To publish your own build:

  1. Create a publisher ID at https://marketplace.visualstudio.com/manage and replace publisher in package.json with your own ID.
  2. Update repository / bugs / homepage URLs to point to your fork.
  3. Install the packaging CLI: npm i -g @vscode/vsce.
  4. Build the VSIX: vsce package (produces sdcc-mdf-0.11.2.vsix).
  5. Publish: vsce publish (needs a Personal Access Token from https://dev.azure.com — see the official guide).

License

MIT © Dzantemir

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft