CoBra - Sistem de operare CP/M cu 80 caractere pe linie afişate simultan

1. Modul de instalare a sistemului de operare



Prima dată cînd mi-a ajuns în mînă acest sistem de operare, a fost în două variante, fiecare sub forma a două fișiere CP/M: Ambele metode de instalare a sistemului expuse mai sus produc un sistem „virusat”, care va lua cu asalt directorul discului și-l va face ferfeniță la orice eroare de tip BAD SECTOR, READ ID DENSITY etc., dacă bineînțeles discheta nu este WRITE PROTECT ! În plus, după această ispravă, sistemul încărcat în memorie se va bălări iremediabil, astfel încît va fi necesară reîncărcarea lui de pe alt disc. Aceasta deoarece generatorul de sistem a fost probabil copiat la origine de pe o dischetă protejată la copiere, rezultatul fiind o copie „infestată”.

Marea „găselniță” care face acest sistem de operare foarte interesant este că afișează 80 de caractere pe linie vizibile simultan, folosind o mică modificare hardware în schemele CoBra, modificare a cărei schemă mi-a parvenit odată cu cele două executabile de instalare. Modificarea inițială conținea doar cîteva diode și trebuia acționată manual, cu un comutator care schimba între configurația schemelor originale și configurația modificată pentru afișarea unui ecran text extins (mai lat decît zona SCREEN a unui Spectrum 48 standard). Doi prieteni cu care stăteam în cămin pe vremea respectivă (Traian Onciu și Dan Teodorescu) - asta după cîte-mi spune Traian că-și aduce acum aminte - s-au apucat și au adus o mică modificare executabilului SY80CHR.COM, și au reproiectat schema circuitului modificării, înlocuind diodele și comutatorul cu porți logice și un multiplexor. Rezultatul a fost că sistemul nu mai necesita comutare manuală între configurația hardware de afișare standard și cea de afișare extinsă, ci aceasta se făcea automat la lansarea sistemului. Totuși problema cea mare a rămas în continuare, sistemul era tot „periculos” de folosit întrucît ștergea discheta sistem oricînd îl apuca damblaua.

Întrucît problema nu mi-a convenit, am încercat și reușit să studiez (prin dezasamblare) codul din executabilul SY80CHR.COM „îmbunătățit” de cei doi prieteni și să-l modific pentru a elimina „capcana”. Am obținut astfel un program de instalare sistem complet „devirusat” precum și „automatizat”. Am salvat executabilul astfel „deprotejat” cu numele SY80CAT+.COM.

În consecință, instalarea acestui sistem CP/M se poate face prin rularea executabilului SY80CAT+.COM, urmată fie de copierea fișierului CBOT.SYS pe discul făcut sistem, fie de rularea executabilului MDC80CHR.COM care să copieze utilitarele de bază pe discul făcut sistem.

O observație importantă: pentru a rula un executabil CP/M fără erori, mărimea fișierului executabil trebuie să fie mai mică decît mărimea maximă a zonei TPA permisă de sistem. Pentru versiunea de CP/M cu care voi lansa executabilele SY80CAT+.COM (22 KB) și MDC80CHR.COM (42 KB) maximul de memorie TPA este de 58 KB, deci nu vor fi probleme.

În continuare am să descriu modul de instalare a acestui sistem CP/M folosind executabilele SY80CAT+.COM și MDC80CHR.COM (MDC80CHR.COM nu e „virusat” în nici un fel, nu prezintă probleme, nu face altceva decît să copieze utilitarele de bază pe disc avînd grijă să scrie D.COM cu codul de CP/M Loader la sfîrșit în poziția necesară pe disc).

1:

Am lansat sistemul CP/M versiunea CHRIS INSTALL cu 40/64 caractere vizibile simultan.

2:

În continuare am tastat comanda de lansare a programului de instalare sistem în pistele 0 și 1.

3:

După un ENTER, apare un mesaj care solicită specificarea unității destinație pentru instalare.

4:

Deoarece mesajul iese din fereastra vizibilă de 40 de coloane text, pagina video se schimbă automat, afișîndu-se jumătatea din dreapta a ecranului virtual de 80 de coloane cu restul mesajului.

5:

Pentru a obține o afișare mai coerentă, am apăsat tasta GRAPH NORM, care schimbă numărul de coloane text vizibile din 40 în 64, reușind să încadrez tot mesajul în porțiunea vizibilă a ecranului text virtual.

6:

În continuare am încercat să specific unitatea destinație prin codul numeric al unității fizice. Vreau să instalez sistemul pe discul prezent în unitatea 3. Dar programul protestează că vrea să i se precizeze codul unității logice (A:, B:, C: sau D:)

7:

Așa că apăs și eu tasta D, întrucît unitatea fizică 3 corespunde unității logice D:. După care programul cere apăsarea tastei ENTER, după ce discheta destinație este introdusă în unitatea D:.

8:

După copierea sistemului în pistele sistem, se așteaptă repetarea operației prin precizarea din nou a unității destinație, sau terminarea prin apăsarea tastei ENTER.

9:

Apăs ENTER și ies din program.

10:

Apoi tastez numele executabilului care instalează utilitarele de bază cu tot cu CP/M Loader.

11:

Și apăs din nou tasta GRAPH NORM pentru a obține o afișare mai clară.

12:

După un ENTER apare un mesaj de start și programul cere din nou precizarea unității destinație.

13:

Conform lecției învățate, apăs tasta D, și apoi programul cere introducerea dischetei în unitatea D după care așteaptă confirmarea cu un ENTER.

14:

După terminarea copierii, programul întreabă dacă se dorește repetarea operației.

15:

Apăs N și ies din program înapoi la promptul CP/M.


2. Descrierea sistemului de operare



Acest sistem (în forma lui originală) este rulabil NUMAI de pe unitățile fizice 2 și 3. Mai exact, dacă se folosesc unități de disc dublă densitate, nu vor putea fi folosite cu acest sistem de operare decît ca unități fizice 2 și/sau 3. Unitățile fizice 0 și 1 sînt presupuse a fi simplă densitate, cu alt număr de sectoare pe pistă. Codul din BOOT ROM știe să încarce sistemul CP/M de pe orice unitate fizică (0-3), dar sistemul în sine, odată încărcat, nu va putea accesa discul de pe care a fost lansat decît dacă unitatea fizică respectivă are densitatea corespunzătoare (unitățile 0, 1 SD, unitățile 2, 3 DD).

Încărcarea lui se face din codul standard de BOOT CoBra în configurația hardware de 80 KB RAM, prin apăsarea tastei D.

Secvenţa de pornire a sistemului, aşa cum este afişată pe ecran la apăsarea tastei D din configuraţia de pornire, arată cam în felul următor:
(plimbaţi mouse-ul peste coloana din stînga, de sus în jos şi urmăriţi imaginea mare din dreapta)

1:

2:

3:

4:

5:


Pentru o înţelegere a funcţionării afişării extinse din punct de vedere hardware, citiţi paragraful cu descrierea acestei modificări din pagina cu comentarii funcţionale ale plăcii de bază. Practic sub acest sistem de operare se extinde porţiunea standard de SCREEN Spectrum la stînga şi la dreapta cu 4 caractere standard Spectrum. Asta înseamnă o porţiune suplimentară de 4 x 8 = 32 pixeli pe orizontală, la stînga şi la dreapta, în detrimentul porţiunii de BORDER. Astfel rezoluţia utilă afişabilă devine de 256 + 32 + 32 = 320 pixeli pe orizontală şi aceiaşi 192 pixeli pe verticală ca la un Spectrum standard. Deci 320 x 192 pixeli. Iar asta, în combinaţie cu folosirea unor caractere condensate de 4 x 8 pixeli permite un ecran text de 320 / 4 = 80 caractere pe linie si 192 / 8 = 24 linii, deci un ecran text de 80 x 24 caractere afişabile simultan pe ecran. Pentru o ilustrare concretă redau mai jos un snapshot obţinut după rularea programului CU.COM (CoBra Utilities) cu care am modificat culoarea BORDER-ului şi a fondului şi caracterelor afişate, pentru o reprezentare clară a posibilităţilor de afişare:


Se observă lăţimea mult mai redusă a porţiunii de BORDER din stînga şi din dreapta, comparativ cu afişarea standard Spectrum din imaginea de mai jos:


Un amănunt interesant: caracterele afişate în zona extinsă sînt stocate în jumătatea superioară a memoriei video care are mărimea de 16 KB. Dar întrucît este vorba doar de cîte o porţiune de cîte 4 caractere standard Spectrum la stînga şi la dreapta zonei SCREEN standard a Spectrum, această jumătate este ocupată doar partial. Datele afişate ocupă segmente de cite 8 octeti separate de spaţii libere de cîte 24 octeţi. În aceste spaţii libere, sistemul este astfel conceput încît stochează o copie integrală a CCP, iar la ieşirea dintr-un program CP/M tranzitoriu, în loc să mai acceseze discul pentru a citi şi readuce componenta CCP în memorie, o readuce prin copiere din memoria video. Discul este astfel accesat mai puţin, reducînd uzura dischetelor. Felicitări Marcel Arefta pentru această găselniţă superbă la CP/M !

