Alright, so I've taken up learning Assembly, now that I am more comfortable with middle-to-lower level languages like C and C++, and I've progressed to the stage that I can start to write crappy programs now.

Here's my first actual assembly program. It's pretty bad. You can move a pixel around with the arrow keys. Mateo, PT_, and Runer. helped me a bit with this one (Mateo helped me realize that the stack exists, and PT_ helped inspire the drawing code. PT_, in his 'P_T' form, and Runer showed me some a lot of useful optimization tips and made me realize how many simple optimizations could have been done.)

Code:
```.nolist #include "ti84pce.inc" .list   .org UserMem-2   .db tExtTok, tAsm84CeCmp     call _RunIndicOff   call _boot_ClearVRAM   ld de, lcdWidth/2; de holds x coord   ld c, lcdHeight/2; y coord stored in c mainLoop:   ; constrain de and c so they are always on the screen.   ld a, c   cp 240d ; remember: it is 0-indexed, so we check if a < 240 (if a = 240 it is out of bounds)   jr c, chk_de   ld c, lcdHeight - 1 chk_de:   ld a, e   push de     ex de, hl     ld de, \$ffffff - lcdWidth + 1 ; if de is >= lcdWidth it will overflow.     adc hl, de   pop de   jr nc, cont   ld de, lcdWidth - 1 cont:   xor a, a ; draw   call draw keyWait: ; waits for a key, keycode returned in a   call _GetCSC ; get key codes   or a, a; check scan codes by comparing a with itself (I got this "hack" from various routines, it is super clever)   jr z, keyWait ; if a is not zero, we are done keyEnd:   ld b, a   ld a, \$ff ; erase   call draw       ; Movement code.       ; input in a (getCSC code)       ; moves the pixel by updating       ; de (x coord) and c (y coord)       ; nothing overly arcane happens       ; I used to check if a was >= 5 or equal to skDel       ; but my code caused bugs so I killed it (and the bugs) chk_down:   djnz chk_left   inc c   jr mainLoop chk_left:   djnz chk_right   dec de   ; this is my crappy routine to check if de overflowed.   ; it just works. Ew.   ex de, hl ; hl is now de   ld de, \$ffffff ; de is saved in hl   adc hl, de ; logic explained below   ex de, hl ; de is now hl   jr c, mainLoop   inc de   jr mainLoop   ; I feel clever writing the above few lines of code,   ; but please burst my ego if you have a better one. chk_right:   djnz chk_up   inc de   jr mainLoop chk_up:   djnz chk_quit   ld a, c   adc a, \$ff; (n + \$ff) % \$100 + ((n + \$ff)>\$100) = n-1 (n!=0)   ld c, a   jr c, mainLoop   inc c   jr mainLoop chk_quit:   ld a, b   cp skDel - 4   jr nz, mainLoop   call _RunIndicOn   ret ; quit draw: ; draws our singular pixel (I set high goals)       ; (whew this is a bit of work, it gave me lots of appreciation for the sprite routines :P)       ; we are using 16bpp mode here, so my routines       ; (which are gently modified 8bpp routines) can       ; probably be optimized       ; takes input in a: 1 = draw the pixel, 0 = erase   push bc     ld l, c     ld h, lcdWidth/2     mlt hl ; this messes with c     add hl, hl ; hl * 2     add hl, hl ; hl * 4 (2 bytes/pixel)     add hl, de     add hl, de ; hl += de * 2     ld bc, vRAM ; this also messes with c     add hl, bc     ld (hl), \$ff ; byte 1, color info     inc hl     ld (hl), a ; byte 2, color info stored in a   pop bc   ret```

