CoBra - Sistem de operare CP/M cu suport pentru dischete DS DD 860KB (86 piste, 10 sectoare/pistă, 512 octeţi/sector)

1. Modul de instalare a sistemului de operare



Pentru instalarea acestei versiuni de CP/M pentru CoBra sînt necesare 2 utilitare CP/M, FDD860KO.COM (program pentru formatare disc cu 86 piste) şi SYS860KO.COM (program pentru instalarea propriu-zisă a sistemului), precum și fişierul SYS860KO.SYS care conţine CP/M Loader-ul şi care trebuie copiat pe dischetă imediat după instalarea sistemului propriu-zis în pistele sistem (0 şi 1) ale dischetei, precum şi utilitarul PIP necesar pentru copierea CP/M Loader-ului.

Pentru început, un sistem CP/M (evident diferit) va trebui încărcat, pentru a lansa comenzile necesare. Am să descriu procesul de instalare folosind versiunea CP/M cu 80 de caractere pe linie, pe care am împachetat-o în ROM şi se lansează foarte convenabil şi rapid.

Înainte de orice se impune un comentariu foarte important:

Fiecare versiune de CP/M are o cantitate limitată de memorie disponibilă pentru programe utilizator. Pentru a garanta execuția corectă a unui program, trebuie ca dimensiunea fișierului executabil al programului să se încadreze în limita de memorie totală disponibilă a sistemului. În cazul de față, generatorul de sistem SYS860KO.COM (20 KB) este cel mai mare din cele trei fișiere enumerate mai sus, și se încadrează fără probleme în limita de 53 KB de memorie disponibilă în sistemul CP/M cu 80 de caractere pe linie.

Prototipul meu CoBra are o unitate fizică de floppy de 3.5" instalată ca unitate fizică 0 şi un emulator fizic de unitate floppy instalat ca unităţile fizice 2 şi 3 (emulatorul emulează 2 unităţi fizice diferite).
Aşa că am folosit emulatorul pentru a lucra cu unităţile 2 şi 3, am confecţionat o imagine floppy conţinînd cele 3 fişiere menţionate mai sus şi am folosit-o ca unitate 3 (D:), şi o imagine de dischetă de 860 KB pe care am montat-o ca unitate 2 (C:).

1:

Am lansat sistemul CP/M din ROM cu unitate implicită D: (conţinînd utilitarele de instalare).

2:

Comanda D (am inclus şi utilitarul D.COM pe lîngă utilitarele de instalare sistem) dezvăluie conţinutul discului D:.

3:

În continuare am tastat comanda de lansare a programului de formatare modificat pentru a suporta formatul de 860 KB cu 86 piste, 10 sectoare/pistă, 512 octeţi/sector. În cazul de faţă s-ar putea sări peste operaţia de formatare întrucît imaginea floppy din emulator a fost creată deja formatată.

4:

După un ENTER, ecranul se schimbă, cerînd alegerea densităţii de formatare a dischetei. Se alege 5" DS 96tpi, adică [1].

5:

În continuare se cere selecţia numărului de sectoare pe pistă şi a capacităţii discului. Se alege IBM 10 DS-DD 860K, adică [2]

6:

În continuare se cere să se precizeze dacă e vorba de formatare sau duplicare. Se apasă tasta F pentru formatare.

7:

În continuare se cere precizarea unităţii fizice în care se află discheta care urmează să fie formatată. Se tastează 2.

8:

În continuare se cere introducerea dischetei care urmează să fie formatată. Se apasă ENTER după ce discheta se află în unitatea 2.

9:

Programul întreabă dacă se formatează toată discheta sau doar o parte din ea. Se apasă Y întrucît formatăm tot discul.

10:

În final, se cere confirmarea operaţiei de formatare, după o avertizare asupra pierderii de date. Se apasă ENTER.

11:

După terminarea formatării, programul întreabă dacă se doreşte repetarea operaţiei sau ieşirea înapoi în sistemul de operare.

12:

Se apasă tasta E şi se iese înapoi la promptul CP/M.

13:

Se tastează comanda de lansare a programului de instalare a sistemului de operare în pistele sistem ale dischetei.

14:

După un ENTER, ecranul se schimbă, cerînd alegerea unuia din două formate posibile de dischetă cu care sistemul care urmează a fi instalat. Evident, se alege formatul de 860 KB prin apăsarea tastei 1.

15:

