6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed May 08, 2024 2:28 pm

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Two 6502 Questions
PostPosted: Fri Dec 19, 2003 5:48 am 
Offline

Joined: Fri Dec 19, 2003 5:29 am
Posts: 2
1) I'm refering to multiple technical documents as I plod along the world of 6502, and I've discovered a conflict: In one doc, it tells me that ORA (Oper),Y instruction requires 5 cycles, always, while another one says that it requires 5 cycles plus one if a page file is crossed... which doc is right about this? im assuming that the latter one is true, and that you determine a page file cross by comparing where the program counter is now with where the value indirectly compared with A lies?

ie, say i type ORA ($1B), Y, with the following established:
byte value
$001B $00
$001C $2D
Y-reg. $05
$2D05 $6D

Assume the Program Counter currently points to $2000.

in this instance, would the instruction require 6 cycles (b/c a page file jump?) or would it require 5 cycles only? (and always?)



2) This is a two-part question (heh, nesting more questions)
2a. I know the stack keeps its values from 0x01FF down to 0x0100, and the tech doc I read about it said that means the stack can hold 128 values, but shouldn't that be 256 values? is it a typo on the author of the doc's part, or am I missing something?

***EDIT: I figured this one out on my own! the addresses are 16-bit, so you can only fit 128 of them on the stack! ***

2b. What occurs when you overflow the stack? (that is try to push a value when the stack pointer already points at 0x01FF?) are flags set? are interrupts called? do the communists invade? and when, timing wise, does the 6502 realize whats going on? and how?


i'll thank you guys ahead of time! These questions may be bone headed, but they're annoying the hell outta me!


