This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

24 bit address in 16 bit processor

Please do not say 'paging' I can not handle the overhead for all the other stuff that fit nicely within 64k.

I have a 2Mbyte flash that occasionally is accessed and the time here is not critical (the system pauses) as opposed to other processes that use only RAM.

Is there an elegant way to access structures in that 24 bit address space or does it have to be bent folded and mutilated to access?

Currently all addresses are specified with an 8 bit 'page' and a 16 bit 'address' and processed as such. I could gain some readability by having the whole in a long.

Also this method require data to be stored so no structure cross a page boundary and that limitation is a nuisance.

Erik

  • Well, that complicates things a bit, but still, couldn't you look at the address and size of the object to determine if it straddles?

    There is more to it, There are 32 copies of struct a, 64 copies of array b etc.

    To process the same struct differently depending on its location would create a piece of code that would be a nightmare to debug.

    Anyhow, I'll see what that cost of requesting a gap would be and if exorbiant, I'll try the suggestions here.

    Thanks all,

    Erik

  • Sounds like the offsetof() macro could come in handy.

        if (((U16)addr + offsetof(structType, fieldName) < (U16)addr)
            { // field straddes 64k boundary
            }
        else
            { // field lies within one 64k segment
            }
    

    Assuming none of your fields are bigger than 32k, that is.

    But isn't such a test at runtime again going to be more expensive than just setting the bank register? I suppose you could figure out at initialization time where the break comes, and store that.

    Is this operation really so time-critical that saving a couple of instructions is worthwhile? Flash access is often slower than RAM access. If you're writing to the flash, it's many orders of magnitude slower than the access time.

  • Is this operation really so time-critical that saving a couple of instructions is worthwhile? Flash access is often slower than RAM access.
    when reading flash timing is of no concern, when NOT reading flash extremely so.
    Basically the unit run in two modes
    Haul @$$ (99.9% of the time)
    work with flash

    Erik

  • As Jon mentioned, the extra instructions to set up the high 8 bits of the address apply only to far and const far data. Regular xdata access does not go through these routines, and will not be slowed down by the code in XBANKING.A51. These routines are essentially the "far access library". So long as you don't declare your normal xdata items far or access them via a far pointer, you should be safe.

    The remaining question seems to be whether or not the actual access pattern is such that detecting the segment boundary is worthwhile. If there's a whole lot of 1-byte reads in the same segment, then you could (in theory) optimize out most of the high-order byte setup, as in the ReadManual4 routine I posted above. It's just a matter of whether the time and code it takes to figure out whether you need to set the high byte is less than the time it takes you just to do it every time. Also, it's perhaps worth considering whether you need consistent execution time for every access, or whether it's okay for some of them to be much longer than others as long as the amortized total is less overall.

  • Also, it's perhaps worth considering whether you need consistent execution time for every access, or whether it's okay for some of them to be much longer than others as long as the amortized total is less overall.
    varying execution time is irrelevant, but code that tries to read something by method a and something by method b will by me be considered 'messy' and outlawed.

    Again, once the flash is in the loop timing is totlly non-critical.

    I will play a bit with far and !far and see what happens.

    Erik

  • one question re banking
    can the 'main' bank be 64k all I have seen say 'home bank' 32k, bank 1 32k

    Erik

  • If you're referring to code banking, the bank size may be anything from 0 to 64K.

    Typically, you'll have a fixed common area which is stored in a 32K ROM (or something like that) and you'll have banking hardware that switches the upper 32K (or whatever's left).

    But, there's nothing that prevents you from using only 8K for the common area and 56K for the banked area.

    If the common area is TOO small, the compiler just merges it into each of the code banks.

    Using that, you could just have 64K banks and let the compiler use whatever it needed for the common area. Of course, that area would be duplicated in each code bank (but if you keep it small, that's not really an issue). But, that may reduce the amount of development work involved.

    Jon

  • I think you're thinking of code banking. The L51_BANK.A51 file contains routines for code banking, and also for data banking. Code banking often has a 32k common section that doesn't get swapped out, plus a 32k window that accesses different portions of the code space as need be.

    XBANKING.A51 is just data banking. I suppose it could be implemented to operate on 32k windows with some appropriate shifts, though I'm not sure what the point would be with only one DPTR. (If you had two DPTRs, I could see having two windows to copy between widely seperated regions of physical address space.)

    Normally you just add on some high order address bits in custom hardware, perhaps an I/O port, and thus have full 64k segments (addressed by the DPTR) plus another byte that holds the "segment register" (if you want to think of it that way). Segment 0 would typically decode to the "normal" xdata space.

    In your case, it sounds like P4 == 0 produces the chip select for a RAM, and P4 != 0 produces a chip select for the flash, as well as A??..A16, while A15..A0 come from the usual pins (connected to the DPTR). So you would configure XBANKING.A51 to

    EXT_IN_SFR EQU 1
    IF EXT_IN_SFR = 1
    ?C?XPAGE1SFR DATA 0B0H ; SFR Address of XPAGE1 register P4
    ELSE
    ?C?XPAGE1ADDR EQU 0FFFAH ; XDATA address of XDATA bank register
    ENDIF

    ?C?XPAGE1RST EQU 0 ; XPAGE1 register value to address X:0 region


    and away you go.

  • Hi Erik,

    Random musing here:

    the 8086 was a 16-bit processor with 20-bit addressing; it formed a 20-bit address from two 16-bit registers (Segment & Offset) and a cunning shift-and-add.

    Could you maybe devise a similar scheme - probably using an external CPLD or something?
    Or maybe a Trisc... oops! not any more! :-(

  • If you're referring to code banking,
    I am obviously referring to data banking

    Erik

  • We are drifting off the subject here, I only need abt 40k of code and 64k of data.
    BUT rarely, I need to access a 2 megabyte DATA flash which contain structures and arrays uploaded from a PC program that generate them. This works fine once I have created pointers (page and offset) where the endianness is reversed EXCEPT when a struct/array cross a 64k boundary. Since the page/offset is a long (32 bits) the result should be ok, but the calculation of the address of an entity in a struct/array is 16 bit only and thus if the base of the struct/array is high in a page the offset to an entry in the struct/array may come out wrong because that entity is in the next page.

    example:
    U32 myarr[64];

    if myarr is located at address fff0 and I access
    myarr[8]
    the access will be to address 000010, not 10010

    Please note that the data is structures within structures within structures and arrays of structures etc, the example above is an extreme simplification.

    ALSO: because some control bits must be changed to access the flash, all accesses to that flash are done via
    U8 ReadFlash (U32 location);

    Erik

  • We are aware of the 16-bit offset limitation. This is why the compiler does not let you define objects that cross a 64KB boundary.


    AppNote 160 shows ways to solve this problem.
    Take a look to: http://www.keil.com/appnotes/docs/apnt_160.asp. See "EXPAND VARIABLE SPACE".

  • I tried the AN160 suggestion, there is no difference. In the case of actually using a MX chip and CX51, this would be a gross error.

    C51  XMACtemq = (ReadPagedFlashC ((U32) (GPtsd + TSDflags), GC_TXI_pg) & OCU_TEXT_MASK);
    001E E500        E     MOV     A,GPtsd+01H
    0020 2401              ADD     A,#01H
    0022 FF                MOV     R7,A
    0023 E500        E     MOV     A,GPtsd
    0025 3400              ADDC    A,#00H
    0027 FE                MOV     R6,A
    0028 E4                CLR     A
    0029 FC                MOV     R4,A
    002A FD                MOV     R5,A
    002B AD00        E     MOV     R5,GC_TXI_pg
    002D 120000      E     LCALL   _ReadPagedFlashC
    
    C51  XMACtemq = (ReadPagedFlashC ((U16) (GPtsd + TSDflags), GC_TXI_pg) & OCU_TEXT_MASK);
    001E E500        E     MOV     A,GPtsd+01H
    0020 2401              ADD     A,#01H
    0022 FF                MOV     R7,A
    0023 E500        E     MOV     A,GPtsd
    0025 3400              ADDC    A,#00H
    0027 FE                MOV     R6,A
    0028 AD00        E     MOV     R5,GC_TXI_pg
    002A 120000      E     LCALL   _ReadPagedFlashC
    
    CX51  XMACtemq = (ReadPagedFlashC ((U16) (GPtsd + TSDflags), GC_TXI_pg) & OCU_TEXT_MASK);
    001E E500        E     MOV     A,GPtsd+01H
    0020 2401              ADD     A,#01H
    0022 FF                MOV     R7,A
    0023 E500        E     MOV     A,GPtsd
    0025 3400              ADDC    A,#00H
    0027 FE                MOV     R6,A
    0028 AD00        E     MOV     R5,GC_TXI_pg
    002A 120000      E     LCALL   _ReadPagedFlashC
    
    CX51  XMACtemq = (ReadPagedFlashC ((U32) (GPtsd + TSDflags), GC_TXI_pg) & OCU_TEXT_MASK);
    001E E500        E     MOV     A,GPtsd+01H
    0020 2401              ADD     A,#01H
    0022 FF                MOV     R7,A
    0023 E500        E     MOV     A,GPtsd
    0025 3400              ADDC    A,#00H
    0027 FE                MOV     R6,A
    0028 E4                CLR     A
    0029 FC                MOV     R4,A
    002A FD                MOV     R5,A
    002B AD00        E     MOV     R5,GC_TXI_pg
    002D 120000      E     LCALL   _ReadPagedFlashC
    

    Erik

  • Instead of:

    U32 address = &MyStruct.MyField;

    what about:

    U32 address = (U32)&MyStruct + offsetof(MyStruct, MyField)

  • fine, but when it is structure within array fo structures within a structure and so on it becomes very unreadable.

    Erik

    Anyhow, with CX51 it should work, bcause there you can address 8Mbyte linearily.