Apare un prompt pentru introducerea dischetei destinaţie în unitatea 2 (C:). Adică singura unitate acceptată pentru instalarea sistemului este 2, de unde şi necesitatea montării imaginii floppy de 860 KB ca unitate 2, la începutul procedurii.

16:

După un ENTER de confirmare, programul întreabă dacă se doreşte repetarea operaţiei.

17:

Se apasă N şi se iese înapoi la promptul CP/M.

18:

În continuare se tastează comanda de copiere a CP/M Loader-ului pe discheta cu sistemul proaspăt instalat.

19:

După terminarea operaţiei de copiere, discheta din unitatea 2 este gata de boot-are cu noul sistem 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:



Sistemul recunoaşte tastele uzuale ale majorităţii versiunilor CP/M CoBra:
O facilitate foarte utilă este că se poate accesa un floppy disc cu formatul CP/M CoBra „obișnuit” de 720 KB (80 piste, 9 sectoare/pistă, 512 octeți/sector) prin intermediul unității logice F:. În imaginile de mai jos se poate vedea o mică demonstrație a acestei facilități: am încărcat CP/M de pe o dischetă cu acest sistem, apoi am schimbat unitatea curentă de pe A: pe F:, am schimbat discheta în unitatea sistem (unitatea fizică 2) introducînd una de 720 KB și apoi am dat comanda DIR pentru a lista conținutul acesteia.

1:

După încărcarea sistemului am tastat comanda de schimbare unitate curentă pe drive logic F:.

2:

După un ENTER sistemul cere introducerea dischetei de 720 KB în unitatea fizică 2.

3:

Am schimbat discheta sistem cu o dischetă formatată în 720 KB după care am apăsat ENTER. Prompterul CP/M s-a schimbat acum în "F>".

4:

Comanda DIR dezvăluie conținutul dischetei de 720 KB. Listingul nu e complet vizibil întrucît se întinde pe mai mult de 40 coloane text și e vizibilă doar jumătatea stîngă a ecranului virtual de 80 coloane.

5:

Cu tasta F4 se comută afișarea pe jumătatea dreaptă a ecranului text CP/M virtual de 80 coloane, dezvăluind și restul listingului.


Pentru determinarea hărții memoriei ocupate de sistem, am început prin a salva conținutul memoriei dintre $0100-$FFFF (cu comanda „SAVE 255 MEMDUMP.BIN”) și a lista conținutul memoriei dintre $0000-$00FF cu utilitarul POWER.

Conținutul primei pagini de memorie listate cu POWER



(snapshot-uri ale celor 2 jumătăți de ecran cu 40 coloane text accesibile cu tasta F4, redînd întregul conținut al ecranului text virtual CP/M de 80 coloane text)

1:

2:

Din listingul obținut se vede că adresa de început a modulului BIOS este $F600 (conținutul locațiilor $0001 și $0002, minus 3).

De asemenea, adresa de început a modulului BDOS este $E806 (conținutul locațiilor $0006 și $0007).

Deci memoria liberă disponibilă programelor utilizator (mărimea zonei TPA) ar fi cam $E800-$0100=$E700 adică 57.75 KB
0000: C3 03 F6 80  05 C3 06 E8  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  06 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: 00 4D 45 4D  44 45 4D 50  20 42 49 4E  03 00 00 7E
0090: 1B 00 1C 00  1D 00 1E 00  1F 00 20 00  21 00 22 00
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


3. Modificarea sistemului pentru a fi scris în piste sistem cu format normal



Cu toate că discheta este formatată (cu utilitarul FDD860KO.COM) la început cu același format pe toate pistele (10 sectoare pe o față de pistă, 512 octeți/sector), atunci cînd se rulează programul generator de sistem (SYS860KO.COM), acesta, înainte de a scrie sistemul în pistele 0 și 1, formatează aceste două piste cu un format non-standard, cu cîte un singur sector pe față de pistă, cu 4096 octeți/sector. Pentru a complica lucrurile și mai mult, codul sistemului de operare este scris în pistele sistem în oglindă (de la coadă la cap) pentru ca nu cumva cineva să se poată uita prea ușor la cod și să-l dezasambleze ca să vadă marile „secrete de stat”.

Conținutul pistelor sistem, extras cu software-ul emulatorului HxC



Așa că pentru a scăpa de această „protecție” am decis să transpun sistemul în pistele sistem formatate cu același format ca și restul dischetei. Astfel, o imagine RAW de dischetă sistem ar putea fi manipulată mai ușor cu un eventual utilitar, care să poată trata și codul din pistele sistem la fel cum tratează codul din zona de date a dischetei.

