denne artikel er fokuseret på at lære, hvordan en mikrocontroller kerne er designet, og er kun beregnet til pædagogisk brug. Besøg venligst www.zilog.com og tjek producentens produktlinje for at vælge en mikrocontroller, der passer til dine projektbehov (fra otte bit 8 Encores! og es80 anerkender den 32-bit ARMBARK-m3-baserede NNEO32! som inkluderer avancerede motorstyringsfunktioner).
min kærlighedsaffære med mikrocontrollere og mikroprocessorer begyndte tilbage i 1988, da jeg arbejdede mod en teknisk grad på CEFET-PR (en fireårig Brasiliansk sekundær/teknisk skole og universitet beliggende i Curitiba). Jeg begyndte med at lære det grundlæggende, mens jeg udforskede den klassiske C-80 (figur 1a).
figur 1A. bogen er 80A (med tilladelse fra Commons).
Spol frem gennem en karriere inden for programmering, der omfattede forfatter af nogle bøger om mikrocontroller programmering (se ressourcer), start af et lille designhus (ScTec) og afslutning af et efteruddannelsesprogram på CEFET-SC (et andet Brasiliansk universitet beliggende i Florianopolis). Dette var i 2008, da jeg havde mere kontakt med programmerbar logik og VHDL, og min nysgerrighed blev toppet. År senere i 2016 fandt jeg et meget overkommeligt FPGA-sæt (Field-Programmable Gate Array) og besluttede at give det en chance og begyndte at lære mere om FPGA-teknologi.
hvad ville være bedre end at designe en softcore for at lære mere om VHDL (vhsic beskrivelse sprog), FPGA ‘ er og mikroprocessorkerner selv? Jeg endte med at vælge en moderne S-80-slægtning: s-8 Encore! (alias, ES8; figur 1b).
figur 1B.
det er en otte-bit mikrocontroller kerne med en enkel — men kraftfuld — instruktion sæt og en meget flot on-chip debugger. Med sin lette IDE (integrated development environment) og gratis ANSI C compiler er det et fremragende projekt at lære (og også undervise) om indlejrede systemer.
før vi dykker ned i dybden af kerneoperationen, VHDL og FPGA ‘ er, lad os tage et blik på Silogen 8 Encore! funktion.
figur 1C.Fps8 på en FPGA.
Silog På 8 Encore!
ES8 er en otte-bit mikrocontroller-familie baseret på Silogs succesrige S8-familie og på den store s-80-arv. Den har en Harvard CISC-maskine med op til 4.096 bytes RAM (filregister og specialfunktionsregistreringsområde), op til 64 KB programhukommelse (normalt flashhukommelse) og op til 64 KB datahukommelse (RAM). ES8-kernen inkluderer også en vectored interrupt controller med programmerbar prioritet og en on-chip debugger, der kommunikerer med værtscomputeren ved hjælp af asynkron seriel kommunikation. Disse mikrocontrollere er pakket med et meget flot perifert sæt, der spænder fra alsidige 16-bit timere til motorstyringstimere, fra flere UARTs (IrDA ready) til USB-enheder og meget mere (besøg www.zilog.com for at kontrollere den fulde produktlinje).
et vigtigt træk ved ES8-programmeringsmodellen er manglen på en fast akkumulator. I stedet kan en af de 4.096 mulige RAM-adresser fungere som akkumulatorer. CPU ‘ en behandler sit vigtigste RAM (filen og sfrs — specialfunktionsregistre — området) som et stort sæt CPU-registre. For at opnå det er RAM opdelt i registergrupper (der er 256 grupper på 16 arbejdsregistre hver). En instruktion fungerer normalt inden for en enkelt arbejdsregistergruppe, som vælges af en SFR ved navn RP (registerpeger). Bemærk, at alle SFRs er placeret på den sidste side af RAM (adresser startende fra 0h00 op til 0hfff).
med hensyn til instruktionssættet er der 83 forskellige instruktioner opdelt i to opcode-sider. Det omfatter sædvanlige instruktioner til grundlæggende operationer som addition, subtraktion, logiske operationer, datamanipulationsinstruktioner, skifteinstruktioner, strømningsændringer, nogle 16-bit instruktioner, bit test og manipulation, 8H8 gange osv.
programhukommelsesområdet er organiseret, så de første adresser er dedikeret til specielle formål. Adresser 0h0000 og 0h0001 er dedikeret til konfigurationsmulighederne; adresser 0h0002 og 0h0003 gemmer nulstillingsvektoren; og så videre. Tabel 1 viser programhukommelsesorganisation.
0x0000 | Option bytes |
0x0002 | Reset vector |
0x0004 | WDT vector |
0x0006 | Illegal instruction vector |
0x0008 to 0x0037 | Interrupt vectors |
0x0038 to 0xFFFF | User program memory area |
TABLE 1. Simplified program memory organization.
nogle enheder inkluderer også et andet datarum (op til 65.536 adresser), som kun kan tilgås ved hjælp af lde/LDEI-instruktioner. Dette område kan bruges til at gemme mindre brugte data (da læsning/skrivning til det er langsommere end RAM/SFR-området).
Fpse8
den første implementering af Fpse8 bruger en meget konservativ og indbygget designtilgang med to hovedbusser: en til programhukommelse og en anden til registerhukommelse. Da jeg valgte ikke at medtage et datahukommelsesområde, implementeres lde/LDEI-instruktionerne ikke.
programhukommelsesbusserne omfatter en 16-bit instruktionsadressebus (IAB), en otte-bit instruktionsdatabus (IDB til læsning af data fra programhukommelsen), en otte-bit instruktionsdatabus (IDB til skrivning af data til programhukommelsen) og et PGM-signal, der styrer skrivning til programhukommelsen. Fps8 inkluderer 16.384 bytes programhukommelse implementeret ved hjælp af synkron blok RAM (hvilket betyder, at programhukommelsesindholdet går tabt, når enheden er slukket).
de fem registerområde busser består af tre til filregisterområdet (bruger RAM) og yderligere to dedikeret til specielle funktionsregistre. Der er en hoved 12-bit filregisteradressebus (FRAB), en otte-bit filregisterinputdatabus (FRIDB), en otte-bit filregisteroutputdatabus (FRODB), en otte-bit registerinputdatabus (RIDB) og endelig en otte-bit registeroutputdatabus (RODB) til skrivning til SFRs. Fps8 inkluderer 2.048 bytes bruger-RAM-hukommelse implementeret ved hjælp af synkron blok-RAM.
figur 2 viser et blokdiagram over Fps8; du kan se CPU ‘ en, to hukommelsesenheder (den ene til programlagring og den anden til datalagring) og også et eksternt timermodul.
figur 2. Fps8 blokdiagram.
Bemærk, at jeg ikke bruger tovejsbusser til sammenkoblinger i dette projekt. Envejs busser er enklere at bruge, selvom de er mindre pladseffektive.
VHDL-beskrivelsen af Fps8 er stor og lidt kompleks, så jeg vil opdele dens drift i nogle moduler for at lette forståelsen:
- Instruktionskømotor
- Instruktionsdekodning
- Afbryd behandling
- Debugger
Instruktionskømotor
Hentningsinstruktioner er en primær opgave for enhver CPU. Fps8 ‘ s Harvard-arkitektur muliggør samtidig hentning og dataadgang (på grund af separate busser til instruktion og data). Det betyder, at CPU ‘ en kan hente en ny instruktion, mens en anden læser eller skriver ind i datahukommelsen.
ES8 har et instruktionsord med variabel længde (instruktionslængden varierer fra en byte op til fem byte); nogle instruktioner er lange, men kører hurtigere end andre. På den måde har en BRK-instruktion en længde på en byte og kører i to cyklusser, mens en LDK-IM, ER1 er fire byte lang og kører i to urcyklusser.
så hvordan kan vi med succes afkode alle disse instruktioner? Med en instruktionskø; det vil sige en mekanisme, der fortsætter med at hente bytes fra programhukommelsen og gemme dem i et otte-byte array:
if (CAN_FETCH=’1′) derefter
IF (IK.FETCH_STATE=F_ADDR) derefter
FETCH_ADDR := PC;
IAB <= PC;
ik.= 0;
IK.RDPOS: = 0;
IK.CNT := 0;
ik.FETCH_STATE: = F_READ;
ellers
hvis (ik.Fuld= ‘0’) derefter
ik.KØ(IK.VPOS): = IDB;
FETCH_ADDR := FETCH_ADDR + 1;
IAB <= FETCH_ADDR;
IK.P. S.: = P. S.1;
IK.CNT: = IK.CNT + 1;
end if;
end if;
end if;
if.CNT=7) derefter ik.Fuld:= ‘1’; ellers ik.Fuld:= ‘0’;
slut hvis;
liste 1. Instruktion kø motor.
hentning styres af et hovedaktiveringssignal (CAN_FETCH), som kan deaktiveres i nogle specielle tilfælde (afbryd behandling, ved LDC/LDCI-instruktioner eller debuggeradgang). Der er også en struktur (IKØ), som gemmer flere interne parametre (hentning tilstand, læse og skrive pointere, kø array selv, en tæller, og en fuld indikator).
køtælleren (CNT) bruges til at identificere antallet af bytes, der er tilgængelige til brug (læsning) i køen. Dekoderfasen bruger dette nummer til at kontrollere, at det ønskede antal bytes til instruktionen allerede er tilgængelig i køen.
Instruktionsdekodning
det er her den egentlige magi sker. Instruktionsdekoderen læser opkoder fra instruktionskøen og oversætter dem til tilsvarende operationer.
Instruktionsdekoderdesign startede med at finde ud af forholdet mellem alle instruktioner og adresseringstilstande. Ved første øjekast er det let at se, at nogle instruktioner (figur 3) er grupperet efter kolonne (DJN, JR cc,ld r1, IM,JP cc, DA og INC r1). Afkodning af en INC r1-instruktion er enkel: på disse single-byte-instruktioner specificerer den høje nibble kilde/destinationsregistret, og den nederste nibble specificerer selve instruktionen (0 gange).
figur 3. Opkoder efter grupper.
de fleste instruktioner kan klassificeres efter nogle grundlæggende regler:
- kolonner (den nederste nibble af en opcode) angiver normalt en adresseringstilstand: Kolonne 0H9 instruktioner,for eksempel, bruger for det meste im, ER1 adresseringstilstand og er fire byte lange (den anden byte er den umiddelbare operand, og de to sidste byte er destinationsudvidelsesadressen).
- rækker (den højere nibble af en opcode) angiver normalt en operation: række 0H0 instruktioner er for det meste tilføjelsesoperationer; række 0H2 instruktioner er for det meste subtraktionsoperationer og så videre.
hvis vi ser på række 0H1, kan vi se, at kolonner 0H0 og 0H1 er RLC-instruktioner, og kolonner 0H2 op til 0H9 er ADC-instruktioner. Så vi kan designe en ALU, der tager en nibble som input (den højere nibble fra opcode) og afkoder den i overensstemmelse hermed. Mens dette ville fungere for kolonner 0H2 til 0H9, ville vi have brug for en anden tilgang til de to første kolonner.
derfor endte jeg med at skrive to enheder: en ALU, der koncentrerer sig om de fleste aritmetiske og logiske instruktioner; og en anden enhed (logisk enhed 2 eller LU2), der udfører andre operationer vist i kolonne 0H0 og 0H1 (ikke alle operationer set på disse kolonner udføres af LU2). Operationskoderne for både ALU og LU2 blev valgt til at matche opcode rækker vist i figur 3.
en anden vigtig detalje er, at alle instruktioner inden for samme kolonne og gruppe er af samme størrelse i bytes, således kan dekodes i samme dekoder sektion.
dekoderdesignet gør brug af en stor endelig tilstandsmaskine (FSM), der skrider frem på hvert ur-kryds. Hver instruktion starter i CPU_DECOD stat. Det er her dekoderen faktisk afkoder opcodes, forbereder busser og interne understøttende signaler og trin til andre udførelsestilstande. Blandt alle disse stater bruges to i vid udstrækning af mange instruktioner: CPU_OMA og CPU_OMA2. Kan du gætte hvorfor? Hvis du sagde, fordi de er relateret til ALU og LU2, du har helt ret!
OMA er en forkortelse for one Memory Access, og det er den sidste tilstand for alle alu-relaterede instruktioner (ADD, ADC, add, ADC, SUB, SBC, sub, SBC, sub, SBC, or, or, Or, og, TC, TCM, TM, TM og nogle varianter af LD og LDC). På den anden side er CPU_OMA2 den sidste tilstand for alle LU2-relaterede instruktioner (RLC, INC, DEC, DA, COM, RL, CLR, RRC, SRA, SRL, RR og bytte).
lad os nu kigge ind i CPU_DECOD-tilstanden. Der henvises til figur 4.
figur 4. CPU_DECOD tilstand.
inden for CPU_DECOD-tilstanden kan vi se, at der sker en masse handling. I begyndelsen initialiseres nogle midlertidige variabler til en standardbetingelse. Bemærk, at NUM_BYTES er meget vigtigt, da det styrer, hvor mange bytes der blev forbrugt af instruktionsdekoderen. Dens værdi bruges i den sidste del af dette trin til at øge PC ‘ en (programtæller), fremme kølæsningsmarkøren og formindske antallet af tilgængelige bytes i køen.
efter initialiseringsafsnittet kan vi se afsnittet afbryd behandling. Det er ansvarligt for at registrere eventuelle afventende afbrydelser og forbereder CPU ‘ en i overensstemmelse hermed. Jeg dækker dette i næste afsnit.
den aktuelle instruktionsdekodningsblok kontrollerer, om en lav strømtilstand ikke er aktiv, og også om debuggertilstanden er slået fra (OCDCR.DBGMODE=0). Eller i debug-tilstand blev der udstedt en enkelt trin debug-kommando (OCDCR.DBGMODE=1 og OCD.SINGLE_STEP=1). Det kontrollerer derefter de tilgængelige bytes i køen og fortsætter med afkodning.
nogle instruktioner (for det meste singlebyte) er afsluttet inden for CPU_DECOD-tilstanden, mens andre har brug for flere tilstande, indtil de er fuldstændigt afsluttet.
Bemærk, at nogle instruktion afkodning kan gøre brug af flere funktioner og procedurer skrevet specielt til Fps8:
- DATAVIT — denne procedure forbereder busser til en skriftlig operation. Det vælger, om destinationen er en intern SFR, en ekstern SFR eller en bruger RAM-placering.
- DATAREAD — dette er en gensidig funktion for DATAVIT. Det bruges til at læse en kildeadresse og vælger automatisk, om det er en intern SFR, en ekstern SFR eller en bruger-RAM-placering.
- CONDITIONCODE — bruges til betingede instruktioner (såsom JR og JP). Det tager en fire-bit tilstandskode, tester den og returnerer resultatet.
- ADRESSER4, ADRESSER8 og ADRESSER12 — disse funktioner returnerer en 12-bit adresse fra en fire -, otte-eller 12-bit kilde. De bruger indholdet af RP-registret til at generere den endelige 12-bit adresse. ADRESSER8 og ADRESSER12 kontrollerer også for enhver undsluppet adresseringstilstand.
- ADDER16 — dette er en 16-bit adder for adresse offset beregning. Det tager en otte-bit signeret operand, tegn udvider den, tilføjer den til 16-bit adressen og returnerer resultatet.
- ALU og LU2 — disse blev diskuteret tidligere og udfører de fleste aritmetiske og logiske operationer.
Interrupt Processing
som jeg sagde før, har ES8 en vectored interrupt controller med programmerbar prioritet. Først, jeg troede, at dette afsnit ikke ville være så svært, fordi afbrydelser ikke er nogen big deal, højre? Nå, da jeg begyndte at finde ud af, hvordan man gør alle de nødvendige opgaver (gemmer kontekst, vektorering, styring af prioriteter osv.), Indså jeg, at det ville være hårdere, end jeg først troede. Efter et par timer kom jeg op med det nuværende design.
Fps8 ‘ s afbrydelsessystem endte med at være simpelt. Det har otte indgange (INT0 til INT7); en global interrupt enable (IRKTL-bit); to registre for priority setting (IRK0ENH og IRK0ENL); og et register for interrupt flags (IRK0). Designet gør brug af en indlejret if-kæde, der genererer en vektoradresse ved påvisning af en afbrydelseshændelse vedrørende en aktiveret afbrydelse.
figur 5 viser et komprimeret billede af afbrydelsessystemet. Bemærk Der er en første if-sætning med et symbol ATM_COUNTER. Dette er en simpel tæller, der bruges af ATM-instruktionen (den deaktiverer afbrydelser i tre instruktionscyklusser, hvilket tillader atomoperationer).
figur 5. FP8 afbryder systemet.
en sidste kommentar vedrørende afbrydelser: Interrupt flag register (IRK0) prøver Afbryder indgange hver stigende kant af systemuret. Der er også to buffervariabler (IRK0_LATCH og OLD_IRK0), der gemmer flagens aktuelle og sidste tilstand. Dette tillader interrupt edge detektion og synkroniserer også de eksterne indgange til det interne ur (FPGA ‘ er fungerer ikke godt med asynkrone interne signaler).
On-Chip Debugger
dette er sandsynligvis den sejeste funktion i denne softcore, da det tillader et kommercielt integreret udviklingsmiljø (IDE; til at kommunikere, programmere og debugere programmer, der kører på FP8. On-chip debugger (OCD) består af en UART med autobaud kapacitet og en kommando processor knyttet til det. UART udfører seriel kommunikation med en vært-PC og leverer kommandoer og data til debugger-tilstandsmaskinen, der behandler debug-kommandoer (debugger-kommandobehandlingen FSM er placeret inde i CPU_DECOD-tilstanden).
figur 6. On-chip debugger UART (Bemærk synkroniseringen).
mit OCD-design implementerer næsten alle kommandoer, der er tilgængelige på det rigtige udstyr, bortset fra dem, der er relateret til datahukommelse (debug-kommandoer 0h0c og 0h0d); read runtime-tælleren (0H3); og read-programhukommelsen CRC (0h0e).
en ting, jeg gerne vil fremhæve, er, at der er behov for pleje, når man beskæftiger sig med asynkrone signaler inde i FPGA ‘ er. Mit første design tog ikke højde for det under behandlingen af indgangssignalet. Resultatet var helt underligt. Mit design havde fungeret fejlfrit i simulering. Jeg hentede det til en FPGA og begyndte at spille rundt med debug seriel interface ved hjælp af en seriel terminal (min FPGA bord har en indbygget seriel-USB konverter).
til min overraskelse, mens jeg for det meste kunne sende kommandoer og modtage de forventede resultater, ville designet undertiden simpelthen fryse og stoppe med at svare. En blød nulstilling ville få tingene til at gå tilbage til deres korrekte funktion, men det var spændende for mig. Hvad skete der?
efter mange tests og nogle Googling fandt jeg ud af, at det muligvis var relateret til de asynkrone kanter af det serielle indgangssignal. Derefter inkluderede jeg en kaskadelås for at synkronisere signalet til mit interne ur, og alle problemerne var væk! Det er en hård måde at lære, at du altid skal synkronisere eksterne signaler, før du fodrer dem i kompleks logik!
jeg må sige, at debugging og raffinering af debugger-koden var den sværeste del af dette projekt; mest fordi det interagerer med alle de andre delsystemer, herunder busser, dekoderen og instruktionskøen.
syntese og test
når den var fuldt kompileret (jeg brugte Kvartus II v9.1 sp2), brugte Fps8-kernen 4.900 logiske elementer, 523 registre, 147.456 bit on-chip-hukommelse og en indlejret ni-bit multiplikator. Samlet set bruger Fps8 80% af EP4CE6 ‘ s tilgængelige ressourcer. Selvom dette er meget, er der stadig nogle 1.200 logiske elementer til rådighed for perifere enheder (min enkle 16-bit timer tilføjer op til omkring 120 logiske elementer og 61 registre). Det passer endda på den mindste Cyclone IV FPGA-EP4CE6-som er den monteret på det billige minikort, jeg brugte her (Figur 7).
figur 7. Altera Cyclone IV EP4CE6 mini bord.
mini board-funktionerne (sammen med EP4CE6-enheden): en EPCS4-seriel konfigurationshukommelse (monteret på undersiden); en FTDI-seriel-til-USB-konverterchip samt et 50 mm krystaloscillatormodul; nogle knapper; lysdioder; og pin-overskrifter for at få adgang til FPGA-stifter. Der er ingen integreret USB-Blaster (til FPGA-programmering), men den pakke, jeg købte, indeholdt også en ekstern programmeringsdongle.
hvad angår den virkelige verdenstest, var det overflødigt at sige, at Fps8 ikke fungerede første gang! Efter at have tænkt lidt og læst compiler output beskeder, Jeg regnede ud, at det sandsynligvis var et timing problem. Dette er et meget almindeligt dilemma, når jeg designer med programmerbar logik, men da dette var mit andet FPGA-design nogensinde, var jeg ikke opmærksom nok på det.
kontrol af timinganalysemeddelelserne kunne jeg se en advarsel om, at det maksimale ur skulle være omkring 24 MH. Først forsøgte jeg at bruge en divider-by-2 til at generere et CPU-ur på 25 MH, men det var ikke pålideligt. Jeg brugte derefter en divider-by-3. Alt begyndte at fungere perfekt!
derfor kører Fps8 i øjeblikket på 16.666 MHG. Det er muligt at opnå højere hastigheder ved at bruge en af de interne PLL ‘ er til at multiplicere/opdele hoveduret for at få ET resulterende ur lavere end 24 MHG, men højere end 16.666 MHG.
programmering og fejlfinding
brug af FP8 er meget enkel og ligetil. Når designet er hentet til FPGA, begynder CPU ‘ en at køre ethvert program, der er indlæst i hukommelsen. Du kan levere en sekskantfil og bruge Plug-in Manager til at ændre programhukommelsesinitialiseringsfilen. På den måde begynder din applikationskode at køre efter et nulstillingssignal.
du kan bruge ide ‘ en til at skrive samling eller C-kode og generere de nødvendige sekskantfiler (jeg vælger normalt 8F1622 som min målenhed, da den også har 2 KB RAM og 16 KB programhukommelse). Takket være on-chip debugger er det også muligt at bruge IDD ‘ en til at hente kode til FP8 ved hjælp af en seriel debugforbindelse (USB, i vores tilfælde).
før du tilslutter, skal du sørge for, at debuggerindstillingerne er de samme som i figur 8. Fjern markeringen i indstillingen” Brug side sletning før blinkning”, og vælg” SerialSmartCable ” som det aktuelle fejlfindingsværktøj. Glem ikke også at kontrollere, om FTDIS virtuelle COM-port er korrekt valgt som debug-port (brug opsætningsknappen). Du kan også indstille den ønskede kommunikationshastighed; 115.200 bps fungerer meget godt for mig.
figur 8. Debugger indstillinger.
Bemærk, at når du opretter forbindelse til Fps8, viser ID-ID ‘ en en advarselsmeddelelse, der informerer dig om, at målenheden ikke er den samme som projektet. Det sker, fordi jeg ikke implementerede nogle ID-hukommelsesområder. Bare ignorere advarslen og fortsætte med debugging session.
når koden er hentet, kan du starte applikationen (GO-knap), trininstruktioner, inspicere eller redigere registre, indstille breakpoints osv. Som med enhver anden god debugger kan du for eksempel vælge PAOUT-registret (under PORTS group) og endda ændre tilstanden for de lysdioder, der er tilsluttet PAOUT.
nogle enkle C-kodeeksempler kan findes i overførsler.
bare husk på, at Fps8 har en flygtig programhukommelse. Således er ethvert program hentet til det tabt, når FPGA er slukket.
lukning
dette projekt tog mig et par uger at gennemføre, men det var dejligt at undersøge og designe en mikrocontroller-kerne.
jeg håber, at dette projekt kan være nyttigt for alle, der ønsker at lære om computing basics, mikrocontrollere, indlejret programmering og/eller VHDL. Jeg tror — at — hvis parret med en billig FPGA bord-Fps8 kan give en fantastisk læring (og undervisning) værktøj. Hav det sjovt! NV
CEFET-PR:
www.utfpr.edu.br
ScTec:
www.sctec.com.br
HCS08 Unleashed:
https://www.amazon.com/HCS08-Unleashed-Designers-Guide-Microcontrollers/dp/1419685929
8 CPU Manual (UM0128):
første gang.zilog.com/docs/UM0128.pdf
Zilog Z8F64xx Product Specification (PS0199):
www.zilog.com/docs/z8encore/PS0199.pdf
Zilog ZDS II IDE User Manual (UM0130):
www.zilog.com/docs/devtools/UM0130.pdf
Zilog ZDS-II Software Download:
https://www.zilog.com/index.php?option=com_zcm&task=view&soft_id=7&Itemid=74
Zilog Microcontroller Product Line:
http://zilog.com/index.php?option=com_product&task=product&businessLine=1&id=2&parent_id=2&Itemid=56
Project Files available at:
https://github.com/fabiopjve/VHDL/tree/master/FPz8
FPz8 at Opencores.org:
http://opencores.org/project,fpz8