218 lines
5.3 KiB
C++
218 lines
5.3 KiB
C++
#include <core.hpp>
|
|
|
|
#include <nba/config.hpp>
|
|
#include <nba/rom/backup/eeprom.hpp>
|
|
#include <nba/rom/backup/sram.hpp>
|
|
#include <nba/rom/backup/flash.hpp>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include <nba/log.hpp>
|
|
using Level = nba::Level;
|
|
using Key = nba::InputDevice::Key;
|
|
|
|
extern const u8 bios_data[16384];
|
|
static u8 *game_data;
|
|
static size_t data_size;
|
|
static void *output[4];
|
|
static nba::core::Core *vm = nullptr;
|
|
static float audios[4096*8];
|
|
static u32 backup_value[3]; // [0] 类型 [1] 容量 [2] 是否携带RTC
|
|
|
|
struct AnoVideoDevice: public nba::VideoDevice
|
|
{
|
|
u32 *buffer_memo = nullptr;
|
|
|
|
void Draw( u32 *buffer ) final
|
|
{
|
|
this->buffer_memo = buffer;
|
|
}
|
|
};
|
|
|
|
// 用BasicInputDevice进行修改
|
|
struct AnoInputDevice: public nba::InputDevice
|
|
{
|
|
void SetKeyStatus(Key key, bool pressed) {
|
|
key_status[static_cast<int>(key)] = pressed;
|
|
}
|
|
|
|
void PollOK( void ){
|
|
keypress_callback();
|
|
}
|
|
|
|
auto Poll(Key key) -> bool final {
|
|
return key_status[static_cast<int>(key)];
|
|
}
|
|
|
|
void SetOnChangeCallback(std::function<void(void)> callback) final {
|
|
keypress_callback = callback;
|
|
}
|
|
private:
|
|
std::function<void(void)> keypress_callback;
|
|
bool key_status[kKeyCount];
|
|
};
|
|
|
|
struct OutterDevices
|
|
{
|
|
std::shared_ptr<nba::VideoDevice> dev_v;
|
|
std::shared_ptr<nba::InputDevice> dev_i;
|
|
std::shared_ptr<nba::AudioDevice> dev_a;
|
|
};
|
|
static OutterDevices outter_dev;
|
|
|
|
void initVM()
|
|
{
|
|
if( vm == nullptr ){
|
|
// emu core
|
|
auto config = std::make_shared<nba::Config>();
|
|
config->skip_bios = true;
|
|
|
|
//setup
|
|
config->video_dev = outter_dev.dev_v = std::make_shared<AnoVideoDevice>();
|
|
config->input_dev = outter_dev.dev_i = std::make_shared<AnoInputDevice>();
|
|
//config->audio_dev = outter_dev.dev_a = std::make_shared<AnoAudioDevice>();
|
|
|
|
vm = new nba::core::Core( config );
|
|
|
|
// bios
|
|
std::vector<u8> bios( bios_data, bios_data+sizeof(bios_data) );
|
|
vm->Attach( bios );
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
u8* getRom( size_t size )
|
|
{
|
|
if( size == 0 ) return game_data;
|
|
|
|
if( game_data == nullptr ){
|
|
game_data = (u8*)malloc(size);
|
|
if( game_data ) data_size = size;
|
|
}
|
|
else if( data_size != size ){
|
|
free(game_data);
|
|
game_data = nullptr;
|
|
|
|
game_data = (u8*)malloc(size);
|
|
if( game_data ) data_size = size;
|
|
}
|
|
return game_data;
|
|
}
|
|
|
|
u8* getIRam()
|
|
{
|
|
return vm->GetBus().memory.iram.data();
|
|
}
|
|
|
|
u8* getWRam()
|
|
{
|
|
return vm->GetBus().memory.wram.data();
|
|
}
|
|
|
|
u32 cyclePerFrame()
|
|
{
|
|
return (u32)nba::CoreBase::kCyclesPerFrame;
|
|
}
|
|
|
|
void** getOutput()
|
|
{
|
|
return output;
|
|
}
|
|
|
|
void run( u32 cycle, u32 input )
|
|
{
|
|
static u32 keys = 0;
|
|
|
|
if( input != keys ){
|
|
keys = input;
|
|
|
|
// setup input
|
|
auto p = outter_dev.dev_i.get();
|
|
auto i = static_cast<AnoInputDevice*>(p);
|
|
for( size_t k=0; k <= (size_t)Key::R; k++ )
|
|
i->SetKeyStatus( (Key)k, ( input & (1<<k) ) != 0 );
|
|
i->PollOK();
|
|
}
|
|
|
|
vm->Run( cycle );
|
|
|
|
auto v = static_cast<const AnoVideoDevice*>( outter_dev.dev_v.get() );
|
|
output[0] = v->buffer_memo;
|
|
|
|
auto buffer = vm->GetAPU().buffer;
|
|
if( buffer ){
|
|
auto avail = buffer->Available();
|
|
if( avail )
|
|
{
|
|
// read to audios
|
|
auto size = avail * 2;
|
|
float *p = audios;
|
|
for( int i=0; i < avail; ++i )
|
|
{
|
|
auto data = buffer->Read();
|
|
*p++ = data.left;
|
|
*p++ = data.right;
|
|
}
|
|
output[1] = (void*)size;
|
|
output[2] = audios;
|
|
}
|
|
else output[1] = output[2] = nullptr;
|
|
}
|
|
else output[1] = output[2] = nullptr;
|
|
|
|
vm->GetROM().Detect(backup_value[0], backup_value[1], backup_value[2]);
|
|
output[3] = backup_value;
|
|
}
|
|
|
|
void go( u32 framecount, u32 input )
|
|
{
|
|
initVM();
|
|
|
|
// rom
|
|
vm->Attach( nba::ROM(std::vector<u8>(game_data, game_data+data_size), nullptr, nullptr, 0xffff'ffff) );
|
|
|
|
// start
|
|
vm->Reset();
|
|
|
|
run(framecount * cyclePerFrame(), input);
|
|
}
|
|
|
|
void replay()
|
|
{
|
|
// new backup
|
|
auto backup = std::unique_ptr<nba::Backup>{};
|
|
auto gpio = std::unique_ptr<nba::GPIO>{};
|
|
|
|
if( backup_value[0] == 0 ) return;
|
|
|
|
vm->Reset();
|
|
if( backup_value[0] == 1 )
|
|
{
|
|
backup = std::make_unique<nba::SRAM>( fs::path{"/"} );
|
|
}
|
|
else if( backup_value[0] == 2 )
|
|
{
|
|
backup = std::make_unique<nba::FLASH>( fs::path{"/"}, backup_value[1] > 512*1024 ? nba::FLASH::Size::SIZE_128K : nba::FLASH::Size::SIZE_64K );
|
|
}
|
|
else if( backup_value[0] == 3 )
|
|
{
|
|
backup = std::make_unique<nba::EEPROM>( fs::path{"/"}, backup_value[1] > 8*1024 ? nba::EEPROM::Size::SIZE_64K : nba::EEPROM::Size::SIZE_4K, vm->GetScheduler() );
|
|
}
|
|
|
|
if( backup_value[2] ){
|
|
gpio->Attach( vm->CreateRTC() );
|
|
}
|
|
|
|
vm->Attach( nba::ROM(std::vector<u8>(game_data, game_data+data_size), std::move(backup), std::move(gpio), 0xffff'ffff) );
|
|
vm->Reset();
|
|
}
|
|
|
|
}
|
|
|
|
#if __EMSCRIPTEN__
|
|
int main(){
|
|
initVM();
|
|
return 0;
|
|
}
|
|
#endif |