Cum am făcut asta:

Pentru început am generat o imagine RAW floppy goală (formatată) de 860 KB cu numele TEST_860K.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=860 | tr '\000' '\345' > TEST_860K.img

întrucît avem 86 piste x 20 sectoare x 512 octeți = 860 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 cu procedeul descris la începutul acestei pagini.

Am scos apoi SD Card-ul din emulator și am copiat înapoi în Linux imaginea TEST_860K.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:


Se poate vedea clar că pe fața 0 a pistei 0 există un singur sector, de 4096 octeți, iar prin punerea cursorului de mouse deasupra zonei verzi (zona sectorului propriu-zis), apare în dreapta jos întreg conținutul sectorului, listat în mod text (hexa) cu tot cu informațiile de formatare aferente. Am selectat cu mouse-ul întregul text, după cum se vede în următoarea imagine, și l-am extras într-un fișier separat, și am repetat operația pentru ambele fețe ale ambelor piste sistem (0 și 1). Am obținut astfel listingul prezentat mai înainte al conținutului pistelor sistem.


Așadar se vede clar că formatul pistelor sistem a fost modificat de către generatorul de sistem. Pentru comparație, în imaginea de mai jos se poate vedea cum arată pista 2 fața 0 (conținînd prima parte a directorului), care are 10 sectoare, numerotate de la 1 la 10, a cîte 512 octeți fiecare:


Apoi am exportat imaginea floppy (cu butonul ”Export” din fereastra principală a HxCFloppyEmulator.exe) în format RAW (cu extensia .img). În acest format, pistele sistem ocupă zona de început a fișierului de 4 x 4 KB = 16 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 SYS860KO.SYS copiat după instalarea sistemului în pistele 0 și 1.

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

Acest fișier are lungimea de 16 KB, adică 2 piste x 2 fețe x 1 sector/față x 4096 octeți/sector.

Folosind utilitarul file-reverse.c scris de mine (prezentat pe pagina „CoBra CP/M - Diverse chestii”), am întors pe dos codul extras și l-am salvat ca 860K_SYS.bin, obținînd astfel codul sistem în ordinea corectă:
./file-reverse 860K_SYS_REV.bin

Apoi, cu comanda
dd if=/dev/zero bs=1k count=4 | tr '\000' '\345' > E5fill.bin
am generat un bloc de octeți $E5 de 4 KB (E5fill.bin) pe care l-am atașat la sfîrșitul fișierului 860K_SYS.bin, obținînd un bloc de 20 KB conținînd codul sistemului urmat de o zonă formatată, care bloc are exact dimensiunea a două piste disc normale pentru acest tip de CP/M (2 piste x 2 fețe x 10 sectoare/față x 512 octeți/sector = 20 KB):
cat 860K_SYS.bin E5fill.bin > 860K_SYS_Tracks_full.bin


Deci în acest moment am obținut pistele sistem în format normal, cu codul sistemului CP/M cu suport pentru dischete de 860 KB, scris în ordinea normală.
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 SYS860KO.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. Din moment ce originalul folosit de acest sistem (SYS860KO.SYS) lucrează cu formatul „protejat” cu sectoare de 4 KB, am decis să încerc să folosesc CP/M Loader-ul de la versiunea de CP/M cu 80 de coloane text vizibile, pe care să-l modific pentru formatul de 10 sectoare pe pistă în loc de 9.

Versiunea de CP/M cu 80 de coloane text vizibile folosește în pistele sistem același format ca pentru restul dischetei (9 sectoare pe o față de pistă, 512 octeți/sector), cu singura deosebire că nu se mai folosește întrețesere logică, adică sistemul are codul stocat în ordinea fizică a sectoarelor. Deci practic formatarea fizică a pistelor sistem e identică pentru toate pistele dischetei, adică exact ce vreau să obțin și pentru versiunea de CP/M cu suport pentru dischete de 860 KB. Singura diferență e că folosește 9 sectoare pe pistă în loc de 10 cît avem în cazul de față, și pentru asta am să-l modific în continuare

CP/M Loader de la CP/M 80 coloane text - codul dezasamblat


