Innehållsförteckning:

Återbesöker Z80 -datorn: 6 steg
Återbesöker Z80 -datorn: 6 steg

Video: Återbesöker Z80 -datorn: 6 steg

Video: Återbesöker Z80 -datorn: 6 steg
Video: Retrospel på Commodore 64 2024, November
Anonim
Besöker Z80 -datorn igen
Besöker Z80 -datorn igen
Besöker Z80 -datorn igen
Besöker Z80 -datorn igen

Tidigare har jag skrivit en guide om hur man bygger en Z80-baserad dator, och jag utformade kretsen så enkel som möjligt så att den kunde byggas så enkelt som möjligt. Jag skrev också ett litet program med samma idé om enkelhet. Denna design fungerade ganska bra, men jag var inte helt nöjd med den. Jag började med att skriva om ett program för det som gjorde det möjligt att programmera det under körning. Detta var för att låta mig testa kodbitar utan att behöva ägna den åt EEPROM, vilket i sin tur skulle kräva att jag programmerade om EEPROM. Det här lät inte som en rolig idé för mig. Sedan började jag tänka på minnesutrymmen. Om jag ville ansluta en hårdvara (huvudsakligen IO) kan en kodbit potentiellt överskrida mängden minnesutrymme som finns tillgängligt för systemet. Kom ihåg att designen endast använde adressbussens nedre byte och sedan användes den nedre biten i den höga byten för att välja mellan ROM- och RAM -utrymmen. Detta innebar att jag bara hade 253 byte utrymme att använda. Du kanske frågar varför 253 istället för 256. Det beror på att min nya kod injicerar tre byte med data i slutet av ett skrivet program (detta kommer att täckas senare, eftersom jag ändrade det för att arbeta med den nya designen).

n

Jag gick tillbaka över mina gamla scheman för att se vad mer som hände. Jag hittade en liten brist med minnesvalskretsen, som jag kommer att täcka när jag kommer dit. Den förenklade versionen: alla skrivförfrågningar skulle faktiskt gå igenom, även om det alltid sattes i RAM. Detta var förmodligen inget värt att oroa sig för, men jag ville göra det ordentligt den här gången. Och med det började jag rita en ny schema. De två bilderna som bifogas den här sidan är före och efter själva kretsen. Jag städade så mycket av spagettikablarna, det är inte roligt.

n

Om du följde med mitt ursprungliga bidrag och planerar att följa med det här kommer du att hata mig. Om du börjar på nytt har du tur. Ta bara delarna i listan (eller motsvarande) och följ med.

Tillbehör:

LM7805 - 5 Volt regulator Z80 - CPU: n; hjärnan i systemAT28C64B - EEPROM. "Permanent" datalagring som används för datorns firmwareIDT6116SA - SRAM; används för att lagra användarkod och /eller allmän datalagringNE555 - Systemklocka74HC374 - Octal D -Latch med /OE; används som ingångschip74LS273 - Octal D -Latch med /MR; utgångs -chipTLC59211 - LED -drivrutinschip (används för att 74LS273 kan driva lysdioder, eftersom det inte ensam kan strömmen) MC14572 - Detta är ett "Line Driver" -chip, men jag tyckte att det var perfekt för minneskontrolllogiken. Den har 4 växelriktare och en NAND- och NOR -grind inbyggd 74LS32 - Quad OR gateCD4001 - Quad NOR gateCD4040 - 12 Stage Ripple Counter; Ritade, men inte implementerade klockavdelare (för att köra systemet med lägre klockhastigheter) 2 10K Ohm -motstånd - En används i 555 -timerkretsen, så använd vilket värde du vill ha för den 4 1K Ohm -resistorer - Den ena används för 555 timerkrets, så använd vad du vill för det. En annan används för att driva lysdioder, så variera den också om du vill 8x330 Ohm Resistor Bus8x10K Ohm Resistor Bus11 LED - Tre används för systemstatus och de andra åtta är utgångar. För de 8 använde jag en stapeldiagram (HDSP -4836) 4 kondensatorer - Två används LM7805; 0,22uF och 0,1uF. Den ena är för 555 -timern, så använd det du tycker är rätt. Den sista är för återställning vid start; 100uF2 N. O. Tryckknappar - Den ena används för inmatning, den andra för återställning 8 SPST DIP -switchar - Datainmatning; Jag använde Piano Key styleWire. Mycket och mycket tråd

n

