I had been working on a 6809 CPU board before summer 2017 called and I went back to outdoor activities.
I finally found the Eagle files for that board and uploaded them to github here.
You can also order the PCB from OSHPark here.
[Edited]
1. The initial bring up test code have been uploaded to github here. This includes a BIOS for serial console using the Real Retro UART board
2. The PDF versions of the schematic and board layout have also been pushed to github
Ancient Computing
For when an iPhone X just isn't fun enough
Sunday, May 6, 2018
Saturday, July 1, 2017
MS BASIC for the RC2014 6502 CPU Part 2
My last article covered building the cc65 cross-compiler for use with Mac OS X.
Today, I'll go through the details of the source code modifications to build a version of MS BASIC for the 6502 RC2014 system. To recap, you probably want to look at this archeological analysis of MS BASIC for the 6502.
If you haven't seen it yet, I had previously also described the port of Lee Davison's Enhanced BASIC in this article.
My fork of the MS BASIC source code is on GitHub here.
I decided to use the Ohio Scientific (OSI) configuration as the starting point for the adaptation.
I started off using CONFIG_SMALL := 0 to use 9-digit floating point but found it to be very slow. So back to 6-digit floating point instead.
The original OSI BASIC was based on MS BASIC 1. To get the "latest/greatest", I used CONFIG_2A to build for MS BASIC 2.
RAMSTART2 is set to the beginning of usable RAM at $400. Remember that the $300 page is used by the Monitor/Debugger.
Finally, the serial input/output routines (MONRDKEY and MONCOUT) point to the BIOS entry points.
- BASROM is set to $5000 which is in RAM: I load the binary to RAM for testing. If you are planning to burn the BASIC image into ROM, you will need to set this value to the start address of where the image will be sitting. For example, if you are replacing EhBASIC on a 6502 RC2014 system, you can set the value to $c100 (current EhBASIC start address).
- Unlike EhBASIC, the OSI build of MS BASIC fits under 8KB, so you can change the size from $2400 to $2000
Solution: comment out the line!!
In the more customized versions of MS BASIC, a <platform>_loadsave.s file was used to define the LOAD and SAVE routines. This was pulled into the build process in a series of conditional compile statements in the loadsave.s file.
To fix the problem, I added the following:
.ifdef OSI
.include "osi_loadsave.s"
.endif
SAVE:
rts
LOAD:
rts
While I was doing that, I added a definition for MONISCNTC. This is a routine to check if CTRL-C has been pressed while a BASIC program is running. We call the non-blocking check_input BIOS API at $ff06 and if there is a keypress, check if it is $03.
What worked was a change in osi_iscntc.s to call MONISCNTC as a subroutine vs a jmp. Thus:
ISCNTC:
; jmp MONISCNTC
jsr MONISCNTC
nop
nop
nop
nop
lsr a
bcc RET2
jsr GETLN
cmp #$03
When I have time, I'll dig into this a little further...
There is no fixed entry point to MS BASIC. Every time after making a code change, I had to look in the osi.lbl file to find the address of the COLD_START routine.
On the other hand, the RC2014 Z80 MS BASIC puts the cold start entry point at the start of the binary image. I used the same approach with my port of Enhanced BASIC.
To make this change, I added the following to the header.s file:
.ifdef OSI
jmp COLD_START
jmp RESTART
.endif
The BASIC entry point is now at the start of the BASIC binary image. This is a jmp to the actual cold start entry point. The warm start entry point is 3 bytes after the start of the binary image. This is again a jmp to the actual warm start routine.
Let's talk about the build scripts next.
By default, the script builds for all the platforms. After each platform is built, the resulting bin and lbl files are copied to the tmp directory. The list (msbasic.lst) file is not copied and is overwritten when the next platform is built. The change to make.sh is to also copy the msbasic.lst file to the tmp directory. This makes debugging conditional builds a lot easier.
Since I am uploading the BASIC binary to RAM for testing, I convert it to Intel Hex format using a bin2hex tool.
The latter is based on a Python library. My fork of that code is here.
Use the Monitor/Debugger to upload it to address $5000, then use the 'G' command to launch it:
g 5000
When prompted for "MEMORY SIZE?" type in 8192. This will prevent the BASIC initialization routine from clobbering the BASIC code in RAM. If you are running BASIC in ROM, you can just hit <ENTER> at the prompt.
When prompted for "TERMINAL WIDTH?", just hit <ENTER>.
At that point, you will see the Microsoft copyright message.
This is what I get on my terminal emulator:
The key difference with the RC2014 Z80 MS BASIC is that lowercase is not recognized for program keywords and variable names. You have to use uppercase characters.
Enhanced BASIC has the same limitation.
In terms of performance, MS BASIC for the 6502 is almost 0.3 seconds slower than Enhanced BASIC and 1/2 a second slower than Z80 BASIC running the same prime number benchmark.
Watch this space!!
Today, I'll go through the details of the source code modifications to build a version of MS BASIC for the 6502 RC2014 system. To recap, you probably want to look at this archeological analysis of MS BASIC for the 6502.
If you haven't seen it yet, I had previously also described the port of Lee Davison's Enhanced BASIC in this article.
My fork of the MS BASIC source code is on GitHub here.
I decided to use the Ohio Scientific (OSI) configuration as the starting point for the adaptation.
defines_osi.c
The first level change is in the defines_osi.s file where you can enable or disable features. You will also customize for your hardware and BIOS entry points here.I started off using CONFIG_SMALL := 0 to use 9-digit floating point but found it to be very slow. So back to 6-digit floating point instead.
The original OSI BASIC was based on MS BASIC 1. To get the "latest/greatest", I used CONFIG_2A to build for MS BASIC 2.
RAMSTART2 is set to the beginning of usable RAM at $400. Remember that the $300 page is used by the Monitor/Debugger.
Finally, the serial input/output routines (MONRDKEY and MONCOUT) point to the BIOS entry points.
osi.cfg
The osi.cfg file defines where in memory the BASIC will reside.- BASROM is set to $5000 which is in RAM: I load the binary to RAM for testing. If you are planning to burn the BASIC image into ROM, you will need to set this value to the start address of where the image will be sitting. For example, if you are replacing EhBASIC on a 6502 RC2014 system, you can set the value to $c100 (current EhBASIC start address).
- Unlike EhBASIC, the OSI build of MS BASIC fits under 8KB, so you can change the size from $2400 to $2000
msbasic.s
After setting up osi.cfg and defines_osi.c, I ran an initial build and hit an error. The .feature force_range was undefined in the version of cc65 that I am using.Solution: comment out the line!!
loadsave.s
The next errors I hit were the undefined functions: LOAD and SAVE.In the more customized versions of MS BASIC, a <platform>_loadsave.s file was used to define the LOAD and SAVE routines. This was pulled into the build process in a series of conditional compile statements in the loadsave.s file.
To fix the problem, I added the following:
.ifdef OSI
.include "osi_loadsave.s"
.endif
osi_loadsave.s
And of course I needed to actually write the LOAD/SAVE routines, which were easy to do (!!):SAVE:
rts
LOAD:
rts
While I was doing that, I added a definition for MONISCNTC. This is a routine to check if CTRL-C has been pressed while a BASIC program is running. We call the non-blocking check_input BIOS API at $ff06 and if there is a keypress, check if it is $03.
osi_iscntc.s
Defining MONISCNTC itself did not enable the use of CTRL-C to break a program. I tried porting over Grant Searle's implementation of the ISCNTC routine but that didn't work either.What worked was a change in osi_iscntc.s to call MONISCNTC as a subroutine vs a jmp. Thus:
ISCNTC:
; jmp MONISCNTC
jsr MONISCNTC
nop
nop
nop
nop
lsr a
bcc RET2
jsr GETLN
cmp #$03
When I have time, I'll dig into this a little further...
inline.s
The last functional fix was in inline.s to enable the use of the backspace key for editing. I added an OSI build condition to the INLINAIM routine to check for a backspace character.header.s
Now that I had everything building and actually running, the next step was to make it all easier to use.There is no fixed entry point to MS BASIC. Every time after making a code change, I had to look in the osi.lbl file to find the address of the COLD_START routine.
On the other hand, the RC2014 Z80 MS BASIC puts the cold start entry point at the start of the binary image. I used the same approach with my port of Enhanced BASIC.
To make this change, I added the following to the header.s file:
.ifdef OSI
jmp COLD_START
jmp RESTART
.endif
The BASIC entry point is now at the start of the BASIC binary image. This is a jmp to the actual cold start entry point. The warm start entry point is 3 bytes after the start of the binary image. This is again a jmp to the actual warm start routine.
Let's talk about the build scripts next.
make.sh
I changed the original make.sh build script to enable a detailed assembly listing of each variant of BASIC.By default, the script builds for all the platforms. After each platform is built, the resulting bin and lbl files are copied to the tmp directory. The list (msbasic.lst) file is not copied and is overwritten when the next platform is built. The change to make.sh is to also copy the msbasic.lst file to the tmp directory. This makes debugging conditional builds a lot easier.
buildit.sh
This is my top level build script.Since I am uploading the BASIC binary to RAM for testing, I convert it to Intel Hex format using a bin2hex tool.
The latter is based on a Python library. My fork of that code is here.
Conclusion
The final MS BASIC build file (osi.hex) has been uploaded to GitHub.Use the Monitor/Debugger to upload it to address $5000, then use the 'G' command to launch it:
g 5000
When prompted for "MEMORY SIZE?" type in 8192. This will prevent the BASIC initialization routine from clobbering the BASIC code in RAM. If you are running BASIC in ROM, you can just hit <ENTER> at the prompt.
When prompted for "TERMINAL WIDTH?", just hit <ENTER>.
At that point, you will see the Microsoft copyright message.
This is what I get on my terminal emulator:
The key difference with the RC2014 Z80 MS BASIC is that lowercase is not recognized for program keywords and variable names. You have to use uppercase characters.
Enhanced BASIC has the same limitation.
In terms of performance, MS BASIC for the 6502 is almost 0.3 seconds slower than Enhanced BASIC and 1/2 a second slower than Z80 BASIC running the same prime number benchmark.
NEXT
I will build a ROM image with MS BASIC+Monitor/Debugger for the 6502 RC2014 system.Watch this space!!
Saturday, June 24, 2017
MS BASIC for the RC2014 6502 CPU Part 1
The RC2014 ships with Nascom's version of MS BASIC for the Z80.
I have ported Lee Davison's Enhanced BASIC to the 6502 CPU board. As described in my previous article, Enhanced BASIC is really quite fast. A 4MHz 6502 CPU running a prime number benchmark with Enhanced BASIC is almost as fast as a 14.7456MHz Z80 running MS BASIC.
There are several versions of MS BASIC for the 6502 dating from the original Apple 1.
Michael Steil wrote an excellent archeological analysis of MS BASIC in this article. The key point of the article is that you are now able to build an exact replica of MS BASIC for several ancient 6502-based microcomputers.
The complete source code is hosted on GitHub.
The challenge though is that you need to use the cc65 cross-compiler to build the binaries from source.
Apparently, the latest versions of cc65 don't work. Folks have recommended using version 2.13.3. This can be found in several places including this GitHub repository.
If you are a Windows user, Grant Searle has a prebuilt set of binaries here. However, if you are a Mac user, you will have to build cc65-2.13.3 yourself.
Here is how I did it:
I have ported Lee Davison's Enhanced BASIC to the 6502 CPU board. As described in my previous article, Enhanced BASIC is really quite fast. A 4MHz 6502 CPU running a prime number benchmark with Enhanced BASIC is almost as fast as a 14.7456MHz Z80 running MS BASIC.
There are several versions of MS BASIC for the 6502 dating from the original Apple 1.
Michael Steil wrote an excellent archeological analysis of MS BASIC in this article. The key point of the article is that you are now able to build an exact replica of MS BASIC for several ancient 6502-based microcomputers.
The complete source code is hosted on GitHub.
The challenge though is that you need to use the cc65 cross-compiler to build the binaries from source.
Apparently, the latest versions of cc65 don't work. Folks have recommended using version 2.13.3. This can be found in several places including this GitHub repository.
If you are a Windows user, Grant Searle has a prebuilt set of binaries here. However, if you are a Mac user, you will have to build cc65-2.13.3 yourself.
Here is how I did it:
- Decompress the cc65 source package to cc65-2.13.3 (you can use another name and substitute accordingly in the following steps)
- Build the cc65 cross-compiler
- cd cc65-2-13.3
- cp make/gcc.mak makefile
- make
- make install
In my next article, I'll talk about how to actually configure and build MS BASIC.
Sunday, June 18, 2017
A 6502 CPU for the RC2014 - Software
Hardware is useless without software. So what software do we have for the 6502 CPU board?
Cross Assembler
The biggest challenge as a Mac user in the ancient computing world is that most cross-development tools for 8-bit microprocessors are for use with Windows (and preferably DOS).
Running VMware Fusion is an option but a relatively expensive one: you need to buy Fusion along with a Windows license.
The other option is running TASM in a DOSbox. But that still requires some work.
Since I am quite lazy, I settled on asmx. This is a multi-CPU cross-assembler (it supports everything from the Z80 to the RCA 1802). The maintainer, Bruce Tomlin, can still be reached by email and has been responsive to my (usually dumb) questions.
The trick to using asmx on a modern OS X computer is the compilation process. Yes, you download the sources and run make on them. By default, make will try to build the old ppc binaries. You'll need to edit the src/Makefile to just compile for i686:
TARGET_ARCH = -arch i686
Bring up
Once you have designed and built a new CPU board, you need at a minimum some code to make sure that the CPU board is working. You don't want the initial test code to be too complicated because complication = risk of errors.
Fortunately, there is the Real Retro UART Board. This is based on the ancient AY-3-1015 or similar UART devices. Unlike the more modern (that being a relative term) devices like the 6850, Zilog SIO, 16550 and others, the AY-3-1015 is hard configured i.e. you configure the device by wiring up various signal pins. There is no need to write code to initialize the device.
This makes bringing up a new CPU a little easier: there's less new code to write. I generally just write a bunch of 'A' characters to the serial console to show that the new CPU is running correctly. With the 6502, the code will look like:
reloop
ldx #'A'
uart_out1
lda uart_status ; serial port status
and #$02 ; is tx buffer empty
beq uart_out1 ; no
stx uart_xmit ; put character to Port
jmp reloop
Monitor/Debugger
To make a new CPU system minimally usable, you need a Monitor/Debugger. This will allow you to develop and test other software.
An interesting article about the various 6502 monitors can be found here.
For the RC2014 6502 CPU board, I took Daryl Rictor's "lite" monitor and heavily modified it. The key changes are the following:
BASIC
No new RC2014 CPU board is complete without a version of BASIC.
The 6502 has several versions of BASIC available. I decided to start with a port of Lee Davison's Enhanced BASIC.
Lee passed away several years ago and the original source host site is no longer available. A copy of the 2.22 version is hosted on GitHub by Klaus2m5 and can be found here. A discussion forum dedicated to EhBASIC (as it is referred to) is here.
My own fork of EhBASIC is on GitHub here. As usual, I've made some changes:
Cross Assembler
The biggest challenge as a Mac user in the ancient computing world is that most cross-development tools for 8-bit microprocessors are for use with Windows (and preferably DOS).
Running VMware Fusion is an option but a relatively expensive one: you need to buy Fusion along with a Windows license.
The other option is running TASM in a DOSbox. But that still requires some work.
Since I am quite lazy, I settled on asmx. This is a multi-CPU cross-assembler (it supports everything from the Z80 to the RCA 1802). The maintainer, Bruce Tomlin, can still be reached by email and has been responsive to my (usually dumb) questions.
The trick to using asmx on a modern OS X computer is the compilation process. Yes, you download the sources and run make on them. By default, make will try to build the old ppc binaries. You'll need to edit the src/Makefile to just compile for i686:
TARGET_ARCH = -arch i686
Bring up
Once you have designed and built a new CPU board, you need at a minimum some code to make sure that the CPU board is working. You don't want the initial test code to be too complicated because complication = risk of errors.
Fortunately, there is the Real Retro UART Board. This is based on the ancient AY-3-1015 or similar UART devices. Unlike the more modern (that being a relative term) devices like the 6850, Zilog SIO, 16550 and others, the AY-3-1015 is hard configured i.e. you configure the device by wiring up various signal pins. There is no need to write code to initialize the device.
This makes bringing up a new CPU a little easier: there's less new code to write. I generally just write a bunch of 'A' characters to the serial console to show that the new CPU is running correctly. With the 6502, the code will look like:
reloop
ldx #'A'
uart_out1
lda uart_status ; serial port status
and #$02 ; is tx buffer empty
beq uart_out1 ; no
stx uart_xmit ; put character to Port
jmp reloop
Monitor/Debugger
To make a new CPU system minimally usable, you need a Monitor/Debugger. This will allow you to develop and test other software.
An interesting article about the various 6502 monitors can be found here.
For the RC2014 6502 CPU board, I took Daryl Rictor's "lite" monitor and heavily modified it. The key changes are the following:
- Provide the same user interface as the Monitor/Debugger for the Z80
- Implement a BIOS-like approach for console I/O with (a) an externally accessible vector table for console I/O calls and (b) a way to swap in handlers for different types of UARTs
- Resume from breakpoint
There are several versions of the Monitor/Debugger, depending on which UART/serial IO board you want to use. If you are using the 16550 board, you'll want to have a 16C550 version of the UART. The 16C550 has the autoflow control feature to automatically toggle the RTS signal without intervention from the 6502. This allows us to run that UART at 115200 baud without overwhelming the 6502.
BASIC
No new RC2014 CPU board is complete without a version of BASIC.
The 6502 has several versions of BASIC available. I decided to start with a port of Lee Davison's Enhanced BASIC.
Lee passed away several years ago and the original source host site is no longer available. A copy of the 2.22 version is hosted on GitHub by Klaus2m5 and can be found here. A discussion forum dedicated to EhBASIC (as it is referred to) is here.
My own fork of EhBASIC is on GitHub here. As usual, I've made some changes:
- Implementation of a SYS function to exit back to the Monitor/Debugger
- Clear cold start and warm start entry points. This is meant to provide a similar user interface as the MS BASIC that is used for the Z80 on the RC2014.
- The use of the BIOS API entry points for console I/O
A pre-build ROM image that combines EhBASIC with the Monitor/Debugger is here. The image is 32KB in size but only the top 16KB is actually used.
The EhBASIC cold start entry point is at $c100 (just above the I/O space) and the warm start entry point is at $c103.
Unlike the RC2014 MS BASIC, EhBASIC only recognizes uppercase (caps) commands/functions. Very retro!
Benchmarks
The Z80 and the 6502 are very different devices.
The Z80 runs four clock cycles to execute the fastest instruction. The 6502 runs just one. The Z80 has more registers and more complex ("dense") instructions compared to the 6502.
Therefore, you cannot compare the Z80 and the 6502 by just looking at the clock speeds.
My estimate is that at a given clock speed, the 6502 is approximately 4 times faster than the Z80. Putting it another way, a 1MHz 6502 runs as fast as a 4MHz Z80. The 7.3728MHz Z80 on the RC2014 is as fast as a 1.8432MHz 6502.
Since we now have a version of BASIC for the 6502, I decided to run a benchmark test. The algorithm used is Robert Sharp's prime number program:
20 PRINT "LIMIT";
30 INPUT L
40 FOR N = 3 TO L
50 FOR D = 2 TO (N-1)
60 IF N/D=INT(N/D) THEN GOTO 100
70 NEXT D
80 PRINT N;
90 GOTO 110
100 PRINT ".";
110 NEXT N
120 END
I ran this on a 14.7456 MHz Z80 (using my Z80 CPU board) and a 4MHz 6502 (using the 6502 board for the RC2014).
To find all prime numbers to 199, the Z80 gave 10.62 seconds (iPhone stopwatch), whereas the 6502 gave 10.82 seconds.
Which mostly confirms my hypothesis. The Z80 runs slightly denser/more efficient code which makes it a little faster.
Future
I will be doing two things in the near future:
- Port of Peter Jennings' Microchess to the RC2014
- Port of MS BASIC along with an update benchmark - see new article here
I have both working today but checking them into GitHub will require some clean up work... :)
And of course, there is Forth with several versions floating around in the 6502 world.
Monday, June 5, 2017
A 6502 CPU for the RC2014 Part 2b
Readers of Part 2 of this series of articles on getting the 6502 CPU to run on the RC2014 will recall that I was having trouble getting the standard RC2014 Serial I/O module to work reliably.
The latter is based on the Motorola 68B50 ACIA which uses the same bus architecture as the 6502. So compatibility should have been a slam dunk.
That it was not was entirely due to human error: mine.
I had correctly re-wired pin 14 (the E clock pin) of the 68B50 to pin 4 (TX_CLK) which is itself derived from the Phi2 signal of the 6502. All good there.
However, by doing that, I had removed the IORQ signal from the address decoding process! This meant that I was randomly reading and (worst) writing to the 68B50 while read/writing memory!
The 6502 should select the 68B50 only when IORQ was valid.
This is solved by removing the M1 signal from the CS0 pin of the 68B50. Remember that the M1 signal is unique to the Z80. In that world, you want it to be high ("1") to validate any I/O cycle. On the 6502 CPU board, we had tied this to VCC.
Now that the CS0 pin of the 68B50 is available, we can use it with IORQ. The latter is active low while the CS0 is active high. Pin 2 of the 74HCT04 is the inverse of IORQ and can be used directly to validate CS0.
So we keep the 74HCT04 and connect its pin 2 to CS0 (pin 8 of the 68B50).
Voici:
And it all works!!
Conclusion
- If you want to explore the world of the 6502 CPU with a RC2014, you can reuse all the standard modules (RAM, ROM, Serial I/O) with a little bit of re-wiring work.
- All you need is the 6502 CPU board, a 6502 CPU and a number of other easy to get components.
The latter is based on the Motorola 68B50 ACIA which uses the same bus architecture as the 6502. So compatibility should have been a slam dunk.
That it was not was entirely due to human error: mine.
I had correctly re-wired pin 14 (the E clock pin) of the 68B50 to pin 4 (TX_CLK) which is itself derived from the Phi2 signal of the 6502. All good there.
However, by doing that, I had removed the IORQ signal from the address decoding process! This meant that I was randomly reading and (worst) writing to the 68B50 while read/writing memory!
The 6502 should select the 68B50 only when IORQ was valid.
This is solved by removing the M1 signal from the CS0 pin of the 68B50. Remember that the M1 signal is unique to the Z80. In that world, you want it to be high ("1") to validate any I/O cycle. On the 6502 CPU board, we had tied this to VCC.
Now that the CS0 pin of the 68B50 is available, we can use it with IORQ. The latter is active low while the CS0 is active high. Pin 2 of the 74HCT04 is the inverse of IORQ and can be used directly to validate CS0.
So we keep the 74HCT04 and connect its pin 2 to CS0 (pin 8 of the 68B50).
Voici:
And it all works!!
Conclusion
- If you want to explore the world of the 6502 CPU with a RC2014, you can reuse all the standard modules (RAM, ROM, Serial I/O) with a little bit of re-wiring work.
- All you need is the 6502 CPU board, a 6502 CPU and a number of other easy to get components.
Saturday, June 3, 2017
A 6502 CPU for the RC2014 Part 2
Today's article will talk about how to use RC2014 hardware with the 6502 CPU Board aka what is compatible and what is not.
You can go Tor-Eirik's route by using only custom memory and I/O boards to build a Replica 1. Or you can use what you already have (e.g. the boards that come with the RC2014 Full Monty kit).
To start, the following picture shows how we are inverting the Z80 and 6502 memory space as discussed in the last article:
RAM
RAM compatibility is the easiest to deal with.
The original 32KB RAM module works as-is. The entire 32KB is mapped to 0000h-7FFFh in the 6502 address space.
The 64KB RAM module works as long as you either disable or remove the lower 32KB device. This may sound counterintuitive until you consider that we're inverting the A15 signal to flip the upper and lower 32KB memory segments. If you look at this picture, the device to remove is U3 (marked as Start-7FFF). You will want to keep the device marked 8000-FFFF as it will be remapped to 0000h-7FFFh by the inverted A15 signal.
My own Real Retro 3KB RAM board will work as long as you short the JP1 jumpers. The latter will map the RAM from 0000h-0C00h in the 6502 memory space.
My Simple RAM/ROM board will also work. You will want to configure it, if you are inverting A15 on the 6502 CPU board, for ROMLO and RAMHI.
ROM
ROM is a little bit more complicated.
There are currently 2 "standard" ROM modules for the RC2014. I'll ignore the 8K module as I think it's no longer available.
The first module is that one that you'll get with the Full Monty kit. This module/board uses a 27512 ROM and splits the 64KB capacity of the ROM into 8 pages of 8KB each.
The address lines A15, A14 and A13 are used to decode the ROM in memory and 3 jumpers are used to select the page.
If we were to use the module without any modifications, we will map the ROM correctly to the top 32KB memory segment of the 6502 address space. However, the A14 and A13 will only select the ROM when they are low (0) which ends up mapping the ROM page to the lowest 8KB of that 32KB memory segment. Instead, we need the ROM page to be mapped to the highest 8KB in memory.
My solution has been to lift off Pins 1 through 3 of U1 (the 74HCT32), then solder a link from Pin 3 (U1) to ground. See this picture:
The next step is to select the right page in the ROM.
Assuming that you are using one of my ROM images and a 27512 ROM, you will probably only be writing the ROM image to the bottom 32KB of the 27512 ROM.
The 6502 boot code and Monitor/Debugger are located at the top part of the ROM image i.e. in page 3 of the 27512. So you will want to configure the jumpers to select Page 3.
The above applies only if you are using a 27512 device. If you are like me and use a 28C256 32KB EEPROM, you will want to tie the jumpers high (to '1').
The Pageable ROM module/board is a little easier although you will still want to make a wiring change.
The latter is to disable the paging circuitry. I have not tested that circuitry with the 6502. However, I have verified that it will crash an Intel 8085 (my 8085 CPU board for the RC2014). The reason for this is that the paging circuitry does not fully qualify I/O requests (e.g. via the WR or RD signals). So the ROM may be paged out in error.
To disable the paging circuitry, remove U6 (74HC393) and U2 (74HCT138). Then solder a link from pin 3 of the 74HC393 to ground.
If you are using a 27512, you will want to configure for a 32KB page size, then select the lower 32KB page (A15 of the 27512 to ground or '0').
If you are using a 28C256, things get more complicated. You will select a 32KB page size, but leave off the left-most jumper. Then jumper the A14 and A15 lines (in the page selector) to high or '1'. See the following illustration:
Page size:
x x x x x
| | | |
x x x x x
x x x x x
Page selection:
x x x x x x
| |
x x x x x x
x x x x x x
My Simple RAM/ROM board will also work. You will want to configure it, if you are inverting A15 on the 6502 CPU board, for ROMLO and RAMHI.
Serial I/O
Serial I/O on the RC2014 is done by a Motorola 68B50 ACIA. This device is bus compatible with the 6502. However, because of the way it is wired for use with the Z80, compatibility with the 6502 is not straightforward.
At the minimum, the E signal (Pin 14) must be disconnected from IORQ. To do this, you just need to pull the 74HCT04! Then you need to connect E to the CLK line of the RC2014 bus. The easiest way is to Pin 3 or 4 of the 68B50.
Finally, you will want to run the 6502 at a baudrate-friendly frequency. This is because the 6502's Phi2 output is connected to CLK and therefore used to generate the baudrate on the 68B50. I use a 1.8432MHz oscillator.
Now, this setup works. However, it has not worked reliably for me. It is possible that the 68B50 needs the actual R/W signal from the 6502 instead of the RD signal. I'll have to investigate further.
My own UART boards (both 16550 versions and the Real Retro UART) work. The key again, with I/O is to add C000h to the original Z80 port addresses.
Dr Baker's SIO board will likely not work as it uses a Z80-specific device. In any case, I have not tested it.
Other hardware
There are a number of other interesting RC2014 boards but I have not tested them for compatibility with the 6502. I would encourage other folks to check them out and let the community know what works vs doesn't work and/or workarounds/patches.
The RC2014 community itself has gone in many directions as far as add-on boards are concerned. Spencer Owen has graciously compiled a list of RC2014-compatible projects here.
Hopefully, the availability of a 6502 CPU board will spur development in even more directions...!
Next
In my next article, I'll cover software for the 6502.
You can go Tor-Eirik's route by using only custom memory and I/O boards to build a Replica 1. Or you can use what you already have (e.g. the boards that come with the RC2014 Full Monty kit).
To start, the following picture shows how we are inverting the Z80 and 6502 memory space as discussed in the last article:
RAM
RAM compatibility is the easiest to deal with.
The original 32KB RAM module works as-is. The entire 32KB is mapped to 0000h-7FFFh in the 6502 address space.
The 64KB RAM module works as long as you either disable or remove the lower 32KB device. This may sound counterintuitive until you consider that we're inverting the A15 signal to flip the upper and lower 32KB memory segments. If you look at this picture, the device to remove is U3 (marked as Start-7FFF). You will want to keep the device marked 8000-FFFF as it will be remapped to 0000h-7FFFh by the inverted A15 signal.
My own Real Retro 3KB RAM board will work as long as you short the JP1 jumpers. The latter will map the RAM from 0000h-0C00h in the 6502 memory space.
My Simple RAM/ROM board will also work. You will want to configure it, if you are inverting A15 on the 6502 CPU board, for ROMLO and RAMHI.
ROM
ROM is a little bit more complicated.
There are currently 2 "standard" ROM modules for the RC2014. I'll ignore the 8K module as I think it's no longer available.
The first module is that one that you'll get with the Full Monty kit. This module/board uses a 27512 ROM and splits the 64KB capacity of the ROM into 8 pages of 8KB each.
The address lines A15, A14 and A13 are used to decode the ROM in memory and 3 jumpers are used to select the page.
If we were to use the module without any modifications, we will map the ROM correctly to the top 32KB memory segment of the 6502 address space. However, the A14 and A13 will only select the ROM when they are low (0) which ends up mapping the ROM page to the lowest 8KB of that 32KB memory segment. Instead, we need the ROM page to be mapped to the highest 8KB in memory.
My solution has been to lift off Pins 1 through 3 of U1 (the 74HCT32), then solder a link from Pin 3 (U1) to ground. See this picture:
The next step is to select the right page in the ROM.
Assuming that you are using one of my ROM images and a 27512 ROM, you will probably only be writing the ROM image to the bottom 32KB of the 27512 ROM.
The 6502 boot code and Monitor/Debugger are located at the top part of the ROM image i.e. in page 3 of the 27512. So you will want to configure the jumpers to select Page 3.
The above applies only if you are using a 27512 device. If you are like me and use a 28C256 32KB EEPROM, you will want to tie the jumpers high (to '1').
The Pageable ROM module/board is a little easier although you will still want to make a wiring change.
The latter is to disable the paging circuitry. I have not tested that circuitry with the 6502. However, I have verified that it will crash an Intel 8085 (my 8085 CPU board for the RC2014). The reason for this is that the paging circuitry does not fully qualify I/O requests (e.g. via the WR or RD signals). So the ROM may be paged out in error.
To disable the paging circuitry, remove U6 (74HC393) and U2 (74HCT138). Then solder a link from pin 3 of the 74HC393 to ground.
If you are using a 27512, you will want to configure for a 32KB page size, then select the lower 32KB page (A15 of the 27512 to ground or '0').
If you are using a 28C256, things get more complicated. You will select a 32KB page size, but leave off the left-most jumper. Then jumper the A14 and A15 lines (in the page selector) to high or '1'. See the following illustration:
Page size:
x x x x x
| | | |
x x x x x
x x x x x
Page selection:
x x x x x x
| |
x x x x x x
x x x x x x
My Simple RAM/ROM board will also work. You will want to configure it, if you are inverting A15 on the 6502 CPU board, for ROMLO and RAMHI.
Serial I/O
Serial I/O on the RC2014 is done by a Motorola 68B50 ACIA. This device is bus compatible with the 6502. However, because of the way it is wired for use with the Z80, compatibility with the 6502 is not straightforward.
At the minimum, the E signal (Pin 14) must be disconnected from IORQ. To do this, you just need to pull the 74HCT04! Then you need to connect E to the CLK line of the RC2014 bus. The easiest way is to Pin 3 or 4 of the 68B50.
Finally, you will want to run the 6502 at a baudrate-friendly frequency. This is because the 6502's Phi2 output is connected to CLK and therefore used to generate the baudrate on the 68B50. I use a 1.8432MHz oscillator.
Now, this setup works. However, it has not worked reliably for me. It is possible that the 68B50 needs the actual R/W signal from the 6502 instead of the RD signal. I'll have to investigate further.
My own UART boards (both 16550 versions and the Real Retro UART) work. The key again, with I/O is to add C000h to the original Z80 port addresses.
Dr Baker's SIO board will likely not work as it uses a Z80-specific device. In any case, I have not tested it.
Other hardware
There are a number of other interesting RC2014 boards but I have not tested them for compatibility with the 6502. I would encourage other folks to check them out and let the community know what works vs doesn't work and/or workarounds/patches.
The RC2014 community itself has gone in many directions as far as add-on boards are concerned. Spencer Owen has graciously compiled a list of RC2014-compatible projects here.
Hopefully, the availability of a 6502 CPU board will spur development in even more directions...!
Next
In my next article, I'll cover software for the 6502.
Sunday, May 28, 2017
A 6502 CPU for the RC2014 Part 1
The RC2014 design is based on the Z80 8-bit microprocessor.
As far as 1970s-era microprocessor design is concerned, the Z80 and 6502 are on polar opposites. The Z80 is based on the Intel 8080 whereas the 6502 is based on the Motorola 6800.
The design philosophies are very different:
- The 6800 and 6502 use a strict synchronous bus. Each memory or I/O access cycle completes within a single clock system. The clock signal is also used to gate the read and write control lines to memory and peripherals.
- The 8080 and Z80 use a loosely asynchronous bus where the memory or I/O access cycles take a variable number of clock cycles to complete. The clock signal is not used to gate read/write access. Unless you want to generate wait states for slow peripherals or use Zilog Z80-specific parts (PIO, CTC etc) in your design, you can safely ignore the clock signal.
So how would you go about building a 6502 CPU board for the RC2014 system?
The RC2014 bus was designed in a very similar way to the S100 bus: where the latter is based on the 8080 signals, the RC2014 bus signals are just Z80 signals.
Let's look at each of the Z80 signals and see how we can generate their equivalent from the 6502. We will only consider the signals that are actively used to access memory and I/O. Signals like RFSH, BUSRQ, WAIT, BUSAK, HALT, NMI are not routed on the base RC2014 system and we'll ignore them for now.
M1
Let's start with a signal that we don't care about. The Z80 M1 signal is used with the IORQ signal to indicate an interrupt acknowledge cycle. This is only really used for Z80 peripheral devices like the Z80 PIO, CTC or SIO. Since the 6502 by default grabs interrupt vectors from high memory, we can tie M1 to Vcc.
RD & WR
These are the read and write signals for memory and I/O. The 6502 has a combined signal R/W which is high for read and low for write. In 6502 designs, the R/W is usually gated with the Phi2 clock to generate separate read and write lines. This is what we will do here.
IORQ
The Z80 (and 8080) have a dedicated I/O address space that is separate from memory. The 6502 does not have anything similar. Instead, its I/O address space is part of its 64KB space: what we referred to in more modern terms as memory-mapped I/O.
6502 designs generally carve out part of the 64KB address space for peripherals. We will do this in our design: we will map out a 256-byte address space for use with the RC2014 bus. The IORQ signal will be decoded and active low when this address space is accessed by the 6502 CPU.
MREQ
As far as the 6502 is concerned, anything that is not used by I/O can be considered memory, so we generate the MREQ signal by inverting the IORQ signal.
Schematic
The design that we come up with is as follows:
IC2 is a 74HCT688 that is used to decode the 256-byte I/O space. Its output is IORQ and is also inverted by IC1E to generate MREQ
The RD and WR signals are generated by a pair of NAND gates (IC4A & B) and an inverter (IC1C).
When you look at the design carefully, you will realize that IC1F inverts the A15 signal from the 6502. What is that for?
In addition to the difference in bus design philosophies, the Z80/8080 and 6502/6800 families differ in one critical area. The Z80/8080 place their reset and interrupt vectors in low memory. The first instruction after a reset is fetched from address 0000h. On the other hand, the 6502/6800 place their reset and interrupt vectors at the top of memory. The address of the first instruction after a reset (on the 6502) is fetched from FFFCh.
The result of this is that in Z80 systems like the RC2014, ROM memory is at the bottom of the memory space and RAM memory is placed at the top. The base RC2014 RAM board has its RAM mapped from 8000h-FFFFh, for example. On the other hand, 6502 designs will place RAM at the bottom of memory (starting at 0000h) and ROM at the top (finishing at FFFFh).
Therefore in order to cleanly map a 6502 CPU into a typical RC2014 memory configuration, we invert the A15 signal of the 6502. This essentially flips the memory map around so that the base RC2014 RAM board will be seen as mapping its RAM at 0000h-7FFFh. The RC2014 ROM boards are a little more complicated but can be made to work.
The A15 jumper strip allows you to select whether to use the inverted A15 signal.
I/O Mapping
What about I/O mapping? In our design, the 74HCT688 will decode the I/O space to be between C000h and C0FFh. This means that if you know the Z80 port address of a given peripheral, you can figure out the 6502 address of the peripheral by adding C000h to the port address.
Board design
The next picture shows the final board design:
As far as 1970s-era microprocessor design is concerned, the Z80 and 6502 are on polar opposites. The Z80 is based on the Intel 8080 whereas the 6502 is based on the Motorola 6800.
The design philosophies are very different:
- The 6800 and 6502 use a strict synchronous bus. Each memory or I/O access cycle completes within a single clock system. The clock signal is also used to gate the read and write control lines to memory and peripherals.
- The 8080 and Z80 use a loosely asynchronous bus where the memory or I/O access cycles take a variable number of clock cycles to complete. The clock signal is not used to gate read/write access. Unless you want to generate wait states for slow peripherals or use Zilog Z80-specific parts (PIO, CTC etc) in your design, you can safely ignore the clock signal.
So how would you go about building a 6502 CPU board for the RC2014 system?
The RC2014 bus was designed in a very similar way to the S100 bus: where the latter is based on the 8080 signals, the RC2014 bus signals are just Z80 signals.
Let's look at each of the Z80 signals and see how we can generate their equivalent from the 6502. We will only consider the signals that are actively used to access memory and I/O. Signals like RFSH, BUSRQ, WAIT, BUSAK, HALT, NMI are not routed on the base RC2014 system and we'll ignore them for now.
M1
Let's start with a signal that we don't care about. The Z80 M1 signal is used with the IORQ signal to indicate an interrupt acknowledge cycle. This is only really used for Z80 peripheral devices like the Z80 PIO, CTC or SIO. Since the 6502 by default grabs interrupt vectors from high memory, we can tie M1 to Vcc.
RD & WR
These are the read and write signals for memory and I/O. The 6502 has a combined signal R/W which is high for read and low for write. In 6502 designs, the R/W is usually gated with the Phi2 clock to generate separate read and write lines. This is what we will do here.
IORQ
The Z80 (and 8080) have a dedicated I/O address space that is separate from memory. The 6502 does not have anything similar. Instead, its I/O address space is part of its 64KB space: what we referred to in more modern terms as memory-mapped I/O.
6502 designs generally carve out part of the 64KB address space for peripherals. We will do this in our design: we will map out a 256-byte address space for use with the RC2014 bus. The IORQ signal will be decoded and active low when this address space is accessed by the 6502 CPU.
MREQ
As far as the 6502 is concerned, anything that is not used by I/O can be considered memory, so we generate the MREQ signal by inverting the IORQ signal.
Schematic
The design that we come up with is as follows:
IC2 is a 74HCT688 that is used to decode the 256-byte I/O space. Its output is IORQ and is also inverted by IC1E to generate MREQ
The RD and WR signals are generated by a pair of NAND gates (IC4A & B) and an inverter (IC1C).
When you look at the design carefully, you will realize that IC1F inverts the A15 signal from the 6502. What is that for?
In addition to the difference in bus design philosophies, the Z80/8080 and 6502/6800 families differ in one critical area. The Z80/8080 place their reset and interrupt vectors in low memory. The first instruction after a reset is fetched from address 0000h. On the other hand, the 6502/6800 place their reset and interrupt vectors at the top of memory. The address of the first instruction after a reset (on the 6502) is fetched from FFFCh.
The result of this is that in Z80 systems like the RC2014, ROM memory is at the bottom of the memory space and RAM memory is placed at the top. The base RC2014 RAM board has its RAM mapped from 8000h-FFFFh, for example. On the other hand, 6502 designs will place RAM at the bottom of memory (starting at 0000h) and ROM at the top (finishing at FFFFh).
Therefore in order to cleanly map a 6502 CPU into a typical RC2014 memory configuration, we invert the A15 signal of the 6502. This essentially flips the memory map around so that the base RC2014 RAM board will be seen as mapping its RAM at 0000h-7FFFh. The RC2014 ROM boards are a little more complicated but can be made to work.
The A15 jumper strip allows you to select whether to use the inverted A15 signal.
I/O Mapping
What about I/O mapping? In our design, the 74HCT688 will decode the I/O space to be between C000h and C0FFh. This means that if you know the Z80 port address of a given peripheral, you can figure out the 6502 address of the peripheral by adding C000h to the port address.
Board design
The next picture shows the final board design:
And the populated board:
Note that the JP1 jumper is needed only if you are using the Western Design Center 65C02. It is used to ground the VPB line.
Eagle design files can be found at GitHub.
Boards can be ordered from OSH Park by clicking on the following icon
The next installment (Part 2) will cover how to use this board with an RC2014 system and will briefly touch on the software.
Subscribe to:
Posts (Atom)