6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Sep 19, 2024 10:08 pm

All times are UTC




Post new topic Reply to topic  [ 26 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Sun Aug 22, 2021 7:59 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1466
Location: Scotland
gfoot wrote:
drogon wrote:
I now know this doesn't work, so I have another solution that does work - it's driven from the 65C02 which executes a WAI instruction, which stops the 65C02 and sets Rdy low which the Atmega detects and does what it needs to do (bring BE low, etc. ) and finished off by sending an NMI to the 65C02 to wake it from WAI.

I think you need to be careful with relying on the WAI here -


Just to be clear here - I've been doing it that way for a long time now (18 months+) and it works very well. I do know what's going on in my current system and yes, there was an issue with asynchronous IRQs but I solved that - this is for a new system.

Thanks,

-Gordon

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 22, 2021 11:28 am 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 727
Location: Tokyo, Japan
BigDumbDinosaur wrote:
...I think you'd have to stop the MPU when SYNC is high....which indicates an opcode fetch is occurring. Stopping the MPU during an opcode fetch should always be safe. Stopping the MPU during an operand fetch or any other step in the current instruction may causing trouble.

This sounded right to me, too, until I went to look at the C64 and released that not only does it not bring SYNC out to the cartridge port (used for DMA by at least the REU), but the 6810 doesn't even have a SYNC output in any of its versions.

I don't know if they might have made other changes from the 6502 internal design that would make it safer to deassert RDY at any time. The data sheet timing diagrams make no mention of RDY that I can see, nor does even the pin descriptions page.

_________________
Curt J. Sampson - github.com/0cjs


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 22, 2021 12:21 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
I might be going backwards here, but I think
- RDY is a synchronous input and needs to be stable fore and aft of the falling edge of the clock. It can be convenient but isn't necessary to use the rising edge of the clock to help with that
- I think all NMOS variants will be ignoring RDY for writes
- CMOS variants of 6502 will be honouring RDY for writes
- but GTE's 65816, at least, honours RDY for writes only in native mode, not emulation mode. Yikes.

I did wonder if Acorn's Communicator would tell us anything, but I can't find a schematic. But, as the glue logic is very like that for their Electron, most likely the clock is stopped when needed, and RDY is not used.

Because RDY is synchronous, that makes it ambiguous to talk about whether or not it's safe to use at any time. I think what we mean is any cycle. SYNC is indeed a safe cycle, as it's always a read, and for some purposes it's worth waiting for a SYNC. However, sometimes there won't be a SYNC often enough, and sometimes there's no SYNC pin, so this is an example of a very simple tactic which is by no means always useful.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 22, 2021 2:40 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
drogon wrote:
I wanted to poke data into the memory window while the 65C02 was running, so thought initially that if I simply pulled Rdy low, then pulled BE low, then did the Atmega stuff to latch onto the RAM, store the data then do the reverse, the 6502 would not notice anything but "magically" would see new data.

I now know this doesn't work
Right. And forgive me for temporarily rewinding this somewhat fragmented discussion to where we were yesterday.

I think we now all understand that the original approach you describe failed because of occasions when the ATmega would happen to update RDY at an inappropriate time in the 'C02 cycle. Because the ATmega and the 'C02 run from different clock sources, every update by the ATmega to RDY runs a small risk of occurring during the brief interval (defined by tPCS and tPCH) during which RDY cannot safely be changed.


drogon wrote:
I think I might just leave this to rest for a while
Ok, but here a simple remedy you may wish to consider. Can you arrange to have both the ATmega and the 'C02 driven by the same clock source? IOW, either use the 'C02 clock to drive the ATmega, or vice versa.

Sorry for not thinking of this sooner. Somehow I had the idea the ATmega was running at dozens or hundreds of MHz (as do some of the Pi's, Arduinos and whatnot). But I belated noticed you have both CPU's running at 16 MHz.

If you connect both CPU's to the same clock source then there'll no longer be any variability regarding when in the 'C02 cycle the RDY signal gets updated, and the frustrating random failures you experienced will cease. With the variability removed, there's little or no remaining challenge. tPCS and tPCH will either be consistently satisfied or -- much less likely -- consistently violated. If it's the latter, just insert an inverter in the path to one clock input or the other.

-- Jeff

_________________
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  
PostPosted: Sun Aug 22, 2021 4:33 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
BigEd wrote:
for some purposes it's worth waiting for a SYNC.
Yes -- for some purposes but not all. And (if I understand you correctly) you're suggesting Gordon's case isn't one that requires waiting for SYNC. I tend to agree, but as I was writing this post I did have one nagging second thought.

I'm tempted to say it simply doesn't matter what the 'C02 is doing -- fetching an opcode or any other activity -- when it gets frozen by the ATmega for a memory update. The only problem that struck me initially is if the 'C02 were actually running code from the region $FF00 through $FFFF and the ATmega updated the very same bytes which the 'C02 was in the process of executing. I can't imagine why Gordon would attempt such a perilous stunt, so I'll rule that out.

But! Also resident in the $FF00 - $FFFF region are the vectors, and if IRQs, NMIs, RSTs or BRKs are being used then a problem could arise in the event that the ATmega happened to do an update that altered the vector in question after the 'C02 had fetched the vector-low byte but before it had fetched the vector-high byte.

SYNC and VPB are both possible candidates for protecting against this vanishingly unlikely event, but both will be unnecessary if IRQs, NMIs, RSTs and BRKs are not in use when the update occurs. Furthermore, it's worth noting that the problem can't manifest unless the ATmega alters both bytes of the vector in question. If one or the other byte remains the same then the 'C02 will either end up going to the new vector or the old vector but not a fatal mix of the two.

BTW, Gordon explained that the ATmega code includes some generous delay before assuming that the RDY signal has been recognized by the 65xx. For this reason -- plus the fact he's using a 'C02 -- I don't think we need to concern ourselves regarding an NMOS CPU's inability to immediately recognize RDY when a write cycle(s) is in progress.

-- Jeff

_________________
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  
PostPosted: Sun Aug 22, 2021 7:18 pm 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1466
Location: Scotland
Dr Jefyll wrote:
BigEd wrote:
for some purposes it's worth waiting for a SYNC.
Yes -- for some purposes but not all. And (if I understand you correctly) you're suggesting Gordon's case isn't one that requires waiting for SYNC. I tend to agree, but as I was writing this post I did have one nagging second thought.

I'm tempted to say it simply doesn't matter what the 'C02 is doing -- fetching an opcode or any other activity -- when it gets frozen by the ATmega for a memory update. The only problem that struck me initially is if the 'C02 were actually running code from the region $FF00 through $FFFF and the ATmega updated the very same bytes which the 'C02 was in the process of executing. I can't imagine why Gordon would attempt such a perilous stunt, so I'll rule that out.


Ok... Er ... perilous stunt... Interesting... But yes, I would and have done....

The strategy is to isolate 65C02 (or '816), attach ATmega to the data and address bus, control RW and read/write RAM. As an optimisation on my current boards (both 6502 and 816), I pull A8-15 high with 10K resistors and just drive A0-7. So, from the ATmega I can "see" $FF00 through $FFFF.
(on the '816 board, the upper address bus is held low as the decode GAL senses the BE output signal from te ATmega and uses that to force them low)

This is how I boot the CPU - write ~200 bytes of boot code, write the vectors, detach the ATmega, BE High, Reset High and off it goes. The boot code relocates itself to lower RAM them uses the WAI mechanism to talk to the ATmega to get the rest of the OS loaded.

Communication currently relies on the ATmega polling the Rdy output from the 65C02 or '816. When this goes low (WAI executed), it BE's the '02/'816 attaches itself, reads/writes what's now a 128 byte data + 6 byte 'command' window at $FF00 and off it goes. There are some tiny fragments of code that DO execute in the $FFxx region, but they are vectors that never change once the system has booted. An example is:

Code:
osRdchV:        jmp     _osRdch                 ; FFE0: (&0210) Get a byte from current input stream
osAsciV:        cmp     #$0D                    ; FFE3:         Output a byte to VDU stream expanding
                bne     osWrchV                 ;               carriage returns (&0D) to LF/CR (&0A,&0D)
osNewlV:        lda     #$0A                    ; FFE7:         Output a CR/LF to VDU stream
                jsr     osWrch                  ; FFE9V:        Outputs A followed by CR to VDU stream
osWrcrV:        lda     #$0D                    ; FFEC          Output a CR to VDU stream
osWrchV:        jmp     _osWrch                 ; FFEE: (&020E) Output a character to the VDU stream


And yes, there are issues with the wrong interrupt causing wake from WAI, but I resolved that in the GAL with logic which blocks interrupts when Rdy is low. (And since these are all level IRQs it works well)

What I'm aiming to do is provide another small window for asynchronous data from the ATmega - hence looking for a mechanism for ATmega initiated communications.

I can try the single crystal approach - and in the early days when I pushed it to 16MHz I did just that because I only had one 16Mhz can osc. But felt running that long clock might give issues in the future - although who knew I'd be running it at 16Mhz on a double sided board with pull up resistors on half the address bus... It was amazing enough on stripboard at 16Mhz...

This picture shows it on stripboard:

https://projects.drogon.net/ruby-6502-on-stripboard/

You can see the green wire from the can to the can socket for the ATmega.

Quote:
But! Also resident in the $FF00 - $FFFF region are the vectors, and if IRQs, NMIs, RSTs or BRKs are being used then a problem could arise in the event that the ATmega happened to do an update that altered the vector in question after the 'C02 had fetched the vector-low byte but before it had fetched the vector-high byte.

SYNC and VPB are both possible candidates for protecting against this vanishingly unlikely event, but both will be unnecessary if IRQs, NMIs, RSTs and BRKs are not in use when the update occurs. Furthermore, it's worth noting that the problem can't manifest unless the ATmega alters both bytes of the vector in question. If one or the other byte remains the same then the 'C02 will either end up going to the new vector or the old vector but not a fatal mix of the two.


Stuff above $FF90 isn't touched once it's booted and running.

Quote:
BTW, Gordon explained that the ATmega code includes some generous delay before assuming that the RDY signal has been recognized by the 65xx. For this reason -- plus the fact he's using a 'C02 -- I don't think we need to concern ourselves regarding an NMOS CPU's inability to immediately recognize RDY when a write cycle(s) is in progress.

-- Jeff


I think what I'll do now is try the single clock approach on an existing board before I spin a new PCB - I'm thinking mostly in 65C02 land but want the option of swapping in an '816 to the same board, so avoiding Sync, VPB and anything else not common to both CPUs is an advantage, but not the end of the world.

And thanks to all who've contributed - it seems use of the Rdy signal takes you almost into uncharted waters - one of those "seemed like a good idea at the time" things though, and on-paper at least it does look interesting but possibly stopping the clock (on 'modern' CPUs at least) is the way to do it more effectively.

Thanks,

-Gordon

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 22, 2021 7:28 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1041
Location: near Heidelberg, Germany
One thing to note is that after a SYNC there may well be writes - when the IRQ occurs.

To halt the NMOS CPU it's easiest to just assert RDY and wait for three cycles that may potentially be storing the interrupt stack frame. The C64 VIC-II does this. No SYNC needed.

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 23, 2021 12:52 pm 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
Quote:
I can try the single crystal approach - and in the early days when I pushed it to 16MHz I did just that because I only had one 16Mhz can osc.
Could you run the 6502 clock from an ATmega pin? Some chips will let you use a timer or other peripheral to output pulses in hardware. You could change the pin back to a GPIO and temporarily control it yourself for clock stretching and other stuff.


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 23, 2021 1:48 pm 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1466
Location: Scotland
Druzyek wrote:
Quote:
I can try the single crystal approach - and in the early days when I pushed it to 16MHz I did just that because I only had one 16Mhz can osc.
Could you run the 6502 clock from an ATmega pin? Some chips will let you use a timer or other peripheral to output pulses in hardware. You could change the pin back to a GPIO and temporarily control it yourself for clock stretching and other stuff.


I don't think I could drive one fast enough - I want 16Mhz an I think the best you can get with a timer is F/2, so 8Mhz (I think, would really need to check)

And I don't really want to clock-stretch - in the "traditional" manner anyway, (mostly because I've nothing that needs stretching), but the ability to "stop the clock" may be advantageous here - if synchronising the ATmega and 65C02/816 clock trick suggested by Jeff doesn't work.

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 Aug 23, 2021 2:54 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Quote:
[...] if synchronising the ATmega and 65C02/816 clock trick suggested by Jeff doesn't work.
Assuming it's tPCS-tPCH violations that caused the trouble (and all the clues support this theory) then my "trick" (??) can certainly be made to work. It may be as simple as using a jumper as shown in the photo on the blog you linked to. But as noted you may possibly require an inverter in the path to one CPU or the other, and I guess you'd use the GAL for this. BTW, because clock signals tend to be critical I would ideally like to see a shorter jumper... and/or a return wire, grounded at both ends, twisted in parallel with the jumper.

In order to give you more specific advice I would have preferred to settle the inverter question in advance, but unfortunately the ATmega datasheet seemingly doesn't reveal what is the timing relation between the ATmega clock input and the appearance of new data on the output port pins.

Quote:
And I don't really want to clock-stretch - in the "traditional" manner anyway, (mostly because I've nothing that needs stretching), but the ability to "stop the clock" may be advantageous here
I'm not sure I see any real distinction between stretching and stopping the clock. Isn't an indefinite stretch equivalent to a stop? Or perhaps you're referring to the question of whether to manipulate the 'C02 by means of RDY as opposed to the Phi2 input.

Quote:
Could you run the 6502 clock from an ATmega pin?
Quote:
I think the best you can get with a timer is F/2, so 8Mhz (I think, would really need to check)
I like Druzyek's idea, although it, too, may possibly require an inverter. As for the speed, would it be possible to run the ATmega at 32 MHz?

-- Jeff

_________________
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  
PostPosted: Mon Aug 23, 2021 4:15 pm 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
drogon wrote:
Druzyek wrote:
Quote:
I can try the single crystal approach - and in the early days when I pushed it to 16MHz I did just that because I only had one 16Mhz can osc.
Could you run the 6502 clock from an ATmega pin? Some chips will let you use a timer or other peripheral to output pulses in hardware. You could change the pin back to a GPIO and temporarily control it yourself for clock stretching and other stuff.
I don't think I could drive one fast enough - I want 16Mhz an I think the best you can get with a timer is F/2, so 8Mhz (I think, would really need to check)

I think you're right. I don't know much about AVRs specifically, so I tried looking into how it works for the ATmega328. It seems there is a fuse you can set when programming that will make the chip output the system clock on one of the pins. I'm not sure if you can pause the output or change it back to a GPIO without reprogramming the fuse. It looks like there is a clock divider but I'm not sure if that can be applied to only the output pin. Maybe it's something to look into more or even consider a different ATmega if it has the same footprint but a more useful clocking scheme.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 26 posts ]  Go to page Previous  1, 2

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: