CC65: Bank switching / Using memcpy for array

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

Post Reply
bngrybt
Posts: 15
Joined: Tue May 09, 2017 5:03 am

CC65: Bank switching / Using memcpy for array

Post by bngrybt » Tue Oct 24, 2017 12:37 pm

I feel like this should be simple, but I've been banging my head against the wall for 2 days with it.

I'm making a game using mapper 11. I only have two 32k PRG banks, one for the main game engine and the other is used to store a bunch of arrays containing 96 bytes of level data. Everything is basically working like I want it to, except I can't use memcpy to copy the array. Here is the code I have at the same address in PRG0 and PRG1

Code: Select all

void Load_Array(void) {
	do_Switch = 1;
	while (do_Switch) {
		new_bank = PRG_bank + CHR_bank;
		change_reg(new_bank);			// Call to bank switching routine
		do_Switch = 0;					// Break the loop so we can return
	}

}

// At the same address in PRG1
void Load_Array1(void) {
	do_Switch = 1;
	while(do_Switch) {	
		new_bank = PRG_bank + CHR_bank;
		change_reg(new_bank);
		
		memcpy(L_MAP, All_Levels[level], 96);

		PRG_bank = 0x00;		// Send us back to PRG0
	}
}
If I use this, the game resets. I'm guessing that what is happening is the code for memcpy doesn't exist in PRG1, and the first code the game encounters is the reset code, which switches back to PRG0 and resets (as it should). I've tried using a for loop instead of memcpy, but I have the same problem. I can copy each byte individually, but that's it.

Code: Select all

	// I tried a for loop, but it also doesn't work.
	for (A = 0; A < 96; ++A) {
		L_MAP[A] = All_Levels[level][A];
	}
	
	// Even this doesn't work.
	L_MAP[A] = All_Levels[level][A];

	// This works, but is disgusting.
	L_MAP[0] = All_Levels[level][0];
	...
	L_MAP[95] = All_Levels[level][95];
Obviously this is hardly ideal, but at least it does show that I'm switching PRG banks successfully. Right now I just have extremely ugly, bloated code that I want to get rid of. I'm guessing that I'll have to write something in assembly that will copy data into my L_MAP array, but I'm having trouble wrapping my head around it for some reason.

User avatar
thefox
Posts: 3141
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: CC65: Bank switching / Using memcpy for array

Post by thefox » Tue Oct 24, 2017 1:20 pm

The compiler has a set of runtime library routines that it will sometimes insert calls into. You have no control when and if such calls are made. If you turn on optimizations, there will probably be less calls (and more inlining), but you can't count on there being no calls. Thus, you must make sure that these library routines are always banked in. In your case, you have to (in whatever way) duplicate them in both of your 32 KB banks, at equivalent addresses. By default they go in the CODE segment.

Two tips: 1) Look at the assembly listing of your code, 2) Use a debugger.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi

User avatar
dougeff
Posts: 2598
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: CC65: Bank switching / Using memcpy for array

Post by dougeff » Tue Oct 24, 2017 1:24 pm

Since memcpy is a c library function... It is likely compiling into one bank and not the other.

My Solution. Compile the 2 banks separately, concatenate them together as a final step.
nesdoug.com -- blog/tutorial on programming for the NES

bngrybt
Posts: 15
Joined: Tue May 09, 2017 5:03 am

Re: CC65: Bank switching / Using memcpy for array

Post by bngrybt » Tue Oct 24, 2017 1:53 pm

dougeff wrote:Since memcpy is a c library function... It is likely compiling into one bank and not the other.

My Solution. Compile the 2 banks separately, concatenate them together as a final step.
I guess this probably sounds easiest. Looking at the assembly listing, it looks like using L_MAP[temp] = All_Levels[level][temp]; makes a call to pushax, which is probably what's messing things up. It'll save me from banging my head against the wall with assembly at least.

bngrybt
Posts: 15
Joined: Tue May 09, 2017 5:03 am

Re: CC65: Bank switching / Using memcpy for array

Post by bngrybt » Tue Oct 24, 2017 7:00 pm

So I tried concatenating two separate projects and while it does solve the memcpy problem, it actually used up 1k more space than my brute-force method. I think the added stability will be worth it in the future though, and I'm not exactly hurting for space. Just thought it was funny that it worked out that way though

calima
Posts: 999
Joined: Tue Oct 06, 2015 10:16 am

Re: CC65: Bank switching / Using memcpy for array

Post by calima » Tue Oct 24, 2017 11:58 pm

Your transition, relying on the same address, is a bit fragile. I'd recommend writing the copy function in asm, and storing it in RAM, so you never have to jump to different code under the same function. You can achieve this by putting it to the DATA segment.

bngrybt
Posts: 15
Joined: Tue May 09, 2017 5:03 am

Re: CC65: Bank switching / Using memcpy for array

Post by bngrybt » Wed Oct 25, 2017 10:55 am

calima wrote:Your transition, relying on the same address, is a bit fragile. I'd recommend writing the copy function in asm, and storing it in RAM, so you never have to jump to different code under the same function. You can achieve this by putting it to the DATA segment.
I tried writing a copy function in asm, but I was having trouble wrapping my head around how to do it. I read some other topics about it, but for some reason I'm just finding it difficult to understand how to do it.

As of right now I have any code related to switching banks stored at $FF00. I'm not switching banks particularly often, only once at the start of each level to fetch the array data, so it's not like I'm doing it multiple times per cycle. Is it still something that could give me headaches later on?

calima
Posts: 999
Joined: Tue Oct 06, 2015 10:16 am

Re: CC65: Bank switching / Using memcpy for array

Post by calima » Thu Oct 26, 2017 6:46 am

It'll probably work fine, but things like cc65 updates could break it.

You can cheat with cc65 to kickstart the asm. Use the memcpy version, and compile with -Ois and the memcpy call should be inlined.

bngrybt
Posts: 15
Joined: Tue May 09, 2017 5:03 am

Re: CC65: Bank switching / Using memcpy for array

Post by bngrybt » Thu Oct 26, 2017 3:21 pm

calima wrote:It'll probably work fine, but things like cc65 updates could break it.

You can cheat with cc65 to kickstart the asm. Use the memcpy version, and compile with -Ois and the memcpy call should be inlined.
I might give that a try. Since I have a fixed length for the arrays it could give me the opportunity to trim out some needless code.

Post Reply