Using Labels as an Address to Read From in Thumb Assembly

Joseph Yiu , in The Definitive Guide to ARM® CORTEX®-M3 and CORTEX®-M4 Processors (Third Edition), 2014

5.6.2 Retentivity access instructions

There are large numbers of memory access instructions in the Cortex®-M3 and Cortex-M4 processors. This is due to the combination of support of various addressing modes, besides as data size and data transfer direction. For normal data transfers, the instructions bachelor are given in Table 5.6

Table 5.6. Memory Access Instructions for Various Data Sizes

Data Type Load (Read from Retention) Store (Write to Retentivity)
eight-bit unsigned LDRB STRB
8-fleck signed LDRSB STRB
sixteen-bit unsigned LDRH STRH
xvi-fleck signed LDRSH STRH
32-fleck LDR STR
Multiple 32-bit LDM STM
Double-word (64-bit) LDRD STRD
Stack operations (32-bit) POP Push

Notation: The LDRSB and the LDRSH automatically perform a sign extend performance on the loaded data to convert it to a signed 32-bit value. For instance, if 0x83 is read in a LDRB instruction, the value is converted into 0xFFFFFF83 before being placed in the destination register.

If the floating point unit is nowadays, the instructions in Table 5.7 are besides available to transfer information between the register bank in the floating indicate unit of measurement and memory.

Tabular array v.vii. Memory Access Instructions for the Floating Bespeak Unit

Data Type Read from Memory (Load) Write to Memory (Shop)
Single-precision data (32-bit) VLDR.32 VSTR.32
Double-precision data (64-bit) VLDR.64 VSTR.64
Multiple data VLDM VSTM
Stack operations VPOP VPUSH

There are besides a number of addressing modes available. In some of these modes, you can also optionally update the register belongings the address (write dorsum).

Immediate offset (pre-index)

The memory address of the data transfer is the sum of a annals value and an immediate constant value (outset). Sometimes this is referred to as "pre-index" addressing. For example:

  LDRB   R0, [R1, #0x3] ; Read a byte value from address R1+0x3, and store the read information in R0.

The offset value can exist positive or negative. Table v.8 shows a listing of commonly used load and store instructions.

Table 5.viii. Memory Access Instructions with Immediate Outset

Example of Pre-alphabetize Accesses
Note: the #offset field is optional
Clarification
LDRB  Rd, [Rn, #offset] Read byte from retentiveness location Rn + commencement
LDRSB Rd, [Rn, #offset] Read and signed extend byte from retentiveness location Rn + commencement
LDRH  Rd, [Rn, #offset] Read half-word from memory location Rn + beginning
LDRSH Rd, [Rn, #first] Read and signed extended half-word from retentiveness location Rn + offset
LDR  Rd, [Rn, #offset] Read word from memory location Rn + offset
LDRD  Rd1,Rd2, [Rn, #offset] Read double-word from memory location Rn + get-go
STRB  Rd, [Rn, #showtime] Store byte to retention location Rn + starting time
STRH  Rd, [Rn, #starting time] Store half-word to memory location Rn + start
STR    Rd, [Rn, #starting time] Shop discussion to memory location Rn + offset
STRD  Rd1,Rd2, [Rn, #offset] Shop double-word to retentiveness location Rn + offset

This addressing mode supports write dorsum of the annals belongings the address. For example:

  LDR   R0, [R1, #0x8]!   ; Later the access to memory[R1+0x8], R1 is updated to R1+0x8

The exclamation marker (!) in the educational activity specifies whether the register holding the address should exist updated (write back) when the teaching is completed. The address used for the data transfer uses the sum of R1+0x8 calculated regardless of whether the exclamation mark (!) is stated. The write back operation tin can be used with a number of load and store instructions every bit shown in Tabular array 5.9.

Table 5.9. Memory Access Instructions with Immediate Offset and Write Back

Example of Pre-index with Write Back
Note: the #offset field is optional
Clarification
LDRBRd, [Rn, #first]! Read byte with write back
LDRSB Rd, [Rn, #offset]! Read and signed extend byte with write back
LDRHRd, [Rn, #start]! Read one-half-word with write back
LDRSH Rd, [Rn, #commencement]! Read and signed extended half-word with write dorsum
LDRRd, [Rn, #offset]! Read word with write back
LDRDRd1,Rd2, [Rn, #kickoff]! Read double-word with write back
STRBRd, [Rn, #start]! Store byte to retentivity with write back
STRHRd, [Rn, #offset]! Store half-give-and-take to retentiveness with write dorsum
STRRd, [Rn, #offset]! Store word to memory with write back
STRDRd1,Rd2, [Rn, #offset]! Shop double-word to retention with write back

Please note that some of these instructions cannot be used with R15(PC) or R13(SP). In addition, the 16-bit versions of these instructions only back up low registers (R0-R7) and do not provide write back.

If the floating point unit is nowadays, the instructions in Table v.10 are as well available to perform LDR and STR operations to the registers in the floating point unit.

Table 5.10. Memory Access Instructions for Floating Bespeak Unit

Examples
Note: the #commencement field is optional
Description
VLDR.32Sd, [Rn, #offset] Read unmarried-precision data from memory to unmarried-precision register Sd
VLDR.64Dd, [Rn, #offset] Read double-precision data from memory to double-precision register Dd
VSTR.32Sd, [Rn, #offset] Write single-precision data from single-precision register Sd to memory
VSTR.64Dd, [Rn, #kickoff] Write double-precision data from double precision annals Dd to memory

Notation that many floating indicate instructions utilise the .32 and .64 suffixes to specify the floating information blazon. In almost toolchains, the .32 and .64 suffixes are optional.

PC-related addressing (Literal)

A memory access tin generate the address value from the current PC value and an offset value (Table five.11 ). This is commonly needed for loading immediate values into a register, likewise known every bit literal pool accesses, equally mentioned earlier in this chapter (LDR pseudo educational activity).

Table 5.11. Memory Access Instructions with PC Related Addressing

Example of Literal Read Description
LDRBRt,[PC, #offset] Load unsigned byte into Rt using PC outset
LDRSB Rt,[PC, #offset] Load and signed extend a byte data into Rt using PC offset
LDRHRt,[PC, #first] Load unsigned one-half-word into Rt using PC offset
LDRSH Rt,[PC, #offset] Load and signed extend a half-word data into Rt using PC get-go
LDRRt, [PC, #beginning] Load a word data into Rt using PC get-go
LDRD Rt,Rt2,[PC, #offset] Load a double-word into Rt and Rt2 using PC offset

If the floating betoken unit is present, the instructions in Table 5.12 are too available.

Table five.12. Floating Point Unit Retentivity Access Instructions with PC-related Addressing

Example of Literal Read Clarification
VLDR.32 Sd,[PC, #outset] Load single-precision information into single-precision annals Sd using PC first
VLDR.64 Dd,[PC, #commencement] Load double-precision information into double-precision register Dd using PC showtime

Register offset (pre-index)

Another useful address style is the register offset. This is often used in the processing of data arrays where the address is a combination of a base address and an offset calculated from an alphabetize value. To make this address adding even more efficient, the index value can be shifted by a distance of 0 to three bits before being added to the base annals. For example:

  LDR   R3, [R0, R2, LSL #2]   ; Read memory[R0+(R2 << ii)] into R3

The shift functioning is optional. You can have a simple operation like

  STR   R5, [R0,R7]   ; Write R5 into retentivity[R0+R7]

Similarly to immediate showtime, there are various forms for unlike data size, as shown in Table five.xiii.

Table 5.13. Retentivity Admission Instructions with Register Beginning

Instance of Annals Offset Accesses Description
LDRBRd, [Rn, Rm{, LSL #n}] Read byte from memory location Rn + (Rm &lt;&lt; northward)
LDRSB Rd, [Rn, Rm{, LSL #north}] Read and signed extend byte from retentiveness location Rn + (Rm &lt;&lt; due north)
LDRHRd, [Rn, Rm{, LSL #north}] Read half-word from memory location Rn + (Rm &lt;&lt; due north)
LDRSH Rd, [Rn, Rm{, LSL #due north}] Read and signed extended half-word from retentiveness location Rn + (Rm &lt;&lt; n)
LDRRd, [Rn, Rm{, LSL #n}] Read word from retention location Rn + (Rm &lt;&lt; n)
STRBRd, [Rn, Rm{, LSL #n}] Store byte to retention location Rn + (Rm &lt;&lt; n)
STRHRd, [Rn, Rm{, LSL #northward}] Store half-give-and-take to retentiveness location Rn + (Rm &lt;&lt; n)
STRRd, [Rn, Rm{, LSL #n}] Store word to memory location Rn + (Rm &lt;&lt; northward)

Post-index

Retention access instructions with mail-index addressing mode also take an immediate offset value. However, the starting time is not used during the memory admission, just is used to update the address register after the data transfer is completed. For case:

  LDR   R0, [R1], #offset ; Read retentiveness[R1], then R1 updated to R1+offset

When the post-index memory addressing fashion is used, there is no demand to apply the assertion mark (!) sign because the base of operations address register is always updated if the information transfer is completed successfully. Tabular array 5.fourteen lists various form of mail indexing memory access instructions.

Table 5.14. Retentivity Access Instructions with Post-Indexing

Example of Post Index Accesses Description
LDRB   Rd,[Rn], #get-go Read byte from retentiveness[Rn] to Rd, then update Rn to Rn+commencement
LDRSB Rd,[Rn], #offset Read and signed extended byte from memory[Rn] to Rd, then update Rn to Rn+offset
LDRH   Rd,[Rn], #offset Read half-give-and-take from memory[Rn] to Rd, then update Rn to Rn+starting time
LDRSH Rd,[Rn], #first Read and signed extended half-give-and-take from memory[Rn] to Rd, then update Rn to Rn+get-go
LDR   Rd,[Rn], #offset Read word from memory[Rn] to Rd, then update Rn to Rn+offset
LDRD   Rd1,Rd2,[Rn], #offset Read double-word from retentivity[Rn] to Rd1, Rd2, then update Rn to Rn+showtime
STRB   Rd,[Rn], #first Store byte to memory[Rn] so update Rn to Rn+offset
STRH   Rd,[Rn], #beginning Shop half-word to memory[Rn] then update Rn to Rn+offset
STR   Rd,[Rn], #showtime Store word to memory[Rn] so update Rn to Rn+offset
STRD   Rd1,Rd2,[Rn], #offset Shop double-word to memory[Rn] then update Rn to Rn+offset

The post-index address mode can be very useful for processing data in an array. As shortly as an element in the array is accessed, the address register tin be adjusted to the side by side chemical element automatically to save code size and execution time.

Delight note that post-alphabetize instructions cannot be used with R15(PC) o R14(SP). The post-index memory access instructions are 32-flake. The outset value can be positive or negative.

Multiple load and multiple shop

Ane of the primal advantages of the ARM architecture is that it allows you lot to read or write multiple data that are contiguous in memory. The LDM (Load Multiple registers) and STM (Store Multiple registers) instructions merely support 32-bit information. They support two types of pre-indexing:

IA: Increment address After each read/write

DB: Decrement accost Before each read/write

The LDM and STM instructions can be used without base address write dorsum (Table 5.fifteen).

Tabular array 5.xv. Multiple Load/Store Retention Access Instructions

Examples of Multiple Load/Store Description
LDMIA Rn,&lt;reg list&gt; Read multiple words from memory location specified by Rn. Address Increment Later (IA) each read.
LDMDB Rn,&lt;reg list&gt; Read multiple words from memory location specified by Rn. Accost Decrement Earlier (DB) each read.
STMIA Rn,&lt;reg list&gt; Write multiple words to memory location specified by Rn. Address increment after each write.
STMDB Rn,&lt;reg listing&gt; Write multiple words to retentiveness location specified past Rn. Address Decrement Earlier each write.

The <reg listing> in Table 5.15 is the annals list. It contains at to the lowest degree one register, and:

Kickoff with "{" and cease with "}"

Employ "-" (hypen) to indicate range. For example, R0-R4 means R0, R1, R2, R3 and R4.

Utilise "," (comma) to divide each annals

For instance, the post-obit instructions read address 0x20000000 to 0x2000000F (iv words) into R0 to R3:

  LDR   R4,=0x20000000 ; Fix R4 to 0x20000000 (address)

  LDMIA R4, {R0-R3}   ; Read 4 words and store them to R0 - R3

The register listing tin can be non-contiguous such as {R1, R3, R5-R7, R9, R11-12}, which contains R1, R3, R5, R6, R7, R8, R11, R12.

Like to other load/store instructions, you can use write dorsum with STM and LDM. For instance:

  LDR   R8,=0x8000     ; Set R8 to 0x8000 (address)

  STMIA R8!, {R0-R3}   ; R8 change to 0x8010 after the store

Tabular array v.16. Multiple Load/Shop Memory Access Instructions with Write Back

Example of Multiple Load / Store with Write Back Description
LDMIA Rn!,&lt;reg list&gt; Read multiple words from memory location specified by Rd. Address Increase After (IA) each read. Rn writes back afterwards the transfer is washed.
LDMDB Rn!,&lt;reg list&gt; Read multiple words from memory location specified by Rd. Accost Decrement Before (DB) each read. Rn writes back after the transfer is done.
STMIA Rn!,&lt;reg list&gt; Write multiple words to retention location specified by Rd. Address increase after each write. Rn writes back after the transfer is done.
STMDB Rn!,&lt;reg list&gt; Write multiple words to memory location specified past Rd. Address Decrement Before each write Rn writes back later on the transfer is done.

Instructions with multiple Load/Shop retention access instructions with write back are listed in Table 5.16. The 16-fleck versions of the LDM and STM instructions are limited to low registers simply and e'er have write back enabled, except when the base annals is one of the destination registers to be updated past the retentivity read.

If the floating indicate unit is present, the instructions in Table 5.17 are likewise available to perform load multiple and store multiple operations to the registers in the floating point unit.

Tabular array 5.17. Multiple Load/Shop Memory Access Instructions for Floating Signal Unit with Write Dorsum

Example of Multiple Load / Store with Write Back Description
VLDMIA.32 Rn, &lt;s_reg list&gt; Read multiple single-precision data. Address Increment After (IA) each read.
VLDMDB.32 Rn, &lt;s_reg list&gt; Read multiple unmarried-precision data. Address Decrement Before (DB) each read.
VLDMIA.64 Rn, &lt;d_reg list&gt; Read multiple double-precision information. Address Increase Afterwards (IA) each read.
VLDMDB.64 Rn, &lt;d_reg list&gt; Read multiple double-precision data. Accost Decrement Earlier (DB) each read.
VSTMIA.32 Rn, &lt;s_reg list&gt; Write multiple single-precision data. Address increment after each write.
VSTMDB.32 Rn, &lt;s_reg list&gt; Write multiple single-precision information. Address decrement before each write.
VSTMIA.64 Rn, &lt;d_reg list&gt; Write multiple double-precision information. Accost increment afterwards each write.
VSTMDB.64 Rn, &lt;d_reg list&gt; Write multiple double-precision data. Accost decrement before each write.
VLDMIA.32 Rn!, &lt;s_reg listing&gt; Read multiple unmarried-precision data. Address Increment After (IA) each read. Rn writes dorsum later on the transfer is done.
VLDMDB.32 Rn!, &lt;s_reg list&gt; Read multiple single-precision data. Address Decrement Earlier (DB) each read. Rn writes dorsum after the transfer is washed.
VLDMIA.64 Rn!, &lt;d_reg list&gt; Read multiple double-precision data. Address Increment After (IA) each read. Rn writes dorsum afterward the transfer is washed.
VLDMDB.64 Rn!, &lt;d_reg listing&gt; Read multiple double-precision data. Address Decrement Before (DB) each read. Rn writes back after the transfer is done.
VSTMIA.32 Rn!, &lt;s_reg listing&gt; Write multiple single-precision information. Address increment after each write. Rn writes back after the transfer is done.
VSTMDB.32 Rn!, &lt;s_reg list&gt; Write multiple single-precision data. Address decrement earlier each write. Rn writes dorsum after the transfer is washed.
VSTMIA.64 Rn!, &lt;d_reg list&gt; Write multiple double-precision data. Address increment after each write. Rn writes back after the transfer is washed.
VSTMDB.64 Rn!, &lt;d_reg list&gt; Write multiple double-precision information. Address decrement before each write. Rn writes dorsum later on the transfer is done.

Stack button and pop

Stack push and pop are another grade of the shop multiple and load multiple. They use the currently selected stack pointer for address generation. The currently selected stack pointer tin can either be the Main Stack Pointer (MSP), or the Process Stack Pointer (PSP), depending on the current mode of the processor and the value in the CONTROL special annals (come across Chapter 4). Instructions for stack button and stack popular are shown in Tabular array v.18.

Table 5.xviii. Stack Button and Stack POP Instructions for Core Registers

Example of Stack Operations Description
Push button &lt;reg listing&gt; Store register(s) in stack.
POP &lt;reg list&gt; Restore register(s) from stack.

The register listing syntax is the same as LDM and STM. For instance:

  PUSH   {R0, R4-R7, R9}   ; Push button R0, R4, R5, R6, R7, R9 into stack

  POP   {R2, R3}       ; Popular R2 and R3 from stack

Usually a Button education volition have a corresponding POP with the aforementioned annals list, but this is not always necessary. For example, a common exception is when Pop is used as a function render:

  Push button   {R4–R6, LR} ; Save R4 to R6 and LR (Link Annals) at the

                                    ; beginning of a subroutine. LR contains the

                                    ; return address

                                ; processing in the subroutine

  Popular   {R4-R6, PC} ; Pop R4 to R6, and return address from stack.

                                  ; the return address is stores into PC straight,

                                  ; this triggers a branch (subroutine return)

Instead of popping the render address into LR, and and then writing it to the program counter (PC), we can write the render address direct to PC to salve instruction count and cycle count.

The 16-chip versions of PUSH and Pop are limited to low registers (R0 to R7), LR (for PUSH), and PC (for Popular). Therefore if a loftier register is modified in a function and the contents of the register need to be saved, you lot need to apply a pair of 32-bit PUSH and Pop instructions.

If the floating indicate unit of measurement is present, the instructions in Tabular array 5.19 are also available to perform stack operations to the registers in the floating signal unit.

Table 5.19. Stack Push button and Stack Pop Instructions for Floating Point Unit of measurement Registers

Example of Stack Operations Description
VPUSH.32 &lt;s_reg listing&gt; Store single-precision annals(due south) in stack. (i.eastward., s0-s31)
VPUSH.64 &lt;d_reg list&gt; Store double-precision annals(s) in stack. (i.e., d0-d15)
VPOP.32   &lt;s_reg list&gt; Restore unmarried-precision annals(s) from stack.
VPOP.64   &lt;d_reg listing&gt; Restore double-precision register(s) from stack.

Different PUSH and POP, VPUSH and VPOP instructions require that:

The registers in the annals listing are sequent

The maximum number of registers stacked/unstacked for each VPUSH or VPOP is 16

If it is necessary to save more sixteen single-precision floating point registers, yous can utilize double-precision teaching, or use two pairs of VPUSH and VPOP.

SP-relative addressing

Also being used for the temporary storage of registers in functions or subroutines, the stack retentiveness is very oftentimes also used for local variables, and accessing these variables requires SP-relative addressing. In that location is no special 32-fleck version of SP-relative addressing as this is already covered by the load and shop instructions with immediate start. However, most 16-bit Thumb instructions can only use low registers. As a result, there is a pair of defended 16-bit version of LDR and STR instructions with SP-relative addressing.

An case of using SP-relative addressing fashion (Effigy 5.five) tin be: at the beginning of a part the SP value can be decremented to reserve space for local variables and and then the local variables tin can be accessed using SP-related addressing. At the end of the function, the SP is incremented to return to the original value, which frees the allocated stack space earlier returning to the calling code.

FIGURE five.5. Local variable space allocation and accesses in stack

Load and store with unprivileged admission level

At that place is a gear up of load and store instructions to permit program code executing in privileged admission level to access retention with unprivileged access rights, as shown in Table five.xx.

Table 5.20. Retentivity Access Instructions with Unprivileged Access Level

Example of LDR/STR with Unprivileged Access Level Clarification
Annotation: the #get-go field is optional
LDRBT   Rd, [Rn, #offset] Read byte from retention location Rn + offset
LDRSBT Rd, [Rn, #offset] Read and signed extend byte from retentiveness location Rn + offset
LDRHT   Rd, [Rn, #offset] Read half discussion from memory location Rn + commencement
LDRSHT Rd, [Rn, #offset] Read and signed extended one-half word from retention location Rn + showtime
LDRT   Rd, [Rn, #offset] Read give-and-take from memory location Rn + outset
STRBT   Rd, [Rn, #offset] Store byte to memory location Rn + starting time
STRHT   Rd, [Rn, #start] Shop half-discussion to memory location Rn + outset
STRT   Rd, [Rn, #beginning] Store word to memory location Rn + offset

These instructions might be needed in some OS environments where an unprivileged application can access an API function (running within the privileged access level) with a data pointer as an input parameter, and this API operates on memory information specified by the arrow. If the information access is carried out using normal load and store instructions, the unprivileged awarding task will then have the power to alter information that is used by other tasks or Os kernel using this API. By coding the API using these special Load and Store instructions with unprivileged access level, the API tin can only access the data which the application task can access.

Sectional accesses

The exclusive access instructions are a special group of retentiveness access instructions for implementing semaphores or MUTEX (Mutual Exclusive) operations. They are normally used within embedded OS where a resource (frequently hardware, merely tin also be software) has to be shared betwixt multiple awarding tasks, or fifty-fifty multiple processors.

Sectional admission instructions include exclusive loads and exclusive stores. Special hardware inside the processor and optionally in the autobus interconnect are needed to monitor exclusive accesses. Inside the processor, a single bit register is present to record an on-going sectional access sequence: we phone call it the local exclusive access monitor. On the system bus level, an sectional admission monitor might also exist present to check if a retention location (or memory device) used by an exclusive access sequence has been accessed by some other processor or coach main. The processor has extra signals in the bus interface to indicate that a transfer is an exclusive admission and to receive a response from the organisation bus level sectional access monitor.

In a semaphore or a MUTEX operation, a data variable in RAM is used to represent a token. It can be used to indicate, for example, that a hardware resource has been allocated to an application task. For instance, presume that if the variable is 0, it indicates the resource is available, and 1 indicates that it is already allocated to a chore. The exclusive access sequence for requesting the resources might be:

one.

The variable is accessed with an exclusive load (read). The local exclusive access monitor inside the processor is updated to indicate an active sectional access transfer and, if a motorbus level exclusive access monitor is present, information technology will also exist updated.

2.

The variable is checked past the application code to determine whether the hardware resource has already been allocated. If the value is 1 (already allocated), and then information technology can retry later or give upward. If the value is 0 (resource free), then it can try to allocate the resources in the adjacent step.

three.

The task uses an exclusive store to write a value of ane to the variable. If the local exclusive access monitor is prepare and there is no error reported by the motorcoach level exclusive access monitor, the variable volition exist updated and the sectional store will get a success return condition. If something happened between the sectional load and sectional shop that could affect the exclusiveness of the access to the variable, the exclusive store will get a failed return status and the variable volition not be updated (either cancelled by the processor itself or the store is blocked by the charabanc level sectional access monitor).

4.

From the return status, the application task knows that if information technology has allocated the hardware resources successfully. If not, it tin can retry later or give up.

The exclusive shop fails if:

The bus level sectional admission monitor returns an sectional neglect response (eastward.1000., the memory location or memory range has been accessed past some other processor)

The local exclusive access monitor is not gear up. This can be acquired past:

a)

Incorrect exclusive access sequence

b)

An interrupt entry/go out between the exclusive load and exclusive store (the retention location or memory range could have been accessed by an interrupt handler or another application task).

c)

Execution of a special educational activity CLREX that clears the local sectional access monitor.

The instructions for exclusive accesses are given in Table 5.21.

Table 5.21. Exclusive Access Instructions

Instance of Exclusive Admission Description
LDREXB   Rt, [Rn] Sectional read byte from retentiveness location Rn
LDREXH   Rt, [Rn] Sectional read half-word from retentivity location Rn
LDREX   Rt, [Rn, #commencement] Exclusive read word from retention location Rn + offset
STREXB   Rd, Rt, [Rn] Sectional store byte in Rt to memory location Rn. Return status in Rd.
STREXH   Rd, Rt, [Rn] Exclusive store half word in Rt to memory location Rn. Render condition in Rd.
STREX   Rd, Rt, [Rn, #offset] Sectional store word in Rt from to location Rn + beginning. Return status in Rd.
CLREX Forcefulness the local sectional access monitor to clear so that next sectional store must fail. This is not a memory access instruction, but is listed here due to its usage.

johnsonquichademad.blogspot.com

Source: https://www.sciencedirect.com/topics/engineering/pseudo-instruction

0 Response to "Using Labels as an Address to Read From in Thumb Assembly"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel