Před tématickým úvodem je třeba omluvit se systematikům. Jejich pozornosti totiž nemohlo uniknout, že poslední dobou dostává pojmenování RPNmania pěkně na frak. Nebýt nedávného Pátku třináctého pro HP-35s a HP-15C, zdálo by se, že RPN byla knokautována zcela nečestně až nesportovně svou mladší sestrou RPL! Naneštěstí, nikdy není tak zle, aby nemohlo být ještě hůř: středobodem aktuálního tématu už není ani ještě nedávno vítězící RPL!!! Sestrovražedný souboj dopadl přesně podle přísloví "Když se dva perou, třetí se směje". Dnešní program je totiž v programovacím jazyku C a to do kontextu skutečně systematicky nezapadá. Sorry...
Úvod | ↑ ↓ |
Odborník křížený se specialistou by řekl: v podpalubí HP-50g temně duní procesor Samsung S3C2410A (ARM920T core). My laici nebudeme tolik hysteričtí a to temné dunění nahradíme slovy ladně po instrukcích skáče, neboť - přiznejme si, přátelé - RISC je prostě RISC. A jelikož psát programy v JSA už není v módě, budeme ho psát... No, děti, kdopak to ví? — Kdo se nám hlásí? — Nikdo? — To je ale ostuda! — Přece v céčku!!! — Cože? — Že nevíte, co je to JSA? To je zkratka pro Jazyk Symbolických Adres! — Pořád nic? — Tak dobře, ať je po vašem: Programy v assembleru se už dnes nevytvářejí, raději použijeme programovací jazyk C. K tomu je zapotřebí mít na stolním počítači nějakou nezbytně nutnou výbavu, ale o tom až později. Každopádně, podivně vyhlížející šifra C@ARM@HP-50g s módními znaky @ je vysvětlena.
Zdrojový text vyplňující celou další kapitolu je v podstatě stejný s modulem roman.c z výchozího tématu. Pouze vstupy a výstupy jsou jiné: zpracování argumentů příkazové řádky a výpisy funkcemi printf() resp. fprintf() zde zastupuje RPL stack. Z něj program odebere vstupní argument a na něj spolu s výsledkem uloží hodnotu typicky nazývanou exit-status. Je-li exit-status nenulový, doprovází ho v další úrovni stacku chybová hláška v textovém tvaru. Novinkou (komplikací) je detekce typu vstupního argumentu. To, co ve "stolní" verzi vyřeší funkce strtoul(), je zde trochu masakr, ale to se nedá nic dělat.
K celé zde popisované atrakci došlo pod vlivem textu Extend your 50g with C. Kromě návodu jak program v céčku pro HP-50g vytvořit (ale o tom opravdu až později :-) je v něm řada moudrých slov. Třeba hned v úvodní kapitole je odstavec Why C?, kde není jediné slovo nepravdivé. V intencích stránek RPNmania je však podstatnější odstavec následující, tedy Why not C?. Druhý z dvojice bodů odpovídajících na otázku si zaslouží plnou citaci: "Small UserRPL routines may be good enough. Why add a layer of complexity? Use the right tool for the right job.". Bóže, kdyby se těchto pravidel držel každý vývojář...
Držme se ale těch naznačených intencí stránek RPNmania. Co seriózního se tu od jejich založení v roce 2009 napsalo? Tato otázka stejně zábavná jako irelevantní. Odpovědí jsou dvě krátká slůvka: VŮBEC NIC! Zato různých hříček a jiných zbytečných hloupostí jako když naseje ¹). Je tedy snadno pochopitelné, že problematika tvorby programu v jazyku C pro HP-50g na tyto stránky právem patří.
¹) Předposlední znak posledního slova ve větě je opravdu 'j'. Vyjádřeno hodnotou ASCII je to 106, nebo také 0x6A. Nezaměňovat, prosím, se znakem s hodnotou 114, tedy 0x72 :-)
Zdrojový text C | ↑ ↓ |
Je to jediný modul romanarm.c. Za povšimnutí stojí fakt, že kromě použití funkcí ze standardní knihovny C (také libc neboli standard C library) se v programu vyskytují pouze symboly reprezentující programovou vrstvu emulátoru procesoru Saturn.
#include <hpgcc49.h> // Prevodni tabulky // #define ROMAN_SROMT_INIT "I" "V" "X" "L" "C" "D" "M" #define ROMAN_SVALT_INIT {1, 5, 10, 50, 100, 500, 1000} // static char const sromt[] = ROMAN_SROMT_INIT; // Maximalni velikost bufferu cislic // #define ROMAN_RESULT_SIZE 40 // Navratove hodnoty funkci // #define RTNVAL_OK 0 #define RTNVAL_ERROR 1 /*============================================================================*\ ARABSKE --> RIMSKE \*============================================================================*/ /* * VSTUPNI BOD */ static int a2r(unsigned value) { unsigned divisor; int sidx, ridx; char result[ROMAN_RESULT_SIZE]; divisor = 1000; sidx = sizeof(sromt) / sizeof(*sromt) - 2; ridx = -1; do { unsigned digit; digit = value / divisor; value -= digit * divisor; switch(digit) { case 4: case 9: result[++ridx] = sromt[sidx + 0]; result[++ridx] = sromt[sidx + 1 + (digit == 9)]; break; default: while(digit) { int idx; idx = sidx; if(digit >= 5) { ++idx; digit -= 5 - 1; } result[++ridx] = sromt[idx]; --digit; } } sidx -= 2; } while((divisor /= 10) > 0); result[ridx + 1] = '\0'; sat_stack_push_string(result); return(RTNVAL_OK); } /*============================================================================*\ RIMSKE --> ARABSKE \*============================================================================*/ /* * ZJISTENI POCTU PREDCHOZICH CISLIC S MENSI HODNOTOU */ static int r2a_prevlessnum(int result[], int ridx) { int resval, number; resval = result[ridx]; number = 0; do { int preval; preval = result[--ridx]; if( preval < 0) preval = -preval; if(resval > preval) ++number; } while(ridx > 0); return(number); } /* * CHYBA */ static int r2a_error(char const format[], char const *valup, char const *val0p) { char errtext[ROMAN_RESULT_SIZE]; sprintf(errtext, format, valup); sat_stack_push_string(val0p); sat_stack_push_string(errtext); return(RTNVAL_ERROR); } /* * VSTUPNI BOD */ static int r2a(char const *valup) { int ridx, result[ROMAN_RESULT_SIZE]; char const *fndp, *val0p; static int const svalt[] = ROMAN_SVALT_INIT; ridx = 0; val0p = valup; do { int sidx; if((fndp = strchr(sromt, toupper(*valup))) == NULL) return(r2a_error("Unknown Digit: %s", valup, val0p)); sidx = fndp - sromt; result[ridx] = svalt[sidx]; if(ridx > 0) switch(r2a_prevlessnum(result, ridx)) { case 1: result[ridx - 1] = -result[ridx - 1]; case 0: break; default: return(r2a_error("Unexpected Digit: %s", valup, val0p)); } ++ridx; } while(*++valup != '\0'); while(--ridx > 0) result[0] += result[ridx]; sat_push_zint_llong(result[0]); return(RTNVAL_OK); } /*============================================================================*\ PROGRAM \*============================================================================*/ /* * TEST: CO JE NA STACKU */ static int what_is_on_stack() { SAT_STACK_ELEMENT elemv; if(sat_get_stack_element(1, &elemv)) return(-1); return(elemv.prologue); } /* * CHYBA */ #define _ERROR_ARG_EMPTY "Empty stack" #define _ERROR_ARG_TYPE "Bad type" #define _ERROR_ARG_RANGE "Bad range" // #define Error_arg(k) (sat_stack_push_string(_ERROR_ARG_##k), RTNVAL_ERROR) /* * ZADANI "ZINT" */ static int val_zint() { ULONGLONG value; value = sat_pop_zint_llong(); if(value - 1 < 3999) return(a2r(value)); sat_push_zint_llong(value); return(Error_arg(RANGE)); } /* * ZADANI "REAL" */ static int val_real() { double value; value = sat_pop_real(); if(value >= 1.0) if(value <= 3999.0) return(a2r(round(value))); sat_push_real(value); return(Error_arg(RANGE)); } /* * VSTUPNI BOD */ int main() { int test; if(sat_stack_depth() <= 0) test = Error_arg(EMPTY); else switch(what_is_on_stack()) { case SAT_DOINT: test = val_zint(); break; case SAT_DOREAL: test = val_real(); break; case SAT_DOCSTR: test = r2a(sat_pop_str_alloc()); break; default: test = Error_arg(TYPE); } sat_push_real(test); return(0); }
Zdrojové texty RPL | ↑ ↓ |
Možná to někoho překvapí, ale navzdory úvodnímu odstavci se kromě programu v jazyku C najde místo i pro pár příkazů RPL.
« → p « p EVAL p PURGE S→EXE "EXTEND/" p + 3 →TAG DUP PURGE STO » »
« IF :3: "EXTEND/romanarm" EVAL THEN DOERR END »
« { HOME PRGM ROMAN } RCL EVAL »
Sestavení programu | ↑ ↓ |
Samozřejmě, že mistři v oboru mohou použít i laptop nebo notebook (také noťas případně notes se hodí náramně). My ostatní to bez špetky studu můžeme klohnit na letitém stroji, který smutně funí na rohu pracovního stolu, případně pod stolem. Pokud stále někdo neví o čem je řeč, nabízejí se další slangové výrazy: komp (starší studentský žargon dokonce nabízí i ekvivalent s českým slovním základem poč); pro toho, kdo trvá na původním názvu Personal Computer, je tu varianta pecko a raritní kousek ze začátku devadesátých let dvacátého století písíňo.
Následující popis ve formě konzolového výpisu jistě postačí. Zachycuje postup pro dvě varianty:
# cd ~/ram/ # wget http://sense.net/~egan/hpgcc/hpgcc-linux.tgz : : # tar -zxf hpgcc-linux.tgz hpgcc/hpgccenv hpgcc/2.0SP2/ # wget http://rpnmania.sweb.cz/roman/arm/romanarm.tar : : # tar -xf romanarm.tar # cd hpgcc/ # . hpgccenv # cd ../roman/ # make arm-elf-gcc -mtune=arm920t -mcpu=arm920t -mlittle-endian -fomit-frame-pointer -msoft-float -Wall -Os -I/root/ram/hpgcc/2.0SP2/include -L/root/ram/hpgcc/2.0SP2/lib -mthumb-interwork -mthumb -c romanarm.c arm-elf-ld -L/root/ram/hpgcc/2.0SP2/lib -T VCld.script /root/ram/hpgcc/2.0SP2/lib/crt0.o romanarm.o -lhpg -lhplib -lgcc -o romanarm.exe elf2hp romanarm.exe romanarm.hp rm romanarm.exe romanarm.o # ls -go total 44 -rw-r--r-- 1 106 May 18 13:04 INSTALL -rw-r--r-- 1 957 May 28 2008 Makefile -rw-r--r-- 1 85 May 23 15:24 ROMANARM -rw-r--r-- 1 60 May 20 17:02 RORPL -rw-r--r-- 1 4369 May 23 15:14 romanarm.c -rw-r--r-- 1 15434 Jul 12 10:17 romanarm.hp #
Pozorní si jistě všimli volby -mthumb v příkazové řádce spuštění překladače arm-elf-gcc. Tato skutečnost poněkud ubírá na intenzitě euforickému zvolání "RISC je prostě RISC" z úvodních řádků tohoto textu. Úsporný mód instrukcí s šestnáctibitovou šířkou procesor ARM ochudí o zcela zásadní výhodu - podmíněné provádění všech instrukcí. Strojový kód je tak víc podobný konvenčním procesorům. To ale nevadí, pořád je to dravec!
Pro hrátky s programy pro ARM se vyplatí vytvořit samostatný adresář. Budiž nazván HPGCC. Pokud má být jinde, než v domovském adresáři HOME, může mít postup vytvoření a vstupu do nově vzniklého adresáře tuto podobu: HOME TEST 'HPGCC' CRDIR HPGCC.
Pokud někdo bude mít ambice programy v C vytvářet, neobejde se bez sady programů pro HP-50g nazvanou ARM Toolbox. Instalace má následující postup:
Stále jsme v adresáři HPGCC, ale ten i přes bouřlivou činnost z předchozího seznamu stále zeje prázdnotou. Je třeba ho použitím Connectivity Kit naplnit RPL programy INSTALL, ROMANARM a vytvořeným souborem romanarm.hp, Ten je stále typu String, ale obsahuje strojový kód pro ARM. Příkaz 'romanarm' INSTALL provede:
Tak, to bylo pro programátory-analytiky. Všichni ostatní na popsané instalační šílenství rezignují. Jednoduše si na zvolené místo prostřednictvím Connectivity Kit přenesou do své HP-50g pouze wrapper ROMANARM a na SD kartu do adresáře /EXTEND/ uloží soubor romanarm.
Použití programu | ↑ ↓ |
Je-li sestavený (nebo stažený) binární program spouštěn wrapperem ROMANARM, použití je stejné jako v případě původního UserRPL řešení. Situace se změní v případě, že zvědavec bude chtít binární program spustit samostatně a ověřit si, že po ukončení jeho běhu zůstanou na stacku hodnoty, které úvodní kapitola slibuje. Následující obrázky ilustrují obě možné situace:
Download | ↑ ↓ |
Zdrojové texty | Hotový binární kód | |
---|---|---|
Jednotlivě | Vše naráz | |
romanarm.c Makefile | romanarm.tar | romanarm |
INSTALL ROMANARM RORPL |