;name: nibblebcd2bin.asm ; ;build: nasm -felf64 nibblebcd2bin.asm -o nibblebcd2bin.o ; ;description: nibblebcd2bin: packed bcd nibble to binary conversion. ; ;use: ;packed bcd: mov rdi,packedbcd ; call nibblebcd2bin ; ;algorithm: ;The algorithm to convert from bcd to binary is quite easy and looks similar to ;the convertion from binary to bcd. Now we shift the least significant bit to the right ;and start the convertion from bit 1. Subsequent we compare each group of 3 bits with 100b ;if bigger than 100b then we subtract 011b from it. Once processed all bitgroups, we shift ;again one bit to the right and start again until the last 3 bits remains. The result is the ;last three bits followed by the bits shifted to the right. ; ;Doing the method above on 64 bits means that we have to loop at most 16 times to check all ;nibbles of a qword. Combined with the number of bits we need to shift right and repeat the ;algorithm takes a lot of loops. This can be done otherwise. ; ;The biggest value that a nibble can take is 1100b. (99 = 10011001, shifted right one place gives ;1001100 1, the last nibble here is 1100b.) Because we need to check if a nibble is bigger than 4 ;(0100b) we see when we write them all down and add 3 to it, bit 3 will be set when the value ;is bigger than 0100b (4) ; 0000b 0001b 0010b 0011b 0100b 0101b 0110b 0111b 1000b 1001b 1010b 1011b 1100b ;add 3 : 0011b 0100b 0101b 0110b 0111b 1000b 1001b 1010b 1011b 1100b 1101b 1110b 1111b ;without the risk that the result overflows and change the entire value. ;If we mask off bit 0, 1 and 2 then ;mask 1000b : 0000b 0000b 0000b 0000b 0000b 1000b 1000b 1000b 1000b 1000b 1000b 1000b 1000b ;successively shift 2 right, subtract from original value, shift 1 right and subtract from original value, ;we only subtract 3 from the nibbles bigger than 0100b. ; 0000b 0001b 0010b 0011b 0100b 0101b 0110b 0111b 1000b 1001b 1010b 1011b 1100b ;add 3 : 0011b 0100b 0101b 0110b 0111b 1000b 1001b 1010b 1011b 1100b 1101b 1110b 1111b ;mask 1000b : 0000b 0000b 0000b 0000b 0000b 1000b 1000b 1000b 1000b 1000b 1000b 1000b 1000b ;>> 2 : 0000b 0000b 0000b 0000b 0000b 0010b 0010b 0010b 0010b 0010b 0010b 0010b 0010b ;subtract: : 0000b 0001b 0010b 0011b 0100b 0011b 0100b 0101b 0110b 0111b 1000b 1001b 1010b ;>> 1 : 0000b 0000b 0000b 0000b 0000b 0001b 0001b 0001b 0001b 0001b 0001b 0001b 0001b ;subtract: : 0000b 0001b 0010b 0011b 0100b 0010b 0011b 0100b 0101b 0110b 0111b 1000b 1001b ; ;to just convert a nibble it's a longer algorith than just compare and subtract, but for longer nibble ;sequences we can expand this method for bytes, words, dwords, qwords, dqwords .... even for SSE and AVX. bits 64 global nibblebcd2bin section .text nibblebcd2bin: ;convert packed bcd in AL to binary in AL. mov rax,rdi ;value in RAX and al,0x0F ;only lower nibble count mov ah,al ;nibble in AH add ah,3 ;add 3 and ah,0x08 ;mask off bit 0,1 and 2 shr ah,2 ;divide by 4, giving 0 or 2 sub al,ah ;subtract from AL ror ah,1 ;divide by 2, giving 0 or 1 sub al,ah ;subtract from AL xor ah,ah ;make AH zero ret