OBS: MC14572 genomgående hålversion är föråldrad, men SMD -versionen är fortfarande aktiv (inte ens "inte för ny design" -status), så du kan behöva köpa ett kretskort för att du ska kunna använda det. En andra 74LS32 kan användas i stället för MC14572 (se schematisk "minnesvalkrets" för tidigare ible)

Steg 1: Snabböversikt över ändringar + scheman

Snabb översikt över förändringar + scheman
Snabb översikt över förändringar + scheman

Hur man läser schemat: En pil som pekas in i ett chip är en ingång: Inmatning> -En pil som pekas bort från ett chip är en utgång: Utgång <-Bussar använder en linje istället för en pil: Buss |-

n

De flesta marker har dragits med sina exakta pinouts. Det lilla doppet har dragits på dessa marker. De flesta marker har också pin -nummer och etiketter på dem. De kan vara lite svåra att läsa. Min penna blev tråkig.

n

När det gäller kretsanslutningar är layouten för den nya designen mestadels oförändrad från originalet. Jag kopplade den nedre nibble av adressen high byte till minnena och använde sedan den övre nibble (A12) låga bit för RAM/ROM -val. Detta innebar att ROM-utrymmet gick från 0000-00FF upp till 0000-0FFF. Ramutrymmet gick från 0100-01FF till 1000-1FFF. Jag bytte också ut minneskontrolllogiken för en bättre design och lade till två nya status -lysdioder (och lite limlogik). Jag har också ritat (men inte trådat) en klockavdelningskrets. Det var att utföra två funktioner. Den uppenbara funktionen är att dela ner klockfrekvensen. Den andra funktionen är avsedd för PWM (Pulse Width Modulation), eftersom 555 inte genererar vågor med 50% driftcykler. Det spelar egentligen ingen roll i den här kretsen, men om du skulle vilja använda klockan för att driva några lysdioder kommer du definitivt att märka effekterna (en (uppsättning) lysdioder blir svagare än den andra). Hela resten av kretsarna är i huvudsak oförändrade.

Steg 2: CPU, minne och minneskontroll

CPU, minne och minneskontroll
CPU, minne och minneskontroll
CPU, minne och minneskontroll
CPU, minne och minneskontroll
CPU, minne och minneskontroll
CPU, minne och minneskontroll
CPU, minne och minneskontroll
CPU, minne och minneskontroll

Det här är delen där läsare av min tidigare version hatar mig. I den ursprungliga byggnaden slängde jag bara delar på brädet på en plats som de såg ut som att de skulle ställa lite problem med att bli uppkopplad. Resultatet såg ut som om någon dumpade en tallrik med spagetti på den och var som "trådar!" Jag ville städa upp det lite, så jag började med att rippa upp allt utom CPU, RAM och ROM. Jag drog upp nästan hela ingångskretsen, utgångskretsen och limlogiken. Det gjorde nästan ont i mig att göra det, men det var nödvändigt. Jag lämnade alla dataanslutningar intakta och adressbussens nedre byte. Jag kopplade sedan de fyra nästa bitarna i adressbussen (A8-A11) över till ROM-chipet. Jag var noga med att gå runt chipet den här gången för att göra det lättare att dra upp för omprogrammering. Jag hoppade också ner adressanslutningarna till RAM -chipet.

n

Med det ur vägen måste jag nu få minneskontrolllogiken tillkopplad. I den ursprungliga schemat hade jag anslutit processorns /MREQ -linjen direkt till /CE till båda minneskretsarna, sedan kopplade jag /WR till RAM: n /WE. Sedan hade jag CPU: ns /RD och /MREQ logiskt OR'd tillsammans samt A9. I huvudsak var det konfigurerat så att alla minnesförfrågningar aktiverade både RAM och ROM, men A9 användes för att välja vilket av chipsen /OE som valdes. Detta var bra och allt eftersom chipsen skulle förbli inaktiva tills en minnesförfrågan gjordes och då bara en /OE skulle vara aktiv under en läsförfrågan. Detta förhindrade överhörning, men introducerade en besvärlig nyans. Eftersom A9 bara användes för att avgöra vilket chip som skickade data och eftersom CPU: n hade direkt åtkomst till RAM /WE -stiftet skulle alla skrivförfrågningar gå igenom. Detta var okej för ROM eftersom dess skrivläge hämmas genom att binda /WE direkt till 5V -matningen. RAM -minnet skulle dock skrivas till oavsett A9. Detta innebar att ett försök att skriva till en ROM -plats skulle skriva till samma plats i RAM -utrymme.

