Section 9.6
Arrays

Methods of addressing elements of an array were discussed in the chapter 8 in the context of STS and LDS. The next CSC-1 program gives a complete example of a program that has an integer array, and which accesses the elements of this array. The program merely sums up all the elements of the array, stopping at the first negative element.

   0:  LOOP:    LDI   1000    ; Get Array[I] (base address)
   1:           ADD   I       ; Add I to base address
   2:           A2S           ; Copy this address to S reg
   3:           LDS           ; Load accum. from this address
   4:           JN    ENDLOOP ; If negative, then done
   5:           ADD   SUM     ; Else add to sum
   6:           STD   SUM
   7:           LOD   I       ; I := I + 1
   8:           ADD   ONE
   9:           STD   I
  10:           JMP   LOOP    ; Go back to top of loop
  11:  ENDLOOP: HLT           ; Halt when done with loop
  12:
  13:  SUM:     NUM   0       ; The sum of the array elements
  14:  I:       NUM   0       ; The counter used as array index
  15:  ONE:     NUM   1       ; Constant value 1
  16:
  16:  =1000       ; This tells the assembler to put these
                   ; next values into memory starting at loc. 1000
1000:  ARRAY:   NUM   47      ; The actual array of values
1001:           NUM   82
1002:           NUM   3
1003:           NUM   26
1004:           NUM   -1      ; A sentinel value, end of array

The style of loops and ifs in this program is not as clear as in the gcd program, so it is not the best program to emulate. The important part to focus on is the accessing of ARRAY[I], which takes place in lines 1 through 4. These lines calculate the address of ARRAY[I] and fetch the integer value at that address, leaving it in the accumulator.

Indirect addressing is an important component of computer programming. Arrays and structures hide it, while pointers make it explicit to the high level language programmer. However, at the machine level, some indirect addressing is going on most of the time. We call it indirect because the address of the word of memory we are trying to fetch or store is not directly given in the machine instruction, but instead is somewhere else, usually in another register.

The CSC-1 has a special register called S (Secondary) which it uses for all indirect loads and stores. The assembly programmer calculates the desired address by using the arithmetic instructions and the A register. Then this value is moved into the S register where it is used by LDS or STS. A secondary register must be used because these load and store instructions, just like their direct counterparts, use the A register to store the actual value to be read or written.

In line 1 the address of the first element of ARRAY, 1000, is put into the A register. Then I is added to it to get the actual address, which is then moved to S by A2S. Then LDS happens, which puts into A the desired element of ARRAY. 1000 is called the base address and the value of I is the offset.

Many machines are byte addressable, so they store one complete integer or one complete float in a 4-byte chunk of memory in order to get enough bits to have a large enough value. In these cases, they multiply the offset by 4 to get the address of the beginning of the correct chunk of memory. Having wide words like the CSC-1 does makes addressing simpler, but tends to waste memory, especially when characters are involved. Since the CSC-1 has 16 bits per word, it could store two ASCII characters in a single word, called packing. If it didn't, then it would be wasting half its memory when it stored character strings. If it did pack two characters per word, then more complex instructions would be needed to unpack and use them. So most machines divide memory into rather small physical words, usually 8-bit bytes.

The following code shows how to add 1 to each element of Array[I]. Notice that the STS instruction is used to change memory when the address is in the S register. The value in S is used twice in the following example: once to get the original value of Array[I] and the second time to tell the computer where it store it back. No operand is used for STS since the address to store is in S and the value to store is in ACC.

LOOP:    LDI   1000    ; Get Array[I] (base address)
         ADD   I       ; Add I to base address
         A2S           ; Copy this address to S reg
         LDS           ; Load accum. from this address
         JN    ENDLOOP ; If negative, then done
         ADD   ONE     ; Add 1 to this value
         STS           ; and store back into Array[I]
         LOD   I       ; I := I + 1
         ADD   ONE
         STD   I
         JMP   LOOP    ; Go back to top of loop
ENDLOOP: HLT           ; Halt when done with loop
  ...
ONE:     NUM   1       ; Constant value 1

If the address of Array[I] were not already in the S register, it would have to be calculated and moved from A to S before issuing the STS instruction. This would be the case if the program were storing initial values in the array, for example.