A simple instruction set architecture (ISA) that operates within the game Turing Complete.
This repository contains its corresponding assembler.
Assembly implementation of the ArchP ISA
Usage: archp_asmc [OPTIONS] [SRC_FILE]
Arguments:
[SRC_FILE] File path to the source assembly file
Options:
--complete <COMPLETE> Print shell auto completions for the specified shell [possible values: bash, elvish, fish, powershell, zsh]
-o, --output <OUTPUT> The output file path [default: <stdout>]
--bin Output binary machine code instead of formatted hex
--disable-macro Disable the macro-instructions
-h, --help Print help
-V, --version Print version
- Comments start with
#or;and continue to the end of the line. - Definite constants using
constdirective:const NAME VALUE(only allowed at the beginning of the file). - Labels are defined by writing the label name followed by a colon (
:) at the beginning of a line. - Operands are separated by spaces or tabs (not
,). - Instructions and labels are case-insensitive.
- Only one instruction or label definition is allowed per line (label and instruction can be on the same line).
- See examples for more details.
Note
The schematic may not be the latest version; please check the commit list to locate the most up-to-date implementation.
Alternatively, you may just get a fixed version from the git tags.
See assets/schematics.
This section is intended for users. If you require detailed information on the encoding formats, please refer to isa.txt.
- 24 general-purpose registers:
r1tor24. - special registers:
r0: always contains 0, you can write to it but it has no effect.pc: program counter (read-only).io: the level input/output (only in level mode).kb: the keyboard input (only in sandbox mode, read-only).rng: the random number generator (read-only).tmp: used by the assembler for expanding macro-instructions.
In this section:
instr: the instruction name.cond: optional condition code (see Conditions).rd: the destination register.rs1: the first source register.rs2: the second source register.imm12: 12-bit signed immediate value, from-2048to2047.addr12: 12-bit unsigned absolute address in number of instructions.immX: will be specified in the instruction description.- numeric literal:
42,-7,0b010101,0xFE42, etc.
Note
The 'signed' and 'unsigned' are merely formal distinctions,
you can always use 0xFFFFFFFE (or 0xFFE in 12 bits) to represent -2.
Note
You can not write addr12 directly as a numeric literal, you must use a label.
Note
The macro features are enabled by default.
You can disable them using the --disable-macro option when invoking the assembler.
- instructions:
add,sub,mul,mulh,mulhu,mulhsu,div,modaddi,subi,muli,mulhi,mulhui,mulhsui,divi,modi
- format:
instr[.cond] rd rs1 rs2/imm12 - pseudo:
li rd imm12=>addi rd r0 imm12mv rd rs1=>addi rd rs1 0inc rd=>addi rd rd 1dec rd=>subi rd rd 1clr rd=>addi rd r0 0neg rd rs1=>sub rd r0 rs1
- macros:
- When using register series instructions, if the third operand is a numeric literal, it will be automatically replaced with an immediate series instruction.
- When using immediate series instructions, if the immediate is larger the 12-bit, it will be automatically expanded into multiple instructions to load the immediate into a temporary register first.
- e.g.
sub r1 r2 0x1234=>subi r1 r2 0x1234=>lui tmp 0x1; addi tmp tmp 0x234; sub r1 r2 tmp
- instructions:
and,or,xor,nand,nor,xnorandi,ori,xori,nandi,norixnori
- format:
instr[.cond] rd rs1 rs2/imm12 - pseudo:
not rd rs1=>xori rd rs1 -1
- macros: Same as Arithmetic instructions.
- instructions:
sll,srl,rol,ror,sra,slli,srli,roli,rori,srai - format:
instr[.cond] rd rs1 rs2/imm5, whereimm5is a 5-bit unsigned immediate value from0to31. - macros: Same as Arithmetic instructions.
- instructions:
cmp,cmpi - format:
instr[.cond] rs1 rs2/imm12 - macros: Same as Arithmetic instructions.
lw[.cond] rd rs1 imm12: load word from memory addressrs1 + imm12intord.lh[.cond] rd rs1 imm12: load half-word from memory addressrs1 + imm12into the lower 16 bits ofrd, sign-extended.lhu[.cond] rd rs1 imm12: load half-word from memory addressrs1 + imm12into the lower 16 bits ofrd, zero-extended.lb[.cond] rd rs1 imm12: load byte from memory addressrs1 + imm12into the lower 8 bits ofrd, sign-extended.lbu[.cond] rd rs1 imm12: load byte from memory addressrs1 + imm12into the lower 8 bits ofrd, zero-extended.sw[.cond] rs1 rs2 imm12: store word fromrs2into memory addressrs1 + imm12.sh[.cond] rs1 rs2 imm12: store the lower 16 bits ofrs2into memory addressrs1 + imm12.sb[.cond] rs1 rs2 imm12: store the lower 8 bits ofrs2into memory addressrs1 + imm12.- note:
- The unit of memory address is in bytes.
- macros:
- It allows you to use a RISC-V-style offset syntax.
- e.g.
lw rd rs1 4=>lw rd 4(rs1);sw rs1 rs2 -8=>sw rs2 -8(rs1)
Caution
Please ensure that the memory addresses accessed by load and store instructions are properly aligned:
lw,sw: 4-bytelh,lhu,sh: 2-bytelb,lbu,sb: 1-byte (no alignment needed) Unaligned memory accesses is an undefined behavior at the hardware level and may lead to unexpected results.
Note
If you are simulating the hardware stack using a stack pointer register (e.g. const sp r10),
remember to initialize it to point to the top of the stack memory region. (e.g. li sp 4096)
Example: fib.asm
lui rd imm20: load upper immediate valueimm20(20-bit unsigned) into the upper 20 bits ofrd, setting the lower 12 bits to 0.
- instructions:
beq,bne,blt,ble,bgt,bge - format:
instr[.cond] rs1 rs2 addr12 - pseudo:
b**z rs1 imm12=>b** rs1 r0 imm12(e.g.beqz,bnez,bltz, etc.)
- macros:
- If the
rs2operand is a numeric literal, it will be automatically expanded to use a temporary register. - A 32-bit immediate literal is also supported.
- e.g.
beq r1 0x1234 10=>lui tmp 0x1; addi tmp tmp 0x234; beq r1 tmp 10
- If the
push[.cond] rs1: push the value ofrs1onto the stack.pop[.cond] rd: pop the top value from the stack intord.
call[.cond] addr12: call a subroutine at the addressaddr12.callr[.cond] rs1: call a subroutine at the address contained inrs1(low 16-bit is valid).ret[.cond]: return from the current subroutine.- note:
- The return address is automatically managed by the hardware stack.
jal[.cond] rd addr12: jump to the addressaddr12and write the return address intord.jalr[.cond] rd rs1: jump to the address contained inrs1(low 16-bit is valid) and write the return address intord.- pseudo:
j addr12=>jal r0 addr12jr rs1=>jalr r0 rs1
- note:
- You may know how to use this instruction if you are familiar with the RISC-V architecture.
col imm24u: set the display color to the 24-bit unsigned immediate valueimm24u(format:0xRRGGBB).spx[.cond] rs1 rs2: set the(rs1, rs2)position to the color specified by the lastcolinstruction.seg[.cond] rs1: display the value ofrs1(as 8-bit unsigned) on a 7-segment display.segi[.cond] imm8u: display the 8-bit unsigned immediate valueimm8uon a 7-segment display.
You can compare two registers using the cmp instruction, or cmpi to compare a register with an immediate value.
The result of the comparison is stored internally and can be used by conditional instructions.
- none: always execute
eq: execute if last comparison was equalne: execute if last comparison was not equallt: execute if last comparison was less thange: execute if last comparison was greater than or equalgt: execute if last comparison was greater thanle: execute if last comparison was less than or equal