n

En lösning för detta skulle vara att koppla om styrlogiken så att CPU: n har direktåtkomst till chipsens /OE- och /WE -stiften och sedan använda MREQ och A12 för att välja vilka chips /CE som drevs. Jag gick med den här idén, men istället för att använda fyra NOR -grindar och en inverter som den ursprungliga designen hittade jag ett besvärligt litet chip som var perfekt för uppgiften. Jag var tvungen att skapa en krets som bara använde de logiska grindarna som finns i chipet, men det var lätt nog. A12 matar direkt in i en NAND -grind och en NOR -grind. /MREQ matas in i NOR -grinden och dess komplimang matas in i NAND -grinden. NAND -grinden används för att driva /CE för RAM och NOR -utgången blir inverterad och används för att driva ROM /CE. Detta gör det så att /MREQ måste vara låg innan något av chipen väljs och sedan väljer A12 vilket som kommer att väljas. Med denna inställning kommer nu inga skrivförfrågningar till ROM att göra någonting. Det sparar också ström eftersom bara ett chip är aktivt istället för båda. När det gäller själva logikchipet har vi fortfarande två oanvända växelriktare inuti. En kommer att vänja sig senare, men vi kommer dit när vi kommer dit.

Steg 3: Lysdioder för systemstatus

Systemstatus -lysdioder
Systemstatus -lysdioder
Systemstatus -lysdioder
Systemstatus -lysdioder

Innan jag började detta projekt försökte jag ansluta till en viss IC, men jag hade problem med det. Osäker på vad som hände använde jag en panelmonterad LED för att sondera runt (en av de enheter som har ett inbyggt motstånd). Att göra detta gav mig en nostalgiidé som fortfarande används idag: status -lysdioder som används för att indikera om minne lästes från eller skrevs till. Den skulle användas tillsammans med ingångs -LED: n som jag redan hade. Ingångs -LED: n var ansluten till /WAIT -signalgeneratorn för att indikera för oss att systemet väntar på ingång (jag kommer dit, oroa dig inte). Jag övervägde att lägga till en lysdiod för att indikera en IO -skrivning, men jag tänkte att utgångs -lysdioderna som ändrats redan skulle vara en bra indikator på det. När jag tänker på det kan jag fortfarande lägga till det ännu. Ändå tycker jag det är bra att veta om minnet läses eller skrivs. Tja, det är användbart för programfelsökning i alla fall. Jag använde det verkligen som sådant när jag försökte få mitt program att fungera:”varför skriver det till minnet? Det ska det inte göra ännu!"

n

För att styra dessa lysdioder använde jag quad NOR -grinden. Jag använde alla portar. Endast två användes för att generera statussignalerna, men chipet har inte strömförmåga att faktiskt driva lysdioderna. De kan sänka så mycket kraft, så jag använde de andra två NOR -grindarna som växelriktare och anslöt lysdioderna som sådana. Eftersom en lysdiod används för att indikera läsningar och den andra för skrivning, och en läs- och skrivförfrågan inte kommer att inträffa samtidigt, kunde jag komma undan med att bara använda ett motstånd för båda lysdioderna. När det gäller signalerna jag behövde avkoda, var det också tillräckligt enkelt. Jag ville att alla minnesläsförfrågningar skulle visas, så den första NOR -porten hade /MREQ och /RD på sina ingångar. Skrivstatusen var lite knepigare, men lika lätt. Jag använde fortfarande /MREQ som en ingång, men att använda /WR som den andra skulle orsaka en mindre nyans som jag ville undvika. Det skulle ha angett ALLA skrivförfrågningar. Jag ville bara ha de som faktiskt gick igenom. Så hur skulle jag göra det? Kommer du ihåg hur jag har konfigurerat systemet så att bara RAM -minnet kan skrivas? Jag använde RAM /CE som den andra ingången till NOR -grinden. Det betyder att lysdioden bara tänds när RAM -minnet väljs och en skrivförfrågan görs. När det gäller LED -färg valde jag orange som läsindikator (men jag hittade bara gula) och rött som skrivindikator.

Steg 4: Inmatning och utmatning

Ingång och utgång
Ingång och utgång
Ingång och utgång
Ingång och utgång
Ingång och utgång
Ingång och utgång

I föregående steg har du kanske märkt att jag redan lagt till några av resten av komponenterna på kortet. Jag reserverade utrymmet så att jag inte av misstag skulle placera ledningar där jag ville ha en komponent (så jag skulle behöva hitta en ny plats för komponenten). Du kanske också har märkt att jag lämnade ingångsbrytarna på plats och kopplade till strömskenan. Jag bestämde mig för att den ursprungliga platsen var den perfekta platsen och bestämde mig för att placera utgångs -lysdioderna i närheten (ovan). Till höger om stapeldisplayen är ingångsspärren. Ovanför är utgångsspärren, och till vänster om den är LED -drivrutinen. Jag började med att ansluta skärmen till drivrutinen eftersom det var det enklaste att göra. Sedan kopplade jag omkopplarna till ingångssidan på ingångsspärren. Därefter anslöt jag utgångssidan på utgångsspärren till LED -drivrutinen. Det här kan verka som en besvärlig ordning för att få dessa trådbundna, men det var av en anledning. Ingången till utgångslåset skulle anslutas till databussen såväl som utgången från ingångslåset. Tanken var att ansluta utgångarna från ingångslåset till ingångarna på utgångslåset, vilket jag gjorde. Sedan var det bara att få den röra ansluten till databussen. Det spelade ingen roll var dessa anslutningar gick fysiskt eftersom de alla skulle vara elektriskt anslutna. Datorn är nu nästan klar.

Steg 5: Återställ och avsluta in- och utdata

Tyvärr, inga bilder för detta steg. Se föregående steg för bilderna.

n

Du kanske har märkt på den sista bilden av föregående steg, jag hade en grön knapp och ett annat logikchip installerat. Chippet är OR -grinden. Två portar används för att generera /WAIT -signalen. Tja, en genererar signalen genom OR-ing /IORQ och /RD från processorn. Utmatningen matas in i den andra grinden, där den får OR'd igen till en tryckknapp. Knappen ger ingången till grinden hög, vilket ger utgången hög. Denna utmatning matas till processorer /WAIT -stift. Medan det inte trycks in håller ett motstånd ingången låg. Jag använde först ett 10K -motstånd, men LS32 satte faktiskt ut spänning på ingången. Motståndet tappade det inte tillräckligt lågt och jag var tvungen att ersätta det med en 1K. Hur som helst är tanken att när en IO -läsförfrågan görs säger den första och andra ELLER -porten processorn att vänta. När du väl ställt in ingångsväxlarna till vad du vill, trycker du på knappen och det tar CPU: n ur väntetillståndet. Den gröna "ingångs" -LED -lampan, som jag kallade den i ett tidigare steg, är ansluten så att /WAIT -pinnen tänds, tänds.

n

Men vi är inte klara ännu. Ingångens flip -flop behöver en signal för att meddela den när datainmatningen är giltig och bör skickas ut till CPU: n. Denna klocknål är aktiv hög. Innan kopplade vi den bara till knappen. Detta är fortfarande ett giltigt alternativ, men den här gången valde jag att lägga det på samma utgång som den andra ELLER -grinden. Denna IC har också en /OE -stift som måste drivas. Om den skulle hållas hög skulle den aldrig infoga data i bussen. Om det hålls lågt, skulle det alltid vara att köra bussen. För att fixa detta använde jag helt enkelt en tredje ELLER -grind. Ingångarna är /IORQ och /RD och utgången går direkt till spärren /OE.

n

Utgångsspärren behöver också klockstiftet för att drivas. Återigen är den aktiv hög. I min schematiska ritning ritade jag den fjärde ELLER -grinden direkt som driver stiftet med /IORQ och /WR. Detta innebar att klockstiftet skulle hållas högt tills en skrivförfrågan gjordes, sedan skulle det gå lågt och sedan högt igen. Detta skulle förmodligen ha varit bra eftersom databussen fortfarande skulle ha haft giltiga data om den direkt efter försöket att skriva, men från en teknisk synvinkel var en skräpdesign. Jag märkte inte detta fel förrän efter att jag hade tagit de sista bilderna, men jag rippade upp den anslutningen och matade sedan OR -grindutgången till en av de oanvända inverterarna från minneskontrolllogiken och kopplade sedan dess utgång till klockstiftet. Jag fixade också schemat och hittade ett annat fel som jag hade gjort. Jag rättade det också.

n

Med allt detta äntligen gjort hade jag en mycket liten mängd arbete att göra: återställningskretsen. Jag lade till en knapp på kortet och använde ett 10K -motstånd för att hålla ena sidan hög. Den andra sidan går direkt till marken. Sidan som hålls hög är /RESET -utgången, som gick till varje chip med en /RESET -stift (CPU och utgångslås). För att åstadkomma återställning startade jag en kondensator till /RESET-utgången. Tanken är att motståndet med stort värde skulle få den relativt stora kondensatorn att laddas långsamt och hålla /RESET -stiften låga under en viss mängd klockcykler (CPU: n behöver fyra klockcykler). Du kan förmodligen redan gissa vad den negativa sidan av denna krets är. Det är samma negativa som den tidigare versionen eftersom det är samma krets. När knappen trycks ned kortas kondensatorn i huvudsak genom knappen. Detta är dåligt för både locket och knappen, så om du vill göra din byggnad lite mer permanent, kanske du vill göra om den. Jag tänkte på en annan 555 timer som är inställd i monostabilt läge. Men med det är datorkretsen nu klar. Jippie. Nu behöver den programmeras.

Steg 6: Programmering

Att programmera det här var en mardröm. Jag byggde en Arduino EEPROM programmerare. Det fungerade inte. Jag byggde en till baserad på någon annans design och kodning. Fungerade fortfarande inte. Jag gick tillbaka till den beprövade metoden att manuellt ställa in adresser och databyte för hand. På något sätt förstörde jag det. Jag försökte igen och fick fortfarande fel. Jag gick tillbaka igen och upptäckte att det var av med en enda byte, så jag korrigerade det och det fungerade slutligen, tack och lov.

n

När det gäller själva programmet ser det ut som att det är superkomplex och svårt att följa, men det är det inte. Det är ganska enkelt, faktiskt. Hälften av det är att kopiera siffror runt. Den andra halvan delas mellan 16-bitars matematik, villkorliga hopp och ännu fler kopieringsnummer runt. Så låt mig gå igenom det och berätta hur det fungerar.

n

Initieringen anger bara några registervärden för användning av programmet. Programslingan är lite mer komplex, men inte mycket. Först accepterar den inmatning till A -registret på port 00. Sedan skrivs E -registret till minnet. På de två första slingorna innehåller E -registret skräpdata, så vi försöker skriva det till de två sista byten ROM -utrymme eftersom det faktiskt inte kommer att skrivas; adresspekaren (IY) ökas sedan. Värdet som lagras i D flyttas sedan till E för att sedan skrivas. A laddas sedan in i D och L och E kopieras till H. HL är där värdejämförelsen sker via subtraktion och kontroll av ZF (nollflagga). Det första värdet jämfört med lagras i registren B och C. B och C behandlas som ett enda 16-bitars register, BC. Om värdena är desamma hoppar programmet rakt in i RAM -utrymmet, där användarkoden antas ligga. Om koden i BC inte är en matchning laddas HL om med initialvärdena från D och E och jämförs igen med värdet i SP på samma sätt som det jämfördes med BC. Om det är en matchning har det samma resultat, men tre extra byte skrivs till minnet. Byte är en kod som får CPU: n att hoppa tillbaka till början av sitt program (en programåterställning). Om den andra jämförelsen inte var en matchning, går programmet där det tar ett värde från användaren.

n

LD SP, EDBFH; exe -kod (lägger till hopp)

n

LD IY, FFEH; initial minnespekare för kodlagring

n

LD BC, EDC3H; exe -kod (ingen loop)

n

slinga; assembler -direktivet så att vi inte behöver veta var i minnet den här delen finns

n

I A, (00H); få programdata

n

LD (IY+00H), E; E innehåller kod som ska lagras

n

INC IY; gå till nästa minnesplats

n

LD E, D; ld D till E

n

LD D, A; ld A till D

n

LD H, E; l E till H

n

LD L, D; ld D till L

n

ELLER A; återställ bärflagga

n

SBC HL, BC; returnerar 0 om exe -kod 2 angavs

n

JP Z, 1000H; hoppa i så fall till och kör programmet

n

LD H, E; annars uppdatera dessa till rätt värden

n

LD L, D

n

ELLER A; första subtraheringen kan ha satt bärflagga. Rensa det

n

SBC HL, SP; returnerar 0 om exe -kod 1 angavs

n

JP NZ, slinga; om inte, upprepa processen (börjar med att få ett värde)

n

LD (IY+00H), C3H; annars, injicera en hoppkod i slutet av användarprogrammet

n

LD (IY+01H), 00H; hopp fungerar i princip som en programåterställning

n

LD (IY+02H), 00H; det är en fullständig återställning om registren ändras

n

JP 1000H; hoppa till och kör användarprogram

Rekommenderad: