Close
0%
0%

Assembly Language for ECM-16/TTL homebrew CPU

Sub-project where the assembly language is described; the assembler program progress updates are posted here

Similar projects worth following
Assembly language for the cpu, is needed to write programs with something other than raw ones and zeros.
In this project, all mnemonics are listed, their usage described, as well as some additional things that make programming feasible for humans.

This is subproject of my ECM-16/TTL homebrew computer main project, where its assembly language is described.

Main part of the language is mnemonics, which directly translate to machine code instructions.

There are also aliases that are convenient substitutes for some instructions, or frequently used instruction sequences.

The directives are for assembler to be able to understand program origin and ending, data types and assignment.

The labels are useful for indicating addresses of specific instructions and variables, without the need to manually calculate them.


The assembler program is published on GitHub, there are releases for Ubuntu and Windows.

  • Instruction types by argument placement

    Pavel11/27/2022 at 13:54 0 comments

    There are 19 ways the arguments are placed into instruction word(s), among them one without any arguments.

    This systematization is for me to have a clearer picture for assembler development.

  • Register names

    Pavel11/24/2022 at 13:23 0 comments

    Among 19 programmer-visible registers there are two main groups of 8 each and 3 special registers scattered around the CPU:


    1) General Purpose Registers: 8 16-bit registers that are accessible to main ALU.

    These registers are named r0, r1, r2, r3, r4, r5, r6 and r7.


    2) Memory Pointer Registers: 8 16-bit registers combined in 4 pairs to hold 32-bit values. The registers are also accessible individually for data transfer. 

    Memory Pointer Pair (32-bit) names, they are used in Indirect Memory Access instructions, Load Immediate into Pointer instruction and Address Arithmetic instructions:

    PC -- Program Counter, updated each time new instruction is fetched

    SP -- Stack Pointer, provides address for storing current PC value when executing JSR instruction

    FP -- Frame Pointer, can be used as additional pointer to manage program stack

    BP -- Base Pointer, can be used as additional pointer, for example, to some data structure in memory, like object or array.

    Individual Memory Pointer register (16-bit) names:

    mp0, or PCH -- high word of PC pair

    mp1, or PCL -- low word of PC pair

    mp2, or SPH -- high word of SP pair

    mp3, or SPL -- low word of SP pair

    mp4, or FPH -- high word of FP pair

    mp5, or FPL -- low word of FP pair

    mp6, or BPH -- high word of BP pair

    mp7, or BPL -- low word of BP pair


    3) Status Register

    SR -- this register is only 4-bits, it contains flags indicating ALU operation output characteristics, such as if there is a carry generated, or oveflow, or the resulting value is negative or zero.

    It can have its value moved into or from one of GPR or MPR  with special MOV operation.


    4) Memory Data Buffer 

    MDB -- 16-bit register -- written to automatically whenever F2 state is active by the value of second word of 2-word instruction.

    It can also be written to or read from to GPR or MPR  manually with special MOV operation.


    5) Interrupt Vector Base

    IVB -- 16-bit register, used to provide the base address for an array of Interrupt Service Routines, is a high word of 32-bit address.

    Can also be written to or read from to GPR or MPR with special MOV operation. The write is used for initial setup of system. 

  • Labels

    Pavel11/24/2022 at 10:29 0 comments

    Labels are symbolic representations of particular addresses in memory that can have either instructions to jump to, or variables to be fetched or stored by some memory access instruction.

    In assembly program label is indicated by colon ':' at the end of the first word (contiguous sequence of non-whitespace characters) in the line.

    example_label:
        <some code>       

    Label can either precede the labeled instruction or variable, or be on the same line.


    During first pass of the assembler, all labels are added to look-up table, which is used on second pass to inline actual values for instruction arguments instead of their symbolic representations.

  • Directives

    Pavel11/24/2022 at 10:08 0 comments

    Following assembler directives are used:


    structural directives:

    these directives determine the context for code that comes after them

    .const  -- optional block containing list of labeled constants -- primarily these are absolute addresses of memory mapped I/O ports

    .text  -- indicates start of proper code block, containing instruction sequence

    .data -- indication of start of block containing static variables


    comment directive
    Anything starting with hash symbol (#) and ending with newline is considered a comment and is ignored.

    Example:
    
    # this whole line is comment
    
        LDi r0 0x01   #comment: this operation adds 1 to value in register r0


    assignment directive:

    =  -- used as assignment statement in constants block

    Example:
    
    .const       #start of constants block
    
       constant_value = 0x1234 


    size directives:

    these are used only in data segment
    .string -- byte-sized array, containing ascii symbols, the value assigned to it is in quotes. At the end of string there is at least one byte with zero value (0x00, C-like string)
    .word -- 16-bit numeric value
    .dword -- 32-bit numeric value
    .long -- 64-bit numeric value

    Example:
    
    var_1:  .word     0x1234        
    var_2:  .dword    0x1234678
    var_3:  .long     0x1234567890123456
    var_4:  .string   "example string, with \"quotes\" inside"

     All parts should be on the same string.

  • Aliases

    Pavel11/23/2022 at 06:31 0 comments

    Aliases are additional mnemonics for pseudo-instructions, which are substituted by assembler with proper instruction mnemonics right before translating to machine code.

    For now, this is a "TO DO" list, to be implemented in assembler.

    There are several groups of aliases:


    Prefixes:

    these are modifiers for MOV and LD/ST (LDr/STr) instructions that change the size of data transferred, this way it is easier to use/understand them.

    Here is translation to proper instruction:

    2W  = SETPR 0     -- Move, Load or Store 2 words into 2 adjacent registers (aligned to even, e.g. r0 and r1, or r6 and r7)

    4W = SETPR 1       -- Move, Load or Store 4 words into 4 adjacent registers (aligned by 4, e.g. to r4, r5, r6 and r7)

    8W = SETPR 2     -- Move, Load or Store 8 words into  8 adjacent registers (either all GPR or all MemPointer registers at once)

    16W = SETPR 3     -- Move, Load or Store 16 words into all 16 registers, first 8 words into GPR and last 8 words into MemPointers

    1B = SETPR 4        -- Load or Store 1 byte into 1 register

    2B = SETPR 5       -- Load or Store 2 bytes into 2 adjacent registers (aligned to even, e.g. r0 and r1, or r6 and r7)

    4B = SETPR 6       -- Load or Store 4 bytes into 4 adjacent registers (aligned by 4, e.g. to r4, r5, r6 and r7)

    8B = SETPR 7       -- Load or Store 8 bytes into 8 adjacent registers (either all GPR or all MemPointer registers at once)

    Byte loads and stores use least significant half of word/register. 

    Byte prefixes are used only for memory accesses, MOV instructions always transfer whole words (full register content)

    Examples of prefix uses:

    4W MOV r4 r0  -- copy registers in range r0..r3 into range r4..r7

    2W LD SPH BP -- load Stack Pointer pair (SPH and SPL) with value at address stored in Base Pointer pair.

    1B STob r0 SP -1 -- push one byte from register r0 to stack


    Multi-word ALU operations

    Provision for loading/storing and moving multiple words per instruction is complemented by extensions of ALU operations -- these just combinations of regular ALU ops that result in effective operations on data with widths bigger than 16 bit.

    Following instructions can have 2-word and 4-word versions:

    ADD, SUB, ADDC, SUBC, AND, ANDN, OR, ORN, XOR, XNOR, SHR, SHL, ASHR, ASHL, ROLC, RORC.

    The versions are distinguished by additional letter added at the end, 'd' for operations on 32-bit values (double-word), 'l' for operations on 64-bit values (long, or quad-word).

    Example:

    ADDl r0 r0 r4

    this is substituted with:

    ADD r3 r3 r7
    ADDC r2 r2 r6
    ADDC r1 r1 r5
    ADDC r0 r0 r4

     by the Assembler.

    Use of these instructions make registers appear longer, while their number drops accordingly: instead 8 16-bit registers, it looks like 4 32-bit or 2 64-bit registers.


    Jump to absolute address

    Regular jumps are PC-relative.

    This alias makes possible jumps to absolute address in ranges 0x0000_0000 -- 0x00FF_FFFF and 0xFF00_0000 -- 0xFFFF_FFFF.

    This is just an immediate load of 25-bit value into Memory Pointer Pair:

    JA address == LDim PC address


    Shorthand for PC-relative loads and stores

    This is for loading and storing to labeled locations (static variables).

    As labels (for variables) are mapped to addresses with respect to program origin, but the program itself may be loaded anywhere in memory, it is handy to provide pc-relative way to access them. This way, the offset is calculated by the assembler. Thus there is no need to have PC as part of instructions.

    Here are relevant aliases:

    LDo rX Label == LDo rX PC <Label - PC - 2>

    STo rX Label == STo rX PC <Label - PC - 2>

    The <Label - PC - 2> is calculated offset from current PC value to labeled value.


    Stack operations (push and pop)

    These are pre-defined loads and stores with update...

    Read more »

  • Mnemonics list

    Pavel11/11/2022 at 19:15 0 comments

    Here, mnemonics for all instructions are listed, with short descriptions:


    ALU instructions (link to machine code description):

    All ALU instructions perform operations only on General Purpose Registers

    All ALU instructions taking 2 bytes in memory.


    instructions updating one of the GPR by const value in range 0..255:

    01 - ADDi rA const      -- add const to value in register rA, save result to same register rA

    02 - SUBi rA const       -- subtract const from value in register rA, save result to same register rA 

    03 - XORi rA const       -- bitwise XOR const with value in register rA, save result to same register rA

    04 - XNORi rA const    -- bitwise XOR inverted const with value in register rA, save result to same register rA

    05 - ORi rA const         -- bitwise OR const with value in register rA, save result to same register rA

    06 - ORNi rA const       -- bitwise OR inverted const with value in register rA, save result to same register rA

    07 - ANDi rA const       -- bitwise AND const with value in register rA, save result to same register rA

    08 - ANDNi rA const    -- bitwise AND inverted const with value in register rA, save result to same register rA


    3-operand Arithmetic instructions

    09 - ADD rY rA rB     -- add value in register rB to value in register rA, and save it to register rY

    10 - SUB rY rA rB      -- subtract value in register rB from value in register rA, and save it to register rY

    11 - ADDC rY rA rB    -- add value in register rB to value in register rA, with carry, and save it to register rY

    12 - SUBC rY rA rB    -- subtract value in register rB to value in register rA, with borrow, and save it to register rY


    3-operand Logic instructions

    13 - XOR rY rA rB      -- bitwise XOR value in register rB with value in register rA, and save it to register rY

    14 - XORN rY rA rB    -- bitwise XOR inverted value in register rB with value in register rA, and save it to register rY

    15 - OR rY rA rB         -- bitwise OR value in register rB with value in register rA, and save it to register rY

    16 - ORN rY rA rB       -- bitwise OR inverted value in register rB with value in register rA, and save it to register rY

    17 - AND rY rA rB       -- bitwise AND value in register rB with value in register rA, and save it to register rY

    18 - ANDN rY rA rB   -- bitwise AND inverted value in register rB with value in register rA, and save it to register rY


    1-bit shift operations

    19 - SHL rA rB     -- shift value in register rB 1 bit left, save result to register rA

    20 - SHR rA rB     -- shift value in register rB 1 bit right, save result to register rA

    21 - ROLC rA rB   -- rotate value in register rB through carry 1 bit left, save result to register rA

    22 - RORC rA rB  -- rotate value in register rB  through carry 1 bit right, save result to register rA

    23 - ASHL rA rB   -- arithmetic shift left value in register rB , same as regular shift, save result to register rA

    24 - ASHR rA rB   -- arithmetic shift right value in register rB, while preserving msb, save result to register rA


    Rotations

    25 - ROTi rY rA 0xF  -- rotate value in register rA 0xF (0-16) bits left, save result to register rY

    26 - ROT rY rA rB    -- rotate value in register rA left by number of bits by value in register rB, save result to register rY


    Invert

    27 - INV rA rB   -- flip bits in value in register rB and store result into register rA


    Byte Sign...

    Read more »

View all 6 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates