Keri sisuni

Kuidas lugeda/kirjutada JUKU ketaste tõmmiseid?

Aastal 2022 ei olnud veel dokumenteeritud, millega ja kuidas lugeda JUKU kahepoolseid flopisid ja huvilised katsetasid kettatõmmiste lugemist eri tööriistadega, saavutades mõnedega neist osalist edu. Allolev on kogemuslugu sellest, kuidas võtsin kätte ja närisin end läbi JUKU flopiketta andmevormingust, mida selle käigus õppisin ja pidasin vajalikuks avalikkusega jagada. Lugu on täiendatud üldistava raamistuse, täpsemate arvutuste ja praktiliste soovitustega lõpuosas.

JUKU 786/788 kB kettad on kahepoolsed topelttihedusega (DSDD) kettad, millel on kummalgi poolel 80 rada, mis on jaotatud 40 sektorisse, millest igaüks mahutab 128 baiti. See teeb kokku 2x80 = 160 rada, 40x128 = 5120 baiti ehk 5 kB ja kokku ketta suuruseks 160x5120 = 819 200 baiti ehk 819 kB. Lugemise teeb keerukaks, et need baidid pole talletatud sisu mõttes mitte järjest, vaid "segamini paisatud". Seetõttu ei või seda võtta järjestikuse 819 kB andmekogumina ja selle osiste olemasolu ignoreerida, vaid tuleb segadus selle eri taseme põhjusest lähtuvalt likvideerida.

Töö teevad ära cpmtools ja libdsk käsikäes ning vajalikud konfifailid on:

  • diskdefs (võib käia nt /etc/cpmtools või /usr/local/share alla)
  • libdskrc (võib käia nt /usr/local/share/LibDsk alla või kodukataloogi kujul .libdskrc)

Aga huvilistele ka veidi pikemalt köögipoolest...

FDMAINT DEC Rainbow 100
FDMAINT ketast kontrollimas, väljast sisse ja üks pool korraga DEC Rainbow 100 manuaal

JUKU jaoks fundamentaalsel opsüsteemi tasemel lähtutakse CP/Mi 128-baidisest sektorisuurusest, mis tähendab, et rajad on kettal jagatud 40 sektorisse ja iga rada on 40x128 = 5120 baiti. Füüsilisel JUKU flopil on rajad aga jagatud 10 sektorisse, mille kaupa arvutatakse ja kirjutatakse tegelikule füüsilisele kettale andmete kontrollsummad. See tähendab, et füüsilisel kettal on CP/Mi 128-baidised sektorid omakorda koondatud neljakaupa 512 baidistesse sektoritesse, st raja maht on 10x4x128 = 10x512 = 5120 baiti. Kuna andmete kodeerimine/dekodeerimine flopi magnetpinnalt on korraldatud riistvara tasemel, siis ei pea andmetõmmiste töötlemisel füüsilise flopiketta omadustele tähelepanu pöörama ning võib piirduda opsüsteemi tasemel kättesaadava andmete vorminguga.

Kasutusel oleva CP/Mi failisüsteemi loogilise ploki suurus on 4096 baiti, igasse sellisesse plokki mahub 32 sektorit, loogilisi plokke mahub kogu ketta mahu sisse 819200/4096 = 200. Ketta kaks esimest rada on reserveeritud süsteemi buutimiseks ja seetõttu jääb loogiliste plokkide jaoks reaalselt 819200 - 2x5120 = 808 960 baiti, mis mahutab 808960/4096 = 197,5 loogilist plokki, mis oleks kokku 197,5x4096 / 1024 = 790 kB. Poolikut loogilist plokki kettale kirjutada pole tark mõte ja kuna esimene loogiline plokk on kasutusel kataloogiplokina, siis tegelike failide jaoks kasutatavaid plokke mahub kettale 196. Seega on JUKU ketta tegelik kasutatav maht 196x4096 = 802 816 baiti, mis on omakorda 802816/1024 = 784 kB. Kuna loogilise ploki maht on 32x128 = 4096 baiti ja füüsilise raja maht on 40x128 = 5120 baiti, siis isegi kui üks on neist on lihtsalt 4 kB ja teine 5 kB, siis kettaga toimetamise eri tasmetel eri ühikutega opereerimine muudab üldpildi kettatõmmiste töötlemisel segaseks ning teeb keerukamaks andmete struktuuri tuletamise nende sisust.

JUKU ketaste spetsiifiline topeltsegadus

