TINY11ELF Development

We provide brief notes on ARM assembly language and a sample program in the section on Assemblers. Here we describe changes to TINY11E to make it output ARM assembly language instead of Intel syntax. The code of the resulting TINY11ELF is on the next page. The changes are summarised in the following list.

  • Clearly, you should inspect the arguments supplied in the many calls to the EmitLn procedure to see the changed assembler code.
  • Procedures ReadIt and WriteIt call different routines.
  • Procedure PopDiv calls the same routine (__divsi3) that the GCC compiler uses for integer division.
  • The header, prolog and epilog for the GNU ARM assembler are very different from those needed by MASM.
  • A leading @ was required in each label for in-line assembler in Delphi. This cannot be used in TINY11ELF; everything on a line after a @ is a comment.

We show below the source code of one of the TINY programs we used to test TINY11ELF.

PROGRAM
VAR 
  COUNT, Num1, Num2, GT, GE, Quotient, Modulus, SQDIFF1, SQDIFF2, SAME
BEGIN
  WHILE COUNT < 5
    READ(Num1)
    READ(Num2)
    IF NUM2 > NUM1
      GT = -1
    ELSE
      GT = 0
    ENDIF
    WRITE(GT)
    IF NUM2 >= NUM1
      GE = -1
    ELSE
      GE = 0
    ENDIF
    WRITE(GE)
    Quotient = Num1 / Num2
    Modulus = Num1 - (Quotient * Num2)
    WRITE(QUOTIENT)
    WRITE(Modulus)
    SQDIFF1 = (Num1 + Num2) * (Num1 - Num2)
    WRITE(SQDIFF1)
    SQDIFF2 = Num1 * Num1 - Num2 * Num2
    WRITE(SQDIFF2)
    if SQDIFF1 = SQDIFF2
      SAME = -1
    ELSE
      SAME = 0
    ENDIF
    WRITE(SAME)
    COUNT = COUNT + 1
  ENDWHILE
END.
The code written to the file temp.s was:
scan_format:
.asciz "%d"
print_format:
.asciz "%d\n"
.align 2
T:
.word -1
F:
.word 0
COUNT:
.word 0
NUM1:
.word 0
NUM2:
.word 0
GT:
.word 0
GE:
.word 0
QUOTIENT:
.word 0
MODULUS:
.word 0
SQDIFF1:
.word 0
SQDIFF2:
.word 0
SAME:
.word 0
.text
.global	main
.type	main, %function
main:
push  {ip, lr}
L0:
ldr r0, COUNT
push {r0}
ldr r0, =5
pop {r12}
cmp r12, r0
ldrlt r0, T
ldrge r0, F
ldr r1, =-1
tst r0, r1
beq L1
L2:
.asciz "Enter NUM1"
.align 2
ldr r0, =L2
bl puts
ldr r0, =scan_format
ldr r1, =NUM1
bl scanf
L3:
.asciz "Enter NUM2"
.align 2
ldr r0, =L3
bl puts
ldr r0, =scan_format
ldr r1, =NUM2
bl scanf
ldr r0, NUM2
push {r0}
ldr r0, NUM1
pop {r12}
cmp r12, r0
ldrgt r0, T
ldrle r0, F
ldr r1, =-1
tst r0, r1
beq L4
eor r0, r0, r0
push {r0}
ldr r0, =1
pop {r12}
sub r0, r12, r0
adr r12, GT
str r0, [r12]
b L5
L4:
ldr r0, =0
adr r12, GT
str r0, [r12]
L5:
ldr r0, GT
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, NUM2
push {r0}
ldr r0, NUM1
pop {r12}
cmp r12, r0
ldrge r0, T
ldrlt r0, F
ldr r1, =-1
tst r0, r1
beq L6
eor r0, r0, r0
push {r0}
ldr r0, =1
pop {r12}
sub r0, r12, r0
adr r12, GE
str r0, [r12]
b L7
L6:
ldr r0, =0
adr r12, GE
str r0, [r12]
L7:
ldr r0, GE
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, NUM1
push {r0}
ldr r0, NUM2
mov r1, r0
pop {r0}
bl	__divsi3
adr r12, QUOTIENT
str r0, [r12]
ldr r0, NUM1
push {r0}
ldr r0, QUOTIENT
push {r0}
ldr r0, NUM2
pop {r12}
mul r0, r12, r0
pop {r12}
sub r0, r12, r0
adr r12, MODULUS
str r0, [r12]
ldr r0, QUOTIENT
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, MODULUS
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, NUM1
push {r0}
ldr r0, NUM2
pop {r12}
add r0, r0, r12
push {r0}
ldr r0, NUM1
push {r0}
ldr r0, NUM2
pop {r12}
sub r0, r12, r0
pop {r12}
mul r0, r12, r0
adr r12, SQDIFF1
str r0, [r12]
ldr r0, SQDIFF1
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, NUM1
push {r0}
ldr r0, NUM1
pop {r12}
mul r0, r12, r0
push {r0}
ldr r0, NUM2
push {r0}
ldr r0, NUM2
pop {r12}
mul r0, r12, r0
pop {r12}
sub r0, r12, r0
adr r12, SQDIFF2
str r0, [r12]
ldr r0, SQDIFF2
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, SQDIFF1
push {r0}
ldr r0, SQDIFF2
pop {r12}
cmp r12, r0
ldreq r0, T
ldrne r0, F
ldr r1, =-1
tst r0, r1
beq L12
eor r0, r0, r0
push {r0}
ldr r0, =1
pop {r12}
sub r0, r12, r0
adr r12, SAME
str r0, [r12]
b L13
L12:
ldr r0, =0
adr r12, SAME
str r0, [r12]
L13:
ldr r0, SAME
mov r1, r0
ldr r0, =print_format
bl printf
ldr r0, COUNT
push {r0}
ldr r0, =1
pop {r12}
add r0, r0, r12
adr r12, COUNT
str r0, [r12]
b L0
L1:
pop {ip, pc}

See our notes on ARM assembly language to see how to assemble and run the code from the Cygwin prompt. We automated the compilation by putting these three lines of code into a text file named tiny.sh.

run TINY11ELF.exe
arm-elf-gcc -o temp.elf temp.s
arm-elf-run temp.elf

(The Cygwin command d2s tiny.sh converts line endings from dos format (#13, #10) to unix (#10)).

Run the batch file by typing bash tiny.sh at the Cygwin prompt.

We copied the ARM assembler-generating code in TINY11ELF to TINY14ELF, which has much greater functionality.

Programming - a skill for life!

by PPS in association with Jack Crenshaw