I have not used PDATA before, so this may be a silly question. Can I set up PDATA dynamically (within the code) to any 256-byte chunk of xdata? So I can change where the PDATA is "looking" in xdata on the fly, and subsequently have byte addressing (and hopefully faster writes within a loop) for any 256-byte section of xdata at a time?
The upper half of the address for pdata is taken from port 2 (usually; your particular variant may have a different SFR for this purpose). You'll want to be sure to restore P2 if you have declared pdata variables. The linker will expect them to live in a particular page (see the PPAGE directive, and PPAGEENABLE / PPAGE_SFR defines in STARTUP.A51). I don't think the C compiler and linker support a "banked pdata" mode, where you can declare more than 256 bytes of pdata that live in different pages, and have the compiler automatically generate the correct values to write to P2.
"see the PPAGE directive, and PPAGEENABLE / PPAGE_SFR defines in STARTUP.A51" Can't see a PPAGE directive in the manuals - just a PPAGE define in STARTUP.A51 "I don't think the C compiler and linker support a 'banked pdata' mode, where you can declare more than 256 bytes of pdata that live in different pages, and have the compiler automatically generate the correct values to write to P2." That's the way I understand it, too. But I don't know if you could "roll your own" using the "XDATA Banking" features in the latest versions? (similar to the way you can give direct 'C' variable access to serial memories) Maybe Jon Ward could suggest...?
It has always seemed to me that it is a pity that it is not possible to take advantage of banking xdata by manipulating P2. The most obvious way to use P2 would be to have versions of library functions such memcpy() that could take advantage of P2 to be almost as fast as the dual data pointer versions. Another way might be to be able to define a function as being compact and then specify a page number in a similary way that using specifies a register bank. Of course, this would cause all sorts of potential complications....
PDATA is strange. And, it is inconsistently implemented. In the Intel 8051, you could use R0/R1 to access 256 bytes of a page that was identified with the port value of P2. Thus, Paged XData or PDATA was born. Then, devices like the Philips 750/751/752 came along with no LCALL/LJMP instructions and no XDATA (and no PDATA either). Then, devices came along with no external memory (so P2 was available as a General Purpose Port) but with 2K or 4K of on-chip XDATA. But what about PDATA? Well, PDATA was either fixed at page 0, or there was an SFR that set the PDATA page. The Keil linker has an associated SIZE with each memory type. So, DATA is 128, IDATA is 256, XDATA is 64K, CODE is 64K, PDATA is 256, and so on. If you try to put more stuff than will fit in a memory are, the linker complains. There is currently no support for PDATA banking to get the compiler to handle more than 256 bytes of PDATA for you. Using PDATA requires several steps:
unsigned char xdata bigbuf [256*40] _at_ 0x0100; unsigned int index; unsigned char pdata *p; . . . P2 = index >> 8; p = index & 0xFF; . . .
Ho-hum. What it is to be world-famous... (or is that infamous...?)
I took some time out to explore the benefits of using P2 in memcpy() and sure enough, in cases of a copy from CODE to XDATA or XDATA to XDATA there is a very significant speed bonus. Futhermore, looking through my recent applications, I see that these transfers are very common. Also, the compiler frequently calls memcpy() even when it is not explicitly mentioned in the source. For example, memcpy() is used to copy or initialise structures. It seems to me that a byte to save a shadow of P2 and a couple of exta instructions in an interrupt such as:
PUSH P2_shadow ... POP P2