Assembly Program for Printing an Unsigned Integer

Assignment: Quiz 10

Write a program printuint.s that prints the unsigned value stored in its data segment at label n. So a skeleton for this program is given by

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    .data
    .align 8
n   .quad 0x123456789ABCDEF

    .text

    /*
        Your code that prints the unsigned byte at label n

    */

On theon submit your instruction set isa.txt and program with the following command

1
submit hpc quiz10 isa.txt printuint.s

C as kind of Pseudo-Code

This C code basically reflects how an assembly implementation can be realized. It intensionally has some expressions that normally might not use in this form. C. However, in this way it provides some opportunity to you for reviewing a view things in C ;-)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
// for: int putchar(int);

unsigned long long n = 0x123456789ABCDEF;

char buf[20];

int
main()
{
    // local variables are used as registers (the compiler will actually use
    // registers here if you compiler with -O1)
    unsigned long long val;
    char digit;
    char *p;

    // fetch variable n into val
    val = n;

    // p point to begin of buf array
    p = buf;
    do {
        digit = val % 10 + '0';
        val /= 10;

        // store ASCII value of digit at *p then increment pointer
        *(p++) = digit;
    } while (val != 0);

    // print stored characters
    for (; p != buf; putchar(*--p)) {
    }

    // print extra newline (not needed for quiz)
    putchar('\n');
}

Test Run after Compiling with gcc

theon$ gcc -Wall -o printuint-gcc printuint.c
theon$ printuint-gcc
81985529216486895
theon$ 

Test Run after Compiling with ucc

theon$ ucc -o printuint-ucc printuint.c
theon$ printuint-ucc
81985529216486895
theon$ 

Provided Material

You can use this ULM Instruction Set for Quiz 11. Here its isa.txt source code:

RRR     (OP u 8) (X u 8) (Y u 8) (Z u 8)
J26     (OP u 8) (XYZ j 24)
U16R    (OP u 8) (XY u 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    RRR
:   movzbq (%X), %Z
    ulm_fetch64(0, 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
    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    RRR
#   The least significant byte in %X gets stored at address %Z.
:   movb    %X, (%Z)
    ulm_store64(0, Z, 0, 0, 1, X);

0x12    RRR
#   Fetches a quad word from address %X into register %Z
:   movq    (%X), %Z
    ulm_fetch64(0, X, 0, 0, ULM_ZERO_EXT, 8, Z);


# 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

Compared to the last session three instructions were added:

  • The instruction divq X, %Y, %Z computes the quotient and remainder of an unsigned integer division. Note that the two results are stored in the register pair %Z and %{Z + 1}:

    \[\begin{array}{lcl}\left\lfloor \frac{u(\%Y)}{u(X)} \right\rfloor & \to & u(\%Z)\\u(\%Y) \bmod u(X) & \to & u(\%\{Z + 1\})\\\end{array}\]
  • The instruction movb %X, (%Y) can be used to store the least significant byte in %X at address %Y:

    \[u(\%X) \bmod 2^8 \to u(M_1(a))\;\text{with}\;a = u(\%Y)\]
  • The instruction movq (%X), %Y can be used to fetch a quad word from address %X into register %Y:

    \[u(M_8(a)) \to u(\%Y)\;\text{with}\;a = u(\%X)\]