Skip to content

A simple instruction set architecture (ISA) that operates within the game Turing Complete.

License

Notifications You must be signed in to change notification settings

PFiS1737/ISA-ArchP

Repository files navigation

ArchP

A simple instruction set architecture (ISA) that operates within the game Turing Complete.

This repository contains its corresponding assembler.

Pictures

Mine Sweeper Snake Game

CLI Usage

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

Assembly Syntax

  • Comments start with # or ; and continue to the end of the line.
  • Definite constants using const directive: 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.

Schematics

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.

ISA

This section is intended for users. If you require detailed information on the encoding formats, please refer to isa.txt.

Registers

  • 24 general-purpose registers: r1 to r24.
  • 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.

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 -2048 to 2047.
  • 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.

Arithmetic

  • instructions:
    • add, sub, mul, mulh, mulhu, mulhsu, div, mod
    • addi, subi, muli, mulhi, mulhui, mulhsui, divi, modi
  • format: instr[.cond] rd rs1 rs2/imm12
  • pseudo:
    • li rd imm12 => addi rd r0 imm12
    • mv rd rs1 => addi rd rs1 0
    • inc rd => addi rd rd 1
    • dec rd => subi rd rd 1
    • clr rd => addi rd r0 0
    • neg 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

Logical

  • instructions:
    • and, or, xor, nand, nor, xnor
    • andi, ori, xori, nandi, nori xnori
  • format: instr[.cond] rd rs1 rs2/imm12
  • pseudo:
    • not rd rs1 => xori rd rs1 -1
  • macros: Same as Arithmetic instructions.

Shift and Rotate

  • instructions: sll, srl, rol, ror, sra, slli, srli, roli, rori, srai
  • format: instr[.cond] rd rs1 rs2/imm5, where imm5 is a 5-bit unsigned immediate value from 0 to 31.
  • macros: Same as Arithmetic instructions.

Comparison

  • instructions: cmp, cmpi
  • format: instr[.cond] rs1 rs2/imm12
  • macros: Same as Arithmetic instructions.

Load and Store

  • lw[.cond] rd rs1 imm12: load word from memory address rs1 + imm12 into rd.
  • lh[.cond] rd rs1 imm12: load half-word from memory address rs1 + imm12 into the lower 16 bits of rd, sign-extended.
  • lhu[.cond] rd rs1 imm12: load half-word from memory address rs1 + imm12 into the lower 16 bits of rd, zero-extended.
  • lb[.cond] rd rs1 imm12: load byte from memory address rs1 + imm12 into the lower 8 bits of rd, sign-extended.
  • lbu[.cond] rd rs1 imm12: load byte from memory address rs1 + imm12 into the lower 8 bits of rd, zero-extended.
  • sw[.cond] rs1 rs2 imm12: store word from rs2 into memory address rs1 + imm12.
  • sh[.cond] rs1 rs2 imm12: store the lower 16 bits of rs2 into memory address rs1 + imm12.
  • sb[.cond] rs1 rs2 imm12: store the lower 8 bits of rs2 into memory address rs1 + 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-byte
  • lh, lhu, sh: 2-byte
  • lb, 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

Load Upper

  • lui rd imm20: load upper immediate value imm20 (20-bit unsigned) into the upper 20 bits of rd, setting the lower 12 bits to 0.

Branching

  • 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 rs2 operand 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

Stack Operations

  • push[.cond] rs1: push the value of rs1 onto the stack.
  • pop[.cond] rd: pop the top value from the stack into rd.

Call and Return

  • call[.cond] addr12: call a subroutine at the address addr12.
  • callr[.cond] rs1: call a subroutine at the address contained in rs1 (low 16-bit is valid).
  • ret[.cond]: return from the current subroutine.
  • note:
    • The return address is automatically managed by the hardware stack.

Jump and Link

  • jal[.cond] rd addr12: jump to the address addr12 and write the return address into rd.
  • jalr[.cond] rd rs1: jump to the address contained in rs1 (low 16-bit is valid) and write the return address into rd.
  • pseudo:
    • j addr12 => jal r0 addr12
    • jr rs1 => jalr r0 rs1
  • note:
    • You may know how to use this instruction if you are familiar with the RISC-V architecture.

Display (only in sandbox mode)

  • col imm24u: set the display color to the 24-bit unsigned immediate value imm24u (format: 0xRRGGBB).
  • spx[.cond] rs1 rs2: set the (rs1, rs2) position to the color specified by the last col instruction.
  • seg[.cond] rs1: display the value of rs1 (as 8-bit unsigned) on a 7-segment display.
  • segi[.cond] imm8u: display the 8-bit unsigned immediate value imm8u on a 7-segment display.

Conditions

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 equal
  • ne: execute if last comparison was not equal
  • lt: execute if last comparison was less than
  • ge: execute if last comparison was greater than or equal
  • gt: execute if last comparison was greater than
  • le: execute if last comparison was less than or equal

References

About

A simple instruction set architecture (ISA) that operates within the game Turing Complete.

Resources

License

Stars

Watchers

Forks

Packages

No packages published