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 "header.hh"
|
||||||
#include "io/io.hh"
|
#include "io/io.hh"
|
||||||
|
#include "memory.hh"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
|
||||||
#include <span>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
@@ -85,7 +84,7 @@ class Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::optional<T> read(uint32_t address) const;
|
T read(uint32_t address) const;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void write(uint32_t address, T value);
|
void write(uint32_t address, T value);
|
||||||
@@ -101,45 +100,11 @@ class Bus {
|
|||||||
static constexpr decltype(cycle_map) init_cycle_count();
|
static constexpr decltype(cycle_map) init_cycle_count();
|
||||||
|
|
||||||
std::unique_ptr<IoDevices> io;
|
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;
|
Header header;
|
||||||
void parse_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
|
#pragma once
|
||||||
#include "lcd.hh"
|
|
||||||
|
#include "display/display.hh"
|
||||||
|
#include "dma.hh"
|
||||||
#include "sound.hh"
|
#include "sound.hh"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
class Bus;
|
class Bus; // forward declaration
|
||||||
|
|
||||||
class IoDevices {
|
class IoDevices {
|
||||||
public:
|
public:
|
||||||
IoDevices(std::weak_ptr<Bus>);
|
IoDevices(std::weak_ptr<Bus>);
|
||||||
@@ -30,9 +33,11 @@ class IoDevices {
|
|||||||
bool low_power_mode;
|
bool low_power_mode;
|
||||||
} system = {};
|
} system = {};
|
||||||
|
|
||||||
struct lcd lcd = {};
|
display::Display display = {};
|
||||||
struct sound sound = {};
|
Sound sound = {};
|
||||||
|
Dma dma = {};
|
||||||
|
|
||||||
std::weak_ptr<Bus> bus;
|
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
|
40000A4h 4 W FIFO_B Channel B FIFO, Data 0-3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct sound {
|
struct Sound {
|
||||||
using u16 = uint16_t;
|
using u16 = uint16_t;
|
||||||
|
|
||||||
// channel 1
|
// 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;
|
||||||
|
};
|
||||||
|
}
|
81
src/bus.cc
81
src/bus.cc
@@ -5,13 +5,32 @@
|
|||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
#define MEMORY(AREA, start) \
|
||||||
|
static constexpr uint32_t AREA##_START = start; \
|
||||||
|
static constexpr uint8_t AREA##_REGION = (AREA##_START >> 24) & 0xFF;
|
||||||
|
|
||||||
|
MEMORY(BIOS, 0x0000000);
|
||||||
|
MEMORY(BOARD_WRAM, 0x2000000);
|
||||||
|
MEMORY(CHIP_WRAM, 0x3000000);
|
||||||
|
MEMORY(PRAM, display::PRAM_START);
|
||||||
|
MEMORY(VRAM, display::VRAM_START);
|
||||||
|
MEMORY(OAM, display::OAM_START);
|
||||||
|
MEMORY(ROM_0, 0x8000000);
|
||||||
|
MEMORY(ROM_1, 0xA000000);
|
||||||
|
MEMORY(ROM_2, 0xC000000);
|
||||||
|
static constexpr uint32_t IO_START = 0x4000000;
|
||||||
|
static constexpr uint32_t IO_END = 0x40003FE;
|
||||||
|
|
||||||
|
#undef MEMORY
|
||||||
|
|
||||||
Bus::Bus(Private,
|
Bus::Bus(Private,
|
||||||
std::array<uint8_t, BIOS_SIZE>&& bios,
|
std::array<uint8_t, BIOS_SIZE>&& bios,
|
||||||
std::vector<uint8_t>&& rom)
|
std::vector<uint8_t>&& rom)
|
||||||
: cycle_map(init_cycle_count())
|
: cycle_map(init_cycle_count())
|
||||||
, bios(std::move(bios))
|
, bios(std::move(bios))
|
||||||
, rom(std::move(rom)) {
|
, rom(std::move(rom)) {
|
||||||
std::string bios_hash = crypto::sha256(this->bios);
|
std::string bios_hash = crypto::sha256(this->bios.data());
|
||||||
static constexpr std::string_view expected_hash =
|
static constexpr std::string_view expected_hash =
|
||||||
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
"fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570";
|
||||||
|
|
||||||
@@ -69,9 +88,8 @@ Bus::init_cycle_count() {
|
|||||||
map[IO_REGION] = { 1, 1, 1, 1 };
|
map[IO_REGION] = { 1, 1, 1, 1 };
|
||||||
map[OAM_REGION] = { 1, 1, 1, 1 };
|
map[OAM_REGION] = { 1, 1, 1, 1 };
|
||||||
*/
|
*/
|
||||||
map[3] = { 1, 1, 1, 1 };
|
|
||||||
map[BOARD_WRAM_REGION] = { .n16 = 3, .n32 = 6, .s16 = 3, .s32 = 6 };
|
map[BOARD_WRAM_REGION] = { .n16 = 3, .n32 = 6, .s16 = 3, .s32 = 6 };
|
||||||
map[PALETTE_RAM_REGION] = { .n16 = 1, .n32 = 2, .s16 = 1, .s32 = 2 };
|
map[PRAM_REGION] = { .n16 = 1, .n32 = 2, .s16 = 1, .s32 = 2 };
|
||||||
map[VRAM_REGION] = { .n16 = 1, .n32 = 2, .s16 = 1, .s32 = 2 };
|
map[VRAM_REGION] = { .n16 = 1, .n32 = 2, .s16 = 1, .s32 = 2 };
|
||||||
// TODO: GamePak access cycles
|
// TODO: GamePak access cycles
|
||||||
|
|
||||||
@@ -79,7 +97,7 @@ Bus::init_cycle_count() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::optional<T>
|
T
|
||||||
Bus::read(uint32_t address) const {
|
Bus::read(uint32_t address) const {
|
||||||
|
|
||||||
// this is cleaned than std::enable_if
|
// this is cleaned than std::enable_if
|
||||||
@@ -99,12 +117,11 @@ Bus::read(uint32_t address) const {
|
|||||||
if (i > area.size() - N) \
|
if (i > area.size() - N) \
|
||||||
break; \
|
break; \
|
||||||
if constexpr (std::is_same_v<T, uint8_t>) \
|
if constexpr (std::is_same_v<T, uint8_t>) \
|
||||||
return area[i]; \
|
return area.read_byte(i); \
|
||||||
else if constexpr (std::is_same_v<T, uint16_t>) \
|
else if constexpr (std::is_same_v<T, uint16_t>) \
|
||||||
return area[i] | area[i + 1] << 8; \
|
return area.read_halfword(i); \
|
||||||
else if constexpr (std::is_same_v<T, uint32_t>) \
|
else if constexpr (std::is_same_v<T, uint32_t>) \
|
||||||
return area[i] | area[i + 1] << 8 | area[i + 2] << 16 | \
|
return area.read_word(i); \
|
||||||
area[i + 3] << 24; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MATCHES_PAK(AREA, area) \
|
#define MATCHES_PAK(AREA, area) \
|
||||||
@@ -114,9 +131,9 @@ Bus::read(uint32_t address) const {
|
|||||||
MATCHES(BIOS, bios)
|
MATCHES(BIOS, bios)
|
||||||
MATCHES(BOARD_WRAM, board_wram)
|
MATCHES(BOARD_WRAM, board_wram)
|
||||||
MATCHES(CHIP_WRAM, chip_wram)
|
MATCHES(CHIP_WRAM, chip_wram)
|
||||||
MATCHES(PALETTE_RAM, palette_ram)
|
MATCHES(PRAM, io->display.pram)
|
||||||
MATCHES(VRAM, vram)
|
MATCHES(VRAM, io->display.vram)
|
||||||
MATCHES(OAM_OBJ_ATTR, oam_obj_attr)
|
MATCHES(OAM, io->display.oam)
|
||||||
|
|
||||||
MATCHES_PAK(ROM_0, rom)
|
MATCHES_PAK(ROM_0, rom)
|
||||||
MATCHES_PAK(ROM_1, rom)
|
MATCHES_PAK(ROM_1, rom)
|
||||||
@@ -125,8 +142,14 @@ Bus::read(uint32_t address) const {
|
|||||||
#undef MATCHES
|
#undef MATCHES
|
||||||
}
|
}
|
||||||
|
|
||||||
glogger.error("Invalid memory region read");
|
glogger.error("invalid memory region read at {:08x}", address);
|
||||||
return {};
|
|
||||||
|
if constexpr (std::is_same_v<T, uint8_t>)
|
||||||
|
return 0xFF;
|
||||||
|
else if constexpr (std::is_same_v<T, uint16_t>)
|
||||||
|
return 0xFFFF;
|
||||||
|
else if constexpr (std::is_same_v<T, uint32_t>)
|
||||||
|
return 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -140,36 +163,32 @@ Bus::write(uint32_t address, T value) {
|
|||||||
: std::is_same_v<T, uint16_t> ? 2
|
: std::is_same_v<T, uint16_t> ? 2
|
||||||
: std::is_same_v<T, uint32_t> ? 4
|
: std::is_same_v<T, uint32_t> ? 4
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
switch (address >> 24 & 0xF) {
|
switch (address >> 24 & 0xF) {
|
||||||
#define MATCHES(AREA, area) \
|
#define MATCHES(AREA, area) \
|
||||||
case AREA##_REGION: { \
|
case AREA##_REGION: { \
|
||||||
uint32_t i = address - AREA##_START; \
|
uint32_t i = address - AREA##_START; \
|
||||||
if (i > area.size() - N) \
|
if (i > area.size() - N) \
|
||||||
break; \
|
break; \
|
||||||
if constexpr (std::is_same_v<T, uint8_t>) { \
|
if constexpr (std::is_same_v<T, uint8_t>) \
|
||||||
area[i] = value; \
|
area.write_byte(i, value); \
|
||||||
} else if constexpr (std::is_same_v<T, uint16_t>) { \
|
else if constexpr (std::is_same_v<T, uint16_t>) \
|
||||||
area[i] = value & 0xFF; \
|
area.write_halfword(i, value); \
|
||||||
area[i + 1] = value >> 8 & 0xFF; \
|
else if constexpr (std::is_same_v<T, uint32_t>) \
|
||||||
} else if constexpr (std::is_same_v<T, uint32_t>) { \
|
area.write_word(i, value); \
|
||||||
area[i] = value & 0xFF; \
|
|
||||||
area[i + 1] = value >> 8 & 0xFF; \
|
|
||||||
area[i + 2] = value >> 16 & 0xFF; \
|
|
||||||
area[i + 3] = value >> 24 & 0xFF; \
|
|
||||||
} \
|
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHES(BOARD_WRAM, board_wram)
|
MATCHES(BOARD_WRAM, board_wram)
|
||||||
MATCHES(CHIP_WRAM, chip_wram)
|
MATCHES(CHIP_WRAM, chip_wram)
|
||||||
MATCHES(PALETTE_RAM, palette_ram)
|
MATCHES(PRAM, io->display.pram)
|
||||||
MATCHES(VRAM, vram)
|
MATCHES(VRAM, io->display.vram)
|
||||||
MATCHES(OAM_OBJ_ATTR, oam_obj_attr)
|
MATCHES(OAM, io->display.oam)
|
||||||
|
|
||||||
#undef MATCHES
|
#undef MATCHES
|
||||||
}
|
}
|
||||||
|
|
||||||
glogger.error("Invalid memory region written");
|
glogger.error("invalid memory region written at {:08x}", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
@@ -177,7 +196,7 @@ Bus::read_byte(uint32_t address) {
|
|||||||
if (address >= IO_START && address <= IO_END)
|
if (address >= IO_START && address <= IO_END)
|
||||||
return io->read_byte(address);
|
return io->read_byte(address);
|
||||||
|
|
||||||
return read<uint8_t>(address).value_or(0xFF);
|
return read<uint8_t>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -198,7 +217,7 @@ Bus::read_halfword(uint32_t address) {
|
|||||||
if (address >= IO_START && address <= IO_END)
|
if (address >= IO_START && address <= IO_END)
|
||||||
return io->read_halfword(address);
|
return io->read_halfword(address);
|
||||||
|
|
||||||
return read<uint16_t>(address).value_or(0xFFFF);
|
return read<uint16_t>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -222,7 +241,7 @@ Bus::read_word(uint32_t address) {
|
|||||||
if (address >= IO_START && address <= IO_END)
|
if (address >= IO_START && address <= IO_END)
|
||||||
return io->read_word(address);
|
return io->read_word(address);
|
||||||
|
|
||||||
return read<uint32_t>(address).value_or(0xFFFFFFFF);
|
return read<uint32_t>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
23
src/io/display/display.cc
Normal file
23
src/io/display/display.cc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "io/display/display.hh"
|
||||||
|
|
||||||
|
namespace matar {
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
/*
|
||||||
|
static constexpr uint LCD_HEIGHT = 160;
|
||||||
|
static constexpr uint LCD_WIDTH = 240;
|
||||||
|
static constexpr uint BLANK = 68;
|
||||||
|
|
||||||
|
static constexpr uint PIXEL_CYCLES = 4; // 4
|
||||||
|
static constexpr uint HDRAW_CYCLES = LCD_WIDTH * PIXEL_CYCLES + 46; // 1006
|
||||||
|
static constexpr uint HBLANK_CYCLES = BLANK * PIXEL_CYCLES - 46; // 226
|
||||||
|
static constexpr uint HREFRESH_CYCLES = HDRAW_CYCLES + HBLANK_CYCLES; // 1232
|
||||||
|
static constexpr uint VDRAW_CYCLES = LCD_HEIGHT * HREFRESH_CYCLES; // 197120
|
||||||
|
static constexpr uint VBLANK_CYCLES = BLANK * HREFRESH_CYCLES; // 83776
|
||||||
|
static constexpr uint VREFRESH_CYCLES = VDRAW_CYCLES + VBLANK_CYCLES; // 280896
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
Display::mode_3() {}
|
||||||
|
}
|
||||||
|
}
|
3
src/io/display/meson.build
Normal file
3
src/io/display/meson.build
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
lib_sources += files(
|
||||||
|
'display.cc'
|
||||||
|
)
|
51
src/io/display/render.cc
Normal file
51
src/io/display/render.cc
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "io/display/display.hh"
|
||||||
|
|
||||||
|
namespace matar {
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
struct TextScreen {
|
||||||
|
uint16_t tile_number : 10;
|
||||||
|
bool mirror_horizontal : 1;
|
||||||
|
bool mirror_vertical : 1;
|
||||||
|
uint8_t palette_number : 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
// if 16th bit is set, this will denote the transparent color in rgb555 format
|
||||||
|
static constexpr uint16_t TRANSPARENT_RGB555 = 0x8000;
|
||||||
|
|
||||||
|
template<int MODE, typename>
|
||||||
|
void
|
||||||
|
Display::render_bitmap_mode() {
|
||||||
|
static constexpr std::size_t VIEWPORT_WIDTH = MODE == 5 ? 160 : 240;
|
||||||
|
|
||||||
|
for (int x = 0; x < LCD_WIDTH; x++) {
|
||||||
|
// pixel to texel for x
|
||||||
|
// shift by 8 cuz both ref.x and a are fixed point floats shifted by 8
|
||||||
|
int32_t x_ = (bg2_rot_scale.ref.x + x * bg2_rot_scale.a) >> 8;
|
||||||
|
int32_t y_ = (bg2_rot_scale.ref.y + x * bg2_rot_scale.c) >> 8;
|
||||||
|
|
||||||
|
// ignore handling area overflow for bitmap modes
|
||||||
|
// i am not sure how well this will turn out
|
||||||
|
|
||||||
|
std::size_t idx = y_ * VIEWPORT_WIDTH + x_;
|
||||||
|
|
||||||
|
// mode 3 and 5 takes 2 bytes per pixel
|
||||||
|
if constexpr (MODE != 4)
|
||||||
|
idx *= 2;
|
||||||
|
|
||||||
|
// offset
|
||||||
|
if constexpr (MODE != 3) {
|
||||||
|
std::size_t offset =
|
||||||
|
lcd_control.value.frame_select_1 ? 0xA000 : 0x0000;
|
||||||
|
idx += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read two bytes
|
||||||
|
if constexpr (MODE == 4)
|
||||||
|
scanline_buffers[2][x] = pram.read_halfword(vram.read_byte(idx));
|
||||||
|
else
|
||||||
|
scanline_buffers[2][x] = vram.read_halfword(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
231
src/io/io.cc
231
src/io/io.cc
@@ -76,6 +76,24 @@ ADDR FIFO_A_H = 0x40000A2;
|
|||||||
ADDR FIFO_B_L = 0x40000A4;
|
ADDR FIFO_B_L = 0x40000A4;
|
||||||
ADDR FIFO_B_H = 0x40000A6;
|
ADDR FIFO_B_H = 0x40000A6;
|
||||||
|
|
||||||
|
// dma
|
||||||
|
ADDR DMA0SAD = 0x40000B0;
|
||||||
|
ADDR DMA0DAD = 0x40000B4;
|
||||||
|
ADDR DMA0CNT_L = 0x40000B8;
|
||||||
|
ADDR DMA0CNT_H = 0x40000BA;
|
||||||
|
ADDR DMA1SAD = 0x40000BC;
|
||||||
|
ADDR DMA1DAD = 0x40000C0;
|
||||||
|
ADDR DMA1CNT_L = 0x40000C4;
|
||||||
|
ADDR DMA1CNT_H = 0x40000C6;
|
||||||
|
ADDR DMA2SAD = 0x40000C8;
|
||||||
|
ADDR DMA2DAD = 0x40000CC;
|
||||||
|
ADDR DMA2CNT_L = 0x40000D0;
|
||||||
|
ADDR DMA2CNT_H = 0x40000D2;
|
||||||
|
ADDR DMA3SAD = 0x40000D4;
|
||||||
|
ADDR DMA3DAD = 0x40000D8;
|
||||||
|
ADDR DMA3CNT_L = 0x40000DC;
|
||||||
|
ADDR DMA3CNT_H = 0x40000DE;
|
||||||
|
|
||||||
// system
|
// system
|
||||||
ADDR POSTFLG = 0x4000300;
|
ADDR POSTFLG = 0x4000300;
|
||||||
ADDR IME = 0x4000208;
|
ADDR IME = 0x4000208;
|
||||||
@@ -131,13 +149,24 @@ IoDevices::read_halfword(uint32_t address) const {
|
|||||||
return var;
|
return var;
|
||||||
|
|
||||||
// lcd
|
// lcd
|
||||||
READ(DISPCNT, lcd.lcd_control)
|
case DISPCNT:
|
||||||
READ(DISPSTAT, lcd.general_lcd_status)
|
return display.lcd_control.read();
|
||||||
READ(VCOUNT, lcd.vertical_counter)
|
case DISPSTAT:
|
||||||
READ(WININ, lcd.inside_win_0_1)
|
return display.general_lcd_status.read();
|
||||||
READ(WINOUT, lcd.outside_win)
|
case BG0CNT:
|
||||||
READ(BLDCNT, lcd.color_special_effects_selection)
|
return display.bg_control[0].read();
|
||||||
READ(BLDALPHA, lcd.alpha_blending_coefficients)
|
case BG1CNT:
|
||||||
|
return display.bg_control[1].read();
|
||||||
|
case BG2CNT:
|
||||||
|
return display.bg_control[2].read();
|
||||||
|
case BG3CNT:
|
||||||
|
return display.bg_control[3].read();
|
||||||
|
|
||||||
|
READ(VCOUNT, display.vertical_counter)
|
||||||
|
READ(WININ, display.inside_win_0_1)
|
||||||
|
READ(WINOUT, display.outside_win)
|
||||||
|
READ(BLDCNT, display.color_special_effects_selection)
|
||||||
|
READ(BLDALPHA, display.alpha_blending_coefficients)
|
||||||
|
|
||||||
// sound
|
// sound
|
||||||
READ(SOUND1CNT_L, sound.ch1_sweep)
|
READ(SOUND1CNT_L, sound.ch1_sweep)
|
||||||
@@ -163,6 +192,37 @@ IoDevices::read_halfword(uint32_t address) const {
|
|||||||
READ(SOUNDCNT_X, sound.ctrl_sound_on_off);
|
READ(SOUNDCNT_X, sound.ctrl_sound_on_off);
|
||||||
READ(SOUNDBIAS, sound.pwm_control);
|
READ(SOUNDBIAS, sound.pwm_control);
|
||||||
|
|
||||||
|
// dma
|
||||||
|
case DMA0CNT_H:
|
||||||
|
return dma.channels[0].control.read();
|
||||||
|
case DMA1CNT_H:
|
||||||
|
return dma.channels[1].control.read();
|
||||||
|
case DMA2CNT_H:
|
||||||
|
return dma.channels[2].control.read();
|
||||||
|
case DMA3CNT_H:
|
||||||
|
return dma.channels[3].control.read();
|
||||||
|
|
||||||
|
READ(DMA0SAD, dma.channels[0].source[0]);
|
||||||
|
READ(DMA0SAD + 2, dma.channels[0].source[1]);
|
||||||
|
READ(DMA0DAD, dma.channels[0].destination[0]);
|
||||||
|
READ(DMA0DAD + 2, dma.channels[0].destination[1]);
|
||||||
|
READ(DMA0CNT_L, dma.channels[0].word_count);
|
||||||
|
READ(DMA1SAD, dma.channels[1].source[0]);
|
||||||
|
READ(DMA1SAD + 2, dma.channels[1].source[1]);
|
||||||
|
READ(DMA1DAD, dma.channels[1].destination[0]);
|
||||||
|
READ(DMA1DAD + 2, dma.channels[1].destination[1]);
|
||||||
|
READ(DMA1CNT_L, dma.channels[1].word_count);
|
||||||
|
READ(DMA2SAD, dma.channels[2].source[0]);
|
||||||
|
READ(DMA2SAD + 2, dma.channels[2].source[1]);
|
||||||
|
READ(DMA2DAD, dma.channels[2].destination[0]);
|
||||||
|
READ(DMA2DAD + 2, dma.channels[2].destination[1]);
|
||||||
|
READ(DMA2CNT_L, dma.channels[2].word_count);
|
||||||
|
READ(DMA3SAD, dma.channels[3].source[0]);
|
||||||
|
READ(DMA3SAD + 2, dma.channels[3].source[1]);
|
||||||
|
READ(DMA3DAD, dma.channels[3].destination[0]);
|
||||||
|
READ(DMA3DAD + 2, dma.channels[3].destination[1]);
|
||||||
|
READ(DMA3CNT_L, dma.channels[3].word_count);
|
||||||
|
|
||||||
// system
|
// system
|
||||||
READ(POSTFLG, system.post_boot_flag)
|
READ(POSTFLG, system.post_boot_flag)
|
||||||
READ(IME, system.interrupt_master_enabler)
|
READ(IME, system.interrupt_master_enabler)
|
||||||
@@ -181,6 +241,18 @@ IoDevices::read_halfword(uint32_t address) const {
|
|||||||
|
|
||||||
void
|
void
|
||||||
IoDevices::write_halfword(uint32_t address, uint16_t halfword) {
|
IoDevices::write_halfword(uint32_t address, uint16_t halfword) {
|
||||||
|
// set lower 16 bits for reference points (BG 2/3)
|
||||||
|
auto ref_low = [](uint32_t original, uint16_t low) {
|
||||||
|
return static_cast<int32_t>((original & 0xFFFF0000) | low);
|
||||||
|
};
|
||||||
|
|
||||||
|
// set upper 12 bits for reference points (BG 2/3)
|
||||||
|
// and sign extend
|
||||||
|
auto ref_high = [](uint32_t original, uint16_t high) {
|
||||||
|
return static_cast<int32_t>(
|
||||||
|
((((high & 0xFFF) << 16) | (original & 0xFFFF)) << 4) >> 4);
|
||||||
|
};
|
||||||
|
|
||||||
switch (address) {
|
switch (address) {
|
||||||
|
|
||||||
#define WRITE(name, var) \
|
#define WRITE(name, var) \
|
||||||
@@ -194,46 +266,75 @@ IoDevices::write_halfword(uint32_t address, uint16_t halfword) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// lcd
|
// lcd
|
||||||
WRITE(DISPCNT, lcd.lcd_control)
|
case DISPCNT:
|
||||||
WRITE(DISPSTAT, lcd.general_lcd_status)
|
display.lcd_control.write(halfword);
|
||||||
WRITE(BG0CNT, lcd.bg0_control)
|
break;
|
||||||
WRITE(BG1CNT, lcd.bg1_control)
|
case DISPSTAT:
|
||||||
WRITE(BG2CNT, lcd.bg2_control)
|
display.general_lcd_status.write(halfword);
|
||||||
WRITE(BG3CNT, lcd.bg3_control)
|
break;
|
||||||
WRITE(BG0HOFS, lcd.bg0_x_offset)
|
case BG0CNT:
|
||||||
WRITE(BG0VOFS, lcd.bg0_y_offset)
|
display.bg_control[0].write(halfword);
|
||||||
WRITE(BG1HOFS, lcd.bg1_x_offset)
|
break;
|
||||||
WRITE(BG1VOFS, lcd.bg1_y_offset)
|
case BG1CNT:
|
||||||
WRITE(BG2HOFS, lcd.bg2_x_offset)
|
display.bg_control[1].write(halfword);
|
||||||
WRITE(BG2VOFS, lcd.bg2_y_offset)
|
break;
|
||||||
WRITE(BG3HOFS, lcd.bg3_x_offset)
|
case BG2CNT:
|
||||||
WRITE(BG3VOFS, lcd.bg3_y_offset)
|
display.bg_control[2].write(halfword);
|
||||||
WRITE(BG2PA, lcd.bg2_rot_scaling_parameters[0])
|
break;
|
||||||
WRITE(BG2PB, lcd.bg2_rot_scaling_parameters[1])
|
case BG3CNT:
|
||||||
WRITE(BG2PC, lcd.bg2_rot_scaling_parameters[2])
|
display.bg_control[3].write(halfword);
|
||||||
WRITE(BG2PD, lcd.bg2_rot_scaling_parameters[3])
|
break;
|
||||||
WRITE(BG2X_L, lcd.bg2_reference_x[0])
|
|
||||||
WRITE(BG2X_H, lcd.bg2_reference_x[1])
|
WRITE(BG0HOFS, display.bg0_offset.x)
|
||||||
WRITE(BG2Y_L, lcd.bg2_reference_y[0])
|
WRITE(BG0VOFS, display.bg0_offset.y)
|
||||||
WRITE(BG2Y_H, lcd.bg2_reference_y[1])
|
WRITE(BG1HOFS, display.bg1_offset.x)
|
||||||
WRITE(BG3PA, lcd.bg3_rot_scaling_parameters[0])
|
WRITE(BG1VOFS, display.bg1_offset.y)
|
||||||
WRITE(BG3PB, lcd.bg3_rot_scaling_parameters[1])
|
WRITE(BG2HOFS, display.bg2_offset.x)
|
||||||
WRITE(BG3PC, lcd.bg3_rot_scaling_parameters[2])
|
WRITE(BG2VOFS, display.bg2_offset.y)
|
||||||
WRITE(BG3PD, lcd.bg3_rot_scaling_parameters[3])
|
WRITE(BG3HOFS, display.bg3_offset.x)
|
||||||
WRITE(BG3X_L, lcd.bg3_reference_x[0])
|
WRITE(BG3VOFS, display.bg3_offset.y)
|
||||||
WRITE(BG3X_H, lcd.bg3_reference_x[1])
|
WRITE(BG2PA, display.bg2_rot_scale.a)
|
||||||
WRITE(BG3Y_L, lcd.bg3_reference_y[0])
|
WRITE(BG2PB, display.bg2_rot_scale.b)
|
||||||
WRITE(BG3Y_H, lcd.bg3_reference_y[1])
|
WRITE(BG2PC, display.bg2_rot_scale.c)
|
||||||
WRITE(WIN0H, lcd.win0_horizontal_dimensions)
|
WRITE(BG2PD, display.bg2_rot_scale.d)
|
||||||
WRITE(WIN1H, lcd.win1_horizontal_dimensions)
|
WRITE_2(BG2X_L,
|
||||||
WRITE(WIN0V, lcd.win0_vertical_dimensions)
|
display.bg2_rot_scale.ref.x,
|
||||||
WRITE(WIN1V, lcd.win1_vertical_dimensions)
|
ref_low(display.bg2_rot_scale.ref.x, halfword));
|
||||||
WRITE(WININ, lcd.inside_win_0_1)
|
WRITE_2(BG2X_H,
|
||||||
WRITE(WINOUT, lcd.outside_win)
|
display.bg2_rot_scale.ref.x,
|
||||||
WRITE(MOSAIC, lcd.mosaic_size)
|
ref_high(display.bg2_rot_scale.ref.x, halfword));
|
||||||
WRITE(BLDCNT, lcd.color_special_effects_selection)
|
WRITE_2(BG2Y_L,
|
||||||
WRITE(BLDALPHA, lcd.alpha_blending_coefficients)
|
display.bg2_rot_scale.ref.y,
|
||||||
WRITE(BLDY, lcd.brightness_coefficient)
|
ref_low(display.bg2_rot_scale.ref.y, halfword));
|
||||||
|
WRITE_2(BG2Y_H,
|
||||||
|
display.bg2_rot_scale.ref.y,
|
||||||
|
ref_high(display.bg2_rot_scale.ref.y, halfword));
|
||||||
|
WRITE(BG3PA, display.bg3_rot_scale.a)
|
||||||
|
WRITE(BG3PB, display.bg3_rot_scale.b)
|
||||||
|
WRITE(BG3PC, display.bg3_rot_scale.c)
|
||||||
|
WRITE(BG3PD, display.bg3_rot_scale.d)
|
||||||
|
WRITE_2(BG3X_L,
|
||||||
|
display.bg3_rot_scale.ref.x,
|
||||||
|
ref_low(display.bg3_rot_scale.ref.x, halfword));
|
||||||
|
WRITE_2(BG3X_H,
|
||||||
|
display.bg3_rot_scale.ref.x,
|
||||||
|
ref_high(display.bg3_rot_scale.ref.x, halfword));
|
||||||
|
WRITE_2(BG3Y_L,
|
||||||
|
display.bg3_rot_scale.ref.y,
|
||||||
|
ref_low(display.bg3_rot_scale.ref.y, halfword));
|
||||||
|
WRITE_2(BG3Y_H,
|
||||||
|
display.bg3_rot_scale.ref.y,
|
||||||
|
ref_high(display.bg3_rot_scale.ref.y, halfword));
|
||||||
|
WRITE(WIN0H, display.win0_horizontal_dimensions)
|
||||||
|
WRITE(WIN1H, display.win1_horizontal_dimensions)
|
||||||
|
WRITE(WIN0V, display.win0_vertical_dimensions)
|
||||||
|
WRITE(WIN1V, display.win1_vertical_dimensions)
|
||||||
|
WRITE(WININ, display.inside_win_0_1)
|
||||||
|
WRITE(WINOUT, display.outside_win)
|
||||||
|
WRITE(MOSAIC, display.mosaic_size)
|
||||||
|
WRITE(BLDCNT, display.color_special_effects_selection)
|
||||||
|
WRITE(BLDALPHA, display.alpha_blending_coefficients)
|
||||||
|
WRITE(BLDY, display.brightness_coefficient)
|
||||||
|
|
||||||
// sound
|
// sound
|
||||||
WRITE(SOUND1CNT_L, sound.ch1_sweep)
|
WRITE(SOUND1CNT_L, sound.ch1_sweep)
|
||||||
@@ -263,6 +364,41 @@ IoDevices::write_halfword(uint32_t address, uint16_t halfword) {
|
|||||||
WRITE(FIFO_B_L, sound.fifo_b[0]);
|
WRITE(FIFO_B_L, sound.fifo_b[0]);
|
||||||
WRITE(FIFO_B_H, sound.fifo_b[1]);
|
WRITE(FIFO_B_H, sound.fifo_b[1]);
|
||||||
|
|
||||||
|
// dma
|
||||||
|
case DMA0CNT_H:
|
||||||
|
dma.channels[0].control.write(halfword);
|
||||||
|
break;
|
||||||
|
case DMA1CNT_H:
|
||||||
|
dma.channels[1].control.write(halfword);
|
||||||
|
break;
|
||||||
|
case DMA2CNT_H:
|
||||||
|
dma.channels[2].control.write(halfword);
|
||||||
|
break;
|
||||||
|
case DMA3CNT_H:
|
||||||
|
dma.channels[3].control.write(halfword);
|
||||||
|
break;
|
||||||
|
|
||||||
|
WRITE(DMA0SAD, dma.channels[0].source[0]);
|
||||||
|
WRITE(DMA0SAD + 2, dma.channels[0].source[1]);
|
||||||
|
WRITE(DMA0DAD, dma.channels[0].destination[0]);
|
||||||
|
WRITE(DMA0DAD + 2, dma.channels[0].destination[1]);
|
||||||
|
WRITE(DMA0CNT_L, dma.channels[0].word_count);
|
||||||
|
WRITE(DMA1SAD, dma.channels[1].source[0]);
|
||||||
|
WRITE(DMA1SAD + 2, dma.channels[1].source[1]);
|
||||||
|
WRITE(DMA1DAD, dma.channels[1].destination[0]);
|
||||||
|
WRITE(DMA1DAD + 2, dma.channels[1].destination[1]);
|
||||||
|
WRITE(DMA1CNT_L, dma.channels[1].word_count);
|
||||||
|
WRITE(DMA2SAD, dma.channels[2].source[0]);
|
||||||
|
WRITE(DMA2SAD + 2, dma.channels[2].source[1]);
|
||||||
|
WRITE(DMA2DAD, dma.channels[2].destination[0]);
|
||||||
|
WRITE(DMA2DAD + 2, dma.channels[2].destination[1]);
|
||||||
|
WRITE(DMA2CNT_L, dma.channels[2].word_count);
|
||||||
|
WRITE(DMA3SAD, dma.channels[3].source[0]);
|
||||||
|
WRITE(DMA3SAD + 2, dma.channels[3].source[1]);
|
||||||
|
WRITE(DMA3DAD, dma.channels[3].destination[0]);
|
||||||
|
WRITE(DMA3DAD + 2, dma.channels[3].destination[1]);
|
||||||
|
WRITE(DMA3CNT_L, dma.channels[3].word_count);
|
||||||
|
|
||||||
// system
|
// system
|
||||||
WRITE_2(POSTFLG, system.post_boot_flag, halfword & 1)
|
WRITE_2(POSTFLG, system.post_boot_flag, halfword & 1)
|
||||||
WRITE_2(IME, system.interrupt_master_enabler, halfword & 1)
|
WRITE_2(IME, system.interrupt_master_enabler, halfword & 1)
|
||||||
@@ -279,4 +415,5 @@ IoDevices::write_halfword(uint32_t address, uint16_t halfword) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
lib_sources += files(
|
lib_sources += files(
|
||||||
'io.cc',
|
'io.cc'
|
||||||
)
|
)
|
Reference in New Issue
Block a user