Studiind listingul de mai sus, se poate vedea că la începutul codului se află o zonă de parametri folosiți de Loader. Aici ar fi de interes cam patru locații:
Așadar am luat pur și simplu fișierul cu codul binar al CP/M Loader-ului pentru CP/M 80 coloane, am modificat cele 4 locații din el cu un editor hexa și am obținut un CP/M Loader adaptat pentru 10 sectoare pe pistă pe care l-am salvat cu numele CPM_KRYSS_Modified_Loader.bin.

Pentru a avea mai multe opțiuni la dispoziție, am luat și CP/M Loader-ul versiunii originale a CP/M CoBra (LK.SYS) și l-am modificat pentru a funcționa cu piste sistem formatate cu 10 sectoare pe o față:

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

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 10 SECTOARE PE PISTĂ, 512 OCTEȚI/SECTOR
Locația Modificare Comentariu
$0000 $E5 -> $00 primul octet trebuie să fie $00 (NOP), nu $E5 (PUSH HL)
$0001 $E5 -> $C3 opcode pentru JP
$0002 $E5 -> $80 adresa de salt pt. începutul codului (octet inferior)
$0003 $E5 -> $00 adresa de salt pt. începutul codului (octet superior)
$0097 $20 -> $28 $28 x $100 = $2800 = 10 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 -> $0A EOT, ultimul nr. de sector de pe o pistă
$00B0 $00 -> $2E valoarea GAP3 pentru 10 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

Am salvat versiunea modificată cu numele LK.SYS_modified.bin.

Și pentru o a treia opțiune am „confecționat” un CP/M Loader personalizat pentru această versiune de CP/M, care afișează un logo la lansare, în stilul versiunii de CP/M modificate de Pîrvu Cristinel-Dan.

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


Am salvat fișierul binar asamblat cu numele CPM_860K_Loader.bin.

În afară de codul propriu-zis al CP/M Loader-ului, mai e nevoie de o intrare în director pentru 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: $53 $59 $53 $38 $36 $40 $4B $4F (Nume fișier, 'SYS860KO')
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 cu numele SYS860KO_direntry.bin.
Acesta conține efectiv primii 32 de octeți ai sectorului 1 pista 2 fața 0. Am confecționat astfel prima intrare în director cu numele SYS860KO.SYS (pentru a păstra denumirea inițială) 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 de pe fața 0, care vor fi goale, adică 512-32 + 6x512 = 3552 octeți. Am generat acest bloc cu comanda bash:
dd if=/dev/zero bs=1 count=3552 | tr '\000' '\345' > E5dirfill_1.bin

