Tento clanek je pro me vylozene provokacni ;-) Hrozne rad bych se ztoporil k tomu, neco si pro atarko napsat. Jenze o tom uz mluvim min 5 let a mam obavu, ze aspon 5 let o tom jen mluvit budu:-(
btw umi neco v asm pro atarko vygenerovat AI? ;-)
Tak to už je nejvyšší čas :-) Já si taky vlastně na sebe upletl bič, protože musím do článků dodat něco funkčního a ne ty polovýtvory, co se mi někde válí na discích...
Jinak CodeRabbitAI kupodivu umí udělat review assembleru 6502 a není to úplná halucinace. Klasické generativní AI jsem nezkoušel, mě to baví psát postaru (taky těžko říct, na čem se to učilo; komunita okolo osmibitů není taková ta klasická open sourcová...)
gcc prece neumi tyhle stare 8 bitove procesory a navic se vyvojem cim dal vice vzdaluje od neceho funkcniho co by na nich bezelo. Da se rici ze je gcc v tomhle smeru cim dal tim vic horsi a horsi.
Nemluve o tom ze ani to C zalozene na zasobnikovem ramci a podporujici implicitne rekurzi neni vhodny jazyk pro tyto procesory.
Z80 to zvlada, ale velmi pomalu a neefektivnimi instrukcemi (cti: napsat to jinak je vzdy lepsi, zapomenout na IX a IY a pouzivat HL a spravne organizovana data) a 6502 na to instrukce ma, ale zase velikost pameti je extremne mala. Platit za rekurzi kdyz nemusis, nebo ji ani nevuzivas je proste spatne.
I nejlepsi prekladac primo pro Z80 je asi 10x horsi nez to napsat rucne v asm nebo v jinem jazyce. Pro 6502 to mozna tak hrozne nebude, ale i tam nic asm neprekona.
no je to trošku na vyšší úrovni abstrakce, takže v CC65 se například pomáhá tím, že __A__ znamená akumulátor, __AX__ dvojici registrů A+X atd. Někdy ten překladač pochopí, co se po něm chce (násobení dvěma převede na ASL), někdy moc ne. Ale s pomocí a pokud ukládá proměnné ne na zásobník, ale do zeropage, z toho leze kód tak cca 2x horší, než od vývojáře (což asi není špatný, ale prostě MOS 6502 není "céčkovský" procesor, tím jsou spíš RISCy).
Cecko umoznuje programovat tak, ze nemas ani tuseni jake problemy mu zpusobujes. Umoznuje ti mit libovolny pocet parametru, volat fci a v ni dalsi fci, v kazde mit lokalni promenne.
Pouziva na to elegantni metodu, ze si kazda fce nejak uklada promenne na zasobnik. Kazda zanorena fce ma svoji oblast. Problem se Z80 je ten, ze to krasne ulozis na zasobnik, ale uz se pak k tomu krome posledni polozky nedostanes... Musis okolo toho delat nejakou dalsi rezii, aby k promennym byl pristup a ta rezie je mnohdy vetsi nez co resis.
Cecko se pak snazi vymyslet neco, co porusuje jeho vlastnosti, ktere od nej cekas. Napriklad zjisti, ze z te fce uz nic nevolas, je posledni, takze by ty promenne mohla mit stale v registrech (leaf function optimization).
Ale ty jsi odstinen tak, ze si neuvedomujes, ze prepravovat 1, 2, 3, 4 nebo i 5 osob v aute je neco jine nez mit tech osob (promennych) 6. Reseni bude jine, co fungovalo predtim uz nemusi.
Cecko pak musi premyslet, jak ohnout samotne zakladni reseni, aby bylo efektivni. S tim musi pocitat vsechno. Ze to co normalne plati, nemusi platit. Knihovny atd.
Nektere jazyky ti povoli jen globalni promenne a kupodivu, ty pak navrhnes reseni, co je mnohem lepsi a snazsi na prevod do asm.
Nektere jazyky maji navic emulovany zasobnik, ale jejich zakladni slova jsou zalozene na tom ze pohodlny pristup mas jen k posledni nebo predposledni polozce. To te nuti napsat to reseni zase jinym algoritmem. A ten prekladac ma usnadnenou praci, protoze misto aby se snazil prevest tvoji abstrakci na instrukcni sadu daneho procesoru si to udelal vicemene za nej ty.
V Cecku napises proste nejaky krasny abstraktni algoritmus, kde prekladac bude premyslet, pak zjisti ze existuje jediny pripad, kdy optimalizace nefunguje a tak ji zavrhne. I kdyz ty vis ze takova data nikdy nedostane, ale napsal si to tak ze on to nepozna. Vubec nevis ze mu hazes klacky pod nohy.
V asm naopak vis, ze kdyz neco treba pretece, tak to je presne ten trik ktery vyuzijes, aby to bylo efektivnejsi. Nebo jakakoliv jina specialni vlastnost daneho procesoru.
Z80 a 6502 jsou tak odlisne pristupy, ze i kdyz delas benchmark tak prijdes na to, ze i ty algoritmy budes mit jine, protoze pro kazdy CPU se hodi jine reseni. Takze i ty klacky co mu hazes pod nohy, muzou byt pokazde nekde jinde.
Proste tyto procesory jsou z doby, kdy C nebylo vsude a kdy jim jeste instrukcni sada nesla naproti.
Existuje takova pekna uloha z rossetacode co zjistuje zda dany retezec je pangram a nebo neni. Tzn. zda obsahuje vsechny pismena abecedy.
Je to jednoducha uloha, ale uz pocet osob se nevleze do jedineho auta.
#include <stdio.h>
int is_pangram(const char *s)
{
const char *alpha = ""
"abcdefghjiklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char ch, wasused[26] = {0};
int total = 0;
while ((ch = *s++) != '\0') {
const char *p;
int idx;
if ((p = strchr(alpha, ch)) == NULL)
continue;
idx = (p - alpha) % 26;
total += !wasused[idx];
wasused[idx] = 1;
if (total == 26)
return 1;
}
return 0;
}
int main(void)
{
int i;
const char *tests[] = {
"The quick brown fox jumps over the lazy dog.",
"The qu1ck brown fox jumps over the lazy d0g."
};
for (i = 0; i < 2; i++)
printf("\"%s\" is %sa pangram\n",
tests[i], is_pangram(tests[i])?"":"not ");
return 0;
}
ja to pojal jako benchmark tak ze udelam 32 bitove binarni pole
#include <stdio.h>
int pangram(const char * str)
{
str--;
unsigned char c;
unsigned long int alphabet = 0;
while (c = *++str) {
c |= 32; // uppercase
c -= 'a';
if ( c<26 ) alphabet |= (long unsigned int) 1 << c;
}
return alphabet==0x3FFFFFF;
}
int main()
{
char *str = "The five boxing wizards jump quickly.";
unsigned int i;
for (i = 10000; i > 0; i--)
pangram(str);
printf("%d\n", pangram(str));
return 0;
}
podle vzoru
: pangram? ( addr len -- ? )
0 -rot bounds do
i c@ 32 or [char] a -
dup 0 26 within if
1 swap lshift or
else drop then
loop
1 26 lshift 1- = ;
s" The five boxing wizards jump quickly." pangram? . \ -1
Tohle funguje jen pokud ma forth 32 bitove a vetsi slova.
pseudo forth 16bit kod:
: pangram ( addr -- ? )
1-
0.
BEGIN
ROT 1+ -ROT 2OVER NIP C@ 0 C<> WHILE 2OVER NIP C@
32 OR [CHAR] a -
DUP 26. WITHIN IF
DBITSET ( d index -- d )
ELSE DROP THEN
REPEAT
67108863. D= NIP ;
A kdyz to zkompilujes z88dk nebo forthem, tak C je 6x pomalejsi.
Docela by me zajimalo i jak si vede C prekladac pro 6502. Z80 to trvalo 2m 51.61s a ten jeho kod uplne zkolaboval a jak ten kod pro sebe rozkouskoval na male casti a ty prevadel do asm tak je to kolikrat ze neco spocita a uklada na "stack" a pak to hned zase vraci do stejnych registru a pouzije znova...
Poprve v zivote jsem si naistaloval cc65 a atari800 a vyzkousel to.
str--; unsigned char c; unsigned long int alphabet = 0;
Tady mu vadilo ze pred deklaraci je uz to str-- i kdyz se neumi vyjadrit a zahltil me nesmyslnymi chybovymi vypisy.
Atarko to spocita asi za cca 4m 19s.
Resit to pres 32 bitove pole je ale takove lidske Z80 asm reseni... Ani jeden prekladac to moc nedava. z88dk nedokaze pochopit myslenku, jen vi ze nema misto na to drzet si v registrech trvale 32 bit cislo, tak zacina zonglovat ho neustale ukladat tim nejpomalejsim resenim do RAM a znovu zpet. Znova a znova. Protoze uz si nepamatuje ze s nim pracoval v predchozim kroku, nebo v pristim znovu bude.
A 6502 se to taky nelibi, ten by chtel to mit jako 26 bajtove pole v rychle strance i kdyz to musi cele nulovat. A asi prekladac pro Z80 by vyplodil neco rychlejsiho timto resenim. Protoze to nastavovani nekonstantniho bitu neni uplne trivialni.
Overoval jsem to a u Z80 se jednalo o sdcc prekladac.
zcc asi neumi 32 bitove hodnoty?
Ale po uprave na dve 16 bitove to spocital asi za cca 38 sekund, vypsal 1 a pak se to zhroutilo. Je to ale uz je jiny program, ktery uz nema problem, ze se vsechno nevleze do registru. Slozitejsi C kod, ale lepsi vysledek v asm.
int pangram(const char * str)
{
unsigned int alphabet_lo = 0; // a..p
unsigned int alphabet_hi = 0; // q..z
unsigned char c;
while (c = *str++) {
c |= 32; // uppercase to lowercase
c -= 'a';
if (c < 16) alphabet_lo |= 1 << c;
else if (c < 26) alphabet_hi |= 1 << (c-16);
}
return (alphabet_lo == 0xFFFF) && (alphabet_hi == 0x03FF);
}
PS: Udelat ty promenne globalni, teda na staticke adrese by to zrychlilo a i vzhledem k jednodusimu kodu/pristupu se usetrilo i misto.
8. 3. 2026, 20:42 editováno autorem komentáře