vb move to nyma
This commit is contained in:
parent
f983fce9ff
commit
0c95088e02
Binary file not shown.
|
@ -9,5 +9,5 @@ make -f pcfx.mak $1 -j
|
||||||
make -f ss.mak $1 -j
|
make -f ss.mak $1 -j
|
||||||
make -f shock.mak $1 -j
|
make -f shock.mak $1 -j
|
||||||
# make -f lynx.mak $1 -j
|
# make -f lynx.mak $1 -j
|
||||||
# make -f vb.mak $1 -j
|
make -f vb.mak $1 -j
|
||||||
# make -f wswan.mak $1 -j
|
# make -f wswan.mak $1 -j
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include <src/types.h>
|
||||||
|
#include <src/mednafen.h>
|
||||||
|
#include <src/vb/vb.h>
|
||||||
|
#include "nyma.h"
|
||||||
|
#include <emulibc.h>
|
||||||
|
#include <waterboxcore.h>
|
||||||
|
|
||||||
|
using namespace MDFN_IEN_VB;
|
||||||
|
|
||||||
|
extern Mednafen::MDFNGI EmulatedVB;
|
||||||
|
|
||||||
|
void SetupMDFNGameInfo()
|
||||||
|
{
|
||||||
|
Mednafen::MDFNGameInfo = &EmulatedVB;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MDFN_IEN_VB
|
||||||
|
{
|
||||||
|
extern uint8* WRAM;
|
||||||
|
extern uint8* GPRAM;
|
||||||
|
extern uint32 GPRAM_Mask;
|
||||||
|
extern uint8* GPROM;
|
||||||
|
extern uint32 GPROM_Mask;
|
||||||
|
extern uint8 FB[2][2][0x6000];
|
||||||
|
extern uint16 CHR_RAM[0x8000 / sizeof(uint16)];
|
||||||
|
extern uint16 DRAM[0x20000 / sizeof(uint16)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo
|
||||||
|
/*static void AccessSystemBus(uint8_t* buffer, int64_t address, int64_t count, bool write)
|
||||||
|
{
|
||||||
|
if (write)
|
||||||
|
{
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
uint32_t addr = address++;
|
||||||
|
uint8_t* ret = buffer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
uint32_t addr = address++;
|
||||||
|
uint8_t* ret = buffer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
ECL_EXPORT void GetMemoryAreas(MemoryArea* m)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
#define AddMemoryDomain(name,data,size,flags) do\
|
||||||
|
{\
|
||||||
|
m[i].Data = data;\
|
||||||
|
m[i].Name = name;\
|
||||||
|
m[i].Size = size;\
|
||||||
|
m[i].Flags = flags;\
|
||||||
|
i++;\
|
||||||
|
}\
|
||||||
|
while (0)
|
||||||
|
AddMemoryDomain("WRAM", WRAM, 65536, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_PRIMARY);
|
||||||
|
AddMemoryDomain("CARTRAM", GPRAM, GPRAM_Mask + 1, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_SAVERAMMABLE);
|
||||||
|
AddMemoryDomain("ROM", GPROM, GPROM_Mask + 1, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4);
|
||||||
|
AddMemoryDomain("CHR RAM", CHR_RAM, sizeof(CHR_RAM), MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4);
|
||||||
|
AddMemoryDomain("DRAM", DRAM, sizeof(DRAM), MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4);
|
||||||
|
AddMemoryDomain("Framebuffer", FB, sizeof(FB), MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4);
|
||||||
|
//AddMemoryDomain("System Bus", (void*)AccessSystemBus, 1ull << 32, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_WORDSIZE4 | MEMORYAREA_FLAGS_FUNCTIONHOOK);
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ include common.mak
|
||||||
|
|
||||||
SRCS += \
|
SRCS += \
|
||||||
$(filter-out %debug.cpp,$(call cppdir,vb)) \
|
$(filter-out %debug.cpp,$(call cppdir,vb)) \
|
||||||
$(call cppdir,hw_cpu/v810)
|
$(call cppdir,hw_cpu/v810) \
|
||||||
|
cdrom_dummy.cpp \
|
||||||
|
vb.cpp
|
||||||
|
|
||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Place your settings in this file to overwrite default and user settings.
|
|
||||||
{
|
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"editor.insertSpaces": false,
|
|
||||||
"files.associations": {
|
|
||||||
"xiosbase": "cpp",
|
|
||||||
"xlocale": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
CXXFLAGS := -I. \
|
|
||||||
-Wall -Werror=int-to-pointer-cast \
|
|
||||||
-std=c++0x -fomit-frame-pointer -fno-exceptions -fno-rtti \
|
|
||||||
-DLSB_FIRST
|
|
||||||
|
|
||||||
TARGET = vb.wbx
|
|
||||||
|
|
||||||
SRCS = $(shell find $(ROOT_DIR) -type f -name '*.cpp')
|
|
||||||
|
|
||||||
include ../common.mak
|
|
|
@ -1,457 +0,0 @@
|
||||||
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
|
|
||||||
|
|
||||||
#include "Blip_Buffer.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
|
|
||||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
||||||
General Public License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version. This
|
|
||||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
||||||
details. You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this module; if not, write to the Free Software Foundation,
|
|
||||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
||||||
|
|
||||||
#ifdef BLARGG_ENABLE_OPTIMIZER
|
|
||||||
#include BLARGG_ENABLE_OPTIMIZER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
|
|
||||||
|
|
||||||
Blip_Buffer::Blip_Buffer()
|
|
||||||
{
|
|
||||||
factor_ = (blip_u64)ULLONG_MAX;
|
|
||||||
offset_ = 0;
|
|
||||||
buffer_ = 0;
|
|
||||||
buffer_size_ = 0;
|
|
||||||
sample_rate_ = 0;
|
|
||||||
reader_accum_ = 0;
|
|
||||||
bass_shift_ = 0;
|
|
||||||
clock_rate_ = 0;
|
|
||||||
bass_freq_ = 16;
|
|
||||||
length_ = 0;
|
|
||||||
|
|
||||||
// assumptions code makes about implementation-defined features
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// right shift of negative value preserves sign
|
|
||||||
buf_t_ i = -0x7FFFFFFE;
|
|
||||||
assert( (i >> 1) == -0x3FFFFFFF );
|
|
||||||
|
|
||||||
// casting to short truncates to 16 bits and sign-extends
|
|
||||||
i = 0x18000;
|
|
||||||
assert( (short) i == -0x8000 );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Blip_Buffer::~Blip_Buffer()
|
|
||||||
{
|
|
||||||
if ( buffer_size_ != silent_buf_size )
|
|
||||||
free( buffer_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
Silent_Blip_Buffer::Silent_Blip_Buffer()
|
|
||||||
{
|
|
||||||
factor_ = 0;
|
|
||||||
buffer_ = buf;
|
|
||||||
buffer_size_ = silent_buf_size;
|
|
||||||
memset( buf, 0, sizeof buf ); // in case machine takes exception for signed overflow
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Buffer::clear( int entire_buffer )
|
|
||||||
{
|
|
||||||
offset_ = 0;
|
|
||||||
reader_accum_ = 0;
|
|
||||||
modified_ = 0;
|
|
||||||
if ( buffer_ )
|
|
||||||
{
|
|
||||||
long count = (entire_buffer ? buffer_size_ : samples_avail());
|
|
||||||
memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
|
|
||||||
{
|
|
||||||
if ( buffer_size_ == silent_buf_size )
|
|
||||||
{
|
|
||||||
assert( 0 );
|
|
||||||
return "Internal (tried to resize Silent_Blip_Buffer)";
|
|
||||||
}
|
|
||||||
|
|
||||||
// start with maximum length that resampled time can represent
|
|
||||||
blip_s64 new_size = (ULLONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
|
|
||||||
|
|
||||||
// simple safety check, since code elsewhere may not be safe for sizes approaching (2 ^ 31).
|
|
||||||
if(new_size > ((1LL << 30) - 1))
|
|
||||||
new_size = (1LL << 30) - 1;
|
|
||||||
|
|
||||||
if ( msec != blip_max_length )
|
|
||||||
{
|
|
||||||
blip_s64 s = ((blip_s64)new_rate * (msec + 1) + 999) / 1000;
|
|
||||||
if ( s < new_size )
|
|
||||||
new_size = s;
|
|
||||||
else
|
|
||||||
assert( 0 ); // fails if requested buffer length exceeds limit
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( buffer_size_ != new_size )
|
|
||||||
{
|
|
||||||
void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ );
|
|
||||||
if ( !p )
|
|
||||||
return "Out of memory";
|
|
||||||
|
|
||||||
//if(new_size > buffer_size_)
|
|
||||||
// memset(buffer_ + buffer_size_, 0, (new_size + blip_buffer_extra_) * sizeof *buffer_
|
|
||||||
|
|
||||||
buffer_ = (buf_t_*) p;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_size_ = new_size;
|
|
||||||
assert( buffer_size_ != silent_buf_size );
|
|
||||||
|
|
||||||
// update things based on the sample rate
|
|
||||||
sample_rate_ = new_rate;
|
|
||||||
length_ = new_size * 1000 / new_rate - 1;
|
|
||||||
if ( msec )
|
|
||||||
assert( length_ == msec ); // ensure length is same as that passed in
|
|
||||||
if ( clock_rate_ )
|
|
||||||
clock_rate( clock_rate_ );
|
|
||||||
bass_freq( bass_freq_ );
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
return 0; // success
|
|
||||||
}
|
|
||||||
|
|
||||||
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
|
|
||||||
{
|
|
||||||
double ratio = (double) sample_rate_ / rate;
|
|
||||||
blip_s64 factor = (blip_s64) floor( ratio * (1LL << BLIP_BUFFER_ACCURACY) + 0.5 );
|
|
||||||
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
|
|
||||||
return (blip_resampled_time_t) factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Buffer::bass_freq( int freq )
|
|
||||||
{
|
|
||||||
bass_freq_ = freq;
|
|
||||||
int shift = 31;
|
|
||||||
if ( freq > 0 )
|
|
||||||
{
|
|
||||||
shift = 13;
|
|
||||||
long f = (freq << 16) / sample_rate_;
|
|
||||||
while ( (f >>= 1) && --shift ) { }
|
|
||||||
}
|
|
||||||
bass_shift_ = shift;
|
|
||||||
//printf("%d\n", bass_shift_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Buffer::end_frame( blip_time_t t )
|
|
||||||
{
|
|
||||||
offset_ += t * factor_;
|
|
||||||
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Buffer::remove_silence( long count )
|
|
||||||
{
|
|
||||||
assert( count <= samples_avail() ); // tried to remove more samples than available
|
|
||||||
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Blip_Buffer::count_samples( blip_time_t t ) const
|
|
||||||
{
|
|
||||||
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
|
|
||||||
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
|
|
||||||
return (long) (last_sample - first_sample);
|
|
||||||
}
|
|
||||||
|
|
||||||
blip_time_t Blip_Buffer::count_clocks( long count ) const
|
|
||||||
{
|
|
||||||
if ( !factor_ )
|
|
||||||
{
|
|
||||||
assert( 0 ); // sample rate and clock rates must be set first
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( count > buffer_size_ )
|
|
||||||
count = buffer_size_;
|
|
||||||
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
|
|
||||||
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Buffer::remove_samples( long count )
|
|
||||||
{
|
|
||||||
if ( count )
|
|
||||||
{
|
|
||||||
remove_silence( count );
|
|
||||||
|
|
||||||
// copy remaining samples to beginning and clear old samples
|
|
||||||
long remain = samples_avail() + blip_buffer_extra_;
|
|
||||||
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
|
|
||||||
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blip_Synth_
|
|
||||||
|
|
||||||
Blip_Synth_Fast_::Blip_Synth_Fast_()
|
|
||||||
{
|
|
||||||
buf = 0;
|
|
||||||
last_amp = 0;
|
|
||||||
delta_factor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Synth_Fast_::volume_unit( double new_unit )
|
|
||||||
{
|
|
||||||
delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !BLIP_BUFFER_FAST
|
|
||||||
|
|
||||||
Blip_Synth_::Blip_Synth_( short* p, int w ) :
|
|
||||||
impulses( p ),
|
|
||||||
width( w )
|
|
||||||
{
|
|
||||||
volume_unit_ = 0.0;
|
|
||||||
kernel_unit = 0;
|
|
||||||
buf = 0;
|
|
||||||
last_amp = 0;
|
|
||||||
delta_factor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef PI
|
|
||||||
#define PI 3.1415926535897932384626433832795029
|
|
||||||
|
|
||||||
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
|
|
||||||
{
|
|
||||||
if ( cutoff >= 0.999 )
|
|
||||||
cutoff = 0.999;
|
|
||||||
|
|
||||||
if ( treble < -300.0 )
|
|
||||||
treble = -300.0;
|
|
||||||
if ( treble > 5.0 )
|
|
||||||
treble = 5.0;
|
|
||||||
|
|
||||||
double const maxh = 4096.0;
|
|
||||||
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
|
|
||||||
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
|
|
||||||
double const to_angle = PI / 2 / maxh / oversample;
|
|
||||||
for ( int i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
double angle = ((i - count) * 2 + 1) * to_angle;
|
|
||||||
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
|
|
||||||
double cos_nc_angle = cos( maxh * cutoff * angle );
|
|
||||||
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
|
|
||||||
double cos_angle = cos( angle );
|
|
||||||
|
|
||||||
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
|
|
||||||
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
|
|
||||||
double b = 2.0 - cos_angle - cos_angle;
|
|
||||||
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
|
|
||||||
|
|
||||||
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void blip_eq_t::generate( float* out, int count ) const
|
|
||||||
{
|
|
||||||
// lower cutoff freq for narrow kernels with their wider transition band
|
|
||||||
// (8 points->1.49, 16 points->1.15)
|
|
||||||
double oversample = blip_res * 2.25 / count + 0.85;
|
|
||||||
double half_rate = sample_rate * 0.5;
|
|
||||||
if ( cutoff_freq )
|
|
||||||
oversample = half_rate / cutoff_freq;
|
|
||||||
double cutoff = rolloff_freq * oversample / half_rate;
|
|
||||||
|
|
||||||
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
|
|
||||||
|
|
||||||
// apply (half of) hamming window
|
|
||||||
double to_fraction = PI / (count - 1);
|
|
||||||
for ( int i = count; i--; )
|
|
||||||
out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction );
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Synth_::adjust_impulse()
|
|
||||||
{
|
|
||||||
// sum pairs for each phase and add error correction to end of first half
|
|
||||||
int const size = impulses_size();
|
|
||||||
for ( int p = blip_res; p-- >= blip_res / 2; )
|
|
||||||
{
|
|
||||||
int p2 = blip_res - 2 - p;
|
|
||||||
long error = kernel_unit;
|
|
||||||
for ( int i = 1; i < size; i += blip_res )
|
|
||||||
{
|
|
||||||
error -= impulses [i + p ];
|
|
||||||
error -= impulses [i + p2];
|
|
||||||
}
|
|
||||||
if ( p == p2 )
|
|
||||||
error /= 2; // phase = 0.5 impulse uses same half for both sides
|
|
||||||
impulses [size - blip_res + p] += (short) error;
|
|
||||||
//printf( "error: %ld\n", error );
|
|
||||||
}
|
|
||||||
|
|
||||||
//for ( int i = blip_res; i--; printf( "\n" ) )
|
|
||||||
// for ( int j = 0; j < width / 2; j++ )
|
|
||||||
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
|
|
||||||
{
|
|
||||||
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
|
|
||||||
|
|
||||||
int const half_size = blip_res / 2 * (width - 1);
|
|
||||||
eq.generate( &fimpulse [blip_res], half_size );
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// need mirror slightly past center for calculation
|
|
||||||
for ( i = blip_res; i--; )
|
|
||||||
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
|
|
||||||
|
|
||||||
// starts at 0
|
|
||||||
for ( i = 0; i < blip_res; i++ )
|
|
||||||
fimpulse [i] = 0.0f;
|
|
||||||
|
|
||||||
// find rescale factor
|
|
||||||
double total = 0.0;
|
|
||||||
for ( i = 0; i < half_size; i++ )
|
|
||||||
total += fimpulse [blip_res + i];
|
|
||||||
|
|
||||||
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
|
|
||||||
//double const base_unit = 37888.0; // allows treble to +5 dB
|
|
||||||
double const base_unit = 32768.0; // necessary for blip_unscaled to work
|
|
||||||
double rescale = base_unit / 2 / total;
|
|
||||||
kernel_unit = (long) base_unit;
|
|
||||||
|
|
||||||
// integrate, first difference, rescale, convert to int
|
|
||||||
double sum = 0.0;
|
|
||||||
double next = 0.0;
|
|
||||||
int const impulses_size_local = this->impulses_size();
|
|
||||||
for ( i = 0; i < impulses_size_local; i++ )
|
|
||||||
{
|
|
||||||
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
|
|
||||||
sum += fimpulse [i];
|
|
||||||
next += fimpulse [i + blip_res];
|
|
||||||
}
|
|
||||||
adjust_impulse();
|
|
||||||
|
|
||||||
// volume might require rescaling
|
|
||||||
double vol = volume_unit_;
|
|
||||||
if ( vol )
|
|
||||||
{
|
|
||||||
volume_unit_ = 0.0;
|
|
||||||
volume_unit( vol );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Synth_::volume_unit( double new_unit )
|
|
||||||
{
|
|
||||||
if ( new_unit != volume_unit_ )
|
|
||||||
{
|
|
||||||
// use default eq if it hasn't been set yet
|
|
||||||
if ( !kernel_unit )
|
|
||||||
treble_eq( -8.0 );
|
|
||||||
|
|
||||||
volume_unit_ = new_unit;
|
|
||||||
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
|
|
||||||
|
|
||||||
if ( factor > 0.0 )
|
|
||||||
{
|
|
||||||
int shift = 0;
|
|
||||||
|
|
||||||
// if unit is really small, might need to attenuate kernel
|
|
||||||
while ( factor < 2.0 )
|
|
||||||
{
|
|
||||||
shift++;
|
|
||||||
factor *= 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( shift )
|
|
||||||
{
|
|
||||||
kernel_unit >>= shift;
|
|
||||||
assert( kernel_unit > 0 ); // fails if volume unit is too low
|
|
||||||
|
|
||||||
// keep values positive to avoid round-towards-zero of sign-preserving
|
|
||||||
// right shift for negative values
|
|
||||||
long offset = 0x8000 + (1 << (shift - 1));
|
|
||||||
long offset2 = 0x8000 >> shift;
|
|
||||||
for ( int i = impulses_size(); i--; )
|
|
||||||
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
|
|
||||||
adjust_impulse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delta_factor = (int) floor( factor + 0.5 );
|
|
||||||
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
long Blip_Buffer::read_samples( blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo )
|
|
||||||
{
|
|
||||||
long count = samples_avail();
|
|
||||||
if ( count > max_samples )
|
|
||||||
count = max_samples;
|
|
||||||
|
|
||||||
if ( count )
|
|
||||||
{
|
|
||||||
int const bass = BLIP_READER_BASS( *this );
|
|
||||||
BLIP_READER_BEGIN( reader, *this );
|
|
||||||
|
|
||||||
if ( !stereo )
|
|
||||||
{
|
|
||||||
for ( blip_long n = count; n; --n )
|
|
||||||
{
|
|
||||||
blip_long s = BLIP_READER_READ( reader );
|
|
||||||
if ( (blip_sample_t) s != s )
|
|
||||||
s = 0x7FFF - (s >> 24);
|
|
||||||
*out++ = (blip_sample_t) s;
|
|
||||||
BLIP_READER_NEXT( reader, bass );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for ( blip_long n = count; n; --n )
|
|
||||||
{
|
|
||||||
blip_long s = BLIP_READER_READ( reader );
|
|
||||||
if ( (blip_sample_t) s != s )
|
|
||||||
s = 0x7FFF - (s >> 24);
|
|
||||||
*out = (blip_sample_t) s;
|
|
||||||
out += 2;
|
|
||||||
BLIP_READER_NEXT( reader, bass );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BLIP_READER_END( reader, *this );
|
|
||||||
|
|
||||||
remove_samples( count );
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
|
|
||||||
{
|
|
||||||
if ( buffer_size_ == silent_buf_size )
|
|
||||||
{
|
|
||||||
assert( 0 );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
|
|
||||||
|
|
||||||
int const sample_shift = blip_sample_bits - 16;
|
|
||||||
int prev = 0;
|
|
||||||
while ( count-- )
|
|
||||||
{
|
|
||||||
blip_long s = (blip_long) *in++ << sample_shift;
|
|
||||||
*out += s - prev;
|
|
||||||
prev = s;
|
|
||||||
++out;
|
|
||||||
}
|
|
||||||
*out -= prev;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,498 +0,0 @@
|
||||||
// Band-limited sound synthesis buffer
|
|
||||||
// Various changes and hacks for use in Mednafen.
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define blip_inline inline __attribute__((always_inline))
|
|
||||||
#else
|
|
||||||
#define blip_inline inline
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
// Blip_Buffer 0.4.1
|
|
||||||
#ifndef BLIP_BUFFER_H
|
|
||||||
#define BLIP_BUFFER_H
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
typedef int32_t blip_long;
|
|
||||||
typedef uint32_t blip_ulong;
|
|
||||||
typedef int64_t blip_s64;
|
|
||||||
typedef uint64_t blip_u64;
|
|
||||||
|
|
||||||
// Time unit at source clock rate
|
|
||||||
typedef blip_long blip_time_t;
|
|
||||||
|
|
||||||
// Output samples are 16-bit signed, with a range of -32768 to 32767
|
|
||||||
typedef short blip_sample_t;
|
|
||||||
enum { blip_sample_max = 32767 };
|
|
||||||
|
|
||||||
class Blip_Buffer {
|
|
||||||
public:
|
|
||||||
typedef const char* blargg_err_t;
|
|
||||||
|
|
||||||
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
|
|
||||||
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
|
|
||||||
// isn't enough memory, returns error without affecting current buffer setup.
|
|
||||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
|
|
||||||
|
|
||||||
// Set number of source time units per second
|
|
||||||
void clock_rate( long );
|
|
||||||
|
|
||||||
// End current time frame of specified duration and make its samples available
|
|
||||||
// (along with any still-unread samples) for reading with read_samples(). Begins
|
|
||||||
// a new time frame at the end of the current frame.
|
|
||||||
void end_frame( blip_time_t time );
|
|
||||||
|
|
||||||
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
|
|
||||||
// the buffer. Returns number of samples actually read and removed. If stereo is
|
|
||||||
// true, increments 'dest' one extra time after writing each sample, to allow
|
|
||||||
// easy interleving of two channels into a stereo output buffer.
|
|
||||||
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
|
|
||||||
|
|
||||||
// Additional optional features
|
|
||||||
|
|
||||||
// Current output sample rate
|
|
||||||
long sample_rate() const;
|
|
||||||
|
|
||||||
// Length of buffer, in milliseconds
|
|
||||||
int length() const;
|
|
||||||
|
|
||||||
// Number of source time units per second
|
|
||||||
long clock_rate() const;
|
|
||||||
|
|
||||||
// Set frequency high-pass filter frequency, where higher values reduce bass more
|
|
||||||
void bass_freq( int frequency );
|
|
||||||
|
|
||||||
// Number of samples delay from synthesis to samples read out
|
|
||||||
int output_latency() const;
|
|
||||||
|
|
||||||
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
|
|
||||||
// false, just clears out any samples waiting rather than the entire buffer.
|
|
||||||
void clear( int entire_buffer = 1 );
|
|
||||||
|
|
||||||
// Number of samples available for reading with read_samples()
|
|
||||||
long samples_avail() const;
|
|
||||||
|
|
||||||
// Remove 'count' samples from those waiting to be read
|
|
||||||
void remove_samples( long count );
|
|
||||||
|
|
||||||
// Experimental features
|
|
||||||
|
|
||||||
// Count number of clocks needed until 'count' samples will be available.
|
|
||||||
// If buffer can't even hold 'count' samples, returns number of clocks until
|
|
||||||
// buffer becomes full.
|
|
||||||
blip_time_t count_clocks( long count ) const;
|
|
||||||
|
|
||||||
// Number of raw samples that can be mixed within frame of specified duration.
|
|
||||||
long count_samples( blip_time_t duration ) const;
|
|
||||||
|
|
||||||
// Mix 'count' samples from 'buf' into buffer.
|
|
||||||
void mix_samples( blip_sample_t const* buf, long count );
|
|
||||||
|
|
||||||
// not documented yet
|
|
||||||
void set_modified() { modified_ = 1; }
|
|
||||||
int clear_modified() { int b = modified_; modified_ = 0; return b; }
|
|
||||||
typedef blip_u64 blip_resampled_time_t;
|
|
||||||
void remove_silence( long count );
|
|
||||||
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
|
|
||||||
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
|
|
||||||
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
|
|
||||||
public:
|
|
||||||
Blip_Buffer();
|
|
||||||
~Blip_Buffer();
|
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
typedef blip_resampled_time_t resampled_time_t;
|
|
||||||
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
|
|
||||||
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
|
|
||||||
private:
|
|
||||||
// noncopyable
|
|
||||||
Blip_Buffer( const Blip_Buffer& );
|
|
||||||
Blip_Buffer& operator = ( const Blip_Buffer& );
|
|
||||||
public:
|
|
||||||
typedef blip_time_t buf_t_;
|
|
||||||
blip_u64 factor_;
|
|
||||||
blip_resampled_time_t offset_;
|
|
||||||
buf_t_* buffer_;
|
|
||||||
blip_long buffer_size_;
|
|
||||||
blip_long reader_accum_;
|
|
||||||
int bass_shift_;
|
|
||||||
private:
|
|
||||||
long sample_rate_;
|
|
||||||
long clock_rate_;
|
|
||||||
int bass_freq_;
|
|
||||||
int length_;
|
|
||||||
int modified_;
|
|
||||||
friend class Blip_Reader;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BLIP_BUFFER_ACCURACY 32
|
|
||||||
#define BLIP_PHASE_BITS 8
|
|
||||||
|
|
||||||
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
|
|
||||||
// but reduce maximum buffer size.
|
|
||||||
//#ifndef BLIP_BUFFER_ACCURACY
|
|
||||||
// #define BLIP_BUFFER_ACCURACY 16
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
|
|
||||||
// noticeable broadband noise when synthesizing high frequency square waves.
|
|
||||||
// Affects size of Blip_Synth objects since they store the waveform directly.
|
|
||||||
//#ifndef BLIP_PHASE_BITS
|
|
||||||
// #if BLIP_BUFFER_FAST
|
|
||||||
// #define BLIP_PHASE_BITS 8
|
|
||||||
// #else
|
|
||||||
// #define BLIP_PHASE_BITS 6
|
|
||||||
// #endif
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
typedef blip_u64 blip_resampled_time_t;
|
|
||||||
int const blip_widest_impulse_ = 16;
|
|
||||||
int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
|
|
||||||
int const blip_res = 1 << BLIP_PHASE_BITS;
|
|
||||||
class blip_eq_t;
|
|
||||||
|
|
||||||
class Blip_Synth_Fast_ {
|
|
||||||
public:
|
|
||||||
Blip_Buffer* buf;
|
|
||||||
int last_amp;
|
|
||||||
int delta_factor;
|
|
||||||
|
|
||||||
void volume_unit( double );
|
|
||||||
Blip_Synth_Fast_();
|
|
||||||
void treble_eq( blip_eq_t const& ) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
class Blip_Synth_ {
|
|
||||||
public:
|
|
||||||
Blip_Buffer* buf;
|
|
||||||
int last_amp;
|
|
||||||
int delta_factor;
|
|
||||||
|
|
||||||
void volume_unit( double );
|
|
||||||
Blip_Synth_( short* impulses, int width );
|
|
||||||
void treble_eq( blip_eq_t const& );
|
|
||||||
private:
|
|
||||||
double volume_unit_;
|
|
||||||
short* const impulses;
|
|
||||||
int const width;
|
|
||||||
blip_long kernel_unit;
|
|
||||||
int impulses_size() const { return blip_res / 2 * width + 1; }
|
|
||||||
void adjust_impulse();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Quality level. Start with blip_good_quality.
|
|
||||||
const int blip_med_quality = 8;
|
|
||||||
const int blip_good_quality = 12;
|
|
||||||
const int blip_high_quality = 16;
|
|
||||||
|
|
||||||
// Range specifies the greatest expected change in amplitude. Calculate it
|
|
||||||
// by finding the difference between the maximum and minimum expected
|
|
||||||
// amplitudes (max - min).
|
|
||||||
template<int quality,int range>
|
|
||||||
class Blip_Synth {
|
|
||||||
public:
|
|
||||||
// Set overall volume of waveform
|
|
||||||
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
|
|
||||||
|
|
||||||
// Configure low-pass filter (see blip_buffer.txt)
|
|
||||||
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
|
|
||||||
|
|
||||||
// Get/set Blip_Buffer used for output
|
|
||||||
Blip_Buffer* output() const { return impl.buf; }
|
|
||||||
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
|
|
||||||
|
|
||||||
// Update amplitude of waveform at given time. Using this requires a separate
|
|
||||||
// Blip_Synth for each waveform.
|
|
||||||
void update( blip_time_t time, int amplitude );
|
|
||||||
|
|
||||||
// Low-level interface
|
|
||||||
|
|
||||||
// Add an amplitude transition of specified delta, optionally into specified buffer
|
|
||||||
// rather than the one set with output(). Delta can be positive or negative.
|
|
||||||
// The actual change in amplitude is delta * (volume / range)
|
|
||||||
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
|
|
||||||
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
|
|
||||||
|
|
||||||
// Works directly in terms of fractional output samples. Contact author for more info.
|
|
||||||
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
|
|
||||||
|
|
||||||
// Same as offset(), except code is inlined for higher performance
|
|
||||||
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
|
|
||||||
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
|
|
||||||
}
|
|
||||||
void offset_inline( blip_time_t t, int delta ) const {
|
|
||||||
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if BLIP_BUFFER_FAST
|
|
||||||
Blip_Synth_Fast_ impl;
|
|
||||||
#else
|
|
||||||
Blip_Synth_ impl;
|
|
||||||
typedef short imp_t;
|
|
||||||
imp_t impulses [blip_res * (quality / 2) + 1];
|
|
||||||
public:
|
|
||||||
Blip_Synth() : impl( impulses, quality ) { }
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Low-pass equalization parameters
|
|
||||||
class blip_eq_t {
|
|
||||||
public:
|
|
||||||
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
|
|
||||||
// treble, small positive values (0 to 5.0) increase treble.
|
|
||||||
blip_eq_t( double treble_db = 0 );
|
|
||||||
|
|
||||||
// See blip_buffer.txt
|
|
||||||
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
|
|
||||||
|
|
||||||
private:
|
|
||||||
double treble;
|
|
||||||
long rolloff_freq;
|
|
||||||
long sample_rate;
|
|
||||||
long cutoff_freq;
|
|
||||||
void generate( float* out, int count ) const;
|
|
||||||
friend class Blip_Synth_;
|
|
||||||
};
|
|
||||||
|
|
||||||
int const blip_sample_bits = 30;
|
|
||||||
|
|
||||||
// Dummy Blip_Buffer to direct sound output to, for easy muting without
|
|
||||||
// having to stop sound code.
|
|
||||||
class Silent_Blip_Buffer : public Blip_Buffer {
|
|
||||||
buf_t_ buf [blip_buffer_extra_ + 1];
|
|
||||||
public:
|
|
||||||
// The following cannot be used (an assertion will fail if attempted):
|
|
||||||
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
|
|
||||||
blip_time_t count_clocks( long count ) const;
|
|
||||||
void mix_samples( blip_sample_t const* buf, long count );
|
|
||||||
|
|
||||||
Silent_Blip_Buffer();
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined (__GNUC__) || _MSC_VER >= 1100
|
|
||||||
#define BLIP_RESTRICT __restrict
|
|
||||||
#else
|
|
||||||
#define BLIP_RESTRICT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Optimized reading from Blip_Buffer, for use in custom sample output
|
|
||||||
|
|
||||||
// Begin reading from buffer. Name should be unique to the current block.
|
|
||||||
#define BLIP_READER_BEGIN( name, blip_buffer ) \
|
|
||||||
const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
|
|
||||||
blip_long name##_reader_accum = (blip_buffer).reader_accum_
|
|
||||||
|
|
||||||
// Get value to pass to BLIP_READER_NEXT()
|
|
||||||
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
|
|
||||||
|
|
||||||
// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
|
|
||||||
// code at the cost of having no bass control
|
|
||||||
int const blip_reader_default_bass = 9;
|
|
||||||
|
|
||||||
// Current sample
|
|
||||||
#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
|
|
||||||
|
|
||||||
// Current raw sample in full internal resolution
|
|
||||||
#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
|
|
||||||
|
|
||||||
// Advance to next sample
|
|
||||||
#define BLIP_READER_NEXT( name, bass ) \
|
|
||||||
(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
|
|
||||||
|
|
||||||
// End reading samples from buffer. The number of samples read must now be removed
|
|
||||||
// using Blip_Buffer::remove_samples().
|
|
||||||
#define BLIP_READER_END( name, blip_buffer ) \
|
|
||||||
(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
|
|
||||||
|
|
||||||
|
|
||||||
// Compatibility with older version
|
|
||||||
const long blip_unscaled = 65535;
|
|
||||||
const int blip_low_quality = blip_med_quality;
|
|
||||||
const int blip_best_quality = blip_high_quality;
|
|
||||||
|
|
||||||
// Deprecated; use BLIP_READER macros as follows:
|
|
||||||
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
|
|
||||||
// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
|
|
||||||
// r.read() -> BLIP_READER_READ( r )
|
|
||||||
// r.read_raw() -> BLIP_READER_READ_RAW( r )
|
|
||||||
// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
|
|
||||||
// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
|
|
||||||
// r.end( buf ) -> BLIP_READER_END( r, buf )
|
|
||||||
class Blip_Reader {
|
|
||||||
public:
|
|
||||||
int begin( Blip_Buffer& );
|
|
||||||
blip_long read() const { return accum >> (blip_sample_bits - 16); }
|
|
||||||
blip_long read_raw() const { return accum; }
|
|
||||||
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
|
|
||||||
void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Blip_Buffer::buf_t_* buf;
|
|
||||||
blip_long accum;
|
|
||||||
};
|
|
||||||
|
|
||||||
// End of public interface
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
template<int quality,int range>
|
|
||||||
blip_inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
|
|
||||||
int delta, Blip_Buffer* blip_buf ) const
|
|
||||||
{
|
|
||||||
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
|
|
||||||
// need for a longer buffer as set by set_sample_rate().
|
|
||||||
assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
|
|
||||||
delta *= impl.delta_factor;
|
|
||||||
blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
|
|
||||||
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
|
|
||||||
|
|
||||||
#if BLIP_BUFFER_FAST
|
|
||||||
blip_long left = buf [0] + delta;
|
|
||||||
|
|
||||||
// Kind of crappy, but doing shift after multiply results in overflow.
|
|
||||||
// Alternate way of delaying multiply by delta_factor results in worse
|
|
||||||
// sub-sample resolution.
|
|
||||||
blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
|
|
||||||
left -= right;
|
|
||||||
right += buf [1];
|
|
||||||
|
|
||||||
buf [0] = left;
|
|
||||||
buf [1] = right;
|
|
||||||
#else
|
|
||||||
|
|
||||||
int const fwd = (blip_widest_impulse_ - quality) / 2;
|
|
||||||
int const rev = fwd + quality - 2;
|
|
||||||
int const mid = quality / 2 - 1;
|
|
||||||
|
|
||||||
imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
|
|
||||||
|
|
||||||
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
|
|
||||||
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
|
|
||||||
|
|
||||||
// straight forward implementation resulted in better code on GCC for x86
|
|
||||||
|
|
||||||
#define ADD_IMP( out, in ) \
|
|
||||||
buf [out] += (blip_long) imp [blip_res * (in)] * delta
|
|
||||||
|
|
||||||
#define BLIP_FWD( i ) {\
|
|
||||||
ADD_IMP( fwd + i, i );\
|
|
||||||
ADD_IMP( fwd + 1 + i, i + 1 );\
|
|
||||||
}
|
|
||||||
#define BLIP_REV( r ) {\
|
|
||||||
ADD_IMP( rev - r, r + 1 );\
|
|
||||||
ADD_IMP( rev + 1 - r, r );\
|
|
||||||
}
|
|
||||||
|
|
||||||
BLIP_FWD( 0 )
|
|
||||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
|
||||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
|
||||||
{
|
|
||||||
ADD_IMP( fwd + mid - 1, mid - 1 );
|
|
||||||
ADD_IMP( fwd + mid , mid );
|
|
||||||
imp = impulses + phase;
|
|
||||||
}
|
|
||||||
if ( quality > 12 ) BLIP_REV( 6 )
|
|
||||||
if ( quality > 8 ) BLIP_REV( 4 )
|
|
||||||
BLIP_REV( 2 )
|
|
||||||
|
|
||||||
ADD_IMP( rev , 1 );
|
|
||||||
ADD_IMP( rev + 1, 0 );
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// for RISC processors, help compiler by reading ahead of writes
|
|
||||||
|
|
||||||
#define BLIP_FWD( i ) {\
|
|
||||||
blip_long t0 = i0 * delta + buf [fwd + i];\
|
|
||||||
blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
|
|
||||||
i0 = imp [blip_res * (i + 2)];\
|
|
||||||
buf [fwd + i] = t0;\
|
|
||||||
buf [fwd + 1 + i] = t1;\
|
|
||||||
}
|
|
||||||
#define BLIP_REV( r ) {\
|
|
||||||
blip_long t0 = i0 * delta + buf [rev - r];\
|
|
||||||
blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
|
|
||||||
i0 = imp [blip_res * (r - 1)];\
|
|
||||||
buf [rev - r] = t0;\
|
|
||||||
buf [rev + 1 - r] = t1;\
|
|
||||||
}
|
|
||||||
|
|
||||||
blip_long i0 = *imp;
|
|
||||||
BLIP_FWD( 0 )
|
|
||||||
if ( quality > 8 ) BLIP_FWD( 2 )
|
|
||||||
if ( quality > 12 ) BLIP_FWD( 4 )
|
|
||||||
{
|
|
||||||
blip_long t0 = i0 * delta + buf [fwd + mid - 1];
|
|
||||||
blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];
|
|
||||||
imp = impulses + phase;
|
|
||||||
i0 = imp [blip_res * mid];
|
|
||||||
buf [fwd + mid - 1] = t0;
|
|
||||||
buf [fwd + mid ] = t1;
|
|
||||||
}
|
|
||||||
if ( quality > 12 ) BLIP_REV( 6 )
|
|
||||||
if ( quality > 8 ) BLIP_REV( 4 )
|
|
||||||
BLIP_REV( 2 )
|
|
||||||
|
|
||||||
blip_long t0 = i0 * delta + buf [rev ];
|
|
||||||
blip_long t1 = *imp * delta + buf [rev + 1];
|
|
||||||
buf [rev ] = t0;
|
|
||||||
buf [rev + 1] = t1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef BLIP_FWD
|
|
||||||
#undef BLIP_REV
|
|
||||||
|
|
||||||
template<int quality,int range>
|
|
||||||
#if BLIP_BUFFER_FAST
|
|
||||||
blip_inline
|
|
||||||
#endif
|
|
||||||
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
|
|
||||||
{
|
|
||||||
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int quality,int range>
|
|
||||||
#if BLIP_BUFFER_FAST
|
|
||||||
blip_inline
|
|
||||||
#endif
|
|
||||||
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
|
|
||||||
{
|
|
||||||
int delta = amp - impl.last_amp;
|
|
||||||
impl.last_amp = amp;
|
|
||||||
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
|
|
||||||
}
|
|
||||||
|
|
||||||
blip_inline blip_eq_t::blip_eq_t( double t ) :
|
|
||||||
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
|
|
||||||
blip_inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
|
|
||||||
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
|
|
||||||
|
|
||||||
blip_inline int Blip_Buffer::length() const { return length_; }
|
|
||||||
blip_inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
|
|
||||||
blip_inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
|
|
||||||
blip_inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
|
|
||||||
blip_inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
|
|
||||||
blip_inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
|
|
||||||
|
|
||||||
blip_inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
|
|
||||||
{
|
|
||||||
buf = blip_buf.buffer_;
|
|
||||||
accum = blip_buf.reader_accum_;
|
|
||||||
return blip_buf.bass_shift_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int const blip_max_length = 0;
|
|
||||||
int const blip_default_length = 250;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,494 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen - Multi-system Emulator */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* endian.h:
|
|
||||||
** Copyright (C) 2006-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __MDFN_ENDIAN_H
|
|
||||||
#define __MDFN_ENDIAN_H
|
|
||||||
|
|
||||||
void Endian_A16_Swap(void *src, uint32 nelements);
|
|
||||||
void Endian_A32_Swap(void *src, uint32 nelements);
|
|
||||||
void Endian_A64_Swap(void *src, uint32 nelements);
|
|
||||||
|
|
||||||
void Endian_A16_NE_LE(void *src, uint32 nelements);
|
|
||||||
void Endian_A32_NE_LE(void *src, uint32 nelements);
|
|
||||||
void Endian_A64_NE_LE(void *src, uint32 nelements);
|
|
||||||
|
|
||||||
void Endian_A16_NE_BE(void *src, uint32 nelements);
|
|
||||||
void Endian_A32_NE_BE(void *src, uint32 nelements);
|
|
||||||
void Endian_A64_NE_BE(void *src, uint32 nelements);
|
|
||||||
|
|
||||||
void Endian_V_NE_LE(void* p, size_t len);
|
|
||||||
void Endian_V_NE_BE(void* p, size_t len);
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
static INLINE uint32 BitsExtract(const uint8* ptr, const size_t bit_offset, const size_t bit_count)
|
|
||||||
{
|
|
||||||
uint32 ret = 0;
|
|
||||||
|
|
||||||
for(size_t x = 0; x < bit_count; x++)
|
|
||||||
{
|
|
||||||
size_t co = bit_offset + x;
|
|
||||||
bool b = (ptr[co >> 3] >> (co & 7)) & 1;
|
|
||||||
|
|
||||||
ret |= (uint64)b << x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE void BitsIntract(uint8* ptr, const size_t bit_offset, const size_t bit_count, uint32 value)
|
|
||||||
{
|
|
||||||
for(size_t x = 0; x < bit_count; x++)
|
|
||||||
{
|
|
||||||
size_t co = bit_offset + x;
|
|
||||||
bool b = (value >> x) & 1;
|
|
||||||
uint8 tmp = ptr[co >> 3];
|
|
||||||
|
|
||||||
tmp &= ~(1 << (co & 7));
|
|
||||||
tmp |= b << (co & 7);
|
|
||||||
|
|
||||||
ptr[co >> 3] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Regarding safety of calling MDFN_*sb<true> on dynamically-allocated memory with new uint8[], see C++ standard 3.7.3.1(i.e. it should be
|
|
||||||
safe provided the offsets into the memory are aligned/multiples of the MDFN_*sb access type). malloc()'d and calloc()'d
|
|
||||||
memory should be safe as well.
|
|
||||||
|
|
||||||
Statically-allocated arrays/memory should be unioned with a big POD type or C++11 "alignas"'d. (May need to audit code to ensure
|
|
||||||
this is being done).
|
|
||||||
*/
|
|
||||||
|
|
||||||
static INLINE uint16 MDFN_bswap16(uint16 v)
|
|
||||||
{
|
|
||||||
return (v << 8) | (v >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE uint32 MDFN_bswap32(uint32 v)
|
|
||||||
{
|
|
||||||
return (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE uint64 MDFN_bswap64(uint64 v)
|
|
||||||
{
|
|
||||||
return (v << 56) | (v >> 56) | ((v & 0xFF00) << 40) | ((v >> 40) & 0xFF00) | ((uint64)MDFN_bswap32(v >> 16) << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LSB_FIRST
|
|
||||||
#define MDFN_ENDIANH_IS_BIGENDIAN 0
|
|
||||||
#else
|
|
||||||
#define MDFN_ENDIANH_IS_BIGENDIAN 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// X endian.
|
|
||||||
//
|
|
||||||
template<int isbigendian, typename T, bool aligned>
|
|
||||||
static INLINE T MDFN_deXsb(const void* ptr)
|
|
||||||
{
|
|
||||||
T tmp;
|
|
||||||
|
|
||||||
memcpy(&tmp, MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), sizeof(T));
|
|
||||||
|
|
||||||
if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN)
|
|
||||||
{
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins.");
|
|
||||||
|
|
||||||
if(sizeof(T) == 8)
|
|
||||||
return MDFN_bswap64(tmp);
|
|
||||||
else if(sizeof(T) == 4)
|
|
||||||
return MDFN_bswap32(tmp);
|
|
||||||
else if(sizeof(T) == 2)
|
|
||||||
return MDFN_bswap16(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Native endian.
|
|
||||||
//
|
|
||||||
template<typename T, bool aligned = false>
|
|
||||||
static INLINE T MDFN_densb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_deXsb<-1, T, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Little endian.
|
|
||||||
//
|
|
||||||
template<typename T, bool aligned = false>
|
|
||||||
static INLINE T MDFN_delsb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_deXsb<0, T, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE uint16 MDFN_de16lsb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_delsb<uint16, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE uint32 MDFN_de24lsb(const void* ptr)
|
|
||||||
{
|
|
||||||
const uint8* ptr_u8 = (const uint8*)ptr;
|
|
||||||
|
|
||||||
return (ptr_u8[0] << 0) | (ptr_u8[1] << 8) | (ptr_u8[2] << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE uint32 MDFN_de32lsb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_delsb<uint32, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE uint64 MDFN_de64lsb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_delsb<uint64, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Big endian.
|
|
||||||
//
|
|
||||||
template<typename T, bool aligned = false>
|
|
||||||
static INLINE T MDFN_demsb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_deXsb<1, T, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE uint16 MDFN_de16msb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_demsb<uint16, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE uint32 MDFN_de24msb(const void* ptr)
|
|
||||||
{
|
|
||||||
const uint8* ptr_u8 = (const uint8*)ptr;
|
|
||||||
|
|
||||||
return (ptr_u8[0] << 16) | (ptr_u8[1] << 8) | (ptr_u8[2] << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE uint32 MDFN_de32msb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_demsb<uint32, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE uint64 MDFN_de64msb(const void* ptr)
|
|
||||||
{
|
|
||||||
return MDFN_demsb<uint64, aligned>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// X endian.
|
|
||||||
//
|
|
||||||
template<int isbigendian, typename T, bool aligned>
|
|
||||||
static INLINE void MDFN_enXsb(void* ptr, T value)
|
|
||||||
{
|
|
||||||
T tmp = value;
|
|
||||||
|
|
||||||
if(isbigendian != -1 && isbigendian != MDFN_ENDIANH_IS_BIGENDIAN)
|
|
||||||
{
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Gummy penguins.");
|
|
||||||
|
|
||||||
if(sizeof(T) == 8)
|
|
||||||
tmp = MDFN_bswap64(value);
|
|
||||||
else if(sizeof(T) == 4)
|
|
||||||
tmp = MDFN_bswap32(value);
|
|
||||||
else if(sizeof(T) == 2)
|
|
||||||
tmp = MDFN_bswap16(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(MDFN_ASSUME_ALIGNED(ptr, (aligned ? sizeof(T) : 1)), &tmp, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Native endian.
|
|
||||||
//
|
|
||||||
template<typename T, bool aligned = false>
|
|
||||||
static INLINE void MDFN_ennsb(void* ptr, T value)
|
|
||||||
{
|
|
||||||
MDFN_enXsb<-1, T, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Little endian.
|
|
||||||
//
|
|
||||||
template<typename T, bool aligned = false>
|
|
||||||
static INLINE void MDFN_enlsb(void* ptr, T value)
|
|
||||||
{
|
|
||||||
MDFN_enXsb<0, T, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE void MDFN_en16lsb(void* ptr, uint16 value)
|
|
||||||
{
|
|
||||||
MDFN_enlsb<uint16, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE void MDFN_en24lsb(void* ptr, uint32 value)
|
|
||||||
{
|
|
||||||
uint8* ptr_u8 = (uint8*)ptr;
|
|
||||||
|
|
||||||
ptr_u8[0] = value >> 0;
|
|
||||||
ptr_u8[1] = value >> 8;
|
|
||||||
ptr_u8[2] = value >> 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE void MDFN_en32lsb(void* ptr, uint32 value)
|
|
||||||
{
|
|
||||||
MDFN_enlsb<uint32, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE void MDFN_en64lsb(void* ptr, uint64 value)
|
|
||||||
{
|
|
||||||
MDFN_enlsb<uint64, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Big endian.
|
|
||||||
//
|
|
||||||
template<typename T, bool aligned = false>
|
|
||||||
static INLINE void MDFN_enmsb(void* ptr, T value)
|
|
||||||
{
|
|
||||||
MDFN_enXsb<1, T, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE void MDFN_en16msb(void* ptr, uint16 value)
|
|
||||||
{
|
|
||||||
MDFN_enmsb<uint16, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE void MDFN_en24msb(void* ptr, uint32 value)
|
|
||||||
{
|
|
||||||
uint8* ptr_u8 = (uint8*)ptr;
|
|
||||||
|
|
||||||
ptr_u8[0] = value >> 16;
|
|
||||||
ptr_u8[1] = value >> 8;
|
|
||||||
ptr_u8[2] = value >> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE void MDFN_en32msb(void* ptr, uint32 value)
|
|
||||||
{
|
|
||||||
MDFN_enmsb<uint32, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool aligned = false>
|
|
||||||
static INLINE void MDFN_en64msb(void* ptr, uint64 value)
|
|
||||||
{
|
|
||||||
MDFN_enmsb<uint64, aligned>(ptr, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
template<typename T, typename BT>
|
|
||||||
static INLINE uint8* ne16_ptr_be(BT* const base, const size_t byte_offset)
|
|
||||||
{
|
|
||||||
#ifdef MSB_FIRST
|
|
||||||
return (uint8*)base + (byte_offset &~ (sizeof(T) - 1));
|
|
||||||
#else
|
|
||||||
return (uint8*)base + (((byte_offset &~ (sizeof(T) - 1)) ^ (2 - std::min<size_t>(2, sizeof(T)))));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static INLINE void ne16_wbo_be(uint16* const base, const size_t byte_offset, const T value)
|
|
||||||
{
|
|
||||||
uint8* const ptr = ne16_ptr_be<T>(base, byte_offset);
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
|
|
||||||
|
|
||||||
if(sizeof(T) == 4)
|
|
||||||
{
|
|
||||||
uint16* const ptr16 = (uint16*)ptr;
|
|
||||||
|
|
||||||
ptr16[0] = value >> 16;
|
|
||||||
ptr16[1] = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*(T*)ptr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static INLINE T ne16_rbo_be(const uint16* const base, const size_t byte_offset)
|
|
||||||
{
|
|
||||||
uint8* const ptr = ne16_ptr_be<T>(base, byte_offset);
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
|
|
||||||
|
|
||||||
if(sizeof(T) == 4)
|
|
||||||
{
|
|
||||||
uint16* const ptr16 = (uint16*)ptr;
|
|
||||||
T tmp;
|
|
||||||
|
|
||||||
tmp = ptr16[0] << 16;
|
|
||||||
tmp |= ptr16[1];
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return *(T*)ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, bool IsWrite>
|
|
||||||
static INLINE void ne16_rwbo_be(uint16* const base, const size_t byte_offset, T* value)
|
|
||||||
{
|
|
||||||
if(IsWrite)
|
|
||||||
ne16_wbo_be<T>(base, byte_offset, *value);
|
|
||||||
else
|
|
||||||
*value = ne16_rbo_be<T>(base, byte_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
template<typename T, typename BT>
|
|
||||||
static INLINE uint8* ne16_ptr_le(BT* const base, const size_t byte_offset)
|
|
||||||
{
|
|
||||||
#ifdef LSB_FIRST
|
|
||||||
return (uint8*)base + (byte_offset &~ (sizeof(T) - 1));
|
|
||||||
#else
|
|
||||||
return (uint8*)base + (((byte_offset &~ (sizeof(T) - 1)) ^ (2 - std::min<size_t>(2, sizeof(T)))));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static INLINE void ne16_wbo_le(uint16* const base, const size_t byte_offset, const T value)
|
|
||||||
{
|
|
||||||
uint8* const ptr = ne16_ptr_le<T>(base, byte_offset);
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
|
|
||||||
|
|
||||||
if(sizeof(T) == 4)
|
|
||||||
{
|
|
||||||
uint16* const ptr16 = (uint16*)ptr;
|
|
||||||
|
|
||||||
ptr16[0] = value;
|
|
||||||
ptr16[1] = value >> 16;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*(T*)ptr = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static INLINE T ne16_rbo_le(const uint16* const base, const size_t byte_offset)
|
|
||||||
{
|
|
||||||
uint8* const ptr = ne16_ptr_le<T>(base, byte_offset);
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
|
|
||||||
|
|
||||||
if(sizeof(T) == 4)
|
|
||||||
{
|
|
||||||
uint16* const ptr16 = (uint16*)ptr;
|
|
||||||
T tmp;
|
|
||||||
|
|
||||||
tmp = ptr16[0];
|
|
||||||
tmp |= ptr16[1] << 16;
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return *(T*)ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T, bool IsWrite>
|
|
||||||
static INLINE void ne16_rwbo_le(uint16* const base, const size_t byte_offset, T* value)
|
|
||||||
{
|
|
||||||
if(IsWrite)
|
|
||||||
ne16_wbo_le<T>(base, byte_offset, *value);
|
|
||||||
else
|
|
||||||
*value = ne16_rbo_le<T>(base, byte_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
template<typename T>
|
|
||||||
static INLINE uint8* ne64_ptr_be(uint64* const base, const size_t byte_offset)
|
|
||||||
{
|
|
||||||
#ifdef MSB_FIRST
|
|
||||||
return (uint8*)base + (byte_offset &~ (sizeof(T) - 1));
|
|
||||||
#else
|
|
||||||
return (uint8*)base + (((byte_offset &~ (sizeof(T) - 1)) ^ (8 - sizeof(T))));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static INLINE void ne64_wbo_be(uint64* const base, const size_t byte_offset, const T value)
|
|
||||||
{
|
|
||||||
uint8* const ptr = ne64_ptr_be<T>(base, byte_offset);
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Unsupported type size");
|
|
||||||
|
|
||||||
memcpy(MDFN_ASSUME_ALIGNED(ptr, sizeof(T)), &value, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static INLINE T ne64_rbo_be(uint64* const base, const size_t byte_offset)
|
|
||||||
{
|
|
||||||
uint8* const ptr = ne64_ptr_be<T>(base, byte_offset);
|
|
||||||
T ret;
|
|
||||||
|
|
||||||
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "Unsupported type size");
|
|
||||||
|
|
||||||
memcpy(&ret, MDFN_ASSUME_ALIGNED(ptr, sizeof(T)), sizeof(T));
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, bool IsWrite>
|
|
||||||
static INLINE void ne64_rwbo_be(uint64* const base, const size_t byte_offset, T* value)
|
|
||||||
{
|
|
||||||
if(IsWrite)
|
|
||||||
ne64_wbo_be<T>(base, byte_offset, *value);
|
|
||||||
else
|
|
||||||
*value = ne64_rbo_be<T>(base, byte_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,130 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct MDFN_Surface
|
|
||||||
{
|
|
||||||
uint32 *pixels;
|
|
||||||
int pitch32;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MDFN_Rect
|
|
||||||
{
|
|
||||||
int x, y, w, h;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EmulateSpecStruct
|
|
||||||
{
|
|
||||||
// Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
|
|
||||||
// Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
|
|
||||||
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
|
|
||||||
uint32 *pixels;
|
|
||||||
|
|
||||||
// Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
|
|
||||||
// Guaranteed to be at least 500ms in length, but emulation code really shouldn't exceed 40ms or so. Additionally, if emulation code
|
|
||||||
// generates >= 100ms,
|
|
||||||
// DEPRECATED: Emulation code may set this pointer to a sound buffer internal to the emulation module.
|
|
||||||
int16 *SoundBuf;
|
|
||||||
|
|
||||||
// Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
|
|
||||||
// Set by emulation code.
|
|
||||||
int64 MasterCycles;
|
|
||||||
|
|
||||||
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
|
|
||||||
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
|
|
||||||
// is ignored while drawing the image.
|
|
||||||
MDFN_Rect DisplayRect;
|
|
||||||
|
|
||||||
// Maximum size of the sound buffer, in frames. Set by the driver code.
|
|
||||||
int32 SoundBufMaxSize;
|
|
||||||
|
|
||||||
// Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
|
|
||||||
int32 SoundBufSize;
|
|
||||||
|
|
||||||
// 0 UDLR SelectStartBA UDLR(right dpad) LtrigRtrig 13
|
|
||||||
int32 Buttons;
|
|
||||||
|
|
||||||
// set by core, true if lagged
|
|
||||||
int32 Lagged;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*typedef struct
|
|
||||||
{
|
|
||||||
|
|
||||||
void (*Emulate)(EmulateSpecStruct *espec);
|
|
||||||
void (*TransformInput)(void); // Called before Emulate, and within MDFN_MidSync(), to implement stuff like setting-controlled PC Engine SEL+RUN button exclusion in a way
|
|
||||||
// that won't cause desyncs with movies and netplay.
|
|
||||||
|
|
||||||
void (*SetInput)(unsigned port, const char *type, uint8* data);
|
|
||||||
bool (*SetMedia)(uint32 drive_idx, uint32 state_idx, uint32 media_idx, uint32 orientation_idx);
|
|
||||||
|
|
||||||
|
|
||||||
// Called when netplay starts, or the controllers controlled by local players changes during
|
|
||||||
// an existing netplay session. Called with ~(uint64)0 when netplay ends.
|
|
||||||
// (For future use in implementing portable console netplay)
|
|
||||||
void (*NPControlNotif)(uint64 c);
|
|
||||||
|
|
||||||
const MDFNSetting *Settings;
|
|
||||||
|
|
||||||
// Time base for EmulateSpecStruct::MasterCycles
|
|
||||||
// MasterClock must be >= MDFN_MASTERCLOCK_FIXED(1.0)
|
|
||||||
// All or part of the fractional component may be ignored in some timekeeping operations in the emulator to prevent integer overflow,
|
|
||||||
// so it is unwise to have a fractional component when the integral component is very small(less than say, 10000).
|
|
||||||
#define MDFN_MASTERCLOCK_FIXED(n) ((int64)((double)(n) * (1LL << 32)))
|
|
||||||
int64 MasterClock;
|
|
||||||
|
|
||||||
// Nominal frames per second * 65536 * 256, truncated.
|
|
||||||
// May be deprecated in the future due to many systems having slight frame rate programmability.
|
|
||||||
uint32 fps;
|
|
||||||
|
|
||||||
// multires is a hint that, if set, indicates that the system has fairly programmable video modes(particularly, the ability
|
|
||||||
// to display multiple horizontal resolutions, such as the PCE, PC-FX, or Genesis). In practice, it will cause the driver
|
|
||||||
// code to set the linear interpolation on by default.
|
|
||||||
//
|
|
||||||
// lcm_width and lcm_height are the least common multiples of all possible
|
|
||||||
// resolutions in the frame buffer as specified by DisplayRect/LineWidths(Ex for PCE: widths of 256, 341.333333, 512,
|
|
||||||
// lcm = 1024)
|
|
||||||
//
|
|
||||||
// nominal_width and nominal_height specify the resolution that Mednafen should display
|
|
||||||
// the framebuffer image in at 1x scaling, scaled from the dimensions of DisplayRect, and optionally the LineWidths array
|
|
||||||
// passed through espec to the Emulate() function.
|
|
||||||
//
|
|
||||||
bool multires;
|
|
||||||
|
|
||||||
int lcm_width;
|
|
||||||
int lcm_height;
|
|
||||||
|
|
||||||
|
|
||||||
int nominal_width;
|
|
||||||
int nominal_height;
|
|
||||||
|
|
||||||
int fb_width; // Width of the framebuffer(not necessarily width of the image). MDFN_Surface width should be >= this.
|
|
||||||
int fb_height; // Height of the framebuffer passed to the Emulate() function(not necessarily height of the image)
|
|
||||||
|
|
||||||
int soundchan; // Number of output sound channels. Only values of 1 and 2 are currently supported.
|
|
||||||
|
|
||||||
|
|
||||||
int rotated;
|
|
||||||
|
|
||||||
std::string name; // Game name, UTF-8 encoding
|
|
||||||
uint8 MD5[16];
|
|
||||||
uint8 GameSetMD5[16]; // A unique ID for the game set this CD belongs to, only used in PC-FX emulation.
|
|
||||||
bool GameSetMD5Valid; // True if GameSetMD5 is valid.
|
|
||||||
|
|
||||||
VideoSystems VideoSystem;
|
|
||||||
GameMediumTypes GameType; // Deprecated.
|
|
||||||
|
|
||||||
RMD_Layout* RMD;
|
|
||||||
|
|
||||||
const char *cspecial; // Special cart expansion: DIP switches, barcode reader, etc.
|
|
||||||
|
|
||||||
std::vector<const char *>DesiredInput; // Desired input device for the input ports, NULL for don't care
|
|
||||||
|
|
||||||
// For mouse relative motion.
|
|
||||||
double mouse_sensitivity;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// For absolute coordinates(IDIT_X_AXIS and IDIT_Y_AXIS), usually mapped to a mouse(hence the naming).
|
|
||||||
//
|
|
||||||
float mouse_scale_x, mouse_scale_y;
|
|
||||||
float mouse_offs_x, mouse_offs_y;
|
|
||||||
} MDFNGI;*/
|
|
|
@ -1,196 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* input.cpp:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "vb.h"
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
static bool InstantReadHack;
|
|
||||||
|
|
||||||
static bool IntPending;
|
|
||||||
|
|
||||||
static uint16 PadData;
|
|
||||||
static uint16 PadLatched;
|
|
||||||
|
|
||||||
static uint8 SCR;
|
|
||||||
static uint16 SDR;
|
|
||||||
|
|
||||||
#define SCR_S_ABT_DIS 0x01
|
|
||||||
#define SCR_SI_STAT 0x02
|
|
||||||
#define SCR_HW_SI 0x04
|
|
||||||
#define SCR_SOFT_CLK 0x10
|
|
||||||
|
|
||||||
#define SCR_PARA_SI 0x20
|
|
||||||
#define SCR_K_INT_INH 0x80
|
|
||||||
|
|
||||||
static uint32 ReadBitPos;
|
|
||||||
static int32 ReadCounter;
|
|
||||||
|
|
||||||
static v810_timestamp_t last_ts;
|
|
||||||
|
|
||||||
void VBINPUT_Init(void)
|
|
||||||
{
|
|
||||||
InstantReadHack = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VBINPUT_SetInstantReadHack(bool enabled)
|
|
||||||
{
|
|
||||||
InstantReadHack = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 VBINPUT_Read(v810_timestamp_t ×tamp, uint32 A)
|
|
||||||
{
|
|
||||||
uint8 ret = 0;
|
|
||||||
|
|
||||||
VBINPUT_Update(timestamp);
|
|
||||||
|
|
||||||
//if(((A & 0xFF) == 0x10 || (A & 0xFF) == 0x14))
|
|
||||||
// printf("Read %d\n", timestamp);
|
|
||||||
|
|
||||||
//if(((A & 0xFF) == 0x10 || (A & 0xFF) == 0x14) && ReadCounter > 0)
|
|
||||||
//{
|
|
||||||
// printf("Input port read during hardware transfer: %08x %d\n", A, timestamp);
|
|
||||||
//}
|
|
||||||
|
|
||||||
switch (A & 0xFF)
|
|
||||||
{
|
|
||||||
case 0x10:
|
|
||||||
if (InstantReadHack)
|
|
||||||
ret = PadData;
|
|
||||||
else
|
|
||||||
ret = SDR & 0xFF;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x14:
|
|
||||||
if (InstantReadHack)
|
|
||||||
ret = PadData >> 8;
|
|
||||||
else
|
|
||||||
ret = SDR >> 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x28:
|
|
||||||
ret = SCR | (0x40 | 0x08 | SCR_HW_SI);
|
|
||||||
if (ReadCounter > 0)
|
|
||||||
ret |= SCR_SI_STAT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// printf("Input Read: %08x %02x\n", A, ret);
|
|
||||||
VB_SetEvent(VB_EVENT_INPUT, (ReadCounter > 0) ? (timestamp + ReadCounter) : VB_EVENT_NONONO);
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VBINPUT_Write(v810_timestamp_t ×tamp, uint32 A, uint8 V)
|
|
||||||
{
|
|
||||||
VBINPUT_Update(timestamp);
|
|
||||||
|
|
||||||
//printf("Input write: %d, %08x %02x\n", timestamp, A, V);
|
|
||||||
switch (A & 0xFF)
|
|
||||||
{
|
|
||||||
case 0x28:
|
|
||||||
if ((V & SCR_HW_SI) && !(SCR & SCR_S_ABT_DIS) && ReadCounter <= 0)
|
|
||||||
{
|
|
||||||
//printf("Start Read: %d\n", timestamp);
|
|
||||||
PadLatched = PadData;
|
|
||||||
ReadBitPos = 0;
|
|
||||||
ReadCounter = 640;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (V & SCR_S_ABT_DIS)
|
|
||||||
{
|
|
||||||
ReadCounter = 0;
|
|
||||||
ReadBitPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (V & SCR_K_INT_INH)
|
|
||||||
{
|
|
||||||
IntPending = false;
|
|
||||||
VBIRQ_Assert(VBIRQ_SOURCE_INPUT, IntPending);
|
|
||||||
}
|
|
||||||
|
|
||||||
SCR = V & (0x80 | 0x20 | 0x10 | 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
VB_SetEvent(VB_EVENT_INPUT, (ReadCounter > 0) ? (timestamp + ReadCounter) : VB_EVENT_NONONO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VBINPUT_Frame(const void* ptr)
|
|
||||||
{
|
|
||||||
PadData = (MDFN_de16lsb(ptr) << 2) | 0x2;
|
|
||||||
}
|
|
||||||
|
|
||||||
v810_timestamp_t VBINPUT_Update(const v810_timestamp_t timestamp)
|
|
||||||
{
|
|
||||||
int32 clocks = timestamp - last_ts;
|
|
||||||
|
|
||||||
if (ReadCounter > 0)
|
|
||||||
{
|
|
||||||
ReadCounter -= clocks;
|
|
||||||
|
|
||||||
while (ReadCounter <= 0)
|
|
||||||
{
|
|
||||||
SDR &= ~(1 << ReadBitPos);
|
|
||||||
SDR |= PadLatched & (1 << ReadBitPos);
|
|
||||||
|
|
||||||
ReadBitPos++;
|
|
||||||
if (ReadBitPos < 16)
|
|
||||||
ReadCounter += 640;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//printf("Read End: %d\n", timestamp);
|
|
||||||
if (!(SCR & SCR_K_INT_INH))
|
|
||||||
{
|
|
||||||
//printf("Input IRQ: %d\n", timestamp);
|
|
||||||
IntPending = true;
|
|
||||||
VBIRQ_Assert(VBIRQ_SOURCE_INPUT, IntPending);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_ts = timestamp;
|
|
||||||
|
|
||||||
return ((ReadCounter > 0) ? (timestamp + ReadCounter) : VB_EVENT_NONONO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VBINPUT_ResetTS(void)
|
|
||||||
{
|
|
||||||
last_ts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VBINPUT_Power(void)
|
|
||||||
{
|
|
||||||
last_ts = 0;
|
|
||||||
PadData = 0;
|
|
||||||
PadLatched = 0;
|
|
||||||
SDR = 0;
|
|
||||||
SCR = 0;
|
|
||||||
ReadBitPos = 0;
|
|
||||||
ReadCounter = 0;
|
|
||||||
IntPending = false;
|
|
||||||
|
|
||||||
VBIRQ_Assert(VBIRQ_SOURCE_INPUT, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* input.h:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __VB_INPUT_H
|
|
||||||
#define __VB_INPUT_H
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
|
|
||||||
void VBINPUT_Init(void) MDFN_COLD;
|
|
||||||
void VBINPUT_SetInstantReadHack(bool);
|
|
||||||
|
|
||||||
void VBINPUT_SetInput(unsigned port, const char *type, uint8 *ptr);
|
|
||||||
|
|
||||||
uint8 VBINPUT_Read(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
|
|
||||||
void VBINPUT_Write(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
||||||
|
|
||||||
void VBINPUT_Frame(const void* ptr);
|
|
||||||
|
|
||||||
int32 VBINPUT_Update(const int32 timestamp);
|
|
||||||
void VBINPUT_ResetTS(void);
|
|
||||||
|
|
||||||
|
|
||||||
void VBINPUT_Power(void);
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,278 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen - Multi-system Emulator */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* math_ops.h:
|
|
||||||
** Copyright (C) 2007-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Some ideas from:
|
|
||||||
** blargg
|
|
||||||
** http://graphics.stanford.edu/~seander/bithacks.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __MDFN_MATH_OPS_H
|
|
||||||
#define __MDFN_MATH_OPS_H
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#include <intrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_lzcount16_0UD(uint16 v)
|
|
||||||
{
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
|
||||||
return 15 ^ 31 ^ __builtin_clz(v);
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
unsigned long idx;
|
|
||||||
|
|
||||||
_BitScanReverse(&idx, v);
|
|
||||||
|
|
||||||
return 15 ^ idx;
|
|
||||||
#else
|
|
||||||
unsigned ret = 0;
|
|
||||||
unsigned tmp;
|
|
||||||
|
|
||||||
tmp = !(v & 0xFF00) << 3; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xF000) << 2; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xC000) << 1; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x8000) << 0; ret += tmp;
|
|
||||||
|
|
||||||
return(ret);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_lzcount32_0UD(uint32 v)
|
|
||||||
{
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
|
||||||
return __builtin_clz(v);
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
unsigned long idx;
|
|
||||||
|
|
||||||
_BitScanReverse(&idx, v);
|
|
||||||
|
|
||||||
return 31 ^ idx;
|
|
||||||
#else
|
|
||||||
unsigned ret = 0;
|
|
||||||
unsigned tmp;
|
|
||||||
|
|
||||||
tmp = !(v & 0xFFFF0000) << 4; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xFF000000) << 3; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xF0000000) << 2; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xC0000000) << 1; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x80000000) << 0; ret += tmp;
|
|
||||||
|
|
||||||
return(ret);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_lzcount64_0UD(uint64 v)
|
|
||||||
{
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
|
||||||
return __builtin_clzll(v);
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#if defined(_WIN64)
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanReverse64(&idx, v);
|
|
||||||
return 63 ^ idx;
|
|
||||||
#else
|
|
||||||
unsigned long idx0;
|
|
||||||
unsigned long idx1;
|
|
||||||
|
|
||||||
_BitScanReverse(&idx1, v >> 0);
|
|
||||||
idx1 -= 32;
|
|
||||||
if(!_BitScanReverse(&idx0, v >> 32))
|
|
||||||
idx0 = idx1;
|
|
||||||
|
|
||||||
idx0 += 32;
|
|
||||||
|
|
||||||
return 63 ^ idx0;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
unsigned ret = 0;
|
|
||||||
unsigned tmp;
|
|
||||||
|
|
||||||
tmp = !(v & 0xFFFFFFFF00000000ULL) << 5; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xFFFF000000000000ULL) << 4; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xFF00000000000000ULL) << 3; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xF000000000000000ULL) << 2; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0xC000000000000000ULL) << 1; v <<= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x8000000000000000ULL) << 0; ret += tmp;
|
|
||||||
|
|
||||||
return(ret);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_tzcount16_0UD(uint16 v)
|
|
||||||
{
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
|
||||||
return __builtin_ctz(v);
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
unsigned long idx;
|
|
||||||
|
|
||||||
_BitScanForward(&idx, v);
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
#else
|
|
||||||
unsigned ret = 0;
|
|
||||||
unsigned tmp;
|
|
||||||
|
|
||||||
tmp = !( (uint8)v) << 3; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x000F) << 2; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x0003) << 1; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x0001) << 0; ret += tmp;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_tzcount32_0UD(uint32 v)
|
|
||||||
{
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
|
||||||
return __builtin_ctz(v);
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
unsigned long idx;
|
|
||||||
|
|
||||||
_BitScanForward(&idx, v);
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
#else
|
|
||||||
unsigned ret = 0;
|
|
||||||
unsigned tmp;
|
|
||||||
|
|
||||||
tmp = !((uint16)v) << 4; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !( (uint8)v) << 3; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x000F) << 2; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x0003) << 1; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x0001) << 0; ret += tmp;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_tzcount64_0UD(uint64 v)
|
|
||||||
{
|
|
||||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
|
||||||
return __builtin_ctzll(v);
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#if defined(_WIN64)
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanForward64(&idx, v);
|
|
||||||
return idx;
|
|
||||||
#else
|
|
||||||
unsigned long idx0, idx1;
|
|
||||||
|
|
||||||
_BitScanForward(&idx1, v >> 32);
|
|
||||||
idx1 += 32;
|
|
||||||
if(!_BitScanForward(&idx0, v))
|
|
||||||
idx0 = idx1;
|
|
||||||
|
|
||||||
return idx0;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
unsigned ret = 0;
|
|
||||||
unsigned tmp;
|
|
||||||
|
|
||||||
tmp = !((uint32)v) << 5; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !((uint16)v) << 4; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !( (uint8)v) << 3; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x000F) << 2; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x0003) << 1; v >>= tmp; ret += tmp;
|
|
||||||
tmp = !(v & 0x0001) << 0; ret += tmp;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Result is defined for all possible inputs(including 0).
|
|
||||||
//
|
|
||||||
static INLINE unsigned MDFN_lzcount16(uint16 v) { return !v ? 16 : MDFN_lzcount16_0UD(v); }
|
|
||||||
static INLINE unsigned MDFN_lzcount32(uint32 v) { return !v ? 32 : MDFN_lzcount32_0UD(v); }
|
|
||||||
static INLINE unsigned MDFN_lzcount64(uint64 v) { return !v ? 64 : MDFN_lzcount64_0UD(v); }
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_tzcount16(uint16 v) { return !v ? 16 : MDFN_tzcount16_0UD(v); }
|
|
||||||
static INLINE unsigned MDFN_tzcount32(uint32 v) { return !v ? 32 : MDFN_tzcount32_0UD(v); }
|
|
||||||
static INLINE unsigned MDFN_tzcount64(uint64 v) { return !v ? 64 : MDFN_tzcount64_0UD(v); }
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_log2(uint32 v) { return 31 ^ MDFN_lzcount32_0UD(v | 1); }
|
|
||||||
static INLINE unsigned MDFN_log2(uint64 v) { return 63 ^ MDFN_lzcount64_0UD(v | 1); }
|
|
||||||
|
|
||||||
static INLINE unsigned MDFN_log2(int32 v) { return MDFN_log2((uint32)v); }
|
|
||||||
static INLINE unsigned MDFN_log2(int64 v) { return MDFN_log2((uint64)v); }
|
|
||||||
|
|
||||||
// Rounds up to the nearest power of 2(treats input as unsigned to a degree, but be aware of integer promotion rules).
|
|
||||||
// Returns 0 on overflow.
|
|
||||||
static INLINE uint64 round_up_pow2(uint32 v) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (tmp < v); }
|
|
||||||
static INLINE uint64 round_up_pow2(uint64 v) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (tmp < v); }
|
|
||||||
|
|
||||||
static INLINE uint64 round_up_pow2(int32 v) { return round_up_pow2((uint32)v); }
|
|
||||||
static INLINE uint64 round_up_pow2(int64 v) { return round_up_pow2((uint64)v); }
|
|
||||||
|
|
||||||
// Rounds to the nearest power of 2(treats input as unsigned to a degree, but be aware of integer promotion rules).
|
|
||||||
static INLINE uint64 round_nearest_pow2(uint32 v, bool round_half_up = true) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (v && (((v - tmp) << 1) >= (tmp + !round_half_up))); }
|
|
||||||
static INLINE uint64 round_nearest_pow2(uint64 v, bool round_half_up = true) { uint64 tmp = (uint64)1 << MDFN_log2(v); return tmp << (v && (((v - tmp) << 1) >= (tmp + !round_half_up))); }
|
|
||||||
|
|
||||||
static INLINE uint64 round_nearest_pow2(int32 v, bool round_half_up = true) { return round_nearest_pow2((uint32)v, round_half_up); }
|
|
||||||
static INLINE uint64 round_nearest_pow2(int64 v, bool round_half_up = true) { return round_nearest_pow2((uint64)v, round_half_up); }
|
|
||||||
|
|
||||||
// Some compilers' optimizers and some platforms might fubar the generated code from these macros,
|
|
||||||
// so some tests are run in...tests.cpp
|
|
||||||
#define sign_8_to_s16(_value) ((int16)(int8)(_value))
|
|
||||||
#define sign_9_to_s16(_value) (((int16)((unsigned int)(_value) << 7)) >> 7)
|
|
||||||
#define sign_10_to_s16(_value) (((int16)((uint32)(_value) << 6)) >> 6)
|
|
||||||
#define sign_11_to_s16(_value) (((int16)((uint32)(_value) << 5)) >> 5)
|
|
||||||
#define sign_12_to_s16(_value) (((int16)((uint32)(_value) << 4)) >> 4)
|
|
||||||
#define sign_13_to_s16(_value) (((int16)((uint32)(_value) << 3)) >> 3)
|
|
||||||
#define sign_14_to_s16(_value) (((int16)((uint32)(_value) << 2)) >> 2)
|
|
||||||
#define sign_15_to_s16(_value) (((int16)((uint32)(_value) << 1)) >> 1)
|
|
||||||
|
|
||||||
// This obviously won't convert higher-than-32 bit numbers to signed 32-bit ;)
|
|
||||||
// Also, this shouldn't be used for 8-bit and 16-bit signed numbers, since you can
|
|
||||||
// convert those faster with typecasts...
|
|
||||||
#define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
|
|
||||||
|
|
||||||
static INLINE int32 clamp_to_u8(int32 i)
|
|
||||||
{
|
|
||||||
if(i & 0xFFFFFF00)
|
|
||||||
i = (((~i) >> 30) & 0xFF);
|
|
||||||
|
|
||||||
return(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE int32 clamp_to_u16(int32 i)
|
|
||||||
{
|
|
||||||
if(i & 0xFFFF0000)
|
|
||||||
i = (((~i) >> 31) & 0xFFFF);
|
|
||||||
|
|
||||||
return(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename U, typename V> static INLINE void clamp(T *val, U minimum, V maximum)
|
|
||||||
{
|
|
||||||
if(*val < minimum)
|
|
||||||
{
|
|
||||||
//printf("Warning: clamping to minimum(%d)\n", (int)minimum);
|
|
||||||
*val = minimum;
|
|
||||||
}
|
|
||||||
if(*val > maximum)
|
|
||||||
{
|
|
||||||
//printf("Warning: clamping to maximum(%d)\n", (int)maximum);
|
|
||||||
*val = maximum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,233 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* timer.cpp:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "vb.h"
|
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
|
|
||||||
#define TC_TENABLE 0x01
|
|
||||||
#define TC_ZSTAT 0x02
|
|
||||||
#define TC_ZSTATCLR 0x04
|
|
||||||
#define TC_TIMZINT 0x08
|
|
||||||
#define TC_TCLKSEL 0x10
|
|
||||||
|
|
||||||
static uint8 TimerControl;
|
|
||||||
static uint16 TimerReloadValue;
|
|
||||||
static uint16 TimerCounter;
|
|
||||||
static int32 TimerDivider;
|
|
||||||
static v810_timestamp_t TimerLastTS;
|
|
||||||
static bool TimerStatus, TimerStatusShadow;
|
|
||||||
static bool ReloadPending;
|
|
||||||
|
|
||||||
v810_timestamp_t TIMER_Update(v810_timestamp_t timestamp)
|
|
||||||
{
|
|
||||||
int32 run_time = timestamp - TimerLastTS;
|
|
||||||
|
|
||||||
if (TimerControl & TC_TENABLE)
|
|
||||||
{
|
|
||||||
TimerDivider -= run_time;
|
|
||||||
while (TimerDivider <= 0)
|
|
||||||
{
|
|
||||||
if (!TimerCounter || ReloadPending)
|
|
||||||
{
|
|
||||||
TimerCounter = TimerReloadValue;
|
|
||||||
ReloadPending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TimerCounter)
|
|
||||||
TimerCounter--;
|
|
||||||
|
|
||||||
if (!TimerCounter || TimerStatus)
|
|
||||||
{
|
|
||||||
TimerStatusShadow = TimerStatus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VBIRQ_Assert(VBIRQ_SOURCE_TIMER, TimerStatusShadow && (TimerControl & TC_TIMZINT));
|
|
||||||
TimerDivider += (TimerControl & TC_TCLKSEL) ? 500 : 2000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TimerLastTS = timestamp;
|
|
||||||
|
|
||||||
return ((TimerControl & TC_TENABLE) ? (timestamp + TimerDivider) : VB_EVENT_NONONO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIMER_ResetTS(void)
|
|
||||||
{
|
|
||||||
TimerLastTS = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 TIMER_Read(const v810_timestamp_t ×tamp, uint32 A)
|
|
||||||
{
|
|
||||||
uint8 ret = 0;
|
|
||||||
|
|
||||||
//if(A <= 0x1C)
|
|
||||||
//printf("Read: %d, %08x\n", timestamp, A);
|
|
||||||
TIMER_Update(timestamp);
|
|
||||||
|
|
||||||
switch (A & 0xFF)
|
|
||||||
{
|
|
||||||
case 0x18:
|
|
||||||
ret = TimerCounter;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x1C:
|
|
||||||
ret = TimerCounter >> 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x20:
|
|
||||||
ret = TimerControl | (0xE0 | TC_ZSTATCLR) | (TimerStatus ? TC_ZSTAT : 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIMER_Write(const v810_timestamp_t ×tamp, uint32 A, uint8 V)
|
|
||||||
{
|
|
||||||
if (A & 0x3)
|
|
||||||
{
|
|
||||||
puts("HWCtrl Bogus Write?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_Update(timestamp);
|
|
||||||
|
|
||||||
//if((A & 0xFF) <= 0x1C)
|
|
||||||
//printf("Write: %d, %08x %02x\n", timestamp, A, V);
|
|
||||||
|
|
||||||
switch (A & 0xFF)
|
|
||||||
{
|
|
||||||
case 0x18:
|
|
||||||
TimerReloadValue &= 0xFF00;
|
|
||||||
TimerReloadValue |= V;
|
|
||||||
ReloadPending = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x1C:
|
|
||||||
TimerReloadValue &= 0x00FF;
|
|
||||||
TimerReloadValue |= V << 8;
|
|
||||||
ReloadPending = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x20:
|
|
||||||
if (V & TC_ZSTATCLR)
|
|
||||||
{
|
|
||||||
if ((TimerControl & TC_TENABLE) && TimerCounter == 0)
|
|
||||||
{
|
|
||||||
//puts("Faulty Z-Stat-Clr");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TimerStatus = false;
|
|
||||||
}
|
|
||||||
TimerStatusShadow = false;
|
|
||||||
}
|
|
||||||
if ((V & TC_TENABLE) && !(TimerControl & TC_TENABLE))
|
|
||||||
{
|
|
||||||
//TimerCounter = TimerReloadValue;
|
|
||||||
TimerDivider = (V & TC_TCLKSEL) ? 500 : 2000;
|
|
||||||
}
|
|
||||||
TimerControl = V & (0x10 | 0x08 | 0x01);
|
|
||||||
|
|
||||||
if (!(TimerControl & TC_TIMZINT))
|
|
||||||
TimerStatus = TimerStatusShadow = false;
|
|
||||||
|
|
||||||
VBIRQ_Assert(VBIRQ_SOURCE_TIMER, TimerStatusShadow && (TimerControl & TC_TIMZINT));
|
|
||||||
|
|
||||||
if (TimerControl & TC_TENABLE)
|
|
||||||
VB_SetEvent(VB_EVENT_TIMER, timestamp + TimerDivider);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIMER_Power(void)
|
|
||||||
{
|
|
||||||
TimerLastTS = 0;
|
|
||||||
|
|
||||||
TimerCounter = 0xFFFF;
|
|
||||||
TimerReloadValue = 0;
|
|
||||||
TimerDivider = 2000; //2150; //2000;
|
|
||||||
|
|
||||||
TimerStatus = false;
|
|
||||||
TimerStatusShadow = false;
|
|
||||||
TimerControl = 0;
|
|
||||||
|
|
||||||
ReloadPending = false;
|
|
||||||
|
|
||||||
VBIRQ_Assert(VBIRQ_SOURCE_TIMER, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 TIMER_GetRegister(const unsigned int id, char *special, const uint32 special_len)
|
|
||||||
{
|
|
||||||
uint32 ret = 0xDEADBEEF;
|
|
||||||
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
case TIMER_GSREG_TCR:
|
|
||||||
ret = TimerControl;
|
|
||||||
if (special)
|
|
||||||
trio_snprintf(special, special_len, "TEnable: %d, TimZInt: %d, TClkSel: %d(%.3f KHz)",
|
|
||||||
(int)(bool)(ret & TC_TENABLE),
|
|
||||||
(int)(bool)(ret & TC_TIMZINT),
|
|
||||||
(int)(bool)(ret & TC_TCLKSEL),
|
|
||||||
(double)VB_MASTER_CLOCK / ((ret & TC_TCLKSEL) ? 500 : 2000) / 1000);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMER_GSREG_DIVCOUNTER:
|
|
||||||
ret = TimerDivider;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMER_GSREG_RELOAD_VALUE:
|
|
||||||
ret = TimerReloadValue;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMER_GSREG_COUNTER:
|
|
||||||
ret = TimerCounter;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TIMER_SetRegister(const unsigned int id, const uint32 value)
|
|
||||||
{
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
case TIMER_GSREG_TCR:
|
|
||||||
TimerControl = value & (TC_TENABLE | TC_TIMZINT | TC_TCLKSEL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMER_GSREG_DIVCOUNTER:
|
|
||||||
TimerDivider = value % ((TimerControl & TC_TCLKSEL) ? 500 : 2000);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMER_GSREG_RELOAD_VALUE:
|
|
||||||
TimerReloadValue = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMER_GSREG_COUNTER:
|
|
||||||
TimerCounter = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* timer.h:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __MDFN_VB_TIMER_H
|
|
||||||
#define __MDFN_VB_TIMER_H
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
|
|
||||||
v810_timestamp_t TIMER_Update(v810_timestamp_t timestamp);
|
|
||||||
void TIMER_ResetTS(void);
|
|
||||||
uint8 TIMER_Read(const v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
void TIMER_Write(const v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
||||||
|
|
||||||
void TIMER_Power(void) MDFN_COLD;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TIMER_GSREG_TCR,
|
|
||||||
TIMER_GSREG_DIVCOUNTER,
|
|
||||||
TIMER_GSREG_RELOAD_VALUE,
|
|
||||||
TIMER_GSREG_COUNTER,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32 TIMER_GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
|
||||||
void TIMER_SetRegister(const unsigned int id, const uint32 value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,333 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
// Defines for the V810 CPU
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
typedef int32 v810_timestamp_t;
|
|
||||||
|
|
||||||
#define V810_FAST_MAP_SHIFT 16
|
|
||||||
#define V810_FAST_MAP_PSIZE (1 << V810_FAST_MAP_SHIFT)
|
|
||||||
#define V810_FAST_MAP_TRAMPOLINE_SIZE 1024
|
|
||||||
|
|
||||||
// Exception codes
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ECODE_TRAP_BASE = 0xFFA0,
|
|
||||||
ECODE_INVALID_OP = 0xFF90,
|
|
||||||
ECODE_ZERO_DIV = 0xFF80, // Integer divide by 0
|
|
||||||
ECODE_FIV = 0xFF70, // Floating point invalid operation
|
|
||||||
ECODE_FZD = 0xFF68, // Floating point zero division
|
|
||||||
ECODE_FOV = 0xFF64, // Floating point overflow
|
|
||||||
//#define ECODE_FUD 0xFF62 // Floating point underflow(unused on V810)
|
|
||||||
//#define ECODE_FPR 0xFF61 // Floating point precision degradation(unused on V810)
|
|
||||||
ECODE_FRO = 0xFF60 // Floating point reserved operand
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
INVALID_OP_HANDLER_ADDR = 0xFFFFFF90, // Invalid opcode/instruction code!
|
|
||||||
ZERO_DIV_HANDLER_ADDR = 0xFFFFFF80, // Integer divide by 0 exception
|
|
||||||
FPU_HANDLER_ADDR = 0xFFFFFF60, // FPU exception
|
|
||||||
TRAP_HANDLER_BASE = 0xFFFFFFA0 // TRAP instruction
|
|
||||||
};
|
|
||||||
|
|
||||||
//System Register Defines (these are the only valid system registers!)
|
|
||||||
#define EIPC 0 //Exeption/Interupt PC
|
|
||||||
#define EIPSW 1 //Exeption/Interupt PSW
|
|
||||||
|
|
||||||
#define FEPC 2 //Fatal Error PC
|
|
||||||
#define FEPSW 3 //Fatal Error PSW
|
|
||||||
|
|
||||||
#define ECR 4 //Exception Cause Register
|
|
||||||
#define PSW 5 //Program Status Word
|
|
||||||
#define PIR 6 //Processor ID Register
|
|
||||||
#define TKCW 7 //Task Controll Word
|
|
||||||
#define CHCW 24 //Cashe Controll Word
|
|
||||||
#define ADDTRE 25 //ADDTRE
|
|
||||||
|
|
||||||
//PSW Specifics
|
|
||||||
#define PSW_IA 0xF0000 // All Interupt bits...
|
|
||||||
#define PSW_I3 0x80000
|
|
||||||
#define PSW_I2 0x40000
|
|
||||||
#define PSW_I1 0x20000
|
|
||||||
#define PSW_I0 0x10000
|
|
||||||
|
|
||||||
#define PSW_NP 0x08000
|
|
||||||
#define PSW_EP 0x04000
|
|
||||||
|
|
||||||
#define PSW_AE 0x02000
|
|
||||||
|
|
||||||
#define PSW_ID 0x01000
|
|
||||||
|
|
||||||
#define PSW_FRO 0x00200 // Floating point reserved operand(set on denormal, NaN, or indefinite)
|
|
||||||
#define PSW_FIV 0x00100 // Floating point invalid operation(set when trying to convert a number too large to an (un)signed integer)
|
|
||||||
|
|
||||||
#define PSW_FZD 0x00080 // Floating point divide by zero
|
|
||||||
#define PSW_FOV 0x00040 // Floating point overflow
|
|
||||||
#define PSW_FUD 0x00020 // Floating point underflow
|
|
||||||
#define PSW_FPR 0x00010 // Floating point precision degradation
|
|
||||||
|
|
||||||
#define PSW_CY 0x00008
|
|
||||||
#define PSW_OV 0x00004
|
|
||||||
#define PSW_S 0x00002
|
|
||||||
#define PSW_Z 0x00001
|
|
||||||
|
|
||||||
//condition codes
|
|
||||||
#define COND_V 0
|
|
||||||
#define COND_C 1
|
|
||||||
#define COND_Z 2
|
|
||||||
#define COND_NH 3
|
|
||||||
#define COND_S 4
|
|
||||||
#define COND_T 5
|
|
||||||
#define COND_LT 6
|
|
||||||
#define COND_LE 7
|
|
||||||
#define COND_NV 8
|
|
||||||
#define COND_NC 9
|
|
||||||
#define COND_NZ 10
|
|
||||||
#define COND_H 11
|
|
||||||
#define COND_NS 12
|
|
||||||
#define COND_F 13
|
|
||||||
#define COND_GE 14
|
|
||||||
#define COND_GT 15
|
|
||||||
|
|
||||||
#define TESTCOND_V (S_REG[PSW] & PSW_OV)
|
|
||||||
|
|
||||||
#define TESTCOND_L (S_REG[PSW] & PSW_CY)
|
|
||||||
#define TESTCOND_C TESTCOND_L
|
|
||||||
|
|
||||||
#define TESTCOND_E (S_REG[PSW] & PSW_Z)
|
|
||||||
#define TESTCOND_Z TESTCOND_E
|
|
||||||
|
|
||||||
#define TESTCOND_NH ((S_REG[PSW] & PSW_Z) || (S_REG[PSW] & PSW_CY))
|
|
||||||
#define TESTCOND_N (S_REG[PSW] & PSW_S)
|
|
||||||
#define TESTCOND_S TESTCOND_N
|
|
||||||
|
|
||||||
#define TESTCOND_LT ((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV)))
|
|
||||||
#define TESTCOND_LE (((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV))) || (S_REG[PSW] & PSW_Z))
|
|
||||||
#define TESTCOND_NV (!(S_REG[PSW] & PSW_OV))
|
|
||||||
|
|
||||||
#define TESTCOND_NL (!(S_REG[PSW] & PSW_CY))
|
|
||||||
#define TESTCOND_NC TESTCOND_NL
|
|
||||||
|
|
||||||
#define TESTCOND_NE (!(S_REG[PSW] & PSW_Z))
|
|
||||||
#define TESTCOND_NZ TESTCOND_NE
|
|
||||||
|
|
||||||
#define TESTCOND_H (!((S_REG[PSW] & PSW_Z) || (S_REG[PSW] & PSW_CY)))
|
|
||||||
#define TESTCOND_P (!(S_REG[PSW] & PSW_S))
|
|
||||||
#define TESTCOND_NS TESTCOND_P
|
|
||||||
|
|
||||||
#define TESTCOND_GE (!((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV))))
|
|
||||||
#define TESTCOND_GT (!(((!!(S_REG[PSW] & PSW_S)) ^ (!!(S_REG[PSW] & PSW_OV))) || (S_REG[PSW] & PSW_Z)))
|
|
||||||
|
|
||||||
// Tag layout
|
|
||||||
// Bit 0-21: TAG31-TAG10
|
|
||||||
// Bit 22-23: Validity bits(one for each 4-byte subblock)
|
|
||||||
// Bit 24-27: NECRV("Reserved")
|
|
||||||
// Bit 28-31: 0
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
V810_EMU_MODE_FAST = 0,
|
|
||||||
V810_EMU_MODE_ACCURATE = 1,
|
|
||||||
_V810_EMU_MODE_COUNT
|
|
||||||
} V810_Emu_Mode;
|
|
||||||
|
|
||||||
class V810
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
V810()
|
|
||||||
MDFN_COLD;
|
|
||||||
~V810() MDFN_COLD;
|
|
||||||
|
|
||||||
// Pass TRUE for vb_mode if we're emulating a VB-specific enhanced V810 CPU core
|
|
||||||
bool Init(V810_Emu_Mode mode, bool vb_mode) MDFN_COLD;
|
|
||||||
|
|
||||||
void SetInt(int level);
|
|
||||||
|
|
||||||
void SetMemWriteBus32(uint8 A, bool value) MDFN_COLD;
|
|
||||||
void SetMemReadBus32(uint8 A, bool value) MDFN_COLD;
|
|
||||||
|
|
||||||
void SetMemReadHandlers(uint8 MDFN_FASTCALL (*read8)(v810_timestamp_t &, uint32), uint16 MDFN_FASTCALL (*read16)(v810_timestamp_t &, uint32), uint32 MDFN_FASTCALL (*read32)(v810_timestamp_t &, uint32)) MDFN_COLD;
|
|
||||||
void SetMemWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
|
|
||||||
|
|
||||||
void SetIOReadHandlers(uint8 MDFN_FASTCALL (*read8)(v810_timestamp_t &, uint32), uint16 MDFN_FASTCALL (*read16)(v810_timestamp_t &, uint32), uint32 MDFN_FASTCALL (*read32)(v810_timestamp_t &, uint32)) MDFN_COLD;
|
|
||||||
void SetIOWriteHandlers(void MDFN_FASTCALL (*write8)(v810_timestamp_t &, uint32, uint8), void MDFN_FASTCALL (*write16)(v810_timestamp_t &, uint32, uint16), void MDFN_FASTCALL (*write32)(v810_timestamp_t &, uint32, uint32)) MDFN_COLD;
|
|
||||||
|
|
||||||
// Length specifies the number of bytes to map in, at each location specified by addresses[] (for mirroring)
|
|
||||||
uint8 *SetFastMap(void *(*allocator)(size_t size), uint32 addresses[], uint32 length, unsigned int num_addresses, const char *name) MDFN_COLD;
|
|
||||||
|
|
||||||
INLINE void ResetTS(v810_timestamp_t new_base_timestamp)
|
|
||||||
{
|
|
||||||
assert(next_event_ts > v810_timestamp);
|
|
||||||
|
|
||||||
next_event_ts -= (v810_timestamp - new_base_timestamp);
|
|
||||||
v810_timestamp = new_base_timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE void SetEventNT(const v810_timestamp_t timestamp)
|
|
||||||
{
|
|
||||||
next_event_ts = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE v810_timestamp_t GetEventNT(void)
|
|
||||||
{
|
|
||||||
return (next_event_ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
v810_timestamp_t Run(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp));
|
|
||||||
void Exit(void);
|
|
||||||
|
|
||||||
void Reset(void) MDFN_COLD;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
GSREG_PR = 0,
|
|
||||||
GSREG_SR = 32,
|
|
||||||
GSREG_PC = 64,
|
|
||||||
GSREG_TIMESTAMP
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
|
|
||||||
void SetRegister(unsigned int which, uint32 value);
|
|
||||||
|
|
||||||
uint32 GetPC(void);
|
|
||||||
void SetPC(uint32);
|
|
||||||
|
|
||||||
INLINE uint32 GetPR(unsigned int which)
|
|
||||||
{
|
|
||||||
return which ? P_REG[which] : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Make sure P_REG[] is the first variable/array in this class, so non-zerfo offset encoding(at assembly level) isn't necessary to access it.
|
|
||||||
uint32 P_REG[32]; // Program registers pr0-pr31
|
|
||||||
uint32 S_REG[32]; // System registers sr0-sr31
|
|
||||||
uint32 PC;
|
|
||||||
uint8 *PC_ptr;
|
|
||||||
uint8 *PC_base;
|
|
||||||
|
|
||||||
uint32 IPendingCache;
|
|
||||||
void RecalcIPendingCache(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
v810_timestamp_t v810_timestamp; // Will never be less than 0.
|
|
||||||
|
|
||||||
private:
|
|
||||||
v810_timestamp_t next_event_ts;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
LASTOP_NORMAL = 0,
|
|
||||||
LASTOP_LOAD = 1,
|
|
||||||
LASTOP_STORE = 2,
|
|
||||||
LASTOP_IN = 3,
|
|
||||||
LASTOP_OUT = 4,
|
|
||||||
LASTOP_HEAVY_MATH = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
V810_Emu_Mode EmuMode;
|
|
||||||
bool VBMode;
|
|
||||||
|
|
||||||
void Run_Fast(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
|
|
||||||
void Run_Accurate(int32 MDFN_FASTCALL (*event_handler)(const v810_timestamp_t timestamp)) NO_INLINE;
|
|
||||||
|
|
||||||
uint8 MDFN_FASTCALL (*MemRead8)(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
uint16 MDFN_FASTCALL (*MemRead16)(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
uint32 MDFN_FASTCALL (*MemRead32)(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
|
|
||||||
void MDFN_FASTCALL (*MemWrite8)(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
||||||
void MDFN_FASTCALL (*MemWrite16)(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
|
||||||
void MDFN_FASTCALL (*MemWrite32)(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
||||||
|
|
||||||
uint8 MDFN_FASTCALL (*IORead8)(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
uint16 MDFN_FASTCALL (*IORead16)(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
uint32 MDFN_FASTCALL (*IORead32)(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
|
|
||||||
void MDFN_FASTCALL (*IOWrite8)(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
||||||
void MDFN_FASTCALL (*IOWrite16)(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
|
||||||
void MDFN_FASTCALL (*IOWrite32)(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
||||||
|
|
||||||
bool MemReadBus32[256]; // Corresponding to the upper 8 bits of the memory address map.
|
|
||||||
bool MemWriteBus32[256];
|
|
||||||
|
|
||||||
int32 lastop; // Set to -1 on FP/MUL/DIV, 0x100 on LD, 0x200 on ST, 0x400 on in, 0x800 on out, and the actual opcode * 2(or >= 0) on everything else.
|
|
||||||
|
|
||||||
#define LASTOP_LD 0x100
|
|
||||||
#define LASTOP_ST 0x200
|
|
||||||
#define LASTOP_IN 0x400
|
|
||||||
#define LASTOP_OUT 0x800
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
HALT_NONE = 0,
|
|
||||||
HALT_HALT = 1,
|
|
||||||
HALT_FATAL_EXCEPTION = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8 Halted;
|
|
||||||
|
|
||||||
bool Running;
|
|
||||||
|
|
||||||
int ilevel;
|
|
||||||
|
|
||||||
bool in_bstr;
|
|
||||||
uint16 in_bstr_to;
|
|
||||||
|
|
||||||
bool bstr_subop(v810_timestamp_t ×tamp, int sub_op, int arg1);
|
|
||||||
void fpu_subop(v810_timestamp_t ×tamp, int sub_op, int arg1, int arg2);
|
|
||||||
|
|
||||||
void Exception(uint32 handler, uint16 eCode);
|
|
||||||
|
|
||||||
// Caching-related:
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32 tag;
|
|
||||||
uint32 data[2];
|
|
||||||
bool data_valid[2];
|
|
||||||
} V810_CacheEntry_t;
|
|
||||||
|
|
||||||
V810_CacheEntry_t Cache[128];
|
|
||||||
|
|
||||||
// Bitstring variables.
|
|
||||||
uint32 src_cache;
|
|
||||||
uint32 dst_cache;
|
|
||||||
bool have_src_cache, have_dst_cache;
|
|
||||||
|
|
||||||
uint8** FastMap;
|
|
||||||
|
|
||||||
// For CacheDump and CacheRestore
|
|
||||||
void CacheOpMemStore(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
||||||
uint32 CacheOpMemLoad(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
|
|
||||||
void CacheClear(v810_timestamp_t ×tamp, uint32 start, uint32 count);
|
|
||||||
void CacheDump(v810_timestamp_t ×tamp, const uint32 SA);
|
|
||||||
void CacheRestore(v810_timestamp_t ×tamp, const uint32 SA);
|
|
||||||
|
|
||||||
uint32 RDCACHE(v810_timestamp_t ×tamp, uint32 addr);
|
|
||||||
//
|
|
||||||
// End caching related
|
|
||||||
//
|
|
||||||
|
|
||||||
uint16 RDOP(v810_timestamp_t ×tamp, uint32 addr, uint32 meow = 2);
|
|
||||||
void SetFlag(uint32 n, bool condition);
|
|
||||||
void SetSZ(uint32 value);
|
|
||||||
|
|
||||||
void SetSREG(v810_timestamp_t ×tamp, unsigned int which, uint32 value);
|
|
||||||
uint32 GetSREG(unsigned int which);
|
|
||||||
|
|
||||||
bool IsSubnormal(uint32 fpval);
|
|
||||||
void FPU_Math_Template(uint32 (V810_FP_Ops::*func)(uint32, uint32), uint32 arg1, uint32 arg2);
|
|
||||||
void FPU_DoException(void);
|
|
||||||
bool CheckFPInputException(uint32 fpval);
|
|
||||||
bool FPU_DoesExceptionKillResult(void);
|
|
||||||
void SetFPUOPNonFPUFlags(uint32 result);
|
|
||||||
|
|
||||||
uint32 BSTR_RWORD(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
void BSTR_WWORD(v810_timestamp_t ×tamp, uint32 A, uint32 V);
|
|
||||||
bool Do_BSTR_Search(v810_timestamp_t ×tamp, const int inc_mul, unsigned int bit_test);
|
|
||||||
|
|
||||||
V810_FP_Ops fpo;
|
|
||||||
|
|
||||||
uint8 DummyRegion[V810_FAST_MAP_PSIZE + V810_FAST_MAP_TRAMPOLINE_SIZE];
|
|
||||||
};
|
|
|
@ -1,72 +0,0 @@
|
||||||
#define DO_MOV_AM(); DO_AM_I();
|
|
||||||
#define DO_ADD_AM(); DO_AM_I();
|
|
||||||
#define DO_SUB_AM(); DO_AM_I();
|
|
||||||
#define DO_CMP_AM(); DO_AM_I();
|
|
||||||
#define DO_SHL_AM(); DO_AM_I();
|
|
||||||
#define DO_SHR_AM(); DO_AM_I();
|
|
||||||
#define DO_JMP_AM(); DO_AM_I();
|
|
||||||
#define DO_SAR_AM(); DO_AM_I();
|
|
||||||
#define DO_MUL_AM(); DO_AM_I();
|
|
||||||
#define DO_DIV_AM(); DO_AM_I();
|
|
||||||
#define DO_MULU_AM(); DO_AM_I();
|
|
||||||
#define DO_DIVU_AM(); DO_AM_I();
|
|
||||||
#define DO_OR_AM(); DO_AM_I();
|
|
||||||
#define DO_AND_AM(); DO_AM_I();
|
|
||||||
#define DO_XOR_AM(); DO_AM_I();
|
|
||||||
#define DO_NOT_AM(); DO_AM_I();
|
|
||||||
#define DO_MOV_I_AM(); DO_AM_II();
|
|
||||||
#define DO_ADD_I_AM(); DO_AM_II();
|
|
||||||
#define DO_SETF_AM(); DO_AM_II();
|
|
||||||
#define DO_CMP_I_AM(); DO_AM_II();
|
|
||||||
#define DO_SHL_I_AM(); DO_AM_II();
|
|
||||||
#define DO_SHR_I_AM(); DO_AM_II();
|
|
||||||
#define DO_EI_AM(); DO_AM_II();
|
|
||||||
#define DO_SAR_I_AM(); DO_AM_II();
|
|
||||||
#define DO_TRAP_AM(); DO_AM_II();
|
|
||||||
#define DO_RETI_AM(); DO_AM_IX();
|
|
||||||
#define DO_HALT_AM(); DO_AM_IX();
|
|
||||||
#define DO_LDSR_AM(); DO_AM_II();
|
|
||||||
#define DO_STSR_AM(); DO_AM_II();
|
|
||||||
#define DO_DI_AM(); DO_AM_II();
|
|
||||||
#define DO_BSTR_AM(); DO_AM_BSTR();
|
|
||||||
#define DO_MOVEA_AM(); DO_AM_V();
|
|
||||||
#define DO_ADDI_AM(); DO_AM_V();
|
|
||||||
#define DO_JR_AM(); DO_AM_IV();
|
|
||||||
#define DO_JAL_AM(); DO_AM_IV();
|
|
||||||
#define DO_ORI_AM(); DO_AM_V();
|
|
||||||
#define DO_ANDI_AM(); DO_AM_V();
|
|
||||||
#define DO_XORI_AM(); DO_AM_V();
|
|
||||||
#define DO_MOVHI_AM(); DO_AM_V();
|
|
||||||
#define DO_LD_B_AM(); DO_AM_VIa();
|
|
||||||
#define DO_LD_H_AM(); DO_AM_VIa();
|
|
||||||
#define DO_LD_W_AM(); DO_AM_VIa();
|
|
||||||
#define DO_ST_B_AM(); DO_AM_VIb();
|
|
||||||
#define DO_ST_H_AM(); DO_AM_VIb();
|
|
||||||
#define DO_ST_W_AM(); DO_AM_VIb();
|
|
||||||
#define DO_IN_B_AM(); DO_AM_VIa();
|
|
||||||
#define DO_IN_H_AM(); DO_AM_VIa();
|
|
||||||
#define DO_CAXI_AM(); DO_AM_VIa();
|
|
||||||
#define DO_IN_W_AM(); DO_AM_VIa();
|
|
||||||
#define DO_OUT_B_AM(); DO_AM_VIb();
|
|
||||||
#define DO_OUT_H_AM(); DO_AM_VIb();
|
|
||||||
#define DO_FPP_AM(); DO_AM_FPP();
|
|
||||||
#define DO_OUT_W_AM(); DO_AM_VIb();
|
|
||||||
#define DO_BV_AM(); DO_AM_III();
|
|
||||||
#define DO_BL_AM(); DO_AM_III();
|
|
||||||
#define DO_BE_AM(); DO_AM_III();
|
|
||||||
#define DO_BNH_AM(); DO_AM_III();
|
|
||||||
#define DO_BN_AM(); DO_AM_III();
|
|
||||||
#define DO_BR_AM(); DO_AM_III();
|
|
||||||
#define DO_BLT_AM(); DO_AM_III();
|
|
||||||
#define DO_BLE_AM(); DO_AM_III();
|
|
||||||
#define DO_BNV_AM(); DO_AM_III();
|
|
||||||
#define DO_BNL_AM(); DO_AM_III();
|
|
||||||
#define DO_BNE_AM(); DO_AM_III();
|
|
||||||
#define DO_BH_AM(); DO_AM_III();
|
|
||||||
#define DO_BP_AM(); DO_AM_III();
|
|
||||||
#define DO_NOP_AM(); DO_AM_III();
|
|
||||||
#define DO_BGE_AM(); DO_AM_III();
|
|
||||||
#define DO_BGT_AM(); DO_AM_III();
|
|
||||||
|
|
||||||
|
|
||||||
#define DO_INVALID_AM(); DO_AM_UDEF();
|
|
|
@ -1,405 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen - Multi-system Emulator */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* v810_fp_ops.cpp:
|
|
||||||
** Copyright (C) 2014-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "vb.h"
|
|
||||||
|
|
||||||
bool V810_FP_Ops::fp_is_zero(uint32 v)
|
|
||||||
{
|
|
||||||
return ((v & 0x7FFFFFFF) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
bool V810_FP_Ops::fp_is_nan(uint32 v)
|
|
||||||
{
|
|
||||||
return((v & 0x7FFFFFFF) > (255 << 23));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool V810_FP_Ops::fp_is_inf(uint32 v)
|
|
||||||
{
|
|
||||||
return((v & 0x7FFFFFFF) == (255 << 23));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool V810_FP_Ops::fp_is_inf_nan_sub(uint32 v)
|
|
||||||
{
|
|
||||||
if ((v & 0x7FFFFFFF) == 0)
|
|
||||||
return (false);
|
|
||||||
|
|
||||||
switch ((v >> 23) & 0xFF)
|
|
||||||
{
|
|
||||||
case 0x00:
|
|
||||||
case 0xff:
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void V810_FP_Ops::fpim_decode(fpim *df, uint32 v)
|
|
||||||
{
|
|
||||||
df->exp = ((v >> 23) & 0xFF) - 127;
|
|
||||||
df->f = (v & 0x7FFFFF) | ((v & 0x7FFFFFFF) ? 0x800000 : 0);
|
|
||||||
df->sign = v >> 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
void V810_FP_Ops::fpim_round(fpim *df)
|
|
||||||
{
|
|
||||||
int vbc = 64 - MDFN_lzcount64(df->f);
|
|
||||||
|
|
||||||
if (vbc > 24)
|
|
||||||
{
|
|
||||||
const unsigned sa = vbc - 24;
|
|
||||||
|
|
||||||
if (1) // round to nearest
|
|
||||||
{
|
|
||||||
uint64 old_f = df->f;
|
|
||||||
|
|
||||||
df->f = (df->f + ((df->f >> sa) & 1) + ((1ULL << (sa - 1)) - 1)) & ~((1ULL << sa) - 1);
|
|
||||||
|
|
||||||
if (df->f != old_f)
|
|
||||||
{
|
|
||||||
//printf("Inexact mr\n");
|
|
||||||
exception_flags |= flag_inexact;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void V810_FP_Ops::fpim_round_int(fpim *df, bool truncate)
|
|
||||||
{
|
|
||||||
if (df->exp < 23)
|
|
||||||
{
|
|
||||||
const unsigned sa = 23 - df->exp;
|
|
||||||
uint64 old_f = df->f;
|
|
||||||
|
|
||||||
//if(sa >= 2)
|
|
||||||
// printf("RI: %lld, %d\n", df->f, sa);
|
|
||||||
|
|
||||||
// round to nearest
|
|
||||||
if (sa > 24)
|
|
||||||
df->f = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (truncate)
|
|
||||||
df->f = df->f & ~((1ULL << sa) - 1);
|
|
||||||
else
|
|
||||||
df->f = (df->f + ((df->f >> sa) & 1) + ((1ULL << (sa - 1)) - 1)) & ~((1ULL << sa) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (df->f != old_f)
|
|
||||||
{
|
|
||||||
//printf("Inexact\n");
|
|
||||||
exception_flags |= flag_inexact;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::fpim_encode(fpim *df)
|
|
||||||
{
|
|
||||||
const int lzc = MDFN_lzcount64(df->f);
|
|
||||||
int tmp_exp = df->exp - lzc;
|
|
||||||
uint64 tmp_walrus = df->f << (lzc & 0x3F);
|
|
||||||
int tmp_sign = df->sign;
|
|
||||||
|
|
||||||
tmp_exp += 40;
|
|
||||||
tmp_walrus >>= 40;
|
|
||||||
|
|
||||||
if (tmp_walrus == 0)
|
|
||||||
tmp_exp = -127;
|
|
||||||
else if (tmp_exp <= -127)
|
|
||||||
{
|
|
||||||
exception_flags |= flag_underflow | flag_inexact;
|
|
||||||
//printf("Subnormal: %lld. %d\n", tmp_walrus, tmp_exp);
|
|
||||||
if (1)
|
|
||||||
{
|
|
||||||
tmp_exp = -127;
|
|
||||||
tmp_walrus = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp_walrus >>= -(tmp_exp + 126);
|
|
||||||
tmp_exp = -127;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tmp_exp >= 128)
|
|
||||||
{
|
|
||||||
exception_flags |= flag_overflow;
|
|
||||||
//printf("Overflow!\n");
|
|
||||||
|
|
||||||
if (1)
|
|
||||||
tmp_exp -= 192;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp_exp = 128;
|
|
||||||
tmp_walrus = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (tmp_sign << 31) | ((tmp_exp + 127) << 23) | (tmp_walrus & 0x7FFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::mul(uint32 a, uint32 b)
|
|
||||||
{
|
|
||||||
fpim ins[2];
|
|
||||||
fpim res;
|
|
||||||
|
|
||||||
if (fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
|
|
||||||
{
|
|
||||||
exception_flags |= flag_reserved;
|
|
||||||
return (~0U);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpim_decode(&ins[0], a);
|
|
||||||
fpim_decode(&ins[1], b);
|
|
||||||
|
|
||||||
//printf("%08x %08x - %d %d %d - %d %d %d\n", a, b, a_exp, a_walrus, a_sign, b_exp, b_walrus, b_sign);
|
|
||||||
|
|
||||||
res.exp = ins[0].exp + ins[1].exp - 23;
|
|
||||||
res.f = ins[0].f * ins[1].f;
|
|
||||||
res.sign = ins[0].sign ^ ins[1].sign;
|
|
||||||
|
|
||||||
fpim_round(&res);
|
|
||||||
|
|
||||||
return fpim_encode(&res);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::add(uint32 a, uint32 b)
|
|
||||||
{
|
|
||||||
fpim ins[2];
|
|
||||||
fpim res;
|
|
||||||
int64 ft[2];
|
|
||||||
int64 tr;
|
|
||||||
int max_exp;
|
|
||||||
|
|
||||||
if (fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
|
|
||||||
{
|
|
||||||
exception_flags |= flag_reserved;
|
|
||||||
return (~0U);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a == b && !(a & 0x7FFFFFFF))
|
|
||||||
{
|
|
||||||
return (a & 0x80000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpim_decode(&ins[0], a);
|
|
||||||
fpim_decode(&ins[1], b);
|
|
||||||
|
|
||||||
max_exp = std::max<int>(ins[0].exp, ins[1].exp);
|
|
||||||
|
|
||||||
//printf("%d:%08llx %d:%08llx\n", ins[0].exp, ins[0].f, ins[1].exp, ins[1].f);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
unsigned sd = (max_exp - ins[i].exp);
|
|
||||||
|
|
||||||
ft[i] = ins[i].f << 24;
|
|
||||||
|
|
||||||
if (sd >= 48)
|
|
||||||
{
|
|
||||||
if (ft[i] != 0)
|
|
||||||
ft[i] = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int64 nft = ft[i] >> sd;
|
|
||||||
|
|
||||||
if (ft[i] != (nft << sd))
|
|
||||||
{
|
|
||||||
nft |= 1;
|
|
||||||
}
|
|
||||||
//{
|
|
||||||
// puts("FPR");
|
|
||||||
// }
|
|
||||||
|
|
||||||
ft[i] = nft;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ins[i].sign)
|
|
||||||
ft[i] = -ft[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
//printf("SOON: %08llx %08llx\n", ft[0], ft[1]);
|
|
||||||
|
|
||||||
tr = ft[0] + ft[1];
|
|
||||||
if (tr < 0)
|
|
||||||
{
|
|
||||||
tr = -tr;
|
|
||||||
res.sign = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
res.sign = false;
|
|
||||||
|
|
||||||
res.f = tr;
|
|
||||||
res.exp = max_exp - 24;
|
|
||||||
|
|
||||||
fpim_round(&res);
|
|
||||||
|
|
||||||
return fpim_encode(&res);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::sub(uint32 a, uint32 b)
|
|
||||||
{
|
|
||||||
return add(a, b ^ 0x80000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::div(uint32 a, uint32 b)
|
|
||||||
{
|
|
||||||
fpim ins[2];
|
|
||||||
fpim res;
|
|
||||||
uint64 mtmp;
|
|
||||||
|
|
||||||
if (fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
|
|
||||||
{
|
|
||||||
exception_flags |= flag_reserved;
|
|
||||||
return (~0U);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp_is_zero(a) && fp_is_zero(b))
|
|
||||||
{
|
|
||||||
exception_flags |= flag_invalid;
|
|
||||||
return (~0U);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpim_decode(&ins[0], a);
|
|
||||||
fpim_decode(&ins[1], b);
|
|
||||||
|
|
||||||
res.sign = ins[0].sign ^ ins[1].sign;
|
|
||||||
|
|
||||||
if (ins[1].f == 0)
|
|
||||||
{
|
|
||||||
//puts("Divide by zero!");
|
|
||||||
exception_flags |= flag_divbyzero;
|
|
||||||
return ((res.sign << 31) | (255 << 23));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res.exp = ins[0].exp - ins[1].exp - 2 - 1; // + 23 - 2;
|
|
||||||
res.f = ((ins[0].f << 24) / ins[1].f) << 2;
|
|
||||||
mtmp = ((ins[0].f << 24) % ins[1].f) << 1;
|
|
||||||
|
|
||||||
//printf("%lld %lld\n", (ins[0].f << 23) % ins[1].f, ins[1].f);
|
|
||||||
|
|
||||||
if (mtmp > ins[1].f)
|
|
||||||
res.f |= 3;
|
|
||||||
else if (mtmp == ins[1].f)
|
|
||||||
res.f |= 2;
|
|
||||||
else if (mtmp > 0)
|
|
||||||
res.f |= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpim_round(&res);
|
|
||||||
|
|
||||||
return fpim_encode(&res);
|
|
||||||
}
|
|
||||||
|
|
||||||
int V810_FP_Ops::cmp(uint32 a, uint32 b)
|
|
||||||
{
|
|
||||||
fpim ins[2];
|
|
||||||
|
|
||||||
if (fp_is_inf_nan_sub(a) || fp_is_inf_nan_sub(b))
|
|
||||||
{
|
|
||||||
exception_flags |= flag_reserved;
|
|
||||||
return (~0U);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpim_decode(&ins[0], a);
|
|
||||||
fpim_decode(&ins[1], b);
|
|
||||||
|
|
||||||
if (ins[0].exp > ins[1].exp)
|
|
||||||
return (ins[0].sign ? -1 : 1);
|
|
||||||
|
|
||||||
if (ins[0].exp < ins[1].exp)
|
|
||||||
return (ins[1].sign ? 1 : -1);
|
|
||||||
|
|
||||||
if (ins[0].f > ins[1].f)
|
|
||||||
return (ins[0].sign ? -1 : 1);
|
|
||||||
|
|
||||||
if (ins[0].f < ins[1].f)
|
|
||||||
return (ins[1].sign ? 1 : -1);
|
|
||||||
|
|
||||||
if ((ins[0].sign ^ ins[1].sign) && ins[0].f != 0)
|
|
||||||
return (ins[0].sign ? -1 : 1);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::itof(uint32 v)
|
|
||||||
{
|
|
||||||
fpim res;
|
|
||||||
|
|
||||||
res.sign = (bool)(v & 0x80000000);
|
|
||||||
res.exp = 23;
|
|
||||||
res.f = res.sign ? (0x80000000 - (v & 0x7FFFFFFF)) : (v & 0x7FFFFFFF);
|
|
||||||
|
|
||||||
fpim_round(&res);
|
|
||||||
|
|
||||||
return fpim_encode(&res);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 V810_FP_Ops::ftoi(uint32 v, bool truncate)
|
|
||||||
{
|
|
||||||
fpim ins;
|
|
||||||
int sa;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (fp_is_inf_nan_sub(v))
|
|
||||||
{
|
|
||||||
exception_flags |= flag_reserved;
|
|
||||||
return (~0U);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpim_decode(&ins, v);
|
|
||||||
fpim_round_int(&ins, truncate);
|
|
||||||
|
|
||||||
sa = ins.exp - 23;
|
|
||||||
|
|
||||||
if (sa < 0)
|
|
||||||
{
|
|
||||||
if (sa <= -32)
|
|
||||||
ret = 0;
|
|
||||||
else
|
|
||||||
ret = ins.f >> -sa;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (sa >= 8)
|
|
||||||
{
|
|
||||||
if (sa == 8 && ins.f == 0x800000 && ins.sign)
|
|
||||||
return (0x80000000);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = ~0U;
|
|
||||||
exception_flags |= flag_invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = ins.f << sa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//printf("%d\n", sa);
|
|
||||||
|
|
||||||
if (ins.sign)
|
|
||||||
ret = -ret;
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen - Multi-system Emulator */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* v810_fp_ops.h:
|
|
||||||
** Copyright (C) 2014-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class V810_FP_Ops
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
uint32 mul(uint32 a, uint32 b);
|
|
||||||
uint32 div(uint32 a, uint32 b);
|
|
||||||
uint32 add(uint32 a, uint32 b);
|
|
||||||
uint32 sub(uint32 a, uint32 b);
|
|
||||||
int cmp(uint32 a, uint32 b);
|
|
||||||
|
|
||||||
uint32 itof(uint32 v);
|
|
||||||
uint32 ftoi(uint32 v, bool truncate);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
flag_invalid = 0x0001,
|
|
||||||
flag_divbyzero = 0x0002,
|
|
||||||
flag_overflow = 0x0004,
|
|
||||||
flag_underflow = 0x0008,
|
|
||||||
flag_inexact = 0x0010,
|
|
||||||
flag_reserved = 0x0020
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint32 get_flags(void)
|
|
||||||
{
|
|
||||||
return exception_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear_flags(void)
|
|
||||||
{
|
|
||||||
exception_flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned exception_flags;
|
|
||||||
|
|
||||||
struct fpim
|
|
||||||
{
|
|
||||||
uint64 f;
|
|
||||||
int exp;
|
|
||||||
bool sign;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool fp_is_zero(uint32 v);
|
|
||||||
bool fp_is_inf_nan_sub(uint32 v);
|
|
||||||
|
|
||||||
unsigned clz64(uint64 v);
|
|
||||||
void fpim_decode(fpim *df, uint32 v);
|
|
||||||
void fpim_round(fpim *df);
|
|
||||||
void fpim_round_int(fpim *df, bool truncate = false);
|
|
||||||
uint32 fpim_encode(fpim *df);
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,170 +0,0 @@
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// File: v810_opt.h
|
|
||||||
//
|
|
||||||
// Description: Defines used in v810_dis.cpp
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef V810_OPT_H_
|
|
||||||
#define V810_OPT_H_
|
|
||||||
|
|
||||||
#define sign_26(num) ((uint32)sign_x_to_s32(26, num))
|
|
||||||
#define sign_16(num) ((uint32)(int16)(num))
|
|
||||||
#define sign_14(num) ((uint32)sign_x_to_s32(14, num))
|
|
||||||
#define sign_12(num) ((uint32)sign_x_to_s32(12, num))
|
|
||||||
#define sign_9(num) ((uint32)sign_x_to_s32(9, num))
|
|
||||||
#define sign_8(_value) ((uint32)(int8)(_value))
|
|
||||||
#define sign_5(num) ((uint32)sign_x_to_s32(5, num))
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
|
||||||
// Define Modes
|
|
||||||
#define AM_I 0x01
|
|
||||||
#define AM_II 0x02
|
|
||||||
#define AM_III 0x03
|
|
||||||
#define AM_IV 0x04
|
|
||||||
#define AM_V 0x05
|
|
||||||
#define AM_VIa 0x06 // Mode6 form1
|
|
||||||
#define AM_VIb 0x0A // Mode6 form2
|
|
||||||
#define AM_VII 0x07
|
|
||||||
#define AM_VIII 0x08
|
|
||||||
#define AM_IX 0x09
|
|
||||||
#define AM_BSTR 0x0B // Bit String Instructions
|
|
||||||
#define AM_FPP 0x0C // Floating Point Instructions
|
|
||||||
#define AM_UDEF 0x0D // Unknown/Undefined Instructions
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
|
||||||
// Table of Instructions Address Modes
|
|
||||||
|
|
||||||
static const int addr_mode[80] = {
|
|
||||||
AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I,
|
|
||||||
AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I, AM_I,
|
|
||||||
AM_II, AM_II, AM_II, AM_II, AM_II, AM_II, AM_II, AM_II,
|
|
||||||
AM_II, AM_IX, AM_IX, AM_UDEF, AM_II, AM_II, AM_II, AM_BSTR,
|
|
||||||
AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF, AM_UDEF,
|
|
||||||
AM_V, AM_V, AM_IV, AM_IV, AM_V, AM_V, AM_V, AM_V,
|
|
||||||
AM_VIa, AM_VIa, AM_UDEF, AM_VIa, AM_VIb, AM_VIb, AM_UDEF, AM_VIb,
|
|
||||||
AM_VIa, AM_VIa, AM_VIa, AM_VIa, AM_VIb, AM_VIb, AM_FPP, AM_VIb,
|
|
||||||
AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III,
|
|
||||||
AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III, AM_III
|
|
||||||
};
|
|
||||||
// All instructions greater than 0x50 are undefined (this should not be posible of cource)
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
|
||||||
// Opcodes for V810 Instruction set
|
|
||||||
#define MOV 0x00
|
|
||||||
#define ADD 0x01
|
|
||||||
#define SUB 0x02
|
|
||||||
#define CMP 0x03
|
|
||||||
#define SHL 0x04
|
|
||||||
#define SHR 0x05
|
|
||||||
#define JMP 0x06
|
|
||||||
#define SAR 0x07
|
|
||||||
#define MUL 0x08
|
|
||||||
#define DIV 0x09
|
|
||||||
#define MULU 0x0A
|
|
||||||
#define DIVU 0x0B
|
|
||||||
#define OR 0x0C
|
|
||||||
#define AND 0x0D
|
|
||||||
#define XOR 0x0E
|
|
||||||
#define NOT 0x0F
|
|
||||||
#define MOV_I 0x10
|
|
||||||
#define ADD_I 0x11
|
|
||||||
#define SETF 0x12
|
|
||||||
#define CMP_I 0x13
|
|
||||||
#define SHL_I 0x14
|
|
||||||
#define SHR_I 0x15
|
|
||||||
#define EI 0x16
|
|
||||||
#define SAR_I 0x17
|
|
||||||
#define TRAP 0x18
|
|
||||||
#define RETI 0x19
|
|
||||||
#define HALT 0x1A
|
|
||||||
//0x1B
|
|
||||||
#define LDSR 0x1C
|
|
||||||
#define STSR 0x1D
|
|
||||||
#define DI 0x1E
|
|
||||||
#define BSTR 0x1F //Special Bit String Inst
|
|
||||||
//0x20 - 0x27 // Lost to Branch Instructions
|
|
||||||
#define MOVEA 0x28
|
|
||||||
#define ADDI 0x29
|
|
||||||
#define JR 0x2A
|
|
||||||
#define JAL 0x2B
|
|
||||||
#define ORI 0x2C
|
|
||||||
#define ANDI 0x2D
|
|
||||||
#define XORI 0x2E
|
|
||||||
#define MOVHI 0x2F
|
|
||||||
#define LD_B 0x30
|
|
||||||
#define LD_H 0x31
|
|
||||||
//0x32
|
|
||||||
#define LD_W 0x33
|
|
||||||
#define ST_B 0x34
|
|
||||||
#define ST_H 0x35
|
|
||||||
//0x36
|
|
||||||
#define ST_W 0x37
|
|
||||||
#define IN_B 0x38
|
|
||||||
#define IN_H 0x39
|
|
||||||
#define CAXI 0x3A
|
|
||||||
#define IN_W 0x3B
|
|
||||||
#define OUT_B 0x3C
|
|
||||||
#define OUT_H 0x3D
|
|
||||||
#define FPP 0x3E //Special Float Inst
|
|
||||||
#define OUT_W 0x3F
|
|
||||||
|
|
||||||
|
|
||||||
// Branch Instructions ( Extended opcode only for Branch command)
|
|
||||||
// Common instrcutions commented out
|
|
||||||
|
|
||||||
#define BV 0x40
|
|
||||||
#define BL 0x41
|
|
||||||
#define BE 0x42
|
|
||||||
#define BNH 0x43
|
|
||||||
#define BN 0x44
|
|
||||||
#define BR 0x45
|
|
||||||
#define BLT 0x46
|
|
||||||
#define BLE 0x47
|
|
||||||
#define BNV 0x48
|
|
||||||
#define BNL 0x49
|
|
||||||
#define BNE 0x4A
|
|
||||||
#define BH 0x4B
|
|
||||||
#define BP 0x4C
|
|
||||||
#define NOP 0x4D
|
|
||||||
#define BGE 0x4E
|
|
||||||
#define BGT 0x4F
|
|
||||||
|
|
||||||
//#define BC 0x41
|
|
||||||
//#define BZ 0x42
|
|
||||||
//#define BNC 0x49
|
|
||||||
//#define BNZ 0x4A
|
|
||||||
|
|
||||||
// Bit String Subopcodes
|
|
||||||
#define SCH0BSU 0x00
|
|
||||||
#define SCH0BSD 0x01
|
|
||||||
#define SCH1BSU 0x02
|
|
||||||
#define SCH1BSD 0x03
|
|
||||||
|
|
||||||
#define ORBSU 0x08
|
|
||||||
#define ANDBSU 0x09
|
|
||||||
#define XORBSU 0x0A
|
|
||||||
#define MOVBSU 0x0B
|
|
||||||
#define ORNBSU 0x0C
|
|
||||||
#define ANDNBSU 0x0D
|
|
||||||
#define XORNBSU 0x0E
|
|
||||||
#define NOTBSU 0x0F
|
|
||||||
|
|
||||||
|
|
||||||
// Floating Point Subopcodes
|
|
||||||
#define CMPF_S 0x00
|
|
||||||
|
|
||||||
#define CVT_WS 0x02
|
|
||||||
#define CVT_SW 0x03
|
|
||||||
#define ADDF_S 0x04
|
|
||||||
#define SUBF_S 0x05
|
|
||||||
#define MULF_S 0x06
|
|
||||||
#define DIVF_S 0x07
|
|
||||||
#define XB 0x08
|
|
||||||
#define XH 0x09
|
|
||||||
#define REV 0x0A
|
|
||||||
#define TRNC_SW 0x0B
|
|
||||||
#define MPYHW 0x0C
|
|
||||||
|
|
||||||
#endif //DEFINE_H
|
|
||||||
|
|
|
@ -1,829 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* vb.cpp:
|
|
||||||
** Copyright (C) 2010-2017 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "vb.h"
|
|
||||||
#include "../emulibc/emulibc.h"
|
|
||||||
#include "../emulibc/waterboxcore.h"
|
|
||||||
#define EXPORT extern "C" ECL_EXPORT
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
struct NativeSyncSettings
|
|
||||||
{
|
|
||||||
int InstantReadHack;
|
|
||||||
int DisableParallax;
|
|
||||||
};
|
|
||||||
struct NativeSettings
|
|
||||||
{
|
|
||||||
int ThreeDeeMode;
|
|
||||||
int SwapViews;
|
|
||||||
int AnaglyphPreset;
|
|
||||||
int AnaglyphCustomLeftColor;
|
|
||||||
int AnaglyphCustomRightColor;
|
|
||||||
int NonAnaglyphColor;
|
|
||||||
int LedOnScale;
|
|
||||||
int InterlacePrescale;
|
|
||||||
int SideBySideSeparation;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void (*input_callback)();
|
|
||||||
static bool lagged;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ANAGLYPH_PRESET_DISABLED = 0,
|
|
||||||
ANAGLYPH_PRESET_RED_BLUE,
|
|
||||||
ANAGLYPH_PRESET_RED_CYAN,
|
|
||||||
ANAGLYPH_PRESET_RED_ELECTRICCYAN,
|
|
||||||
ANAGLYPH_PRESET_RED_GREEN,
|
|
||||||
ANAGLYPH_PRESET_GREEN_MAGENTA,
|
|
||||||
ANAGLYPH_PRESET_YELLOW_BLUE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32 AnaglyphPreset_Colors[][2] =
|
|
||||||
{
|
|
||||||
{0, 0},
|
|
||||||
{0xFF0000, 0x0000FF},
|
|
||||||
{0xFF0000, 0x00B7EB},
|
|
||||||
{0xFF0000, 0x00FFFF},
|
|
||||||
{0xFF0000, 0x00FF00},
|
|
||||||
{0x00FF00, 0xFF00FF},
|
|
||||||
{0xFFFF00, 0x0000FF},
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint32 VB3DMode;
|
|
||||||
|
|
||||||
static uint8 *WRAM = NULL;
|
|
||||||
|
|
||||||
static uint8 *GPRAM = NULL;
|
|
||||||
static const uint32 GPRAM_Mask = 0xFFFF;
|
|
||||||
|
|
||||||
static uint8 *GPROM = NULL;
|
|
||||||
static uint32 GPROM_Mask;
|
|
||||||
|
|
||||||
V810 *VB_V810 = NULL;
|
|
||||||
|
|
||||||
VSU *VB_VSU = NULL;
|
|
||||||
static uint32 VSU_CycleFix;
|
|
||||||
|
|
||||||
static uint8 WCR;
|
|
||||||
|
|
||||||
static int32 next_vip_ts, next_timer_ts, next_input_ts;
|
|
||||||
|
|
||||||
static uint32 IRQ_Asserted;
|
|
||||||
|
|
||||||
static INLINE void RecalcIntLevel(void)
|
|
||||||
{
|
|
||||||
int ilevel = -1;
|
|
||||||
|
|
||||||
for (int i = 4; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (IRQ_Asserted & (1 << i))
|
|
||||||
{
|
|
||||||
ilevel = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VB_V810->SetInt(ilevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VBIRQ_Assert(int source, bool assert)
|
|
||||||
{
|
|
||||||
assert(source >= 0 && source <= 4);
|
|
||||||
|
|
||||||
IRQ_Asserted &= ~(1 << source);
|
|
||||||
|
|
||||||
if (assert)
|
|
||||||
IRQ_Asserted |= 1 << source;
|
|
||||||
|
|
||||||
RecalcIntLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
static MDFN_FASTCALL uint8 HWCTRL_Read(v810_timestamp_t ×tamp, uint32 A)
|
|
||||||
{
|
|
||||||
uint8 ret = 0;
|
|
||||||
|
|
||||||
if (A & 0x3)
|
|
||||||
{
|
|
||||||
//puts("HWCtrl Bogus Read?");
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (A & 0xFF)
|
|
||||||
{
|
|
||||||
default: //printf("Unknown HWCTRL Read: %08x\n", A);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x18:
|
|
||||||
case 0x1C:
|
|
||||||
case 0x20:
|
|
||||||
ret = TIMER_Read(timestamp, A);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x24:
|
|
||||||
ret = WCR | 0xFC;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x10:
|
|
||||||
case 0x14:
|
|
||||||
case 0x28:
|
|
||||||
lagged = false;
|
|
||||||
if (input_callback)
|
|
||||||
input_callback();
|
|
||||||
ret = VBINPUT_Read(timestamp, A);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MDFN_FASTCALL void HWCTRL_Write(v810_timestamp_t ×tamp, uint32 A, uint8 V)
|
|
||||||
{
|
|
||||||
if (A & 0x3)
|
|
||||||
{
|
|
||||||
puts("HWCtrl Bogus Write?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (A & 0xFF)
|
|
||||||
{
|
|
||||||
default: //printf("Unknown HWCTRL Write: %08x %02x\n", A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x18:
|
|
||||||
case 0x1C:
|
|
||||||
case 0x20:
|
|
||||||
TIMER_Write(timestamp, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x24:
|
|
||||||
WCR = V & 0x3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x10:
|
|
||||||
case 0x14:
|
|
||||||
case 0x28:
|
|
||||||
VBINPUT_Write(timestamp, A, V);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 MDFN_FASTCALL MemRead8(v810_timestamp_t ×tamp, uint32 A)
|
|
||||||
{
|
|
||||||
uint8 ret = 0;
|
|
||||||
A &= (1 << 27) - 1;
|
|
||||||
|
|
||||||
//if((A >> 24) <= 2)
|
|
||||||
// printf("Read8: %d %08x\n", timestamp, A);
|
|
||||||
|
|
||||||
switch (A >> 24)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
ret = VIP_Read8(timestamp, A);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
ret = HWCTRL_Read(timestamp, A);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
ret = WRAM[A & 0xFFFF];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
if (GPRAM)
|
|
||||||
ret = GPRAM[A & GPRAM_Mask];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7:
|
|
||||||
ret = GPROM[A & GPROM_Mask];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 MDFN_FASTCALL MemRead16(v810_timestamp_t ×tamp, uint32 A)
|
|
||||||
{
|
|
||||||
uint16 ret = 0;
|
|
||||||
|
|
||||||
A &= (1 << 27) - 1;
|
|
||||||
|
|
||||||
//if((A >> 24) <= 2)
|
|
||||||
// printf("Read16: %d %08x\n", timestamp, A);
|
|
||||||
|
|
||||||
switch (A >> 24)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
ret = VIP_Read16(timestamp, A);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
ret = HWCTRL_Read(timestamp, A);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
ret = MDFN_de16lsb<true>(&WRAM[A & 0xFFFF]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
if (GPRAM)
|
|
||||||
ret = MDFN_de16lsb<true>(&GPRAM[A & GPRAM_Mask]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7:
|
|
||||||
ret = MDFN_de16lsb<true>(&GPROM[A & GPROM_Mask]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MDFN_FASTCALL MemWrite8(v810_timestamp_t ×tamp, uint32 A, uint8 V)
|
|
||||||
{
|
|
||||||
A &= (1 << 27) - 1;
|
|
||||||
|
|
||||||
//if((A >> 24) <= 2)
|
|
||||||
// printf("Write8: %d %08x %02x\n", timestamp, A, V);
|
|
||||||
|
|
||||||
switch (A >> 24)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
VIP_Write8(timestamp, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
VB_VSU->Write((timestamp + VSU_CycleFix) >> 2, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
HWCTRL_Write(timestamp, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
WRAM[A & 0xFFFF] = V;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
if (GPRAM)
|
|
||||||
GPRAM[A & GPRAM_Mask] = V;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7: // ROM, no writing allowed!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MDFN_FASTCALL MemWrite16(v810_timestamp_t ×tamp, uint32 A, uint16 V)
|
|
||||||
{
|
|
||||||
A &= (1 << 27) - 1;
|
|
||||||
|
|
||||||
//if((A >> 24) <= 2)
|
|
||||||
// printf("Write16: %d %08x %04x\n", timestamp, A, V);
|
|
||||||
|
|
||||||
switch (A >> 24)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
VIP_Write16(timestamp, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
VB_VSU->Write((timestamp + VSU_CycleFix) >> 2, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
HWCTRL_Write(timestamp, A, V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
MDFN_en16lsb<true>(&WRAM[A & 0xFFFF], V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
if (GPRAM)
|
|
||||||
MDFN_en16lsb<true>(&GPRAM[A & GPRAM_Mask], V);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7: // ROM, no writing allowed!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FixNonEvents(void)
|
|
||||||
{
|
|
||||||
if (next_vip_ts & 0x40000000)
|
|
||||||
next_vip_ts = VB_EVENT_NONONO;
|
|
||||||
|
|
||||||
if (next_timer_ts & 0x40000000)
|
|
||||||
next_timer_ts = VB_EVENT_NONONO;
|
|
||||||
|
|
||||||
if (next_input_ts & 0x40000000)
|
|
||||||
next_input_ts = VB_EVENT_NONONO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EventReset(void)
|
|
||||||
{
|
|
||||||
next_vip_ts = VB_EVENT_NONONO;
|
|
||||||
next_timer_ts = VB_EVENT_NONONO;
|
|
||||||
next_input_ts = VB_EVENT_NONONO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static INLINE int32 CalcNextTS(void)
|
|
||||||
{
|
|
||||||
int32 next_timestamp = next_vip_ts;
|
|
||||||
|
|
||||||
if (next_timestamp > next_timer_ts)
|
|
||||||
next_timestamp = next_timer_ts;
|
|
||||||
|
|
||||||
if (next_timestamp > next_input_ts)
|
|
||||||
next_timestamp = next_input_ts;
|
|
||||||
|
|
||||||
return (next_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RebaseTS(const v810_timestamp_t timestamp)
|
|
||||||
{
|
|
||||||
//printf("Rebase: %08x %08x %08x\n", timestamp, next_vip_ts, next_timer_ts);
|
|
||||||
|
|
||||||
assert(next_vip_ts > timestamp);
|
|
||||||
assert(next_timer_ts > timestamp);
|
|
||||||
assert(next_input_ts > timestamp);
|
|
||||||
|
|
||||||
next_vip_ts -= timestamp;
|
|
||||||
next_timer_ts -= timestamp;
|
|
||||||
next_input_ts -= timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VB_SetEvent(const int type, const v810_timestamp_t next_timestamp)
|
|
||||||
{
|
|
||||||
//assert(next_timestamp > VB_V810->v810_timestamp);
|
|
||||||
|
|
||||||
if (type == VB_EVENT_VIP)
|
|
||||||
next_vip_ts = next_timestamp;
|
|
||||||
else if (type == VB_EVENT_TIMER)
|
|
||||||
next_timer_ts = next_timestamp;
|
|
||||||
else if (type == VB_EVENT_INPUT)
|
|
||||||
next_input_ts = next_timestamp;
|
|
||||||
|
|
||||||
if (next_timestamp < VB_V810->GetEventNT())
|
|
||||||
VB_V810->SetEventNT(next_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32 MDFN_FASTCALL EventHandler(const v810_timestamp_t timestamp)
|
|
||||||
{
|
|
||||||
if (timestamp >= next_vip_ts)
|
|
||||||
next_vip_ts = VIP_Update(timestamp);
|
|
||||||
|
|
||||||
if (timestamp >= next_timer_ts)
|
|
||||||
next_timer_ts = TIMER_Update(timestamp);
|
|
||||||
|
|
||||||
if (timestamp >= next_input_ts)
|
|
||||||
next_input_ts = VBINPUT_Update(timestamp);
|
|
||||||
|
|
||||||
return (CalcNextTS());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called externally from debug.cpp in some cases.
|
|
||||||
void ForceEventUpdates(const v810_timestamp_t timestamp)
|
|
||||||
{
|
|
||||||
next_vip_ts = VIP_Update(timestamp);
|
|
||||||
next_timer_ts = TIMER_Update(timestamp);
|
|
||||||
next_input_ts = VBINPUT_Update(timestamp);
|
|
||||||
|
|
||||||
VB_V810->SetEventNT(CalcNextTS());
|
|
||||||
//printf("FEU: %d %d %d\n", next_vip_ts, next_timer_ts, next_input_ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void VB_Power(void)
|
|
||||||
{
|
|
||||||
memset(WRAM, 0, 65536);
|
|
||||||
|
|
||||||
VIP_Power();
|
|
||||||
VB_VSU->Power();
|
|
||||||
TIMER_Power();
|
|
||||||
VBINPUT_Power();
|
|
||||||
|
|
||||||
EventReset();
|
|
||||||
IRQ_Asserted = 0;
|
|
||||||
RecalcIntLevel();
|
|
||||||
VB_V810->Reset();
|
|
||||||
|
|
||||||
VSU_CycleFix = 0;
|
|
||||||
WCR = 0;
|
|
||||||
|
|
||||||
ForceEventUpdates(0); //VB_V810->v810_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*struct VB_HeaderInfo
|
|
||||||
{
|
|
||||||
char game_title[256];
|
|
||||||
uint32 game_code;
|
|
||||||
uint16 manf_code;
|
|
||||||
uint8 version;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
/*static void ReadHeader(const uint8 *const rom_data, const uint64 rom_size, VB_HeaderInfo *hi)
|
|
||||||
{
|
|
||||||
iconv_t sjis_ict = iconv_open("UTF-8", "shift_jis");
|
|
||||||
|
|
||||||
if (sjis_ict != (iconv_t)-1)
|
|
||||||
{
|
|
||||||
char *in_ptr, *out_ptr;
|
|
||||||
size_t ibl, obl;
|
|
||||||
|
|
||||||
ibl = 20;
|
|
||||||
obl = sizeof(hi->game_title) - 1;
|
|
||||||
|
|
||||||
in_ptr = (char *)rom_data + (0xFFFFFDE0 & (rom_size - 1));
|
|
||||||
out_ptr = hi->game_title;
|
|
||||||
|
|
||||||
iconv(sjis_ict, (ICONV_CONST char **)&in_ptr, &ibl, &out_ptr, &obl);
|
|
||||||
iconv_close(sjis_ict);
|
|
||||||
|
|
||||||
*out_ptr = 0;
|
|
||||||
|
|
||||||
MDFN_zapctrlchars(hi->game_title);
|
|
||||||
MDFN_trim(hi->game_title);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hi->game_title[0] = 0;
|
|
||||||
|
|
||||||
hi->game_code = MDFN_de32lsb(rom_data + (0xFFFFFDFB & (rom_size - 1)));
|
|
||||||
hi->manf_code = MDFN_de16lsb(rom_data + (0xFFFFFDF9 & (rom_size - 1)));
|
|
||||||
hi->version = rom_data[0xFFFFFDFF & (rom_size - 1)];
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void VB_ExitLoop(void)
|
|
||||||
{
|
|
||||||
VB_V810->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*MDFNGI EmulatedVB =
|
|
||||||
{
|
|
||||||
|
|
||||||
PortInfo,
|
|
||||||
Load,
|
|
||||||
TestMagic,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
CloseGame,
|
|
||||||
|
|
||||||
SetLayerEnableMask,
|
|
||||||
NULL, // Layer names, null-delimited
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
VIP_CPInfo,
|
|
||||||
1 << 0,
|
|
||||||
|
|
||||||
CheatInfo_Empty,
|
|
||||||
|
|
||||||
false,
|
|
||||||
StateAction,
|
|
||||||
Emulate,
|
|
||||||
NULL,
|
|
||||||
VBINPUT_SetInput,
|
|
||||||
NULL,
|
|
||||||
DoSimpleCommand,
|
|
||||||
NULL,
|
|
||||||
VBSettings,
|
|
||||||
MDFN_MASTERCLOCK_FIXED(VB_MASTER_CLOCK),
|
|
||||||
0,
|
|
||||||
false, // Multires possible?
|
|
||||||
|
|
||||||
0, // lcm_width
|
|
||||||
0, // lcm_height
|
|
||||||
NULL, // Dummy
|
|
||||||
|
|
||||||
384, // Nominal width
|
|
||||||
224, // Nominal height
|
|
||||||
|
|
||||||
384, // Framebuffer width
|
|
||||||
256, // Framebuffer height
|
|
||||||
|
|
||||||
2, // Number of output sound channels
|
|
||||||
};*/
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace MDFN_IEN_VB;
|
|
||||||
|
|
||||||
EXPORT int Load(const uint8 *rom, int length, const NativeSyncSettings *syncSettings)
|
|
||||||
{
|
|
||||||
const uint64 rom_size = length;
|
|
||||||
V810_Emu_Mode cpu_mode = V810_EMU_MODE_ACCURATE;
|
|
||||||
|
|
||||||
if (rom_size != round_up_pow2(rom_size))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
// throw MDFN_Error(0, _("VB ROM image size is not a power of 2."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rom_size < 256)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
//throw MDFN_Error(0, _("VB ROM image size is too small."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rom_size > (1 << 24))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
//throw MDFN_Error(0, _("VB ROM image size is too large."));
|
|
||||||
}
|
|
||||||
|
|
||||||
VB_V810 = new V810();
|
|
||||||
VB_V810->Init(cpu_mode, true);
|
|
||||||
|
|
||||||
VB_V810->SetMemReadHandlers(MemRead8, MemRead16, NULL);
|
|
||||||
VB_V810->SetMemWriteHandlers(MemWrite8, MemWrite16, NULL);
|
|
||||||
|
|
||||||
VB_V810->SetIOReadHandlers(MemRead8, MemRead16, NULL);
|
|
||||||
VB_V810->SetIOWriteHandlers(MemWrite8, MemWrite16, NULL);
|
|
||||||
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
VB_V810->SetMemReadBus32(i, false);
|
|
||||||
VB_V810->SetMemWriteBus32(i, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint32> Map_Addresses;
|
|
||||||
|
|
||||||
for (uint64 A = 0; A < 1ULL << 32; A += (1 << 27))
|
|
||||||
{
|
|
||||||
for (uint64 sub_A = 5 << 24; sub_A < (6 << 24); sub_A += 65536)
|
|
||||||
{
|
|
||||||
Map_Addresses.push_back(A + sub_A);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WRAM = VB_V810->SetFastMap(alloc_plain, &Map_Addresses[0], 65536, Map_Addresses.size(), "WRAM");
|
|
||||||
Map_Addresses.clear();
|
|
||||||
|
|
||||||
// Round up the ROM size to 65536(we mirror it a little later)
|
|
||||||
GPROM_Mask = (rom_size < 65536) ? (65536 - 1) : (rom_size - 1);
|
|
||||||
|
|
||||||
for (uint64 A = 0; A < 1ULL << 32; A += (1 << 27))
|
|
||||||
{
|
|
||||||
for (uint64 sub_A = 7 << 24; sub_A < (8 << 24); sub_A += GPROM_Mask + 1)
|
|
||||||
{
|
|
||||||
Map_Addresses.push_back(A + sub_A);
|
|
||||||
//printf("%08x\n", (uint32)(A + sub_A));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GPROM = VB_V810->SetFastMap(alloc_sealed, &Map_Addresses[0], GPROM_Mask + 1, Map_Addresses.size(), "Cart ROM");
|
|
||||||
Map_Addresses.clear();
|
|
||||||
|
|
||||||
memcpy(GPROM, rom, rom_size);
|
|
||||||
|
|
||||||
// Mirror ROM images < 64KiB to 64KiB
|
|
||||||
for (uint64 i = rom_size; i < 65536; i += rom_size)
|
|
||||||
{
|
|
||||||
memcpy(GPROM + i, GPROM, rom_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*VB_HeaderInfo hinfo;
|
|
||||||
|
|
||||||
ReadHeader(GPROM, rom_size, &hinfo);
|
|
||||||
|
|
||||||
MDFN_printf(_("Title: %s\n"), hinfo.game_title);
|
|
||||||
MDFN_printf(_("Game ID Code: %u\n"), hinfo.game_code);
|
|
||||||
MDFN_printf(_("Manufacturer Code: %d\n"), hinfo.manf_code);
|
|
||||||
MDFN_printf(_("Version: %u\n"), hinfo.version);
|
|
||||||
|
|
||||||
MDFN_printf(_("ROM: %uKiB\n"), (unsigned)(rom_size / 1024));
|
|
||||||
MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());*/
|
|
||||||
|
|
||||||
/*MDFN_printf("\n");
|
|
||||||
|
|
||||||
MDFN_printf(_("V810 Emulation Mode: %s\n"), (cpu_mode == V810_EMU_MODE_ACCURATE) ? _("Accurate") : _("Fast"));*/
|
|
||||||
|
|
||||||
for (uint64 A = 0; A < 1ULL << 32; A += (1 << 27))
|
|
||||||
{
|
|
||||||
for (uint64 sub_A = 6 << 24; sub_A < (7 << 24); sub_A += GPRAM_Mask + 1)
|
|
||||||
{
|
|
||||||
//printf("GPRAM: %08x\n", A + sub_A);
|
|
||||||
Map_Addresses.push_back(A + sub_A);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GPRAM = VB_V810->SetFastMap(alloc_plain, &Map_Addresses[0], GPRAM_Mask + 1, Map_Addresses.size(), "Cart RAM");
|
|
||||||
Map_Addresses.clear();
|
|
||||||
|
|
||||||
memset(GPRAM, 0, GPRAM_Mask + 1);
|
|
||||||
|
|
||||||
VIP_Init();
|
|
||||||
VB_VSU = new VSU();
|
|
||||||
VBINPUT_Init();
|
|
||||||
|
|
||||||
VB3DMode = 0;
|
|
||||||
uint32 prescale = 1;
|
|
||||||
uint32 sbs_separation = 0;
|
|
||||||
bool reverse = false;
|
|
||||||
|
|
||||||
VIP_Set3DMode(VB3DMode, reverse, prescale, sbs_separation);
|
|
||||||
|
|
||||||
VIP_SetParallaxDisable(syncSettings->DisableParallax);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto presetColor = 1;
|
|
||||||
|
|
||||||
uint32 lcolor = 0xff0000;
|
|
||||||
uint32 rcolor = 0x00ff00;
|
|
||||||
|
|
||||||
if (presetColor != ANAGLYPH_PRESET_DISABLED)
|
|
||||||
{
|
|
||||||
lcolor = AnaglyphPreset_Colors[presetColor][0];
|
|
||||||
rcolor = AnaglyphPreset_Colors[presetColor][1];
|
|
||||||
}
|
|
||||||
VIP_SetAnaglyphColors(lcolor, rcolor);
|
|
||||||
VIP_SetDefaultColor(0xffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
VBINPUT_SetInstantReadHack(syncSettings->InstantReadHack);
|
|
||||||
|
|
||||||
VIP_SetLEDOnScale(1750 / 1000.0);
|
|
||||||
|
|
||||||
VB_Power();
|
|
||||||
|
|
||||||
/*switch (VB3DMode)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VB3DMODE_VLI:
|
|
||||||
MDFNGameInfo->nominal_width = 768 * prescale;
|
|
||||||
MDFNGameInfo->nominal_height = 224;
|
|
||||||
MDFNGameInfo->fb_width = 768 * prescale;
|
|
||||||
MDFNGameInfo->fb_height = 224;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VB3DMODE_HLI:
|
|
||||||
MDFNGameInfo->nominal_width = 384;
|
|
||||||
MDFNGameInfo->nominal_height = 448 * prescale;
|
|
||||||
MDFNGameInfo->fb_width = 384;
|
|
||||||
MDFNGameInfo->fb_height = 448 * prescale;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VB3DMODE_CSCOPE:
|
|
||||||
MDFNGameInfo->nominal_width = 512;
|
|
||||||
MDFNGameInfo->nominal_height = 384;
|
|
||||||
MDFNGameInfo->fb_width = 512;
|
|
||||||
MDFNGameInfo->fb_height = 384;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VB3DMODE_SIDEBYSIDE:
|
|
||||||
MDFNGameInfo->nominal_width = 384 * 2 + sbs_separation;
|
|
||||||
MDFNGameInfo->nominal_height = 224;
|
|
||||||
MDFNGameInfo->fb_width = 384 * 2 + sbs_separation;
|
|
||||||
MDFNGameInfo->fb_height = 224;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
MDFNGameInfo->lcm_width = MDFNGameInfo->fb_width;
|
|
||||||
MDFNGameInfo->lcm_height = MDFNGameInfo->fb_height;*/
|
|
||||||
|
|
||||||
VB_VSU->SetSoundRate(44100);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT void SetSettings(const NativeSettings *settings)
|
|
||||||
{
|
|
||||||
VB3DMode = settings->ThreeDeeMode;
|
|
||||||
uint32 prescale = settings->InterlacePrescale;
|
|
||||||
uint32 sbs_separation = settings->SideBySideSeparation;
|
|
||||||
bool reverse = settings->SwapViews;
|
|
||||||
|
|
||||||
VIP_Set3DMode(VB3DMode, reverse, prescale, sbs_separation);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto presetColor = settings->AnaglyphPreset;
|
|
||||||
|
|
||||||
uint32 lcolor = settings->AnaglyphCustomLeftColor;
|
|
||||||
uint32 rcolor = settings->AnaglyphCustomRightColor;
|
|
||||||
|
|
||||||
if (presetColor != ANAGLYPH_PRESET_DISABLED)
|
|
||||||
{
|
|
||||||
lcolor = AnaglyphPreset_Colors[presetColor][0];
|
|
||||||
rcolor = AnaglyphPreset_Colors[presetColor][1];
|
|
||||||
}
|
|
||||||
VIP_SetAnaglyphColors(lcolor, rcolor);
|
|
||||||
VIP_SetDefaultColor(settings->NonAnaglyphColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
VIP_SetLEDOnScale(settings->LedOnScale / 1000.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT void GetMemoryAreas(MemoryArea *m)
|
|
||||||
{
|
|
||||||
m[0].Data = WRAM;
|
|
||||||
m[0].Name = "WRAM";
|
|
||||||
m[0].Size = 65536;
|
|
||||||
m[0].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_WORDSIZE4;
|
|
||||||
|
|
||||||
m[1].Data = GPRAM;
|
|
||||||
m[1].Name = "CARTRAM";
|
|
||||||
m[1].Size = GPRAM_Mask + 1;
|
|
||||||
m[1].Flags = MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE | MEMORYAREA_FLAGS_WORDSIZE4;
|
|
||||||
|
|
||||||
m[2].Data = GPROM;
|
|
||||||
m[2].Name = "ROM";
|
|
||||||
m[2].Size = GPROM_Mask + 1;
|
|
||||||
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE4;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT void FrameAdvance(MyFrameInfo *frame)
|
|
||||||
{
|
|
||||||
v810_timestamp_t v810_timestamp;
|
|
||||||
lagged = true;
|
|
||||||
|
|
||||||
VBINPUT_Frame(&frame->Buttons);
|
|
||||||
|
|
||||||
VIP_StartFrame(frame);
|
|
||||||
|
|
||||||
v810_timestamp = VB_V810->Run(EventHandler);
|
|
||||||
|
|
||||||
FixNonEvents();
|
|
||||||
ForceEventUpdates(v810_timestamp);
|
|
||||||
|
|
||||||
frame->Samples = VB_VSU->EndFrame((v810_timestamp + VSU_CycleFix) >> 2, frame->SoundBuffer, 8192);
|
|
||||||
|
|
||||||
VSU_CycleFix = (v810_timestamp + VSU_CycleFix) & 3;
|
|
||||||
|
|
||||||
frame->Cycles = v810_timestamp;
|
|
||||||
frame->Lagged = lagged;
|
|
||||||
|
|
||||||
TIMER_ResetTS();
|
|
||||||
VBINPUT_ResetTS();
|
|
||||||
VIP_ResetTS();
|
|
||||||
|
|
||||||
RebaseTS(v810_timestamp);
|
|
||||||
|
|
||||||
VB_V810->ResetTS(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT void PredictFrameSize(MyFrameInfo *frame)
|
|
||||||
{
|
|
||||||
VIP_CalcFrameSize(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT void HardReset()
|
|
||||||
{
|
|
||||||
VB_Power();
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT void SetInputCallback(void (*callback)())
|
|
||||||
{
|
|
||||||
input_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
126
waterbox/vb/vb.h
126
waterbox/vb/vb.h
|
@ -1,126 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* vb.h:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstring>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
typedef uint8_t uint8;
|
|
||||||
typedef uint16_t uint16;
|
|
||||||
typedef uint32_t uint32;
|
|
||||||
typedef uint64_t uint64;
|
|
||||||
typedef int8_t int8;
|
|
||||||
typedef int16_t int16;
|
|
||||||
typedef int32_t int32;
|
|
||||||
typedef int64_t int64;
|
|
||||||
|
|
||||||
#define MDFN_FASTCALL
|
|
||||||
#define INLINE inline
|
|
||||||
#define MDFN_COLD
|
|
||||||
#define NO_INLINE
|
|
||||||
//#define MDFN_ASSUME_ALIGNED(p, align) ((decltype(p))__builtin_assume_aligned((p), (align)))
|
|
||||||
#define MDFN_ASSUME_ALIGNED(p, align) (p)
|
|
||||||
#define trio_snprintf snprintf
|
|
||||||
#define TRUE true
|
|
||||||
#define FALSE false
|
|
||||||
#ifndef __alignas_is_defined
|
|
||||||
#define alignas(p)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct MyFrameInfo
|
|
||||||
{
|
|
||||||
uint32_t* VideoBuffer;
|
|
||||||
int16_t* SoundBuffer;
|
|
||||||
int64_t Cycles;
|
|
||||||
int32_t Width;
|
|
||||||
int32_t Height;
|
|
||||||
int32_t Samples;
|
|
||||||
int32_t Lagged;
|
|
||||||
int32_t Buttons;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "endian.h"
|
|
||||||
#include "math_ops.h"
|
|
||||||
#include "blip/Blip_Buffer.h"
|
|
||||||
#include "v810/v810_fp_ops.h"
|
|
||||||
#include "v810/v810_cpu.h"
|
|
||||||
|
|
||||||
#include "git.h"
|
|
||||||
|
|
||||||
#include "vsu.h"
|
|
||||||
#include "vip.h"
|
|
||||||
#include "timer.h"
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
VB3DMODE_ANAGLYPH = 0,
|
|
||||||
VB3DMODE_CSCOPE = 1,
|
|
||||||
VB3DMODE_SIDEBYSIDE = 2,
|
|
||||||
VB3DMODE_OVERUNDER = 3,
|
|
||||||
VB3DMODE_VLI,
|
|
||||||
VB3DMODE_HLI,
|
|
||||||
VB3DMODE_ONLYLEFT,
|
|
||||||
VB3DMODE_ONLYRIGHT
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VB_MASTER_CLOCK 20000000.0
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
VB_EVENT_VIP = 0,
|
|
||||||
VB_EVENT_TIMER,
|
|
||||||
VB_EVENT_INPUT,
|
|
||||||
// VB_EVENT_COMM
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VB_EVENT_NONONO 0x7fffffff
|
|
||||||
|
|
||||||
void VB_SetEvent(const int type, const v810_timestamp_t next_timestamp);
|
|
||||||
|
|
||||||
#define VBIRQ_SOURCE_INPUT 0
|
|
||||||
#define VBIRQ_SOURCE_TIMER 1
|
|
||||||
#define VBIRQ_SOURCE_EXPANSION 2
|
|
||||||
#define VBIRQ_SOURCE_COMM 3
|
|
||||||
#define VBIRQ_SOURCE_VIP 4
|
|
||||||
|
|
||||||
void VBIRQ_Assert(int source, bool assert);
|
|
||||||
|
|
||||||
void VB_ExitLoop(void);
|
|
||||||
|
|
||||||
void ForceEventUpdates(const v810_timestamp_t timestamp);
|
|
||||||
|
|
||||||
uint8 MDFN_FASTCALL MemRead8(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
uint16 MDFN_FASTCALL MemRead16(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
|
|
||||||
void MDFN_FASTCALL MemWrite8(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
||||||
void MDFN_FASTCALL MemWrite16(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
|
||||||
}
|
|
1425
waterbox/vb/vip.cpp
1425
waterbox/vb/vip.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,83 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* vip.h:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace MDFN_IEN_VB
|
|
||||||
{
|
|
||||||
void VIP_Init(void) MDFN_COLD;
|
|
||||||
void VIP_Power(void) MDFN_COLD;
|
|
||||||
|
|
||||||
void VIP_SetInstantDisplayHack(bool) MDFN_COLD;
|
|
||||||
void VIP_SetAllowDrawSkip(bool) MDFN_COLD;
|
|
||||||
void VIP_Set3DMode(uint32 mode, bool reverse, uint32 prescale, uint32 sbs_separation) MDFN_COLD;
|
|
||||||
void VIP_SetParallaxDisable(bool disabled) MDFN_COLD;
|
|
||||||
void VIP_SetDefaultColor(uint32 default_color) MDFN_COLD;
|
|
||||||
void VIP_SetAnaglyphColors(uint32 lcolor, uint32 rcolor) MDFN_COLD; // R << 16, G << 8, B << 0
|
|
||||||
void VIP_SetLEDOnScale(float coeff) MDFN_COLD;
|
|
||||||
|
|
||||||
v810_timestamp_t MDFN_FASTCALL VIP_Update(const v810_timestamp_t timestamp);
|
|
||||||
void VIP_ResetTS(void);
|
|
||||||
|
|
||||||
void VIP_StartFrame(MyFrameInfo* frame);
|
|
||||||
void VIP_CalcFrameSize(MyFrameInfo* frame);
|
|
||||||
|
|
||||||
MDFN_FASTCALL uint8 VIP_Read8(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
MDFN_FASTCALL uint16 VIP_Read16(v810_timestamp_t ×tamp, uint32 A);
|
|
||||||
|
|
||||||
MDFN_FASTCALL void VIP_Write8(v810_timestamp_t ×tamp, uint32 A, uint8 V);
|
|
||||||
MDFN_FASTCALL void VIP_Write16(v810_timestamp_t ×tamp, uint32 A, uint16 V);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
VIP_GSREG_IPENDING = 0, // Current pending interrupt(bits)
|
|
||||||
VIP_GSREG_IENABLE,
|
|
||||||
|
|
||||||
VIP_GSREG_DPCTRL,
|
|
||||||
|
|
||||||
VIP_GSREG_BRTA,
|
|
||||||
VIP_GSREG_BRTB,
|
|
||||||
VIP_GSREG_BRTC,
|
|
||||||
VIP_GSREG_REST,
|
|
||||||
VIP_GSREG_FRMCYC,
|
|
||||||
VIP_GSREG_XPCTRL,
|
|
||||||
|
|
||||||
VIP_GSREG_SPT0,
|
|
||||||
VIP_GSREG_SPT1,
|
|
||||||
VIP_GSREG_SPT2,
|
|
||||||
VIP_GSREG_SPT3,
|
|
||||||
|
|
||||||
VIP_GSREG_GPLT0,
|
|
||||||
VIP_GSREG_GPLT1,
|
|
||||||
VIP_GSREG_GPLT2,
|
|
||||||
VIP_GSREG_GPLT3,
|
|
||||||
|
|
||||||
VIP_GSREG_JPLT0,
|
|
||||||
VIP_GSREG_JPLT1,
|
|
||||||
VIP_GSREG_JPLT2,
|
|
||||||
VIP_GSREG_JPLT3,
|
|
||||||
|
|
||||||
VIP_GSREG_BKCOL,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32 VIP_GetRegister(const unsigned int id, char *special, const uint32 special_len);
|
|
||||||
void VIP_SetRegister(const unsigned int id, const uint32 value);
|
|
||||||
}
|
|
|
@ -1,493 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* vip_draw.inc:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define BGM_AFFINE 0x2
|
|
||||||
#define BGM_OBJ 0x3
|
|
||||||
|
|
||||||
|
|
||||||
static void DrawBG(uint8 *target, uint16 RealY, bool lr, uint8 bgmap_base_raw, bool overplane, uint16 overplane_char, uint32 SourceX, uint32 SourceY, uint32 scx, uint32 scy, uint16 DestX, uint16 DestY, uint16 DestWidth, uint16 DestHeight)
|
|
||||||
{
|
|
||||||
const uint16 *CHR16 = CHR_RAM;
|
|
||||||
const uint16 *BGMap = DRAM;
|
|
||||||
uint32 BGMap_Base = bgmap_base_raw << 12;
|
|
||||||
int32 start_x, final_x;
|
|
||||||
const uint32 bgsc_overplane = DRAM[overplane_char];
|
|
||||||
const uint32 BGMap_XCount = 1 << scx;
|
|
||||||
const uint32 BGMap_YCount = 1 << scy;
|
|
||||||
const uint32 SourceX_Size = 512 * BGMap_XCount;
|
|
||||||
const uint32 SourceY_Size = 512 * BGMap_YCount;
|
|
||||||
const uint32 SourceX_Mask = overplane ? 0x1FFF : (SourceX_Size - 1);
|
|
||||||
const uint32 SourceY_Mask = overplane ? 0x1FFF : (SourceY_Size - 1);
|
|
||||||
|
|
||||||
if((uint16)(RealY - DestY) > DestHeight)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//printf("%d, %d, %d, %d\n", overplane, srcXSize, srcYSize, bgmap_base_raw);
|
|
||||||
|
|
||||||
DestX = sign_10_to_s16(DestX);
|
|
||||||
|
|
||||||
if(DestX & 0x8000)
|
|
||||||
SourceX -= DestX;
|
|
||||||
|
|
||||||
start_x = (int16)DestX;
|
|
||||||
final_x = (int16)DestX + DestWidth;
|
|
||||||
|
|
||||||
if(start_x < 0)
|
|
||||||
start_x = 0;
|
|
||||||
|
|
||||||
if(final_x > 383)
|
|
||||||
final_x = 383;
|
|
||||||
|
|
||||||
if(start_x > final_x)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Optimization:
|
|
||||||
SourceY &= SourceY_Mask;
|
|
||||||
BGMap_Base |= (((SourceY >> 3) & 0x3F) * 0x40) | (((SourceY << 3) & ~0xFFF) << scx);
|
|
||||||
|
|
||||||
for(int x = start_x; x <= final_x; x++)
|
|
||||||
{
|
|
||||||
uint32 bgsc;
|
|
||||||
uint32 char_no;
|
|
||||||
uint32 palette_selector;
|
|
||||||
uint32 hflip_xor;
|
|
||||||
uint32 vflip_xor;
|
|
||||||
|
|
||||||
SourceX &= SourceX_Mask;
|
|
||||||
|
|
||||||
bgsc = bgsc_overplane;
|
|
||||||
|
|
||||||
if(SourceX < SourceX_Size && SourceY < SourceY_Size)
|
|
||||||
bgsc = BGMap[(BGMap_Base | ((SourceX << 3) & ~0xFFF) | ((SourceX >> 3) & 0x3F)) & 0xFFFF];
|
|
||||||
|
|
||||||
char_no = bgsc & 0x7FF;
|
|
||||||
palette_selector = bgsc >> 14;
|
|
||||||
hflip_xor = (bgsc & 0x2000) ? 7 : 0; //(((int32)bgsc << 18) >> 31) & 0x7;
|
|
||||||
vflip_xor = (bgsc & 0x1000) ? 7 : 0; //(((int32)bgsc << 19) >> 31) & 0x7;
|
|
||||||
|
|
||||||
unsigned int char_sub_y = vflip_xor ^ (SourceY & 0x7);
|
|
||||||
|
|
||||||
if(!(SourceX & 7) && (x + 7) <= final_x)
|
|
||||||
{
|
|
||||||
uint32 pixels = CHR16[char_no * 8 + char_sub_y];
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
unsigned int char_sub_x;
|
|
||||||
uint8 *sub_target = target + x + 8;
|
|
||||||
|
|
||||||
for(int sub_x = -8; sub_x < 0; sub_x++)
|
|
||||||
{
|
|
||||||
if(pixels & 3) sub_target[sub_x] = GPLT_Cache[palette_selector][pixels & 3];
|
|
||||||
pixels >>= 2;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(bgsc & 0x2000)
|
|
||||||
{
|
|
||||||
if((pixels >> 14) & 3) target[0 + x] = GPLT_Cache[palette_selector][(pixels >> 14) & 3];
|
|
||||||
if((pixels >> 12) & 3) target[1 + x] = GPLT_Cache[palette_selector][(pixels >> 12) & 3];
|
|
||||||
if((pixels >> 10) & 3) target[2 + x] = GPLT_Cache[palette_selector][(pixels >> 10) & 3];
|
|
||||||
if((pixels >> 8) & 3) target[3 + x] = GPLT_Cache[palette_selector][(pixels >> 8) & 3];
|
|
||||||
if((pixels >> 6) & 3) target[4 + x] = GPLT_Cache[palette_selector][(pixels >> 6) & 3];
|
|
||||||
if((pixels >> 4) & 3) target[5 + x] = GPLT_Cache[palette_selector][(pixels >> 4) & 3];
|
|
||||||
if((pixels >> 2) & 3) target[6 + x] = GPLT_Cache[palette_selector][(pixels >> 2) & 3];
|
|
||||||
if((pixels >> 0) & 3) target[7 + x] = GPLT_Cache[palette_selector][(pixels >> 0) & 3];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if((pixels >> 0) & 3) target[0 + x] = GPLT_Cache[palette_selector][(pixels >> 0) & 3];
|
|
||||||
if((pixels >> 2) & 3) target[1 + x] = GPLT_Cache[palette_selector][(pixels >> 2) & 3];
|
|
||||||
if((pixels >> 4) & 3) target[2 + x] = GPLT_Cache[palette_selector][(pixels >> 4) & 3];
|
|
||||||
if((pixels >> 6) & 3) target[3 + x] = GPLT_Cache[palette_selector][(pixels >> 6) & 3];
|
|
||||||
if((pixels >> 8) & 3) target[4 + x] = GPLT_Cache[palette_selector][(pixels >> 8) & 3];
|
|
||||||
if((pixels >> 10) & 3) target[5 + x] = GPLT_Cache[palette_selector][(pixels >> 10) & 3];
|
|
||||||
if((pixels >> 12) & 3) target[6 + x] = GPLT_Cache[palette_selector][(pixels >> 12) & 3];
|
|
||||||
if((pixels >> 14) & 3) target[7 + x] = GPLT_Cache[palette_selector][(pixels >> 14) & 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
x += 7;
|
|
||||||
SourceX += 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned int char_sub_x;
|
|
||||||
|
|
||||||
char_sub_x = hflip_xor ^ (SourceX & 0x7);
|
|
||||||
|
|
||||||
uint8 pixel = (CHR16[char_no * 8 + char_sub_y] >> (char_sub_x * 2)) & 0x3;
|
|
||||||
|
|
||||||
if(pixel)
|
|
||||||
target[x] = GPLT_Cache[palette_selector][pixel]; //target[x] = (GPLT[palette_selector] >> (pixel * 2)) & 0x3;
|
|
||||||
SourceX++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DrawAffine(uint8 *target, uint16 RealY, bool lr, uint32 ParamBase, uint32 BGMap_Base, bool OverplaneMode, uint16 OverplaneChar, uint32 scx, uint32 scy,
|
|
||||||
uint16 DestX, uint16 DestY, uint16 DestWidth, uint16 DestHeight)
|
|
||||||
{
|
|
||||||
const uint16 *CHR16 = CHR_RAM;
|
|
||||||
const uint16 *BGMap = DRAM;
|
|
||||||
|
|
||||||
const uint32 BGMap_XCount = 1 << scx;
|
|
||||||
const uint32 BGMap_YCount = 1 << scy;
|
|
||||||
const uint32 SourceX_Size = 512 * BGMap_XCount;
|
|
||||||
const uint32 SourceY_Size = 512 * BGMap_YCount;
|
|
||||||
|
|
||||||
const uint16 *param_ptr = &DRAM[(ParamBase + 8 * (RealY - DestY)) & 0xFFFF];
|
|
||||||
int16 mx = param_ptr[0], mp = (ParallaxDisabled ? 0 : param_ptr[1]), my = param_ptr[2], dx = param_ptr[3], dy = param_ptr[4];
|
|
||||||
|
|
||||||
uint32 SourceX, SourceY;
|
|
||||||
uint32 SourceX_Mask, SourceY_Mask;
|
|
||||||
|
|
||||||
int32 start_x, final_x;
|
|
||||||
const uint32 bgsc_overplane = DRAM[OverplaneChar];
|
|
||||||
|
|
||||||
|
|
||||||
DestX = sign_10_to_s16(DestX);
|
|
||||||
|
|
||||||
if((uint16)(RealY - DestY) > DestHeight)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SourceX = (int32)mx << 6;
|
|
||||||
SourceY = (int32)my << 6;
|
|
||||||
|
|
||||||
if(DestX & 0x8000)
|
|
||||||
{
|
|
||||||
SourceX += dx * (65536 - DestX);
|
|
||||||
SourceY += dy * (65536 - DestX);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mp >= 0 && lr)
|
|
||||||
{
|
|
||||||
SourceX += dx * mp;
|
|
||||||
SourceY += dy * mp;
|
|
||||||
}
|
|
||||||
else if(mp < 0 && !lr)
|
|
||||||
{
|
|
||||||
SourceX += dx * -mp;
|
|
||||||
SourceY += dy * -mp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(OverplaneMode)
|
|
||||||
{
|
|
||||||
SourceX_Mask = 0x3FFFFFF; //(((uint32)SourceX_Size << 9) * 2) - 1;
|
|
||||||
SourceY_Mask = 0x3FFFFFF; //(((uint32)SourceY_Size << 9) * 2) - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SourceX_Mask = ((uint32)SourceX_Size << 9) - 1;
|
|
||||||
SourceY_Mask = ((uint32)SourceY_Size << 9) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
start_x = (int16)DestX;
|
|
||||||
final_x = (int16)DestX + DestWidth;
|
|
||||||
|
|
||||||
if(start_x < 0)
|
|
||||||
start_x = 0;
|
|
||||||
|
|
||||||
if(final_x > 383)
|
|
||||||
final_x = 383;
|
|
||||||
|
|
||||||
if(dy == 0) // Optimization for no rotation.
|
|
||||||
{
|
|
||||||
SourceY &= SourceY_Mask;
|
|
||||||
|
|
||||||
if(SourceY >= (SourceY_Size << 9))
|
|
||||||
return;
|
|
||||||
|
|
||||||
BGMap_Base |= (((SourceY >> 6) & ~0xFFF) << scx) | (((SourceY >> 12) & 0x3F) * 0x40);
|
|
||||||
for(int x = start_x; x <= final_x; x++)
|
|
||||||
{
|
|
||||||
uint32 bgsc;
|
|
||||||
uint32 hflip_xor;
|
|
||||||
uint32 vflip_xor;
|
|
||||||
uint32 pixel = 0;
|
|
||||||
|
|
||||||
SourceX &= SourceX_Mask;
|
|
||||||
|
|
||||||
bgsc = bgsc_overplane;
|
|
||||||
|
|
||||||
if(SourceX < (SourceX_Size << 9))
|
|
||||||
bgsc = BGMap[(BGMap_Base | ((SourceX >> 6) & ~0xFFF) | ((SourceX >> 12) & 0x3F)) & 0xFFFF];
|
|
||||||
|
|
||||||
//hflip_xor = bgsc & 0x2000 ? 0xE : 0;
|
|
||||||
//vflip_xor = bgsc & 0x1000 ? 0x7 : 0;
|
|
||||||
hflip_xor = ((int32)(bgsc << 18) >> 30) & 0xE;
|
|
||||||
vflip_xor = ((int32)(bgsc << 19) >> 31) & 0x7;
|
|
||||||
|
|
||||||
unsigned int char_sub_y = vflip_xor ^ ((SourceY >> 9) & 0x7);
|
|
||||||
unsigned int char_sub_x = hflip_xor ^ ((SourceX >> 8) & 0xE);
|
|
||||||
|
|
||||||
pixel = (CHR16[((bgsc & 0x7FF) * 8) | char_sub_y] >> char_sub_x) & 0x3;
|
|
||||||
|
|
||||||
if(pixel)
|
|
||||||
target[x] = GPLT_Cache[bgsc >> 14][pixel];
|
|
||||||
|
|
||||||
SourceX += dx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
for(int x = start_x; x <= final_x; x++)
|
|
||||||
{
|
|
||||||
uint32 bgsc;
|
|
||||||
uint32 char_no;
|
|
||||||
uint32 palette_selector;
|
|
||||||
uint32 hflip_xor;
|
|
||||||
uint32 vflip_xor;
|
|
||||||
uint8 pixel = 0;
|
|
||||||
|
|
||||||
SourceX &= SourceX_Mask;
|
|
||||||
SourceY &= SourceY_Mask;
|
|
||||||
|
|
||||||
bgsc = bgsc_overplane;
|
|
||||||
|
|
||||||
if(SourceX < (SourceX_Size << 9) && SourceY < (SourceY_Size << 9))
|
|
||||||
{
|
|
||||||
uint32 m_index = ((SourceX >> 6) & ~0xFFF) + (((SourceY >> 6) & ~0xFFF) << scx);
|
|
||||||
uint32 sub_index = ((SourceX >> 12) & 0x3F) + (((SourceY >> 12) & 0x3F) * 0x40);
|
|
||||||
|
|
||||||
bgsc = BGMap[(BGMap_Base | m_index | sub_index) & 0xFFFF];
|
|
||||||
|
|
||||||
//bgsc = BGMap[(BGMapBase + (SourceX >> 12) + (SourceY >> 12) * (SourceX_Size >> 3)) & 0xFFFF ];
|
|
||||||
}
|
|
||||||
char_no = bgsc & 0x7FF;
|
|
||||||
palette_selector = bgsc >> 14;
|
|
||||||
hflip_xor = bgsc & 0x2000 ? 7 : 0; //(((int32)bgsc << 18) >> 31) & 0x7;
|
|
||||||
vflip_xor = bgsc & 0x1000 ? 7 : 0; //(((int32)bgsc << 19) >> 31) & 0x7;
|
|
||||||
|
|
||||||
unsigned int char_sub_y = vflip_xor ^ ((SourceY >> 9) & 0x7);
|
|
||||||
unsigned int char_sub_x = hflip_xor ^ ((SourceX >> 9) & 0x7);
|
|
||||||
|
|
||||||
pixel = (CHR16[char_no * 8 + char_sub_y] >> (char_sub_x * 2)) & 0x3;
|
|
||||||
|
|
||||||
if(pixel)
|
|
||||||
target[x] = GPLT_Cache[palette_selector][pixel];
|
|
||||||
|
|
||||||
SourceX += dx;
|
|
||||||
SourceY += dy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int obj_search_which;
|
|
||||||
|
|
||||||
static void DrawOBJ(uint8 *fb[2], uint16 Y, bool lron[2])
|
|
||||||
{
|
|
||||||
const uint16 *CHR16 = CHR_RAM;
|
|
||||||
|
|
||||||
int32 start_oam;
|
|
||||||
int32 end_oam;
|
|
||||||
|
|
||||||
start_oam = SPT[obj_search_which];
|
|
||||||
|
|
||||||
end_oam = 1023;
|
|
||||||
if(obj_search_which)
|
|
||||||
end_oam = SPT[obj_search_which - 1];
|
|
||||||
|
|
||||||
int32 oam = start_oam;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const uint16 *oam_ptr = &DRAM[(0x1E000 + (oam * 8)) >> 1];
|
|
||||||
const uint32 jy = oam_ptr[2];
|
|
||||||
const uint32 tile_y = (Y - jy) & 0xFF; // I think this mask is right. See: http://www.planetvb.com/modules/newbb/viewtopic.php?topic_id=3797&forum=2
|
|
||||||
|
|
||||||
if(tile_y >= 8)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint32 jx = oam_ptr[0];
|
|
||||||
uint32 jp = ParallaxDisabled ? 0 : (oam_ptr[1] & 0x3FFF);
|
|
||||||
uint32 palette_selector = oam_ptr[3] >> 14;
|
|
||||||
uint32 vflip_xor = (oam_ptr[3] & 0x1000) ? 7 : 0;
|
|
||||||
uint32 char_sub_y = vflip_xor ^ tile_y;
|
|
||||||
bool jlron[2] = { (bool)(oam_ptr[1] & 0x8000), (bool)(oam_ptr[1] & 0x4000) };
|
|
||||||
uint32 char_no = oam_ptr[3] & 0x7FF;
|
|
||||||
const uint32 pixels_save = CHR16[char_no * 8 + char_sub_y];
|
|
||||||
|
|
||||||
for(int lr = 0; lr < 2; lr++)
|
|
||||||
{
|
|
||||||
if(!(jlron[lr] & lron[lr]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint32 pixels = pixels_save;
|
|
||||||
int32 x = sign_x_to_s32(10, (jx + (lr ? jp : -jp))); // It may actually be 9, TODO?
|
|
||||||
|
|
||||||
if(x >= -7 && x < 384) // Make sure we always keep the pitch of our 384x8 buffer large enough(with padding before and after the visible space)
|
|
||||||
{
|
|
||||||
uint8 *target = &fb[lr][x];
|
|
||||||
|
|
||||||
if(oam_ptr[3] & 0x2000)
|
|
||||||
{
|
|
||||||
target += 7;
|
|
||||||
|
|
||||||
for(int meow = 8; meow; meow--)
|
|
||||||
{
|
|
||||||
if(pixels & 3)
|
|
||||||
*target = JPLT_Cache[palette_selector][pixels & 3];
|
|
||||||
target--;
|
|
||||||
pixels >>= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(int meow = 8; meow; meow--)
|
|
||||||
{
|
|
||||||
if(pixels & 3)
|
|
||||||
*target = JPLT_Cache[palette_selector][pixels & 3];
|
|
||||||
target++;
|
|
||||||
pixels >>= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
if(oam_ptr[3] & 0x2000)
|
|
||||||
{
|
|
||||||
if((pixels >> 14) & 3) fb[lr][0 + x] = JPLT_Cache[palette_selector][(pixels >> 14) & 3];
|
|
||||||
if((pixels >> 12) & 3) fb[lr][1 + x] = JPLT_Cache[palette_selector][(pixels >> 12) & 3];
|
|
||||||
if((pixels >> 10) & 3) fb[lr][2 + x] = JPLT_Cache[palette_selector][(pixels >> 10) & 3];
|
|
||||||
if((pixels >> 8) & 3) fb[lr][3 + x] = JPLT_Cache[palette_selector][(pixels >> 8) & 3];
|
|
||||||
if((pixels >> 6) & 3) fb[lr][4 + x] = JPLT_Cache[palette_selector][(pixels >> 6) & 3];
|
|
||||||
if((pixels >> 4) & 3) fb[lr][5 + x] = JPLT_Cache[palette_selector][(pixels >> 4) & 3];
|
|
||||||
if((pixels >> 2) & 3) fb[lr][6 + x] = JPLT_Cache[palette_selector][(pixels >> 2) & 3];
|
|
||||||
if((pixels >> 0) & 3) fb[lr][7 + x] = JPLT_Cache[palette_selector][(pixels >> 0) & 3];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if((pixels >> 0) & 3) fb[lr][0 + x] = JPLT_Cache[palette_selector][(pixels >> 0) & 3];
|
|
||||||
if((pixels >> 2) & 3) fb[lr][1 + x] = JPLT_Cache[palette_selector][(pixels >> 2) & 3];
|
|
||||||
if((pixels >> 4) & 3) fb[lr][2 + x] = JPLT_Cache[palette_selector][(pixels >> 4) & 3];
|
|
||||||
if((pixels >> 6) & 3) fb[lr][3 + x] = JPLT_Cache[palette_selector][(pixels >> 6) & 3];
|
|
||||||
if((pixels >> 8) & 3) fb[lr][4 + x] = JPLT_Cache[palette_selector][(pixels >> 8) & 3];
|
|
||||||
if((pixels >> 10) & 3) fb[lr][5 + x] = JPLT_Cache[palette_selector][(pixels >> 10) & 3];
|
|
||||||
if((pixels >> 12) & 3) fb[lr][6 + x] = JPLT_Cache[palette_selector][(pixels >> 12) & 3];
|
|
||||||
if((pixels >> 14) & 3) fb[lr][7 + x] = JPLT_Cache[palette_selector][(pixels >> 14) & 3];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} while( (oam = (oam - 1) & 1023) != end_oam);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void VIP_DrawBlock(uint8 block_no, uint8 *fb_l, uint8 *fb_r)
|
|
||||||
{
|
|
||||||
for(int y = 0; y < 8; y++)
|
|
||||||
{
|
|
||||||
memset(fb_l + y * 512, BKCOL, 384);
|
|
||||||
memset(fb_r + y * 512, BKCOL, 384);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj_search_which = 3;
|
|
||||||
|
|
||||||
for(int world = 31; world >= 0; world--)
|
|
||||||
{
|
|
||||||
const uint16 *world_ptr = &DRAM[(0x1D800 + world * 0x20) >> 1];
|
|
||||||
|
|
||||||
uint32 bgmap_base = world_ptr[0] & 0xF;
|
|
||||||
bool end = world_ptr[0] & 0x40;
|
|
||||||
bool over = world_ptr[0] & 0x80;
|
|
||||||
uint32 scy = (world_ptr[0] >> 8) & 3;
|
|
||||||
uint32 scx = (world_ptr[0] >> 10) & 3;
|
|
||||||
uint32 bgm = (world_ptr[0] >> 12) & 3;
|
|
||||||
bool lron[2] = { (bool)(world_ptr[0] & 0x8000), (bool)(world_ptr[0] & 0x4000) };
|
|
||||||
|
|
||||||
uint16 gx = sign_11_to_s16(world_ptr[1]);
|
|
||||||
uint16 gp = ParallaxDisabled ? 0 : sign_9_to_s16(world_ptr[2]);
|
|
||||||
uint16 gy = sign_11_to_s16(world_ptr[3]);
|
|
||||||
uint16 mx = world_ptr[4];
|
|
||||||
uint16 mp = ParallaxDisabled ? 0 : sign_9_to_s16(world_ptr[5]);
|
|
||||||
uint16 my = world_ptr[6];
|
|
||||||
uint16 window_width = sign_11_to_s16(world_ptr[7]);
|
|
||||||
uint16 window_height = (world_ptr[8] & 0x3FF);
|
|
||||||
uint32 param_base = (world_ptr[9] & 0xFFF0);
|
|
||||||
uint16 overplane_char = world_ptr[10];
|
|
||||||
|
|
||||||
if(end)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(((512 << scx) + (512 << scy)) > 4096)
|
|
||||||
{
|
|
||||||
printf("BG Size too large for world: %d(scx=%d, scy=%d)\n", world, scx, scy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if(world != 2)
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
// if(block_no == 8)
|
|
||||||
// printf("World: %d; gx: %d, gp: %d, gy: %d, mx: %d, mp: %d, my: %d, window_width: %d, window_height: %d\n", world, gx, gp, gy, mx, mp, my, window_width, window_height);
|
|
||||||
|
|
||||||
for(int y = 0; y < 8; y++)
|
|
||||||
{
|
|
||||||
uint8 *fb[2] = { &fb_l[y * 512], &fb_r[y * 512] };
|
|
||||||
|
|
||||||
if(bgm == BGM_OBJ)
|
|
||||||
{
|
|
||||||
if(!lron[0] || !lron[1])
|
|
||||||
printf("Bad OBJ World? %d(%d/%d) %d~%d\n", world, lron[0], lron[1], SPT[obj_search_which], obj_search_which ? (SPT[obj_search_which - 1] + 1) : 0);
|
|
||||||
|
|
||||||
DrawOBJ(fb, (block_no * 8) + y, lron);
|
|
||||||
}
|
|
||||||
else if(bgm == BGM_AFFINE)
|
|
||||||
{
|
|
||||||
//if(((block_no * 8) + y) == 128)
|
|
||||||
// printf("Draw affine: %d %d\n", gx, gp);
|
|
||||||
for(int lr = 0; lr < 2; lr++)
|
|
||||||
{
|
|
||||||
if(lron[lr])
|
|
||||||
{
|
|
||||||
DrawAffine(fb[lr], (block_no * 8) + y, lr, param_base, bgmap_base * 4096, over, overplane_char, scx, scy,
|
|
||||||
gx + (lr ? gp : -gp), gy, window_width, window_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
for(int lr = 0; lr < 2; lr++)
|
|
||||||
{
|
|
||||||
uint16 srcX, srcY;
|
|
||||||
uint16 RealY = (block_no * 8) + y;
|
|
||||||
uint16 DestX;
|
|
||||||
uint16 DestY;
|
|
||||||
|
|
||||||
srcX = mx + (lr ? mp : -mp);
|
|
||||||
srcY = my + (RealY - gy);
|
|
||||||
|
|
||||||
DestX = gx + (lr ? gp : -gp);
|
|
||||||
DestY = gy;
|
|
||||||
|
|
||||||
if(lron[lr])
|
|
||||||
{
|
|
||||||
if(bgm == 1) // HBias
|
|
||||||
srcX += (int16)DRAM[(param_base + (((RealY - DestY) * 2) | lr)) & 0xFFFF];
|
|
||||||
|
|
||||||
DrawBG(fb[lr], RealY, lr, bgmap_base, over, overplane_char, (int32)(int16)srcX, (int32)(int16)srcY, scx, scy, DestX, DestY, window_width, window_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bgm == BGM_OBJ)
|
|
||||||
if(obj_search_which)
|
|
||||||
obj_search_which--;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,507 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* vsu.cpp:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "vb.h"
|
|
||||||
|
|
||||||
static const unsigned int Tap_LUT[8] = {15 - 1, 11 - 1, 14 - 1, 5 - 1, 9 - 1, 7 - 1, 10 - 1, 12 - 1};
|
|
||||||
|
|
||||||
VSU::VSU()
|
|
||||||
{
|
|
||||||
Synth.volume(1.0 / 6 / 2);
|
|
||||||
|
|
||||||
for (int ch = 0; ch < 6; ch++)
|
|
||||||
{
|
|
||||||
for (int lr = 0; lr < 2; lr++)
|
|
||||||
last_output[ch][lr] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VSU::~VSU()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSU::SetSoundRate(double rate)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < 2; y++)
|
|
||||||
{
|
|
||||||
sbuf[y].set_sample_rate(rate ? rate : 44100, 50);
|
|
||||||
sbuf[y].clock_rate((long)(VB_MASTER_CLOCK / 4));
|
|
||||||
sbuf[y].bass_freq(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSU::Power(void)
|
|
||||||
{
|
|
||||||
SweepControl = 0;
|
|
||||||
SweepModCounter = 0;
|
|
||||||
SweepModClockDivider = 1;
|
|
||||||
|
|
||||||
for (int ch = 0; ch < 6; ch++)
|
|
||||||
{
|
|
||||||
IntlControl[ch] = 0;
|
|
||||||
LeftLevel[ch] = 0;
|
|
||||||
RightLevel[ch] = 0;
|
|
||||||
Frequency[ch] = 0;
|
|
||||||
EnvControl[ch] = 0;
|
|
||||||
RAMAddress[ch] = 0;
|
|
||||||
|
|
||||||
EffFreq[ch] = 0;
|
|
||||||
Envelope[ch] = 0;
|
|
||||||
WavePos[ch] = 0;
|
|
||||||
FreqCounter[ch] = 1;
|
|
||||||
IntervalCounter[ch] = 0;
|
|
||||||
EnvelopeCounter[ch] = 1;
|
|
||||||
|
|
||||||
EffectsClockDivider[ch] = 4800;
|
|
||||||
IntervalClockDivider[ch] = 4;
|
|
||||||
EnvelopeClockDivider[ch] = 4;
|
|
||||||
|
|
||||||
LatcherClockDivider[ch] = 120;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModWavePos = 0;
|
|
||||||
|
|
||||||
NoiseLatcherClockDivider = 120;
|
|
||||||
NoiseLatcher = 0;
|
|
||||||
|
|
||||||
lfsr = 0;
|
|
||||||
|
|
||||||
memset(WaveData, 0, sizeof(WaveData));
|
|
||||||
memset(ModData, 0, sizeof(ModData));
|
|
||||||
|
|
||||||
last_ts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSU::Write(int32 timestamp, uint32 A, uint8 V)
|
|
||||||
{
|
|
||||||
if(A & 0x3)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
A &= 0x7FF;
|
|
||||||
|
|
||||||
Update(timestamp);
|
|
||||||
|
|
||||||
//printf("VSU Write: %d, %08x %02x\n", timestamp, A, V);
|
|
||||||
|
|
||||||
if (A < 0x280)
|
|
||||||
WaveData[A >> 7][(A >> 2) & 0x1F] = V & 0x3F;
|
|
||||||
else if (A < 0x400)
|
|
||||||
{
|
|
||||||
//if(A >= 0x300)
|
|
||||||
// printf("Modulation mirror write? %08x %02x\n", A, V);
|
|
||||||
ModData[(A >> 2) & 0x1F] = V;
|
|
||||||
}
|
|
||||||
else if (A < 0x600)
|
|
||||||
{
|
|
||||||
int ch = (A >> 6) & 0xF;
|
|
||||||
|
|
||||||
//if(ch < 6)
|
|
||||||
//printf("Ch: %d, Reg: %d, Value: %02x\n", ch, (A >> 2) & 0xF, V);
|
|
||||||
|
|
||||||
if (ch > 5)
|
|
||||||
{
|
|
||||||
if (A == 0x580 && (V & 1))
|
|
||||||
{
|
|
||||||
//puts("STOP, HAMMER TIME");
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
IntlControl[i] &= ~0x80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
switch ((A >> 2) & 0xF)
|
|
||||||
{
|
|
||||||
case 0x0:
|
|
||||||
IntlControl[ch] = V & ~0x40;
|
|
||||||
|
|
||||||
if (V & 0x80)
|
|
||||||
{
|
|
||||||
EffFreq[ch] = Frequency[ch];
|
|
||||||
if (ch == 5)
|
|
||||||
FreqCounter[ch] = 10 * (2048 - EffFreq[ch]);
|
|
||||||
else
|
|
||||||
FreqCounter[ch] = 2048 - EffFreq[ch];
|
|
||||||
IntervalCounter[ch] = (V & 0x1F) + 1;
|
|
||||||
EnvelopeCounter[ch] = (EnvControl[ch] & 0x7) + 1;
|
|
||||||
|
|
||||||
if (ch == 4)
|
|
||||||
{
|
|
||||||
SweepModCounter = (SweepControl >> 4) & 7;
|
|
||||||
SweepModClockDivider = (SweepControl & 0x80) ? 8 : 1;
|
|
||||||
ModWavePos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
WavePos[ch] = 0;
|
|
||||||
|
|
||||||
if (ch == 5) // Not sure if this is correct.
|
|
||||||
lfsr = 1;
|
|
||||||
|
|
||||||
//if(!(IntlControl[ch] & 0x80))
|
|
||||||
// Envelope[ch] = (EnvControl[ch] >> 4) & 0xF;
|
|
||||||
|
|
||||||
EffectsClockDivider[ch] = 4800;
|
|
||||||
IntervalClockDivider[ch] = 4;
|
|
||||||
EnvelopeClockDivider[ch] = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x1:
|
|
||||||
LeftLevel[ch] = (V >> 4) & 0xF;
|
|
||||||
RightLevel[ch] = (V >> 0) & 0xF;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x2:
|
|
||||||
Frequency[ch] &= 0xFF00;
|
|
||||||
Frequency[ch] |= V << 0;
|
|
||||||
EffFreq[ch] &= 0xFF00;
|
|
||||||
EffFreq[ch] |= V << 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x3:
|
|
||||||
Frequency[ch] &= 0x00FF;
|
|
||||||
Frequency[ch] |= (V & 0x7) << 8;
|
|
||||||
EffFreq[ch] &= 0x00FF;
|
|
||||||
EffFreq[ch] |= (V & 0x7) << 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x4:
|
|
||||||
EnvControl[ch] &= 0xFF00;
|
|
||||||
EnvControl[ch] |= V << 0;
|
|
||||||
|
|
||||||
Envelope[ch] = (V >> 4) & 0xF;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x5:
|
|
||||||
EnvControl[ch] &= 0x00FF;
|
|
||||||
if (ch == 4)
|
|
||||||
EnvControl[ch] |= (V & 0x73) << 8;
|
|
||||||
else if (ch == 5)
|
|
||||||
{
|
|
||||||
EnvControl[ch] |= (V & 0x73) << 8;
|
|
||||||
lfsr = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
EnvControl[ch] |= (V & 0x03) << 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x6:
|
|
||||||
RAMAddress[ch] = V & 0xF;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x7:
|
|
||||||
if (ch == 4)
|
|
||||||
{
|
|
||||||
SweepControl = V;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE void VSU::CalcCurrentOutput(int ch, int &left, int &right)
|
|
||||||
{
|
|
||||||
if (!(IntlControl[ch] & 0x80))
|
|
||||||
{
|
|
||||||
left = right = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int WD;
|
|
||||||
int l_ol, r_ol;
|
|
||||||
|
|
||||||
if (ch == 5)
|
|
||||||
WD = NoiseLatcher; //(NoiseLatcher << 6) - NoiseLatcher;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (RAMAddress[ch] > 4)
|
|
||||||
WD = 0;
|
|
||||||
else
|
|
||||||
WD = WaveData[RAMAddress[ch]][WavePos[ch]]; // - 0x20;
|
|
||||||
}
|
|
||||||
l_ol = Envelope[ch] * LeftLevel[ch];
|
|
||||||
if (l_ol)
|
|
||||||
{
|
|
||||||
l_ol >>= 3;
|
|
||||||
l_ol += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
r_ol = Envelope[ch] * RightLevel[ch];
|
|
||||||
if (r_ol)
|
|
||||||
{
|
|
||||||
r_ol >>= 3;
|
|
||||||
r_ol += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
left = WD * l_ol;
|
|
||||||
right = WD * r_ol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSU::Update(int32 timestamp)
|
|
||||||
{
|
|
||||||
//puts("VSU Start");
|
|
||||||
int left, right;
|
|
||||||
|
|
||||||
for (int ch = 0; ch < 6; ch++)
|
|
||||||
{
|
|
||||||
int32 clocks = timestamp - last_ts;
|
|
||||||
int32 running_timestamp = last_ts;
|
|
||||||
|
|
||||||
// Output sound here
|
|
||||||
CalcCurrentOutput(ch, left, right);
|
|
||||||
Synth.offset_inline(running_timestamp, left - last_output[ch][0], &sbuf[0]);
|
|
||||||
Synth.offset_inline(running_timestamp, right - last_output[ch][1], &sbuf[1]);
|
|
||||||
last_output[ch][0] = left;
|
|
||||||
last_output[ch][1] = right;
|
|
||||||
|
|
||||||
if (!(IntlControl[ch] & 0x80))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
while (clocks > 0)
|
|
||||||
{
|
|
||||||
int32 chunk_clocks = clocks;
|
|
||||||
|
|
||||||
if (chunk_clocks > EffectsClockDivider[ch])
|
|
||||||
chunk_clocks = EffectsClockDivider[ch];
|
|
||||||
|
|
||||||
if (ch == 5)
|
|
||||||
{
|
|
||||||
if (chunk_clocks > NoiseLatcherClockDivider)
|
|
||||||
chunk_clocks = NoiseLatcherClockDivider;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (EffFreq[ch] >= 2040)
|
|
||||||
{
|
|
||||||
if (chunk_clocks > LatcherClockDivider[ch])
|
|
||||||
chunk_clocks = LatcherClockDivider[ch];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (chunk_clocks > FreqCounter[ch])
|
|
||||||
chunk_clocks = FreqCounter[ch];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == 5 && chunk_clocks > NoiseLatcherClockDivider)
|
|
||||||
chunk_clocks = NoiseLatcherClockDivider;
|
|
||||||
|
|
||||||
FreqCounter[ch] -= chunk_clocks;
|
|
||||||
while (FreqCounter[ch] <= 0)
|
|
||||||
{
|
|
||||||
if (ch == 5)
|
|
||||||
{
|
|
||||||
int feedback = ((lfsr >> 7) & 1) ^ ((lfsr >> Tap_LUT[(EnvControl[5] >> 12) & 0x7]) & 1) ^ 1;
|
|
||||||
lfsr = ((lfsr << 1) & 0x7FFF) | feedback;
|
|
||||||
|
|
||||||
FreqCounter[ch] += 10 * (2048 - EffFreq[ch]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FreqCounter[ch] += 2048 - EffFreq[ch];
|
|
||||||
WavePos[ch] = (WavePos[ch] + 1) & 0x1F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LatcherClockDivider[ch] -= chunk_clocks;
|
|
||||||
while (LatcherClockDivider[ch] <= 0)
|
|
||||||
LatcherClockDivider[ch] += 120;
|
|
||||||
|
|
||||||
if (ch == 5)
|
|
||||||
{
|
|
||||||
NoiseLatcherClockDivider -= chunk_clocks;
|
|
||||||
if (!NoiseLatcherClockDivider)
|
|
||||||
{
|
|
||||||
NoiseLatcherClockDivider = 120;
|
|
||||||
NoiseLatcher = ((lfsr & 1) << 6) - (lfsr & 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EffectsClockDivider[ch] -= chunk_clocks;
|
|
||||||
while (EffectsClockDivider[ch] <= 0)
|
|
||||||
{
|
|
||||||
EffectsClockDivider[ch] += 4800;
|
|
||||||
|
|
||||||
IntervalClockDivider[ch]--;
|
|
||||||
while (IntervalClockDivider[ch] <= 0)
|
|
||||||
{
|
|
||||||
IntervalClockDivider[ch] += 4;
|
|
||||||
|
|
||||||
if (IntlControl[ch] & 0x20)
|
|
||||||
{
|
|
||||||
IntervalCounter[ch]--;
|
|
||||||
if (!IntervalCounter[ch])
|
|
||||||
{
|
|
||||||
IntlControl[ch] &= ~0x80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EnvelopeClockDivider[ch]--;
|
|
||||||
while (EnvelopeClockDivider[ch] <= 0)
|
|
||||||
{
|
|
||||||
EnvelopeClockDivider[ch] += 4;
|
|
||||||
|
|
||||||
if (EnvControl[ch] & 0x0100) // Enveloping enabled?
|
|
||||||
{
|
|
||||||
EnvelopeCounter[ch]--;
|
|
||||||
if (!EnvelopeCounter[ch])
|
|
||||||
{
|
|
||||||
EnvelopeCounter[ch] = (EnvControl[ch] & 0x7) + 1;
|
|
||||||
|
|
||||||
if (EnvControl[ch] & 0x0008) // Grow
|
|
||||||
{
|
|
||||||
if (Envelope[ch] < 0xF || (EnvControl[ch] & 0x200))
|
|
||||||
Envelope[ch] = (Envelope[ch] + 1) & 0xF;
|
|
||||||
}
|
|
||||||
else // Decay
|
|
||||||
{
|
|
||||||
if (Envelope[ch] > 0 || (EnvControl[ch] & 0x200))
|
|
||||||
Envelope[ch] = (Envelope[ch] - 1) & 0xF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end while(EnvelopeClockDivider[ch] <= 0)
|
|
||||||
} // end while(IntervalClockDivider[ch] <= 0)
|
|
||||||
|
|
||||||
if (ch == 4)
|
|
||||||
{
|
|
||||||
SweepModClockDivider--;
|
|
||||||
while (SweepModClockDivider <= 0)
|
|
||||||
{
|
|
||||||
SweepModClockDivider += (SweepControl & 0x80) ? 8 : 1;
|
|
||||||
|
|
||||||
if (((SweepControl >> 4) & 0x7) && (EnvControl[ch] & 0x4000))
|
|
||||||
{
|
|
||||||
if (SweepModCounter)
|
|
||||||
SweepModCounter--;
|
|
||||||
|
|
||||||
if (!SweepModCounter)
|
|
||||||
{
|
|
||||||
SweepModCounter = (SweepControl >> 4) & 0x7;
|
|
||||||
|
|
||||||
if (EnvControl[ch] & 0x1000) // Modulation
|
|
||||||
{
|
|
||||||
if (ModWavePos < 32 || (EnvControl[ch] & 0x2000))
|
|
||||||
{
|
|
||||||
ModWavePos &= 0x1F;
|
|
||||||
|
|
||||||
EffFreq[ch] = (EffFreq[ch] + (int8)ModData[ModWavePos]);
|
|
||||||
if (EffFreq[ch] < 0)
|
|
||||||
{
|
|
||||||
//puts("Underflow");
|
|
||||||
EffFreq[ch] = 0;
|
|
||||||
}
|
|
||||||
else if (EffFreq[ch] > 0x7FF)
|
|
||||||
{
|
|
||||||
//puts("Overflow");
|
|
||||||
EffFreq[ch] = 0x7FF;
|
|
||||||
}
|
|
||||||
ModWavePos++;
|
|
||||||
}
|
|
||||||
//puts("Mod");
|
|
||||||
}
|
|
||||||
else // Sweep
|
|
||||||
{
|
|
||||||
int32 delta = EffFreq[ch] >> (SweepControl & 0x7);
|
|
||||||
int32 NewFreq = EffFreq[ch] + ((SweepControl & 0x8) ? delta : -delta);
|
|
||||||
|
|
||||||
//printf("Sweep(%d): Old: %d, New: %d\n", ch, EffFreq[ch], NewFreq);
|
|
||||||
|
|
||||||
if (NewFreq < 0)
|
|
||||||
EffFreq[ch] = 0;
|
|
||||||
else if (NewFreq > 0x7FF)
|
|
||||||
{
|
|
||||||
//EffFreq[ch] = 0x7FF;
|
|
||||||
IntlControl[ch] &= ~0x80;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
EffFreq[ch] = NewFreq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end while(SweepModClockDivider <= 0)
|
|
||||||
} // end if(ch == 4)
|
|
||||||
} // end while(EffectsClockDivider[ch] <= 0)
|
|
||||||
clocks -= chunk_clocks;
|
|
||||||
running_timestamp += chunk_clocks;
|
|
||||||
|
|
||||||
// Output sound here too.
|
|
||||||
CalcCurrentOutput(ch, left, right);
|
|
||||||
Synth.offset_inline(running_timestamp, left - last_output[ch][0], &sbuf[0]);
|
|
||||||
Synth.offset_inline(running_timestamp, right - last_output[ch][1], &sbuf[1]);
|
|
||||||
last_output[ch][0] = left;
|
|
||||||
last_output[ch][1] = right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_ts = timestamp;
|
|
||||||
//puts("VSU End");
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 VSU::EndFrame(int32 timestamp, int16 *SoundBuf, int32 SoundBufMaxSize)
|
|
||||||
{
|
|
||||||
int32 ret = 0;
|
|
||||||
|
|
||||||
Update(timestamp);
|
|
||||||
last_ts = 0;
|
|
||||||
|
|
||||||
if (SoundBuf)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < 2; y++)
|
|
||||||
{
|
|
||||||
sbuf[y].end_frame(timestamp);
|
|
||||||
ret = sbuf[y].read_samples(SoundBuf + y, SoundBufMaxSize, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 VSU::PeekWave(const unsigned int which, uint32 Address)
|
|
||||||
{
|
|
||||||
assert(which <= 4);
|
|
||||||
|
|
||||||
Address &= 0x1F;
|
|
||||||
|
|
||||||
return (WaveData[which][Address]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSU::PokeWave(const unsigned int which, uint32 Address, uint8 value)
|
|
||||||
{
|
|
||||||
assert(which <= 4);
|
|
||||||
|
|
||||||
Address &= 0x1F;
|
|
||||||
|
|
||||||
WaveData[which][Address] = value & 0x3F;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 VSU::PeekModWave(uint32 Address)
|
|
||||||
{
|
|
||||||
Address &= 0x1F;
|
|
||||||
return (ModData[Address]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VSU::PokeModWave(uint32 Address, uint8 value)
|
|
||||||
{
|
|
||||||
Address &= 0x1F;
|
|
||||||
|
|
||||||
ModData[Address] = value & 0xFF;
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
/******************************************************************************/
|
|
||||||
/* Mednafen Virtual Boy Emulation Module */
|
|
||||||
/******************************************************************************/
|
|
||||||
/* vsu.h:
|
|
||||||
** Copyright (C) 2010-2016 Mednafen Team
|
|
||||||
**
|
|
||||||
** This program is free software; you can redistribute it and/or
|
|
||||||
** modify it under the terms of the GNU General Public License
|
|
||||||
** as published by the Free Software Foundation; either version 2
|
|
||||||
** of the License, or (at your option) any later version.
|
|
||||||
**
|
|
||||||
** This program is distributed in the hope that it will be useful,
|
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
** GNU General Public License for more details.
|
|
||||||
**
|
|
||||||
** You should have received a copy of the GNU General Public License
|
|
||||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class VSU
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VSU()
|
|
||||||
MDFN_COLD;
|
|
||||||
~VSU() MDFN_COLD;
|
|
||||||
|
|
||||||
void SetSoundRate(double rate) MDFN_COLD;
|
|
||||||
|
|
||||||
void Power(void) MDFN_COLD;
|
|
||||||
|
|
||||||
void Write(int32 timestamp, uint32 A, uint8 V);
|
|
||||||
|
|
||||||
int32 EndFrame(int32 timestamp, int16 *SoundBuf, int32 SoundBufMaxSize);
|
|
||||||
|
|
||||||
uint8 PeekWave(const unsigned int which, uint32 Address);
|
|
||||||
void PokeWave(const unsigned int which, uint32 Address, uint8 value);
|
|
||||||
|
|
||||||
uint8 PeekModWave(uint32 Address);
|
|
||||||
void PokeModWave(uint32 Address, uint8 value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CalcCurrentOutput(int ch, int &left, int &right);
|
|
||||||
|
|
||||||
void Update(int32 timestamp);
|
|
||||||
|
|
||||||
uint8 IntlControl[6];
|
|
||||||
uint8 LeftLevel[6];
|
|
||||||
uint8 RightLevel[6];
|
|
||||||
uint16 Frequency[6];
|
|
||||||
uint16 EnvControl[6]; // Channel 5/6 extra functionality tacked on too.
|
|
||||||
|
|
||||||
uint8 RAMAddress[6];
|
|
||||||
|
|
||||||
uint8 SweepControl;
|
|
||||||
|
|
||||||
uint8 WaveData[5][0x20];
|
|
||||||
|
|
||||||
uint8 ModData[0x20];
|
|
||||||
|
|
||||||
int32 EffFreq[6];
|
|
||||||
int32 Envelope[6];
|
|
||||||
|
|
||||||
int32 WavePos[6];
|
|
||||||
int32 ModWavePos;
|
|
||||||
|
|
||||||
int32 LatcherClockDivider[6];
|
|
||||||
|
|
||||||
int32 FreqCounter[6];
|
|
||||||
int32 IntervalCounter[6];
|
|
||||||
int32 EnvelopeCounter[6];
|
|
||||||
int32 SweepModCounter;
|
|
||||||
|
|
||||||
int32 EffectsClockDivider[6];
|
|
||||||
int32 IntervalClockDivider[6];
|
|
||||||
int32 EnvelopeClockDivider[6];
|
|
||||||
int32 SweepModClockDivider;
|
|
||||||
|
|
||||||
int32 NoiseLatcherClockDivider;
|
|
||||||
uint32 NoiseLatcher;
|
|
||||||
|
|
||||||
uint32 lfsr;
|
|
||||||
|
|
||||||
int32 last_output[6][2];
|
|
||||||
int32 last_ts;
|
|
||||||
|
|
||||||
Blip_Buffer sbuf[2];
|
|
||||||
Blip_Synth<blip_good_quality, 1024> Synth;
|
|
||||||
Blip_Synth<blip_med_quality, 1024> NoiseSynth;
|
|
||||||
};
|
|
Loading…
Reference in New Issue