sega/sega_beena.cpp: Emulated Advanced Pico BEENA and TV Ocha-Ken. (#11213)

Basic functionality is supported, making most games playable.

StoryWare display is not yet implemented.

Game-specific peripherals are not emulated.

There are still some issues with graphics.

emu/ioport.h: Fixed rarely-used PORT_CROSSHAIR_MAPPER and PORT_CROSSHAIR_MAPPER_MEMBER macros.

cpu/arm7: Added AP2010 CPU device.

sound/ap2010pcm.cpp: Added basic AP2010 PCM audio output device.

Systems promoted to working
------------------------
Sega Advanced Pico BEENA

New working systems
------------------------
Sega TV Ocha-Ken
This commit is contained in:
qufb 2023-10-27 17:06:55 +01:00 committed by GitHub
parent e2eb4551ce
commit ba621ec24d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 2521 additions and 83 deletions

View file

@ -194,6 +194,8 @@ if CPUS["ARM7"] then
MAME_DIR .. "src/devices/cpu/arm7/arm7.h",
MAME_DIR .. "src/devices/cpu/arm7/arm7thmb.cpp",
MAME_DIR .. "src/devices/cpu/arm7/arm7ops.cpp",
MAME_DIR .. "src/devices/cpu/arm7/ap2010cpu.cpp",
MAME_DIR .. "src/devices/cpu/arm7/ap2010cpu.h",
MAME_DIR .. "src/devices/cpu/arm7/lpc210x.cpp",
MAME_DIR .. "src/devices/cpu/arm7/lpc210x.h",
MAME_DIR .. "src/devices/cpu/arm7/upd800468.cpp",

View file

@ -112,7 +112,6 @@ if (SOUNDS["AC97"]~=null) then
end
---------------------------------------------------
-- Apple custom sound chips
--@src/devices/sound/asc.h,SOUNDS["ASC"] = true
@ -1656,3 +1655,15 @@ if (SOUNDS["NN71003F"]~=null) then
MAME_DIR .. "src/devices/sound/nn71003f.h",
}
end
---------------------------------------------------
-- AP2010
--@src/devices/sound/ap2010pcm.h,SOUNDS["AP2010"] = true
---------------------------------------------------
if (SOUNDS["AP2010"]~=null) then
files {
MAME_DIR .. "src/devices/sound/ap2010pcm.cpp",
MAME_DIR .. "src/devices/sound/ap2010pcm.h",
}
end

View file

@ -0,0 +1,43 @@
// license:BSD-3-Clause
// copyright-holders:QUFB
/***************************************************************************
ARM7TDMI CPU component of the AP2010 LSI
***************************************************************************/
#include "emu.h"
#include "ap2010cpu.h"
DEFINE_DEVICE_TYPE(AP2010CPU, ap2010cpu_device, "ap2010cpu", "AP2010 CPU")
ap2010cpu_device::ap2010cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: arm7_cpu_device(mconfig, AP2010CPU, tag, owner, clock, 4, ARCHFLAG_T, ENDIANNESS_BIG)
{ }
void ap2010cpu_device::add_hotspot(offs_t pc)
{
if (m_hotspot_select < std::size(m_hotspot)) {
m_hotspot[m_hotspot_select] = pc;
m_hotspot_select++;
}
}
void ap2010cpu_device::execute_run()
{
for (size_t i = 0; i < ARM7_MAX_HOTSPOTS; i++) {
if (m_hotspot[i] == 0) {
break;
}
if (m_hotspot[i] == pc()) {
int32_t icount = *m_icountptr;
if (icount > 30) {
eat_cycles(icount - 30);
break;
}
}
}
arm7_cpu_device::execute_run();
}

View file

@ -0,0 +1,36 @@
// license:BSD-3-Clause
// copyright-holders:QUFB
/***************************************************************************
ARM7TDMI CPU component of the AP2010 LSI
***************************************************************************/
#ifndef MAME_CPU_ARM7_AP2010CPU_H
#define MAME_CPU_ARM7_AP2010CPU_H
#pragma once
#include "arm7.h"
#include "arm7core.h"
class ap2010cpu_device : public arm7_cpu_device
{
public:
ap2010cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
void add_hotspot(offs_t pc);
protected:
// device_execute_interface overrides
virtual void execute_run() override;
private:
uint32_t m_hotspot_select = 0;
uint32_t m_hotspot[ARM7_MAX_HOTSPOTS];
};
// device type definition
DECLARE_DEVICE_TYPE(AP2010CPU, ap2010cpu_device)
#endif // MAME_CPU_ARM7_AP2010CPU_H

View file

