2.1
### uVision Project, (C) Keil Software
soln
0x4
ARM-ADS
6090000::V6.9::.ARMCLANG
1
ARMCM4_FP
ARM
ARM.CMSIS.5.4.0
http://www.keil.com/pack/
IRAM(0x20000000,0x00020000)
IROM(0x00000000,0x00040000) CPUTYPE("Cortex-M4")
FPU2 CLOCK(12000000) ESEL ELITTLE
UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000)
0
$$Device:ARMCM4_FP$DeviceARMARMCM4IncludeARM
CM4_FP.h
0
0
0
0
0
0
1
.Objects
target_sim
1
0
0
1
1
.Listings
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
3
1
SARMCM3.DLL
-MPU
DCM.DLL
-pCM4
SARMCM3.DLL
-MPU
TCM.DLL
-pCM4
1
0
0
0
16
1
0
0
1
0
-1
1
BINUL2CM3.DLL
0
0
1
1
1
1
1
1
1
0
1
1
0
1
1
0
0
1
1
1
1
1
1
1
1
1
0
0
"Cortex-M4"
0
0
0
1
1
0
0
2
0
0
8
0
1
0
0
3
3
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x20000000
0x20000
1
0x0
0x40000
0
0x0
0x0
1
0x0
0x0
1
0x0
0x0
1
0x0
0x0
1
0x0
0x40000
1
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x0
0x0
0
0x20000000
0x10000
0
0x20010000
0x10000
1
1
0
0
1
0
0
0
0
0
3
0
0
1
1
0
3
3
1
1
0
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
1
0
0x00000000
0x20000000
Source for soln
140_main.c
1
.source140_main.c
140_asm_functions.s
2
.source140_asm_functions.s
::CMSIS
::Compiler
::Device
RTEDeviceARMCM4startup_ARMCM4.s
RTEDeviceARMCM4system_ARMCM4.c
RTEDeviceARMCM4_FPstartup_ARMCM4.s
RTEDeviceARMCM4_FPsystem_ARMCM4.c
RTEDeviceSTM32L476VGTxstartup_stm32l476xx.s
RTEDeviceSTM32L476VGTxsystem_stm32l4xx.c
1.0
### uVision Project, (C) Keil Software
*.c
*.s*; *.src; *.a*
*.obj; *.o
*.lib
*.txt; *.h; *.inc
*.plm
*.cpp
0
0
0
soln
0x4
ARM-ADS
12000000
1
1
0
1
0
1
65535
0
0
0
79
66
8
.Listings
1
1
1
0
1
1
0
1
0
0
0
0
1
1
1
1
1
1
1
0
0
1
0
1
7
1
0
1
1
1
1
1
1
1
1
1
1
1
1
0
1
1
1
1
0
0
1
1
0
0
BINUL2CM3.DLL
0
ARMRTXEVENTFLAGS
-L70 -Z18 -C0 -M0 -T1
0
DLGDARM
(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-
1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0)
0
ARMDBGFLAGS
-T0
0
UL2CM3
UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000)
0
0
36
1
9244
0
0
0
0
0
1
.source140_main.c
target_simsource/140_main.c36
1
0
38
1
0
0
0
0
0
0
0
.source140_main.c
0
1
localv,0x0A
1
1
pint
2
1
str
1
1
0x20010000
0
0
0
1
1
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
Source for soln
1
0
0
0
1
1
1
0
0
0
.source140_main.c
140_main.c
0
0
1
2
2
0
0
0
.source140_asm_functions.s
140_asm_functions.s
0
0
::CMSIS
0
0
0
1
::Compiler
1
0
0
1
::Device
1
0
0
1
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#define MY_ARRAY_BASE (0x20010000)
// Functions defined in a .s file
extern void task5(void);
extern void task6(void);
extern void task7(void);
extern void task10(void);
extern void task11(void);
extern void task12(void);
extern void task13(void);
extern void task14(void);
extern void task15(void);
// Global variable
uint32_t *gPtrArray1, *gPtrArray2;
uint32_t gVar1 = 6, gVar2;
volatile uint32_t gTemp1;
volatile uint32_t gTemp2;
int main(void) {
// We configure the RAM into the following two blocks in
"Options for Target..." ->
// "Target" -> "IRAM1 and IRAM2", with the first being
default:
// 1) Starting: 0x20000000; size: 0x10000 (2^16 B = 2^6 kB)
// 2) Starting: 0x20010000; size: 0x10000 (2^16 B = 2^6 kB)
// As a result, we can put our own data starting at
0x20010000.
// Initialize the global pointers
gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00);
gPtrArray2 = (uint32_t *)(MY_ARRAY_BASE + 0x40);
// Task 1. Load, modify, and store of a global var---example
1
gTemp1 = 0x10;
gTemp1 += 1;
// Task 2. Load, modify, and store of a global var---example
2
gTemp2 = 0x20;
gTemp2 += (gTemp1<<8);
printf("gTemp1 = 0x%X, gTemp2 = 0x%Xn", gTemp1,
gTemp2);
// Task 3. Load, modify, and store of a local var---example 1
volatile uint32_t lTemp1 = 0x1000;
lTemp1 += 1;
// Task 4. Load, modify, and store of a local var---example 2
volatile uint32_t lTemp2 = 0x2000;
lTemp2 += (lTemp1<<16);
printf("lTemp1 = 0x%X, lTemp2 = 0x%Xn", lTemp1,
lTemp2);
// Task 5. LDR pseudo instruction.
task5();
// Task 6. Load/Modify/Store using offset addressing.
gVar1 += 0x10;
task6(); // Task6: perform the above task using assembly
// Task 7. Load/Modify/Store using pseudo instruction.
gVar2 = 0x12345678;
gVar2 += gVar1;
task7(); // Task7: perform the above task using assembly
gVar1 = 6;
// Task 10. Register offset-based addressing---a simple
example.
// Note that this is especially useful for pointer arithmetic
here.
for (int i = 0; i < gVar1; i++) {
*(gPtrArray1 + i) = (uint32_t)(i*2 + 1); // i is register
offset based
}
// clear the memory for task10 in assembly
for (int i = 0; i < gVar1; i++) { *(gPtrArray1 + i) = 0; }
task10(); // task10: perform the above task using assembly
// Task 11. Register offset-based addressing---another simple
example.
// Note that this is especially useful for pointer arithmetic
here.
for (int i = 0; i < gVar1; i++) {
*(gPtrArray2 + i) = (uint32_t)(i*4 + 1);
}
// clear the memory for task11 in assembly
for (int i = 0; i < gVar1; i++) { *(gPtrArray2 + i) = 0; }
task11(); // task11: perform the above task using assembly
// Task 12. Register offset-based addressing---more
complicated case.
for (int i = 0; i < gVar1; i++) {
*(gPtrArray2 + i) = (*(gPtrArray1 + i))++; // Note that
the input data is changed as well
}
// clear the memory for task12 in assembly
for (int i = 0; i < gVar1; i++) { *(gPtrArray2 + i) = 0; }
task12(); // task12: perform the above task using assembly
printf("Task 2 is done.n");
// Task 13. Immediate offset addressing.
for (int i = 0; i < gVar1-1; i++) {
// We use immediate offset addressing twice in the
righthand side of the following
*(gPtrArray2 + i) = *(gPtrArray1) + *(gPtrArray1+1);
gPtrArray1++;
}
// clear the memory for task13 in assembly
gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); //
Restore the pointer
for (int i = 0; i < gVar1-1; i++) { *(gPtrArray2 + i) = 0; }
task13(); // task13: perform the above task using assembly
gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); //
Restore the pointer
// Task 14. Immediate offset addressing and pre-index
addressing.
for (int i = 0; i < gVar1-1; i++) {
//*(gPtrArray2 + i) = *(gPtrArray1) + 2 *
(*(++gPtrArray1));
// The above statement can be implemented below to force
the ''sequencing'':
// See: https://en.wikipedia.org/wiki/Sequence_point
uint32_t temp = *(gPtrArray1);
*(gPtrArray2 + i) = temp + 2 * (*(++gPtrArray1));
}
gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); //
Restore the pointer
for (int i = 0; i < gVar1-1; i++) { *(gPtrArray2 + i) = 0; }
task14(); // task14: perform the above task using assembly
gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); //
Restore the pointer
// Task 15. Post-index addressing and immediate offset
addressing.
for (int i = 0; i < gVar1-1; i++) {
//*(gPtrArray2 + i) = *(gPtrArray1++) + 4 *
(*gPtrArray1);
uint32_t temp = *(gPtrArray1++);
*(gPtrArray2 + i) = temp + 4 * (*gPtrArray1);
}
gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); //
Restore the pointer
for (int i = 0; i < gVar1-1; i++) { *(gPtrArray2 + i) = 0; }
task15(); // task15: perform the above task using assembly
while (1);
}
AREA my_fancy_asm_code, CODE, READONLY ;
Define the program area
; Export functions defined in this file. These functions
need to be declared
; in the file calling them.
EXPORT task5
EXPORT task6
EXPORT task7
EXPORT task10
EXPORT task11
EXPORT task12
EXPORT task13
EXPORT task14
EXPORT task15
IMPORT gPtrArray1
IMPORT gPtrArray2
IMPORT gVar1
IMPORT gVar2
ALIGN ; Align the data in the boundary of 4
bytes.
task5 PROC
LDR r0, =0x10 ; Pseudo code; see the disassembly
for the true code
LDR r1, =0x12345678 ; Pseudo code; see the
disassembly for the true code
LDR r2, =gVar1 ; Loading the address of the global
variable gVar1
LDR r3, =gPtrArray1 ; Loading the address of the
global variable gPtrArray1
BX lr
ENDP
task6 PROC
LDR r0, =0x10 ; Pseudo code; see the disassembly
for the true code
LDR r1, =gVar1 ; Loading the address of the global
variable gVar1
LDR r2, [r1]
ADD r0, r2
STR r0, [r1]
BX lr
ENDP
task7 PROC
LDR r0, =0x12345678 ; Pseudo code; see the
disassembly for the true code
LDR r1, =gVar1
LDR r1, [r1]
ADD r0, r1
LDR r2, =gVar2 ; Loading the address of the global
variable gVar2
STR r0, [r2]
BX lr
ENDP
task10 PROC
LDR r0, =gPtrArray1 ; Loading the address of the
global variable gPtrArray1
LDR r0, [r0] ; Loading the content of the global
variable gPtrArray1
LDR r1, =gVar1 ; Loading the address of the global
variable gVar1
LDR r1, [r1] ; Loading the content of the global
variable gVar1
MOV r2, #0 ; variable (int) i
task10_loop
CMP r2, r1 ; test = r2 - r1
BGE task10_end ; if test >= 0, then branch to
task10_end
MOV r3, r2, LSL #1 ; r3 <- 2 * r2
ADD r3, #1 ; r3 <- r3 + 1
STR r3, [r0, r2, LSL #2] ; r3 -> mem[r0 + 4*r2] or r3 ->
mem[r0 + i]
ADD r2, #1 ; r2 <- r2 + 1
B task10_loop ; branch to task10_loop
task10_end
BX lr ; return
ENDP
; If you need to use registers starting from r4, you need to
PUSH them first to save the
; run-time environment for the caller. You need to POP them up
at the exit of the code.
task11 PROC
LDR r0, =gPtrArray2
LDR r0, [r0]
LDR r1, =gVar1
LDR r1, [r1]
MOV r2, #0
task11_loop
CMP r2, r1
BGE task11_end
MOV r3, r2, LSL #2
ADD r3, #1
STR r3, [r0, r2, LSL #2]
ADD r2, #1
B task11_loop
task11_end
BX lr
ENDP
task12 PROC
PUSH {r4, lr}
LDR r0, =gPtrArray1
LDR r0, [r0]
LDR r4, =gPtrArray2
LDR r4, [r4]
LDR r1, =gVar1
LDR r1, [r1]
MOV r2, #0
task12_loop
CMP r2, r1
BGE task12_end
LDR r3, [r0, r2, LSL #2]
STR r3, [r4, r2, LSL #2]
ADD r3, #1
STR r3, [r0, r2, LSL #2]
ADD r2, #1
B task12_loop
task12_end
POP {r4, pc} ; Pop lr to pc, which is the same as BX
lr.
ENDP
task13 PROC
PUSH {r4-r5, lr}
LDR r0, =gPtrArray1
LDR r0, [r0]
LDR r4, =gPtrArray2
LDR r4, [r4]
LDR r1, =gVar1
LDR r1, [r1]
SUB r1, #1
MOV r2, #0
task13_loop
CMP r2, r1
BGE task13_end
LDR r3, [r0]
LDR r5, [r0, #4]
ADD r3, r5
STR r3, [r4, r2, LSL #2]
ADD r2, #1
ADD r0, #4
B task13_loop
task13_end
POP {r4-r5, pc}
ENDP
task14 PROC
PUSH {r4-r5, lr}
LDR r0, =gPtrArray1
LDR r0, [r0]
LDR r4, =gPtrArray2
LDR r4, [r4]
LDR r1, =gVar1
LDR r1, [r1]
SUB r1, #1
MOV r2, #0
task14_loop
CMP r2, r1
BGE task14_end
LDR r3, [r0]
LDR r5, [r0, #4]!
ADD r3, r5, LSL #1
STR r3, [r4, r2, LSL #2]
ADD r2, #1
B task14_loop
task14_end
POP {r4-r5, pc}
ENDP
task15 PROC
PUSH {r4-r5, lr}
LDR r0, =gPtrArray1
LDR r0, [r0]
LDR r4, =gPtrArray2
LDR r4, [r4]
LDR r1, =gVar1
LDR r1, [r1]
SUB r1, #1
MOV r2, #0
task15_loop
CMP r2, r1
BGE task15_end
LDR r3, [r0], #4
LDR r5, [r0]
ADD r3, r5, LSL #2
STR r3, [r4, r2, LSL #2]
ADD r2, #1
B task15_loop
task15_end
POP {r4-r5, pc}
ENDP
END ; End of the entire file
AREA my_fancy_asm_code, CODE, READONLY ;
Define the program area
; Export functions defined in this file. These functions
need to be declared
; in the file calling them.
EXPORT task10
EXPORT task11
EXPORT task12
EXPORT task13
EXPORT task14
EXPORT task15
IMPORT gPtrArray10a
IMPORT gPtrArray11a
IMPORT gPtrArray12a
IMPORT gPtrArray13a
IMPORT gPtrArray14a
IMPORT gPtrArray15a
IMPORT gVar1
ALIGN ; Align the data in the boundary of 4
bytes.
task10 PROC
LDR r0, =gPtrArray10a ; Loading the address of the
global variable gPtrArray10a
LDR r0, [r0] ; Loading the content of the global
variable gPtrArray10a
LDR r1, =gVar1 ; Loading the address of the global
variable gVar1
LDR r1, [r1] ; Loading the content of the global
variable gVar1
MOV r2, #0 ; variable (int) i
task10_loop
CMP r2, r1 ; test = r2 - r1
BGE task10_end ; if test >= 0, then branch to
task10_end
MOV r3, r2, LSL #2 ; r3 <- r2 * 4
SUB r3, #15 ; r3 <- r3 - 15
STRB r3, [r0, r2] ; r3 -> mem[r0 + r2] or r3 ->
mem[r0 + i]
ADD r2, #1 ; r2 <- r2 + 1
B task10_loop ; branch to task10_loop
task10_end
BX lr ; return
ENDP
; If you need to use registers starting from r4, you need to
PUSH them first to save the
; run-time environment for the caller. You need to POP them up
at the exit of the code.
task11 PROC
BX lr
ENDP
task12 PROC
PUSH {r4-r5, lr}
LDR r0, =gPtrArray10a
LDR r0, [r0]
LDR r4, =gPtrArray12a
LDR r4, [r4]
LDR r1, =gVar1
LDR r1, [r1]
MOV r2, #0
task12_loop
CMP r2, r1
BGE task12_end
LDRSB r3, [r0, r2]
LDR r5, =10
SUB r5, r3
STRH r5, [r4, r2, LSL #1]
ADD r3, #1
STRB r3, [r0, r2]
ADD r2, #1
B task12_loop
task12_end
POP {r4-r5, pc} ; Pop lr to pc, which is the same as
BX lr.
ENDP
task13 PROC
PUSH {r4-r5, lr}
POP {r4-r5, pc}
ENDP
task14 PROC
PUSH {r4-r5, lr}
LDR r0, =gPtrArray12a
LDR r0, [r0]
LDR r4, =gPtrArray14a
LDR r4, [r4]
LDR r1, =gVar1
LDR r1, [r1]
SUB r1, #1
MOV r2, #0
task14_loop
CMP r2, r1
BGE task14_end
LDRSH r3, [r0]
LDRSH r5, [r0, #2]!
ADD r3, r5, LSL #3
STR r3, [r4, r2, LSL #2]
ADD r2, #1
B task14_loop
task14_end
POP {r4-r5, pc}
ENDP
task15 PROC
PUSH {r4-r5, lr}
POP {r4-r5, pc}
ENDP
END
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#define MY_ARRAY_BASE (0x20010000)
// Functions defined in a .s file
extern void task10(void);
extern void task11(void);
extern void task12(void);
extern void task13(void);
extern void task14(void);
extern void task15(void);
// Global variable
// Pointers for the C version.
int8_t *gPtrArray10c = (int8_t *) (MY_ARRAY_BASE +
0x00);
uint8_t *gPtrArray11c = (uint8_t *) (MY_ARRAY_BASE +
0x40);
int16_t *gPtrArray12c = (int16_t *) (MY_ARRAY_BASE +
0x80);
uint16_t *gPtrArray13c = (uint16_t *) (MY_ARRAY_BASE +
0xC0);
int32_t *gPtrArray14c = (int32_t *) (MY_ARRAY_BASE +
0x100);
uint32_t *gPtrArray15c = (uint32_t *) (MY_ARRAY_BASE +
0x140);
// Pointers for the asm version.
int8_t *gPtrArray10a = (int8_t *) (MY_ARRAY_BASE +
0x20);
uint8_t *gPtrArray11a = (uint8_t *) (MY_ARRAY_BASE +
0x60);
int16_t *gPtrArray12a = (int16_t *) (MY_ARRAY_BASE +
0xA0);
uint16_t *gPtrArray13a = (uint16_t *) (MY_ARRAY_BASE +
0xE0);
int32_t *gPtrArray14a = (int32_t *) (MY_ARRAY_BASE +
0x120);
uint32_t *gPtrArray15a = (uint32_t *) (MY_ARRAY_BASE +
0x160);
int8_t gVar1 = 8;
int main(void) {
// Task 10. Register offset-based addressing---a simple
example.
for (int i = 0; i < gVar1; i++) {
*(gPtrArray10c + i) = (int8_t)(i*4 - 15); // i is saved in a
register
}
task10(); // task10: perform the above task using
assembly
// Task 11. Register offset-based addressing---another simple
example.
for (int i = 0; i < gVar1; i++) {
*(gPtrArray11c + i) = (uint8_t)(i*32 + 2);
}
task11(); // task11: perform the above task using
assembly
// Task 12. Register offset-based addressing---more
complicated case.
for (int i = 0; i < gVar1; i++) {
*(gPtrArray12c + i) = 10 - (*(gPtrArray10c + i))++;
} // Note that the input data is changed as well in
the above line
task12(); // task12: perform the above task using
assembly
// Task 13. Immediate offset addressing.
for (int i = 0; i < gVar1-1; i++) {
// We use immediate offset addressing twice below
(righthand side)
*(gPtrArray13c + i) = *(gPtrArray11c) +
*(gPtrArray11c+1);
gPtrArray11c++;
}
task13(); // task13: perform the above task using assembly
// Task 14. Immediate offset addressing and pre-index
addressing.
for (int i = 0; i < gVar1-1; i++) {
uint32_t temp = *(gPtrArray12c);
*(gPtrArray14c + i) = temp + 8 * (*(++gPtrArray12c));
}
task14(); // task14: perform the above task using assembly
// Task 15. Post-index addressing and immediate offset
addressing.
for (int i = 0; i < gVar1-1; i++) {
uint32_t temp = *(gPtrArray13c++);
*(gPtrArray15c + i) = temp + 16 * (*gPtrArray13c);
}
task15(); // task15: perform the above task using assembly
while (1);
}

2.1 ### uVision Project, (C) Keil Software .docx

  • 1.
    2.1 ### uVision Project,(C) Keil Software soln 0x4 ARM-ADS 6090000::V6.9::.ARMCLANG 1 ARMCM4_FP ARM ARM.CMSIS.5.4.0 http://www.keil.com/pack/ IRAM(0x20000000,0x00020000) IROM(0x00000000,0x00040000) CPUTYPE("Cortex-M4") FPU2 CLOCK(12000000) ESEL ELITTLE UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000) 0 $$Device:ARMCM4_FP$DeviceARMARMCM4IncludeARM CM4_FP.h
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
    RTEDeviceSTM32L476VGTxsystem_stm32l4xx.c 1.0 ### uVision Project,(C) Keil Software *.c *.s*; *.src; *.a* *.obj; *.o *.lib *.txt; *.h; *.inc *.plm *.cpp 0 0 0
  • 15.
  • 16.
  • 17.
    1 1 1 1 0 0 1 1 0 0 BINUL2CM3.DLL 0 ARMRTXEVENTFLAGS -L70 -Z18 -C0-M0 -T1 0 DLGDARM (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,- 1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0) 0
  • 18.
    ARMDBGFLAGS -T0 0 UL2CM3 UL2CM3(-S0 -C0 -P0-FD20000000 -FC1000) 0 0 36 1 9244 0 0 0 0 0 1 .source140_main.c target_simsource/140_main.c36 1 0 38 1 0 0 0 0 0
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
    // Functions definedin a .s file extern void task5(void); extern void task6(void); extern void task7(void); extern void task10(void); extern void task11(void); extern void task12(void); extern void task13(void); extern void task14(void); extern void task15(void); // Global variable uint32_t *gPtrArray1, *gPtrArray2; uint32_t gVar1 = 6, gVar2; volatile uint32_t gTemp1;
  • 24.
    volatile uint32_t gTemp2; intmain(void) { // We configure the RAM into the following two blocks in "Options for Target..." -> // "Target" -> "IRAM1 and IRAM2", with the first being default: // 1) Starting: 0x20000000; size: 0x10000 (2^16 B = 2^6 kB) // 2) Starting: 0x20010000; size: 0x10000 (2^16 B = 2^6 kB) // As a result, we can put our own data starting at 0x20010000. // Initialize the global pointers gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); gPtrArray2 = (uint32_t *)(MY_ARRAY_BASE + 0x40); // Task 1. Load, modify, and store of a global var---example 1 gTemp1 = 0x10; gTemp1 += 1;
  • 25.
    // Task 2.Load, modify, and store of a global var---example 2 gTemp2 = 0x20; gTemp2 += (gTemp1<<8); printf("gTemp1 = 0x%X, gTemp2 = 0x%Xn", gTemp1, gTemp2); // Task 3. Load, modify, and store of a local var---example 1 volatile uint32_t lTemp1 = 0x1000; lTemp1 += 1; // Task 4. Load, modify, and store of a local var---example 2 volatile uint32_t lTemp2 = 0x2000; lTemp2 += (lTemp1<<16); printf("lTemp1 = 0x%X, lTemp2 = 0x%Xn", lTemp1, lTemp2);
  • 26.
    // Task 5.LDR pseudo instruction. task5(); // Task 6. Load/Modify/Store using offset addressing. gVar1 += 0x10; task6(); // Task6: perform the above task using assembly // Task 7. Load/Modify/Store using pseudo instruction. gVar2 = 0x12345678; gVar2 += gVar1; task7(); // Task7: perform the above task using assembly gVar1 = 6; // Task 10. Register offset-based addressing---a simple example. // Note that this is especially useful for pointer arithmetic here.
  • 27.
    for (int i= 0; i < gVar1; i++) { *(gPtrArray1 + i) = (uint32_t)(i*2 + 1); // i is register offset based } // clear the memory for task10 in assembly for (int i = 0; i < gVar1; i++) { *(gPtrArray1 + i) = 0; } task10(); // task10: perform the above task using assembly // Task 11. Register offset-based addressing---another simple example. // Note that this is especially useful for pointer arithmetic here. for (int i = 0; i < gVar1; i++) { *(gPtrArray2 + i) = (uint32_t)(i*4 + 1); } // clear the memory for task11 in assembly for (int i = 0; i < gVar1; i++) { *(gPtrArray2 + i) = 0; } task11(); // task11: perform the above task using assembly // Task 12. Register offset-based addressing---more
  • 28.
    complicated case. for (inti = 0; i < gVar1; i++) { *(gPtrArray2 + i) = (*(gPtrArray1 + i))++; // Note that the input data is changed as well } // clear the memory for task12 in assembly for (int i = 0; i < gVar1; i++) { *(gPtrArray2 + i) = 0; } task12(); // task12: perform the above task using assembly printf("Task 2 is done.n"); // Task 13. Immediate offset addressing. for (int i = 0; i < gVar1-1; i++) { // We use immediate offset addressing twice in the righthand side of the following *(gPtrArray2 + i) = *(gPtrArray1) + *(gPtrArray1+1); gPtrArray1++; } // clear the memory for task13 in assembly gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); // Restore the pointer
  • 29.
    for (int i= 0; i < gVar1-1; i++) { *(gPtrArray2 + i) = 0; } task13(); // task13: perform the above task using assembly gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); // Restore the pointer // Task 14. Immediate offset addressing and pre-index addressing. for (int i = 0; i < gVar1-1; i++) { //*(gPtrArray2 + i) = *(gPtrArray1) + 2 * (*(++gPtrArray1)); // The above statement can be implemented below to force the ''sequencing'': // See: https://en.wikipedia.org/wiki/Sequence_point uint32_t temp = *(gPtrArray1); *(gPtrArray2 + i) = temp + 2 * (*(++gPtrArray1)); } gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); // Restore the pointer for (int i = 0; i < gVar1-1; i++) { *(gPtrArray2 + i) = 0; } task14(); // task14: perform the above task using assembly
  • 30.
    gPtrArray1 = (uint32_t*)(MY_ARRAY_BASE + 0x00); // Restore the pointer // Task 15. Post-index addressing and immediate offset addressing. for (int i = 0; i < gVar1-1; i++) { //*(gPtrArray2 + i) = *(gPtrArray1++) + 4 * (*gPtrArray1); uint32_t temp = *(gPtrArray1++); *(gPtrArray2 + i) = temp + 4 * (*gPtrArray1); } gPtrArray1 = (uint32_t *)(MY_ARRAY_BASE + 0x00); // Restore the pointer for (int i = 0; i < gVar1-1; i++) { *(gPtrArray2 + i) = 0; } task15(); // task15: perform the above task using assembly while (1); }
  • 31.
    AREA my_fancy_asm_code, CODE,READONLY ; Define the program area ; Export functions defined in this file. These functions need to be declared ; in the file calling them. EXPORT task5 EXPORT task6 EXPORT task7 EXPORT task10 EXPORT task11 EXPORT task12 EXPORT task13 EXPORT task14 EXPORT task15 IMPORT gPtrArray1 IMPORT gPtrArray2
  • 32.
    IMPORT gVar1 IMPORT gVar2 ALIGN; Align the data in the boundary of 4 bytes. task5 PROC LDR r0, =0x10 ; Pseudo code; see the disassembly for the true code LDR r1, =0x12345678 ; Pseudo code; see the disassembly for the true code LDR r2, =gVar1 ; Loading the address of the global variable gVar1 LDR r3, =gPtrArray1 ; Loading the address of the global variable gPtrArray1 BX lr ENDP task6 PROC LDR r0, =0x10 ; Pseudo code; see the disassembly for the true code
  • 33.
    LDR r1, =gVar1; Loading the address of the global variable gVar1 LDR r2, [r1] ADD r0, r2 STR r0, [r1] BX lr ENDP task7 PROC LDR r0, =0x12345678 ; Pseudo code; see the disassembly for the true code LDR r1, =gVar1 LDR r1, [r1] ADD r0, r1 LDR r2, =gVar2 ; Loading the address of the global variable gVar2 STR r0, [r2] BX lr ENDP
  • 34.
    task10 PROC LDR r0,=gPtrArray1 ; Loading the address of the global variable gPtrArray1 LDR r0, [r0] ; Loading the content of the global variable gPtrArray1 LDR r1, =gVar1 ; Loading the address of the global variable gVar1 LDR r1, [r1] ; Loading the content of the global variable gVar1 MOV r2, #0 ; variable (int) i task10_loop CMP r2, r1 ; test = r2 - r1 BGE task10_end ; if test >= 0, then branch to task10_end MOV r3, r2, LSL #1 ; r3 <- 2 * r2 ADD r3, #1 ; r3 <- r3 + 1 STR r3, [r0, r2, LSL #2] ; r3 -> mem[r0 + 4*r2] or r3 -> mem[r0 + i] ADD r2, #1 ; r2 <- r2 + 1 B task10_loop ; branch to task10_loop task10_end
  • 35.
    BX lr ;return ENDP ; If you need to use registers starting from r4, you need to PUSH them first to save the ; run-time environment for the caller. You need to POP them up at the exit of the code. task11 PROC LDR r0, =gPtrArray2 LDR r0, [r0] LDR r1, =gVar1 LDR r1, [r1] MOV r2, #0 task11_loop CMP r2, r1 BGE task11_end MOV r3, r2, LSL #2 ADD r3, #1
  • 36.
    STR r3, [r0,r2, LSL #2] ADD r2, #1 B task11_loop task11_end BX lr ENDP task12 PROC PUSH {r4, lr} LDR r0, =gPtrArray1 LDR r0, [r0] LDR r4, =gPtrArray2 LDR r4, [r4] LDR r1, =gVar1 LDR r1, [r1] MOV r2, #0 task12_loop CMP r2, r1
  • 37.
    BGE task12_end LDR r3,[r0, r2, LSL #2] STR r3, [r4, r2, LSL #2] ADD r3, #1 STR r3, [r0, r2, LSL #2] ADD r2, #1 B task12_loop task12_end POP {r4, pc} ; Pop lr to pc, which is the same as BX lr. ENDP task13 PROC PUSH {r4-r5, lr} LDR r0, =gPtrArray1 LDR r0, [r0] LDR r4, =gPtrArray2 LDR r4, [r4]
  • 38.
    LDR r1, =gVar1 LDRr1, [r1] SUB r1, #1 MOV r2, #0 task13_loop CMP r2, r1 BGE task13_end LDR r3, [r0] LDR r5, [r0, #4] ADD r3, r5 STR r3, [r4, r2, LSL #2] ADD r2, #1 ADD r0, #4 B task13_loop task13_end POP {r4-r5, pc} ENDP
  • 39.
    task14 PROC PUSH {r4-r5,lr} LDR r0, =gPtrArray1 LDR r0, [r0] LDR r4, =gPtrArray2 LDR r4, [r4] LDR r1, =gVar1 LDR r1, [r1] SUB r1, #1 MOV r2, #0 task14_loop CMP r2, r1 BGE task14_end LDR r3, [r0] LDR r5, [r0, #4]! ADD r3, r5, LSL #1 STR r3, [r4, r2, LSL #2] ADD r2, #1
  • 40.
    B task14_loop task14_end POP {r4-r5,pc} ENDP task15 PROC PUSH {r4-r5, lr} LDR r0, =gPtrArray1 LDR r0, [r0] LDR r4, =gPtrArray2 LDR r4, [r4] LDR r1, =gVar1 LDR r1, [r1] SUB r1, #1 MOV r2, #0 task15_loop CMP r2, r1 BGE task15_end
  • 41.
    LDR r3, [r0],#4 LDR r5, [r0] ADD r3, r5, LSL #2 STR r3, [r4, r2, LSL #2] ADD r2, #1 B task15_loop task15_end POP {r4-r5, pc} ENDP END ; End of the entire file AREA my_fancy_asm_code, CODE, READONLY ; Define the program area ; Export functions defined in this file. These functions need to be declared ; in the file calling them. EXPORT task10
  • 42.
    EXPORT task11 EXPORT task12 EXPORTtask13 EXPORT task14 EXPORT task15 IMPORT gPtrArray10a IMPORT gPtrArray11a IMPORT gPtrArray12a IMPORT gPtrArray13a IMPORT gPtrArray14a IMPORT gPtrArray15a IMPORT gVar1 ALIGN ; Align the data in the boundary of 4 bytes. task10 PROC LDR r0, =gPtrArray10a ; Loading the address of the
  • 43.
    global variable gPtrArray10a LDRr0, [r0] ; Loading the content of the global variable gPtrArray10a LDR r1, =gVar1 ; Loading the address of the global variable gVar1 LDR r1, [r1] ; Loading the content of the global variable gVar1 MOV r2, #0 ; variable (int) i task10_loop CMP r2, r1 ; test = r2 - r1 BGE task10_end ; if test >= 0, then branch to task10_end MOV r3, r2, LSL #2 ; r3 <- r2 * 4 SUB r3, #15 ; r3 <- r3 - 15 STRB r3, [r0, r2] ; r3 -> mem[r0 + r2] or r3 -> mem[r0 + i] ADD r2, #1 ; r2 <- r2 + 1 B task10_loop ; branch to task10_loop task10_end BX lr ; return ENDP
  • 44.
    ; If youneed to use registers starting from r4, you need to PUSH them first to save the ; run-time environment for the caller. You need to POP them up at the exit of the code. task11 PROC BX lr ENDP task12 PROC PUSH {r4-r5, lr} LDR r0, =gPtrArray10a LDR r0, [r0] LDR r4, =gPtrArray12a LDR r4, [r4] LDR r1, =gVar1 LDR r1, [r1] MOV r2, #0
  • 45.
    task12_loop CMP r2, r1 BGEtask12_end LDRSB r3, [r0, r2] LDR r5, =10 SUB r5, r3 STRH r5, [r4, r2, LSL #1] ADD r3, #1 STRB r3, [r0, r2] ADD r2, #1 B task12_loop task12_end POP {r4-r5, pc} ; Pop lr to pc, which is the same as BX lr. ENDP task13 PROC PUSH {r4-r5, lr}
  • 46.
    POP {r4-r5, pc} ENDP task14PROC PUSH {r4-r5, lr} LDR r0, =gPtrArray12a LDR r0, [r0] LDR r4, =gPtrArray14a LDR r4, [r4] LDR r1, =gVar1 LDR r1, [r1] SUB r1, #1 MOV r2, #0 task14_loop CMP r2, r1 BGE task14_end LDRSH r3, [r0] LDRSH r5, [r0, #2]!
  • 47.
    ADD r3, r5,LSL #3 STR r3, [r4, r2, LSL #2] ADD r2, #1 B task14_loop task14_end POP {r4-r5, pc} ENDP task15 PROC PUSH {r4-r5, lr} POP {r4-r5, pc} ENDP END #include <stdio.h> #include <stdint.h> #include <stdbool.h>
  • 48.
    #define MY_ARRAY_BASE (0x20010000) //Functions defined in a .s file extern void task10(void); extern void task11(void); extern void task12(void); extern void task13(void); extern void task14(void); extern void task15(void); // Global variable // Pointers for the C version. int8_t *gPtrArray10c = (int8_t *) (MY_ARRAY_BASE + 0x00); uint8_t *gPtrArray11c = (uint8_t *) (MY_ARRAY_BASE + 0x40); int16_t *gPtrArray12c = (int16_t *) (MY_ARRAY_BASE + 0x80); uint16_t *gPtrArray13c = (uint16_t *) (MY_ARRAY_BASE + 0xC0);
  • 49.
    int32_t *gPtrArray14c =(int32_t *) (MY_ARRAY_BASE + 0x100); uint32_t *gPtrArray15c = (uint32_t *) (MY_ARRAY_BASE + 0x140); // Pointers for the asm version. int8_t *gPtrArray10a = (int8_t *) (MY_ARRAY_BASE + 0x20); uint8_t *gPtrArray11a = (uint8_t *) (MY_ARRAY_BASE + 0x60); int16_t *gPtrArray12a = (int16_t *) (MY_ARRAY_BASE + 0xA0); uint16_t *gPtrArray13a = (uint16_t *) (MY_ARRAY_BASE + 0xE0); int32_t *gPtrArray14a = (int32_t *) (MY_ARRAY_BASE + 0x120); uint32_t *gPtrArray15a = (uint32_t *) (MY_ARRAY_BASE + 0x160); int8_t gVar1 = 8; int main(void) { // Task 10. Register offset-based addressing---a simple example.
  • 50.
    for (int i= 0; i < gVar1; i++) { *(gPtrArray10c + i) = (int8_t)(i*4 - 15); // i is saved in a register } task10(); // task10: perform the above task using assembly // Task 11. Register offset-based addressing---another simple example. for (int i = 0; i < gVar1; i++) { *(gPtrArray11c + i) = (uint8_t)(i*32 + 2); } task11(); // task11: perform the above task using assembly // Task 12. Register offset-based addressing---more complicated case. for (int i = 0; i < gVar1; i++) { *(gPtrArray12c + i) = 10 - (*(gPtrArray10c + i))++; } // Note that the input data is changed as well in the above line
  • 51.
    task12(); // task12:perform the above task using assembly // Task 13. Immediate offset addressing. for (int i = 0; i < gVar1-1; i++) { // We use immediate offset addressing twice below (righthand side) *(gPtrArray13c + i) = *(gPtrArray11c) + *(gPtrArray11c+1); gPtrArray11c++; } task13(); // task13: perform the above task using assembly // Task 14. Immediate offset addressing and pre-index addressing. for (int i = 0; i < gVar1-1; i++) { uint32_t temp = *(gPtrArray12c); *(gPtrArray14c + i) = temp + 8 * (*(++gPtrArray12c)); } task14(); // task14: perform the above task using assembly
  • 52.
    // Task 15.Post-index addressing and immediate offset addressing. for (int i = 0; i < gVar1-1; i++) { uint32_t temp = *(gPtrArray13c++); *(gPtrArray15c + i) = temp + 16 * (*gPtrArray13c); } task15(); // task15: perform the above task using assembly while (1); }