2017-11-12 17:46:47 +01:00
|
|
|
#include "externals.hh"
|
|
|
|
#include "control.hh"
|
|
|
|
#include "globals.hh"
|
|
|
|
#include "sync.hh"
|
2017-11-14 14:25:55 +01:00
|
|
|
#include "profiling.hh"
|
2017-11-12 17:46:47 +01:00
|
|
|
|
|
|
|
using namespace ops;
|
|
|
|
using namespace ebcl;
|
|
|
|
|
|
|
|
|
|
|
|
/*= OPCODE INFORMATIONS ========================================================*/
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct T_OpInfo
|
|
|
|
{
|
|
|
|
char const* name;
|
2017-11-12 18:38:31 +01:00
|
|
|
uint32_t nArgs;
|
|
|
|
int32_t sdMain{ 0 };
|
|
|
|
int32_t sdFPU{ 0 };
|
|
|
|
uint32_t fpuReq{ 0 };
|
2017-11-12 17:46:47 +01:00
|
|
|
|
2017-11-12 18:38:31 +01:00
|
|
|
template< typename ... Mods >
|
|
|
|
constexpr T_OpInfo( char const* name ,
|
|
|
|
uint32_t nArgs ,
|
|
|
|
Mods&&... mods );
|
|
|
|
|
|
|
|
constexpr T_OpInfo( char const* name );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template< typename ... Mods >
|
|
|
|
constexpr void ApplyMods_( T_OpInfo& op , Mods&&... mods );
|
|
|
|
|
|
|
|
template< >
|
|
|
|
constexpr void ApplyMods_( T_OpInfo& )
|
|
|
|
{ }
|
|
|
|
|
|
|
|
template< typename M0 , typename ... Mods >
|
|
|
|
constexpr void ApplyMods_(
|
|
|
|
T_OpInfo& op ,
|
|
|
|
M0&& mod ,
|
|
|
|
Mods&&... mods )
|
|
|
|
{
|
|
|
|
mod.applyTo( op );
|
|
|
|
ApplyMods_( op , std::forward< Mods >( mods ) ... );
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename ... Mods >
|
|
|
|
constexpr T_OpInfo::T_OpInfo(
|
|
|
|
char const* name ,
|
|
|
|
uint32_t nArgs ,
|
|
|
|
Mods&&... mods )
|
|
|
|
: name( name ) , nArgs( nArgs )
|
|
|
|
{
|
|
|
|
ApplyMods_( *this , std::forward< Mods >( mods ) ... );
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr T_OpInfo::T_OpInfo( char const* name )
|
|
|
|
: T_OpInfo( name , 0 )
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
struct OpStackMain
|
|
|
|
{
|
|
|
|
int32_t value;
|
|
|
|
explicit constexpr OpStackMain( int32_t v ) : value( v ) { }
|
|
|
|
constexpr void applyTo( T_OpInfo& op )
|
|
|
|
{ op.sdMain = value; }
|
2017-11-12 17:46:47 +01:00
|
|
|
};
|
|
|
|
|
2017-11-12 18:38:31 +01:00
|
|
|
struct OpStackFPU
|
|
|
|
{
|
|
|
|
int32_t value;
|
|
|
|
explicit constexpr OpStackFPU( int32_t v ) : value( v ) { }
|
|
|
|
constexpr void applyTo( T_OpInfo& op )
|
|
|
|
{ op.sdFPU = value; }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-11-12 17:46:47 +01:00
|
|
|
static T_KeyValueTable< E_OpType , T_OpInfo > OpInfoTable_{ ([]() {
|
|
|
|
T_KeyValueTable< E_OpType , T_OpInfo > infos;
|
|
|
|
|
|
|
|
infos.add( E_OpType::OP_END , T_OpInfo{ "end" } );
|
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_CALL , T_OpInfo{ "call" , 1 } );
|
2017-11-12 18:38:31 +01:00
|
|
|
infos.add( E_OpType::OP_RET , T_OpInfo{ "ret" , 1 , OpStackMain{ -1 } } );
|
2017-11-12 22:20:11 +01:00
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_SKIP , T_OpInfo{ "skip" , 1 } );
|
|
|
|
infos.add( E_OpType::OP_COND_SKIP , T_OpInfo{ "cond-skip" , 2 } );
|
2017-11-12 17:46:47 +01:00
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_RES_STACK , T_OpInfo{ "res-stack" , 1 } );
|
2017-11-12 18:38:31 +01:00
|
|
|
infos.add( E_OpType::OP_PUSH , T_OpInfo{ "push" , 0 , OpStackMain{ 1 } } );
|
2017-11-12 17:46:47 +01:00
|
|
|
infos.add( E_OpType::OP_POP , T_OpInfo{ "pop" , 1 } );
|
2017-11-14 12:49:59 +01:00
|
|
|
infos.add( E_OpType::OP_DUP , T_OpInfo{ "dup" , 1 , OpStackMain{ 1 } } );
|
2017-11-12 17:46:47 +01:00
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_LOAD , T_OpInfo{ "load" , 1 } );
|
|
|
|
infos.add( E_OpType::OP_SLOAD , T_OpInfo{ "load-stack" , 1 } );
|
2017-11-13 17:20:45 +01:00
|
|
|
infos.add( E_OpType::OP_CONST , T_OpInfo{ "const" , 1 } );
|
2017-11-12 17:46:47 +01:00
|
|
|
//
|
2017-11-12 18:38:31 +01:00
|
|
|
infos.add( E_OpType::OP_FP_LOAD , T_OpInfo{ "fp-load" , 1 , OpStackFPU{ 1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_SLOAD , T_OpInfo{ "fp-load-stack" , 1 , OpStackFPU{ 1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_STORE , T_OpInfo{ "fp-store" , 1 , OpStackFPU{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_SSTORE , T_OpInfo{ "fp-store-stack" , 1 , OpStackFPU{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_SSTORE_INT , T_OpInfo{ "fp-store-stack-int" , 1 , OpStackFPU{ -1 } } );
|
2017-11-12 17:46:47 +01:00
|
|
|
//
|
2017-11-12 18:38:31 +01:00
|
|
|
infos.add( E_OpType::OP_FP_CMP , T_OpInfo{ "fp-cmp" , 1 , OpStackFPU{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_ADD , T_OpInfo{ "fp-add" , 0 , OpStackFPU{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_SUB , T_OpInfo{ "fp-sub" , 0 , OpStackFPU{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-mul" , 0 , OpStackFPU{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-div" , 0 , OpStackFPU{ -1 } } );
|
2017-11-13 16:58:38 +01:00
|
|
|
infos.add( E_OpType::OP_FP_POW , T_OpInfo{ "fp-pow" , 0 , OpStackFPU{ -1 } } );
|
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_FP_NEG , T_OpInfo{ "fp-neg" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_INV , T_OpInfo{ "fp-inv" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_NOT , T_OpInfo{ "fp-not" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_SIN , T_OpInfo{ "fp-sin" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_COS , T_OpInfo{ "fp-cos" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_TAN , T_OpInfo{ "fp-tan" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_SQRT , T_OpInfo{ "fp-sqrt" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_EXP , T_OpInfo{ "fp-exp" , 0 } );
|
|
|
|
infos.add( E_OpType::OP_FP_LN , T_OpInfo{ "fp-ln" , 0 } );
|
2017-11-13 09:25:32 +01:00
|
|
|
//
|
2017-11-13 10:02:16 +01:00
|
|
|
infos.add( E_OpType::OP_INIT_PIPELINE , T_OpInfo{ "pipeline" , 1 , OpStackMain{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_INIT_PROGRAM , T_OpInfo{ "program" , 1 , OpStackMain{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_INIT_TEXTURE , T_OpInfo{ "texture" , 2 , OpStackMain{ -3 } } );
|
2017-11-13 18:16:48 +01:00
|
|
|
infos.add( E_OpType::OP_INIT_SAMPLER , T_OpInfo{ "sampler" , 2 , OpStackMain{ -3 } } );
|
2017-11-13 14:41:03 +01:00
|
|
|
infos.add( E_OpType::OP_FB_ATTACH , T_OpInfo{ "fb-attach" , 2 , OpStackMain{ -1 } } );
|
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_USE_FRAMEBUFFER , T_OpInfo{ "use-framebuffer" , 0 , OpStackMain{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_FB_TOGGLE , T_OpInfo{ "fb-toggle" , 2 } );
|
|
|
|
infos.add( E_OpType::OP_USE_PIPELINE , T_OpInfo{ "use-pipeline" , 0 , OpStackMain{ -1 } } );
|
|
|
|
infos.add( E_OpType::OP_USE_PROGRAM , T_OpInfo{ "use-program" , 0 , OpStackMain{ -1 } } );
|
2017-11-13 16:58:38 +01:00
|
|
|
infos.add( E_OpType::OP_USE_TEXTURE , T_OpInfo{ "use-texture" , 1 , OpStackMain{ -2 } } );
|
2017-11-13 17:20:45 +01:00
|
|
|
infos.add( E_OpType::OP_UNIFORMS , T_OpInfo{ "uniforms" , 2 , OpStackMain{ -2 } } );
|
2017-11-13 17:28:57 +01:00
|
|
|
infos.add( E_OpType::OP_VIEWPORT , T_OpInfo{ "viewport" , 0 , OpStackMain{ -4 } } );
|
2017-11-13 09:25:32 +01:00
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_FULLSCREEN , T_OpInfo{ "fullscreen" } );
|
2017-11-13 10:02:16 +01:00
|
|
|
infos.add( E_OpType::OP_CLEAR , T_OpInfo{ "clear" , 0 , OpStackMain{ -4 } } );
|
|
|
|
//
|
|
|
|
infos.add( E_OpType::OP_UI_PENTER , T_OpInfo{ "ui-prof-enter" , 1 } );
|
|
|
|
infos.add( E_OpType::OP_UI_PEXIT , T_OpInfo{ "ui-prof-exit" } );
|
2017-11-13 18:51:15 +01:00
|
|
|
infos.add( E_OpType::OP_UI_INPUT_DFT , T_OpInfo{ "ui-input-default" , 2 } );
|
|
|
|
infos.add( E_OpType::OP_UI_ODBG , T_OpInfo{ "ui-odbg" , 2 , OpStackMain{ -1 } } );
|
2017-11-12 17:46:47 +01:00
|
|
|
|
|
|
|
return infos;
|
|
|
|
})( ) };
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
uint32_t ops::ArgumentsFor(
|
|
|
|
const E_OpType op ) noexcept
|
|
|
|
{
|
|
|
|
assert( OpInfoTable_.contains( op ) );
|
|
|
|
return OpInfoTable_.get( op )->nArgs;
|
|
|
|
}
|
|
|
|
|
2017-11-12 18:38:31 +01:00
|
|
|
int32_t ops::DeltaMainStack(
|
|
|
|
const E_OpType op ) noexcept
|
|
|
|
{
|
|
|
|
assert( OpInfoTable_.contains( op ) );
|
|
|
|
return OpInfoTable_.get( op )->sdMain;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t ops::DeltaFPUStack(
|
|
|
|
const E_OpType op ) noexcept
|
|
|
|
{
|
|
|
|
assert( OpInfoTable_.contains( op ) );
|
|
|
|
return OpInfoTable_.get( op )->sdFPU;
|
|
|
|
}
|
|
|
|
|
2017-11-12 17:46:47 +01:00
|
|
|
|
|
|
|
/*= STRING FORMATTING ==========================================================*/
|
|
|
|
|
|
|
|
T_StringBuilder& ops::operator<<(
|
|
|
|
T_StringBuilder& sb ,
|
|
|
|
const E_OpType et )
|
|
|
|
{
|
|
|
|
assert( OpInfoTable_.contains( et ) );
|
|
|
|
sb << OpInfoTable_.get( et )->name;
|
|
|
|
return sb;
|
|
|
|
}
|
|
|
|
|
|
|
|
T_StringBuilder& ops::operator<<(
|
|
|
|
T_StringBuilder& sb ,
|
|
|
|
T_Op const& op )
|
|
|
|
{
|
|
|
|
sb << op.op;
|
|
|
|
const auto args{ OpInfoTable_.get( op.op )->nArgs };
|
2017-11-12 22:20:11 +01:00
|
|
|
for ( auto i = 0u ; i < args ; i ++ ) {
|
|
|
|
sb << ' ' << op.args[ i ];
|
2017-11-12 17:46:47 +01:00
|
|
|
}
|
|
|
|
return sb;
|
|
|
|
}
|
2017-11-14 12:49:59 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*= EMULATOR ===================================================================*/
|
|
|
|
|
|
|
|
X_OpFailure::X_OpFailure(
|
|
|
|
T_Op const& op ,
|
|
|
|
T_String error ) noexcept
|
|
|
|
: op_( &op ) , error_( std::move( error ) )
|
|
|
|
{
|
|
|
|
T_StringBuilder sb;
|
|
|
|
sb << "operation (" << op << ") failed; source: " << op.location
|
|
|
|
<< '\0';
|
|
|
|
fullMessage_ = std::move( sb );
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* X_OpFailure::what( ) const noexcept
|
|
|
|
{
|
|
|
|
return fullMessage_.data( );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
T_OpContext::T_OpContext(
|
|
|
|
T_OpProgram& program ) noexcept
|
|
|
|
: program( program )
|
|
|
|
{
|
|
|
|
stack.ensureCapacity( stack.growth( ) );
|
|
|
|
|
|
|
|
const auto nc{ program.constants.size( ) };
|
|
|
|
const auto ts{ 3 + nc + program.nVariables
|
|
|
|
+ program.nPrograms + program.nPipelines
|
|
|
|
+ program.nSamplers + program.nTextures };
|
|
|
|
values.resize( ts );
|
2017-11-14 14:25:55 +01:00
|
|
|
initialInputs.resize( program.inputs.size( ) );
|
2017-11-14 12:49:59 +01:00
|
|
|
|
|
|
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
|
|
|
values[ i + 3 ] = program.constants[ nc ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void T_OpContext::run(
|
|
|
|
const E_RunTarget target ,
|
|
|
|
const float time ,
|
|
|
|
const float width ,
|
|
|
|
const float height )
|
|
|
|
{
|
|
|
|
assert( !aborted );
|
|
|
|
x87sp = 0;
|
|
|
|
instrPtr = program.ops.firstOf( target == R_INIT ? program.init : program.frame );
|
|
|
|
values[ 0 ] = time;
|
|
|
|
values[ 1 ] = width;
|
|
|
|
values[ 2 ] = height;
|
|
|
|
stack.clear( );
|
|
|
|
stack.add( 0xffffffff );
|
|
|
|
|
|
|
|
while ( 0 /* FIXME */ ) {
|
|
|
|
// if ( instrPtr >= program.ops.
|
|
|
|
auto const& instr{ program.ops[ instrPtr ] };
|
|
|
|
|
|
|
|
switch ( instr.op ) {
|
|
|
|
|
|
|
|
case OP_END:
|
|
|
|
throw X_OpFailure{ instr , "invalid instruction" };
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_CALL:
|
|
|
|
if ( program.ops.size( ) <= instr.args[ 0 ] ) {
|
|
|
|
throw X_OpFailure{ instr , "invalid function index" };
|
|
|
|
}
|
|
|
|
stack.add( instrPtr + 1 );
|
|
|
|
instrPtr = program.ops.firstOf( instr.args[ 0 ] );
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case OP_RET:
|
|
|
|
ensureStack( instr , 1 + instr.args[ 0 ] );
|
|
|
|
instrPtr = stack.last( ).u;
|
|
|
|
stack.resize( stack.size( ) - instr.args[ 0 ] - 1 );
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case OP_SKIP:
|
|
|
|
// FIXME: make sure we don't go past the end
|
|
|
|
instrPtr += instr.args[ 0 ];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_COND_SKIP:
|
|
|
|
ensureStack( instr , 1 );
|
|
|
|
if ( stack.last( ).u != instr.args[ 1 ] ) {
|
|
|
|
// FIXME: make sure we don't go past the end
|
|
|
|
instrPtr += instr.args[ 0 ];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_RES_STACK:
|
|
|
|
stack.resize( stack.size( ) + instr.args[ 0 ] );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_PUSH:
|
|
|
|
stack.add( wreg );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_POP:
|
|
|
|
ensureStack( instr , instr.args[ 0 ] + 1 );
|
|
|
|
stack.resize( stack.size( ) - instr.args[ 0 ] - 1 );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_DUP:
|
|
|
|
ensureStack( instr , instr.args[ 0 ] + 1 );
|
|
|
|
stack.add( stack[ stack.size( ) - instr.args[ 0 ] - 1 ] );
|
|
|
|
break;
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_LOAD:
|
|
|
|
checkAddress( instr , instr.args[ 0 ] );
|
|
|
|
wreg = values[ instr.args[ 0 ] ];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_SLOAD:
|
|
|
|
ensureStack( instr , instr.args[ 0 ] + 1 );
|
|
|
|
wreg = stack[ stack.size( ) - instr.args[ 0 ] - 1 ];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_CONST:
|
|
|
|
wreg = instr.args[ 0 ];
|
|
|
|
break;
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_FP_LOAD:
|
|
|
|
ensureFpuStack( instr , 0 , 1 );
|
|
|
|
checkAddress( instr , instr.args[ 0 ] );
|
|
|
|
x87stack[ x87sp ++ ] = values[ instr.args[ 0 ] ].f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_FP_STORE:
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
checkAddress( instr , instr.args[ 0 ] );
|
|
|
|
values[ instr.args[ 0 ] ].f = x87stack[ -- x87sp ];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_FP_SLOAD:
|
|
|
|
ensureFpuStack( instr , 0 , 1 );
|
|
|
|
ensureStack( instr , instr.args[ 0 ] + 1 );
|
|
|
|
x87stack[ x87sp ++ ] = stack[ stack.size( ) - instr.args[ 0 ] - 1 ].f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_FP_SSTORE:
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
ensureStack( instr , instr.args[ 0 ] + 1 );
|
|
|
|
stack[ stack.size( ) - instr.args[ 0 ] - 1 ].f = x87stack[ -- x87sp ];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_FP_SSTORE_INT:
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
ensureStack( instr , instr.args[ 0 ] + 1 );
|
|
|
|
stack[ stack.size( ) - instr.args[ 0 ] - 1 ].i = int32_t( x87stack[ -- x87sp ] );
|
|
|
|
break;
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_FP_CMP:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 2 , 0 );
|
|
|
|
const auto v2( x87stack[ x87sp - 1 ] ) ,
|
|
|
|
v1( x87stack[ x87sp - 2 ] );
|
|
|
|
x87sp --;
|
|
|
|
|
|
|
|
const bool rv{ ([&]( ) -> bool {
|
|
|
|
switch ( instr.args[ 0 ] ) {
|
|
|
|
case 0: return v1 == v2;
|
|
|
|
case 1: return v1 != v2;
|
|
|
|
case 2: return v1 > v2;
|
|
|
|
case 3: return v1 >= v2;
|
|
|
|
case 4: return v1 < v2;
|
|
|
|
case 5: return v1 <= v2;
|
|
|
|
}
|
|
|
|
throw X_OpFailure( instr , "invalid operation" );
|
|
|
|
})() };
|
|
|
|
x87stack[ x87sp - 1 ] = rv ? 1 : 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_ADD:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 2 , 0 );
|
|
|
|
x87stack[ x87sp - 2 ] += x87stack[ x87sp - 1 ];
|
|
|
|
x87sp --;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_SUB:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 2 , 0 );
|
|
|
|
x87stack[ x87sp - 2 ] -= x87stack[ x87sp - 1 ];
|
|
|
|
x87sp --;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_MUL:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 2 , 0 );
|
|
|
|
x87stack[ x87sp - 2 ] *= x87stack[ x87sp - 1 ];
|
|
|
|
x87sp --;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_DIV:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 2 , 0 );
|
|
|
|
if ( x87stack[ x87sp - 1 ] == 0 ) {
|
|
|
|
throw X_OpFailure{ instr , "arithmetic error" };
|
|
|
|
}
|
|
|
|
x87stack[ x87sp - 2 ] *= x87stack[ x87sp - 1 ];
|
|
|
|
x87sp --;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_POW:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 2 , 0 );
|
|
|
|
x87stack[ x87sp - 2 ] = pow( x87stack[ x87sp - 2 ] ,
|
|
|
|
x87stack[ x87sp - 1 ] );
|
|
|
|
x87sp --;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_FP_NEG:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 1 );
|
|
|
|
x87stack[ x87sp - 1 ] = -x87stack[ x87sp - 1 ];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_INV:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 1 );
|
|
|
|
if ( x87stack[ x87sp - 1 ] == 0 ) {
|
|
|
|
throw X_OpFailure{ instr , "arithmetic error" };
|
|
|
|
}
|
|
|
|
x87stack[ x87sp - 1 ] = 1.0 / x87stack[ x87sp - 1 ];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_NOT:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
x87stack[ x87sp - 1 ] = x87stack[ x87sp - 1 ] == 0 ? 1 : 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_SIN:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
x87stack[ x87sp - 1 ] = sin( x87stack[ x87sp - 1 ] );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_COS:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
x87stack[ x87sp - 1 ] = cos( x87stack[ x87sp - 1 ] );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_TAN:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 1 );
|
|
|
|
const auto c( cos( x87stack[ x87sp - 1 ] ) );
|
|
|
|
if ( c == 0 ) {
|
|
|
|
throw X_OpFailure{ instr , "arithmetic error" };
|
|
|
|
}
|
|
|
|
x87stack[ x87sp - 1 ] = sin( x87stack[ x87sp - 1 ] ) / c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_SQRT:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 0 );
|
|
|
|
const auto v( x87stack[ x87sp - 1 ] );
|
|
|
|
if ( v < 0 ) {
|
|
|
|
throw X_OpFailure{ instr , "arithmetic error" };
|
|
|
|
}
|
|
|
|
x87stack[ x87sp - 1 ] = sqrt( v );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_EXP:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 0 ); // FIXME: need FPU stack space
|
|
|
|
x87stack[ x87sp - 1 ] = exp( x87stack[ x87sp - 1 ] );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_FP_LN:
|
|
|
|
{
|
|
|
|
ensureFpuStack( instr , 1 , 0 ); // FIXME: need FPU stack space
|
|
|
|
x87stack[ x87sp - 1 ] = log( x87stack[ x87sp - 1 ] );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-11-14 14:25:55 +01:00
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// TODO resource init
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// TODO resource usage
|
|
|
|
|
|
|
|
case OP_UNIFORMS:
|
|
|
|
{
|
|
|
|
ensureStack( instr , 3 + instr.args[ 0 ] );
|
|
|
|
|
|
|
|
const auto ss( stack.size( ) );
|
|
|
|
T_OpValue values[ 4 ];
|
|
|
|
for ( auto i = 0u ; i <= instr.args[ 0 ] ; i ++ ) {
|
|
|
|
values[ i ] = stack[ ss - 2 - i ];
|
|
|
|
}
|
|
|
|
// FIXME can't actually finish this, I'm stupid.
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_VIEWPORT:
|
|
|
|
{
|
|
|
|
ensureStack( instr , 4 );
|
|
|
|
const auto ss( stack.size( ) );
|
|
|
|
glViewport( stack[ ss - 1 ].f , stack[ ss - 2 ].f ,
|
|
|
|
stack[ ss - 3 ].f , stack[ ss - 4 ].f );
|
|
|
|
stack.resize( ss - 4 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_FULLSCREEN:
|
|
|
|
glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_CLEAR:
|
|
|
|
{
|
|
|
|
ensureStack( instr , 4 );
|
|
|
|
const auto ss( stack.size( ) );
|
|
|
|
glClearColor( stack[ ss - 1 ].f , stack[ ss - 2 ].f ,
|
|
|
|
stack[ ss - 3 ].f , stack[ ss - 4 ].f );
|
|
|
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
|
|
|
stack.resize( ss - 4 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
case OP_UI_PENTER:
|
|
|
|
{
|
|
|
|
T_String const& section( program.uiStrings[ instr.args[ 0 ] ] );
|
|
|
|
Globals::Profiler( ).start( section );
|
|
|
|
profiling.add( section );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OP_UI_PEXIT:
|
|
|
|
Globals::Profiler( ).end( profiling.last( ) );
|
|
|
|
profiling.removeLast( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OP_UI_INPUT_DFT:
|
|
|
|
initialInputs[ instr.args[ 0 ] ] = values[ instr.args[ 1 ] ].f;
|
|
|
|
break;
|
2017-11-14 12:49:59 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
instrPtr ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void T_OpContext::ensureStack(
|
|
|
|
T_Op const& op ,
|
|
|
|
const uint32_t min )
|
|
|
|
{
|
|
|
|
if ( stack.size( ) < min ) {
|
|
|
|
throw X_OpFailure{ op , "stack underrun" };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void T_OpContext::ensureFpuStack(
|
|
|
|
T_Op const& op ,
|
|
|
|
const uint32_t minStacked ,
|
|
|
|
const uint32_t minFree )
|
|
|
|
{
|
|
|
|
if ( x87sp < minStacked ) {
|
|
|
|
throw X_OpFailure{ op , "FPU stack underrun" };
|
|
|
|
}
|
|
|
|
if ( 8 - x87sp < minFree ) {
|
|
|
|
throw X_OpFailure{ op , "FPU stack overflow" };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void T_OpContext::checkAddress(
|
|
|
|
T_Op const& op ,
|
|
|
|
const uint32_t address )
|
|
|
|
{
|
|
|
|
if ( address >= values.size( ) ) {
|
|
|
|
throw X_OpFailure( op , "invalid access" );
|
|
|
|
}
|
|
|
|
}
|