Assembly Language

Figure 7.2: The assembly language program to count occurrences of a character.

In [8]:
;
; Program to count occurrences of a character in a File.
; Character to be input from the keyboard.
; Result to be displayed on the monitor.
; Program works only if no more than 9 occurrences are found.
;
;
; Initialization
;
        .ORIG   x3000
        AND     R2,R2,#0      ; R2 is counter, initialize to 0
        LD      R3,PTR        ; R3 is pointer to characters
        TRAP    x23           ; R0 gets character input
        LDR     R1,R3,#0      ; R1 gets the next character
;
; Test character for end of file
;
TEST    ADD     R4,R1,#-4     ; Test for EOT
        BRz     OUTPUT        ; If done, prepare the output
;
; Test character for match.  If a match, increment count.
;
        NOT     R1,R1
        ADD     R1,R1,R0      ; If match, R1 = xFFFF
        NOT     R1,R1         ; If match, R1 = x0000	
        BRnp    GETCHAR       ; If no match, do not increment
        ADD     R2,R2,#1
;
; Get next character from the file
;
GETCHAR ADD     R3,R3,#1      ; Increment the pointer
        LDR     R1,R3,#0      ; R1 gets the next character to test
        BRnzp   TEST            
;
; Output the count.
;
OUTPUT  LD      R0,ASCII      ; Load the ASCII template
        ADD     R0,R0,R2      ; Convert binary to ASCII
        OUT                   ; ASCII code in R0 is displayed
        
        ;; Show a linefeed number to advance line:
        AND     R0,R0, #0
        ADD     R0,R0, #10
        TRAP    x21           ; ASCII code in R0 is displayed
        TRAP    x25           ; Halt machine
;
; Storage for pointer and ASCII template
;
ASCII   .FILL   x0030
PTR:    .FILL   FILE
FILE    .STRINGZ "xxxxxxxxxxxxxxxxxxxxxxxxxxyz"
        .FILL   #4
        .END
Assembled! Use %dis or %dump to examine; use %exe to run.
In [9]:
%dis
============================================================
Memory disassembled:
============================================================
           x3000: x54A0  AND R2, R2, #0                            [line: 1]
           x3001: x2614  LD R3, PTR                                [line: 2]
           x3002: xF023  IN                                        [line: 3]
           x3003: x62C0  LDR R1, R3, 0                             [line: 4]
TEST:      x3004: x187C  ADD R4, R1, #-4                           [line: 8]
           x3005: x0408  BRz OUTPUT (or 8)                         [line: 9]
           x3006: x927F  NOT R1, R1                                [line: 13]
           x3007: x1240  ADD R1, R1, R0                            [line: 14]
           x3008: x927F  NOT R1, R1                                [line: 15]
           x3009: x0A01  BRnp GETCHAR (or 1)                       [line: 16]
           x300A: x14A1  ADD R2, R2, #1                            [line: 17]
GETCHAR:   x300B: x16E1  ADD R3, R3, #1                            [line: 21]
           x300C: x62C0  LDR R1, R3, 0                             [line: 22]
           x300D: x0FF6  BRnzp TEST                                [line: 23]
OUTPUT:    x300E: x2006  LD R0, ASCII                              [line: 27]
           x300F: x1002  ADD R0, R0, R2                            [line: 28]
           x3010: xF021  OUT                                       [line: 29]
           x3011: x5020  AND R0, R0, #0                            [line: 32]
           x3012: x102A  ADD R0, R0, #10                           [line: 33]
           x3013: xF021  OUT                                       [line: 34]
           x3014: xF025  HALT                                      [line: 35]
ASCII:     x3015: x0030  NOOP - (no BR to x3046) (or 48, '0')      [line: 39]
PTR:       x3016: x3017  ST R0, x302E                              [line: 40]
FILE:      x3017: x0078  NOOP - (no BR to x3090) (or 120, 'x')     [line: 41]
           x3018: x0078 - 120 (or 120, 'x')
           x3019: x0078 - 120 (or 120, 'x')
           x301A: x0078 - 120 (or 120, 'x')
           x301B: x0078 - 120 (or 120, 'x')
           x301C: x0078 - 120 (or 120, 'x')
           x301D: x0078 - 120 (or 120, 'x')
           x301E: x0078 - 120 (or 120, 'x')
           x301F: x0078 - 120 (or 120, 'x')
           x3020: x0078 - 120 (or 120, 'x')
           x3021: x0078 - 120 (or 120, 'x')
           x3022: x0078 - 120 (or 120, 'x')
           x3023: x0078 - 120 (or 120, 'x')
           x3024: x0078 - 120 (or 120, 'x')
           x3025: x0078 - 120 (or 120, 'x')
           x3026: x0078 - 120 (or 120, 'x')
           x3027: x0078 - 120 (or 120, 'x')
           x3028: x0078 - 120 (or 120, 'x')
           x3029: x0078 - 120 (or 120, 'x')
           x302A: x0078 - 120 (or 120, 'x')
           x302B: x0078 - 120 (or 120, 'x')
           x302C: x0078 - 120 (or 120, 'x')
           x302D: x0078 - 120 (or 120, 'x')
           x302E: x0078 - 120 (or 120, 'x')
           x302F: x0078 - 120 (or 120, 'x')
           x3030: x0078 - 120 (or 120, 'x')
           x3031: x0079 - 121 (or 121, 'y')
           x3032: x007A - 122 (or 122, 'z')
           x3033: x0000 - \0
           x3034: x0004  NOOP - (no BR to x3039) (or 4)            [line: 42]
