commit 15f0d752f62d22ad7356cb579a36d1cb29ce817a Author: Alex Date: Mon Sep 7 12:44:32 2026 +0300 Initial commit: FT812 Viewer (reworked - no .XM/.XMZ) Wild Commander plugin for JPG/PNG/DLS/DXP/AVI via the FT812 (EVE) chip. XM/XMZ support (and the ESP32 audio-playback code it needed) has been removed here so this plugin can be installed alongside xmplay (https://git.alexkorochinskiy.ru/alex/xmplayer.git) without both registering for the same extensions - see README.md. Co-Authored-By: Claude Sonnet 5 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..110aa05 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Build output (SDCC/Z80 toolchain — regenerated by build.bat) +obj/ +bin/ +build/ + +# SDCC-generated files if they ever end up outside obj/ +*.rel +*.lst +*.map +*.noi +*.sym +*.lk +*.ihx +*.adb +*.cdb +*.omf + +# Editor/OS cruft +.vscode/ +*.swp +Thumbs.db +.DS_Store diff --git a/FTVIEW.WMF b/FTVIEW.WMF new file mode 100644 index 0000000..e58c714 Binary files /dev/null and b/FTVIEW.WMF differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8419c3c --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# FT812 Viewer + +Плагин длÑ� Wild Commander (ZX Evolution / TS-Conf), показывающий изображениÑ� +и видео через графичеÑ�кий чип FT812 (EVE) платы. + +> âš ï¸� **Это переработаннаÑ� верÑ�иÑ�.** Стандартный (оригинальный) `ftview` +> дополнительно Ñ�ам региÑ�трируетÑ�Ñ� на раÑ�ширениÑ� `.XM` и `.XMZ` и +> проигрывает их через ESP32-Ñ�опроцеÑ�Ñ�ор. Из Ñ�той верÑ�ии поддержка `.XM` и +> `.XMZ` убрана: воÑ�произведение модулей вынеÑ�ено в отдельный плагин +> [xmplay](https://git.alexkorochinskiy.ru/alex/xmplayer.git), а у Wild +> Commander таблица "раÑ�ширение → плагин" Ñ�татичеÑ�каÑ� и зашиваетÑ�Ñ� в +> заголовок при Ñ�борке — еÑ�ли поÑ�тавить `xmplay` вмеÑ�те Ñ�о Ñ�тандартным +> (не переработанным) `ftview`, оба будут претендовать на одни и те же +> раÑ�ширениÑ� и конфликтовать. Ставить Ñ�ту верÑ�ию `ftview` вмеÑ�те Ñ� `xmplay`, +> не Ñ�тандартную. + +## ТребованиÑ� + +- ZX Evolution / TS-Conf Ñ� графичеÑ�ким чипом FT812 (EVE) +- Wild Commander + +## ВозможноÑ�ти + +- `.JPG`, `.PNG` — проÑ�мотр изображений +- `.DLS` — воÑ�произведение "Ñ�ырого" display list FT812 (уже Ñ�компилированнаÑ� + команда отриÑ�овки, без разбора формата) +- `.DXP` — Ñ�вой формат раÑ�трового изображениÑ� (заголовок Ñ� Ñ�игнатурой, + типом и размерами + данные) +- `.AVI` — воÑ�произведение видео через вÑ�троенный видеодекодер FT812 + (`MediaFifo`, полноÑ�кранно, Ñ�о звуком) + +## Управление + +| Клавиша | ДейÑ�твие | +|---------|-------------------| +| PgDn | Следующий файл | +| PgUp | Предыдущий файл | +| Esc | Выйти | + +## УÑ�тановка + +Скопировать `ftview.wmf` в каталог плагинов Wild Commander. Плагин Ñ�ам +региÑ�трируетÑ�Ñ� на `.JPG`, `.PNG`, `.DLS`, `.DXP` и `.AVI`. + +## Сборка + +Ð�ужен [SDCC](http://sdcc.sourceforge.net/) верÑ�ии 4.0.0 (зафикÑ�ирована в +`build.bat`) и `hex2bin` — оба еÑ�ть в тулчейне SDK ZX Evolution. ВерÑ�иÑ� +SDCC важна: Ñ�обранные другой верÑ�ией `lib/ft812`/`lib/tsconf`/`lib/sdk` +дают неÑ�овмеÑ�тимый ABI (разнаÑ� конвенциÑ� `sdcccall`) без Ñ�вной ошибки +Ñ�борки — плагин проÑ�то виÑ�нет или ведёт Ñ�ебÑ� не так на реальном железе. + +``` +build.bat +``` + +Результат — `ftview.wmf` в корне проекта. + +## СтатуÑ� + +Проверено на реальном железе: проÑ�мотр JPG/PNG, воÑ�произведение DLS/AVI, +навигациÑ� по файлам. diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..bf84a2d --- /dev/null +++ b/build.bat @@ -0,0 +1,55 @@ +set SDCC=E:\SDCC\4.0.0 +set path=%SDCC%\bin;E:\zx-evo-master\pentevo\tools\hex2bin;%path% + +if not exist obj md obj +del /q /s obj >nul + +sdasz80 -o obj/crt0.rel src/crt0.s +if errorlevel 1 pause & exit + +sdcc -Isrc -I../lib/sdk -I../lib/ft812 -I../lib/tsconf -mz80 --std-sdcc11 --opt-code-speed --no-std-crt0 obj/crt0.rel --code-loc 0x8003 --data-loc 0xA800 src/main.c ../lib/ft812/ft812.lib ../lib/tsconf/ts.lib ../lib/sdk/sdk.lib -o obj/out.hex +if errorlevel 1 pause & exit +if exist obj/out.hex hex2bin obj/out.hex >nul + +for %%i in (obj/out.bin) do set sz=%%~zi +set /a sz=(%sz% - 1) / 512 + 1 + +REM A WC plugin page is exactly 16KB = 32 512-byte blocks (WALK in WCVW.ASM +REM loads N_BLK0 blocks straight off disk into the #C000-#FFFF window as +REM one contiguous chunk - anything past 32 blocks overflows that window). +REM --data-loc 0xAE00 (the value ftview shipped with) left so much unused +REM gap between code and data that the total came to 33 blocks - one over +REM the limit. That silently broke WC's boot-time [PLUGINS] autoload +REM (wc.ini parsing never reached [LPANEL]/[RPANEL]) while F3/open-by- +REM extension still worked, since by then the plugin was already resident +REM and didn't need a fresh disk load. Confirmed on real hardware +REM 2026-08-28 by comparing against the original shipped ftview.wmf (which +REM never got anywhere near 32 blocks) and a from-GitHub unmodified +REM rebuild (which hit the exact same 33-block overflow). 0xA800 leaves +REM enough headroom above current code size without wasting most of a page. +if %sz% GTR 32 ( + echo ERROR: build needs %sz% x 512-byte blocks, but a single WC plugin page holds only 32 - shrink the code or lower --data-loc's headroom above it. + pause + exit +) + +REM Pad obj/out.bin up to a whole number of 512-byte blocks (sz*512 bytes). +REM hex2bin only emits the bytes actually present in the hex file, which +REM generally is NOT block-aligned, while N_BLK0 below always rounds up - +REM so the unpadded file was technically short of what the header promised +REM (not the cause of the autoload bug above - the original shipped binary +REM has the same kind of shortfall and works fine - but still worth being +REM exact about). +set /a padded=%sz% * 512 +powershell -NoProfile -Command "$fs=[System.IO.File]::Open('obj\out.bin',[System.IO.FileMode]::Open,[System.IO.FileAccess]::Write); $fs.SetLength(%padded%); $fs.Close()" + +sdcc -DN_BLK0=%sz% -Isrc -I../lib/sdk -I../lib/ft812 -I../lib/tsconf --no-std-crt0 -mz80 --std-sdcc11 --opt-code-speed src/wc_h.c -o obj/hdr.hex +if errorlevel 1 pause & exit +if exist obj/hdr.hex hex2bin obj/hdr.hex >nul + +copy /b obj\hdr.bin + obj\out.bin ftview.wmf >nul + +REM imgcpy.exe ftview.wmf unreal\wc.img=c:\wc\ftview.wmf +REM if errorlevel 1 pause & exit + +REM unreal\unreal diff --git a/src/crt0.s b/src/crt0.s new file mode 100644 index 0000000..23b53f5 --- /dev/null +++ b/src/crt0.s @@ -0,0 +1,24 @@ + + .module crt0 + .globl _main + + .area _HEADER (ABS) + .org 0x8000 + jp _main + + ;; Ordering of segments for the linker. + .area _HOME + .area _CODE + .area _INITIALIZER + .area _GSINIT + .area _GSFINAL + + .area _DATA + .area _INITIALIZED + .area _BSEG + .area _BSS + .area _HEAP + + .area _GSINIT + .area _GSFINAL + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..bc4b317 --- /dev/null +++ b/src/main.c @@ -0,0 +1,456 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tsconf.h" + +#include + +typedef struct +{ + u8 sig[3]; + u8 type; + u16 xs; + u16 ys; +} DXP; + +typedef struct +{ + u16 sig; + u16 len; + u8 prec; + u8 ys[2]; + u8 xs[2]; +} SOF; + +typedef struct +{ + u32 sig; + u8 xs[4]; + u8 ys[4]; + u8 bits; + u8 ctype; +} IHDR; + +typedef struct +{ + u32 len; + u32 sig; +} tRNS; + +// const is to get rid of vars runtime init - const located in RAM anyway +const u8 state_ft = 0; + +#define FS_BUF_SIZE 0x1000 +u8 fs_buf[FS_BUF_SIZE]; // at 0xAE00 (_PAGE2 to get page) +u8 cmdl[0x180]; + +u16 ret_sp; +u32 filesize; +u8 file_ext; +u8 call_type; + +// --- Extensions --------------------------- +enum +{ + EXT_JPG, + EXT_PNG, + EXT_DLS, + EXT_DXP, + EXT_AVI, +}; + +// --- Windows ------------------------------ +const WC_TX_WINDOW err_no_ft = +{ + /* window with header and text */ WC_WIND_HDR_TXT, + /* cursor color mask */ 0, + /* X,Y (position) */ 24, 10, + /* W,H (size) */ 32, 5, + /* paper/ink (window color) */ 0x2F, + /* -reserved- */ 0, + /* window restore buffer address */ 0, + /* separators */ 0, 0, + /* header text */ "\x0E" " Error! ", + /* footer text */ "", + /* window text */ "\x0E\x0C\x01" "No VDAC2 detected!", +}; + +const WC_TX_WINDOW win_about = +{ + /* window with header and text */ WC_WIND_HDR_TXT, + /* cursor color mask */ 0, + /* X,Y (position) */ 22, 10, + /* W,H (size) */ 36, 5, + /* paper/ink (window color) */ 0x4F, + /* -reserved- */ 0, + /* window restore buffer address */ 0, + /* separators */ 0, 0, + /* header text */ "\x0E" " About ", + /* footer text */ "", + /* window text */ "\x0E\x0C\x01" "FT812 Viewer v1.2, (c)2024 TSL" +}; + +// --- FT812 -------------------------------- +bool vdac2_init() +{ + if ((ts_rreg(TS_STATUS) & 7) != 7) + return false; + + ft_init(FT_MODE_1024_768_59); + return ft_rreg8(FT_REG_ID) == 0x7C; +} + +void show_jpg_png(u8 is_jpg) +{ + u32 sz = filesize; + u16 xs = 1024; u16 ys = 768; + u8 fmt = FT_RGB565; + u16 ofs = 0; + + wc_vmode(0x87); + wc_load512(fs_buf, FS_BUF_SIZE >> 9); + + if (is_jpg) // JPEG + { + int i; + for (i = 0; i < (FS_BUF_SIZE - sizeof(SOF)); i++) + { + SOF *sof = (SOF*)&fs_buf[i]; + + if ((sof->sig & 0xF0FF) == 0xC0FF) // SOFn + { + xs = ((u16)sof->xs[0] << 8) + sof->xs[1]; + ys = ((u16)sof->ys[0] << 8) + sof->ys[1]; + break; + } + } + } + else // PNG + { + int i; + for (i = 0; i < (FS_BUF_SIZE - sizeof(IHDR)); i++) + { + IHDR *ihdr = (IHDR*)&fs_buf[i]; + + if (ihdr->sig == 0x52444849) + { + xs = ((u16)ihdr->xs[2] << 8) + ihdr->xs[3]; + ys = ((u16)ihdr->ys[2] << 8) + ihdr->ys[3]; + + switch (ihdr->ctype) + { + case 0: + fmt = FT_L8; + break; + + case 3: + fmt = FT_PALETTED565; + ofs = 512; + + for (i = 0; i < (FS_BUF_SIZE - sizeof(tRNS)); i++) + { + tRNS *trns = (tRNS*)&fs_buf[i]; + + if ((trns->len == 0x01000000) && (trns->sig == 0x534E5274)) + { + fmt = FT_PALETTED4444; + break; + } + } + break; + + case 6: + fmt = FT_ARGB4; + break; + } + break; + } + } + } + + ft_ccmd_start(cmdl); + ft_Dlstart(); + ft_Clear(1, 1, 1); + if (ofs) ft_PaletteSource(FT_RAM_G); + ft_SetBitmap(FT_RAM_G + ofs, fmt, xs, ys); + ft_Begin(FT_BITMAPS); + ft_Vertex2ii((1024 - min(1024, xs)) >> 1, (768 - min(768, ys)) >> 1, 0, 0); + ft_Display(); + ft_ccmd(FT_CCMD_SWAP); + ft_LoadImage(FT_RAM_G, FT_OPT_NODL); + ft_ccmd_write(); + + while (sz) + { + u16 s; + s = min(sz, FS_BUF_SIZE); + if (!ft_load_cfifo(fs_buf, s)) return; + sz -= s; + if (sz) wc_load512(fs_buf, FS_BUF_SIZE >> 9); + } + ft_cp_wait(); +} + +void show_dxp() +{ + u32 sz, o; + u16 xo, yo; + DXP *d; + + wc_vmode(0x87); + wc_load512(fs_buf, FS_BUF_SIZE >> 9); + + sz = filesize - sizeof(DXP); + d = (DXP*)fs_buf; + o = (u32)d->xs * ((u32)d->ys >> 2); + xo = (1024 - d->xs) >> 1; + yo = (768 - d->ys) >> 1; + + ft_ccmd_start(cmdl); + ft_Dlstart(); + ft_Clear(1, 1, 1); + // ft_ccmd(ft_SaveContext()); + + ft_BitmapHandle(0); + ft_SetBitmap(FT_RAM_G + o, FT_L2, d->xs, d->ys); + ft_BitmapHandle(1); + ft_SetBitmap(FT_RAM_G, FT_RGB565, d->xs >> 2, d->ys >> 2); + ft_BitmapSize(FT_NEAREST, FT_BORDER, FT_BORDER, d->xs, d->ys); + + ft_Begin(FT_BITMAPS); + ft_ColorA(255); + ft_BlendFunc(FT_ONE, FT_ZERO); + ft_Vertex2ii(xo, yo, 0, 0); + + ft_ColorMask(1, 1, 1, 0); + ft_BitmapTransformA(64); + ft_BitmapTransformE(64); + ft_BlendFunc(FT_ONE_MINUS_DST_ALPHA, FT_ZERO); + ft_Vertex2ii(xo, yo, 1, 0); + ft_BlendFunc(FT_DST_ALPHA, FT_ONE); + ft_Vertex2ii(xo, yo, 1, 1); + + // ft_RestoreContext(); + // ft_SetBase(10); + // ft_Number(0, 0, 18, 0, filesize); + + ft_Display(); + ft_ccmd(FT_CCMD_SWAP); + ft_ccmd_write(); + ft_cp_wait(); + + { + u8 *bptr = fs_buf + sizeof(DXP); + u16 bsz = FS_BUF_SIZE - sizeof(DXP); + + if (d->type == 0) + { + u32 gptr = FT_RAM_G; + + while (sz) + { + u16 s = min(sz, bsz); + ft_write(bptr, gptr, s); + gptr += s, sz -= s, bptr = fs_buf, bsz = FS_BUF_SIZE; + + if (sz) wc_load512(fs_buf, FS_BUF_SIZE >> 9); + } + } + else + { + ft_ccmd_start(cmdl); + ft_Inflate(FT_RAM_G); + ft_ccmd_write(); + + while (sz) + { + u16 s = min(sz, bsz); + if (!ft_load_cfifo(bptr, s)) return; + sz -= s, bptr = fs_buf, bsz = FS_BUF_SIZE; + + if (sz) wc_load512(fs_buf, FS_BUF_SIZE >> 9); + } + + ft_cp_wait(); + } + } +} + +void show_dls() +{ + wc_vmode(0x87); + wc_load512(fs_buf, FS_BUF_SIZE >> 9); + ft_write_dl(fs_buf, filesize >> 2); + ft_wreg8(FT_REG_DLSWAP, FT_DLSWAP_FRAME); +} + +void show_avi() +{ + u32 sz = filesize; + + wc_vmode(0x87); + + ft_wreg32(FT_REG_FREQUENCY, 64000000UL); + + ft_ccmd_start(cmdl); + ft_Dlstart(); + ft_ClearColorRGB(128, 128, 160); + ft_Clear(1, 1, 1); + ft_Display(); + ft_ccmd(FT_CCMD_SWAP); + ft_ccmd_write(); + ft_cp_wait(); + // delay(50000); + +#define CHUNK_SIZE 4096 +#define FIFO_ADDR 0x080000 +#define FIFO_SIZE 0x080000 + + ft_MediaFifo(FIFO_ADDR, FIFO_SIZE); + ft_ccmd_write(); + ft_cp_wait(); + + u32 waddr = FIFO_ADDR; + while (waddr < (FIFO_ADDR + FIFO_SIZE - CHUNK_SIZE)) + { + wc_load512(fs_buf, CHUNK_SIZE >> 9); + ft_load_ram_dma(fs_buf, *(u8*)_PAGE2, waddr, CHUNK_SIZE); + waddr += CHUNK_SIZE; + } + + ft_PlayVideo(OPT_FULLSCREEN | OPT_SOUND | OPT_MEDIAFIFO | OPT_NOTEAR); + ft_ccmd_write(); + + while (sz) + { + ft_wreg32(REG_MEDIAFIFO_WRITE, waddr); + + wc_load512(fs_buf, CHUNK_SIZE >> 9); + + while (1) + { + u32 raddr = ft_rreg32(REG_MEDIAFIFO_READ); + u32 free = FIFO_SIZE - ((waddr >= raddr) ? (waddr - raddr) : (FIFO_SIZE - (raddr - waddr))); + if (free >= CHUNK_SIZE) break; + } + + ft_load_ram_dma(fs_buf, *(u8*)_PAGE2, waddr, CHUNK_SIZE); + waddr += CHUNK_SIZE; + if (waddr >= (FIFO_ADDR + FIFO_SIZE)) waddr = FIFO_ADDR; + } + + // ft_cp_wait_free(CHUNK_SIZE); + // u16 s = min(sz, CHUNK_SIZE); + // wc_load512(fs_buf, CHUNK_SIZE >> 9); + // ft_load_ram_dma(fs_buf, *(u8*)_PAGE2, s); + // sz -= s; +} + +// --- Aux functions ------------------------ +void wait_esc_key() +{ + while (1) + { + __asm + halt + __endasm; + + if (wc_api__bool(_ESC)) + break; + } +} + +void about() +{ + wc_api_u16(_PRWOW, (u16)&win_about); + wait_esc_key(); + wc_api_u16(_RRESB, (u16)&win_about); + wc_exit(WC_EXIT); +} + +void error_ft() +{ + wc_api_u16(_PRWOW, (u16)&err_no_ft); + wait_esc_key(); + wc_api_u16(_RRESB, (u16)&err_no_ft); + wc_exit(WC_EXIT); +} + +void main_start() +{ + if (!state_ft) + *(u8*)&state_ft = vdac2_init() ? 1 : 2; + + if (state_ft != 1) + error_ft(); + + else switch (file_ext) + { + case EXT_JPG: + case EXT_PNG: + show_jpg_png(file_ext == EXT_JPG); + break; + + case EXT_DXP: + show_dxp(); + break; + + case EXT_DLS: + show_dls(); + break; + + case EXT_AVI: + show_avi(); + break; + } + + // poll keys + while (1) + { + __asm + halt + __endasm; + + if (wc_api__bool(_PGD)) // PgDn - next file + wc_exit(WC_NEXT_FILE); + + if (wc_api__bool(_PGU)) // PgUp - previous file + wc_exit(WC_PREV_FILE); + + if (wc_api__bool(_ESC)) // Esc - exit + wc_exit(WC_EXIT); + } +} + +// ------------------------------------------ +void main() +{ + __asm + ld (_ret_sp), sp + ld (_call_type), a + ex af, af + ld (_file_ext), a + ld (_filesize), hl + ld (_filesize + 2), de + __endasm; + + switch (call_type) + { + case WC_CALL_EXT: + main_start(); + break; + + case WC_CALL_MENU: + about(); + break; + + default: + wc_exit(WC_EXIT); + } +} diff --git a/src/tsconf.h b/src/tsconf.h new file mode 100644 index 0000000..7adb4ef --- /dev/null +++ b/src/tsconf.h @@ -0,0 +1,195 @@ + +#pragma once + +__sfr __at 0x57 SPI_DATA; +__sfr __at 0x77 SPI_CTRL; + +__sfr __at 0xFE BORDER; + +__sfr __banked __at 0x00AF TS_VCONFIG; +__sfr __banked __at 0x00AF TS_STATUS; +__sfr __banked __at 0x01AF TS_VPAGE; +__sfr __banked __at 0x02AF TS_GXOFFSL; +__sfr __banked __at 0x03AF TS_GXOFFSH; +__sfr __banked __at 0x04AF TS_GYOFFSL; +__sfr __banked __at 0x05AF TS_GYOFFSH; +__sfr __banked __at 0x06AF TS_TSCONFIG; +__sfr __banked __at 0x07AF TS_PALSEL; +__sfr __banked __at 0x0FAF TS_BORDER; +__sfr __banked __at 0x10AF TS_PAGE0; +__sfr __banked __at 0x11AF TS_PAGE1; +__sfr __banked __at 0x12AF TS_PAGE2; +__sfr __banked __at 0x13AF TS_PAGE3; +__sfr __banked __at 0x15AF TS_FMADDR; +__sfr __banked __at 0x16AF TS_TMPAGE; +__sfr __banked __at 0x17AF TS_T0GPAGE; +__sfr __banked __at 0x18AF TS_T1GPAGE; +__sfr __banked __at 0x19AF TS_SGPAGE; +__sfr __banked __at 0x1AAF TS_DMASADDRL; +__sfr __banked __at 0x1BAF TS_DMASADDRH; +__sfr __banked __at 0x1CAF TS_DMASADDRX; +__sfr __banked __at 0x1DAF TS_DMADADDRL; +__sfr __banked __at 0x1EAF TS_DMADADDRH; +__sfr __banked __at 0x1FAF TS_DMADADDRX; +__sfr __banked __at 0x20AF TS_SYSCONFIG; +__sfr __banked __at 0x21AF TS_MEMCONFIG; +__sfr __banked __at 0x22AF TS_HSINT; +__sfr __banked __at 0x23AF TS_VSINTL; +__sfr __banked __at 0x24AF TS_VSINTH; +__sfr __banked __at 0x25AF TS_DMAWPD; +__sfr __banked __at 0x26AF TS_DMALEN; +__sfr __banked __at 0x27AF TS_DMACTR; +__sfr __banked __at 0x27AF TS_DMASTATUS; +__sfr __banked __at 0x28AF TS_DMANUM; +__sfr __banked __at 0x29AF TS_FDDVIRT; +__sfr __banked __at 0x2AAF TS_INTMASK; +__sfr __banked __at 0x2BAF TS_CACHECONF; +__sfr __banked __at 0x2CAF TS_DMANUMH; +__sfr __banked __at 0x2DAF TS_DMAWPA; +__sfr __banked __at 0x40AF TS_T0XOFFSL; +__sfr __banked __at 0x41AF TS_T0XOFFSH; +__sfr __banked __at 0x42AF TS_T0YOFFSL; +__sfr __banked __at 0x43AF TS_T0YOFFSH; +__sfr __banked __at 0x44AF TS_T1XOFFSL; +__sfr __banked __at 0x45AF TS_T1XOFFSH; +__sfr __banked __at 0x46AF TS_T1YOFFSL; +__sfr __banked __at 0x47AF TS_T1YOFFSH; + +// TS parameters +#define TS_FM_EN 0x10 + +// FPGA arrays +#define TS_FM_CRAM 0x0000 +#define TS_FM_SFILE 0x0200 + +// VIDEO +#define TS_VID_256X192 0x00 +#define TS_VID_320X200 0x40 +#define TS_VID_320X240 0x80 +#define TS_VID_360X288 0xC0 +#define TS_VID_RASTER_BS 6 + +#define TS_VID_ZX 0x00 +#define TS_VID_16C 0x01 +#define TS_VID_256C 0x02 +#define TS_VID_TEXT 0x03 +#define TS_VID_FT812 0x04 +#define TS_VID_NOGFX 0x20 +#define TS_VID_MODE_BS 0 + +// PALSEL +#define TS_PAL_GPAL_MASK 0x0F +#define TS_PAL_GPAL_BS 0 +#define TS_PAL_T0PAL_MASK 0x30 +#define TS_PAL_T0PAL_BS 4 +#define TS_PAL_T1PAL_MASK 0xC0 +#define TS_PAL_T1PAL_BS 6 + +// TSU +#define TS_TSU_T0ZEN 0x04 +#define TS_TSU_T1ZEN 0x08 +#define TS_TSU_T0EN 0x20 +#define TS_TSU_T1EN 0x40 +#define TS_TSU_SEN 0x80 + +// SYSTEM +#define TS_SYS_ZCLK3_5 0x00 +#define TS_SYS_ZCLK7 0x01 +#define TS_SYS_ZCLK14 0x02 +#define TS_SYS_ZCLK_BS 0 + +#define TS_SYS_CACHEEN 0x04 + +// MEMORY +#define TS_MEM_ROM128 0x01 +#define TS_MEM_W0WE 0x02 +#define TS_MEM_W0MAP_N 0x04 +#define TS_MEM_W0RAM 0x08 + +#define TS_MEM_LCK512 0x00 +#define TS_MEM_LCK128 0x40 +#define TS_MEM_LCKAUTO 0x80 +#define TS_MEM_LCK1024 0xC0 +#define TS_MEM_LCK_BS 6 + +// INT +#define TS_INT_VEC_FRAME 0xFF +#define TS_INT_VEC_LINE 0xFD +#define TS_INT_VEC_DMA 0xFB +#define TS_INT_VEC_WTP 0xF9 + +#define TS_INT_MSK_FRAME 0x01 +#define TS_INT_MSK_LINE 0x02 +#define TS_INT_MSK_DMA 0x04 +#define TS_INT_MSK_WTP 0x08 + +// DMA +#define TS_DMA_WNR 0x80 +#define TS_DMA_SALGN 0x20 +#define TS_DMA_DALGN 0x10 +#define TS_DMA_ASZ 0x08 + +#define TS_DMA_RAM 0x01 +#define TS_DMA_BLT 0x81 +#define TS_DMA_FILL 0x04 +#define TS_DMA_SPI_RAM 0x02 +#define TS_DMA_WTP_RAM 0x07 +#define TS_DMA_RAM_SPI 0x82 +#define TS_DMA_IDE_RAM 0x03 +#define TS_DMA_RAM_IDE 0x83 +#define TS_DMA_RAM_CRAM 0x84 +#define TS_DMA_RAM_SFILE 0x85 + +#define TS_WPD_GLU 0 +#define TS_WPD_COM 1 + +// SPRITES +#define TS_SP_XF 0x80 +#define TS_SP_YF 0x80 +#define TS_SP_LEAP 0x40 +#define TS_SP_ACT 0x20 + +#define TS_SP_SIZE8 0x00 +#define TS_SP_SIZE16 0x02 +#define TS_SP_SIZE24 0x04 +#define TS_SP_SIZE32 0x06 +#define TS_SP_SIZE40 0x08 +#define TS_SP_SIZE48 0x0A +#define TS_SP_SIZE56 0x0C +#define TS_SP_SIZE64 0x0E +#define TS_SP_SIZE_BS 1 + +#define TS_SP_PAL_MASK 0xF0 + +#define TS_SP_XF_W 0x8000 +#define TS_SP_YF_W 0x8000 +#define TS_SP_LEAP_W 0x4000 +#define TS_SP_ACT_W 0x2000 + +#define TS_SP_SIZE8_W 0x0000 +#define TS_SP_SIZE16_W 0x0200 +#define TS_SP_SIZE24_W 0x0400 +#define TS_SP_SIZE32_W 0x0600 +#define TS_SP_SIZE40_W 0x0800 +#define TS_SP_SIZE48_W 0x0A00 +#define TS_SP_SIZE56_W 0x0C00 +#define TS_SP_SIZE64_W 0x0E00 +#define TS_SP_SIZE_BS_W 9 + +#define TS_SP_X_MASK_W 0x01FF +#define TS_SP_Y_MASK_W 0x01FF +#define TS_SP_TNUM_MASK_W 0x0FFF +#define TS_SP_PAL_MASK_W 0xF000 + +// TILES +#define TS_TL_XF 0x40 +#define TS_TL_YF 0x80 +#define TS_TL_PAL_MASK 0x30 +#define TS_TL_PAL_BS 4 + +#define TS_TL_XF_W 0x4000 +#define TS_TL_YF_W 0x8000 + +#define TS_TL_TNUM_MASK_W 0x0FFF +#define TS_TL_PAL_MASK_W 0x3000 +#define TS_TL_PAL_BS_W 12 diff --git a/src/wc_api.c b/src/wc_api.c new file mode 100644 index 0000000..8d1fce2 --- /dev/null +++ b/src/wc_api.c @@ -0,0 +1,76 @@ + +bool wc_api__bool(u8 a) __naked +{ + a; // to avoid SDCC warning + __asm + ld hl, #2 + add hl, sp + ld a, (hl) + call _WCAPI + ld l, #0 + ret z + inc l + ret + __endasm; +} + +void wc_api_u16(u8 a, u16 b) __naked +{ + a; // to avoid SDCC warning + b; // to avoid SDCC warning + __asm + ld hl, #2 + add hl, sp + ld a, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + push bc + pop ix + jp _WCAPI + __endasm; +} + +bool wc_vmode(u8 a) __naked +{ + a; // to avoid SDCC warning + __asm + ld hl, #2 + add hl, sp + ld a, (hl) + ex af, af + ld a, #_GVmod + jp _WCAPI + __endasm; +} + +u16 wc_load512(u8 *a, u8 b) __naked +{ + a; // to avoid SDCC warning + b; // to avoid SDCC warning + __asm + ld hl, #2 + add hl, sp + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld b, (hl) + ex de, hl + ld a, #_LOAD512 + jp _WCAPI + __endasm; +} + +void wc_exit(u8 rc) +{ + rc; // to avoid SDCC warning + __asm + ld hl, #2 + add hl, sp + ld a, (hl) + ld sp, (_ret_sp) + ret + __endasm; +} diff --git a/src/wc_api.h b/src/wc_api.h new file mode 100644 index 0000000..423e64e --- /dev/null +++ b/src/wc_api.h @@ -0,0 +1,309 @@ + +// WildCommander API Header +// Refer to plugins/READ_ME.TXT + +#pragma once + +//--------------------------------------- +// Addresses +#define _WCINT 0x5BFF // àäðåñ îáðàáîòêè int wild commander + +#define _PAGE0 0x6000 // íîìåð ñòðàíèöû ïîäêëþ÷åííîé ñ àäðåñà 0x0000-0x3fff +#define _PAGE1 0x6001 // íîìåð ñòðàíèöû ïîäêëþ÷åííîé ñ àäðåñà 0x4000-0x7fff +#define _PAGE2 0x6002 // íîìåð ñòðàíèöû ïîäêëþ÷åííîé ñ àäðåñà 0x8000-0xdfff +#define _PAGE3 0x6003 // íîìåð ñòðàíèöû ïîäêëþ÷åííîé ñ àäðåñà 0xc000-0xffff +#define _ABT 0x6004 // ôëàã âûñòàâëÿåòñÿ, åñëè áûë íàæàò ESC +#define _ENT 0x6005 // ôëàã âûñòàâëÿåòñÿ, åñëè áûë íàæàò ENTER +#define _WCAPI 0x6006 // òî÷êà äîñòóïà ê ôóíêöèÿì +#define _TMN 0x6009 // ñèíõðà. ïåðåìåííàÿ-òàéìåð, èíêðåìåíòèòñÿ ïî èíòó + +//--------------------------------------- +// API functions +#define _MNGC_PL 0x00 // âêëþ÷åíèå ñòðàíèöû íà 0xC000 (èç âûäåëåííîãî áëîêà) + // íóìåðàöèÿ ñîâïàäàåò ñ èñïîëüçóþùåéñÿ â +36 + // i:A' - íîìåð ñòðàíèöû (îò 0) + // 0xFF - ñòðàíèöà ñ ôîíòîì (1ãî òåêñòîâîãî ýêðàíà) + // 0xFE - ïåðâûé òåêñòîâûé ýêðàí (â í¸ì ïàíåëè) +#define _MNG0_PL 0x78 +#define _MNG8_PL 0x79 + +#define _PRWOW 0x01 // âûâîä îêíà íà ýêðàí + // i:IX - àäðåñ ïî êîòîðîìó ëåæèò ñòðóêòóðà îêíà (SOW) + +#define _RRESB 0x02 // còèðàíèå îêíà (âîññòàíîâëåíèå èíôîðìàöèè) + // i:IX - SOW + +#define _PRSRW 0x03 // ïå÷àòü ñòðîêè â îêíå + // i:IX - SOW + // HL - Text addres (äîëæåí áûòü â 0x8000-0xBFFF!) + // D - Y + // E - X + // BC - Length + +#define _PRIAT 0x04 // âûñòàâëåíèå öâåòà (âûçûâàåòñÿ ñðàçó ïîñëå PRSRW) + // i:PRSRW - âûñòàâëåííûå êîîðäèíàòû è äëèíà + // A' - öâåò + +#define _GADRW 0x05 // ïîëó÷åíèå àäðåñà â îêíå + // i:IX - SOW + // D - Y + // E - X + // o:HL - Address + +#define _CURSOR 0x06 // ïå÷àòü êóðñîðà + // i:IX - SOW + +#define _CURSER 0x07 // ñòèðàíèå êóðñîðà (âîññòàíîâëåíèå öâåòà) + // i:IX - SOW + +#define _YN 0x08 // ìåíþ ok/cancel + // i:A' + // 0x01 - èíèöèàëèçàöèÿ (âû÷èñëÿåò êîîðäèíàòû) + // 0x00 - îáðàáîòêà íàæàòèé (âûçûâàòü ðàç â ôðåéì) + // 0xFF - âûõîä + // o:NZ - âûáðàí CANCEL + // Z - âûáðàí OK + +#define _ISTR 0x09 // ðåäàêòèðîâàíèå ñòðîêè + // i:A' + // 0xFF - èíèöèàëèçàöèÿ (ðèñóåò êóðñîð) + // i:HL - àäðåñ ñòðîêè + // DE - CURMAX+CURNOW (äëèíà ñòðîêè + íà÷àëüíàÿ ïîçèöèÿ êóðñîðà â íåé) + // 0x00 - îïðîñ êëàâèàòóðû + // >îïðàøèâàåò LF,RG,BackSpace + // >ñîáñòâåííî ðåäàêòèðóåòñÿ ñòðîêà + // >íóæíî âûçûâàòü êàæäûé ôðåéì + // 0x01 - âûõîä (ñòèðàåò êóðñîð) + +#define _NORK 0x0A // ïåðåâîä áàéòà â HEX (òåêñòîâûé ôîðìàò) + // i:HL - Text Address + // A - Value + +#define _DMAPL 0x0D // ðàáîòà ñ DMA + // i: A' - òèï îïåðàöèè + // 0x00 - èíèò S è D (BHL - Source, CDE - Destination) + // 0x01 - èíèò S (BHL) + // 0x02 - èíèò D (CDE) + // 0x03 - èíèò S ñ ïàãîé èç îêíà (HL, B - 0-3 [íîìåð îêíà]) + // 0x04 - èíèò D ñ ïàãîé èç îêíà (HL, B - 0-3 [íîìåð îêíà]) + // 0x05 - âûñòàâëåíèå DMA_T (B - êîë-âî á¸ðñòîâ) + // 0x06 - âûñòàâëåíèå DMA_N (B - ðàçìåð á¸ðñòà) + // + // 0xFD - çàïóñê áåç îæèäàíèÿ çàâåðøåíèÿ (o:NZ - DMA çàíÿòà) + // 0xFE - çàïóñê ñ îæèäàíèåì çàâåðøåíèÿ (o:NZ - DMA çàíÿòà) + // 0xFF - îæèäàíèå ãîòîâíîñòè äìà + // + // â ôóíêöèÿõ 0x00-0x02 ôîðìàò B/C ñëåäóþùèé: + // [7]:%1 - âûáîð ñòðàíèöû èç áëîêà âûäåëåííîãî ïëàãèíó (0-5) + // %0 - âûáîð ñòðàíèöû èç âèäåî áóôåðîâ (0-31) + // [6-0]:íîìåð ñòðàíèöû + +#define _TURBOPL 0x0E // i:B - âûáîð Z80/AY + // 0x00 - ìåíÿåòñÿ ÷àñòîòà Z80 + // i:C - %00 - 3.5 MHz + // %01 - 7 MHz + // %10 - 14 MHz + // %11 - 28 MHz (â äàííûé ìîìåíò 14MHz) + // 0x01 - ìåíÿåòñÿ ÷àñòîòà AY + // i:C - %00 - 1.75 MHz + // %01 - 1.7733 MHz + // %10 - 3.5 MHz + // %11 - 3.546 MHz + +#define _GEDPL 0x0F // âîññòàíîâëåíèå ïàëèòðû, âñåõ îôñåòîâ è txt ðåæèìà + // ! îáÿçàòåëüíî âûçûâàòü ïðè çàïóñêå ïëàãèíà! + // (âêëþ÷àåò îñíîâíîé txt ýêðàí) + // i:none + +// êëàâèàòóðà: NZ - êëàâèøà íàæàòà +//-------------------------------------------------- +#define _SPKE 0x10 // (SPACE) +#define _UPPP 0x11 // (UP Arrow) +#define _DWWW 0x12 // (Down Arrow) +#define _LFFF 0x13 // (Left Arrow) +#define _RGGG 0x14 // (Right Arrow) +#define _TABK 0x15 // (Tab) +#define _ENKE 0x16 // (Enter) +#define _ESC 0x17 // (Escape) +#define _BSPC 0x18 // (Backspace) +#define _PGU 0x19 // (pgUP) +#define _PGD 0x1A // (pgDN) +#define _HOME 0x1B +#define _END 0x1C +#define _F1 0x1D +#define _F2 0x1E +#define _F3 0x1F +#define _F4 0x20 +#define _F5 0x21 +#define _F6 0x22 +#define _F7 0x23 +#define _F8 0x24 +#define _F9 0x25 +#define _F10 0x26 +#define _ALT 0x27 +#define _SHIFT 0x28 +#define _CTRL 0x29 +#define _KBSCN 0x2A // îïðîñ êëàâèø + // i:A' - îáðàáîò÷èê + // 0x00 - ó÷èòûâàåò SHIFT (TAI1/TAI2) + // 0x01 - âñåãäà âûäàåò êîä èç TAI1 + // o: NZ: A - TAI1/TAI2 (see PS2P.ASM) + // Z: A=0x00 - unknown key + // A=0xFF - buffer end + +#define _CAPS 0x2C // (Caps Lock) +#define _ANYK 0x2D // any key +#define _USPO 0x2E // pause for keyboard ready (recomended for NUSP) +#define _NUSP 0x2F // waiting for any key + +// ðàáîòà ñ ôàéëàìè: +//--------------------------------------- +#define _LOAD512 0x30 // ïîòîêîâàÿ çàãðóçêà ôàéëà + // i:HL - Address + // B - Blocks (512b) + // o:HL - New Value + +#define _SAVE512 0x31 // ïîòîêîâàÿ çàïèñü ôàéëà + // i:HL - Address + // B - Blocks (512b) + // o:HL - New Value + +#define _GIPAGPL 0x32 // ïîçèöèîíèðîâàòü íà íà÷àëî ôàéëà + // (ñðàçó ïîñëå çàïóñêà ïëàãèíà — óæå âûçâàíà) + +#define _TENTRY 0x33 // ïîëó÷èòü ENTRY(32) èç êîììàíäåðà + // (ñòðóêòóðà êàê â êàòàëîãå FAT32) + // i:DE - Address + // o:DE(32) - ENTRY + +#define _CHTOSEP 0x34 // ðàçëîæåíèå öåïî÷êè àêòèâíîãî ôàéëà â ñåêòîðà + // i:DE - BUFFER (êóäà êèäàòü íîìåðà ñåêòîðîâ) + // BC - BUFFER END (=BUFFER+BUFFERlenght) + +#define _TENTRYN 0x35 // reserved ??? + +#define _TMRKDFL 0x36 // ïîëó÷èòü çàãîëîâîê ìàðêèðîâàííîãî ôàéëà + // i:HL - File number (1-2047) + // DE - Address (32byte buffer) [0x8000-0xBFFF!] + // (if HL=0// o:BC - count of marked files) + // o:NZ - File not found or other error + // Z - Buffer updated + // >òàê æå äåëàåòñÿ ïîçèöèîíèðîâàíèåíà íà íà÷àëî ýòîãî ôàéëà!!! + // >ñîîòâ. ôóíêöèè LOAD512/SAVE512 áóäóò ÷èòàòü/ïèñàòü ýòîò ôàéë îò íà÷àëà. + +#define _TMRKNXT 0x37 // reserved ??? + +#define _STREAM 0x39 // ðàáîòà ñ ïîòîêàìè + // i:D - íîìåð ïîòîêà (0/1) + // B - óñòðîéñòâî: 0-SD(ZC) + // 1-Nemo IDE Master + // 2-Nemo IDE Slave + // C - ðàçäåë (íå ó÷èòûâàåòñÿ) + // BC=0xFFFF: âêëþ÷àåò ïîòîê èç D (íå âîçâðàùàåò ôëàãîâ) + // èíà÷å ñîçäàåò/ïåðåñîçäàåò ïîòîê. + // o:NZ - óñòðîéñòâî èëè ðàçäåë íå íàéäåíû + // Z - ìîæíî íà÷èíàòü ðàáîòàòü ñ ïîòîêîì + +#define _MKFILE 0x3A // ñîçäàíèå ôàéëà â àêòèâíîì êàòàëîãå + // i:DE(12) - name(8)+ext(3)+flag(1) + // HL(4) - File Size + // o:NZ - Operation failed + // A - type of error (in next versions!) + // Z - File created + // ENTRY(32) [use TENTRY] + +#define _FENTRY 0x3B // ïîèñê ôàéëà/êàòàëîãà â àêòèâíîé äèðåêòîðèè + // i:HL - flag(1),name(1-12),0x00 + // flag:0x00 - file + // 0x10 - dir + // name:"NAME.TXT","DIR"... + // o: Z - entry not found + // NZ - CALL GFILE/GDIR for activating file/dir + // [DE,HL] - file length + +#define _LOAD256 0x3C // reserved ??? +#define _LOADNONE 0x3D // reserved ??? + +#define _GFILE 0x3E // âûñòàâèòü óêàçàòåëü íà íà÷àëî íàéäåííîãî ôàéëà + // (âûçûâàåòñÿ ïîñëå FENTRY!) + +#define _GDIR 0x3F // ñäåëàòü íàéäåííûé êàòàëîã àêòèâíûì + // (âûçûâàåòñÿ ïîñëå FENTRY!) + +// ðàáîòà ñ ðåæèìàìè ãðàôèêè +//--------------------------------------- +#define _MNGV_PL 0x40 // âêëþ÷åíèå âèäåî ñòðàíèöû + // i:A' - íîìåð âèäåî ñòðàíèöû + // 0x00 - îñíîâíîé ýêðàí (òõò) + // >ïàëèòðà âûñòàâëÿåòñÿ àâòîìàòîì + // >êàê è âñå ðåæèìû è ñìåùåíèÿ + // 0x01 - 1é âèäåî áóôåð (16 ñòðàíèö) + // 0x02 - 2é âèäåî áóôåð (16 ñòðàíèö) + +#define _MNGCVPL 0x41 // âêëþ÷åíèå ñòðàíèöû èç âèäåî áóôåðîâ + // i:A' - íîìåð ñòðàíèöû + // 0x00-0x0F - ñòðàíèöû èç 1ãî âèäåî áóôåðà + // 0x10-0x1F - ñòðàíèöû èç 2ãî âèäåî áóôåðà + +#define _GVmod 0x42 // âêëþ÷åíèå âèäåî ðåæèìà (ðàçðåøåíèå+òèï) + // i:A' - âèäåî ðåæèì + // [7-6]: %00 - 256x192 + // %01 - 320x200 + // %10 - 320x240 + // %11 - 360x288 + // [5-2]: %0000 + // [1-0]: %00 - ZX + // %01 - 16c + // %10 - 256c + // %11 - txt + +#define _GYoff 0x43 // âûñòàâëåíèå ñìåùåíèÿ ýêðàíà ïî Y + // i:HL - Y (0-511) + +#define _GXoff 0x44 // âûñòàâëåíèå ñìåùåíèÿ ýêðàíà ïî X + // i:HL - X (0-511) + +#define _GVtm 0x69 // âûñòàâëåíèå ñòðàíèöû äëÿ TileMap +#define _GVtl 0x70 // âûñòàâëåíèå ñòðàíèöû äëÿ TileGraphics +#define _GVsgp 0x71 // âûñòàâëåíèå ñòðàíèöû äëÿ SpriteGraphics + +typedef enum +{ + WC_WIND_HDR_TXT = 1, +} WC_WIND_TYPE; + +typedef struct +{ + WC_WIND_TYPE type; + u8 curs_col_mask; + u8 x_pos; + u8 y_pos; + u8 x_size; + u8 y_size; + u8 attr; + u8 res0; + u16 restore_addr; + u8 div0; + u8 div1; + u16 *hdr_txt; + u16 *ftr_txt; + u16 *wnd_txt; +} WC_TX_WINDOW; + +typedef enum +{ + WC_CALL_EXT = 0x00, + WC_CALL_ONLOAD = 0x01, + WC_CALL_TIMER = 0x02, + WC_CALL_MENU = 0x03, + WC_CALL_EDIT = 0x14, +} WC_CALL_TYPE; + +typedef enum +{ + WC_EXIT = 0, + WC_TYPE_UNK = 1, + WC_NEXT_FILE = 2, + WC_REREAD_DIR = 3, + WC_PREV_FILE = 4, +} WC_EXIT_SIGNAL; diff --git a/src/wc_h.c b/src/wc_h.c new file mode 100644 index 0000000..4ec0061 --- /dev/null +++ b/src/wc_h.c @@ -0,0 +1,28 @@ + +#include +#include + +static const WC_HDR hdr = +{ + /* +00 -reserved- */ "", + /* +16 Magic string */ {'W', 'i', 'l', 'd', 'C', 'o', 'm', 'm', 'a', 'n', 'd', 'e', 'r', 'M', 'D', 'L'}, + /* +32 Format version */ 7, + /* +33 -reserved- */ "", + /* +34 Number of pages */ 1, + /* +35 Page at 0x8000 */ 0, + /* +36 Page definitions */ { + /* +0 Page, +1 NBlocks */ {0, N_BLK0} + /* */ }, + /* +48 -reserved- */ "", + /* +64 Extensions */ { + /* */ {'J', 'P', 'G'}, + /* */ {'P', 'N', 'G'}, + /* */ {'D', 'L', 'S'}, + /* */ {'D', 'X', 'P'}, + /* */ {'A', 'V', 'I'}, + /* */ }, + /* +160 0x00 */ "", + /* +161 Max file size */ 0xFFFFFFFF, + /* +165 Plugin name */ "FT812 Viewer", + /* +197 Starting condition */ SC_MENU // also run by extension +}; diff --git a/src/wc_h.h b/src/wc_h.h new file mode 100644 index 0000000..d32d3dc --- /dev/null +++ b/src/wc_h.h @@ -0,0 +1,36 @@ + +#pragma once + +#include + +typedef enum +{ + SC_EXT, + SC_ONLOAD, + SC_TIMER, + SC_MENU, +} SCOND; + +typedef struct +{ + u8 page; + u8 size; +} WC_HDR_BLK; + +typedef struct +{ + u8 res0[16]; /* +00 reserved */ + char mdl[16]; /* +16 Magic string */ + u8 ver; /* +32 Format version */ + u8 res1[1]; /* +33 reserved */ + u8 num_pages; /* +34 Number of pages */ + u8 page2; /* +35 Page at 0x8000 */ + WC_HDR_BLK blk[6]; /* +36 Page definitions */ + u8 res2[16]; /* +48 -reserved- */ + char ext[32][3]; /* +64 Extensions */ + u8 res3[1]; /* +160 0x00 */ + u32 file_max_size; /* +161 Max file size */ + char name[32]; /* +165 Plugin name */ + SCOND cond; /* +197 Starting condition */ + u8 res4[314]; /* +198 -reserved- */ +} WC_HDR;