summaryrefslogtreecommitdiff
path: root/vdp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vdp.cpp')
-rw-r--r--vdp.cpp118
1 files changed, 106 insertions, 12 deletions
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<uint32_t>(reinterpret_cast<const uint8_t*>(buf)[0]) << 24) |
+ (static_cast<uint32_t>(reinterpret_cast<const uint8_t*>(buf)[1]) << 16) |
+ (static_cast<uint32_t>(reinterpret_cast<const uint8_t*>(buf)[2]) << 8) |
+ (static_cast<uint32_t>(reinterpret_cast<const uint8_t*>(buf)[3]) << 0);
+}
+
+static inline uint16_t GetU16BE(const void *buf)
+{
+ return
+ (static_cast<uint16_t>(reinterpret_cast<const uint8_t*>(buf)[0]) << 8) |
+ (static_cast<uint16_t>(reinterpret_cast<const uint8_t*>(buf)[1]) << 0);
+}
+
+void VDP::renderScrollALine(const size_t line_index, const size_t hcell_count)
+{
+ const uint8_t scrolla_reg = _reg[static_cast<size_t>(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<size_t>(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<size_t>(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;
}