diff --git a/Labs/13. Programming/README.md b/Labs/13. Programming/README.md index 7d40255..b2d4c11 100644 --- a/Labs/13. Programming/README.md +++ b/Labs/13. Programming/README.md @@ -625,7 +625,7 @@ Disassembly of section .data: При написании программы, помните что в C++ сильно ограничена арифметика указателей, поэтому при присваивании указателю целочисленного значения адреса, необходимо использовать оператор `reinterpret_cast`. -Для того, чтобы уменьшить ваше взаимодействие черной магией указателей, вам представлен файл [platform.h](platform.h), в котором объявлены структуры, в которых происходит отображение полей на физические адреса периферийных устройств. Вам нужно лишь проинициализировать указатель на структуру физическим адресом периферийного устройства (преобразовав перед этим целочисленное значение в тип указателя с помощью макроса `CAST`, представленного в файле `platform.h`). +Для того, чтобы уменьшить ваше взаимодействие с черной магией указателей, вам представлен файл [platform.h](platform.h), в котором объявлены указатели структуры, отвечающие за отображение полей на физические адреса периферийных устройств. Вам нужно лишь воспользоваться указателем на ваше периферийное устройство. Пример взаимодействия с периферийным устройством через вымышленную структуру: @@ -633,22 +633,24 @@ Disassembly of section .data: #include "platform.h" /* - Создаем указатель на структуру SUPER_COLLIDER_HANDLE и инициализируем этот - указатель адресом 0xFF000000, поскольку в нашей системе это периферийное - устройство расположено под номером 255. - При инициализации указателя, мы делали преобразование типа посредством - макроса CAST(type, address) из заголовочного файла platform.h + Создаем заголовочном файле "platform.h" объявлен collider_ptr — указатель на структуру SUPER_COLLIDER_HANDLE. + Доступ к полям этой структуры можно осуществлять через оператор "->". + Также в этом файле объявлен указатель collider_mem, который указывает на + некоторую память этого периферийного устройства. Данный указатель можно + использовать в качестве имени массива. */ -struct SUPER_COLLIDER_HANDLE* collider_ptr = CAST(struct SUPER_COLLIDER_HANDLE*, 0xFF000000); int main(int argc, char** argv) { - while(1){ // В бесконечном цикле - while (!(collider_ptr->ready)); // Постоянно опрашиваем регистр ready, - // пока тот не станет равен 1. + while(1){ // В бесконечном цикле + while (!(collider_ptr->ready)); // Постоянно опрашиваем регистр ready, + // пока тот не станет равен 1. - // После чего запускаем коллайдер, записав - collider_ptr->start = 1; // 1 в контрольный регистр start + // После чего запускаем коллайдер, + collider_ptr->start = 1; // записав 1 в контрольный регистр start + collider_mem[0] += collider_mem[1]; // Пример взаимодействия с памятью, + // Используя объявленный в platform.h + // указатель в качестве имени массива. } } @@ -671,6 +673,8 @@ extern "C" void int_handler() } ``` +Если одним из ваших периферийных устройств был VGA-контроллер, использовать не указатель на структуру, а объявленные в том же файле указатели на байты: `char_map`, `color_map`, `tiff_map`. Как вы знаете, указатель может использоваться в качестве имени массива, а значит вы можете обращаться к нужному вам байту в соответствующей области памяти VGA-контроллера как к элементу массива. Например, для того, чтобы записать символ в шестое знакоместо второй строки, вам необходимо будет обратиться к `char_map[2*80+6]` (2*80 — индекс начала второй строки). + --- ### Порядок выполнения задания diff --git a/Labs/13. Programming/platform.h b/Labs/13. Programming/platform.h index f569545..d1da15d 100644 --- a/Labs/13. Programming/platform.h +++ b/Labs/13. Programming/platform.h @@ -4,79 +4,103 @@ #ifdef __cplusplus #define CAST(type, addr) reinterpret_cast(addr) #else -#define CAST(type, addr) (type) (addr) +#define CAST(type, addr) (type)(addr) #endif +/* + При включенных уровнях оптимизации, компилятор может следить за тем, + присваиваем ли мы что-то переменной, и если нет — считать что это не переменная + а константа и выкинуть её из программы. + Ключевое слово volatile сообщает компилятору, что значение данного объекта + может быть изменено извне. Например (как это происходит в нашем случае), + значение может меняться контроллером периферийного устройства. +*/ + struct SW_HANDLE { - const uint32_t value; + volatile const uint32_t value; }; +struct SW_HANDLE *const sw_ptr = CAST(struct SW_HANDLE *const, 0x01000000); struct LED_HANDLE { - uint32_t value; - uint32_t mode; - const uint32_t __unused__[7]; - uint32_t rst; + volatile uint32_t value; + volatile uint32_t mode; + volatile const uint32_t __unused__[7]; + volatile uint32_t rst; }; +struct LED_HANDLE *const led_ptr = CAST(struct LED_HANDLE *const, 0x02000000); struct PS2_HANDLE { - const uint32_t scan_code; - const uint32_t unread_data; - const uint32_t __unused__[7]; - uint32_t rst; + volatile const uint32_t scan_code; + volatile const uint32_t unread_data; + volatile const uint32_t __unused__[7]; + volatile uint32_t rst; }; +struct PS2_HANDLE *const ps2_ptr = CAST(struct PS2_HANDLE *const, 0x03000000); struct HEX_HANDLE { - uint32_t hex0; - uint32_t hex1; - uint32_t hex2; - uint32_t hex3; - uint32_t hex4; - uint32_t hex5; - uint32_t hex6; - uint32_t hex7; - uint32_t bitmask; - uint32_t rst; + volatile uint32_t hex0; + volatile uint32_t hex1; + volatile uint32_t hex2; + volatile uint32_t hex3; + volatile uint32_t hex4; + volatile uint32_t hex5; + volatile uint32_t hex6; + volatile uint32_t hex7; + volatile uint32_t bitmask; + volatile uint32_t rst; }; +struct HEX_HANDLE *const hex_ptr = CAST(struct HEX_HANDLE *const, 0x04000000); struct RX_HANDLE { - const uint32_t data; - const uint32_t unread_data; - const uint32_t busy; - uint32_t baudrate; - uint32_t parity_bit; - uint32_t stop_bit; - const uint32_t __unused__[3]; - uint32_t rst; + volatile const uint32_t data; + volatile const uint32_t unread_data; + volatile const uint32_t busy; + volatile uint32_t baudrate; + volatile uint32_t parity_bit; + volatile uint32_t stop_bit; + volatile const uint32_t __unused__[3]; + volatile uint32_t rst; }; +struct RX_HANDLE *const rx_ptr = CAST(struct RX_HANDLE *const, 0x05000000); struct TX_HANDLE { - uint32_t data; - const uint32_t __unused1__[1]; - const uint32_t busy; - uint32_t baudrate; - uint32_t parity_bit; - uint32_t stop_bit; - const uint32_t __unused2__[3]; - uint32_t rst; + volatile uint32_t data; + volatile const uint32_t __unused1__[1]; + volatile const uint32_t busy; + volatile uint32_t baudrate; + volatile uint32_t parity_bit; + volatile uint32_t stop_bit; + volatile const uint32_t __unused2__[3]; + volatile uint32_t rst; }; +struct TX_HANDLE *const tx_ptr = CAST(struct TX_HANDLE *const, 0x06000000); -struct VGA_HANDLE +volatile uint8_t * const char_map = CAST(uint8_t * const, 0x07000000); +volatile uint8_t * const color_map = CAST(uint8_t * const, 0x07001000); +volatile uint8_t * const tiff_map = CAST(uint8_t * const, 0x07002000); + +struct TIMER_HANDLE { - uint8_t * char_map; - uint8_t * color_map; - uint32_t * tiff_map; + volatile const uint32_t system_counter; + volatile uint32_t delay; + volatile uint32_t mode; + volatile uint32_t repeat_counter; + volatile const uint32_t __unused2__[5]; + volatile uint32_t rst; }; +struct TIMER_HANDLE *const timer_ptr = CAST(struct TIMER_HANDLE *const, 0x08000000); struct SUPER_COLLIDER_HANDLE { - const uint32_t ready; - uint32_t start; - const uint32_t status; - uint32_t emergency_switch; + volatile const uint32_t ready; + volatile uint32_t start; + volatile const uint32_t status; + volatile uint32_t emergency_switch; }; +struct SUPER_COLLIDER_HANDLE *const collider_ptr = CAST(struct TIMER_HANDLE *const, 0xFF000000);