From f40bfc9267b13b54e6379dfe7539447662879d24 Mon Sep 17 00:00:00 2001 From: Sean Bartell Date: Sat, 25 Jun 2011 21:32:25 -0400 Subject: Add codecs to librbcodec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius Tested-by: Nils Wallménius --- lib/rbcodec/codecs/libspc/spc_cpu.c | 1049 +++++++++++++++++++++++++++++++++++ 1 file changed, 1049 insertions(+) create mode 100644 lib/rbcodec/codecs/libspc/spc_cpu.c (limited to 'lib/rbcodec/codecs/libspc/spc_cpu.c') diff --git a/lib/rbcodec/codecs/libspc/spc_cpu.c b/lib/rbcodec/codecs/libspc/spc_cpu.c new file mode 100644 index 0000000000..23dcc257de --- /dev/null +++ b/lib/rbcodec/codecs/libspc/spc_cpu.c @@ -0,0 +1,1049 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006-2007 Adam Gashlin (hcs) + * Copyright (C) 2004-2007 Shay Green (blargg) + * Copyright (C) 2002 Brad Martin + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* The CPU portion (shock!) */ +#include "codeclib.h" +#include "spc_codec.h" +#include "spc_profiler.h" + +#undef check +#define check assert + +#define READ( addr ) (SPC_read( this, addr, spc_time_ )) +#define WRITE( addr, value ) (SPC_write( this, addr, value, spc_time_ )) + +#define READ_DP( addr ) READ( (addr) + dp ) +#define WRITE_DP( addr, value ) WRITE( (addr) + dp, value ) + +#define READ_PROG16( addr ) GET_LE16( RAM + (addr) ) + +#define READ_PC( pc ) (*(pc)) +#define READ_PC16( pc ) GET_LE16( pc ) + +#define SET_PC( n ) (pc = RAM + (n)) +#define GET_PC() (pc - RAM) + +static unsigned char const cycle_table [0x100] = { + 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 */ +}; + +#define MEM_BIT() CPU_mem_bit( this, pc, spc_time_ ) + +static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ ) + ICODE_ATTR_SPC; + +static unsigned CPU_mem_bit( THIS, uint8_t const* pc, long const spc_time_ ) +{ + unsigned addr = READ_PC16( pc ); + unsigned t = READ( addr & 0x1FFF ) >> (addr >> 13); + return (t << 8) & 0x100; +} + +/* status flags */ +enum { st_n = 0x80 }; +enum { st_v = 0x40 }; +enum { st_p = 0x20 }; +enum { st_b = 0x10 }; +enum { st_h = 0x08 }; +enum { st_i = 0x04 }; +enum { st_z = 0x02 }; +enum { st_c = 0x01 }; + +#define IS_NEG (nz & 0x880) + +#define CALC_STATUS( out )\ +{\ + 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;\ +} + +#define SET_STATUS( in )\ +{\ + status = in & ~(st_n | st_z | st_c | st_p);\ + c = in << 8;\ + nz = ((in << 4) & 0x800) | (~in & st_z);\ + dp = (in << 3) & 0x100;\ +} + + +/* stack */ +#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) + +long CPU_run( THIS, long start_time ) +{ +#if 0 + ENTER_TIMER(cpu); +#endif + + register long spc_time_ = start_time; + +#ifdef CPU_ARM + uint8_t* const ram_ = ram.ram; + #undef RAM + #define RAM ram_ +#endif + + int a = this->r.a; + int x = this->r.x; + int y = this->r.y; + + uint8_t const* pc; + SET_PC( this->r.pc ); + + uint8_t* sp; + SET_SP( this->r.sp ); + + int status; + int c; + int nz; + unsigned dp; + { + int temp = this->r.status; + SET_STATUS( temp ); + } + + goto loop; + + /* main loop */ +cbranch_taken_loop: + pc += *(int8_t const*) pc; + spc_time_ += 2; +inc_pc_loop: + pc++; +loop: + check( (unsigned) GET_PC() < 0x10000 ); + check( (unsigned) GET_SP() < 0x100 ); + check( (unsigned) a < 0x100 ); + check( (unsigned) x < 0x100 ); + check( (unsigned) y < 0x100 ); + + unsigned opcode = *pc; + int cycles = this->cycle_table [opcode]; + unsigned data = *++pc; + if ( (spc_time_ += cycles) > 0 ) + goto out_of_time; + switch ( opcode ) + { + +/* Common instructions */ + +#define BRANCH( cond )\ +{\ + pc++;\ + int offset = (int8_t) data;\ + if ( cond ) {\ + pc += offset;\ + spc_time_ += 2;\ + }\ + goto loop;\ +} + + case 0xF0: /* BEQ (most common) */ + BRANCH( !(uint8_t) nz ) + + case 0xD0: /* BNE */ + BRANCH( (uint8_t) nz ) + + case 0x3F: /* CALL */ + PUSH16( GET_PC() + 2 ); + SET_PC( READ_PC16( pc ) ); + goto loop; + + case 0x6F: /* RET */ + SET_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:\ + data += 0x100 * READ_PC( ++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_PC16( 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_PC16( 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_PC16( 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 */ + WRITE_DP( READ_PC( ++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*/\ + addr = READ_PC( ++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 */ + nz = READ_DP( READ_PC( ++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_PC16( 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_PC16( 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 */ + addr = READ_PC( ++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 + (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_PC16( 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_PC16( 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_PC16( 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 += (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) */ + SET_PC( READ_PC16( pc ) + x ); + /* fall through */ + case 0x5F: /* JMP abs */ + SET_PC( READ_PC16( pc ) ); + goto loop; + +/* 13. SUB-ROUTINE CALL RETURN COMMANDS */ + + case 0x0F:{/* BRK */ + check( 0 ); /* untested */ + PUSH16( GET_PC() + 1 ); + SET_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 */ + PUSH16( GET_PC() + 1 ); + SET_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( GET_PC() ); + SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) ); + goto loop; + +/* 14. STACK OPERATION COMMANDS */ + + { + int temp; + case 0x7F: /* RET1 */ + temp = POP(); + SET_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_PC16( 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 += 2; + goto loop; + + case 0x6A: /* AND1 C,/mem.bit */ + check( 0 ); /* untested */ + c &= ~MEM_BIT(); + pc += 2; + goto loop; + + case 0x0A: /* OR1 C,mem.bit */ + check( 0 ); /* untested */ + c |= MEM_BIT(); + pc += 2; + goto loop; + + case 0x2A: /* OR1 C,/mem.bit */ + check( 0 ); /* untested */ + c |= ~MEM_BIT(); + pc += 2; + goto loop; + + case 0x8A: /* EOR1 C,mem.bit */ + c ^= MEM_BIT(); + pc += 2; + goto loop; + + case 0xEA: { /* NOT1 mem.bit */ + data = READ_PC16( 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_PC16( 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 += 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( 0 ); /* untested */ + status |= st_i; + goto loop; + + case 0xC0: /* DI */ + check( 0 ); /* untested */ + status &= ~st_i; + goto loop; + +/* 17. OTHER COMMANDS */ + + case 0x00: /* NOP */ + goto loop; + + /*case 0xEF:*/ /* SLEEP */ + /*case 0xFF:*/ /* STOP */ + case 0xFF: + c |= 1; /* force switch table to have 256 entries, + hopefully helping optimizer */ + } /* switch */ + + /* unhandled instructions fall out of switch so emulator can catch them */ + +out_of_time: + /* undo partial execution of opcode */ + spc_time_ -= this->cycle_table [*--pc]; + { + int temp; + CALC_STATUS( temp ); + this->r.status = (uint8_t) temp; + } + + this->r.pc = GET_PC(); + this->r.sp = (uint8_t) GET_SP(); + this->r.a = (uint8_t) a; + this->r.x = (uint8_t) x; + this->r.y = (uint8_t) y; + +#if 0 + EXIT_TIMER(cpu); +#endif + return spc_time_; +} + +void CPU_Init( THIS ) +{ + ci->memcpy( this->cycle_table, cycle_table, sizeof cycle_table ); +} + -- cgit v1.2.3