I have a SBC I assembled (it's the L-Star) and I'm having a blast with this thing. So I'm building an expansion card for it and I need to be able to halt the CPU (65C02) to handle some external I/O.
Unfortunately, BE is not available without modifying the board (which I do not want to do).
The only pins I have access to via my expansion board are Addr/Data, IRQ, NMI, SOB, SYNC, R/W and PHI2.
The schematics for the L-Star board I have are here: https://github.com/jacgoudsmit/L-Star/r ... ematic.pdf
My plan was to have the micro-controller halt the CPU by holding PHI2 low (the mcu generates the 1MHz clock). Then, while the CPU is stopped, use the address lines to signal another micro-controller with some data (located on my expansion board). Once the expansion mcu is finished, it would then use the address pins to signal the host micro-controller that it was done.
So the two mcu's would be turning address pins on/off while they communicate.
Q: Is this going to cause any problems with the 65C02?
Q: Should I wait until PHI2 is low before I allow the clock to be stopped?
In case you're wondering, the mcu on the expansion card will monitor the RAMEN pin from the host. When it is HIGH, the host RAM chip will be disabled...meaning we're in "I/O" mode. The host will monitor a specific address and when it's captured, disable the RAM.
Thanks!
Can I disable a 65C02 with only PHI2?
Can I disable a 65C02 with only PHI2?
Cat; the other white meat.
- jac_goudsmit
- Posts: 229
- Joined: 23 Jun 2011
- Location: Rancho Cucamonga, California
- Contact:
Re: Can I disable a 65C02 with only PHI2?
Hi cbmeeks,
Can you elaborate on what exactly you want to do? It sounds like you're trying to make this unnecessarily complicated by using the address bus for signaling. It's probably much easier to just let the 65C02 run a program that e.g. reads a byte from a location that your MCU catches, and then writes that byte into memory. You could use the SOB pin and the BVS instruction on the 65C02 to let it know that it received the last input from the I/O device (the MCU).
The 65C02 controls the address bus at all time, even when you hold the clock low, so you can't use the address pins for signaling (unless you use BE to take the 65C02 off the address line). However, during Phi1 (i.e. whenever the clock is low), the 65C02 doesn't use the data bus, so you can stop the 65C02 and use the data bus to communicate between two microcontrollers. You can make this wicked-fast by implementing a smart protocol that uses all 8 data bit lines at the same time (but half-duplex, so while one MCU writes, the other one reads). Depending on which MCU you use, you could probably transfer several megabytes per second this way, but it's probably difficult to implement. Alternatively, you could simply use a known protocol such as SPI or I2C or RS-232 to communicate data between the MCUs over the data bus while the 65C02 is "parked" with CLK0 low.
When the 65C02 is stopped in Phi1 (CLK0 low), it really doesn't care what happens on the data bus. But you can't manipulate the address bus for communication because it's always under control of the 65C02. You will damage the 65C02 if you try to override the address bus.
Even if you would use BE to take the address bus offline (while the clock is stopped, obviously), it would still be a dangerous thing to use the address bus as signals. There could be many other devices on the address bus that will interpret it as such: an address. If you twiddle with the address bus pins and accidentally form an address that one of those devices listens to, that device could behave in some way that you may not be able to predict.
Bottom line: manipulating the address lines can't be done without using BE, and even with BE it's really a bad idea to just use the address bus pins as signal lines. Don't do it.
If you want to have the data bus available to you, it makes most sense to stop the clock when it's in low state, yes.
The difficult part of stopping and restarting the clock is that you have to make sure that the last pulse (before stopping) and the first pulse (after restarting) are long enough. The current L-Star firmware doesn't bother to do this correctly, because it only starts the clock once: when the system starts up and the 65C02 needs to go through a reset cycle anyway. One day I will rewrite the clock cog so it inspects the current state of the timer to make sure that it doesn't generate any clock pulses that are too short, before it stops the clock. Also, the current clock module can only stop the clock in Phi2 because of how the Propeller works (the actual pin output is ORed between the OUTA value and the timer output so the easiest way to stop the clock is to put a 1 in the bit in OUTA).
The RAMEN pin is not on the expansion port. It wouldn't do you any good to monitor it anyway, because the code that controls it (which doesn't exist yet) will monitor the clock pin. During normal operation, the RAM chip will only be enabled during Phi2. So if you stop the clock, RAMEN will not become active and the RAM chip will stay off the data bus.
The RAM chip control code (which, again, I still have to write), will make it possible to do DMA (which I think is what you're trying to do) by making it possible to enable the RAM chip for certain addresses during Phi1, and feeding STA <absolute address> instructions to the 65C02. Then all your MCU would need to do is put the data on the data bus at the right time, and wait until the clock goes high. This is all a bit "up in the air" but it will work when it's done, and it'll be documented in the source code. The module will probably be called RAMcontrol.spin, so if you see it on Github, that's probably the module you want to read.
===Jac
cbmeeks wrote:
My plan was to have the micro-controller halt the CPU by holding PHI2 low (the mcu generates the 1MHz clock). Then, while the CPU is stopped, use the address lines to signal another micro-controller with some data (located on my expansion board). Once the expansion mcu is finished, it would then use the address pins to signal the host micro-controller that it was done.
Quote:
So the two mcu's would be turning address pins on/off while they communicate.
Quote:
Q: Is this going to cause any problems with the 65C02?
Even if you would use BE to take the address bus offline (while the clock is stopped, obviously), it would still be a dangerous thing to use the address bus as signals. There could be many other devices on the address bus that will interpret it as such: an address. If you twiddle with the address bus pins and accidentally form an address that one of those devices listens to, that device could behave in some way that you may not be able to predict.
Bottom line: manipulating the address lines can't be done without using BE, and even with BE it's really a bad idea to just use the address bus pins as signal lines. Don't do it.
Quote:
Q: Should I wait until PHI2 is low before I allow the clock to be stopped?
The difficult part of stopping and restarting the clock is that you have to make sure that the last pulse (before stopping) and the first pulse (after restarting) are long enough. The current L-Star firmware doesn't bother to do this correctly, because it only starts the clock once: when the system starts up and the 65C02 needs to go through a reset cycle anyway. One day I will rewrite the clock cog so it inspects the current state of the timer to make sure that it doesn't generate any clock pulses that are too short, before it stops the clock. Also, the current clock module can only stop the clock in Phi2 because of how the Propeller works (the actual pin output is ORed between the OUTA value and the timer output so the easiest way to stop the clock is to put a 1 in the bit in OUTA).
Quote:
In case you're wondering, the mcu on the expansion card will monitor the RAMEN pin from the host.
Quote:
... the host RAM chip will be disabled...meaning we're in "I/O" mode. The host will monitor a specific address and when it's captured, disable the RAM.
===Jac
Re: Can I disable a 65C02 with only PHI2?
jac_goudsmit wrote:
Hi cbmeeks,
Can you elaborate on what exactly you want to do? It sounds like you're trying to make this unnecessarily complicated by using the address bus for signaling. It's probably much easier to just let the 65C02 run a program that e.g. reads a byte from a location that your MCU catches, and then writes that byte into memory. You could use the SOB pin and the BVS instruction on the 65C02 to let it know that it received the last input from the I/O device (the MCU).
Can you elaborate on what exactly you want to do? It sounds like you're trying to make this unnecessarily complicated by using the address bus for signaling. It's probably much easier to just let the 65C02 run a program that e.g. reads a byte from a location that your MCU catches, and then writes that byte into memory. You could use the SOB pin and the BVS instruction on the 65C02 to let it know that it received the last input from the I/O device (the MCU).
So the problem I was trying to solve was:
1) Efficiently communicate with expansion Propeller by sending commands (like the 65C22)
2) Re-route video through the expansion board.
3) No modifications to the L-Star other than using the built-in jumpers. Preferably no jumper wires either. I know the L-Star is a hobbyist computer. But the fun for me is treating it like it is an Apple I rolling off the assembly line and I'm building expansion cards for it.
I didn't mention that I would disable the L-Star video and take that pin to control RAMEN. Because video would be hosted by the expansion board. Once I can communicate with the expansion board Propeller, the sky's the limit.
jac_goudsmit wrote:
The 65C02 controls the address bus at all time, even when you hold the clock low, so you can't use the address pins for signaling (unless you use BE to take the 65C02 off the address line). However, during Phi1 (i.e. whenever the clock is low), the 65C02 doesn't use the data bus, so you can stop the 65C02 and use the data bus to communicate between two microcontrollers. You can make this wicked-fast by implementing a smart protocol that uses all 8 data bit lines at the same time (but half-duplex, so while one MCU writes, the other one reads). Depending on which MCU you use, you could probably transfer several megabytes per second this way, but it's probably difficult to implement. Alternatively, you could simply use a known protocol such as SPI or I2C or RS-232 to communicate data between the MCUs over the data bus while the 65C02 is "parked" with CLK0 low.
Utilizing the data bus, I could probably come up with a protocol that allowed the host/expansion to send data back/forth that way.
jac_goudsmit wrote:
When the 65C02 is stopped in Phi1 (CLK0 low), it really doesn't care what happens on the data bus. But you can't manipulate the address bus for communication because it's always under control of the 65C02. You will damage the 65C02 if you try to override the address bus.
jac_goudsmit wrote:
If you want to have the data bus available to you, it makes most sense to stop the clock when it's in low state, yes.
The difficult part of stopping and restarting the clock is that you have to make sure that the last pulse (before stopping) and the first pulse (after restarting) are long enough.
The difficult part of stopping and restarting the clock is that you have to make sure that the last pulse (before stopping) and the first pulse (after restarting) are long enough.
But...assuming 1 MHz, that is 500ns per half-cycle. So if I were 20ns into the LOW half-cycle or 400ns into the HIGH half-cycle, could I not stop it indefinitely if I wanted to? I mean, how would the CPU even know? I've always thought of the clock as time and by stopping it, the CPU has no notion of time anymore.
Oh, wait...I think I see what you're saying....
So if I was 20ns into the LOW half-cycle, I would need to make sure when I started the clock back up, I would run another 480ns at LOW right?
Like:
Code: Select all
LOW --> 20ns * STOP CLOCK...DO LOTS OF WORK * Finish LOW with 480ns HIGH....
___________ ____________________|----------
jac_goudsmit wrote:
The current L-Star firmware doesn't bother to do this correctly, .....
jac_goudsmit wrote:
The RAMEN pin is not on the expansion port. It wouldn't do you any good to monitor it anyway, because the code that controls it (which doesn't exist yet) will monitor the clock pin. During normal operation, the RAM chip will only be enabled during Phi2. So if you stop the clock, RAMEN will not become active and the RAM chip will stay off the data bus.
1) Disable L-Star video and connect the pin to RAMEN
2) Host (L-Star) starts up and disables external RAM.
3) Host "disables" 65C02 by either not starting the clock or holding the clock LOW.
4) Host enables RAM and sends ROM images from EEPROM to RAM. So ROM is now RAM (which I'm fine with).
5) Host enables 65C02...perhaps forces the fake reset or something to kick start it on the external RAM which now contains Krusader, Woz, etc.
Now, how will the expansion board Propeller know the host is sending commands to it? It it monitors P25 (which *is* on the expansion port) for a transition to HIGH, then it knows the host has disabled the external RAM. One drawback to this is during the boot-up when the host holds the RAM high for a bit. Not sure how I would handle that just yet. Perhaps a small delay on the expansion board Propeller of a few milliseconds.
jac_goudsmit wrote:
The RAM chip control code (which, again, I still have to write), will make it possible to do DMA (which I think is what you're trying to do) by making it possible to enable the RAM chip for certain addresses during Phi1, and feeding STA <absolute address> instructions to the 65C02. Then all your MCU would need to do is put the data on the data bus at the right time, and wait until the clock goes high. This is all a bit "up in the air" but it will work when it's done, and it'll be documented in the source code. The module will probably be called RAMcontrol.spin, so if you see it on Github, that's probably the module you want to read.
Cat; the other white meat.
- jac_goudsmit
- Posts: 229
- Joined: 23 Jun 2011
- Location: Rancho Cucamonga, California
- Contact:
Re: Can I disable a 65C02 with only PHI2?
cbmeeks wrote:
The external Propeller would act as a dedicated video buffer (sorta like the TMS9918) of 8-16K of video RAM. It would draw an image from its internal RAM. The host computer (L-Star) would send commands to the card for changing video RAM, drawing chars, etc.
From a quick glance at the datasheet, emulation with a Propeller shouldn't be too hard, and as a matter of fact, it looks like it's already been done.
If you have an actual chip, you can just connect it to the 65C02 bus the way you would normally connect an I/O device:
- The databus lines connect to CD0-CD7. Note, CD0 (not CD7) is the MSB!
- MODE connects to A0
- Some glue logic on the address bus makes !CSR or !CSW low during Phi2, depending on R/W
Either way, you will end up with the TMS chip (or emulator) in 65C02 address space at two addresses that you set by designing the glue logic. The video memory won't be accessible to the 65C02, but that's okay; it won't get in the way of other things like RAM memory or other I/O devices, and the TMS chip is probably much faster at doing cool things like graphics anyway.
Quote:
I am curious on how the Apple II did it, however. I know the video controller used the RAM during the PHI1 (LOW). But wouldn't it have to change the address bus to get the video data?
Quote:
But...assuming 1 MHz, that is 500ns per half-cycle. So if I were 20ns into the LOW half-cycle or 400ns into the HIGH half-cycle, could I not stop it indefinitely if I wanted to? I mean, how would the CPU even know? I've always thought of the clock as time and by stopping it, the CPU has no notion of time anymore.
Quote:
So if I was 20ns into the LOW half-cycle, I would need to make sure when I started the clock back up, I would run another 480ns at LOW right?
Quote:
Here is how I thought I would handle <downloading EEPROM to RAM>
...
3) Host "disables" 65C02 by either not starting the clock or holding the clock LOW.
4) Host enables RAM and sends ROM images from EEPROM to RAM.
...
3) Host "disables" 65C02 by either not starting the clock or holding the clock LOW.
4) Host enables RAM and sends ROM images from EEPROM to RAM.
There's another problem by the way: the EEPROM and the 65C02 share the same Propeller pin as clock. It will be necessary to connect the RDY line to another pin so that the 65C02 won't execute instructions while the Propeller is playing with the EEPROM.
Quote:
Now, how will the expansion board Propeller know the host is sending commands to it? It it monitors P25...
Yes, it's possible to use P25-P27 to control any devices on an expansion board. In fact, ALL Propeller I/O pins are connected to the expansion board so you have maximum flexibility. But you have to keep in mind that the 65C02 and the RAM chip are also connected to those pins at the same time!
So the easiest way for the system to do I/O is in the traditional way known to all 6502 computers: map the I/O in one or more memory locations, and use 6502 assembly (or C or whatever) to access those locations to get to the I/O data. Sure, if you don't need a keyboard or video you have 3 pins that you can use to communicate with the expansion bus (but actually more likely you'll have one or two pins free because a sophisticated system will probably need to have the main board Prop connected to RAMEN and RDY) or maybe even none at all (if the main Prop needs NMI to initiate a memory transfer).
In other words: you shouldn't count on having P25 (or any other pin) available for any magic, but you don't have to: one 74HC138 chip connected to the address bus is enough to generate chip-enable-not signals for up to 8 devices that are 256 bytes apart in high memory space. Read Garth Wilson's pages for more information.
Quote:
I'd like the idea of running the host faster. Perhaps 2-4 MHz which we're not going to be able to do with memory.spin.
===Jac
Re: Can I disable a 65C02 with only PHI2?
jac_goudsmit wrote:
I must admit, I never had a close look at the TMS9918 (and TMS9928/TMS9929) until today, but I would say that would be an excellent choice for a project such as this. They're still easily available via eBay.....
I'm also familiar with the Propeller emulation of it.
I was mostly using the TMS as an example. The video driver I'd like to use is actually much simpler (similar to the ULA of the ZX Spectrum).
I actually have several of the real TMS chips. But I didn't want to install one of them because they are pretty tricky to get going from what I understand. Mainly because of the odd 10.xxxx MHz crystal it needs isn't common. I have a few of them but they were pricey.
jac_goudsmit wrote:
That's correct, you can stop the clock at any time, so if the clock is already high you can keep it high, and if the clock is already low you can keep it low. But things like reading data from the data bus happen at the transitions of the clock, and those can't be too close together in time or things inside the 6502 (or in our case, in the Propeller software) start acting together in weird ways, or won't be ready for the next clock transition.
jac_goudsmit wrote:
There's another problem by the way: the EEPROM and the 65C02 share the same Propeller pin as clock. It will be necessary to connect the RDY line to another pin so that the 65C02 won't execute instructions while the Propeller is playing with the EEPROM.
jac_goudsmit wrote:
For expansion boards, you really should try to stay in the world of the 65C02. It's always possible to go from the 65C02 world to the world of any I/O devices and microcontrollers that are attached to the bus, but because the 65C02 has control over the address bus, the reverse is more difficult and you will need help from the 65C02.
Well, I'm not discouraged. In fact, I've learned even more. Thanks.
So, stepping back...a better idea for an A/V board for the L-Star would be to simply send data via the add/data bus like normal I/O.
Perhaps I should write a "video.spin" cog that would be similar to the PIA cog but for sending data to the board I/O?
Thanks!
Cat; the other white meat.