PDA

View Full Version : [C related] Structs, records, pointers...



Legolas
20-12-2006, 01:31 PM
I'm a bit in stuck... I need to convert following code to pascal:



#define OAM_SUB ((uint16*)0x07000400)

SpriteEntry OAMCopySub[128];
void updateOAM(void) {
unsigned int i;
for&#40;i = 0; i < 128 * sizeof&#40;SpriteEntry&#41; / 4 ; i++&#41;
&#123;
&#40;&#40;uint32*&#41;OAM_SUB&#41;&#91;i&#93; = &#40;&#40;uint32*&#41;OAMCopySub&#41;&#91;i&#93;;
&#125;
&#125;

where SpriteEntry is a struct. OAM_SUB is translated as
const
OAM_SUB : puint16 = pointer($07000400);

The problem is that I can't figure a way to typecast hte array of record to OAM_SUB :scratch:

VilleK
20-12-2006, 01:48 PM
You can do something like this:


type
PInt32 = ^integer;
var
Data &#58; array&#91;0..10&#93; of TMyRecord;
begin
PInt32&#40;@Data&#41;^ &#58;= 42;
end;

JernejL
20-12-2006, 01:55 PM
I'm a bit in stuck... I need to convert following code to pascal:



#define OAM_SUB &#40;&#40;uint16*&#41;0x07000400&#41;

SpriteEntry OAMCopySub&#91;128&#93;;
void updateOAM&#40;void&#41; &#123;
unsigned int i;
for&#40;i = 0; i < 128 * sizeof&#40;SpriteEntry&#41; / 4 ; i++&#41;
&#123;
&#40;&#40;uint32*&#41;OAM_SUB&#41;&#91;i&#93; = &#40;&#40;uint32*&#41;OAMCopySub&#41;&#91;i&#93;;
&#125;
&#125;

where SpriteEntry is a struct. OAM_SUB is translated as
const
OAM_SUB : puint16 = pointer($07000400);

The problem is that I can't figure a way to typecast hte array of record to OAM_SUB :scratch:

declare stuff like this:



OAMCopySub = packed record or something

POAMCopySub = ^OAMCopySub; // a pointer variant



then use POAMCopySub in variable and set it to that pointer.

Legolas
20-12-2006, 02:20 PM
Thanks to all! :D
Now I'm @ work, so I'll try later :)

Legolas
20-12-2006, 08:08 PM
Ok, I have found a solution that works, or at least that compiles :roll:
I have tried this "monster":
for i := 0 to (128 * sizeof(SpriteEntry) div 4) - 1 do
pu32((@OAM_SUB[i])^) := pu32((@OAMCopySub[i])^);

As I have said before, it compiles, though it does not work as expected, because I get corrupted sprites. Hopefully it should be a wrong (or missing) typecast somewhere...
Bug hunting time :rambo:

JernejL
21-12-2006, 12:22 AM
pointer wrestling in C is bad enough, translating such code is one of worst tasks you can get, good luck :/

Setharian
21-12-2006, 05:50 AM
I'm not familiar with GBA (?) types, so I'll use the regular Delphi ones....


var
OAMCopySub&#58; array&#91;0..127&#93; of SpriteEntry;

...

procedure UpdateOAM;
type
PLongs ^TLongs;
TLongs = array&#91;0..MAXWORD-1&#93; of Longword;
begin
for i &#58;= 0 to &#40;128 * SizeOf&#40;SpriteEntry&#41; div SizeOf&#40;Longword&#41;&#41; -1 do
begin
PLongs&#40;OAM_SUB&#41;^&#91;i&#93; &#58;= PLongs&#40;@OAMCopySub&#41;^&#91;i&#93;;
end;
end;

if pu32 is ^Longword, then u32 should be a Longword and thus all you have to do is replace Longword by u32 ;)

on the other hand if you have a "Move" procedure at your disposal you could as well use it.....


Move&#40;OAMCopySub, OAM_SUB^, SizeOf&#40;OAMCopySub&#41;&#41;;

I think this is the easiest solution if it can be done...

Legolas
21-12-2006, 01:08 PM
Yes, in fact it is NDS code :mrgreen:

Move could be a solution, but it works only on Dualis emulator; on real hardware the memory is not copied at all. To tell short, I have decided to replace this loop by a dma copy, that takes care to copy the right amount of bytes at time.
dmaCopy(@OAMCopySub, OAM_SUB, sizeof(OAMCopySub));

Legolas
11-01-2007, 08:24 PM
I'm resuming this old thread because I need some other help :P
Well, I have converted a struct to pascal but I have some alignment problems. The original code is this:

typedef struct sTransferRegion &#123;
uint32 heartbeat;
int16 touchX, touchY;
int16 touchXpx, touchYpx;
int16 touchZ1, touchZ2;
uint16 tdiode1, tdiode2;
uint32 temperature;
uint16 buttons;
union &#123;
uint8 curtime&#91;8&#93;;
struct &#123;
u8 rtc_command;
u8 rtc_year;
u8 rtc_month;
u8 rtc_day;

u8 rtc_incr;
u8 rtc_hours;
u8 rtc_minutes;
u8 rtc_seconds;
&#125;;
&#125;;
uint16 battery;
uint16 aux;
pTransferSound soundData;
vuint32 mailAddr;
vuint32 mailData;
vuint8 mailRead;
vuint8 mailBusy;
vuint32 mailSize;
&#125; TransferRegion, * pTransferRegion;


And this is my (bad) translation
sTransferRegion = record
heartbeat: cuint32;
touchX, touchY: cint16;
touchXpx, touchYpx: cint16;
touchZ1, touchZ2: cint16;
tdiode1, tdiode2: cuint16;
temperature: cuint32;
buttons: cuint16;
union: record
case integer of
0: (curtime: array [0..7] of cuint8);
1: (
rtc_command: cuint8;
rtc_year: cuint8;
rtc_month: cuint8;
rtc_day: cuint8;
rtc_incr: cuint8;
rtc_hours: cuint8;
rtc_minutes: cuint8;
rtc_seconds: cuint8;
);
end;
battery: cuint16;
aux: cuint16;
soundData: pTransferSound;
mailAddr: cuint32;
mailData: cuint32;
mailRead: cuint8;
mailBusy: cuint8;
mailSize: cuint32;
end;
TransferRegion = sTransferRegion;
pTransferRegion = ^sTransferRegion;



I think that the problem is in the union part... the nested record I have used is an ugly trick to avoid the limitation that forces to put variant parts as the last field in a record.
Any better solution? :scratch:

JSoftware
11-01-2007, 08:56 PM
my first idea was that it should be a packed record but having a second look it seems to align just fine...

edit: or wait a minute. won't the last field be scewed into the last 4 padded bytes?

Legolas
11-01-2007, 09:47 PM
Uhm... I don't know... sizeof gives 60 for c struct and 56 for pascal record :think:

JSoftware
11-01-2007, 09:49 PM
sizeof the unpacked record in delphi is 60. What exactly is a vuintxx?

edit: a quick search tells me it means a volatile field? how could the end of a c struct be volatile?

Legolas
11-01-2007, 10:04 PM
Really I don't care about volatile, because it is an optimization that fpc can't handle yet, so I simply ignore it.

Correction: the record size is 60 too... I forgot to remove a "packed" I have put to make a try :oops:

BTW, the alignment problem remains :(

VilleK
12-01-2007, 08:09 AM
If you find out where in the struct the alignment differs then
you could make a packed record, and then inserting padding
bytes manually until it fits.

Like this:

sTransferRegion = packed record
heartbeat: cuint32;
touchX, touchY: cint16;
touchXpx, touchYpx: cint16;
touchZ1, touchZ2: cint16;
tdiode1, tdiode2: cuint16;
pad1,pad2 : byte; //padding
buttons: cuint16;
pad3,pad4 : byte; //padding
...etc


Also my first guess would be that the c/pascal alignment could
differ at the last 8-bit fields: mailRead, mailBusy: cuint8;

Legolas
14-01-2007, 02:34 PM
So, I resolved that alignment issue. To tell the truth it was the effect and not the cause... :roll:

Now I have another problem (I hope it will be the last one...). I have a function in a c library that requires as parameter a pointer to a void function:


typedef void &#40;* VoidFunctionPointer&#41;&#40;void&#41;;
void irqSet&#40;IRQ_MASK irq, VoidFunctionPointer handler&#41;;

I have translated it as:
procedure irqSet(irq: IRQ_MASK; handler: Pointer); cdecl; external;

and it works if I use it in this way:

irqSet(IRQ_VBLANK, @myProcedure);

Now the problem comes if I try to pass to irqSet a void function that is implemented in another c library:

extern void Wifi_Interrupt&#40;&#41;;
translated as:
procedure Wifi_Interrupt(); cdecl; external;
hangs on:
irqSet(IRQ_WIFI, @Wifi_Interrupt); :scratch:

JSoftware
14-01-2007, 02:39 PM
would this make any difference?

type
VoidFunctionPointer = procedure; cdecl;

procedure irqSet(irq: IRQ_MASK; handler: VoidFunctionPointer); cdecl; external;

Legolas
14-01-2007, 03:23 PM
Unfortunately, the only difference is that in this way does not work for pascal procedures too :(