ECAD & Architecture Workshop Four

Introduction to the ARM tools


workshop home | workshops: 1 | 2 | 3 | 4 | 5 | 6

ARM Developer Suite

;;----------------------------------------------------------------------
;; ECAD+Arch Workshop 4
;; Your name
;; Your college
;; date
;;----------------------------------------------------------------------

        AREA text,CODE
	ENTRY
	;; This section is called "text", and contains code

	;;; Print "Hello world"

	;; Get the offset to the string in r4.
	;; The variable '.' contains the value of
	;; pc (r15) at the time of assembly.
	add	r4,pc,#(hello -8 -.)

loop				; This is a label
	;; Call putchar to display each character
	;; to illustrate how a loop works

	ldrb	r0,[r4],#1	; Get next byte, and post index r4
	cmp	r0,#0		; Stop when we hit a null
	beq	outputstring

	bl	putchar
	b	loop

outputstring
	;; Alternatively, use putsting to write out the
	;; whole string in one go
	add	r0,pc,#(hello -8 -.)
	bl	putstring

finish
	;; Standard exit code: SWI 0x18
	;; with argument 0x20026
	mov	r0,#0x18
	mov	r1,#0x20000
	add	r1,r1,#0x26
	SWI	0x123456

hello
        DCB     "Hello World\n",0
        END
;; I/O routines

	AREA text,CODE

	EXPORT printhex, putchar, putstring

printhex
	; Print number in r0 as 8 hex digits
	; Conforms to APCS
	stmfd	sp!,{r4,lr}

	add	r2,pc,#(hex_digits-8-.)
	add	r3,pc,#(print_hex_string-8-.)
	mov	r4,#28

printhex_loop
	;; For r4 = 28 to 0 step -4
	mov	r1,r0,lsr r4	; Get digit n
	and	r1,r1,#0x0f	; mask off lower nibble
	ldrb	r1,[r2,r1]	; r1 now contains a hex number, look it up in table
	strb	r1,[r3],#1
	subs	r4,r4,#4
	bpl	printhex_loop

	add	r0,pc,#(print_hex_string-8-.)
	bl	putstring

	ldmfd	sp!,{r4,pc}

hex_digits
	DCB	"0123456789ABCDEF"
print_hex_string
	DCB	"12345678",0	; storage for 8 digit hex string, null terminated
	ALIGN


putchar
	; Entry: Takes char in r0.
	; Conforms to APCS
	; Call SYS_WRITEC, with r1 containing a POINTER TO a character.

	; SYS_WRITEC = 3, SYS_WRITE0 = 4, SYS_READC = 7

	stmfd	sp!,{r4-r12,lr}

	add	r1,r15,#(putchar_temp -8 -.)
	strb	r0,[r1]
	mov	r0,#3
	swi	0x123456

	ldmfd	sp!,{r4-r12,pc}

putchar_temp
	DCB	0

	ALIGN

putstring
	; Entry: Takes pointer to a null terminated string in r0
	; Conforms to APCS
	; uses Call SYS_WRITE0

	stmfd	r13!,{r4-r12,lr}

	mov	r1,r0
	mov	r0,#4
	swi	0x123456

	ldmfd	r13!,{r4-r12,pc}

	END
	IMPORT	printhex
	IMPORT	putchar
	IMPORT	putstring

AXD (ARM Debugger for Windows and UNIX)

Start AXD with Project | Debug.

When AXD loads, it may ask you to choose a target. This refers to running the program on the ARM board, rather than in the emulator. As the link to the board is rather slow, we'll run the first half of this exercise in the emulator (select ARMUL).

Now, let's go back and look at the program's execution in more detail.

In summary, "step in" (F8) will do one instruction at a time; "step over" will do one instruction or subroutine at a time; and breakpoints halt the run whenever they are hit. They provide different granularities of control over debugging.

Now try it on the ARM board. To do this:

  1. Make sure the board is connected to your PC via a serial cable (not the Altera's parallel cable) and switched on.
  2. Select Options | Configure Target..., and click on ADP.
  3. Configure it like this:

Task

Write a program to produce a table of primes in hexadecimal. The table should be neatly printed on the console and should include an index number by each prime.

One method for determining if N is prime is to try dividing it by primes less that the sqrt(N). Alternatively you could use the Sieve of Erastothenes method. Note that the ARM does not have instructions that perform division and remainder operations. However, you can use the code from the Computer Design notes:

DivStart			; enter with numbers in r0 and r1
	mov	r2,#1		; bit to control the division
Div1	cmp	r1,#0x80000000	; shift r1 left until top bit set...
	cmpcc	r1,r0		; ...or r1>r0
	movcc	r1,r1,ASL#1	; shift r1 left if require
	movcc	r2,r2,ASL#1	; shift r2 left if r1 is shifted
	bcc	Div1		; repeat whilst more shifting required
	mov	r3,#0		; zero r3
Div2	cmp	r0,r1		; test for possible subtraction
	subcs	r0,r0,r1	; subtract if r0>r1
	addcs	r3,r3,r2	; put relevant bit into result
	movs	r2,r2,LSR#1	; shift control bit
	movne	r1,r1,LSR#1	; halve unless finished
	bne	Div2		; loop if there is more to do
				; divide result in r3
				; remainder in r0
	mov	r1,r3		; divide result (r0/r1) now in r1
	mov	r15,r14		; return from subroutine

To define a memory area to store your table of primes, add the following code to the end of your code (just before the END):

	ALIGN			; ensure allocated memory is word aligned
primes_table	%	4096	; 4096 bytes is enough space for 1024 primes

You can obtain the start address for this table using:

	add	r5,r15,#(primes_table -8 -.)

This computes the address by determining how far the memory area is from the PC and then adding it to the PC. "." is short had for the current address for this instruction and the "-8" is required because the real PC is always 2 instructions ahead of the one being executed due to the pipelining.

Once you have written your primes program, comment it and put the answer to the following question in comments at the end of the code.

Questions

Ticking Criteria

  1. Your code needs to be cleanly formatted and commented.
  2. When measuring how long the code takes to execute you must remove most of the output so that execution is not limited by output bandwidth.
  3. Answers to the questions for the lab must be added to the end of your code.