CPW Part 15: Code Generation for Jump Instructions

Exercise

For unsigned integers support for conditional jumps ordered relations (See Session 5, Page 3):

  • Extend the enumerated constants as follows:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    // supported instruction
    enum GenOp
    {
        GEN_CONDJMP_BEGIN,
        GEN_EQUAL = GEN_CONDJMP_BEGIN,
        GEN_NOT_EQUAL,
        GEN_ABOVE,
        GEN_ABOVE_EQUAL,
        GEN_BELOW,
        GEN_BELOW_EQUAL,
        GEN_CONDJMP_END,
    
        // ...
    };
    
  • This is our current instruction set:

    RRR     (OP u 8) (X u 8) (Y u 8) (Z u 8)
    RSR     (OP u 8) (X u 8) (Y s 8) (Z u 8)
    J26     (OP u 8) (XYZ j 24)
    U16R    (OP u 8) (XY u 16) (Z u 8)
    J18R    (OP u 8) (XY j 16) (Z u 8)
    
    
    0x01    RRR
    :   halt    %X
        ulm_halt(ulm_regVal(X));
    
    0x02    RRR
    :   getc    %X
        ulm_setReg(ulm_readChar() & 0xFF, X);
    
    0x03    RRR
    :   putc    %X
        ulm_printChar(ulm_regVal(X) & 0xFF);
    
    0x04    J26
    :   jmp XYZ
        ulm_unconditionalRelJump(XYZ);
    
    0x05    RRR
    :   subq    X, %Y, %Z
        ulm_sub64(X, ulm_regVal(Y), Z);
    
    0x06    J26
    :   jnz XYZ
    :   jne XYZ
        ulm_conditionalRelJump(ulm_statusReg[ULM_ZF] == 0, XYZ);
    
    0x07    J26
    :   jz  XYZ
    :   je  XYZ
        ulm_conditionalRelJump(ulm_statusReg[ULM_ZF] == 1, XYZ);
    
    0x08    U16R
    :   ldzwq   XY, %Z
        ulm_setReg(XY, Z);
    
    0x09    RSR
    :   movzbq Y(%X), %Z
    :   movzbq (%X), %Z
        ulm_fetch64(Y, X, 0, 0, ULM_ZERO_EXT, 1, Z);
    
    0x0A    RRR
    :   addq    X, %Y, %Z
        ulm_add64(X, ulm_regVal(Y), Z);
    
    0x0B    RRR
    :   imulq   %X, %Y, %Z
        ulm_mul64(ulm_regVal(X), ulm_regVal(Y), Z);
    
    0x0C    J26
    :   ja      XYZ
        ulm_conditionalRelJump(ulm_statusReg[ULM_ZF] == 0
                            && ulm_statusReg[ULM_CF] == 0, XYZ);
    
    0x0D    J26
    :   jb      XYZ
        ulm_conditionalRelJump(ulm_statusReg[ULM_CF] == 1, XYZ);
    
    0x0E    RRR
    :   addq    %X, %Y, %Z
    :   movq    %X, %Z
        ulm_add64(ulm_regVal(X), ulm_regVal(Y), Z);
    
    0x0F    RRR
    :   imulq   X, %Y, %Z
        ulm_mul64(X, ulm_regVal(Y), Z);
    
    0x10    RRR
    #   Uses the 128-bit unsigned integer divider. The 64-bits stored in %Y are
    #   therefore zero extended with %0 to 128 bits and then used as numerator.
    #   The immediate value X is used as unsigned denominator.
    #
    #   The result of the operation is the quotient and the remainder. These results
    #   will be stored in a register pair: The quotient is stored in %Z and the
    #   remainder in %{Z + 1}.
    :   divq    X, %Y, %Z
        ulm_div128(X, ulm_regVal(Y), ulm_regVal(0), Z, 0, Z + 1);
    
    0x11    RSR
    #   The least significant byte in %X gets stored at address %Z.
    :   movb    %X, Y(%Z)
    :   movb    %X, (%Z)
        ulm_store64(Y, Z, 0, 0, 1, X);
    
    0x12    RSR
    #   Fetches a quad word from address %X into register %Z
    :   movq    Y(%X), %Z
    :   movq    (%X), %Z
        ulm_fetch64(Y, X, 0, 0, ULM_ZERO_EXT, 8, Z);
    
    0x13    RRR
    :   putc    X
        ulm_printChar(X & 0xFF);
    
    #   void ulm_absJump(uint64_t destAddr, ulm_Reg ret);
    0x14    RRR
    :   jmp     %X,     %Y
    :   call    %X,     %Y
    :   ret     %X
        ulm_absJump(ulm_regVal(X), Y);
    
    0x15    U16R
    :   shldwq  XY, %Z
        ulm_setReg(ulm_regVal(Z) << 16 | XY, Z);
    
    0x16    J18R
    :   ldpa    XY, %Z
        ulm_setReg(ulm_ipVal() + XY, Z);
    
    0x17    RRR
    :   ldfp    Y(%X), %Z
    :   ldfp    (%X), %Z
        ulm_fetch64(Y * 8, X, 0, 0, ULM_ZERO_EXT, 8, Z);
    
    0x18    RRR
    :   subq    %X, %Y, %Z
        ulm_sub64(ulm_regVal(X), ulm_regVal(Y), Z);
    
    0x19    RSR
    :   movq    %X, Y(%Z)
    :   movq    %X, (%Z)
        ulm_store64(Y, Z, 0, 0, 8, X);
    
    0x1A    RRR
    #   Uses the 128-bit unsigned integer divider. The 64-bits stored in %Y are
    #   therefore zero extended with %0 to 128 bits and then used as numerator.
    #   The value %X is used as unsigned denominator.
    #
    #   The result of the operation is the quotient and the remainder. These results
    #   will be stored in a register pair: The quotient is stored in %Z and the
    #   remainder in %{Z + 1}.
    :   divq    %X, %Y, %Z
        ulm_div128(ulm_regVal(X), ulm_regVal(Y), ulm_regVal(0), Z, 0, Z + 1);
    
    # General meaning of the mnemonics
    
    @addq
    #   Integer addition.
    @getc
    #   Get character
    @divq
    #   64-bit unsigned integer division
    @halt
    #   Halt program
    @imulq
    #   64-bit unsigned and signed integer multiplication.
    @ja
    #   Jump if above (conditional jump).
    @jb
    #   Jump if below (conditional jump).
    @je
    #   Jump if equal (conditional jump).
    @jmp
    #   Jump (unconditional jump).
    @jne
    #   Jump if not equal (conditional jump).
    @jnz
    #   Jump if not zero (conditional jump).
    @jz
    #   Jump if zero (conditional jump).
    @ldzwq
    #   Load zero extended word to quad word register.
    @putc
    #   Put character
    @subq
    #   Integer subtraction.
    @movb
    #   Move a byte from a register to memory (store instruction).
    @movzbq
    #   Move zero extended byte to quad word register (fetch instruction).
    @movq
    #   Move quad word
    @shldwq
    #   Shift (destination register) and load word
    @ldpa
    #   Load Pool Address
    @ldfp
    #   Load from Pool
    

    Extend it for two conditional jump instructions jae (jump above equal) and jbe (jump below equal).

    Update

    In the original isa.txt the instruction divq where all operands are registers was missing.

  • Adapt the implementation of genCondJmp().

  • Extend the test for the code generation interface before you proceed.