diff options
author | waker <wakeroid@gmail.com> | 2009-08-16 20:42:17 +0200 |
---|---|---|
committer | waker <wakeroid@gmail.com> | 2009-08-16 20:51:54 +0200 |
commit | 1e7c5ae1fa743a73fbc0c1831201271691c6ae95 (patch) | |
tree | fa24c03544ba4066d57f288d91b6e3df9d80c4fd /gme/Spc_Cpu.cpp | |
parent | 36df76395c9e7af90bfe5bfb8c717de7a552847a (diff) |
fixed gme source distribution
Diffstat (limited to 'gme/Spc_Cpu.cpp')
-rw-r--r-- | gme/Spc_Cpu.cpp | 1062 |
1 files changed, 0 insertions, 1062 deletions
diff --git a/gme/Spc_Cpu.cpp b/gme/Spc_Cpu.cpp deleted file mode 100644 index fb9983b8..00000000 --- a/gme/Spc_Cpu.cpp +++ /dev/null @@ -1,1062 +0,0 @@ -// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ - -#include "Spc_Cpu.h" - -#include "blargg_endian.h" -#include "Snes_Spc.h" - -/* Copyright (C) 2004-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 */ - -#include "blargg_source.h" - -// Several instructions are commented out (or not even implemented). These aren't -// used by the SPC files tested. - -// Optimize performance for the most common instructions, and size for the rest: -// -// 15% 0xF0 BEQ rel -// 8% 0xE4 MOV A,dp -// 4% 0xF5 MOV A,abs+X -// 4% 0xD0 BNE rel -// 4% 0x6F RET -// 4% 0x3F CALL addr -// 4% 0xF4 MOV A,dp+X -// 3% 0xC4 MOV dp,A -// 2% 0xEB MOV Y,dp -// 2% 0x3D INC X -// 2% 0xF6 MOV A,abs+Y -// (1% and below not shown) - -Spc_Cpu::Spc_Cpu( Snes_Spc* e, uint8_t* ram_in ) : ram( ram_in ), emu( *e ) -{ - remain_ = 0; - assert( INT_MAX >= 0x7FFFFFFF ); // requires 32-bit int - blargg_verify_byte_order(); -} - -#define READ( addr ) (emu.read( addr )) -#define WRITE( addr, value ) (emu.write( addr, value )) - -#define READ_DP( addr ) READ( (addr) + dp ) -#define WRITE_DP( addr, value ) WRITE( (addr) + dp, value ) - -#define READ_PROG( addr ) (ram [addr]) -#define READ_PROG16( addr ) GET_LE16( &READ_PROG( addr ) ) - -int Spc_Cpu::read( spc_addr_t addr ) -{ - return READ( addr ); -} - -void Spc_Cpu::write( spc_addr_t addr, int data ) -{ - WRITE( addr, data ); -} - -// Cycle table derived from text copy of SPC-700 manual (using regular expressions) -static unsigned char const cycle_table [0x100] = { -// 0 1 2 3 4 5 6 7 8 9 A B C D E F - 2,8,4,5,3,4,3,6,2,6,5,4,5,4,6,8, // 0 - 2,8,4,5,4,5,5,6,5,5,6,5,2,2,4,6, // 1 - 2,8,4,5,3,4,3,6,2,6,5,4,5,4,5,4, // 2 - 2,8,4,5,4,5,5,6,5,5,6,5,2,2,3,8, // 3 - 2,8,4,5,3,4,3,6,2,6,4,4,5,4,6,6, // 4 - 2,8,4,5,4,5,5,6,5,5,4,5,2,2,4,3, // 5 - 2,8,4,5,3,4,3,6,2,6,4,4,5,4,5,5, // 6 - 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,6, // 7 - 2,8,4,5,3,4,3,6,2,6,5,4,5,2,4,5, // 8 - 2,8,4,5,4,5,5,6,5,5,5,5,2,2,12,5,// 9 - 3,8,4,5,3,4,3,6,2,6,4,4,5,2,4,4, // A - 2,8,4,5,4,5,5,6,5,5,5,5,2,2,3,4, // B - 3,8,4,5,4,5,4,7,2,5,6,4,5,2,4,9, // C - 2,8,4,5,5,6,6,7,4,5,4,5,2,2,6,3, // D - 2,8,4,5,3,4,3,6,2,4,5,3,4,3,4,3, // E - 2,8,4,5,4,5,5,6,3,4,5,4,2,2,4,3 // F -}; - -// The C,mem instructions are hardly used, so a non-inline function is used for -// the common access code. -unsigned Spc_Cpu::mem_bit( spc_addr_t pc ) -{ - unsigned addr = READ_PROG16( pc ); - unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13); - return (t << 8) & 0x100; -} - -spc_time_t Spc_Cpu::run( spc_time_t cycle_count ) -{ - remain_ = cycle_count; - - uint8_t* const ram = this->ram; // cache - - // Stack pointer is kept one greater than usual SPC stack pointer to allow - // common pre-decrement and post-increment memory instructions that some - // processors have. Address wrap-around isn't supported. - #define PUSH( v ) (*--sp = uint8_t (v)) - #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) - #define POP() (*sp++) - #define SET_SP( v ) (sp = ram + 0x101 + (v)) - #define GET_SP() (sp - 0x101 - ram) - - uint8_t* sp; - SET_SP( r.sp ); - - // registers - unsigned pc = (unsigned) r.pc; - int a = r.a; - int x = r.x; - int y = r.y; - - // status flags - - const int st_n = 0x80; - const int st_v = 0x40; - const int st_p = 0x20; - const int st_b = 0x10; - const int st_h = 0x08; - const int st_i = 0x04; - const int st_z = 0x02; - const int st_c = 0x01; - - #define IS_NEG (nz & 0x880) - - #define CALC_STATUS( out ) do {\ - out = status & ~(st_n | st_z | st_c);\ - out |= (c >> 8) & st_c;\ - out |= (dp >> 3) & st_p;\ - if ( IS_NEG ) out |= st_n;\ - if ( !(nz & 0xFF) ) out |= st_z;\ - } while ( 0 ) - - #define SET_STATUS( in ) do {\ - status = in & ~(st_n | st_z | st_c | st_p);\ - c = in << 8;\ - nz = (in << 4) & 0x800;\ - nz |= ~in & st_z;\ - dp = (in << 3) & 0x100;\ - } while ( 0 ) - - int status; - int c; // store C as 'c' & 0x100. - int nz; // Z set if (nz & 0xFF) == 0, N set if (nz & 0x880) != 0 - unsigned dp; // direct page base - { - int temp = r.status; - SET_STATUS( temp ); - } - - goto loop; - - unsigned data; // first operand of instruction and temporary across function calls - - // Common endings for instructions -cbranch_taken_loop: // compare and branch - pc += (BOOST::int8_t) READ_PROG( pc ); - remain_ -= 2; -inc_pc_loop: // end of instruction with an operand - pc++; -loop: - - check( (unsigned) pc < 0x10000 ); - check( (unsigned) GET_SP() < 0x100 ); - - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - unsigned opcode = READ_PROG( pc ); - pc++; - // to do: if pc is at end of memory, this will get wrong byte - data = READ_PROG( pc ); - - if ( remain_ <= 0 ) - goto stop; - - remain_ -= cycle_table [opcode]; - - // Use 'data' for temporaries whose lifetime crosses read/write calls, otherwise - // use a local temporary. - switch ( opcode ) - { - - #define BRANCH( cond ) {\ - pc++;\ - int offset = (BOOST::int8_t) data;\ - if ( cond ) {\ - pc += offset;\ - remain_ -= 2;\ - }\ - goto loop;\ - } - -// Most-Common - - case 0xF0: // BEQ (most common) - BRANCH( !(uint8_t) nz ) - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ) - - case 0x3F: // CALL - PUSH16( pc + 2 ); - pc = READ_PROG16( pc ); - goto loop; - - case 0x6F: // RET - pc = POP(); - pc += POP() * 0x100; - goto loop; - -#define CASE( n ) case n: - -// Define common address modes based on opcode for immediate mode. Execution -// ends with data set to the address of the operand. -#define ADDR_MODES( op )\ - CASE( op - 0x02 ) /* (X) */\ - data = x + dp;\ - pc--;\ - goto end_##op;\ - CASE( op + 0x0F ) /* (dp)+Y */\ - data = READ_PROG16( data + dp ) + y;\ - goto end_##op;\ - CASE( op - 0x01 ) /* (dp+X) */\ - data = READ_PROG16( uint8_t (data + x) + dp );\ - goto end_##op;\ - CASE( op + 0x0E ) /* abs+Y */\ - data += y;\ - goto abs_##op;\ - CASE( op + 0x0D ) /* abs+X */\ - data += x;\ - CASE( op - 0x03 ) /* abs */\ - abs_##op:\ - pc++;\ - data += 0x100 * READ_PROG( pc );\ - goto end_##op;\ - CASE( op + 0x0C ) /* dp+X */\ - data = uint8_t (data + x);\ - CASE( op - 0x04 ) /* dp */\ - data += dp;\ - end_##op: - -// 1. 8-bit Data Transmission Commands. Group I - - ADDR_MODES( 0xE8 ) // MOV A,addr - // case 0xE4: // MOV a,dp (most common) - mov_a_addr: - a = nz = READ( data ); - goto inc_pc_loop; - case 0xBF: // MOV A,(X)+ - data = x + dp; - x = uint8_t (x + 1); - pc--; - goto mov_a_addr; - - case 0xE8: // MOV A,imm - a = data; - nz = data; - goto inc_pc_loop; - - case 0xF9: // MOV X,dp+Y - data = uint8_t (data + y); - case 0xF8: // MOV X,dp - data += dp; - goto mov_x_addr; - case 0xE9: // MOV X,abs - data = READ_PROG16( pc ); - pc++; - mov_x_addr: - data = READ( data ); - case 0xCD: // MOV X,imm - x = data; - nz = data; - goto inc_pc_loop; - - case 0xFB: // MOV Y,dp+X - data = uint8_t (data + x); - case 0xEB: // MOV Y,dp - data += dp; - goto mov_y_addr; - case 0xEC: // MOV Y,abs - data = READ_PROG16( pc ); - pc++; - mov_y_addr: - data = READ( data ); - case 0x8D: // MOV Y,imm - y = data; - nz = data; - goto inc_pc_loop; - -// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 - - ADDR_MODES( 0xC8 ) // MOV addr,A - WRITE( data, a ); - goto inc_pc_loop; - - { - int temp; - case 0xCC: // MOV abs,Y - temp = y; - goto mov_abs_temp; - case 0xC9: // MOV abs,X - temp = x; - mov_abs_temp: - WRITE( READ_PROG16( pc ), temp ); - pc += 2; - goto loop; - } - - case 0xD9: // MOV dp+Y,X - data = uint8_t (data + y); - case 0xD8: // MOV dp,X - WRITE( data + dp, x ); - goto inc_pc_loop; - - case 0xDB: // MOV dp+X,Y - data = uint8_t (data + x); - case 0xCB: // MOV dp,Y - WRITE( data + dp, y ); - goto inc_pc_loop; - - case 0xFA: // MOV dp,dp - data = READ( data + dp ); - case 0x8F: // MOV dp,#imm - pc++; - WRITE_DP( READ_PROG( pc ), data ); - goto inc_pc_loop; - -// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. - - case 0x7D: // MOV A,X - a = x; - nz = x; - goto loop; - - case 0xDD: // MOV A,Y - a = y; - nz = y; - goto loop; - - case 0x5D: // MOV X,A - x = a; - nz = a; - goto loop; - - case 0xFD: // MOV Y,A - y = a; - nz = a; - goto loop; - - case 0x9D: // MOV X,SP - x = nz = GET_SP(); - goto loop; - - case 0xBD: // MOV SP,X - SET_SP( x ); - goto loop; - - //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2) - - case 0xAF: // MOV (X)+,A - WRITE_DP( x, a ); - x++; - goto loop; - -// 5. 8-BIT LOGIC OPERATION COMMANDS - -#define LOGICAL_OP( op, func )\ - ADDR_MODES( op ) /* addr */\ - data = READ( data );\ - case op: /* imm */\ - nz = a func##= data;\ - goto inc_pc_loop;\ - { unsigned addr;\ - case op + 0x11: /* X,Y */\ - data = READ_DP( y );\ - addr = x + dp;\ - pc--;\ - goto addr_##op;\ - case op + 0x01: /* dp,dp */\ - data = READ_DP( data );\ - case op + 0x10: /*dp,imm*/\ - pc++;\ - addr = READ_PROG( pc ) + dp;\ - addr_##op:\ - nz = data func READ( addr );\ - WRITE( addr, nz );\ - goto inc_pc_loop;\ - } - - LOGICAL_OP( 0x28, & ); // AND - - LOGICAL_OP( 0x08, | ); // OR - - LOGICAL_OP( 0x48, ^ ); // EOR - -// 4. 8-BIT ARITHMETIC OPERATION COMMANDS - - ADDR_MODES( 0x68 ) // CMP addr - data = READ( data ); - case 0x68: // CMP imm - nz = a - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x79: // CMP (X),(Y) - data = READ_DP( x ); - nz = data - READ_DP( y ); - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x69: // CMP (dp),(dp) - data = READ_DP( data ); - case 0x78: // CMP dp,imm - pc++; - nz = READ_DP( READ_PROG( pc ) ) - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x3E: // CMP X,dp - data += dp; - goto cmp_x_addr; - case 0x1E: // CMP X,abs - data = READ_PROG16( pc ); - pc++; - cmp_x_addr: - data = READ( data ); - case 0xC8: // CMP X,imm - nz = x - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x7E: // CMP Y,dp - data += dp; - goto cmp_y_addr; - case 0x5E: // CMP Y,abs - data = READ_PROG16( pc ); - pc++; - cmp_y_addr: - data = READ( data ); - case 0xAD: // CMP Y,imm - nz = y - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - { - int addr; - case 0xB9: // SBC (x),(y) - case 0x99: // ADC (x),(y) - pc--; // compensate for inc later - data = READ_DP( x ); - addr = y + dp; - goto adc_addr; - case 0xA9: // SBC dp,dp - case 0x89: // ADC dp,dp - data = READ_DP( data ); - case 0xB8: // SBC dp,imm - case 0x98: // ADC dp,imm - pc++; - addr = READ_PROG( pc ) + dp; - adc_addr: - nz = READ( addr ); - goto adc_data; - -// catch ADC and SBC together, then decode later based on operand -#undef CASE -#define CASE( n ) case n: case (n) + 0x20: - ADDR_MODES( 0x88 ) // ADC/SBC addr - data = READ( data ); - case 0xA8: // SBC imm - case 0x88: // ADC imm - addr = -1; // A - nz = a; - adc_data: { - if ( opcode & 0x20 ) - data ^= 0xFF; // SBC - int carry = (c >> 8) & 1; - int ov = (nz ^ 0x80) + carry + (BOOST::int8_t) data; // sign-extend - int hc = (nz & 15) + carry; - c = nz += data + carry; - hc = (nz & 15) - hc; - status = (status & ~(st_v | st_h)) | ((ov >> 2) & st_v) | ((hc >> 1) & st_h); - if ( addr < 0 ) { - a = (uint8_t) nz; - goto inc_pc_loop; - } - WRITE( addr, (uint8_t) nz ); - goto inc_pc_loop; - } - - } - -// 6. ADDITION & SUBTRACTION COMMANDS - -#define INC_DEC_REG( reg, n )\ - nz = reg + n;\ - reg = (uint8_t) nz;\ - goto loop; - - case 0xBC: INC_DEC_REG( a, 1 ) // INC A - case 0x3D: INC_DEC_REG( x, 1 ) // INC X - case 0xFC: INC_DEC_REG( y, 1 ) // INC Y - - case 0x9C: INC_DEC_REG( a, -1 ) // DEC A - case 0x1D: INC_DEC_REG( x, -1 ) // DEC X - case 0xDC: INC_DEC_REG( y, -1 ) // DEC Y - - case 0x9B: // DEC dp+X - case 0xBB: // INC dp+X - data = uint8_t (data + x); - case 0x8B: // DEC dp - case 0xAB: // INC dp - data += dp; - goto inc_abs; - case 0x8C: // DEC abs - case 0xAC: // INC abs - data = READ_PROG16( pc ); - pc++; - inc_abs: - nz = ((opcode >> 4) & 2) - 1; - nz += READ( data ); - WRITE( data, (uint8_t) nz ); - goto inc_pc_loop; - -// 7. SHIFT, ROTATION COMMANDS - - case 0x5C: // LSR A - c = 0; - case 0x7C:{// ROR A - nz = ((c >> 1) & 0x80) | (a >> 1); - c = a << 8; - a = nz; - goto loop; - } - - case 0x1C: // ASL A - c = 0; - case 0x3C:{// ROL A - int temp = (c >> 8) & 1; - c = a << 1; - nz = c | temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x0B: // ASL dp - c = 0; - data += dp; - goto rol_mem; - case 0x1B: // ASL dp+X - c = 0; - case 0x3B: // ROL dp+X - data = uint8_t (data + x); - case 0x2B: // ROL dp - data += dp; - goto rol_mem; - case 0x0C: // ASL abs - c = 0; - case 0x2C: // ROL abs - data = READ_PROG16( pc ); - pc++; - rol_mem: - nz = (c >> 8) & 1; - nz |= (c = READ( data ) << 1); - WRITE( data, (uint8_t) nz ); - goto inc_pc_loop; - - case 0x4B: // LSR dp - c = 0; - data += dp; - goto ror_mem; - case 0x5B: // LSR dp+X - c = 0; - case 0x7B: // ROR dp+X - data = uint8_t (data + x); - case 0x6B: // ROR dp - data += dp; - goto ror_mem; - case 0x4C: // LSR abs - c = 0; - case 0x6C: // ROR abs - data = READ_PROG16( pc ); - pc++; - ror_mem: { - int temp = READ( data ); - nz = ((c >> 1) & 0x80) | (temp >> 1); - c = temp << 8; - WRITE( data, nz ); - goto inc_pc_loop; - } - - case 0x9F: // XCN - nz = a = (a >> 4) | uint8_t (a << 4); - goto loop; - -// 8. 16-BIT TRANSMISION COMMANDS - - case 0xBA: // MOVW YA,dp - a = READ_DP( data ); - nz = (a & 0x7F) | (a >> 1); - y = READ_DP( uint8_t (data + 1) ); - nz |= y; - goto inc_pc_loop; - - case 0xDA: // MOVW dp,YA - WRITE_DP( data, a ); - WRITE_DP( uint8_t (data + 1), y ); - goto inc_pc_loop; - -// 9. 16-BIT OPERATION COMMANDS - - case 0x3A: // INCW dp - case 0x1A:{// DECW dp - data += dp; - - // low byte - int temp = READ( data ); - temp += ((opcode >> 4) & 2) - 1; // +1 for INCW, -1 for DECW - nz = ((temp >> 1) | temp) & 0x7F; - WRITE( data, (uint8_t) temp ); - - // high byte - data = uint8_t (data + 1) + dp; - temp >>= 8; - temp = uint8_t (temp + READ( data )); - nz |= temp; - WRITE( data, temp ); - - goto inc_pc_loop; - } - - case 0x9A: // SUBW YA,dp - case 0x7A: // ADDW YA,dp - { - // read 16-bit addend - int temp = READ_DP( data ); - int sign = READ_DP( uint8_t (data + 1) ); - temp += 0x100 * sign; - status &= ~(st_v | st_h); - - // to do: fix half-carry for SUBW (it's probably wrong) - - // for SUBW, negate and truncate to 16 bits - if ( opcode & 0x80 ) { - temp = (temp ^ 0xFFFF) + 1; - sign = temp >> 8; - } - - // add low byte (A) - temp += a; - a = (uint8_t) temp; - nz = (temp | (temp >> 1)) & 0x7F; - - // add high byte (Y) - temp >>= 8; - c = y + temp; - nz = (nz | c) & 0xFF; - - // half-carry (temporary avoids CodeWarrior optimizer bug) - unsigned hc = (c & 15) - (y & 15); - status |= (hc >> 4) & st_h; - - // overflow if sign of YA changed when previous sign and addend sign were same - status |= (((c ^ y) & ~(y ^ sign)) >> 1) & st_v; - - y = (uint8_t) c; - - goto inc_pc_loop; - } - - case 0x5A: { // CMPW YA,dp - int temp = a - READ_DP( data ); - nz = ((temp >> 1) | temp) & 0x7F; - temp = y + (temp >> 8); - temp -= READ_DP( uint8_t (data + 1) ); - nz |= temp; - c = ~temp; - nz &= 0xFF; - goto inc_pc_loop; - } - -// 10. MULTIPLICATION & DIVISON COMMANDS - - case 0xCF: { // MUL YA - unsigned temp = y * a; - a = (uint8_t) temp; - nz = ((temp >> 1) | temp) & 0x7F; - y = temp >> 8; - nz |= y; - goto loop; - } - - case 0x9E: // DIV YA,X - { - // behavior based on SPC CPU tests - - status &= ~(st_h | st_v); - - if ( (y & 15) >= (x & 15) ) - status |= st_h; - - if ( y >= x ) - status |= st_v; - - unsigned ya = y * 0x100 + a; - if ( y < x * 2 ) - { - a = ya / x; - y = ya - a * x; - } - else - { - a = 255 - (ya - x * 0x200) / (256 - x); - y = x + (ya - x * 0x200) % (256 - x); - } - - nz = (uint8_t) a; - a = (uint8_t) a; - - goto loop; - } - -// 11. DECIMAL COMPENSATION COMMANDS - - // seem unused - // case 0xDF: // DAA - // case 0xBE: // DAS - -// 12. BRANCHING COMMANDS - - case 0x2F: // BRA rel - pc += (BOOST::int8_t) data; - goto inc_pc_loop; - - case 0x30: // BMI - BRANCH( IS_NEG ) - - case 0x10: // BPL - BRANCH( !IS_NEG ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - - case 0x70: // BVS - BRANCH( status & st_v ) - - case 0x50: // BVC - BRANCH( !(status & st_v) ) - - case 0x03: // BBS dp.bit,rel - case 0x23: - case 0x43: - case 0x63: - case 0x83: - case 0xA3: - case 0xC3: - case 0xE3: - pc++; - if ( (READ_DP( data ) >> (opcode >> 5)) & 1 ) - goto cbranch_taken_loop; - goto inc_pc_loop; - - case 0x13: // BBC dp.bit,rel - case 0x33: - case 0x53: - case 0x73: - case 0x93: - case 0xB3: - case 0xD3: - case 0xF3: - pc++; - if ( !((READ_DP( data ) >> (opcode >> 5)) & 1) ) - goto cbranch_taken_loop; - goto inc_pc_loop; - - case 0xDE: // CBNE dp+X,rel - data = uint8_t (data + x); - // fall through - case 0x2E: // CBNE dp,rel - pc++; - if ( READ_DP( data ) != a ) - goto cbranch_taken_loop; - goto inc_pc_loop; - - case 0xFE: // DBNZ Y,rel - y = uint8_t (y - 1); - BRANCH( y ) - - case 0x6E: { // DBNZ dp,rel - pc++; - unsigned temp = READ_DP( data ) - 1; - WRITE_DP( (uint8_t) data, (uint8_t) temp ); - if ( temp ) - goto cbranch_taken_loop; - goto inc_pc_loop; - } - - case 0x1F: // JMP (abs+X) - pc = READ_PROG16( pc ) + x; - // fall through - case 0x5F: // JMP abs - pc = READ_PROG16( pc ); - goto loop; - -// 13. SUB-ROUTINE CALL RETURN COMMANDS - - case 0x0F:{// BRK - check( false ); // untested - PUSH16( pc + 1 ); - pc = READ_PROG16( 0xFFDE ); // vector address verified - int temp; - CALC_STATUS( temp ); - PUSH( temp ); - status = (status | st_b) & ~st_i; - goto loop; - } - - case 0x4F: // PCALL offset - pc++; - PUSH16( pc ); - pc = 0xFF00 + data; - goto loop; - - case 0x01: // TCALL n - case 0x11: - case 0x21: - case 0x31: - case 0x41: - case 0x51: - case 0x61: - case 0x71: - case 0x81: - case 0x91: - case 0xA1: - case 0xB1: - case 0xC1: - case 0xD1: - case 0xE1: - case 0xF1: - PUSH16( pc ); - pc = READ_PROG16( 0xFFDE - (opcode >> 3) ); - goto loop; - -// 14. STACK OPERATION COMMANDS - - { - int temp; - case 0x7F: // RET1 - temp = POP(); - pc = POP(); - pc |= POP() << 8; - goto set_status; - case 0x8E: // POP PSW - temp = POP(); - set_status: - SET_STATUS( temp ); - goto loop; - } - - case 0x0D: { // PUSH PSW - int temp; - CALC_STATUS( temp ); - PUSH( temp ); - goto loop; - } - - case 0x2D: // PUSH A - PUSH( a ); - goto loop; - - case 0x4D: // PUSH X - PUSH( x ); - goto loop; - - case 0x6D: // PUSH Y - PUSH( y ); - goto loop; - - case 0xAE: // POP A - a = POP(); - goto loop; - - case 0xCE: // POP X - x = POP(); - goto loop; - - case 0xEE: // POP Y - y = POP(); - goto loop; - -// 15. BIT OPERATION COMMANDS - - case 0x02: // SET1 - case 0x22: - case 0x42: - case 0x62: - case 0x82: - case 0xA2: - case 0xC2: - case 0xE2: - case 0x12: // CLR1 - case 0x32: - case 0x52: - case 0x72: - case 0x92: - case 0xB2: - case 0xD2: - case 0xF2: { - data += dp; - int bit = 1 << (opcode >> 5); - int mask = ~bit; - if ( opcode & 0x10 ) - bit = 0; - WRITE( data, (READ( data ) & mask) | bit ); - goto inc_pc_loop; - } - - case 0x0E: // TSET1 abs - case 0x4E:{// TCLR1 abs - data = READ_PROG16( pc ); - pc += 2; - unsigned temp = READ( data ); - nz = temp & a; - temp &= ~a; - if ( !(opcode & 0x40) ) - temp |= a; - WRITE( data, temp ); - goto loop; - } - - case 0x4A: // AND1 C,mem.bit - c &= mem_bit( pc ); - pc += 2; - goto loop; - - case 0x6A: // AND1 C,/mem.bit - check( false ); // untested - c &= ~mem_bit( pc ); - pc += 2; - goto loop; - - case 0x0A: // OR1 C,mem.bit - check( false ); // untested - c |= mem_bit( pc ); - pc += 2; - goto loop; - - case 0x2A: // OR1 C,/mem.bit - check( false ); // untested - c |= ~mem_bit( pc ); - pc += 2; - goto loop; - - case 0x8A: // EOR1 C,mem.bit - c ^= mem_bit( pc ); - pc += 2; - goto loop; - - case 0xEA: { // NOT1 mem.bit - data = READ_PROG16( pc ); - pc += 2; - unsigned temp = READ( data & 0x1FFF ); - temp ^= 1 << (data >> 13); - WRITE( data & 0x1FFF, temp ); - goto loop; - } - - case 0xCA: { // MOV1 mem.bit,C - data = READ_PROG16( pc ); - pc += 2; - unsigned temp = READ( data & 0x1FFF ); - unsigned bit = data >> 13; - temp = (temp & ~(1 << bit)) | (((c >> 8) & 1) << bit); - WRITE( data & 0x1FFF, temp ); - goto loop; - } - - case 0xAA: // MOV1 C,mem.bit - c = mem_bit( pc ); - pc += 2; - goto loop; - -// 16. PROGRAM STATUS FLAG OPERATION COMMANDS - - case 0x60: // CLRC - c = 0; - goto loop; - - case 0x80: // SETC - c = ~0; - goto loop; - - case 0xED: // NOTC - c ^= 0x100; - goto loop; - - case 0xE0: // CLRV - status &= ~(st_v | st_h); - goto loop; - - case 0x20: // CLRP - dp = 0; - goto loop; - - case 0x40: // SETP - dp = 0x100; - goto loop; - - case 0xA0: // EI - check( false ); // untested - status |= st_i; - goto loop; - - case 0xC0: // DI - check( false ); // untested - status &= ~st_i; - goto loop; - -// 17. OTHER COMMANDS - - case 0x00: // NOP - goto loop; - - //case 0xEF: // SLEEP - //case 0xFF: // STOP - - } // switch - - // unhandled instructions fall out of switch so emulator can catch them - -stop: - pc--; - - { - int temp; - CALC_STATUS( temp ); - r.status = (uint8_t) temp; - } - - r.pc = pc; - r.sp = (uint8_t) GET_SP(); - r.a = (uint8_t) a; - r.x = (uint8_t) x; - r.y = (uint8_t) y; - - return remain_; -} |