Prop2 as a 6502 SoC (or Spin2 Sanity Check)
John Sherman
Posts: 4
My wife bought me a knockoff Arduino Mega for Christmas, and I started the Ben Eater 6502 (Link) class to learn about assembly programming and computer architecture. Since I couldn't justify buying the kit, I've been using the Arduino to fake pretty much everything except the 6502, which I already had. So ram, rom, PIA, etc., was all being emulated on the Arduino. This came with a real speed penalty (the 65c02 could only run at about 80khz) and the Arduino's ram is pretty limited (8K). I looked at a few options, and ended up seeing that Parallax had come out with a new Propeller. The Prop2 seems tailor made for messing around with 8-bit computers! Plenty fast, plenty of I/O, and plenty of ram. From a quick glance, it seems like it would be possible for a single Prop2 paired with a 6502 to emulate all of the hardware of something like the Apple II.
That's the goal, and for the moment I'm attempting to emulate the Apple I as a proof of concept and an opportunity to learn Spin2. I don't actually have a Prop, and saving for one will take a minute, which means I'm learning a new language but can't actually test anything just yet. I was hoping I might be able to ask for clarification on a few things to make sure I'm headed down the right path.
Address decoding shenanigans:
Here, I'm using Jon's serial terminal object. My understanding is that term.rx() will grab each character entered by the user and set kbdChar to the 7 bit ascii value. The high bit in this case acts as a faux interrupt on the 6820 that is being minimally emulated by the Prop.
Starting the terminal and alternating between grabbing values from the serial terminal and running a clock cycle.
This is where I really feel like I'm flying blind. My understanding is that if I specify a PINRPINW on an 8-pin range (23..16), then assigningpassing the value of a BYTE variable to it will cause those pins to be set high or low in accordance with the assigned value. e: So a value like $8D would lead to pin 23 set high and all others low.
e: After rereading the documentation, I see I misunderstood PINW a bit. I need to pass the value rather than assigning. Those changes are reflected below.
I'm sure this code is a mess, but I really appreciate the help.
That's the goal, and for the moment I'm attempting to emulate the Apple I as a proof of concept and an opportunity to learn Spin2. I don't actually have a Prop, and saving for one will take a minute, which means I'm learning a new language but can't actually test anything just yet. I was hoping I might be able to ask for clarification on a few things to make sure I'm headed down the right path.
Address decoding shenanigans:
'******************************************* '** ** '** ** '** MEMORY MAP ** '** ** '** ** '******************************************* ' Based off values contained here: https://www.applefritter.com/replica/chapter7 con RAM_S = $0000 RAM_E = $8000 WOZ_MON_S = $FF00 WOZ_MON_E = $FFFF BASIC_S = $E000 BASIC_E = $EFFF IO_S = $D010 IO_E = $D013
Here, I'm using Jon's serial terminal object. My understanding is that term.rx() will grab each character entered by the user and set kbdChar to the 7 bit ascii value. The high bit in this case acts as a faux interrupt on the 6820 that is being minimally emulated by the Prop.
pub getSerial() if term.available() if (kbdCR & $80 == $00) tempChar := term.rx() kbdChar := tempchar | $80 kbdCR := kbdCR | $80
Starting the terminal and alternating between grabbing values from the serial terminal and running a clock cycle.
pub main() setup() wait_for_terminal(true) repeat getSerial() cpuTick()
This is where I really feel like I'm flying blind. My understanding is that if I specify a PINRPINW on an 8-pin range (23..16), then assigningpassing the value of a BYTE variable to it will cause those pins to be set high or low in accordance with the assigned value. e: So a value like $8D would lead to pin 23 set high and all others low.
e: After rereading the documentation, I see I misunderstood PINW a bit. I need to pass the value rather than assigning. Those changes are reflected below.
var WORD addr BYTE dataIn BYTE rwState pub cpuTick() pinh(PIN_CLK) ' Pin tied to the clock of the 6502 rwState := pinr(PIN_RW) ' Polls R/W pin from 6502. I'm expecting it to return a single bit value addr := pinr(15..0) ' Reads the 16 bit address bus from the 6502 in a variable of type WORD if (rwState == %1) if (WOZ_MON_S <= addr && WOZ_MON_E >= addr) ' Checks to see where in the memory map the addr lies. pinw(23..16, apple1Rom[addr - WOZ_MON_S]) elseif (BASIC_S <= addr && BASIC_E >= addr) ' Integer Basic, starts at E000 'Handle this later elseif (RAM_S <= addr && RAM_E >= addr) ' User ram space $0000->$8000 'Handle this later elseif (IO_S <= addr && IO_E >= addr) if (addr == PIA_KBD) pinw(23..16, kbdChar) ' Should grab the global kbdChar variable and send it to the 6502 kbdCR := kbdCR & $7F ' Clears the faux interrupt elseif (addr == PIA_KBD_CR) pinw(23..16, kbdCR) ' Sends an "enter" command else 'Handle this later
I'm sure this code is a mess, but I really appreciate the help.
Comments
I’m doing a whole Z80 / CPM2.2 on a P2. On the P1 it ran about equivalent to a 4MHz Z80 so I expect around 25MHz on my RetroBlade2 board. See both RetroBlade2 threads under the P2 section.
As for your pinw etc questions, I’ll have to leave that for someone with more knowledge about those spin instructions although you should be able to write a “byte” block of pins.
That might be a goal later on once the peripherals are all performing as expected. It's just not where I want to be putting my focus at this stage of the project.
The Retroblade is very cool. Definitely the aesthetic I'm going for with this project.
Perhaps you can also grab some inspiration from projects of other propeller users, such as Jon Thomasson's "Retro II - An Apple II Compatible 6502 Computer":
https://forums.parallax.com/discussion/172080/retro-ii-an-apple-ii-compatible-6502-computer/p1
It uses a P1, but the P2 can do a lot more for such kind of designs, and perhaps, help get rid of some of the other chips.
Hope it helps
Henrique
https://forums.parallax.com/discussion/171704/propeller-2-live-forum-early-adopter-series-topics-speakers-and-registration/p1
We have an event today, and tomorrow, another one. Always great stuff.
Just register and have a seat...
That would be great!
Hi John Sherman,
This might be even closer to what you are wanting to do with the P2. All of the peripherals, including RAM even are done by the P1. I have one of these, and it was fun to put together and since I used to do 6502 Assembly in High School, it really was fun for me. I would love to see someone do a P2 version. https://forums.parallax.com/discussion/165586/l-star-software-defined-computer-as-an-apple-i
@Yanomani thanks for the link. The full Apple ][ implementation is pretty neat too.
Yeah, these two projects were definitely partial inspirations for what I'm working on. The Retro II was especially interesting, and looking over his project is what convinced me that the extra I/O of the Prop2 could handle all the functions he was forced to split between 2 props, some 74xx logic chips, and an expensive dual-port ram module. My hope is that I can push it all the way to emulating the IIGS, which was my childhood computer.
I also worked a bit more on the Spin program for emulating the Apple I (Github). I'm still flying blind until I can scrounge up some drachma for one of the development kits. I'm assuming there are plenty of mistakes that will make themselves known once I can finally test this.
I would suggest starting with @Cluso99's, appropriately named for this task, RetroBlade2. I love mine, especially since I can play with the P2 with nothing more than a usb2serial adapter, a USB extension cable and the RetroBlade2. It's quite nice. https://forums.parallax.com/discussion/172262/clusos-retroblade2-single-chip-computer-small-stock-available-for-new-orders-payment#latest It's only $55 delivered stateside too!
I did do some 6502 assembler back in the 80’s and Rockwell 6511 in the 90’s.
A completer Apple //e or //c should not be that difficult! Shame I chucked my Apple //c out tho I still think I have the ProDos floppies and books in the garage. Probably don’t have anything to read those floppies tho???
The C64 video chip has some interesting... nuances though, it needs to be emulated in cycle accurate sync with the CPU for some effects to work (such as the scrolling in Mayhem in Monsterland, which works by glitching the video chip's state machine to start fetching character data earlier than intended. The unnecessary reads go nowhere, but now the address counter is offset until the next frame -> full hardware accelerated horizontal scrolling. The amount of scrolling depends on which cycle the glitch is triggered on).
To emulate A8 one needs 6502, Antic, Pokey and GTIA - 4 chips to emulate - and there are 8 cogs available - it should be doable.