F28PL1 Programming Languages Lecture 3: Assembly Language 2 Running assembly programs on the ARM-MDK • ARM-MDK does not simulate a bare CPU • oriented to embedded systems with memory, peripherals etc • STM32-Discovery board is: – STMicroelectronics - STM32F103VB • assumes no operating system • must provide start up file – code to initialise peripherals, interrupts etc • STM32-Discovery uses: – STM32F10x.s – .s == assembler Running assembly programs on the ARM-MDK • start up file associates reset button on board with: ; Reset Handler Reset_Handler • • • • PROC EXPORT IMPORT LDR BX ENDP Reset_Handler __main R0, =__main R0 [WEAK] ; text == comment Reset_Handler – labelled procedure start PROC – start of procedure EXPORT Reset_Handler – make Reset_Handler visible externally Running assembly programs on the ARM-MDK ; Reset Handler Reset_Handler PROC EXPORT IMPORT LDR BX ENDP Reset_Handler __main R0, =__main R0 [WEAK] • IMPORT – make external label __main visible internally • LDR R0,=__main – load R0 with address for __main • BX R0 – branch indirect on R0 i.e. set PC to address for __main from R0 • ENDP - end procedure – not a return! Running assembly programs on the ARM-MDK • ARM-MDK expects every project to include a main.c – usually defining a main function – compiler generates assembly with EXPORTed __main label – start up then IMPORTs __main • can’t embed Thumb2 assembly language in C • provide a dummy main.c containing only: /* main.c */ • GJM’s main.c Running assembly programs on the ARM-MDK • provide own assembly language file with __main: ; Main __main AREA ASMmain, CODE PROC EXPORT __main <assembly code> ENDL B ENDL ENDP END • AREA – introduces block of code or data – name + attributes • __main – labelled procedure start • EXPORT __main – make __main visible externally Running assembly programs on the ARM-MDK AREA ; Main __main ASMmain, CODE PROC EXPORT __main <assembly code> ENDL B ENDL ENDP END • ENDL B ENDL – endless loop at end of program • END – end of source file • template in GJM’s ASMmain.s Create new project • • • • • create a new folder for new project copy dummy main.c to folder copy ASMmain.s template to folder run Keil μVision 4 Project -> New μVision Project – in new folder – give project same name Create new project • Select Device for Target -> STMicroelectronics -> STM32F103VB – OK • Copy STM32 Startup Code to Project Folder and Add Project to File? – No • Project Window now shows: +Target 1 • select + • Project Window now shows: +Target 1+Source Group 1 Create new project • select inner + • Project Window now shows: +Target 1+Source Group 1 • Source Group 1 /right mouse button… • …Add Files To Group ‘Source Group 1’ • Add: STM32F10x.s • Add: main.c and (possibly renamed) ASMmain.s – Close Compile/assemble • ASMmain.s/double left mouse button • ASMmain.s opens in tabbed window • add your assembler code • Project -> Build Target – details in lower window • fix program and repeat until: “project.axf" - 0 Error(s), 0 Warning(s). Execute program on simulator • Debug -> Start/Stop Debug Session – OK • View -> Register Window • View -> Disassembly Window • select STM32F10x.s tab Execute program on simulator • select reset button: RST • yellow arrow points at: LDR R0,=__main • repeatedly select step button: • watch indicated instruction & registers changing • to leave simulator: Debug -> Start/Stop Debug Session Multiply & divide MUL {Rd, }Rn,Rm Rd = Rn*Rm UDIV {Rd,}Rn,Rm Rd = Rn/Rm • unsigned • rounds down i.e. 7/3 == 2 Expressions • for: var1 = var2 op var3 • with: var1 RN R1 var2 RN R2 var3 RN R3 op R1,R2,R3 • e.g. x = y*z; x RN 1 y RN 2 z RN 3 MUL x,y,z Expressions • for: var1 = var2 op1 var3 op2 var4 • if op1 and op2 have same precedence • or op1 has higher precedence than op2 op1 R1,R2,R3 op2 R1,,R4 e.g. x = y*z-a; ... a RN 4 MUL x,y,z SUB x,a Expressions • for: var1 = var2 op1 var3 op2 var4 • if op2 has higher precedence than op1 • must evaluate op2 expression in new register op2 Ri,R3,R4 op1 R1,,R2,Ri e.g. x = MUL ADD e.g. x = ADD MUL y+z*a; R5,z,a x,y,R5 y*(z+a) R5,z,a x,y,R5 Expressions • draw expression tree • allocate registers to nodes – from bottom left – if expression in assignment then start with register for destination variable • accumulate into register for left operand • can re-use any register whose value is no longer required Example: Pythagorus int x; /* R1 */ int y; /* R2 */ int z; /* R3 */ int p; /* R4 */ x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; == * + z * x z * x y y Example: Pythagorus int x; /* R1 */ int y; /* R2 */ int z; /* R3 */ int p; /* R4 */ x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; == * + z * R5 x z * x y y Example: Pythagorus int x; /* R1 */ int y; /* R2 */ int z; /* R3 */ int p; /* R4 */ x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; == * + z * R5 x z * R6 x y y Example: Pythagorus int x; /* R1 */ int y; /* R2 */ int z; /* R3 */ int p; /* R4 */ x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; == * + R5 z * R5 x z * R6 x y y Example: Pythagorus int x; /* R1 */ int y; /* R2 */ int z; /* R3 */ int p; /* R4 */ x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; == * R6 + R5 z * R5 x z * R6 x y y Example: Pythagoras int x; /* R1 */ int y; /* R2 */ int z; /* R3 */ int p; /* R4 */ x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; == CMP * R6 + R5 z * R5 x z * R6 x y y Example: Pythagoras int x; int y; int z; int p; x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; AREA ; Main __main x y z p RN RN RN RN PYTH, CODE PROC EXPORT 1 2 3 4 MOV x,#3 MOV y,#4 MOV z,#5 __main Example: Pythagoras int x; int y; int z; int p; x = 3; y = 4; z = 5; if(x*x+y*y==z*z) p=1; else p=0; SAME ENDL MUL R5,x,x MUL R6,y,y ADD R5,R6 MUL R6,z,z CMP R5,R6 BEQ SAME MOV p,#0 B ENDL MOV p,#1 B ENDL ENDP END Structured programming • assembly language requires intricate use of labels & branches • easy to produce “spaghetti code” • design assembly programs using high level program structures – condition – iteration • use template to translate high level to label + branch Structured programming: if IF exp1 op exp2 THEN command1 ELSE command2 not(=) NE not(!=) EQ not(<) GE not(<=) GT not(>) LE not(>=) LT Ri = exp1 IFALSE IEND Rj = exp2 CMP Ri,Rj Bnot(op) IFALSE command1 B IEND command2 Structured programming: if IF exp1 op exp2 THEN command Ri = exp1 Rj = exp2 CMP Ri,Rj Bnot(op) IEND command IEND Structured programming: while WHILE exp1 op exp2 DO command WLOOP Ri = exp1 Rj = exp2 CMP Ri,Rj Bnot(op) WEND command B WLOOP WEND Example: is x prime? • dreadful algorithm...! int x; int n; int p; x = 23; n = 2; p = 1; while(n<x) if(x%n==0) { p = 0; break; else n = n+1; } AREA PYTH, CODE ; Main __main PROC EXPORT __main x RN 1 n RN 2 p RN 3 MOV x,#25 MOV n,#2 MOV p,#1 Example: is x prime? • dreadful algorithm...! int x; int n; int p; x = 23; n = 2; p = 1; while(n<x) if(x%n==0) { p = 0; break; else n = n+1; TEST NOTP } ENDL CMP n,x n<x BEQ ENDL UDIV R4,x,n MUL R4,n x%n==0 CMP R4,x (x/n)*n==x BNE NOTP MOV p,#0 p=0; break B ENDL ADD n,#1 n = n+1 B TEST B ENDL ENDP END