vb move to nyma

This commit is contained in:
CasualPokePlayer 2022-05-29 17:21:01 -07:00
parent f983fce9ff
commit 0c95088e02
29 changed files with 73 additions and 9503 deletions

Binary file not shown.

View File

@ -9,5 +9,5 @@ make -f pcfx.mak $1 -j
make -f ss.mak $1 -j
make -f shock.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

69
waterbox/nyma/vb.cpp Normal file
View File

@ -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);
}

View File

@ -2,6 +2,8 @@ include common.mak
SRCS += \
$(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

View File

@ -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"
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;*/

View File

@ -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 &timestamp, 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 &timestamp, 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);
}
}

View File

@ -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 &timestamp, uint32 A);
void VBINPUT_Write(v810_timestamp_t &timestamp, 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

View File

@ -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

View File

@ -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 &timestamp, 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 &timestamp, 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;
}
}
}

View File

@ -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 &timestamp, uint32 A);
void TIMER_Write(const v810_timestamp_t &timestamp, 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

View File

@ -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 &timestamp, uint32 A);
uint16 MDFN_FASTCALL (*MemRead16)(v810_timestamp_t &timestamp, uint32 A);
uint32 MDFN_FASTCALL (*MemRead32)(v810_timestamp_t &timestamp, uint32 A);
void MDFN_FASTCALL (*MemWrite8)(v810_timestamp_t &timestamp, uint32 A, uint8 V);
void MDFN_FASTCALL (*MemWrite16)(v810_timestamp_t &timestamp, uint32 A, uint16 V);
void MDFN_FASTCALL (*MemWrite32)(v810_timestamp_t &timestamp, uint32 A, uint32 V);
uint8 MDFN_FASTCALL (*IORead8)(v810_timestamp_t &timestamp, uint32 A);
uint16 MDFN_FASTCALL (*IORead16)(v810_timestamp_t &timestamp, uint32 A);
uint32 MDFN_FASTCALL (*IORead32)(v810_timestamp_t &timestamp, uint32 A);
void MDFN_FASTCALL (*IOWrite8)(v810_timestamp_t &timestamp, uint32 A, uint8 V);
void MDFN_FASTCALL (*IOWrite16)(v810_timestamp_t &timestamp, uint32 A, uint16 V);
void MDFN_FASTCALL (*IOWrite32)(v810_timestamp_t &timestamp, 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 &timestamp, int sub_op, int arg1);
void fpu_subop(v810_timestamp_t &timestamp, 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 &timestamp, uint32 A, uint32 V);
uint32 CacheOpMemLoad(v810_timestamp_t &timestamp, uint32 A);
void CacheClear(v810_timestamp_t &timestamp, uint32 start, uint32 count);
void CacheDump(v810_timestamp_t &timestamp, const uint32 SA);
void CacheRestore(v810_timestamp_t &timestamp, const uint32 SA);
uint32 RDCACHE(v810_timestamp_t &timestamp, uint32 addr);
//
// End caching related
//
uint16 RDOP(v810_timestamp_t &timestamp, uint32 addr, uint32 meow = 2);
void SetFlag(uint32 n, bool condition);
void SetSZ(uint32 value);
void SetSREG(v810_timestamp_t &timestamp, 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 &timestamp, uint32 A);
void BSTR_WWORD(v810_timestamp_t &timestamp, uint32 A, uint32 V);
bool Do_BSTR_Search(v810_timestamp_t &timestamp, const int inc_mul, unsigned int bit_test);
V810_FP_Ops fpo;
uint8 DummyRegion[V810_FAST_MAP_PSIZE + V810_FAST_MAP_TRAMPOLINE_SIZE];
};

View File

@ -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();

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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 &timestamp, 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 &timestamp, 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 &timestamp, 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 &timestamp, 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 &timestamp, 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 &timestamp, 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;
}

View File

@ -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 &timestamp, uint32 A);
uint16 MDFN_FASTCALL MemRead16(v810_timestamp_t &timestamp, uint32 A);
void MDFN_FASTCALL MemWrite8(v810_timestamp_t &timestamp, uint32 A, uint8 V);
void MDFN_FASTCALL MemWrite16(v810_timestamp_t &timestamp, uint32 A, uint16 V);
}

File diff suppressed because it is too large Load Diff

View File

@ -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 &timestamp, uint32 A);
MDFN_FASTCALL uint16 VIP_Read16(v810_timestamp_t &timestamp, uint32 A);
MDFN_FASTCALL void VIP_Write8(v810_timestamp_t &timestamp, uint32 A, uint8 V);
MDFN_FASTCALL void VIP_Write16(v810_timestamp_t &timestamp, 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);
}

View File

@ -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--;
}
}

View File

@ -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;
}

View File

@ -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;
};