Urmează apoi cei 512 octeți ai uneia din cele trei opțiuni de CP/M Loader descrise mai sus (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 12 sectoare goale (sectoarele 9 10 fața 0 pista 2 plus sectoarele 1 2 3 4 5 6 7 8 9 10 fața 1 pista 2) cu care se completează pista 2.
Și în fine, toate sectoarele (goale) ale pistelor 3-85, adică 83 piste x 20 sectoare.
Deci 12 + 83 x 20 = 1672 sectoare de 512 octeți. Am generat și acest bloc cu comanda bash:
dd if=/dev/zero bs=512 count=1672 | 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 (860K_KR_SYSDISK.img) cu CP/M Loader-ul modificat al versiunii CP/M cu 80 coloane text, am executat comanda:
cat 860K_SYS_Tracks_full.bin SYS860KO_direntry.bin E5dirfill_1.bin CPM_KRYSS_Modified_Loader.bin E5dirfill_2.bin > 860K_KR_SYSDISK.img

2. Pentru o imagine RAW de dischetă sistem CP/M (860K_LK_SYSDISK.img) cu CP/M Loader adaptat de la versiunea originală a CP/M CoBra (1989 ITCI Brasov), am executat comanda:
cat 860K_SYS_Tracks_full.bin SYS860KO_direntry.bin E5dirfill_1.bin LK.SYS_modified.bin E5dirfill_2.bin > 860K_LK_SYSDISK.img

3. Pentru o imagine RAW de dischetă sistem CP/M (860K_CL_SYSDISK.img) cu CP/M Loader personalizat (logo), am executat comanda:
cat 860K_SYS_Tracks_full.bin SYS860KO_direntry.bin E5dirfill_1.bin CPM_860K_Loader.bin E5dirfill_2.bin > 860K_CL_SYSDISK.img

Am transformat aceste 3 imagini RAW în imagini HFE, folosind software-ul emulatorului HxC, și am obținut 3 imagini de dischete sistem CP/M utilizabile cu acest emulator, cu toate pistele formatate la fel.

ATENȚIE!

La conversia din RAW în HFE trebuie completați corect toți parametrii din fereastra „Load Raw image”, corespunzător formatului cu 10 sectoare pe pistă.
În caz contrar imaginea HFE va fi generată greșit și nu va fi utilizabilă. Vezi instrucțiunile de la secțiunea „CP/M - Diverse chestii”.


3. Modificarea sistemului pentru a fi lansat și de pe unitățile fizice 0 și 1 ca unități DD



Toate sistemele CP/M scrise pentru CoBra au fost concepute pe vremea cînd încă mai existau și unități floppy simplă densitate (de regulă de 8"). Ca urmare în codul sistemului a fost rezervată folosirea unităților fizice 0 și 1 pentru unități simplă densitate (SD), și folosirea unităților fizice 2 și 3 pentru unități dublă densitate (DD).

Consecința este că, dacă folosim unități floppy dublă densitate (singurele care mai există în practică), nu putem încărca CP/M de pe ele decît dacă le conectăm ca unitate fizică 2 sau 3. Redau mai jos un snapshot care arată ce se întîmplă atunci cînd încerc să încarc sistemul de pe discheta introdusă în unitatea fizică 0:

Ca un mic comentariu, am să menționez și de unde anume vine eroarea din imaginea alăturată:

Cam toate versiunile CP/M pentru CoBra au încorporată în BIOS o rutină care, imediat după lansarea sistemului și afișarea mesajului de început la marginea de sus a ecranului, citește pista 0 fața 0 a discului unde se așteaptă să găsească un sector unic de 4096 octeți, cu numărul de sector 32. După aceea compară mărimea sectorului găsit și numărul lui cu niște valori stocate într-o zonă de date a CP/M. Dacă valorile citite nu corespund cu valorile stocate, se ia decizia de a reseta calculatorul înapoi în configurația de BOOT, lansînd codul din BOOT ROM. Scopul acestei șmecherii este de a împiedica o eventuală hăcuială din partea neaveniților cu scopul de a copia codul sistemului și a-l transpune în piste sistem cu formatare normală.

Interesant este că unele versiuni CP/M au această decizie dezactivată (cum e cazul versiunii de față), dar testul în sine tot este executat. Testul constă efectiv dintr-o instrucțiune Read ID trimisă la 8272, urmată de citirea de la 8272 a octeților cu rezultatul comenzii. Mesajul de eroare din imaginea alăturată exact asta exprimă: eroare la execuția comenzii Read ID, din cauza faptului că densitatea discului (DD) nu corespunde cu densitatea specificată în tabelul DPB atribuit unității respective (SD). Ca urmare citirea datelor de pe disc nu se poate efectua.

Întrucît limitarea mi se pare aiurea, am decis să modific codul sistemului pentru a-l convinge să folosească toate cele 4 unități fizice posibile ca unități dublă densitate. Pentru a realiza asta, este nevoie de ceva glagorie în legătură cu funcționarea internă a CP/M. Mai exact și mai pe scurt, pentru fiecare unitate fizică există un Disk Parameter Block (DPB, 15 octeți) și un Disk Parameter Header (DPH, 16 octeți). DPB conține parametrii caracteristici ai unității cum ar fi numărul de sectoare pe pistă și mărimea blocului de alocare pe disc. DPH conține adresa de început a DPB, adresa de început a tabelei de translatare sectoare (XLT), și alte cîteva adrese ale unor zone de memorie folosite de CP/M pentru fiecare unitate fizică în parte.

O teorie ceva mai superficială ar fi că modificarea DPH pentru unitățile 0 și 1 astfel încît să folosească aceleași XLT și DPB ca unitățile 2 și 3 ar trebui să rezolve problema. În practică, pe lîngă asta mai e nevoie și de ceva hăcuială suplimentară a codului din BIOS, pentru a vedea dacă nu cumva mai există și vreo rutină care să manevreze acești parametri în funcție de numărul unității fizice.

Și într-adevăr am găsit și astfel de rutine:

Funcția BIOS SECTRAN (vezi listingul BIOS de mai jos) folosește o discriminare între unitățile 0,1 și 2,3 în calcularea numărului sectorului logic. Pentru scopul de față, ar fi nevoie de ștergerea instrucțiunii JR Z,$F812 de la adresa $F80C prin înlocuire cu două NOP-uri.

Modulul BIOS din CPM 860K - listingul dezasamblării


Blocul de cod denumit de mine BLOCK#1 (vezi listingul BLOCK#1 de mai jos și de asemenea listingul Boot Sector-ului dezasamblat de și mai jos) folosește două astfel de condiționări în rutinele BIOS READ/WRITE, la adresele $6EA9 (JR Z,$6EAD) și $6EC3 (JR NZ,$6ED4). Pentru scopul de față ar fi nevoie de înlocuirea JR Z,$6EAD cu două NOP-uri și a instrucțiunii JR NZ,$6ED4 cu JR $6ED4.

Modulul BLOCK#1 din CPM 860K - listingul dezasamblării


Tot în BLOCK#1 mai este o condiționare la adresa $7035 (JR Z,$703F) și încă una la adresa $70AC (JR Z,$70B3), care ambele ar trebui înlocuite și ele cu cîte două NOP-uri,

Sintetizînd toate acestea, am scris un Boot Sector modificat (cu lungimea totală de 256 octeți) care să modifice aceste locații de memorie imediat după despachetarea blocurilor de cod CP/M la adresele lor de lucru și înainte de lansarea efectivă a sistemului. Prezint mai jos listingul Boot Sector-ului original și al acestui Boot Sector modificat.

Boot Sector-ul original din CPM 860K - listing dezasamblare

Boot Sector-ul modificat pentru CPM 860K - listing în Assembler


Am înlocuit primii 256 octeți (codul sistemului începe după primii 256 octeți, după cum se poate vedea din Boot Sector-ul original) din blocul de cod conținînd pistele sistem cu acest Boot Sector modificat:
tail -c 20224 "../Modification for regular system track format/860K_SYS_Tracks_full.bin" > DATA.bin
cat Boot_Sector_modified.bin DATA.bin > 860K_SYS_Tracks_full_modified.bin
rm -fv DATA.bin

și am generat din nou cele trei versiuni de dischetă sistem discutate anterior:

1. Pentru o imagine RAW de dischetă sistem CP/M (860K_KR_SYSDISK.img) cu CP/M Loader-ul modificat al versiunii CP/M cu 80 coloane text, am executat comanda:
cat 860K_SYS_Tracks_full_modified.bin SYS860KO_direntry.bin E5dirfill_1.bin CPM_KRYSS_Modified_Loader.bin E5dirfill_2.bin > 860K_KR_SYSDISK.img

2. Pentru o imagine RAW de dischetă sistem CP/M (860K_LK_SYSDISK.img) cu CP/M Loader adaptat de la versiunea originală a CP/M CoBra (1989 ITCI Brasov), am executat comanda:
cat 860K_SYS_Tracks_full_modified.bin SYS860KO_direntry.bin E5dirfill_1.bin LK.SYS_modified.bin E5dirfill_2.bin > 860K_LK_SYSDISK.img

3. Pentru o imagine RAW de dischetă sistem CP/M (860K_CL_SYSDISK.img) cu CP/M Loader personalizat (logo), am executat comanda:
cat 860K_SYS_Tracks_full_modified.bin SYS860KO_direntry.bin E5dirfill_1.bin CPM_860K_Loader.bin E5dirfill_2.bin > 860K_CL_SYSDISK.img

Și am obținut astfel trei variante de dischetă sistem de pe care CP/M poate fi încărcat cu succes folosind oricare din unitățile 0-3:

În final, două tabele 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 suport pentru discuri de 860K
(cu piste sistem formatate normal, 10 sectoare/pistă)
cu sistem încărcabil numai de pe unitățile fizice 2 și 3

Tip CP/M Loader Format RAW Format HFE Screenshot
LK.SYS modificat 860K_LK_SYSDISK.img 860K_LK_SYSDISK.hfe
CP/M 80 coloane 860K_KR_SYSDISK.img 860K_KR_SYSDISK.hfe
Personalizat (logo) 860K_CL_SYSDISK.img 860K_CL_SYSDISK.hfe


IMAGINI DISCHETE SISTEM BOOTABILE - CP/M cu suport pentru discuri de 860K
(cu piste sistem formatate normal, 10 sectoare/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 860K_LK_SYSDISK.img 860K_LK_SYSDISK.hfe
CP/M 80 coloane 860K_KR_SYSDISK.img 860K_KR_SYSDISK.hfe
Personalizat (logo) 860K_CL_SYSDISK.img 860K_CL_SYSDISK.hfe