This repository adds an experimental MCS-251 target to the Small Device C
Compiler (SDCC) while preserving the mature MCS-51 target. The compiler target
names are mcs51 and mcs251, selected with -mmcs51 and -mmcs251.
The upstream documentation index remains in
doc/README.txt. MCS-251 target notes are collected under
doc/mcs251/, and the parallel Simplified Chinese
manual is under doc/zh-CN/. All documentation stays in
the original doc/ tree.
The exact MCS-251 instruction coverage, positive and negative tests, and
current compiler-selection limits are recorded in the
MCS-251 instruction-set support document.
Out-of-tree builds keep generated files out of the source checkout. MCS-51 is enabled by default; MCS-251 must be enabled explicitly.
On Debian or Ubuntu:
sudo apt-get update
sudo apt-get install build-essential bison flex gputils libboost-dev \
libreadline-dev texinfo zlib1g-devOn macOS:
xcode-select --install
brew install bison boost flex gputils gnu-sed readline texinfo
export PATH="$(brew --prefix bison)/bin:$(brew --prefix flex)/bin:$PATH"git clone https://github.com/zevorn/sdcc-c251.git
cd sdcc-c251
mkdir build
cd build
CFLAGS=-std=gnu17 ../configure \
--enable-mcs251-port \
--prefix="$PWD/install"
make -j4
make installOn macOS, also add Homebrew's Boost include directory:
CFLAGS=-std=gnu17 \
CPPFLAGS="-I$(brew --prefix boost)/include" \
../configure \
--enable-mcs251-port \
--prefix="$PWD/install"CFLAGS=-std=gnu17 selects the host compiler dialect. It is needed because
some inherited ASxxxx sources still use K&R function definitions rejected by
C23; it does not change the C dialect accepted by SDCC.
The default configuration also builds the other maintained SDCC targets. Use
../configure --help and the corresponding --disable-<target>-port options
for a smaller target-specific build.
Confirm that both compiler targets were built:
install/bin/sdcc --version
grep -E '^(mcs51|mcs251)$' ports.buildRun the MCS-251 instruction, compiler, code-generation and diagnostic checks, then compile the MCS-51 regression source through the shared code paths:
make -C sdas/as251 check
make -C src/mcs251 check
make -C support/valdiag test-mcs251
bin/sdcc -mmcs51 -I../device/include -S \
-o /tmp/mcs51-smoke.asm \
../src/mcs251/tests/mcs51-regression.cA complete MCS-251 library build produces four ABI-matched directories under
device/lib/build/:
mcs251-smallmcs251-small-stack-automcs251-largemcs251-large-stack-auto
MCS-251 uses the common SDCC C frontend, so its language syntax support is the
same as MCS-51. Strict ISO C17 source is accepted with --std=c17, and the
preprocessor defines __STDC_VERSION__ as 201710L. C17 is a defect-correction
revision of C11 rather than a new syntax revision. SDCC also provides ISO C
modes and SDCC extension modes. This downstream additionally accepts
--std=gnu11 and --std=gnu17; these modes select the corresponding ISO base
revision and enable only the GNU extensions implemented by the frontend. They
do not imply complete GCC compatibility. The default remains the SDCC-extended
C11 mode. Select another mode with, for example, --std=sdcc23 or
--std=c23.
Do not confuse the host-build setting CFLAGS=-std=gnu17 with the language
mode used for firmware. That CFLAGS value only tells GCC or Clang how to
compile SDCC itself. The firmware language mode is passed directly to sdcc,
for example sdcc -mmcs251 --std=gnu17 source.c.
The current GNU C compatibility boundary is:
sdcppis based on GNU CPP, but this does not make the C parser GCC-compatible.__typeof(type-or-expression)and__typeof__(type-or-expression)are accepted, although nontrivial expressions still have implementation limits.__builtin_types_compatible_p(type1, type2)is accepted in GNU11 and GNU17 modes and folds to an integer constant expression. It observes C type compatibility for qualifiers, arrays, function prototypes, structures and enumerations.__builtin_expect(expression, expected)is accepted in GNU11 and GNU17. Both integer arguments are converted tolongand evaluated once, and the result is the value ofexpression. A constant expectation supplies a 90/10 branch probability to the common optimizer; it does not change program semantics.__builtin_constant_p(expression)is accepted in GNU11 and GNU17 and folds to an integer constant expression. It conservatively reports whether the common frontend can prove the operand constant. The operand is analyzed but never evaluated; volatile accesses, assignments, increments and function calls produce zero.- The MCS-51 and MCS-251 targets provide the GNU
__builtin_clz*,__builtin_ctz*,__builtin_popcount*and__builtin_ffs*families in GNU11 and GNU17. Constant arguments fold in the frontend; dynamic arguments are evaluated once and use ABI-matched runtime helpers forint,longandlong long. As in GNU C,clzandctzhave undefined results for zero, whileffsreturns zero for zero. - The same targets provide
__builtin_bswap16,__builtin_bswap32and__builtin_bswap64with the GNUuint16_t,uint32_tanduint64_tsignatures. Constant arguments fold in the frontend; dynamic arguments are evaluated once and use width-matched runtime helpers. - The MCS-51 and MCS-251 targets provide the type-generic
__builtin_add_overflow,__builtin_sub_overflowand__builtin_mul_overflowoperations in GNU11 and GNU17. They perform the calculation with infinite precision, store the wrapped result in a writable standard integer object, and return_Boolto report whether the exact result fits. Each argument is evaluated once, and the runtime helper writes the result in the selected target's byte order. - The same targets also provide all 18 GNU typed add, subtract and multiply
overflow builtins for signed and unsigned
int,longandlong long. These are thesadd,uadd,ssub,usub,smulandumulfamilies, with thelandllsuffixes. The two operands are converted to the type named by the builtin before exact arithmetic; the result pointer must name that exact writable integer type. Arguments are evaluated once, and__has_builtinreports each supported spelling in GNU11 and GNU17. __has_builtin(name)reports the builtins accepted by the selected frontend mode. Unknown names produce zero.__builtin_offsetofand__builtin_unreachableare available in every mode; the GNU-only queries and MCS builtins above are reported only in GNU11 and GNU17.- Statement expressions
({ ... })are accepted in GNU11 and GNU17. The final expression statement supplies the value and type; an empty block or a block ending in another statement has typevoid. Declarations and side effects retain their normal block scope and source order. __auto_typeis accepted in GNU11 and GNU17. A declaration must contain one identifier declarator with an initializer. The initializer determines the object type and is evaluated once; the declared name enters scope only after its initializer.- The driver defines target data-model macros such as
__SIZEOF_INT__,__SIZEOF_POINTER__,__INT32_TYPE__,__INTPTR_TYPE__and the integer constant macros. Host preprocessor ABI and architecture macros are removed. MCS-51 reports little-endian layout; native MCS-251 reports big-endian layout. Both keep a 16-bitintand a three-byte generic pointer. MCS-51 retains a 16-bitsize_t; MCS-251 ABI revision 2 uses a 32-bitsize_tso object-size calculations cover its complete flat address space. __asm__("instruction")accepts a basic literal usingsdas251/ASxxxx instruction syntax. GCC extended-asm operands and constraints are not accepted.case low ... highis accepted with--std=sdcc2y; the default language mode rejects it.- A zero-length trailing array is accepted when it follows another structure member. Prefer a standard flexible array in portable code.
- Common
__attribute__((...))placements are parsed directly, but most attribute names are currently syntax-only. - Nested functions, labels as values and computed
gotoare not supported. - Keyword aliases including
__inline__,__signed__,__const__,__restrict__and__volatile__are accepted.__extension__remains unsupported.
The gcc_attr.h compatibility header only translates attribute syntax. The
frontend implements the C23 nodiscard, maybe_unused, deprecated and
fallthrough attributes; other translated GCC attribute names can be warned
about and ignored. In particular, this mechanism is not a promise that
packed, section, cleanup, vector_size or target-specific GCC
attributes have GCC semantics.
MCS-251 assembly output is ASxxxx syntax and is assembled by sdas251. There
is currently no GNU assembler (GAS) backend for this target. When porting GCC
code, isolate extensions behind __SDCC or __SDCC_mcs251, replace extended
inline assembly with SDCC/ASxxxx assembly, and use standard C or SDCC language
extensions for the remaining code.
The current compiler cannot build stock Zephyr. Zephyr 4.4 defaults to C17,
but its common headers and build pipeline also require GNU-compatible
attributes, builtins, statement expressions, __typeof__, section placement,
weak symbols and compiler barriers. The implemented GNU language modes remove
part of this frontend gap, including type-compatibility queries and statement
expressions, inferred object types, branch-expectation hints and
constant-expression, bit-counting, byte-swapping, generic overflow and typed
overflow queries; they are not by themselves Zephyr support.
There are two additional compatibility boundaries outside the C parser:
- The normal MCS-251 ABI has a 16-bit
int, a 32-bitsize_tand a 24-bit pointer. Zephyr requires a 32-bitint, and its ELF post-link tools treat pointers as either 32 or 64 bits. A Zephyr ABI must be separately selectable so the existing MCS-251 and MCS-51 ABIs do not change. sdas251andsdldcurrently produce ASxxxx.relobjects and Intel HEX images. Zephyr requires relocatable ELF objects, named sections, archives, relocations, symbol tables and a final ELF executable for its generated offsets and other post-link processing.
The compatibility target is the GNU C subset required by Zephyr 4.4, with C17
as the first acceptance baseline. Completion also requires an SDCC toolchain
definition and MCS-251 architecture, SoC and board ports in a Zephyr
downstream. The work is complete only when a Zephyr image is compiled, linked
and run on the MCS-251 QEMU target while the existing MCS-51 and MCS-251
regressions remain green. See the
Zephyr and GNU C compatibility assessment
for the detailed requirements and implementation gates.
QEMU is only the execution backend for firmware generated by SDCC. The test
cases, expected results and pass/fail decisions all come from this SDCC
repository. The runtime tests use the MCS-51 family system emulators maintained
in processmission/qemu. QEMU
provides qemu-system-mcs51 with the stc8g1k08a machine and
qemu-system-mcs251 with the stc32g144k246 machine.
Install the additional QEMU build dependencies on Debian or Ubuntu:
sudo apt-get install libglib2.0-dev libpixman-1-dev ninja-build \
pkg-config python3-venvClone and build the two emulators next to the SDCC checkout:
cd ../..
git clone --branch devel https://github.com/processmission/qemu.git
cd qemu
./configure \
--target-list=mcs51-softmmu,mcs251-softmmu \
--disable-docs \
--disable-werror
ninja -C build qemu-system-mcs51 qemu-system-mcs251Return to the SDCC build directory and run the minimal runtime checks:
cd ../sdcc-c251/build
QEMU_BUILD=../../qemu/build
make -C src/mcs251 check-uart-qemu \
QEMU_MCS251="$QEMU_BUILD/qemu-system-mcs251"
make -C src/mcs251 check-mcs51-qemu \
QEMU_MCS51="$QEMU_BUILD/qemu-system-mcs51"check-uart-qemu builds default and size-optimized MCS-251 firmware and checks
its UART echo protocol. check-mcs51-qemu runs an MCS-51 firmware image and
verifies that shared compiler paths still match the upstream SDCC 4.6.0
assembly and image digests. The broader check-qemu target remains available
for manual ABI, memory-model, official-example, peripheral and GDB-stub tests;
those hardware-oriented checks are not the primary compiler CI gate.
Run the general compiler regression suites as a broader check:
make -C support/regression -j4 \
test-mcs251 \
test-mcs251-stack-auto \
test-mcs251-large \
test-mcs251-large-stack-auto \
QEMU_MCS251="$QEMU_BUILD/qemu-system-mcs251"
make -C support/regression -j4 test-mcs51The four MCS-251 lanes execute in QEMU. The mature MCS-51 regression suite uses
ucSim for its full set of memory models; check-mcs51-qemu supplies the QEMU
runtime and binary-stability cross-check. The inherited generic regression
cases are useful while developing MCS-251, but they are not a CI gate until
their memory-placement expectations have been baselined for the 251 models.
For trace logging and GDB-stub procedures, see
doc/mcs251/debugging.md. When a runtime failure is
not explained by generated code or the ABI, check QEMU before changing the
shared MCS-51 implementation.
The SDCC MCS-51 family CI workflow runs for every pull request targeting
main and every push to main. It:
- builds an SDCC configuration containing MCS-51 and MCS-251;
- checks every recorded MCS-251 instruction form, opcode map, relocation and invalid operand case;
- runs MCS-251 compiler, code-generation and language diagnostics across all four memory/stack models;
- runs the full upstream MCS-51 regression set;
- builds pinned QEMU execution backends and runs only the MCS-251 UART smoke and MCS-51 binary-stability checks;
- uploads SDCC regression and diagnostic logs when a job fails.
The QEMU revision is recorded in
mcs51-family.yml so a QEMU update is an
explicit, reviewable CI change.
The independent SDCC Windows package workflow builds a relocatable 64-bit
Windows ZIP for every pull request and every push to main. The package
contains native Windows executables such as sdcc.exe, sdcpp.exe,
sdas8051.exe, sdas251.exe and sdld.exe, together with the MCS-51 and
MCS-251 headers and runtime libraries.
Open the
SDCC Windows package workflow,
select a successful run, and download the
sdcc-mcs251-windows-x64-<commit>.zip artifact. Extract it to any directory
and either add its bin directory to PATH or invoke bin\sdcc.exe directly.
No MSYS2 installation is required to use the downloaded compiler.
CI verifies the package from ordinary PowerShell, outside the MSYS2 build shell. It uses the packaged compiler, preprocessor, assemblers, linker, headers and libraries to produce both MCS-51 and MCS-251 Intel HEX images before the ZIP is published. Artifacts are retained for 30 days.
The Windows package is built with the 64-bit UCRT toolchain supplied by MSYS2. Install MSYS2, open an MSYS2 UCRT64 terminal, and install the same dependencies used by CI:
pacman -Syu
pacman -S --needed \
bison flex git make python texinfo \
mingw-w64-ucrt-x86_64-boost \
mingw-w64-ucrt-x86_64-toolchain \
mingw-w64-ucrt-x86_64-zlibIf pacman -Syu asks to close the terminal, close it, open a new UCRT64
terminal, run pacman -Syu again, and then install the dependencies. The
following commands must also run in the UCRT64 terminal, not in the plain
MSYS terminal or PowerShell:
git config --global core.autocrlf input
git clone https://github.com/zevorn/sdcc-c251.git
cd sdcc-c251
mkdir windows-build
cd windows-build
CFLAGS=-std=gnu17 LDFLAGS=-static ../configure \
--enable-mcs251-port \
--prefix=/sdcc \
--datarootdir=/sdcc \
'docdir=${datarootdir}/doc' \
include_dir_suffix=include \
non_free_include_dir_suffix=non-free/include \
lib_dir_suffix=lib \
non_free_lib_dir_suffix=non-free/lib \
'sdccconf_h_dir_separator=\\' \
--disable-z80-port \
--disable-z180-port \
--disable-r2k-port \
--disable-r2ka-port \
--disable-r3ka-port \
--disable-r4k-port \
--disable-r5k-port \
--disable-r6k-port \
--disable-sm83-port \
--disable-tlcs90-port \
--disable-ez80-port \
--disable-z80n-port \
--disable-r800-port \
--disable-ds390-port \
--disable-ds400-port \
--disable-pic14-port \
--disable-pic16-port \
--disable-hc08-port \
--disable-s08-port \
--disable-stm8-port \
--disable-pdk13-port \
--disable-pdk14-port \
--disable-pdk15-port \
--disable-mos6502-port \
--disable-mos65c02-port \
--disable-f8-port \
--disable-f8l-port \
--disable-ucsim \
--disable-sdcdb \
--disable-non-free
cd ..This configuration builds only the MCS-51 and MCS-251 compiler ports. It uses static host linking so that the installed executables do not require an MSYS2 runtime on the destination machine.
Build the compiler and native tools first. Before the device libraries are built, stage both parts of the native preprocessor in the compiler's build search directory:
make -C windows-build -j2 sdcc-base
install -m 755 windows-build/support/cpp/gcc/cpp.exe \
windows-build/bin/sdcpp.exe
install -m 755 windows-build/support/cpp/gcc/cc1.exe \
windows-build/bin/cc1.exe
make -C windows-build -j2Install into a staging directory and assemble the relocatable package tree:
make -C windows-build \
DESTDIR="$PWD/windows-build/windows-stage" install
mkdir -p windows-package/sdcc-mcs251
cp -a windows-build/windows-stage/sdcc/. \
windows-package/sdcc-mcs251/
cp README.md COPYING sdas/COPYING3 windows-package/sdcc-mcs251/Keep the complete sdcc-mcs251 directory: sdcc.exe locates the
preprocessor backend, headers and target libraries relative to its own
location. Copying only bin/sdcc.exe does not produce a working toolchain.
Open PowerShell in the repository root to verify the package outside MSYS2:
$sdcc = Resolve-Path ".\windows-package\sdcc-mcs251\bin\sdcc.exe"
& $sdcc --version
& $sdcc --print-search-dirs
"void main(void) { for (;;) {} }" |
Set-Content -Encoding ascii -Path .\windows-smoke.c
& $sdcc -mmcs51 --model-small `
-o .\windows-smoke-mcs51.ihx .\windows-smoke.c
& $sdcc -mmcs251 --model-small `
-o .\windows-smoke-mcs251.ihx .\windows-smoke.cFinally, create a distributable ZIP from PowerShell:
Compress-Archive -Path .\windows-package\sdcc-mcs251 `
-DestinationPath .\sdcc-mcs251-windows-x64.zipThe CI definition in
windows-package.yml is the
executable reference for this procedure. In addition to the two smoke
commands above, CI verifies all four MCS-251 memory/stack configurations
before publishing the ZIP.
The upstream English manual keeps its original LyX layout under doc/. Enable
it with --enable-doc during configuration and use the normal make target.
Build the Simplified Chinese PDF and HTML manually with:
make -C doc/zh-CN check allSee doc/zh-CN/README.md for the Pandoc, XeLaTeX and
CJK font dependencies.