From a0664148fd697682704813658f0ffd51d1260bd3 Mon Sep 17 00:00:00 2001 From: beeanyew Date: Sun, 3 Jan 2021 03:55:49 +0100 Subject: [PATCH] Add dumb framebuffer RTG Driver source, prebuilt .card files available in rtg_driver_amiga directory. RTG enabled by specifying "setvar rtg" at the end of the config file. There is currently no visual output, because it's 4 AM. --- Makefile | 1 + config_file/config_file.c | 2 +- config_file/config_file.h | 2 +- emulator.c | 8 + gpio/gpio.c | 65 +- platforms/amiga/amiga-platform.c | 17 +- platforms/amiga/rtg/rtg.c | 197 ++++++ platforms/amiga/rtg/rtg.h | 45 ++ .../amiga/rtg/rtg_driver_amiga/boardinfo.h | 658 ++++++++++++++++++ platforms/amiga/rtg/rtg_driver_amiga/build.sh | 2 + platforms/amiga/rtg/rtg_driver_amiga/pigfx.c | 518 ++++++++++++++ .../amiga/rtg/rtg_driver_amiga/pigfx020.card | Bin 0 -> 2072 bytes .../amiga/rtg/rtg_driver_amiga/pigfx030.card | Bin 0 -> 2072 bytes .../amiga/rtg/rtg_driver_amiga/settings.h | 184 +++++ 14 files changed, 1652 insertions(+), 47 deletions(-) create mode 100644 platforms/amiga/rtg/rtg.c create mode 100644 platforms/amiga/rtg/rtg.h create mode 100644 platforms/amiga/rtg/rtg_driver_amiga/boardinfo.h create mode 100644 platforms/amiga/rtg/rtg_driver_amiga/build.sh create mode 100644 platforms/amiga/rtg/rtg_driver_amiga/pigfx.c create mode 100644 platforms/amiga/rtg/rtg_driver_amiga/pigfx020.card create mode 100644 platforms/amiga/rtg/rtg_driver_amiga/pigfx030.card create mode 100644 platforms/amiga/rtg/rtg_driver_amiga/settings.h diff --git a/Makefile b/Makefile index 9c656bb..edb8135 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ MAINFILES = emulator.c \ platforms/dummy/dummy-registers.c \ platforms/amiga/Gayle.c \ platforms/amiga/gayle-ide/ide.c \ + platforms/amiga/rtg/rtg.c \ platforms/shared/rtc.c MUSASHIFILES = m68kcpu.c softfloat/softfloat.c diff --git a/config_file/config_file.c b/config_file/config_file.c index b0b9a48..4ac9670 100644 --- a/config_file/config_file.c +++ b/config_file/config_file.c @@ -382,7 +382,7 @@ struct emulator_config *load_config_file(char *filename) { memset(var_value, 0x00, 128); get_next_string(parse_line, var_name, &str_pos, ' '); get_next_string(parse_line, var_value, &str_pos, ' '); - cfg->platform->setvar(var_name, var_value); + cfg->platform->setvar(cfg, var_name, var_value); break; } diff --git a/config_file/config_file.h b/config_file/config_file.h index 4a3e5f4..358a570 100644 --- a/config_file/config_file.h +++ b/config_file/config_file.h @@ -82,7 +82,7 @@ struct platform_config { int (*platform_initial_setup)(struct emulator_config *cfg); void (*handle_reset)(struct emulator_config *cfg); void (*shutdown)(struct emulator_config *cfg); - void (*setvar)(char *var, char *val); + void (*setvar)(struct emulator_config *cfg, char *var, char *val); }; unsigned int get_m68k_cpu_type(char *name); diff --git a/emulator.c b/emulator.c index d3faa74..f9c1295 100644 --- a/emulator.c +++ b/emulator.c @@ -22,6 +22,7 @@ #include "platforms/amiga/Gayle.h" #include "platforms/amiga/gayle-ide/ide.h" #include "platforms/amiga/amiga-registers.h" +#include "platforms/amiga/rtg/rtg.h" #include "gpio/gpio.h" int kb_hook_enabled = 0; @@ -263,6 +264,9 @@ static unsigned int target = 0; unsigned int target = 0; \ switch(cfg->platform->id) { \ case PLATFORM_AMIGA: { \ + if (address >= PIGFX_RTG_BASE && address < PIGFX_RTG_BASE + PIGFX_RTG_SIZE) { \ + return rtg_read((address & 0x0FFFFFFF), a); \ + } \ if (custom_read_amiga(cfg, address, &target, a) != -1) { \ return target; \ } \ @@ -332,6 +336,10 @@ unsigned int m68k_read_memory_32(unsigned int address) { if (address >= cfg->custom_low && address < cfg->custom_high) { \ switch(cfg->platform->id) { \ case PLATFORM_AMIGA: { \ + if (address >= PIGFX_RTG_BASE && address < PIGFX_RTG_BASE + PIGFX_RTG_SIZE) { \ + rtg_write((address & 0x0FFFFFFF), value, a); \ + return; \ + } \ if (custom_write_amiga(cfg, address, value, a) != -1) { \ return; \ } \ diff --git a/gpio/gpio.c b/gpio/gpio.c index 1f9c567..fbdd3dd 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -37,32 +37,25 @@ unsigned char toggle; static int g = 0; inline void write16(uint32_t address, uint32_t data) { - uint32_t addr_h_s = (address & 0x0000ffff) << 8; - uint32_t addr_h_r = (~address & 0x0000ffff) << 8; - uint32_t addr_l_s = (address >> 16) << 8; - uint32_t addr_l_r = (~address >> 16) << 8; - uint32_t data_s = (data & 0x0000ffff) << 8; - uint32_t data_r = (~data & 0x0000ffff) << 8; - // asm volatile ("dmb" ::: "memory"); W16 *(gpio) = gpfsel0_o; *(gpio + 1) = gpfsel1_o; *(gpio + 2) = gpfsel2_o; - *(gpio + 7) = addr_h_s; - *(gpio + 10) = addr_h_r; + *(gpio + 7) = ((address & 0x0000ffff) << 8); + *(gpio + 10) = ((~address & 0x0000ffff) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; - *(gpio + 7) = addr_l_s; - *(gpio + 10) = addr_l_r; + *(gpio + 7) = ((address >> 16) << 8); + *(gpio + 10) = ((~address >> 16) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; // write phase - *(gpio + 7) = data_s; - *(gpio + 10) = data_r; + *(gpio + 7) = ((data & 0x0000ffff) << 8); + *(gpio + 10) = ((~data & 0x0000ffff) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; @@ -79,12 +72,6 @@ inline void write8(uint32_t address, uint32_t data) { data = data + (data << 8); // EVEN, A0=0,UDS else data = data & 0xff; // ODD , A0=1,LDS - uint32_t addr_h_s = (address & 0x0000ffff) << 8; - uint32_t addr_h_r = (~address & 0x0000ffff) << 8; - uint32_t addr_l_s = (address >> 16) << 8; - uint32_t addr_l_r = (~address >> 16) << 8; - uint32_t data_s = (data & 0x0000ffff) << 8; - uint32_t data_r = (~data & 0x0000ffff) << 8; // asm volatile ("dmb" ::: "memory"); W8 @@ -92,19 +79,19 @@ inline void write8(uint32_t address, uint32_t data) { *(gpio + 1) = gpfsel1_o; *(gpio + 2) = gpfsel2_o; - *(gpio + 7) = addr_h_s; - *(gpio + 10) = addr_h_r; + *(gpio + 7) = ((address & 0x0000ffff) << 8); + *(gpio + 10) = ((~address & 0x0000ffff) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; - *(gpio + 7) = addr_l_s; - *(gpio + 10) = addr_l_r; + *(gpio + 7) = ((address >> 16) << 8); + *(gpio + 10) = ((~address >> 16) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; // write phase - *(gpio + 7) = data_s; - *(gpio + 10) = data_r; + *(gpio + 7) = ((data & 0x0000ffff) << 8); + *(gpio + 10) = ((~data & 0x0000ffff) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; @@ -117,25 +104,20 @@ inline void write8(uint32_t address, uint32_t data) { } inline uint32_t read16(uint32_t address) { - volatile int val; - uint32_t addr_h_s = (address & 0x0000ffff) << 8; - uint32_t addr_h_r = (~address & 0x0000ffff) << 8; - uint32_t addr_l_s = (address >> 16) << 8; - uint32_t addr_l_r = (~address >> 16) << 8; - + int val; // asm volatile ("dmb" ::: "memory"); R16 *(gpio) = gpfsel0_o; *(gpio + 1) = gpfsel1_o; *(gpio + 2) = gpfsel2_o; - *(gpio + 7) = addr_h_s; - *(gpio + 10) = addr_h_r; + *(gpio + 7) = ((address & 0x0000ffff) << 8); + *(gpio + 10) = ((~address & 0x0000ffff) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; - *(gpio + 7) = addr_l_s; - *(gpio + 10) = addr_l_r; + *(gpio + 7) = ((address >> 16) << 8); + *(gpio + 10) = ((~address >> 16) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; @@ -155,24 +137,19 @@ inline uint32_t read16(uint32_t address) { inline uint32_t read8(uint32_t address) { int val; - uint32_t addr_h_s = (address & 0x0000ffff) << 8; - uint32_t addr_h_r = (~address & 0x0000ffff) << 8; - uint32_t addr_l_s = (address >> 16) << 8; - uint32_t addr_l_r = (~address >> 16) << 8; - // asm volatile ("dmb" ::: "memory"); R8 *(gpio) = gpfsel0_o; *(gpio + 1) = gpfsel1_o; *(gpio + 2) = gpfsel2_o; - *(gpio + 7) = addr_h_s; - *(gpio + 10) = addr_h_r; + *(gpio + 7) = ((address & 0x0000ffff) << 8); + *(gpio + 10) = ((~address & 0x0000ffff) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; - *(gpio + 7) = addr_l_s; - *(gpio + 10) = addr_l_r; + *(gpio + 7) = ((address >> 16) << 8); + *(gpio + 10) = ((~address >> 16) << 8); GPIO_CLR = 1 << 7; GPIO_SET = 1 << 7; diff --git a/platforms/amiga/amiga-platform.c b/platforms/amiga/amiga-platform.c index 5eac5d7..acdb424 100644 --- a/platforms/amiga/amiga-platform.c +++ b/platforms/amiga/amiga-platform.c @@ -5,6 +5,7 @@ #include "amiga-autoconf.h" #include "amiga-registers.h" #include "../shared/rtc.h" +#include "rtg/rtg.h" int handle_register_read_amiga(unsigned int addr, unsigned char type, unsigned int *val); int handle_register_write_amiga(unsigned int addr, unsigned int value, unsigned char type); @@ -33,6 +34,8 @@ extern unsigned char cdtv_sram[32 * SIZE_KILO]; #define min(a, b) (a < b) ? a : b #define max(a, b) (a > b) ? a : b +static uint8_t rtg_enabled; + inline int custom_read_amiga(struct emulator_config *cfg, unsigned int addr, unsigned int *val, unsigned char type) { if (!ac_z2_done && addr >= AC_Z2_BASE && addr < AC_Z2_BASE + AC_SIZE) { if (ac_z2_pic_count == 0) { @@ -136,6 +139,13 @@ void adjust_ranges_amiga(struct emulator_config *cfg) { cfg->custom_low = min(cfg->custom_low, AC_Z3_BASE); cfg->custom_high = max(cfg->custom_high, AC_Z3_BASE + AC_SIZE); } + if (rtg_enabled) { + if (cfg->custom_low == 0) + cfg->custom_low = PIGFX_RTG_BASE; + else + cfg->custom_low = min(cfg->custom_low, PIGFX_RTG_BASE); + cfg->custom_high = max(cfg->custom_high, PIGFX_RTG_BASE + PIGFX_RTG_SIZE); + } printf("Platform custom range: %.8X-%.8X\n", cfg->custom_low, cfg->custom_high); printf("Platform mapped range: %.8X-%.8X\n", cfg->mapped_low, cfg->mapped_high); @@ -227,7 +237,7 @@ int setup_platform_amiga(struct emulator_config *cfg) { return 0; } -void setvar_amiga(char *var, char *val) { +void setvar_amiga(struct emulator_config *cfg, char *var, char *val) { if (!var) return; @@ -250,6 +260,11 @@ void setvar_amiga(char *var, char *val) { printf("[AMIGA] CDTV mode enabled.\n"); cdtv_mode = 1; } + if (strcmp(var, "rtg") == 0) { + printf("[AMIGA] RTG Enabled.\n"); + rtg_enabled = 1; + adjust_ranges_amiga(cfg); + } if (strcmp(var, "rtc_type") == 0) { if (val && strlen(val) != 0) { if (strcmp(val, "msm") == 0) { diff --git a/platforms/amiga/rtg/rtg.c b/platforms/amiga/rtg/rtg.c new file mode 100644 index 0000000..e26cabf --- /dev/null +++ b/platforms/amiga/rtg/rtg.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include "rtg.h" +#include "../../../config_file/config_file.h" + +static uint16_t palette[256]; +static uint8_t rtg_mem[64 * SIZE_MEGA]; // FIXME + +static uint8_t rtg_u8[4]; +static uint16_t rtg_x[3], rtg_y[3]; +static uint16_t rtg_format; +static uint32_t rtg_address[2]; +static uint32_t rtg_rgb[2]; + +static uint8_t rtg_enabled; + +uint16_t rtg_display_width, rtg_display_height; +uint16_t rtg_display_format; +uint16_t rtg_pitch, rtg_total_rows; +uint16_t rtg_offset_x, rtg_offset_y; + +uint32_t framebuffer_addr; + +static void handle_rtg_command(uint32_t cmd); + +static const char *op_type_names[OP_TYPE_NUM] = { + "BYTE", + "WORD", + "LONGWORD", + "MEM", +}; + +static const char *rtg_format_names[RTGFMT_NUM] = { + "8BPP CLUT", + "16BPP RGB (565)", + "32BPP RGB (RGBA)", + "15BPP RGB (555)", +}; + +unsigned int rtg_read(uint32_t address, uint8_t mode) { + //printf("%s read from RTG: %.8X\n", op_type_names[mode], address); + if (address >= PIGFX_REG_SIZE) { + if (rtg_mem) { + switch (mode) { + case OP_TYPE_BYTE: + return (rtg_mem[address - PIGFX_REG_SIZE]); + break; + case OP_TYPE_WORD: + return *(( uint16_t *) (&rtg_mem[address - PIGFX_REG_SIZE])); + break; + case OP_TYPE_LONGWORD: + return *(( uint32_t *) (&rtg_mem[address - PIGFX_REG_SIZE])); + break; + default: + return 0; + } + } + } + + return 0; +} + +void rtg_write(uint32_t address, uint32_t value, uint8_t mode) { + //printf("%s write to RTG: %.8X (%.8X)\n", op_type_names[mode], address, value); + if (address >= PIGFX_REG_SIZE) { + if (rtg_mem) { + switch (mode) { + case OP_TYPE_BYTE: + rtg_mem[address - PIGFX_REG_SIZE] = value; + break; + case OP_TYPE_WORD: + *(( uint16_t *) (&rtg_mem[address - PIGFX_REG_SIZE])) = value; + break; + case OP_TYPE_LONGWORD: + *(( uint32_t *) (&rtg_mem[address - PIGFX_REG_SIZE])) = value; + break; + default: + return; + } + } + } + else { + switch (mode) { + case OP_TYPE_BYTE: + switch (address) { + case RTG_U81: + case RTG_U82: + case RTG_U83: + case RTG_U84: + rtg_u8[address - RTG_U81] = value; + } + break; + case OP_TYPE_WORD: + switch (address) { + case RTG_X1: + rtg_x[0] = value; + break; + case RTG_X2: + rtg_x[1] = value; + break; + case RTG_X3: + rtg_x[2] = value; + break; + case RTG_Y1: + rtg_y[0] = value; + break; + case RTG_Y2: + rtg_y[1] = value; + break; + case RTG_Y3: + rtg_y[2] = value; + break; + case RTG_FORMAT: + rtg_format = value; + break; + case RTG_COMMAND: + handle_rtg_command(value); + break; + } + break; + case OP_TYPE_LONGWORD: + switch (address) { + case RTG_ADDR1: + rtg_address[0] = value; + break; + case RTG_ADDR2: + rtg_address[1] = value; + break; + case RTG_RGB1: + rtg_rgb[0] = value; + break; + case RTG_RGB2: + rtg_rgb[1] = value; + break; + } + break; + } + } + + return; +} + +static void handle_rtg_command(uint32_t cmd) { + //printf("Handling RTG command %d (%.8X)\n", cmd, cmd); + switch (cmd) { + case RTGCMD_SETGC: + rtg_display_format = rtg_format; + rtg_display_width = rtg_x[0]; + rtg_display_height = rtg_y[0]; + if (rtg_u8[0]) { + rtg_pitch = rtg_x[1]; + rtg_total_rows = rtg_y[1]; + } + else { + rtg_pitch = rtg_x[1]; + rtg_total_rows = rtg_y[1]; + } + //printf("Set RTG mode:\n"); + //printf("%dx%d pixels\n", rtg_display_width, rtg_display_height); + //printf("Pixel format: %s\n", rtg_format_names[rtg_display_format]); + break; + case RTGCMD_SETPAN: + //printf("Command: SetPan.\n"); + framebuffer_addr = rtg_address[0]; + rtg_offset_x = rtg_x[1]; + rtg_offset_y = rtg_y[1]; + rtg_pitch = (rtg_x[0] << rtg_display_format); + //printf("Set panning to $%.8X\n", framebuffer_addr); + //printf("Offset X/Y: %d/%d\n", rtg_offset_x, rtg_offset_y); + //printf("Pitch: %d (%d bytes)\n", rtg_x[0], rtg_pitch); + break; + case RTGCMD_SETCLUT: { + //printf("Command: SetCLUT.\n"); + //printf("Set palette entry %d to %d, %d, %d\n", rtg_u8[0], rtg_u8[1], rtg_u8[2], rtg_u8[3]); + int r = (int)((float)rtg_u8[1] / 255.0f * 31.0f); + int g = (int)((float)rtg_u8[2] / 255.0f * 63.0f); + int b = (int)((float)rtg_u8[3] / 255.0f * 31.0f); + palette[rtg_u8[0]] = ((r & 0x1F) << 11) | ((g & 0x3F) << 6) | ((b & 0x1F) << 6); + break; + } + case RTGCMD_SETDISPLAY: + //printf("Command: SetDisplay.\n"); + if (rtg_enabled != rtg_u8[1]) { + //printf("RTG Display %s\n", (rtg_u8[1]) ? "enabled" : "disabled"); + rtg_enabled = rtg_u8[1]; + //if (rtg_enabled) + //printf("%dx%d pixels\n", rtg_display_width, rtg_display_height); + } + break; + case RTGCMD_ENABLE: + case RTGCMD_SETSWITCH: + // Implementing this command only matters if the Pi is to pass through the analog (or digital) + // native video, otherwise this does nothing. + break; + } +} diff --git a/platforms/amiga/rtg/rtg.h b/platforms/amiga/rtg/rtg.h new file mode 100644 index 0000000..c90276d --- /dev/null +++ b/platforms/amiga/rtg/rtg.h @@ -0,0 +1,45 @@ +#define PIGFX_RTG_BASE 0x70000000 +#define PIGFX_RTG_SIZE 0x04000000 + +#define PIGFX_REG_SIZE 0x00010000 + +#define CARD_OFFSET 0 + +enum pi_regs { + RTG_COMMAND = CARD_OFFSET + 0x00, + RTG_X1 = CARD_OFFSET + 0x02, + RTG_X2 = CARD_OFFSET + 0x04, + RTG_X3 = CARD_OFFSET + 0x06, + RTG_Y1 = CARD_OFFSET + 0x08, + RTG_Y2 = CARD_OFFSET + 0x0A, + RTG_Y3 = CARD_OFFSET + 0x0C, + RTG_FORMAT = CARD_OFFSET + 0x0E, + RTG_RGB1 = CARD_OFFSET + 0x10, + RTG_RGB2 = CARD_OFFSET + 0x14, + RTG_ADDR1 = CARD_OFFSET + 0x18, + RTG_ADDR2 = CARD_OFFSET + 0x1C, + RTG_U81 = CARD_OFFSET + 0x20, + RTG_U82 = CARD_OFFSET + 0x21, + RTG_U83 = CARD_OFFSET + 0x22, + RTG_U84 = CARD_OFFSET + 0x23, +}; + +enum rtg_cmds { + RTGCMD_SETGC, + RTGCMD_SETPAN, + RTGCMD_SETCLUT, + RTGCMD_ENABLE, + RTGCMD_SETDISPLAY, + RTGCMD_SETSWITCH, +}; + +enum rtg_formats { + RTGFMT_8BIT, + RTGFMT_RBG565, + RTGFMT_RGB32, + RTGFMT_RGB555, + RTGFMT_NUM, +}; + +void rtg_write(uint32_t address, uint32_t value, uint8_t mode); +unsigned int rtg_read(uint32_t address, uint8_t mode); diff --git a/platforms/amiga/rtg/rtg_driver_amiga/boardinfo.h b/platforms/amiga/rtg/rtg_driver_amiga/boardinfo.h new file mode 100644 index 0000000..0d6e56e --- /dev/null +++ b/platforms/amiga/rtg/rtg_driver_amiga/boardinfo.h @@ -0,0 +1,658 @@ +#ifndef boardinfo_H +#define boardinfo_H + +#ifndef LIBRARIES_PICASSO96_H +#include +#endif + +#ifndef EXEC_INTERRUPTS_H +#include +#endif + +#ifndef EXEC_LIBRARIES_H +#include +#endif + +#ifndef EXEC_SEMAPHORES_H +#include +#endif + +#ifndef GRAPHICS_GFX_H +#include +#endif + +#ifndef GRAPHICS_VIEW_H +#include +#endif + +#ifndef DEVICES_TIMER_H +#include +#endif + +#ifndef settings_H +#include "settings.h" +#endif + +/* registerized parameters */ + +#ifdef __STORMGCC__ + #define ASM +#else + #ifdef __GNUC__ + #define ASM + #define __REGD0(x) x __asm("d0") + #define __REGD1(x) x __asm("d1") + #define __REGD2(x) x __asm("d2") + #define __REGD3(x) x __asm("d3") + #define __REGD4(x) x __asm("d4") + #define __REGD5(x) x __asm("d5") + #define __REGD6(x) x __asm("d6") + #define __REGD7(x) x __asm("d7") + #define __REGA0(x) x __asm("a0") + #define __REGA1(x) x __asm("a1") + #define __REGA2(x) x __asm("a2") + #define __REGA3(x) x __asm("a3") + #define __REGA4(x) x __asm("a4") + #define __REGA5(x) x __asm("a5") + #define __REGA6(x) x __asm("a6") + #define __REGA7(x) x __asm("a7") + #else + #define ASM + #define __REGD0(x) __reg("d0") x + #define __REGD1(x) __reg("d1") x + #define __REGD2(x) __reg("d2") x + #define __REGD3(x) __reg("d3") x + #define __REGD4(x) __reg("d4") x + #define __REGD5(x) __reg("d5") x + #define __REGD6(x) __reg("d6") x + #define __REGD7(x) __reg("d7") x + #define __REGA0(x) __reg("a0") x + #define __REGA1(x) __reg("a1") x + #define __REGA2(x) __reg("a2") x + #define __REGA3(x) __reg("a3") x + #define __REGA4(x) __reg("a4") x + #define __REGA5(x) __reg("a5") x + #define __REGA6(x) __reg("a6") x + #define __REGA7(x) __reg("a7") x + #endif +#endif + +/************************************************************************/ + +#define MAXSPRITEWIDTH 32 +#define MAXSPRITEHEIGHT 48 + +/************************************************************************/ + +#define DI_P96_INVALID 0x1000 +#define DI_P96_MONITOOL 0x2000 + +/************************************************************************/ +/* Types for BoardType Identification + */ +typedef enum { + BT_NoBoard, + BT_oMniBus, + BT_Graffity, + BT_CyberVision, + BT_Domino, + BT_Merlin, + BT_PicassoII, + BT_Piccolo, + BT_RetinaBLT, + BT_Spectrum, + BT_PicassoIV, + BT_PiccoloSD64, + BT_A2410, + BT_Pixel64, + BT_uaegfx, // 14 + BT_CVision3D, + BT_Altais, + BT_Prometheus, + BT_Mediator, + BT_powerfb, + BT_powerpci, + BT_CVisionPPC, + BT_GREX, + BT_Prototype7, + BT_Reserved, + BT_Reserved2, + BT_MNT_VA2000, + BT_MNT_ZZ9000, + BT_MaxBoardTypes +} BTYPE; + +/************************************************************************/ +/* Types for PaletteChipType Identification + */ +typedef enum { + PCT_Unknown, + PCT_S11483, // Sierra S11483: HiColor 15 bit, oMniBus, Domino + PCT_S15025, // Sierra S15025: TrueColor 32 bit, oMniBus + PCT_CirrusGD542x, // Cirrus GD542x internal: TrueColor 24 bit + PCT_Domino, // is in fact a Sierra S11483 + PCT_BT482, // BrookTree BT482: TrueColor 32 bit, Merlin + PCT_Music, // Music MU9C4910: TrueColor 24 bit, oMniBus + PCT_ICS5300, // ICS 5300: ...., Retina BLT Z3 + PCT_CirrusGD5446, // Cirrus GD5446 internal: TrueColor 24 bit + PCT_CirrusGD5434, // Cirrus GD5434 internal: TrueColor 32 bit + PCT_S3Trio64, // S3 Trio64 internal: TrueColor 32 bit + PCT_A2410_xxx, // A2410 DAC, *type unknown* + PCT_S3ViRGE, // S3 ViRGE internal: TrueColor 32 bit + PCT_3dfxVoodoo, // 3dfx Voodoo internal + PCT_TIPermedia2, // TexasInstruments TVP4020 Permedia2 internal + PCT_ATIRV100, // ATI Technologies Radeon/Radeon 7000 internal + PCT_reserved, + PCT_reserved2, + PCT_MNT_VA2000, + PCT_MNT_ZZ9000, + PCT_MaxPaletteChipTypes +} PCTYPE; + +/************************************************************************/ +/* Types for GraphicsControllerType Identification + */ +typedef enum { + GCT_Unknown, + GCT_ET4000, + GCT_ETW32, + GCT_CirrusGD542x, + GCT_NCR77C32BLT, + GCT_CirrusGD5446, + GCT_CirrusGD5434, + GCT_S3Trio64, + GCT_TI34010, + GCT_S3ViRGE, + GCT_3dfxVoodoo, + GCT_TIPermedia2, + GCT_ATIRV100, + GCT_reserved, + GCT_reserved2, + GCT_MNT_VA2000, + GCT_MNT_ZZ9000, + GCT_MaxGraphicsControllerTypes +} GCTYPE; + +/************************************************************************/ + +#define RGBFF_PLANAR RGBFF_NONE +#define RGBFF_CHUNKY RGBFF_CLUT + +#define RGBFB_PLANAR RGBFB_NONE +#define RGBFB_CHUNKY RGBFB_CLUT + +/************************************************************************/ + +enum{ + DPMS_ON, /* Full operation */ + DPMS_STANDBY, /* Optional state of minimal power reduction */ + DPMS_SUSPEND, /* Significant reduction of power consumption */ + DPMS_OFF /* Lowest level of power consumption */ +}; + +/************************************************************************/ + +struct CLUTEntry { + UBYTE Red; + UBYTE Green; + UBYTE Blue; +}; + +struct ColorIndexMapping { + ULONG ColorMask; + ULONG Colors[256]; +}; + +/************************************************************************/ + +struct GfxMemChunk { + struct MinNode Node; + char *Ptr; + ULONG Size; + BOOL Used; +}; + +/************************************************************************/ + +struct Template { + APTR Memory; + WORD BytesPerRow; + UBYTE XOffset; // 0 <= XOffset <= 15 + UBYTE DrawMode; + ULONG FgPen; + ULONG BgPen; +}; + +/************************************************************************/ + +struct Pattern { + APTR Memory; + UWORD XOffset, YOffset; + ULONG FgPen, BgPen; + UBYTE Size; // Width: 16, Height: (1<AllocBitMap() */ + +#define ABMA_Friend (TAG_USER+0) +#define ABMA_Depth (TAG_USER+1) +#define ABMA_RGBFormat (TAG_USER+2) +#define ABMA_Clear (TAG_USER+3) +#define ABMA_Displayable (TAG_USER+4) +#define ABMA_Visible (TAG_USER+5) +#define ABMA_NoMemory (TAG_USER+6) +#define ABMA_NoSprite (TAG_USER+7) +#define ABMA_Colors (TAG_USER+8) +#define ABMA_Colors32 (TAG_USER+9) +#define ABMA_ModeWidth (TAG_USER+10) +#define ABMA_ModeHeight (TAG_USER+11) +#define ABMA_RenderFunc (TAG_USER+12) +#define ABMA_SaveFunc (TAG_USER+13) +#define ABMA_UserData (TAG_USER+14) +#define ABMA_Alignment (TAG_USER+15) +#define ABMA_ConstantBytesPerRow (TAG_USER+16) +#define ABMA_UserPrivate (TAG_USER+17) +#define ABMA_ConstantByteSwapping (TAG_USER+18) +/* + * THOR: New for V45 Gfx/Intuiton + * "by accident", this is identically to SA_DisplayID of intuition + * resp. SA_Behind, SA_Colors, SA_Colors32 + */ +#define ABMA_DisplayID (TAG_USER + 32 + 0x12) +#define ABMA_BitmapInvisible (TAG_USER + 32 + 0x17) +#define ABMA_BitmapColors (TAG_USER + 32 + 0x09) +#define ABMA_BitmapColors32 (TAG_USER + 32 + 0x23) + +/************************************************************************/ + +/* Tags for bi->GetBitMapAttr() */ + +#define GBMA_MEMORY (TAG_USER+0) +#define GBMA_BASEMEMORY (TAG_USER+1) +#define GBMA_BYTESPERROW (TAG_USER+2) +#define GBMA_BYTESPERPIXEL (TAG_USER+3) +#define GBMA_BITSPERPIXEL (TAG_USER+4) +#define GBMA_RGBFORMAT (TAG_USER+6) +#define GBMA_WIDTH (TAG_USER+7) +#define GBMA_HEIGHT (TAG_USER+8) +#define GBMA_DEPTH (TAG_USER+9) + +/************************************************************************/ + +struct BoardInfo{ + UBYTE *RegisterBase, *MemoryBase, *MemoryIOBase; + ULONG MemorySize; + char *BoardName,VBIName[32]; + struct CardBase *CardBase; + struct ChipBase *ChipBase; + struct ExecBase *ExecBase; + struct Library *UtilBase; + struct Interrupt HardInterrupt; + struct Interrupt SoftInterrupt; + struct SignalSemaphore BoardLock; + struct MinList ResolutionsList; + BTYPE BoardType; + PCTYPE PaletteChipType; + GCTYPE GraphicsControllerType; + UWORD MoniSwitch; + UWORD BitsPerCannon; + ULONG Flags; + UWORD SoftSpriteFlags; + UWORD ChipFlags; // private, chip specific, not touched by RTG + ULONG CardFlags; // private, card specific, not touched by RTG + + UWORD BoardNum; // set by rtg.library + UWORD RGBFormats; + + UWORD MaxHorValue[MAXMODES]; + UWORD MaxVerValue[MAXMODES]; + UWORD MaxHorResolution[MAXMODES]; + UWORD MaxVerResolution[MAXMODES]; + ULONG MaxMemorySize, MaxChunkSize; + + ULONG MemoryClock; + + ULONG PixelClockCount[MAXMODES]; + + APTR ASM (*AllocCardMem)(__REGA0(struct BoardInfo *bi), __REGD0(ULONG size), __REGD1(BOOL force), __REGD2(BOOL system)); + BOOL ASM (*FreeCardMem)(__REGA0(struct BoardInfo *bi), __REGA1(APTR membase)); + + BOOL ASM (*SetSwitch)(__REGA0(struct BoardInfo *), __REGD0(BOOL)); + + void ASM (*SetColorArray)(__REGA0(struct BoardInfo *), __REGD0(UWORD), __REGD1(UWORD)); + + void ASM (*SetDAC)(__REGA0(struct BoardInfo *), __REGD7(RGBFTYPE)); + void ASM (*SetGC)(__REGA0(struct BoardInfo *), __REGA1(struct ModeInfo *), __REGD0(BOOL)); + void ASM (*SetPanning)(__REGA0(struct BoardInfo *), __REGA1(UBYTE *), __REGD0(UWORD), __REGD1(WORD), __REGD2(WORD), __REGD7(RGBFTYPE)); + UWORD ASM (*CalculateBytesPerRow)(__REGA0(struct BoardInfo *), __REGD0(UWORD), __REGD7(RGBFTYPE)); + APTR ASM (*CalculateMemory)(__REGA0(struct BoardInfo *), __REGA1(APTR), __REGD7(RGBFTYPE)); + ULONG ASM (*GetCompatibleFormats)(__REGA0(struct BoardInfo *), __REGD7(RGBFTYPE)); + BOOL ASM (*SetDisplay)(__REGA0(struct BoardInfo *), __REGD0(BOOL)); + + LONG ASM (*ResolvePixelClock)(__REGA0(struct BoardInfo *), __REGA1(struct ModeInfo *), __REGD0(ULONG), __REGD7(RGBFTYPE)); + ULONG ASM (*GetPixelClock)(__REGA0(struct BoardInfo *bi), __REGA1(struct ModeInfo *), __REGD0(ULONG), __REGD7(RGBFTYPE)); + void ASM (*SetClock)(__REGA0(struct BoardInfo *)); + + void ASM (*SetMemoryMode)(__REGA0(struct BoardInfo *), __REGD7(RGBFTYPE)); + void ASM (*SetWriteMask)(__REGA0(struct BoardInfo *), __REGD0(UBYTE)); + void ASM (*SetClearMask)(__REGA0(struct BoardInfo *), __REGD0(UBYTE)); + void ASM (*SetReadPlane)(__REGA0(struct BoardInfo *), __REGD0(UBYTE)); + + void ASM (*WaitVerticalSync)(__REGA0(struct BoardInfo *), __REGD0(BOOL)); + BOOL ASM (*SetInterrupt)(__REGA0(struct BoardInfo *), __REGD0(BOOL)); + + void ASM (*WaitBlitter)(__REGA0(struct BoardInfo *)); + + void ASM (*ScrollPlanar)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(UWORD), __REGD1(UWORD), __REGD2(UWORD), __REGD3(UWORD), __REGD4(UWORD), __REGD5(UWORD), __REGD6(UBYTE)); + void ASM (*ScrollPlanarDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(UWORD), __REGD1(UWORD), __REGD2(UWORD), __REGD3(UWORD), __REGD4(UWORD), __REGD5(UWORD), __REGD6(UBYTE)); + void ASM (*UpdatePlanar)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct RenderInfo *), __REGD0(SHORT), __REGD1(SHORT), __REGD2(SHORT), __REGD3(SHORT), __REGD4(UBYTE)); + void ASM (*UpdatePlanarDefault)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct RenderInfo *), __REGD0(SHORT), __REGD1(SHORT), __REGD2(SHORT), __REGD3(SHORT), __REGD4(UBYTE)); + void ASM (*BlitPlanar2Chunky)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct RenderInfo *), __REGD0(SHORT), __REGD1(SHORT), __REGD2(SHORT), __REGD3(SHORT), __REGD4(SHORT), __REGD5(SHORT), __REGD6(UBYTE), __REGD7(UBYTE)); + void ASM (*BlitPlanar2ChunkyDefault)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct RenderInfo *), __REGD0(SHORT), __REGD1(SHORT), __REGD2(SHORT), __REGD3(SHORT), __REGD4(SHORT), __REGD5(SHORT), __REGD6(UBYTE), __REGD7(UBYTE)); + + void ASM (*FillRect)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(ULONG), __REGD5(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*FillRectDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(ULONG), __REGD5(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*InvertRect)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*InvertRectDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitRect)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(WORD), __REGD5(WORD), __REGD6(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitRectDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(WORD), __REGD5(WORD), __REGD6(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitTemplate)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct Template *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitTemplateDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct Template *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitPattern)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct Pattern *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitPatternDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct Pattern *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*DrawLine)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct Line *), __REGD0(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*DrawLineDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct Line *), __REGD0(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitRectNoMaskComplete)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(WORD), __REGD5(WORD), __REGD6(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitRectNoMaskCompleteDefault)(__REGA0(struct BoardInfo *), __REGA1(struct RenderInfo *), __REGA2(struct RenderInfo *), __REGD0(WORD), __REGD1(WORD), __REGD2(WORD), __REGD3(WORD), __REGD4(WORD), __REGD5(WORD), __REGD6(UBYTE), __REGD7(RGBFTYPE)); + void ASM (*BlitPlanar2Direct)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct RenderInfo *), __REGA3(struct ColorIndexMapping *), __REGD0(SHORT), __REGD1(SHORT), __REGD2(SHORT), __REGD3(SHORT), __REGD4(SHORT), __REGD5(SHORT), __REGD6(UBYTE), __REGD7(UBYTE)); + void ASM (*BlitPlanar2DirectDefault)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct RenderInfo *), __REGA3(struct ColorIndexMapping *), __REGD0(SHORT), __REGD1(SHORT), __REGD2(SHORT), __REGD3(SHORT), __REGD4(SHORT), __REGD5(SHORT), __REGD6(UBYTE), __REGD7(UBYTE)); + BOOL ASM (*EnableSoftSprite)(__REGA0(struct BoardInfo *),__REGD0(ULONG formatflags),__REGA1(struct ModeInfo *)); + BOOL ASM (*EnableSoftSpriteDefault)(__REGA0(struct BoardInfo *),__REGD0(ULONG formatflags),__REGA1(struct ModeInfo *)); + APTR ASM (*AllocCardMemAbs)(__REGA0(struct BoardInfo *),__REGD0(ULONG size), __REGA1(char *target)); + void ASM (*SetSplitPosition)(__REGA0(struct BoardInfo *),__REGD0(SHORT)); + void ASM (*ReInitMemory)(__REGA0(struct BoardInfo *),__REGD0(RGBFTYPE)); + void ASM (*Reserved2Default)(__REGA0(struct BoardInfo *)); + void ASM (*Reserved3)(__REGA0(struct BoardInfo *)); + void ASM (*Reserved3Default)(__REGA0(struct BoardInfo *)); + + int ASM (*WriteYUVRect)(__REGA0(struct BoardInfo *), __REGA1(APTR), __REGD0(SHORT), __REGD1(SHORT), __REGA2(struct RenderInfo *), __REGD2(SHORT), __REGD3(SHORT), __REGD4(SHORT), __REGD5(SHORT), __REGA3(struct TagItem *)); + int ASM (*WriteYUVRectDefault)(__REGA0(struct BoardInfo *), __REGA1(APTR), __REGD0(SHORT), __REGD1(SHORT), __REGA2(struct RenderInfo *), __REGD2(SHORT), __REGD3(SHORT), __REGD4(SHORT), __REGD5(SHORT), __REGA3(struct TagItem *)); + + BOOL ASM (*GetVSyncState)(__REGA0(struct BoardInfo *), __REGD0(BOOL)); + ULONG ASM (*GetVBeamPos)(__REGA0(struct BoardInfo *)); + void ASM (*SetDPMSLevel)(__REGA0(struct BoardInfo *), __REGD0(ULONG)); + void ASM (*ResetChip)(__REGA0(struct BoardInfo *)); + ULONG ASM (*GetFeatureAttrs)(__REGA0(struct BoardInfo *), __REGA1(APTR), __REGD0(ULONG), __REGA2(struct TagItem *)); + + struct BitMap * ASM (*AllocBitMap)(__REGA0(struct BoardInfo *), __REGD0(ULONG), __REGD1(ULONG), __REGA1(struct TagItem *)); + BOOL ASM (*FreeBitMap)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGA2(struct TagItem *)); + ULONG ASM (*GetBitMapAttr)(__REGA0(struct BoardInfo *), __REGA1(struct BitMap *), __REGD0(ULONG)); + + BOOL ASM (*SetSprite)(__REGA0(struct BoardInfo *), __REGD0(BOOL), __REGD7(RGBFTYPE)); + void ASM (*SetSpritePosition)(__REGA0(struct BoardInfo *), __REGD0(WORD), __REGD1(WORD), __REGD7(RGBFTYPE)); + void ASM (*SetSpriteImage)(__REGA0(struct BoardInfo *), __REGD7(RGBFTYPE)); + void ASM (*SetSpriteColor)(__REGA0(struct BoardInfo *), __REGD0(UBYTE), __REGD1(UBYTE), __REGD2(UBYTE), __REGD3(UBYTE), __REGD7(RGBFTYPE)); + + APTR ASM (*CreateFeature)(__REGA0(struct BoardInfo *), __REGD0(ULONG), __REGA1(struct TagItem *)); + ULONG ASM (*SetFeatureAttrs)(__REGA0(struct BoardInfo *), __REGA1(APTR), __REGD0(ULONG), __REGA2(struct TagItem *)); + BOOL ASM (*DeleteFeature)(__REGA0(struct BoardInfo *), __REGA1(APTR), __REGD0(ULONG)); + struct MinList SpecialFeatures; + + struct ModeInfo *ModeInfo; /* Chip Settings Stuff */ + RGBFTYPE RGBFormat; + WORD XOffset; + WORD YOffset; + UBYTE Depth; + UBYTE ClearMask; + BOOL Border; + ULONG Mask; + struct CLUTEntry CLUT[256]; + + struct ViewPort *ViewPort; /* ViewPort Stuff */ + struct BitMap *VisibleBitMap; + struct BitMapExtra *BitMapExtra; + struct MinList BitMapList; + struct MinList MemList; + + WORD MouseX; + WORD MouseY; /* Sprite Stuff */ + UBYTE MouseWidth; + UBYTE MouseHeight; + UBYTE MouseXOffset; + UBYTE MouseYOffset; + UWORD *MouseImage; + UBYTE MousePens[4]; + struct Rectangle MouseRect; + UBYTE *MouseChunky; + UWORD *MouseRendered; + UBYTE *MouseSaveBuffer; + + ULONG ChipData[16]; /* for chip driver needs */ + ULONG CardData[16]; /* for card driver needs */ + + APTR MemorySpaceBase; /* the base address of the board memory address space */ + ULONG MemorySpaceSize; /* size of that area */ + + APTR DoubleBufferList; /* chain of dbinfos being notified on vblanks */ + + struct timeval SyncTime; /* system time when screen was set up, used for pseudo vblanks */ + ULONG SyncPeriod; /* length of one frame in micros */ + struct MsgPort SoftVBlankPort; /* MsgPort for software emulation of board interrupt */ + + struct MinList WaitQ; /* for WaitTOF and WaitBOVP, all elements will be signaled on VBlank */ + + LONG EssentialFormats; /* these RGBFormats will be used when user does not choose "all" + will be filled by InitBoard() */ + UBYTE *MouseImageBuffer; /* rendered to the destination color format */ + /* Additional viewport stuff */ + struct ViewPort *backViewPort; /* The view port visible on the screen behind */ + struct BitMap *backBitMap; /* Its bitmap */ + struct BitMapExtra *backExtra; /* its bitmapExtra */ + WORD YSplit; + ULONG MaxPlanarMemory; /* Size of a bitplane if planar. If left blank, MemorySize>>2 */ + ULONG MaxBMWidth; /* Maximum width of a bitmap */ + ULONG MaxBMHeight; /* Maximum height of a bitmap */ +}; + +/* BoardInfo flags */ +/* 0-15: hardware flags */ +/* 16-31: user flags */ +#define BIB_HARDWARESPRITE 0 /* board has hardware sprite */ +#define BIB_NOMEMORYMODEMIX 1 /* board does not support modifying planar bitmaps while displaying chunky and vice versa */ +#define BIB_NEEDSALIGNMENT 2 /* bitmaps have to be aligned (not yet supported!) */ +#define BIB_CACHEMODECHANGE 3 /* board memory may be set to Imprecise (060) or Nonserialised (040) */ +#define BIB_VBLANKINTERRUPT 4 /* board can cause a hardware interrupt on a vertical retrace */ +#define BIB_HASSPRITEBUFFER 5 /* board has allocated memory for software sprite image and save buffer */ + +#define BIB_VGASCREENSPLIT 6 /* has a screen B with fixed screen position for split-screens */ + +#define BIB_DBLSCANDBLSPRITEY 8 /* hardware sprite y position is doubled on doublescan display modes */ +#define BIB_ILACEHALFSPRITEY 9 /* hardware sprite y position is halved on interlace display modes */ +#define BIB_ILACEDBLROWOFFSET 10 /* doubled row offset in interlaced display modes needs additional horizontal bit */ +#define BIB_INTERNALMODESONLY 11 /* board creates its resolutions and modes automatically and does not support user setting files (UAE) */ +#define BIB_FLICKERFIXER 12 /* board can flicker fix Amiga RGB signal */ +#define BIB_VIDEOCAPTURE 13 /* board can capture video data to a memory area */ +#define BIB_VIDEOWINDOW 14 /* board can display a second mem area as a pip */ +#define BIB_BLITTER 15 /* board has blitter */ + +#define BIB_HIRESSPRITE 16 /* mouse sprite has double resolution */ +#define BIB_BIGSPRITE 17 /* user wants big mouse sprite */ +#define BIB_BORDEROVERRIDE 18 /* user wants to override system overscan border prefs */ +#define BIB_BORDERBLANK 19 /* user wants border blanking */ +#define BIB_INDISPLAYCHAIN 20 /* board switches Amiga signal */ +#define BIB_QUIET 21 /* not yet implemented */ +#define BIB_NOMASKBLITS 22 /* perform blits without taking care of mask */ +#define BIB_NOP2CBLITS 23 /* use CPU for planar to chunky conversions */ +#define BIB_NOBLITTER 24 /* disable all blitter functions */ +#define BIB_SYSTEM2SCREENBLITS 25 /* allow data to be written to screen memory for cpu as blitter source */ +#define BIB_GRANTDIRECTACCESS 26 /* all data on the board can be accessed at any time without bi->SetMemoryMode() */ + +#define BIB_OVERCLOCK 31 /* enable overclocking for some boards */ + +#define BIB_IGNOREMASK BIB_NOMASKBLITS + +#define BIF_HARDWARESPRITE (1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "boardinfo.h" + +#define WRITESHORT(cmd, val) *(unsigned short *)((unsigned int)(b->RegisterBase)+cmd) = val; +#define WRITELONG(cmd, val) *(unsigned int *)((unsigned int)(b->RegisterBase)+cmd) = val; +#define WRITEBYTE(cmd, val) *(unsigned char *)((unsigned int)(b->RegisterBase)+cmd) = val; + +#define CARD_OFFSET 0x70000000 +#define CARD_REGSIZE 0x00010000 +// 32MB "VRAM" +#define CARD_MEMSIZE 0x02000000 + +// "Register" offsets for sending data to the RTG. +enum pi_regs { + RTG_COMMAND = 0x00, + RTG_X1 = 0x02, + RTG_X2 = 0x04, + RTG_X3 = 0x06, + RTG_Y1 = 0x08, + RTG_Y2 = 0x0A, + RTG_Y3 = 0x0C, + RTG_FORMAT = 0x0E, + RTG_RGB1 = 0x10, + RTG_RGB2 = 0x14, + RTG_ADDR1 = 0x18, + RTG_ADDR2 = 0x1C, + RTG_U81 = 0x20, + RTG_U82 = 0x21, + RTG_U83 = 0x22, + RTG_U84 = 0x23, +}; + +enum rtg_cmds { + RTGCMD_SETGC, + RTGCMD_SETPAN, + RTGCMD_SETCLUT, + RTGCMD_ENABLE, + RTGCMD_SETDISPLAY, + RTGCMD_SETSWITCH, +}; + +enum rtg_formats { + RTGFMT_8BIT, + RTGFMT_RBG565, + RTGFMT_RGB32, + RTGFMT_RGB555, +}; + +const unsigned short rgbf_to_rtg[16] = { + RTGFMT_8BIT, // 0x00 + RTGFMT_8BIT, // 0x01 + 0, // 0x02 + 0, // 0x03 + 0, // 0x04 + RTGFMT_RGB555, // 0x05 + 0, // 0x06 + 0, // 0x07 + RTGFMT_RGB32, // 0x08 + RTGFMT_RGB32, // 0x09 + RTGFMT_RBG565, // 0x0A + RTGFMT_RGB555, // 0x0B + 0, // 0x0C + RTGFMT_RGB555, // 0x0D + 0, // 0x0E + 0, // 0x0F +}; + +struct GFXBase { + struct Library libNode; + BPTR segList; + struct ExecBase* sysBase; + struct ExpansionBase* expansionBase; +}; + +int FindCard(__REGA0(struct BoardInfo* b)); +int InitCard(__REGA0(struct BoardInfo* b)); + +void SetDAC (__REGA0(struct BoardInfo *b), __REGD7(RGBFTYPE format)); +void SetGC (__REGA0(struct BoardInfo *b), __REGA1(struct ModeInfo *mode_info), __REGD0(BOOL border)); +void SetColorArray (__REGA0(struct BoardInfo *b), __REGD0(UWORD start), __REGD1(UWORD num)); +void SetPanning (__REGA0(struct BoardInfo *b), __REGA1(UBYTE *addr), __REGD0(UWORD width), __REGD1(WORD x_offset), __REGD2(WORD y_offset), __REGD7(RGBFTYPE format)); +BOOL SetSwitch (__REGA0(struct BoardInfo *b), __REGD0(BOOL enabled)); +BOOL SetDisplay (__REGA0(struct BoardInfo *b), __REGD0(BOOL enabled)); + +UWORD CalculateBytesPerRow (__REGA0(struct BoardInfo *b), __REGD0(UWORD width), __REGD7(RGBFTYPE format)); +APTR CalculateMemory (__REGA0(struct BoardInfo *b), __REGA1(unsigned int addr), __REGD7(RGBFTYPE format)); +ULONG GetCompatibleFormats (__REGA0(struct BoardInfo *b), __REGD7(RGBFTYPE format)); + +LONG ResolvePixelClock (__REGA0(struct BoardInfo *b), __REGA1(struct ModeInfo *mode_info), __REGD0(ULONG pixel_clock), __REGD7(RGBFTYPE format)); +ULONG GetPixelClock (__REGA0(struct BoardInfo *b), __REGA1(struct ModeInfo *mode_info), __REGD0(ULONG index), __REGD7(RGBFTYPE format)); +void SetClock (__REGA0(struct BoardInfo *b)); + +void SetMemoryMode (__REGA0(struct BoardInfo *b), __REGD7(RGBFTYPE format)); +void SetWriteMask (__REGA0(struct BoardInfo *b), __REGD0(UBYTE mask)); +void SetClearMask (__REGA0(struct BoardInfo *b), __REGD0(UBYTE mask)); +void SetReadPlane (__REGA0(struct BoardInfo *b), __REGD0(UBYTE plane)); + +void WaitVerticalSync (__REGA0(struct BoardInfo *b), __REGD0(BOOL toggle)); + +static ULONG LibStart(void) { + return(-1); +} + +static const char LibraryName[] = "PiRTG.card"; +static const char LibraryID[] = "$VER: PiRTG.card 0.01\r\n"; + +__saveds struct GFXBase* OpenLib(__REGA6(struct GFXBase *gfxbase)); +BPTR __saveds CloseLib(__REGA6(struct GFXBase *gfxbase)); +BPTR __saveds ExpungeLib(__REGA6(struct GFXBase *exb)); +ULONG ExtFuncLib(void); +__saveds struct GFXBase* InitLib(__REGA6(struct ExecBase *sysbase), + __REGA0(BPTR seglist), + __REGD0(struct GFXBase *exb)); + +static const APTR FuncTab[] = { + (APTR)OpenLib, + (APTR)CloseLib, + (APTR)ExpungeLib, + (APTR)ExtFuncLib, + + (APTR)FindCard, + (APTR)InitCard, + (APTR)((LONG)-1) +}; + +struct InitTable +{ + ULONG LibBaseSize; + APTR FunctionTable; + APTR DataTable; + APTR InitLibTable; +}; + +static struct InitTable InitTab = { + (ULONG) sizeof(struct GFXBase), + (APTR) FuncTab, + (APTR) NULL, + (APTR) InitLib +}; + +static const struct Resident ROMTag = { + RTC_MATCHWORD, + &ROMTag, + &ROMTag + 1, + RTF_AUTOINIT, + 83, + NT_LIBRARY, + 0, + (char *)LibraryName, + (char *)LibraryID, + (APTR)&InitTab +}; + +#define CLOCK_HZ 100000000 + +static struct GFXBase *_gfxbase; +const char *gfxname = "PiStorm RTG"; +char dummies[128]; + +__saveds struct GFXBase* InitLib(__REGA6(struct ExecBase *sysbase), + __REGA0(BPTR seglist), + __REGD0(struct GFXBase *exb)) +{ + _gfxbase = exb; + return _gfxbase; +} + +__saveds struct GFXBase* OpenLib(__REGA6(struct GFXBase *gfxbase)) +{ + gfxbase->libNode.lib_OpenCnt++; + gfxbase->libNode.lib_Flags &= ~LIBF_DELEXP; + + return gfxbase; +} + +BPTR __saveds CloseLib(__REGA6(struct GFXBase *gfxbase)) +{ + gfxbase->libNode.lib_OpenCnt--; + + if (!gfxbase->libNode.lib_OpenCnt) { + if (gfxbase->libNode.lib_Flags & LIBF_DELEXP) { + return (ExpungeLib(gfxbase)); + } + } + return 0; +} + +BPTR __saveds ExpungeLib(__REGA6(struct GFXBase *exb)) +{ + BPTR seglist; + struct ExecBase *SysBase = *(struct ExecBase **)4L; + + if(!exb->libNode.lib_OpenCnt) { + ULONG negsize, possize, fullsize; + UBYTE *negptr = (UBYTE *)exb; + + seglist = exb->segList; + + Remove((struct Node *)exb); + + negsize = exb->libNode.lib_NegSize; + possize = exb->libNode.lib_PosSize; + fullsize = negsize + possize; + negptr -= negsize; + + FreeMem(negptr, fullsize); + return(seglist); + } + + exb->libNode.lib_Flags |= LIBF_DELEXP; + return 0; +} + +ULONG ExtFuncLib(void) +{ + return 0; +} + +static LONG zorro_version = 0; + +static struct GFXData *gfxdata; +//MNTZZ9KRegs* registers; + +#define LOADLIB(a, b) if ((a = (struct a*)OpenLibrary(b,0L))==NULL) { \ + KPrintF("Failed to load %s.\n", b); \ + return 0; \ + } \ + +static BYTE card_already_found; +static BYTE card_initialized; + +int FindCard(__REGA0(struct BoardInfo* b)) { + //if (card_already_found) +// return 1; + struct ConfigDev* cd = NULL; + struct ExpansionBase *ExpansionBase = NULL; + struct DOSBase *DOSBase = NULL; + struct IntuitionBase *IntuitionBase = NULL; + struct ExecBase *SysBase = *(struct ExecBase **)4L; + + LOADLIB(ExpansionBase, "expansion.library"); + LOADLIB(DOSBase, "dos.library"); + LOADLIB(IntuitionBase, "intuition.library"); + + b->MemorySize = CARD_MEMSIZE; + b->RegisterBase = (void *)CARD_OFFSET; + b->MemoryBase = (void *)(CARD_OFFSET + CARD_REGSIZE); + + return 1; +} + +#define HWSPRITE 1 +#define VGASPLIT (1 << 6) +#define FLICKERFIXER (1 << 12) +#define INDISPLAYCHAIN (1 << 20) +#define DIRECTACCESS (1 << 26) + +int InitCard(__REGA0(struct BoardInfo* b)) { + //if (!card_initialized) +// card_initialized = 1; +// else + //return 1; + + int max, i; + struct ExecBase *SysBase = *(struct ExecBase **)4L; + + b->CardBase = (struct CardBase *)_gfxbase; + b->ExecBase = SysBase; + b->BoardName = "PiStorm RTG"; + b->BoardType = BT_MNT_ZZ9000; + b->PaletteChipType = PCT_MNT_ZZ9000; + b->GraphicsControllerType = GCT_MNT_ZZ9000; + + b->Flags = BIF_INDISPLAYCHAIN | BIF_GRANTDIRECTACCESS; + b->RGBFormats = 1 | 2 | 512 | 1024 | 2048; + b->SoftSpriteFlags = 0; + b->BitsPerCannon = 8; + + for(i = 0; i < MAXMODES; i++) { + b->MaxHorValue[i] = 1920; + b->MaxVerValue[i] = 1080; + b->MaxHorResolution[i] = 1920; + b->MaxVerResolution[i] = 1080; + b->PixelClockCount[i] = 1; + } + + b->MemoryClock = CLOCK_HZ; + + //b->AllocCardMem = (void *)NULL; + //b->FreeCardMem = (void *)NULL; + b->SetSwitch = (void *)SetSwitch; + b->SetColorArray = (void *)SetColorArray; + b->SetDAC = (void *)SetDAC; + b->SetGC = (void *)SetGC; + b->SetPanning = (void *)SetPanning; + b->CalculateBytesPerRow = (void *)CalculateBytesPerRow; + b->CalculateMemory = (void *)CalculateMemory; + b->GetCompatibleFormats = (void *)GetCompatibleFormats; + b->SetDisplay = (void *)SetDisplay; + + b->ResolvePixelClock = (void *)ResolvePixelClock; + b->GetPixelClock = (void *)GetPixelClock; + b->SetClock = (void *)SetClock; + + b->SetMemoryMode = (void *)SetMemoryMode; + b->SetWriteMask = (void *)SetWriteMask; + b->SetClearMask = (void *)SetClearMask; + b->SetReadPlane = (void *)SetReadPlane; + + b->WaitVerticalSync = (void *)WaitVerticalSync; + //b->SetInterrupt = (void *)NULL; + + //b->WaitBlitter = (void *)NULL; + + //b->ScrollPlanar = (void *)NULL; + //b->UpdatePlanar = (void *)NULL; + + //b->BlitPlanar2Chunky = (void *)NULL; + //b->BlitPlanar2Direct = (void *)NULL; + + //b->FillRect = (void *)NULL; + //b->InvertRect = (void *)NULL; + //b->BlitRect = (void *)NULL; + //b->BlitTemplate = (void *)NULL; + //b->BlitPattern = (void *)NULL; + //b->DrawLine = (void *)NULL; + //b->BlitRectNoMaskComplete = (void *)NULL; + //b->EnableSoftSprite = (void *)NULL; + + //b->AllocCardMemAbs = (void *)NULL; + //b->SetSplitPosition = (void *)NULL; + //b->ReInitMemory = (void *)NULL; + //b->WriteYUVRect = (void *)NULL; + //b->GetVSyncState = (void *)NULL; + //b->GetVBeamPos = (void *)NULL; + //b->SetDPMSLevel = (void *)NULL; + //b->ResetChip = (void *)NULL; + //b->GetFeatureAttrs = (void *)NULL; + //b->AllocBitMap = (void *)NULL; + //b->FreeBitMap = (void *)NULL; + //b->GetBitMapAttr = (void *)NULL; + + //b->SetSprite = (void *)NULL; + //b->SetSpritePosition = (void *)NULL; + //b->SetSpriteImage = (void *)NULL; + //b->SetSpriteColor = (void *)NULL; + + //b->CreateFeature = (void *)NULL; + //b->SetFeatureAttrs = (void *)NULL; + //b->DeleteFeature = (void *)NULL; + + return 1; +} + +void SetDAC (__REGA0(struct BoardInfo *b), __REGD7(RGBFTYPE format)) { + WRITESHORT(RTGCMD_SETPAN, 0x0001); + // Used to set the color format of the video card's RAMDAC. + // This needs no handling, since the PiStorm doesn't really have a RAMDAC or a video card chipset. +} + +void SetGC (__REGA0(struct BoardInfo *b), __REGA1(struct ModeInfo *mode_info), __REGD0(BOOL border)) { + WRITESHORT(RTGCMD_SETPAN, 0x0002); + b->ModeInfo = mode_info; + // Send width, height and format to the RaspberryPi Targetable Graphics. + WRITESHORT(RTG_X1, mode_info->Width); + WRITESHORT(RTG_Y1, mode_info->Height); + WRITESHORT(RTG_FORMAT, rgbf_to_rtg[b->RGBFormat]); + WRITESHORT(RTG_COMMAND, RTGCMD_SETGC); +} + +int setswitch = 0; +int old_setswitch = -1; +BOOL SetSwitch (__REGA0(struct BoardInfo *b), __REGD0(BOOL enabled)) { + WRITESHORT(RTGCMD_SETPAN, 0x0003); + // Called when enabling/disabling the native Amiga video passthrough something. + // Doesn't need to do anything for now. + if (old_setswitch == -1) + old_setswitch = enabled; + else + old_setswitch = setswitch; + + setswitch = enabled; + if (old_setswitch != enabled) { + //WRITEBYTE(RTG_U81, (unsigned char)enabled); + //WRITESHORT(RTG_COMMAND, RTGCMD_SETSWITCH); + } + + return old_setswitch; +} + +void SetPanning (__REGA0(struct BoardInfo *b), __REGA1(UBYTE *addr), __REGD0(UWORD width), __REGD1(WORD x_offset), __REGD2(WORD y_offset), __REGD7(RGBFTYPE format)) { + WRITESHORT(RTGCMD_SETPAN, 0x0004); + // Set the panning offset, or the offset used for the current display area on the Pi. + // The address needs to have CARD_BASE subtracted from it to be used as an offset on the Pi side. + if (!b) + return; + + b->XOffset = x_offset; + b->YOffset = y_offset; + + WRITELONG(RTG_ADDR1, (unsigned int)addr); + WRITESHORT(RTG_X1, width); + WRITESHORT(RTG_X2, b->XOffset); + WRITESHORT(RTG_Y2, b->YOffset); + WRITESHORT(RTG_COMMAND, RTGCMD_SETPAN); +} + +void SetColorArray (__REGA0(struct BoardInfo *b), __REGD0(UWORD start), __REGD1(UWORD num)) { + // Sets the color components of X color components for 8-bit paletted display modes. + if (!b->CLUT) + return; + for(int i = start; i < num; i++) { + WRITEBYTE(RTG_U81, (unsigned char)i); + WRITEBYTE(RTG_U82, (unsigned char)b->CLUT[i].Red); + WRITEBYTE(RTG_U83, (unsigned char)b->CLUT[i].Green); + WRITEBYTE(RTG_U84, (unsigned char)b->CLUT[i].Blue); + WRITESHORT(RTG_COMMAND, RTGCMD_SETCLUT); + } +} + +UWORD CalculateBytesPerRow (__REGA0(struct BoardInfo *b), __REGD0(UWORD width), __REGD7(RGBFTYPE format)) { + WRITESHORT(RTGCMD_SETPAN, 0x0006); + if (!b) + return 0; + + UWORD pitch = width; + + switch(format) { + default: + return pitch; + case 0x05: case 0x0A: case 0x0B: case 0x0D: + return (width * 2); + case 0x08: case 0x09: + return (width * 4); + } +} + +APTR CalculateMemory (__REGA0(struct BoardInfo *b), __REGA1(unsigned int addr), __REGD7(RGBFTYPE format)) { + WRITESHORT(RTGCMD_SETPAN, 0x0007); + if (!b) + return (APTR)addr; + + if (addr > (unsigned int)b->MemoryBase && addr < (((unsigned int)b->MemoryBase) + b->MemorySize)) { + addr = ((addr + 0x1000) & 0xFFFFF000); + } + + return (APTR)addr; +} + +ULONG GetCompatibleFormats (__REGA0(struct BoardInfo *b), __REGD7(RGBFTYPE format)) { + // It is of course compatible with all the formats ever. + return 0xFFFFFFFF; +} + +static int display_enabled = 0; +BOOL SetDisplay (__REGA0(struct BoardInfo *b), __REGD0(BOOL enabled)) { + WRITESHORT(RTGCMD_SETPAN, 0x0009); + if (!b) + return 0; + + // Enables or disables the display. + WRITEBYTE(RTG_U82, (unsigned char)enabled); + WRITESHORT(RTG_COMMAND, RTGCMD_SETDISPLAY); + + if (display_enabled != enabled) { + display_enabled = enabled; + return !display_enabled; + } + return display_enabled; +} + +LONG ResolvePixelClock (__REGA0(struct BoardInfo *b), __REGA1(struct ModeInfo *mode_info), __REGD0(ULONG pixel_clock), __REGD7(RGBFTYPE format)) { + mode_info->PixelClock = CLOCK_HZ; + mode_info->pll1.Clock = 0; + mode_info->pll2.ClockDivide = 1; + + return 0; +} + +ULONG GetPixelClock (__REGA0(struct BoardInfo *b), __REGA1(struct ModeInfo *mode_info), __REGD0(ULONG index), __REGD7(RGBFTYPE format)) { + // Just return 100MHz. + return CLOCK_HZ; +} + +// None of these five really have to do anything. +void SetClock (__REGA0(struct BoardInfo *b)) { +} + +void SetMemoryMode (__REGA0(struct BoardInfo *b), __REGD7(RGBFTYPE format)) { +} + +void SetWriteMask (__REGA0(struct BoardInfo *b), __REGD0(UBYTE mask)) { +} + +void SetClearMask (__REGA0(struct BoardInfo *b), __REGD0(UBYTE mask)) { +} + +void SetReadPlane (__REGA0(struct BoardInfo *b), __REGD0(UBYTE plane)) { +} + +void WaitVerticalSync (__REGA0(struct BoardInfo *b), __REGD0(BOOL toggle)) { + // I don't know why this one has a bool in D0, but it isn't used for anything. +} diff --git a/platforms/amiga/rtg/rtg_driver_amiga/pigfx020.card b/platforms/amiga/rtg/rtg_driver_amiga/pigfx020.card new file mode 100644 index 0000000000000000000000000000000000000000..56b677546ba031c3f795376907d4d45497a91c8c GIT binary patch literal 2072 zcmah~Z)j6j6hHUAm)A68SsG;oSLFKgXKfAXTUNWS3zD|}NngWTNIN&2xMbFZ%&tje zGA881Yml)`KRC8;gW-pLa59RBh)Nlq_(8-EQAA{j*@l}l!W7-+R;upYo75I5>^<)N zoqO)N=bn4cJ?8>Q51{c`nkWO1uaNdM$E}E70O>a8v+xuAjFM*#xu#Ky-U6x`1Gj-C z;@CT=6CSeGz`I7tm|B_}ji*;TJHas*25ZI^7&cDh>airv1D8a(e!tPN4|%e_2Uxnp zy9d-jOdT<1p2!6Vtp{fwwDsVsPOBqd{1AvCKgeuJ+rS-gfD^2Fh}Cug-!qRr>I-?J zexWZgGW0LnJ&XLAN7r;S?T#X!#6+JIb{Khxzmc41N>-ndEDA|;ndD$o^7=E9Ukb@1 z%Ou^tGQ~rI-HZDJ_{w?0&zL8%S`6*n{ZT$Oxi_1e3{GUzh*2r5P zZ+~lVq;G(^nl{P$XPJ#db=n&`I8dj3T1AzZOYHCNigZmg*O=KA=|8|+Z*%;-IcLK& z9%3$WD&dKy{yuMXYn=}22QoX0&;uVrFF9GsC0w+*jj~8X7)KR8CeVXJWN>^gORc>mUT)mZyGK^iR@q9+Dl5zGG(G zZ<(1jqh{s>Y<6tcH_eQ!k)%x{)kqSlU!$=a?B}u4z}vbkRxSFcX_?Wa-`@%H$;x=U zN|{vs7VO8ScR5)Yusl^OUaXq;;GBsks_~m(OfA+?uCI3~Uad{5!Y+w9#Tof|ro;|_i$ug@wXF2MXv|J!bS^%_G5iwL3_wY1wAu!kpU8~AKU_Gynd~cp3NFlva zL%oZiBnS!=S94m7<5|4H!Ck4sI6e&9HYfVo5{GF)?d9ied>O9*0c>N~4rBWU>+U`N zdgu!P$|h_(%~AfiD0mYUE^Rlamgfj=_Yht}eiTl?Ik*5f;1BqdSc#jgr4D+O9;avM zS$ct9ra#hOXr11t^AeS8l1o}6sZy8pvC^Rg6iw+-`joJ;MbVXnvJKBbpbGQE3pS9X z6VjY?Q93VOm9AU%TMk+dE8Fq3GT5jn-DtyoZ20zphjoM8?Fj5cTE^F8fxlfW2eQ+h zkyF1V|1nA_MK|}%8>J^<)N zoqO)N=bn4cJ?8>Q51{c`nkWO1uaNdM$E}E70O>a8v+xuAjFM*#xu#Ky-U6x`1Gj-C z;@CT=6CSeGz`I7tm|B_}ji*;TJHas*25ZI^7&cDh>airv1D8a(e!tPN4|%e_2Uxnp zy9d-jOdT<1p2!6Vtp{fwwDsVsPOBqd{1AvCKgeuJ+rS-gfD^2Fh}Cug-!qRr>I-?J zexWZgGW0LnJ&XLAN7r;S?T#X!#6+JIb{Khxzmc41N>-ndEDA|;ndD$o^7=E9Ukb@1 z%Ou^tGQ~rI-HZDJ_{w?0&zL8%S`6*n{ZT$Oxi_1e3{GUzh*2r5P zZ+~lVq;G(^nl{P$XPJ#db=n&`I8dj3T1AzZOYHCNigZmg*O=KA=|8|+Z*%;-IcLK& z9%3$WD&dKy{yuMXYn=}22QoX0&;uVrFF9GsC0w+*jj~8X7)KR8CeVXJWN>^gORc>mUT)mZyGK^iR@q9+Dl5zGG(G zZ<(1jqh{s>Y<6tcH_eQ!k)%x{)kqSlU!$=a?B}u4z}vbkRxSFcX_?Wa-`@%H$;x=U zN|{vs7VO8ScR5)Yusl^OUaXq;;GBsks_~m(OfA+?uCI3~Uad{5!Y+w9#Tof|ro;|_i$ug@wXF2MXv|J!bS^%_G5iwL3_wY1wAu!kpU8~AKU_Gynd~cp3NFlva zL%oZiBnS!=S94m7<5|4H!Ck4sI6e&9HYfVo5{GF)?d9ied>O9*0c>N~4rBWU>+U`N zdgu!P$|h_(%~AfiD0mYUE^Rlamgfj=_Yht}eiTl?Ik*5f;1BqdSc#jgr4D+O9;avM zS$ct9ra#hOXr11t^AeS8l1o}6sZy8pvC^Rg6iw+-`joJ;MbVXnvJKBbpbGQE3pS9X z6VjY?Q93VOm9AU%TMk+dE8Fq3GT5jn-DtyoZ20zphjoM8?Fj5cTE^F8fxlfW2eQ+h zkyF1V|1nA_MK|}%8>J