Welcome, Guest. Please login or register.


Author Topic: Some ASM code snippets/ideas (Read 2346 times)

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Chrome 46.0.2490.80 Chrome 46.0.2490.80
    • View Profile
Some ASM code snippets/ideas
« on: 2015.November.05. 18:17:59 »
Well, I thought to open a topic where we could share some useful code examples or ideas.

1. A method for switching buffer addresses (for drawing to the correct buffer) when using double buffering.

It comes from the source code for Rigor Mortis for the CPC which is based on disassembly of Elmar Krieger's (author of "Prehistorik 2" and "Super Cauldron" for the amstrad) game engine. The Source (among many others) can be found at http://cpcrulez.fr/coding_menu-src.htm

We prepare a LUT for the two buffer addresses:
Code: [Select]
first_buffer_address dw $0000
second_buffer_address dw $4000
...and we use a 16-bit variable for choosing between the two addresses:
Code: [Select]
double_buffer_offset dw $0002
We use it to offset to the wanted address so should be $0000 or $0002.
Everytime we want to change the offset we do:
Code: [Select]
ld hl,double_buffer_offset
ld a,(hl)
xor 2
ld (hl),a
To get the correct buffer address:
Code: [Select]
ld bc,(double_buffer_offset)
ld hl,first_buffer_address
add hl,bc
Now the wanted address is stored in memory at hl, so to get the address:
Code: [Select]
ld e,(hl)
inc l
ld d,(hl)
The address is now in de.

Earlier I switched the addresses by storing additional address variables for the active and hidden buffer address and switch the two for every game frame and also have a variable that stored the number of active buffer (0 or 1), because many times you have to choose which sprite background buffer to use (for which screen).
I find the one by Elmar Krieger to be somewhat cleaner and prettier...


2. Second is something like the strategy pattern in OOP (at least reminds me of it)...

When you want to use some optional code, like for example an optional gfx effect, additional game mode mechanic, switching music or something like that then you can do:

in your mainloop:
Code: [Select]
call something_dispatcher

the called subroutine is a simple jump:
Code: [Select]
something_dispatcher:
jp something

You can set the jump to what you want it to do...
For example for switching music/sfx/no sound you could set the dispatch address to the right routine...
When you don't want to do the "something" you set the jp address to a ret:
Code: [Select]
just_a_ret:
ret
To set the dispatch address to it:
Code: [Select]
ld hl,something_dispatch+1
ld (hl),just_a_ret

Else you can do conditionals every time but the presented method is a little quicker and cleaner (at least for me)...
One disadvantage would be that it's self modyfying code...
« Last Edit: 2015.November.05. 19:19:45 by ssr86 »

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Chrome 46.0.2490.80 Chrome 46.0.2490.80
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #1 on: 2015.November.05. 18:25:43 »
3. This I use for a simple Pause game mechanic after pressing the STOP button...:

