From 7b16c23f705f1cb60dd303f10f0eb3c49a72e65e Mon Sep 17 00:00:00 2001 From: NewRisingSun <8vytz1+dhp372pv94ebg@sharklasers.com> Date: Fri, 11 Apr 2025 19:30:14 +0200 Subject: [PATCH] Rewrite mapper 355 to actually work, using emulation of the PIC using NES 2.0 Misc. ROM data. --- src/boards/355.c | 121 ++++ src/boards/3d-block.c | 95 --- src/boards/pic16c5x.c | 1001 ++++++++++++++++++++++++++++++ src/boards/pic16c5x.h | 57 ++ src/boards/pic16c5x_ops_00x.inc | 16 + src/boards/pic16c5x_ops_main.inc | 287 +++++++++ 6 files changed, 1482 insertions(+), 95 deletions(-) create mode 100644 src/boards/355.c delete mode 100644 src/boards/3d-block.c create mode 100644 src/boards/pic16c5x.c create mode 100644 src/boards/pic16c5x.h create mode 100644 src/boards/pic16c5x_ops_00x.inc create mode 100644 src/boards/pic16c5x_ops_main.inc diff --git a/src/boards/355.c b/src/boards/355.c new file mode 100644 index 0000000..5f2c659 --- /dev/null +++ b/src/boards/355.c @@ -0,0 +1,121 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * Copyright (C) 2025 NewRisingSun + * + * 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 "mapinc.h" +#include "pic16c5x.h" + +static uint32 address; +static uint8 *picrom = NULL; + +static uint8_t pci16c5x_read(int port) { + if (port == 0) { + return (1 | + (address & 0x0040 ? 0x02 : 0) | /* A6 -> RA1 */ + (address & 0x0020 ? 0x04 : 0) | /* A5 -> RA2 */ + (address & 0x0010 ? 0x08 : 0)); /* A4 -> RA3 */ + } else if (port == 1) { + return ( + (address & 0x1000 ? 0x01 : 0) | /* A12 -> RB0 */ + (address & 0x0080 ? 0x02 : 0) | /* A7 -> RB1 */ + (address & 0x0400 ? 0x04 : 0) | /* A10 -> RB2 */ + (address & 0x0800 ? 0x08 : 0) | /* A11 -> RB3 */ + (address & 0x0200 ? 0x10 : 0) | /* A9 -> RB4 */ + (address & 0x0100 ? 0x20 : 0) | /* A8 -> RB5 */ + (address & 0x2000 ? 0x40 : 0) | /* A13 -> RB6 */ + (address & 0x4000 ? 0x80 : 0)); /* A14 -> RB7 */ + } + return (0xFF); +} + +static void pci16c5x_write(int port, int val) { + if (port == 0) { + if (val & 0x1001) { + X6502_IRQEnd(FCEU_IQEXT); + } else { + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void M355CPUIRQHook(int a) { + while (a--) { + pic16c5x_run(); + } +} + +static readfunc cpuRead[0x10000]; +static writefunc cpuWrite[0x10000]; + +static DECLFR(M355Read) { + address = A; + if (A >= 0x8000) { + return CartBR(A); + } + return cpuRead[A](A); +} + +static DECLFW(M355Write) { + address = A; + if (cpuWrite[A]) { + cpuWrite[A](A, V); + } +} + +static void M355Power(void) { + int x; + + address = 0; + + pic16c5x_reset(1); + + setprg32(0x8000, 0); + setchr8(0); + + for (x = 0; x < 0x10000; x++) { + cpuRead[x] = GetReadHandler(x); + cpuWrite[x] = GetWriteHandler(x); + } + + SetReadHandler(0, 0xFFFF, M355Read); + SetWriteHandler(0, 0xFFFF, M355Write); +} + +static void M355Reset(void) { + address = 0; + pic16c5x_reset(0); +} + +static void M355Close(void) { + picrom = NULL; +} + +void UNL3DBlock_Init(CartInfo *info) { + if (MiscROM && info->miscROMSize) picrom = MiscROM; + if (picrom) { + pic16c54_init(picrom, pci16c5x_read, pci16c5x_write); + pic16c5x_add_statesinfo(); + } + info->Power = M355Power; + info->Reset = M355Reset; + info->Close = M355Close; + MapIRQHook = M355CPUIRQHook; + AddExState(&address, sizeof(address), 0, "ADDR"); +} diff --git a/src/boards/3d-block.c b/src/boards/3d-block.c deleted file mode 100644 index c5ed2ea..0000000 --- a/src/boards/3d-block.c +++ /dev/null @@ -1,95 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 - * - * 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 "mapinc.h" - -static uint8 reg[4], IRQa; -static int16 IRQCount, IRQPause; - -static int16 Count = 0x0000; - -static SFORMAT StateRegs[] = -{ - { reg, 4, "REGS" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { 0 } -}; - -static void Sync(void) { - setprg32(0x8000, 0); - setchr8(0); -} - -/* #define Count 0x1800 */ -#define Pause 0x010 - -static DECLFW(UNL3DBlockWrite) { - switch (A) { -/* 4800 32 */ -/* 4900 37 */ -/* 4a00 01 */ -/* 4e00 18 */ - case 0x4800: reg[0] = V; break; - case 0x4900: reg[1] = V; break; - case 0x4a00: reg[2] = V; break; - case 0x4e00: reg[3] = V; IRQCount = Count; IRQPause = Pause; IRQa = 1; X6502_IRQEnd(FCEU_IQEXT); break; - } -} - -static void UNL3DBlockPower(void) { - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4800, 0x4E00, UNL3DBlockWrite); -} - -static void UNL3DBlockReset(void) { - Count += 0x10; - FCEU_printf("Count=%04x\n", Count); -} - -static void FP_FASTAPASS(1) UNL3DBlockIRQHook(int a) { - if (IRQa) { - if (IRQCount > 0) { - IRQCount -= a; - } else { - if (IRQPause > 0) { - IRQPause -= a; - X6502_IRQBegin(FCEU_IQEXT); - } else { - IRQCount = Count; - IRQPause = Pause; - X6502_IRQEnd(FCEU_IQEXT); - } - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void UNL3DBlock_Init(CartInfo *info) { - info->Power = UNL3DBlockPower; - info->Reset = UNL3DBlockReset; - MapIRQHook = UNL3DBlockIRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/pic16c5x.c b/src/boards/pic16c5x.c new file mode 100644 index 0000000..1443e00 --- /dev/null +++ b/src/boards/pic16c5x.c @@ -0,0 +1,1001 @@ +/* license:BSD-3-Clause + copyright-holders:Tony La Porta */ + /**************************************************************************\ + * Microchip PIC16C5x Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + * * + * **** Change Log **** * + * TLP (06-Apr-2003) * + * - First Public release. * + * BO (07-Apr-2003) Ver 1.01 * + * - Renamed 'sleep' function to 'sleepic' to avoid C conflicts. * + * TLP (09-Apr-2003) Ver 1.10 * + * - Fixed modification of file register $03 (Status). * + * - Corrected support for 7FFh (12-bit) size ROMs. * + * - The 'call' and 'goto' instructions weren't correctly handling the * + * STATUS page info correctly. * + * - The FSR register was incorrectly oring the data with 0xe0 when read. * + * - Prescaler masking information was set to 3 instead of 7. * + * - Prescaler assign bit was set to 4 instead of 8. * + * - Timer source and edge select flags/masks were wrong. * + * - Corrected the memory bank selection in GET/SET_REGFILE and also the * + * indirect register addressing. * + * BMP (18-May-2003) Ver 1.11 * + * - PIC16C5x_get_reg functions were missing 'returns'. * + * TLP (27-May-2003) Ver 1.12 * + * - Fixed the WatchDog timer count. * + * - The Prescaler rate was incorrectly being zeroed, instead of the * + * actual Prescaler counter in the CLRWDT and SLEEP instructions. * + * - Added masking to the FSR register. Upper unused bits are always 1. * + * TLP (27-Aug-2009) Ver 1.13 * + * - Indirect addressing was not taking into account special purpose * + * memory mapped locations. * + * - 'iorlw' instruction was saving the result to memory instead of * + * the W register. * + * - 'tris' instruction no longer modifies Port-C on PIC models that * + * do not have Port-C implemented. * + * TLP (07-Sep-2009) Ver 1.14 * + * - Edge sense control for the T0 count input was incorrectly reversed * + * LE (05-Feb-2017) Ver 1.15 * + * - Allow writing all bits of the status register except TO and PD. * + * This enables e.g. bcf, bsf or clrf to change the flags when the * + * status register is the destination. * + * - Changed rlf and rrf to update the carry flag in the last step. * + * Fixes the case where the status register is the destination. * + * hap (12-Feb-2017) Ver 1.16 * + * - Added basic support for the old GI PIC1650 and PIC1655. * + * - Made RTCC(aka T0CKI) pin an inputline handler. * + * * + * * + * **** Notes: **** * + * PIC WatchDog Timer has a separate internal clock. For the moment, we're * + * basing the count on a 4MHz input clock, since 4MHz is the typical * + * input frequency (but by no means always). * + * A single scaler is available for the Counter/Timer or WatchDog Timer. * + * When connected to the Counter/Timer, it functions as a Prescaler, * + * hence prescale overflows, tick the Counter/Timer. * + * When connected to the WatchDog Timer, it functions as a Postscaler * + * hence WatchDog Timer overflows, tick the Postscaler. This scenario * + * means that the WatchDog timeout occurs when the Postscaler has * + * reached the scaler rate value, not when the WatchDog reaches zero. * + * CLRWDT should prevent the WatchDog Timer from timing out and generating * + * a device reset, but how is not known. The manual also mentions that * + * the WatchDog Timer can only be disabled during ROM programming, and * + * no other means seem to exist??? * + * * + \**************************************************************************/ + +#include +#include "pic16c5x.h" + +/******************** CPU Internal Registers *******************/ +static uint16 m_PC; +static uint16 m_PREVPC; /* previous program counter */ +static uint8 m_W; +static uint8 m_OPTION; +static uint16 m_CONFIG; +static uint8 m_ALU; +static uint16 m_WDT; +static uint8 m_TRISA; +static uint8 m_TRISB; +static uint8 m_TRISC; +static uint16 m_STACK[2]; +static uint16 m_prescaler; /* Note: this is really an 8-bit register */ +static uint16 m_opcode; +static uint8 m_internalram[128]; +static uint8 *m_rom; + +static int m_icount; +static int m_picmodel; +static int m_delay_timer; +static uint16 m_temp_config; +static int m_rtcc; +static uint8 m_count_pending; /* boolean type */ +static int8 m_old_data; +static uint8 m_picRAMmask; +static uint16 m_picROMmask; +static int m_inst_cycles; +static int m_clock2cycle; + +/*address_space *m_program; +memory_access_cache<1, -1, ENDIANNESS_LITTLE> *m_cache; +address_space *m_data;*/ + +/* i/o handlers */ +static pic16c5x_readfunc m_read; +static pic16c5x_writefunc m_write; + +static void PIC16C5x(int program_width, int data_width, int picmodel, uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) +{ + m_rom = rom; + m_picmodel = picmodel; + m_temp_config = 0; + m_picRAMmask = ((1 << data_width) - 1); + m_picROMmask = ((1 << program_width) - 1); + m_read = _rd; + m_write = _wr; + m_PC = 0; + m_PREVPC = 0; + m_W = 0; + m_OPTION = 0; + m_CONFIG = 0; + m_ALU = 0; + m_WDT = 0; + m_TRISA = 0; + m_TRISB = 0; + m_TRISC = 0; + m_prescaler = 0; + m_icount = 0; + m_delay_timer = 0; + m_rtcc = 0; + m_count_pending = 0; + m_old_data = 0; + m_inst_cycles = 0; + m_clock2cycle = 0; +} + +void pic16c54_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x16C54, rom, _rd, _wr); } +void pic16c55_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x16C55, rom, _rd, _wr); } +void pic16c56_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x(10, 5, 0x16C56, rom, _rd, _wr); } +void pic16c57_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x(11, 7, 0x16C57, rom, _rd, _wr); } +void pic16c58_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x(11, 7, 0x16C58, rom, _rd, _wr); } +void pic1650_init (uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x1650, rom, _rd, _wr); } +void pic1655_init (uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x1655, rom, _rd, _wr); } + +#define M_OPCODE_B0 (m_opcode & 0xFF) +#define M_OPCODE_B1 ((m_opcode >> 8) & 0xFF) +#define M_OPCODE_S0 m_opcode + +#define M_RDRAM(A) m_internalram[A &m_picRAMmask] +#define M_WRTRAM(A,V) m_internalram[A &m_picRAMmask] =(V) +#define M_RDOP(A) m_rom[(A &m_picROMmask) <<1 |0] | m_rom[(A &m_picROMmask) <<1 |1] <<8 +#define ADDR_MASK 0x7ff + +#define TMR0 m_internalram[1] +#define PCL m_internalram[2] +#define STATUS m_internalram[3] +#define FSR m_internalram[4] +#define PORTA m_internalram[5] +#define PORTB m_internalram[6] +#define PORTC m_internalram[7] +#define PORTD m_internalram[8] +#define INDF M_RDRAM(FSR) + +#define ADDR (M_OPCODE_B0 & 0x1f) + + +/******** The following is the Status Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | PA | TO | PD | Z | DC | C | */ +#define PA_REG 0xe0 /* PA Program Page Preselect - bit 8 is unused here */ +#define TO_FLAG 0x10 /* TO Time Out flag (WatchDog) */ +#define PD_FLAG 0x08 /* PD Power Down flag */ +#define Z_FLAG 0x04 /* Z Zero Flag */ +#define DC_FLAG 0x02 /* DC Digit Carry/Borrow flag (Nibble) */ +#define C_FLAG 0x01 /* C Carry/Borrow Flag (Byte) */ + +#define PA (STATUS & PA_REG) +#define TO (STATUS & TO_FLAG) +#define PD (STATUS & PD_FLAG) +#define ZERO (STATUS & Z_FLAG) +#define DC (STATUS & DC_FLAG) +#define CARRY (STATUS & C_FLAG) + + +/******** The following is the Option Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | 0 | 0 | TOCS | TOSE | PSA | PS | */ +#define T0CS_FLAG 0x20 /* TOCS Timer 0 clock source select */ +#define T0SE_FLAG 0x10 /* TOSE Timer 0 clock source edge select */ +#define PSA_FLAG 0x08 /* PSA Prescaler Assignment bit */ +#define PS_REG 0x07 /* PS Prescaler Rate select */ + +#define T0CS (m_OPTION & T0CS_FLAG) +#define T0SE (m_OPTION & T0SE_FLAG) +#define PSA (m_OPTION & PSA_FLAG) +#define PS (m_OPTION & PS_REG) + + +/******** The following is the Config Flag register definition. *********/ + /* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | CP | WDTE | FOSC | */ + /* CP Code Protect (ROM read protect) */ +#define WDTE_FLAG 0x04 /* WDTE WatchDog Timer enable */ +#define FOSC_FLAG 0x03 /* FOSC Oscillator source select */ + +#define WDTE (m_CONFIG & WDTE_FLAG) +#define FOSC (m_CONFIG & FOSC_FLAG) + + +/************************************************************************ + * Shortcuts + ************************************************************************/ + +#define CLR(flagreg, flag) ( flagreg &= (uint8)(~flag) ) +#define SET(flagreg, flag) ( flagreg |= flag ) + + +/* Easy bit position selectors */ +#define POS ((M_OPCODE_B0 >> 5) & 7) +static const unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; +static const unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + +static INLINE void CALCULATE_Z_FLAG(void) +{ + if (m_ALU == 0) SET(STATUS, Z_FLAG); + else CLR(STATUS, Z_FLAG); +} + +static INLINE void CALCULATE_ADD_CARRY(void) +{ + if ((uint8)(m_old_data) > (uint8)(m_ALU)) { + SET(STATUS, C_FLAG); + } + else { + CLR(STATUS, C_FLAG); + } +} + +static INLINE void CALCULATE_ADD_DIGITCARRY(void) +{ + if (((uint8)(m_old_data) & 0x0f) > ((uint8)(m_ALU) & 0x0f)) { + SET(STATUS, DC_FLAG); + } + else { + CLR(STATUS, DC_FLAG); + } +} + +static INLINE void CALCULATE_SUB_CARRY(void) +{ + if ((uint8)(m_old_data) < (uint8)(m_ALU)) { + CLR(STATUS, C_FLAG); + } + else { + SET(STATUS, C_FLAG); + } +} + +static INLINE void CALCULATE_SUB_DIGITCARRY(void) +{ + if (((uint8)(m_old_data) & 0x0f) < ((uint8)(m_ALU) & 0x0f)) { + CLR(STATUS, DC_FLAG); + } + else { + SET(STATUS, DC_FLAG); + } +} + + + +static INLINE uint16 POP_STACK(void) +{ + uint16 data = m_STACK[1]; + m_STACK[1] = m_STACK[0]; + return (data & ADDR_MASK); +} +static INLINE void PUSH_STACK(uint16 data) +{ + m_STACK[0] = m_STACK[1]; + m_STACK[1] = (data & ADDR_MASK); +} + + + +static INLINE uint8 GET_REGFILE(uint32_t addr) /* Read from internal memory */ +{ + uint8 data = 0; + + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) { + addr |= (FSR & 0x60); /* FSR bits 6-5 are used for banking in direct mode */ + } + + if ((addr & 0x10) == 0) addr &= 0x0f; + + switch(addr) + { + case 0: /* Not an actual register, so return 0 */ + data = 0; + break; + case 4: data = (FSR | (uint8)(~m_picRAMmask)); + break; + case 5: /* read port A */ + if (m_picmodel == 0x1650) { + data = m_read(PIC16C5x_PORTA) & PORTA; + } + else if (m_picmodel == 0x1655) { + data = m_read(PIC16C5x_PORTA) & 0x0f; + } + else { + data = m_read(PIC16C5x_PORTA); + data &= m_TRISA; + data |= ((uint8)(~m_TRISA) & PORTA); + data &= 0x0f; /* 4-bit port (only lower 4 bits used) */ + } + break; + case 6: /* read port B */ + if (m_picmodel == 0x1650) { + data = m_read(PIC16C5x_PORTB) & PORTB; + } + else if (m_picmodel != 0x1655) { /* B is output-only on 1655 */ + data = m_read(PIC16C5x_PORTB); + data &= m_TRISB; + data |= ((uint8)(~m_TRISB) & PORTB); + } + break; + case 7: /* read port C */ + if (m_picmodel == 0x1650 || m_picmodel == 0x1655) { + data = m_read(PIC16C5x_PORTC) & PORTC; + } + else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + data = m_read(PIC16C5x_PORTC); + data &= m_TRISC; + data |= ((uint8)(~m_TRISC) & PORTC); + } + else { /* PIC16C54, PIC16C56, PIC16C58 */ + data = M_RDRAM(addr); + } + break; + case 8: /* read port D */ + if (m_picmodel == 0x1650) { + data = m_read(PIC16C5x_PORTD) & PORTD; + } + else { + data = M_RDRAM(addr); + } + break; + default: data = M_RDRAM(addr); + break; + } + return data; +} + +static INLINE void STORE_REGFILE(uint32_t addr, uint8 data) /* Write to internal memory */ +{ + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) { + addr |= (FSR & 0x60); /* FSR bits 6-5 are used for banking in direct mode */ + } + + if ((addr & 0x10) == 0) addr &= 0x0f; + + switch(addr) + { + case 0: /* Not an actual register, nothing to save */ + break; + case 1: m_delay_timer = 2; /* Timer starts after next two instructions */ + if (PSA == 0) m_prescaler = 0; /* Must clear the Prescaler */ + TMR0 = data; + break; + case 2: PCL = data; + m_PC = ((STATUS & PA_REG) << 4) | data; + break; + case 3: STATUS = (STATUS & (TO_FLAG | PD_FLAG)) | (data & (uint8)(~(TO_FLAG | PD_FLAG))); + break; + case 4: FSR = (data | (uint8)(~m_picRAMmask)); + break; + case 5: /* write port A */ + if (m_picmodel == 0x1650) { + m_write(PIC16C5x_PORTA, data); + } + else if (m_picmodel != 0x1655) { /* A is input-only on 1655 */ + data &= 0x0f; /* 4-bit port (only lower 4 bits used) */ + m_write(PIC16C5x_PORTA, data & (uint8)(~m_TRISA)); + } + PORTA = data; + break; + case 6: /* write port B */ + if (m_picmodel == 0x1650 || m_picmodel == 0x1655) { + m_write(PIC16C5x_PORTB, data); + } + else { + m_write(PIC16C5x_PORTB, data & (uint8)(~m_TRISB)); + } + PORTB = data; + break; + case 7: /* write port C */ + if (m_picmodel == 0x1650 || m_picmodel == 0x1655) { + m_write(PIC16C5x_PORTC, data); + } + else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + m_write(PIC16C5x_PORTC, data & (uint8)(~m_TRISC)); + } + PORTC = data; /* also writes to RAM */ + break; + case 8: /* write port D */ + if (m_picmodel == 0x1650) { + m_write(PIC16C5x_PORTD, data); + } + PORTD = data; /* also writes to RAM */ + break; + default: M_WRTRAM(addr, data); + break; + } +} + + +static INLINE void STORE_RESULT(uint32_t addr, uint8 data) +{ + if (M_OPCODE_B0 & 0x20) + { + STORE_REGFILE(addr, data); + } + else + { + m_W = data; + } +} + + +/************************************************************************ + * Emulate the Instructions + ************************************************************************/ + +/* This following function is here to fill in the void for */ +/* the opcode call function. This function is never called. */ + + +static INLINE void illegal(void) +{ + /* printf("PIC16C5x: PC=%03x, Illegal opcode = %04x\n", (m_PC-1), M_OPCODE_S0); */ +} + +/* + Note: + According to the manual, if the STATUS register is the destination for an instruction that affects the Z, DC or C bits + then the write to these three bits is disabled. These bits are set or cleared according to the device logic. + To ensure this is correctly emulated, in instructions that write to the file registers, always change the status flags + *after* storing the result of the instruction. + e.g. CALCULATE_*, SET(STATUS,*_FLAG) and CLR(STATUS,*_FLAG) should appear as the last steps of the instruction emulation. +*/ + +static INLINE void addwf(void) +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data + m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_ADD_CARRY(); + CALCULATE_ADD_DIGITCARRY(); +} + +static INLINE void andwf(void) +{ + m_ALU = GET_REGFILE(ADDR) & m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void andlw(void) +{ + m_ALU = M_OPCODE_B0 & m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +static INLINE void bcf(void) +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU &= bit_clr[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +static INLINE void bsf(void) +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU |= bit_set[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +static INLINE void btfss(void) +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS]) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void btfsc(void) +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void call(void) +{ + PUSH_STACK(m_PC); + m_PC = ((STATUS & PA_REG) << 4) | M_OPCODE_B0; + m_PC &= 0x6ff; + PCL = m_PC & 0xff; +} + +static INLINE void clrw(void) +{ + m_W = 0; + SET(STATUS, Z_FLAG); +} + +static INLINE void clrf(void) +{ + STORE_REGFILE(ADDR, 0); + SET(STATUS, Z_FLAG); +} + +static INLINE void clrwdt(void) +{ + m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + SET(STATUS, PD_FLAG); +} + +static INLINE void comf(void) +{ + m_ALU = (uint8)(~(GET_REGFILE(ADDR))); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void decf(void) +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void decfsz(void) +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void goto_op(void) +{ + m_PC = ((STATUS & PA_REG) << 4) | (M_OPCODE_S0 & 0x1ff); + m_PC &= ADDR_MASK; + PCL = m_PC & 0xff; +} + +static INLINE void incf(void) +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void incfsz(void) +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void iorlw(void) +{ + m_ALU = M_OPCODE_B0 | m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +static INLINE void iorwf(void) +{ + m_ALU = GET_REGFILE(ADDR) | m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void movf(void) +{ + m_ALU = GET_REGFILE(ADDR); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void movlw(void) +{ + m_W = M_OPCODE_B0; +} + +static INLINE void movwf(void) +{ + STORE_REGFILE(ADDR, m_W); +} + +static INLINE void nop(void) +{ + /* Do nothing */ +} + +static INLINE void option(void) +{ + m_OPTION = m_W & (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); +} + +static INLINE void retlw(void) +{ + m_W = M_OPCODE_B0; + m_PC = POP_STACK(); + PCL = m_PC & 0xff; +} + +static INLINE void rlf(void) +{ + uint8 bit7; + m_ALU = GET_REGFILE(ADDR); + bit7 = m_ALU & 0x80; + m_ALU <<= 1; + if (STATUS & C_FLAG) m_ALU |= 1; + STORE_RESULT(ADDR, m_ALU); + if (bit7) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); +} + +static INLINE void rrf(void) +{ + uint8 bit0; + m_ALU = GET_REGFILE(ADDR); + bit0 = m_ALU & 1; + m_ALU >>= 1; + if (STATUS & C_FLAG) m_ALU |= 0x80; + STORE_RESULT(ADDR, m_ALU); + if (bit0) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); +} + +static INLINE void sleepic(void) +{ + if (WDTE) m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + CLR(STATUS, PD_FLAG); +} + +static INLINE void subwf(void) +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data - m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_SUB_CARRY(); + CALCULATE_SUB_DIGITCARRY(); +} + +static INLINE void swapf(void) +{ + m_ALU = ((GET_REGFILE(ADDR) << 4) & 0xf0); + m_ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f); + STORE_RESULT(ADDR, m_ALU); +} + +static INLINE void tris(void) +{ + switch(M_OPCODE_B0 & 0x7) + { + case 5: if (m_TRISA == m_W) break; + else { m_TRISA = m_W | 0xf0; m_write(PIC16C5x_PORTA, 0x1000 | (PORTA & (uint8)(~m_TRISA) & 0x0f)); break; } + case 6: if (m_TRISB == m_W) break; + else { m_TRISB = m_W; m_write(PIC16C5x_PORTB, 0x1000 | (PORTB & (uint8)(~m_TRISB))); break; } + case 7: if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + if (m_TRISC == m_W) break; + else { m_TRISC = m_W; m_write(PIC16C5x_PORTC, 0x1000 | (PORTC & (uint8)(~m_TRISC))); break; } + } + else { + illegal(); break; + } + default: illegal(); break; + } +} + +static INLINE void xorlw(void) +{ + m_ALU = m_W ^ M_OPCODE_B0; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +static INLINE void xorwf(void) +{ + m_ALU = GET_REGFILE(ADDR) ^ m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + + + + +/*********************************************************************** + * Opcode Table (Cycles, Instruction) + ***********************************************************************/ + +static const uint8 s_opcode_main_cycles[256] = { +/*00*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*08*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*18*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*20*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*28*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*30*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*38*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*40*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*48*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*50*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*58*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*60*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*68*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*70*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*78*/ 1, 1, 1, 1, 1, 1, 1, 1, + +/*80*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*88*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*90*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*98*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*A0*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*A8*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*B0*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*B8*/ 2, 2, 2, 2, 2, 2, 2, 2, + +/*C0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*C8*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*D0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*D8*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*E0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*E8*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*F8*/ 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static const uint8 s_opcode_00x_cycles[16] = { +/*00*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*08*/ 1, 1, 1, 1, 1, 1, 1, 1 +}; + + + +/**************************************************************************** + * Inits CPU emulation + ****************************************************************************/ + +enum +{ + PIC16C5x_PC=1, PIC16C5x_STK0, PIC16C5x_STK1, PIC16C5x_FSR, + PIC16C5x_W, PIC16C5x_ALU, PIC16C5x_STR, PIC16C5x_OPT, + PIC16C5x_TMR0, PIC16C5x_PRTA, PIC16C5x_PRTB, PIC16C5x_PRTC, PIC16C5x_PRTD, + PIC16C5x_WDT, PIC16C5x_TRSA, PIC16C5x_TRSB, PIC16C5x_TRSC, + PIC16C5x_PSCL +}; + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ + +static INLINE void PIC16C5x_reset_regs(void) +{ + m_PC = m_picROMmask; + m_CONFIG = m_temp_config; + m_TRISA = 0xff; + m_TRISB = 0xff; + m_TRISC = 0xff; + m_OPTION = (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); + PCL = 0xff; + FSR |= (uint8)(~m_picRAMmask); + m_prescaler = 0; + m_delay_timer = 0; + m_inst_cycles = 0; + m_count_pending = 0; +} + +void pic16c5x_reset(uint8 hard) +{ + if (hard) { + memset(m_internalram, 0, sizeof(m_internalram)); + PIC16C5x_reset_regs(); + CLR(STATUS, PA_REG); + SET(STATUS, (TO_FLAG | PD_FLAG)); + m_icount = 0; + m_clock2cycle = 0; + } else { + SET(STATUS, (TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG)); + PIC16C5x_reset_regs(); + } +} + +void pic16c5x_set_config(uint16 data) +{ + m_temp_config = data; +} + + + +/**************************************************************************** + * WatchDog + ****************************************************************************/ + +static INLINE void PIC16C5x_update_watchdog(int counts) +{ + /* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */ + /* the timeout period of 0.018ms based on a 4MHz input clock. */ + /* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */ + /* which effectively makes the PIC run at 1MHz internally. */ + + /* If the current instruction is CLRWDT or SLEEP, don't update the WDT */ + + if ((M_OPCODE_S0 != 3) && (M_OPCODE_S0 != 4)) + { + uint16 old_WDT = m_WDT; + + m_WDT -= counts; + + if (m_WDT > 0x464f) { + m_WDT = 0x464f - (0xffff - m_WDT); + } + + if (((old_WDT != 0) && (old_WDT < m_WDT)) || (m_WDT == 0)) + { + if (PSA) { + m_prescaler++; + if (m_prescaler >= (1 << PS)) { /* Prescale values from 1 to 128 */ + m_prescaler = 0; + CLR(STATUS, TO_FLAG); + /* PIC16C5x_soft_reset(); */ + } + } + else { + CLR(STATUS, TO_FLAG); + /* PIC16C5x_soft_reset(); */ + } + } + } +} + + +/**************************************************************************** + * Update Timer + ****************************************************************************/ + +static INLINE void PIC16C5x_update_timer(int counts) +{ + if (PSA == 0) { + m_prescaler += counts; + if (m_prescaler >= (2 << PS)) { /* Prescale values from 2 to 256 */ + TMR0 += (m_prescaler / (2 << PS)); + m_prescaler %= (2 << PS); /* Overflow prescaler */ + } + } + else { + TMR0 += counts; + } +} + +void pic16c5x_set_input(int line, int state) +{ + switch (line) + { + /* RTCC/T0CKI pin */ + case PIC16C5x_RTCC: + if (T0CS && state != m_rtcc) /* Count mode, edge triggered */ + if ((T0SE && !state) || (!T0SE && state)) + m_count_pending = 1; + + m_rtcc = state; + break; + + default: + break; + } +} + + +void pic16c5x_run(void) +{ + if ((++m_clock2cycle &3) ==0) m_icount++; + + while (m_icount > 0) { + if (PD == 0) /* Sleep Mode */ + { + m_count_pending = 0; + m_inst_cycles = 1; + if (WDTE) { + PIC16C5x_update_watchdog(1); + } + } + else + { + if (m_count_pending) { /* RTCC/T0CKI clocked while in Count mode */ + m_count_pending = 0; + PIC16C5x_update_timer(1); + } + + m_PREVPC = m_PC; + + M_OPCODE_S0 = M_RDOP(m_PC); + /* printf("%04X: %03X %03X\n", m_PC, M_OPCODE_S0, M_OPCODE_B0); */ + m_PC++; + PCL++; + + if (m_picmodel == 0x1650 || m_picmodel == 0x1655 || (M_OPCODE_S0 & 0xff0) != 0x000) { /* Do all opcodes except the 00? ones */ + uint8 b1 = (M_OPCODE_S0 >> 4) & 0xff; + m_inst_cycles = s_opcode_main_cycles[b1]; + switch (b1) { + #include "pic16c5x_ops_main.inc" + } + } + else { /* Opcode 0x00? has many opcodes in its minor nibble */ + uint8 b1 = M_OPCODE_B0 & 0x1f; + m_inst_cycles = s_opcode_00x_cycles[b1]; + switch (b1) { + #include "pic16c5x_ops_00x.inc" + } + } + + if (!T0CS) { /* Timer mode */ + if (m_delay_timer) { + m_delay_timer--; + } + else { + PIC16C5x_update_timer(m_inst_cycles); + } + } + if (WDTE) { + PIC16C5x_update_watchdog(m_inst_cycles); + } + } + + m_icount -= m_inst_cycles; + } +} + +void AddExState(void *v, uint32 s, int type, char *desc); + +void pic16c5x_add_statesinfo(void) { + AddExState(&m_PC, sizeof(m_PC), 0, "PC00"); + AddExState(&m_PREVPC, sizeof(m_PREVPC), 0, "PRPC"); + AddExState(&m_W, sizeof(m_W), 0, "W000"); + AddExState(&m_OPTION, sizeof(m_OPTION), 0, "OPT0"); + AddExState(&m_CONFIG, sizeof(m_CONFIG), 0, "CONF"); + AddExState(&m_ALU, sizeof(m_ALU), 0, "ALU"); + AddExState(&m_WDT, sizeof(m_WDT), 0, "WDT"); + AddExState(&m_TRISA, sizeof(m_TRISA), 0, "TRSA"); + AddExState(&m_TRISB, sizeof(m_TRISB), 0, "TRSB"); + AddExState(&m_TRISC, sizeof(m_TRISC), 0, "TRSC"); + AddExState(&m_STACK[0], sizeof(m_STACK[0]), 0, "STC0"); + AddExState(&m_STACK[1], sizeof(m_STACK[1]), 0, "STC1"); + AddExState(&m_prescaler, sizeof(m_prescaler), 0, "PSCL"); + AddExState(&m_opcode, sizeof(m_opcode), 0, "OPS0"); + AddExState(m_internalram, sizeof(m_internalram), 0, "IRAM"); + AddExState(&m_icount, sizeof(m_icount), 0, "ICNT"); + AddExState(&m_delay_timer, sizeof(m_delay_timer), 0, "DTIM"); + AddExState(&m_rtcc, sizeof(m_rtcc), 0, "RTCC"); + AddExState(&m_count_pending, sizeof(m_count_pending), 0, "CNTP"); + AddExState(&m_inst_cycles, sizeof(m_inst_cycles), 0, "ICYC"); + AddExState(&m_clock2cycle, sizeof(m_clock2cycle), 0, "CL2C"); +} \ No newline at end of file diff --git a/src/boards/pic16c5x.h b/src/boards/pic16c5x.h new file mode 100644 index 0000000..67c03dc --- /dev/null +++ b/src/boards/pic16c5x.h @@ -0,0 +1,57 @@ +/* license:BSD-3-Clause */ +/* copyright-holders:Tony La Porta */ + /**************************************************************************\ + * Microchip PIC16C5x_ Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + \**************************************************************************/ + +#ifndef _PIC16C5x_H +#define _PIC16C5x_H + +#include "../../fceu-types.h" + +typedef uint8 (*pic16c5x_readfunc)(int); +typedef void (*pic16c5x_writefunc)(int, int); + +enum { + PIC16C5x_RTCC = 0 +}; + + +/* in the mid-90s RTCC was renamed to T0CKI */ +#define PIC16C5x_T0CKI PIC16C5x_RTCC + +/* i/o ports */ +enum { + PIC16C5x_PORTA = 0, + PIC16C5x_PORTB, + PIC16C5x_PORTC, + PIC16C5x_PORTD +}; + +/**************************************************************************** + * Function to configure the CONFIG register. This is actually hard-wired + * during ROM programming, so should be called in the driver INIT, with + * the value if known (available in HEX dumps of the ROM). + */ +void pic16c5x_set_input(int line, int state); +void pic16c5x_set_config(uint16 data); +void pic16c5x_reset(uint8 hard); +void pic16c5x_run(void); +void pic16c5x_add_statesinfo(void); + +void pic16c54_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c55_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c56_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c57_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c58_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic1650_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic1655_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); + +#endif /* _PIC16C5x_H */ diff --git a/src/boards/pic16c5x_ops_00x.inc b/src/boards/pic16c5x_ops_00x.inc new file mode 100644 index 0000000..67f058e --- /dev/null +++ b/src/boards/pic16c5x_ops_00x.inc @@ -0,0 +1,16 @@ +case 0x00: nop(); break; +case 0x01: illegal(); break; +case 0x02: option(); break; +case 0x03: sleepic(); break; +case 0x04: clrwdt(); break; +case 0x05: tris(); break; +case 0x06: tris(); break; +case 0x07: tris(); break; +case 0x08: illegal(); break; +case 0x09: illegal(); break; +case 0x0A: illegal(); break; +case 0x0B: illegal(); break; +case 0x0C: illegal(); break; +case 0x0D: illegal(); break; +case 0x0E: illegal(); break; +case 0x0F: illegal(); break; \ No newline at end of file diff --git a/src/boards/pic16c5x_ops_main.inc b/src/boards/pic16c5x_ops_main.inc new file mode 100644 index 0000000..f054d54 --- /dev/null +++ b/src/boards/pic16c5x_ops_main.inc @@ -0,0 +1,287 @@ +case 0x00: nop(); break; +case 0x01: illegal(); break; +case 0x02: movwf(); break; +case 0x03: movwf(); break; +case 0x04: clrw(); break; +case 0x05: illegal(); break; +case 0x06: clrf(); break; +case 0x07: clrf(); break; +/*08*/ +case 0x08: subwf(); break; +case 0x09: subwf(); break; +case 0x0A: subwf(); break; +case 0x0B: subwf(); break; +case 0x0C: decf(); break; +case 0x0D: decf(); break; +case 0x0E: decf(); break; +case 0x0F: decf(); break; +/*10*/ +case 0x10: iorwf(); break; +case 0x11: iorwf(); break; +case 0x12: iorwf(); break; +case 0x13: iorwf(); break; +case 0x14: andwf(); break; +case 0x15: andwf(); break; +case 0x16: andwf(); break; +case 0x17: andwf(); break; +/*18*/ +case 0x18: xorwf(); break; +case 0x19: xorwf(); break; +case 0x1A: xorwf(); break; +case 0x1B: xorwf(); break; +case 0x1C: addwf(); break; +case 0x1D: addwf(); break; +case 0x1E: addwf(); break; +case 0x1F: addwf(); break; +/*20*/ +case 0x20: movf(); break; +case 0x21: movf(); break; +case 0x22: movf(); break; +case 0x23: movf(); break; +case 0x24: comf(); break; +case 0x25: comf(); break; +case 0x26: comf(); break; +case 0x27: comf(); break; +/*28*/ +case 0x28: incf(); break; +case 0x29: incf(); break; +case 0x2A: incf(); break; +case 0x2B: incf(); break; +case 0x2C: decfsz(); break; +case 0x2D: decfsz(); break; +case 0x2E: decfsz(); break; +case 0x2F: decfsz(); break; +/*30*/ +case 0x30: rrf(); break; +case 0x31: rrf(); break; +case 0x32: rrf(); break; +case 0x33: rrf(); break; +case 0x34: rlf(); break; +case 0x35: rlf(); break; +case 0x36: rlf(); break; +case 0x37: rlf(); break; +/*38*/ +case 0x38: swapf(); break; +case 0x39: swapf(); break; +case 0x3A: swapf(); break; +case 0x3B: swapf(); break; +case 0x3C: incfsz(); break; +case 0x3D: incfsz(); break; +case 0x3E: incfsz(); break; +case 0x3F: incfsz(); break; +/*40*/ +case 0x40: bcf(); break; +case 0x41: bcf(); break; +case 0x42: bcf(); break; +case 0x43: bcf(); break; +case 0x44: bcf(); break; +case 0x45: bcf(); break; +case 0x46: bcf(); break; +case 0x47: bcf(); break; +/*48*/ +case 0x48: bcf(); break; +case 0x49: bcf(); break; +case 0x4A: bcf(); break; +case 0x4B: bcf(); break; +case 0x4C: bcf(); break; +case 0x4D: bcf(); break; +case 0x4E: bcf(); break; +case 0x4F: bcf(); break; +/*50*/ +case 0x50: bsf(); break; +case 0x51: bsf(); break; +case 0x52: bsf(); break; +case 0x53: bsf(); break; +case 0x54: bsf(); break; +case 0x55: bsf(); break; +case 0x56: bsf(); break; +case 0x57: bsf(); break; +/*58*/ +case 0x58: bsf(); break; +case 0x59: bsf(); break; +case 0x5A: bsf(); break; +case 0x5B: bsf(); break; +case 0x5C: bsf(); break; +case 0x5D: bsf(); break; +case 0x5E: bsf(); break; +case 0x5F: bsf(); break; +/*60*/ +case 0x60: btfsc(); break; +case 0x61: btfsc(); break; +case 0x62: btfsc(); break; +case 0x63: btfsc(); break; +case 0x64: btfsc(); break; +case 0x65: btfsc(); break; +case 0x66: btfsc(); break; +case 0x67: btfsc(); break; +/*68*/ +case 0x68: btfsc(); break; +case 0x69: btfsc(); break; +case 0x6A: btfsc(); break; +case 0x6B: btfsc(); break; +case 0x6C: btfsc(); break; +case 0x6D: btfsc(); break; +case 0x6E: btfsc(); break; +case 0x6F: btfsc(); break; +/*70*/ +case 0x70: btfss(); break; +case 0x71: btfss(); break; +case 0x72: btfss(); break; +case 0x73: btfss(); break; +case 0x74: btfss(); break; +case 0x75: btfss(); break; +case 0x76: btfss(); break; +case 0x77: btfss(); break; +/*78*/ +case 0x78: btfss(); break; +case 0x79: btfss(); break; +case 0x7A: btfss(); break; +case 0x7B: btfss(); break; +case 0x7C: btfss(); break; +case 0x7E: btfss(); break; +case 0x7D: btfss(); break; +case 0x7F: btfss(); break; +/*80*/ +case 0x80: retlw(); break; +case 0x81: retlw(); break; +case 0x82: retlw(); break; +case 0x83: retlw(); break; +case 0x84: retlw(); break; +case 0x85: retlw(); break; +case 0x86: retlw(); break; +case 0x87: retlw(); break; +/*88*/ +case 0x88: retlw(); break; +case 0x89: retlw(); break; +case 0x8A: retlw(); break; +case 0x8B: retlw(); break; +case 0x8C: retlw(); break; +case 0x8D: retlw(); break; +case 0x8E: retlw(); break; +case 0x8F: retlw(); break; +/*90*/ +case 0x90: call(); break; +case 0x91: call(); break; +case 0x92: call(); break; +case 0x93: call(); break; +case 0x94: call(); break; +case 0x95: call(); break; +case 0x96: call(); break; +case 0x97: call(); break; +/*98*/ +case 0x98: call(); break; +case 0x99: call(); break; +case 0x9A: call(); break; +case 0x9B: call(); break; +case 0x9C: call(); break; +case 0x9D: call(); break; +case 0x9E: call(); break; +case 0x9F: call(); break; +/*A0*/ +case 0xA0: goto_op(); break; +case 0xA1: goto_op(); break; +case 0xA2: goto_op(); break; +case 0xA3: goto_op(); break; +case 0xA4: goto_op(); break; +case 0xA5: goto_op(); break; +case 0xA6: goto_op(); break; +case 0xA7: goto_op(); break; +/*A8*/ +case 0xA8: goto_op(); break; +case 0xA9: goto_op(); break; +case 0xAA: goto_op(); break; +case 0xAB: goto_op(); break; +case 0xAC: goto_op(); break; +case 0xAD: goto_op(); break; +case 0xAE: goto_op(); break; +case 0xAF: goto_op(); break; +/*B0*/ +case 0xB0: goto_op(); break; +case 0xB1: goto_op(); break; +case 0xB2: goto_op(); break; +case 0xB3: goto_op(); break; +case 0xB4: goto_op(); break; +case 0xB5: goto_op(); break; +case 0xB6: goto_op(); break; +case 0xB7: goto_op(); break; +/*B8*/ +case 0xB8: goto_op(); break; +case 0xB9: goto_op(); break; +case 0xBA: goto_op(); break; +case 0xBB: goto_op(); break; +case 0xBC: goto_op(); break; +case 0xBD: goto_op(); break; +case 0xBE: goto_op(); break; +case 0xBF: goto_op(); break; +/*C0*/ +case 0xC0: movlw(); break; +case 0xC1: movlw(); break; +case 0xC2: movlw(); break; +case 0xC3: movlw(); break; +case 0xC4: movlw(); break; +case 0xC5: movlw(); break; +case 0xC6: movlw(); break; +case 0xC7: movlw(); break; +/*C8*/ +case 0xC8: movlw(); break; +case 0xC9: movlw(); break; +case 0xCA: movlw(); break; +case 0xCB: movlw(); break; +case 0xCC: movlw(); break; +case 0xCD: movlw(); break; +case 0xCE: movlw(); break; +case 0xCF: movlw(); break; +/*D0*/ +case 0xD0: iorlw(); break; +case 0xD1: iorlw(); break; +case 0xD2: iorlw(); break; +case 0xD3: iorlw(); break; +case 0xD4: iorlw(); break; +case 0xD5: iorlw(); break; +case 0xD6: iorlw(); break; +case 0xD7: iorlw(); break; +/*D8*/ +case 0xD8: iorlw(); break; +case 0xD9: iorlw(); break; +case 0xDA: iorlw(); break; +case 0xDB: iorlw(); break; +case 0xDC: iorlw(); break; +case 0xDD: iorlw(); break; +case 0xDE: iorlw(); break; +case 0xDF: iorlw(); break; +/*E0*/ +case 0xE0: andlw(); break; +case 0xE1: andlw(); break; +case 0xE2: andlw(); break; +case 0xE3: andlw(); break; +case 0xE4: andlw(); break; +case 0xE5: andlw(); break; +case 0xE6: andlw(); break; +case 0xE7: andlw(); break; +/*E8*/ +case 0xE8: andlw(); break; +case 0xE9: andlw(); break; +case 0xEA: andlw(); break; +case 0xEB: andlw(); break; +case 0xEC: andlw(); break; +case 0xED: andlw(); break; +case 0xEE: andlw(); break; +case 0xEF: andlw(); break; +/*F0*/ +case 0xF0: xorlw(); break; +case 0xF1: xorlw(); break; +case 0xF2: xorlw(); break; +case 0xF3: xorlw(); break; +case 0xF4: xorlw(); break; +case 0xF5: xorlw(); break; +case 0xF6: xorlw(); break; +case 0xF7: xorlw(); break; +/*F8*/ +case 0xF8: xorlw(); break; +case 0xF9: xorlw(); break; +case 0xFA: xorlw(); break; +case 0xFB: xorlw(); break; +case 0xFC: xorlw(); break; +case 0xFD: xorlw(); break; +case 0xFE: xorlw(); break; +case 0xFF: xorlw(); break;