uPD7220 Retro Graphics Card (and VGA hack)

Making an 80s GDC run for the first time in decades, and my first real hack on

Public Chat
Similar projects worth following
The uPD7220 is a fascinating chip from the 1980s. It was meant to control CRT displays and provide graphics capabilities, but I have found a way to make it output a valid VGA signal.

It is really complex, so understanding it takes a lot of studying of the sparse available information (and virtually no example code), but most certainly worth it. I intend on sharing my understanding and lessons here so more people can more easily use this awesome chip!!!

I plan on posting more on this when I can!



This is best used for designing a circuit with the uPD7220 and for understanding how to initialize and draw with it.

Programming Manual? :

This will explain how to send commands and generally how the CPU to uPD7220 interface works.

My Z80 code:

This is the graphics driver I am writing for my Z80 computer.  It's good example code, but it currently has numerous limitations, so look at the arduino sketch I uploaded to this project as well.


I want a graphics card for my Z80 computer so it can operate completely independently, as in, without a serial monitor.

I don't want to use a propeller chip or other powerful microcontroller because those chips don't go with the rest of my Z80 computer.  Besides, something about this design just feels really... pure, I suppose.  Clean.

NOTE: The information provided in this details section is very condensed.  There is much, much more to be understood.  I recommend STUDYING the documents I linked and uploaded.  The following information is just a brief overview.

How does the hardware work?

The uPD7220 generates VSYNC, HSYNC, and BLANK signals.  It generates a few other signals for the memory interface, but these must be interpreted.  The uPD7220 address and data lines share a bus, so the address has to be latched.  Also, to write to memory, there are special cycles which require external hardware to generate a write enable.

There are two clocks.  The pixel clock, which is currently 8Mhz, is used to output pixels.  The uPD7220 takes lower frequencies, so the pixel clock is halved to make the 2xWCLK clock, which is sent to the uPD7220.

The uPD7220 reads the pixel data onto the data bus, where it is latched every fourth pixel clock rising edge.  The shift registers output pixel data while the uPD7220 prepares for the next set of pixels.

The port which goes to the system microprocessor is directly connected to the uPD7220, except for two OR gates which generate the WE and RD signals.

How does the software work?

There are two ports that can be written/read on the uPD7220:

0Status registerParameter load
1Data to CPU FIFOCommand load

Before each write, the status register FIFO full flag must be checked first.  If the FIFO is full, then a write will create undefined behaviour.

The uPD7220 must be initialized properly first.  If it is not initiallized right, then random commands will crash it when it is least expected.  These commands all must be used in initialization:

0x00 : reset (followed by graphics parameters)

0x47 : pitch (aka tell the GDC the number of horizontal words there are per line)

0x70 : set up PRAM so drawing operations work

0x4B : CCHAR : set up character parameters.  

0x46 : set the zoom.  Otherwise zoom may be random.

0x6B : start the display!  YEET!


KiCad raw PCB design. This can be uploaded directly to OSHPark.

x-kicad-pcb - 1.89 MB - 05/08/2024 at 01:52


Updated schematic, with all KiCad design files. This is a bit messed up due to the KiCad version change and transfer, but the PCB design should work fine as is. This fixes the connections to the color resistor networks, and fixes the oscillator.

Zip Archive - 3.62 MB - 05/08/2024 at 01:51



Updated schematic, provided in PDF format. This fixes the connections to the color resistor networks, and fixes the oscillator.

Adobe Portable Document Format - 138.46 kB - 05/08/2024 at 01:50


Python3 program to create valid VGA video timings for the uPD7220. Use it to generate values to plug into videoconf.h

plain - 5.11 kB - 04/04/2019 at 06:05



An arduino sketch used to control my graphics card. Use it as example code, a test program, or as a base for your own driver!

ino - 3.77 kB - 04/04/2019 at 06:04


View all 8 files

  • 1 × Z7220 Super Rad 1980s GDC, clone of uPD7220. The Z7220 is fast enough, the original isn't
  • 4 × 74173 Logic ICs / Flip-Flops, Latches, Registers
  • 4 × 1k Resistor
  • 1 × 10k Resistor
  • 1 × 8,10, or 12 Mhz DIP8 Oscillator

