6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 6:12 pm

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Sat Apr 14, 2012 6:50 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
I've been asked for a clarification of this topic. (The topic begins here.) But right now I want to backtrack and lay out the basics of how dclxvi's 65816 six-cycle NEXT operates -- as I probably should have done in the first place! :roll: Then in an additional post (below) I'll touch on my hardware mod and the problem it solves.

Attachment:
RTS threading 0 rev1.gif
RTS threading 0 rev1.gif [ 10.27 KiB | Viewed 3523 times ]
In the lower part of this diagram there are three routines which I've named ROUTINE1, ROUTINE2, ROUTINE3. Of course they don't actually do anything because they're mostly NOPs. But we will see how they can be invoked in sequence by CALLER (at the top of the diagram). We want CALLER to execute ROUTINE1, ROUTINE2, ROUTINE3 (etc) almost as if we had explicitly coded JSR ROUTINE1, JSR ROUTINE2 and so on.

But CALLER has no JSR opcodes; it is just a list of addresses -- a form of Direct Threaded Code (DTC). For ease of discussion I've located ROUTINE1 at address 1111, ROUTINE2 at 2222 and so on. If we assume the 65816 Stack Pointer has been set to 3FFF and an RTS has been executed then we'll see the process set in motion. (Some of you will immediately grasp this, but here are the exact details.)

    The RTS pops the 16-bit value at ( SP+1 ) and increments SP by 2. The popped value goes to the PC, which is subsequently incremented by 1. In this case the 16-bit value at 4000 is 1110, so the PC ends up at 1111 -- the address of ROUTINE1. SP is left at 4001. Machine code is fetched and executed starting at 1111. When the work (represented by NOPs) is done the routine exits with an RTS.

    Again RTS pops the 16-bit value at (SP+1) and increments SP by 2. The popped value goes to the PC, which is subsequently incremented by 1. In this case the 16-bit value at 4002 is 2221, so the PC ends up at 2222 -- the address of ROUTINE2. SP is left at 4003. Machine code is fetched and executed starting at 2222. When the work is done the routine exits with an RTS.

    Again RTS pops (SP+1) and the pattern continues. SP is left at 4005 and machine code is fetched and executed starting at 3333. When the work is done ROUTINE3 exits with an RTS.

This demonstrates how the S register and RTS can be used as an Interpreter to "execute" a list of addresses. The advantage is that no JSR instructions are used -- only RTS. There is a substantial benefit in that the cost for each routine called is 2 bytes (not 3), and 6 cycles -- not 12 !

The S register in this setting acts as the "Interpretive Pointer," ie; the FORTH "program counter," and RTS is what vectors us to the NEXT routine to execute. FORTH implementations vary widely. dclxvi's use of SP and RTS is radically unusual.


Last edited by Dr Jefyll on Sun Mar 06, 2022 3:50 pm, edited 4 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 14, 2012 7:03 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
dclxvi wrote:
Your program is stored on the stack (!) which means that anything that pushes onto the stack will clobber your program
To illustrate this, let's run some scenarios (referring to the routines in the post above).
  • If an interrupt occurs during ROUTINE1, SP will be at 4001, which means 4001 (and the bytes below) is where the 65816 will save its PC and P registers.
  • If an interrupt occurs during ROUTINE2 then 4003 and the bytes below is where PC and P will get written.
  • If an interrupt occurs during ROUTINE3 then 4005 and the bytes below get written.
This is the "clobber your program" effect! We see that SP is unpredictable. But the region holding the address lists is guaranteed to take a hit. :?

The solution is to use the 65C816's facility for multiple 64K banks. For example, 4001 in Bank 0 is distinct from 4001 in any other bank, and that's what saves the day. All we have to do is tweak the CPU's policy of steering all stack-related operations to Bank 0. For example we allow the CPU use 400_ (whatever) in Bank 0 when an interrupt occurs, but the hardware mod forces activation of 400_ (whatever) in the Program Bank when RTS accesses the list. That's how we manage to use the SP register for two different functions.

What is perhaps counter-intuitive about the scheme is that SP is somewhat of a loose cannon; we have very little control over where interrupts will write to! All we know for sure is that PC and P will get saved in Bank 0, and it'll be somewhere in the region of Bank 0 that corresponds to the region that holds the address lists in the Program Bank. The diagram below illustrates the two corresponding regions.

The address lists might be a dozen or so Kbytes in size, and the corresponding Bank 0 region slightly larger -- certainly far more memory than any interrupt would need. Nevertheless, the uncertainly about SP forces us to reserve that amount solely for interrupt usage -- a wasteful yet reasonable tradeoff, given memory prices nowadays.

-- Jeff


Attachments:
RTS threading 1 .gif
RTS threading 1 .gif [ 17.04 KiB | Viewed 3897 times ]

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
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 3 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: