Indeks English versionEnglish version

Uruchamianie programów maszynowych na mikrokomputerze Casio PB-2000C

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).


Konfiguracja systemu

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.


Przykładowy program w asemblerze

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:

Załadowanie programu maszynowego do pamięci

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");
}

Start kodu maszynowego

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!                    
_