This project is yet another m68k homebrew computer that is starting to look like it might actually be finished someday.
The idea is to design and develop a system running the Motorola MC68010P10 with supporting circuitry and then port my existing minimal OS to it.
This is starting to look like it'll actually get completed someday. Right now, I have a 68010 running at 8MHz and a TTL address decoder comprising 10 7400-series ICs. The CPU is hooked up to control, data and address buses allowing it to talk to the memory and run code from the on-board ROM.
IO is handled by the Motorola MC68901 Multi-Function Peripheral. This gives a UART for a serial terminal amongst other things. I plan to use a Yamaha V9958 to give graphical output, and have not yet decided on a sound chip.
There's (at least) one area where this project won't be period-appropriate - I plan to integrate USB to make it easier to work with in the twenty-first century.
In my last log, I talked about how I was getting interrupts to work, but that I hadn't yet made them work properly. It appeared that, no matter what the interrupt source in the MFP it would always present $FF as the vector during IACK. This was especially strange because the vector base set in the MFP's VR register is $40, so where the $FF was coming from was a mystery.
I suspected my DTACK generator wasn't robust enough as it didn't take IACK into account, so my first step was to redesign the DTACK generator to take that line into account. No EAGLE schematic yet but in Logisim the design looks like this:
This also adds in a way to generate the MFP's DS signal during IACK since the MC68010 doesn't appear to assert LDS during this time, and without DS the MFP won't generate DTACK.
This improved things somewhat, but it still wasn't working. Breaking out the probe and looking at the data lines during IACK was telling:
A glance at the mess that is D0 (and to an extent D1 and D3) told me what the problem was - I know the bus doesn't float at this point (especially because it's still not stable after the MFP asserts DTACK), so this can only be contention.
Sure enough, further tracing revealed that, due to the design of the address decoder, the ROMCS lines also get asserted for a short while during an IACK cycle. This is because I didn't gate the address decoder off with anything which, while not exactly efficient, was good enough at the time. Gating it off with AS wouldn't help, as the CPU asserts AS during IACK. I realised I could gate it off with the inverted IACK signal from the new circuit from the shot above.
That looked much better:
Nice clean edges, and tracing all the data lines showed the MFP was putting 0100 0101 on the bus, which is $45, exactly the right vector for the MFPs Timer C interrupt.
A quick fix in the software to put the handler on vector $45, and all is working perfectly. Just need to tidy it up on the board and wire it up correctly, and I can move on to the software support for the interrupts. Currently it's just thrown together on an extra board, and looks like this:
Now I have the MC68901 MFP integrated and the UART is working, I spent a bit of time this weekend setting up Timer C of the MFP as a timer tick I can use in the OS for multitasking.
For testing purposes, I've set the timer up at about 18Hz and have the interrupt handler just flash an LED connected to MFP GPIO 0. That way, I can visually see that the handler is being run. The code that sets up the MFP now looks like this (I've also upped the UART to 19200 baud):
* Initialise MFP
* Trashes: D0
* Modifies: MFP Regs
move.b #$FF, MFP_DDR ; All GPIOs are output
* Timer setup - Timer D controls serial clock, C is kernel tick
move.b #$00, MFP_TCDR ; Timer C count is 0 (equivalent to 255) for 18Hz
move.b #$0C, MFP_TDDR ; Timer D count is 12 for 19.2KHz
move.b #$71, MFP_TCDCR ; Enable timer C with /200 and D with /4 prescaler
* USART setup
move.b #$08, MFP_UCR ; Fundamental clock, async, 8N1
move.b #$05, MFP_TSR ; Set pin state high and enable transmitter
* Interrupt setup - Enable timer C interrupt for kernel tick
move.l #MFP_VECBASE, D0
move.b D0, MFP_VR
or.b #$20, MFP_IERB ; Enable Timer C interrupt...
move.b #$20, MFP_IMRB ; ... and unmask it.
The code for the handler is very simple:
bchg.b #0, MFP_GPDR
Because I'm using vectored interrupts, this should be on vector 0x45 (MFP_VECBASE is 0x40 and Timer C is at offset 5 in the MFP), but because of a limitation of my IO DTACK generation it's not actually working that way - the IO DTACK circuit doesn't take account of /IACK and so /DTACK is immediately asserted, presumably before the MFP can put the vector on the bus. This causes the vector to always be FF, so for now the handler is just mapped there for testing.
To actually fix this, I'll need to revisit the /IODTACK generator. I've not put anything down in EAGLE yet, but my plan is to build something like the following:
After a trying weekend working on the m68k build (see the previous two logs for details) I finally reached the "Hello, World" stage in the board's development. That's right, the UART is now working and integrated with the USB to TTL converter I'm using at the moment.
Once I'd worked out how to get the UART properly initialised, I hooked up the analyzer to the TCLK and SO lines of the 68901 and ran a simple bit of code that would just output "Ok". Here's the trace from that:
The "Ok" characters were moved into the UART data register as immediates. Expanding this to support sending out a null-terminated message exposed a wiring mistake in the board - it was the first time I'd done byte-sized reads from ROM space and it turned out I'd wired the chip selects backwards to the address decoder. With that fixed, I was able to output characters from a constant string in a loop:
Finally, by hooking up the USB converter and plugging it in (to my Windows laptop as the cable is too short to reach my main machine), I was able to verify the results in a terminal:
And just like that, the rosco_m68k now has a way to do output. The challenges and annoyances of the weekend are forgiven - onward and upward!
So I talked in the previous log about how I had some issues while integrating the MC68901 MFP that I initially assumed were hardware-related, but that turned out to be software. Once I got past that, I hoped it would be plain sailing. Boy, was I wrong.
It's been a very frustrating couple of days on the m68k project. All my own fault, of course.
Some background: I've been hooking up the MC68901 MFP which will give me some GPIO capabilities, a UART (actually a USART but I'm not using the S), some timers and support for vectored interrupts. All was going pretty well - it's a lot less wiring than most of the other chips on the board (five address lines, eight data, a few control lines and a bit of extra glue logic).
Now that the board is reliably running code (more on that below) I'm into the next stage of planning, which will involve hooking up the MC68901 MFP (Multi-function Peripheral). This will give me some interrupt timers (meaning I'll have a tick for the kernel to use) and a USART which I'm going to use for the initial IO to an external terminal (via a USB converter).
Most of the work here will be simply connecting it to the bus, but it will mean DTACK-grounded isn't going to cut it any more, at least when /IOSEL is asserted. With that in mind, I designed a small circuit that will look after DTACK for me:
As I mentioned in yesteday's log, I finally got the computer to run some code from ROM, but that is was unreliable and always seemed to wander off into oblivion after some time (a few tens-of-thousands of microseconds).
After a frustrating few days, the rosco_m68k is now successfully running code from the EEPROMs! It turns out I'd wired the ROMs to the wrong half of the data bus (facepalm, endianness again), and also needed to make a few other tweaks to get it working.
So I finally gathered all the parts I needed, and since I have some time off work this week I managed to build the address decoder. I'm happy to say it was fairly painless although time-consuming - routing all the wires has taken the best part of a day. To be fair, a couple of hours of that were spent debugging a couple of mis-wired connections though.