mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-04-20 16:37:19 +00:00
Implement DMA push method for sound.
This commit is contained in:
parent
8e34c1657c
commit
945e63bdb2
@ -7,6 +7,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
||||
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
include_directories(${SDL2_INCLUDE_DIRS})
|
||||
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/cpu/ppc/")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/devices/")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/machines/")
|
||||
@ -15,7 +18,8 @@ add_subdirectory("${PROJECT_SOURCE_DIR}/thirdparty/")
|
||||
include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}/devices"
|
||||
"${PROJECT_SOURCE_DIR}/cpu/ppc"
|
||||
"${PROJECT_SOURCE_DIR}/debugger"
|
||||
"${PROJECT_SOURCE_DIR}/thirdparty")
|
||||
"${PROJECT_SOURCE_DIR}/thirdparty"
|
||||
${SDL2_LIBRARIES})
|
||||
|
||||
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/*.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/debugger/*.cpp")
|
||||
@ -27,11 +31,15 @@ add_executable(dingusppc ${SOURCES} $<TARGET_OBJECTS:cpu_ppc>
|
||||
$<TARGET_OBJECTS:machines>
|
||||
$<TARGET_OBJECTS:loguru>)
|
||||
|
||||
target_link_libraries(dingusppc ${SDL2_LIBRARIES})
|
||||
|
||||
add_executable(testppc ${TEST_SOURCES} $<TARGET_OBJECTS:cpu_ppc>
|
||||
$<TARGET_OBJECTS:devices>
|
||||
$<TARGET_OBJECTS:machines>
|
||||
$<TARGET_OBJECTS:loguru>)
|
||||
|
||||
target_link_libraries(testppc ${SDL2_LIBRARIES})
|
||||
|
||||
add_custom_command(
|
||||
TARGET testppc POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
|
@ -25,8 +25,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru.hpp>
|
||||
#include "endianswap.h"
|
||||
#include "awacs.h"
|
||||
#include "machines/machinebase.h"
|
||||
#include "SDL.h"
|
||||
|
||||
static int awac_freqs[8] = {44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350};
|
||||
|
||||
AWACDevice::AWACDevice()
|
||||
{
|
||||
@ -40,6 +44,12 @@ AWACDevice::AWACDevice()
|
||||
AWACDevice::~AWACDevice()
|
||||
{
|
||||
delete this->audio_proc;
|
||||
|
||||
if (this->snd_buf)
|
||||
delete[] this->snd_buf;
|
||||
|
||||
if (this->snd_out_dev)
|
||||
SDL_CloseAudioDevice(snd_out_dev);
|
||||
}
|
||||
|
||||
uint32_t AWACDevice::snd_ctrl_read(uint32_t offset, int size)
|
||||
@ -67,7 +77,7 @@ void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size)
|
||||
|
||||
switch(offset) {
|
||||
case AWAC_SOUND_CTRL_REG:
|
||||
this->snd_ctrl_reg = value;
|
||||
this->snd_ctrl_reg = BYTESWAP_32(value);
|
||||
LOG_F(INFO, "New sound control value = 0x%X", this->snd_ctrl_reg);
|
||||
break;
|
||||
case AWAC_CODEC_CTRL_REG:
|
||||
@ -82,3 +92,77 @@ void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size)
|
||||
LOG_F(ERROR, "AWAC: unsupported register at offset 0x%X", offset);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AWACDevice::convert_data(const uint8_t *data, int len)
|
||||
{
|
||||
int i;
|
||||
uint16_t *p_in, *p_out;
|
||||
|
||||
if (len > this->buf_len) {
|
||||
if (this->snd_buf)
|
||||
delete this->snd_buf;
|
||||
this->snd_buf = new uint8_t[len];
|
||||
this->buf_len = len;
|
||||
}
|
||||
|
||||
p_in = (uint16_t *)data;
|
||||
p_out = (uint16_t *)this->snd_buf;
|
||||
|
||||
for (i = 0; i < len; i += 8) {
|
||||
p_out[i] = p_in[i];
|
||||
p_out[i+1] = p_in[i+2];
|
||||
p_out[i+2] = p_in[i+1];
|
||||
p_out[i+3] = p_in[i+3];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void AWACDevice::dma_start()
|
||||
{
|
||||
SDL_AudioSpec snd_spec, snd_settings;
|
||||
|
||||
SDL_zero(snd_spec);
|
||||
snd_spec.freq = awac_freqs[(this->snd_ctrl_reg >> 8) & 7];
|
||||
snd_spec.format = AUDIO_S16MSB; /* yes, AWAC accepts big-endian data */
|
||||
snd_spec.channels = 2;
|
||||
snd_spec.samples = 4096; /* buffer size, chosen empirically */
|
||||
snd_spec.callback = NULL;
|
||||
|
||||
this->snd_out_dev = SDL_OpenAudioDevice(NULL, 0, &snd_spec, &snd_settings, 0);
|
||||
if (!this->snd_out_dev) {
|
||||
LOG_F(ERROR, "Could not open sound output device, error %s", SDL_GetError());
|
||||
} else {
|
||||
LOG_F(INFO, "Created audio output channel, sample rate = %d", snd_spec.freq);
|
||||
this->wake_up = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AWACDevice::dma_end()
|
||||
{
|
||||
if (this->snd_out_dev) {
|
||||
SDL_CloseAudioDevice(this->snd_out_dev);
|
||||
this->snd_out_dev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AWACDevice::dma_push(uint8_t *buf, int size)
|
||||
{
|
||||
uint32_t dst_len;
|
||||
|
||||
dst_len = this->convert_data(buf, size);
|
||||
if (dst_len) {
|
||||
if (SDL_QueueAudio(this->snd_out_dev, this->snd_buf, dst_len)) {
|
||||
LOG_F(ERROR, "SDL_QueueAudio error: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
if (this->wake_up) {
|
||||
SDL_PauseAudioDevice(this->snd_out_dev, 0); /* start audio playing */
|
||||
this->wake_up = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AWACDevice::dma_pull(uint8_t *buf, int size)
|
||||
{
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cinttypes>
|
||||
#include "i2c.h"
|
||||
#include "dbdma.h"
|
||||
#include "SDL.h"
|
||||
|
||||
/** AWAC registers offsets. */
|
||||
enum {
|
||||
@ -98,7 +100,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class AWACDevice {
|
||||
class AWACDevice : public DMACallback {
|
||||
public:
|
||||
AWACDevice();
|
||||
~AWACDevice();
|
||||
@ -106,11 +108,26 @@ public:
|
||||
uint32_t snd_ctrl_read(uint32_t offset, int size);
|
||||
void snd_ctrl_write(uint32_t offset, uint32_t value, int size);
|
||||
|
||||
/* DMACallback methods */
|
||||
void dma_start();
|
||||
void dma_end();
|
||||
void dma_push(uint8_t *buf, int size);
|
||||
void dma_pull(uint8_t *buf, int size);
|
||||
|
||||
protected:
|
||||
uint32_t convert_data(const uint8_t *data, int len);
|
||||
|
||||
private:
|
||||
uint32_t snd_ctrl_reg = {0};
|
||||
uint16_t control_regs[8] = {0}; /* control registers, each 12-bits wide */
|
||||
uint8_t is_busy = 0;
|
||||
AudioProcessor *audio_proc;
|
||||
|
||||
SDL_AudioDeviceID snd_out_dev = 0;
|
||||
bool wake_up = false;
|
||||
|
||||
uint8_t* snd_buf = 0;
|
||||
uint32_t buf_len = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -52,8 +52,9 @@ uint8_t DMAChannel::interpret_cmd()
|
||||
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
||||
break;
|
||||
}
|
||||
LOG_F(INFO, "Transfer data, addr = 0x%X, length = 0x%X",
|
||||
cmd_struct.address, cmd_struct.req_count);
|
||||
this->dma_cb->dma_push(
|
||||
mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
||||
cmd_struct.req_count);
|
||||
this->cmd_ptr += 16;
|
||||
break;
|
||||
case 1:
|
||||
@ -66,8 +67,9 @@ uint8_t DMAChannel::interpret_cmd()
|
||||
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
||||
break;
|
||||
}
|
||||
LOG_F(INFO, "Transfer data, addr = 0x%X, length = 0x%X",
|
||||
cmd_struct.address, cmd_struct.req_count);
|
||||
this->dma_cb->dma_push(
|
||||
mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
||||
cmd_struct.req_count);
|
||||
this->cmd_ptr += 16;
|
||||
break;
|
||||
case 2:
|
||||
@ -190,6 +192,8 @@ void DMAChannel::start()
|
||||
|
||||
LOG_F(INFO, "Starting DMA channel, stat = 0x%X", this->ch_stat);
|
||||
|
||||
this->dma_cb->dma_start();
|
||||
|
||||
while (this->interpret_cmd() != 7) {
|
||||
}
|
||||
}
|
||||
@ -212,4 +216,5 @@ void DMAChannel::abort()
|
||||
void DMAChannel::pause()
|
||||
{
|
||||
LOG_F(INFO, "Pausing DMA channel");
|
||||
this->dma_cb->dma_end();
|
||||
}
|
||||
|
@ -59,9 +59,17 @@ typedef struct DMACmd {
|
||||
uint16_t xfer_stat;
|
||||
} DMACmd;
|
||||
|
||||
class DMACallback {
|
||||
public:
|
||||
virtual void dma_start(void) = 0;
|
||||
virtual void dma_end(void) = 0;
|
||||
virtual void dma_push(uint8_t *buf, int size) = 0;
|
||||
virtual void dma_pull(uint8_t *buf, int size) = 0;
|
||||
};
|
||||
|
||||
class DMAChannel {
|
||||
public:
|
||||
DMAChannel() = default;
|
||||
DMAChannel(DMACallback *cb) { this->dma_cb = cb; };
|
||||
~DMAChannel() = default;
|
||||
|
||||
uint32_t reg_read(uint32_t offset, int size);
|
||||
@ -77,6 +85,7 @@ protected:
|
||||
void pause(void);
|
||||
|
||||
private:
|
||||
DMACallback *dma_cb = 0;
|
||||
uint16_t ch_stat = 0;
|
||||
uint32_t cmd_ptr = 0;
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
|
||||
gMachineObj->add_subdevice("ViaCuda", this->viacuda);
|
||||
|
||||
this->screamer = new AWACDevice();
|
||||
this->snd_out_dma = new DMAChannel();
|
||||
this->snd_out_dma = new DMAChannel(this->screamer);
|
||||
}
|
||||
|
||||
HeathrowIC::~HeathrowIC()
|
||||
|
6
main.cpp
6
main.cpp
@ -30,6 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include "ppcemu.h"
|
||||
#include "debugger/debugger.h"
|
||||
#include "machines/machinefactory.h"
|
||||
#include "SDL.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -71,6 +72,11 @@ int main(int argc, char **argv)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO)){
|
||||
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if ((checker == "1") || (checker == "realtime") || \
|
||||
(checker == "-realtime") || (checker == "/realtime")) {
|
||||
ppc_exec();
|
||||
|
Loading…
x
Reference in New Issue
Block a user