It is currently Mon Nov 20, 2017 10:23 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 98 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7  Next
Author Message
 Post subject: Re: NES Programming Blog
PostPosted: Tue May 10, 2016 1:08 am 
Offline
Formerly WhatULive4
User avatar

Joined: Fri Oct 30, 2009 4:43 am
Posts: 338
I saw your video. Should be useful for beginners, I did find the loud clicking a bit distracting, I'm not sure if the mic was picking that up, or if it is a part of your recording software.


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Mon May 16, 2016 5:12 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
I made a video about using the debugging tools of FCEUX. I probably forgot about a dozen things to mention, but it was getting pretty long.

https://youtu.be/d2XkJQFs0OQ

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Fri Aug 12, 2016 7:19 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
I've updated every example code (except for the Spacy Shooty game code, which I plan to rewrite from scratch).

Most of the changes are cosmetic (make comments easier to read), or just trying to make the code more stable.
-added a second v-blank wait in the startup code, before writing to PPU. Which I must have accidentally removed and never put back in.
-moved 'things that need to be done every frame' (like sprite DMA) to NMI code
-added a write to a000 (mirroring) to the init code for my MMC3 examples
-removed the copy of nes.lib from every zip, which apparently was completely unnecessary to keep a copy of, since cc65 is able to find its own copy

At some point, I will also update the Spacy Shooty example code.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Sun Aug 14, 2016 4:41 am 
Offline

Joined: Thu Nov 24, 2011 7:16 am
Posts: 163
dougeff wrote:
I've updated every example code (except for the Spacy Shooty game code, which I plan to rewrite from scratch).

Most of the changes are cosmetic (make comments easier to read), or just trying to make the code more stable.
-added a second v-blank wait in the startup code, before writing to PPU. Which I must have accidentally removed and never put back in.
-moved 'things that need to be done every frame' (like sprite DMA) to NMI code
-added a write to a000 (mirroring) to the init code for my MMC3 examples
-removed the copy of nes.lib from every zip, which apparently was completely unnecessary to keep a copy of, since cc65 is able to find its own copy

At some point, I will also update the Spacy Shooty example code.


Great! :beer:


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Sun Aug 14, 2016 8:10 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
I've decided to finally do some testing with structs vs cc65.

If you declare the actual struct in the global space, it puts them in the BSS, and actually takes about as much time to access as any other variable...

Code:
struct foo {
   unsigned char X;
   int Y;
   int Z;
};

struct foo B;

void main (void){
   B.X = 4;
   B.Y = 5;
}



compiles to ...

Code:
lda     #$04
   sta     _B

   ldx     #$00
   lda     #$05
   sta     _B+1
   stx     _B+1+1



If, however, you put the struct in the local space, it puts them in the C stack.

Code:
void main (void){
   struct foo C;

   C.X = 3;
   C.Y = 4;
}


compiles to...

Code:
   jsr     decsp5
   lda     #$03
   ldy     #$00
   sta     (sp),y

   iny
   lda     #$04
   sta     (sp),y
   lda     #$00
   iny
   sta     (sp),y


Conclusions, just like variables are faster in cc65 if decared globally, structs seem to also be faster if declared globally. And, much better than I thought.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Mon Aug 15, 2016 8:18 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
Yeah, structs by itself are not too bad. It's arrays of structs indexed by non-constants that can be problematic, e.g.:
Code:
struct foo {
   unsigned char X;
   int Y;
   int Z;
};

struct foo B[5];
unsigned char i;

void main (void){
   for ( i = 0; i < 5; ++i ) {
       B[i].X = 4;
       B[i].Y = 123;
   }
}
The above code has to generate code to multiply the index by the struct size (5) to index the array.

"Structs of arrays" is better:
Code:
struct foo {
   unsigned char X[5];
   int Y[5];
   int Z[5];
};

struct foo B;
unsigned char i;

void main (void){
   for ( i = 0; i < 5; ++i ) {
       B.X[i] = 4;
       B.Y[i] = 123;
   }
}

