Tämä konekielinen Commodore 64 -ohjelma piirtää Barnsleyn saniainen -nimisen fraktaalin bittikarttatilassa. Muuttujat ovat 32-bittisiä fixed-point lukuja joiden alimmat 24-bittiä merkitsee desimaaliosaa. Koodi on kirjoitettu xa-assemblerin syntaksille ja assemblerin erityisominaisuuksien käyttämistä on vältetty, joten muille syntakseille kääntämisen pitäisi olla helppoa. Koodin alussa on BASIC-headeri joten ohjelma voidaan ladata tavalliseen tapaan.
Koodissa on paljon optimoinnin varaa mutta sen jätän lukijan tehtäväksi. Jatkokehityksenä voisi myös yhdistää matriisifunktion laskemisen yhdeksi aliohjelmaksi jolle annetaan parametrit joko valmiista tai käyttäjän syöttämästä taulukosta. Myös koordinaattitaulukot luovat silmukat voisi muuttaa käyttämään itsemuokkautuvaa koodia jolloin koodin koko laskisi rajusti ilman merkittävää vaikutusta nopeuteen.
;barnsley.s ;Eino-Pekka Kanto ;2019 ;Saniainen lasketaan seuraavan matriisifunktion avulla: ; [a b] [ x ] [ e ] ;f(x, y) = [ ] [ ] + [ ] ; [c d] [ y ] [ f ] ;Seuraavassa taulukossa on parametrit funktiolle ja todennäköisyys p jolla parametrit valitaan: ;/-----------------------------------------\ ;| | a | b | c | d |e| f | p | ;|----------------------------------------| ;|f1| 0 | 0 | 0 | 0,16|0| 1,60| 0,01| ;|----------------------------------------| ;|f2| 0,85| 0,04|-0,04| 0,85|0| 1,60| 0,85| ;|----------------------------------------| ;|f3| 0,20|-0,26| 0,23| 0,22|0| 1,60| 0,07| ;|----------------------------------------| ;|f4|-0,15| 0,28| 0,26| 0,24|0| 0,44| 0,07| ;\----------------------------------------/ ; ;f1 luo saniaisen varren, f2 kopioi lehdykät, f3 luo suurimman vasemmanpuoleisen lehden ; ja f4 vastaavasti oikeanpuoleisen. tmp = $02 ;Muuttujat laitetaan nollasivulle x = $06 y = $0a x_prev = $0e y_prev = $12 multiplicand = $16 multiplier = $1a product = $1e y_table_l = $c000 ;Koordinaattitaulukot laitetaan osoitteisiin $c000, $c100, $c200 ja $c300 y_table_h = $c100 x_table = $c200 mask_table = $c300 .word $0801 ;Ohjelma ladataan BASIC-alueelle kohtaan $0801- * = $0801 basic: .word end_of_basic ;"SYS2061" eli hypätään oikean koodin alkuun .word 2019 .byte $9e .asc "2061" end_of_basic: .byte 0,0,0 start: LDA #$3b ;Laitetaan VIC korkean resoluution tilaan LDX #$08 STA $d011 STX $d016 LDA #$00 ;Laitetaan reunus mustaksi STA $d020 LDA $dd00 ;Ladataan akkuun rekisteri joka ohjaa mm. VIC-II muistipankkeja AND #$fc ORA #$03 ;Valitaan grafiikan muistialueeksi $0000-$3fff STA $dd00 ;Tallennetaan arvo takaisin rekisteriin LDA #$18 ;Valitaan värimuistiksi $0400-$07e7 ja bittikartaksi $2000-$3f40 STA $d018 LDY #$00 ;Nollataan laskuri clear_screen_l: LDA #$50 ;Bittikartta täytetään nollilla STA $0400,Y ;Tyhjennetään värimuisti STA $0500,Y STA $0600,Y STA $0700,Y LDA #$00 ;Edustan väriksi valitaan vihreä ja taustaväriksi musta STA $2000,Y ;Tyhjennetään bittikartta STA $2100,Y ;Tämä tapa vie paljon muistia mutta on nopea ajaa STA $2200,Y ;Vähemmän muistia vievä mutta hieman hitaampi tapa on käyttää itsemuuttuvaa koodia STA $2300,Y ;Sen jätän kuitenkin lukijan tehtäväksi STA $2400,Y STA $2500,Y STA $2600,Y STA $2700,Y STA $2800,Y STA $2900,Y STA $2a00,Y STA $2b00,Y STA $2c00,Y STA $2d00,Y STA $2e00,Y STA $2f00,Y STA $3000,Y STA $3100,Y STA $3200,Y STA $3300,Y STA $3400,Y STA $3500,Y STA $3600,Y STA $3700,Y STA $3800,Y STA $3900,Y STA $3a00,Y STA $3b00,Y STA $3c00,Y STA $3d00,Y STA $3e00,Y STA $3f00,Y LDA #$00 ;Nollataan myös koordinaattitaulukot STA y_table_l,Y STA y_table_h,Y INY ;Korotetaan laskuria kunnes se pyörähtää ympäri BNE clear_screen_l ;Jos laskuri ei ole nolla niin jatketaan LDX #200 ;Seuraavaksi tehdään seuraavanlainen taulukko välillä x = [0, 200] make_ytable_l: TXA ;Taulukko lasketaan funktiolla f(x) = (x mod 8) + (320 * floor(x/8)) LSR LSR LSR TAY ;Otetaan tulos talteen CLC ;Lasketaan 64*floor(x/8) ROL ;Alempi tavu on akussa ROL y_table_h,X CLC ROL ROL y_table_h,X CLC ROL ROL y_table_h,X CLC ROL ROL y_table_h,X CLC ROL ROL y_table_h,X CLC ROL ROL y_table_h,X STA y_table_l,X ;Tallennetaan alempi tavu CLC ;Koska 320*x = 256*x + 64*x niin ylätavu voidaan laskea yhteen suoraan TYA ADC y_table_h,X STA y_table_h,X TXA ;Lasketaan x mod 8 eli otetaan alimmat kolme bittiä muuttujasta x AND #$07 CLC ADC y_table_l,X ;Ja lasketaan se yhteen jo valmiiksi lasketun arvon kanssa STA y_table_l,X LDA y_table_h,X ADC #$00 ;Lasketaan taulukkoon mukaan myös bittikartan alkuosoite $2000 STA y_table_h,X CLC LDA y_table_h,X ADC #$20 STA y_table_h,X DEX ;Vähennetään laskuria CPX #$ff ;Tarkistetaan pyörähtikö laskuri jo ympäri BNE make_ytable_l ;Jos ei vielä niin jatketaan silmukkaa LDX #$00 make_xtable_l: TXA ;Tämä taulukko lasketaan funktiolla f(x) = 8 * floor(x/8) välillä x = [0, 255] AND #$f8 ;Eli otetaan laskurista vain 5 ylintä bittiä STA x_table,X TXA ;Tehdään samalla maskitaulukko eli lasketaan toiseen taulukkoon AND #$07 ; funktio f(x) = 2 ^ (7 - (x mod 8)) välillä x = [0, 255] TAY LDA mt_template,Y ;Huijataan vähän ja haetaan oikea arvo maskitaulukosta STA mask_table,X INX ;Jos laskuri on yli 255 niin lopetetaan BNE make_xtable_l LDA #$ff ;Asetetaan SID tuottamaan satunnaislukuja STA $d40e STA $d40f LDA #$80 STA $d412 ;Nyt satunnaislukuja saa osoitteesta $d41b LDA #$00 ;Tyhjennetään muuttujia STA x_prev STA x_prev+1 STA x_prev+2 STA x_prev+3 STA y_prev STA y_prev+1 STA y_prev+2 STA y_prev+3 JMP mainloop_start ;Hypätään pääsilmukkaan ;Huomaa että fixed-point luvut ovat muodossa Q8.23 mainloop: LDA x ;Koska x on välillä ]-2,1820; 2,6558[ ja y [0; 9,9983[ niin x-koordinaatteihin CLC ; täytyy lisätä 2,3 ja kertoa se luvulla 51 ja y-koordinaatti täytyy ADC #$cd ; kertoa luvulla 20 STA multiplicand LDA x+1 ADC #$cc STA multiplicand+1 ;Kerrotaan x+2,3 luvulla 51 LDA x+2 ADC #$4c STA multiplicand+2 LDA x+3 ADC #$02 STA multiplicand+3 LDA #$00 STA multiplier STA multiplier+1 STA multiplier+2 LDA #$33 STA multiplier+3 JSR multiply LDA product+6 STA tmp LDA y ;Kerrotaan y luvulla 20 STA multiplicand LDA y+1 STA multiplicand+1 LDA y+2 STA multiplicand+2 LDA y+3 STA multiplicand+3 LDA #$00 STA multiplier STA multiplier+1 STA multiplier+2 LDA #$14 STA multiplier+3 JSR multiply LDA #$c8 ;Käännetään kuva ympäri ts. y=200-y SEC SBC product+6 TAY LDX tmp JSR plot_pixel ;Piirretään pikseli LDA x ;Kopioidaan vanhat x- ja y-muuttujat talteen STA x_prev LDA x+1 STA x_prev+1 LDA x+2 STA x_prev+2 LDA x+3 STA x_prev+3 LDA y STA y_prev LDA y+1 STA y_prev+1 LDA y+2 STA y_prev+2 LDA y+3 STA y_prev+3 mainloop_start: LDA #$00 STA x STA x+1 STA x+2 STA x+3 STA y STA y+1 STA y+2 STA y+3 LDA $d41b ;Ladataan akkuun satunnaisluku CMP #4 ;f1 todennäköisyys on 0,01 BCS cmp1 ;Tarkistetaan onko satunnaisluku pienempi kuin todennäköisyys JMP f1 cmp1: CMP #221 ;f2 todennäköisyys on 0,85 BCS cmp2 JMP f2 cmp2: CMP #238 ;f3 todennäköisyys on 0,07 BCS cmp3 JMP f3 cmp3: JMP f4 ;f4 todennäköisyys on 0,07 f1: LDA #$00 ;x = 0 STA x STA x+1 STA x+2 STA x+3 LDA y_prev ;y = y_prev * 0,16 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$c2 STA multiplier LDA #$f5 STA multiplier+1 LDA #$28 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA y LDA product+4 STA y+1 LDA product+5 STA y+2 LDA product+6 STA y+3 f1_end: JMP mainloop ;Hypätään takaisin pääsilmukkaan f2: LDA x_prev ;x = x_prev * 0,85 STA multiplicand LDA x_prev+1 STA multiplicand+1 LDA x_prev+2 STA multiplicand+2 LDA x_prev+3 STA multiplicand+3 LDA #$9a STA multiplier LDA #$99 STA multiplier+1 LDA #$d9 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA x LDA product+4 STA x+1 LDA product+5 STA x+2 LDA product+6 STA x+3 LDA y_prev ;x = x + y_prev * 0,04 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$70 STA multiplier LDA #$3d STA multiplier+1 LDA #$0a STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA x CLC ADC product+3 STA x LDA x+1 ADC product+4 STA x+1 LDA x+2 ADC product+5 STA x+2 LDA x+3 ADC product+6 STA x+3 LDA y_prev ;y = y_prev * 0,85 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$9a STA multiplier LDA #$99 STA multiplier+1 LDA #$d9 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA y LDA product+4 STA y+1 LDA product+5 STA y+2 LDA product+6 STA y+3 LDA x_prev ;y = y - x_prev * 0,04 STA multiplicand LDA x_prev+1 STA multiplicand+1 LDA x_prev+2 STA multiplicand+2 LDA x_prev+3 STA multiplicand+3 LDA #$70 STA multiplier LDA #$3d STA multiplier+1 LDA #$0a STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA y SEC SBC product+3 STA y LDA y+1 SBC product+4 STA y+1 LDA y+2 SBC product+5 STA y+2 LDA y+3 SBC product+6 STA y+3 LDA y ;y = y + 1,6 CLC ADC #$9a STA y LDA y+1 ADC #$99 STA y+1 LDA y+2 ADC #$99 STA y+2 LDA y+3 ADC #$01 STA y+3 f2_end: JMP mainloop f3: LDA x_prev ;x = x_prev * 0,2 STA multiplicand LDA x_prev+1 STA multiplicand+1 LDA x_prev+2 STA multiplicand+2 LDA x_prev+3 STA multiplicand+3 LDA #$33 STA multiplier LDA #$33 STA multiplier+1 LDA #$33 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA x LDA product+4 STA x+1 LDA product+5 STA x+2 LDA product+6 STA x+3 LDA y_prev ;x = x - y_prev * 0,26 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$5c STA multiplier LDA #$8f STA multiplier+1 LDA #$42 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA x SEC SBC product+3 STA x LDA x+1 SBC product+4 STA x+1 LDA x+2 SBC product+5 STA x+2 LDA x+3 SBC product+6 STA x+3 LDA x_prev ;y = x_prev * 0,23 STA multiplicand LDA x_prev+1 STA multiplicand+1 LDA x_prev+2 STA multiplicand+2 LDA x_prev+3 STA multiplicand+3 LDA #$47 STA multiplier LDA #$e1 STA multiplier+1 LDA #$3a STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA y LDA product+4 STA y+1 LDA product+5 STA y+2 LDA product+6 STA y+3 LDA y_prev ;y = y + y_prev * 0,22 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$eb STA multiplier LDA #$51 STA multiplier+1 LDA #$38 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA y CLC ADC product+3 STA y LDA y+1 ADC product+4 STA y+1 LDA y+2 ADC product+5 STA y+2 LDA y+3 ADC product+6 STA y+3 LDA y ;y = y + 1,6 CLC ADC #$9a STA y LDA y+1 ADC #$99 STA y+1 LDA y+2 ADC #$99 STA y+2 LDA y+3 ADC #$01 STA y+3 f3_end: JMP mainloop f4: LDA y_prev ;x = y_prev * 0,28 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$14 STA multiplier LDA #$ae STA multiplier+1 LDA #$47 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA x LDA product+4 STA x+1 LDA product+5 STA x+2 LDA product+6 STA x+3 LDA x_prev ;x = x - x_prev * 0,15 STA multiplicand LDA x_prev+1 STA multiplicand+1 LDA x_prev+2 STA multiplicand+2 LDA x_prev+3 STA multiplicand+3 LDA #$66 STA multiplier LDA #$66 STA multiplier+1 LDA #$26 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA x SEC SBC product+3 STA x LDA x+1 SBC product+4 STA x+1 LDA x+2 SBC product+5 STA x+2 LDA x+3 SBC product+6 STA x+3 LDA x_prev ;y = x_prev * 0,26 STA multiplicand LDA x_prev+1 STA multiplicand+1 LDA x_prev+2 STA multiplicand+2 LDA x_prev+3 STA multiplicand+3 LDA #$5c STA multiplier LDA #$8f STA multiplier+1 LDA #$42 STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA product+3 STA y LDA product+4 STA y+1 LDA product+5 STA y+2 LDA product+6 STA y+3 LDA y_prev ;y = y + y_prev * 0,24 STA multiplicand LDA y_prev+1 STA multiplicand+1 LDA y_prev+2 STA multiplicand+2 LDA y_prev+3 STA multiplicand+3 LDA #$a4 STA multiplier LDA #$70 STA multiplier+1 LDA #$3d STA multiplier+2 LDA #$00 STA multiplier+3 JSR multiply LDA y CLC ADC product+3 STA y LDA y+1 ADC product+4 STA y+1 LDA y+2 ADC product+5 STA y+2 LDA y+3 ADC product+6 STA y+3 LDA y ;y = y + 0,44 CLC ADC #$d7 STA y LDA y+1 ADC #$a3 STA y+1 LDA y+2 ADC #$70 STA y+2 LDA y+3 ADC #$00 STA y+3 f4_end: JMP mainloop multiply: LDX #$00 ;X-rekisteri kertoo tuloksen etumerkin LDA multiplicand+3 BPL mult_skip1 ;Tarkistetaan tekijöiden etumerkit EOR #$ff ;Mikäli tekijä on negatiivinen niin se muutetaan positiiviseksi STA multiplicand+3 LDA multiplicand+2 EOR #$ff STA multiplicand+2 LDA multiplicand+1 EOR #$ff STA multiplicand+1 LDA multiplicand EOR #$ff CLC ADC #$01 STA multiplicand INX ;Jos etumerkki on - niin lisätään X-rekisteriin 1 mult_skip1: LDA multiplier+3 BPL multiply_start EOR #$ff STA multiplier+3 LDA multiplier+2 EOR #$ff STA multiplier+2 LDA multiplier+1 EOR #$ff STA multiplier+1 LDA multiplier EOR #$ff CLC ADC #$01 STA multiplier INX multiply_start: LDA #$00 ;Tyhjennetään tulon ylätavut STA product+4 STA product+5 STA product+6 STA product+7 LDY #$20 ;Tekijät on 32-bittisiä joten laitetaan laskuriin 32 mult_shift: LSR multiplier+3 ;Shiftataan kertojaa oikealle ja jos viimeinen bitti ROR multiplier+2 ; on 0 niin ei lisätä kerrottavaa tuloon. ROR multiplier+1 ROR multiplier BCC mult_rotate LDA product+4 CLC ADC multiplicand STA product+4 LDA product+5 ADC multiplicand+1 STA product+5 LDA product+6 ADC multiplicand+2 STA product+6 LDA product+7 ADC multiplicand+3 mult_rotate: ROR ;Pyöritetään akkua oikealle. Akussa on tulon ylin tavu STA product+7 ;Tallennetaan akku ja pyöritetään tuloa oikealle ROR product+6 ROR product+5 ROR product+4 ROR product+3 ROR product+2 ROR product+1 ROR product DEY ;Vähennetään laskuria ja poistutaan jos ollaan menty nollaan BNE mult_shift mult_end: TXA ;Jos X on 1 niin tulon etumerkin pitää olla negatiivinen ja se muutetaan AND #$01 BEQ mult_out ;Muuten poistutaan aliohjelmasta LDA product+7 EOR #$ff STA product+7 LDA product+6 EOR #$ff STA product+6 LDA product+5 EOR #$ff STA product+5 LDA product+4 EOR #$ff STA product+4 LDA product+3 EOR #$ff STA product+3 LDA product+2 EOR #$ff STA product+2 LDA product+1 EOR #$ff STA product+1 LDA product EOR #$ff CLC ADC #$01 STA product mult_out: RTS plot_pixel: LDA y_table_l,Y ;Ladataan muistipaikka akkuun y-koordinaattien perusteella STA tmp LDA y_table_h,Y STA tmp+1 LDY x_table,X ;Ladataan y-rekisteriin x-koordinaatin osoite LDA (tmp),Y ORA mask_table,X ;Sytytetään pikseli STA (tmp),Y RTS mt_template: .byte $80, $40, $20, $10, $08, $04, $02, $01
Aihe on jo aika vanha, joten et voi enää vastata siihen.