Code: [Select]
try_pause_game:

 ;EP keyboard matrix:
 ;        b7    b6    b5    b4    b3    b2    b1    b0
 ;Row    80H   40H   20H   10H   08H   04H   02H   01H
 ; 0   L.SH.     Z     X     V     C     B     \     N
 ; 1    CTRL     A     S     F     D     G  LOCK     H
 ; 2     TAB     W     E     T     R     Y     Q     U
 ; 3     ESC     2     3     5     4     6     1     7
 ; 4      F1    F2    F7    F5    F6    F3    F8    F4
 ; 5         ERASE     ^     0     -     9           8
 ; 6             ]     :     L     ;     K           J
 ; 7     ALT ENTER   LEFT  HOLD   UP   RIGHT DOWN  STOP
 ; 8     INS SPACE R.SH.     .     /     ,   DEL     M
 ; 9                   [     P     @     0           I

check_stop_pressed:
           ld a,7        ; row number
           out (0b5h),a  ; scan row and get result
           in a,(0b5h)
           bit 0,a
           ret nz

; simple pause game mechanism...
; blocking the execution of interrupts
; and gameloop continuation after pressing
; the stop key and unblocking everything
; after pressing it for the second time

    di

    ld a,201
    out (border),a

    ld hl,last_key_pressed
    call ploop1           ; wait until key released
    call ploop1           ; wait until pressed second time
    
    ld a,0
    out (border),a
    ei
    ret

ploop1:
    ld (hl),a
    ld a,7
    out (0b5h),a
    in a,(0b5h)
    cp (hl)
    jr z,ploop1
    bit 0,a
    jr z,ploop1
    ret

last_key_pressed  db 0
« Last Edit: 2015.November.07. 11:18:16 by ssr86 »

Offline ergoGnomik

  • EP lover
  • *
  • Posts: 790
  • Country: hu
  • Stray cat from Commodore alley
  • OS:
  • Windows NT 6.3 Windows NT 6.3
  • Browser:
  • Firefox 41.0 Firefox 41.0
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #2 on: 2015.November.05. 18:27:34 »
Wiki topic?

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Chrome 46.0.2490.80 Chrome 46.0.2490.80
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #3 on: 2015.November.05. 18:41:29 »
4. Basic joystick "waggling" mechanics like in old sports games (decathlon, summer games etc.):

Code: [Select]
joy_control:
         ld hl,last_key_pressed

         call joyscan
              
         ld e,(hl)
         ld (hl),d

try_down:

         bit 2,d
         jp nz,try_up

         bit 2,e
         jp z,try_up

         jp waggle_incrementation

try_up:
         bit 3,d
         ret nz

         bit 3,e
         ret z

waggle_incrementation:

         ld a,(waggle_increment)
         ld c,a
         ld a,(counter)
         add a,c
         cp COUNTER_RESET-1
         jr c,$+4
         ld a,COUNTER_RESET-2
         ld (counter),a

         ret
        

joyscan:
           ld c,0        ; first row
           ld d,0
joy_loop1: ld b,5        ; read four directions + fire
           ;ld e,d
joy_loop2: ld a,c        ; row number
           inc c         ; next row
           out (0b5h),a  ; scan row and get result
           in a,(0b6h)   ; get each bit in turn and
           rra           ;  shift result into d
           rl d
           djnz joy_loop2
ret



waggle_counter_decrement:

                    ; decrease counter:
                    ld hl,counter
                    ld a,(hl)
                    or a
                    ret z

                    ld a,(counter_decrement_step)
                    ld c,a
                    ld a,(hl)
                    sub c
                    jp nc,$+4
                    xor a
                    ld (hl),a

                    ret


; variables:
counter                db counter_reset
counter_decrement_step db 1
waggle_increment       db 2

COUNTER_RESET          equ 64
"waggle_decrement" should be called every frame or few so the counter will go down (which could mean the player slows down).
"waggle_incrementation" is called when you do an up/down(can change to left/right or whatever) movement...

Wiki topic?
Sorry, but what does that mean? :oops:
« Last Edit: 2015.November.05. 20:24:57 by ssr86 »

Offline lgb

  • EP addict
  • *
  • Posts: 3496
  • Country: hu
  • æðsta yfirmaður
  • OS:
  • Linux (Ubuntu) Linux (Ubuntu)
  • Browser:
  • Firefox 42.0 Firefox 42.0
    • View Profile
    • http://lgb.hu/
Re: Some ASM code snippets/ideas
« Reply #4 on: 2015.November.05. 19:00:20 »
Sorry, but what does that mean? :oops:

I _think_ he was about the wiki section of the site, check the top of this page out, the blue "WIKI" button. Wiki is (or would be) a great place to document things, collecting tricks etc.

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Chrome 46.0.2490.80 Chrome 46.0.2490.80
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #5 on: 2015.November.05. 19:22:59 »
I _think_ he was about the wiki section of the site, check the top of this page out, the blue "WIKI" button. Wiki is (or would be) a great place to document things, collecting tricks etc.
Oh, but the wiki pages don't seem to allow discussion... Also for the wiki everything would have to be better written...(I mean text quality). Forum topic allows more informal presentation..

Offline lgb

  • EP addict
  • *
  • Posts: 3496
  • Country: hu
  • æðsta yfirmaður
  • OS:
  • Linux (Ubuntu) Linux (Ubuntu)
  • Browser:
  • Firefox 42.0 Firefox 42.0
    • View Profile
    • http://lgb.hu/
Re: Some ASM code snippets/ideas
« Reply #6 on: 2015.November.05. 20:01:02 »
Oh, but the wiki pages don't seem to allow discussion... Also for the wiki everything would have to be better written...(I mean text quality). Forum topic allows more informal presentation..

Yes, that's the point. For discussion it's better to do on the forum, of course. But of course if there are useful tips - I think! - it's maybe worth to document it on the wiki as well, still of course there can be a forum topic to discuss it. Personally what I always find hard is to try to find something I remember in one of the topics eg a year ago, always mission impossible to do ... If you see my point.

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Chrome 46.0.2490.80 Chrome 46.0.2490.80
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #7 on: 2015.November.06. 07:36:54 »
5. Adding 8 bit value to a 16-bit register

Instead of
Code: [Select]
ld bc,$00nn
add hl,bc
You can do:
Code: [Select]
; add $nn to HL
ld a,l
add a,$nn
ld l,a
adc a,h
; a=l+h+carry
sub l
ld h,a
It takes one byte more and is a little bit slower but if you don't want to corrupt bc or de then this is very useful.
Else you could save bc on the stack and restore its value after the add but the presented method is a little less expensive.

Below is a similar alternative to subtraction:
Code: [Select]
; subtract $nn from HL
ld a,l
sub $nn
ld l,a
sbc a,l
add a,h
ld h,a

Yes, that's the point. For discussion it's better to do on the forum, of course. But of course if there are useful tips - I think! - it's maybe worth to document it on the wiki as well, still of course there can be a forum topic to discuss it. Personally what I always find hard is to try to find something I remember in one of the topics eg a year ago, always mission impossible to do ... If you see my point.
If these "examples" are verified to be useful, tested for correctness and written with a "cleaner" language, maybe then I will try to put them to to the wiki page ;P .

I have an unfinished "article" about different methods for flipping and shifting of sprites (maybe also on clipping)...  I'll try to finish it and maybe I will upload that to the wiki...
« Last Edit: 2015.November.06. 08:04:06 by ssr86 »

Offline lgb

  • EP addict
  • *
  • Posts: 3496
  • Country: hu
  • æðsta yfirmaður
  • OS:
  • Linux (Ubuntu) Linux (Ubuntu)
  • Browser:
  • Firefox 42.0 Firefox 42.0
    • View Profile
    • http://lgb.hu/
Re: Some ASM code snippets/ideas
« Reply #8 on: 2015.November.06. 07:59:32 »
If these "examples" are verified to be useful, tested for correctness and written with a "cleaner" language, maybe then I will try to put them to to the wiki page ;P .

I have an unfinished "article" about different methods for flipping and shifting of sprites (maybe also on clipping)...  I'll try to finish it and maybe I will upload that to the wiki...

I think this is the most correct way to do, indeed :)

