It is currently Mon Oct 15, 2018 10:53 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Fri Oct 05, 2018 11:35 am 
Offline
User avatar

Joined: Wed Sep 05, 2018 11:13 am
Posts: 69
Location: Colorado
So, for objects I want to move at a fractional speed on every nmi, something like 0.5 or 1.25 pixels every time an nmi runs, I'm currently using a second byte where I'm only using bit 6 and 7.

I've been messing around with Easy6502 trying to get something working, but I've been running into issues.

here's the code I've been using on Easy6502:

Code:
; set up all of the variables
; the floating point portion will only be 2 bits
; this will support 1/4 parts
   lda #$3
   sta subtract_float
   lda #5
   sta whole_number
   sta starting_whole_number
   lda #2
   sta float_number
   sta starting_float_number

   ; before storing this number in
   ; the float_number variable I'm going to
   ; shift it over 6 bits
   asl
   asl
   asl
   asl
   asl
   asl
   
   sta float_number_shifted

   lda subtract_float   
   ; 6 shifts to use bits 7 and 6
   clc
   asl
   asl
   asl
   asl
   asl
   asl

   ; if the carry is clear the shifts didn't
   ; overflow
   bcc skip_dec_1
      ; if the carry flag was set dec
      ; the whole number
      dec whole_number
      jmp skip_dec_whole_2
   skip_dec_1:
   sec
   sbc float_number
   ; if the carry is clear we must dec the
   ; whole number
   bcs skip_dec_whole_2
      dec whole_number
skip_dec_whole_2:
   lsr
   lsr
   lsr
   lsr
   lsr
   lsr
   sta float_number

jmp end
starting_whole_number:
   nop
starting_float_number:
   nop
float_number_shifted:
   nop
whole_number:
   nop
float_number:
   nop
subtract_float:
   nop

end:


I think I'm just going about this the wrong way. Does anyone have any suggestions?

Thanks

_________________
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 11:42 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7648
Location: Seattle
Use 8.8 fixed point instead: it's a lot easier to manage.

8.8 looks just like ordinary 16-bit math, except that you only use the upper byte when displaying the results.


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 11:46 am 
Offline
User avatar

Joined: Wed Sep 05, 2018 11:13 am
Posts: 69
Location: Colorado
lidnariq wrote:
Use 8.8 fixed point instead: it's a lot easier to manage.

8.8 looks just like ordinary 16-bit math, except that you only use the upper byte when displaying the results.



That's a good idea. I need to keep it simple.

Thanks

_________________
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 12:29 pm 
Offline
User avatar

Joined: Sat Feb 16, 2013 11:52 am
Posts: 320
lidnariq wrote:
Use 8.8 fixed point instead: it's a lot easier to manage.

8.8 looks just like ordinary 16-bit math, except that you only use the upper byte when displaying the results.


Fixed point is great, and usually clamping off the LSB for functions that work with regular 8-bit integers is ok for most cases, especially when deciding where to put a sprite on screen or which position to use when calculating collisions. The decimal part of the number is simply a base 256 fraction so the concept is very simple and effective.

Having an actual floating point number (Signed mantissa times base 10 exponentiation) seems overly complex for a machine like the NES.

_________________
This is a block of text that can be added to posts you make. There is a 255 character limit.


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 12:40 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6875
Location: Canada
BTW there are many very readily available floating point implementations for 6502 if you do want to use them. e.g.
http://www.6502.org/source/floats/wozfp1.txt

They're slow, of course, but I'm sure that's already taken for granted. ;)


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 3:03 pm 
Offline
User avatar

Joined: Wed Sep 05, 2018 11:13 am
Posts: 69
Location: Colorado
So if I want to have a negative decimal number, like -1.25, how would that work using fixed point? I was thinking that #$E0 in the low byte could represent -0.25, but then would I need $FF in the high byte? I'm a little confused as to what I would do if the high byte were negative and the low positive, or if I should just make the low byte 1/256 and assume the sign is based on the high byte.

Any suggestions as to how to handle 16 bit negative numbers?

Thanks

_________________
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 3:04 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20656
Location: NE Indiana, USA (NTSC)
In q8 fixed point:
  • 1.25 is represented as 320/256, or $0140.
  • -1.25 is represented as -320/256, or $FEC0. This is equal to $10000 - $0140.


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 3:07 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6875
Location: Canada
battagline wrote:
So if I want to have a negative decimal number, like -1.25, how would that work using fixed point? I was thinking that #$E0 in the low byte could represent -0.25, but then would I need $FF in the high byte? I'm a little confused as to what I would do if the high byte were negative and the low positive, or if I should just make the low byte 1/256 and assume the sign is based on the high byte.

Any suggestions as to how to handle 16 bit negative numbers?

Signed fixed point numbers work the same as other signed numbers. It's the standard two's complement representation, where the highest bit indicates sign. (On that linked article, maybe look at the tables to get an idea. The first column is the number respresented, and the second column is how it'd be stored.)


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 7:44 pm 
Offline

Joined: Wed Nov 30, 2016 4:45 pm
Posts: 116
Location: Southern California
May I broaden the scope to scaled-integer? Because fixed-point is just a limited subset of scaled-integer arithmetic. The first half of the front page of the section of my website section on large look-up tables is an article about scaled-integer, showing how to do things with it that most people don't realize can be done without floating-point.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 7:57 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6875
Location: Canada
What is your definition of "scaled integer" that makes it different from "fixed point"? As far as I can tell that article treats them as synonyms. (I'm unfamiliar with "scaled integer" as a term.)


Top
 Profile  
 
PostPosted: Fri Oct 05, 2018 8:38 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7648
Location: Seattle
I'd arbitrary guess that "scaled integer" means things where the fixed point isn't necessarily on a power of two...

Garth's linked page wrote:
Keep in mind that the scale factor in scaled-integer arithmetic does not necessarily have to be evenly divisible by 16, 10, 5, 2, or even an integer at all! (See the situation with degrees and radians further down.) Also, the six log and antilog tables can be used for any base, by scaling. In scaled-integer, they work best in base 2; but from there, you get the natural (base e) log for example by multiplying the base-2 log by 7050/10171 (or just cranking that number into the scale factor). The table descriptions page gives supporting information.

He then gives examples, such as choosing to handle currency as integral cents instead of dollars, or scaling trigonometric functions to have a period of some power of two (instead of 360°, 2π, τ, 400ᵍ, &c)


Top
 Profile  
 
PostPosted: Sat Oct 06, 2018 10:04 am 
Offline
User avatar

Joined: Wed Sep 05, 2018 11:13 am
Posts: 69
Location: Colorado
Thanks guys... it took me a little while to understand why the math behind 2s compliment works.

So just to make sure I understand it, let me try to explain it and anyone feel free to tell me what I'm getting wrong.

When you are doing 2s complement, you are effectively subtracting the number you have from a number one value higher than the highest number you have based on the number of bits you can represent.

So if you do 2s compliment to 3, you are basically taking 256 and subtracting 3 to get 253. Then when you add any number to 253 that is larger than 3, it is essentially wrapping back around when you exceed the maximum number you support. flipping the bits and adding one is basically a fast way of subtracting from 256 in binary. If I'm understanding this right, you could do a similar inverting if you had decimal numbers instead of binary. If you had 3 decimal digits and wanted to represent negative numbers with them, you could have any number over 500 represent a negative number and flip any positive number to a negative number by subtracting each digit from 10 and adding 1

representing 398 as a negative number in this system would be 602 (1000-398), so if you wanted to see what would happen if you added -398 to 420, you would add 420 to 602 and get 1022, but since there are only 3 digits we are keeping track of we end up with 022 or 22 (420-398). The way you get to 1000 when you can't hold 1000 in memory is to put the highest number into memory you can hold (999) and subtract from that. Since you want to go one higher than the highest number you can hold in memory, you then have to add one to your result, so it would be 999-398+1.

when you perform an eor #$ff in binary, that's just a faster way of getting #$ff - (value)

I apologize if my explanation doesn't make sense to anyone other than me.

please let me know if I'm getting this wrong.

Thanks

_________________
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com


Top
 Profile  
 
PostPosted: Sat Oct 06, 2018 10:42 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6875
Location: Canada
Yes, I think you have it correct.

In general, signed operations are similar to unsigned ones but sometimes slightly more cumbersome:

  • For adding and subtracting the operations are the same.
  • For comparison, they are different (e.g. $FF should be less than $01). This requires looking at a few flags at once to resolve (details here).
  • For left shift, it is the same as unsigned. (ASL followed by ROL for consecutive bytes.)
  • For right shift, you need to duplicate the high bit to maintain sign. (CMP #$80 followed by ROR, then ROR for consecutive bytes.)


Last edited by rainwarrior on Sat Oct 06, 2018 1:05 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Oopsie woopsie
PostPosted: Sat Oct 06, 2018 1:00 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20656
Location: NE Indiana, USA (NTSC)
rainwarrior wrote:
For right shift, you need to duplicate the high bit to maintain sign. (CMP #$80 followed by ROL, then ROL for consecutive bytes.)

Isn't ROR for right shift?


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: Google [Bot] and 2 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:  
Powered by phpBB® Forum Software © phpBB Group