The HD6309 computer design files are available for download here. Press the ‘Clone or download’ button, then press ‘Download ZIP’.
The bootloader for the HD6309 computer got enhanced today. It now supports SREC format as input, instead of the custom format:
Yesterday ended with the pizzazz of a wet newspaper when I couldn’t get the HD6309 computer working. Of course, I couldn’t just let this slide, so today I took another shot at bringing up the board.
With a fresh mind and a strong cup of coffee I examined the board that had thwarted me yesterday. The first thing I tried was to add 100pF capacitors tot the clock oscillators as the signals to the processor and UART were ringing like there’s no tomorrow. The divided down E and Q signals, which are generated by the CPU based on this clock, looked fine. However, it’s unclear if the undivided clock signal is used internally by the CPU, so better safe than sorry. That didn’t fix things either.
At this point I took a look at the programs for the memory and IO decoder GALs. I use WinCUPL to compile these into fuse maps that the TL866 programmer can read. WinCUPL generates quite a few files and one of them is a report that has a .doc extension. It contains the simplified/optimised logic equations for the GAL.
WinCUPL lets you write the logic equations in a high-level manner, such as:
io_cs_n = !(addr:'B'1110XXXXXXXXXXXX);
Here, addr is a 16-bit address, X means ‘don’t care’ and ‘!’ means negation, so IO_CS_N will go low if the top four bits of the address are 1110. At least, that’s the idea. It turns out that WinCUPL has a bug in it that will not apply the negation. You won’t see that in the waveform simulation of your design, but it will show up in the .doc file equations!
The .doc file will show:
io_cs_n => a15 & a14 & a13 & !a12
,which is wrong!
To work around this problem, I directly wrote the simplified equation, instead of relying on the compiler:
io_cs_n = !a15 # !a14 # !a13 # a12;
,where ‘#’ means OR in the WinCUPL language.
There were several other places in the memory and IO decoder programs that caused erroneous compiler output. It is even a documented bug, which they claim has been fixed. Not the case, so watch out if you’re using WinCUPL.
I also noticed an error on my part; I didn’t use the IO_CS_N signal in the IO decoder GAL, which means that IO devices were being selected at the same time as the RAM or ROM! Two devices were competing for the same bus, which won’t give the best outcome.
Fixing both GALs instantly turned the machine into something predictable. It no longer did random things when I pressed the reset button. Progress!
One more thing…
I could see the CPU executing the code I had written:
START: JMP START
It was reading only from ROM and the address lines were not toggling, except for a few least-significant ones.
It was time to try the bootloader I had developed and tested using the emulator. No luck, the UART wasn’t responding. The cause of the problem manifested itself when I probed the RESET line and I accidentally ‘shorted’ the RESET pin to OUT1, which was outputting a logic ‘1’. The UART spang to life! During my handling of the board, the bodge wire I had connected to the RESET of the UART must have come loose!
Resoldering the reset wire finally fixed the computer and I’m now greeted with the bootloader screen every time I press the reset button!
9600 baud — the world is my oyster!
Most of the system seems to be working, including the RAM, which the bootloader checks by reading and writing patterns.
During development I disabled the expansion port and memory mapper. I will have to update the GALs to get them working, but that’s something for another time…
It’s 23:00, the 30th of May. For me, this marks the end of the Retro Challenge 2017/04. I wish I had something working by now, but I must admit defeat — for now.
I did manage to get the HD6309 computer working once when it produced a continuous string of the letter E via the UART. This convinces me that all the connections are correct but that there are timing or glitching issues. The CPU seems to be running some program, just not the one I wrote 🙂 .
To eliminate a partially dead CPU, I replaced it with another one. No change. The CPUs came from EBAY, all from the same seller. Maybe they’re all factory rejects, who knows?
The TL866A programmer has served me well, but I’ve done the “EEPROM dance” more times than I care to remember.
I went over the circuit several times using the oscilloscope. Apart from ringing on the READ, WRITE and E lines, nothing appeared to be overly wrong.
As a last-ditch effort, I added 100pF capacitors to ground on the READ and WRITE lines, which removed much of the ringing. That didn’t make it work any better however. The ringing is most likely a consequence of using “modern” parts, such as the two ATF16V8B GALs. They are pretty fast devices and it shows.
The 150ns access time of the ROM should short enough to supply a HD63C09 running at just over 1.8 MHz with data. The RAM is definitely fast enough, having an access time of 55ns. I might try reducing the clock speed in the future, just to make sure.
I’m glad I participated in the Retro Challenge and it was a challenge indeed! Part of the fun was helping Alan with his 68000 project and seeing others building and developing things: recreations of Andy Warhol classics, a COSMAC system, a TMS9900 CPU implemented in an FPGA and many others.
I’ll probably partake in the Retro Challenge again in the future, although I’m not sure I’d take on a completely self-designed computer with a PCB anytime soon. Speaking of which, I will upload all the design files and software to my GITHUB account sometime this week.
I hope you enjoyed this journey as much as I did. That’s it for now!
Today is the last day of the Retrochallenge 2017/04! Yesterday I tried to get the HD6309 computer up and running. The short version is that it still doesn’t run properly but it is “doing things”. By this I mean it behaves erratically.
When ordering the components, the AT28C64B I had planned to use was out of stock, so I ordered an AT28C256. They come in the same DIP28 package and use two additional pins (1 and 26) for addressing that are labeled not connected on the AT28C64B. So I wired those to ground on the back of the board.
To test the board, I wrote a program that lights up the LEDs connected to OUT1 and OUT2 pins of the SC16C550 UART and continuously sends 0xAA on the TX line. This seems like a small test but for this to work, the CPU, ROM, UART and two GALs must be fully working. Of course, it “didn’t work”.
Using an oscilloscope, I checked for clock signals. They were all there. Then I checked to see if the CPU was toggling its address lines: yes! The ROM_CS and IO_CS lines on the memory decoder GAL are next. Yes, they have activity too! So its very likely the program is actually running and trying to access the UART.
The SC16C550B UART
At this point, the main suspect is the UART. So I started looking at the schematic to see if I had made any mistakes in connecting up the data lines, address lines or the read/write lines. They all seemed fine. Then I spotted a potential mistake… Can you see it?
Anyone, anyone? Bueller? The reset pin on the component does not have a negation bar but the driving reset signal does. It is very uncommon to have an active high reset but I’m also quite meticulous when it comes to making schematic symbols. To be sure this is a problem, I checked the SC16C550B datasheet:
It is indeed an active high reset! So, I cut the reset trace going to the UART on the back of the board and connected it to ground. This way, the UART won’t be reset but I hope by writing to all the necessary registers I can put the UART in a defined state. This assumes that the UART doesn’t contain any internal/non-accessible flip-flops that need to be reset for it to function properly.
With the UART reset fix in place, I tried again. Something is happening on the UART TX line but the LEDs still won’t light up . At least the UART is doing something!
The first thing to check is the baud rate. Using my oscilloscope I measured the on time of the narrowest part of the bit pattern. Remember I’m sending 0xAA? I chose that because the bit pattern is ‘10101010’, which is ideal for measuring.
I expected to be close to 9600 baud, but it was way off! Hmm, that’s not a good sign. The registers of the UART aren’t receiving data correctly or correct data. This also explains why the LEDs aren’t lighting up. To make matters worse, the behaviour of the system changes every time I press the reset button.
The reset line has a 10uF timing capacitor on. This gives a long reset time but it also means that the voltage on the reset pin rises very slowly — too slowly perhaps. So I replaced the capacitor with a 100nF one. This didn’t fix the problem.
As an extra precaution, I inserted some NOP instructions between the UART accesses to increase the time between writes. That did seem to change the behaviour but everything is still unpredictable.
Unfortunately, this is one of those cases where a lot of things can cause this. Here’s a list of causes in order of hopefulness:
- The UART interface won’t work properly without a reset pulse.
- Bad solder joints.
- The data or address lines aren’t stable when data is written to UART.
- The CPU isn’t reading the ROM correctly.
- The CPU isn’t working properly.
I’ll first try and see if I can write data to the 8-bit expansion port. This will give me an idea if the bus timings are okay and that the CPU is behaving correctly.
Yesterday was our king‘s birthday and everything stops, including delivery services. The PCB and components I needed for the HD6309 computer still hadn’t turned up. I did have tracking available on both packages, but until the last minute, they kept showing May 1st. Luckily, this afternoon, both packages arrived!
I quickly assembled the board. It went well, except for soldering the 12MHz CPU oscillator; I ordered the wrong package — it’s a lot smaller than the 7x5mm footprint I used. The UART has a 7+ MHz oscillator with 7x5mm footprint so I think I’ll use that.
After assembling the board, the first thing I checked is that there were no shorts. Without fitting the CPU, EPROM and GALs, I applied 5V to the board. Setting a very low current limit is advisable to save components from releasing their magic smoke. The current meter on my power supply is an old analogue one with a bent needle; I estimate the current to be around 20 mA. This is to be expected as there is a power LED:
So far so good!
I have the programming files for the memory decoder GAL done. I need to create the IO decoder GAL files, create a few additiona test programs, and adapt the bootloader I showed previously to use the SCC16C550 UART.
Lots to do, so little time!
This week I exchanged the Z80 core in my RC2014 Z80 computer emulator, with an MC6809 core. I couldn’t seem to find a decent HD6309 core but, as you probably know from the previous blog posts, the HD6309 will run MC6809 binaries! For the time being, I’ll have to live without all the fancy new HD6309 instructions in the emulator but at least I’ll be able to write simple programs for the HD6309 computer.
The hardware the emulator mimics is just the MC6809 core and a very simple UART. The UART isn’t based on any existing design but has a simple interface. It has a transmit and receive register and a status register for the transmitter and receiver. The UART serves as a placeholder for the actual SC16C550B UART. I’ll adapt the bootloader to suit the actual hardware later. The first goal is to get a simple bootloader working.
6809/6309 instruction set
I had never programmed in 6809 assembler until this weekend 🙂 . The only CPUs I have assembler experience with is the Z80, AVR, ARM Cortex and 16-bit/32-bit x86. They have a very different notation, especially when it comes to the addressing modes.
For instance, loading the AX register with the memory contents of the address in the DI register on the x86 is:
On the 6809/6309, loading the A register with the memory contents of the address in the X register is:
The 6809 will also allow you to increment the X register by one in the same instruction:
or by two:
I also created a few bugs related to immediate versus indirect loads. On the 6809/6309, loading the X register with a number ($1234), the syntax should be:
which will load the 16-bit register X with the memory contents at address $1234.
It seems that there aren’t very many online resources that have example programs for the 6809/6309, so it took me a while to get the details figured out. I must say that, even without the additional 6309 instructions, the capabilities of the 6809 are already impressive.
The bootloader is nothing fancy. It checks the RAM (0x0000 .. 0xDFFF) by writing the all-zeros and all-ones pattern to each location and reads it back. If the memory check fails, it will send ‘E’ to the UART and stop. It will continue if the test was successful.
The next step is to setup the stack pointer, so we’re able to call subroutines, and write the startup banner to the UART to show the operator the computer is working.
The loader will wait for a two-byte start address and a two-byte end address, describing the block of memory to be loaded. The addresses are formatted most-significant byte first. The start and end addresses are printed to the console via the UART.
After obtaining the start and end addresses, the loader expects to receive the bytes that make up the memory block. The end address is one byte past the block; it does not get written. When the block is complete, the loader jumps to the start of the block.
; HD6309 COMPUTER - Retrochallenge 04/2017 ; ; BOOTLOADER V1.0 ; By Niels A. Moseley ; ; ================================================== ; SYSTEM CONSTANTS ; ================================================== RAMSTART EQU $0000 RAMEND EQU $E000 STACK EQU $DFF0 ; ================================================== ; UART ADDRESSES ; ================================================== SERIALTX EQU $E000 SERIALRX EQU $E001 SERIALTXS EQU $E002 SERIALRXS EQU $E003 ; ================================================== ; MONITOR ADDRESSES ; ================================================== LDENDADDR EQU $DFFE JMPADDR EQU $DFFC ORG $F000 ; START OF ROM ; ================================================== ; OUTPUT A CHARACTER TO THE CONSOLE ; BLOCKS ON UART TX FULL ; ================================================== OUTC: PSHS B OUTC_1: LDB SERIALTXS BNE OUTC_1 STA SERIALTX PULS B RTS ; ================================================== ; GET A CHARACTER FROM THE CONSOLE ; BLOCKS ON UART RX EMPTY ; ================================================== INBYTE: PSHS B INBYTE_1: LDB SERIALRXS BEQ INBYTE_1 LDA SERIALRX PULS B RTS ; ================================================== ; WRITE A REGISTER AS HEX TO UART ; BLOCKS ON UART TX FULL ; ================================================== PRINTAHEX: PSHS A PSHS A ; convert MS nibble LSRA LSRA LSRA LSRA CMPA #9 BLS PRINTAHEX_1 ADDA #7 ; 'A'-'9'-1 : 65 - 57 - 1 = 7 PRINTAHEX_1: ADDA #'0' JSR OUTC ; convert LS nibble PULS A ANDA #$0F CMPA #9 BLS PRINTAHEX_2 ADDA #7 PRINTAHEX_2: ADDA #'0' JSR OUTC PULS A RTS ; ================================================== ; PRINT STRING POINTED TO BY X ; BLOCKS ON UART TX FULL ; ================================================== PRINTSTRING: PSHS A PRINTSTRING_1: LDA ,X+ BEQ PS_END JSR OUTC JMP PRINTSTRING_1 PS_END: PULS A RTS ; ================================================== ; DUMMY INTERRUPT SERVICE ROUTINE ; ================================================== DUMMYISR: RTI ; ================================================== ; START OF PROGRAM ; ================================================== START: ORCC #%01010000 ; disable interrupts ; CHECK MEMORY 0 .. 0xDFFF LDX #RAMSTART MEMCHKLP: CLRA STA ,X LDA ,X CMPA #$00 BNE MEMERROR ; jump if not zero LDA #$FF STA ,X LDA ,X+ CMPA #$FF BNE MEMERROR ; jump if not equal CMPX #RAMEND BNE MEMCHKLP JMP MEMOK MEMERROR: LDA #'E' STA SERIALTX STOP: JMP STOP ; PRINT THE SIGN-ON MESSAGE MEMOK: LDS #STACK ; LOAD THE STACK LDX #SIGNON JSR PRINTSTRING ; ================================================== ; START OF UPLOAD CODE ; ================================================== ; ; PROTOCOL: ; * LOAD START ADDRESS, MSB FIRST ; * LOAD END ADDRESS, MSB FIRST ; * DATA ; * JUMP TO START ADDRESS ; BOOTLOADER: CLRB JSR INBYTE TFR A,B JSR INBYTE EXG A,B STD JMPADDR ; store jump address ; print the load address LDX #LOADADDRSTR JSR PRINTSTRING JSR PRINTAHEX EXG A,B JSR PRINTAHEX LDX #EOLSTR JSR PRINTSTRING ; get end address bytes JSR INBYTE TFR A,B JSR INBYTE EXG A,B STD LDENDADDR ; store length ; print the end address LDX #ENDADDRSTR JSR PRINTSTRING JSR PRINTAHEX EXG A,B JSR PRINTAHEX LDX #EOLSTR JSR PRINTSTRING ; load the program LDX JMPADDR LOADLP: CMPX LDENDADDR BEQ LDEND JSR INBYTE STA ,X+ JMP LOADLP LDEND: LDX #LOADEDSTR JSR PRINTSTRING JMP [JMPADDR] SIGNON: .db 12 ; form feed .ascii "HD6309 Bootloader v1.0" .db 13,10 .ascii "By Niels Moseley" .db 13,10,0 LOADADDRSTR: .asciz "Start: $" ENDADDRSTR: .asciz "End : $" LOADEDSTR: .ascii "Loaded!" ; note: must be followed by 13,10,0!! EOLSTR: .db 13,10,0 ; ================================================== ; RESET AND INTERRUPT VECTOR TABLE ; ================================================== ORG $FFF2 SWI3VECTOR: FDB DUMMYISR SWI2VECTOR: FDB DUMMYISR FIRQVECTOR: FDB DUMMYISR IRQVECTOR: FDB DUMMYISR SWIVECTOR: FDB DUMMYISR NMIVECTOR: FDB DUMMYISR RESETVECTOR: FDB START
The mandatory screenshot of the bootloader running in the emulator, waiting for the start address:
A simple test program
I wrote a simple test program to test the bootloader. It prints a simple banner and echos all the characters coming in from the UART.
; ================================================== ; SYSTEM CONSTANTS ; ================================================== RAMSTART EQU $0000 RAMEND EQU $E000 STACK EQU $DFF0 ; ================================================== ; UART ADDRESSES ; ================================================== SERIALTX EQU $E000 SERIALRX EQU $E001 SERIALTXS EQU $E002 SERIALRXS EQU $E003 ORG $0000 ; START OF RAM JMP START ; ================================================== ; OUTPUT A CHARACTER TO THE CONSOLE ; BLOCKS ON UART TX FULL ; ================================================== OUTC: PSHS B OUTC_1: LDB SERIALTXS BNE OUTC_1 STA SERIALTX PULS B RTS ; ================================================== ; GET A CHARACTER FROM THE CONSOLE ; BLOCKS ON UART RX EMPTY ; ================================================== INBYTE: PSHS B INBYTE_1: LDB SERIALRXS BEQ INBYTE_1 LDA SERIALRX PULS B RTS ; ================================================== ; WRITE A REGISTER AS HEX TO UART ; BLOCKS ON UART TX FULL ; ================================================== PRINTAHEX: PSHS A PSHS A ; convert MS nibble LSRA LSRA LSRA LSRA CMPA #9 BLS PRINTAHEX_1 ADDA #7 ; 'A'-'9'-1 : 65 - 57 - 1 = 7 PRINTAHEX_1: ADDA #'0' JSR OUTC ; convert LS nibble PULS A ANDA #$0F CMPA #9 BLS PRINTAHEX_2 ADDA #7 PRINTAHEX_2: ADDA #'0' JSR OUTC PULS A RTS ; ================================================== ; PRINT STRING POINTED TO BY X ; BLOCKS ON UART TX FULL ; ================================================== PRINTSTRING: PSHS A PRINTSTRING_1: LDA ,X+ BEQ PS_END JSR OUTC JMP PRINTSTRING_1 PS_END: PULS A RTS ; ================================================== ; START OF PROGRAM ; ================================================== START: ORCC #%01010000 ; disable interrupts LDS #STACK ; LOAD THE STACK LDX #SIGNON JSR PRINTSTRING ; echo input to the output ECHOE: JSR INBYTE JSR OUTC JMP ECHOE SIGNON: .ascii "Hello from a loaded program!" .db 13,10,0,0
And here is the screenshot of it working in the emulator:
I’m using the LWTOOLS toolchain. I’m pretty impressed by the quality of the software. Although I haven’t tried them yet, it does offer support for the additional instructions the HD6309 offers over the MC6809.
I’m running a little behind; I still need to make the configuration files for the GALs and order most of the components. This will be unnecessary if the PCB does not arrive on time — fingers crossed!
P.S. This week I’ll create a repository on my GITHUB account that will hold the emulator source code and the two 6809 programs; stay tuned!