6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Apr 28, 2024 12:04 pm

All times are UTC




Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Mon Jan 07, 2019 10:26 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1399
Location: Scotland
Not sure the best place to post this, so here it is...

I was tripped up recently in my Ruby 6502 SBC when using WAI.

WAI is great - I use it to communicate with my host processor (ATmega) which pulls BE low to grab the 6502 bus and then pings back with an IRQ to get the 6502 going again. (I detect WAI on the host by reading the Rdy line)

Enter NMI... NMI during WAI kick-starts the 6502 and it vectors off to the NMI vector, runs the NMI code and returns to the WAI. Great! Except when the 6502 is held in /BE mode, then it reads whatever comes off the tri-stated input data lines, ends up in never never land ...

So just mentioning this in-case anyone else starts to see unpredictable behaviour if using this scenario (WAI with /BE) in the vague hope a google, etc. search lands them here. The upshot is that letting the 6502 run when BE is low is not a good thing, and it will run if it gets an NMI or IRQ while BE is held low during WAI with nothing external also holding Rdy low.

So now when I detect Rdy low, I immediately pull it low to force the 6502 to halt for the duration, but it's introducing latency into my NMI code, so working on a plan B, however it does work. Host lets BE go high, then lets Rdy go high, 6502 immediately vectors off to do the NMI (if an NMI happened), then returns to the WAI where it finds IRQ low so carries on at the next instruction.

Cheers,

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 07, 2019 6:15 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8147
Location: Midwestern USA
drogon wrote:
I was tripped up recently in my Ruby 6502 SBC when using WAI...Enter NMI... NMI during WAI kick-starts the 6502 and it vectors off to the NMI vector, runs the NMI code and returns to the WAI.

You should be able to avoid this behavior by disabling IRQs immediately before executing the WAI instruction. When an IRQ or NMI hits, the MPU will restart at the instruction immediately following WAI and will not take the IRQ or NMI vector.

Code:
;alternate usage of WAI instruction
;
         sei                   ;disable IRQs
         wai                   ;halt MPU & WAIt for IRQ or NMI
         nop                   ;execution continues here upon IRQ or NMI...
                               ;IRQ or NMI vector is not taken

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


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 07, 2019 6:35 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Yes, RDY needs to be qualified by BE. The bidirectionality of the RDY pin can be a bit of a pain in this respect.

To restore your NMI latency, you'll need to make your coprocessor notice /NMI being asserted and voluntarily release the bus.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 07, 2019 8:42 pm 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1399
Location: Scotland
BigDumbDinosaur wrote:
drogon wrote:
I was tripped up recently in my Ruby 6502 SBC when using WAI...Enter NMI... NMI during WAI kick-starts the 6502 and it vectors off to the NMI vector, runs the NMI code and returns to the WAI.

You should be able to avoid this behavior by disabling IRQs immediately before executing the WAI instruction. When an IRQ or NMI hits, the MPU will restart at the instruction immediately following WAI and will not take the IRQ or NMI vector.


I do. Actually, I don't, but since I never enable the IRQ interrupt anywhere, it's the same thing. I'm taking full advantage of the zero latency interrupt thingy.

But you've got me thinking now and I may need to do some more tests - however - the net effect is the same - if the 6502 wakes up (unexpectedly due to NMI) while the host has BE pulled low then it's going to come to no good whatsoever. I'm fairly confident that the NMI is taken via it's vector though - it's being generated by a timer on a 6522 and if you don't read the bottom byte of the counter then it doesn't fire again (in free running mode) and it keeps on going...

I'm using BE as I have an area of shared RAM that I use between the 6502 and the host for comms - serial, etc. so right now the scenario is that I poll on the host for Rdy going low (WAI executed), then pull Rdy low, then pull BE low, then do the transaction, release BE then Rdy then wait for the next Rdy low. If an NMI comes in while I have Rdy pulled low then it's "remembered" until it goes high, then taken. (There is only one NMI source and if it's not serviced then it stops, so easy to tell if it's ever missed) Latency might be an issue if it were something other than a little hobby/vanity project but I'm happy that it just keeps on counting.

Cheers,

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 07, 2019 8:46 pm 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1399
Location: Scotland
Chromatix wrote:
Yes, RDY needs to be qualified by BE. The bidirectionality of the RDY pin can be a bit of a pain in this respect.


It's not that tricky to manage though - the host is an ATmega, so at power-up, I put the pin into output mode and set it low. Then change it to input mode to listen for Rdy being pulled low by the 6502 and at that point, I just change the pin to output mode and the previously set 0 output is remembered. I didn't need to pull it low by the ATmega until I started to fiddle with NMI though.

(The Rdy pin has a 3k3 pull-up)

Cheers,

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 10, 2023 10:19 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 703
Location: Texas
Older topic here, but I have a question.

BigDumbDinosaur wrote:
When an IRQ or NMI hits, the MPU will restart at the instruction immediately following WAI and will not take the IRQ or NMI vector.


If you use SEI, then the IRQ interrupt vector won't be taken, but an NMI interrupt will jump to the NMI vector still, correct?

Also, since I'm here talking about it, on the 65816 datasheet (can't find it on the 6502 datasheet), there is a 'cycle by cycle' section [ screenshots below ]. For the WAI command, there is a 'setup time' between the processor seeing the WAI command, and then doing it's thing to shut down and bring RDY low. But while it's doing that, if NMI falls, wouldn't it automatically jump to the NMI vector when it's done with it's WAI command stuff? As in, in the 2 cycles between the processor seeing WAI and having RDY go low, an NMI would make the processor keep going and it might (or might not) just simply *toggle* the RDY line. Am I right here?

Code:
Normal operation...
Cycle 1: 6502 sees WAI command, RDY is high
Cycle 2: Internal processes, RDY is still high
Cycle 3: 6502 stops and now brings RDY low
Cycle 4+: 6502 sees NMI fall, jumps to vector, 6502 is in NMI ISR.

But what if...
Cycle 1: 6502 sees WAI command, RDY is high
Cycle 1.5: /NMI falls, triggering an interrupt after the next instruction is finished(?)
Cycle 2: Internal processes, RDY is still high
Cycle 3: 6502 stops, but then starts back up, jumps to vector, RDY toggles(?)
Cycle 4+: 6502 is in NMI ISR.


Thoughts?

Thank you.

Chad


Attachments:
WAI1.png
WAI1.png [ 15.58 KiB | Viewed 6358 times ]
WAI2.png
WAI2.png [ 5.68 KiB | Viewed 6358 times ]
Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 10, 2023 10:28 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
My understanding is that it takes 1-2 cycles for the IRQ or NMI to make its way through to the point that it can cause an interrupt sequence on the next instruction fetch cycle. I suspect this is metastability protection, and I'd guess that it also takes that time to unblock WAI's second cycle. Then I'd expect the NMI sequence will occur on the next instruction fetch, as would an IRQ sequence if the interrupt disable bit was clear.

A few months ago I took some oscilloscope traces of this sort of thing, showing IRQ, RDY, PHI2, and SYNC I think. I'll see if I can find that thread and link it. Edit: here: viewtopic.php?f=4&t=7732 The scope trace in my second post show the details. But not what happens if an interrupt happens in the early stages of WAI. I do have a test rig that I could use quite easily to analyse that, deliberately triggering interrupts at various points relative to the WAI instruction.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 10, 2023 11:12 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 703
Location: Texas
gfoot wrote:
My understanding is that it takes 1-2 cycles for the IRQ or NMI to make its way through to the point that it can cause an interrupt sequence on the next instruction fetch cycle. I suspect this is metastability protection, and I'd guess that it also takes that time to unblock WAI's second cycle. Then I'd expect the NMI sequence will occur on the next instruction fetch, as would an IRQ sequence if the interrupt disable bit was clear.

