6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed May 15, 2024 9:01 am

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Sun Jan 09, 2022 10:22 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
* Shell-Metzner Sort (133 bytes)
* based on 65816 instructions - but 6502 sort (187 bytes) available on request

* The only caveat is that all strings or numbers have to be the same length
* totally relocatable within bank #0 in the first 64kb of mem
* uses zero-page, not Direct page
* this sort is good for sorting dates (YY/MM/DD), variables & addresses of fixed length
* but will take a little more programming to modify for strings of varying lengths

Code:
* Enter these 5 entries before calling
STRLEN      = $00   ; length of strings
STRTPOSN   = $02   ; start position in string
NUMCHARS   = $04   ; # of chars to compare
NUMENTRY   = $06   ; # of words in list
STRTMEM   = $08   ; starting address of word list

ENDPOSN   = $0A
INTERMED   = $0C

LO_CNT      = $E0
HI_CNT      = $E2
FVAR      = $E4
PVAR      = $E6
LO_PTR      = $E8
HI_PTR      = $EA

        ORG  ????     ; did I mention it is totally relocatable?

   CLC
   XCE
   REP #$30

   CLC
   LDA STRTPOSN
   ADC NUMCHARS
   STA ENDPOSN

   LDA NUMENTRY   ; I=N
   STA INTERMED

L200F   LSR INTERMED   ; I=INT (I/2)
   BNE L201D
   RTS

* always start comparing with word at midpoint
L201D   SEC   
   LDA NUMENTRY   ; # of entries   
   SBC INTERMED
   STA FVAR   ; F = N - I

   LDA #0
L2034   STA PVAR   : P=P+1
L2038   STA LO_CNT   ; L=P

* get half-way point

   CLC      ; H=L+I
   ADC INTERMED   ; add half way point
   STA HI_CNT   : Hi counter

* this is a multiply by max # of chars in string

   LDA #0   
   LDY STRLEN
   BEQ ADDLO

]LP   ADC LO_CNT
   DEY
   BNE ]LP   ; always

ADDLO   ADC STRTMEM
   STA LO_PTR

   LDA #0
   LDY STRLEN
   BEQ ADDHI

]LP   ADC HI_CNT
   DEY
   BNE ]LP   ; always

ADDHI   ADC STRTMEM
   STA   HI_PTR
   
COMPARE SEP #$30
   LDY STRTPOSN
]LP   LDA (HI_PTR),Y   ; is STR$(H)<STR$(L)?
   CMP (LO_PTR),Y
   BCC L209B   ; yes, go swap
   BNE L20C3   ; no, but they are also not the same

   INY
   CPY ENDPOSN   ; last position to check
   BNE ]LP

L20C3   LDA PVAR   ; P=P+1
   INC
   CMP FVAR   : is P>F
   BCC L2034   ; no, goto STA Pvar : STA LO
   BEQ L2034   ; no, goto STA Pvar : STA LO
   BNE L200F   ; yes, goto I=I/2


*Swap strings

L209B   LDY STRLEN   ; Y= max string length
   DEY      ; make from 1- to 0-
]LP   LDA (LO_PTR),Y
   TAX
   LDA (HI_PTR),Y
   STA (LO_PTR),Y
   TXA
   STA (HI_PTR),Y

   DEY
   BPL ]LP
   REP #$30

NEXT   SEC
   LDA LO_CNT   ; L=L-I
   SBC INTERMED   ; INTERMEDIATE
   BMI L20C3   ; if <0 goto P=P+1
   BNE L2038   ; if >0 goto STA LO_CNT: H=L+I
   BRA L20C3   ; if =0 goto P=P+1


Last edited by IamRob on Mon Jan 10, 2022 5:21 pm, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 11:10 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8183
Location: Midwestern USA
Here's a more readable version with some added comments:

Code:
STRLEN   = $00                 ; length of strings
STRTPOSN = $02                 ; start position in string
NUMCHARS = $04                 ; # of chars to compare
NUMENTRY = $06                 ; # of words in list
STRTMEM  = $08                 ; starting address of word list...

;   STRTMEM has to be a 24-bit location if this code is
;   to work on a system with extended memory.

ENDPOSN  = $0A

;   ENDPOSN has to be a 24-bit location if this code is
;   to work on a system with extended memory.

INTERMED = $0C

;   INTERMED has to be a 24-bit location if this code is
;   to work on a system with extended memory.


;   The below assignments must be 24-bits to
;   work on a system with extended memory.

