CodeWalrus

Development => Calculators => Calc Projects, Programming & Tutorials => Topic started by: _iPhoenix_ on July 09, 2018, 12:16:43 am

Title: _iPhoenix_ tries to do Assembly things.
Post by: _iPhoenix_ on July 09, 2018, 12:16:43 am

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 and PT_ helped me a bit with this one (Mateo helped me realize that the stack exists, and PT_ helped inspire the drawing code).


Code: [Select]
.nolist
#include "ti84pce.inc"
.list


  .org UserMem-2
  .db tExtTok, tAsm84CeCmp
 
  call _boot_ClearVRAM
  call _RunIndicOff
  ld de, $0050; de holds x coord
  ld c, $50; y coord stored in c
mainLoop:
  ld a, 1 ; draw
  call draw
  call keyWait
  push af ; dammit I love this trick.
    ld a, 0 ; erase
    call draw
  pop af
  call move
  ld a, b; if b is zero, we stop.
  or a, a
  jr z, quit ; relative jump is shorter, byte-wise
  jr mainLoop
quit:
  call _RunIndicOn
  ret
 
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 others have made :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 ; save c onto the stack (as part of bc)
    ld b, 160d
    mlt bc ; this messes with c
    push bc ; thanks, Mateo
    pop hl
    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
    inc hl
    or a, a
    jr z, _erase
_draw: ; label not needed, included for legibility.
    ld (hl), $00 ; byte 2
    jr _end
_erase:
    ld (hl), $ff ; byte 2
_end:
  pop bc ; restore bc (particularly c)
  ret
 
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)
  ret nz ; if a is not zero, return
  jr keyWait ; otherwise jump (relative jump saves bytes, according to my highly scientific testing)


move: ; 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)
   ld b, 1 ; we will set b to 0 if we want to quit
chk_Quit: ; label not used, but it increases legibility and does not harm anything (imho)
  cp skDel
  jp nz, chk_Down
  ld b, 0 ; we want to quit
  ret
chk_Down:
  cp skDown
  jp nz, chk_Left
  inc c
  ret
chk_Left:
  cp skLeft
  jp nz, chk_Right
  dec de
  ret
chk_Right:
  cp skRight
  jp nz, chk_Up
  inc de
  ret
chk_Up:
  cp skUp
  ret nz
  dec c
  ret


As you can probably tell, it's as optimized as I can get it, which is to say not very optimized. I realize these things come with time. [size=0]When will the Dunning-Kruger effect kick in? I like feeling competent...[/size] 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. :)


Tips are always welcome.
Title: Re: _iPhoenix_ tries to do Assembly things.
Post by: mazhat on July 10, 2018, 04:11:04 am
I am glad you are pursuing Assembly!
I finished only one program, but I just don't know about
all the hacks, and tricks of the hardware to be even close to decent.
It's a real challenge for smarty pants, such as yourself.

I looked through my old files and found it,
also I know that the beginning isn't optimised,
but I didn't really feel like doing it lol.

Code: [Select]
;Low Quality Bootleg Sprite Routine
;Created By Matt C./ Mazhat
;
.NOLIST
#define   EQU   .equ
#define   equ   .equ
#define   END   .end
#define   end   .end
#include "ti83plus.inc"
#include "mirage.inc"
.LIST
     .org $9d93 ;Origin (set back two to account for AsmPrgm)
.db $BB,$6D ;Compiled AsmPrgm token
ret ;So TIOS wont run the program
.db 1 ;Identifier as MirageOS program
.db %00000000,%00000000 ;15x15 button
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db %00000000,%00000000
.db "Made by Matt C",0 ;Zero terminated description

;Program code starts here

;Reset the variables and such
ld a, 0
ld (posY), a ;Set posY
ld a, 0
ld (posX), a ;Set posX
ld a, $00
ld (animCounter), a

animation:
;
;Yes, I know this part is REALLY bad,
;BUT BOY AM I DONE WITH THIS PROGRAM.
call drawSprite
ld a, 0
ld (posX), a
call drawSprite
ld a, 1
ld (posX), a
call drawSprite
ld a, 2
ld (posX), a
call drawSprite
ld a, 3
ld (posX), a
call drawSprite
ld a, 4
ld (posX), a
call drawSprite
ld a, 5
ld (posX), a
call drawSprite
ld a, 6
ld (posX), a
call drawSprite
ld a, 7
ld (posX), a
call drawSprite

ld a, 0
ld (posY), a
call drawSprite
ld a, 1
ld (posY), a
call drawSprite
ld a, 2
ld (posY), a
call drawSprite
ld a, 3
ld (posY), a
call drawSprite
ld a, 4
ld (posY), a
call drawSprite
ld a, 5
ld (posY), a
call drawSprite
ld a, 6
ld (posY), a
call drawSprite
ld a, 7
ld (posY), a
call drawSprite


call drawSprite
ld a, 7
ld (posX), a
call drawSprite
ld a, 6
ld (posX), a
call drawSprite
ld a, 5
ld (posX), a
call drawSprite
ld a, 4
ld (posX), a
call drawSprite
ld a, 3
ld (posX), a
call drawSprite
ld a, 2
ld (posX), a
call drawSprite
ld a, 1
ld (posX), a
call drawSprite
ld a, 0
ld (posX), a
call drawSprite

ld a, 7
ld (posY), a
call drawSprite
ld a, 6
ld (posY), a
call drawSprite
ld a, 5
ld (posY), a
call drawSprite
ld a, 4
ld (posY), a
call drawSprite
ld a, 3
ld (posY), a
call drawSprite
ld a, 2
ld (posY), a
call drawSprite
ld a, 1
ld (posY), a
call drawSprite
ld a, 0
ld (posY), a
call drawSprite