JUKU EKDOS 2.30 lähtekoodi päises on dokumenteeritud rasvases kirjas, et ketta formaadi aluseks on DEC Rainbow 100 flopiformaat. Lähtekood annab ka teada ülejäänud juba mainitud parameetrid:

; DPB constants for 5" 96 TPI DSDD diskettes (2x80 tracks):
TRACKS  EQU 160 ; 5"DD
BLKSIZ  EQU 4096    ; block length
DIRTRK  EQU 2   ; directory track # (3 if 5"SD)
BLOCKS  EQU 197 ; (TRACKS-DIRTRK)*CPMSPT/(BLKSIZ/128)-1
DIRENT  EQU 128 ; directory entries
DIRCHK  EQU 20H

Need vastavad üldjoontes ülal tehtud arvutustele, kuigi kommentaaris toodud tehte (TRACKS-DIRTRK)*CPMSPT/(BLKSIZ/128)-1 tulemuseks oleks tegelikult 196,5, millest on justkui ümardamise teel saadud 197. Koodis kasutatud väärtus on küll korrektne, aga selgituseks toodud tehe võib olla põhjuseks, miks toob opsüsteem JUKU flopiketta kasutatavaks mahuks 786 kB, sest 196,5x4096 = 804864 baiti, mille järel 804864/1024 = 786 kB. Reaalsuses mahub aga JUKU flopile kas 784 kB jagu faile või 788 kB jagu loogilisi plokke koos kataloogiplokiga. Lisanduv poolik loogiline plokk on opsüsteemile kättesaadav ja seega pole avakraanil toodud osutused 786 kB ketastele otseselt valed, aga ei JUKU enda ega CP/Mi tarkvara ei suuda üldiselt fantoomploki 2048 baidiga korrektselt ümber käia ning parimal juhul saab seda kasutada salajaste sõnumite talletamiseks.

Kuna JUKU flopid ei ole andmete keerulise struktuuri tõttu loetavad tavapäraste CP/Mi andmetõmmiste töötlemise tööriistade jaoks, siis tasub panna tähele, et juba DEC Rainbow 100 on ajalooliselt tunnustatud peavalu, sest selle paisktabel ei ühildunud teiste tootjate standarditega. JUKU kasutab/viitab Rainbow kettaformaati ilmselt pigem juhuslikel põhjustel või kuna selle kettalugeja ühendas kaks ühepoolset kettalugejat ning sobis seega teatud määral koodidoonoriks -- igatahes JUKU paisktabel tundub peale vaadates veel omal moel eksootiline ja on samuti leitav lähtekoodist:

; *** Sector translate vectors, two 40 byte areas ***
;
TRANS:  DB  1,2,3,4,9,10,11,12
    DB  17,18,19,20,25,26,27,28
    DB  33,34,35,36,5,6,7,8
    DB  13,14,15,16,21,22,23,24
    DB  29,30,31,32,37,38,39,40
;
TRANS1: DB  1,2,3,4,9,10,11,12
    DB  17,18,19,20,25,26,27,28
    DB  33,34,35,36,5,6,7,8
    DB  13,14,15,16,21,22,23,24
    DB  29,30,31,32,37,38,39,40 

Kui lähemalt vaadata, siis on näha, et selline paisktabel ehk skew table koosneb tegelikult neljastest plokkidest nagu 1,2,3,4 või 33,34,35,36 ja tabeli lihtsustatud väljendus oleks õigupoolest 1,3,5,7,9,2,4,6,8,10. Selline oleks paisktabel, kui see määratleda lähtuvalt JUKU flopide 4x128 = 512-baidistest füüsilistest sektoritest. See tähendab, et sektoreid iga üksiku raja kohta loetakse nii, et esmalt loetakse paarituarvulise järjekorranumbriga ja siis kõik paarisarvulise järjekorranumbriga 512-baidisteks ühendatud sektorid, millest kumbagi on raja kohta viis. Sellist järjest lugemise vältimist oli omal ajal väidetavalt vaja, et arvutid kettalt tulevaid andmeid ikka töödelda jõuaks ja puhvrid ei hakkaks üle ajama:

"Standard CP/M systems are shipped with a skew factor of 6, where six physical sectors are skipped between each logical read operation. This skew factor allows enough time between sectors for most programs to load their buffers without missing the next sector. In particular computer systems that use fast processors, memory, and disk subsystems, the skew factor might be changed to improve overall response."