However, this code still has the problem that the 16-bit Y and Z need a multiplication by 2 to access them. Splitting them into separate byte-sized YLo, YHi, ZLo, ZHi members could generate more optimal code, but that in turn would complicate the actual use of those members (say, if you want to add or assign a value to "YLo, YHi").

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Tue Sep 06, 2016 3:38 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
Things I figured out this weekend, and will be corrected on my blog.

I wrote the code for most of the pages very quickly, and occasionally I would get error messages from the cc65 compiler. "converting pointer to int without a cast" "incompatible pointer type" etc...and I didn't know what caused them, but I slapped an (int) on there, and the error message went away. But, it didn't look right to me, and I could never find any example code that required type casting to fix error messages...so it bothered me a bit.

Well, the reason I never found example code to match what I was doing, was because I was doing things wrong. The ASM code was correct, so I assumed I had correctly addressed the issue, but once I saw the correct answer...I see that I hadn't.

example...

Code:
const int AllBackgrounds[] = {(int) &n1,(int) &n2,(int) &n3,(int) &n4 };


I slapped some (int)'s on there because it gave me error messages...but what I really wanted was this...

Code:
const unsigned char * const All_Backgrounds[]={n1,n2,n3,n4};


and the companion piece...

Code:
UnRLE(BGDaddress);


I believe the error was that my prototype said this...

Code:
void __fastcall__ UnRLE(int data);


and, what I really wanted was this...

Code:
void __fastcall__ UnRLE(const unsigned char *data);


because, what I'm really doing with the code, is an array of constant pointers to an array of constant characters. And, what I'm really passing to the function is a pointer to an array.

This will be fixed soon on the blog example code.

Further, I don't think I've fully tested 'controller 2' input code. All my example code only tests 'controller 1'. I will have to do that as well.
EDIT, I tested it. Works fine.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Last edited by dougeff on Tue Sep 06, 2016 3:13 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Tue Sep 06, 2016 2:53 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
I've updated every example code on the blog. As usual, if anyone spots any outrageous bugs or bad programming practices, let me know. Thanks.

Here's a quick link to the Spacy Shooty source code...

http://dl.dropboxusercontent.com/s/70f8 ... Spacy4.zip

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Mon Oct 17, 2016 3:47 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
Update (10-17-2016) I updated reset.s in every file, to make sure that initlib and copydata were included. Also changed, added Wait_Vblank(); to several files, just before rendering was turned on, to fix 1 frame of misaligned screens. Finally, changed the .cfg file on the MMC3 examples, to include the missing segments that I had deleted.

See here for further discussion on missing 'copydata'...causing errors.

viewtopic.php?f=10&t=14947

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Thu Feb 09, 2017 2:46 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1823
Location: DIGDUG
Update Feb 9, 2017

I changed every .cfg file to include a "ONCE" segment, so it will compile with the latest version of cc65.

I added a makefile for Linux users, and people who prefer Gnu Make to .bat files. Well, Linux users will have to edit the makefile slightly. I originally wrote them on a Linux computer, but then brought them over to my Windows computer, and edited them to work there...
...anyway, Linux users will have to uncomment out the lines rm *.o and comment the lines del *.o. (etc for .nes files under CLEAN:)


UNRELATED SIDENOTE:
I wrote a 6502 disassembler in python. I might post it in a few weeks.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Thu Feb 09, 2017 3:29 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19234
Location: NE Indiana, USA (NTSC)
If you are using Make from MSYS, you'll probably have GNU Coreutils, which includes rm. For other things that tend to vary, such as presence or absence of .exe in the name of a native executable produced by the linker, you can use the presence or absence of environment variable COMSPEC to set makefile variables.

See Writing portable makefiles.


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Fri Feb 10, 2017 6:31 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1460
thefox wrote:
However, this code still has the problem that the 16-bit Y and Z need a multiplication by 2 to access them.

Isn't multiplication of 2, 4, 8, 16 etc. unproblematic since the compiler can turn it into a simple bit shift? So, an array of ints shouldn't be that much of an issue. At least it's not comparable to the access complexity of an array of a struct.

thefox wrote:
Splitting them into separate byte-sized YLo, YHi, ZLo, ZHi members could generate more optimal code, but that in turn would complicate the actual use of those members (say, if you want to add or assign a value to "YLo, YHi").

Yeah, I would highly adivse against that. If you happen to need an integer in an NES game (which should be more the exception than the rule) let the compiler handle it. Don't fiddle around with two byte values if they are supposed to represent a single number.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Fri Feb 10, 2017 10:19 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
DRW wrote:
thefox wrote:
However, this code still has the problem that the 16-bit Y and Z need a multiplication by 2 to access them.

Isn't multiplication of 2, 4, 8, 16 etc. unproblematic since the compiler can turn it into a simple bit shift? So, an array of ints shouldn't be that much of an issue. At least it's not comparable to the access complexity of an array of a struct.

Yeah it's not a huge problem, but non-optimal nevertheless.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Fri Feb 10, 2017 10:57 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5822
Location: Canada
DRW wrote:
thefox wrote:
However, this code still has the problem that the 16-bit Y and Z need a multiplication by 2 to access them.

Isn't multiplication of 2, 4, 8, 16 etc. unproblematic since the compiler can turn it into a simple bit shift? So, an array of ints shouldn't be that much of an issue. At least it's not comparable to the access complexity of an array of a struct.

It's not just a bit shift. If you can do an array access with an 8-bit index, it can just go into X or Y. If the index is wider, it can't do that anymore, and you get a 16-bit shift plus a 16-bit add operation on a temporary pointer, and then on top of that the array access becomes indirect.

Here's an example:
Code:
unsigned char ac[35];
unsigned int  ai[35];

void index_test()
{
   static unsigned char i;

   // 1.
   i = index();
   ac[i] = 5; // 8-bit index on 8-bit array

   // 2.
   i = index();
   ac[i*2] = 6; // index is promoted to 16-bit int

   // 3.
   i = index() * 2;
   ac[i] = 7; // index was implicitly cast back to 8-bit before use

   // 4.
   i = index();
   ai[i] = 8; // index is promoted to 16-bit int by implicit mulitplication by 2
}


And the generated assembly:
Code:
; 1.
; i = index();
   jsr     _index
   sta     L0017
; ac[i] = 5;
   ldy     L0017
   lda     #$05
   sta     _ac,y

; 2.
; i = index();
   jsr     _index
   sta     L0017
; ac[i*2] = 6;
   ldx     #$00
   lda     L0017
   asl     a
   bcc     L3763
   inx
   clc
L3763:   adc     #<(_ac)
   sta     ptr1
   txa
   adc     #>(_ac)
   sta     ptr1+1
   lda     #$06
   ldy     #$00
   sta     (ptr1),y

; 3.
; i = index() * 2;
   jsr     _index
   asl     a
   sta     L0017
; ac[i] = 7;
   ldy     L0017
   lda     #$07
   sta     _ac,y

; 4.
; i = index();
   jsr     _index
   sta     L0017
; ai[i] = 8;
   ldx     #$00
   lda     L0017
   asl     a
   bcc     L3764
   inx
   clc
L3764:   adc     #<(_ai)
   sta     ptr1
   txa
   adc     #>(_ai)
   sta     ptr1+1
   lda     #$08
   ldy     #$00
   sta     (ptr1),y
   iny
   lda     #$00
   sta     (ptr1),y


The difference between examples 2 and 3 especially shows how helpful it can be to undo integer promotion before accessing the array with it. With example 4, once you use arrays of 16-bit (or larger) types all indexed access becomes full 16-bit indirection, and you can't really do anything to stop that.

So... not as bad as a multiplication, but if you're looking to reduce some of your overhead, it's actually not a terrible idea to "manually" pack striped arrays. A syntax vs convenience tradeoff, though you could simplify the syntax with macros.


Top
 Profile  
 
 Post subject: Re: NES Programming Blog
PostPosted: Sat Feb 11, 2017 3:22 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1460
O.k., yeah, that makes sense. Maybe I could have optimized some stuff with this knowledge in my game because the x position of each character was an integer.
(y was a byte because I had a status bar at the top, so I could simply declare that every sprite that has a position within the status bar is declared as out of screen and I didn't render these sprites at all.)

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 98 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: russellsprouts, za909 and 12 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