@ -0,0 +1,227 @@
// license:BSD-3-Clause
// copyright-holders:QUFB
/**********************************************************************
PCM audio functions of the AP2010 LSI
**********************************************************************/
#include "emu.h"
#include "ap2010pcm.h"
#include <algorithm>
#define VERBOSE (0)
#include "logmacro.h"
// device type definition
DEFINE_DEVICE_TYPE(AP2010PCM, ap2010pcm_device, "ap2010pcm", "AP2010 PCM")
ap2010pcm_device::ap2010pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, AP2010PCM, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, m_sample_rate(0)
, m_fifo_size(0)
, m_fifo_head(0)
, m_fifo_tail(0)
, m_fifo_fast_size(0)
, m_fifo_fast_head(0)
, m_fifo_fast_tail(0)
, m_stream(nullptr)
{ }
void ap2010pcm_device::device_start()
{
m_regs = make_unique_clear<uint32_t[]>(0x40/4);
m_sample_rate = 8000;
std::fill(std::begin(m_fifo_data), std::end(m_fifo_data), 0);
std::fill(std::begin(m_fifo_fast_data), std::end(m_fifo_fast_data), 0);
m_stream = stream_alloc(0, 1, m_sample_rate);
save_pointer(NAME(m_regs), 0x40/4);
save_item(NAME(m_volume));
save_item(NAME(m_sample_rate));
save_item(NAME(m_fifo_data));
save_item(NAME(m_fifo_size));
save_item(NAME(m_fifo_head));
save_item(NAME(m_fifo_tail));
save_item(NAME(m_fifo_fast_data));
save_item(NAME(m_fifo_fast_size));
save_item(NAME(m_fifo_fast_head));
save_item(NAME(m_fifo_fast_tail));
}
void ap2010pcm_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
auto &buffer = outputs[0];
buffer.fill(0);
int16_t sample = 0;
uint16_t sample_empty_count = 0;
uint16_t fifo_size = m_fifo_size;
uint16_t fifo_fast_size = m_fifo_fast_size;
for (size_t i = 0; i < buffer.samples(); i++) {
if (m_fifo_fast_size) {
sample = fifo_fast_pop();
} else if (m_fifo_size) {
sample = fifo_pop();
} else {
sample = 0;
sample_empty_count++;
}
buffer.put_int(i, sample * m_volume, 32768);
}
if (fifo_size && sample_empty_count) {
LOG("pcm 0s = %d (had %d + fast %d, needed %d)\n", sample_empty_count, fifo_size, fifo_fast_size, buffer.samples());
}
}
uint32_t ap2010pcm_device::reg_r(offs_t offset)
{
offset &= 0x3f;
if (offset == 0) {
// PCM data (0x5001000c) only received when 0x50010000 & 1 != 0;
// PCM parameters (0x50010010, 0x50010018) only received when 0x50010000 & 4 != 0;
return (m_regs[0x4/4] != 0) ? 0x0f : 0;
} else if (offset == 0x4/4 && m_fifo_size > 0x1ff) {
// TODO: Verify in hardware, bit 1 might be cleared while busy playing?
return m_regs[offset] & 0xfffffffe;
} else if (offset == 0x1c/4) {
uint32_t fifo_size = m_fifo_size;
LOG("pcm asked size -> %d\n", fifo_size);
if (fifo_size > 0x1ff) {
// FIXME: Expected max length, what happens if more data is streamed?
fifo_size = 0x1ff;
} else if (fifo_size > 1) {
/*
Workaround to avoid missing samples during data stream:
while (dVar1 = read_volatile_4(PCM_CTRL), (dVar1 & 1) != 0) {
len = read_volatile_4(PCM_BUFLEN);
len_diff = 0x13e - (len & 0x1ff);
cVar2 = read_volatile_1(w_sound_test_var1);
if (cVar2 == '\x10') {
if (len_diff < 1) {
return in_lr;
}
pcm_write_1x_data();
}
...
}
*/
fifo_size -= 2;
}
return fifo_size;
}
return m_regs[offset];
}
void ap2010pcm_device::reg_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
offset &= 0x3f;
COMBINE_DATA(&m_regs[offset]);
m_stream->update();
switch (offset) {
case 0x4/4:
if ((data & 0x78) == 0x78) {
m_sample_rate = 8000 * (1 + BIT(data, 1));
m_stream->set_sample_rate(m_sample_rate);
// When a new stream starts, stop playback of previous stream
m_fifo_size = 0;
m_fifo_head = 0;
m_fifo_tail = 0;
LOG("pcm stream start, rate = %d\n", m_sample_rate);
}
break;
case 0xc/4:
if (ACCESSING_BITS_16_31) {
fifo_push((data & 0xffff0000U) >> 16);
}
if (ACCESSING_BITS_0_15) {
fifo_push(data & 0x0000ffffU);
}
break;
// These samples are always played first
case 0x10/4:
if (ACCESSING_BITS_16_31) {
fifo_fast_push((data & 0xffff0000U) >> 16);
}
if (ACCESSING_BITS_0_15) {
fifo_fast_push(data & 0x0000ffffU);
}
break;
// Panning. TODO: Identify bits for each channel
case 0x14/4:
LOG("pcm pan = %08x\n", data);
break;
// Volume control. When video output is disabled, it's possible to adjust volume
// using the 2 touch areas on the bottom-left of the Storyware. Range 0..345
case 0x18/4:
m_volume = std::min(((data & 0x1ff00000U) >> 20) / 345.0f, 1.0f);
LOG("pcm vol = %08x -> %d\n", data, m_volume);
break;
}
}
uint16_t ap2010pcm_device::fifo_pop()
{
uint16_t sample = m_fifo_data[m_fifo_head];
m_fifo_head = (m_fifo_head + 1) & (FIFO_MAX_SIZE - 1);
m_fifo_size--;
return sample;
}
uint16_t ap2010pcm_device::fifo_fast_pop()
{
uint16_t sample = m_fifo_fast_data[m_fifo_fast_head];
m_fifo_fast_head = (m_fifo_fast_head + 1) & (FIFO_MAX_SIZE - 1);
m_fifo_fast_size--;
return sample;
}
void ap2010pcm_device::fifo_push(uint16_t sample)
{
if (sample == 0) {
return;
}
// trash old data
if (m_fifo_size > FIFO_MAX_SIZE - 1) {
fifo_pop();
}
m_fifo_data[m_fifo_tail] = sample;
m_fifo_tail = (m_fifo_tail + 1) & (FIFO_MAX_SIZE - 1);
m_fifo_size++;
}
void ap2010pcm_device::fifo_fast_push(uint16_t sample)
{
if (sample == 0) {
return;
}
// trash old data
if (m_fifo_fast_size > FIFO_MAX_SIZE - 1) {
fifo_fast_pop();
}
m_fifo_fast_data[m_fifo_fast_tail] = sample;
m_fifo_fast_tail = (m_fifo_fast_tail + 1) & (FIFO_MAX_SIZE - 1);
m_fifo_fast_size++;
}

