8 votos

Dirección absoluta de una función en un Microchip XC16

Dispositivo: dsPIC33FJ128GP802

Tengo algunos *.s archivos de la siguiente manera

.global _D1
.section .speex, code
_D1:
.pword 0x66C821,  0x1B0090,  0xD96C36,  0x9B60B0,  0xDD4E36,  0xBF4E53
.pword 0xD1098B,  0x719BD9,  0x873989,  0x003B69,  0x279035,  0xED4244
.pword 0xE1403C,  0x54D439,  0x826550,  0xC59627,  0xDD0432,  0x88FA29

He declarado la misma en un *.h

extern void D1(void);

Ahora estoy pasando el D1 a una tabla de la función de lectura

nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);

Mi problema es que, si la dirección de D1 está por encima de 0X8000, la rutina no es la correcta. Traté de grandes y pequeños modelos de código, pero el resultado es el mismo. Creo que esto es debido a la 16 bits de la limitación de los punteros ¿Hay algún método para acceder a la dirección absoluta de D1 directamente desde el código. Puede ser algo como el construido en la función o en las macros.

20voto

fearphage Puntos 250

Los datos que usted describe (24-bit uso de memoria de programa para almacenar datos) no puede ser definido y se inicializa en C, y no se puede leer directamente a través de la C; la única manera de acceder a ella es mediante la encapsulación en un C-rescatable de la asamblea o de la función de un valor intrínseco.

En realidad, hay dos preguntas aquí:

  1. cómo jugar muy bien con el compilador, ensamblador y enlazador, de modo que al definir el 24 bits de datos en un archivo de ensamblaje como reubicable de datos con un nombre simbólico D1, en lugar de sin nombre datos en una dirección fija, el compilador puede ver esta variable para determinar su dirección

  2. cómo acceder a los datos

La 2ª pregunta (¿cómo acceder a los datos) es respondida por 33EP partes en DS70613C y debe ser respondida por 33FJ partes en DS70204C (pero los ejemplos en la 33FJ manual sólo el uso de los 16 bits más bajos). He aquí un ejemplo de fragmento de código de la 33EP manual de referencia que funciona para 33EP partes + debe de 33FJ (no tengo un 33FJ dispositivo fácilmente disponibles):

(nota: el código utiliza int, mientras que sería mejor utilizar a uint16_t y #include <stdint.h>)

int prog_data[10] __attribute__((space(prog))) =
  {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999};

unsigned int lowWord[10], highWord[10];
unsigned int tableOffset, loopCount;

int main(void){
    TBLPAG = __builtin_tblpage (prog_data);
    tableOffset = __builtin_tbloffset (prog_data);
    /* Read all 10 constants into the lowWord and highWord arrays */
    for (loopCount = 0; loopCount < 10; loopCount ++)
    {
        lowWord[loopCount] = __builtin_tblrdl (tableOffset);
        highWord[loopCount] = __builtin_tblrdh (tableOffset);
        tableOffset +=2;
    }
    while(1)
        ;
}

Tenga en cuenta que las funciones integradas __builtin_tblrdl() y __builtin_tblrdh() se utiliza para leer el alta y baja de palabras de 16 bits de datos desde un programa de la localización de memoria, y __builtin_tblpage() and __builtin_tbloffset() puede ser utilizado para extraer la página y el desplazamiento de la dirección. En este ejemplo en particular, el highWord matriz siempre es 0, y el lowWord matriz coincide con el prog_data define e inicializa en C.

Por favor no punteros se utilizan aquí! Aunque es posible el uso normal de las variables que están marcados con la etiqueta const, de modo que se encuentran por el enlazador en el programa de sólo lectura del espacio, y por lo que se puede leer la memoria usando el estándar de C puntero técnicas, con el compilador automáticamente la gestión de la paginación de registros para usted, usted sólo puede almacenar datos de 16 bits. Usted necesita para acceder a la TBLRDL y TBLRDH funciones integradas para obtener todos los 24 bits de datos.

En cuanto a la manera de jugar muy bien con el compilador/enlazador/etc, tienes que engañar al compilador y decirle que es sólo de ver de datos de 16 bits. Aquí un ejemplo en el que trabajó para llegar a la variable D1 declarado en otro lugar:

#define D1_SIZE 18
extern uint16_t __attribute__((space(prog))) D1[D1_SIZE];

#define READ_DATA(dst, v, len) readData(dst, __builtin_tblpage(v), __builtin_tbloffset(v), len)
void readData(uint32_t *pdst, uint16_t page, uint16_t offset, uint16_t len)
{
    TBLPAG = page;
    while (len-- > 0)
    {
        uint16_t lo = __builtin_tblrdl (offset);
        uint16_t hi = __builtin_tblrdh (offset);
        *pdst++ = (((uint32_t)(hi)) << 16) | ((uint32_t)(lo));
        offset += 2;
    }
}

...

uint32_t d1copy[D1_SIZE];
READ_DATA(d1copy, D1, D1_SIZE);

Esto hace la lectura correcta de 24-bit de valores y los almacena en la parte inferior de 24 bits de un uint32_t. Los extern D1 variable declarada en C es una variable ficticia que es sólo utilizado para llegar a la dirección de inicio al tomar ventaja de la forma en que el compilador/montador/enlazador de trabajar juntos. Las funciones integradas manejar el resto de la obra.

Lo que no sé es cómo obtener automáticamente el tamaño de los datos, ya que se define + inicializado en la asamblea.

1voto

pacmanlikespie Puntos 9

No convertir a unsigned long y la espalda. Buscando problemas. Básicamente lo que hace es mentir, para el compilador. La declaración correcta para nowPlaying.archivo1 es

struct
{
    // other stuff ...
    void (*D1)(void);
    // other stuff ...
} nowPlaying;

Y lo mismo para la función():

extern void function(void (*file)(void));

y eliminar todos los typecasts.

O, si @PeterJ sugiere, se trata de datos, debe ser declarada como extern corto D1[] en ambos lugares: y usted realmente no necesita el ensamblador; usted podría haber declarado todo en C como const corto D1[] = {...}; El compilador debe poner en el segmento de código como es const.

0voto

RelaXNow Puntos 1164

Parece que la respuesta más simple es escribir la subrutina de ensamblador. Si no recuerdo mal, C30 no accede a la memoria de programa como los datos de uso de 24 bits punteros. En el mejor de los que puede tener acceso a la memoria de programa a través de la PSV ventana, pero entonces sólo puede ver los 16 bits más bajos de cada uno de los 24 bits de la memoria de programa de word.

Si sería muy sencillo escribir una rutina de ensamblador que se puede llamar desde C30 que devuelve el 24 bits de datos de 24 bits de la memoria de programa de la dirección. Sin embargo, los datos de una colección de 24 bits de valores o una lista de bytes que pasan a ser lleno del 3 por palabra? Si es esto último, entonces es aún más fácil. Escribir una rutina de ensamblador que le da un byte de direcciones de vista de la memoria de programa. La dirección tendrá que ser de 24 bits, pero los valores de los datos ahora sólo 8 bits.

O simplemente escribir toda la rutina en ensamblador. Si estás haciendo este tipo de bajo nivel de bytes de los golpes y de la memoria del embalaje, es probablemente más fácil. En ensamblador sólo puede hacer lo que quiera en la forma en que la máquina quiere hacerlo. En C, usted tiene que averiguar lo que los encantamientos a murmurar para que el compilador tiene que escribir el código de la máquina para usted. A veces es más fácil hacerlo usted mismo directamente. El dsPIC arquitectura es particularmente fácil escribir el código de la asamblea para, definitivamente más fácil que un PIC 16.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X