Exceptionally Odd Behaviour On The 940t


Sephnroth

Member
Joined
Dec 25, 2005
Messages
151
Age
39
Location
UK
Website
Visit site
Hey, thanks to Dzz's great tutorials and his indulgance with my questions I learned what I needed to get started with coding for the 940. At first I did a quick test peice of code which simply set a shared variable to 0 during initialisation and then set it to 6 when the 940 was in its main loop - I read the result on the 920 and it was working grand (used printf to read the var from console)

so then I started work on a basic sound engine the idea being get bare bones mixer, get wavs working on it then see about other formats. At first I wrote a load of stupid code because I was under the ridiculous impression that I could use asm SWI calls from the 940 so was trying to open() wavs and ioctl from there. When I found out it was frustrating but no problem, I can iocotl on the 920 and buffer file data through the shared variable struct. I wrote code to do that buffering and went to test it on the 940 (the first test since my basic "set a variable" test) and noticed that the status variable was always reading 0 suddenly, it should still be 6.

after much messing around I realised that if I excluded my mixer.c file from my 940 project (which gets compiled into a .bin and loaded that way at runtime) then suddenly the status switched to 6 as it should do! This is odd because I dont use any of the code in that file yet! I commented out all the stuff I was going to move to the 920 anyway so I was left with just the bare bones mixer and it STILL breaks the whole thing if that c file is compiled and linked into the project :/ Anyone got any clues why? heres the relevent files


940 code:

main file with the loop and status setting (and also the code to read buffered wav data, note those malloc functions are empty at present):

Code:
#include "lib940.h"
#include "shared940.h"
#include "heavenlymixer.h"

volatile tSharedVariables *gGlobStruct;

//USER ENTRY POINT, start your coding for the 940t here

/*
	//920 writes these, 940 reads them
	unsigned int	nLoadWavStatus;
	unsigned char	cWavBuffer[512];
	unsigned int	nTotalSize;
	unsigned int	nThisSampleSize;
	unsigned int	nThisSampleStart;

	//940 writes these, 920 reads
	BOOL940			bFinishedRead;
	unsigned int	nLastSampleStart;
*/

unsigned int nLastStart = -1;
unsigned char *tmpWavBuffer = 0;

#define _user_malloc(s) malloc940(s)
#define _user_free(p) free940(p)

void main940() {
	int p;

	gGlobStruct = (tSharedVariables *) 0xF00000;
	gGlobStruct->usStatus = 5;

	gGlobStruct->bQuitProgram = 0;


	while (!gGlobStruct->bQuitProgram) {
		gGlobStruct->usStatus = 6;



		//the 920 has a wav to load, its going to buffer the data to us so lets read it and tell it when we're ready for more
		if (gGlobStruct->nLoadWavStatus == WAV_LOAD) {			
			
			if (gGlobStruct->nThisSampleStart == 0) {	//bit of an unnessiary check this one, but you never know..

				if (tmpWavBuffer != 0) { 
					_user_free(tmpWavBuffer);	//free any old temporary wav data if it exists
				}

				tmpWavBuffer = _user_malloc(gGlobStruct->nTotalSize);	//allocate a temp buffer for the new data

				while (gGlobStruct->nLoadWavStatus == WAV_LOAD) {		//while in load status loop

					if (nLastStart != gGlobStruct->nThisSampleStart) {	//if the last starting point we read from doesnt equal the new one then fresh data exists to load
						gGlobStruct->bFinishedRead = 0;			//let the 920 know we are definatly not finished

						for (p = 0; p < gGlobStruct->nThisSampleLength; p++) {
						//	tmpWavBuffer[p + gGlobStruct->nThisSampleStart] = gGlobStruct->cWavBuffer[p];	//copy the data in offset by the last copy we did
						}

						nLastStart = gGlobStruct->nThisSampleStart;		//set the last start to the current one
					} else {
						gGlobStruct->bFinishedRead = 1;			//here we let the 920 know we are ready for fresh data
																		//it will change the sample start when it updates with new data so this process will repeat
					}						

				}

				//if we get to here we should have the complete wav data in our buffer
				//pass it to the audio system and free our temp buffer

				//LoadWav(tmpWavBuffer, 0, 0);
				_user_free(tmpWavBuffer);
				tmpWavBuffer = 0;
			}
		}


	}
}

you might also note that at the start of the function now it sets the variable to 5 instead of 0, that was a test and the showed what i most feared, the output of that var was still 0 so this function is never getting called.

this is heavenlymixer.c which breaks the whole thing, excluding it fixes it just fine -_-

Code:
#include "heavenlymixer.h"
#include "lib940.h"

t_sndChannel	sChannels[MAX_CHANNELS];
short			sSoundBuffer[STANDARD_BUFFER_SIZE];
int				devDSP;
int				bSoundInit	= 0;




void UpdateMixer(short *sOutput, unsigned int unBufferSize) {
	int i, nChan, nSample1, nSample2;	

	for (i = 0; i < (unBufferSize >> 1); i++) {			//for the length of the buffer..
		nSample1 = 0;									//reset the sample to 0
	
		//////////////////////////////
		//  calculate audio sample  //
		//////////////////////////////

		for (nChan = 0; nChan < MAX_CHANNELS; nChan++) {	//loop through all the possiable channels
			t_sndChannel *thisChanPtr = &sChannels[nChan];	//create a temporary pointer (optimisation, means you dont need to calculate the addres of nChannels[nChan] every time)

			if (thisChanPtr->bPlay == 1) {					//if playing..

				nSample1 += thisChanPtr->sndData[thisChanPtr->sndPos] * thisChanPtr->sndVol;	//add the sample data multiplied by the volume
				thisChanPtr->sndPos++;						//up the current position in this peice of audio

				if (thisChanPtr->sndPos >= thisChanPtr->sndLength) {	//if beyond the real length of the audio..
					if (thisChanPtr->loopLength == 0) {					//and it doesnt loop..
						thisChanPtr->bPlay = 0;							//stop the playback.
					} else {											//otherwise if it does loop..

						while (thisChanPtr->sndPos >= thisChanPtr->sndLength) {
							thisChanPtr->sndPos -= thisChanPtr->loopLength;	//rewind the song back to its loop point
						}

					}
				}
			}
		}

		//////////////////////////////
		//  write sample to buffer  //
		//////////////////////////////

		nSample1 >>= 2;		//it.. um.. does something important, I forgot :/

		//mix sample with buffer (simply compatbility, maybe something has already added to it?) then check for clipping (dont want to blow peoples ears now :P)
		nSample2 = ((int)*sOutput) + nSample1;

		if (nSample2 > CLIP_MAX) { nSample2 = CLIP_MAX; }
		if (nSample2 < CLIP_MIN) { nSample2 = CLIP_MIN; }
		
		//write this audio sample into the output buffer
		*sOutput++ = (short)nSample2;

		//have to do it again because gp2x = stereo sound and this = mono mixer

		nSample2 = ((int)*sOutput) + nSample1;

		if (nSample2 > CLIP_MAX) { nSample2 = CLIP_MAX; }
		if (nSample2 < CLIP_MIN) { nSample2 = CLIP_MIN; }
				
		*sOutput++ = (short)nSample2;

	}	
}

void ResetSound() {
	int nChan;

	for (nChan = 0; nChan < MAX_CHANNELS; nChan++) {
		sChannels[nChan].bPlay = 0;
		sChannels[nChan].loopLength = 0;
		sChannels[nChan].sndData = 0;
		sChannels[nChan].sndLength = 0;
		sChannels[nChan].sndPos = 0;
		sChannels[nChan].sndVol = 0;
	}

	ClearBuffer(STANDARD_BUFFER_SIZE);
}

void ClearBuffer(int nSize) {
	int i;

	for (i = 0; i < nSize; i++) {
		sSoundBuffer[i] = 0;
	}
}

void LoadWav(unsigned char *wav_data, int nChan, int nLoop) {
	if (nChan < 0 || nChan >= MAX_CHANNELS) {
		return;
	}
}

and just incase its of any relevence, the entry point for the 940 code, but this is just the standard setup from dzz's demo tutorials:

Code:
extern void main940();
void entry940(void) __attribute__((naked));

void entry940(void) {
	asm volatile (
		"b .CodeEntryPoint			@ reset all entry points to same place (0x0)\n"
		"b .CodeEntryPoint\n"
		"b .CodeEntryPoint\n"
		"b .CodeEntryPoint\n"
		"b .CodeEntryPoint\n"
		"b .CodeEntryPoint\n"
		"b .CodeEntryPoint\n"
		"b .CodeEntryPoint\n"
		".CodeEntryPoint:\n"
		"mov sp, #0x100000			@ set the top of the stack at 1M\n"
		"sub sp, sp, #4				@ minus 4\n"
		
		/* 
			Setting up memory region 0 as uncached
			bit 0		= enable
			bit 1-5		= 5-bit region size 
			bit 12,31	= base address. both regions have base address of zero
		*/

		"mov r0, #0x3F				@ region data\n"
		"mcr p15, 0, r0, c6, c0, 0	@ data region 0\n"
		"mcr p15, 0, r0, c6, c0, 1	@ code region 0\n"

		/*
			set up region 1 (first 16M)
		*/

		"mov r0, #0x2F				@ region data\n"
		"mcr p15, 0, r0, c6, c1, 0	@ data region 1\n"
		"mcr p15, 0, r0, c6, c1, 1	@ code region 1\n"

		/* set region 1 to be cachable */

		"mov r0, #2					@ 2 means region 1.  1 == 0, 4 == 2, etc\n"
		"mcr p15, 0, r0, c2, c0, 0	@ turn on data cache\n"
		"mcr p15, 0, r0, c2, c0, 1	@ turn on instruction cache\n"

		/* enable data buffering in region 1 */

		"mcr p15, 0, r0, c3, c0, 0	@ turn on write buffer\n"

		/* enable protection for all memory regions */

		"mov r0, #15\n"
		"mcr p15, 0, r0, c5, c0, 0	@ set full data permission\n"
		"mcr p15, 0, r0, c5, c0, 1	@ set full code permission\n"
		"mcr p15, 0, r0, c1, c0, 0	@ fetch current control register\n"
		"orr r0, r0, #1				@ enable protection unit\n"
		"orr r0, r0, #9				@ enable D cache\n"
		"orr r0, r0, #0x1000		@ enable I cache\n"
		"orr r0, r0, #0xC0000000	@ async + fastbus\n"
		"mcr p15, 0, r0, c1, c0, 0	@ set control register\n"
	);

	//call the "users" entry point:

	main940();
}

thats it for 940 code.

920:

940.cpp in full, pretty much dzz's demo stuff but 940 memory shifted to 48mb offset to be sdl freindly:

Code:
#include "stdio.h"
#include "stdlib.h"
#include "fcntl.h"
#include "unistd.h"
#include "string.h"
#include "sys/mman.h"
#include "shared940.h"

// Hexidecimal reprisentations of the number of bytes in a set amount of megs for memory mapping
// for example, when I map 16megs of memory starting at the 48mb offset in the ram i would map HEX16 at HEX48

#define HEX48	0x3000000
#define HEX16	0x1000000
#define HEX15	0xF00000
#define HEX2	0x200000
#define HEX1	0x100000	

volatile tSharedVariables	*gGlobStruct;
volatile unsigned long		*gMmsp2Regs32;
volatile unsigned short		*gMmsp2Regs16;
unsigned char				*gMemoryPointer;
int							nDevMem;

int Init940() {
	nDevMem = open("/dev/mem", O_RDWR);

	gMmsp2Regs32 = (unsigned long *) mmap(0, 0x10000, 3, 1, nDevMem, 0xC0000000);	//the processor registers, 32 bit
	gMmsp2Regs16 = (unsigned short *) gMmsp2Regs32;									//16bit version

	gMemoryPointer = (unsigned char *)mmap(0, HEX16, 3, 1, nDevMem, HEX48);			//16mb of memory offset by 48mb
	gGlobStruct = (tSharedVariables *) (gMemoryPointer + HEX15);	//last meg used for shared variable stack
	gGlobStruct->bQuitProgram = false;
	gGlobStruct->usStatus = 0;

	gMmsp2Regs16[0x3B48 >> 1] = (1 << 7) | 3;	//reset the 940t and inform it that its been shifted to the 48mb offset
	gMmsp2Regs16[0x0904 >> 1] &= (~(1 << 0));	//pause the 940t

	//need to copy the pre-compiled code that the 940 has to run into its memory space.
	//for triple triad I have stored that code in 940audio.bin (ogg engine)

	int f = open("940audio.bin", O_RDONLY);		//open the precompiled code
	
	if (f < 0) {
		return -1;	//error :(
	}

	int nOffset = 0;
	int nRead = 0;
	unsigned char buff[1024];

	while((nRead = read(f, buff, 1024)) > 0) {			//while there is code left to read, read it..
		memcpy(gMemoryPointer + nOffset, buff, nRead);	//copy it in to the mapped memory for the 940t..
		nOffset += nRead;								//up the locations for the next copy
	}

	close(f);	//close the file

	//there are two interrupts that connect the two processors, but I dont use them so I need to disable them
	
	gMmsp2Regs16[0x3B40 >> 1] = 0;	//interrupt 1
	gMmsp2Regs16[0x3B42 >> 1] = 0;	//interrupt 2

	//now take the 940 out of reset state and get that thing executing

	gMmsp2Regs16[0x3B48 >> 1] = 3;	//take out of reset, preserve the memory shift setting from earlier (3)
	gMmsp2Regs16[0x0904 >> 1] |= (1 << 0);	//begin execution!

	return 0;
}

unsigned short Get940Status() {
	return gGlobStruct->usStatus;
}


void Shutdown940() {
	gMmsp2Regs16[0x3B48 >> 1] = (1 << 7) | 3;	//reset the 940 cpu
	gMmsp2Regs16[0x0904 >> 1] &= (~(1 << 0));	//pause it

	munmap(gMemoryPointer, 0xF00000);
	munmap((void *)gMmsp2Regs32, 0x10000);

	close(nDevMem);
}

//still untested loadwav to buffer wav data to the 940 (512byte buffer)
void LoadWav(const char *szFilename, int nChannel, int nLoop) {

	FILE *nFile = fopen(szFilename, "r+");

	fseek(nFile, 0, SEEK_END);
	gGlobStruct->nTotalSize = ftell(nFile);
	fseek(nFile, 0, SEEK_SET);

	if (gGlobStruct->nTotalSize >= 512) {
		int nCopied = 0;
		int nThisCopy = 0;
		unsigned char tmpBuffer[512];

		while (nCopied != gGlobStruct->nTotalSize) {
			if (gGlobStruct->nTotalSize - nCopied < 512) {
				nThisCopy = gGlobStruct->nTotalSize - nCopied;
			} else {
				nThisCopy = 512;
			}

			fread(tmpBuffer, 1, nThisCopy, nFile);

			for (int p = 0; p < nThisCopy; p++) {
				gGlobStruct->cWavBuffer[p] = tmpBuffer[p];
			}

			gGlobStruct->nThisSampleStart = nCopied;
			gGlobStruct->nThisSampleLength = nThisCopy;
			gGlobStruct->bFinishedRead = false;
			gGlobStruct->nLoadWavStatus == WAV_LOAD;

			nCopied += nThisCopy;

			while(!gGlobStruct->bFinishedRead) {

			};


		}
	} else {
		int nThisCopy = gGlobStruct->nTotalSize;
		unsigned char tmpBuffer[512];

		fread(tmpBuffer, 1, nThisCopy, nFile);

		for (int p = 0; p < nThisCopy; p++) {
			gGlobStruct->cWavBuffer[p] = tmpBuffer[p];
		}

		gGlobStruct->nThisSampleStart = 0;
		gGlobStruct->nThisSampleLength = nThisCopy;
		gGlobStruct->bFinishedRead = false;
		gGlobStruct->nLoadWavStatus == WAV_LOAD;

		while (!gGlobStruct->bFinishedRead) {

		}

	}

	gGlobStruct->nLoadWavStatus == 0;

	fclose(nFile);


}

im completly stumped. i commented pretty much everything out of the mixer except the main mixer because I cant afford to remove that, the whole point of this exercise is to get the heavy audio work going on the 940! if i take the mixer off I may as well do the lot on the 920. but simply if heavenlymixer.c is compiled into the bin, usStatus == 0. if excluded, == 6 as it should be

im so lost as to what to do >< sorry for long post, but if anyone can help, thanks!

EDIT:

bah this was supposed to be the I Need Help dev forum --; sorry :/
 
Check your .bin with a hex editor to make sure it starts with:

060000ea050000ea040000ea030000ea020000ea010000ea000000ea

If it doesn't then that's your problem. If found that changing the order in which things were linked sometimes caused the compiler to stick some junk before that line.

HTH,
Andrew
 
spot on, just compared the two bin files and without the mixer the hex reads as you say it should and with it doesnt. okay, now how can I fix that? my ide is visual studio 2k5e and i belive it just links *.o is there a linker option or something i;ve missed to prevent it from doing this?
 
The problem you have is that your entry940() isn't located at 0x0.

My way is to use a custom (hand-written) linker script and my own crt0.s, that way you can easily exactly define what goes where.

Also, only point the reset vector to your CEP, point the others elsewhere. If you accidentally enable an IRQ or cause another type of exception, the last thing you want it to do is try and write your entire program.

I've posted many 940 examples around the boards and on IRC, so you'll either have already downloaded one, or should find one easily enough.
 
Sephnroth posted on Aug 18 2006 at 05:10 PM said:
squidge i'm having a bit of trouble finding that easilly findable code of yours ^^;; i've been searching the forums for an age for things like crt0.s etc but i can only come up with:

http://www.gp32x.de/board/index.php?showt...t0.s&st=60#

and the link there is dead - have a fresh link?

thanks :)

I've made a similar ld script for gpu940. Find it here :

http://cvs.gna.org/cvsweb/gpu940/bin/?cvsroot=gpu940

You will also find a crt0.S which was given by squidge at that time (errors are mine).
 
Last edited by a moderator:
Back
Top