A few months ago I took some oscilloscope traces of this sort of thing, showing IRQ, RDY, PHI2, and SYNC I think. I'll see if I can find that thread and link it. Edit: here: viewtopic.php?f=4&t=7732 The scope trace in my second post show the details. But not what happens if an interrupt happens in the early stages of WAI. I do have a test rig that I could use quite easily to analyse that, deliberately triggering interrupts at various points relative to the WAI instruction.


That link was super excellent. It seems Gordon was having this issue I'm talking about, at least I believe that's what is going on.

If anyone else has more info I'd love to hear it. Right now I'm going to assume that a falling NMI between the 6502 reading WAI and driving RDY low will still cause it to jump to the NMI vector. But what does RDY look like? Does it stay high, or does it toggle within a half-cycle? Or does it stay low for a cycle or two?

Thank you George!

Chad


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 11, 2023 12:18 am 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
sburrow wrote:
If anyone else has more info I'd love to hear it. Right now I'm going to assume that a falling NMI between the 6502 reading WAI and driving RDY low will still cause it to jump to the NMI vector. But what does RDY look like? Does it stay high, or does it toggle within a half-cycle? Or does it stay low for a cycle or two?

Here are the results of some tests using my Arduino rig. This was executing the sequence:

Code:
    NOP
    WAI
    TXS

I triggered NMI in the middle of both phases of the clock, covering a few cycles either side of the WAI instruction. All samples and signal transitions take place halfway through the high or low phase.

Case 1 - NMI occured early enough to be processed before the WAI instruction (one and a half cycles before the WAI instruction's SYNC cycle):
Code:
  20 H R  -n  -S  000a  R  ea   <= NMI pulse
  21 l R  --  --  000b  R  cb
  21 H R  --  --  000b  R  cb
  22 l R  --  -S  000b  R  cb   <= NMI interrupt sequence on WAI's SYNC cycle
  22 H R  --  -S  000b  R  cb
  23 l R  --  --  000b  R  cb
  23 H R  --  --  000b  R  cb
  24 l R  --  --  01ff  w  cb
  24 H R  --  --  01ff  w  00
  25 l R  --  --  01fe  w  00
  25 H R  --  --  01fe  w  0b
  26 l R  --  --  01fd  w  0b
  26 H R  --  --  01fd  w  22
  27 l R  --  v-  fffa  R  00
  27 H R  --  v-  fffa  R  00
  28 l R  --  v-  fffb  R  00
  28 H R  --  v-  fffb  R  00
  29 l R  --  -S  0000  R  e6   <= ISR starts
  29 H R  --  -S  0000  R  e6
  30 l R  --  --  0001  R  ff
  30 H R  --  --  0001  R  ff
  31 l R  --  --  00ff  R  00
  31 H R  --  --  00ff  R  00
  32 l R  --  --  00ff  R  00
  32 H R  --  --  00ff  R  00
  33 l R  --  --  00ff  w  00
  33 H R  --  --  00ff  w  01
  34 l R  --  -S  0002  R  40   <= RTI
  34 H R  --  -S  0002  R  40
  35 l R  --  --  0003  R  a2
  35 H R  --  --  0003  R  a2
  36 l R  --  --  01fc  R  00
  36 H R  --  --  01fc  R  00
  37 l R  --  --  01fd  R  22
  37 H R  --  --  01fd  R  22
  38 l R  --  --  01fe  R  0b
  38 H R  --  --  01fe  R  0b
  39 l R  --  --  01ff  R  00
  39 H R  --  --  01ff  R  00
  40 l R  --  -S  000b  R  cb   <= WAI cycle 1
  40 H R  --  -S  000b  R  cb
  41 l R  --  --  000c  R  9a   <= WAI cycle 2
  41 H -  --  --  000c  R  9a   <= RDY goes low
  42 l -  --  --  000c  R  9a   <= WAI cycle 2, take 2
  42 H -  --  --  000c  R  9a


Case 2 - one half cycle later; now WAI executes, and NMI is picked up a little later:
Code:
  21 l R  -n  --  000b  R  cb   <= NMI pulse
  21 H R  --  --  000b  R  cb
  22 l R  --  -S  000b  R  cb   <= WAI cycle 1
  22 H R  --  -S  000b  R  cb
  23 l R  --  --  000c  R  9a   <= WAI cycle 2
  23 H R  --  --  000c  R  9a   <= RDY didn't go low at all
  24 l R  --  --  000c  R  9a   <= WAI cycle 3
  24 H R  --  --  000c  R  9a
  25 l R  --  -S  000c  R  9a   <= NMI sequence
  25 H R  --  -S  000c  R  9a
  26 l R  --  --  000c  R  9a
  26 H R  --  --  000c  R  9a
  27 l R  --  --  01ff  w  9a
  27 H R  --  --  01ff  w  00
  28 l R  --  --  01fe  w  00
  28 H R  --  --  01fe  w  0c
  29 l R  --  --  01fd  w  0c
  29 H R  --  --  01fd  w  22
  30 l R  --  v-  fffa  R  00
  30 H R  --  v-  fffa  R  00
  31 l R  --  v-  fffb  R  00
  31 H R  --  v-  fffb  R  00
  32 l R  --  -S  0000  R  e6   <= ISR
  32 H R  --  -S  0000  R  e6
  33 l R  --  --  0001  R  ff
  33 H R  --  --  0001  R  ff
  34 l R  --  --  00ff  R  00
  34 H R  --  --  00ff  R  00
  35 l R  --  --  00ff  R  00
  35 H R  --  --  00ff  R  00
  36 l R  --  --  00ff  w  00
  36 H R  --  --  00ff  w  01
  37 l R  --  -S  0002  R  40   <= RTI
  37 H R  --  -S  0002  R  40
  38 l R  --  --  0003  R  a2
  38 H R  --  --  0003  R  a2
  39 l R  --  --  01fc  R  00
  39 H R  --  --  01fc  R  00
  40 l R  --  --  01fd  R  22
  40 H R  --  --  01fd  R  22
  41 l R  --  --  01fe  R  0c
  41 H R  --  --  01fe  R  0c
  42 l R  --  --  01ff  R  00
  42 H R  --  --  01ff  R  00
  43 l R  --  -S  000c  R  9a   <= instruction after WAI (TXS)
  43 H R  --  -S  000c  R  9a
  44 l R  --  --  000d  R  8e
  44 H R  --  --  000d  R  8e


Case 3 - NMI occurs during low phase of WAI cycle 2 - this is the earliest it can occur while still seeing RDY go low at least for half a cycle:
Code:
  22 l R  --  -S  000b  R  cb   <= WAI cycle 1
  22 H R  --  -S  000b  R  cb
  23 l R  -n  --  000c  R  9a   <= WAI cycle 2, NMI pulse
  23 H -  --  --  000c  R  9a   <= RDY goes low
  24 l R  --  --  000c  R  9a   <= WAI cycle 2 take 2, RDY goes high
  24 H R  --  --  000c  R  9a
  25 l R  --  --  000c  R  9a   <= WAI cycle 3
  25 H R  --  --  000c  R  9a
  26 l R  --  -S  000c  R  9a   <= NMI sequence
  26 H R  --  -S  000c  R  9a


Case 4 - NMI occurs several cycles after WAI, during the high phase of the clock:
Code:
  22 l R  --  -S  000b  R  cb   <= WAI cycle 1
  22 H R  --  -S  000b  R  cb
  23 l R  --  --  000c  R  9a   <= WAI cycle 2
  23 H -  --  --  000c  R  9a   <= RDY goes low
  24 l -  --  --  000c  R  9a   <= WAI cycle 2, take 2
  24 H -  -n  --  000c  R  9a   <= NMI pulse
  25 l R  --  --  000c  R  9a   <= WAI cycle 2, take 3 - RDY is high now
  25 H R  --  --  000c  R  9a
  26 l R  --  --  000c  R  9a   <= WAI cycle 3
  26 H R  --  --  000c  R  9a
  27 l R  --  -S  000c  R  9a   <= NMI sequence
  27 H R  --  -S  000c  R  9a


Case 5 - NMI occurs one half-cycle later again, during the low phase of the clock:
Code:
  22 l R  --  -S  000b  R  cb   <= WAI cycle 1
  22 H R  --  -S  000b  R  cb
  23 l R  --  --  000c  R  9a   <= WAI cycle 2
  23 H -  --  --  000c  R  9a   <= RDY goes low
  24 l -  --  --  000c  R  9a   <= WAI cycle 2 take 2
  24 H -  --  --  000c  R  9a
  25 l -  -n  --  000c  R  9a   <= WAI cycle 2 take 3, NMI pulse
  25 H -  --  --  000c  R  9a
  26 l R  --  --  000c  R  9a   <= WAI cycle 2 take 4, RDY goes high
  26 H R  --  --  000c  R  9a
  27 l R  --  --  000c  R  9a   <= WAI cycle 3
  27 H R  --  --  000c  R  9a
  28 l R  --  -S  000c  R  9a   <= NMI sequence
  28 H R  --  -S  000c  R  9a


In my notes above, I'm guessing where WAI's cycle 3 is because it's no different than cycle 2 as far as the external signals look. But I'm assuming cycle 2 is the only one that can repeat.

Overall, I think that as for any other instruction, if NMI occurs one-and-a-half clock cycles before the instruction's SYNC cycle, then the NMI sequence happens instead of the instruction, and the instruction waits until after the NMI handler has run. If NMI occurs later than that, then the instruction begins as usual.

In WAI's case, it looks like with an NMI that's early enough, RDY doesn't go low at all - however, I am only sampling it halfway through the high or low periods of the clock, I'm not watching for edges, and it's possible that it dips briefly then goes up again, e.g. on the rising edge of the PHI2 clock. I'm pretty sure I did observe this in my oscilloscope traces in the other post.

In general for WAI, after cycle 2 and RDY has gone low, then after an interrupt, on the next falling edge of the clock RDY will go high again, then cycle 2 will execute one more time, then cycle 3, then the WAI instruction has finished, and the interrupt interrupts the following instruction (if it's not masked). After the RTI control returns to that next instruction.

Note the edge case that it's possible for NMI to happen before RDY goes low, yet still have RDY go low for half a cycle.


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 11, 2023 1:08 am 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 703
Location: Texas
Wow George, that is a VERY detailed response. Thank you so much for that!

Like you said, it *can* go low, but it also *can* stay high, depending on when it falls. Also, as you said, it could possibly toggle in between a half-cycle, but still, it's interesting to see this behavior.

Ok, good to know! I'm rethinking my plans using NMI and WAI together. Thank you George. I hope this data is useful to some other folks out there!

Chad


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 11, 2023 1:44 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
A related topic from almost eight years ago is at viewtopic.php?f=4&t=4129 .

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 16, 2023 11:49 am 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
GARTHWILSON wrote:
A related topic from almost eight years ago is at viewtopic.php?f=4&t=4129 .

Hi Garth, I meant to ask but forgot - what was this tester you were using, did you publish the details anywhere?


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 16, 2023 7:29 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
gfoot wrote:
GARTHWILSON wrote:
A related topic from almost eight years ago is at viewtopic.php?f=4&t=4129 .

Hi Garth, I meant to ask but forgot - what was this tester you were using, did you publish the details anywhere?

I have not published any details.  I'd have to clean up my notes and diagrams quite a bit to make them presentable.  I built it up on perfboard, with a board-edge connector to use with my workbench computer, so VIAs on the latter twiddle or monitor the various pins of the processor I'm testing, under software control on the workbench computer.  I could feed the DUT an instruction, twiddle the clock line, and change the state of an interrupt input for example, stopping every half cycle to decide what I wanted to do next, depending on what I observed.  So as you can imagine, it was very slow that way, but would never get ahead of me, and I had total control.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


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

All times are UTC


Who is online

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