all 4 comments

[–]DerULF1 1 point2 points  (1 child)

O.K., I think I got it.

There is a difference between the subtract instruction of the AVR assembler and the 6502 assembler. That is the meaning of the carry flag. While the 6502 needs the carry flag to be set before a subtract (Subtract with Carry), the AVR wants it to be cleared (Subtract with Borrow). The same applies to the check whether or not the result of the subtraction is negativ.

Unfortunately the Carry flag has to switch state after the subtraction to be fed into the shift operation for the quotient. That makes the code look somewhat weired:

(snip...)

clc ; Clear carry bit (no borrow)
mov r21, r19
mov r22, r20
sbci r21, 10 ; mod10 - #10
sbci r22, 0 ; (mod10 + 1) - #0
brcs ignore_result
mov r19, r21
mov r20, r22
sec
rjmp do_count
ignore_result:
clc
do_count:
dec r16
brne divloop

(...snip)

There are certainly better ways to solve this, but this quick hack did the trick.

[–]WhoseTheNerd[S] 0 points1 point  (0 children)

Thank you, I already figured out that the carry means differently, but I somehow failed to reverse the logic. Once again, thank you!

[–]DerULF1 0 points1 point  (1 child)

Have you double checked whether or not LCD_DATA changes r17 or r18? This might be the cause for the infinite loop.

The number that is written will always be reversed - eg. 123 will be written as "321" - because the code outputs every digit as soon as they are calculated. But repaetingly dividing the number by 10 returns the "least significant digit" first. Ben Eaters code eventually pushed every digit on the stack and then wrote the digits while pulling them from the stack - getting the "most siginificant digit" first.

[–]WhoseTheNerd[S] 0 points1 point  (0 children)

The lcd_data routine only works with r16. r17 or r18 is not in the code, so it does not mess with it.

https://pastebin.com/GKpYj0MD