JeffSort on the 6502
Posted: Thu Mar 25, 2004 3:23 pm
After looking at the sorting algorithms in the Source Code Repository I was inspired to make a contribution myself. I choose to make an implementation of the JeffSort algorithm. (Not this one but this one!
)
It was done from memory before I found that page, so it might not be quite right.
On that page Jeff claims it's an O(1) algorithm, but as far as I can see it's really O(n)... but I'm not sure i remember how that O(x) stuff works so maybe I'm wrong... or maybe I've made a different sorting algorithm
Anyway, here is what I came up with:It seems to do what it's suposed to from my testing, but it's not unlikely I've missed something. I'm sure you guys could think of lots of optimizations, so if you have any sugestions, I'm all ears.
Oh, and I'm probably way off on that cycle count, so if anybody could check out that I would be gratefull. I think each additional element should add the same amount of extra time (except when going from 255 to 256 elements, a a few cycles is saved there because of the 6502s lack of BRA opcode
. Also, if there is 256 identical elements, then it will run a lot faster than when there is 256 varying elements because nothing gets written. That however only happens with 256 elements, not any fewer. I think, I'm probably wrong
)
Edit: Decided to include the code from Jeffs page to show what the algorithm is suposed to do:
Looking at that I realised that maybe I should have included rangehi and rangelo as parameters in my implementation to speed it up. And maybe I should do a version for signed numbers too...
It was done from memory before I found that page, so it might not be quite right.
On that page Jeff claims it's an O(1) algorithm, but as far as I can see it's really O(n)... but I'm not sure i remember how that O(x) stuff works so maybe I'm wrong... or maybe I've made a different sorting algorithm
Anyway, here is what I came up with:
Code: Select all
;
; JeffSort, an O(n) sort for small numbers, in 6502 assembly.
;
;
; Input: Pointer to buffer to be sorted in $FE.
; Number of elements in buffer (n) in register Y.
;
; Output: Sorted buffer starting at adress pointed to by $FE.
; Number of elements in buffer (n) in register Y and A.
; X=0.
;
; This version support a maximum of 256 8bit values.
; (Use Y=0 for 256 elements.)
;
; Estimated execution time, not including jsr/rts:
;
; 9987 + (n * 42) cycles
;
; That estimate may WAY off... It can be sped up a bit with loop
; unrolling and stuff like that, but that is left as an exercise
; for the reader :P
;
;
; Code is Copyright 2004 Erik Lien.
; Algorithm by Jeffrey Franklin.
;
; License: Use as you wish, but at your own risk.
;
!to "jeffsort.o"
buffer=$FE ;pointer to n byte buffer with values to be sorted.
temp=$C100 ;257 byte working buffer.
*=$C000
Sort lda #0
tax
clear sta temp,x ;Clear first 256 bytes of working buffer.
dex
bne clear
count dey ;Count how many elements there is of each type.
lda (buffer),y
tax
inc temp,x
cpy #0
bne count
ldx #0
fill tya
cmp temp,x
beq next
txa
sta (buffer),y
iny
bne fill
next lda temp,x
clc
adc temp+1,x ;Here is why temp has to be 257 bytes, not 256.
sta temp+1,x ;Easily fixed, but my fix added n*2 cycles, no good...
inx
bne fill
done rtsOh, and I'm probably way off on that cycle count, so if anybody could check out that I would be gratefull. I think each additional element should add the same amount of extra time (except when going from 255 to 256 elements, a a few cycles is saved there because of the 6502s lack of BRA opcode
Edit: Decided to include the code from Jeffs page to show what the algorithm is suposed to do:
Code: Select all
Algorithm: procedure JeffSort (var a: array of integer; lo, hi,
rangelo, rangehi: integer);
var
JeffCount: array [rangelo..rangehi] of integer;
i, j: integer;
begin
for i:=rangelo to rangehi do
JeffCount[i] := 0;
for i:=lo to hi do
inc (JeffCount[a[i]]);
for i:=rangelo to rangehi do
if (JeffCount[i] > 0) then
for j := 1 to JeffCount[i] do
begin
a[lo] := i;
inc (lo);
end;
end;