[TI ASM] Optimizations

Got questions? Got answers? Go here for both.

Moderator: MaxCoderz Staff

User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

I've already made my multi-line text displayer used in bubble bobble...

Code: Select all

  call DrawText
  .dw Textlines
  ret

DrawText:
	ex (sp),hl
	ld e,(hl)
	inc hl
	ld d,(hl)
	inc hl
	ex (sp),hl
	ex de,hl
	;now loop...
DrawTextLoop:
	ld e,(hl)
	inc hl
	ld d,(hl)
	inc hl
	ld (pencol),de
	vputs
	ld a,(hl)
	inc a
	jr nz,DrawTextLoop
	ret

Textlines:
 .db 4,8,"Hello world!",0
 .db 4,14,"Line 2!",0,255
You know your hexadecimal output routine is broken when it displays the character 'G'.
eightythreeplus
New Member
Posts: 12
Joined: Sat 01 Oct, 2005 6:16 pm
Location: Fairbury, IL, USA

Post by eightythreeplus »

Here is an optimization I've used many times. Suppose you have a variable that contains a letter representing the current player (like 'O' or 'X' for Tic-Tac-Toe). After each move, the variable will alternate between each of two states - $4F or $58. Here is the simplest way to make this work (assuming the current state is in register a):

Code: Select all

     cp $4F
     jp Z, state2
     ld a, $4F
     jp done

state2:
     ld a, $58

done:

At the end of the code, register a contains the other value ($58 if it was $4F, or $4F if it was $58). But this code can be made shorter and faster. If you add $4F and $58, you get $A7. You can get the same results by evaluating $A7 - a. Here's how:

Code: Select all

     neg a
     add a, $A7

The code is much shorter and faster, but harder to understand what is going on (which is why you would document it :).
* 219C9DEF0A45C954492052756C65732100 *
DarkerLine
Calc Wizard
Posts: 526
Joined: Tue 08 Mar, 2005 1:37 am
Location: who wants to know?
Contact:

Post by DarkerLine »

Even shorter and even harder to understand:

Code: Select all

xor $17
Explanation: $4F xor $58 = $17.

Therefore $4F xor $17 = $58 and $58 xor $17 = $4F.

I don't think you can get any smaller.
just try to be nice to people.
_________________
My TI Blog - http://mpl.unitedti.org/
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

By the way, when you want to calculate N-A generally, never do this:

Code: Select all

neg
add a,N
You can cut off a byte and some clocks by doing it this way:

Code: Select all

cpl
add a,N+1
This is because neg is practically equivalent to cpl \ inc a.
eightythreeplus
New Member
Posts: 12
Joined: Sat 01 Oct, 2005 6:16 pm
Location: Fairbury, IL, USA

Post by eightythreeplus »

Ahh, so if I have two states [x] and [y] that I want to alternate between:

Code: Select all

     ld a, [x]
     xor [y]
     ld (xor_val), a

Now if I save the value in register a, the following code will cause an alternation between the states [x] and [y] (assuming register b contains the current state):

Code: Select all

     ld a, (xor_val)
     xor b

Is this correct, DarkerLine?
* 219C9DEF0A45C954492052756C65732100 *
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

Yes, that's correct.
eightythreeplus
New Member
Posts: 12
Joined: Sat 01 Oct, 2005 6:16 pm
Location: Fairbury, IL, USA

Post by eightythreeplus »

In the expression N - a, it would actually be more efficient to use the "neg a/ add a, N" combination if N refers to a register rather than a constant. Or would there be a more efficient method in that situation?
* 219C9DEF0A45C954492052756C65732100 *
eightythreeplus
New Member
Posts: 12
Joined: Sat 01 Oct, 2005 6:16 pm
Location: Fairbury, IL, USA

Post by eightythreeplus »

If you are displaying multiple strings at different locations and the strings are located sequentially in memory, you can optimize by using the de register to set curRow and curCol rather than the hl register; it does add 1 byte for each "ld (xxxx), de" instruction, but you save 3 because you don't have to repoint hl to the next string after it is "messed up" with a screen-coordinate value.

Change

Code: Select all

     ld hl, $0303
     ld (curRow), hl
     ld hl, strPtr1
     b_call(_PutS)

     ld hl, $0505
     ld (curRow), hl
     ld hl, strPtr2
     b_call(_PutS)

to

Code: Select all

     ld de, $0303
     ld (curRow), de
     ld hl, strPtr1
     b_call(_PutS)

     ld de, $0505
     ld (curRow), de
     b_call(_PutS)

when strPtr2 follows strPtr1 in memory to save 1 byte. Another alternative would be to save and retrieve hl from the stack; this would save de from being destroyed, but it would also keep you from using stack-related operations between the two blocks of code.
* 219C9DEF0A45C954492052756C65732100 *
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

Flags instead of bit, whenever possible, can save around 8 T-states.

Code: Select all

in (c)
jp s,label
instead of:

Code: Select all

in a,(c)
bit 7,a
jp z,label
works for sign bit since its a copy of bit 7
Last edited by King Harold on Fri 24 Nov, 2006 5:12 pm, edited 2 times in total.
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

That’s wrong. The dummy input does not use the flag register as the destination! It just sets the flags as in all other inputs and throws away the value that was read.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

It works though, for bit 7 anyway, its a pitty bits 5 and 3 don't have a conditional thing, they're also copies of the real value - or so the manual says.
@coBB: sorry wasn't paying much attention - corrected now :P
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

You could use the flag trick for an LCD waiter:

Code: Select all

WaitLCD:
	ld c,$10
-:	in (c)
	ret p
	jr {-}
will wait until the LCD driver is ready for the next command, CPU speed etc. doesn't matter.
snowman_hater
New Member
Posts: 19
Joined: Mon 01 Jan, 2007 12:17 pm
Location: Ticalc, Obsessing over Stats

Post by snowman_hater »

instead of putting 2 nop's between setting the key group and reading from the key pad, use a 1-byte instruction that takes like 7 t-states.

Code: Select all

ld a,$fe
out (1),a
ld a,(de)
in a,(1)
User avatar
Halifax
Sir Posts-A-Lot
Posts: 225
Joined: Mon 01 Jan, 2007 10:39 am
Location: Pennsylvania, US

Post by Halifax »

Gambit wrote:Normally, you would use the following to increment a variable:

Code: Select all

ld a,(var)
inc a
ld (var),a
But if hl is not tied up and all you do is check flags, use indirection:

Code: Select all

ld hl,var
inc (hl)
ld a,(hl)   ;Optional
Does this not waste 10 tstates.I looked up the tstates for the instructions and their parameters and it shows that indirection wastes 10 tstates.
Liazon
Calc Guru
Posts: 962
Joined: Thu 27 Oct, 2005 8:28 pm

Post by Liazon »

Halifax wrote:
Gambit wrote:Normally, you would use the following to increment a variable:

Code: Select all

ld a,(var)
inc a
ld (var),a
But if hl is not tied up and all you do is check flags, use indirection:

Code: Select all

ld hl,var
inc (hl)
ld a,(hl)   ;Optional
Does this not waste 10 tstates.I looked up the tstates for the instructions and their parameters and it shows that indirection wastes 10 tstates.
IIRC


ld a,(var) :arrow: 13 tstates
inc a :arrow: 4 tstates
ld (var),a :arrow: 13 tstates
total :arrow: 30 tstates

ld hl,var :arrow: 10 tstates
inc (hl) :arrow: 11 tstates
ld a,(hl) <optional> :arrow: 7 tstates
total :arrow: 28 tstates

and LESS space iirc taken up. (2 bytes less)

only downside probably is the fact you've swamped 2 registers.
Image Image Image
Post Reply