[TI ASM] Optimizations

Got questions? Got answers? Go here for both.

Moderator: MaxCoderz Staff

User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

ex hl,de is not defined in TASM80.tab (it's defined as ex de,hl). You need to add it yourself or define it in your program.
Another pitfall is that ex de,hl does not just copy one register to another - the ex instruction exchanges the values, so what was in de is now in hl and what was in hl is now in de. You can use the ex instruction to exchange registers between the two register files, or use exx to exchange all the registers through the register files to their shadow pair (useful for interrupts).

Oh, and when multiplying by powers of two, add a,a is faster than the equivalent shift operation (IIRC).
DarkAuron
Maxcoderz Staff
Posts: 1349
Joined: Sat 18 Dec, 2004 6:53 pm

Post by DarkAuron »

Although if you don't care about it bit 0 being updated you can use rla or rlca to rotate (same speed and size as add a,a), but yes add a,a is faster than the pure shift.
[Gridwars Score] - E: 1860037 M: 716641 H: 261194
koolmansam375
Extreme Poster
Posts: 479
Joined: Fri 17 Dec, 2004 11:09 pm
Contact:

Post by koolmansam375 »

i learned optimization tricks from this:

http://www.ticalc.org/archives/files/fi ... 28502.html

It has size optimization and time optimization techniques
Image

Pongwars shall live!

blog is down atm. :-(
lloydkirk1989
Calc Wizard
Posts: 680
Joined: Wed 22 Dec, 2004 5:37 am
Location: West Palm Beach,FL
Contact:

Post by lloydkirk1989 »

Thats a rather thorough guide. I'll have to read it. :) Seeing that its in a zip file and the online version is not working, I might as well upload it to the web.
http://hostingproject.info/lloydkirk1989/z80optim.html
User avatar
Jim e
Calc King
Posts: 2457
Joined: Sun 26 Dec, 2004 5:27 am
Location: SXIOPO = Infinite lives for both players
Contact:

Post by Jim e »

I don't know about that guide, i went through it, and alot seem fine enough but there were mistakes and code not fully optimised(just a little). But one thing did get to me was this
Whenever you need to call subroutines, you might consider using:
ld HL,param1
call sub1
ld HL,param2
call sub2
ld HL,param3
call sub1
...
sub1:
...
ret
sub2:
...
ret
This is the conventional way to do this. However, there is a much more efficient way to do this using what's known as call tables. Here's how they work:
ld SP,callTable
ret ; Jump to sub1
sub1:
pop HL
...
ret
sub2:
pop HL
...
ret
callTable:
.dw sub1,param1
.dw sub2,param2
.dw sub1,param3
In the first line, callTable is stored into the Stack Pointer (SP). Please note that altering the Stack Pointer can be potentially damaging. You'll probably want to save the contents of SP before using a call table. If used properly, call tables will prove to be very efficient. It is, as you can see, a very complex way of calling routines. And in fact, they don't always make your programs more efficient. Generally, you will only want to use call tables when you are passing a different parameters to several consecutive subroutines.
There is just so many problems with this. First off, it rare that you would have code set up in such a way that you could list many values and calls so linearly. Second his use of the stack is a bad one, it renders use of bcalls, calls, pushes and pops all useless.
This in't a very good method for a call table, situation is far to specific to be considered useful.

LDDing the table to the stack would be better and safer, it would at least allow for use of calls and pushes.

Any way heres one I remembered.

Code: Select all

;Instead of
    ld de,-767
    add hl,de

;try this
    dec h  ; -256
    dec h  ; -512
    dec h  ; -768
    inc hl  ; -767
That can be used for other things, but it's good for fastcopy routines and mappers. :wink:
Image
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

benryves wrote:ex hl,de is not defined in TASM80.tab (it's defined as ex de,hl). You need to add it yourself or define it in your program.
But such 'tricks' are definitely discouraged if you intend to distribute your source.

There are other strange things on the page Jim linked, e. g. the section about case insensitivity also contains serious errors.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

CoBB wrote:
benryves wrote:ex hl,de is not defined in TASM80.tab (it's defined as ex de,hl). You need to add it yourself or define it in your program.
But such 'tricks' are definitely discouraged if you intend to distribute your source.
I think there is a directive that means you can add new "instructions" to TASM's database when compiling from the current source file. But yes, it is messy and far better to stick to the ex de,hl that is more usually accepted.
User avatar
Dwedit
Maxcoderz Staff
Posts: 579
Joined: Wed 15 Dec, 2004 6:06 am
Location: Chicago!
Contact:

Post by Dwedit »

I always liked stack tricks... Such as this:

Code: Select all

  call Disp
  .db "This is some text",0
  ret

Disp:
  pop hl
  bcall(_vputs)
  jp (hl)
Not a speed optimization, but it eliminates 2-byte pointers, since it just uses the call's return address.
It also heavily distrubs disassembly.
You know your hexadecimal output routine is broken when it displays the character 'G'.
User avatar
Jim e
Calc King
Posts: 2457
Joined: Sun 26 Dec, 2004 5:27 am
Location: SXIOPO = Infinite lives for both players
Contact:

Post by Jim e »

I like that one, it could allow for an easy to use macro. And really how often is text displaying the buggy part of code.
Image
koolmansam375
Extreme Poster
Posts: 479
Joined: Fri 17 Dec, 2004 11:09 pm
Contact:

Post by koolmansam375 »

There are some mistakes in the Optimization guide but other than that it is good for learning how to optimize.
Image

Pongwars shall live!

blog is down atm. :-(
DarkAuron
Maxcoderz Staff
Posts: 1349
Joined: Sat 18 Dec, 2004 6:53 pm

Post by DarkAuron »

Dwedit wrote:I always liked stack tricks... Such as this:

Code: Select all

  call Disp
  .db "This is some text",0
  ret

Disp:
  pop hl
  bcall(_vputs)
  jp (hl)
Not a speed optimization, but it eliminates 2-byte pointers, since it just uses the call's return address.
It also heavily distrubs disassembly.
:o That's awesome
[Gridwars Score] - E: 1860037 M: 716641 H: 261194
Stickmanofdoom
Regular Member
Posts: 86
Joined: Fri 17 Dec, 2004 8:20 pm
Contact:

Post by Stickmanofdoom »

Another good "article" about optimization is http://www.ticalc.org/pub/text/z80/z80opt.zip
It takes the examples and explanations further than most other articles.
sigma
New Member
Posts: 27
Joined: Thu 31 Mar, 2005 10:56 pm
Location: Stuck in 8-bit land.

Post by sigma »

If you want a 16-bit loop counter, never, ever do this:

Code: Select all

- ; Loop body
  ;   .
  ;   .
  ;   .
  ld  a, d
  or  e
  jp  nz, -
Do this instead:

Code: Select all

  dec  de
  ld  b, e
  inc  b
  inc  d
- ; Loop body
  ;   .
  ;   .
  ;   .
  djnz  -
  dec  d
  jp  nz, -
More info: http://map.tni.nl/articles/fast_loops.php
Stickmanofdoom
Regular Member
Posts: 86
Joined: Fri 17 Dec, 2004 8:20 pm
Contact:

Post by Stickmanofdoom »

If you want to add A to any 2-byte register and can't destroy any other registers besides A:

Code: Select all

 add a,l
 ld l,a
 adc a,h
 sub l
 ld h,a
CalcKing
Regular Member
Posts: 147
Joined: Sat 18 Dec, 2004 3:24 am
Contact:

Post by CalcKing »

Expanding on Dwedit's trick, I created a macro system for Bot Attack.

Using it, I changed

Code: Select all

	ld	hl,0
	ld	(currow),hl
	ld	hl,title	; Draw title text
	bcall(_puts)

	ld      bc,(0*256)+55
        ld      de,(94*256)+55
        bcall(_darkline)	; Underline title text

	ld	de,1+(256*9)
	ld	hl,txt_author	; Draw author's name... ;-)
	call	cur_vputs

	ld	de,4+(256*18)
	ld	hl,txt_start	; Draw "2nd - Start"
	call	cur_vputs

	ld	de,4+(256*25)
	ld	hl,txt_size	; Draw "(/,*,-,+) - Area:"
	call	cur_vputs

	ld	de,4+(256*32)
	ld	hl,txt_bots	; Draw "(LEFT/RIGHT) - # of bots:"
	call	cur_vputs

	ld	de,4+(256*39)
	ld	hl,txt_quit	; Draw "Clear - Exit"
	call	cur_vputs

	...

;-----> Optimized vput routine
; inputs:	de=coordinates
;		hl=pointer to string
; output: String displayed, smaller than using redundant code
cur_vputs:
	ld	(pencol),de
	bcall(_vputs)
	ret
into

Code: Select all

#define	curVPutS(curPos)	call	cur_vputs \ .dw	curPos

	...

	ld	hl,0
	ld	(currow),hl
	ld	hl,title	; Draw title text
	bcall(_puts)

	ld      bc,(0*256)+55
        ld      de,(94*256)+55
        bcall(_darkline)	; Underline title text

	curVPutS(1+(256*9))			; Draw author's name... ;-)
	.db	"by Peter Wakefield",0

	curVPutS(4+(256*18))			; Draw "2nd - Start"
	.db	"2nd - Start",0

	curVPutS(4+(256*25))			; Draw "(/,*,-,+) - Area:"
	.db	"(/,*,-,+) - Area: ",0

	curVPutS(4+(256*32))			; Draw "(LEFT/RIGHT) - # of bots:"
	.db	$CF,"/",$05,"  - # of bots: ",0

	curVPutS(4+(256*39))			; Draw "Clear - Exit"
	.db	"Clear - Exit",0

	...

;-----> Optimized vputs routine
; inputs:	bytes following call: CoordLSB,CoordMSB,Null-terminated string
; output: String displayed, smaller than using redundant code
cur_vputs:
	pop	hl
	ld	e,(hl)
	inc	hl
	ld	d,(hl)
	inc	hl
	ld	(pencol),de
	bcall(_vputs)
	jp	(hl)
This greatly reduced the size of my title screen, and would have reduced the size much more had I not already been using a routine for size reduction.

For those who do not see it already, the main difference with this routine is that it defines coordinates as in-line variables along with the string which is displayed. Again, this is good for title screens where there are constant coordinates for text. :wink:
Long live Z80 and #tiasm!


^^ Alas, I wrote that a long time ago. :(
Post Reply