Pole teada, kas sellist aeglustamist oli JUKU flopiseadmete puhul reaalselt vaja, aga tänapäeva mõistes on ilmselt tegu tarbetu abinõuga ning seetõttu ei tee me kindlasti midagi halba, kui paisktabelit loetavuse mõttes lihtsustame. Küll aga ei piisa, kui söödame oma lihtsustatud või ka lihtsustamata paisktabeli cpmtools'ile, sest kuigi ketta algus loetakse enam-vähem, siis esimestest failidest edasi läheb kõik juba parajaks segapudruks.

Kui seda valminud putru lähemalt vaadelda, selgub et JUKU kettaformaadil veel teine standardist hälbiv iseärasus, mis ei seostu üldse paisktabelitega ja muudab kettad tavalisi CP/Mi kettalid lugevatele tööriistadele arusaamatuks. Nimelt kirjutatakse JUKU ketta ühe poole rajad täis ja siis minnakse teise poole radu kirjutama uuesti algusest, st ketta teisest servast. Tavapärane on kirjutada radu kordamööda ühele ja teisele poolele või hakata rajanumbritega ühte kettaserva jõudes nendega teiselt poolelt tagasi tulema. Seega on JUKU flopidel tavapäraste ketaste suhtes segadus kahes mõttes, esiteks paisktabeli tõttu ja teiseks radade paigutuse tõttu kettal. Ette rutates võib ütelda, et algse hüpoteesi kohaselt kurja juureks oletatud paisktabel osutub radade segaduse lahendamise järel õigupoolest täiesti standardseks.

Millega ja mispidi neid siis lugeda?

Tegelikult cpmtools koos libdsk'i kettaseadetega loeb JUKU diskid edukalt välja. Mõlemad on olemas kõigile viisakatele tänapäeva opsüsteemidele, aga peab veenduma, kas cpmtools'i seadetes ehk ülal viidatud diskdef failis saab viidata libdsk'i seadetes määratletud .libdskrc kirjetele. Sisuliselt on vaja teha kahte asja:

  1. Tuleb .libdiskrc failis määratleda kettatõmmis kui kahe lugemispeaga loetav, st parameeter heads = 2 ja silindrite arvuks määrata ühe poole radade arv cylinders = 80. Kettapooltele kirjutatavate radade järjekorra kohta peab ütlema, et neid kirjutatakse ketta väljast sissepoole liikudes järjest ning kui üks pool saab täis, siis jätkatakse teise poolega uuesti väljast sissepoole ehk parameeter sides = outout. Kettatõmmise tüübi nimeks määrame JUKU ehk paneme pealkirjaks [juku].

  2. Tuleb cpmtools'i diskdefs failis määratleda sobiv radade ja sektorite arv, määratleda eriotstarbelised rajad nagu süsteemile määratud kaks rada parameetriga boottrk 2 ja failide asukohti kettal kirjeldav rada parameetriga maxdir 128. Ütlasi tuleb diskdefs failis osutada, et kasutataks libdsk'i geomeetriat kettapoolte lugemiseks ning seda teeb parameeter libdsk:format juku. Siin tuleb nüüd määratleda ka paisktabel ja seda on võimalik määratleda EKDOSi lähtekoodi viisil või lihtsustada nii, nagu ülal osutasin.

Kui alustuseks vaadata JUKU enda utiliite, siis need näitavad ketta eri parameetreid samuti üpris erinevalt:

STAT KULT DOCTOR
STAT näitab 40 sektorit raja kohta KULT näitab ka paisktabelit Software Soulutions DISK EDITOR & DIAGNOSTICS annab kõige põhjalikuma ülevaate (aga ei erista 32 baidiseid plokke)

JUKU CP/Mil põhinevale 128-baidisele sektorisuurusele truuks jäädes peaksime määrama .libdiskrc failis parameetrid ilmselt nii:

[juku-origin]
description = JUKU E5101 5.25" DSDD (2 x 80 x 40 * 128)
sides = outout
cylinders = 80
heads = 2
secsize = 128
sectors = 40
datarate = DD

Samamoodi austades algset paisktabelit peaks olema diskdefs kirje (küll tuleb tabeli väärtused muuta nullist algavaks):

# JUKU E5101 original (DEC Rainbow 100 feat DSDD)
diskdef juku-origin
  seclen 128
  tracks 160
  sectrk 40
  blocksize 4096
  skewtab 0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27,32,33,34,35,4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31,36,37,38,39
  boottrk 2
  maxdir 128
  os 2.2
  libdsk:format juku-origin
end

Kui lihtsustame aga paisktabeli ja ühendame CP/Mi 128-baidised sektorid neljakaupa üheks 512-baidiseks füüsiliseks sektoriks, siis peaks sobima vastavalt:

[juku]
description = JUKU E5101 5.25" DSDD (2 x 80 x 10 * 512)
sides = outout
cylinders = 80
heads = 2
secsize = 512
sectors = 10
datarate = DD

Ja cpmtools'i diskdefs lühendatud paisktabeliga on lõpuks ketta poolte lugemise segaduse eemaldamise järel täiesti tavaline paiskfaktor väärtusega 2 ehk skew 2:

# JUKU E5101 \w optimized skew (DEC Rainbow 100 feat DSDD)
diskdef juku
  seclen 512
  tracks 160
  sectrk 10
  blocksize 4096
  skew 2
  #skewtab 0,2,4,6,8,1,3,5,7,9
  boottrk 2
  maxdir 128
  os 2.2
  libdsk:format juku
end

Kuna cpmtools'i kõik versioonid kõigi libdsk'i versioonidega praktikas ei ühildu, siis pole välistatud ka libdsk'i seadistustes määratletud geomeetria ignoreerimine, aga sel juhul võiks saada näiteks kirjeldada kõik sektorid ja plokid ühel rajal üheainsa suure paisktabelina. Selline häkk teeks tabeli umbes 160x10x4 ≈ 6 kB pikkuseks, mis ei ole küll tänapeäva mõistes päris maailmalõpp, aga cpmtools ei pruugi vaikimisi nii pikka tabelit seedida. Libdsk'i seadistamisel võiks doonoriks sobida ka mõne acorn flopi geomeetria, mis on üks väheseid, milles outout lugemisviis kasutusel olla olnud (vt "used by some Acorn formats [and JUKU]"). Lõppeks võib lihtsaim viis Gordioni sõlme raiumiseks olla, kui teha elementaarsed muudatused otse cpmtools'i lähtekoodi ja kompileerida see ise.

Lõppseis ja töö viljad

Lõpptulemus näeb cpmtools'i fsed.cpm -f juku-origin ORIG.CPM ekraanil välja nii:

Info (I) Datamap (M) Kataloogikirje (0x5000)
JUKU E5101 algupärase laotuse infotabel Algupärase laotuse andmekaart Ketta sisu peaks aga algupärase/optimeeritud versiooni puhul juhul sama olema

Ühtlasi peaks töötama kõik cpmtools'i käsud, millega brausida ketaste sisu ning teha failioperatsioone kopeerimisest kustutamiseni:

cpmls -f juku DISK.CPM
cpmls -f juku -licF DISK.CPM
cpmcp -f juku GAMES.CPM 0:*.* jukugames
cpmcp -f juku GAMESX.CPM jukugames/INDY.* 0:

Kui määrata juku keskkonnamuutujas CPMTOOLSFMT vaikimisi formaadiks, siis võib -f juku ka ära jätta:

CPMTOOLSFMT="juku"
export CPMTOOLSFMT

Toetatud kettatüüpide ja -vormingute nimekirju libdsk'i poolel näitavad dskutil -types ja dskutil -formats, cpmtools lubatud formaatide nimekirja ei paista väljastavat ja nendega tuleb tutvuda diskdefs seadistusfaili tasemel. Õigupoolest on JUKU ketaste lugemiseks täiendavate libdsk'i vahenditeta vaja cpmtools'i lähtekoodi täiendada vaid ühe reaga kahes funktsioons, mis juhendaks neid otsima radu kettatõmmisel õigest kohast ja sellise täiendusega CpmtoolsGUI eksperimentaalse JUKU versiooni leiab siit.

Alates 2025. aasta juulist suudab aga lisapingutusteta töödelda JUKU kettaid ka Fluxengine'i arendusversioon.

On küll mõnevõrra tüütu kaevuda ajalooliste kettaformaatide iseärasustesse, kuid mõningase pusimise ja loomkatsete tulemusel saab ka maailma kõige unikaalsema CP/Mi kettaformaadi loetud. JUKU tunnustuseks võib ütelda, et tõenäoliselt pole kunagi eksisteerinud ühtegi teist arvutisüsteemi, mis oleks ilma pusserdamiseta JUKU kettaid suutnud lugeda -- seega kaksteist punkti ja ugrikrüpto eriauhind teadurile, kes selle vormingu välja mõtles!

P. S. Füüsilistest ketastest tõmmiste tegemine on ka huvitav, aga eraldi kirjatükki vääriv teema.