ЛР13. Обновление platform.h и руководства к нему.

This commit is contained in:
Andrei Solodovnikov
2023-12-22 14:51:27 +03:00
parent b4d83d31dd
commit 75f7d1e38d
2 changed files with 84 additions and 56 deletions

View File

@@ -625,7 +625,7 @@ Disassembly of section .data:
При написании программы, помните что в C++ сильно ограничена арифметика указателей, поэтому при присваивании указателю целочисленного значения адреса, необходимо использовать оператор `reinterpret_cast`. При написании программы, помните что в 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" #include "platform.h"
/* /*
Создаем указатель на структуру SUPER_COLLIDER_HANDLE и инициализируем этот Создаем заголовочном файле "platform.h" объявлен collider_ptr — указатель на структуру SUPER_COLLIDER_HANDLE.
указатель адресом 0xFF000000, поскольку в нашей системе это периферийное Доступ к полям этой структуры можно осуществлять через оператор "->".
устройство расположено под номером 255. Также в этом файле объявлен указатель collider_mem, который указывает на
При инициализации указателя, мы делали преобразование типа посредством некоторую память этого периферийного устройства. Данный указатель можно
макроса CAST(type, address) из заголовочного файла platform.h использовать в качестве имени массива.
*/ */
struct SUPER_COLLIDER_HANDLE* collider_ptr = CAST(struct SUPER_COLLIDER_HANDLE*, 0xFF000000);
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
while(1){ // В бесконечном цикле while(1){ // В бесконечном цикле
while (!(collider_ptr->ready)); // Постоянно опрашиваем регистр ready, while (!(collider_ptr->ready)); // Постоянно опрашиваем регистр ready,
// пока тот не станет равен 1. // пока тот не станет равен 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 — индекс начала второй строки).
--- ---
### Порядок выполнения задания ### Порядок выполнения задания

View File

@@ -4,79 +4,103 @@
#ifdef __cplusplus #ifdef __cplusplus
#define CAST(type, addr) reinterpret_cast<type>(addr) #define CAST(type, addr) reinterpret_cast<type>(addr)
#else #else
#define CAST(type, addr) (type) (addr) #define CAST(type, addr) (type)(addr)
#endif #endif
/*
При включенных уровнях оптимизации, компилятор может следить за тем,
присваиваем ли мы что-то переменной, и если нет — считать что это не переменная
а константа и выкинуть её из программы.
Ключевое слово volatile сообщает компилятору, что значение данного объекта
может быть изменено извне. Например (как это происходит в нашем случае),
значение может меняться контроллером периферийного устройства.
*/
struct SW_HANDLE 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 struct LED_HANDLE
{ {
uint32_t value; volatile uint32_t value;
uint32_t mode; volatile uint32_t mode;
const uint32_t __unused__[7]; volatile const uint32_t __unused__[7];
uint32_t rst; volatile uint32_t rst;
}; };
struct LED_HANDLE *const led_ptr = CAST(struct LED_HANDLE *const, 0x02000000);
struct PS2_HANDLE struct PS2_HANDLE
{ {
const uint32_t scan_code; volatile const uint32_t scan_code;
const uint32_t unread_data; volatile const uint32_t unread_data;
const uint32_t __unused__[7]; volatile const uint32_t __unused__[7];
uint32_t rst; volatile uint32_t rst;
}; };
struct PS2_HANDLE *const ps2_ptr = CAST(struct PS2_HANDLE *const, 0x03000000);
struct HEX_HANDLE struct HEX_HANDLE
{ {
uint32_t hex0; volatile uint32_t hex0;
uint32_t hex1; volatile uint32_t hex1;
uint32_t hex2; volatile uint32_t hex2;
uint32_t hex3; volatile uint32_t hex3;
uint32_t hex4; volatile uint32_t hex4;
uint32_t hex5; volatile uint32_t hex5;
uint32_t hex6; volatile uint32_t hex6;
uint32_t hex7; volatile uint32_t hex7;
uint32_t bitmask; volatile uint32_t bitmask;
uint32_t rst; volatile uint32_t rst;
}; };
struct HEX_HANDLE *const hex_ptr = CAST(struct HEX_HANDLE *const, 0x04000000);
struct RX_HANDLE struct RX_HANDLE
{ {
const uint32_t data; volatile const uint32_t data;
const uint32_t unread_data; volatile const uint32_t unread_data;
const uint32_t busy; volatile const uint32_t busy;
uint32_t baudrate; volatile uint32_t baudrate;
uint32_t parity_bit; volatile uint32_t parity_bit;
uint32_t stop_bit; volatile uint32_t stop_bit;
const uint32_t __unused__[3]; volatile const uint32_t __unused__[3];
uint32_t rst; volatile uint32_t rst;
}; };
struct RX_HANDLE *const rx_ptr = CAST(struct RX_HANDLE *const, 0x05000000);
struct TX_HANDLE struct TX_HANDLE
{ {
uint32_t data; volatile uint32_t data;
const uint32_t __unused1__[1]; volatile const uint32_t __unused1__[1];
const uint32_t busy; volatile const uint32_t busy;
uint32_t baudrate; volatile uint32_t baudrate;
uint32_t parity_bit; volatile uint32_t parity_bit;
uint32_t stop_bit; volatile uint32_t stop_bit;
const uint32_t __unused2__[3]; volatile const uint32_t __unused2__[3];
uint32_t rst; 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; volatile const uint32_t system_counter;
uint8_t * color_map; volatile uint32_t delay;
uint32_t * tiff_map; 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 struct SUPER_COLLIDER_HANDLE
{ {
const uint32_t ready; volatile const uint32_t ready;
uint32_t start; volatile uint32_t start;
const uint32_t status; volatile const uint32_t status;
uint32_t emergency_switch; volatile uint32_t emergency_switch;
}; };
struct SUPER_COLLIDER_HANDLE *const collider_ptr = CAST(struct TIMER_HANDLE *const, 0xFF000000);