View all 13 components

  • V2 Board Design

    Dylan Brophy6 days ago 0 comments

    KiCad 3D render of my board design:I tried to make the parts of the circuit clearly visible on the board.  I also added LEDs, which I typically forget when designing a board. Every board needs blinking lights. Well, I think this board has turned out nicely, at least in the 3D render; it has the clean look I wanted.

    Here's the ratsnest and basic layout before I routed it:The board now:This board was a lot easier to route than I expected.  Anyway, expect an update in maybe 10 days when I actually assemble it.

  • V2 Schematic Ready

    Dylan Brophy6 days ago 0 comments

    I have the schematic finished now.  I checked the major critical paths to the VRAM, fining one that was too slow.  The VRAM takes up to 55ns from address input to data output, and I have only 62.5ns, so really it is super close.  Since the uPD7220 uses an address latching mechanism, I managed to move my address-modifying critical path to before this latching is done.  The timing there is much more forgiving.  Other than that, I added some pretty LEDs and checked/fixed some of the logic done in the circuit.I may add more decoupling capacitors still, but that isn't a real design change.  The capacitors are the only SMD components I'm using.

    In total I'm using 32 TTL ICs, two RAM chips, and the uPD7220 of course.  Loading it in the PCB editor, it looks smaller than I may have expected, but I don't think I'll feel the same when I receive the finished board - it is significantly bigger than my original uPD7220 card:I think I'll also need to make some minor adjustments to the circuit design so the routing is easier, but these are not really functional changes - things like changing the bit order on registers, or rearranging the allocation of gates from chips.

  • New Schematic is Nearly Complete

    Dylan Brophy05/10/2024 at 18:55 0 comments

    My schematic so far:

    This schematic is way better organized, and hopefully it will still make sense to me 5 years from now.  I've added a ton of features since the last board revision, namely:

    • The CPU can now directly access the VRAM
    • I doubled the maximum pixel clock by allowing for uPD7220's wide mode (see last log)
    • Added support for double buffering
    • I octupled the maximum VRAM to 512KiB from 32KiB.  Now we can have larger resolutions with enough RAM left over to double-buffer

    Doing all this added a TON of extra logic, so if you compare the above schematic with the schematic of the previous board, this one has at least twice the components, and is far denser.

    I had to add a lot of buffers so that the VRAM bus could be shared.  This concerns me because it adds a few tens of nanoseconds to certain datapaths, meanwhile I've doubled the maximum VRAM clock speed to 16Mhz.  The VRAM uses 55ns alone, and that doesn't count any of the hardware for uPD7220 memory cycle detection, bus sharing logic, etc.  So the next step will include checking my datapaths to make sure all the components process fast enough for my clocks.

    Here is some of the new logic for handling the communication from the main processor directly to VRAM:Some of this logic is wrong I think, namely I'm suspicious of the two bottom NAND gates, and I need to add logic for the WAIT line, but this image should give some idea of what the logic is supposed to do.  After the main processor writes the lower address byte, the byte-select for the VRAM is reset to zero.  Then the processor can write a single byte to the VRAM, which automatically switches the selected byte so the processor can write the other byte.  This is done because the VRAM has a 16-bit bus and the processor has an 8-bit bus.  Depending on weather the address counting is enabled, the address registers will actually count up to the next word in VRAM, so that the processor can send up to 128KiB of uninterrupted data to VRAM.  This is done in-between accesses done by the uPD7220, as the bus is shared, and the uPD7220 gets priority.

    The exact behavior of the board's logic is controlled by a special control register I added:I realize now, looking at this, that I may be able to remove a latch by using A0 for byte select instead of automatically selecting it.  Something to think about.  Anyway, in the image above you can see that the config register can enable/disable the wide mode logic, control automatic address count, enable or disable double-buffering, to swap buffers, and set A16/A17 for direct VRAM access.  The double-buffer enable will make the uPD7220 and processor write to the opposite buffer as the one being displayed, but the buffer still must be manually swapped by the processor.

    Anyway, this is where I'm at now.  The schematic isn't quite finished, once I finish it and have the board design I'll upload the files to the project.

    [edit] bonus: falstad simulation of part of the circuit responsible for loading pixel data from VRAM and clocking it out, which allows wide mode:  Simulation

  • "Wide display mode"

    Dylan Brophy05/09/2024 at 16:20 0 comments

    I found part of the datasheet discussing "wide display mode", which tells the uPD7220 to skip an address each time it loads a word to be displayed.  Here are the relevant sections of the datasheet:As it turns out, I don't think I can get it to add 4 instead of just adding two as described above; this limits my maximum clock speed to 24Mhz (32Mhz on the faster Z7220), so the maximum resolution would be limited by this.  On the other hand, the uPD7220 supports interlacing, so I might be able to push out a higher resolution that way.  Without interlacing under this config, I can't even get to 640x480, but with interlacing I can get at least to 720x480.  I'll have to play with the settings.

    I'll need to add a 16-bit register to handle this, since I don't have a real 32-bit bus to load color data from:
    I still need to add the logic to generate LD_PIX_TMP, which requires detection of the uPD7220's memory cycles.

    The waveforms should look something like this:

    The clock at the top is the pixel clock, the fastest it can do is 4x the max GDC clock (so 24Mhz for uPD7220, 32Mhz for certain Z7220 variants).  The third clock from the top is the GDC clock.  The color shift registers load every fourth pixel clock, shown on the 6th signal down from the top.  Each GDC memory cycle we will now be loading 8 pixels instead of just 4, so you see the pixel number reflect this.  Once the address is latched, we can load two words in succession, at twice the GDC clock speed.  To do this, we use the 16-bit register previously mentioned, which loads twice during this single GDC memory cycle, once for each 16-bit word.  The first time it does this, the color shift registers are immediately loaded, thus saving the color data for the first four pixels.  This way, the same 16-bit register can be reused to save the next word.  The LOAD signal to this register is shown as the active-low signal on the bottom of the image above.

    Here's the logic I designed to generate this waveform:
    As a bonus, I'm including a timing diagram from the datasheet so it is easier to find later:This image details the cycles of various uPD7220 memory accesses, and is super useful for designing the memory control logic.

  • We can certainly make this better.

    Dylan Brophy05/09/2024 at 15:39 0 comments

    I hadn't looked at this project in a long time, and the other day I was browsing it and noticed several comments asking for the schematics. But hadn't I uploaded schematics?  So I double checked the files, found the attached schematic zip, and decided to open it up.  Oh geez, what a mess!  It had been created with a very old KiCad version compared to today, and I don't think I uploaded the symbol libraries, so the schematics were useless.  I can see now why people asked for the schematics!Broken schematic

    Very useful indeed. (not)
    I spent some time the other day cleaning this up, as well as fixing a few hardware bugs related to the color DAC and oscillator.  I modified the schematic to match the modifications on my board at home, which works quite well.  Here's the schematic now, which I uploaded:
    Repaired schematic
    A lot better, but still messy.
    The wires are very messy, consistent with how I made many schematics in highschool.  Clearly, this schematic needs to be redone from scratch.  Well, if I'm going to redo the schematic and roll a new board, why not make a bunch of improvements too?  Well, this is exactly what I've been working on.

    Upgrading the board
    If you saw my log in #Arduino Desktop, then you'll know that I mentioned this project, in that I may want to add it to another Teensy or ESP32 based computer system.  A Teensy 4.1 could write a lot of data to VRAM very quickly, which would be great for drawing bitmaps, and in-between the uPD7220 can draw other shapes.  In that log I also mentioned double-buffering the uPD7220, so there would effectively be two RAM banks, which could be switched by some command.  To my knowledge, the uPD7220 does not support this, so I needed to add the logic myself.  I'm still working on the schematic, but here's where we are so far:I'm not a huge fan of the old board's low resolution.  I want at least 640x480, if not higher.  Adding more memory for this is quite easy, and in the new schematic this is already handled - the hard part is getting the clock speeds high enough.  The uPD7220 can clock at 6Mhz, and the current card gets this by dividing it out of a 12Mhz clock.  With a Z7220 the clock is a bit higher, 8Mhz and 16Mhz respectively, but this is nowhere near the pixel bandwidth needed for higher resolutions.  My solution to this will be to divide the uPD7220's clock one or two times so we can get 24Mhz or 48Mhz pixel clocks on a uPD7220.  That should allow us to get way better resolutions:
    I really hope I'm using this calculator right.
    The 800x600 resolution in the above image is a good spot, and uses about half of the VRAM, leaving the other half to be used for double buffering.  I haven't made this part of the circuit yet, and one big thing I'd need to figure out is how to get the right signals to the VRAM for loading the pixels.  I could generate the VRAM's A0 with some logic to load two words out of VRAM each time the uPD thinks it's loading one, but this introduces an issue where the uPD would not be able to draw graphics to half of the pixels.  Perhaps there is a way to have the uPD skip a word each pixel load, then simply modify the A0 line to load this way?  I don't know yet, I need to consult the datasheet and see how this type of thing was done in the past.  I have a feeling they may have used two uPD7220s for this type of thing, but let's see if we can do it without that.  The chips are rare, after all, and the Z7220s are even more rare.

    Here is the current clock generator circuit for the new board, which should behave exactly the same as the old board; its job is to generate clocks for the board and to control when pixels are loaded into the output buffer:
    Anyway, I have more stuff to figure out with the board.  If any of you have good ideas on the clocks and loading twice the pixels from RAM, let me know :)
    Hopefully my schematics are prettier and more useful this time; I think they will...
    Read more »

  • Zilog Made a Clone!

    Dylan Brophy04/18/2019 at 01:47 0 comments

    I bought this chip off of Ebay.  It seems that Zilog created a uPD7220 clone - and it works!  These chips seem to be rather rare and information on them is scarce.  I did manage to deduce that there were two variants of chips:  one operating at 6Mhz, and one at 8Mhz.  I got the 8Mhz one and tried doubling my pixel clock to 16Mhz (the GDC uses a halved clock).  That worked too, and that allowed me to make a more stable video signal.  I had a problem with the 8Mhz pixel clock where there was not time to output a valid video signal.  Now I can output more pixels than I have VRAM for.

    The chip is also a super pretty Zilog gem <3

  • Rendering characters!

    Dylan Brophy04/05/2019 at 19:41 0 comments

    I've managed to make my card render characters!  I used the Z80 computer this project was originally intended for this time, instead of the Arduino testbench.

    There is not a font yet, so I just rendered a bunch of smiley faces and tested that the program could keep track of the cursor position.

    Smiley faces are a good way to do testing.

    It's working very well, but I would like to render things a bit faster.  I think the Z80 math routines run slow however, for calculating cursor positions and colors.

    It doesn't help that my card has 16 colors - it appears that the uPD7220 was designed to just do black and white.  This means that I have to send a few more commands to the uPD7220 to select a group of bits for a pixel (multiple colors) instead of just one bit (black and white).  The uPD7220 automatically selects a single bit when a command is sent to set the VRAM address, but my program must select multiple.

    Here is my graphics driver for the Z80:

    You may need to look at some of the other files, but all graphics functions are there (er, rather, the ones I've written thus far).

  • Finally on HaD after more than a year! And finally working!

    Dylan Brophy04/04/2019 at 06:29 0 comments

    Over a year ago I wanted a graphics card for my Z80 computer.  I made a prototype with the uPD7220, but I never got it working.  Until...

    As it turned out, I made TONS on mistakes in the original design.  There are issues with the new design too, but it works well enough (after a hack, more on that later). Anyway, after playing with the first prototype and trying various hacks, I ended up with a valid VGA signal!

    I don't think the uPD7220 was ever supposed to output VGA, considering VGA was introduced about four years after the uPD was, so it's awesome that it can output a VGA signal.

    After studying the uPD datasheet and my schematic in depth, I eventually found most of the problems and ended up with my second prototype (which I am using now).  I've managed to get it to do the basic things I need it to do.  Getting from basic initialization to drawing pixels was very difficult, especially with such a complex device and no example code/libraries, but it was definately worth it.  I now want to share what I've learned about it so that more people can use this GDC (GDC = Graphic Display Controller).

    I plan on adding more and more information to this project so others can use my work as a reference.  I also am going to create a Z80 driver, which I will post here as well.

View all 8 project logs

  • 1
    Software: Understanding the interface between the uPD7220 and the CPU

    I am writing this expecting the reader to have a strong knowledge of computer hardware.  You have been warned.

    The uPD7220 occupies two addresses in IO space and has an 8-bit data bus.  There are also the WE and RD enables, but there is no chip select (WE and RD should be generated with that in mind).

    uPD7220 write ports:

    0: Parameters

    1 : Commands

    uPD7220 read ports:

    0: Status register

    1 : Data to CPU

    Internal FIFO, and properly writing to it

    The two write ports both go to the same FIFO inside the uPD7220.  This FIFO can fill up, but there are bits in the status register which indicate if the FIFO is empty or full.  When writing to the uPD7220, the program must ALWAYS first check if that FIFO is full - if it is, then the program has to wait for there to be space.

    Sending commands

    The command byte is always sent first, into port 1.  After this, parameters are sent to port 0.  Some commands have quirks and nuances, and need some extra attention.  For instance, my uPD7220 can crash if my program does not wait for the FIFO to empty after sending a WDAT command.  I have not had this issue with any other command.  More on commands later, just introducing the proper way to send them.

    Reading data

    There is a flag in the status register to indicate that data is ready to be read.  When a command is sent to read data, this flag will be set shortly after, and then it is safe to read from port 1 (Data to CPU).  Always check the data ready flag before reading from port 1

    A quick word on the DMA flag

    If you are not using DMA or have not sent a DMA command and this flag is set, then something probably went wrong.  A command was likely sent incorrectly, or setup skipped a step.  If that is the case, the uPD7220 will probably crash in the next few commands (if it hasn't already).  Basically this means your program is doing something wrong, as in not sending a command needed for initialization or sending a command incorrectly.

    Status Register Flags

    0Data ReadyThe CPU can now read at least a byte from uPD7220 port 1
    1FIFO FullThe command/parameter FIFO is full, do not write
    2FIFO EmptyThe command/parameter FIFO is empty
    3Drawing in progressThe uPD7220 is currently executing a drawing operation
    4DMA ExecuteThe uPD7220 thinks a DMA operation is in progress
    5Vertical SyncIndicates that vertical retrace is active
    6Horizontal BlankIndicates that horizontal blanking is active
    7Light Pen DetectIndicates that a valid Light Pen address can be read

    I'm not sure that anyone would use the light pen feature, and I myself am not really researching it.

View all instructions

Enjoy this project?



Ray R wrote 08/03/2023 at 18:42 point

I love this stuff. I was looking at the Intel clone of this and was hoping someone would work on a board. It would be great to connect to a retro 65816 CPU system as a period correct design. Thanks for sharing.

  Are you sure? yes | no

Dylan Brophy wrote 05/08/2024 at 02:04 point

If the intel chip is pin-compatible, which I bet it is, then it should be plug-and-play.  I haven't played with that IC before, but yea I'm sure something really cool could be done.  I've thought about making an updated version of this card, or maybe porting the interface to another bus, like that used in some of the Z80 computers on Tindie.  One big thing is the software - I don't know what old software exists to use the uPD7220.  I was born in the early 2000s so I never got to live through that retro-computer era.  It seems like it was really cool though, even I have nostalgia for it!  XD

  Are you sure? yes | no

Frédéric wrote 12/27/2022 at 22:54 point

Hi Dylan, very nice project!! Do you have any update about this project, up-to-date schematic? I try building this card but I got some problems. The video output seem to be the address mapping instead of content of memory.

  Are you sure? yes | no

Dylan Brophy wrote 05/08/2024 at 02:00 point

Thank you, I worked hard on it!  Yes, I had made a mistake in the designs.  The video output resistor networks were connected to the wrong IC pins - this can be fixed by moving the resistors around on the board design I previously uploaded.  I did this and my card works fine.  I can take a picture and upload if you want, it's pretty easy to do.

I also just uploaded some designs where I fixed that issue, as well as a potential issue with the oscillator.  You can see the three new files uploaded to the project - there is a PDF, kicad_pcb, and then a zip with all the design files.  If you are still interested - sorry for the late reply, I had changed my email and HaD notifications went to the old email.

I was thinking about making an upgraded version of the card that could push more pixels or supported double buffering.

  Are you sure? yes | no

Eric Hazen wrote 12/29/2021 at 13:51 point

Hey Dylan... not sure if you're still thinking about this project, but I thought I'd ping you before launching on my own version.  Is there an updated (even if still not 100% correct) schematic you'd be willing to share?

I designed a graphics card based on the 7220 back in about '82 when it was new (1024x768, 16 colors from palette of 4096) for the then new IBM-PC.  Never marketed successfully, but it worked and as a result I have a few original 7220 chips around.

  Are you sure? yes | no

Dylan Brophy wrote 05/08/2024 at 01:57 point

I know it's a few years late, but I just uploaded some designs where I fixed the issues in the design.  You can see the three files uploaded to the project - there is a PDF, kicad_pcb, and then a zip with all the design files.  There is also an older zip that was there before, but that old PCB design has some bugs.  Don't know what you're up to now with that project, but the stuff is there.

I'm curious how you got that high resolution, I haven't been on this project in years but I think I remember having issues getting the resolution high considering the clock speed.

  Are you sure? yes | no

lezanderson wrote 12/17/2019 at 11:43 point

Cool little video project.

The upd7220 / NEC 72020 VDP  was quite a powerful video chip for it's time. Shame it wasn't used more.

  Are you sure? yes | no

EtchedPixels wrote 10/09/2019 at 15:36 point

I did wonder about 6545 as it has the ability to have private RAM I will follow your project with interest

  Are you sure? yes | no

Dylan Brophy wrote 10/10/2019 at 01:08 point

I haven't taken a look at that IC - what do you mean "private RAM" exactly?

  Are you sure? yes | no

Dave's Dev Lab wrote 10/10/2019 at 22:31 point

normally CRTC chips require the video memory to be muxed between the host's address space and the CRTC controller address space. the R6545 allows for the video ram to be connected only to the CRTC and the host communicates through the CRTC to the video ram. this reduces the complexity of both the number of components as well as signal routing....

  Are you sure? yes | no

zpekic wrote 08/13/2021 at 14:41 point

TMS9918 and its many descendants such as V9938 and V9958 controlled Dynamic VRAM that could sit outside of CPU address space.

  Are you sure? yes | no

EtchedPixels wrote 10/08/2019 at 19:55 point

I was looking at this with a view to trying to build an RC2014 card based on the same chip (or it's Intel version : 82720).  I'm curious if you took this one further or what the other design mistakes you reference were beyond the shift register, and I assume the colour mapping.

Did you look at the Intel iSBX275 schematic in the manual ?

  Are you sure? yes | no

Dave's Dev Lab wrote 10/09/2019 at 15:24 point

i've been experimenting with the HD8645/HD6545 chipset for generating VGA as well. i looked at using the 7220 but the avalibilty of those chips was an issue. plus there were a lot more reference schematics to go by including the original IBM MDA and CGA cards...

  Are you sure? yes | no

Dylan Brophy wrote 10/09/2019 at 15:42 point

I did get farther than this, I'm just terrible at documenting my work XD.  It's buggy but I can display text and my OS now uses it for STDOUT (or rather it's equivelent).

There should be new code on the repo, but I haven't looked at any of this in quite some time.  

  Are you sure? yes | no

Dave's Dev Lab wrote 10/09/2019 at 15:47 point

any chance on getting an updated pdf schematic?

  Are you sure? yes | no

Dylan Brophy wrote 10/10/2019 at 01:10 point

@Dave's Dev Lab I'm not sure that I ever updated the schematic... I might take a look later but I have been very very busy lately.

  Are you sure? yes | no

Dave's Dev Lab wrote 10/10/2019 at 02:12 point

yep no worries!

  Are you sure? yes | no

Ken Yap wrote 04/04/2019 at 13:30 point

👍 Good on you for tackling this old chip. I have one (D2) in its very distinctive ceramic package. I must have pulled it from a microcomputer. If anybody wants it for the cost of postage, PM me.

  Are you sure? yes | no

Dylan Brophy wrote 04/04/2019 at 17:49 point

Thanks!  The D2s are really good too, can reach 8Mhz if I remember correctly (mine can only reach 6Mhz), so maximum 16Mhz pixel clock.  Where does one get old microcomputers?

  Are you sure? yes | no

Ken Yap wrote 04/04/2019 at 21:54 point

I used to go dumpster diving.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates