io: add display unit
added rendering for modes 3,4,5 also changed how memory structuring works Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
@@ -2,9 +2,8 @@
|
||||
|
||||
#include "header.hh"
|
||||
#include "io/io.hh"
|
||||
#include "memory.hh"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
namespace matar {
|
||||
@@ -85,7 +84,7 @@ class Bus {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::optional<T> read(uint32_t address) const;
|
||||
T read(uint32_t address) const;
|
||||
|
||||
template<typename T>
|
||||
void write(uint32_t address, T value);
|
||||
@@ -101,45 +100,11 @@ class Bus {
|
||||
static constexpr decltype(cycle_map) init_cycle_count();
|
||||
|
||||
std::unique_ptr<IoDevices> io;
|
||||
Memory<BIOS_SIZE> bios = {};
|
||||
Memory<0x40000> board_wram = {};
|
||||
Memory<0x80000> chip_wram = {};
|
||||
Memory<> rom;
|
||||
|
||||
#define MEMORY_REGION(name, start) \
|
||||
static constexpr uint32_t name##_START = start; \
|
||||
static constexpr uint8_t name##_REGION = start >> 24 & 0xF;
|
||||
|
||||
#define DECL_MEMORY(name, ident, start, end) \
|
||||
MEMORY_REGION(name, start) \
|
||||
std::array<uint8_t, end - start + 1> ident = {};
|
||||
|
||||
MEMORY_REGION(BIOS, 0x00000000)
|
||||
std::array<uint8_t, BIOS_SIZE> bios = {};
|
||||
|
||||
// board working RAM
|
||||
DECL_MEMORY(BOARD_WRAM, board_wram, 0x02000000, 0x0203FFFF)
|
||||
|
||||
// chip working RAM
|
||||
DECL_MEMORY(CHIP_WRAM, chip_wram, 0x03000000, 0x03007FFF)
|
||||
|
||||
// palette RAM
|
||||
DECL_MEMORY(PALETTE_RAM, palette_ram, 0x05000000, 0x050003FF)
|
||||
|
||||
// video RAM
|
||||
DECL_MEMORY(VRAM, vram, 0x06000000, 0x06017FFF)
|
||||
|
||||
// OAM OBJ attributes
|
||||
DECL_MEMORY(OAM_OBJ_ATTR, oam_obj_attr, 0x07000000, 0x070003FF)
|
||||
|
||||
#undef DECL_MEMORY
|
||||
|
||||
MEMORY_REGION(ROM_0, 0x08000000)
|
||||
MEMORY_REGION(ROM_1, 0x0A000000)
|
||||
MEMORY_REGION(ROM_2, 0x0C000000)
|
||||
|
||||
MEMORY_REGION(IO, 0x04000000)
|
||||
static constexpr uint32_t IO_END = 0x040003FE;
|
||||
|
||||
#undef MEMORY_REGION
|
||||
|
||||
std::vector<uint8_t> rom;
|
||||
Header header;
|
||||
void parse_header();
|
||||
};
|
||||
|
159
include/io/display/display.hh
Normal file
159
include/io/display/display.hh
Normal file
@@ -0,0 +1,159 @@
|
||||
#include "memory.hh"
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
|
||||
namespace matar {
|
||||
namespace display {
|
||||
static constexpr int LCD_WIDTH = 240;
|
||||
|
||||
// there are 5 modes
|
||||
static constexpr uint N_MODES = 6;
|
||||
// there are 4 backgrounds that can be layered depending on mode
|
||||
// there is also 1 object layer
|
||||
static constexpr uint N_BACKGROUNDS = 4;
|
||||
|
||||
static constexpr uint32_t PRAM_START = 0x5000000;
|
||||
static constexpr uint32_t VRAM_START = 0x6000000;
|
||||
static constexpr uint32_t OAM_START = 0x7000000;
|
||||
|
||||
template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
|
||||
struct Point {
|
||||
T x;
|
||||
T y;
|
||||
};
|
||||
|
||||
struct Color {
|
||||
public:
|
||||
Color(uint16_t raw)
|
||||
: red(raw & 0b11111)
|
||||
, green(raw >> 5 & 0b11111)
|
||||
, blue(raw >> 10 & 0b11111) {}
|
||||
|
||||
uint16_t read() const {
|
||||
return (red & 0b11111) | ((green << 5) & 0b11111) |
|
||||
((blue << 10) & 0b11111);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
|
||||
struct DisplayControl {
|
||||
struct {
|
||||
uint8_t mode : 3;
|
||||
int : 1; // unused
|
||||
bool frame_select_1 : 1;
|
||||
bool hblank_free_interval : 1;
|
||||
bool obj_character_vram_mapping : 1;
|
||||
bool forced_blank : 1;
|
||||
bool screen_display_0 : 1;
|
||||
bool screen_display_1 : 1;
|
||||
bool screen_display_2 : 1;
|
||||
bool screen_display_3 : 1;
|
||||
bool screen_display_obj : 1;
|
||||
bool window_display_0 : 1;
|
||||
bool window_display_1 : 1;
|
||||
bool obj_window_display : 1;
|
||||
} value;
|
||||
|
||||
uint16_t read() const { return std::bit_cast<uint16_t>(value); };
|
||||
void write(uint16_t raw) { value = std::bit_cast<decltype(value)>(raw); };
|
||||
};
|
||||
|
||||
struct DisplayStatus {
|
||||
struct {
|
||||
bool vblank_flag : 1;
|
||||
bool hblank_flag : 1;
|
||||
bool vcounter_flag : 1;
|
||||
bool vblank_irq_enable : 1;
|
||||
bool hblank_irq_enable : 1;
|
||||
bool vcounter_irq_enable : 1;
|
||||
int : 2; // unused
|
||||
uint8_t vcount_setting : 8;
|
||||
} value;
|
||||
|
||||
uint16_t read() const { return std::bit_cast<uint16_t>(value); };
|
||||
void write(uint16_t raw) { value = std::bit_cast<decltype(value)>(raw); };
|
||||
};
|
||||
|
||||
struct BackgroundControl {
|
||||
struct {
|
||||
uint8_t priority : 2;
|
||||
uint8_t character_base_block : 2;
|
||||
int : 2; // unused
|
||||
bool mosaic : 1;
|
||||
bool colors256 : 1;
|
||||
uint8_t screen_base_block : 5;
|
||||
bool bg_2_3_wraparound : 1;
|
||||
uint8_t screen_size : 2;
|
||||
} value;
|
||||
|
||||
uint16_t read() const { return std::bit_cast<uint16_t>(value); };
|
||||
void write(uint16_t raw) { value = std::bit_cast<decltype(value)>(raw); };
|
||||
};
|
||||
|
||||
struct RotationScaling {
|
||||
// these are all 16 bit signed "fixed point" floats
|
||||
// shifted by 8
|
||||
int16_t a;
|
||||
int16_t b;
|
||||
int16_t c;
|
||||
int16_t d;
|
||||
|
||||
// following points have 28 bit signed "fixed point" floats as coords
|
||||
// shifted by 8
|
||||
Point<int32_t> ref;
|
||||
|
||||
private:
|
||||
Point<int32_t> internal [[maybe_unused]]
|
||||
;
|
||||
};
|
||||
|
||||
struct Display {
|
||||
public:
|
||||
using u16 = uint16_t;
|
||||
|
||||
Memory<0x400> pram;
|
||||
Memory<0x18000> vram;
|
||||
Memory<0x400> oam;
|
||||
|
||||
DisplayControl lcd_control;
|
||||
DisplayStatus general_lcd_status;
|
||||
u16 vertical_counter;
|
||||
BackgroundControl bg_control[4];
|
||||
Point<u16> bg0_offset;
|
||||
Point<u16> bg1_offset;
|
||||
Point<u16> bg2_offset;
|
||||
Point<u16> bg3_offset;
|
||||
RotationScaling bg2_rot_scale;
|
||||
RotationScaling bg3_rot_scale;
|
||||
u16 win0_horizontal_dimensions;
|
||||
u16 win1_horizontal_dimensions;
|
||||
u16 win0_vertical_dimensions;
|
||||
u16 win1_vertical_dimensions;
|
||||
u16 inside_win_0_1;
|
||||
u16 outside_win;
|
||||
u16 mosaic_size;
|
||||
u16 color_special_effects_selection;
|
||||
u16 alpha_blending_coefficients;
|
||||
u16 brightness_coefficient;
|
||||
|
||||
private:
|
||||
// 1 color is 16 bits in ARGB555 format
|
||||
std::array<std::array<uint16_t, LCD_WIDTH>, N_BACKGROUNDS> scanline_buffers;
|
||||
|
||||
template<int MODE,
|
||||
typename = std::enable_if_t<MODE == 3 || MODE == 4 || MODE == 5>>
|
||||
void render_bitmap_mode();
|
||||
|
||||
template<int LAYER, typename = std::enable_if_t<LAYER >= 0 && LAYER <= 3>>
|
||||
void render_text_layer();
|
||||
};
|
||||
}
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-avoid-c-arrays)
|
39
include/io/dma.hh
Normal file
39
include/io/dma.hh
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
|
||||
namespace matar {
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
|
||||
struct DmaControl {
|
||||
struct {
|
||||
int : 4; // this is supposed to be 5 bits, however, to align the struct
|
||||
// to 16 bits, we will adjust for the first LSB in the
|
||||
// read/write
|
||||
uint8_t dst_adjustment : 2;
|
||||
uint8_t src_adjustment : 2;
|
||||
bool repeat : 1;
|
||||
bool transfer_32 : 1;
|
||||
int : 1;
|
||||
uint8_t start_timing : 2;
|
||||
bool irq_enable : 1;
|
||||
bool enable : 1;
|
||||
} value;
|
||||
|
||||
uint16_t read() const { return std::bit_cast<uint16_t>(value) << 1; };
|
||||
void write(uint16_t raw) {
|
||||
value = std::bit_cast<decltype(value)>(static_cast<uint16_t>(raw >> 1));
|
||||
};
|
||||
};
|
||||
|
||||
struct Dma {
|
||||
using u16 = uint16_t;
|
||||
|
||||
struct {
|
||||
u16 source[2];
|
||||
u16 destination[2];
|
||||
u16 word_count;
|
||||
DmaControl control;
|
||||
} channels[4];
|
||||
};
|
||||
// NOLINTEND(cppcoreguidelines-avoid-c-arrays)
|
||||
|
||||
}
|
@@ -1,11 +1,14 @@
|
||||
#pragma once
|
||||
#include "lcd.hh"
|
||||
|
||||
#include "display/display.hh"
|
||||
#include "dma.hh"
|
||||
#include "sound.hh"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace matar {
|
||||
class Bus;
|
||||
class Bus; // forward declaration
|
||||
|
||||
class IoDevices {
|
||||
public:
|
||||
IoDevices(std::weak_ptr<Bus>);
|
||||
@@ -30,9 +33,11 @@ class IoDevices {
|
||||
bool low_power_mode;
|
||||
} system = {};
|
||||
|
||||
struct lcd lcd = {};
|
||||
struct sound sound = {};
|
||||
display::Display display = {};
|
||||
Sound sound = {};
|
||||
Dma dma = {};
|
||||
|
||||
std::weak_ptr<Bus> bus;
|
||||
friend class Bus;
|
||||
};
|
||||
}
|
||||
|
@@ -1,84 +0,0 @@
|
||||
#include <cstdint>
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
|
||||
|
||||
/*
|
||||
4000000h 2 R/W DISPCNT LCD Control
|
||||
4000002h 2 R/W - Undocumented - Green Swap
|
||||
4000004h 2 R/W DISPSTAT General LCD Status (STAT,LYC)
|
||||
4000006h 2 R VCOUNT Vertical Counter (LY)
|
||||
4000008h 2 R/W BG0CNT BG0 Control
|
||||
400000Ah 2 R/W BG1CNT BG1 Control
|
||||
400000Ch 2 R/W BG2CNT BG2 Control
|
||||
400000Eh 2 R/W BG3CNT BG3 Control
|
||||
4000010h 2 W BG0HOFS BG0 X-Offset
|
||||
4000012h 2 W BG0VOFS BG0 Y-Offset
|
||||
4000014h 2 W BG1HOFS BG1 X-Offset
|
||||
4000016h 2 W BG1VOFS BG1 Y-Offset
|
||||
4000018h 2 W BG2HOFS BG2 X-Offset
|
||||
400001Ah 2 W BG2VOFS BG2 Y-Offset
|
||||
400001Ch 2 W BG3HOFS BG3 X-Offset
|
||||
400001Eh 2 W BG3VOFS BG3 Y-Offset
|
||||
4000020h 2 W BG2PA BG2 Rotation/Scaling Parameter A (dx)
|
||||
4000022h 2 W BG2PB BG2 Rotation/Scaling Parameter B (dmx)
|
||||
4000024h 2 W BG2PC BG2 Rotation/Scaling Parameter C (dy)
|
||||
4000026h 2 W BG2PD BG2 Rotation/Scaling Parameter D (dmy)
|
||||
4000028h 4 W BG2X BG2 Reference Point X-Coordinate
|
||||
400002Ch 4 W BG2Y BG2 Reference Point Y-Coordinate
|
||||
4000030h 2 W BG3PA BG3 Rotation/Scaling Parameter A (dx)
|
||||
4000032h 2 W BG3PB BG3 Rotation/Scaling Parameter B (dmx)
|
||||
4000034h 2 W BG3PC BG3 Rotation/Scaling Parameter C (dy)
|
||||
4000036h 2 W BG3PD BG3 Rotation/Scaling Parameter D (dmy)
|
||||
4000038h 4 W BG3X BG3 Reference Point X-Coordinate
|
||||
400003Ch 4 W BG3Y BG3 Reference Point Y-Coordinate
|
||||
4000040h 2 W WIN0H Window 0 Horizontal Dimensions
|
||||
4000042h 2 W WIN1H Window 1 Horizontal Dimensions
|
||||
4000044h 2 W WIN0V Window 0 Vertical Dimensions
|
||||
4000046h 2 W WIN1V Window 1 Vertical Dimensions
|
||||
4000048h 2 R/W WININ Inside of Window 0 and 1
|
||||
400004Ah 2 R/W WINOUT Inside of OBJ Window & Outside of Windows
|
||||
400004Ch 2 W MOSAIC Mosaic Size
|
||||
400004Eh - - Not used
|
||||
4000050h 2 R/W BLDCNT Color Special Effects Selection
|
||||
4000052h 2 R/W BLDALPHA Alpha Blending Coefficients
|
||||
4000054h 2 W BLDY Brightness (Fade-In/Out) Coefficient
|
||||
4000056h - - Not used
|
||||
*/
|
||||
|
||||
struct lcd {
|
||||
using u16 = uint16_t;
|
||||
|
||||
u16 lcd_control;
|
||||
u16 general_lcd_status;
|
||||
u16 vertical_counter;
|
||||
u16 bg0_control;
|
||||
u16 bg1_control;
|
||||
u16 bg2_control;
|
||||
u16 bg3_control;
|
||||
u16 bg0_x_offset;
|
||||
u16 bg0_y_offset;
|
||||
u16 bg1_x_offset;
|
||||
u16 bg1_y_offset;
|
||||
u16 bg2_x_offset;
|
||||
u16 bg2_y_offset;
|
||||
u16 bg3_x_offset;
|
||||
u16 bg3_y_offset;
|
||||
u16 bg2_rot_scaling_parameters[4];
|
||||
u16 bg2_reference_x[2];
|
||||
u16 bg2_reference_y[2];
|
||||
u16 bg3_rot_scaling_parameters[4];
|
||||
u16 bg3_reference_x[2];
|
||||
u16 bg3_reference_y[2];
|
||||
u16 win0_horizontal_dimensions;
|
||||
u16 win1_horizontal_dimensions;
|
||||
u16 win0_vertical_dimensions;
|
||||
u16 win1_vertical_dimensions;
|
||||
u16 inside_win_0_1;
|
||||
u16 outside_win;
|
||||
u16 mosaic_size;
|
||||
u16 color_special_effects_selection;
|
||||
u16 alpha_blending_coefficients;
|
||||
u16 brightness_coefficient;
|
||||
};
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-avoid-c-arrays)
|
@@ -30,7 +30,7 @@
|
||||
40000A4h 4 W FIFO_B Channel B FIFO, Data 0-3
|
||||
*/
|
||||
|
||||
struct sound {
|
||||
struct Sound {
|
||||
using u16 = uint16_t;
|
||||
|
||||
// channel 1
|
||||
|
60
include/memory.hh
Normal file
60
include/memory.hh
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
// ill use [] instead of at because i dont want if (...) throw conditions for
|
||||
// all accesses to improve performance (?)
|
||||
|
||||
// we are also not gonna perform bound checks, as i expect the user to handle
|
||||
// those
|
||||
|
||||
namespace matar {
|
||||
template<std::size_t N = 0>
|
||||
class Memory {
|
||||
// we can use either a vector or an array with this
|
||||
using Container = std::
|
||||
conditional_t<(N != 0), std::array<uint8_t, N>, std::vector<uint8_t>>;
|
||||
|
||||
public:
|
||||
Memory() = default;
|
||||
Memory(auto x)
|
||||
: memory(x) {}
|
||||
|
||||
uint8_t read_byte(std::size_t idx) const { return memory[idx]; }
|
||||
|
||||
void write_byte(std::size_t idx, uint8_t byte) { memory[idx] = byte; }
|
||||
|
||||
uint16_t read_halfword(std::size_t idx) const {
|
||||
return memory[idx] | memory[idx + 1] << 8;
|
||||
}
|
||||
|
||||
void write_halfword(std::size_t idx, uint16_t halfword) {
|
||||
memory[idx] = halfword & 0xFF;
|
||||
memory[idx + 1] = halfword >> 8 & 0xFF;
|
||||
}
|
||||
|
||||
uint32_t read_word(std::size_t idx) const {
|
||||
return memory[idx] | memory[idx + 1] << 8 | memory[idx + 2] << 16 |
|
||||
memory[idx + 3] << 24;
|
||||
}
|
||||
|
||||
void write_word(std::size_t idx, uint32_t word) {
|
||||
memory[idx] = word & 0xFF;
|
||||
memory[idx + 1] = word >> 8 & 0xFF;
|
||||
memory[idx + 2] = word >> 16 & 0xFF;
|
||||
memory[idx + 3] = word >> 24 & 0xFF;
|
||||
}
|
||||
|
||||
uint8_t& operator[](std::size_t idx) { return memory.at(idx); }
|
||||
|
||||
Container& data() { return memory; }
|
||||
|
||||
std::size_t size() const { return memory.size(); }
|
||||
|
||||
private:
|
||||
Container memory;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user