Den Rational 1000 computer som Terma har doneret til Datamuseum.dk er underlig og jo mere man graver, jo underligere bliver den.
Når man kigger på en moderne computer, indeholder den en frygtelig masse tilpasningslag. F.eks udfører moderne CPU'er ikke de instruktioner der står i deres manualer, de oversætter dem til et internt instruktionssæt fordi det er den eneste måde at parallelisere de fundamentale begrænsninger, som f.eks antallet af registre. Det betyder at dem der skriver compilere skal tænke over ikke bare det instruktionssæt de skal producere kode med, men også den interne arkitektur af den CPU der skal udføre koden. Det er, for at sige det, noget rod.
Ca. en gang hver tiende år er der nogen der får nok af de "alt for komplexe instruktionssæt" og opfinder et "nyt simpelt instruktionssæt" og hvis det bliver en success, kommer marketingafdelingen snart og siger "Kunderne kræver en instruktion der kan ...".
Det skete for IBM's S/360, det skete for Intels x86, det skete for Motorolas 68K, det skete for MIPS, det er sket for ARM, det er i fuld gang for AMD64 og inden længe begynder det for RiscV.
De forsøg der har været på at starte med "fulkomne" eller "omfattende" instruktionssæt har langt hen ad vejen klaret sig bedre, i den forstand at de ikke er blevet meget værre og i større grad har bevaret deres orden og arkitektur hen ad vejen, her kunne man nævne Digitals VAX, CCI Power6/32 (aka "Tahoe") og lidt afhængig af om man kigger på det rå antal instruktioner eller på deres ortogonale arkitektur, hører 68K egentlig til her.
Der er også folk der har prøvet meget skæve ting, Intels iAPX432 var f.eks en (temmelig) objektorienteret arkitektur, og Linn (som i: Sondek grammofonen) byggede deres egen helt specielle "Numerik" processor lidt efter samme idegrundlag.
Helt ude i yderbanen finder vi så Rational 1000 computeren, der internt blev kaldt en "MISC" arkitektur: "Massive Instruction Set Computer". Ikke fordi den har pokkers mange instruktioner når det kommer til stykket, men de får en masse fra hånden.
Grunden til at vi ikke har kunnet finde nogen manual på instruktionssættet, er at det ikke blev anset for et supporteret interface, der findes simpelthen ikke nogen assembler til R1000. Computeren er bygget til at udføre Ada programmer og ada-compileren spytter de koder ud, som compiler-teamet har aftalt med mikrokode-teamet, instruktioner der så koncist som muligt kommunikerer hvad der skal ske.
Vi har dog fundet en disassembler i et binært kodesegment[1], for det kan debuggeren godt og så finder vi ud af at der f.eks er instruktioner der hedder:
Execute Heap_Access,Adaptive_Balanced_Tree_Lookup
og
Action Heap_Access,Diana_Put_Node_On_Seq_Type
Manglen på dokumentation af sådanne instruktioner gør det lidt op ad bakke at skrive en software emulator for en R1000 på normal vis.
Men vi har diagrammerne, vi har ihvertfald én version af nogle diagrammer, vi har mikrokoden, så må det i stedet blive en emulering på mikrokodeniveau.
Mikrokodefilen ligger som en fil i "I/O Controllerens" filsystem og indeholder hele mikrokoden, til alle kortene som en stor binær blob. Formatet er ikke dokumenteret, vi har lidt dokumentation på de individuelle korts mikrokode, men ikke på hvordan det er pakket i filen.
IOC'en er en 68020 service processor for hoved-cpu'en, den er ansvarlig for bootstrap og derefter sørger den for I/O til disk/tape/LAN osv.
Bootstrap foregår ved at mikrokoden downloades til den "diagnostic processor" der sidder på hvert kort via en multidrop RS-232 forbindelse.
Baseret på Karl Stenerud's "Musashi" emulator til 68K familien, har vi nu lavet en emulator for IOC'en og den kommer så langt at den kan download'e mikrokoden til en meget primitiv emulering af diag-processorne, så lad os tale lidt om dem:
På hvert af de bageplade-store printkort sidder der en 8052 microcontroller, som har fingrene i alt på kortet. Michael Druke, som designede hardwaren, kalder dem for hans "Diagnostic Archipelago", fordi de som en øgruppe i Stillehavet omringer hele kortet med testpunkter.
Og nej, det er ikke JTAG, denne design beslutning blev taget ca. fem år inden det Philips' Bleeker startede blev til JTAG i 1990 og JTAG har ikke nogen distribueret intelligens.
Diag-processoren kan bruges "in vivo" når kortet sidder i maskinen eller in vitro når man fejlsøger et enkelt kort på arbejdsbordet. Det sidste er specielt smart når hvert kort har fat i en håndfuld 64 bit brede busser.
I praksis foregår det ved at man downloader et "experiment" til 8052'eren, som fortolker byteværdierne som kommandoer.
Jeg behøver ikke sige at vi heller ikke har nogen dokumentation på det "instruktionssæt", vel ? [2]
Status lige nu er at jeg har gennemskuet den overordnede protokol imellem IOC og diag-8052'eren nok til at IOC'en tror den har download'et mikrokoden og det initielle indhold af registrene i R1000 CPU'en.
Ved hjælp af dette har jeg kunnet gennemskue hvilke bytes der går til hvilket kort og efter at have rodet med det nogle dage kan jeg nu producere plots som dette:
Der viser hvorledes mikroinstruktionerne til addition og subtraktition af floats hænger sammen.
De enkelte instruktioner ser f.eks således ud:
2860:
seq_cond_sel 0a VAL.ALU_LT_ZERO(late)
seq_en_micro 0
seq_latch 1
fiu_len_fill_lit 74 zero-fill 0x34
fiu_len_fill_reg_ctl 1 Load Literal Load Literal
fiu_load_oreg 1 hold_oreg
fiu_oreg_src 0 rotator output
fiu_tivi_src 4 fiu_var
typ_alu_func 1a PASS_B
typ_b_adr 16 CSA/VAL_BUS
typ_c_adr 3b GP 0x4
typ_c_mux_sel 0 ALU
val_a_adr 15 ZERO_COUNTER
val_alu_func 1a PASS_B
val_b_adr 05 GP 0x5
ioc_adrbs 2 typ
ioc_fiubs 1 val
ioc_tvbs 2 fiu/val
Så vidt jeg kan forstå situationen, så tror vores IOC emulator at R1000 CPU'en er startet og den prøver at sende et "svar" via den FIFO, hvor R1000 normalt beder om I/O operationer, for at downloade de første kodesegmenter til RAM, så R1000 CPU'en får noget at tygge på.
Et eller andet sted i mikrokodens 15444 instruktioner er der altså en bootloader af en art. Jeg håber at disassembleringen af download-programmet der kører på IOC'en giver et hint om hvor.
Det betyder også at noget af det første vi skal have implementeret er R1000's RAM lager og her er R1000 decideret genial.
I en almindelig computer, som f.eks en PC, arbejdet programmet i et "logisk addresserum" af en eller anden art.
Disse addresser oversættes fra "logiske" til "fysiske" addresser via en træ-struktur af tabeller ("page-tables") i RAM og først derefter kan man tilgå den faktiske lokation i RAM man gerne vil have.
Det er, for at sige det rent ud: Pissesløvt.
Det har det altid været, uanset hvem der har implementeret det og hvad enten de har lavet pagetabellerne den ene eller den anden vej.
For at fedte sig uden om langsomheden er der alle mulige caches involveret, ikke bare L1, L2, L3 og L4, men også "Page Lookaside Buffers" og meget andet gejl og selvom det er imponerende hvor hurtigt det faktisk går på moderne hardware[3], så er det stadig noget klamp og en permanent kilde til "side-channel" attacks.
Men det er faktisk værre end som så: En ting er den mapning mellem logiske og fysiske RAM addresser som kernen skal holde styr på, den skal også holde styr på mapningen mellem de fysiske RAM addresser og de tilhørende logiske filsystems addresser[4] og for at det ikke skal være løgn, skal den også holde styr på mapningen mellem de logiske filsystems addresser ("3. block i /bin/ls") og den fysiske addresse på disken ("sektor 0x194240-194243").
R1000 har droppet alt det skrammel og har i princippet ikke noget RAM lager som vi kender det, men kun et L1 Cache og hvis der ikke er plads der, må det ud på disken - og det hele kører i logiske addresser.
Programmet arbejdet i et segment, det har et nummer, det nummer er første sektor disken.
Når programmet prøver at læse eller skrive en lokation i segmentet, sendes en 67bit bred addresse afsted, indeholdende segmentet, segmentets type, sidenummeret (= sekventielle sektornumre), hvilket 128bit ord i siden og hvilket bit i dette 128bit ord.
Ram kortet har som alle andre cache's et "tag" og et "data" store hvor tag-store ved hvad det faktisk er der ligger i data-store.
Dengang Intel lancerede deres første 2104 dynamiske RAM, på hele 4096x1 bits, havde de et problem: Med 12 adresseben, 3 forsyningsspændinger, GND, CE, WR og Data-in og Data-out skulle der bruges et 20 bens hus og det havde Intel ikke udstyr til.
Men fordi selve RAM'array'en er todimensional skal den faktisk ikke bruge alle 12 addressebits til at begynde med, først skal den bruge 6 til at vælge "række" og først senere skal den så bruge de andre 6 til at vælge "kolonne" og derfor kan addresserne multiplexes på kun 6 ben uden at der spildes nogen tid.
Michael Druke's genistreg er at give DRAM'chippene den del af addressen der er indenfor en side først, og samtidig slå op i et lille hurtigt statisk RAM "tag-store" der kunne nå at levere den 'variable' del af addressen inden RAM chippene skal bruge den.
Nettoresultatet er at hele baladen med at oversætte fra logiske til fysiske addresser ingen tid tager: RAM kortets cache funktion gør det samtidig med at RAM chippene laver første halvdel af deres interne arbejde.
Det er simpelthen ufatteligt smart gjort og man kan kun begræde at vi idag lever i det kvantebukseben, hvor det er helt utænkeligt at gøre det igen, fordi alle operativsystemer har "nogle millioner" linier kode for meget til at køre på så smart hardware.
Ohh well...
phk
PS: Ja, der kommer en opdatering om datamuseum.dk så snart vi har noget at fortælle :-/
[1] Et herligt eksempel på "bootstrapping" :-)
[2] Vi krydser fingre for at et af kortene i reservedelsbunken har en 8052 der ikke er maskeprogrammeret, så vi kan læse programmet ud.
[3] Hvilket minder mig om at jeg skal have skrevet om vores ESO projekt.
[4] Filsystem kan i den forbindelse godt være en swap-paritition, kernen skal stadig holde styr på hvor ting havner.