LO_CNT   = $E0
HI_CNT   = $E2
FVAR     = $E4
PVAR     = $E6
LO_PTR   = $E8
HI_PTR   = $EA

         ORG ????              ; did I mention it is totally relocatable?

;   Yes, the code is relocatable, but as written, will not
;   work on a system with extended memory.  Also, you
;   should temporarily relocate direct page to the stack &
;   thus localize DP usage.

         CLC                   ;must be...
         XCE                   ;in native mode
         REP #%00110000        ;16-bit registers

         CLC
         LDA STRTPOSN
         ADC NUMCHARS
         STA ENDPOSN

         LDA NUMENTRY          ; I=N
         STA INTERMED

L200F    LSR INTERMED          ; I=INT (I/2)
         BNE L201D
         RTS

;   always start comparing with word at midpoint

L201D    SEC
         LDA NUMENTRY          ; # of entries
         SBC INTERMED
         STA FVAR              ; F = N - I

         LDA #0
L2034    STA PVAR              : P=P+1
L2038    STA LO_CNT            ; L=P

;   get half-way point

         CLC                   ; H=L+I
         ADC INTERMED          ; add half way point
         STA HI_CNT            : Hi counter

;   this is a multiply by max # of chars in string

         LDA #0
         LDY LO_CNT
         BEQ ADDLO

]LP      ADC STRLEN
         DEY
         BNE ]LP               ; always

ADDLO    ADC STRTMEM
         STA LO_PTR

         LDA #0
         LDY HI_CNT
         BEQ ADDHI

]LP      ADC STRLEN
         DEY
         BNE ]LP               ; always

ADDHI    ADC STRTMEM
         STA HI_PTR


COMPARE  SEP #%00110000        ;8-bit registers
         LDY STRTPOSN
]LP      LDA (HI_PTR),Y        ; is STR$(H)<STR$(L)?
         CMP (LO_PTR),Y
         BCC L209B             ; yes, go swap
         BNE L20C3             ; no, but they are also not the same

         INY
         CPY ENDPOSN           ; last position to check
         BNE ]LP

L20C3    LDA PVAR              ; P=P+1
         INC
         CMP FVAR              : is P>F
         BCC L2034             ; no, goto STA Pvar : STA LO
         BEQ L2034             ; no, goto STA Pvar : STA LO
         BNE L200F             ; yes, goto I=I/2


;   Swap strings

L209B    LDY STRLEN            ; Y= max string length
         DEY                   ; make from 1- to 0-
]LP      LDA (LO_PTR),Y
         TAX
         LDA (HI_PTR),Y
         STA (LO_PTR),Y
         TXA
         STA (HI_PTR),Y

         DEY
         BPL ]LP
         REP #%00110000        ;16-bit registers

NEXT SEC
         LDA LO_CNT            ; L=L-I
         SBC INTERMED          ; INTERMEDIATE
         BMI L20C3             ; if <0 goto P=P+1
         BNE L2038             ; if >0 goto STA LO_CNT: H=L+I
         BRA L20C3             ; if =0 goto P=P+1

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 12:49 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1929
Location: Sacramento, CA, USA
Where's the FORTH?

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 12:53 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 858

Good question.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 1:01 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8183
Location: Midwestern USA
barrym95838 wrote:
Where's the FORTH?

I was wondering about that as well. I suppose it could be used to sort user-defined words so lookup functions can use a binary search on them.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 1:14 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 858

IamRob did mention using an insertion sort in his Forth; however, a brief mention that this was for his Forth would have been nice.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 4:13 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
That is why I posted it here.

Due to its small size, easy setup and relocatability, I thought it would almost be perfect as a primitive as a Forth word. In one of my other threads "Making Forth words into primitives", a lot of code is getting tightly packed to make an efficient Forth. Which means, the dictionary of words itself has to be separate from the code. One of the two ways to implement this was to sort the dictionary and use a binary search to find the Word and its entry point. This way eliminates the need for links, while the other way includes using links still.

Granted, without links one also loses the ability to have vocabularies, but with very packed code, not only allows for header-less words, it also makes it much easier to make stand-alone Forth applications, which is one of my goals.

I didn't mention too much about this method possibly being used with or in Forth because I still feel like I am the amateur to Forth in this group. Everyone else here is already moved on to 32-bit and/or Ansi Forths and using expanded memory. Everyone here would know better than me if this is something that they could benefit from.

Also, if someone more experienced in 65816 programming could test drive it and approve it, I will send if off to the moderator to have it listed under the CODE heading at the top under the 6502.org menus.

Hopefully this is a win-win for somebody. Nobody should have anything to lose and Everybody might at least be interested.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: