Поддельный регистр читает в C - PullRequest
4 голосов
/ 29 июля 2011

У меня есть существующая база кода для встроенной системы без операционной системы. Я пытаюсь собрать его с помощью x86 gcc, а не просто кросс-компилятора, в качестве первого шага к возможности модульного тестирования на хосте. К сожалению, есть прямое регистровое чтение и запись повсеместно, вместо использования предоставленного уровня абстракции. Один из вариантов, конечно, это исправить; замените прямой доступ к регистрам вызовами функций доступа к GPIO. Я надеюсь ускорить работу, введя макрос (используемый только в сборке x86) для переопределения фрагментов кода, таких как

myvar = (GPIOC->IDR >> 6) & 0x03;   // Read bits 6 and 7
GPIOD->CRL &= 0xFFFFFF0F;

что-то вроде:

myvar = (myGpiocIdrReadFunc() >> 6) & 0x03;   // Read bits 6 and 7
myGpiodClrWriteFunc() &= 0xFFFFFF0F;

GPIOx определены как указатели на физический адрес. Конечно, если я попытаюсь читать и писать напрямую по адресам на моем ПК с помощью исполняемого файла, созданного на платформе x86, это будет нарушением прав доступа. К сожалению, если я попробую что-то вроде этого:

#define GPIOC->IDR { myGpiocIdrReadFunc() }

компилятору это не нравится "->", говоря "пропущены пробелы после имени макроса."

Если вы уже решали подобные проблемы, как вы это сделали?

Ответы [ 5 ]

4 голосов
/ 29 июля 2011
typedef struct {
    int IDR;
    int CRL;
} gpio_t;

gpio_t c;
gpio_t d;

gpio_t * GPIOC = &c;
gpio_t * GPIOD = &d;

Просто продолжайте добавлять регистры типа IDR к struct, пока компилятор кричит на вас.

РЕДАКТИРОВАТЬ Я отредактировал ответ после того, как увидел ваш комментарий о том, что вы на самом деле хотите смоделировать значения, так как вы можете, но имейте в виду, что вам нужно инициализировать их, как в вашем оборудовании. *

1 голос
/ 29 июля 2011

В случае, если решение от hexa не вполне достаточно, вот второй вариант, который позволяет вам фактически моделировать поведение регистров, на которые ссылаются (включая побочные эффекты и т.д.). Как недостаток, для этого требуется C ++ (и ваш существующий код C может быть скомпилирован как C ++, что часто является сложным требованием), и что структуры не используют собственные типы напрямую, а вместо этого используют псевдоним.

Вы можете определить класс, который реализует operator=, operator int и любые другие функции доступа, которые вам могут понадобиться (&= и т. Д.). Если поля в структуре GPIOC указывают на тип, который вы можете изменить, вы можете просто изменить этот тип, чтобы он ссылался на ваш класс регистров.

Примерно так:

#ifdef USE_REAL_HW

typedef volatile uint32_t HW_REGISTER32;

#else // (USE_REAL_HW not defined)

template<class T>
class RegisterAbstractionClass {
public:
    const T operator= (const T value) {
        data = value;
        return value;
    };
    operator const T() {
        return data;
    };
    // Other operators...
protected:
    volatile T data;
};

typedef RegisterAbstractionClass<uint32_t> HW_REGISTER32;

#endif // (USE_REAL_HW)

typedef struct {
    HW_REGISTER32 IDR;
    HW_REGISTER32 CRL;
} gpio_t;

(Обратите внимание, что вышеприведенное несколько упрощено: и IDR, и CRL будут вести себя одинаково в этом случае, что, вероятно, не относится к аппаратному обеспечению.)

1 голос
/ 29 июля 2011

Кажется, вы после буквально заменили эту строку в источнике. Почему бы вам просто не сделать это с неинтерактивным редактором, таким как sed? Возможно, у вас есть система сборки, которая может, в зависимости от архитектуры, заменить или нет.

0 голосов
/ 29 июля 2011

Вы, похоже, неправильно определили свой #define.Попробуйте "#define MyGpiocIdrReadFunc () x86ReadFunc ()" для макроса в вашей тестовой системе.Конечно, вам нужно заменить все чтения из GPIOC-> IDR на MyGpiocIdrReadFunc ().Вам также нужно будет реализовать эту функцию.Вероятно, это примерно столько же, сколько исправление кода для использования упомянутого вами уровня абстракции.

0 голосов
/ 29 июля 2011

Не думаю, что это будет легко.

Обратите внимание, что SFR обычно volatile, и многие арифметические операции являются атомарными. Итак, код

GPIOD->CRL &= 0xFFFFFF0F;

не будет эквивалентно

setter(CLR_reg, getter(CLR_reg) & 0xFFFFFF0F);

Также обратите внимание, что может быть занят цикл ожидания прерывания и даже обработчики прерываний.

...