As you can probably tell, it's as optimized as I can get it, which is to say not very optimized. It's optimized (I think? I'm obviously not a good judge of these things. Yet.), not obfuscated. I realize these things come with time. When will the Dunning-Kruger effect kick in? I like feeling mildly competent... I'm trying to keep my code optimized and readable so I can look back on it later.

My current assembly setup is SC3 and the Project Builder. This is a temporary setup, and I'm switching to better tools soon.
A lot of fun progress has happened since that first post! I've decided on a very simple game where you (a square) walk around a screen collecting coins (also squares).

Features:

• Slow!
• Large! Ok, this one is a lie, it's only like 300 bytes
• Unoriginal!
• Nut-free!
• Low-quality graphics!
• Documentation not included!
• 80% All-natural!
• Not a scam!

This game is clearly the pinnacle of ez80 programming and should be worshipped as such.
Before some person tells me that my program is excellent or that I'm still learning or something, I know. This post is a bit of a joke, I'm still learning and I'm actually super proud of what I have done so far.

Edit:
I thought I'd post my source code in case anyone had any tips. PT_ suggested that I should be reading directly from the port instead of using GetCSC (and I can see why, looking at CEmu's disassembler, it is an absolutely massive routine, larger than my entire program!), and I tried to, but I think I'm going to do that one particular optimization later.

