; filepath: d:\Hardware\avrfibo.s ; Fibonacci sequence generator for ATmega328p ; Outputs 80-digit numbers via UART .include "m328pdef.inc" .equ F_CPU = 16000000 ; CPU Frequency .equ BAUD = 9600 ; Desired Baud Rate .equ UBRR_VAL = (F_CPU / 16 / BAUD) - 1 .def temp1 = r16 ; General purpose temp .def temp2 = r17 ; General purpose temp .def sum = r18 ; Digit sum .def carry = r19 ; Decimal carry (0 or 1) .def inner_cnt= r20 ; Inner loop counter (80) .def outer_lo = r21 ; Outer loop counter low byte .def outer_hi = r22 ; Outer loop counter high byte .def ascii_val= r23 ; Value to print .def zero = r1 ; Holds constant 0 (ldi zero, 0) .cseg .org 0x0000 rjmp main ; Basic UART Transmit Character Routine uart_putc: ; Wait for empty transmit buffer lds r16, UCSR0A sbrs r16, UDRE0 rjmp uart_putc ; Put data into buffer, sends the data sts UDR0, ascii_val ret ; Basic UART Initialization uart_init: ; Set Baud Rate ldi temp1, high(UBRR_VAL) sts UBRRH, temp1 ldi temp1, low(UBRR_VAL) sts UBRRL, temp1 ; Enable Transmitter ldi temp1, (1 << TXEN0) sts UCSR0B, temp1 ; Set Frame Format: 8data, 1stop bit (default) ; ldi temp1, (1< current = array2 + 79 ldi YL, low(array2 + 79) ldi YH, high(array2 + 79) ; Z (r31:r30) -> previous = array1 + 79 ldi ZL, low(array1 + 79) ldi ZH, high(array1 + 79) ; Set initial value current[79] = 1 ldi temp1, 1 st Y, temp1 ; Store 1 at the end of array2 ; Initialize outer loop counter (383) ldi outer_lo, low(383) ldi outer_hi, high(383) outer_loop: ; --- Calculate next Fibonacci number --- ; Z points to previous, Y points to current ; Result will be stored in previous (pointed to by Z) ldi inner_cnt, 80 ; 80 digits ; Start with carry=0 path rjmp carry0_path ; Enter the loop with carry=0 carry1_path: ; This is the path when carry=1 from previous iteration ld temp1, -Z ; Load previous[j] and decrement Z ld temp2, -Y ; Load current[j] and decrement Y add temp1, temp2 ; Add current digit inc temp1 ; Add carry=1 ; Check for decimal overflow cpi temp1, 10 ; Compare with 10 brlo store_no_carry ; If < 10, no new carry carry_with_overflow: ; Handle carry case subi temp1, 10 ; Subtract 10 st Z, temp1 ; Store result dec inner_cnt ; Decrement counter brne carry1_path ; If counter not zero, continue with carry=1 rjmp inner_done ; Exit if counter is zero carry0_path: ; This is the path when carry=0 from previous iteration ld temp1, -Z ; Load previous[j] and decrement Z ld temp2, -Y ; Load current[j] and decrement Y add temp1, temp2 ; Add current digit (no carry to add) ; Check for decimal overflow cpi temp1, 10 ; Compare with 10 brsh carry_with_overflow ; If >= 10, reuse the common overflow code ; Fall through to common store with no carry store_no_carry: st Z, temp1 ; Store result dec inner_cnt ; Decrement counter brne carry0_path ; If counter not zero, continue with carry=0 rjmp inner_done ; Exit if counter is zero inner_done: ; Continue with rest of program ; --- Pointer Swap --- ; Swap Y (current) and Z (previous) movw r24, YL ; Use r25:r24 as temp storage for Y movw YL, ZL ; Y = Z movw ZL, r24 ; Z = temp (original Y) ; Now Y points to the newly calculated number (which was 'previous' before swap) ; Z points to the number that was 'current' before swap ; --- Print the current number (pointed to by Y) --- ldi ascii_val, '|' rcall uart_putc ; Reset Y pointer to the start of the current array for printing ; Calculate start address = Y_end_addr - 79 ; Since Y points to end (index 79), add 1 to get address *after* array adiw YL, 1 ; Y now points just past the end ; Subtract 80 to point to the beginning (index 0) subi YL, 80 sbci YH, 0 ldi inner_cnt, 80 print_loop: ld ascii_val, Y+ ; Load digit from current array, increment pointer subi ascii_val, -'0' ; Add '0' (ASCII 48) to convert to ASCII char rcall uart_putc dec inner_cnt brne print_loop ldi ascii_val, '|' rcall uart_putc ldi ascii_val, '\n' ; Newline rcall uart_putc ; --- Decrement outer loop counter --- subi outer_lo, 1 sbci outer_hi, 0 ; Check if counter is zero or outer_lo, outer_hi brne outer_loop ; Branch if not zero end_loop: rjmp end_loop ; Infinite loop when done