
Countdown clock Arm Assembly DE1-SoC system
Assembly was a very challenging class for me. The code conversion side of the class was very thought-provoking and rewarding. To challenge myself at the end of the semester, I attempted and successfully completed this project that compiles major topics covered in the class: from stacks to using branching and iterative techniques.
For a DE1-SoC system, I wrote an ARM assembly code that down counts from a decimal number
to 0 by 1 while displaying the numbers on the HEX3-HEX0 7 segments and simultaneously on the VGA screen. The starting number is determined by the positions of SW3-SW0, SW3 being the 1000’s position, SW2 being the 100s position, SW1 for 10s, and SW0 for units. Once the SW3-SW0 position determines the starting number, they are used no more. The counting-down process pauses when SW8 is pressed (i.e., SW8 = 1) and resumes when SW8 is released (SW8 = 0).
On the screen with the background colored by the pixel color determined by the last four-
digits of my Howard ID, I displayed the numbers horizontally at (10, 20) location of the monitor.

.data
.equ switches, 0xFF200040 // Address for the switches
.equ segment_address, 0xFF200020 // Address for 7-segment display
.equ vga_pixel_mem, 0xc8000000 // Address for VGA pixel memory
.equ vga_char_mem, 0xc9000080 // Address for VGA character memory
// Lookup table for 7-segment encoding
my_lookup:
.word 0x3F3F3F3F, 0x3F3F3F06, 0x3F3F063F, 0x3F3F0606, 0x3F063F3F, 0x3F063F06, 0x3F06063F, 0x3F060606
.word 0x063F3F3F, 0x063F3F06, 0x063F063F, 0x063F0606, 0x06063F3F, 0x06063F06, 0x0606063F, 0x06060606
// 7-segment digit patterns for numbers 0-9
count:
.word 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7C, 0x07, 0x7F, 0x67
.text
.global _start
_start:
// Initialize registers to zero
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
mov r4, #0
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
mov r9, #0
mov r10, #0
push {r1, r2, r3, r4}
// Set initial values for VGA
LDR R1, =vga_pixel_mem
LDR R2, =0x3241 // Set pixel color from last 4 digits of ID: 3241
MOV R3, #0
MOV R4, #0
// Loop through the pixels to fill the VGA screen
y_part:
MOV R3, #0
x_part:
BL draw_pixel
ADD R3, R3, #1
CMP R3, #0x140
BNE x_part
ADD R4, R4, #1
CMP R4, #240
BNE y_part
B main
// Draw one pixel to the screen
draw_pixel:
PUSH {R5}
ADD R5, R3, LSL #1 // Calculate X offset
ADD R5, R4, LSL #10 // Calculate Y offset
STRH R2, [R1, R5] // Store pixel color
POP {R5}
BX LR
// Initialize keys based on switch values
main:
pop {r1, r2, r3, r4}
LDR r0, =switches // Load address of switch register
LDR R2, =segment_address // Load address of segment display
ldr r4, =my_lookup // Load lookup table for 7-segment encoding
// Get value from switches
LDR r1, [r0]
mov r3, r1
// Get the corresponding 7-segment pattern from the lookup table
ldr r5, [r4, r3, lsl #2]
mov r3, #1 // Counter for digits
mov r6, #0 // Running total for decimal conversion
// Loop through the digits for conversion
loop:
and r7, r5, #0xff000000
CMP R3, #1
BEQ extract_first_digit
mul r9, r10, r8
add r6, r6, r9
mov r9, #0
and r7, r5, #0x00ff0000
CMP R3, #2
BEQ extract_second_digit
mov r9, #0
and r7, r5, #0x0000ff00
CMP R3, #3
BEQ extract_third_digit
mov r9, #0
and r7, r5, #0x000000ff
CMP R3, #4
BEQ extract_fourth_digit
mov r9, #0
ldr r4, =count
b countdown_main
// Extracts least significant byte (LSB)
extract_fourth_digit:
ldr r8, =#1
cmp r7, #0x06
BEQ assign_one
B assign_zero
// Extracts third digit from the right
extract_third_digit:
ldr r8, =#10
cmp r7, #0x0600
BEQ assign_one
B assign_zero
// Extracts second digit from the left
extract_second_digit:
ldr r8, =#100
cmp r7, #0x060000
BEQ assign_one
B assign_zero
// Extracts most significant byte (MSB)
extract_first_digit:
ldr r8, =#1000
cmp r7, #0x06000000
BEQ assign_one
B assign_zero
// Assigns 0 for false
assign_zero:
mov r10, #0
ADD R3, R3, #1
b loop
// Assigns 1 for true
assign_one:
mov r10, #1
ADD R3, R3, #1
b loop
// Main countdown function
countdown_main:
ldr r7, [r0]
cmp r7, #0x200
bge pause // Pause if SW8 is pressed
cmp r6, #-1
beq stop // Stop if countdown reaches 0
mov r8, #0 // Counter for thousandth place
mov r10, #0 // Counter for hundredth place
mov r11, #0 // Counter for tenth place
mov r12, #0 // Counter for ones place
mov r3, r6
cmp r6, #1000
bge thousandth
cmp r6, #100
bge hundredth
cmp r6, #10
bge tenth
b ones
// Convert to thousandth place
thousandth:
cmp r3, #1000
blt hundredth
sub r3, r3, #1000
add r8, r8, #1
b thousandth
// Convert to hundredth place
hundredth:
cmp r3, #100
blt tenth
sub r3, r3, #100
add r10, r10, #1
b hundredth
// Convert to tenth place
tenth:
cmp r3, #10
blt ones
sub r3, r3, #10
add r11, r11, #1
b tenth
// Handle ones place conversion
ones:
mov r12, r3
push {r1, r3, r4, r5, r7, r9}
ldr r1, =vga_pixel_mem
ldr r4, =vga_char_mem
mov r7, #1
mov r9, #1
b redo
new_ones:
pop {r1, r3, r4, r5, r7, r9}
ldr r8, [r4, r8, lsl #2]
lsl r8, r8, #24
ldr r10, [r4, r10, lsl #2]
lsl r10, r10, #16
ldr r11, [r4, r11, lsl #2]
lsl r11, r11, #8
ldr r12, [r4, r12, lsl #2]
add r8, r8, r10
add r8, r8, r11
add r8, r8, r12
str r8, [r2]
sub r6, r6, #1
BL refresh_time
b countdown_main
// Pause function for when SW8 is pressed
pause:
ldr r7, [r0]
cmp r7, #0x200
blt countdown_main
bne pause
// Delay for display refresh
refresh_time:
push {r1}
LDR r1, =0x200000
keep:
SUBS r1, r1, #1
BNE keep
pop {r1}
BX LR
// Redo the decimal conversion and display
redo:
mov r3, #0x30
add r3, r3, r8
bl char_output
add r7, r7, #1
mov r3, #0x30
add r3, r3, r10
bl char_output
add r7, r7, #1
mov r3, #0x30
add r3, r3, r11
bl char_output
add r7, r7, #1
mov r3, #0x30
add r3, r3, r12
bl char_output
add r7, r7, #1
mov r3, #32
bl char_output
b new_ones
// Helper function to output character to the screen
char_output:
push {r5}
mov r5, #0
add r5, r9, lsl #7
add r5, r5, r7
strb r3, [r4, r5]
pop {r5}
bx lr
stop:
b stop
The program retrieves the value of the switches (e.g., from 0xFF200040) and processes it to
display on the 7-segment display. The switch value is indexed into my lookup table to get a
corresponding 7-segment pattern, which is then displayed on the segment display. The countdown
timer decrements a value stored in r6. This value controls the countdown, which is displayed on
the VGA screen. The code checks the value of r6 (the countdown value) and converts it to a four–
digit decimal number by breaking it down into thousands, hundreds, tens, and one’s places. It does
so by comparing the value against thresholds (1000, 100, 10) and subtracting the appropriate
amounts. My program then iterates through the digits of the countdown value. Each digit is
extracted by comparing the value against predefined thresholds. Each digit is then assigned to a
corresponding place. If the countdown reaches zero, the program jumps to the stop label ending
the program.