Author |
Message |
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 23 Apr 2009 09:44:31 pm Post subject: |
|
|
I am coding for a Galaxian-type game, and would like to use jump tables to switch levels. I'm fairly new to this concept, so any help would be greatly appreciated .
By the way, I DID look up the jump table and vector table section of Learning ASM in 28 Days tutorial, so I have a light idea of what it's about, but I simply cannot get it to work for me. Also, I'm coding for the TI83+/TI84+ family, if that matters. |
|
Back to top |
|
|
DigiTan Unregistered HyperCam 2
Super Elite (Last Title)
Joined: 10 Nov 2003 Posts: 4468
|
Posted: 23 Apr 2009 10:07:59 pm Post subject: |
|
|
Basically, with jump tables all it takes is the slightest mistake and things will get horribly ugly. Like shaving. Since you already tried it, I'm betting it's something minor. But just to get started, here's a small routine that loads 1 of 3 levels. It takes in register <A>, locates to right spot in the table, moves that address to HL, and BAM! ...a jp (hl) command to win the game. ...Well...load it anyway.
Code: ;-------------------------------------------------------\
Level_loader: ;
; IN: A = level number to load (0-2) ;
; OUT: -nothing- ;
; RESULT: Will jump to the proper level based on ;
; what <A> register is ;
;--------------------------------------------------------
ld hl,jump_table ; HL -> Table of places to jump
add a,a ; Table entries are 2 bytes. So multiply by 2
ld e,a ; E == the offset of the table
ld d,0 ; Clear unused byte
add hl,de ; HL -> The address of where to jump
ld e,(hl) ; These 3 instructions act like "LD DE,(HL)"
inc hl
ld d,(hl) ; Now DE == Address to jump to
ex de,hl ; Now HL == Address to jump to
jp (hl) ; Go ahead and jump!
jump_table:
.dw ForestLevel, CaveLevel, SkyLevel
Things to keep in mind:
- The <A> register had to be multiplied by two because ForestLevel, CaveLevel, and SkyLevel are 2-byte numbers.
- TI's store these addresses with the least-significant byte first. At least when ".dw" is used.
- Make sure it's ".dw" instead of ".db"
- Make sure the places you're jumping into have working code too, or else the jump table code may get the blame!
Last edited by Guest on 23 Apr 2009 10:10:16 pm; edited 1 time in total |
|
Back to top |
|
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 23 Apr 2009 10:32:48 pm Post subject: |
|
|
ah, you're right! One little mistake...I forgot to multiply the input ('a', in this case) by 2. Does .dw always form 2-byte numbers? Also, would the following code be acceptable, for the sake of organization?
Code: jumptable:
.dw level1
.dw level2
.dw boss1
....
|
|
Back to top |
|
|
DigiTan Unregistered HyperCam 2
Super Elite (Last Title)
Joined: 10 Nov 2003 Posts: 4468
|
Posted: 23 Apr 2009 10:50:16 pm Post subject: |
|
|
Yep. They're exactly the same. .DW (or .word for some assmblers) will always make it a 16-bit number, even if it's a zero. Others like .db, .byte, and .text will be 8-bit. |
|
Back to top |
|
|
darkstone knight
Advanced Member
Joined: 07 Sep 2008 Posts: 438
|
Posted: 24 Apr 2009 05:06:56 am Post subject: |
|
|
note that:
.dw $1234
is different than:
.db $12,$34 |
|
Back to top |
|
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 24 Apr 2009 04:03:34 pm Post subject: |
|
|
ok, great, thanks! That was a huge help. Makes my programming life a lot easier . Oh, and one more quick question. To multiply by 2, you added 'a' onto itself. Wouldn't the RLA instruction do the same thing? If so, which method is quicker?
Last edited by Guest on 24 Apr 2009 04:04:04 pm; edited 1 time in total |
|
Back to top |
|
|
darkstone knight
Advanced Member
Joined: 07 Sep 2008 Posts: 438
|
Posted: 24 Apr 2009 04:11:08 pm Post subject: |
|
|
add (reg8): 4 or 7 (HL)
rra: 4 cycles, but uses the carry
i use add... iets easier to understand than shifts, and does work on registers other than A |
|
Back to top |
|
|
simplethinker snjwffl
Active Member
Joined: 25 Jul 2006 Posts: 700
|
Posted: 24 Apr 2009 04:12:19 pm Post subject: |
|
|
TKD_01 wrote: ok, great, thanks! That was a huge help. Makes my programming life a lot easier . Oh, and one more quick question. To multiply by 2, you added 'a' onto itself. Wouldn't the RLA instruction do the same thing? If so, which method is quicker?
They both take four T-states and are one-byte each. The only difference is the flags they affect; for add, S Z H C are affected as defined, P/V detects overflow, N is cleared; for rla: S Z P/V are not affected, H N are reset, C is the previous bit 7. |
|
Back to top |
|
|
calc84maniac
Elite
Joined: 22 Jan 2007 Posts: 770
|
Posted: 24 Apr 2009 04:24:34 pm Post subject: |
|
|
simplethinker wrote: TKD_01 wrote: ok, great, thanks! That was a huge help. Makes my programming life a lot easier . Oh, and one more quick question. To multiply by 2, you added 'a' onto itself. Wouldn't the RLA instruction do the same thing? If so, which method is quicker?
They both take four T-states and are one-byte each. The only difference is the flags they affect; for add, S Z H C are affected as defined, P/V detects overflow, N is cleared; for rla: S Z P/V are not affected, H N are reset, C is the previous bit 7.
Actually, RLA is more similar to ADC A,A since it shifts the carry flag into the lsb.
Last edited by Guest on 11 Jul 2010 05:45:58 pm; edited 1 time in total |
|
Back to top |
|
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 24 Apr 2009 06:35:30 pm Post subject: |
|
|
Ah, ok, got it. Now just one more question . What would be the fastest way to clear the graph buffer, a.k.a. plotsScreen?
Last edited by Guest on 24 Apr 2009 06:36:34 pm; edited 1 time in total |
|
Back to top |
|
|
Taricorp
Member
Joined: 09 Mar 2006 Posts: 188
|
Posted: 24 Apr 2009 09:23:26 pm Post subject: |
|
|
Fast:
Code: ld hl,plotSScreen
ld (hl),0
ld de,plotSScreen+1
ld bc,767
ldir
Faster, but requires disabling interrupts:
Code: di
ld b,(768/2)/6
ld hl,0
add hl,sp
ld de,0
ld sp,plotSScreen+767
loop:
push de
push de
push de
push de
push de
push de
djnz loop
ld sp,hl
ei
|
|
Back to top |
|
|
Galandros
Active Member
Joined: 29 Aug 2008 Posts: 565
|
Posted: 25 Apr 2009 03:58:22 am Post subject: |
|
|
If you clear the graph buffer right after printing it to screen see this routine to write to screen and erase it after:
http://wikiti.brandonw.net/index.php?title...nd_Improvements
This is better than writing to the screen and after that clearing gbuf, using one of the routines above, because instead of wasting time in waiting, it erases the gbuf.
Also ldir could be unrolled to ldi's (8 or more compensate) to improve speed at cost of space. |
|
Back to top |
|
|
darkstone knight
Advanced Member
Joined: 07 Sep 2008 Posts: 438
|
Posted: 25 Apr 2009 05:27:48 am Post subject: |
|
|
Galandros wrote: Also ldir could be unrolled to ldi's (8 or more compensate) to improve speed at cost of space.
i wanted to say that, but it will erase plotsscreen+768, wich destroys randseed |
|
Back to top |
|
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 25 Apr 2009 09:00:37 am Post subject: |
|
|
I believe that for my needs, I'm going to stick with Taricorp's Fast portion of code. The code contained with the link you gave me, Galandros, does not do sprite clipping, which I need . And I dont really want to have to go in and modify the code.
Thanks again for all the help!
Oh and one more thing, the last byte of the plotsscreen contains the randseed? I'm assuming we acces this through plotsscreen+767?
Last edited by Guest on 25 Apr 2009 09:02:30 am; edited 1 time in total |
|
Back to top |
|
|
darkstone knight
Advanced Member
Joined: 07 Sep 2008 Posts: 438
|
|
Back to top |
|
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 25 Apr 2009 09:44:41 am Post subject: |
|
|
darkstone knight wrote:
Ok..I didn't find anything about the randseed. But that doesnt really matter.
@Galandros:
What would you then recommend to clear the plotsscreen? I dont need to write it, only to clear it.
Last edited by Guest on 25 Apr 2009 09:44:55 am; edited 1 time in total |
|
Back to top |
|
|
darkstone knight
Advanced Member
Joined: 07 Sep 2008 Posts: 438
|
Posted: 25 Apr 2009 09:53:14 am Post subject: |
|
|
if you dont need faster than 1/1000 seconds stick to LDIR, oterwise use the push method
randseed1 and randseed2 are 9 bytes (each) located at plotsscreen+767, corrupting then will make rand return numbers out of bounds (like 3,27071e53
Last edited by Guest on 11 Jul 2010 05:46:13 pm; edited 1 time in total |
|
Back to top |
|
|
TKD_01
Advanced Newbie
Joined: 20 Feb 2009 Posts: 51
|
Posted: 25 Apr 2009 10:00:03 am Post subject: |
|
|
darkstone knight wrote: if you dont need faster than 1/1000 seconds stick to LDIR, oterwise use the push method
randseed1 and randseed2 are 9 bytes (each) located at plotsscreen+767, corrupting then will make rand return numbers out of bounds (like 3,27071e53
Ah, ok. That makes sense. And ya, I'll give the push method a try.
Thanks again!
EDIT:
The push method works a bit faster, but the only problem is that the last 7 pixel pixels of the bottom row constantly flash on and off when one of my sprites goes on top of that section.
Last edited by Guest on 11 Jul 2010 05:46:29 pm; edited 1 time in total |
|
Back to top |
|
|
simplethinker snjwffl
Active Member
Joined: 25 Jul 2006 Posts: 700
|
Posted: 25 Apr 2009 12:33:57 pm Post subject: |
|
|
darkstone knight wrote: if you dont need faster than 1/1000 seconds stick to LDIR, oterwise use the push method
randseed1 and randseed2 are 9 bytes (each) located at plotsscreen+767, corrupting then will make rand return numbers out of bounds (like 3,27071e53
So that's why sometimes ASM games cause funky random numbers to be returned?
Last edited by Guest on 11 Jul 2010 05:45:42 pm; edited 1 time in total |
|
Back to top |
|
|
FloppusMaximus
Advanced Member
Joined: 22 Aug 2008 Posts: 472
|
Posted: 25 Apr 2009 02:28:56 pm Post subject: |
|
|
Back up a minute, guys. No, the random seed is not located at plotSScreen plus 767. (Think about it: if that were true, wouldn't you expect to see garbage in the lower right corner of the graph screen?)
What darkstone knight originally said was correct:
darkstone knight wrote: Galandros wrote: Also ldir could be unrolled to ldi's (8 or more compensate) to improve speed at cost of space.
i wanted to say that, but it will erase plotsscreen+768, wich destroys randseed
seed1 is located at plotSScreen plus 768. Therefore, correctly written assembly programs, which write to at most (plotSScreen + 767), will not affect the RNG. Buggy assembly programs, however, sometimes do.
darkstone knight's point above, which was a good one, was that unrolling the LDIR into 8 LDIs in the obvious way would not work, because 767 is not divisible by 8. Now, there are ways that you could still unroll it if you wanted to, e.g.
Code: ld b,96
jr loopstart
loop:
ldi
loopstart:
ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi
djnz loop
But that is still not as efficient, in either speed or code size, as using PUSHes.
In any case I think this is a rather silly thing to be arguing about. For most purposes, LDIR is quite fast enough to clear the screen. If you really need the extra speed, use the PUSH loop or the funky copy-and-clear routine Galandros mentioned. |
|
Back to top |
|
|
|