BIOS-ul este scris astfel încît consideră unităţile fizice 0 şi 1 ca fiind unităţi de 8" SSSD (26 sectoare a cîte 128 octeti pe pistă) iar unităţile 2 şi 3 unităţi de 5.25" (sau 3.5") DSDD 720K. Întrucît unităţile de 8" sînt practic inexistente în ziua de azi, asta înseamnă că singurele unităţi fizice cu care poate funcţiona acest sistem sînt 2 şi 3.

În afară de asta este conceput astfel încît dacă se încarcă sistemul de pe unitatea 2, aceasta devine unitate A: (în loc de C:, cum ar fi normal) iar litera C: este atribuită unităţii fizice 0.

Asta inseamnă că, deşi programul de BOOT poate încărca sistem de pe orice unitate (0, 1, 2 sau 3), dacă se folosesc doar unităţi de 5.25 sau 3.5" de 720K nu se va putea încarca sistemul decît de pe unitatea 2 sau 3. Mai mult, nici dupa încărcarea sistemului nu se vor putea folosi unităţile 0 şi 1 întrucît sistemul se aşteaptă ca ele să fie unităţi simplă densitate de 8".

Din acest motiv, în prezent am hotărît să modific sistemul, după cum am descris în continuare mai jos, cu trei scopuri:

3. Identificarea şi dezasamblarea componentelor: CCP, BDOS, BIOS



Punctul de plecare în analiza sistemului de operare CP/M este rutina de încărcare sistem de pe disc aflată în BOOT ROM. Prin analiza ei am aflat cum decurge încărcarea sistemului de pe disc de la zero.

Procesul de încărcare a acestei versiuni de CP/M are următorii paşi:
  1. La apăsarea tastei D din configuraţia de BOOT, rutina de încărcare CP/M din BOOT ROM caută pe disc un sector ascuns care conţine o secvenţă de cod denumită "CP/M Loader". O încarcă în memorie la adresa $FC00 şi o lansează în execuţie.

    Ca să intru în detalii, algoritmul de localizare a CP/M Loader-ului pe disc este următorul: (se poate afla prin studierea codului dezasamblat de BOOT ROM 80K)

    1. Se citesc primele 64 înregistrări (intrări, records) din directorul discului în memorie, adică primii 2KB ai directorului;
    2. În aceste înregistrări se caută primul fișier cu număr utilizator 0 și extensia SYS, unde cei 3 octeți ai extensiei pot avea bitul 7 setat sau nu ($53, $59, $53 sau $D3, $D9, $D3). Pe dischetele din arhivă acest fișier este denumit CHRIS.SYS sau Kryss.SYS, unde octeții extensiei au bitul 7 setat, adică extensia nu e afișabilă;
    3. Dacă fișierul este găsit, i se citește prima adresă de bloc alocat pe disc, s-o notăm cu B. Ambele fișiere, CHRIS.SYS și Kryss.SYS, au în înregistrarea din director o singură adresă de bloc, care este $0007, deci B=7;
    4. se calculează o adresă absolută de sector ca fiind Sect# = (B * 8) + 1 = 57;
    5. Se folosește ca număr de sectoare pe pistă 36;
    6. Se calculează un număr de pistă ca fiind Trk# = Sect# DIV 36 + 2 = 3 (unde prin DIV am notat operatorul de împărțire cu rezultat întreg);
    7. Se calculează un număr de sector pe pistă ca fiind Sec# = (Sect# MOD 36 - 1) DIV 4 + 1 = 6;
    8. Se translatează numărul de sector pe pistă folosind o tabelă de translatare (1 5 9 4 8 3 7 2 6) și se obține Sec# = 3;
    9. Se citesc de pe disc în memorie la adresa $0000 sectoarele: Sec# de pe pista Trk# fața 0 și Sec#+1 de pe pista Trk#+1 fața 0;
    10. Se face un salt la adresa $0000 lansîndu-se în execuție codul din sectoarele citite, care se așteaptă să conțină codul de CP/M Loader.

    Dacă se studiază alocarea pe disc, se constată că sectorul 3 de pe pista 3 fața 0 este ultimul sector al ultimului bloc (blocul $0004) alocat fișierului D.COM, iar zona de date a acestui fișier se termină înainte de ultimele 3 sectoare ale ultimului bloc. Blocul $0004 conține sectoarele 6, 8 de pe pista 2 fața 1 și sectoarele 1, 3 de pe pista 3 fața 0, iar conținutul fișierului D.COM se termină în sectorul 6 de pe pista 2 fața 1. Din această cauză se poate spune că sectorul 3 de pe pista 3 fața 0 este un sector „ascuns”, întrucît el este „oficial” alocat fișierului D.COM, dar de fapt conține altceva decît octeții acestui fișier.

    Întregul algoritm nu este altceva decît o mare mînăreală ciobănească, întrucît mărimea blocului folosit în calcul (1KB) este greșită (blocul folosit pe dischetele DD este de 2KB) și de asemenea numărul de sectoare pe pistă folosit (36) este și el greșit (dischetele DD au 9 sectoare pe o față de pistă). Pentru a face mînăreala să funcționeze, s-a ales 7 ca număr de bloc alocat pentru fișierul Kryss.SYS care de fapt are lungime zero și există doar ca o intrare în director, astfel ca rezultatul algoritmului să fie sectorul 3 pista 3 fața 0, adică exact zona unde generatorul acestui sistem a scris ultimul bloc al fișierului D.COM atunci cînd sistemul a fost instalat. Dacă fișierul D.COM (și el evident mînărit ca să facă toată cretineala asta să funcționeze) ar fi înlocuit cu versiunea originală așa cum a fost scrisă de Digital Research, sistemul nu s-ar mai putea încărca de pe disc. Evident, toată mascarada are ca scop ascunderea cu orice preț a codului de CP/M Loader pentru utilizatori „neinițiați”.

    Partea interesantă e că la origine sistemul CP/M CoBra fusese conceput să funcționeze cu CP/M Loaderul salvat pe disc ca fișier independent, absolut ne-„mînărit” și perfect copiabil și studiabil de către oricine. Fișierul era denumit LK.SYS și pentru a funcționa trebuie să fie primul fișier copiat pe discul sistem, adică să fie scris în blocul 2, care este primul bloc disponibil pentru alocare fișiere. Dacă în algoritmul de mai sus folosim 2 ca număr de bloc, vom obține Trk# = 2 și Sec# = 8. Iar sectorul 8 de pe pista 2 fața 0 este chiar primul sector alocabil de pe disc, deci algoritmul funcționează corect și pentru un CP/M Loader salvat ca fișier standard pe disc în primul sector alocabil.

    De fapt, prima metodă de instalare a acestui sistem CP/M descrisă la început (cu fișierele AMTISYS.COM și CBOT.SYS) chiar asta face, întrucît fișierul CBOT.SYS conține chiar CP/M Loader-ul acestei versiuni de sistem, ca fișier standard copiabil pe disc.

  2. "CP/M Loader"-ul încarcă de pe disc în memorie toate sectoarele pistelor sistem, în ordinea lor fizică (pista 0 faţa 0, pista 0 faţa 1, pista 1 faţa 0, pista 1 faţa 1). Ele sînt incărcate începînd cu adresa $0000. După ce toate sectoarele au fost încărcate, se face un salt la adresa $0000, adică se lanseaza în execuţie codul conţinut în primul sector de pe disc (pista 0 faţa 0 sector 1). Acesta se numeşte "Boot Sector".
  3. Codul conţinut în "Boot Sector" mută componentele sistemului (CCP, BDOS, BIOS) la adresele la care ele trebuie rulate în mod normal şi apoi face un salt la rutina WBOOT din BIOS, iniţializînd astfel sistemul.

CP/M Loader - codul dezasamblat

Boot Sector - codul dezasamblat


În momentul în care am început acest proiect, am avut la dispoziţie o arhivă cu toate dischetele de 3.5" folosite de mine cu CoBra pe vremea respectivă, şi pe care prin '95-'97 am avut fericita inspiraţie să le copiez cu Teledisk şi să stochez imaginile astfel obţinute pe un CD cu date. Aceste dischete de 3.5" rămăseseră în ţară cînd am plecat, dar am luat cu mine toate dischetele de 5.25" folosite cu CoBra. Deci am pornit proiectul cu imaginile Teledisk ale dischetelor de 3.5" si cu dischetele fizice de 5.25".

Cinci din dischetele de 3.5" erau dischete cu utilitare de CP/M, şi pe care le făcusem la vremea respectivă dischete sistem (bootabile) cu acest sistem cu 80 caractere pe linie. Aşa că am luat programul SAMdisk şi cu el am extras în mod text pistele sistem (0 şi 1, ambele feţe) din imaginile UTILS1.TD0, UTILS2.TD0, UTILS3.TD0, UTILS4.TD0, UTILS5.TD0, folosind succesiunea de comenzi (din Linux, în bash):

> wine SAMdisk.exe view UTILS1.TD0 -c0 > UTILS1_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS1.TD0 -c1 >> UTILS1_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS2.TD0 -c0 > UTILS2_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS2.TD0 -c1 >> UTILS2_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS3.TD0 -c0 > UTILS3_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS3.TD0 -c1 >> UTILS3_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS4.TD0 -c0 > UTILS4_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS4.TD0 -c1 >> UTILS4_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS5.TD0 -c0 > UTILS5_systrk_hexdump.txt
> wine SAMdisk.exe view UTILS5.TD0 -c1 >> UTILS5_systrk_hexdump.txt

Am folosit această succesiune de comenzi pentru a obţine un listing al fiecărei piste care să conţină pistele listate continuu, adică pentru fiecare pistă faţa 0 urmată de faţa 1. În mod normal SAMdisk listează toate pistele de pe faţa 0 a dischetei, după care trece la faţa a doua, ceea ce nu prea pică bine aici.

Apoi am înlocuit textul "UTILSn" (n=2,3,4,5) din fişierele UTILSn_systrk_hexdump.txt cu "UTILS1" pentru a face o comparaţie cu MD5SUM între toate cele 5 fişiere (afară de stringul "UTILSn" în mod teoretic nu ar mai trebui să existe alte diferenţe între aceste 5 fişiere).

Ca rezultat al comenzii "md5sum *systrk*", am obţinut următoarele:

845e8f608cd9c609cc5ad8164c5a203a  UTILS1_systrk_hexdump.txt
6d46d60edf4e075ce11d67faa4e1d664  UTILS2_systrk_hexdump.txt
845e8f608cd9c609cc5ad8164c5a203a  UTILS3_systrk_hexdump.txt
845e8f608cd9c609cc5ad8164c5a203a  UTILS4_systrk_hexdump.txt
845e8f608cd9c609cc5ad8164c5a203a  UTILS5_systrk_hexdump.txt

Rezultatul după cum se vede este identic pentru UTILS1.TD0, UTILS3.TD0, UTILS4.TD0 si UTILS5.TD0. Cel mai probabil discheta UTILS2 a avut ceva erori la scriere întrucît structura ei listată cu SAMdisk arată astfel:

> wine SAMdisk.exe scan UTILS2.TD0
[UTILS2.TD0]
80 Cyls, 2 Heads:
250Kbps MFM, 6 sectors, 512 bytes/sector:
  0.0  1[r] 1[r] 6 7 8 9
250Kbps MFM, 9 sectors, 512 bytes/sector:
  1.0  1 2 3 4 5 6 7 8 9
  2.0  1 2 3 4 5 6 7 8 9
  3.0  1 2 3 4 5 6 7 8 9
	.
	.
	.
 79.0  1 2 3 4 5 6 7 8 9
250Kbps MFM, 9 sectors, 512 bytes/sector:
  0.1  1 2 3 4 5 6 7 8 9
  1.1  1 2 3 4 5 6 7 8 9
  2.1  1 2 3 4 5 6 7 8 9
  3.1  1 2 3 4 5 6 7 8 9
	.
	.
	.
 79.1  1 2 3 4 5 6 7 8 9

adică se vede clar că pista 0 faţa 1 are doar 8 sectoare din care primele 4 sectoare au acelaşi număr, 1, ceea ce este o eroare, cel mai probabil la formatarea dischetei. Dealtfel în prezent am constatat că de fapt discheta UTILS2 nici nu e bootabilă, ceea ce era şi de aşteptat.

În continuare am să mă refer la două fişiere:
  1. Imaginea hexa a pistelor sistem extrasă în fişierul "UTILS1_systrk_hexdump.txt" (deci imaginea corectă fără erori a pistelor sistem).
  2. Imaginea memoriei de la adresa 0100h la FFFFh extrasă în fişierul "snapshot 0100-FFFF.bin". Am salvat această imagine cu comanda standard SAVE din CP/M („SAVE 255 MEMDUMP.BIN”). De remarcat că întrucît imaginea memoriei a fost luată începînd cu adresa 0100h, adresele listate la începutul fiecărei linii de octeţi trebuie adunate cu 100h pentru a obţine adresa efectivă din memorie.
Redau mai jos conţinutul acestora, unul lîngă altul, pentru comparaţie. Prin compararea acestor fişiere se pot localiza componentele CP/M în conţinutul pistelor sistem extrase de pe dischete.

UTILS1_systrk_hexdump.txt

snapshot 0100-FFFF.hexdump


Pentru analiză mai e nevoie şi de imaginea zonei de memorie sistem 0000-00FF dintr-o sesiune CP/M. Întrucît comanda SAVE nu poate salva zona de memorie sistem 0000-00FF, am făcut asta cu utilitarul POWER.COM lansat în CP/M imediat după încărcarea sistemului. Cu comanda „DUMPH 0, 100” am obţinut următorul listing:

0000: C3 03 DF 80  00 C3 06 D1  00 00 00 00  00 00 00 00
0010: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
0020: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
0030: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
0040: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
0050: 00 00 00 00  00 00 00 00  00 00 00 00  01 3F 3F 3F
0060: 3F 3F 3F 3F  3F 3F 3F 3F  00 00 00 74  00 20 20 20
0070: 20 20 20 20  20 20 20 20  00 00 00 00  00 00 00 00
0080: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
0090: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
00A0: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
00B0: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
00C0: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
00D0: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
00E0: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5
00F0: E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5  E5 E5 E5 E5

După cum (ar trebui să) se ştie, adresa din locaţiile 0001 şi 0002, minus 3, reprezintă adresa de început a modulului BIOS pentru orice implementare. Din listingul de mai sus se vede că această adresă de început este în cazul nostru DF00.

De asemenea după cum (ar trebui să) se ştie, adresa din locaţiile 0006 şi 0007 este utilizată ca adresă de sfîrşit a zonei TPA. Asta ar însemna începutul BDOS. Deci începutul BDOS ar fi la adresa D106.

1. BIOS
********
În "UTILSn_systrk_hexdump.txt", prin comparare cu şirul de octeţi din "snapshot 0100-FFFF.bin" care începe de la DE00 (adica DF00 în memoria reală), se observă că BIOS-ul este localizat pe cyl00/side1 în sectoarele 4 5 6 7 8 9. Afară de această zonă de cod propriu-zis (denumită BIOS-1), BIOS mai include în continuare şi intervalul cyl01/side0/sec1 - cyl01/side1/ 1/2 sec1 care este o zonă de manevră pentru date.

2. BDOS
********
De asemenea, prin compararea "UTILSn_systrk_hexdump.txt" cu "snapshot 0100-FFFF.bin" se observă că începutul BDOS (punct intrare D106, valoare aflată în locaţiile 0006-0007) aşa cum apare în imaginea memoriei, corespunde cu începutul sectorului 6 pista 0 faţa 0 (mai exact locaţia 006 din el).

3. CCP
********
Apoi începutul CCP, aflat la adresa C900 (determinată observînd că pînă la C900 memoria contine zerouri) în imaginea memoriei, corespunde cu începutul sectorului 2 pista 0 faţa 0.

În imaginea memoriei salvată în fişierul "snapshot 0100-FFFF.bin" se mai observă un bloc de cod pe care l-am denumit UNKNOWN, între adresele 3FF9-47FF cu conţinutul identic cu sectoarele 6-9 pista 1 faţa 1, la sfîrşitul ultimei piste sistem.

Acest bloc este rămas de la încărcarea iniţială a celor doua piste sistem în memorie începînd de la adresa 0000, după terminarea execuţiei primului sector de pe disc (la sfîrşitul căreia se apelează rutina 5F62 care şterge memoria între 0008-3FF8).
La momentul în care pistele sistem sînt încărcate începind de la 0000, procesorul are acces la DRAM#1.
La momentul în care rutina 5F62 şterge memoria, procesorul are acces la VRAM în loc de DRAM#1
Blocul UNKNOWN se află fizic în DRAM#1.
Ştergerea efectuată de rutina 5F62 se opreşte cu 8 octeţi înainte de DRAM#1/VRAM şi oricum nu are cum să ştearga ceva din DRAM#1.
Acest bloc nu pare să aibă nici o utilitate, conţine 3 fragmente disparate din BOOT SECTOR care nu au nici o noimă iar restul codului nu are nici o utilitate. Acest bloc este lăsat in mijlocul zonei TPA probabil din motiv că nu mai contează dacă este suprascris de programe tranzitorii CP/M, codul fiind oricum nefolosit.

Din analiza loader-ului CP/M (aflat pe disc în ultimul sector al zonei alocate fişierului D.COM) se constată că în procesul de încărcare a CP/M, după ce codul de BOOT încarcă loader-ul la adresa 0000, acesta (loader-ul) se relochează la FC00.

De acolo în continuare loader-ul încarcă pistele sistem, 4 x 9 sectoare = 36 sectoare = 18KB (care au factor de întreţesere 1:1) începînd de la adresa 0000.

Apoi este executat un salt la adresa 0000, deci la începutul primului sector de pe disc încărcat în memorie. Am denumit acest sector BOOT SECTOR. Analiza acestuia lămureşte adresele finale de încărcare a componentelor CP/M:
Deci localizarea componentelor CP/M, în ordinea în care sînt scrise în pistele sistem, ar fi următoarea:
(Poziţia iniţială este zona de memorie ocupată imediat dupa încărcarea pistelor sistem în memorie iar poziţia finală este zona ocupată după relocarea în domeniul de adrese necesar funcţionării CP/M)

Poziţia initială Poziţia finală Poziţia în pistele sistem Mărime
BOOT SECTOR 0000-01FF - - - cyl00_side0_sec1 1sec x 200h = 200h (0.5K)
CCP 0200-09FF C900-D0FF cyl00_side0_sec2-5 4sec x 200h = 800h (2K)
BDOS 0A00-17FF D100-DEFF cyl00_side0_sec6-9 plus
cyl00_side1_sec1-3
7sec x 200h = E00h (3.5K)
BIOS-1 1800-24FF DF00-EBFF cyl00_side1_sec4-9 plus
cyl01_side0_1/2 sec1
6.5sec x 200h = D00h (3.25K)
(ultimii 170h octeţi sînt de fapt "00", nefolosiţi)
BIOS-2 2500-36FF EC00-FDFF cyl01_side0_2/2 sec1 pînă la
cyl01_side1_1/2 sec1
9sec x 200h = 1200h
zonă goală, cu excepţia ultimului sect şi jumătate
care conţine zona DPH + 3 şiruri de date
BLOCK#1 3700-3B75 5B00-5F75(VRAM) cyl01_side1_100 sec1 pina la
cyl01_side1_175 sec3
476h
BLOCK#2 3B76-4074 7B00-7FFE(VRAM) cyl01_side1_176 sec3 pina la
cyl01_side1_074 sec6
4FFh
UNKNOWN 3FF9-47FF 3FF9-47FF cyl01_side1_sec6-9 4sec x 200h = 800h (2K)

Pistele sistem sînt încărcate în ordinea de pe disc în memorie de la adresa 0000 şi apoi este executat codul de la început (sect 1 cyl 00 side 0). Analizînd acest sector, se observă că o porţiune de cod aflată în sectoarele 1-6 cyl 01 side 1 este separată în două bucăţi care sînt relocate astfel: Din compararea imaginii de memorie CP/M "snapshot 0100-FFFF.bin" cu imaginea pistelor sistem "UTILSn_systrk_hexdump.txt" se mai observă şi că sectoarele din pistele sistem sînt înregistrate pe disc în ordinea normală, adică au un factor de întreţesere de 1:1.

Începutul BIOS din "snapshot 0100-FFFF.bin" (de la adresa DF00) este identic cu începutul sectorului 4 de pe pista 0 faţa 1, iar conţinutul BIOS (cu excepţia unor blocuri de date care sînt modificate la încărcarea sistemului) continuă să fie identic pînă la locaţia 0B7F cu conţinutul sectorului 9 pista 0 faţa 1 pînă la locaţia 017F din acest sector. Deci asta înseamnă aproximativ 4,5 KB din cei 8,25KB ai imaginii salvate.

Redau mai jos listingurile celor trei componente ale acestei versiuni de CP/M, dezasamblate de mine cu unele comentarii. Nu am apucat să comentez absolut tot, dar în timp intenţionez s-o fac şi pe asta.

CCP (C900-D0FF) - codul dezasamblat

BDOS (D100-DEFF) - codul dezasamblat

BIOS (DF00-FDFF) - codul dezasamblat


4. "Împachetarea" sistemului pentru stocare în şi lansare din ROM



Pentru stocarea sistemului în ROM am eliminat sectoarele 1-8 de pe cyl01/side0 care corespund unor zone de manevră folosite de CP/M şi sectoarele 7-9 de pe cyl01/side1 care conţin după cum am explicat anterior cod inutil.

Am redus astfel mărimea efectivă a sistemului la 12.5KB, de la cei 18KB iniţiali (2 piste x 2 fete x 9 sectoare x 0.5KB/sector).

Apoi am modificat Boot Sector-ul pentru a reloca blocurile de date astfel modificate la adresele corecte. Redau mai jos listingul dezasamblat al Boot Sector-ului modificat:

Boot Sector modificat pentru lansare din ROM


Pentru a obţine imaginea binară care se scrie în ROM, se asamblează un bloc de date conţinînd în ordine:
  1. BOOT SECTOR-ul cyl00/side0/sec1, modificat ca mai sus (1 sector, 0.5KB)
  2. Intervalul cyl00/side0/sec2 - cyl00/side1/sec9 (17 sectoare, 8.5KB).
  3. Intervalul cyl01/side0/sec9 - cyl01/side1/sec6 (7 sectoare, 3.5KB)
În total 25 sectoare, 3200h=12.5KB. Acest bloc se scrie în ROM ca orice alt sistem de tip Spectrum de 16K. Evident, ultimii 3.5K din felia standard de 16K alocata unui Basic Spectrum vor rămîne nefolosiţi.

Apoi pentru lansare din configuraţia de BOOT, eu am folosit următoarea secvenţă rulată din cadrul Boot Manager-ului:

			; ######### CP/M ROM LOADING #########
CPM0	LD	A,$00	; default drive 0
	JR	CPM
CPM1	LD	A,$01	; default drive 1
	JR	CPM
CPM2	LD	A,$02	; default drive 2
	JR	CPM
CPM3	LD	A,$03	; default drive 3
CPM	LD	HL,$4000
	LD	DE,$8000
	LD	BC,$3200
	LDIR
	LD	HL,$8004 ; DSK Byte, location used as mailbox from BOOT to CP/M for user choice of default drive
	LD	(HL),A	; set default CP/M logical drive
	LD	HL,$0000 ; jump address in upcoming CP/M config
	LD	A,$40
	OUT	($FE),A	; set O6=1 for CP/M config
	XOR	A
	LD	R,A
	JP	(HL)



Imaginea binară a acestui sistem CP/M poate fi descărcată la secţiunea "BOOT ROM" din partea de "Software", ca parte integrantă a imaginii SYSTEM ROM disponibilă ca link de download.

5. Comportarea sistemului modificat pentru lansare din ROM



Din configuraţia de BOOT, din Boot Manager-ul scris de mine, se poate încărca CP/M din ROM prin apasarea a 4 combinaţii diferite de taste: CTRL+0, CTRL+9, CTRL+8 sau CTRL+7. Fiecare din aceste combinaţii lansează sistemul cu unitatea implicită 0 (A:), 1 (B:), 2 (C:) sau 3 (D:) respectiv. Unitatea logică aleasă nu mai este redenumită de către sistem în A:, ci este păstrată asocierea 0=A:, 1=B:, 2=C:, 3=D: pe toată durata sesiunii de lucru.

După ce a fost astfel modificat, sistemul afişează la pornire un ecran precum cel de mai jos:


Mesajul afişat în imaginea exemplu de mai sus precizează că sistemul a fost lansat cu unitatea logică B: (adică unitatea fizica 1) ca unitate implicită. Întrucît la iniţializare sistemul CP/M e conceput să citească tabela directoare a discului implicit, consecinţa este că, deşi sistemul se lansează acum din ROM, fără să mai fie nevoie de dischetă sistem, totuşi este nevoia ca la lansare, în unitatea aleasă de utilizator ca unitate implicită, să existe un disc introdus (nu e nevoie să fie disc sistem, dar trebuie să fie cel putin formatat dacă nu şi cu date pe el).

Astfel modificat, sistemul mai permite de asemenea şi folosirea oricăreia dintre cele 4 unităţi fizice posibile cu dischete "obişnuite" în format CoBra de 3.5" sau 5.25" DSDD de 720KB (80 piste, doua feţe, 9 sectoare pe fiecare faţă a unei piste, factor de întreţesere 2). Reamintesc aici că versiunea iniţială nemodificată nu permitea folosirea acestor dischete decît cu unităţile 2 (C:) sau 3 (D:).

6. Compatibilitatea sistemului modificat pentru lansare din ROM cu programe CP/M existente



Întrucît modificarea adusă de mine sistemului îi schimbă comportamentul standard, e posibil ca anumite programe existente să se manifeste diferit cînd sînt rulate sub acest sistem. Mai exact, comportamentul standard al CP/M este ca unitatea de pornire (de pe care a fost încărcat sistemul) să fie văzută ca unitate logică A:, indiferent de numărul ei ca unitate fizică.

Am constatat asta atunci cînd am încercat să rulez binecunoscutul utilitar POWER.COM. Am avut neplăcuta surpriză să constat că, înainte de a afişa orice altceva, programul generează un mesaj de eroare care spune că unitatea 0 nu este READY:


La început am crezut că poate am scăpat eu ceva atunci cînd am hăcuit sistemul şi i-am modificat comportamentul ca să nu mai ceară ce unitate logică are el chef. Am săpat şi am tot săpat, dar n-am găsit nici o scăpare. Atunci am luat utilitarul POWER.COM la bani mărunţi şi l-am dezasamblat ca să văd ce anume din el are pretenţia să acceseze unitatea 0.

Am constatat după ceva bătaie de cap că de fapt utilitarul are pretenţia să chiţăie unitatea logică A:, adică unitatea de pe care s-a încărcat sistemul. Din moment ce sistemul în cazul de faţă se încarcă din ROM şi unitatea sistem nu mai există, ci numai o unitate aleasă de utilizator ca implicită, a trebuit să-i schimb năravul acestui utilitar. Săpînd prin el am constatat că într-una din zonele lui de date se află o locaţie (la adresa $016A din programul încărcat în zona TPA, adică la offset 006A din fişierul executabil) care este folosită de program cu titlul de unitate logică, conform aceleiaşi definiţii a unităţii logice care este folosită pentru locaţia 0 a unui FCB standard CP/M.

Mai exact, locaţia 0 dintr-un FCB, conform manualului CP/M 2.2, are următoarea semnificaţie:

Cod unitate între 0 şi 16:
Locaţia $016A din POWER.COM are valoarea $01, şi utilitarul o foloseşte ca valoare iniţială pentru codul unităţii pe care încearcă să o acceseze la lansarea utilitarului.
Prin schimbarea valorii acestui octet din $01 în $00 am rezolvat problema, lămurindu-l să acceseze totdeauna unitatea curentă în loc de unitatea implicită (logică A:).
Redau mai jos listingul dezasamblării POWER.COM (versiunea 3.03), cu unele comentarii făcute de mine. Nu am studiat tot codul, de la cap la coadă, ci am studiat şi comentat doar atît cît a fost necesar ca să depistez de unde venea problema.

POWER.COM 3.03 - cod dezasamblat şi (parţial) comentat


7. Modificarea sistemului pentru a funcționa și cu unitățile 0 și 1 tot ca unități DSDD 720 KB



Am făcut această modificare cam la 4 ani după modificarea pentru lansare din SYSTEM ROM. Ca urmare, din cauză că la acel moment ulterior luasem toate celelalte versiuni de CP/M la puricat, studiat și modificat, și studiul a fost făcut pe altă cale (cu ajutorul emulatorului HxC - achiziție recentă - și imaginilor de disc .HFE), și analiza de față este făcută în același stil. Nu mai plec de la analiza pe sectoare, ci de la blocul de cod sistem salvat dintr-o imagine .HFE pe care am instalat sistemul cu ajutorul emulatorului HxC.

Pentru început am generat o imagine RAW floppy goală (formatată) de 720 KB cu numele TEST_KRYS80.img. Asta se poate face în mai multe moduri, unul ar fi cu utilitarul cobra-cpm-diskimg-copy.c scris de mine, altul ar fi cu software-ul emulatorului floppy HxC. Sau, pentru utilizatori Linux înrăiți (ca mine), pur și simplu cu comanda bash:
dd if=/dev/zero bs=1k count=720 | tr '\000' '\345' > TEST_KRYS80.img

întrucît avem 80 piste x 18 sectoare x 512 octeți = 720 KB.

Am convertit apoi imaginea RAW în imagine HFE folosind HxCFloppyEmulator.exe, am pus-o pe un SD Card și în emulator am instalat sistemul pe ea prin rularea executabilului SY80CAT+.COM urmată de copierea fișierului CBOT.SYS.

Am scos apoi SD Card-ul din emulator și am copiat înapoi în Linux imaginea TEST_KRYS80.hfe. Am încărcat-o în HxCFloppyEmulator.exe:


și am deschis fereastra Track Analyzer selectînd pista 0 fața 0, ca în imaginea de mai jos:

Pista 0
Fața 0
Pista 0
Fața 1
Pista 1
Fața 0
Pista 1
Fața 1
NOTĂ:

Se observă că pista 1 fața 0 are sectoarele 1-8 goale (pline cu zerouri).
Track Analyzer reprezintă sectoarele pline cu zerouri cu un verde mai decolorat.


Examinînd pistele sistem pe ambele fețe se vede că au același format ca și restul pistelor de pe disc (9 sectoare pe față, 512 octeți/sector). Asta înseamnă că și CP/M Loader-ul acestei versiuni CP/M lucrează cu formatul standard de pistă.

Apoi am exportat imaginea floppy (cu butonul ”Export” din fereastra principală a HxCFloppyEmulator.exe) în format RAW cu numele TEST_KRYS80.img. În acest format, pistele sistem ocupă zona de început a fișierului de 4 x 4,5 KB = 18 KB, după care urmează zona de director. Întrucît imaginea dischetei nu conține nimic altceva decît sistemul proaspăt instalat, directorul va conține o singură înregistrare (32 octeți), în prima poziție din director, pentru fișierul CBOT.SYS copiat după instalarea sistemului în pistele 0 și 1.

Am extras datele din pistele 0 și 1 într-un fișier separat, numit KRYS80_SYS_Tracks_full.bin, cu comanda bash:
head -c 18K TEST_KRYS80.img > KRYS80_SYS_Tracks_full.bin

Acest fișier are lungimea de 18 KB, adică 2 piste x 2 fețe x 9 sectoare/față x 512 octeți/sector.

Mai departe, pentru a obține o imagine completă de dischetă sistem bootabilă, este nevoie de generarea zonei de director cu prima intrare alocată CP/M Loader-ului (un nume de fișier cu extensia SYS, cum ar fi LK.SYS, ca să păstrăm denumirea originală), și de atașarea zonei de date (de regulă maxim 512 octeți, adică un sector) a CP/M Loader-ului propriu-zis, urmată de restul întregii zone de date a dischetei.

Pentru început m-am ocupat de problema zonei de date. Întrucît îmi place să am cît mai multe opțiuni la dispoziție, m-am gîndit la 3:
  1. CP/M Loader-ul original al acestei versiuni (provenit din fișierul CBOT.SYS) adus la dimensiunea de 512 octeți
  2. Un CP/M Loader adaptat din cel original dar personalizat cu un logo în stilul celui de la versiunea CP/M CHRIS a lui Pîrvu Cristinel-Dan
  3. Un CP/M Loader adaptat din versiunea originală a CP/M CoBra (cu 40 coloane text vizibile) pentru a funcționa cu piste sistem în format standard
Redau mai jos listingurile în Assembler ale acestor 3 variante.

CP/M Loader versiunea originală a acestui sistem, CBOT.SYS - codul dezasamblat



CP/M Loader personalizat (cu logo) - listing în Assembler



CP/M Loader versiunea originală CoBra, LK.SYS - codul dezasamblat

Aceasta e versiunea originală a CP/M Loader-ului folosit cu prima versiune de CP/M CoBra. Este proiectat să funcționeze cu piste sistem formatate cu cîte un singur sector pe o față de pistă, cu 4096 octeți/sector. Imediat după acest listing prezint un tabel cu modificări care adaptează acest CP/M Loader pentru lucrul cu piste sistem cu format standard. Aplicînd aceste modificări direct fișierului binar LK.SYS (cu un editor hexa) se obține foarte elegant un CP/M Loader pentru versiunea CP/M de față (cu 80 coloane text vizibile).

NOTĂ:
  1. Din motive obscure, fișierul LK.SYS păstrat pe dischetele din arhiva mea are dimensiunea de 1152 octeți. Totuși, din listingul dezasamblării de mai jos se vede clar că numai primii 512 octeți conțin codul util de CP/M Loader, restul fiind probabil un rest de cod salvat împreună din greșeală sau poate intenționat pentru a provoca neinițiaților ceva confuzie... Pentru scopul de față am eliminat ce era inutil păstrînd numai primii 512 octeți din acest fișier.
  2. După cum se vede mai jos, primii 128 octeți par a fi lăsați cu valoarea înscrisă la formatarea dischetei (E5). În mod normal, această zonă liberă ar fi trebuit să înceapă cu o instrucțiune de salt (JP) la începutul zonei de cod propriu-zis (adresa 0080 din acest listing). Din cauză că această instrucțiune de salt lipsește, ce se întîmplă în realitate este că la lansarea CP/M Loader-ului, înainte de execuția codului propriu-zis de CP/M Loader, se execută 128 de instrucțiuni PUSH HL (E5 este codul instrucțiunii PUSH HL) care încarcă zona de stivă cu 256 de octeți în mod inutil. Întrucît la acel moment zona de stivă se află undeva pe la FC00 (la adrese mari) acest lucru nu perturbă îndeplinirea scopului final. Totuși acest ciobănism nu este corect și în versiunea finală de CP/M Loader folosită de mine am adăugat instrucțiunea de salt corespunzătoare la început.


MODIFICARE LK.SYS PENTRU A FUNCȚIONA CU 9 SECTOARE PE PISTĂ, 512 OCTEȚI/SECTOR
Locația Modificare Comentariu
$0097 $20 -> $24 $24 x $100 = $2400 = 9 KB = 1 pistă ambele fețe
$0098 $FF -> $00 adresa de start pentru salvare va fi $0000
$0099 $3F -> $00
$00AD $00 -> $01 comanda MT Read Data să înceapă la sectorul 1
$00AE $00 -> $02 512 octeți/sector
$00AF $00 -> $09 EOT, ultimul nr. de sector de pe o pistă
$00B0 $00 -> $50 valoarea GAP3 pentru 9 sect/pistă, 512 octeți/sector
$01AD $04 -> $01 un singur octet de copiat cu LDIR, anume nr. pistă
$01B1 $2B -> $06 înlocuire DEC HL și LD B,(HL) cu LD B,$02
pentru a specifica 512 octeți/sector
$01B2 $46 -> $02
$01B3 $2B -> $3E înlocuire DEC HL și LD A,(HL) cu LD A,$01
pentru a specifica sector nr. 1
$01B4 $7E -> $01
$01B5 $12 -> $00 ștergere instrucțiune LD (DE),A
$01C2 $CB -> $00 ștergere instrucțiune care schimba
opcode pt. INI cu opcode pt. IND
$01C3 $DE -> $00
$01FC $23 -> $21 înlocuire instrucțiuni INC HL și RET
cu LD HL,$0000 și RET
pentru ca JP (HL) să sară la $0000
după ce ambele piste sistem sînt citite
$01FD $C9 -> $00
$01FE $00 -> $00
$01FF $00 -> $C9

Acum că am stabilit ce opțiuni avem pentru codul de CP/M Loader, pasul următor este generarea, ca fișier binar, a intrării în director folosibile cu el.

Poate fi foarte bine și generat direct și editat cu un editor hexa. Sînt necesari 32 octeți după cum urmează:

octetul 0: $00 (User Number)
octeții 1-8: $4C $4B $20 $20 $20 $20 $20 $20 (Nume fișier, 'LK ')
octeții 9-11: $53 $59 $53 (Extensia numelui, 'SYS')
octetul 12: $00 (Xl, Nr. extensiei logice de 16KB, octetul inferior al valorii pe 16 biți)
octetul 13: $00 (Byte Count, nr. octeți folosiți în ultima înregistrare de 128 octeți. CP/M 2.2 nu suportă acest octet, care este lăsat pe 0)
octetul 14: $00 (Xh, Nr. extensiei logice de 16KB, octetul superior al valorii pe 16 biți)
octetul 15: $04 (Record Count, nr înregistrări de 128 octeți folosiți de ultima extensie)
octețul 16: $02 (octetul inferior al numărului (2) primului bloc alocat pe disc - blocurile 0 și 1 sînt ocupate de directorul CP/M)
octetul 17: $00 (octetul superior al numărului primului bloc alocat pe disc)
octeții 18-31: $00 (LK.SYS ocupă un singur bloc de 2KB, deci restul de 7 blocuri adresabile de această intrare de director vor avea valoarea $0000)

Am salvat fișierul astfel generat LK_direntry.bin.
Am confecționat astfel prima intrare în director cu numele LK.SYS (pentru a păstra denumirea standard originală de la CoBra) pe care o voi asocia mai departe cu conținutul CP/M Loader-ului.

Apoi este nevoie de un bloc de octeți $E5 corespunzător restului de sector 1 și sectoarelor 2 3 4 5 6 7, care vor fi goale, adică 512-32 + 6x512 = 3552 octeți. Am generat acest bloc (E5dirfill_1.bin) cu comanda bash:
dd if=/dev/zero bs=1 count=3552 | tr '\000' '\345' > E5dirfill_1.bin

Urmează apoi cei 512 octeți ai CP/M Loader-ului CPM_KRYSS_Loader.bin (sectorul 8 fața 0 pista 2 este primul sector de date de pe disc, deci aici trebuie pus codul Loader-ului).
Apoi urmează alte 10 sectoare goale (sectorul 9 fața 0 pista 2 plus sectoarele 1 2 3 4 5 6 7 8 9 fața 1 pista 2) cu care se completează pista 2.
Și în fine, toate sectoarele (goale) ale pistelor 3-79, adică 77 piste x 20 sectoare.
Deci 10 + 77 x 18 = 1396 sectoare de 512 octeți. Am generat și acest bloc (E5dirfill_2.bin) cu comanda bash:
dd if=/dev/zero bs=512 count=1396 | tr '\000' '\345' > E5dirfill_2.bin

După care am pus cap la cap toate bucățile în 3 feluri diferite:

1. Pentru o imagine RAW de dischetă sistem CP/M (KRYS80_KR_SYSDISK.img) cu CP/M Loader-ul original al acestei versiuni, am executat comanda:
cat KRYS80_SYS_Tracks_full_modified.bin LK_direntry.bin E5dirfill_1.bin CPM_KRYSS_Loader.bin E5dirfill_2.bin > KRYS80_KR_SYSDISK.img

2. Pentru o imagine RAW de dischetă sistem CP/M (KRYS80_CL_SYSDISK.img) cu CP/M Loader personalizat (logo), am executat comanda:
cat KRYS80_SYS_Tracks_full_modified.bin LK_direntry.bin E5dirfill_1.bin CPM_80c_Loader.bin E5dirfill_2.bin > KRYS80_CL_SYSDISK.img

3. Pentru o imagine RAW de dischetă sistem CP/M (KRYS80_LK_SYSDISK.img) cu CP/M Loader adaptat de la versiunea originală a CP/M CoBra (1989 ITCI Brasov), am executat comanda:
cat KRYS80_SYS_Tracks_full_modified.bin LK_direntry.bin E5dirfill_1.bin LK_modified.bin E5dirfill_2.bin > KRYS80_LK_SYSDISK.img

Am convertit aceste imagini în format HFE și punîndu-le pe SD Card, am încărcat sistemul cu succes de pe toate unitățile fizice posibile (0, 1, 2 și 3).

Am adaptat și mesajul de start pentru a reflecta exact versiunea modificată:



În final, un tabel cu link-uri pentru download ale tuturor imaginilor de disc sistem generate pentru această versiune CP/M:

PRECIZARE IMPORTANTĂ:



Pentru lansarea sistemului CP/M de pe imaginile de dischetă de mai jos NU ESTE NECESAR „Boot-ul CoBra Unificat” scris de mine și prezentat aici la secțiunea „Software / BOOT ROM”.

Aceste imagini de dischetă pot fi foarte bine lansate cu un cod de BOOT original de 2KB (ca pe vremuri). Dealtfel, și dacă se folosește „Boot-ul CoBra Unificat”, pentru lansarea oricărui sistem de pe dischetă, din meniul lui va trebui intrat mai întîi într-unul din codurile BOOT vechi, și apoi din acel BOOT, cu tasta D se încarcă sistem CP/M de pe dischetă.

IMAGINI DISCHETE SISTEM BOOTABILE - CP/M cu 80 coloane text vizibile simultan
(cu piste sistem formatate normal, 9 sect/pistă)
cu sistem încărcabil de pe orice unitate fizică (0, 1, 2 sau 3)

Tip CP/M Loader Format RAW Format HFE Screenshot
LK.SYS modificat KRYS80_LK_SYSDISK.img KRYS80_LK_SYSDISK.hfe
CP/M 80 coloane KRYS80_KR_SYSDISK.img KRYS80_KR_SYSDISK.hfe
Personalizat (logo) KRYS80_CL_SYSDISK.img KRYS80_CL_SYSDISK.hfe