Technická dokumentace modulů pro procesory

Překladač se skládá z preprocesoru, parseru a vlastního jádra, které přeloží jednu konkrétní instrukci pro daný procesor. Tato jádra jsou napsána jako zásuvné moduly.

Objekt:

Objekt má tedy jednu jedinou metodu parseOpcode a má volitelný atribut endian – pokud je true, jedná se o Big Endian (Motorola), jinak je procesor Little Endian (Intel, 6502).

Metoda parseOpcode dostává dva parametry: první je s, což je rozparsovaná instrukce, viz dále, a druhý je vars, což jsou hodnoty proměnných, které jsou v dané chvíli známé (tj. v prvním průběhu ty, které jsou už definované, ve druhém všechny, včetně dopočítaných).

Metoda parseOpcode vezme údaje z objektu s, identifikuje instrukci, doplní její operační kód a informace o celkové délce instrukce, a vrátí rozšířený objekt s.

V okamžiku volání metody má objekt s tento formát:

  • opcode je název instrukce (uppercase)
  • numline je číslo aktuálního řádku
  • addr je adresa, na které je instrukce
  • params je pole s parametry, které jsou zadány za instrukcí. Např. u instrukce „MOV A,B“ bude mít params dvě položky, „A“ a „B“
  • bytes, lens jsou položky, které musí metoda doplnit. bytes je celková délka instrukce a lens je pole, v němž jsou jednotlivé operační kódy a kódy parametrů.

Pokud není instrukce rozpoznána, musí metoda vrátit hodnotu null. Překladač pak vyvolá chybový stav „nerozpoznaná instrukce“.

Prosté instrukce

Jednoduché instrukce, jako „NOP“, které zabírají jediný bajt a nemají parametry, přeloží metoda tak, že do s.bytes uloží 1 a do s.lens[0] zapíše operační kód instrukce.

Instrukce s parametrem

Důležité je myslet na to, že hodnotu parametru dopočítá překladač ve druhém průchodu, takže se o ni nestará překládací modul. Ten ale musí doplnit volání parsovací funkce. Příklad – instrukce MVI A, 123

V poli „params“ budou hodnoty „A“ a „123“. Operační kód se spočítá z názvu „MVI“ a prvního parametru (params[0]). Do atributu s.bytes zadáme 2 a do pole lens[0] se zapíše operační kód (0x3F). Do pole lens[1] je potřeba zapsat funkci, která druhému průchodu řekne, že má spočítat aktuální hodnotu druhého parametru (params[1]). Takto:

Tedy jako hodnotu předáváme funkci s jedním parametrem (vars, známé pole proměnných) a funkce vrací výsledek výrazu Parser.evaluate(params[1],vars) – což je interní funkce překladače, která parsuje výrazy.

V případě dvoubajtového parametru (třeba LXI) se do lens[0] zapíše operační kód, do lens[1] výše uvedená funkce a do lens[2] hodnota null. Překladač pak doplní vypočítanou hodnotu na místa 1 a 2.

Vícebajtové operační kódy

Není problém, stačí jen správně nastavit bytes a kódy do pole lens.

Relativní skoky, krátké/dlouhé instrukce atd.

Lze využít volání Parser.evaluate(výraz, vars), který vrátí vypočítanou hodnotu výrazu. Pro spočítání relativního skoku lze použít pseudoproměnnou vars._PC, která obsahuje aktuální adresu překládané instrukce.

Problém může nastat u procesorů jako je 6502, kde lze zapsat instrukci LDA #10 a překladač se musí rozhodnout, jestli využije krátkou verzi se zero page, nebo dlouhou s absolutní adresou. V takovém případě je možné právě využít volání Parser.evaluate() a nechat si spočítat aktuální hodnotu výrazu. Pokud je známá, tj. nejsou v ní použité zatím nedefinované proměnné, dostanete výsledek, který můžete použít při rozhodování. Pokud je ve výrazu nějaká dopředná reference, nastane problém a Parser.evaluate vyhodí výjimku. Je potřeba si ji odchytit.

Výjimky

Pokud metoda narazí např. na podivnou kombinaci parametrů, musí vyhodit výjimku. Příklad: