Update to ares v114r08 release.

- PlayStation: fixed a bug in the SLLV instruction
  - PlayStation: implemented interrupts
このコミットが含まれているのは:
Near 2020-06-24 09:25:00 +00:00
コミット 0ed46cc2b1
16個のファイルの変更346行の追加55行の削除

ファイルの表示

@ -2,7 +2,7 @@
namespace ares {
static const string Name = "ares";
static const string Version = "114.7";
static const string Version = "114.8";
static const string Copyright = "ares team";
static const string License = "BY-NC-ND 4.0";
static const string LicenseURI = "https://creativecommons.org/licenses/by-nc-nd/4.0/";

ファイルの表示

@ -26,13 +26,21 @@ auto CPU::raiseException(uint code, uint coprocessor) -> void {
auto CPU::instruction() -> void {
auto address = PC;
if(auto interrupts = scc.cause.interruptPending & scc.status.interruptMask) {
if(interrupt.line & scc.status.frame[0].interruptEnable) {
scc.cause.interruptPending = interrupts;
step(1);
return raiseException(0);
}
}
if constexpr(1) {
pipeline.address = address;
pipeline.instruction = bus.readWord(address);
//instructionDebug();
decoderEXECUTE();
instructionEpilogue();
step(1);
step(2);
}
}
@ -65,8 +73,8 @@ auto CPU::instructionEpilogue() -> bool {
}
auto CPU::instructionDebug() -> void {
pipeline.address = PC;
pipeline.instruction = bus.readWord(pipeline.address);
//pipeline.address = PC;
//pipeline.instruction = bus.readWord(pipeline.address);
static vector<bool> mask;
if(!mask) mask.resize(0x0800'0000);

ファイルの表示

@ -87,7 +87,7 @@
op(0x01, INVALID);
op(0x02, SRL, RD, RT, SA);
op(0x03, SRA, RD, RT, SA);
op(0x04, SLLV, RD, RT, SA);
op(0x04, SLLV, RD, RT, RS);
op(0x05, INVALID);
op(0x06, SRLV, RD, RT, RS);
op(0x07, SRAV, RD, RT, RS);

ファイルの表示

@ -7,7 +7,7 @@
auto disassemble(u32 address, u32 instruction) -> string;
template<typename... P> auto hint(P&&... p) const -> string;
bool showColors = true;
bool showColors = false;
bool showValues = true;
//private:

ファイルの表示

@ -4,6 +4,7 @@ namespace ares::PlayStation {
CPU cpu;
#include "core/core.cpp"
#include "interrupt.cpp"
#include "dma.cpp"
#include "serialization.cpp"

ファイルの表示

@ -19,14 +19,57 @@ struct CPU : Thread {
#include "core/core.hpp"
struct DMA : Memory::IO<DMA> {
struct Interrupt {
enum : uint { Vblank, GPU, CDROM, DMA, Timer0, Timer1, Timer2, Peripheral, SIO, SPU, PIO };
CPU& self;
Interrupt(CPU& self) : self(self) {}
//interrupt.cpp
auto poll() -> void;
auto pulse(uint source) -> void;
auto raise(uint source) -> void;
auto lower(uint source) -> void;
auto readByte(u32 address) -> u8;
auto readHalf(u32 address) -> u16;
auto readWord(u32 address) -> u32;
auto writeByte(u32 address, u8 data) -> void;
auto writeHalf(u32 address, u16 data) -> void;
auto writeWord(u32 address, u32 data) -> void;
struct Source {
uint1 line = 0;
uint1 stat = 0;
uint1 mask = 0;
};
uint1 line = 0;
Source vblank;
Source gpu;
Source cdrom;
Source dma;
Source timer0;
Source timer1;
Source timer2;
Source peripheral;
Source sio;
Source spu;
Source pio;
} interrupt{*this};
struct DMA {
enum : uint { MDECIN, MDECOUT, GPU, CDROM, SPU, PIO, OTC }; //channels
CPU& self;
DMA(CPU& self) : self(self) {}
//dma.cpp
auto readByte(u32 address) -> u8;
auto readHalf(u32 address) -> u16;
auto readWord(u32 address) -> u32;
auto writeByte(u32 address, u8 data) -> void;
auto writeHalf(u32 address, u16 data) -> void;
auto writeWord(u32 address, u32 data) -> void;
auto transferLinear(uint c) -> void;
auto transferLinked(uint c) -> void;

ファイルの表示

@ -1,20 +1,28 @@
auto CPU::DMA::readByte(u32 address) -> u8 {
return 0;
}
auto CPU::DMA::readHalf(u32 address) -> u16 {
return 0;
}
auto CPU::DMA::readWord(u32 address) -> u32 {
uint32 data = 0;
uint32 c = address >> 4 & 7;
//DnMADR: DMA Base Address
if((address & 0xffff'ff0f) == 0x1f80'1080 && c < 7) {
if((address & 0xffff'ff8f) == 0x1f80'1080 && c < 7) {
data.bit(0,23) = channel[c].address;
}
//DnBCR: DMA Block Control
if((address & 0xffff'ff0f) == 0x1f80'1084 && c < 7) {
if((address & 0xffff'ff8f) == 0x1f80'1084 && c < 7) {
data.bit( 0,15) = channel[c].length;
data.bit(16,31) = channel[c].blocks;
}
//DnCHCR: DMA Channel Control
if((address & 0xffff'ff0f) == 0x1f80'1088 && c < 7) {
if((address & 0xffff'ff8f) == 0x1f80'1088 && c < 7) {
data.bit( 0) = channel[c].direction;
data.bit( 1) = channel[c].step;
data.bit( 2) = channel[c].chopping.enable;
@ -68,6 +76,12 @@ auto CPU::DMA::readWord(u32 address) -> u32 {
return data;
}
auto CPU::DMA::writeByte(u32 address, u8 value) -> void {
}
auto CPU::DMA::writeHalf(u32 address, u16 value) -> void {
}
auto CPU::DMA::writeWord(u32 address, u32 value) -> void {
uint32 data = value;
uint32 c = address >> 4 & 7;
@ -95,12 +109,14 @@ auto CPU::DMA::writeWord(u32 address, u32 value) -> void {
channel[c].trigger = data.bit(28);
channel[c].unknown = data.bit(29,30);
//print(c, " ", channel[c].direction, " ", channel[c].synchronization, " ", hex(channel[c].address, 8L), "\n");
if(channel[c].active()) {
//u32 base = address & 0xffff'fff0;
//print("DMA", c, " ", hex(readWord(base + 8), 8L), " ", hex(readWord(base + 0), 8L), " ", hex(readWord(base + 4), 8L), "\n");
if(channel[c].synchronization == 0) transferLinear(c);
if(channel[c].synchronization == 1) transferLinear(c);
if(channel[c].synchronization == 2) transferLinked(c);
self.interrupt.pulse(CPU::Interrupt::DMA);
}
}
@ -194,6 +210,8 @@ auto CPU::DMA::transferLinked(uint c) -> void {
address = header & 0xffffff;
if(address & 0x800000) break;
} while(--timeout);
channel[c].enable = 0;
channel[c].trigger = 0;
}
auto CPU::DMA::pollIRQ() -> void {

146
ares/ps1/cpu/interrupt.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,146 @@
auto CPU::Interrupt::poll() -> void {
line = 0;
line |= vblank.stat & vblank.mask;
line |= gpu.stat & gpu.mask;
line |= cdrom.stat & cdrom.mask;
line |= dma.stat & dma.mask;
line |= timer0.stat & timer0.mask;
line |= timer1.stat & timer1.mask;
line |= timer2.stat & timer2.mask;
line |= peripheral.stat & peripheral.mask;
line |= sio.stat & sio.mask;
line |= spu.stat & spu.mask;
line |= pio.stat & pio.mask;
self.scc.cause.interruptPending.bit(2) = line;
}
auto CPU::Interrupt::pulse(uint source) -> void {
raise(source);
lower(source);
}
auto CPU::Interrupt::raise(uint source) -> void {
if(source == 0 && !vblank.line) vblank.line = vblank.stat = 1;
if(source == 1 && !gpu.line) gpu.line = gpu.stat = 1;
if(source == 2 && !cdrom.line) cdrom.line = cdrom.stat = 1;
if(source == 3 && !dma.line) dma.line = dma.stat = 1;
if(source == 4 && !timer0.line) timer0.line = timer0.stat = 1;
if(source == 5 && !timer1.line) timer1.line = timer1.stat = 1;
if(source == 6 && !timer2.line) timer2.line = timer2.stat = 1;
if(source == 7 && !peripheral.line) peripheral.line = peripheral.stat = 1;
if(source == 8 && !sio.line) sio.line = sio.stat = 1;
if(source == 9 && !spu.line) spu.line = spu.stat = 1;
if(source == 10 && !pio.line) pio.line = pio.stat = 1;
poll();
}
auto CPU::Interrupt::lower(uint source) -> void {
if(source == 0) vblank.line = 0;
if(source == 1) gpu.line = 0;
if(source == 2) cdrom.line = 0;
if(source == 3) dma.line = 0;
if(source == 4) timer0.line = 0;
if(source == 5) timer1.line = 0;
if(source == 6) timer2.line = 0;
if(source == 7) peripheral.line = 0;
if(source == 8) sio.line = 0;
if(source == 9) spu.line = 0;
if(source == 10) pio.line = 0;
poll();
}
auto CPU::Interrupt::readByte(u32 address) -> u8 {
uint8 data = 0;
print("* read byte ", hex(address, 8L), "\n");
return data;
}
auto CPU::Interrupt::readHalf(u32 address) -> u16 {
uint16 data = 0;
//I_STAT
if(address == 0x1f80'1070) {
data.bit( 0) = vblank.stat;
data.bit( 1) = gpu.stat;
data.bit( 2) = cdrom.stat;
data.bit( 3) = dma.stat;
data.bit( 4) = timer0.stat;
data.bit( 5) = timer1.stat;
data.bit( 6) = timer2.stat;
data.bit( 7) = peripheral.stat;
data.bit( 8) = sio.stat;
data.bit( 9) = spu.stat;
data.bit(10) = pio.stat;
}
//I_MASK
if(address == 0x1f80'1074) {
data.bit( 0) = vblank.mask;
data.bit( 1) = gpu.mask;
data.bit( 2) = cdrom.mask;
data.bit( 3) = dma.mask;
data.bit( 4) = timer0.mask;
data.bit( 5) = timer1.mask;
data.bit( 6) = timer2.mask;
data.bit( 7) = peripheral.mask;
data.bit( 8) = sio.mask;
data.bit( 9) = spu.mask;
data.bit(10) = pio.mask;
}
return data;
}
auto CPU::Interrupt::readWord(u32 address) -> u32 {
uint32 data = 0;
data |= readHalf(address & ~3 | 0) << 0;
data |= readHalf(address & ~3 | 2) << 16;
return data;
}
auto CPU::Interrupt::writeByte(u32 address, u8 value) -> void {
uint8 data = value;
print("* write byte ", hex(address, 8L), "\n");
}
auto CPU::Interrupt::writeHalf(u32 address, u16 value) -> void {
uint16 data = value;
//I_STAT
if(address == 0x1f80'1070) {
if(!data.bit( 0)) vblank.stat = 0;
if(!data.bit( 1)) gpu.stat = 0;
if(!data.bit( 2)) cdrom.stat = 0;
if(!data.bit( 3)) dma.stat = 0;
if(!data.bit( 4)) timer0.stat = 0;
if(!data.bit( 5)) timer1.stat = 0;
if(!data.bit( 6)) timer2.stat = 0;
if(!data.bit( 7)) peripheral.stat = 0;
if(!data.bit( 8)) sio.stat = 0;
if(!data.bit( 9)) spu.stat = 0;
if(!data.bit(10)) pio.stat = 0;
poll();
}
//I_MASK
if(address == 0x1f80'1074) {
vblank.mask = data.bit( 0);
gpu.mask = data.bit( 1);
cdrom.mask = data.bit( 2);
dma.mask = data.bit( 3);
timer0.mask = data.bit( 4);
timer1.mask = data.bit( 5);
timer2.mask = data.bit( 6);
peripheral.mask = data.bit( 7);
sio.mask = data.bit( 8);
spu.mask = data.bit( 9);
pio.mask = data.bit(10);
poll();
}
}
auto CPU::Interrupt::writeWord(u32 address, u32 value) -> void {
uint32 data = value;
writeHalf(address & ~3 | 0, value >> 0);
writeHalf(address & ~3 | 2, value >> 16);
}

ファイルの表示

@ -22,8 +22,13 @@ auto GPU::unload() -> void {
}
auto GPU::main() -> void {
if(io.vcounter == 240) {
cpu.interrupt.raise(CPU::Interrupt::Vblank);
}
if(++io.vcounter == 262) {
io.vcounter = 0;
cpu.interrupt.lower(CPU::Interrupt::Vblank);
refreshed = true;
}

ファイルの表示

@ -1,6 +1,6 @@
//Graphics Processing Unit
struct GPU : Thread, Memory::IO<GPU> {
struct GPU : Thread {
Node::Component node;
Node::Screen screen;
@ -14,14 +14,19 @@ struct GPU : Thread, Memory::IO<GPU> {
auto power(bool reset) -> void;
//io.cpp
auto readByte(u32 address) -> u8;
auto readHalf(u32 address) -> u16;
auto readWord(u32 address) -> u32;
auto writeByte(u32 address, u8 data) -> void;
auto writeHalf(u32 address, u16 data) -> void;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
struct IO {
u16 vcounter = 0;
uint16 vcounter = 0;
uint2 dmaDirection = 0;
} io;
//unserialized:

ファイルの表示

@ -1,3 +1,11 @@
auto GPU::readByte(u32 address) -> u8 {
return 0;
}
auto GPU::readHalf(u32 address) -> u16 {
return 0;
}
auto GPU::readWord(u32 address) -> u32 {
uint32 data = 0;
@ -7,14 +15,27 @@ auto GPU::readWord(u32 address) -> u32 {
//GPUSTAT
if(address == 0x1f80'1814) {
data.bit(26) = 1; //ready to receive command
data.bit(27) = 1; //ready to send VRAM to CPU
data.bit(28) = 1; //ready to receive DMA block
switch(io.dmaDirection) {
case 0: data.bit(25) = 0; break;
case 1: data.bit(25) = 1; break;
case 2: data.bit(25) = 1; break;
case 3: data.bit(25) = 1; break;
}
data.bit(26) = 1; //ready to receive command
data.bit(27) = 1; //ready to send VRAM to CPU
data.bit(28) = 1; //ready to receive DMA block
data.bit(29,30) = io.dmaDirection;
}
return data;
}
auto GPU::writeByte(u32 address, u8 value) -> void {
}
auto GPU::writeHalf(u32 address, u16 value) -> void {
}
auto GPU::writeWord(u32 address, u32 value) -> void {
uint32 data = value;
@ -24,5 +45,9 @@ auto GPU::writeWord(u32 address, u32 value) -> void {
//GP1
if(address == 0x1f80'1814) {
u8 command = data >> 24;
if(command == 0x04) {
io.dmaDirection = data.bit(0,1);
}
}
}

ファイルの表示

@ -5,11 +5,14 @@
if(address <= 0x1eff'ffff) return unmapped; \
if(address <= 0x1f7f'ffff) return unmapped; \
if(address <= 0x1f80'03ff) return cpu.cache.access(__VA_ARGS__); \
if(address <= 0x1f80'107f) return unmapped; \
if(address <= 0x1f80'106f) return unmapped; \
if(address <= 0x1f80'107f) return cpu.interrupt.access(__VA_ARGS__); \
if(address <= 0x1f80'10ff) return cpu.dma.access(__VA_ARGS__); \
if(address <= 0x1f80'17ff) return unmapped; \
if(address <= 0x1f80'180f) return unmapped; \
if(address <= 0x1f80'181f) return gpu.access(__VA_ARGS__); \
if(address <= 0x1f80'1bff) return unmapped; \
if(address <= 0x1f80'1fff) return spu.access(__VA_ARGS__); \
if(address <= 0x1fbf'ffff) return unmapped; \
if(address <= 0x1fff'ffff) return bios.access(__VA_ARGS__); \
return unmapped; \

ファイルの表示

@ -94,43 +94,6 @@ struct Writable {
u32 maskWord = 0;
};
template<typename T>
struct IO {
auto readByte(u32 address) -> u8 {
auto data = ((T*)this)->readWord(address);
switch(address & 3) {
case 0: return data >> 0;
case 1: return data >> 8;
case 2: return data >> 16;
case 3: return data >> 24;
} unreachable;
}
auto readHalf(u32 address) -> u16 {
auto data = ((T*)this)->readWord(address);
switch(address & 2) {
case 0: return data >> 0;
case 2: return data >> 16;
} unreachable;
}
auto writeByte(u32 address, u8 data) -> void {
switch(address & 3) {
case 0: return ((T*)this)->writeWord(address, data << 0);
case 1: return ((T*)this)->writeWord(address, data << 8);
case 2: return ((T*)this)->writeWord(address, data << 16);
case 3: return ((T*)this)->writeWord(address, data << 24);
}
}
auto writeHalf(u32 address, u16 data) -> void {
switch(address & 2) {
case 0: return ((T*)this)->writeWord(address, data << 0);
case 2: return ((T*)this)->writeWord(address, data << 16);
}
}
};
}
struct Bus {

52
ares/ps1/spu/io.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,52 @@
auto SPU::readByte(u32 address) -> u8 {
return 0;
}
auto SPU::readHalf(u32 address) -> u16 {
uint16 data = 0;
//SPURAMCNT
if(address == 0x1f80'1dac) {
data.bit(1,3) = io.ramTransferType;
}
//SPUSTAT
if(address == 0x1f80'1dae) {
data.bit(0) = io.cdAudioEnable;
data.bit(1) = io.externalAudioEnable;
data.bit(2) = io.cdAudioReverb;
data.bit(3) = io.externalAudioReverb;
data.bit(4,5) = io.ramTransferMode;
data.bit(7) = io.ramTransferMode.bit(1); //unverified
}
return data;
}
auto SPU::readWord(u32 address) -> u32 {
return 0;
}
auto SPU::writeByte(u32 address, u8 value) -> void {
}
auto SPU::writeHalf(u32 address, u16 value) -> void {
uint16 data = value;
//SPUCNT
if(address == 0x1f80'1daa) {
io.cdAudioEnable = data.bit(0);
io.externalAudioEnable = data.bit(1);
io.cdAudioReverb = data.bit(2);
io.externalAudioReverb = data.bit(3);
io.ramTransferMode = data.bit(4,5);
}
//SPURAMCHT
if(address == 0x1f80'1dac) {
io.ramTransferType = data.bit(1,3);
}
}
auto SPU::writeWord(u32 address, u32 value) -> void {
}

ファイルの表示

@ -3,6 +3,7 @@
namespace ares::PlayStation {
SPU spu;
#include "io.cpp"
#include "serialization.cpp"
auto SPU::load(Node::Object parent) -> void {
@ -33,6 +34,7 @@ auto SPU::step(uint clocks) -> void {
auto SPU::power(bool reset) -> void {
Thread::reset();
io = {};
}
}

ファイルの表示

@ -14,8 +14,28 @@ struct SPU : Thread {
auto power(bool reset) -> void;
//io.cpp
auto readByte(u32 address) -> u8;
auto readHalf(u32 address) -> u16;
auto readWord(u32 address) -> u32;
auto writeByte(u32 address, u8 data) -> void;
auto writeHalf(u32 address, u16 data) -> void;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
struct IO {
//SPUCNT
uint1 cdAudioEnable = 0;
uint1 externalAudioEnable = 0;
uint1 cdAudioReverb = 0;
uint1 externalAudioReverb = 0;
uint2 ramTransferMode = 0;
//SPURAMCNT
uint3 ramTransferType = 0;
} io;
};
extern SPU spu;