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.
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 (and likely other channels), and I just noticed there's a discussion about interfacing with the 6502
here.
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
I don't know how far the emulated version of the chip goes; it looks like it's part of a bigger project, so it's possible that the !CSR, !CSW and MODE lines don't simply connect to a Propeller pin. If they don't, it should be easy to modify it, though.
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.
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?
Most 6502 systems that map the video memory into the 6502 address space do the same thing: the video generator accesses the video RAM chips during Phi1 while the 6502 isn't on the data bus. If you look at the schematic of those systems, you will also see that the video RAM address bus is not connected directly to the 6502, but to a number of multiplexers (e.g. 74xx257), which switch between the CRT controller's address bus and the 6502 address bus, at the rate of the clock that also runs the 6502. At 1MHz, the CRT controller can access the video RAM exactly fast enough to generate 40 characters per row. On systems like the CBM 8032 that have 80 columns, there's some electronic trickery where the video RAM is organized so that the CPU accesses it with 8 bits at a time, but the CRT controller accesses it with 16 bits at a time.
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.
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.
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?
Ummmm... no. All I was saying that if you want to stop the clock in (let's say) LOW state, you have to make sure that the instructions to stop the clock have time to do so before the timer is already going high. So for example let's say the timer is 400ns into Phi1. If you want to stop the clock at that point in time, you'll have to probably execute a few assembly instructions to disable the timer and take it off the output pin. If those assembly instructions take longer than 100ns to execute, the timer will have already made the pin HIGH. If your assembly instructions take (say) 125ns to set the clock low, the Propeller will have generated a 25ns Phi2. Now let's say the 65C02 wanted to read an address that's mapped inside the Propeller using a Memory cog. The Propeller firmware has to retrieve the byte from hub memory and put it on the data bus. But by the time it puts the byte on the data bus, the clock has already gone from high to low, and that's when the 65C02 latches the data from the data bus into its internal data bus flipflops. And because there was nothing on the databus, the program won't do what it's supposed to do.
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.
The Propeller needs the help of the 65C02 to fill the RAM, because the 65C02 controls the address bus that determines where each byte gets stored. So I'll feed STA Absolute instructions to the 65C02, and when it thinks it's storing the accumulator into an address in the RAM chip, I let the Propeller store a different byte during Phi1. During Phi2 I keep the RAM chip disabled while this is going on. The matters of how to feed fake instructions to the 65C02 have already been solved, though I don't have time to elaborate on them right now. It will probably work in a similar way as the fake reset code that's in the memory cog now.
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.
Now, how will the expansion board Propeller know the host is sending commands to it? It it monitors P25...
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.
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.
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.
I think it's probably possible to speed up the system to 2 or maybe 4 MHz and slowing down the 65C02 down whenever it talks to the Propeller. I think because of the discussed problems with stopping and restarting the clock, it might be easier to do this by controlling RDY. The main problem there is that the RDY control cog will only have one or two instructions to decide whether to slow down, and then it still has to do it. I'll have to do some more research for that, it's not at the top of the list of priorities. Let's get some (more) cool things working at 1MHz or (with a 6.25MHz crystal) 1.25MHz.
===Jac