16-bit arithmetic on an 8 bit device in assembly (Part One)
The PFS154 has three 11-bit (2048 increments) hardware PWM channels, which is great - but it is an 8-bit microcontroller. So it might be time to explore 16-bit arithmetic to cover the possibility I might use the full PWM capabilities on this device.
Crazily I have also decided to explore this from an AVR assembly perspective (???). The problem with this is that the PFS154 is not part of the AVR family, I have no familiarity with the instruction set for Padauk assembly, and as well no experience with the toolchain to program the PFS154 in assembly. So...
I'm going to start with subtraction. From my AVR by example booklet, the sub command simply subtracts one register from another. When zero is reached the flag is raised and a branch can be initiated. It's pretty simple code - check out the video below for the code running on Gerd's excellent AVR-SIM.
.nolist .include "tn13adef.inc" ; Define device ATtiny13A .list .dseg .org SRAM_START .cseg .org 000000 Main: ldi r16, low(RAMEND) out SPL, r16 ; Init LSB stack pointer .equ mycount = 146 ; initialise countdown (0x92) Loop: ldi r16, mycount ; load counter ldi r19, 1 rcall Countdown subi r22, -1 ; how many loops? rjmp Loop Countdown: sub r16, r19 cpi r16, 0 brbc 1, Countdown ret ; End of source code
A quick screen grab shows the beast humming along happily subtracting (and keeping an 8-bit count of the loops in R22). Note that AVR has no "add immediate"(addi) command on the premise that you can subtract immediate (subi) using -1 instead. It's a little weird but 5 - ( -1) = 6 and that's OK with the AVR (and me).
Two byte (16-bit) subtraction uses both sub and subc for the low and high bytes respectively. The subc command is subtract with carry which will use the registers defined to effectively result in a 16-bit operation, as per the code below.
.nolist .include "tn13adef.inc" ; Define device ATtiny13A .list .dseg .org SRAM_START .cseg .org 000000 Main: ldi r16, low(RAMEND) out SPL, r16 ; Init LSB stack pointer .equ mycount = 900 ; initialise countdown (0x0384) Loop: ldi r16, high(mycount) ; load high byte 0x03 ldi r17, low(mycount) ; load low byte 0x84 ldi r19, 1 ldi r20, 0 rcall Countdown subi r22, -1 rjmp Loop Countdown: sub r17, r19 sbc r16, r20 cpi r17, 0 brbc 1, Countdown cpi r16, 0 brbc 1, Countdown ret ; End of source code
See below for a quick screen grab of this code in action.
Note that this code only subtracts one at a time, but the same process applies to larger 16 bit integers as per the code below.
.nolist .include "tn13adef.inc" ; Define device ATtiny13A .list .dseg .org SRAM_START .cseg .org 000000 Main: ldi r16, low(RAMEND) out SPL, r16 ; Init LSB stack pointer .equ higher = 425 ; 0x01A9 .equ lower = 342 ; 0x0156 Loop: ldi r16, high(higher) ; load high byte 0x01 ldi r17, low(higher) ; load low byte 0xA9 ldi r18, high(lower) ; load high byte 0x01 ldi r19, low(lower) ; load low byte 0x56 sub r17, r19 ; subtract low byte sbc r16, r18 ; subtract high byte with carry ; result in r16:r17 = 0x0053 rjmp Loop ; End of source code
No comments:
Post a Comment