A silly little transpiler/assembler for SHENZHEN I/O, a rad programming game by Zachtronics.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



This is just a silly tool to make it easier to write assembly for the microprocessors in SHENZHEN I/O, an awesome programming game released recently by Zachtronics.

WARNING: The source contains mild spoilers! :) You have been warned!

Now features unnecessarily pretty graphviz output using the new --dotfile argument!


> .\run_shenasm.py -h
usage: run_shenasm.py [-h] [-o OUTPUT] [-c {MC6000,MC4000,MC4000X}] [-v]
                      [--dotfile DOTFILE]

simple assembler/compiler for making it easier to write SHENZHEN.IO programs

positional arguments:
  input                 the input file to ingest

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        the output file path
  -c {MC6000,MC4000,MC4000X}, --chip {MC6000,MC4000,MC4000X}
                        inform assembler of target chip for better diagnostics
  -v, --verbose         flag to cause more verbose output during execution
  --dotfile DOTFILE     write a graphviz compatible .dot file containing the
                        intermediate representation graph of the input

Example: Pulse Generator

# the pin we'll pulse the outputs on
alias output_pin p1

# the width of the pulses on period and off period
const on_duration 2
const off_duration 4

# the value we'll emit to the output pin during the on and off phases
const on_value 100
const off_value 0

# the actual code:
  mov on_value output_pin   # write the on value to the output pin
  slp on_duration           # sleep for the on duration
  mov off_value output_pin  # write the off value to the output pin
  slp off_duration          # sleep for the off duration
  # the microprocessors in the game automatically loop to the beginning
  # so this will run forever now

Which compiles to:

  mov 100 p1
  slp 2
  mov 0 p1
  slp 4

Assembly Syntax

The assembly used is almost entirely identical to that in SHENZHEN.IO, the only differences are:

Preprocessor Directives

There is currently only one supported directive:

  • !include "some/filepath/here.asm" - textually includes the specified file in-place

'Macro' Instructions

Mneumonic Argument 1 Argument 2 Explanation
alias name register allows you to use name in place of register elsewhere in the program
const name value allows you to use name instead of value elsewhere in the program

To do

  • Verify types of instruction arguments
  • Verify register references exist on selected chip
  • Warn about exceeding memory space limitations of selected chip
  • Generate intermediate representation (IR) graph of input program
    • Detect unused code (possibly not?)
    • Tidy up IR graph by merging consecutive conditional nodes
    • Maybe replace jump instructions with edges in IR graph?
    • Make assembler generate output FROM IR graph instead?
    • Add compiler flag to automatically remove unused code
  • Detect and remove redundant labels?
  • Basic optimisation (probably not?)
  • Detect unused aliases/constants?
  • Compress label names
  • Error on redefinitions of alias/const names
  • Add support for including other files textually (preprocessor style)
  • Improve error reporting to use source file and source line
  • Make errors accumulate and prevent output, rather than immediate abort?
  • Make constants evaluate simple expressions?