8x16 and whatever else unreg wants to know

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tokumaru wrote:
unregistered wrote:

Code: Select all

;= ... (Y / 16) * (2 * 16) + (X / 16)
;= ... ((Y / 16) * 16) * 2 + (X / 16)
Is that correct?
Looks correct to me. Take care with that optimization you did though: you might look at (Y / 16) * 16 and feel tempted to skip all the shifting, but then you'll be keeping the lower 4 bits of Y, which will screw up the result when you add (X / 16) later. The correct way to optimize this formula is (Y AND $F0) * 2 + (X / 16). Multiplications and divisions are obviously done by shifting bits.

Also, since you have only 2 screens worth of collision data, you should ignore the higher bits (you only need bits 0 through 8) of the X coordinate, otherwise you might end up with a pointer to a memory location past the area you have defined for collision data.
unregistered wrote:My collision data is kept in a 15 rows by 32 columns table in 0600-07DF.
If you add $600 to the result from the formula above, you'll end up with a 16-bit pointer you can use to read from this table. You could even skip adding (X / 16) to the pointer and put that into the Y registers instead. The complete code might look like this:

Code: Select all

lda PixelY ;8-bit Y coordinate
and #$0f ;same as shifting right 4 times and then left 4 times
asl ;shift one more time to complete the multiplication by 32
sta Pointer+0 ;the low byte of the pointer is ready
lda #$06 ;prepare to add the high byte of the base address
adc #$00 ;add to the highest bit (carry) of PixelY * 32
sta Pointer+1 ;the high byte of the pointer is ready
lda PixelX+1 ;high byte of 16-bit X coordinate
lsr ;get the only bit we need from it
lda PixelX+0 ;low byte of the 16-bit X coordinate
ror ;put the high bit in
lsr ;shift 3 times to complete the division by 16
lsr
lsr
tay ;put the row offset in the index register
lda (Pointer), y ;get the collision data
This is just one way to do it. Another approach would be to store the collision data a bit differently, as 2 16x15 blocks, instead of a single 32x15 one. That way you could use only the lower bytes of the coordinates to form an 8-bit index and check the 9th bit of the X coordinate to decide between reading from the first or the second collision table. The options are endless, so pick what works best for you. =)
Thank you * 1,000,000 tokumaru!!! :D Being able to see just how it should work meant volumes for me because... I have received help from other threads... I think that's where I got the function linear_position from... and I also had another function called use_colTables that I got from Kasumi... and somehow I mixed them both together so our girl would fall and reach the ground and stop!! :D And then after fixing some things she began to fall through the ground... and I messed up and couldn't remember how the two functions worked together... until just a little while ago I read your code there and I went and changed use_colTables and linear_position16bit a little and IT WORKS!!!!!!!!!!!!!!!!!!!!!!!!!!!! I'M SO HAPPY THANK YOU SO MUCH TOKUMARU!! :D :D It was so nice to finally get some code that encompassed the entire method for linear position! WOOOOOHOOOOOO!! :mrgreen:

edit:
tokumaru wrote:
tepples wrote:This is what Super Mario Bros. does: a 32x13-metatile sliding window stored as two 16x13 halves.
This might be a good approach because it better matches the name table layout, in addition to the possibility of accessing any part of each table with an 8-bit index.
this is part of my edit... wow, it would be fun to try this Mario's way (thank U tepples :D)... but it works so far with the 32x15 way that my code does... and I do think that it would be nice to access with an 8 bit index AND also it would be easier to read the two 16x15 halves ( 16x15 instead of 16x13 because my game doesn't use a status bar unlike Mario who does) instead of the 32x15 thing that I have because the hex editor in FCEUX lists everything in 16 sections... the extra lines will be confusing... but I'm going to create a Monitor covering that so I'll be able to move it to see the different sections... that will be fun to make I think... :)

final edit.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

Ok... I want to make our sprite character disappear... my goal is also to have her stop being animated when she reaches the end of my sister's level. In the past I've been told to set her sprite y coord to "F0" and since she is the only sprite right now I have the code

Code: Select all

  lda #$F0
  sta sprite+0
...

...it runs right after

Code: Select all

  sta onscreenX+1 ;onscreenX+1 should always be 0.  If ever it is nonzero than it's also off the screen.
  beq @continue
. This code worked before... but I changed or fixed something else and it stopped working. :x :( It continues to not work... she continues to run across the screen after, being teleported to the other side of the screen and, memory location $0200 holds a #$F0. That's verified. :) Before, when it worked, her last frame would just remain on the screen but she would not be on the screen anymore! :D Well, I don't remember what I changed or fixed... please help me. Supper time! :)
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

Hello good people. How do I divide by 6 in assembly? My sister suggested I could divide by 2 three times... but that doesn't work in assembly... I think... because dividing by 2 three times is dividing by 8.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tepples »

The most efficient method depends on what you need to divide by 6 for. You could multiply by $2A. Or use an actual divide loop. Or if you're doing random number generator, multiply by 6 instead of mod 6.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

I found a nice divide by 6 routine in this thread by Omegamatrix. :D I will reply to his thread in a bit.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 and whatever else unreg wants to know

Post by tokumaru »

More importantly, you should think hard and decide whether you really need a division by 6. So far it seems you're programming a platform engine, and I can't really think of any reason to divide by 6 in such an engine. Why exactly do you need that division? The best thing to do would be to avoid divisions altogether.
tomaitheous
Posts: 592
Joined: Thu Aug 28, 2008 1:17 am
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tomaitheous »

Tokumaru makes a great point. This is low level optimization vs higher level optimization. Maybe think of a way to use divide by 8; come at it with a different approach. But for low level, I would look at factors in the original expression. As in, what's the range for the value that's divided by 6? Is it something between 0 and 31, or such? Is speed a concern (this is done more than once per frame)? Then use a small look-up table.


On a side note, there's:
A/6 = A/2 - A/3. But it has a side effect of rounding up/down depending on if the results of the two operations before subtraction (if your division results in tourniqueting the decimal part). It's based on A/C - A/(C+1) = A/C*(C+1) = A/C^2+C.
__________________________
http://pcedev.wordpress.com
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tomaitheous wrote:Tokumaru makes a great point. This is low level optimization vs higher level optimization. Maybe think of a way to use divide by 8; come at it with a different approach.
tokumaru does make a great point. Maybe I could use a divide by 8... I thought of doing that... but then I asked my question.
tomaitheous wrote:But for low level, I would look at factors in the original expression. As in, what's the range for the value that's divided by 6? Is it something between 0 and 31, or such?
That's an interesting question... um the value divided by 6 ranges from 20 to 67.
tomaitheous wrote:Is speed a concern (this is done more than once per frame)? Then use a small look-up table.
Speed is always a concern. Thank you that's a great idea... a small lookup table... I have a good idea about how to make one. This page helped me to understand what a lookup table is.

Thank you tepples, tokumaru, and tomaitheous for your responses and tokumaru you do make a great point... like tomaitheous said... but I can't tell you why I think I need my divide by 6. It makes sense to me to use it right now so yall will just have to trust me. :)
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 and whatever else unreg wants to know

Post by tokumaru »

unregistered wrote:I can't tell you why I think I need my divide by 6. It makes sense to me to use it right now so yall will just have to trust me. :)
Then definitely use a look-up table, since the range of numbers is so small. With the number to be divided loaded in the X register you can simply do LDA DivideBy6Table-20, x to get the result.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tokumaru wrote:
unregistered wrote:I can't tell you why I think I need my divide by 6. It makes sense to me to use it right now so yall will just have to trust me. :)
Then definitely use a look-up table, since the range of numbers is so small. With the number to be divided loaded in the X register you can simply do LDA DivideBy6Table-20, x to get the result.
Thank you tokumaru and tomaitheous! :D :D :)
How do I start my lookup table? Maybe I can figure this out... I'll play with it. :D
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 and whatever else unreg wants to know

Post by tokumaru »

unregistered wrote:How do I start my lookup table?
You could write all the values by hand, but it's usually a better option to let the assembler do the hard work. If you're using ASM6, this should do it:

Code: Select all

DivideBy6Table:
	Value = 20
	.rept 48 ;there are 48 values between 20 and 67
	.db Value / 6
	Value = Value + 1
	.endr
There's nothing special about look-up tables, they simply contain pre-calculated values so that you don't have to calculate them during runtime, which saves you some CPU time. Whether you should use look-up tables for specific tasks depends on how much ROM you're willing to dedicate to such tables and how often said tasks are performed. Sometimes they can be prohibitively large, but for something as small as 48 bytes it just makes sense to have all the results pre-calculated.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tokumaru wrote:
unregistered wrote:How do I start my lookup table?
You could write all the values by hand, but it's usually a better option to let the assembler do the hard work. If you're using ASM6, this should do it:

Code: Select all

DivideBy6Table:
	Value = 20
	.rept 48 ;there are 48 values between 20 and 67
	.db Value / 6
	Value = Value + 1
	.endr
!!!!!!!!!!!!!!!!!WOW!!!!!!!!!!!!!!!!!!!!!!!!!!
tokumaru wrote:There's nothing special about look-up tables, they simply contain pre-calculated values so that you don't have to calculate them during runtime, which saves you some CPU time. Whether you should use look-up tables for specific tasks depends on how much ROM you're willing to dedicate to such tables and how often said tasks are performed. Sometimes they can be prohibitively large, but for something as small as 48 bytes it just makes sense to have all the results pre-calculated.
Thank you incredibly much tokumaru! I feel everyone can benefit and learn everything there is to know about lookup tables! Those words are gold and a fitting close to this lookup table grandness... THANKS SO MUCH TOKUMARU!! :D ...AND THANK YOU TOMAITHEOUS FOR MENTIONINGRECOMMENDING LOOKUP TABLES! :D

edit.

edit2.
tomaitheous
Posts: 592
Joined: Thu Aug 28, 2008 1:17 am
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tomaitheous »

LUTs or look-up tables, are the magic elixir of the 65x processors. Free indexing is really nice ;) They can really speed up the processor operations (albeit at the expense of memory). I tend to have LUTs just for shift+Add or shift+OR for quick address translation for larger tables (it gets the upper address bits for larger tables). Don't forget split tables too (lsb/msb), for faster access. But yeah, a table could have multiple operations/calculations in them.
__________________________
http://pcedev.wordpress.com
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

rainwarrior[color=#FF00FF], on [url=http://http://forums.nesdev.com/viewtopic.php?f=10&t=12246&p=139231&hilit=fceux+conditional+breakpoints#p139231]this page[/url],[/color] wrote:Other helpful things when debugging:

1. Debug > Trace logger.

This lets you dump a text file containing every instruction executed and the status of every register/flag at each step.

2. Conditional breakpoints.

This lets you set a breakpoint that also has a condition.
See: FCEUX debugger guide


For example, if you know that if something is wrong if A is 5 at line $8075, then what you can do it start a trace log at a time before things go wrong, create an execuition breakpoint on 8075 with the condition A==#5, then run until the breakpoint is hit. Stop the trace at this point, and you will have a log of everything that happened up until that breakpoint. From here you can work backwards from the end of the file until you see exactly what caused the problem.
Thank you * 100000000 rainwarrior!! :D That FCEUX debugger guide page helped me to set an extremely helpful conditional breakpoint! Wooooooooohoooo!

Now I have a question for anyone... How do you accomplish Symbolic Debugging? :? I read about that on the site that rainwarrior linked to... in the section under "Symbolic Debugging". In the debug menu I right click on an address and a menu pops up and then I type "AddHealthpoints" and all that happens is that all of the text in the debugger is highlighted. :shock: :? :( I just want the address I clicked on to show up as JSR AddHealthpoints... just like the paragraph says. :? :)
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tepples »

To enable symbolic debugging, you need to make a .nl (name list) file. There should be tools to turn the list of exported symbols produced by an assembler into a .nl file; if not, you could always whip one up in JScript or Python.
Post Reply