ReC98/th04/hardware/grcg.hpp

47 lines
1.7 KiB
C++
Raw Normal View History

// Redefined versions of master.lib's grcg_setmode() and grcg_setcolor().
void near grcg_setmode_rmw_seg1(void);
void near grcg_setmode_tdw(void);
// In contrast to master.lib's own grcg_setcolor(), these keep the current
// GRCG mode, and reenable interrupts before returning.
#define grcg_setcolor_direct_seg1(col) \
_AH = col; \
grcg_setcolor_direct_seg1_raw();
void near grcg_setcolor_direct_seg1_raw(void);
void near grcg_setcolor_direct_seg3_raw(void);
// Implementation macros
// ---------------------
#define grcg_setmode_rmw_inlined() { \
outportb2(0x7C, 0xC0); \
}
// Builds the contents of a GRCG tile register from the x86 carry flag by
// extending its value to a full byte (CF=0 → 0x00, CF=1 → 0xFF).
//
// (Technically returns a dots8_t, but why add a planar.h dependency just for
// one type.)
inline uint8_t tile_register_from_carry(uint8_t unused) {
__emit__(0x1A, 0xC0); // SBB AL, AL
return _AL;
}
// And this is why [col] is stored in AH: x86 simply only supports AL as the
// source operand for OUT. By shifting each successive bit of [col] into the
// carry flag and using the function above, we get the minimum of three
// instructions (SHR, SBB, OUT) per bitplane, with no register spills. Quite a
// beautiful optimization!
#define grcg_setcolor_direct_inlined(col) { \
disable(); \
_DX = 0x7E; \
/* Just in case people want to call this with an immediate color value… */ \
_AH = col; \
outportb(_DX, tile_register_from_carry(_AH >>= 1)); \
outportb(_DX, tile_register_from_carry(_AH >>= 1)); \
outportb(_DX, tile_register_from_carry(_AH >>= 1)); \
outportb(_DX, tile_register_from_carry(_AH >>= 1)); \
enable(); \
}
// ---------------------