6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 16, 2024 12:14 pm

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: An algorithm for ROLL
PostPosted: Tue May 03, 2016 8:19 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
While reading Andrew's Forth for the 265SXB, I noticed that ROLL was "TODO" (https://github.com/andrew-jacobs/w65c81 ... -forth.asm). That's more than I did in Tali Forth, where I took one look at that word and decided to skip it, though it is CORE EXT (http://www.forth200x.org/documents/html ... #core:ROLL). This got got me thinking that I should man up and figure out how to implement it. I've come up with this algorithm as a suggestion.

We start with this model of what the Data Stack looks like:
Code:
   6  5  4  3  2  1  <- position on Data Stack, 1 is TOS and 2 is NOS
  0C 0A 08 04 02 00  <- offset in memory in bytes (+00 is TOS)

   E  D  C  B  A  n  <- situation before ROLL
Now, the Forth specs say that 0 ROLL is a null operation (which isn't really true, because n is dropped), 1 ROLL is SWAP and 2 ROLL is ROT. This gives us:
Code:
   6  5  4  3  2  1 
  0C 0A 08 04 02 00 

   E  D  C  B  A  n      ; starting stack for each of the following

      E  D  C  B  A      ; 0 ROLL ("null operation")
      E  D  C  A  B      ; 1 ROLL (SWAP)
      E  D  B  A  C      ; 2 ROLL (ROT)
      E  C  B  A  D      ; 3 ROLL
The two steps of the algrorithm are now:
Quote:
1. Move the stack entry at position (n+2) to position 1
2. Move every entry from (n+3) to the last entry up by one position
This works because any entries between positions 2 and (n+2) retain their stack positions, which is slightly counter-intuitive for how you usually think of stacks but works if you think about the memory positions.

I haven't gotten around to any code yet (stupid glorious sunshine means I'm outside in the garden), but I wanted to put that up here for discussion. Will add an implementation for testing as soon as I can.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2016 6:18 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
Yeah, ROLL is a cycle hog because of the move ... PICK is so much more desirable, and can be implemented in only two machine instructions plus a one machine instruction NEXT on my 65m32 DTC forth. When I get home, I'll see if I got around to coding ROLL in any of my unfinished forth projects, but I get the feeling that I put it off, due to the yucky feeling I get from dealing with something so inherently inefficient. Many hard-core Forthers don't like PICK or ROLL, but I think that PICK is a nice little hack inside a word that should probably be re-factored, but isn't, for whatever reason.

Mike B.

[PS: You're not really suggesting that the deepest stack items be moved to close the gap left during the ROLL, are you?]


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2016 7:05 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
This seems to work and isn't too monstrous
Code:
; ROLL ( xu xu-1 ... x0 u -- xu-1 ... x0 xu )
;
; Remove u. Rotate u+1 items on the top of the stack. An ambiguous condition
; exists if there are less than u+2 items on the stack before ROLL is executed.

                HEADER  4,"ROLL",NORMAL
ROLL:
                asl     <1                      ; Convert count to index
                ldx     <1
                beq     ROLL_2                  ; Zero? Nothing to do
                lda     <3,x                    ; Save the final value
                pha
ROLL_1:         lda     <1,x                    ; Move x-1 to x
                sta     <3,x
                dex                             ; And repeat
                dex
                bne     ROLL_1
                pla                             ; Recover the new top value
                sta     <3
ROLL_2:         jmp     DROP                    ; Drop the count

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 19, 2016 3:18 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
Here's the one from PETTIL, that weird Forth with the split stack and separate TOS. Garth has been suggesting it probably isn't very good from day one, but I just wouldn't listen and now I am really beginning to rethink this split stack with separate TOS vs. the traditional FIG stack with all that (zp,X) addressing vs just a split stack. Evidence is hard to come by.

Still, this code today is 6 bytes smaller than the 34 bytes it took up yesterday. Thanks for nudging me to look at it.
Code:
roll
    txa
    clc
    adc tos
    tax
    lda stackh,x
    pha
    lda stackl,x
    pha
roll01
    inx
    dec tos
    bmi rfrom01
    dex
    lda stackh-1,x
    sta stackh,x
    lda stackl-1,x
    sta stackl,x
    dex
    bne roll01          ; bra

rfrom
    jsr slip              ; slip something onto the stack -- this DUPs TOS onto the split stack
rfrom01
    pla
    sta tos
    pla
    sta tos+1
    jmp next


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 14, 2019 12:37 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
scotws wrote:
Now, the Forth specs say that 0 ROLL is a null operation (which isn't really true, because n is dropped), 1 ROLL is SWAP and 2 ROLL is ROT.

The specs do not say that ROLL is a null operation when the top of the stack is 0 ( zero) but that 0 ROLL is a null operation. The stack before 0 ROLL is the same as after 0 ROLL. The 0 and ROLL have to be considered together. ROT is not a null operation but ROT ROT ROT certainly is.
Oh and here is Fleet Forth's implementation of ROLL
Code:
SCR# 3B
// ROLL
HEX
CODE ROLL
   0 ,X LDA,  3F # AND,
   POP.JMP 0= BRAN,
   XSAVE STX,  .A ASL,  TAY,
   XSAVE ADC,
   POP.JMP 0< BRAN,
   TAX,  INX,  INX,
   0 ,X LDA,  PHA,  1 ,X LDA,  PHA,
   BEGIN,
      0FF ,X LDA,  1 ,X STA,
      DEX,  DEY,
   0= UNTIL,
   PLA,
   PUT JMP,  END-CODE

The branch to POP.JMP is a branch into ON
Code:
SCR# 3A
// ON OFF
HEX
CODE ON  ( N -- )
   DEY,  TYA,
   0 X) STA,  0 ,X INC,
   0= IF,  1 ,X INC,  THEN,
   0 X) STA,
   LABEL POP.JMP
   POP JMP,
END-CODE
CODE OFF  ( N -- )
   -2 ALLOT
   ' ON @ 1+ ,
END-CODE

Since this source is for a metacompiler, as opposed to a regular Forth assembler, using a label does not increase the target size ( it only exists on the host.)

Cheers,
Jim


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 4 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: