nickspoon
vultum stultum habes
Well, I've got a bitmap reading function, but it uses fopen(). I can't seem to change that into a readable file pointer.
I'll have code for "reading from a file" in the next installment. There is already a system call in asmlib.s for opening a file, I just need to add another one to read from the file. These functions will match the open() and read() system calls rather than fopen and fread, but it should be easy to convert the code.nickspoon posted on May 17 2006 at 03:48 PM said:Well, I've got a bitmap reading function, but it uses fopen(). I can't seem to change that into a readable file pointer.
void Do940Stuff()
{
// do something interesting here
while(1)
; // do nothing forever!
}
extern void Do940Stuff();
void code940(void) __attribute__((naked));
void code940(void)
{
asm volatile (
"b .CodeEntryPoint @ have all the entry points jump to start of the code\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 stack top (1M)\n"
"sub sp, sp, #4 @ minus 4, just to be tidy\n"
"@ set up memory region 0 -- the whole 4GB address space, uncached\n"
"@ bit 0 = enable\n"
"@ bits 1-5: 5-bit region size (N). Size = 2^(N+1). For this\n"
"@ partition, set all bits for maximum size\n"
"@ bits 12:31: base address. Both regions in this example have a\n"
"@ base address of zero\n"
"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 which is the first 16 megabytes.\n"
"@ bit 0 = enable\n"
"@ bits 1-5: as above. 16 MB is 2^24 so N is 23. In hex, 23==0x17.\n"
"@ (0x17<<1) | 1 = 0x2F\n"
"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 cacheable (so the first 16M will be cacheable)\n"
"mov r0, #2 @ 2 means region 1 (1 would have meant region 0, 4 would mean region 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"
"@ set region 1 to be bufferable too (only data)\n"
"mcr p15, 0, r0, c3, c0, 0 @ turn on write buffer\n"
"@ set protection on for all regions\n"
"mov r0, #15 @ more than we actually need\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"
"mrc p15, 0, r0, c1, c0, 0 @ fetch current control reg\n"
"orr r0, r0, #1 @ 0x00000001: enable protection unit\n"
"orr r0, r0, #4 @ 0x00000004: enable D cache\n"
"orr r0, r0, #0x1000 @ 0x00001000: enable I cache\n"
"orr r0, r0, #0xC0000000 @ 0xC0000000: async+fastbus\n"
"mcr p15, 0, r0, c1, c0, 0 @ set control reg\n"
// ok, now we're ready to rock
);
Do940Stuff();
}
CROSS_COMPILE = C:/devkitGP2X/bin/arm-linux-
LDFLAGS = -static
CXX = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
CXXFLAGS = -IC:/devkitGP2X/include -Wall -Werror
LIBS = -Lc:/devkitGP2X/lib
CODE940_TARGET = code940
CODE940_OBJS = main.o code.o
all : $(CODE940_TARGET)
$(CODE940_TARGET) : $(CODE940_OBJS)
$(LD) -e code940 -Ttext 0x0 $(CODE940_OBJS) -o $(CODE940_TARGET)
$(CROSS_COMPILE)objcopy -O binary code940 code940.bin
ls -l code940.bin
cp code940.bin ..
main.o: main.c
$(CXX) $(CXXFLAGS) -O0 -c main.c
code.o: code.c
$(CXX) $(CXXFLAGS) -O2 -c code.c
int Startup940()
{
int fd;
unsigned char buffer[1024];
int nRead, nOffset;
g_pusRegs[0x3B48>>1] = (1<<7) | 2; // (1<<7)==reset, 2 == memory address shift
g_pusRegs[0x0904>>1] &= (~(1<<0)); // pause the 940
// copy the data
fd = OpenFile("code940.bin", 0); // 0 == O_RDONLY
if(fd < 0)
return 0; // could not open the file
nOffset = 0;
while((nRead = ReadFile(fd, buffer, 1024)) > 0)
{
dzzmemcpy(g_pNoncachedMemory + nOffset, buffer, nRead);
nOffset += nRead;
}
CloseFile(fd);
// Make sure that interrupts connecting the two processors are
// disabled, since we won't use them
g_pusRegs[0x3B40>>1] = 0;
g_pusRegs[0x3B42>>1] = 0;
// Take the second processor out of the 'reset' state
g_pusRegs[0x3B48>>1] = 2; // 2 for the memory address shift
// Enable the second processor
g_pusRegs[0x0904>>1] |= (1<<0);
return 1; // the program is going
}
void Shutdown940()
{
g_pusRegs[0x3B48>>1] = (1<<7) | 2; // reset the 940
g_pusRegs[0x0904>>1] &= (~(1<<0)); // pause the 940
}
typedef struct
{
int nData; // just a dummy value, we'll do something more useful later
} SharedData;
typedef struct
{
char DBuf[1024]; // shared data
int nNextWriteDebug; // next character to write to
int nNextReadDebug; // next character to read from
} SharedData;
while(g_pSharedData->nLock != 0)
; // do nothing... wait for the lock to be released
g_pSharedData->nLock = 1;
// do our work here
g_pSharedData->nLock = 0;
typedef struct
{
unsigned int uLock; // lock to regulate access to shared data
char DBuf[1024]; // shared data
int nNextWriteDebug; // next character to write to
int nNextReadDebug; // next character to read from
} SharedData;
Lock:
mov r2, #1 @ value to set the lock to
LockLoop:
swp r3, r2, [r0] @ swap 1 into the lock
cmp r3, #1 @ if a 1 was already there,
beq LockLoop @ go back and try again
mov pc, lr
Unlock:
mov r2, #0 @ set the lock to 0
str r2, [r0]
mov pc, lr
Dzz posted on May 18 2006 at 06:14 AM said:Anyway, as Squidge points out, there's no harm in pretending it's necessary in this case.
twetmore posted on May 24 2006 at 05:55 AM said:The 920 read code actually does reference (reads) the write pointer (nNextWriteDebug), so it is quite possible for the 920 and 940 to conflict in the buffer.
rixed posted on May 24 2006 at 06:09 AM said:Not if the write of the pointer is atomic, which is the case here (single bus operation).
Of course, the end pointer must be updated (by the writer) once the new datas have been fully written.
Similarly, the begin pointer must be updated (by the reader) once all datas was read.
START Buffer: _ _ _ _ _
E
B
940T writes "abc" Buffer: a b c _ _
E
B
920T reads "a" Buffer: a b c _ _
E
B
940T writes "defg" Buffer: f g c d e
E
B
920T reads "g" Buffer: f g c d e
E
B
RESULT
940T sends: abcdefg
920T receives: ag
twetmore posted on May 25 2006 at 03:56 AM said:The remaining problem (or design decision) is with the 940 writing "past" the begin pointer. This "problem" is separate from the locking issue.
Yes, I believe I did not do this check. For my little debugging facility I didn't care very much but thinking about it now, I see that people may want to adapt the code to other purposes so I should have done the 'buffer full' check. It would be better to return failure from that function than overrun the buffer.rixed posted on May 25 2006 at 07:32 AM said:twetmore posted on May 25 2006 at 03:56 AM said:The remaining problem (or design decision) is with the 940 writing "past" the begin pointer. This "problem" is separate from the locking issue.
The 940 must find out if there are room to fit new datas, as well as the 920 must find out if there are available datas waiting.
This is standard circular buffer things.
The cast is not behaving like you would want and you are subtracting too much. Try this:satacoy posted on May 28 2006 at 11:52 AM said:I've been following along with the demo articles. Thanks Dzz for all the knowlege!
I'm struggling a bit with the 940. Specifically, I'm having trouble accessing the MMSP2 registers from the 940.
I understand needing to use MMAP from the 920, since it's using virtual addressing. On the 940 though, shouldn't I be able to just point to them at 0xC0000000? I'm subtracting 0x2000000 due to the address offset setup, but I'm still not getting the behavior I expect.
So, to get the base of the registers, I'm doing:
unsigned short * pusRegs = (unsigned short *) 0xC0000000 - 0x2000000;
However button presses or vsync checks don't seem to be working. Any ideas?
Dzz posted on May 28 2006 at 12:26 PM said:The cast is not behaving like you would want and you are subtracting too much. Try this:
unsigned short * pusRegs = (unsigned short *) (0xC0000000 - 0x2000000);
void Do940Stuff()
{
g_pSharedData = (SharedData *) 0x1E00000;
SendDebug("Testing from the 940!");
SendDebug("Hello!");
unsigned short * pusRegs = (unsigned short *) (0xC0000000 - 0x2000000);
while(1){
// See if the left should button is pressed
if((pusRegs[0x1184>>1] & 0x400) == 0) {
Lock((unsigned int *) (&g_pSharedData->uLock));
Unlock((unsigned int *) (&g_pSharedData->uLock));
}
}
}
Yeah, that that makes it obvious just by looking at it what's going on! :lol:Squidge posted on May 28 2006 at 02:39 PM said:value = MSP_GPIOAPINLVL;
I'll check it out and let you know what I find! If there is an issue with the synchronization primitives I'm eager to find it!satacoy posted on May 28 2006 at 02:43 PM said:That got me a bit farther, but now I'm hitting a bigger issue that I've been chasing for a few days now. The Lock and Unlock procedures are causing me grief. Boiling it down to the simplest test case I can think of, if you replace "Do940Stuff" in the 6b article source with this:
I'm afraid I am not able to reproduce any problem With this code the only thing that happens for me is that the frame time counter goes up from 31 to 42. It goes back to 31 when I release the button. I think this is because the 940 code is hammering that poor lock variable pretty hard, which is both eating some memory bandwidth and delaying access on the 920. I think.satacoy posted on May 28 2006 at 02:43 PM said:replace "Do940Stuff" in the 6b article source with this:
Code:void Do940Stuff() { g_pSharedData = (SharedData *) 0x1E00000; SendDebug("Testing from the 940!"); SendDebug("Hello!"); unsigned short * pusRegs = (unsigned short *) (0xC0000000 - 0x2000000); while(1){ // See if the left should button is pressed if((pusRegs[0x1184>>1] & 0x400) == 0) { Lock((unsigned int *) (&g_pSharedData->uLock)); Unlock((unsigned int *) (&g_pSharedData->uLock)); } } }
asm (
"DoDelay:\n"
" subs r0, r0, #1\n"
" bne DoDelay\n"
" mov pc, lr\n"
);
void DoDelay(int nCount);
Dzz posted on May 28 2006 at 03:25 PM said:Actually, I was just able to reproduce the issue, it doesn't happen all the time for me. I'll investigate.
There's definitely something not right going on here. I'm beginning to suspect that the hardware support to make sure the SWP instruction is atomic might not be implemented in the MagicEyes memory controller. I'm not sure how to figure out whether that's the case or not.satacoy posted on May 28 2006 at 03:35 PM said:Your binary also locks up my unit. The time does jump up to 42, but then the unit is locked, and no combination of button hitting/releasing will bring it back to life.
I've tried adding delays to my code yesterday, but end up with the same issue regardless of how long I delay. I'll play around with it a bit more, and try your delay code to see if it makes any difference. Bizarre!
Dzz posted on May 28 2006 at 03:25 PM said:Actually, I was just able to reproduce the issue, it doesn't happen all the time for me. I'll investigate.
That's good. I was starting to think I was losing my mind!