6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Sep 21, 2024 5:42 pm

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Tue Sep 08, 2020 8:49 am 
Offline

Joined: Thu Apr 23, 2020 12:57 pm
Posts: 11
Hi,

What is the best (fast) method on 6502 to make a scaling down of specific 8bit value by other 8bit value.
Lets say I have byte value A and I want to scale it by [0,1) in form of byte value B ($0-$FF, so $80 is 0.5).

scaled= A * B (hex%)

A = $C0
B = $80
scaled = $C0 * $80 / $100
scaled = $6000 / $100
scaled = $60

You can therefore do it by 8bit x 8bit multiplication and using the high byte of the result, but maybe there is a better (faster) way of doing it? Or the only method for speeding it up is to use some fast 8bit multiplication routine e.g. https://codebase64.org/doku.php?id=base ... iplication ?

Example use case: I have a sine table $0-$FF and I want to perform scaling of the value to move some objects on different sine-related trajectories (spirals of different radius, waves of different amplitude)


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 08, 2020 9:29 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
Yes, scaling is multiplication. As you say, there are fast methods, and if you need limited precision in the result you can save a bit. Maybe you can even pre-scale your values.

If multiplying by constants you may find you can hard code the approach with some shifts and adds, or indeed shifts and subtracts when there are runs of 1's. The shifts too you might be able to do as a lookup, if you have the space.

Best case is both limited precision and constants, so you only need two or three shifts and adds and you can hard code the routine for each constant.


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 08, 2020 9:30 am 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 702
Location: North Tejas
8 bits in and 8 bits out?

Code:
    ldx     Value
    lda     Sine,X


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 08, 2020 10:09 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 325
It's a bit hungry on RAM (2K of tables), but you could have a table of pre-scaled sin values for each power of two, and add the appropriate ones to get any scale you like. Like this:
Code:
; scale in A, parameter in X
; returns scale*sin(X)/256
   EOR #$ff
   STA scale
   LDA #0
   LSR scale
   BCS skip1
   ADC sin1, X
skip1:
   LSR scale
   BCS skip2
   ADC sin2, X
skip2:
   ...
   LSR scale
   BCS skip8
   ADC sin8, X
skip8:

Normally you'd want to add when the bit of the scale is 1, but if we invert it first we can add when the bit is 0 and that saves a CLC. With a fixed scale it's just a series of CLC / ADC tableN,X, one pair for each 1 bit in the scale.

It's not completely accurate: you'll be losing some carries that should be coming from the absent low byte. But it might be good enough depending on what you want to use it for.

It turns out that the first table is entirely 0, so the low bit of the scale doesn't contribute anything. On the plus side, you can save a few cycles and one 256 byte table.


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 08, 2020 7:57 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8510
Location: Southern California
This topic will be relevant: Simple 8bit division routine
It includes a way to take the logarithm that's quick and dirty but might still give good enough accuracy for what you want. Once you get the logs of the inputs, you can just add the logs for multiplication, or subtract for division. You can chain these without having to get logs over and over or take the antilog until you're done with the chain of multiplications and divisions. Then taking the antilog is just the reverse. No tables are used.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 09, 2020 4:51 am 
Offline

Joined: Wed Mar 02, 2016 12:00 pm
Posts: 343
You either throw a large table at the problem (x*y=65536 bytes for 8-bit precision) or cut it down to smaller tables and some computation. The fastest way is always a table:

Code:
        stx mod+1
mod: lda table,y


The table is precomputed and is so large that you need banked memory... not very practical unless your system supports it.

For a smaller 256 byte table, you can have 4*4bit precomputed and make the 8*8bit result out of that:

Code:
mult88f
        txa             ;2
        and     #$f     ;2
        sta     m4s1+1  ;4
        asl             ;2
        asl             ;2
        asl             ;2
        asl             ;2
        sta     m4u1+1  ;4
        txa             ;2
        and     #$f0    ;2
        sta     m4s2+1  ;4
        lsr             ;2
        lsr             ;2
        lsr             ;2
        lsr             ;2 (c=0)
        sta     m4s3+1  ;4
        tya             ;2
        and     #$f0    ;2
        tax             ;2
        tya             ;2
        and     #$f     ;2
        tay
m4s1    lda     tab44,x ;5
m4s2    adc     tab44,y ;5 h4bx*l4by - c=0
        sta     $92     ;3
        ror             ;2 shift right and put carry in bit7
        lsr             ;2
        lsr             ;2
        lsr             ;2 all bits in bit4-bit0
        sta     $93     ;3 high byte result (e.g. *16)
        lda     $92     ;3
        and     #$f     ;2
        asl             ;2
        asl             ;2
        asl             ;2
        asl             ;2 *16
m4u1    adc     tab44,y ;5 l4bx*l4by
        sta     $92     ;3
m4s3    lda     tab44,x ;5 h4bx*h4by*16*16
        adc     $93     ;3 result high byte, add overflow carry
        sta     $93     ;3


It is 106 cycles to compute the 16-bit result. The 4*4bit table can be made with this code:

Code:
initmult
         ; set up 15x15 multiplication table
        ldx     #$0     ; multiplier
        ldy     #$0     ; index

iml0    tya
        clc
        adc     #16
        sta     imc1+1
        txa             ; start value=multiplier
        sta     $96     ; add multiplier to A each round
iml1    sta     tab44,y
        adc     $96
        iny
imc1    cpy     #00
        bne     iml1
        inx
        cpx     #16
        bne     iml0
        rts


You can also have slightly larger tables (512 bytes, 1024 bytes) and save another 20-40 cycles on the multiplication (like in the link you referred to).


If you only want to scale by a predefined factor (like 1/10th), you can just throw a division at the problem:

A/10=A*26/256=(A*16+A*8+A*2)/256.

Which can be done by a few ADD, ASL and LSR.


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 09, 2020 11:08 am 
Offline

Joined: Thu Apr 23, 2020 12:57 pm
Posts: 11
Thank you all for great answers so far! I'll need some time to process them to find the best approach to my cases. For sure idea of using logarithms is a good one and worth checking from accuracy perspective. Scaling is multiplication and there are some very fast multiplication routines e.g. https://github.com/tebe6502/Mad-Assembl ... lu_8x8.asm that may be even faster than using logarithms. I will need to check different approaches and profile the code.


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 10, 2020 6:18 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 674
You could probably get a lot of very directly applicable info from Steve Judd's exploration into 3d graphics in C=Hacking. His fastest multiplication is 24-26 cycles, for 8*8=8 bit, though there's a few different takes & places on it. He also uses -64 to +64 to represent a -1.0 to +1.0 sin/cos scale factor, instead of mapping 0-255 to 0.0-1.0.

In issues 8-10 there's "A Different Perspective" which works through all the math & fill routines (issue 9 has the core multiply routine), while issue 12 has Polygonamy, which is the final demo.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 14 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: