Last active
July 30, 2022 06:40
-
-
Save shawnnapora/c4a4e8892ea26184bc3c17021d4cba63 to your computer and use it in GitHub Desktop.
Euler problem 1 on ATTiny85
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. | |
; Find the sum of all the multiples of 3 or 5 below 1000. | |
.include "tn85def.inc" | |
.def counter_lR = r24 ; adiw works against r24+ | |
.def counter_hR = r25 | |
.def zeroR = r1 ; so we can carry with adc since there's no adic | |
.def threeR = r18 | |
.def fiveR = r19 | |
.def result_lR = r20 | |
.def result_hR = r21 | |
.def result_sR = r22 | |
.equ max = 999 ; multiples of 3 or 5 below 1000, but it will take action on the last element | |
.cseg | |
.org 0x00 | |
setup: | |
ldi r16, (1<<PINB0) ; mask for pb0 | |
out DDRB, r16 ; enable pb0 for output | |
; set up stack. SRAM starts at 0x60, so allocate 16 bytes for now. The stack grows downward. | |
; https://ww1.microchip.com/downloads/en/devicedoc/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf#G1.1179139 | |
.equ stackStart = 0x70 | |
ldi r16, HIGH(stackStart) | |
out SPH, r16 | |
ldi r16, LOW(stackStart) | |
out SPL, r16 | |
; zero our counters and results registers | |
clr counter_lR | |
clr counter_hR | |
clr zeroR | |
clr threeR | |
clr fiveR | |
clr result_lR | |
clr result_hR | |
clr result_sR | |
loop: | |
; increment counters | |
adiw counter_lR, 1 | |
inc threeR | |
inc fiveR | |
; check divisibility by 3 | |
cpi threeR, 3 | |
brne check_five ; if our counter isn't 3, try 5 next | |
add result_lR, counter_lR ; otherwise add the result to our result counter | |
adc result_hR, counter_hR ; and carry the overflow from the lower byte add | |
adc result_sR, zeroR ; add the zero register to handle overflow from lower bytes | |
clr threeR ; reset the 3 counter to 0 | |
cpi fiveR, 5 ; sometimes three and five will both need attention, but we shouldn't fall through and add again | |
brne check_counter | |
clr fiveR | |
rjmp check_counter | |
check_five: | |
cpi fiveR, 5 | |
brne check_counter ; if our counter isn't 5, check our big counter | |
add result_lR, counter_lR | |
adc result_hR, counter_hR | |
adc result_sR, zeroR | |
clr fiveR | |
check_counter: | |
; check to see if counter is max (1000) yet, loop back if not | |
cpi counter_lR, LOW(max) | |
brne loop | |
cpi counter_hR, HIGH(max) | |
brne loop | |
; if we're here, we've hit our max and we're done with the above. it's time to blink an LED! | |
emit_answer: | |
.def val1R = r1 | |
.def bitLoopR = r16 | |
.def maskR = r17 | |
.def delayR = r18 | |
.def iLooplR = r24 ; sbiw works against register pairs for registers r24+ | |
.def iLoophR = r25 | |
.equ multVal = 15625 ; 4_000_000 loops to one second @8MHz, divided by 256 so one byte of all ones is a full second of delay | |
.equ shortDelay = 25 ; tenth of a second for short delay | |
.equ longDelay = 255 ; full second | |
mov val1R, result_lR | |
rcall write_byte | |
mov val1R, result_hR | |
rcall write_byte | |
mov val1R, result_sR | |
rcall write_byte | |
endLoop: | |
rjmp endLoop | |
write_byte: | |
ldi bitLoopR, 8 ; we're going to shift a byte, bit by bit | |
write_bits: | |
; first, toggle led off/on real quick to allow multiple on or off bytes to be visible | |
clr maskR ; zero our led register | |
ldi delayR, shortDelay | |
rcall write_delay | |
inc maskR | |
ldi delayR, shortDelay | |
rcall write_delay | |
; then write our bit | |
clr maskR ; zero our led register | |
lsr val1R ; shift val1R and store the LSB in the C flag | |
adc maskR, maskR ; with maskR zeroed, adc will just add the C flag | |
ldi delayR, longDelay | |
rcall write_delay | |
dec bitLoopR | |
brne write_bits | |
ret | |
write_delay: ; expects the delay value in delayR, mask in maskR, falls to delay overwriting oLooplR and oLoophR | |
out PORTB, maskR | |
delay: ; expects the delay value to be in delayR, overwrites oLooplR and oLoophR. | |
ldi iLooplR, LOW(multVal) | |
ldi iLoophR, HIGH(multVal) | |
delay_loop: | |
sbiw iLooplR, 1 ; word instruction to decrement register pair | |
brne delay_loop | |
dec delayR | |
brne delay | |
ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[shawn@localhost avr]$ avra euler_0001.asm | |
AVRA: advanced AVR macro assembler Version 1.3.0 Build 1 (8 May 2010) | |
Copyright (C) 1998-2010. Check out README file for more info | |
AVRA is an open source assembler for Atmel AVR microcontroller family | |
It can be used as a replacement of 'AVRASM32.EXE' the original assembler | |
shipped with AVR Studio. We do not guarantee full compatibility for avra. | |
AVRA comes with NO WARRANTY, to the extent permitted by law. | |
You may redistribute copies of avra under the terms | |
of the GNU General Public License. | |
For more information about these matters, see the files named COPYING. | |
Pass 1... | |
tn85def.inc(44) : PRAGMA directives currently ignored | |
tn85def.inc(48) : PRAGMA directives currently ignored | |
tn85def.inc(53) : PRAGMA directives currently ignored | |
tn85def.inc(54) : PRAGMA directives currently ignored | |
tn85def.inc(647) : PRAGMA directives currently ignored | |
tn85def.inc(648) : PRAGMA directives currently ignored | |
tn85def.inc(649) : PRAGMA directives currently ignored | |
tn85def.inc(650) : PRAGMA directives currently ignored | |
euler_0001.asm(78) : Warning : r1 is already assigned to 'zeroR'! | |
euler_0001.asm(81) : Warning : r18 is already assigned to 'threeR'! | |
euler_0001.asm(82) : Warning : r24 is already assigned to 'counter_lR'! | |
euler_0001.asm(83) : Warning : r25 is already assigned to 'counter_hR'! | |
Pass 2... | |
tn85def.inc(44) : PRAGMA directives currently ignored | |
tn85def.inc(48) : PRAGMA directives currently ignored | |
tn85def.inc(53) : PRAGMA directives currently ignored | |
tn85def.inc(54) : PRAGMA directives currently ignored | |
tn85def.inc(647) : PRAGMA directives currently ignored | |
tn85def.inc(648) : PRAGMA directives currently ignored | |
tn85def.inc(649) : PRAGMA directives currently ignored | |
tn85def.inc(650) : PRAGMA directives currently ignored | |
done | |
Used memory blocks: | |
Code : Start = 0x0000, End = 0x0042, Length = 0x0043 | |
Assembly complete with no errors (4 warnings). | |
Segment usage: | |
Code : 67 words (134 bytes) | |
Data : 0 bytes | |
EEPROM : 0 bytes | |
[shawn@localhost avr]$ sudo minipro -p ATTINY85 -w euler_0001.hex | |
[sudo] password for shawn: | |
Found TL866II+ 04.2.126 (0x27e) | |
Chip ID OK: 0x1E930B | |
Found Intel hex file. | |
Erasing... 0.01Sec OK | |
Writing Code... 1.06Sec OK | |
Reading Code... 0.44Sec OK | |
Verification OK | |
[shawn@localhost avr]$ python -c "print(0b0000000111000111011010000)" | |
233168 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment