Level 55: Sum of an Array

Open level →

Task

Goal: assemble and run the first full program: it reads an 8-word array from data memory and sums it. New instruction — lui (U-format): imm20 in bits [31:12], value = imm20 << 12; the array base 0x1000 is built as lui x10, 0x1. The array 3 1 4 1 5 9 2 6 is preloaded into DMEM by the platform (visible in the Execution block). Predict the cycle count and compare bitwise with the golden.

The first complete golden run: the program reads an array of eight 32-bit words from data memory and sums it. Everything needed is already built: lw from level 52, beq from level 53, the loop from level 54. The new instruction is just one — lui (the U-format): the 12-bit immediate of addi covers only −2048…2047, while the array base lives at 0x1000.

lui rd, imm20 puts 20 bits into the upper half of the register: lui x10, 0x1 gives x10 = 0x1 << 12 = 0x00001000 — exactly the DMEM base. The array 3 1 4 1 5 9 2 6 is preloaded into memory by the platform before the start (addresses 0x1000–0x101C, visible in the Execution block); there is no need to write it into the program.

The canonical array_sum program:

        lui  x10, 0x1       # 0:  x10 = 0x1000, the array base
        addi x11, x0, 0     # 4:  the sum
        addi x12, x0, 8     # 8:  the counter (top down, 8 elements)
loop:   beq  x12, x0, done  # 12
        addi x12, x12, -1   # 16
        slli x14, x12, 2    # 20: the byte offset (i-1)*4
        add  x14, x10, x14  # 24
        lw   x15, 0(x14)    # 28
        add  x11, x11, x15  # 32
        beq  x0, x0, loop   # 36: → 12
done:   .end                # 40

Level tasks:

  1. Pack the lui word in "Word from fields" (it appeared in the mnemonic list on level 55) and take apart the U-format: imm20 in bits [31:12], the low 12 bits are zeros.
  2. Assemble the program in the Assembler tab. The word address: the counter x12 decreases by 1 per iteration, the shift slli x14, x12, 2 multiplies it by 4 (the byte offset), and add adds the base.
  3. Run it cycle by cycle: the Execution block shows the memory window with the array (the highlight marks changed words; the program only reads, so the values stay in place).
  4. Predict the cycle count before running — the first "Check" will ask for it and compare it with the trace.

The level's negative scenario: replace the address step with 1 (lw x15, 1(x10)). The lw lands at 0x1001, which is not a multiple of 4. The reference core stops there with the error ERR_DATA_ADDRESS_MISALIGNED and freezes the state: the failing instruction does not execute, and no partial sum appears. This is not "a sum of word pieces" but an error with a freeze — compare the behavior with the trace, not with intuition.

Solution for self-check

First count the cycles on paper. The solution below is a set of checkpoints.

What you should get: array_sum yields x11 = 31 (3 + 1 + 4 + 1 + 5 + 9 + 2 + 6) in 60 cycles (3 setup + 8 iterations × 7 + 1); DMEM is unchanged, and lw at 0x1001 halts the machine with ERR_DATA_ADDRESS_MISALIGNED and a frozen state.

Step 1 — the U-format. lui has neither rs1 nor funct3: the word consists of imm20 [31:12], rd [11:7], and opcode 0110111. The register value = imm20 << 12, the low 12 bits are zeros. lui x10, 0x1 = 0x00001537, x10 = 0x00001000.

Step 2 — sign compensation in li. From level 55 on, the li rd, imm32 pseudo-instruction with a large constant expands to lui + addi. The addi immediate is signed: if bit 11 of the low part is 1, adding it "carries" a one into the upper half, so the assembler increases imm20 in advance: hi = (v + 0x800) >> 12. Check: li x10, 0x1000 — upper 0x1, lower 0, no compensation; li x10, 0x1FFF — upper 0x2, lower −1.

Step 3 — count cycles. The preparation is 3 instructions (lui + two addi). Each iteration: the beq guard, the addi step, slli, add, lw, add, and the jump-back beq — 7 instructions, 8 iterations. On the last iteration the counter is already 0, the beq guard is taken and leads to done. Total: 3 + 8 × 7 + 1 = 60 cycles. The .end halt (jal x0, 0) adds no cycle, and the PC freezes at 40.

Step 4 — compare the result. The sum 3+1+4+1+5+9+2+6 = 31 lands in x11. The DMEM is unchanged at the end (the program only reads). If you experiment with the step of 1, the trace will show an ERR_DATA_ADDRESS_MISALIGNED record at PC 28, and x11 will stay zero — the state is frozen, the sum is not "corrupted", it simply does not exist.

Check yourself

Why cannot the array base be written with a single addi?

The 12-bit signed immediate only covers −2048…2047. The base 0x1000 is built by lui — it puts imm20 into the top 20 register bits, and an addi fixes the low part if needed (the li pseudo-instruction does this on its own).