The Damm algorithm is a checksum algorithm which detects all single digit errors and adjacent transposition errors.



The algorithm is named after H. Michael Damm.



Task

Verify the checksum, stored as last digit of an input.



.text
.global	_start
	@@@	Check if the zero-terminated ASCII string in [r0],
	@@@	which should contain a decimal number, has a
	@@@	matching check digit. Zero flag set if true,
	@@@	check digit returned in r0.
damm:	mov	r1,#0		@ R1 = interim digit
	ldr	r2,=3f		@ R2 = table base address
1:	ldrb	r3,[r0],#1	@ Load byte
	tst	r3,r3		@ Zero yet?
	beq	2f		@ If so, stop
	sub	r3,r3,#'0	@ Subtract ASCII 0
	lsl	r1,r1,#1	@ Table lookup 
	add	r1,r1,r1,lsl#2	@ R3 = R1*10 + R3
	add	r3,r1,r3
	ldrb	r1,[r2,r3]	@ R1 = new interim digit
	b	1b		@ Next value
2:	movs	r0,r1		@ Set flag according to r0.
	bx	lr
3:	.byte	0,3,1,7,5,9,8,6,4,2	@ Since the table is constant,
	.byte	7,0,9,2,1,5,4,8,6,3	@ it can be stored as part of
	.byte	4,2,0,6,8,7,1,3,5,9	@ the subroutine.
	.byte	1,7,5,0,9,8,3,4,2,6	@ This way the OS will even mark
	.byte	6,1,2,3,0,4,5,9,7,8	@ it as read-only, so we can
	.byte	3,6,7,4,2,0,9,5,8,1	@ be sure nothing changes it.
	.byte	5,8,6,9,7,2,0,1,3,4
	.byte	8,9,4,5,3,6,2,0,1,7
	.byte	9,4,3,8,6,1,7,2,0,5
	.byte	2,5,8,1,4,3,6,7,9,0
.align	4			@ Instructions must be word-aligned
	@@@	Grab the argument from the command line, and see
	@@@	if it matches.
_start:	pop	{r0}		@ Is there even an argument?
	cmp 	r0,#2
	movne	r7,#1		@ If not, exit immediately
	swine	#0
	add	sp,sp,#4	@ Discard program name
	pop	{r0}		@ Grab argument
	bl	damm		@ Check if it matches
	ldreq	r1,=pass	@ If yes, say 'pass'
	ldrne	r1,=fail	@ If not, say 'fail'
	mov	r0,#1		@ Print string to stdout
	mov	r2,#5		@ Both are 5 characters
	mov	r7,#4		@ Write syscall = 4
	swi	#0
	mov	r0,#0		@ Exit
	mov	r7,#1
	swi	#0 
pass:	.ascii	"Pass\n"
fail:	.ascii	"Fail\n"