doubleDabble.asm - RLH-2110/gbCalc GitHub Wiki

Table of contents

Overview
The Double Dabble routine
The subroutines
Note

Overview

This file contains a routine to turn binary numbers into BCD using Double dabble
If you are not familiar with it, there is a video from Computerphile

The Double Dabble routine

The routine has been misnamed into prepareResult, Probably because this routine was first only intended to work with wResult
At first the routine prepares the result for the local double dabble routine

; will use: A, BC, HL, 
; and (RAM) wTmp1,wTmp2, wTmpH (adressed as wDoubleDabble)
prepareResult::
	push de


	; first make sure that the result is treated as a positive number when used in BCD

	


	; if the number is not negative, skip the next code
	ld a,[wResult+1]
	and a, %1000_0000 ; check for the sign
	ld [wResultNegative],a ; is the number was signed, then a is $80 with is nz which means this is "true" otherwhise its "false"

	jp z,.resultPositive


	; flip all bits
	ld a,[wResult]
	xor a,$ff
	ld [wResult],a
	ld a,[wResult+1]
	xor a,$ff
	ld [wResult+1],a

	; add 1
	ld a,[wResult]
	inc a
	ld [wResult],a
	
	jp nz,.resultPositive ; no carry on increment

	; carry on increment

	; add 1 to upper byte
	ld a,[wResult+1]
	inc a
	ld [wResult+1],a


	.resultPositive:

Then we set up some stuff and go into the double dabble loop:

	; clear space for Double Dabble
	ld hl,wDoubleDabble		; DESTINATION
	ld bc,doubleDabbleSize	; BYTES
	ld d,0 					; VALUE
	call SetMem

	; load the number into double dable
	ld a,[wResult+1] ; little endian
	ld [wDoubleDabble + dd_numberIndex],a ; big endian
	ld a,[wResult] ; little endian
	ld [wDoubleDabble + dd_numberIndex+1],a ; big endian


	ld c,16 ; counter (for every bit)
	.doubleDabbleLoop

		call doubleDabbleCheck
		call doubleDabbleShift
		

		dec c

		; if c > 0
		ld a,c
		cp a,0
		jr nz, .doubleDabbleLoop

	pop de
	ret

The subroutines

You probably saw that we just call 2 subroutines in the double dabble routine
First we have the routine to shift all bits left

; uses a
doubleDabbleShift: 
	
	ld a,[wDoubleDabble+4]
	sla a
	ld [wDoubleDabble+4],a


	ld a,[wDoubleDabble+3]
	rla
	ld [wDoubleDabble+3],a


	ld a,[wDoubleDabble+2]
	rla
	ld [wDoubleDabble+2],a


	ld a,[wDoubleDabble+1]
	rla
	ld [wDoubleDabble+1],a


	ld a,[wDoubleDabble]
	rla
	ld [wDoubleDabble],a
	
	ret

Then we have the routine to check and adjust the segments

; uses A,B,HL
doubleDabbleCheck:
	
	ld b,dd_numberIndex-1 ; the first byte thats not the orignal number
	
	.doubleDabbleCheck_loop

		; load adress into hl and apply offset
		ld hl,wDoubleDabble
		ld a,l
		add a,b
		ld l,a
		;
		ld a,h
		adc a,0 ; just adds carry
		ld h,a


		; check first segment
		ld a,[hl]
		and $0f

		cp a,$05
		jr c, .doubleDabbleCheck_segment2 ; if a < 5

		; add 3 to first segment
		ld a,[hl]
		add a,$03
		ld [hl],a


		.doubleDabbleCheck_segment2

		;check second segment
		ld a,[hl]
		and $f0

		cp a,$50
		jr c, .doubleDabbleCheck_next ; if a < 5

		; add 3 to second segment
		ld a,[hl]
		add a,$30
		ld [hl],a

		.doubleDabbleCheck_next

		dec b
		ld a,b
		cp a,0
		jr nz, .doubleDabbleCheck_loop

	ret

Note

there is also a routine to unpack BCD, but it's in utility.asm