Pamatuji si, že zmiňované "assemblery" (tak jsme ji říkávali) se do mého zorného pole dostaly někdy v době, kdy jsem něco slyšel o Pascalu a že ve v Pascalu nemusí číslovat řádky. Protože jsem někde získal ATMAS II https://atariwiki.org/wiki/Wiki.jsp?page=Atmas%20II a tam se řádky číslovat nemusely, zkoušel jsem v něm něco dělat. Jakmile jsem sehnal českou dokumentaci z nějakého Atari klubu, nebylo co řešit - mé opovržení číslováním řádků dosáhlo vrcholu a Basic jsem vzal na milost pouze jako Turbo Basic s příkazem RENUM. :-)
Nicméně ne všechny programy pro Atari byly psány přímo na Atari. Např. Rescue on Fractalus byl vyvíjen na sálovém počítači VAX https://en.wikipedia.org/wiki/Rescue_on_Fractalus!
Díky za doplnění. Ano, Atari a později velké herní společnosti si mohli dovolit crossplatform vývoj (to asi bylo hodně drahé). My ostatní se museli spokojit s kazeťákem popř. kazeťák+cartridge (u nás), popřípadě disketovka+cartridge (takový sen; jak už jsem psal, tak atarácké disketovky byly naprosto nechutně drahé).
Jinak ten MAC/65 umí automatické číslování řádků. Má to svoje výhody i nevýhody (hlavně na klávesnici Atari, kde jsou šipky přes Control).
Teda, já už úplně zapomněl, že i MAC/65 čísloval řádky... Nikdy jsem s tím nezískal praxi, protože jsem jeden z těch "zdánlivě bláznivých", kdo používali monitor TM2304 a čtverečkovaný papír. Proto mi to neutkvělo v paměti. To je teda šílenost, vždyť se vždycky uváděla jako jedna z hlavních nevýhod psaní přímo do paměti potřeba přesouvat kód, když chtěl člověk "psát něco nového doprostřed" - to ale tady s ručním přečíslováváním nesmyslných čísel řádků vůbec není rychlejší!
Navíc na počítači s cca 20 řádky na obrazovce je stejně potřeba mít celý program na papíře...
Co považuju naopak za úplně úžasnou funkci je to krokování programu. Fakt to fungovalo? Pamatuje si to někdo ještě z té doby?
to krokování se dělalo klávesou OPTION a docela dobře fungovalo. Interně to (asi) bylo řešené tak, že tam DDT vkládat BRK. Takže teoreticky, kdyby program dělal třeba self modifikaci, tak to selže.... hmm to si musím vyzkoušet :-)
To jsem zvědavý :)
Já to dělal ručně - testoval jsem si takhle rutinu po rutině s návratem do monitoru.
Ještě k těm přesunům: monitor měl funkci Q - readddr.: přesun bloku s tím, že si ho disassembluje a změní argumenty JMP, JSR a LDA/STA pokud jsou absolutní a vedou do této oblasti. Pochopitelně to nevychytává všechno, např. odkazy na tyto adresy v kódu mimo přesouvanou část, ale těch bylo minimum, při rozumné organizaci kódu.
Což mi připomíná, že mi vždycky bylo z tohoto důvodu líto, že není i instrukce BNC - Branch No Condition - aby člověk mohl mít relativní skoky i bez podmínek a právě se tím nemusel zabývat. Možná jste si všimli v kódu G-driveru, že tam to na pár místech simuluji tím, že znám nastavení flagů v daném místě kódu :)
25. 8. 2026, 15:06 editováno autorem komentáře
Ne, 8088 už měl příznak TF (=Trap Flag) ve status registru, který když byl nahozený, tak se po provedení každé instrukce vyvolalo sw přerušení (novější terminologií bychom řekli výjimka).
Aha, zajimave. Z nejakyho duvodu jsem si myslel, ze debugger cpal na kazdou predpovezenou nasledujici adresu trap/restart.
S tím BRK snad, ale klon 6502 použitý v Atari měl právě u tohoto příkazu nějaký problém, kdy se po realizaci instrukce BRK a ukončení její obsluhy nepokračovalo na instrukci (byte) za ní bezprostředně následujícím (BRK + 1) ale až na BRK + 2. Pamatuji, když jsem na své z Kanady importované stotřicítce nemohl nahrát Mercenary. Nejdříve krátký zavaděč a potom nějaké dlouhé bloky. V zavaděči byl test PAL/NTSC a když NTSC, tak konec. Podařilo se mi to odstranit náhradou nějaké instrukce v tom zavaděči právě dvěma BRKy, přičemž ten druhý, jak jsem později zjistil, by se nikdy nerealizoval.
Jojo, ten druhý bajt se údajně používal pro identifikaci, který BRK to byl, když jich bylo více. Dalo se to vytáhnout čtením návratové adresy ze zásobníku a nějaký offset k tomu.
Heh, google mi teď našel https://breq.dev/2025/04/23/6502/ - tam to je popsáno u BBC Micro. A také že Apple III používalo BRK <číslo> jako volání systémových funkcí. Fí ha, člověk se pořád učí. :-)
zajimave, takze self-modified kod to i pri krokovani zvlada. DDT je sofistikovanejsi, nez se zda ;) A nebo to zkousim spatne:
01 .OPT OBJ
02 *= $9000
03 LDA #0
04 STA $9005
05 INX
(myslenka je asi jasna: namisto INX se zapise instrukce BRK. A DDT to umozni krokovat...tj nevrati tam INX ale ponecha BRK)
Jo, to asi projde, protože opravdu poctivě vykonává instrukci po instrukci, takže tou dobou, kdy se k tomu má dostat, už v té paměti je, co tam má být. Mě dostalo, že mu krokování funguje i v ROM, např.:
10 *=cokoli
20 JSR $C0DF
Pak bych chtěl poděkovat Wikipedii za ponouknutí vyzkoušet:
10 *=$0600
20 LDA $4
2.5E1 STA 712
0.3E2 BRK
Taková blbost, ale mě to prostě pobavilo :)
no moje teorie byla, ze pred provedenim STA se za tuto instrukci musi vlozit BRK a po provedeni obnovit puvodni INX (nebo cokoli jineho tam bylo).
Já nejdřív nepochopil přesně ten timing, proč ho to mělo rozbít, to se omlouvám, už tomu rozumím, jak to bylo myšleno. Ale všechno zlé je pro něco dobré: paralelně jsem vyzkoušel ten odskok do ROM a tam se už potvrdilo na 100%, že to musí dělat jinak, protože jenom fakt machři umějí zapsat nejen BRK ale cokoliv do ROM :)
Moje první hypotéza je, že to dělá opačným směrem: nakopíruje si pokaždé tu jedinou instrukci někam do svého bufferu, kde má za ní BRK. Není to dokonalá hypotéza, protože proti ní trošku hovoří relativní skoky. To by musel mít ten buffer alespoň 256 bytes a musel by být plovoucí.
Asi vypadá zbytečně dělat hypotézy, když by bylo možné analyzovat přímo ten kód debuggeru nebo ještě líněji najít někoho, kdo už to udělal a napsal o tom na internet :D Ale baví mě to zamýšlení se, se znalostí architektury stroje, co by bylo možné.
Poku je kód v RAM, používá se BRK pro krokování, BPT i step out, když je kód v EPROM, tak DDT sw emuluje 6502 nad stínovými registry.
"atarácké disketovky byly naprosto nechutně drahé"
ona ta disketovka v ty dobe stala zhruba totez, co to atarko (nove cca 10kKc, rekneme rok 85, ovsem cena zalezela na znamostech/kurzu bonu/pristupku k zapadnim menam ...) a navic byla prakticky nesehnatelna, uplne stejne jako diskety do ni. Nadto kapacita oturbeny kazety byla vyrazne lepsi.
V nejmodernejsi variante mela totiz ta disketovka 180kB jedno nebo 360kB oboustrana. Na jednu stranu prumerne oturbene 90min kazety se dalo naladovat +- 10MB. I uplne bez turba byla kapacita takovy pasky neco kolem 3MB na jednu stranu. Takze se bavime zhruba o pomeru 1:20 ale taky klidne 1:200+ ... a samozrejme i tohle byl jeden z tech duvodu, proc ty disketovky nikdo nijak zvlast neresil.
Maximalne v dobach PC si nadsenci vyrobili redukci na standardni PC disketu. A v dobach soucasnych ... mel sem v ruce cardridge, uvnitr bylo pico. Po startu z toho najela miniappka se seznamem "disket" (tech tam bylo asi tak mililon ...) a po "zasunuti" diskety se s tim uz dalo presne stejne jako s tou disketovkou fungovat.
Je to tak. Jen dodám, že my jsme tehdy byli velmi specifický "trh": pravděpodobně v dobách rozmachu 8bit Atari na Západě nikdy běžný uživatel neměl tolik SW jako my tady. Zaprvé my jsme k tomu přišli později, takže ho bylo celkově mnohem víc, a zadruhé tam bylo zvykem za věci platit. Takže u nás ten poměr počet dostupných disket na počet vlastněného SW byl řádově jiný...
Typicky se tak na disketu dával SW, který s ní pak aktivně pracoval: buď hry, které si dohrávaly své další části (International Karate byl z diskety bohatší než z kazety, myslím) nebo uživatelské programy jako textový editor Čapek (počeštěný SpeedScript), TurboBasic apod.
Nebo samozřejmě hra/-y, které byly zrovna v kursu a hrály se mockrát za den :D
Je to tak, některé verze her pro kazetu byly osekané, např. takový Jumpman měl variantu Jumpman Junior, která byla pro kazety a byla osekaná o úrovně. Ale technicky šlo i průběžně donahrávat z kazety, ja vím, že jsme takhle s bráchou hráli Gauntlet. Ale spíš se tomu tvůrci vyhýbali, už jen co si pamatuji, tak často nahrávání nové úrovně z kazety toho Gauntletu končilo zásekem hry, takže to byl pro nás i konec hry.
Jinak Německo, Československo a Polsko mělo opravdu velké zastoupení vlastníků, nadšenců a programátorů. Ale pojem "legální SW" tu asi znal málokdo. Minimálně na malém městě, natož aby u nás byla oficiální prodejna. Však hry se buď získávaly kopírováním od známých, nebo byla hromada inzerátů v Annonci a podobných, kde na vyžádání poslal inzerent seznam, člověk si zaškrtal, co chce, poslal to zpátky, a došla mu na dobírku kazeta s vybraným SW.
Goonies znám, ale na dodatečný loading se nepamatuji. Buď byla osekaná verze na kazetu, nebo už jsou osekané mé vzpomínky.
Existovala verze hry pro rozšířenou pamět a tam se pak úrovně nedočítaly. Ale jak originální kazetová verze tak i naše turbo verze úrovně dočítaly.
i Jumpman (Senior) byl IMHO na kazete. I kdyz mozna to je dilo nekoho z CSSR/CSFR, kdyz prevadel disketovou verzi do Turba.
však to má jen 34 kB, to se snad dá nahrát na jeden zátah, maximálně nadvakrát (Ninja).
https://a8.fandal.cz/detail.php?files_id=4116
Aha, tak už jsem si našel původní informaci, ten Junior byl zmenšen ne kvůli kazetě, ale kvůli vydání na cartridge, aby se ušetřilo za paměťové čipy. No tak v tom případě my měli doma bohužel jen Junior verzi na kazetě.
Těch 10 MB na kazetě je opravdu plus minus. 90 minut x 60 sekund x 3600 bitů za sekundu děleno 8 vychází na 2 430 000 bajtů, tedy kolem 2 MB.
No právě - v Pascalu se řádky skutečně číslovat nemusely Nebo spíš - pro účely překladače - přímo v kódu, ani nemohly. Ale chtělo už to mít na tom prostředí k dispozici nějaký slušný celobrázkový editor, kde by se ta vkládání a přesuny řádku daly provádět přímo při psaní kódu.
Což byl často problém i později, Jak si nemnozí vzpomenou, tak ještě v MS DOSu byl standardně přibalen edlin - řádkový editor. Který při listingu na obrazovku sám zobrazoval pořadová čísla řádků v souboru.
A právě skrze ta zobrazená pořadová čísla řádků pak programátor interními příkazy prováděl editaci souboru.
Změn řádek č. 25 na, zruš řádek 50, nebo "vlož za řádek 99 nový - a při příštím listingu se ta aktuální pořadová čísla řádků sama aktualizovala..
Dalším příkladem byl cross-assembler CAMAC, běžící na minipočítači Data General. Minipočítač přišel v roce 1981 na $100,000 (přibližně $360,000 v roce 2026). To se mohlo vyplatit bohaté společnosti s mnoha vývojáři.
Ale myslím, že tehdejší hodně nadupané IBM PC (ne AT, ne XT) s 384 KB RAM by nějaký ten cross-assembler zvládlo. Byť jen pro jednoho uživatele.
Commodore +4/16/116 mel celkem kvalitni monitor i s disasseblerem a assemblerem.
Navic umel 'nemazat' pamet pri resetu, pokud se drzela klavesa BREAK :-)
Takze celkem 'jednoduse' slo zjistit na jake adrese je pocet zivotu - vypsat si na papir(!) adresy v pameti s touto hodnotou.
Pak znovu spustit hru, pri dalsi ztrate zivotu (jine cislo) opet BREAK + RESET a znovu hledani tohoto cisla. Po par pokusech se podarilo najit misto pameti a pak uz se pres disassembler dalo najit, kde v programu se na dane misto zapisuje.
Samozrejme ze nektere hry mely pocet zivotu v BCD, nektere v ASCII, ale co, byli jsme mladi (zakladni skola, gympl) a bylo hromadu casu a zadne povinnosti .......
25. 8. 2026, 10:07 editováno autorem komentáře
1 ; ============================================ 2 ; SNAKE GAME — Atari 8-bit (XL/XE) 3 ; Assembler: MADS (mads snake.asm -o:snake.xex) 4 ; Input: Joystick port 1 5 ; ============================================ 6 7 ; --- OS / Hardware Equates --- 8 RTCLOK = $0014 ; jiffy clock (~60 Hz NTSC) 9 SAVMSC = $0058 ; screen memory pointer 10 STICK0 = $0278 ; joystick 0 11 COLOR1 = $02C5 ; text luminance 12 COLOR2 = $02C6 ; background 13 COLOR4 = $02C8 ; border 14 RANDOM = $D20A ; hardware RNG 15 CH = $02FC ; last key pressed 16 ATRACT = $004D ; attract-mode timer 17 CRSINH = $02F0 ; cursor inhibit (1=off) 18 NMIEN = $D40E ; NMI enable 19 20 ; Screen geometry (Graphics 0 = ANTIC mode 2) 21 SCRW = 40 22 SCRH = 24 23 24 ; Internal screen character codes 25 CH_SPACE = $00 26 CH_WALL = $E0 ; inverse space (solid block) 27 CH_BODY = $14 ; diamond body segment 28 CH_FOOD = $00+$80 ; inverse space for food pellet 29 CH_HEAD = $13+$80 ; inverse 'S' 30 31 ; Joystick bit patterns 32 JOY_UP = 14 33 JOY_DOWN = 13 34 JOY_LEFT = 11 35 JOY_RIGHT = 7 36 37 ; --- Zero-page variables --- 38 ZPTMP = $80 ; 2-byte pointer 39 ZPTMP2 = $82 ; 2-byte pointer 40 HEADIDX = $84 ; ring-buffer head index 41 TAILIDX = $85 ; ring-buffer tail index 42 DIRX = $86 ; direction X: $FF / $00 / $01 43 DIRY = $87 ; direction Y: $FF / $00 / $01 44 HEADX = $88 ; current head column 45 HEADY = $89 ; current head row 46 FOODX = $8A ; food column 47 FOODY = $8B ; food row 48 SCORE = $8C ; 2-byte BCD score 49 SPEED = $8E ; frames between moves 50 GROW = $8F ; segments left to grow 51 NEWX = $90 ; candidate head column 52 NEWY = $91 ; candidate head row 53 FOODCNT = $92 ; food-eaten counter (for speed ramp) 54 DEAD = $93 ; nonzero = game over 55 56 ; Ring buffers — 256 entries each, page-aligned 57 RING_X = $0600 58 RING_Y = $0700 59 60 ; ============================================ 61 org $2000 62 ; ============================================ 63 64 ; ---------- ENTRY ---------- 65 Start 66 lda #0 67 sta NMIEN ; blank screen during setup 68 69 lda #$0E ; bright white text 70 sta COLOR1 71 lda #$94 ; dark blue playfield 72 sta COLOR2 73 lda #$00 ; black border 74 sta COLOR4 75 76 lda #$40 77 sta NMIEN ; VBI on, DLI off 78 79 lda #1 80 sta CRSINH ; hide cursor 81 82 ; ---------- NEW GAME ---------- 83 NewGame 84 lda #0 85 sta SCORE 86 sta SCORE+1 87 sta DEAD 88 sta HEADIDX 89 sta TAILIDX 90 sta FOODCNT 91 92 lda #8 ; ~7.5 moves/s (NTSC) 93 sta SPEED 94 lda #3 ; snake starts at length 4 95 sta GROW 96 97 lda #1 ; initial direction: right 98 sta DIRX 99 lda #0 100 sta DIRY 101 102 jsr ClearScreen 103 jsr DrawBorder 104 jsr DrawScore 105 106 lda #SCRW/2 ; place head at center 107 sta HEADX 108 sta RING_X 109 lda #SCRH/2 110 sta HEADY 111 sta RING_Y 112 113 ldx HEADX 114 ldy HEADY 115 lda #CH_HEAD 116 jsr PlotChar 117 118 jsr PlaceFood 119 120 ; "PRESS FIRE" prompt — row 10, col 14 121 lda SAVMSC 122 clc 123 adc #<(10*SCRW+14) 124 sta ZPTMP 125 lda SAVMSC+1 126 adc #>(10*SCRW+14) 127 sta ZPTMP+1 128 ldy #0 129 @title lda TitleMsg,y 130 beq @twait 131 sta (ZPTMP),y 132 iny 133 bne @title 134 135 @twait lda #0 136 sta ATRACT 137 lda $D010 ; TRIG0 hardware 138 bne @twait 139 140 ; erase prompt 141 lda SAVMSC 142 clc 143 adc #<(10*SCRW+14) 144 sta ZPTMP 145 lda SAVMSC+1 146 adc #>(10*SCRW+14) 147 sta ZPTMP+1 148 ldy #11 149 lda #CH_SPACE 150 @eclr sta (ZPTMP),y 151 dey 152 bpl @eclr 153 154 lda RTCLOK 155 sta DEAD ; reuse as last-clock seed 156 ; (DEAD is cleared below before loop) 157 158 lda #0 159 sta DEAD 160 161 lda RTCLOK 162 sta FOODCNT ; (reuse byte briefly; reset below) 163 lda #0 164 sta FOODCNT 165 166 ; ---------- MAIN LOOP ---------- 167 GameLoop 168 lda #0 169 sta ATRACT 170 171 ; --- speed gate --- 172 @wait lda RTCLOK 173 sec 174 sbc FOODCNT ; FOODCNT doubles as "last tick" here 175 ; Oops — I'm reusing FOODCNT. Let me use a proper variable. 176 ; Actually let me just use the Y-indirect trick with RTCLOK. 177 ; I'll track "last clock" in a separate place. 178 ; Fix: use DEAD as temp... no. Let me just compare directly. 179 jmp @wait2 180 @wait2 181 ; Simple timing: busy-wait until SPEED jiffies have passed 182 ; since last move. Store last-move-clock at $94. 183 LASTCLK = $94 184 lda RTCLOK 185 sec 186 sbc LASTCLK 187 cmp SPEED 188 bcc @wait2 189 190 lda RTCLOK 191 sta LASTCLK 192 193 ; --- read joystick --- 194 jsr ReadJoy 195 196 ; --- compute candidate position --- 197 lda HEADX 198 clc 199 adc DIRX 200 sta NEWX 201 202 lda HEADY 203 clc 204 adc DIRY 205 sta NEWY 206 207 ; --- wall collision --- 208 lda NEWX 209 beq HitWall ; column 0 210 cmp #SCRW-1 211 beq HitWall ; column 39 212 lda NEWY 213 beq HitWall ; row 0 214 cmp #SCRH-2 215 bcs HitWall ; row >= 22 216 217 ; --- self collision (read screen) --- 218 ldx NEWX 219 ldy NEWY 220 jsr ReadChar 221 cmp #CH_BODY 222 beq HitSelf 223 224 ; --- food? --- 225 lda NEWX 226 cmp FOODX 227 bne NoFood 228 lda NEWY 229 cmp FOODY 230 bne NoFood 231 232 ; ate food 233 lda GROW 234 clc 235 adc #3 236 sta GROW 237 238 sed 239 lda SCORE 240 clc 241 adc #$10 ; +10 pts 242 sta SCORE 243 lda SCORE+1 244 adc #0 245 sta SCORE+1 246 cld 247 248 jsr DrawScore 249 250 ; speed ramp: every 5 pellets, decrease delay (min 3) 251 inc FOODCNT 252 lda FOODCNT 253 cmp #5 254 bne @noramp 255 lda #0 256 sta FOODCNT 257 lda SPEED 258 cmp #3 259 beq @noramp 260 dec SPEED 261 @noramp 262 jsr PlaceFood 263 264 NoFood 265 ; --- move snake --- 266 ; old head -> body 267 ldx HEADX 268 ldy HEADY 269 lda #CH_BODY 270 jsr PlotChar 271 272 ; update head coords 273 lda NEWX 274 sta HEADX 275 lda NEWY 276 sta HEADY 277 278 ; push into ring buffer 279 inc HEADIDX 280 ldx HEADIDX 281 lda HEADX 282 sta RING_X,x 283 lda HEADY 284 sta RING_Y,x 285 286 ; draw head 287 ldx HEADX 288 ldy HEADY 289 lda #CH_HEAD 290 jsr PlotChar 291 292 ; grow or trim tail 293 lda GROW 294 beq @trim 295 dec GROW 296 jmp GameLoop 297 298 @trim ; erase tail cell on screen 299 ldx TAILIDX 300 lda RING_X,x 301 sta NEWX ; temp reuse 302 lda RING_Y,x 303 sta NEWY 304 305 ldx NEWX 306 ldy NEWY 307 lda #CH_SPACE 308 jsr PlotChar 309 310 inc TAILIDX 311 jmp GameLoop 312 313 ; ---------- COLLISION ---------- 314 HitWall 315 HitSelf 316 ; flash screen 317 ldx #8 318 @flash lda #$34 319 sta COLOR1 320 jsr WaitFrames 321 lda #$0E 322 sta COLOR1 323 jsr WaitFrames 324 dex 325 bne @flash 326 327 ; "GAME OVER" — row 11, col 15 328 lda SAVMSC 329 clc 330 adc #<(11*SCRW+15) 331 sta ZPTMP 332 lda SAVMSC+1 333 adc #>(11*SCRW+15) 334 sta ZPTMP+1 335 ldy #0 336 @gmsg lda GameOverMsg,y 337 beq @gwait 338 sta (ZPTMP),y 339 iny 340 bne @gmsg 341 342 ; "PRESS FIRE" — row 13, col 14 343 @gwait2 344 lda SAVMSC 345 clc 346 adc #<(13*SCRW+14) 347 sta ZPTMP 348 lda SAVMSC+1 349 adc #>(13*SCRW+14) 350 sta ZPTMP+1 351 ldy #0 352 @pmsg lda TitleMsg,y 353 beq @gfire 354 sta (ZPTMP),y 355 iny 356 bne @pmsg 357 358 @gfire lda #0 359 sta ATRACT 360 lda $D010 361 bne @gfire 362 363 jsr WaitFrames ; debounce 364 jsr WaitFrames 365 jmp NewGame 366 367 ; ============================================ 368 ; SUBROUTINES 369 ; ============================================ 370 371 ; --- Read joystick, update direction (prevent reversal) --- 372 ReadJoy 373 lda STICK0 374 375 cmp #JOY_RIGHT 376 bne @nR 377 lda DIRX 378 cmp #$FF 379 beq @done ; block: already going left 380 lda #1 381 sta DIRX 382 lda #0 383 sta DIRY 384 rts 385 @nR cmp #JOY_LEFT 386 bne @nL 387 lda DIRX 388 cmp #1 389 beq @done 390 lda #$FF 391 sta DIRX 392 lda #0 393 sta DIRY 394 rts 395 @nL cmp #JOY_UP 396 bne @nU 397 lda DIRY 398 cmp #1 399 beq @done 400 lda #0 401 sta DIRX 402 lda #$FF 403 sta DIRY 404 rts 405 @nU cmp #JOY_DOWN 406 bne @done 407 lda DIRY 408 cmp #$FF 409 beq @done 410 lda #0 411 sta DIRX 412 lda #1 413 sta DIRY 414 @done rts 415 416 ; --- Clear screen (960 bytes) --- 417 ClearScreen 418 lda SAVMSC 419 sta ZPTMP 420 lda SAVMSC+1 421 sta ZPTMP+1 422 lda #CH_SPACE 423 ldy #0 424 ldx #4 ; 4 full pages = 1024 (> 960) 425 @pg sta (ZPTMP),y 426 iny 427 bne @pg 428 inc ZPTMP+1 429 dex 430 bne @pg 431 rts 432 433 ; --- Draw border walls --- 434 DrawBorder 435 ; top row (row 0) 436 lda SAVMSC 437 sta ZPTMP 438 lda SAVMSC+1 439 sta ZPTMP+1 440 ldy #SCRW-1 441 lda #CH_WALL 442 @top sta (ZPTMP),y 443 dey 444 bpl @top 445 446 ; bottom row (row 22) 447 lda SAVMSC 448 clc 449 adc RowLo+22 450 sta ZPTMP 451 lda SAVMSC+1 452 adc RowHi+22 453 sta ZPTMP+1 454 ldy #SCRW-1 455 lda #CH_WALL 456 @bot sta (ZPTMP),y 457 dey 458 bpl @bot 459 460 ; left + right columns (rows 1-21) 461 ldx #1 462 @side lda SAVMSC 463 clc 464 adc RowLo,x 465 sta ZPTMP 466 lda SAVMSC+1 467 adc RowHi,x 468 sta ZPTMP+1 469 470 ldy #0 471 lda #CH_WALL 472 sta (ZPTMP),y ; col 0 473 ldy #SCRW-1 474 sta (ZPTMP),y ; col 39 475 476 inx 477 cpx #22 478 bne @side 479 rts 480 481 ; --- Plot character (X=col, Y=row, A=char) --- 482 PlotChar 483 pha 484 lda RowLo,y 485 clc 486 adc SAVMSC 487 sta ZPTMP 488 lda RowHi,y 489 adc SAVMSC+1 490 sta ZPTMP+1 491 txa 492 tay ; Y = column for indirect index 493 pla 494 sta (ZPTMP),y 495 rts 496 497 ; --- Read character (X=col, Y=row -> A=char) --- 498 ReadChar 499 lda RowLo,y 500 clc 501 adc SAVMSC 502 sta ZPTMP 503 lda RowHi,y 504 adc SAVMSC+1 505 sta ZPTMP+1 506 txa 507 tay 508 lda (ZPTMP),y 509 rts 510 511 ; --- Place food at a random empty cell --- 512 PlaceFood 513 @retry lda RANDOM 514 and #$3F ; 0-63 515 cmp #38 516 bcs @retry 517 adc #1 ; 1-38 518 sta FOODX 519 tax 520 521 lda RANDOM 522 and #$1F ; 0-31 523 cmp #21 524 bcs @retry 525 adc #1 ; 1-21 526 sta FOODY 527 tay 528 529 jsr ReadChar 530 cmp #CH_SPACE 531 bne @retry ; occupied — try again 532 533 ldx FOODX 534 ldy FOODY 535 lda #CH_FOOD 536 jsr PlotChar 537 rts 538 539 ; --- Draw score on row 23 --- 540 DrawScore 541 lda SAVMSC 542 clc 543 adc RowLo+23 544 sta ZPTMP 545 lda SAVMSC+1 546 adc RowHi+23 547 sta ZPTMP+1 548 549 ; "SCORE:" label 550 ldy #1 551 @lbl lda ScoreLbl-1,y 552 beq @digits 553 sta (ZPTMP),y 554 iny 555 bne @lbl 556 557 @digits ; 4 BCD digits 558 lda SCORE+1 559 lsr 560 lsr 561 lsr 562 lsr 563 ora #$10 ; screen code '0' = $10 564 sta (ZPTMP),y 565 iny 566 567 lda SCORE+1 568 and #$0F 569 ora #$10 570 sta (ZPTMP),y 571 iny 572 573 lda SCORE 574 lsr 575 lsr 576 lsr 577 lsr 578 ora #$10 579 sta (ZPTMP),y 580 iny 581 582 lda SCORE 583 and #$0F 584 ora #$10 585 sta (ZPTMP),y 586 rts 587 588 ; --- Wait ~4 jiffies --- 589 WaitFrames 590 lda RTCLOK 591 clc 592 adc #4 593 sta ZPTMP2 ; temp 594 @wf cmp RTCLOK 595 bne @wf 596 rts 597 598 ; ============================================ 599 ; DATA 600 ; ============================================ 601 602 ; Row-start offsets (row * 40) 603 RowLo 604 .byte $00,$28,$50,$78,$A0,$C8,$F0,$18 605 .byte $40,$68,$90,$B8,$E0,$08,$30,$58 606 .byte $80,$A8,$D0,$F8,$20,$48,$70,$98 607 RowHi 608 .byte $00,$00,$00,$00,$00,$00,$00,$01 609 .byte $01,$01,$01,$01,$01,$02,$02,$02 610 .byte $02,$02,$02,$02,$03,$03,$03,$03 611 612 ; Screen-code strings (null-terminated) 613 ; ATASCII -> internal: chr - $20 (for $20..$5F) 614 ; 'P'=$30 'R'=$32 'E'=$25 'S'=$33 ' '=$00 615 ; 'F'=$26 'I'=$29 !=$01 616 ScoreLbl 617 .byte $33,$23,$2F,$32,$25,$1A,$00 ; "SCORE:" 618 619 ; "PRESS FIRE!" in screen codes 620 TitleMsg 621 .byte $30,$32,$25,$33,$33,$00,$26,$29,$32,$25,$01,$00 622 623 ; "GAME OVER" inverse (add $80) 624 GameOverMsg 625 .byte $A7,$A1,$AD,$A5,$80,$AF,$B6,$A5,$B2,$00 626 627 ; ============================================ 628 ; Run address 629 ; ============================================ 630 org $02E0 631 .word Start
Toz.. muzete to nekdo zkontrolovat? Psal to samozrejme cloude, ale neslo mu to. Hold toho ma na netu prilis malo k uceni :D A trvalo mu to 30minut... coz je na prumerny maly AI task docela hodne. Na druhou stranu ja bych se to 14dnuiucil a pak tyden psal. POdle zkusenosti "an technologii co znam, to blije obcas hrozny veci, taks e to bnojim pouzit na technlologii co neznam"... Tohle presen spada sem. Ale prekvapil ze zpatlal aspon neco vzheldem k tomu jak malo materialu je na netu
ahoj Jirko. Ze bych si AI slop dotahl i do Atarka, kdyz s tim v praci bojuju 8 hodin denne? No, zkusim tedy
Já tedy se přiznám, že takhle to tedy ze zásady nezkusím. Ne že bych věřil na to, že se mi do atárka dostane vir a znásilní mi papouška. Ale to je právě ta zásada - copak jsme to tu nečetli už tolikrát, zrovna na root.cz ??? Už o tom proběhlo tolik zpráviček, kolik projektů řeší zaplavení AI slopem, kdy je strašně snadné něco vygenerovat, a pak ti "autoři" (čti: přeposílači) očekávají, že tím zaměstnají skutečné vývojáře. Pardon, ale to podporovat nechci.
Minimálně emulátor Atari je k dispozici všem, na mnoha platformách. Očekávám tady tudíž zaslanou hotovou a odladěnou variantu, a ne za půl hodiny někomu vyrobit práci na několik hodin.
A naopak: jako každý fanda se rád podívám na tu člověkem odladěnou verzi, i kdyby k ní napsal, že se třeba trápí s jedním KONKRÉTNÍM problémem - a pokusím se mu s ním pomoct.
a to plne chapu. Jenze to je Jirka, on je chudak Javista (v lepsich casech jsme byli v jednom tymu), tak proc mu trosku nepomoci ;)
Jo, je to AI slop. Ja sam nebyl ochoten venovat cas tomu to hodit do emulatoru. Hlavne na tom neplytvej vic cyklu nez "rychle oko". Vzdycky kdyz mam k dispozici nejaky lepsi model, rad zkousim jak moc to neumi resit problemy (nejen programco), ktere nejsou na netu opsane milionkrat. Ted mam na chvili opus 4.neco, ale nemel jsem problem k vyzkouseni, protoze uz mi dosli technologie ktere "to nezna" a "ja dokazu zkontrolovat". Navic kdyz tomu das hada v "normalnim" jazyce, ma to za minutu napsany, a docela hezky. Tak sem chtel zkusit. Ale trvalo mu to tak dlouho ze jsem oddriftoval jinam. Z dnesniho raniho pohledu je to normlani spam.
Kdyz sme u te javy, tak dycky modely nachytam na novych JEPech. Jednoduse z vise zminenych duvodu: protoze je nikdo nerozpitval milionkrat (minimlane v dobe generovani modelu).
takže po přepisu do ca65 (sorry, ale kvůli MADS jsem si Pascal nestahoval :-)
1) nějaká návěští se musela opravit
2) ovšem AI "zapoměla" na to, že cíle skoků jsou jen v rozsahu jednoho (signed) bajtu
ca65 snake1.asm -t atari -o snake1.o -l snake1_list.asm --list-bytes 100
snake1.asm(209): Error: Range error (158 not in [-128..127])
snake1.asm(211): Error: Range error (154 not in [-128..127])
snake1.asm(213): Error: Range error (150 not in [-128..127])
snake1.asm(215): Error: Range error (146 not in [-128..127])
snake1.asm(222): Error: Range error (135 not in [-128..127])
Možná mašinu přesvědčit, ať dodržuje specifikaci MOS 6502? :-)
[kupodivu to nenasekalo žádné syntaktické chyby]
26. 8. 2026, 11:31 editováno autorem komentáře
tak ja ho zminim mozna prespriste. Na kazete jsem ho mel (dvojku), ale vlastne tehdy bez manualu k byla magicka nepochopitelna vec.
Což mi připomělo, že tehdy byla docela běžná praxe zkoušet, co která klávesa dělá (třeba Ctrl+něco) a pak se podělit s kamarády. Takové distribuované AI, vlastně Natural I. Šmarja, to byly sice krásné časy mládí, ale jinak hrůza pomyslet. Vlastně dnes je to podobné - kdo má detailní návod k mobilu?
Jo, rychlost šíření informace a tím pádem schopnost jedince poskládat informace do většího celku byla dost obtížná. Ale lidi se zařídili podle toho - jako v každé době.
Třeba z dnešního pohledu to mělo jeden efekt, který mi z mladších málokdo věří: počítače byly společenská záležitost. A to jak jednotlivě (doma u kohokoli s počítačem se sešlo dalších 1-5 kamarádů), tak i pak na vysoké - počítačový lab byl zároveň společenská místnost, kde se člověk seznámil napříč ročníky a probral úplně cokoli. Snad neexistovalo, že by u jednoho kompu seděl člověk sám, pokud vyloženě neprosil, ať ho ignorujeme, že finišuje bakalářku :) Ostatně, existovaly hry typu Červi, založené na tom, že 4-6 lidí stálo u jedné klávesnice (nebo i 8?) - a každý měl své dvě klávesy :) Dneska bychom řekli: "Hm... A jak se to připojuje online?" a hráli každý ze svého pokoje, i když kámoš bydlí o tři baráky vedle...
nezapomenout na Tank wars! a později Scorched Earth. To mělo i stránku smlouvání ("hele když mě teď nesejmeš, tak ti další dva tahy dám pokoj a odstřelíme napřed Honzu")
Fanouškům Scorched Earth bych doporučil hru Destruct, která je tajnou součástí hry Tyrian od Epic Megagames. Sice jen pro dva hráče, ale řežete se navzájem v reálném čase.
Pamatujete nekdo na jazyk "Action!"? V tom jsem zase programoval ja. Krome Turbo Basicu. Assembler jsem (kvuli chybejici dokumentaci k Atari) pochopil az na PC.
27. 8. 2026, 17:24 editováno autorem komentáře
tak tak, zmiňuji ho v článku a bude o něm samostatný díl (ale nevím kdy :-). Dokonce jsem k tomu měl i nějaké přeložené manuály (nebo v polštině - prostě něco, co jsem tehdy dokázal přečíst, takže CZ, SK nebo PL).
Já si ho tehdy jen párkrát zkusil, inspirován pražským Zpravodajem, kde o něm pěli ódy na rychlost. Ale dostal jsem se k němu příliš pozdě, bohužel. Fakt byl tak dobrý? Prý se přímo v něm daly psát hry, jak byl ten překlad kvalitní. Ale to se mi nezdá - to měl podporu pro všechny ty grafické vymyšlenosti Atari?
Detaily uz si nepamatuju. Ale na wiki pisou: "BYTE in 1985 praised the compilation and execution speed of software written in Action!. Using the Byte Sieve benchmark as a test, ten iterations of the sieve completed in 18 seconds in Action!, compared to 10 seconds for assembly and 38 minutes in BASIC."
Coz se teda zda dost neuveritelny
27. 8. 2026, 22:17 editováno autorem komentáře
Podporu pro všechny grafické vymyšlenosti samozřejmě ACTION neměl. Ale nestál jim v cestě. Měl příkazy na rychlé přesuny dat mezi adresami, a to pro znalce grafiky na Atari stačí. A rychlé běžné příkazy na kreslení. Zároveň byl šitý na míru procesoru 6502 a dobře to koulel se zásobníkem.
Nejlepší knihovnu pro práci s grafikou na Atari má podle mne Mad Pascal, to je ovšem cross-kompilátor.
Když se nad tím zamyslýme, tak napsat univerzální knihovnu pro kreslení na Atari je mimořádný úkol. Napište algoritmus pro vykreslení kruhu přes 30 řádků v hrubé bitmapové grafice, další dva řádky se širokým textem, dalších 50 řádků v jemné bitmapové grafice, dalších 10 řádků v režimu GTIA a s kusy obrazové paměti rozsetými po celém adresním prostoru. Takové obrazovky nebyly nic neobvyklého. Na Atari se grafika nekreslila, na něm se na míru programovala...
... Zlatý videorežim 13H na PC.