Code:
```.nolist #include "ti84pce.inc" square_size     .equ 8d ; I'm making this an equate for readability, changing it without modifying other parts of the program will cause you problems. coin_size       .equ 6d ; don't change this either score_location  .equ pixelShadow coin_y_location .equ pixelShadow + 2 coin_x_location .equ pixelShadow + 1 ; yummy little-endian format coin_location   .equ pixelShadow + 1 ; for 24 byte registers. rng_seed             .equ \$71dc ; this can be anything non-zero rng_seed_location    .equ pixelShadow + 4 ; +3 is upper byte of 24 bit register after ld <reg24>, coin_location .list     .org UserMem - 2   .db tExtTok, tAsm84CeCmp     call _RunIndicOff   call _boot_ClearVRAM   ; <init palette>, code came from C toolchain.   ld   de,mpLcdPalette ; address of mmio palette   ld   b,e ; b = 0 _paletteLoop:   ld   a,b   rrca   xor   a,b   and   a,224   xor   a,b   ld   (de),a   inc   de   ld   a,b   rla   rla   rla   ld   a,b   rra   ld   (de),a   inc   de   inc   b   jr   nz,_paletteLoop ; loop for 256 times to fill palette ; </init palette>     ld a, lcdBpp8   ld (mpLcdCtrl), a   ; seed rng   ld hl, rng_seed   ld (rng_seed_location), hl     ld de, 0 ; clear upper byte     ld a, 0   ld (score_location), a   ld (coin_location + 2), a     ld d, (lcdHeight/square_size)/2 ; d holds y coord   ld e, (lcdWidth/square_size)/2 ; e holds x coord     jr _move_coin ; just for simplicity.   main_loop:   ld hl, (coin_location)   cp a, a ; thank you, jcgter <3   sbc hl, de   jr nz, _   ld hl, score_location   inc (hl) _move_coin:   call rng   cp lcdWidth/square_size + 1   jr c, __   sub lcdWidth/square_size __:   ld (coin_y_location), a   call rng   ld a, r   and %00000111 ; bitmask, limit to 0-7.   add a, c   ld (coin_x_location), a   call draw_coin _:   xor a, a ; draw   call draw kbd_read:   call _GetCSC   or a   jr z, kbd_read   ld b, a   cp skDel   jr nz, kbd_end   ld a, lcdBpp16 ; quit   ld (mpLcdCtrl), a   call _RunIndicOn   ret ; quit kbd_end:   ld a, \$ff ; erase   call draw ; Movement code. ; input in b (getCSC code) ; moves the pixel by updating ; de (x coord) and c (y coord) ; nothing overly arcane happens ; I used to check if a was >= 5 or equal to skDel ; but my code caused bugs so I killed it (and the bugs) chk_down:   djnz chk_left   inc d   ld a, d   cp lcdHeight/square_size   jr c, main_loop   ld d, lcdHeight/square_size - 1   jr main_loop chk_left:   djnz chk_right   dec e   ld a, e   inc a ; check for overflow (this is a pretty sweet optimization)   jr nz, main_loop   ld e, 0   jr main_loop chk_right:   djnz chk_up   inc e   ld a, e   cp lcdWidth/square_size   jr c, main_loop   ld e, lcdWidth/square_size - 1   jr main_loop chk_up:   djnz main_loop   dec d   ld a, d   inc a ; check for overflow   jr nz, main_loop   ld d, 0   jr main_loop draw: ; (whew this is a bit of work, it gave me lots of appreciation for the sprite routines :P) ; takes input in a: 00 = draw the pixel, ff = erase   ld c, b   ld (colorSet+1), a ; writes the color byte into the program.   push de     push de ; thanks, dTal, PT_, Runer and zeda for making me realize that I should never do assembly programming while extremely tired.       ld e, lcdWidth/2       mlt de       ex de, hl       add hl, hl ; this gets rid of the /2 part above       add hl, hl ; the below stuff multiplies hl by square_size, which is 8.       add hl, hl       add hl, hl       ld de, vRAM ; while we have corrupted de, let's use it to make hl point into vRAM.       add hl, de     pop de     ld d, square_size     mlt de     add hl, de     ld de, lcdWidth - square_size     ld a, square_size _loopOuter:     ld b, square_size _loopInner: colorSet:     ld (hl), \$00 ; The color byte gets written in here.     inc hl     djnz _loopInner         add hl, de     dec a     jr nz, _loopOuter   pop de   ld b, c   ret draw_coin: ; draws the coin! (some of this is repeated code, but I'm really concerned about speed.) ; this routine is like a tank, it destroys everything.   push de     ld de, \$0     ld hl, coin_y_location     ld e, lcdWidth/2     ld d, (hl)     mlt de     ex de, hl     add hl, hl ; this gets rid of the /2 part above     add hl, hl ; the below stuff multiplies hl by square_size, which is 8.     add hl, hl     add hl, hl     ld de, vRAM+lcdWidth ; the '+lcdWidth' is to center it on the grid. The coin is 6x6 on an 8x8 grid, so we need 1 pixel of padding all around.     add hl, de     ld b, square_size     ld a, (coin_x_location)     ld c, a     mlt bc     add hl, bc     inc hl     ld de, lcdWidth - coin_size     ld a, coin_size _loopOuter2:     ld b, coin_size _loopInner2:     ld (hl), \$a4 ; gold     inc hl     djnz _loopInner2     add hl, de     dec a     jr nz, _loopOuter2   pop de   ret rng: ; generates a random number, 1-32, and stores the result in a ; destroys hl, bc ; to seed the rng (16-bit seed in hl): ; ld (rng_seed_location), hl   ld b, 5 ; max output of rng = 2^b (0 <= b <= 7)   ld hl, (rng_seed_location) ; seed rng with previous output   ld c, \$00 ; we will be using c to hold the output, because we need a for other things. _rng: ; A highly modified Galois LFSR. Nicely, the current ; example source code on wikipedia pretty much directly ports over.   srl h ; shifts h, fills gap with 0. sets carry flag to what "fell off".   rr l ; shifts l, fills gap with what fell off h.   rl c ; output here, this is what is different from the wikipedia code. Carry flag (what fell off l) is pushed into bit 0 of c. I love this.   bit 0, c   jr nz, _   ld a, h   xor \$B4 ; magic # from wiki article.   ld h, a _:   djnz _rng   ld (rng_seed_location), hl   ld a, c   ret```

If you want to play the "game" yourself, you can download it from here.
You use the arrow keys to move around, and [del] to quit.

After quitting, the program will leave a few artifacts on the screen. I'm not sure how to fix that yet, because I haven't spent the time looking into fixing it. If they bother you too much, just press [2nd][quit] after running the program and the TI-OS will remove them by redrawing the screen.

I'm still using SC3 to compile my code, but I'm going to be switching really soon.

Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

»
» All times are UTC - 5 Hours

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum