io: i really ought to be working on the ppu and apu by now
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
@@ -13,9 +13,9 @@ I am using LLVM's clang and libcxx as the primary toolchain.
|
|||||||
|
|
||||||
## Static libraries
|
## Static libraries
|
||||||
|
|
||||||
| Name | Version | Required? |
|
| Name | Version | Required? | Purpose |
|
||||||
|:------:|:----------|:---------:|
|
|:------:|:--------|:---------:|:---------:|
|
||||||
| catch2 | >= 3.4 | for tests |
|
| catch2 | >= 3.4 | no | for tests |
|
||||||
|
|
||||||
This goes without saying but using a different toolchain to compile these libraries before linking probably won't work.
|
This goes without saying but using a different toolchain to compile these libraries before linking probably won't work.
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "memory.hh"
|
#include "memory.hh"
|
||||||
|
#include "io/io.hh"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
@@ -18,6 +19,7 @@ class Bus {
|
|||||||
void write_word(uint32_t address, uint32_t word);
|
void write_word(uint32_t address, uint32_t word);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
IoDevices io;
|
||||||
std::shared_ptr<Memory> memory;
|
std::shared_ptr<Memory> memory;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
|
|
||||||
|
|
||||||
namespace matar {
|
|
||||||
class IoRegisters {
|
|
||||||
public:
|
|
||||||
uint8_t read(uint32_t) const;
|
|
||||||
void write(uint32_t, uint8_t);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct {
|
|
||||||
bool post_boot_flag = false;
|
|
||||||
bool interrupt_master_enabler = false;
|
|
||||||
} system;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOLINTEND(cppcoreguidelines-avoid-c-arrays)
|
|
32
include/io/io.hh
Normal file
32
include/io/io.hh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lcd.hh"
|
||||||
|
#include "sound.hh"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace matar {
|
||||||
|
class IoDevices {
|
||||||
|
public:
|
||||||
|
uint8_t read_byte(uint32_t) const;
|
||||||
|
void write_byte(uint32_t, uint8_t);
|
||||||
|
|
||||||
|
uint32_t read_word(uint32_t) const;
|
||||||
|
void write_word(uint32_t, uint32_t);
|
||||||
|
|
||||||
|
uint16_t read_halfword(uint32_t) const;
|
||||||
|
void write_halfword(uint32_t, uint16_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
using u16 = uint16_t;
|
||||||
|
bool post_boot_flag;
|
||||||
|
bool interrupt_master_enabler;
|
||||||
|
u16 interrupt_enable;
|
||||||
|
u16 interrupt_request_flags;
|
||||||
|
u16 waitstate_control;
|
||||||
|
bool low_power_mode;
|
||||||
|
} system = {};
|
||||||
|
|
||||||
|
struct lcd lcd = {};
|
||||||
|
struct sound sound = {};
|
||||||
|
};
|
||||||
|
}
|
84
include/io/lcd.hh
Normal file
84
include/io/lcd.hh
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#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)
|
3
include/io/meson.build
Normal file
3
include/io/meson.build
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
headers += files(
|
||||||
|
'io.hh'
|
||||||
|
)
|
66
include/io/sound.hh
Normal file
66
include/io/sound.hh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays)
|
||||||
|
|
||||||
|
/*
|
||||||
|
4000060h 2 R/W SOUND1CNT_L Channel 1 Sweep register (NR10)
|
||||||
|
4000062h 2 R/W SOUND1CNT_H Channel 1 Duty/Length/Envelope (NR11, NR12)
|
||||||
|
4000064h 2 R/W SOUND1CNT_X Channel 1 Frequency/Control (NR13, NR14)
|
||||||
|
4000066h - - Not used
|
||||||
|
4000068h 2 R/W SOUND2CNT_L Channel 2 Duty/Length/Envelope (NR21, NR22)
|
||||||
|
400006Ah - - Not used
|
||||||
|
400006Ch 2 R/W SOUND2CNT_H Channel 2 Frequency/Control (NR23, NR24)
|
||||||
|
400006Eh - - Not used
|
||||||
|
4000070h 2 R/W SOUND3CNT_L Channel 3 Stop/Wave RAM select (NR30)
|
||||||
|
4000072h 2 R/W SOUND3CNT_H Channel 3 Length/Volume (NR31, NR32)
|
||||||
|
4000074h 2 R/W SOUND3CNT_X Channel 3 Frequency/Control (NR33, NR34)
|
||||||
|
4000076h - - Not used
|
||||||
|
4000078h 2 R/W SOUND4CNT_L Channel 4 Length/Envelope (NR41, NR42)
|
||||||
|
400007Ah - - Not used
|
||||||
|
400007Ch 2 R/W SOUND4CNT_H Channel 4 Frequency/Control (NR43, NR44)
|
||||||
|
400007Eh - - Not used
|
||||||
|
4000080h 2 R/W SOUNDCNT_L Control Stereo/Volume/Enable (NR50, NR51)
|
||||||
|
4000082h 2 R/W SOUNDCNT_H Control Mixing/DMA Control
|
||||||
|
4000084h 2 R/W SOUNDCNT_X Control Sound on/off (NR52)
|
||||||
|
4000086h - - Not used
|
||||||
|
4000088h 2 BIOS SOUNDBIAS Sound PWM Control
|
||||||
|
400008Ah .. - - Not used
|
||||||
|
4000090h 2x10h R/W WAVE_RAM Channel 3 Wave Pattern RAM (2 banks!!)
|
||||||
|
40000A0h 4 W FIFO_A Channel A FIFO, Data 0-3
|
||||||
|
40000A4h 4 W FIFO_B Channel B FIFO, Data 0-3
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct sound{
|
||||||
|
using u16 = uint16_t;
|
||||||
|
|
||||||
|
// channel 1
|
||||||
|
u16 ch1_sweep;
|
||||||
|
u16 ch1_duty_length_env;
|
||||||
|
u16 ch1_freq_control;
|
||||||
|
|
||||||
|
// channel 2
|
||||||
|
u16 ch2_duty_length_env;
|
||||||
|
u16 ch2_freq_control;
|
||||||
|
|
||||||
|
// channel 3
|
||||||
|
u16 ch3_stop_wave_ram_select;
|
||||||
|
u16 ch3_length_volume;
|
||||||
|
u16 ch3_freq_control;
|
||||||
|
u16 ch3_wave_pattern[8];
|
||||||
|
|
||||||
|
// channel 4
|
||||||
|
u16 ch4_length_env;
|
||||||
|
u16 ch4_freq_control;
|
||||||
|
|
||||||
|
// control
|
||||||
|
u16 ctrl_stereo_volume;
|
||||||
|
u16 ctrl_mixing;
|
||||||
|
u16 ctrl_sound_on_off;
|
||||||
|
u16 pwm_control;
|
||||||
|
|
||||||
|
// fifo
|
||||||
|
u16 fifo_a[2];
|
||||||
|
u16 fifo_b[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOLINTEND(cppcoreguidelines-avoid-c-arrays)
|
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "header.hh"
|
#include "header.hh"
|
||||||
#include "io.hh"
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -51,8 +50,6 @@ class Memory {
|
|||||||
MEMORY_REGION(ROM_2, 0x0C000000)
|
MEMORY_REGION(ROM_2, 0x0C000000)
|
||||||
|
|
||||||
#undef MEMORY_REGION
|
#undef MEMORY_REGION
|
||||||
|
|
||||||
IoRegisters io;
|
|
||||||
std::unordered_map<uint32_t, uint8_t> invalid_mem;
|
std::unordered_map<uint32_t, uint8_t> invalid_mem;
|
||||||
std::vector<uint8_t> rom;
|
std::vector<uint8_t> rom;
|
||||||
Header header;
|
Header header;
|
||||||
|
@@ -8,5 +8,6 @@ inc = include_directories('.')
|
|||||||
|
|
||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
subdir('util')
|
subdir('util')
|
||||||
|
subdir('io')
|
||||||
|
|
||||||
install_headers(headers, subdir: meson.project_name(), preserve_path: true)
|
install_headers(headers, subdir: meson.project_name(), preserve_path: true)
|
1248
nix/Cargo.lock
generated
Normal file
1248
nix/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
src/bus.cc
28
src/bus.cc
@@ -3,16 +3,28 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace matar {
|
namespace matar {
|
||||||
|
|
||||||
|
static constexpr uint32_t IO_START = 0x4000000;
|
||||||
|
static constexpr uint32_t IO_END = 0x40003FE;
|
||||||
|
|
||||||
Bus::Bus(const Memory& memory)
|
Bus::Bus(const Memory& memory)
|
||||||
: memory(std::make_shared<Memory>(memory)) {}
|
: memory(std::make_shared<Memory>(memory)) {}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
Bus::read_byte(uint32_t address) {
|
Bus::read_byte(uint32_t address) {
|
||||||
|
if (address >= IO_START && address <= IO_END)
|
||||||
|
return io.read_byte(address);
|
||||||
|
|
||||||
return memory->read(address);
|
return memory->read(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Bus::write_byte(uint32_t address, uint8_t byte) {
|
Bus::write_byte(uint32_t address, uint8_t byte) {
|
||||||
|
if (address >= IO_START && address <= IO_END) {
|
||||||
|
io.write_byte(address, byte);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memory->write(address, byte);
|
memory->write(address, byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +33,9 @@ Bus::read_halfword(uint32_t address) {
|
|||||||
if (address & 0b01)
|
if (address & 0b01)
|
||||||
glogger.warn("Reading a non aligned halfword address");
|
glogger.warn("Reading a non aligned halfword address");
|
||||||
|
|
||||||
|
if (address >= IO_START && address <= IO_END)
|
||||||
|
return io.read_halfword(address);
|
||||||
|
|
||||||
return read_byte(address) | read_byte(address + 1) << 8;
|
return read_byte(address) | read_byte(address + 1) << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +44,11 @@ Bus::write_halfword(uint32_t address, uint16_t halfword) {
|
|||||||
if (address & 0b01)
|
if (address & 0b01)
|
||||||
glogger.warn("Writing to a non aligned halfword address");
|
glogger.warn("Writing to a non aligned halfword address");
|
||||||
|
|
||||||
|
if (address >= IO_START && address <= IO_END) {
|
||||||
|
io.write_halfword(address, halfword);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
write_byte(address, halfword & 0xFF);
|
write_byte(address, halfword & 0xFF);
|
||||||
write_byte(address + 1, halfword >> 8 & 0xFF);
|
write_byte(address + 1, halfword >> 8 & 0xFF);
|
||||||
}
|
}
|
||||||
@@ -38,6 +58,9 @@ Bus::read_word(uint32_t address) {
|
|||||||
if (address & 0b11)
|
if (address & 0b11)
|
||||||
glogger.warn("Reading a non aligned word address");
|
glogger.warn("Reading a non aligned word address");
|
||||||
|
|
||||||
|
if (address >= IO_START && address <= IO_END)
|
||||||
|
return io.read_word(address);
|
||||||
|
|
||||||
return read_byte(address) | read_byte(address + 1) << 8 |
|
return read_byte(address) | read_byte(address + 1) << 8 |
|
||||||
read_byte(address + 2) << 16 | read_byte(address + 3) << 24;
|
read_byte(address + 2) << 16 | read_byte(address + 3) << 24;
|
||||||
}
|
}
|
||||||
@@ -47,6 +70,11 @@ Bus::write_word(uint32_t address, uint32_t word) {
|
|||||||
if (address & 0b11)
|
if (address & 0b11)
|
||||||
glogger.warn("Writing to a non aligned word address");
|
glogger.warn("Writing to a non aligned word address");
|
||||||
|
|
||||||
|
if (address >= IO_START && address <= IO_END) {
|
||||||
|
io.write_word(address, word);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
write_byte(address, word & 0xFF);
|
write_byte(address, word & 0xFF);
|
||||||
write_byte(address + 1, word >> 8 & 0xFF);
|
write_byte(address + 1, word >> 8 & 0xFF);
|
||||||
write_byte(address + 2, word >> 16 & 0xFF);
|
write_byte(address + 2, word >> 16 & 0xFF);
|
||||||
|
40
src/io.cc
40
src/io.cc
@@ -1,40 +0,0 @@
|
|||||||
#include "io.hh"
|
|
||||||
#include "util/log.hh"
|
|
||||||
|
|
||||||
namespace matar {
|
|
||||||
#define ADDR static constexpr uint32_t
|
|
||||||
|
|
||||||
ADDR POSTFLG = 0x4000300;
|
|
||||||
ADDR IME = 0x4000208;
|
|
||||||
|
|
||||||
#undef ADDR
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
IoRegisters::read(uint32_t address) const {
|
|
||||||
switch (address) {
|
|
||||||
case POSTFLG:
|
|
||||||
return system.post_boot_flag;
|
|
||||||
case IME:
|
|
||||||
return system.interrupt_master_enabler;
|
|
||||||
default:
|
|
||||||
glogger.warn("Unused IO address read at 0x{:08X}", address);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
IoRegisters::write(uint32_t address, uint8_t byte) {
|
|
||||||
switch (address) {
|
|
||||||
case POSTFLG:
|
|
||||||
system.post_boot_flag = byte & 1;
|
|
||||||
break;
|
|
||||||
case IME:
|
|
||||||
system.interrupt_master_enabler = byte & 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
glogger.warn("Unused IO address written at 0x{:08X}", address);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
279
src/io/io.cc
Normal file
279
src/io/io.cc
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
#include "io/io.hh"
|
||||||
|
#include "util/bits.hh"
|
||||||
|
#include "util/log.hh"
|
||||||
|
|
||||||
|
namespace matar {
|
||||||
|
#define ADDR static constexpr uint32_t
|
||||||
|
|
||||||
|
// lcd
|
||||||
|
ADDR DISPCNT = 0x4000000;
|
||||||
|
ADDR DISPSTAT = 0x4000004;
|
||||||
|
ADDR VCOUNT = 0x4000006;
|
||||||
|
ADDR BG0CNT = 0x4000008;
|
||||||
|
ADDR BG1CNT = 0x400000A;
|
||||||
|
ADDR BG2CNT = 0x400000C;
|
||||||
|
ADDR BG3CNT = 0x400000E;
|
||||||
|
ADDR BG0HOFS = 0x4000010;
|
||||||
|
ADDR BG0VOFS = 0x4000012;
|
||||||
|
ADDR BG1HOFS = 0x4000014;
|
||||||
|
ADDR BG1VOFS = 0x4000016;
|
||||||
|
ADDR BG2HOFS = 0x4000018;
|
||||||
|
ADDR BG2VOFS = 0x400001A;
|
||||||
|
ADDR BG3HOFS = 0x400001C;
|
||||||
|
ADDR BG3VOFS = 0x400001E;
|
||||||
|
ADDR BG2PA = 0x4000020;
|
||||||
|
ADDR BG2PB = 0x4000022;
|
||||||
|
ADDR BG2PC = 0x4000024;
|
||||||
|
ADDR BG2PD = 0x4000026;
|
||||||
|
ADDR BG2X_L = 0x4000028;
|
||||||
|
ADDR BG2X_H = 0x400002A;
|
||||||
|
ADDR BG2Y_L = 0x400002C;
|
||||||
|
ADDR BG2Y_H = 0x400002E;
|
||||||
|
ADDR BG3PA = 0x4000030;
|
||||||
|
ADDR BG3PB = 0x4000032;
|
||||||
|
ADDR BG3PC = 0x4000034;
|
||||||
|
ADDR BG3PD = 0x4000036;
|
||||||
|
ADDR BG3X_L = 0x4000038;
|
||||||
|
ADDR BG3X_H = 0x400003A;
|
||||||
|
ADDR BG3Y_L = 0x400003C;
|
||||||
|
ADDR BG3Y_H = 0x400003E;
|
||||||
|
ADDR WIN0H = 0x4000040;
|
||||||
|
ADDR WIN1H = 0x4000042;
|
||||||
|
ADDR WIN0V = 0x4000044;
|
||||||
|
ADDR WIN1V = 0x4000046;
|
||||||
|
ADDR WININ = 0x4000048;
|
||||||
|
ADDR WINOUT = 0x400004A;
|
||||||
|
ADDR MOSAIC = 0x400004C;
|
||||||
|
ADDR BLDCNT = 0x4000050;
|
||||||
|
ADDR BLDALPHA = 0x4000052;
|
||||||
|
ADDR BLDY = 0x4000054;
|
||||||
|
|
||||||
|
// sound
|
||||||
|
ADDR SOUND1CNT_L = 0x4000060;
|
||||||
|
ADDR SOUND1CNT_H = 0x4000062;
|
||||||
|
ADDR SOUND1CNT_X = 0x4000064;
|
||||||
|
ADDR SOUND2CNT_L = 0x4000068;
|
||||||
|
ADDR SOUND2CNT_H = 0x400006C;
|
||||||
|
ADDR SOUND3CNT_L = 0x4000070;
|
||||||
|
ADDR SOUND3CNT_H = 0x4000072;
|
||||||
|
ADDR SOUND3CNT_X = 0x4000074;
|
||||||
|
ADDR SOUND4CNT_L = 0x4000078;
|
||||||
|
ADDR SOUND4CNT_H = 0x400007C;
|
||||||
|
ADDR SOUNDCNT_L = 0x4000080;
|
||||||
|
ADDR SOUNDCNT_H = 0x4000082;
|
||||||
|
ADDR SOUNDCNT_X = 0x4000084;
|
||||||
|
ADDR SOUNDBIAS = 0x4000088;
|
||||||
|
ADDR WAVE_RAM0_L = 0x4000090;
|
||||||
|
ADDR WAVE_RAM0_H = 0x4000092;
|
||||||
|
ADDR WAVE_RAM1_L = 0x4000094;
|
||||||
|
ADDR WAVE_RAM1_H = 0x4000096;
|
||||||
|
ADDR WAVE_RAM2_L = 0x4000098;
|
||||||
|
ADDR WAVE_RAM2_H = 0x400009A;
|
||||||
|
ADDR WAVE_RAM3_L = 0x400009C;
|
||||||
|
ADDR WAVE_RAM3_H = 0x400009E;
|
||||||
|
ADDR FIFO_A_L = 0x40000A0;
|
||||||
|
ADDR FIFO_A_H = 0x40000A2;
|
||||||
|
ADDR FIFO_B_L = 0x40000A4;
|
||||||
|
ADDR FIFO_B_H = 0x40000A6;
|
||||||
|
|
||||||
|
// system
|
||||||
|
ADDR POSTFLG = 0x4000300;
|
||||||
|
ADDR IME = 0x4000208;
|
||||||
|
ADDR IE = 0x4000200;
|
||||||
|
ADDR IF = 0x4000202;
|
||||||
|
ADDR WAITCNT = 0x4000204;
|
||||||
|
ADDR HALTCNT = 0x4000301;
|
||||||
|
|
||||||
|
#undef ADDR
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
IoDevices::read_byte(uint32_t address) const {
|
||||||
|
uint16_t halfword = read_halfword(address & ~1);
|
||||||
|
|
||||||
|
if (address & 1)
|
||||||
|
halfword >>= 8;
|
||||||
|
|
||||||
|
return halfword & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IoDevices::write_byte(uint32_t address, uint8_t byte) {
|
||||||
|
uint16_t halfword = read_halfword(address & ~1);
|
||||||
|
|
||||||
|
if (address & 1)
|
||||||
|
write_halfword(address & ~1,
|
||||||
|
(static_cast<uint16_t>(byte) << 8) | (halfword & 0xFF));
|
||||||
|
else
|
||||||
|
write_halfword(address & ~1,
|
||||||
|
(static_cast<uint16_t>(byte) | (halfword & 0xFF00)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
IoDevices::read_word(uint32_t address) const {
|
||||||
|
return read_halfword(address) | read_halfword(address + 2) << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IoDevices::write_word(uint32_t address, uint32_t word) {
|
||||||
|
write_halfword(address, word & 0xFFFF);
|
||||||
|
write_halfword(address + 2, (word >> 16) & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
IoDevices::read_halfword(uint32_t address) const {
|
||||||
|
switch (address) {
|
||||||
|
|
||||||
|
#define READ(name, var) \
|
||||||
|
case name: \
|
||||||
|
return var;
|
||||||
|
|
||||||
|
// lcd
|
||||||
|
READ(DISPCNT, lcd.lcd_control)
|
||||||
|
READ(DISPSTAT, lcd.general_lcd_status)
|
||||||
|
READ(VCOUNT, lcd.vertical_counter)
|
||||||
|
READ(WININ, lcd.inside_win_0_1)
|
||||||
|
READ(WINOUT, lcd.outside_win)
|
||||||
|
READ(BLDCNT, lcd.color_special_effects_selection)
|
||||||
|
READ(BLDALPHA, lcd.alpha_blending_coefficients)
|
||||||
|
|
||||||
|
// sound
|
||||||
|
READ(SOUND1CNT_L, sound.ch1_sweep)
|
||||||
|
READ(SOUND1CNT_H, sound.ch1_duty_length_env)
|
||||||
|
READ(SOUND1CNT_X, sound.ch1_freq_control)
|
||||||
|
READ(SOUND2CNT_L, sound.ch2_duty_length_env)
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
default:
|
||||||
|
glogger.warn("Unused IO address read at 0x{:08X}", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IoDevices::write_halfword(uint32_t address, uint16_t halfword) {
|
||||||
|
switch (address) {
|
||||||
|
|
||||||
|
#define WRITE(name, var) \
|
||||||
|
case name: \
|
||||||
|
var = halfword; \
|
||||||
|
break;
|
||||||
|
|
||||||
|
#define WRITE_2(name, var, val) \
|
||||||
|
case name: \
|
||||||
|
var = val; \
|
||||||
|
break;
|
||||||
|
|
||||||
|
// lcd
|
||||||
|
WRITE(DISPCNT, lcd.lcd_control)
|
||||||
|
WRITE(DISPSTAT, lcd.general_lcd_status)
|
||||||
|
WRITE(BG0CNT, lcd.bg0_control)
|
||||||
|
WRITE(BG1CNT, lcd.bg1_control)
|
||||||
|
WRITE(BG2CNT, lcd.bg2_control)
|
||||||
|
WRITE(BG3CNT, lcd.bg3_control)
|
||||||
|
WRITE(BG0HOFS, lcd.bg0_x_offset)
|
||||||
|
WRITE(BG0VOFS, lcd.bg0_y_offset)
|
||||||
|
WRITE(BG1HOFS, lcd.bg1_x_offset)
|
||||||
|
WRITE(BG1VOFS, lcd.bg1_y_offset)
|
||||||
|
WRITE(BG2HOFS, lcd.bg2_x_offset)
|
||||||
|
WRITE(BG2VOFS, lcd.bg2_y_offset)
|
||||||
|
WRITE(BG3HOFS, lcd.bg3_x_offset)
|
||||||
|
WRITE(BG3VOFS, lcd.bg3_y_offset)
|
||||||
|
WRITE(BG2PA, lcd.bg2_rot_scaling_parameters[0])
|
||||||
|
WRITE(BG2PB, lcd.bg2_rot_scaling_parameters[1])
|
||||||
|
WRITE(BG2PC, lcd.bg2_rot_scaling_parameters[2])
|
||||||
|
WRITE(BG2PD, lcd.bg2_rot_scaling_parameters[3])
|
||||||
|
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(SOUND1CNT_L, sound.ch1_sweep)
|
||||||
|
WRITE(SOUND1CNT_H, sound.ch1_duty_length_env)
|
||||||
|
WRITE(SOUND1CNT_X, sound.ch1_freq_control)
|
||||||
|
WRITE(SOUND2CNT_L, sound.ch2_duty_length_env)
|
||||||
|
WRITE(SOUND2CNT_H, sound.ch2_freq_control)
|
||||||
|
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]);
|
||||||
|
|
||||||
|
// 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_2
|
||||||
|
|
||||||
|
default:
|
||||||
|
glogger.warn("Unused IO address written at 0x{:08X}", address);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
3
src/io/meson.build
Normal file
3
src/io/meson.build
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
lib_sources += files(
|
||||||
|
'io.cc',
|
||||||
|
)
|
@@ -41,10 +41,6 @@ Memory::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)
|
||||||
|
|
||||||
if (address >= 0x04000000 && address <= 0x040003FE)
|
|
||||||
return io.read(address);
|
|
||||||
|
|
||||||
MATCHES(PALETTE_RAM, palette_ram)
|
MATCHES(PALETTE_RAM, palette_ram)
|
||||||
MATCHES(VRAM, vram)
|
MATCHES(VRAM, vram)
|
||||||
MATCHES(OAM_OBJ_ATTR, oam_obj_attr)
|
MATCHES(OAM_OBJ_ATTR, oam_obj_attr)
|
||||||
@@ -68,12 +64,6 @@ Memory::write(uint32_t address, uint8_t byte) {
|
|||||||
|
|
||||||
MATCHES(BOARD_WRAM, board_wram)
|
MATCHES(BOARD_WRAM, board_wram)
|
||||||
MATCHES(CHIP_WRAM, chip_wram)
|
MATCHES(CHIP_WRAM, chip_wram)
|
||||||
|
|
||||||
if (address >= 0x04000000 && address <= 0x040003FE) {
|
|
||||||
io.write(address, byte);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MATCHES(PALETTE_RAM, palette_ram)
|
MATCHES(PALETTE_RAM, palette_ram)
|
||||||
MATCHES(VRAM, vram)
|
MATCHES(VRAM, vram)
|
||||||
MATCHES(OAM_OBJ_ATTR, oam_obj_attr)
|
MATCHES(OAM_OBJ_ATTR, oam_obj_attr)
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
lib_sources = files(
|
lib_sources = files(
|
||||||
'memory.cc',
|
'memory.cc',
|
||||||
'bus.cc',
|
'bus.cc',
|
||||||
'io.cc'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('util')
|
subdir('util')
|
||||||
subdir('cpu')
|
subdir('cpu')
|
||||||
|
subdir('io')
|
||||||
|
|
||||||
lib_cpp_args = []
|
lib_cpp_args = []
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@ class Logger {
|
|||||||
using LogLevel = matar::LogLevel;
|
using LogLevel = matar::LogLevel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Logger(LogLevel level = LogLevel::Debug, FILE* stream = stderr)
|
Logger(LogLevel level = LogLevel::Debug, FILE* stream = stdout)
|
||||||
: level(0)
|
: level(0)
|
||||||
, stream(stream) {
|
, stream(stream) {
|
||||||
set_level(level);
|
set_level(level);
|
||||||
|
Reference in New Issue
Block a user