Simple multiplication

Here you can ask questions or provide insights about how to use efficiently 6502 assembly code on the Oric.
Pengwin
Pilot Officer
Posts: 68
Joined: Sun Jan 07, 2007 11:03 pm
Location: Scotland
Contact:

Simple multiplication

Just checking I have understood things.
I have written, what I hope is a simple multiplication routine to multiply 2 bytes, returning a word. This could obviously be very useful for calculating screen addresses.

Just want to check that what I have come up with is as efficient as possible, so I would like some of you gurus to have a quick look over it please.

First up, I have designated these locations for custom maths routines I may come up with:

Code: Select all

``````; First operand for custom maths routines
#define		MATHOP1	\$00
; Second operand for custom math routines
#define		MATHOP2	\$02
; Answer from custom maths routines
#define		MATHRES	\$04
``````
Then I have the subroutine that uses those locations:

Code: Select all

``````; Multiply routine
;
; This routine multiplies two bytes together,
; resulting in a word.
;
; Pass the two arguments via (Page 0 addresses):
;		MATHOP1			(\$00)
;		MATHOP2			(\$02)
;
; The jump to the subroutine:
;		multiply
;
; The answer is held in (Page 0 address):
;		MATHRES			(\$04)
; and 	MATHRES+1		(\$05)
;
; Corrupts the following registers:
;			P, X, A
;
; Corrupts the following memory locations:
;			MATHOP1

Multiply
.(
cld
lda #0
sta MATHRES
sta MATHRES + 1
ldx #8
multloop	asl MATHRES
rol MATHRES + 1
asl MATHOP1
bcc multnext
clc
lda MATHOP2
adc MATHRES
sta MATHRES
lda MATHRES + 1
adc #0
sta MATHRES + 1
multnext	dex
bne multloop
rts
.)``````
Have I understood things correctly? Is there a more efficient way of doing this?

Chema
Game master
Posts: 2349
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Simple multiplication

Hi!

You're using the shift & add method for 8 bit, aren't you? That is quite fast and compact.

If you ever need a really fast method you can check my post here. I really needed that speed in 1337, due all the matrix operations that were needed.

Check www.6502.org for more interesting sources for this and other areas.

Oh, and if you are looking for a fast method to obtain the pixel address for a given coordinate pair (x,y) stored in regs X and Y respectively to set/clear a pixel in HIRES screen, check this code (from Dbug). tmp0 is a ZP address:

Code: Select all

``````
lda _HiresAddrLow,y
sta tmp0+0
lda _HiresAddrHigh,y
sta tmp0+1
ldy _TableDiv6,x
lda _TableBit6Reverse,x
ora (tmp0),y
sta (tmp0),y
``````
The code to setup those tables is (I've taken this from 1337, modifying a couple of bits by hand, so don't trust it 100% - However I think the code has been posted somewhere, maybe in the SVN, maybe even it is included in the OSDK):

Code: Select all

``````#define X_SIZE      240
#define Y_SIZE      200
#define ROW_SIZE    X_SIZE/6

.dsb 256-(*&255)
_HiresAddrLow           .dsb Y_SIZE
.dsb 256-(*&255)
_HiresAddrHigh          .dsb Y_SIZE
.dsb 256-(*&255)
_TableDiv6              .dsb X_SIZE
.dsb 256-(*&255)
_TableBit6Reverse
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1

.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1

.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1

.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1
.byt 32,16,8,4,2,1

.dsb 256-(*&255)

.byt 0

_GenerateTables
.(
ldx #0
loop
; generate two bytes screen adress
clc
lda tmp0+0
sta _HiresAddrLow,x
adc #ROW_SIZE
sta tmp0+0
lda tmp0+1
sta _HiresAddrHigh,x
adc #0
sta tmp0+1

inx
cpx #Y_SIZE
bne loop
.)
.(
; Generate multiple of 6 data table
lda #0      ; cur div
tay         ; cur mod
tax
loop
sta _TableDiv6,x
iny
cpy #6
bne skip_mod
ldy #0
adc #0      ; carry = 1!
skip_mod

inx
cpx #X_SIZE
bne loop
.)
rts
``````

Dbug
Site Admin
Posts: 2799
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Simple multiplication

Pengwin wrote:Just checking I have understood things.
I have written, what I hope is a simple multiplication routine to multiply 2 bytes, returning a word. This could obviously be very useful for calculating screen addresses.
As Chema wrote, the best way is to not calculate screen addresses at all but instead to use tables.
If you have room, just store the table in the data section, already generated.
If you want to make a small demo, you can store the table in the bss section and generate it on startup.

The fastest code is the one you don't run

Chema
Game master
Posts: 2349
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Simple multiplication

Dbug wrote:The fastest code is the one you don't run
Yeah, that I learned from you, Dbug. I remember how I was trying to make a fast compact pixel_address and line routines and how you demonstrated me that it was way better to use tables and avoid running code.

You enlightened me indeed!

Pengwin
Pilot Officer
Posts: 68
Joined: Sun Jan 07, 2007 11:03 pm
Location: Scotland
Contact:

Re: Simple multiplication

Thanks for the answers guys, plus the tip of using tables for screen coordinates, I can see how that could save a massive number of clock cycles.