In [11]:
%exe
Input a character> A
A
0
============================================================
Computation completed
============================================================
Instructions: 544
Cycles: 4012 (0.002006 milliseconds)

============================================================
Registers:
============================================================
PC: x048E
N: 0 Z: 0 P: 1 
R0: x000A R1: x0004 R2: x0000 R3: x3034 
R4: x0000 R5: x0000 R6: x0000 R7: x3015 

First pass: Symbol Table

Symbol Address
TEST x3004
GETCHAR x300B
OUTPUT x300E
ASCII x3015
PTR x3016
FILE x3017

Second pass: computing offsets

Consider:

        LD      R3,PTR        ; R3 is pointer to characters

PTR is x3016. We know that PC+ (x3002) plus offset should equal x3016, so we simply subtract: x3016 - x3002 to get x0014. Is this what the %dis shows?

x3001: x2614 - 0010 0110 0001 0100 - 0010 011 0 0001 0100
                                     LD   R3  x14
                                     LD   R3  #20

High-Level Programming Concepts

Declaration of Variables

High-level LC3
int a; // simple variable (uninitialized) a .BLKW 1 ; simple variable (or .FILL 0)
int b = 2014; // simple initialized variable b .FILL #2014 ; simple initialized variable
int c[10]; // array of 10 (uninitialized) c .BLKW 10 ; array of ten ints (initialized to 0)
int *d = &e; // address of e d .FILL e ; store address of e in variable d

Assignment of values

High-level LC3
b = a; LD R0, a ; load from memory to a register
ST R0, b ; store from register to memory
b = a + 1; LD R0, a ; load from memory to a register
ADD R0, R0, #1 ; increment value
ST R0, b ; store from register to memory

Assignment using pointers

High-level LC3
pa = &a; LEA R0, a ; get the address of the variable
ST R0, pa ; store it in the pointer variable
b = *pa; LDI R0, pa ; get the value at the address stored in pa
ST R0, b ; store it in b
*pa = b; LD R0, b ; load the value of b
STI R0, pa ; store it at the address stored in pa

Comparison: if

High-level LC3
if (a < b) { LD R0, a ; load a
LD R1, b ; load b
NOT R1, R1 ; begin 2's complement of b
ADD R1, R1, #1 ; R1 now has -b
ADD R0, R0, R1 ; R0 = a + (-b)
; condition code now set
BRzp SKIP ; if false, skip over code
// do something ; code to do something (the then clause)
} SKIP ; remainder of code after if

Comparison: if/else

High-level

uint a = 1;
uint b = 2;

if (a < b) {
  // do something
}
else {
  // do something else
}

LC-3

LD  R0, A       ; load a
     LD  R1, B       ; load b
     NOT R1, R1      ; begin 2's complement of b
     ADD R1, R1, #1  ; R1 now has -b
     ADD R0, R0, R1  ; R0 = a + (-b)
                     ; condition code now set
     BRzp ELSE       ; if false, skip over code
        ; do something 
     BR   END_ELSE   ; don't execute else code
ELSE:                ; code for else clause here
        ; do something else
END_ELSE:            ; remainder of code after else
     HALT
A: .FILL x01
B: .FILL x02

Designing Large Programs

In [12]:
.ORIG   x4000
             
             ;;JSR START
             ;;HALT
             
             LEA R0, START
             JSRR R0
             HALT 
             
START        ST      R7,SaveR7
             JSR     SaveReg
             ;; 
             ;; do lots of stuff that messes with all of the resgisters!!
             ;; 
             JSR     RestoreReg
             LD      R7,SaveR7
             RET                 ; JMP R7 terminates 

SaveR7       .FILL   x0000       ;; close to where it is used

SaveReg      ST      R1,SaveR1
             ST      R2,SaveR2
             ST      R3,SaveR3
             ST      R4,SaveR4
             ST      R5,SaveR5
             ST      R6,SaveR6
             RET
;
RestoreReg   LD      R1,SaveR1
             LD      R2,SaveR2
             LD      R3,SaveR3
             LD      R4,SaveR4
             LD      R5,SaveR5
             LD      R6,SaveR6
             RET
SaveR1       .FILL   x0000
SaveR2       .FILL   x0000
SaveR3       .FILL   x0000
SaveR4       .FILL   x0000
SaveR5       .FILL   x0000
SaveR6       .FILL   x0000
             .END
Assembled! Use %dis or %dump to examine; use %exe to run.
In [13]:
%exe
============================================================
Computation completed
============================================================
Instructions: 22
Cycles: 187 (0.000093 milliseconds)

============================================================
Registers:
============================================================
PC: x048E
N: 0 Z: 0 P: 1 
R0: x4003 R1: x0000 R2: x0000 R3: x0000 
R4: x0000 R5: x0000 R6: x0000 R7: x4003