From CPCWiki - THE Amstrad CPC encyclopedia!
Jump to: navigation, search

FPGAmstrad cc2.jpg

This is a VHDL version of Amstrad CPC 6128 running on FPGA starter-kit NEXYS2 500k-gates from Digilent. A starter-kit is a board made for learning FPGA, so it is a standard FPGA development board.

Please refer to [MiST-board CoreDocAmstrad] for the final user version, running on MiST-board platform.

Games running on it are : Tempest, Fruity Frank, Boulder Dash, Classic Invader, Xevious, Wiz'lair, Ghost'n'Goblins, Chase HQ, Xor, P47, Bruce Lee, Gryzor (romnation's one), Prince of Persia, Trail Blazer, Antiriad, Buggy Boy, Crazy Cars II, Donkey Kong, Axiens, Invaders, Arkanoid, Ikari Warriors, Barbarian, Barbarian II, Bubble Ghost, Super Ski, Action Fighter, Cauldron, Dan Dare I II and III, The Empire Strikes Back, Star Wars, Rick Dangerous I and II, Bomb Jack I and II, POP-UP, Mario Bros, Rock Raid, Rygar, Hyperbowl, Sapiens.



How to assemble it

You need:

  • a "NEXYS2 500kgates" starter kit from Diligent [[1]] (1200kgates should be better for future version => in fact I choosen NEXYS4, it is same RAM inside) also in France : [[2]] or in Germany : [[3]]
  • a "PMODSD" module for reading sdcard [[4]]
  • an alimentation (cause they don't give it with starter kit) [[5]]
  • optionally a DIGILENT USB JTAG (normally starter kit can be programmed directly by usb, but I don't have tested this way) [[6]]
  • a 4GB SDCARD (no more), I have exactly a "SDHC 4GB class4 Verbatim"
  • the binary of this project (candidate 002) : source+500k-gates binary [[7]] ; 1200k-gates binary [[8]]
  • several ROM files: OS6128.ROM BASIC1-1.ROM AMSDOS.ROM (from JavaCPC[[9]]); MAXAM.ROM[[10]]

A package that contains minimum set of ROM and DSK for filling simply sdcard [[28]] (OS6128, BASIC1-1, AMSDOS, MAXAM)

You have to:

  • program FPGA with the binary file "amstrad_switch_z80_vga_sd.bit" of this project, for it I use Digilent Adept software and my USB JTAG cable
  • format your 4GB SDCARD in FAT32 4096 byte allocation size
  • copy ROM and DSK on SDCARD
  • plug PMODSD on slot JC1 of starter kit, and set all 8 switches to 0
  • plug VGA, and turn on starter kit

FPGAmstrad minimal plug.jpg

You can:

  • plug a PS/2 keyboard, and type "cat"
  • increment switch to select another disk at boot, if screen became RED, it's that binary value done by switches is too big, leds are doing a small animation when a disk is correctly loaded
  • plug principal joystick on slot JB1 (Vcc 3.3v is common)
  • plug another joystick on slot JA1 (Vcc 3.3v is common)
  • plug a jack on slot JD1, one at upper GND plug, and second wire at next plug, just at left of it (if it was 3.3v Vcc, choose the right one instead)

FPGAmstrad sound plug.jpg

Wires are plugs at upper part of pmod D.

From bottom to upper: [nothing: Vcc 3.3v] [blue: GND] [red: sound]

Sure you can connect a jack...

And two joysticks. On pmod B: bottom is (both) 3.3v, so joystick's common, next is (both) GND (not used), and others are joystick connections, to test manually :)




Last news about this project

In March 2015, FPGAmstrad is stable on MiST-board, please refer to mist-board CoreDocAmstrad and mist-board amstrad bin core

In December 2014, FPGAmstrad is stable on NEXYS4, WIP, BOOTLOADER improved, VRAM improved (with BORDER colors !), RAM relaxed, no more timeout in keyboard key-press, Ghouls 'n' Ghosts, Macadam, a lot more to do. 14% of platform is used.

In November 2014, I bought MIST board, with two pro joysticks.

In September 2014, I bought NEXYS4, more powerfull than NEXYS2, with same external RAM, internal mini-sd, no PS/2 (it is a pmod option)... I have some patchs to make (MSB FAT32 offset). I would like to make a USB snifer also with it (usb to ethernet (wireshark))


I am Freemac, my IRL name is Renaud Hélias.

You can contact me by mail to renaudhelias @t gmail d0t com, if you have questions about assembling this project.

Follow me on my google plus account!

Tests done

Great games that are running properly are listed at top of page.

On NEXYS4 version

Games that doesn't run are :

  • moktar.dsk prehistorik.dsk: lag (key/joystick press lag)
  • aigle_d_or.dsk: keyboard keys bad mapping evidence (pressing right arrow press also F3, then display "impossible" in this game in same time of moving, in fact it is not a joystick playable game) - this bug is located (some values appears double on keymap array)
  • super_cauldron.dsk: strange disk sector size evidence (not implemented yet)
  • ACPC_logon_system.dsk: text scrolling lag. This demo will be used for horizontal ink calibration (when I’ll buy a luxurious FPGA platform... I need in fact 224Ko of internal RAM to do it), and CRTC overcounts.
  • atomic driver: does freeze (problem of interrupt cycle ?), it is a really simple dsk format.

Arkanoid.dsk stars use rupture address (changing address several time during display of one image), it is now supported on "candidate 001" version of FPGAmstrad

Gryzor and Prince of Percia use rupture ink/mode (changing ink and mode during display of one image), it is now supported on "candidate 002" version of FPGAmstrad

Gryzor is really sensitive to Amstrad general stability : do press esc at start menu does activate music during game, if no music, FPGAmstrad is in an instable version (last known stable version r003.8)

Crazycars2.dsk first car image use 32Ko of VRAM, it is now supported on "candidate 001" version of FPGAmstrad.

Ghouls'n'Ghost.dsk / Ecole.dsk does need RAM write when writing in ROM (RAM is beside ROM, hard to emulate with asynchronous SDRAM controler, MiST does use a hacked synchronous RAM done for that)

A lot of demos don't pass in NEXYS4 FPGAmstrad's version (I need to implement back the SDRAM hacked in MiST board FPGAmstrad version). CPCRULES demos is a cool ressource as it contains simple dsk formats.

Others bugs are about dsk format, in fact a dsk is uncompressed into RAM at startup, so all dsk access are direct:

  • CP/M format: normally it runs, but in fact... it doesn't
  • protected format: all format with strange sector size fail
  • double side format: as you need to reboot in order to change disk, it's impossible to change disk while you are playing
  • save: disks are writable, save is done in RAM, and it’s not persistent.


  • Spindizzy
  • Asphalt (tested on alpha but not on last version)
  • Ghostbusters, Ghostbusters 2, Rambo III, Sorcery, Commando, Yie Are Kung Fu 2, Kane (shoot X/Y)

On MiST version

Games that doesn't run are :

  • commando.dsk: pixels that should be deleted are not deleted (only VRAM &C000-FFFF seems used)
  • atomdriv.dsk: freeze (the music does freeze also)
  • saboteur2.dsk: freeze (nice music and then freeze)
  • split ink demo.dsk: (from cpcrulez) : may help about ink raster calibration.
  • protext.rom: In edit mode, if I press continuously one key, it does write ten letter and freeze/crash. As a number is incremented in live at top right, I think also about an interrupt vector not long enough.

crazycar.dsk does use lowerVRAM=00 (&0000-3FFF and &C000-FFFF area for VRAM)

crazycar2.dsk does use lowerVRAM=10 (&8000-BFFF and &C000-FFFF area for VRAM) while overscan presentation, and lowerVRAM=00 (&0000-3FFF and &C000-FFFF area for VRAM) during play.

buggyboy.dsk: I found one dsk running correctly and another not : problem on this last one is about turning left/right effect : the car continues straight (it seems a prototype bad version)

superski.dsk : don't forget to disable autofire, in jump, do press fire+up or down.

Game Welcome Title Game
CrazyCar2 1011 0011
One 0111 0011
Scarabus 0111 0011
Ace 0010
Tintin 0111 1011 0111
Devil's Crown 0001 0011
Mach 3 0111 0111 0110
Paranoia (1994) 1011 0001
World Class Rugby 1011 0001 0001

XOR.dsk does use lowerVRAM=01 (&4000-7FFF and &C000-FFFF area for VRAM)

Effort done

Instruction timing

I tested instruction timing of T80 compare to instruction timing of JavaCPC emulator. I deduce synchronization of Z80 with CRTC on M1 signal by WAIT_n insertion in order to have a multiple of 4 Tstates per instruction. I deduce also one WAIT_n inserted during MEM_WR operation (yes I log testbench T80, I’m crazy)

I just made a test bench log of T80 (log of instruction's M1, and first M1 coming after knowing that I send a lot of NOP after my instruction), and compare it to a JavaCPC timing array. Some instructions was not tested (interrupt wait, and special timing (instructions with change timing)), but all others passed correctly.

Test of a real Zilog 80

Z80fx2bb.jpg Code name : Z80fx2bb, real Z80@2MHz (instead of 4MHz) on fx2bb extension card.

For it I plug all wires simply from 1 to 40. Some wires are cut, some are Vcc, others GND. Z80 output are directly connected, Z80 input are pull-up with red-red-red resistors (I like red), Z80 is powered 5v (pmod can give 5v using jumper). In fact z80 is so old component that powering it 5v do output 3.3v.

In fact the only difference between T80 of opencore and real Z80 is that T80 run on rising_edge, and Z80 run during low state. Test past with little modification of sequencer forcing it do nothing during low state of z80, resulting a downclock (memory is too overclocked with this sequencer modification), perhaps using buffer on address bus and data bus could solve this detail... but as it runs for me it is not a problem.

Alignment of HSYNC Interrupt

Interrupt are respected since version "candidate 001" of FPGAmstrad.

JavaCPC running norecess.jpg

JavaCPC running norecess's "using-interrupts" code [[29]]

It could be interesting to test this asm code on next version of FPGAmstrad.


VRAM contains 800x300 amstrad pixels (VZoom x2), displayed 640x480.

RAM_palette contains the ink list and the mode for each line of VRAM.

Sniffing of a real Amstrad

Cpc plus m1.jpg Code name: Raptor

I listen to some wires of my Amstrad CPC 6128 plus, but I can't access VSYNC/HSYNC output of CRTC, so I have to buy another model in order to do this test. In fact you can listen at clock of Amstrad and transmit it to FPGA DCM component, resulting a accelerated clock sequence, that's it, with FPGA DCM you can overclock output Amstrad clock signal in order to insert more operations, I use this tip for listening signals and save them inside starter kit asynchronous RAM (write, stop write, write, stop write... I’m a perfectionist paranoid...)

You can power Amstrad CPC using extension port, applying 5v. By doing it, power down button of Amstrad doesn’t run. Using this way you reach a common 5v power between starter-kit and Amstrad. I connected wires from extension port directly to FPGA, as they are used just for listening.

DONE : ROM and RAM extension

In r004, you have more RAM +512KB, and you can add ROMs.

  • LowerROM has .eZZ file extension
  • UpperROM has .e00 ot eFF file extension (hexa)

DONE: Another disk selector

In first version of FPGAmstrad (NEXYS2) I used switches for disk selection. As final FPGA platform doesn't have any switches set, I have to add an BASIC instruction for it, something like "OUT &CAFE,disk_number" could be fine.

Since FPGAmstrad in NEXYS4, disk selection is done from keyboard, using "OUT &CAFE,disk_number" instruction. A reset key was added also. "PRINT INP(&CAFE)" does print current disk selected number.

DONE : A advanced dsk drive

Done on r004, I added also a second Drive in order to copy easily files from one disk to another.

Irregular sector size ok.

You just have to select Drive A or B from OSD before selecting another dsk file.

Write is done directly on sdcard dsk file, so you can save games, and write texts...

You can now change disk without reset. And then play games using several disks.

TODO : A X/Y input

I want to work also on screen-pen entry, is there a manner to detect an analog X/Y as pen or gun ? YES : Markus Hohmann does it, he implements the lightgun on JavaCPC-GX4000 using mouse :)


register 11,12 and 13 ?

TODO : A SCART output

In order to plug FPGAmstrad on TV, and help debugging. And also to test a simple scan-doubler.


CRTC0 seems the best one, some demo does cry when detecting a poor CRTC1 (CRTC1 seem a low cost version of CRTC0). I have to implement a CRTC0 instead of my current CRTC1...

DONE : More ROM and RAM

BaseRAM is 64KB, extension RAM is 512KB, FPGAmstrad has now 576KB of RAM.

-- "001" dsk_A(19:0) DSK_A
-- "0000000" "xx" ROMBase L U0 U7 U1 <= finally only L is used
-- "0000001" "xx" ROMBase 4 5 6 7 <= finally not used
-- "0000010" "xx" RAMBase
-- "0000011" "xx" RAMBank page 0
-- "0000111" "xx" RAMBank page 1
-- "0001111" "xx" RAMBank page 3
-- "0101111" "xx" RAMBank page 7
-- "100000000"    ROMBank 0-255

ROM files does finish with file extension from .e00 to .eFF, LowerROM is a fixed name. So you can now use one LowerROM and 256 UpperROMs on FPGAmstrad.

Turned into experimental fork (will be back to main trunk after dsk dev)

TODO : Scanline

Scanline is an effect existing in CRTC used by Wolfenstrad demo.

It is also a simple visual effect to enable/disable, making games looking like old CRT monitors.


Using a simple PWM, data is entered at a certain speed, the PWM clock speed.

If you simulate a constant PWM output signal at middle range of voltage (state just between 0V and 5V : 2.5V), it results an alternance of 0V and 5V, that result in a noise sound. In Arkanoid, this defect make some continues sounds instead of silents...

My idea is generating a sound having a frequency upper that dog ultra sound, while I want to simulate a constant 2.5V.

For this I do use two clocks entries in my PWM : one about data entry, and another about algorithm execution.

This result a high quality sound output (in addition to this nice Yamaha sound chip from fpgaarcade)

DONE : FAT32 fragmented files support

Actually, on final platform somes files are managed by OSD (on screen display), so you feel as if some files are deleted after a certain time (of hard reboot), but in fact files are still here : you just have to defrag de SDCARD.

To fix that, FAT32 not fragmented files need to be supported.

DONE : Stereo sound output

STarKos 1.21 running on FPGAmstrad

Sound chip was modified in order to get channel A+B at left, and channel B+C at right. It was tested OK using STarKos 1.21 sound tracker (track "Carpet")

Agile method

This project results of a experiment applying Agile method. Finally this project has taken 5 months. The result is a standalone platform that can run several games of Amstrad. Normally, I had to dedicate 2 months on this project, but as result was so great, I continue to a standalone and better version.

This project was done for my father birthday, so sorry that I can't deliver it yet :^)

One day perhaps I'll write one book, or write a lot of wiki page by there, presenting step by step this adventure :)

But I want really to validate project before doing it. So it will stand a few I think.

Minimal Amstrad Architecture: Build your own Z80 Amstrad Computer

I explain here my first great experiment, having Amstrad saying hello :)

First schematic: Z80+RAM+ROM

Z80 can address from 0x0000 to 0xFFFF.

RAM is from 0x0000 to 0xFFFF.

You have lower and upper ROM, so starting at address 0x0000 you put OS464.ROM, and at address xC000 you put BASIC1-0.ROM.

  • When Z80 do READ MEMORY, you read ROM
  • When Z80 do WRITE MEMORY, you write RAM
  • When Z80 do WRITE IO, you do nothing
  • When Z80 do READ IO, you response it DATA=0x00

When you run this schematic on FPGA, RAM changes!

Second schematic RAM+VGA

With JavaCPC, when you snapshoot, and hex edit result file, you see RAM content starting at a certain address.

Do "paper 2", "cls" on JavaCPC, the screen became RED, and then save a snapshoot, you can see that last part (from 0xC000 to 0xFFFF) had change from a lot of 0x00 into a lot of 0xFF

So last part of RAM is used for video (it's shown on Quasar [[30]] and other legend websites...)

For making my VGA module, I take a look at UNIX "modeline" command that give us all timing for VGA signals, and it run :)

After having a VGA module displaying a RED screen (yeah!), I made it scanning last part of RAM (from 0xC000 to 0xFFFF), and I solved the puzzle.

Crtc puzzle.jpg

RAM contain lines of 0xFF, each finishing by 0x00, but lines are not in great order

Third schematic Z80+ROM+RAM+VGA

Goal is: RAM empty at startup, VGA displays hello after run.

So you put the two last schematics together and tadam... got a problem.

The problem is that two components are accessing RAM in the same time: the Z80 and the VGA, so you had to make a sequencer. A sequencer is simply a counter fed by a clock: 00, 01, 10, 11. And you manage work task like this:

  • 00 RAM WRITE start from Z80
  • 01 RAM WRITE end from Z80
  • 10 RAM READ start from VGA
  • 11 RAM READ end from VGA

You plug sequencer(1) on z80 clock and not(sequencer(1)) on VGA...but another problem appears: VGA uses 25MHz speed for scanning RAM. So Z80 has to use same speed xD

To solve this problem you can use a special RAM done for this problem, a RAM that you can WRITE at a certain speed, and READ at another speed, this magic component is called ramb16_s16_s16. Note that they have no problem to write simultaneously on two RAM components, so that you can dump video RAM content using starter kit RAM, and you can display VGA using FPGA internal ramb16_s16_s16 RAM.

Build your own z80 amstrad computer.jpg

First and Second schematics video


Here I do program FPGA with a serial port RAM filler (homemade), and then I do upload ROMs (sooo long, you can show several blue progress bars), and then I do program FPGA first schematic : Z80+RAM+ROM, executing it, and then I do program second schematic : VGA is plugged on FPGA platform and does display "Ready".

Just about the "RAM filler", filling a RAM with data is perhaps the more important thing* about using FPGA platforms, do just remember that a RAM does keep its content as long as voltage is entered on it. So you can program FPGA without erasing RAM content. So you can program three FPGA programs : one for filling RAM, one for running a program using RAM, one for dumping RAM. Here I did use a serial transmit, but in fact, in last versions of FPGAmstrad, I do use a SDCARD with a homemade bootloader (filling RAM from SDCARD content)

I did use also Mock components, in first version of FPGAmstrad, FPGA platforms was too small, so I could have FPGAmstrad only with cool sound and low graphics, or else FPGAmstrad with cool graphics and no sound. Both using 100% of this old FPGA platform. A Mock component is a fake component, an empty one, just telling back "I'm OK, please thrust me I do exist" to others components trying to communicate with me (it's a entity with same in out ports as original but using constant output values)

Third schematic Z80+ROM+RAM+VGA video


The three main FPGAmstrad schematics

FPGAmstrad_bootloader_sd schematic

After having a first running Amstrad, I had to turn it into as standalone version. In fact before this step Amstrad ROM was put into RAM using serial port (#RAM_dump), it was slow, and Amstrad ROM was lost when I unplug electricity.

Bootloader FAT32 SDCARD is the only component playing with sdcard. Its tasks, all launched at boot, are:

- deploying ROM file on physical RAM

- deploying Nth DSK file on physical RAM, N being the binary number selected by 8 switches

State machine

Both component of Bootloader, it is to say SPI_MASTER and SDRAM_FAT32_LOADER components, does use several state-machine, one state-machine per process, each process communicating with another one using "MASTER/SLAVE" : the master state-machine does ask a slave to do something, and slave does notify master when its task is finished.

Theses state-machine does use led debug : an integer contain the state of state machine, and this integer is displayed on 8 leds so you know where you are, it's for that I add several crash state in order to understand why and where component crash. In MiST-board, this is displayed on the five 7-segment I added in OSD, I add also a input in order to select one or another state machine.

FPGAmstrad_amstrad_video schematic


The main component of this schematic is called aZRaEL_vram2vgaAmstradMiaow, due to my first experimentation about drawing a picture on VGA screen.

VGA display component use same parameters than unix modeline command, that's all you need, with that parameters you can display something on VGA at the frequency/resolution you choose.

AZRaEL RAM test ok zoom4 decal64 inv.jpg

AZRaEL test vram2vga.jpg


RAM and VGA does not use the same frequency. I add between them a magical VRAM having two clock entries and solving this problem automatically.

The magic RAM in FPGA, getting two clock entries, is not as magical as I was thinking : in fact it does solve clock equations using the clock manager (DCM) and BUFG components (saying phase is freedom between input and output). If you want a set of clock synchronized do not add a BUFG in one of its wires. If you don't care about synchronize of two clocks, just add it and then it will help to solve finer and greater the clock manager equations of DCM while compiling.

If you seem interested about strange clocks generated during last step of FPGA compile, do look after "time constraints file" and "timing closure".

FPGAmstrad_amstrad_motherboard schematic

This is the core part of FPGAmstrad, it does represent the motherboard schematic of Amstrad, it was aligned to JavaCPC source code.

I does fill this schematic component per component, comparing behaviour to JavaCPC components.

JavaCPC is developed in Java, and Java is so cool (Java is better computer language ever, and VHDL is better FPGA language ever =P)

I tickle JavaCPC in order to compare its components to my ones.

Emulator Architecture
 while (¡stop_emulation)
 Figura 2. Basic Emulator Algorithm.

Extracted from the book [[31]],

Using this way, emulators reach a better running time. They don't need to implement the system-bus architecture[[32]] (CONTROL DATA ADDRESS) crossing Von Neumann architecture[[33]] (CU ALU MEM IO).

Component Architecture

Java is an object language, so having new, set, get, for each of its objects.

A Component Architecture in object language has a special cycle life :

  • Build all components (new new new new new)
  • Plug all components together (set set set set set)
  • Run a main component.

Main component is Z80 on JavaCPC. In fact, JavaCPC's Z80 is already configured in order to run each instruction with a certain timing : a timing already synchronized with CRTC (each instruction takes 4 Tstates or 8 Tstates, Z80@4MHz CRTC@16bit@1MHz so drawing 8 colored pixels on mode 1 takes 4 Tstates)

My main component is #Clock_sequence

In real Amstrad, main component is GateArray.

The fact of choosing Z80 as main component just respects the emulation architecture.

Java debug mode

You can run JavaCPC on debug mode in Eclipse, and insert breakpoints.

It's useful for listening wires, and cut them. You can in live pause debug, cut a function and continue run.

Cut a wire, cut a function

Wire are done for sending message, a message in programming is a function call.

When we cut a input wire, we generally plug it to GND or Vcc.

For cutting a function, you have to insert a cut on it. A cut it's a return. You can insert a (very bad) forcing cut as:

 if (1==1) return 0;

everywhere. So function is ended at this moment and next lines became death code. It exists quality code program for checking death code, because it's generally a bug of development, normally we put code in comment.

It is the way I used in order to induce JavaCPC, comparing it with my project.

Clock sequence

When we have to make several components to communicate in a perfect timing, making a sequencer is a nice approach : "It is now your turn to do something".

Clock sequence : first try (prototype)

Original Gatearray of Amstrad is a sequencer (counter plugged with a clock), it manage synchronization between video card and z80 and memory access.

Historically there is a link between CU of CU/ALU, and... control bus and... how making your own sequencer. But I will say no more in order to not disturb these text part xD

Whatever, I made my own sequencer here in form of a bus of 4 wires called CLK4. CLK4 execute a simple repetitive sequence like 0001 0010 0011... CLK4(3), the last wire is directly connected to Z80 clock entry. Component not using explicit CLK4 as clock entry are generally using a not(CLK4(3)) entry, in order to do operation not as same time than z80.

Real Amstrad use buffer memory in front of each address and data access, and real z80 is clock low state active. Normally if you follow datasheet of z80 you know how to map memory following CU comportment. Or you do as Amstrad, saying that z80 CU sucks, I create my own sequencer, managing all my memories access, alternating CRTC work and z80 work with little synchronization, insert by the way more pixels that can support my small CRTC...

How to use a sequence in VHDL :

if rising_edge(master_clk) then

 if seq="00" then

 elsif seq="01" then

 elsif seq="10" then


 end if

end if

What not to do :

if rising_edge(seq[0]) then

end if

Because that can auto-generate bad unwanted sub-clocks...

Clock sequence : under time constraints (quality)

In fact, it's better to create you clock sequencer wiring each CLK and not(CLK) directly from DCM, in this case you enter in time constraints norm, and then rules/checks are done on every _edge instruction. Choosing only one sort of _edge (rising or falling) seems better also. Using that way you just have more "bad compiling error" shown, helping you creating a better code (more stable/quality).

Clock sequence using a counter plugged with a clock was in fact a bad practice (but running fine in my first versions of FPGAmstrad as I'm a good blind developer), because output are not under clock constraint : just think about that a "not" component added just after a clock wire is a Time Constraints bad practice... destroying "time constraint" solver (the one telling you when your clock domains are bad (and why), "time constraint" is last step of FPGA compiling process, it is a important step about quality, it shall be respected (generaly in a very last development effort, I shall say in a deploy effort))

Clock sequence : mirror VRAM (performance)

In order to get a better external RAM performance, and getting more luck about porting my project into others FPGA platform, I do now use a "Mirror VRAM" : external is just used by Z80 read and write (no more clock sequence finally ^^'). And a write in video RAM zone (like "poke &C000,255") does just write also in another parallel RAM, a FPGA internal RAM, that I call VRAM, this VRAM can be written at a certain speed and read at another for VGA purpose (FPGA internal RAM can be used like that)

USB joystick

Before learning final platform and its embedded controlers (USB joystick with a controler, is just 7 wires : left right up down buttonX buttonY buttonZ), and after having destroyed 12 collector original joysticks during tests... I did some research about simply connecting a modern USB joystick into FPGA. It was a part of my Agile Method run, I worked about two months on it.

Sniffing USB frames

USB uses two wires in order to transmit frames, green and white, each with two logical values: 0v and 5v.

Let's plug a joystick on PC, if you listen at its two wires, you can sniff a USB transmission. Finally you can save it for example on RAM.

These two wires can be traduced into one with four states: 00 01 10 11.

One of this states is sleep state, in fact it depends on USB mode you use.

USB mode: USB1 or USB2; low speed, full speed or high speed

For sampling, I speed up five times the saving speed on RAM. I succeed sampling an USB1 transmission: "Logitech dual action USB joystick", and an USB2: "Sony PS3 USB joystick". PS3 joystick is not stable enough with my FPGA, but Logitech joystick is correct.

pull up and pull down

If you respect USB protocol, you have to plug some pull-up and pull-down resistors and some capacitors. But as I am a bad electrician, I just simulate then in VHDL, they are important because they cause USB speed negotiations. You also have an electronic mechanism in order to detect presence of joystick plug, I don't care about it.

For reaching which wire you have to pull-up or pull-down, here the tips :

  • For slave (ideal for sniffing) : just take your USB1 joystick without plug it, just supply it (+5v red, 0v black), and test while-black and green-black with voltmeter, if you have got 5v then put a VHDL pull-up, and if you have got 0v then put a VHDL pull-down.
  • For master (ideal for creating a mini-host) : just take your PC USB1 port, and test while-black and green-black with voltmeter, if you have got 5v then put a VHDL pull-up, and if you have got 0v then put a VHDL pull-down. Normally you result two pull-down.

Synchronize, decode and check USB frames

One time sample is done, it is not readable. In fact USB frames are synchronized (they started with a certain synchronization pattern), encoded (NRZI), and checked (CRC). CRC type depends on frame length. Encoding is done for synchronization optimization.

Then using USB HID manual, you can understand type of frames, and author of them, and remark that the author alternate: USB master (PC) or USB slave (joystick)

You can use some "USB sniffer software" in order to understand more easily some frames contain, but they generally don't give all frame, and full frame.

great crc check example in perl - offered by www.usb.org

Build a minimum USB master frames state-machine

Let's just plug a USB joystick on FPGA, directly, permanently, thinking about minimum coding size : we can't implement full HID USB protocol on FPGA ^^'

Objective here is to build a minimum state-machine graph, having for transaction between state a "frame transmission". It is normal on USB protocol to have error of transmission, so you have also to put "error frame transmission" on the graph.

At stabilization, you finally switch between two states, one sending a certain frame that contains at different offset simply certain values of joystick button.

At start, some frames are employed for "next frame description", they can generally be ignored, as our USB architecture is fixed and minimal (one USB joystick, that's all)

go further with USB sniffer

A better way to snif USB could be generation of TCP/IP packets encapsuling USB packets, and to record them directly on PC from a RJ45 plug, using this way I could save more than 10 seconds of information transmission (RAM size is limited on FPGA platfoms)


Why NEXYS2 500kgates starter kit

Xilinx schematics

Xilinx webpack software permit drawing schematics as book schematics, My point of view is : "For programming a FPGA, you draw a schematic as old books and just press one button. Each component on this schematic can be edited, in a language called VHDL".

My source code is not Altera compatible because of schematics drawn, but webpack can export vhdl code from schematics if you want.

RAM dump

A starter kit that contains a RAM component, that you can dump separaly : you can change schematics without loosing RAM content ! - and so write a schematic for dump only ;)

While power is on you can:

  • programming FPGA with a program/schematics done for filling RAM
  • press reset button
  • programming FPGA with a program/schematics done for using RAM
  • press reset button
  • programming FPGA with a program/schematics done for reading RAM
  • press reset button

My own made program does it with poor serial port, so for dumping all RAM content it takes about 3 hours, and for dumping Amstrad RAM part it is about 15 minutes.

On [Diligent NEXYS2 official page], you can download a "Onboard Memory controller reference design" that contains explanation and VHDL source code about dumping on RAM/ROM of NEXYS2 directly from PC (usb port). I didn't tested this yet, but it is certainly a nicer approach :P

FPGA internal RAM size

It's to know that a FPGA chip contain 45Ko internal RAM (360Kb for NEXYS2 500k-gates, and 504Kb for 1200k-gates) so you can't insert a dsk inside. This internal RAM is already used in part by T80 (z80 from opencores), by the soundchip, and for special RAM ramb16_s16_s16 (RAM with two different speed one for writing another for reading, in fact two RAM with a common part) that I use for VGA mode.

VHDL components size

T80 (z80 processor) take 100kgates

Yamaha sound chip (from fpgaarcade) take 50kgates

InterruptGenerator + VGA mode take 50kgates

Bootloader (for standalone) take about 120kgates (FAT32 protocol, SPI protocol, DSK protocol)

Actually the project take about 99.9% of 500kgates. But I think that TV mode will take a lower size. A bigger size shall be great for Amstrad CPC Plus version, if JavaCPC evolve, and then if I evolve ;)

Why MiST-board final platform

Final version of FPGAmstrad

MiST-board : CoreDocAmstrad

Altera schematics

Here doc about deploy of FPGAmstrad into MiST-board platform : MiST-board : CoreDocAmstradNotes.

USB competition-pro Joystick

my favorite one <3

SDCARD entry robust

SDCARD player is nice built. It is not destroyed after 30 insertions. It is also easy to program FPGA : I just have to put my files into a SDCARD, and it runs, that's all.

Metal case

It's a true final platform.

Source code

The project binary downloadable on #How_to_assemble_it section contains in fact source code and the binary file (.bit)

This is a simple zip of project folder.

The project was done using Xilinx webpack

It contains some direct drawn schematics, and VHDL components


I explode the main schematic into a task by component, so the schematic is big.

Starter kit use only one RAM physical component for RAM ROM and DSK alignment, so I had to manage accesses (it is possible in fact because Z80 is a sequential processor)

My clock take 4 wires, in fact it exists a clock sequence #Clock_sequence (during 1 z80 tic, I do several things)

RAM is done for being dump, comparable to JavaCPC snapshoots.


sound chip is ym2149 fpgaarcade one, patched, and repatched in order to get stereo sound.

PPI chip is 8255 CPCWiki one, patched.

PWM chip is PWM_DAC fpga4fun one, patched in order to get high sound quality (my PWM has two clocks in entry)

And thanks

Certainly first thanks to Markus Hohmann, for having programmed a Java version of CPC, I love Java and VHDL, so this project comes from this Java Amstrad emulator.

Secondary Steve Ciarca, author of "Build your own Z80 computer" (1981), so nice book.

Then the author of the VHDL version of yamaha sound chip : fpgaarcade. And opencores for the Z80 (T80)...

And websites that give access to so much old Amstrad resources like :

And more :

Others tricks

If you aren't ready yet, here somes experiments (youtube) on real Amstrad :