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;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										85
									
								
								src/bus.cc
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								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,17 +88,16 @@ 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[PRAM_REGION]       = { .n16 = 1, .n32 = 2, .s16 = 1, .s32 = 2 };
 | 
				
			||||||
    map[PALETTE_RAM_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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return map;
 | 
					    return map;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										359
									
								
								src/io/io.cc
									
									
									
									
									
								
							
							
						
						
									
										359
									
								
								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;
 | 
				
			||||||
@@ -130,45 +148,87 @@ IoDevices::read_halfword(uint32_t address) const {
 | 
				
			|||||||
    case name:                                                                 \
 | 
					    case name:                                                                 \
 | 
				
			||||||
        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();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // sound
 | 
					            READ(VCOUNT, display.vertical_counter)
 | 
				
			||||||
        READ(SOUND1CNT_L, sound.ch1_sweep)
 | 
					            READ(WININ, display.inside_win_0_1)
 | 
				
			||||||
        READ(SOUND1CNT_H, sound.ch1_duty_length_env)
 | 
					            READ(WINOUT, display.outside_win)
 | 
				
			||||||
        READ(SOUND1CNT_X, sound.ch1_freq_control)
 | 
					            READ(BLDCNT, display.color_special_effects_selection)
 | 
				
			||||||
        READ(SOUND2CNT_L, sound.ch2_duty_length_env)
 | 
					            READ(BLDALPHA, display.alpha_blending_coefficients)
 | 
				
			||||||
        READ(SOUND2CNT_H, sound.ch2_freq_control)
 | 
					 | 
				
			||||||
        READ(SOUND3CNT_L, sound.ch3_stop_wave_ram_select)
 | 
					 | 
				
			||||||
        READ(SOUND3CNT_H, sound.ch3_length_volume)
 | 
					 | 
				
			||||||
        READ(SOUND3CNT_X, sound.ch3_freq_control)
 | 
					 | 
				
			||||||
        READ(WAVE_RAM0_L, sound.ch3_wave_pattern[0]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM0_H, sound.ch3_wave_pattern[1]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM1_L, sound.ch3_wave_pattern[2]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM1_H, sound.ch3_wave_pattern[3]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM2_L, sound.ch3_wave_pattern[4]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM2_H, sound.ch3_wave_pattern[5]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM3_L, sound.ch3_wave_pattern[6]);
 | 
					 | 
				
			||||||
        READ(WAVE_RAM3_H, sound.ch3_wave_pattern[7]);
 | 
					 | 
				
			||||||
        READ(SOUND4CNT_L, sound.ch4_length_env);
 | 
					 | 
				
			||||||
        READ(SOUND4CNT_H, sound.ch4_freq_control);
 | 
					 | 
				
			||||||
        READ(SOUNDCNT_L, sound.ctrl_stereo_volume);
 | 
					 | 
				
			||||||
        READ(SOUNDCNT_H, sound.ctrl_mixing);
 | 
					 | 
				
			||||||
        READ(SOUNDCNT_X, sound.ctrl_sound_on_off);
 | 
					 | 
				
			||||||
        READ(SOUNDBIAS, sound.pwm_control);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // system
 | 
					            // sound
 | 
				
			||||||
        READ(POSTFLG, system.post_boot_flag)
 | 
					            READ(SOUND1CNT_L, sound.ch1_sweep)
 | 
				
			||||||
        READ(IME, system.interrupt_master_enabler)
 | 
					            READ(SOUND1CNT_H, sound.ch1_duty_length_env)
 | 
				
			||||||
        READ(IE, system.interrupt_enable);
 | 
					            READ(SOUND1CNT_X, sound.ch1_freq_control)
 | 
				
			||||||
        READ(IF, system.interrupt_request_flags);
 | 
					            READ(SOUND2CNT_L, sound.ch2_duty_length_env)
 | 
				
			||||||
        READ(WAITCNT, system.waitstate_control);
 | 
					            READ(SOUND2CNT_H, sound.ch2_freq_control)
 | 
				
			||||||
 | 
					            READ(SOUND3CNT_L, sound.ch3_stop_wave_ram_select)
 | 
				
			||||||
 | 
					            READ(SOUND3CNT_H, sound.ch3_length_volume)
 | 
				
			||||||
 | 
					            READ(SOUND3CNT_X, sound.ch3_freq_control)
 | 
				
			||||||
 | 
					            READ(WAVE_RAM0_L, sound.ch3_wave_pattern[0]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM0_H, sound.ch3_wave_pattern[1]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM1_L, sound.ch3_wave_pattern[2]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM1_H, sound.ch3_wave_pattern[3]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM2_L, sound.ch3_wave_pattern[4]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM2_H, sound.ch3_wave_pattern[5]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM3_L, sound.ch3_wave_pattern[6]);
 | 
				
			||||||
 | 
					            READ(WAVE_RAM3_H, sound.ch3_wave_pattern[7]);
 | 
				
			||||||
 | 
					            READ(SOUND4CNT_L, sound.ch4_length_env);
 | 
				
			||||||
 | 
					            READ(SOUND4CNT_H, sound.ch4_freq_control);
 | 
				
			||||||
 | 
					            READ(SOUNDCNT_L, sound.ctrl_stereo_volume);
 | 
				
			||||||
 | 
					            READ(SOUNDCNT_H, sound.ctrl_mixing);
 | 
				
			||||||
 | 
					            READ(SOUNDCNT_X, sound.ctrl_sound_on_off);
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					            READ(POSTFLG, system.post_boot_flag)
 | 
				
			||||||
 | 
					            READ(IME, system.interrupt_master_enabler)
 | 
				
			||||||
 | 
					            READ(IE, system.interrupt_enable);
 | 
				
			||||||
 | 
					            READ(IF, system.interrupt_request_flags);
 | 
				
			||||||
 | 
					            READ(WAITCNT, system.waitstate_control);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef READ
 | 
					#undef READ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -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,82 +266,146 @@ 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(BG2Y_L, lcd.bg2_reference_y[0])
 | 
					 | 
				
			||||||
        WRITE(BG2Y_H, lcd.bg2_reference_y[1])
 | 
					 | 
				
			||||||
        WRITE(BG3PA, lcd.bg3_rot_scaling_parameters[0])
 | 
					 | 
				
			||||||
        WRITE(BG3PB, lcd.bg3_rot_scaling_parameters[1])
 | 
					 | 
				
			||||||
        WRITE(BG3PC, lcd.bg3_rot_scaling_parameters[2])
 | 
					 | 
				
			||||||
        WRITE(BG3PD, lcd.bg3_rot_scaling_parameters[3])
 | 
					 | 
				
			||||||
        WRITE(BG3X_L, lcd.bg3_reference_x[0])
 | 
					 | 
				
			||||||
        WRITE(BG3X_H, lcd.bg3_reference_x[1])
 | 
					 | 
				
			||||||
        WRITE(BG3Y_L, lcd.bg3_reference_y[0])
 | 
					 | 
				
			||||||
        WRITE(BG3Y_H, lcd.bg3_reference_y[1])
 | 
					 | 
				
			||||||
        WRITE(WIN0H, lcd.win0_horizontal_dimensions)
 | 
					 | 
				
			||||||
        WRITE(WIN1H, lcd.win1_horizontal_dimensions)
 | 
					 | 
				
			||||||
        WRITE(WIN0V, lcd.win0_vertical_dimensions)
 | 
					 | 
				
			||||||
        WRITE(WIN1V, lcd.win1_vertical_dimensions)
 | 
					 | 
				
			||||||
        WRITE(WININ, lcd.inside_win_0_1)
 | 
					 | 
				
			||||||
        WRITE(WINOUT, lcd.outside_win)
 | 
					 | 
				
			||||||
        WRITE(MOSAIC, lcd.mosaic_size)
 | 
					 | 
				
			||||||
        WRITE(BLDCNT, lcd.color_special_effects_selection)
 | 
					 | 
				
			||||||
        WRITE(BLDALPHA, lcd.alpha_blending_coefficients)
 | 
					 | 
				
			||||||
        WRITE(BLDY, lcd.brightness_coefficient)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // sound
 | 
					            WRITE(BG0HOFS, display.bg0_offset.x)
 | 
				
			||||||
        WRITE(SOUND1CNT_L, sound.ch1_sweep)
 | 
					            WRITE(BG0VOFS, display.bg0_offset.y)
 | 
				
			||||||
        WRITE(SOUND1CNT_H, sound.ch1_duty_length_env)
 | 
					            WRITE(BG1HOFS, display.bg1_offset.x)
 | 
				
			||||||
        WRITE(SOUND1CNT_X, sound.ch1_freq_control)
 | 
					            WRITE(BG1VOFS, display.bg1_offset.y)
 | 
				
			||||||
        WRITE(SOUND2CNT_L, sound.ch2_duty_length_env)
 | 
					            WRITE(BG2HOFS, display.bg2_offset.x)
 | 
				
			||||||
        WRITE(SOUND2CNT_H, sound.ch2_freq_control)
 | 
					            WRITE(BG2VOFS, display.bg2_offset.y)
 | 
				
			||||||
        WRITE(SOUND3CNT_L, sound.ch3_stop_wave_ram_select)
 | 
					            WRITE(BG3HOFS, display.bg3_offset.x)
 | 
				
			||||||
        WRITE(SOUND3CNT_H, sound.ch3_length_volume)
 | 
					            WRITE(BG3VOFS, display.bg3_offset.y)
 | 
				
			||||||
        WRITE(SOUND3CNT_X, sound.ch3_freq_control)
 | 
					            WRITE(BG2PA, display.bg2_rot_scale.a)
 | 
				
			||||||
        WRITE(WAVE_RAM0_L, sound.ch3_wave_pattern[0]);
 | 
					            WRITE(BG2PB, display.bg2_rot_scale.b)
 | 
				
			||||||
        WRITE(WAVE_RAM0_H, sound.ch3_wave_pattern[1]);
 | 
					            WRITE(BG2PC, display.bg2_rot_scale.c)
 | 
				
			||||||
        WRITE(WAVE_RAM1_L, sound.ch3_wave_pattern[2]);
 | 
					            WRITE(BG2PD, display.bg2_rot_scale.d)
 | 
				
			||||||
        WRITE(WAVE_RAM1_H, sound.ch3_wave_pattern[3]);
 | 
					            WRITE_2(BG2X_L,
 | 
				
			||||||
        WRITE(WAVE_RAM2_L, sound.ch3_wave_pattern[4]);
 | 
					                    display.bg2_rot_scale.ref.x,
 | 
				
			||||||
        WRITE(WAVE_RAM2_H, sound.ch3_wave_pattern[5]);
 | 
					                    ref_low(display.bg2_rot_scale.ref.x, halfword));
 | 
				
			||||||
        WRITE(WAVE_RAM3_L, sound.ch3_wave_pattern[6]);
 | 
					            WRITE_2(BG2X_H,
 | 
				
			||||||
        WRITE(WAVE_RAM3_H, sound.ch3_wave_pattern[7]);
 | 
					                    display.bg2_rot_scale.ref.x,
 | 
				
			||||||
        WRITE(SOUND4CNT_L, sound.ch4_length_env);
 | 
					                    ref_high(display.bg2_rot_scale.ref.x, halfword));
 | 
				
			||||||
        WRITE(SOUND4CNT_H, sound.ch4_freq_control);
 | 
					            WRITE_2(BG2Y_L,
 | 
				
			||||||
        WRITE(SOUNDCNT_L, sound.ctrl_stereo_volume);
 | 
					                    display.bg2_rot_scale.ref.y,
 | 
				
			||||||
        WRITE(SOUNDCNT_H, sound.ctrl_mixing);
 | 
					                    ref_low(display.bg2_rot_scale.ref.y, halfword));
 | 
				
			||||||
        WRITE(SOUNDCNT_X, sound.ctrl_sound_on_off);
 | 
					            WRITE_2(BG2Y_H,
 | 
				
			||||||
        WRITE(SOUNDBIAS, sound.pwm_control);
 | 
					                    display.bg2_rot_scale.ref.y,
 | 
				
			||||||
        WRITE(FIFO_A_L, sound.fifo_a[0]);
 | 
					                    ref_high(display.bg2_rot_scale.ref.y, halfword));
 | 
				
			||||||
        WRITE(FIFO_A_H, sound.fifo_a[1]);
 | 
					            WRITE(BG3PA, display.bg3_rot_scale.a)
 | 
				
			||||||
        WRITE(FIFO_B_L, sound.fifo_b[0]);
 | 
					            WRITE(BG3PB, display.bg3_rot_scale.b)
 | 
				
			||||||
        WRITE(FIFO_B_H, sound.fifo_b[1]);
 | 
					            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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // system
 | 
					            // sound
 | 
				
			||||||
        WRITE_2(POSTFLG, system.post_boot_flag, halfword & 1)
 | 
					            WRITE(SOUND1CNT_L, sound.ch1_sweep)
 | 
				
			||||||
        WRITE_2(IME, system.interrupt_master_enabler, halfword & 1)
 | 
					            WRITE(SOUND1CNT_H, sound.ch1_duty_length_env)
 | 
				
			||||||
        WRITE(IE, system.interrupt_enable);
 | 
					            WRITE(SOUND1CNT_X, sound.ch1_freq_control)
 | 
				
			||||||
        WRITE(IF, system.interrupt_request_flags);
 | 
					            WRITE(SOUND2CNT_L, sound.ch2_duty_length_env)
 | 
				
			||||||
        WRITE(WAITCNT, system.waitstate_control);
 | 
					            WRITE(SOUND2CNT_H, sound.ch2_freq_control)
 | 
				
			||||||
        WRITE_2(HALTCNT, system.low_power_mode, get_bit(halfword, 7));
 | 
					            WRITE(SOUND3CNT_L, sound.ch3_stop_wave_ram_select)
 | 
				
			||||||
 | 
					            WRITE(SOUND3CNT_H, sound.ch3_length_volume)
 | 
				
			||||||
 | 
					            WRITE(SOUND3CNT_X, sound.ch3_freq_control)
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM0_L, sound.ch3_wave_pattern[0]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM0_H, sound.ch3_wave_pattern[1]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM1_L, sound.ch3_wave_pattern[2]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM1_H, sound.ch3_wave_pattern[3]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM2_L, sound.ch3_wave_pattern[4]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM2_H, sound.ch3_wave_pattern[5]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM3_L, sound.ch3_wave_pattern[6]);
 | 
				
			||||||
 | 
					            WRITE(WAVE_RAM3_H, sound.ch3_wave_pattern[7]);
 | 
				
			||||||
 | 
					            WRITE(SOUND4CNT_L, sound.ch4_length_env);
 | 
				
			||||||
 | 
					            WRITE(SOUND4CNT_H, sound.ch4_freq_control);
 | 
				
			||||||
 | 
					            WRITE(SOUNDCNT_L, sound.ctrl_stereo_volume);
 | 
				
			||||||
 | 
					            WRITE(SOUNDCNT_H, sound.ctrl_mixing);
 | 
				
			||||||
 | 
					            WRITE(SOUNDCNT_X, sound.ctrl_sound_on_off);
 | 
				
			||||||
 | 
					            WRITE(SOUNDBIAS, sound.pwm_control);
 | 
				
			||||||
 | 
					            WRITE(FIFO_A_L, sound.fifo_a[0]);
 | 
				
			||||||
 | 
					            WRITE(FIFO_A_H, sound.fifo_a[1]);
 | 
				
			||||||
 | 
					            WRITE(FIFO_B_L, sound.fifo_b[0]);
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					            WRITE_2(POSTFLG, system.post_boot_flag, halfword & 1)
 | 
				
			||||||
 | 
					            WRITE_2(IME, system.interrupt_master_enabler, halfword & 1)
 | 
				
			||||||
 | 
					            WRITE(IE, system.interrupt_enable);
 | 
				
			||||||
 | 
					            WRITE(IF, system.interrupt_request_flags);
 | 
				
			||||||
 | 
					            WRITE(WAITCNT, system.waitstate_control);
 | 
				
			||||||
 | 
					            WRITE_2(HALTCNT, system.low_power_mode, get_bit(halfword, 7));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef WRITE
 | 
					#undef WRITE
 | 
				
			||||||
#undef WRITE_2
 | 
					#undef WRITE_2
 | 
				
			||||||
@@ -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