Last edited by RedKnight on Fri Dec 19, 2003 7:10 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 19, 2003 6:56 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
For first question:
The extra clock is taken if the indexing takes you across a page boundary-- ie, if it causes the high byte of the resulting address to change. So if 1B points to 2DF0 and Y contained F, that takes you to 2DFF, which requires only the five clocks. But if Y contained 10, that would take you to 2E00, which is in the next page, so the extra clock is taken to increment the high byte of the resulting address. That takes you to six clocks. It has nothing to do with where the program counter is at the time. No 6502 instruction takes more than 6 clocks (except BRK since it's actually a type of interrupt and takes 7.)

For question 2a:
Yes, 100 to 1FF is 256 bytes. There' no point in grouping them in twos to say it's 128 cells or words, because individual bytes get put on the stack just as often as addresses. Then when you have an interrupt, the interrupt sequence puts the return address (two bytes) on the stack, followed by the status byte, for a total of three. The RTI does the reverse, taking three bytes off the stack.

For 2b:
When you overflow the stack, it wraps around. Your reset routine should normally initialize the stack pointer at FF, because the stack grows down. If you were to push enough onto the stack to get down to 100, the next push will go to 1FF, not 0FF. I've written 10,000-line programs and plenty of others of various shorter lengths though, and never needed anywhere near as much stack space as the 6502 provides.

When you overflow the stack, the processor would only be affected when you unwind and get clear back around to where the first things put on the stack got overwritten. Then things could get interesting, but more likely you'd just get a crash. The only times I've wrapped around were when an erroneous program got stuck in a loop endlessly pushing stuff onto the stack.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 19, 2003 7:41 am 
Offline

Joined: Fri Dec 19, 2003 5:29 am
Posts: 2
the way i test for a page boundary cross is that i take the address of the program counter, divide it by 256, then divide the new address by 256 and compare the two - if they're not the same, its a different page - this is valid, correct? (its integer division, so any pieces are just forgotten about)



ok, thanks for helping me out - one point of confusion - i was under the impression that certain instructions that use Absolute, X addressing require 7 clock cycles, for example INC or DEC $4400, X ... thats off the 6502 opcodes chart by John Picken that i found on this site... memory lapse on your part or mistake in the tech document?


and, again, thanks for helping me out about the stack thing - i'll code it so that if you hit 0x100, the entire program will just fatally crash with a nasty-sounding error message.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 19, 2003 9:13 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
You're right about crossing the page boundary, but the easy way is just look at the high bytes. If they're different, the two addresses are in different pages.

> i was under the impression that certain instructions that use Absolute, X
> addressing require 7 clock cycles, for example INC or DEC $4400, X ...

Oh, you're right-- the indexed read-modify-write intsructions where the page boundary is crossed.

> thats off the 6502 opcodes chart by John Picken that i found on this
> site... memory lapse on your part or mistake in the tech document?

Answer: A. However, IIRC, that's the one where he says one cycle is two phase-2 clocks, which is not true. When something like LDA # says it's two cycles, that's two microseconds (not four) at 1MHz.

> i'll code it so that if you hit 0x100, the entire program will just fatally
> crash with a nasty-sounding error message.

You'd either have to be continually checking (which would waste a lot of processor time), or have a hardware circuit that produces an interrupt if address 100 is ever accessed, or just accept that if it ever does happen, things will go out of control so you won't be able to give the nasty-sounding error message anyway. But if you only overwrite the first few bytes of the stack, you may not know it for a long time (unless you do indeed keep doing the wasteful checking). Since the the stack space is so much more than necessary, I usually initialize the stack at 1FF and put some of my variables in the other end of page 1.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Dec 20, 2003 6:19 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
RedKnight wrote:
the way i test for a page boundary cross is that i take the address of the program counter, divide it by 256, then divide the new address by 256 and compare the two - if they're not the same, its a different page - this is valid, correct? (its integer division, so any pieces are just forgotten about)


You would be correct to say that they are in different pages, but the page boundary isn't necessarily crossed.

Moreover, your test is invalid: the program counter has absolutely nothing what-so-ever to do with how long an instruction takes to execute. Once the instruction is inside the CPU, the value of the PC register is ignored. What determines a page boundary cross at this point is the data that the individual CPU instruction is working with. Garth gave a perfectly fine example in a previous post; I suggest studying his text again.

--
Samuel A. Falvo II


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Dec 20, 2003 8:11 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
Good grief, I missed that too. I guess I'll have to slow down and quit being in such a hurry. I basically said RedKnight's test was valid but just not the easy way to do it. Samuel's right. It does not matter where the program counter is at the time. In RedKnight's example, the processor reads addresses 001B and 001C, which tell it another address, 2D00. Then it adds the 5 from the Y register, and gets 2D05 for the effective address. This (going from 2D00 2D05) does not cross a page boundary even if the program pointer was at 2000. What takes the extra clock is incrementing the page number (2D in this case) if the addition of the low byte produced a carry. If 1B-1C contained 2D05 and Y contained FC, the sum would be 2E01, so the extra clock would be needed to take the high byte from 2D to 2E.

> Moreover, your test is invalid: the program counter has absolutely
> nothing what-so-ever to do with how long an instruction takes to execute.

I might add a little exception to this. A conditional relative branch instruction takes two clocks if the branch is not taken, and usually three if it is taken. But if the branch takes the program counter across a page boundary, it takes four clocks. Fortunately most branching takes you to another part of the same page, so only a small percentage of branches take four clocks. Why? Because A., you don't usually branch very far; and B., even maximum-length branches ($80 and $7F) only have a 50% chance of landing you in another page. If exact cycle count were important for a timing loop, you would have to pay attention to this and possibly use an assembler directive to alert you in the unlikely event of a page-boundary crossing with such a branch, or use a conditional assembly to take care of it automatically.


> ***EDIT: I figured this one out on my own! the addresses are 16-bit,
> so you can only fit 128 of them on the stack! ***

Forget about that, because you don't just put addresses on the stack. You can store individual registers (A, X, Y, and P), you can pass parameters of any size on the stack, and even an interrupt puts an odd number of bytes (three) on the stack. The number of bytes on the stack has only a 50% chance of being even, and having for example $24 bytes on the stack means virtually nothing about how many little packets of information are there. The chances that it'd be $12 are pretty slim, so you can't automatically assume.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 30, 2003 10:49 am 
Offline

Joined: Tue Dec 30, 2003 10:35 am
Posts: 42
If page 1 ($100-$1FF) won't be used for anything but the stack, there's no need to initialize the stack pointer to any definite value for proper operation. The stack will overflow only when more than 256 bytes are pushed on it regardless of where the top is; wrap-around of the pointer doesn't affect the logical operation in any way.

Some benefits of initialization do come to mind:
- Predictability when debugging
- Possible use of lower part of page 1 for data storage
- Much easier access to stack parameters

The last reason needs a little bit of elaboration. By transferring the stack pointer to X, stack parameters can easily be accessed using indexed addressing:

Code:
tsx
lda $100+offset,x ; offset constant selects which parameter


This will fail if the stack pointer wrapped around partway through pushing the parameters for this routine. For example, the most recently pushed byte might be at $1FF, which would place the next at $100, then $101, etc. This is a good reason to initialize the stack pointer to $1FF (S = $FF) at startup.


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 8 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: