Design Criteria : speed
; *** Iterate through all non unique byte values
; *** less than 254 of any quantity
; *** buffer multple of 4 and zero terminated
byteOdom proc STDCALL buff:DWORD,qty:DWORD,range:DWORD
push edi ; push edi onto the stack
mov edi,buff ; address of odomoeter values
mov edx,256 ; highest byte value+1
sub edx,range ; byte range n to 255
mov ecx,qty ; number of bytes in odometer
lp00:
mov [edi+ecx-1],dl ; initialize one byte in buffer
loop lp00 ; decement ecx and loop till zero
dec byte ptr [edi] ; start with -1 for first iteration
next:
sub ebx,ebx ; zero a forward dword offset
lp01:
mov eax,ebx ; working dword offset
inc ebx ; point to next dword
inc dword ptr [edi+eax*4] ; increment dword
je lp01 ; loop if these 4 expired to zero
sub ebx,ebx ; byte offset forward pointer
lp02:
mov eax,ebx ; working byte offset pointer
inc ebx ; point to next byte
cmp [edi+eax],dl ; compare byte to lowest byte value
jc notOk ; jump if byte not within valid range
; *** odometer values incremented and correct
mov eax,[edi] ; get least significant odometer byte
sub eax,edx ; normalize to get the value
nop ; action to be taken
jmp next ; loop and increment the odometer
notOk:
cmp byte ptr [edi+eax],0 ; compare byte to zero
mov byte ptr [edi+eax],dl ; reset byte to lowest value
je lp02 ; loop and check next byte
pop edi
ret
byteOdom endp
pseudocode
let lowValue = 256 -
odometer range
fill an array of
quantity elements with lowValue
do
do
increment 4 array elements
little endian with carry
point to next 4 array elements
loop while incremented elements all equal zero
for each element in array
if element = 0
element = lowValue
end if
loop while element > 1
if element > 1
value = array[0 to
odometer range] - lowValue
rem action to be taken
endif
while element > 1
More
This snippet is a trade-off between time saved computing elements in an array and 'normalizing' the data it contains. Two primary considerations are the reversed oder of the odometer - little endian (or least significant byte first) and the high bit alignment of the data. The speed increase from this approach is the ability to increment 4 elements with one command but that is also a trade off as the range of values is limited from 0 to 253.
The byte wise data for a 7 digit odometer with a range of 0 to 5 and current value of 0543210 is stored as follows:
250 is a high bit aligned value normalized to 0 when 250 is subtracted. The order should not be of major concern unless the value represents an index. In this case, determining the index value should be done in reverse order. The final value of zero is required as an array terminator. When this value is no longer zero the odometer has expired.
If the data and application are written to suit this high ended little endian odometer, the efficiency of the snippet will be maintained.
Methodology: when a double word (4 bytes) is moved from memory into a register, it is read so that the first byte is the right most register value. Moving the first 4 bytes from the array above into a register produces 0xFDFCFBFA. Incrementing this value produces 0xFDFCFBFB.
When the first 4 bytes increment from 0xFFFFFFFF to 0x00000000, the next four bytes are incremented; from 0x00FAFFFE to 0x00FAFFFF. Next the array is scanned for an invalid value such as 00 or 01. Scanning will stop at the first valid value as all following values must be valid. When a 00 is enocuntered it is reset to FA (250), in this example only. In the case of a 01, the function is exited as the odometer has expired.
When the penultimate array state of 0xFFFFFFFF 0x00FFFFFF is incremented, the end result is 0x00000000 0x01000000 which now contains the value 01; indicating the function must exit.