Offline Mobsie

  • Beginner
  • *
  • Posts: 27
  • Country: de
  • OS:
  • Mac OS X 10.11.1 Mac OS X 10.11.1
  • Browser:
  • Safari 9.0.1 Safari 9.0.1
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #9 on: 2015.November.06. 16:44:04 »
GREAT!

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Chrome 46.0.2490.80 Chrome 46.0.2490.80
    • View Profile
Re: Some ASM code snippets/ideas
« Reply #10 on: 2015.November.07. 12:00:39 »
6. Next comes from an example posted by Zozo in https://enterpriseforever.com/programming/19-faster-ldir/msg43374/#msg43374 and it shows how you can use the accumulator as the loop counter when you need to use it also in the middle of the loop and you can't use stack (because, like in the source example, you abuse the stack for moving data):
(although honestly the entire code posted by Zozo should be pasted here as an example of stack abuse technique)
Code: [Select]
 
routine_start:

                ld a,INITIAL_LOOP_COUNTER_VALUE
                ld (loop_counter+1),a    
    
loop:        
                    [...]
loop_counter:        
                ld a,0 ; SMC - loaded with INITIAL_LOOP_COUNTER_VALUE at the beginning
                dec a
                ld (loop_counter+1),a
                jp nz,loop

                ret
« Last Edit: 2015.November.07. 12:03:40 by ssr86 »