6502 General Purpose Microcontroller
A arduino like board powered by the W65C02 chip!
Journal
Session | Date | Hours Spent |
---|---|---|
1 | May 18, 2025 | 3 |
2 | May 19, 2025 | 5 |
3 | May 20, 2025 | 4 |
4 | May 21, 2025 | 6 |
5 | May 22, 2025 | 5 |
6 | May 23, 2025 | 6 |
7 | May 24, 2025 | 7 |
8 | May 25, 2025 | 7 |
9 | May 26, 2025 | 4 |
10 | May 27, 2025 | 4 |
11 | May 28, 2025 | 2 |
12 | Jun 20, 2025 | 3 |
13 | Jul 01, 2025 | 4 |
14 | Jul 03, 2025 | 6 |
15 | Jul 04, 2025 | 3 |
16 | Jul 05, 2025 | 4 |
17 | Jul 10, 2025 | 2 |
18 | Aug 06, 2025 | 1 |
Total Hours Planning | 53 | |
Total Hours Assemblying | 23 | |
Total Hours Spent | 76 |
Session 1: May 18, 2025 - Beginning
Hours Spent: 3
Every project needs to start somewhere, I have been wanting to mess with the 6502 microcontroller for a while now, and I wanted to expand my hardware experience as well as improve my assembly skills since I started making games for the GameBoy.
The original project idea was spontaneous and originated as a challenge to use a limiting chip that powered hundred of well-known devices, the 6502, in the modern age where tiny and powerful chips like the RP2040 dominate.
The current chips I definitely plan to have are:
Chip/Name | Description | Quantity |
---|---|---|
W65C02S6TPG-14 | The actual W6502S chip, the brains of the microcontroller | 1 |
W65C22S6TPG-14 | The Versatile Interface Adapter of the W6502S, basically handles latched I/O | 2 |
256KiB EEPROM | The Location where the binary will be read from | 1 |
64 KiB RAM | The General Work RAM1 | 1 |
As for the EEPROM, I'll need to make a cheap EEPROM programmer, that turns out to not be that hard with the correct chips, however more research is always needed. A nice to have for the board would be USB-C power.
[!IMPORTANT]
The clock speed of the 6502 is To Be Determined at a later date and will be chosen accordingly to make sure the timings on the RAM are sufficient
Session 2: May 19, 2025 - The start of the Schematic
Hours Spent: 5
The main focus on today has mostly been documentation and putting a start on the PCB design. I focused on connecting the 2 fundamental parts of the project, the W65C02, which is the controller, to the W65C22, the Versatile Interface Adapter. Below is how the schematic is currently looking as well as a brief description on each component
| Component | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------ |
| W65C02 | The main chip, exposes the R/W pin, Data Bus and Address Bus for the other Components |
| VIA1 | The first Versatile Interface Adapter for I/O operations. Exposes both ports on the VIA0_P bus |
| Decoupling Caps | Stabilizes Power Supply Voltage, one cap for each IC |
| PWR PINS
VIA1 Pin | The header to expose the power to the future PCB |
| PWR TGL | The toggle switch for the power, defaults to disabled via a pull-down resistor |
| OSCILLATOR | Provides a clock signal for the ICs, Frequency is TBD but I'll start with 1MHz |
| RESET BTN | Allows for manual operation resets via bridging the ground voltage to the W65C02 |
| I/O Address Matching | Handles the chip select signal for the VIA. Currently the VIA is taking up the whole 0x4000 - 0x8000 memory block. |
The first drafts of the memory map have also been started, here is the current plan
From | To | Usage |
---|---|---|
0x0000 | 0x4000 | RAM2 |
0x4000 | 0x8000 | I/O Operations |
0x8000 | 0xFFFF | ROM3 |
[!NOTE]
The memory map still needs a lot of work but I am for maximum efficiency on both ROM and RAM while keeping costs low.
So far so good, the documentation has been a non issue and is rather well written. The architecture is very simple to which makes it easier to implement than depend on already made solutions.
Session 3: May 20, 2025 - EEPROM & SRAM
Hours Spent: 4
Today is a pretty light but fundamental day on designing the schematic. This is the first introduction of the SRAM and EEPROM modules, the RAM and ROM of our controller.
Here is a schematic of how they are connected
[!NOTE] This schematic showcases a different memory mapping than the original that was switched on the 4th Session
The A0-A15 pins are directly connected to the 65C02 address bus while the DQ0
-DQ7
and I/O0
-I/O7
are connected to the data bus. The important thing to note here are the Chip Select and Chip Enable logic for the SRAM and EEPROM.
Timings - EEPROM
The EEPROM Iām using, the AT28C256, has a read access time of 150ns. According to the 65C02 datasheet, the address setup time is 30ns. This means the total minimum delay for a read operation is around 180ns. Additionally, the logic gates involved introduce a worst-case propagation delay of 25ns each, resulting in a total of 50ns delay for the Chip Select signal to propagate through the logic circuitry.
That limits our clock speed to 4,3478MHz at the worst possible outcome
Figure: W65C02 timing diagram
[!warning] The above times is only a guesstimate, don't take it for granted and I am not going through part of the R/W flow to discuss every delay
Timings - SRAM
The SRAM module I'm using, the AS6C6225, has a read/write delay of approximately 55ns. Accounting for logic gate delays at worst environmental factors, which are again ~50ns, we can measure and confirm if our SRAM module is compatible with the controller.
The read part seems to be in line with what we expect, plenty of time for the clock and the read to happen. Now onto the write part, the other crucial part of why we need a RAM module.
Upon closer inspect to the write characteristics and timing cycle diagram we can spot a potential issue.
Figure: AS6C6225 Timing Table
The address can be invalidated before the write happens, meaning that there is a chance to write data in an unknown place in RAM and corrupt it. The recommended solution for this according to many forum posts and other designs from 6502.org many choose to tie the SRAM Clock Enable pin to the clock so it only write and stops writing before the address changes, The address hold time in this case is 10ns.
With that in consideration we have landed in this clock chip arrangement
[!NOTE] This schematic showcases a different memory mapping than the original that was switched on the 4th Session but the idea is the same
Session 4: May 21, 2025 - Memory Rework, PD, Crystal, IO, ACIA, EEPROM Programmer
Hours Spent: 6
Lots of changes today on the schematic, first and foremost I discovered and spend a lot of time reading the 6502 Primer, which has been a massive help.
A lot of time today was spent trying to figure out not intutive and cross checking that the SRAM timings work fine. I also spent a lot of time researching the correct footprints from LCSC that I will need to have in order to begin the design of the PCB module.
The most important change for today is the reworked memory map which priorities RAM space than ROM space. As such after a lot of research and brainstorming the most optimal ways to get the best of both worlds I had 3 viable solutions.
- Use a multiplexer IC
- Use a 6502 ready address IC
- Make a custom combination by arranging the logic gates in different ways
Avoiding cost and wanting to do it myself I opted for the 3rd option and switched the logic gates in a way so we have more ram and less rom, as I view wram being more important especially when comparated to the relative efficient assembly rom that will be put.
Here is a map of the new memory space:
From | To | Usage |
---|---|---|
0x0000 | 0x7FFF | SRAM |
0x8400 | 0x87FF | ACIA1 |
0x8800 | 0x8FFF | ACIA0 |
0x9000 | 0x9FFF | VIA1 |
0xA000 | 0xBFFF | VIA0 |
0xC000 | 0xFFFF | ROM |
And the specs: + 16 KiB of ROM + 32 KiB of RAM
Another thing I wanted to tackle today are the I/O ports and expansion slots, as such I hooked up both the VIA's and ACIA's pins to headers on the board. I also exposed the power pins and interrupt handlers. Last thing to note is the addition of a header of rows that expand a modular interface of the address and data lines of the 6502 for further expansion using flex cables. 4
The board will also contain a EEPROM Programmer controlled by a RPI pico using picoprom
The final board revision will contain 2x VIAs and 2x ACIAs for a lot of I/O opportunities and serial.
[!info] A cool feature I will try to implement is on the fly program execution using serial
Now for the main board design, I've also added a USB-C & DC Barrel Jack power source. For the Interrupts I have exposed a header that using jumper cables one will be able to select where the interrupt gets chosen from. Last thing to note is that the crystal oscillator now exposes a header for override the board oscillator with an external oscillator if needed, controlled via the tristate pin
Session 5: May 22, 2025 - Schematic Polishing, Decoupling Capacitors
Hours Spent: 5
Today was a lot of important progress on polishing the kicad schematics and adding all the needed capacitors as well as a voltage step down converter for the DC Barrel Jack.
Before this moment I haven't checked the Electric Rule Checker at all, and after I did I was in for a shock. At least 100+ violations of Bus graphically connected but is not a member of that bus
. Hmm that was a bit suspicious, last time I used KiCad buses I never got that error
After a bit of investigation work, this forum post clued me in to what was happening. Since the last time I used KiCad buses was a while ago on an older version for platform control the buses on the newer kicad version were updated. After painstakingly rerouting all of the schematic wire I was still getting bus violations, but to duplicate entries?
After a lot of head scratching the issue was my bus alias definitions, it turns out the nested bus names also act as local/global variables to the schematic. Oops...
I've also spend some time today on assigning proper footprints and getting the necessary LCSC footprint parts to every component, that process was very time consuming because I had to export every easyeda part by hand. Thankfully, or not, I decided to use the included DIP Socket footprints of KiCad thinking that they were going to work okay.
[!NOTE] The screenshot was taken after the fact because I accidentally deleted the original one, woops
Session 6: May 23, 2025 - First PCB Draft Revision, Fail?
Hours Spent: 6
Today I started routing the first PCB routing draft, I started of with 2 layers, one signal and the other primarily a ground plane. I capped myself the PCB at 100mm x 100mm
.
Upon loading all the components I noticed that a lot of them take much more space than originally realized and that I will have to make them a snug fit, but leaving that worry to future me. Firstly I started wiring the ROM chip to the W65C02 while making sure the 4MHz crystal oscillator was close enough.
Hm, that doesn't look quite right, I was leaving space in the middle for all the data pins and GPIO signals that work so they don't crosstalk that much. Quickly I realized the waste of space orienting the ICs like that would have on the board and I decided to opt for another design that preserves much more space and makes the address and data pins have similar widths to prevent incorrect memory access later, or reach race conditions
That seems much better but it still has some bends, angles and via's that I would like to avoid. The usage of via's in the middle in the start like that also provide worst problems later down when I try to connect everything and squeeze as much space I can get out of this thing.
Although I still continued to route as much as I was able to put down.
Halfway through I realized that the crystal oscillator that I used for the W65C02 was not available at the size and frequency that I want but I left that for the next session to figure out.
Session 7: May 24, 2025 - 3rd PCB Revision
Hours Spent: 7
Today I redid the PCB again, I was not ultimately that happy with the distance between the chips and chose to redo the design of he board again. This time with 4 layers and them being stacked like this:
- Top Layer (Signals)
- In1 Copper Layer - Ground Plane (GND)
- In2 Copper Layer - Power Plane (+5V)
- Bottom Layer (Signals)
I chose this layer setup to provide the optimal chance to minimize crosstalk and provide the most optimal routing.
Routing everything was going really well until I had to connect the IC8 and IC6 parts, in this case the ACIA ICs, that was when everything started to be a lot harder. I had to use a few more via's than I would like but in the end everything was connected and that's what mattered. I tried to keep clear of possible points of cross talk and nearly the same amount of vias to every IC chip to minimize longer paths with more resistances. Other than that here is the design I nailed down.
Session 8: May 25, 2025 - CAD Hours Spent: 7
Ultimately I was quite happy with how the PCB turned out, even tho everything is a tight fit. That means the next step for the project is the CAD, I also wanted to take a break from PCB design, considering I stayed up quite late so I could finish it
For the CAD I have 2 choices of software to use 1. FreeCAD 2. Onshape
However considering the convenience of Onshape being all online, I decided to choose that over FreeCad.
After a lot of brainstorming both on paper and draw.io I came up for the following parts that I would like the CAD project to have.
- PCB Frame, holds the PCB in place and prevents accidental contact with the PCB layers to prevent scratching and other surface damage
- Case, Covers the frame to prevent the ICs from being handled incorrectly and prevents the potential of ESD Damage
[!warning] CMOS chips like the W65C02 are very sensitive to ESD damage so we need to be very caution with the handling of the chips
I decided to do the PCB frame larger than needed and add a seperate 3D printed part as a filler so I can sand it down if the clearance got too tight
All that considered here is the frame and case drawing
Session 9: May 26 - Schematic Review, Schematic, PCB review and Fixing DRC issues
Hours Spent: 4
Woah, new session! It will mostly be spent on cleanup of the schematics and cad5 While analyzing the schematic I realized I never added the voltage step down from 12V to 5V, that could have been bad... Well here it is:
I had to design my own symbol for it but that wasn't that bad, KiCad is really nice with working on actually.
For the PCB I noticed that some components were misaligned so I aligned them and added some symbols and footprints with information like the memory layout of the board. Neat!
As for the CAD I added a new extension board for the frame, it has a place for a motherboard for easy access and provides a stable surface to work and carry. Onshape is exceeding my expectations really quickly, it really is an amazing tool to use
Session 10: May 27 - LCSC Part Review, fiting in PCB, Footprints and BOM Hours Spent: 4
After reviewing the footprints I realized I made a glaring issue with the built-in footprints. I turns out LCSC has the footprints in a 90 degree offset, leading to them being wrong in the PCB construction. To fix that I will again manually change update the footprint one part of the time, align it back to the proper place and fix the 10+ DRC violations due to track collisions or tracks being connected accidentally.
The same issue happened with the Pin Header, here is the JLCPCB part assembly preview to visualize the problem better
I also found a solution to the crystal that I needed and LCSC didn't stock. I found a matching through hole crystal in mouser that I can manually solder by myself. For that I moved the pads to the back left edge of the board so I can't risk any of the more critical components being damaged. To avoid further PCB damage too I will add kaptop tape to the areas at risk
Last things for this session I added more informative silkscreen on the board and checked the clearance one more time.
Session 11: May 28 - CA65, Project Template, Build System
Hours Spent: 2
I'm really happy with the progress of the project so far, today I did more code stuff by doing a sample project that can be compiled and used on the board so I can do testing when I have the actual boards. Here is how I have the code project setup so far
.
āāā Makefile # Used to configure the building
āāā gpmc.cfg # The CA65 linker file to declare segments
āāā gpmc.inc # Helper include which contains the I/O mappings
āāā src
ā āāā main.s # The main program
āāā startup.s # Contains the startup logic
āāā vectors.s # Adds the code vectors to the ROM
Configuring CA65 was not that hard, making the Makefile took more time. Here is the linker script I decided to end up with the following configuration and segments (explanation below)
MEMORY {
ZP: start = $0, size = $100, type = rw, define = yes;
RAM: start = $200, size = $7E00, define = yes;
ROM: start = $C000, size = $4000, type = ro, file = %O;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, define = yes;
BSS: load = RAM, type = bss, define = yes;
STARTUP: load = ROM, type = ro;
CODE: load = ROM, type = ro;
RODATA: load = ROM, type = ro;
VECTORS: load = ROM, type = ro, start = $FFFA;
}
[...]
Segment | Usage |
---|---|
ZEROPAGE | Fast access RAM |
BSS | Normal Work RAM |
STARTUP | Contains startup logic |
CODE | Well, the code |
RODATA | Read Only Data, ie strings |
VECTORS | Vectors in memory, ie IRQ |
As for the makefile I ended up with the following commands
+ make all
- Builds the main ROM file
+ make clean
- Cleans the directory of build artifacts
The most interesting part of the Makefile
to point out would be the creation of the actual binary file due to the way we have setup our memory config. Currently ROM gets enabled when both A15 and A14 bits get triggered, that means our sequence always starts with 11(...)
However the EEPROM takes in A0-A14 bits, meaning our memory locations are always with an offset of 0x4000
in hex or 16384
in decimal. That we must prepend 16384
bytes to the flash file before we can use, else we will read invalid addresses. Thus this gives us the following command:
sh
dd if=/dev/zero bs=16384 count=1 2>/dev/null | cat - $(name).out > $(name).bin
Session 12: June 20 - First Parts, ROM
Hours Spent: 3
Woah! It's been a while. In the meantime I have been working on the HEV Unit, but now the Mouser parts are here, so let's get unboxing. After going over to the post office and picking up the package, I found a bag with all of the parts inside, sealed away from humidity and potential ESD damage.
Now that we have the ROM chip, it's time to build the flasher. For this I will be using a spare Pico H I have laying around with picoprom. From the Pico I have cables extensions attached in a breadboard with the specified pinout.
Connecting everything was more tedious than originally imagined but it is what it is. The next step is building the firmware since I didn't have the .uf2 on hand. To do this I first setup the pico-sdk with the manual environment configuration. After cloning everything, it's time to build the pico examples to see if everything was working correctly. Turns out, it wasn't, I installed a deprecated brew arm compiler by mistake, woops, now it works!
Before attaching the ROM chip I want to take care of the cables that are hanging around and about. To do this I first plan to insulate the ends so they don't chance by mistake and tape them so they don't move.
Session 13: July 1 - PCB Disaster
Hours Spent: 4
Welp I picked up the PCB, it looks very good but only after starting to look closer I realized a mistake that I made between conversion rates and LCSC. Turns out DIP-28 socket have a sibling of sorts, DIP-28 Wide that LCSC doesn't really market so as my naive self I decided to go with the DIP-28, as that is what all the other documentation said DIP-28
not DIP-28 Wide
.
That means a bunch of components now don't fit, but after scarfing a bit, I think I can fix it. With a bit of soldering and wire I can fix everything. Well the ROM will be the hardest part, see it is very stuck and I can't solder it down as it will move, so I will go with a ZIF socket instead, adding a QOL feature as well.
Session 14: July 3 - Attempt at fixing
Hours Spent: 6
Woah, that was fast, parts arrived. After I sat down and looked at everything I realized what a grueling task this was going to be. So, I started by preparing my workspace and getting the wire wrap ready.
First I attached the ZIF socket and took a quick look. Yikes that is a lot of space and soldering. So with a playlist, podcasts and a lot of free time at hand I started to solder every. single. wire. I tried my best to mount everything with appropriate supports and even had a angle bracelet and an ESD safe workspace to remove any dangers.
After all that soldering I was too tired to actually test it, so is for tomorrow.
Session 15: July 4 - Debugging Hell
Hours Spent: 3
New day! Nerve wracking... After a quick inspection I found and fixed some cold joints. After that I tried to setup my flashing setup correctly. For that had to setup the SDK and Build the UF2, but after that process everything should be working.
Of course it isn't, why would XMODEM work without problems, after debugging that I ended up just using another program specifically for XMODEM and it finally worked, now let's upload.
Great! Upload complete and verified without problems, now let's put it on the board and-. Oh, oh no, the led is turning on, so that's good but it seems stuck? It was supposed to be blinking. Very sporadic behaviour, sometimes it doesn't even turn on. (You can see my confused expression when talking to acon about it)
I went on and rewrote the program with different assemblers and no dice, sigh :(
Yes, even a lot of nop's didn't work, it's not a SRAM issue.
Session 16: July 5 - Debugging Hell, Pt 2
**_Hours Spent: 4
Sigh, let's continue from where we left off, this time with a fancy new tool, the digital analyzer, didn't think I would need this, but hey. Turning the board on and expecting for the led to light, and... it doesn't work anymore? why? what changed?
My first clue was that LCSC had sent me some bad crystals, after hooking up the logic analyzer i was seeing no output from it? that was weird, I even cross checked with the datasheet and no luck, sigh. To combat that I hooked up another lower freq crystal I had lying around, and hooray the crystal signal is clean again, everything should be working!
Nope, I spoke too soon, something is broken again. Why :c I tried to trace if every wire is connected again and even run a multimeter test for continuity and everything seems to be connected. I truly am baffled, what happened?! I reviewed my schematic again and everything seems to be in order, weird... This is so confusing. I hooked up my logic analyzer to the address pins and to my surprise it was doing stuff, not sure why it's not working tho. The logic gates seem to be responding as well.
I truly can't find what's going on.
Session 17: July 10 - Review
Hours Spent: 2
After leaving the project on the backburner while I was busy with studying, I eventually returned. Now after powering it on, it worked? sometimes. I can't replicate it everytime, it's very rare and inconsistent. My wiring again seems okay but maybe something disconnected or is not making good enough contact? The multimeter says everything is okay, this truly is baffling me. :/
Session 18: Aug 6 - Demo
Hours Spent: 1
After taking the project to make the demo, great, it stopped working altogether, not even sometimes anymore, it just isn't working how it's supposed to and I have no clue why. I truly am baffled. I tried my best after soldering and resoldering and reviewing schematics to make this work like it's supposed to but no dice.
I didn't have a 3D printer on hand, neither did my friends, so I couldn't print and by the time I realized that alternative options were available it was a bit late.
I'm sorry it didn't come out like I expected it, I had high hopes that this idea would work, but here we are.