Indeks | English version![]() |
PB-2000C w zamierzeniu nie pozwala użytkownikowi na uruchamianie własnych programów w asemblerze, ale można go przechytrzyć modyfikując w monitorze adres procedury obsługi klawisza [BRK].
Wciśnięcie klawisza [BRK] powoduje skok pod adres zawarty w zmiennej systemowej ACJMP (&H0CE2), ale tylko w banku 0 (pamięć ROM), podczas gdy własny program maszynowy można umieścić tylko w banku 1 (pamięć RAM). Zmiana banku pamięci licznika programu PC okazała się możliwa przez ustawienie wskaźnika ACJMP na adres poniższego kodu w wewnętrznej pamięci ROM procesora:
0276: PPS $6 0277: PST UA,$6 0278: RTN
Dzięki szczęśliwemu zbiegowi okoliczności prowadzi to do adresu &HC021 w banku 1 (rejestr UA zawiera &H11). Zmiana banku pamięci licznika programu PC jest bezpieczna, ponieważ przerwania są w tym momencie zablokowane (rejestr IE zawiera &H00).
Wymagany jest PB-2000C z 64kB pamięci RAM.
Jeżeli w pozycji menu [memory] zmienimy rozmiar bloku pamięci przydzielonego dla plików na 16350 bajtów, to pierwszy plik będzie się rozpoczynał od adresu &HC021. Można w nim bezpiecznie umieścić program maszynowy.
<memory> c file work 58879 41505 16350 1024 free 16350 1024 c,file?41505,16350 |
Pierwsza pozycja katalogu zarezerwowana dla pliku przechowującego program maszynowy będzie modyfikowana przez dalej opisany program ładujący. Trzeba dopilnować, żeby nie zawierał jakichś ważnych danych, ponieważ zostaną one utracone.
Program wyświetla tekst "Hello World!" a następnie czeka na wciśnięcie dowolnego klawisza, po którym następuje powrót do systemu. Do asemblacji należy użyć asemblera HD61 z opcją /p w celu otrzymania pliku wynikowego typu PBF.
ORG &HC021 START &HC021 PST UA,&H55 LDW $2,&H2AF0 ;przywrócenie domyślnego adresu skoku LDW $23,&H3280 ;BRSTR, ustawia ACJMP CAL SYSCAL LDW $23,&H328F ;wybór LCD jako urządzenia wyjściowego CAL SYSCAL LDW $15,M1 ;adres łańcucha LD $17,M2-M1 ;długość łańcucha LDW $23,&H293B ;wyświetlenie łańcucha CAL SYSCAL LDW $23,&H5774 ;KYIN, czekanie na wciśnięcie klawisza CAL SYSCAL PST UA,&H54 JP &H707C ;powrót do systemu, tryb CAL ; wywołanie podprogramu o adresie $23,$24 w banku pamięci 0 SYSCAL: GST UA,$6 PHS $6 LDW $6,&H0276-1 PHSW $7 PST UA,&H54 JP $23 M1: DB &H0C,"Hello World!",&H0D,&H0A M2:
Program wczytuje z ramdysku, stacji dysków lub portu RS232 kod maszynowy w formacie PBF (utworzony np. przez asembler HD61), zamienia go na postać binarną i zapisuje do pierwszego pliku ramdysku. Ewentualny poprzedni plik na pierwszej pozycji katalogu zostanie przepisany.
main() { FILE *infp,*outfp; char filename[24]; char byte[2]; unsigned addr1,addr2,x,sum; /* test konfiguracji systemu */ if (*(short*)0x0AAA != 0xC021) { printf ("Bad system configuration\n"); abort(); } /* otwarcie pliku PBF */ for (x=0;x<24;x++) filename[x]='\0'; printf ("PBF file name: "); scanf ("%23s",filename); if ((infp=fopen(filename,"rt")) == NULL) { printf ("Input file open error\n"); abort(); } /* zmiana nazwy i typu pierwszego pliku w katalogu (gdy istnieje) */ addr2 = *(unsigned short*)0x0AB4; if (*(unsigned short*)0x0AB0 < addr2) { for (addr1=addr2-27; addr1<addr2-15; addr1++) *(char*)addr1 = '$'; } if ((outfp=fopen("$$$$$$$$.$$$","wb")) == NULL) { printf ("Output file open error\n"); abort(); } /* odczyt naglowka pliku wejściowego */ for (x=0;x<13;x++) { if ((filename[x]=fgetc(infp)) == ',') break; } filename[x]='\0'; if (x>12 || fscanf(infp,"%u,%u,%u\n",&addr1,&addr2,&x) != 3) { printf ("Bad header\n"); abort(); } if (addr1 != 0xC021) { printf ("Bad ORG\n"); abort(); } /* konwersja PBF->BIN */ sum=0; while (addr1<=addr2 && feof(infp)==0) { if ((byte[0]=fgetc(infp)) != ',') { byte[1]=fgetc(infp); sscanf(byte,"%2X",&x); if (fputc(x,outfp) != x) { printf ("File write error\n"); abort(); } sum+=x; addr1++; } else { if (fscanf(infp,"%u\n",&x) != 1 || x != sum) { printf ("Bad checksum\n"); abort(); } sum=0; } } fclose(outfp); fclose(infp); if (addr1<=addr2) { printf ("Unexpected EOF\n"); abort(); } if (rename("$$$$$$$$.$$$",filename)) { printf ("Rename failed\n"); abort(); } printf ("Done!\n"); }
Uruchomić monitor wpisując CLEAR MON w trybie CALC.
Wpisać wartość &H0276 do zmiennej systemowej ACJMP pod adresem &H0CE2.
>E0CE2 0CE2 AE-76 6F-02 FF- |
Wcisnąć klawisz [BRK].
Hello World! _ |