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

Accessing far memory, linking problem

Former Member
Former Member

I have a serial EEPROM used as a far memory expansion. Writing and reading routines for an i2c bus are in a C-code:

void start_write (void far * w_addr) {

        wait_smb_free ();
        smb_address = (unsigned int)w_addr;     // EEPROM address
}

void write_page (unsigned char w_count) {

        data_number = w_count;                          // number of data bytes.
        wait_smb_free ();
}

//      write into an EEPROM

void from_mem_into_eeprom (unsigned char far * wr_addr, unsigned int wr_count, unsigned char * wr_dataptr) {
        unsigned char   wr_ii;

        while (wr_count) {
                smb_buffer[wr_ii] = *wr_dataptr;
                start_write (wr_addr);                  // cnt bytes
                if (wr_count < 8)
                        wr_ii = wr_count;
                write_page (wr_ii);                             // cnt byte(s)
                wr_count -= wr_ii;
        }
}

void byte_into_eeprom (unsigned char far * bw_addr, unsigned char out_b) {

        start_write (bw_addr);
        smb_buffer[0] = out_b;                  // Data byte
        write_page (1);                                 // 1 byte
}

void word_into_eeprom (unsigned int far * ww_addr, unsigned int out_w) {

        from_mem_into_eeprom ((void *)ww_addr, sizeof(int), (void *)&out_w);
}



void read_eeprom (void far * rd_addr, unsigned char rd_count) {

        wait_smb_free (SMB_Wait_Error);
        smb_address = (unsigned int)rd_addr;    // EEPROM address
        data_number = rd_count;                         // number of data bytes.
        wait_smb_free ();               // Wait for transfer to finish
}

unsigned char byte_from_eeprom (unsigned char far * br_addr) {

        read_eeprom (br_addr, sizeof(char));
        return (smb_buffer[0]);
}

unsigned int word_from_eeprom (unsigned int far * wr_addr) {

        read_eeprom (wr_addr, sizeof(int));
        return (*(unsigned int *)smb_buffer);
}

XBANKING.A51 is something like this:

        NAME    ?C?XBANKING     ; 'far' Memory Access Support


PUBLIC ?B?SMEM, ?B?TMEM, ?B?UMEM, ?B?VMEM ;PUBLIC ?C?XPAGE1SFR, ?C?XPAGE1RST PUBLIC ?C?CLDXPTR, ?C?CSTXPTR, ?C?ILDXPTR, ?C?ISTXPTR PUBLIC ?C?PLDXPTR, ?C?PSTXPTR, ?C?LLDXPTR, ?C?LSTXPTR
EXTRN CODE (_byte_from_eeprom, _byte_into_eeprom) EXTRN CODE (_word_from_eeprom, _word_into_eeprom)
?C?LIB_CODE SEGMENT CODE RSEG ?C?LIB_CODE
;---------------------------------------------------------------------- ; CLDXPTR: Load BYTE in A via Address given in R1/R2/R3 ?C?CLDXPTR: LCALL _byte_from_eeprom MOV A, R7 RET
;---------------------------------------------------------------------- ; CSTXPTR: Store BYTE in A via Address given in R1/R2/R3 ?C?CSTXPTR: MOV R5, A LCALL _byte_into_eeprom RET
;---------------------------------------------------------------------- ; ILDXPTR: Load WORD in A(LSB)/B(HSB) via Address given in R1/R2/R3 ?C?ILDXPTR: LCALL _word_from_eeprom RET
;---------------------------------------------------------------------- ; ISTXPTR: Store WORD in A(HSB)/B(LSB) via Address given in R1/R2/R3 ?C?ISTXPTR: MOV R5, B MOV R4, A LCALL _word_into_eeprom RET
END

If I used direct calls to the routines, linking would done without failures:

                byte_into_eeprom ((void *)&test_block_e.test_byte, 0x30);
                if (byte_from_eeprom ((void *)&test_block_e.test_byte) != 0x30)
                        jj++;
                word_into_eeprom ((void *)&test_block_e.test_word, 0x60A1);
                if (word_from_eeprom ((void *)&test_block_e.test_word) != 0x60A1)
                        jj++;

However, I’d like to assign a value to a variable:

void self_test_1 (void) {
        unsigned int    result1, temp1;

        temp1 = meas_uct_cC();
        result1 = 0;
        result1 |= check_value (test_block_e.battV = meas_bat_mV(),11000,13750);
        result1 |= check_value (test_block_e.vd3V = meas_3vd_mV(), 3150, 3450) << 2;
        result1 |= check_value (test_block_e.vd5V = meas_5vd_mV(), 4750, 5250) << 4;

        if (temp1 > 6000)
                hw_error |= OverHeat;
        test_block_e.hw_result |= result1;
}

Test_block_e is a sample structure in the far memory.
In this case local variables (result1 and temp1) are overwritten by local variable (out_w) in EEPROM writing routine.
Linker makes only one byte difference:

      00000001H   SYMBOL    DATA     ---       ww_addr
      00000019H   SYMBOL    DATA     WORD      out_w

      00000018H   SYMBOL    DATA     WORD      result1
      0000001AH   SYMBOL    DATA     WORD      temp1

Are there any requirements if an external routine is called in XBANKING.A51?

  • Are there any requirements if an external routine is called in XBANKING.A51?

    In a nutshell: forget about writing them in C, or forget about using any of the code or resources involved from anywhere else in the code. Data overlaying is pretty much guaranteed to ruin your day otherwise.

  • Former Member
    0 Former Member in reply to HansBernhard Broeker

    Unfortunately, dedicated C code is difficult task for the linker also.

    *** WARNING L57: UNCALLED FUNCTION, IGNORED FOR OVERLAY PROCESS
        NAME:    _BYTE_INTO_EEPROM/SMB
    
    *** WARNING L57: UNCALLED FUNCTION, IGNORED FOR OVERLAY PROCESS
        NAME:    _WORD_INTO_EEPROM/SMB
    
    *** WARNING L57: UNCALLED FUNCTION, IGNORED FOR OVERLAY PROCESS
        NAME:    _BYTE_FROM_EEPROM/SMB
    
    *** WARNING L57: UNCALLED FUNCTION, IGNORED FOR OVERLAY PROCESS
        NAME:    _WORD_FROM_EEPROM/SMB
    


    As a workaround I'll skip XBANKING.A51 and direct accessing/assigning so far.