From 18eb8db9c253601ca05dc02b2003e3a3eaebc5ed Mon Sep 17 00:00:00 2001 From: Oxore Date: Sat, 6 May 2023 21:03:55 +0300 Subject: Impl scroll A static rendering --- vdp.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 12 deletions(-) (limited to 'vdp.cpp') diff --git a/vdp.cpp b/vdp.cpp index 6817c2d..765855c 100644 --- a/vdp.cpp +++ b/vdp.cpp @@ -45,6 +45,32 @@ ((reg) = ((reg) & ~(MODESET2_M2_MASK << MODESET2_M2_SHIFT)) \ | ((v & MODESET2_M2_MASK) << MODESET2_M2_SHIFT)) +#define SCROLLA_ADDR_MASK (0x38) +#define SCROLLA_ADDR_SHIFT (10) +#define SCROLLA_ADDR_GET(reg) \ + ((((uint16_t)(reg)) & (SCROLLA_ADDR_MASK)) << SCROLLA_ADDR_SHIFT) +#define SCROLLA_ADDR_SET(reg, v) \ + ((reg) = ((reg) & ~SCROLLA_ADDR_MASK) \ + | (((uint16_t)(v) >> SCROLLA_ADDR_SHIFT) & SCROLLA_ADDR_MASK)) + +// 0: V32 CELL, 1: V64 CELL, 2: Prohibited, 3: V128 CELL +#define SCROLLSIZE_VCELL_MASK (3) +#define SCROLLSIZE_VCELL_SHIFT (4) +#define SCROLLSIZE_VCELL_GET(reg) \ + (((reg) & (SCROLLSIZE_VCELL_MASK << SCROLLSIZE_VCELL_SHIFT)) >> SCROLLSIZE_VCELL_SHIFT) +#define SCROLLSIZE_VCELL_SET(reg, v) \ + ((reg) = ((reg) & ~(SCROLLSIZE_VCELL_MASK << SCROLLSIZE_VCELL_SHIFT)) \ + | ((v & SCROLLSIZE_VCELL_MASK) << SCROLLSIZE_VCELL_SHIFT)) + +// 0: H32 CELL, 1: H64 CELL, 2: Prohibited, 3: H128 CELL +#define SCROLLSIZE_HCELL_MASK (3) +#define SCROLLSIZE_HCELL_SHIFT (0) +#define SCROLLSIZE_HCELL_GET(reg) \ + (((reg) & (SCROLLSIZE_HCELL_MASK << SCROLLSIZE_HCELL_SHIFT)) >> SCROLLSIZE_HCELL_SHIFT) +#define SCROLLSIZE_HCELL_SET(reg, v) \ + ((reg) = ((reg) & ~(SCROLLSIZE_HCELL_MASK << SCROLLSIZE_HCELL_SHIFT)) \ + | ((v & SCROLLSIZE_HCELL_MASK) << SCROLLSIZE_HCELL_SHIFT)) + #define DMASRCADRHIGH_DMD_MASK (3) #define DMASRCADRHIGH_DMD_SHIFT (6) #define DMASRCADRHIGH_DMD_GET(reg) \ @@ -53,6 +79,10 @@ ((reg) = ((reg) & ~(DMASRCADRHIGH_DMD_MASK << DMASRCADRHIGH_DMD_SHIFT)) \ | ((v & DMASRCADRHIGH_DMD_MASK) << DMASRCADRHIGH_DMD_SHIFT)) +static constexpr size_t kCellWidthPixels = 8; +static constexpr size_t kCellHeightPixels = 8; +static constexpr size_t kPixelsPerByte = 2; + uint32_t VDP::Read(const uint32_t offset, const enum bitness bitness) { uint32_t ret{}; @@ -139,6 +169,66 @@ void VDP::Write(const uint32_t offset, const enum bitness bitness, const uint32_ } } +static inline size_t scrollsize_cells_count(uint8_t xcell_value) +{ + assert(xcell_value <= 3); + // It actually returns 96 when xcell_value == 2, but it is prohibited and we + // just assume that this is not the case. + return (xcell_value + 1) * 32; +} + +static inline uint32_t RenderColorFromCRAM(uint16_t color) +{ + const uint32_t blue = ((color >> 9) & 7) << 5; + const uint32_t green = ((color >> 5) & 7) << 5; + const uint32_t red = ((color >> 1) & 7) << 5; + return 0xff000000 | (red << 16) | (green << 8) | blue; +} + +static inline uint32_t GetU32BE(const void *buf) +{ + return + (static_cast(reinterpret_cast(buf)[0]) << 24) | + (static_cast(reinterpret_cast(buf)[1]) << 16) | + (static_cast(reinterpret_cast(buf)[2]) << 8) | + (static_cast(reinterpret_cast(buf)[3]) << 0); +} + +static inline uint16_t GetU16BE(const void *buf) +{ + return + (static_cast(reinterpret_cast(buf)[0]) << 8) | + (static_cast(reinterpret_cast(buf)[1]) << 0); +} + +void VDP::renderScrollALine(const size_t line_index, const size_t hcell_count) +{ + const uint8_t scrolla_reg = _reg[static_cast(RegID::kScrollAAddress)]; + const uint16_t scrolla_addr = SCROLLA_ADDR_GET(scrolla_reg); + const size_t cy = line_index / kCellHeightPixels; + const size_t y = line_index % kCellHeightPixels; + for (size_t cx = 0; cx < hcell_count; cx++) { + if (cx * kCellWidthPixels >= kRenderWidth) { + break; + } + const uint16_t cell_id = GetU16BE( + _vram + scrolla_addr + (cy * hcell_count + cx) * sizeof(uint16_t)); + const uint32_t val = GetU32BE( + _vram + (cell_id * kCellHeightPixels + y) * (kCellWidthPixels / kPixelsPerByte)); + for (size_t x = 0; x < kCellWidthPixels; x++) { + if (cx * kCellWidthPixels + x >= kRenderWidth) { + continue; + } + const size_t color_index = (val >> ((kCellWidthPixels - 1 - x) * 4)) & 0xf; + const uint16_t cram_color = GetU16BE(_cram + color_index * sizeof(uint16_t)); + const uint32_t color = RenderColorFromCRAM(cram_color); + const size_t render_offset = + ((cy * kCellHeightPixels + y) * kRenderWidth) + cx * kCellWidthPixels + x; + _rendered_buffer[render_offset] = color; + } + } +} + bool VDP::Scanline() { const uint16_t mode_set_2 = _reg[static_cast(RegID::kModeSet2)]; @@ -146,20 +236,23 @@ bool VDP::Scanline() return true; } const uint16_t lines_per_screen = _status.pal_mode ? kLinesPerScreenPAL : kLinesPerScreenNTSC; - // TODO remove the `1 || ` part - if (1 || _lines_counter + 1 == lines_per_screen) { - for (size_t i = 0; i < render_width; i++) { + if (_lines_counter >= (int)kRenderHeight) { + // just render palette + for (size_t i = 0; i < kRenderWidth; i++) { const size_t color_index = (i * 2) % kCRAMSize; - const uint16_t cram_color = (((uint16_t)_cram[color_index]) << 8) | _cram[color_index + 1]; - const uint8_t blue = ((cram_color >> 9) & 7) << 4; - const uint8_t green = ((cram_color >> 5) & 7) << 4; - const uint8_t red = ((cram_color >> 1) & 7) << 4; - const uint32_t color = 0xff000000 | (red << 16) | (green << 8) | blue; - _rendered_buffer[render_width * _lines_counter + i] = color; + const uint16_t cram_color = GetU16BE(_cram +color_index * sizeof(uint16_t)); + const uint32_t color = RenderColorFromCRAM(cram_color); + _rendered_buffer[kRenderWidth * _lines_counter + i] = color; } } else { - for (size_t i = 0; i < render_width; i++) { - _rendered_buffer[render_width * _lines_counter + i] = 0xff000000; + // Render sprites + const uint8_t scrollsize_reg = _reg[static_cast(RegID::kScrollSize)]; + const uint8_t vcell = SCROLLSIZE_VCELL_GET(scrollsize_reg); + const uint8_t hcell = SCROLLSIZE_HCELL_GET(scrollsize_reg); + // 2 is prohibited value, so we just won't render if it is set + if (vcell != 2 && hcell != 2) { + const size_t hcell_count = scrollsize_cells_count(hcell); + renderScrollALine(_lines_counter, hcell_count); } } _lines_counter++; @@ -329,11 +422,12 @@ void VDP::writeControl(const uint16_t value) reg_val); } _reg[reg_num] = reg_val; + // TODO print warnings of all invalid values or writes that ignore a mask } else if (!_control_write_second_word) { // Write first word // CD1 CD0 A13 A12 A11 A10 A9 A8 // A7 A6 A5 A4 A3 A2 A1 A0 - _address = value & 0x3f; + _address = value & 0x3fff; _address_mode = (value >> 14) & 0x3; _control_write_second_word = true; } -- cgit v1.2.3