diff --git a/assets/xml/misc/locerrmsg.xml b/assets/xml/misc/locerrmsg.xml new file mode 100644 index 0000000000..d6f8bfdaaa --- /dev/null +++ b/assets/xml/misc/locerrmsg.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/xml/misc/memerrmsg.xml b/assets/xml/misc/memerrmsg.xml new file mode 100644 index 0000000000..92c15f4746 --- /dev/null +++ b/assets/xml/misc/memerrmsg.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/include/color.h b/include/color.h index 06cf639720..438d857ad9 100644 --- a/include/color.h +++ b/include/color.h @@ -3,6 +3,9 @@ #include "PR/ultratypes.h" +// For checking the alpha bit in an RGBA16 pixel +#define RGBA16_PIXEL_OPAQUE 1 + typedef struct { /* 0x0 */ u8 r; /* 0x1 */ u8 g; diff --git a/include/functions.h b/include/functions.h index 55945e4c84..3c8c8a2f21 100644 --- a/include/functions.h +++ b/include/functions.h @@ -15,9 +15,9 @@ s32 DmaMgr_FindDmaIndex(u32 vromAddr); const char* func_800809F4(u32 param_1); void DmaMgr_ProcessMsg(DmaRequest* req); void DmaMgr_ThreadEntry(void* arg); -s32 DmaMgr_SendRequestImpl(DmaRequest* request, void* vramStart, u32 vromStart, size_t size, UNK_TYPE4 unused, +s32 DmaMgr_SendRequestImpl(DmaRequest* request, void* vramStart, uintptr_t vromStart, size_t size, UNK_TYPE4 unused, OSMesgQueue* callback, void* callbackMesg); -s32 DmaMgr_SendRequest0(void* vramStart, u32 vromStart, size_t size); +s32 DmaMgr_SendRequest0(void* vramStart, uintptr_t vromStart, size_t size); void DmaMgr_Start(void); void DmaMgr_Stop(void); void* Yaz0_FirstDMA(void); @@ -356,8 +356,8 @@ const char* strchr(const char* __s, s32 __c); size_t strlen(const char* __s); void* memcpy(void* __dest, const void* __src, size_t __n); void osCreateMesgQueue(OSMesgQueue* mq, OSMesg* msq, s32 count); -void osInvalICache(void* vaddr, s32 nbytes); -void osInvalDCache(void* vaddr, s32 nbytes); +void osInvalICache(void* vaddr, size_t nbytes); +void osInvalDCache(void* vaddr, size_t nbytes); void __osTimerServicesInit(void); void __osTimerInterrupt(void); void __osSetTimerIntr(OSTime tim); @@ -3257,10 +3257,10 @@ s32 func_80178A94(s32 param_1, s32 param_2); // void func_80178DAC(void); // void func_80178E3C(void); // void func_80178E7C(void); -void Check_WriteRGBA16Pixel(u16* buffer, u32 x, u32 y, u16 value); -void Check_WriteI4Pixel(u16* buffer, u32 x, u32 y, u32 value); -void Check_DrawI4Texture(u16* buffer, u32 x, u32 y, u32 width, u32 height, u8* texture); -void Check_ClearRGBA16(s16* buffer); +// void Check_WriteRGBA16Pixel(u16* buffer, u32 x, u32 y, u32 value); +// void Check_WriteI4Pixel(u16* buffer, u32 x, u32 y, u32 value); +// void Check_DrawI4Texture(u16* buffer, u32 x, u32 y, u32 width, u32 height, u8* texture); +// void Check_ClearRGBA16(u16* buffer); // void Check_DrawExpansionPakErrorMessage(void); // void Check_DrawRegionLockErrorMessage(void); void Check_ExpansionPak(void); diff --git a/include/os.h b/include/os.h index 568cc17942..904d78a29f 100644 --- a/include/os.h +++ b/include/os.h @@ -1,6 +1,7 @@ #ifndef _OS_H_ #define _OS_H_ +#include "libc/stdint.h" #include "libc/stdlib.h" #include "ultra64/thread.h" #include "ultra64/message.h" @@ -84,7 +85,7 @@ typedef struct { typedef struct { /* 0x00 */ OSIoMesgHdr hdr; /* 0x08 */ void* dramAddr; - /* 0x0C */ u32 devAddr; + /* 0x0C */ uintptr_t devAddr; /* 0x10 */ size_t size; /* 0x14 */ OSPiHandle* piHandle; } OSIoMesg; // size = 0x88 diff --git a/include/segment_symbols.h b/include/segment_symbols.h index a2dc30ff39..0044936729 100644 --- a/include/segment_symbols.h +++ b/include/segment_symbols.h @@ -1161,7 +1161,9 @@ DECLARE_ROM_SEGMENT(scene_texture_07) DECLARE_ROM_SEGMENT(scene_texture_08) DECLARE_ROM_SEGMENT(nintendo_rogo_static) DECLARE_ROM_SEGMENT(title_static) +DECLARE_SEGMENT(memerrmsg) DECLARE_ROM_SEGMENT(memerrmsg) +DECLARE_SEGMENT(locerrmsg) DECLARE_ROM_SEGMENT(locerrmsg) DECLARE_ROM_SEGMENT(parameter_static) DECLARE_ROM_SEGMENT(week_static) diff --git a/include/ultra64/vi.h b/include/ultra64/vi.h index 471665e3e3..ca9b8e45eb 100644 --- a/include/ultra64/vi.h +++ b/include/ultra64/vi.h @@ -5,14 +5,14 @@ #include "ultra64/message.h" /* Special Features */ -#define OS_VI_GAMMA_ON 0x0001 -#define OS_VI_GAMMA_OFF 0x0002 -#define OS_VI_GAMMA_DITHER_ON 0x0004 -#define OS_VI_GAMMA_DITHER_OFF 0x0008 -#define OS_VI_DIVOT_ON 0x0010 -#define OS_VI_DIVOT_OFF 0x0020 -#define OS_VI_DITHER_FILTER_ON 0x0040 -#define OS_VI_DITHER_FILTER_OFF 0x0080 +#define OS_VI_GAMMA_ON (1 << 0) +#define OS_VI_GAMMA_OFF (1 << 1) +#define OS_VI_GAMMA_DITHER_ON (1 << 2) +#define OS_VI_GAMMA_DITHER_OFF (1 << 3) +#define OS_VI_DIVOT_ON (1 << 4) +#define OS_VI_DIVOT_OFF (1 << 5) +#define OS_VI_DITHER_FILTER_ON (1 << 6) +#define OS_VI_DITHER_FILTER_OFF (1 << 7) #define OS_VI_GAMMA 0x08 #define OS_VI_GAMMA_DITHER 0x04 diff --git a/include/variables.h b/include/variables.h index 033443d663..93b7790cb2 100644 --- a/include/variables.h +++ b/include/variables.h @@ -12,7 +12,7 @@ extern u32 osRomBase; extern u32 osResetType; extern u32 osCicId; extern u32 osVersion; -extern u32 osMemSize; +extern size_t osMemSize; extern s32 osAppNmiBuffer[0x10]; extern u16 gFramebuffer1[SCREEN_HEIGHT][SCREEN_WIDTH]; // at 0x80000500 extern u8 D_80025D00[]; diff --git a/include/z64.h b/include/z64.h index 5118d0c35d..dbc7b60f4f 100644 --- a/include/z64.h +++ b/include/z64.h @@ -513,6 +513,13 @@ typedef union { F3DVertexNormal normal; } F3DVertex; // size = 0x10 +// End of RDRAM without the Expansion Pak installed +#define NORMAL_RDRAM_END 0x80400000 +// End of RDRAM with the Expansion Pak installed +#define EXPANDED_RDRAM_END 0x80800000 +// Address at the end of normal RDRAM after which is room for a screen buffer +#define FAULT_FB_ADDRESS (NORMAL_RDRAM_END - sizeof(u16[SCREEN_HEIGHT][SCREEN_WIDTH])) + typedef struct { /* 0x00 */ u16* fb; /* 0x04 */ u16 w; diff --git a/spec b/spec index 05efcb13c2..c68c1cf911 100644 --- a/spec +++ b/spec @@ -8860,14 +8860,16 @@ beginseg name "memerrmsg" compress romalign 0x1000 - include "build/baserom/memerrmsg.o" + include "build/assets/misc/memerrmsg/memerrmsg.o" + number 1 endseg beginseg name "locerrmsg" compress romalign 0x1000 - include "build/baserom/locerrmsg.o" + include "build/assets/misc/locerrmsg/locerrmsg.o" + number 1 endseg beginseg diff --git a/src/boot_O2_g3/CIC6105.c b/src/boot_O2_g3/CIC6105.c index 7e9d960bf6..4745ad5c89 100644 --- a/src/boot_O2_g3/CIC6105.c +++ b/src/boot_O2_g3/CIC6105.c @@ -1,6 +1,5 @@ #include "prevent_bss_reordering.h" #include "global.h" -#include "prevent_bss_reordering.h" UNK_TYPE4 D_8009BE30; UNK_TYPE4 D_8009BE34; diff --git a/src/boot_O2_g3/fault.c b/src/boot_O2_g3/fault.c index b32b5aa98a..4c9a1a28ce 100644 --- a/src/boot_O2_g3/fault.c +++ b/src/boot_O2_g3/fault.c @@ -714,7 +714,7 @@ void Fault_CommitFB() { osViSetYScale(1.0f); osViSetMode(&osViModeNtscLan1); osViSetSpecialFeatures(0x42); // gama_disable|dither_fliter_enable_aa_mode3_disable - osViBlack(0); + osViBlack(false); if (sFaultContext->fb) { fb = sFaultContext->fb; diff --git a/src/boot_O2_g3/fault_drawer.c b/src/boot_O2_g3/fault_drawer.c index 949faadf18..41f6c17627 100644 --- a/src/boot_O2_g3/fault_drawer.c +++ b/src/boot_O2_g3/fault_drawer.c @@ -5,7 +5,7 @@ extern const u32 sFaultDrawerFont[]; FaultDrawer* sFaultDrawContext = &sFaultDrawerStruct; FaultDrawer sFaultDrawerDefault = { - (u16*)0x803DA800, // fb - TODO map out buffers in this region and avoid hard-coded pointer + (u16*)FAULT_FB_ADDRESS, // fb SCREEN_WIDTH, // w SCREEN_HEIGHT, // h 16, // yStart diff --git a/src/boot_O2_g3/idle.c b/src/boot_O2_g3/idle.c index f2cded98c2..7a1d636431 100644 --- a/src/boot_O2_g3/idle.c +++ b/src/boot_O2_g3/idle.c @@ -19,11 +19,11 @@ OSMesgQueue gPiMgrCmdQ; void Idle_ClearMemory(void* begin, void* end) { if (begin < end) { - bzero(begin, (u32)end - (u32)begin); + bzero(begin, (uintptr_t)end - (uintptr_t)begin); } } -void Idle_InitFramebuffer(u32* ptr, u32 numBytes, u32 value) { +void Idle_InitFramebuffer(u32* ptr, size_t numBytes, u32 value) { s32 temp = sizeof(u32); while (numBytes) { @@ -36,7 +36,7 @@ void Idle_InitScreen(void) { Idle_InitFramebuffer((u32*)gFramebuffer1, 0x25800, 0x00010001); ViConfig_UpdateVi(0); osViSwapBuffer(gFramebuffer1); - osViBlack(0); + osViBlack(false); } void Idle_InitMemory(void) { @@ -52,7 +52,7 @@ void Idle_InitCodeAndMemory(void) { DmaRequest dmaReq; OSMesgQueue queue; OSMesg mesg; - u32 oldSize; + size_t oldSize; osCreateMesgQueue(&queue, &mesg, 1); @@ -71,7 +71,7 @@ void Idle_InitCodeAndMemory(void) { } void Main_ThreadEntry(void* arg) { - StackCheck_Init(&sIrqMgrStackInfo, sIrqMgrStack, sIrqMgrStack + sizeof(sIrqMgrStack), 0, 256, "irqmgr"); + StackCheck_Init(&sIrqMgrStackInfo, sIrqMgrStack, sIrqMgrStack + sizeof(sIrqMgrStack), 0, 0x100, "irqmgr"); IrqMgr_Init(&gIrqMgr, &sIrqMgrStackInfo, Z_PRIORITY_IRQMGR, 1); DmaMgr_Start(); Idle_InitCodeAndMemory(); @@ -87,15 +87,15 @@ void Idle_InitVideo(void) { gViConfigYScale = 1.0; switch (osTvType) { - case 1: + case OS_TV_NTSC: D_8009B290 = 2; gViConfigMode = osViModeNtscLan1; break; - case 2: + case OS_TV_MPAL: D_8009B290 = 30; gViConfigMode = osViModeMpalLan1; break; - case 0: + case OS_TV_PAL: D_8009B290 = 44; gViConfigMode = osViModeFpalLan1; gViConfigYScale = 0.833f; @@ -108,7 +108,7 @@ void Idle_InitVideo(void) { void Idle_ThreadEntry(void* arg) { Idle_InitVideo(); osCreatePiManager(150, &gPiMgrCmdQ, sPiMgrCmdBuff, ARRAY_COUNT(sPiMgrCmdBuff)); - StackCheck_Init(&sMainStackInfo, sMainStack, sMainStack + sizeof(sMainStack), 0, 1024, "main"); + StackCheck_Init(&sMainStackInfo, sMainStack, sMainStack + sizeof(sMainStack), 0, 0x400, "main"); osCreateThread(&gMainThread, Z_THREAD_ID_MAIN, Main_ThreadEntry, arg, sMainStack + sizeof(sMainStack), Z_PRIORITY_MAIN); osStartThread(&gMainThread); diff --git a/src/boot_O2_g3/viconfig.c b/src/boot_O2_g3/viconfig.c index d32fc9b918..6539421e69 100644 --- a/src/boot_O2_g3/viconfig.c +++ b/src/boot_O2_g3/viconfig.c @@ -3,13 +3,13 @@ void ViConfig_UpdateVi(u32 mode) { if (mode != 0) { switch (osTvType) { - case 2: + case OS_TV_MPAL: osViSetMode(&osViModeMpalLan1); break; - case 0: + case OS_TV_PAL: osViSetMode(&osViModePalLan1); break; - case 1: + case OS_TV_NTSC: default: osViSetMode(&osViModeNtscLan1); break; @@ -47,8 +47,8 @@ void ViConfig_UpdateVi(u32 mode) { void ViConfig_UpdateBlack(void) { if (gViConfigUseDefault != 0) { - osViBlack(1); + osViBlack(true); } else { - osViBlack(0); + osViBlack(false); } } diff --git a/src/boot_O2_g3/z_std_dma.c b/src/boot_O2_g3/z_std_dma.c index 2903b488f6..25fc8fbb08 100644 --- a/src/boot_O2_g3/z_std_dma.c +++ b/src/boot_O2_g3/z_std_dma.c @@ -9,12 +9,12 @@ OSMesg sDmaMgrMsgs[32]; OSThread sDmaMgrThread; u8 sDmaMgrStack[0x500]; -s32 DmaMgr_DMARomToRam(u32 rom, void* ram, size_t size) { +s32 DmaMgr_DMARomToRam(uintptr_t rom, void* ram, size_t size) { OSIoMesg ioMsg; OSMesgQueue queue; OSMesg msg[1]; s32 ret; - u32 buffSize = sDmaMgrDmaBuffSize; + size_t buffSize = sDmaMgrDmaBuffSize; osInvalDCache(ram, size); osCreateMesgQueue(&queue, msg, ARRAY_COUNT(msg)); @@ -23,7 +23,7 @@ s32 DmaMgr_DMARomToRam(u32 rom, void* ram, size_t size) { while (buffSize < size) { ioMsg.hdr.pri = 0; ioMsg.hdr.retQueue = &queue; - ioMsg.devAddr = (u32)rom; + ioMsg.devAddr = rom; ioMsg.dramAddr = ram; ioMsg.size = buffSize; ret = osEPiStartDma(gCartHandle, &ioMsg, 0); @@ -39,9 +39,9 @@ s32 DmaMgr_DMARomToRam(u32 rom, void* ram, size_t size) { } ioMsg.hdr.pri = 0; ioMsg.hdr.retQueue = &queue; - ioMsg.devAddr = (u32)rom; + ioMsg.devAddr = rom; ioMsg.dramAddr = ram; - ioMsg.size = (u32)size; + ioMsg.size = size; ret = osEPiStartDma(gCartHandle, &ioMsg, 0); if (ret) { goto END; @@ -109,11 +109,11 @@ const char* func_800809F4(u32 a0) { } void DmaMgr_ProcessMsg(DmaRequest* req) { - u32 vrom; + uintptr_t vrom; void* ram; size_t size; - u32 romStart; - u32 romSize; + uintptr_t romStart; + size_t romSize; DmaEntry* dmaEntry; s32 index; @@ -172,7 +172,7 @@ void DmaMgr_ThreadEntry(void* a0) { } } -s32 DmaMgr_SendRequestImpl(DmaRequest* request, void* vramStart, u32 vromStart, size_t size, UNK_TYPE4 unused, +s32 DmaMgr_SendRequestImpl(DmaRequest* request, void* vramStart, uintptr_t vromStart, size_t size, UNK_TYPE4 unused, OSMesgQueue* queue, OSMesg msg) { if (gIrqMgrResetStatus >= 2) { return -2; @@ -190,7 +190,7 @@ s32 DmaMgr_SendRequestImpl(DmaRequest* request, void* vramStart, u32 vromStart, return 0; } -s32 DmaMgr_SendRequest0(void* vramStart, u32 vromStart, size_t size) { +s32 DmaMgr_SendRequest0(void* vramStart, uintptr_t vromStart, size_t size) { DmaRequest req; OSMesgQueue queue; OSMesg msg[1]; diff --git a/src/code/sys_initial_check.c b/src/code/sys_initial_check.c index 7b0a26cc89..84871255b8 100644 --- a/src/code/sys_initial_check.c +++ b/src/code/sys_initial_check.c @@ -1,17 +1,116 @@ +/** + * File: sys_initial_check.c + * Description: Functions for checking for the presence of the Expansion Pak and the correct TV type (PAL/NTSC/MPAL), + * and functions for printing error messages directly to screen if not found or incorrect. + * + * These checks are some of the first functions run in Main, before even setting up the system heap, and any image files + * are DMA'd directly to fixed RAM addresses. + */ #include "global.h" +#include "misc/locerrmsg/locerrmsg.h" +#include "misc/memerrmsg/memerrmsg.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_WriteRGBA16Pixel.s") +#define SIZEOF_LOCERRMSG (sizeof(gNotDesignedForSystemErrorTex)) +#define SIZEOF_MEMERRMSG (sizeof(gExpansionPakNotInstalledErrorTex) + sizeof(gSeeInstructionBookletErrorTex)) -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_WriteI4Pixel.s") +// Address with enough room after to load either of the error message image files before the fault screen buffer at the +// end of RDRAM +#define CHECK_ERRMSG_STATIC_SEGMENT (u8*)(FAULT_FB_ADDRESS - MAX(SIZEOF_LOCERRMSG, SIZEOF_MEMERRMSG)) -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_DrawI4Texture.s") +void Check_WriteRGBA16Pixel(u16* buffer, u32 x, u32 y, u32 value) { + if (value & RGBA16_PIXEL_OPAQUE) { + (&buffer[x])[y * SCREEN_WIDTH] = value; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_ClearRGBA16.s") +void Check_WriteI4Pixel(u16* buffer, u32 x, u32 y, u32 value) { + Check_WriteRGBA16Pixel(buffer, x, y, value * GPACK_RGBA5551(16, 16, 16, 0) + GPACK_RGBA5551(12, 12, 12, 1)); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_DrawExpansionPakErrorMessage.s") +/** + * x and y are the coordinates of the bottom-left corner. + */ +void Check_DrawI4Texture(u16* buffer, s32 x, s32 y, s32 width, s32 height, u8* texture) { + s32 v; + s32 u; + u8 pixelPair; + u8* pixelPairPtr = texture; -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_DrawRegionLockErrorMessage.s") + // I4 textures are bitpacked 2 pixels per byte, so this writes a pair of pixels in each iteration using bitmasking. + for (v = 0; v < height; v++) { + for (u = 0; u < width; u += 2, pixelPairPtr++) { + pixelPair = *pixelPairPtr; + Check_WriteI4Pixel(buffer, x + u, y + v, pixelPair >> 4); + pixelPair = *pixelPairPtr; + Check_WriteI4Pixel(buffer, x + u + 1, y + v, pixelPair & 0xF); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_ExpansionPak.s") +void Check_ClearRGBA16(u16* buffer) { + u32 x; + u32 y; -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_initial_check/Check_RegionIsSupported.s") + for (y = 0; y < SCREEN_HEIGHT; y++) { + for (x = 0; x < SCREEN_WIDTH; x++) { + Check_WriteRGBA16Pixel(buffer, x, y, 1); + } + } +} + +/** + * Draw error message textures directly to a screen buffer at the end of normal RDRAM + */ +void Check_DrawExpansionPakErrorMessage(void) { + DmaMgr_SendRequest0(CHECK_ERRMSG_STATIC_SEGMENT, SEGMENT_ROM_START(memerrmsg), SEGMENT_SIZE(memerrmsg)); + Check_ClearRGBA16((u16*)FAULT_FB_ADDRESS); + Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 96, 71, 128, 37, CHECK_ERRMSG_STATIC_SEGMENT); + Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 96, 127, 128, 37, + CHECK_ERRMSG_STATIC_SEGMENT + sizeof(gExpansionPakNotInstalledErrorTex)); + osWritebackDCacheAll(); + osViSwapBuffer((u16*)FAULT_FB_ADDRESS); + osViBlack(false); +} + +/** + * Draw error message texture directly to a screen buffer at the end of normal RDRAM + */ +void Check_DrawRegionLockErrorMessage(void) { + DmaMgr_SendRequest0(CHECK_ERRMSG_STATIC_SEGMENT, SEGMENT_ROM_START(locerrmsg), SEGMENT_SIZE(locerrmsg)); + Check_ClearRGBA16((u16*)FAULT_FB_ADDRESS); + Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 56, 112, 208, 16, CHECK_ERRMSG_STATIC_SEGMENT); + osWritebackDCacheAll(); + osViSwapBuffer((u16*)FAULT_FB_ADDRESS); + osViBlack(false); +} + +/** + * If Expansion pak is not installed, display error message until console is turned off + */ +void Check_ExpansionPak(void) { + // Expansion pak installed + if (osMemSize >= 0x800000) { + return; + } + + Check_DrawExpansionPakErrorMessage(); + osDestroyThread(NULL); + while (true) {} +} + +/** + * If region is not NTSC or MPAL, display error message until console is turned off + */ +void Check_RegionIsSupported(void) { + s32 regionSupported = false; + + if ((osTvType == OS_TV_NTSC) || (osTvType == OS_TV_MPAL)) { + regionSupported = true; + } + + if (!regionSupported) { + Check_DrawRegionLockErrorMessage(); + osDestroyThread(NULL); + while (true) {} + } +} diff --git a/src/libultra/io/viblack.c b/src/libultra/io/viblack.c index abc0b3b204..6b8fec9536 100644 --- a/src/libultra/io/viblack.c +++ b/src/libultra/io/viblack.c @@ -8,7 +8,7 @@ void osViBlack(u8 active) { if (active) { __osViNext->state |= 0x20; } else { - __osViNext->state &= 0xffdf; + __osViNext->state &= ~0x20; } __osRestoreInt(saveMask); diff --git a/src/libultra/io/visetspecial.c b/src/libultra/io/visetspecial.c index 6e7a6ac43a..a5ef1220a4 100644 --- a/src/libultra/io/visetspecial.c +++ b/src/libultra/io/visetspecial.c @@ -3,34 +3,33 @@ void osViSetSpecialFeatures(u32 func) { register u32 saveMask = __osDisableInt(); - if (func & 1) { - __osViNext->features |= 8; + if (func & OS_VI_GAMMA_ON) { + __osViNext->features |= OS_VI_GAMMA; } - if (func & 2) { - __osViNext->features &= ~8; + if (func & OS_VI_GAMMA_OFF) { + __osViNext->features &= ~OS_VI_GAMMA; } - if (func & 4) { - __osViNext->features |= 4; + if (func & OS_VI_GAMMA_DITHER_ON) { + __osViNext->features |= OS_VI_GAMMA_DITHER; } - if (func & 8) { + if (func & OS_VI_GAMMA_DITHER_OFF) { + __osViNext->features &= ~OS_VI_GAMMA_DITHER; + } + if (func & OS_VI_DIVOT_ON) { - __osViNext->features &= ~4; + __osViNext->features |= OS_VI_DIVOT; } - if (func & 0x10) { + if (func & OS_VI_DIVOT_OFF) { - __osViNext->features |= 0x10; + __osViNext->features &= ~OS_VI_DIVOT; } - if (func & 0x20) { - - __osViNext->features &= ~0x10; + if (func & OS_VI_DITHER_FILTER_ON) { + __osViNext->features |= OS_VI_DITHER_FILTER; + __osViNext->features &= ~(OS_VI_UNK100 | OS_VI_UNK200); } - if (func & 0x40) { - __osViNext->features |= 0x10000; - __osViNext->features &= ~0x300; - } - if (func & 0x80) { - __osViNext->features &= ~0x10000; - __osViNext->features |= __osViNext->modep->comRegs.ctrl & 0x300; + if (func & OS_VI_DITHER_FILTER_OFF) { + __osViNext->features &= ~OS_VI_DITHER_FILTER; + __osViNext->features |= __osViNext->modep->comRegs.ctrl & (OS_VI_UNK100 | OS_VI_UNK200); } __osViNext->state |= 8;