ld a, (animCounter) ;Put counter into a
inc a ;increase a
ld (animCounter), a ;therefore increase counter
cp 5 ;animate five times
jp nz, animation

ld hl, textHello
b_call(_HomeUp) ;(CurCol) = 0, (CurRow) = 0.
b_call(_putS) ;Display String in HL

ret
animCounter:
.db $00
textHello:
.db "MADE IN ASM",0
DrawSprite:
ld ix, sprite ;Put sprite address into ix
;ld hl, plotsscreen ;First part of buffer
ld hl, 0 ;empty out the hl register
ld de, (posY) ;Get the Y position

;Check for Vertical Clipping (UP)
ld a, (posY)
ld c, $08 ;Else set the counter to 8
or a ;cp 0
jp m, clipUp ;If y-pos is negative

add hl, de ;mutliply Y by 12
add hl, de
add hl, de
add hl, hl
add hl, hl
ld bc, plotsscreen
add hl, bc
;Check for Vertical Clipping (down)
ld a, (posY) ;Get the Y Position
cp 56
jp p, clipDown ;If the sprite goes off screen
ld c, $08 ;Else set the counter to 8

;Finding the byte on the buffer where the sprite is
ld a, (posX) ;X-Position
ld de, 0 ;Empty de
bufByte:
cp 8 ;Check if less than 8
jp m, addOffsetX ;If Negative Return value (Return back)
sub 8 ;Take away 8 from 'a' register
inc de ;X Offset increase
jp bufByte ;Else repeat
addOffsetX:
add hl, de ;Add the x-offset to hl
shiftRight: ;We are bitshifting the sprite according to x, really
ld a, (posX) ;First lets see if it goes over the right side of the screen
or a ;Check if it goes over the screen
jp m, spriteLoop ;Skip if it does (If negative)

ld b, (ix) ;put sprite into b
ld a, (posX) ;put x-pos into a

ld de, 0 ;x-offset: set to zero
jp mod ;Get how many bitshifts we need (put into 'a' register)
;(For Previous Line: If it doesn't straddle on two bytes, skips to spriteLoop)
sr1:
;ld (LSD), a ;Get the amount we bitshifted by and put it into c for later use by shiftLeft
srl b ;Bitshift sprite right
dec a ;Decrease counter
or a ;cp 0
jp nz, sr1 ;If we're not done the shifting
ld (hl), b ;load sprite image into screen when finished shifting
shiftLeft: ;The byte we need to shift left (The second byte)
ld a, (posX) ;First lets see if it goes over the right side of the screen
cp 88 ;Check if it goes over the screen
jp p, spriteLoop ;Skip if it does


ld b, (ix) ;Put the sprite into b
inc hl ;X-Offset byte on buffer + 1
ld a, 8 ;Let's get the bytes we need to shift left using the number we used to shift right
sub e ;Get the left shift value (It will be negative)
;ld e, (LSD)
;sub e ;8-(# that we shifted right by) = How many left shifts we need for this byte
sl1:
sla b ;Bitshift sprite left
dec a ;Dec counter
or a ;cp 0
jp nz, sl1
ld (hl), b ;load sprite image into screen
dec hl
jp spriteLoop
drawToBuffer:
ld (hl), b ;load sprite image into screen
spriteLoop:
;ld (hl), b ;load sprite image into screen

dec c ;dec counter
ld a, c ;load counter into a

inc ix ;next sprite byte
ld de, 12
add hl, de ;next 'y' position on screen

cp $01 ;loop x8
jp p, shiftRight ;Drain the grain in the counter
b_call(_grBufCpy)
b_call(_grBufClr)
ret
clipDown:
sub 64 ;Take away 64 from Y-POS (register a)
NEG ;NEGATE IT
ld c, a ;Put that number into the counter for drawing sprites
jp shiftRight
clipUp:
ld de, plotsscreen ;Get the plotSScreen
add hl, de ;Put plotSScreen into hl
NEG ;Negate 'a' to get a positive value
CLUP:
dec a ;Counter: The amount of bytes that need to be skipped

dec c ;Remainer bytes to draw
inc ix ;Skip the byte

or a
jp nz, CLUP ;Keep skipping until we have the bytes we need to draw

jp shiftRight
mod:
ld e, a ;Get the amount we bitshifted by and put it into ** for later use by shiftLeft
cp 8 ;Check if The number is already a mutliple of eight (no need for bitshift)
jp z, drawToBuffer ;If zero just draw it without bit shifting anything
or a ;Due to technicality, 0 is not a multiple of 8
jp z, drawToBuffer ;So just do the same thing
cp 8
jp m, sr1 ;If Negative Return value (Return back)
sub 8 ;Take away 8 from 'a' register
jp mod ;Else repeat
;LSD:;leftShiftData:
.db $00
sprite:
.db %01111110
.db %10000001
.db %10100101
.db %10000001
.db %10100101
.db %10011001
.db %10000001
.db %01111110
posX:
.db 0
posY:
.db 0

end
Title: Re: _iPhoenix_ tries to do Assembly things.
Post by: _iPhoenix_ on July 12, 2018, 10:32:20 pm
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).


(https://i.imgur.com/xLGE9x0.gif)




Features:


This game is clearly the pinnacle of ez80 programming and should be worshipped as such.
Title: Re: _iPhoenix_ tries to do Assembly things.
Post by: Caleb Hansberry on July 15, 2018, 11:49:06 pm
I'm also happy you're working on ez80 assembly. It's absolutely a worthwhile endeavor!