mirror of
https://github.com/whaison/psxact.git
synced 2024-05-16 19:10:33 -04:00
Fixing some major bugs with interrupts.
This commit is contained in:
parent
4c911c465d
commit
a1038d7fa9
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
bin/
|
||||
cmake-build-*/
|
||||
.idea/
|
||||
|
|
|
@ -48,8 +48,8 @@ void cpu::run(int count) {
|
|||
state.cop0.regs[13] &= ~(1 << 10);
|
||||
}
|
||||
|
||||
auto iec = state.cop0.regs[12] & 1;
|
||||
auto irq = state.cop0.regs[12] & state.cop0.regs[13] & 0xf0;
|
||||
auto iec = (state.cop0.regs[12] & 1) != 0;
|
||||
auto irq = (state.cop0.regs[12] & state.cop0.regs[13] & 0xff00) != 0;
|
||||
|
||||
if (iec && irq) {
|
||||
enter_exception(0x0);
|
||||
|
@ -74,10 +74,10 @@ void cpu::enter_exception(uint32_t code) {
|
|||
|
||||
if (state.is_branch_delay_slot) {
|
||||
epc = state.regs.this_pc - 4;
|
||||
cause |= (1 << 31);
|
||||
cause |= 0x80000000;
|
||||
} else {
|
||||
epc = state.regs.this_pc;
|
||||
cause &= ~(1 << 31);
|
||||
cause &= ~0x80000000;
|
||||
}
|
||||
|
||||
state.cop0.regs[12] = status;
|
||||
|
@ -105,7 +105,7 @@ static uint32_t segments[8] = {
|
|||
0x7fffffff, //
|
||||
0x1fffffff, // kseg0 ($8000_0000 - $9fff_ffff)
|
||||
0x1fffffff, // kseg1 ($a000_0000 - $bfff_ffff)
|
||||
0x3fffffff, // kseg2 ($c000_0000 - $ffff_ffff)
|
||||
0xffffffff, // kseg2 ($c000_0000 - $ffff_ffff)
|
||||
0xffffffff //
|
||||
};
|
||||
|
||||
|
@ -188,15 +188,23 @@ void cpu::write_data_word(uint32_t address, uint32_t data) {
|
|||
}
|
||||
|
||||
uint32_t cpu::mmio_read(int, uint32_t address) {
|
||||
switch (address - 0x1f801070) {
|
||||
case 0: return state.i_stat;
|
||||
case 4: return state.i_mask;
|
||||
switch (address) {
|
||||
case 0x1f801070:
|
||||
return state.i_stat;
|
||||
|
||||
case 0x1f801074:
|
||||
return state.i_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu::mmio_write(int, uint32_t address, uint32_t data) {
|
||||
switch (address - 0x1f801070) {
|
||||
case 0: state.i_stat = state.i_stat & data; break;
|
||||
case 4: state.i_mask = data & 0x7ff; break;
|
||||
switch (address) {
|
||||
case 0x1f801070:
|
||||
state.i_stat = state.i_stat & data;
|
||||
break;
|
||||
|
||||
case 0x1f801074:
|
||||
state.i_mask = data & 0x7ff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,13 +11,6 @@ static inline uint32_t get_register_index(uint32_t address) {
|
|||
return (address >> 2) & 3;
|
||||
}
|
||||
|
||||
void dma::initialize() {
|
||||
state.dpcr = 0x07654321;
|
||||
state.dicr = 0x00000000;
|
||||
|
||||
state.channels[2].dst_address = 0x1f801810;
|
||||
}
|
||||
|
||||
uint32_t dma::mmio_read(int size, uint32_t address) {
|
||||
auto channel = get_channel_index(address);
|
||||
if (channel == 7) {
|
||||
|
@ -30,9 +23,9 @@ uint32_t dma::mmio_read(int size, uint32_t address) {
|
|||
}
|
||||
else {
|
||||
switch ((address >> 2) & 3) {
|
||||
case 0: return state.channels[channel].base_address;
|
||||
case 1: return state.channels[channel].block_control;
|
||||
case 2: return state.channels[channel].channel_control;
|
||||
case 0: return state.channels[channel].address;
|
||||
case 1: return state.channels[channel].counter;
|
||||
case 2: return state.channels[channel].control;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,9 +39,9 @@ void dma::mmio_write(int size, uint32_t address, uint32_t data) {
|
|||
case 0: state.dpcr = data & 0xffffffff; break;
|
||||
|
||||
case 1:
|
||||
state.dicr &= (0xff000000 );
|
||||
state.dicr |= (0x00ff803f & data);
|
||||
state.dicr &= ~(0x7f000000 & data);
|
||||
state.dicr &= ( 0xff000000);
|
||||
state.dicr |= (data & 0x00ff803f);
|
||||
state.dicr &= ~(data & 0x7f000000);
|
||||
break;
|
||||
|
||||
case 2: break;
|
||||
|
@ -57,139 +50,100 @@ void dma::mmio_write(int size, uint32_t address, uint32_t data) {
|
|||
}
|
||||
else {
|
||||
switch ((address >> 2) & 3) {
|
||||
case 0: state.channels[channel].base_address = data; break;
|
||||
case 1: state.channels[channel].block_control = data; break;
|
||||
case 2: state.channels[channel].channel_control = data; break;
|
||||
case 0: state.channels[channel].address = data & 0x00ffffff; break;
|
||||
case 1: state.channels[channel].counter = data & 0xffffffff; break;
|
||||
case 2: state.channels[channel].control = data & 0x71770703; break;
|
||||
}
|
||||
}
|
||||
|
||||
dma::main();
|
||||
}
|
||||
|
||||
static void dma_sync_mode_0(dma::channel_t &channel) {
|
||||
if ((channel.channel_control & 0x10000000) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto count = channel.block_control & 0xffff;
|
||||
|
||||
auto address = channel.base_address & 0xffffff;
|
||||
auto address_step = (channel.channel_control & 2) ? 0xfffffffc : 0x00000004;
|
||||
|
||||
do {
|
||||
if (count == 1) {
|
||||
bus::write_word(address, 0x00ffffff);
|
||||
} else {
|
||||
bus::write_word(address, address - 4);
|
||||
}
|
||||
|
||||
address += address_step;
|
||||
|
||||
count = (count - 1) & 0xffff;
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
|
||||
channel.channel_control &= ~0x11000000;
|
||||
void dma::main() {
|
||||
if (state.dpcr & 0x08000000) { run_channel(6); }
|
||||
if (state.dpcr & 0x00800000) { run_channel(5); }
|
||||
if (state.dpcr & 0x00080000) { run_channel(4); }
|
||||
if (state.dpcr & 0x00008000) { run_channel(3); }
|
||||
if (state.dpcr & 0x00000800) { run_channel(2); }
|
||||
if (state.dpcr & 0x00000080) { run_channel(1); }
|
||||
if (state.dpcr & 0x00000008) { run_channel(0); }
|
||||
}
|
||||
|
||||
static void dma_sync_mode_1(dma::channel_t &channel) {
|
||||
if ((channel.channel_control & 0x01000000) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto bs = channel.block_control & 0xffff;
|
||||
auto ba = channel.block_control >> 16;
|
||||
static void run_channel_2_data_read() {
|
||||
auto address = state.channels[2].address & 0x00ffffff;
|
||||
auto bs = (state.channels[2].counter >> 0) & 0xffff;
|
||||
auto ba = (state.channels[2].counter >> 16) & 0xffff;
|
||||
|
||||
bs = bs ? bs : 0x10000;
|
||||
ba = ba ? ba : 0x10000;
|
||||
|
||||
auto length = bs * ba;
|
||||
auto address = channel.base_address & 0x00ffffff;
|
||||
auto address_step = (channel.channel_control & 2) ? 0xfffffffc : 0x00000004;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
auto data = bus::read_word(address);
|
||||
bus::write_word(channel.dst_address, data);
|
||||
address += address_step;
|
||||
for (int a = 0; a < ba; a++) {
|
||||
for (int s = 0; s < bs; s++) {
|
||||
auto data = bus::read_word(0x1f801810);
|
||||
bus::write_word(address, data);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
|
||||
channel.channel_control &= ~0x11000000;
|
||||
state.channels[2].control &= ~0x01000000;
|
||||
}
|
||||
|
||||
static void dma_sync_mode_2(dma::channel_t &channel) {
|
||||
if ((channel.channel_control & 0x01000000) == 0) {
|
||||
return;
|
||||
static void run_channel_2_data_write() {
|
||||
auto address = state.channels[2].address & 0x00ffffff;
|
||||
auto bs = (state.channels[2].counter >> 0) & 0xffff;
|
||||
auto ba = (state.channels[2].counter >> 16) & 0xffff;
|
||||
|
||||
bs = bs ? bs : 0x10000;
|
||||
ba = ba ? ba : 0x10000;
|
||||
|
||||
for (int a = 0; a < ba; a++) {
|
||||
for (int s = 0; s < bs; s++) {
|
||||
auto data = bus::read_word(address);
|
||||
bus::write_word(0x1f801810, data);
|
||||
address += 4;
|
||||
}
|
||||
}
|
||||
|
||||
auto address = channel.base_address & 0xffffff;
|
||||
state.channels[2].control &= ~0x01000000;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto header = bus::read_word(address);
|
||||
auto count = header >> 24;
|
||||
static void run_channel_2_list() {
|
||||
auto address = state.channels[2].address & 0xffffff;
|
||||
|
||||
while (address != 0xffffff) {
|
||||
auto value = bus::read_word(address);
|
||||
auto count = value >> 24;
|
||||
|
||||
for (auto index = 0; index < count; index++) {
|
||||
address += 4;
|
||||
auto command = bus::read_word(address);
|
||||
|
||||
bus::write_word(channel.dst_address, command);
|
||||
auto command = bus::read_word(address += 4);
|
||||
bus::write_word(0x1f801810, command);
|
||||
}
|
||||
|
||||
address = header & 0xffffff;
|
||||
|
||||
if (address == 0xffffff) {
|
||||
break;
|
||||
}
|
||||
address = value & 0xffffff;
|
||||
}
|
||||
|
||||
channel.channel_control &= ~0x11000000;
|
||||
state.channels[2].control &= ~0x01000000;
|
||||
}
|
||||
|
||||
static void dma_irq(int level) {
|
||||
if (!(state.dicr & 0x80000000) && level) {
|
||||
bus::irq_req(3);
|
||||
static void run_channel_6() {
|
||||
auto address = state.channels[6].address & 0xffffff;
|
||||
auto counter = state.channels[6].counter & 0xffff;
|
||||
|
||||
counter = counter ? counter : 0x10000;
|
||||
|
||||
for (int i = 1; i < counter; i++) {
|
||||
bus::write_word(address, address - 4);
|
||||
address -= 4;
|
||||
}
|
||||
|
||||
state.dicr &= ~0x80000000;
|
||||
state.dicr |= level << 31;
|
||||
bus::write_word(address, 0x00ffffff);
|
||||
|
||||
state.channels[6].control &= ~0x11000000;
|
||||
}
|
||||
|
||||
void dma::main() {
|
||||
auto channel_irq_enable = 1 << 16;
|
||||
auto channel_irq_request = 1 << 24;
|
||||
auto mask = 0x00000008;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
auto &channel = state.channels[i];
|
||||
|
||||
if (state.dpcr & mask) {
|
||||
switch ((channel.channel_control >> 9) & 3) {
|
||||
case 0: dma_sync_mode_0(channel); break;
|
||||
case 1: dma_sync_mode_1(channel); break;
|
||||
case 2: dma_sync_mode_2(channel); break;
|
||||
case 3: break;
|
||||
}
|
||||
|
||||
if (state.dicr & channel_irq_enable) {
|
||||
state.dicr |= channel_irq_request;
|
||||
}
|
||||
}
|
||||
|
||||
channel_irq_enable <<= 1;
|
||||
channel_irq_request <<= 1;
|
||||
mask <<= 4;
|
||||
}
|
||||
|
||||
int force = (state.dicr >> 15) & 1;
|
||||
int enable = (state.dicr >> 16) & 0x7f;
|
||||
int master = (state.dicr >> 23) & 1;
|
||||
int request = (state.dicr >> 24) & 0x7f;
|
||||
|
||||
if (force || (master && (enable & request) != 0)) {
|
||||
dma_irq(1);
|
||||
} else {
|
||||
dma_irq(0);
|
||||
}
|
||||
void dma::run_channel(int n) {
|
||||
if (n == 2 && state.channels[2].control == 0x01000200) { return run_channel_2_data_read(); }
|
||||
if (n == 2 && state.channels[2].control == 0x01000201) { return run_channel_2_data_write(); }
|
||||
if (n == 2 && state.channels[2].control == 0x01000401) { return run_channel_2_list(); }
|
||||
if (n == 6 && state.channels[6].control == 0x11000002) { return run_channel_6(); }
|
||||
}
|
||||
|
|
|
@ -4,27 +4,24 @@
|
|||
#include <cstdint>
|
||||
|
||||
namespace dma {
|
||||
struct channel_t {
|
||||
uint32_t dst_address;
|
||||
uint32_t base_address;
|
||||
uint32_t block_control;
|
||||
uint32_t channel_control;
|
||||
};
|
||||
|
||||
struct state_t {
|
||||
uint32_t dpcr = 0x07654321;
|
||||
uint32_t dicr;
|
||||
uint32_t dicr = 0x00000000;
|
||||
|
||||
channel_t channels[7];
|
||||
struct {
|
||||
uint32_t address;
|
||||
uint32_t counter;
|
||||
uint32_t control;
|
||||
} channels[7];
|
||||
};
|
||||
|
||||
void initialize();
|
||||
|
||||
uint32_t mmio_read(int size, uint32_t address);
|
||||
|
||||
void mmio_write(int size, uint32_t address, uint32_t data);
|
||||
|
||||
void main();
|
||||
|
||||
void run_channel(int n);
|
||||
}
|
||||
|
||||
#endif //PSXACT_DMA_CORE_HPP
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
static gpu::state_t state;
|
||||
|
||||
static int gp0_command_size[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // $00
|
||||
1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // $00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // $10
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 9, 1, 1, 1, // $20
|
||||
6, 1, 1, 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, // $30
|
||||
|
@ -149,6 +149,27 @@ static inline void write_gp0(uint32_t data) {
|
|||
case 0x00: get_gp0_data(); break; // nop
|
||||
case 0x01: get_gp0_data(); break; // clear texture cache
|
||||
|
||||
case 0x02: { // fill rectangle
|
||||
auto color = gp0_to_color(get_gp0_data());
|
||||
auto point1 = gp0_to_point(get_gp0_data());
|
||||
auto point2 = gp0_to_point(get_gp0_data());
|
||||
|
||||
point1.x = (point1.x + 0x0) & ~0xf;
|
||||
point2.x = (point2.x + 0xf) & ~0xf;
|
||||
|
||||
for (int y = 0; y < point2.y; y++) {
|
||||
for (int x = 0; x < point2.x; x++) {
|
||||
gpu::draw_point(point1.x + x,
|
||||
point1.y + y,
|
||||
color.r,
|
||||
color.g,
|
||||
color.b);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x28: { // monochrome quad, opaque
|
||||
auto color = get_gp0_data();
|
||||
auto point1 = get_gp0_data();
|
||||
|
|
|
@ -9,11 +9,12 @@ int main(int argc, char *argv[]) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
freopen("C:/Users/Adam.Becker/stdout.log", "w", stdout);
|
||||
|
||||
std::string bios_file_name(argv[1]);
|
||||
std::string game_file_name(argv[2]);
|
||||
|
||||
cpu::initialize();
|
||||
dma::initialize();
|
||||
bus::initialize(bios_file_name, game_file_name);
|
||||
|
||||
renderer::initialize();
|
||||
|
|
Loading…
Reference in a new issue