Fixing DMA interrupts.

This commit is contained in:
Adam Becker 2016-11-25 11:11:31 -07:00
parent adef3b48fe
commit 955f16d4dc
5 changed files with 50 additions and 44 deletions

View file

@ -27,6 +27,8 @@ void bus::irq_ack(int interrupt) {
}
void bus::irq_req(int interrupt) {
printf("bus::irq_req(%d)\n", interrupt);
cpu::state.i_stat |= (1 << interrupt);
}

View file

@ -66,24 +66,8 @@ uint32_t cdrom::mmio_read(int size, uint32_t address) {
return 0;
}
static void (*response2)();
static void get_id_response_no_disk() {
set_resp(0x08); set_resp(0x40);
set_resp(0x00); set_resp(0x00);
// the bios isn't interested in these, and the current fifo implementation
// could cause memory leaks.
//
// set_resp(0x00); set_resp(0x00); set_resp(0x00); set_resp(0x00);
cdrom::state.interrupt_request = 5;
bus::irq_req(2);
response2 = nullptr;
}
static void command_get_stat() {
set_resp(0);
set_resp(0x02);
cdrom::state.interrupt_request = 3;
bus::irq_req(2);
@ -92,10 +76,10 @@ static void command_get_stat() {
static void command_test() {
switch (get_arg()) {
case 0x20:
set_resp(96);
set_resp(1);
set_resp(1);
set_resp(2);
set_resp(0x99);
set_resp(0x02);
set_resp(0x01);
set_resp(0xc3);
cdrom::state.interrupt_request = 3;
bus::irq_req(2);
@ -103,15 +87,6 @@ static void command_test() {
}
}
static void command_get_id() {
set_resp(0);
cdrom::state.interrupt_request = 3;
bus::irq_req(2);
response2 = &get_id_response_no_disk;
}
void cdrom::mmio_write(int size, uint32_t address, uint32_t data) {
assert(size == BYTE);
@ -132,9 +107,6 @@ void cdrom::mmio_write(int size, uint32_t address, uint32_t data) {
case 0x19:
return command_test();
case 0x1a:
return command_get_id();
default:
printf("cd-rom command: $%02x\n", data);
break;
@ -177,10 +149,6 @@ void cdrom::mmio_write(int size, uint32_t address, uint32_t data) {
case 1: // interrupt flag register
state.interrupt_request &= ~data;
if (response2) {
response2();
}
break;
case 2: // audio volume for cd-left to spu-right

View file

@ -22,7 +22,7 @@ uint32_t dma::mmio_read(int size, uint32_t address) {
}
}
else {
switch ((address >> 2) & 3) {
switch (get_register_index(address)) {
case 0: return state.channels[channel].address;
case 1: return state.channels[channel].counter;
case 2: return state.channels[channel].control;
@ -36,7 +36,7 @@ void dma::mmio_write(int size, uint32_t address, uint32_t data) {
auto channel = get_channel_index(address);
if (channel == 7) {
switch (get_register_index(address)) {
case 0: state.dpcr = data & 0xffffffff; break;
case 0: state.dpcr = data; break;
case 1:
state.dicr &= ( 0xff000000);
@ -49,7 +49,7 @@ void dma::mmio_write(int size, uint32_t address, uint32_t data) {
}
}
else {
switch ((address >> 2) & 3) {
switch (get_register_index(address)) {
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;
@ -86,6 +86,8 @@ static void run_channel_2_data_read() {
}
state.channels[2].control &= ~0x01000000;
dma::irq_channel(2);
}
static void run_channel_2_data_write() {
@ -105,6 +107,8 @@ static void run_channel_2_data_write() {
}
state.channels[2].control &= ~0x01000000;
dma::irq_channel(2);
}
static void run_channel_2_list() {
@ -123,6 +127,8 @@ static void run_channel_2_list() {
}
state.channels[2].control &= ~0x01000000;
dma::irq_channel(2);
}
static void run_channel_6() {
@ -139,11 +145,40 @@ static void run_channel_6() {
bus::write_word(address, 0x00ffffff);
state.channels[6].control &= ~0x11000000;
dma::irq_channel(6);
}
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 == 2) {
if (state.channels[2].control == 0x01000200) { return run_channel_2_data_read(); }
if (state.channels[2].control == 0x01000201) { return run_channel_2_data_write(); }
if (state.channels[2].control == 0x01000401) { return run_channel_2_list(); }
}
if (n == 6 && state.channels[6].control == 0x11000002) { return run_channel_6(); }
}
void dma::irq_channel(int n) {
int flag = 1 << (n + 24);
int mask = 1 << (n + 16);
if (state.dicr & mask) {
state.dicr |= flag;
}
auto forced = ((state.dicr >> 15) & 1) != 0;
auto master = ((state.dicr >> 23) & 1) != 0;
auto signal = ((state.dicr >> 16) & (state.dicr >> 24) & 0x7f) != 0;
auto active = forced || (master && signal);
if (active) {
if (!(state.dicr & 0x80000000)) {
bus::irq_req(3);
}
state.dicr |= 0x80000000;
} else {
state.dicr &= ~0x80000000;
}
}

View file

@ -21,6 +21,8 @@ namespace dma {
void main();
void irq_channel(int n);
void run_channel(int n);
}

View file

@ -1,6 +1,5 @@
#include "bus.hpp"
#include "cpu/cpu_core.hpp"
#include "dma/dma_core.hpp"
#include "gpu/gpu_core.hpp"
#include "renderer.hpp"