View file

@ -0,0 +1,65 @@
// license:BSD-3-Clause
// copyright-holders:QUFB
/**********************************************************************
PCM audio functions of the AP2010 LSI
According to the Advanced Pico Beena's 2005-04-05 press release, it supports
CELP with sample rates 8kHz and 16kHz. It is used as output for OGG files,
which are decoded by the BIOS to signed 16-bit big endian PCM.
**********************************************************************/
#ifndef MAME_SOUND_AP2010PCM_H
#define MAME_SOUND_AP2010PCM_H
#pragma once
class ap2010pcm_device : public device_t, public device_sound_interface
{
public:
static constexpr feature_type imperfect_features() { return feature::SOUND; }
ap2010pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
uint32_t reg_r(offs_t offset);
void reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
protected:
// device_t implementation
virtual void device_start() override;
// device_sound_interface implementation
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// FIXME: Games check this against 0x1ff, but samples are lost with that limit
static inline constexpr uint16_t FIFO_MAX_SIZE = 0x800;
uint16_t fifo_pop();
uint16_t fifo_fast_pop();
void fifo_push(uint16_t sample);
void fifo_fast_push(uint16_t sample);
std::unique_ptr<uint32_t[]> m_regs;
float m_volume;
uint32_t m_sample_rate;
uint16_t m_fifo_data[FIFO_MAX_SIZE];
uint16_t m_fifo_size;
uint16_t m_fifo_head;
uint16_t m_fifo_tail;
uint16_t m_fifo_fast_data[FIFO_MAX_SIZE];
uint16_t m_fifo_fast_size;
uint16_t m_fifo_fast_head;
uint16_t m_fifo_fast_tail;
sound_stream *m_stream;
};
DECLARE_DEVICE_TYPE(AP2010PCM, ap2010pcm_device)
#endif // MAME_SOUND_AP2010PCM_H

View file

@ -1223,10 +1223,10 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s
configurer.field_set_crosshair(CROSSHAIR_AXIS_##axis, altaxis, scale, offset);
#define PORT_CROSSHAIR_MAPPER(_callback) \
configurer.field_set_crossmapper(ioport_field_crossmap_delegate(_callback, #_callback, DEVICE_SELF, (device_t *)nullptr));
configurer.field_set_crossmapper(ioport_field_crossmap_delegate(owner, DEVICE_SELF, _callback, #_callback));
#define PORT_CROSSHAIR_MAPPER_MEMBER(_device, _class, _member) \
configurer.field_set_crossmapper(ioport_field_crossmap_delegate(&_class::_member, #_class "::" #_member, _device, (_class *)nullptr));
configurer.field_set_crossmapper(ioport_field_crossmap_delegate(owner, _device, &_class::_member, #_class "::" #_member));
// how many optical counts for 1 full turn of the control
#define PORT_FULL_TURN_COUNT(_count) \

12
src/mame/layout/beena.lay Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!--
license:CC0-1.0
-->
<mamelayout version="2">
<view name="Single Screen">
<bounds x="0" y="0" width="704" height="480" />
<screen index="0">
<bounds left="0" top="0" right="704" bottom="480" />
</screen>
</view>
</mamelayout>

View file

@ -39255,6 +39255,7 @@ sderby2 // (c) 1985
@source:sega/sega_beena.cpp
beena //
tvochken //
@source:sega/sega_sawatte.cpp
sawatte //

File diff suppressed because it is too large Load diff