Hogwarts Wand Docs: ../server/picsim.c

Wand Sourcecode: ../server/picsim.c

//
// picsim.c - PIC C simulator for embedding pic microcode into a C program
//
// Copyright (C) 2006  Nathan (Acorn) Pooley
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation.
// 
// 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 (gpl.txt) 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.
// 
// You can contact the author, Nathan (Acorn) Pooley, by writing
// to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA  94086, USA
// or through the form at http://www.rawbw.com/~acorn/wand/feedback.html
//

// #@DOC@ PIC C simulator for embedding pic microcode into a C program

//###########################################################################
//############################### INCLUDES ##################################
//###########################################################################

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "picsim.h"
#include "ac_assert.h"

//###########################################################################
//############################### DEFINES ###################################
//###########################################################################

#define PIC_REG_CNT_LOG2            12
#define PIC_REG_CNT                 (1UL<<PIC_REG_CNT_LOG2)

#define PIC_FLASH_BANK_CNT_LOG2     6
#define PIC_FLASH_BANK_CNT          (1UL<<PIC_FLASH_BANK_CNT_LOG2)
#define PIC_FLASH_BANK_BYTES_LOG2   10
#define PIC_FLASH_BANK_BYTES        (1UL<<PIC_FLASH_BANK_BYTES_LOG2)

#define ASSERT(c) AC_ASSERT(c)

//###########################################################################
//############################### TYPEDEFS ##################################
//###########################################################################

typedef int (*picRegFunc)(picChip *ch, picReg *reg, int val);

typedef struct picRegNamespaceRec {
    const char *name;
    picRegFunc findFunc;
    struct picRegNamespaceRec *next;
} picRegNamespace;

struct picRegRec {
    int          id;
    int          sub;
    picRegFunc   rd;
    picRegFunc   wr;
    picRegNamespace *ns;
    char        *name;
    picReg      *next;
};

struct picChipRec {

    picReg  *regList[PIC_REG_CNT];
    picReg  *regs;
    picRegNamespace *ns_list;
    picRegNamespace *ns_global;
    picRegNamespace *ns_local;
    picRegNamespace *ns_param;
    picRegNamespace *ns_inoutparam;
    picRegNamespace *ns_return;
    picRegNamespace *ns_sfr;

    int      ram[0xfff];
    short   *flash[PIC_FLASH_BANK_CNT];

    int      flashSize;

    int      skip;
    int      movff_tmp;
    int      plusw_savew;
    int      cycle;

    int      trace;
};



enum {
    ST_N        =   0x10,
    ST_OV       =   0x08,
    ST_Z        =   0x04,
    ST_DC       =   0x02,
    ST_C        =   0x01,

    ST_END      =   0x7fffffff
};


//###########################################################################
//############################### GLOBALS ###################################
//###########################################################################

picChip *picCurChip = 0;

const char *picNamespaceSfr = "Sfr";
const char *picNamespaceGlobal = "Global";
const char *picNamespaceLocal = "Local";
const char *picNamespaceParam = "Param";
const char *picNamespaceInOutParam = "Param";
const char *picNamespaceReturn = "Return";

//###########################################################################
//############################### CODE ######################################
//###########################################################################

#if 0   // not used
//===========================================================================
// picFatalError() - big bad error
//===========================================================================
static void picFatalError(picChip *ch)
{
    ASSERT(!"Fatal error in picsim");
}
#endif

//===========================================================================
// picRegFindFuncLocal() - local variable init
//===========================================================================
static int picRegFindFuncLocal(picChip *ch, picReg *r, int val)
{
    picRegErase(ch,r->id);
    return 0;
}

//===========================================================================
// picRegFindFuncParam() - local variable init
//===========================================================================
static int picRegFindFuncParam(picChip *ch, picReg *r, int val)
{
    return 0;
}

//===========================================================================
// picRegFindFuncInOut() - local variable init
//===========================================================================
static int picRegFindFuncInOut(picChip *ch, picReg *r, int val)
{
    return 0;
}

//===========================================================================
// picRegFindFuncReturn() - local variable init
//===========================================================================
static int picRegFindFuncReturn(picChip *ch, picReg *r, int val)
{
    picRegErase(ch,r->id);
    return 0;
}

//===========================================================================
// picRegFindFuncGlobal() - local variable init
//===========================================================================
static int picRegFindFuncGlobal(picChip *ch, picReg *r, int val)
{
    return 0;
}

//===========================================================================
// picRegFindFuncSfr() - Sfr variable init
//===========================================================================
static int picRegFindFuncSfr(picChip *ch, picReg *r, int val)
{
    return 0;
}

//===========================================================================
// picNamespaceFind() - find (& create) a namespace
//===========================================================================
static picRegNamespace *picNamespaceFind(picChip *ch, const char *name,
                                            int create)
{
    picRegNamespace *ns;
    
    if (name == picNamespaceLocal) return ch->ns_local;
    if (name == picNamespaceParam) return ch->ns_param;
    if (name == picNamespaceInOutParam) return ch->ns_inoutparam;
    if (name == picNamespaceReturn) return ch->ns_return;
    if (name == picNamespaceGlobal) return ch->ns_global;
    if (name == picNamespaceSfr) return ch->ns_sfr;
    
    if (name) {
        for (ns=ch->ns_list; ns; ns=ns->next) {
            if (ns->name && !strcmp(name,ns->name)) {
                return ns;
            }
        }
    }
    
    if (create) {
        ns = calloc(1,sizeof(picRegNamespace));
        if (ns) {
            ns->name = name ? strdup(name) : 0;
            ns->findFunc = picRegFindFuncGlobal;
            ns->next = ch->ns_list;
            ch->ns_list = ns;
        }
    }
    return ns;
}

//===========================================================================
// picRegWriteFsr() - fsr reg write
//===========================================================================
static int picRegWriteFsr(picChip *ch, picReg *reg, int val)
{
    picReg *sub = ch->regList[reg->sub];
    picReg *fsrh = ch->regList[reg->sub+FSR0H-FSR0L];
    picReg *fsrl = ch->regList[reg->sub+FSR0L-FSR0L];
    int x = (ch->ram[fsrh->id] | ch->ram[fsrl->id]) >> 8;
    int idx = (ch->ram[fsrh->id] << 8) | ch->ram[fsrl->id];
    int idx2 = idx;
    int w;

    switch(reg->id - sub->id) {
        case PLUSW0-FSR0L:
            w = ch->plusw_savew;
            ASSERT(w>=-128 && w<=128);
            idx += w;
            ASSERT(idx > 0x17f);
            ASSERT(idx < 0xf80);
            ch->ram[idx] = val;
            ch->plusw_savew = -1000;
            return val;

        case POSTDEC0-FSR0L:
            idx2 -= 2;
        case POSTINC0-FSR0L:
            idx2 += 1;
        case PREINC0-FSR0L:
        case INDF0-FSR0L:
            ASSERT(idx > 0x17f);
            ASSERT(idx < 0xf80);
            ASSERT(x == 0);
            ch->ram[fsrh->id] = idx2 >> 8;
            ch->ram[fsrl->id] = idx2 & 0xff;
            ch->ram[idx] = val;
            return val;

        default:
            ASSERT(!"Bad reg in picRegWriteFsr");
            return -1;
    }
}

//===========================================================================
// picRegReadFsr() - fsr reg read
//===========================================================================
static int picRegReadFsr(picChip *ch, picReg *reg, int val)
{
    picReg *sub = ch->regList[reg->sub];
    picReg *fsrh = ch->regList[reg->sub+FSR0H-FSR0L];
    picReg *fsrl = ch->regList[reg->sub+FSR0L-FSR0L];
    int x = (ch->ram[fsrh->id] | ch->ram[fsrl->id]) >> 8;
    int idx = (ch->ram[fsrh->id] << 8) | ch->ram[fsrl->id];
    int w;

    switch(reg->id - sub->id) {
        case PLUSW0-FSR0L:
            w = ch->ram[WREG];
            if (w & ~0xff) return 0xff00;
            ASSERT(w != 0x80); // manual is vague on this value
            if (w & 0x80) w -= 256;
            ASSERT(ch->plusw_savew < -128); // should be invalid
            ch->plusw_savew = w;
            idx += w;
            ASSERT(idx > 0x17f);
            ASSERT(idx < 0xf80);
            return x ? 0xff00 : ch->ram[idx];

        case PREINC0-FSR0L:
            idx++;
            ASSERT(idx > 0x17f);
            ASSERT(idx < 0xf80);
            ch->ram[fsrh->id] = idx >> 8;
            ch->ram[fsrl->id] = idx & 0xff;
            return x ? 0xff00 : ch->ram[idx];
            
        case POSTDEC0-FSR0L:
        case POSTINC0-FSR0L:
        case INDF0-FSR0L:
            ASSERT(idx > 0x17f);
            ASSERT(idx < 0xf80);
            return x ? 0xff00 : ch->ram[idx];

        default:
            ASSERT(!"Bad reg in picRegWriteFsr");
    }
    return -1;
}

#if 0
//===========================================================================
// picRegWriteGeneric() - generic reg write
//===========================================================================
static int picRegWriteGeneric(picChip *ch, picReg *reg, int val)
{
    return (ch->ram[reg->id] = val);
}

//===========================================================================
// picRegReadGeneric() - generic reg read
//===========================================================================
static int picRegReadGeneric(picChip *ch, picReg *reg, int val)
{
    return ch->ram[reg->id];
}
#endif

//===========================================================================
// picRegWrite() - reg write
//===========================================================================
static int picRegWrite(picChip *ch, int id, int val)
{
    picReg *reg;
    ASSERT((unsigned int)id < PIC_REG_CNT);
    if ((unsigned int)id >= PIC_REG_CNT) return -1;
    reg = ch->regList[id];
    if (reg && reg->wr) {
        return reg->wr(ch,reg,val);
    } else {
        return (ch->ram[id] = val);
    }
}

//===========================================================================
// picRegRead() - reg read
//===========================================================================
static int picRegRead(picChip *ch, int id)
{
    picReg *reg;
    ASSERT((unsigned int)id < PIC_REG_CNT);
    if ((unsigned int)id >= PIC_REG_CNT) return -1;
    reg = ch->regList[id];
    if (reg && reg->rd) {
        return reg->rd(ch,reg,0);
    } else {
        return ch->ram[id];
    }
}

//===========================================================================
// picOpcodeName() - return name of opcode
//===========================================================================
const char *picOpcodeName(
                picChip *chip,
                unsigned int op)
{
    static char *opStr[] = {
        #define PIC_OPCODES_STR(f)  #f,
        PIC_OPCODES(PIC_OPCODES_STR)
        0
    };
    if (op < PIC_INST_CNT) {
        return opStr[op];
    }
    return "???";
}

//===========================================================================
// picRegName() - return name of reg (a string)
//===========================================================================
const char *picRegName(
                picChip *chip,
                int     id,
                int     maxlen)
{
    picChip *ch = chip ? chip : picCurChip;
    static char buf[100];
    picReg *r;

    if (id==WREG) return "WREG";
    if (id==STATUS) return "STATUS";
    if (maxlen <=0 || maxlen > sizeof(buf)-1) maxlen = sizeof(buf)-1;

    snprintf(buf,maxlen, "reg[%03x]",id);
    buf[maxlen] = 0;

    if (!ch) return buf;

    for (r=ch->regs; r; r=r->next) {
        if (id == r->id) {
            snprintf(buf,maxlen, "reg[%03x](%s)",id,r->name);
            break;
        }
    }

    buf[maxlen] = 0;
    return buf;
}

//===========================================================================
// picRegCreate() - create a new register
//===========================================================================
static picReg *picRegCreate(
                picChip *ch,
                int     id,
                int     sub,
                const char *name,
                picRegFunc r,
                picRegFunc w,
                const char *namespace)
{
    picReg *reg = calloc(1,sizeof(picReg));

    if (id < 0) {
        for (id=0; ch->regList[id]; id++);
    }
    ASSERT((unsigned int)id < PIC_REG_CNT);
    ASSERT(ch->regList[id] == 0);
    ch->regList[id] = reg;
    reg->rd   = r;
    reg->wr   = w;
    reg->name = strdup(name);
    reg->sub  = sub;
    reg->id   = id;
    reg->ns   = picNamespaceFind(ch,namespace,1);
    if (!reg->ns) reg->ns = ch->ns_global;
    reg->next = ch->regs;
    ch->regs = reg;


    return reg;
}

//===========================================================================
// picChipReset() - reset chip
//===========================================================================
void picChipReset(picChip *chip, enum picResetTypeEnum r)
{
    picChip *ch = chip ? chip : picCurChip;
    if (r == PIC_RESET_POWERON) {
        memset(ch->ram, 0xff, sizeof(ch->ram));
    }
    picRegWrite(ch,BSR,0);

    ch->skip = 0;
    ch->movff_tmp = -1;
}

//===========================================================================
// picChipSetCurrent() - Call this before running instructions
//===========================================================================
int picChipSetCurrent(picChip *ch)
{
    picCurChip = ch;
    return 0;
}

//===========================================================================
// picChipCreate() - create a pic chip
//===========================================================================
// name - name to identify this chip
// partnum - part number.  e.g. pic18lf2525
//
picChip *picChipCreate(const char *name, const char *partnum)
{
    picChip *ch = calloc(1,sizeof(picChip));

    //
    // init special registers
    //
    ch->plusw_savew = -1000;

    //
    // init register namespaces
    //
    ch->ns_sfr        = picNamespaceFind(ch, 0, 1);
    ch->ns_global     = picNamespaceFind(ch, 0, 1);
    ch->ns_param      = picNamespaceFind(ch, 0, 1);
    ch->ns_inoutparam = picNamespaceFind(ch, 0, 1);
    ch->ns_return     = picNamespaceFind(ch, 0, 1);
    ch->ns_local      = picNamespaceFind(ch, 0, 1);

    ch->ns_sfr->findFunc        = picRegFindFuncSfr;
    ch->ns_local->findFunc      = picRegFindFuncLocal;
    ch->ns_param->findFunc      = picRegFindFuncParam;
    ch->ns_inoutparam->findFunc = picRegFindFuncInOut;
    ch->ns_return->findFunc     = picRegFindFuncReturn;
    ch->ns_global->findFunc     = picRegFindFuncGlobal;

    ch->ns_sfr->name        = picNamespaceSfr;
    ch->ns_local->name      = picNamespaceLocal;
    ch->ns_param->name      = picNamespaceParam;
    ch->ns_inoutparam->name = picNamespaceInOutParam;
    ch->ns_return->name     = picNamespaceReturn;
    ch->ns_global->name     = picNamespaceGlobal;

    //
    // init Special Function Registers (SFRs)
    //
    #define REGI(name,rd,wr,sub) picRegCreate(ch,name,sub,#name,rd,wr, \
                                            picNamespaceSfr)

    REGI(FSR0L,    0,             0,              FSR0L);
    REGI(FSR0H,    0,             0,              FSR0L);
    REGI(INDF0,    picRegReadFsr, picRegWriteFsr, FSR0L);
    REGI(POSTINC0, picRegReadFsr, picRegWriteFsr, FSR0L);
    REGI(POSTDEC0, picRegReadFsr, picRegWriteFsr, FSR0L);
    REGI(PREINC0,  picRegReadFsr, picRegWriteFsr, FSR0L);
    REGI(PLUSW0,   picRegReadFsr, picRegWriteFsr, FSR0L);

    REGI(FSR1L,    0,             0,              FSR1L);
    REGI(FSR1H,    0,             0,              FSR1L);
    REGI(INDF1,    picRegReadFsr, picRegWriteFsr, FSR1L);
    REGI(POSTINC1, picRegReadFsr, picRegWriteFsr, FSR1L);
    REGI(POSTDEC1, picRegReadFsr, picRegWriteFsr, FSR1L);
    REGI(PREINC1,  picRegReadFsr, picRegWriteFsr, FSR1L);
    REGI(PLUSW1,   picRegReadFsr, picRegWriteFsr, FSR1L);

    REGI(FSR2L,    0,             0,              FSR2L);
    REGI(FSR2H,    0,             0,              FSR2L);
    REGI(INDF2,    picRegReadFsr, picRegWriteFsr, FSR2L);
    REGI(POSTINC2, picRegReadFsr, picRegWriteFsr, FSR2L);
    REGI(POSTDEC2, picRegReadFsr, picRegWriteFsr, FSR2L);
    REGI(PREINC2,  picRegReadFsr, picRegWriteFsr, FSR2L);
    REGI(PLUSW2,   picRegReadFsr, picRegWriteFsr, FSR2L);

    #undef  REGI
    #define REGI(name) picRegCreate(ch,name,-1,#name,0,0, \
                                            picNamespaceSfr)

    REGI(WREG);
    REGI(STATUS);
    REGI(BSR);
    REGI(TBLPTRU);
    REGI(TBLPTRH);
    REGI(TBLPTRL);
    REGI(TABLAT);
    REGI(PRODH);
    REGI(PRODL);

    #undef  REGI

    ch->flashSize = PIC_FLASH_BANK_BYTES * PIC_FLASH_BANK_CNT;
    picChipReset(ch, PIC_RESET_POWERON);

    return ch;
}

//===========================================================================
// picChipDestroy() - destroy a pic chip
//===========================================================================
void picChipDestroy(picChip *ch)
{
    ASSERT(!"Unimplemented");
}

//===========================================================================
// picRegX() - get which bits are unknown
//===========================================================================
unsigned int picRegX(picChip *chip, int id)
{
    picChip *ch = chip ? chip : picCurChip;
    ASSERT(ch);
    return (picRegRead(ch,id) >> 8) & 0xff;
}

//===========================================================================
// picRegValU() - get unsigned register value
//===========================================================================
unsigned int picRegValU(picChip *chip, int id)
{
    picChip *ch = chip ? chip : picCurChip;
    ASSERT(ch);
    return picRegRead(ch,id) & 0xff;
}

//===========================================================================
// picRegValS() - get signed register value
//===========================================================================
signed int picRegValS(picChip *chip, int id)
{
    picChip *ch = chip ? chip : picCurChip;
    int val = picRegRead(ch,id) & 0xff;
    ASSERT(ch);
    if (val & 0x80) val = -((-val)&0xff);
    return val;
}

//===========================================================================
// picRegSet() - set register values
//===========================================================================
void picRegSet(picChip *chip, int id, int val)
{
    picChip *ch = chip ? chip : picCurChip;
    ASSERT(ch);
    picRegWrite(ch,id,val & 0xff);
}

//===========================================================================
// picRegSet32() - set up to 32 bit reg val
//===========================================================================
void picRegSet32(picChip *chip, int id0, int id1, int id2, int id3, int val)
{
    picChip *ch = chip ? chip : picCurChip;
    ASSERT(ch);
    picRegWrite(ch,id0, (val)     & 0xff);
    if (id1<0) return;
    picRegWrite(ch,id1, (val>>8)  & 0xff);
    if (id2<0) return;
    picRegWrite(ch,id2, (val>>16) & 0xff);
    if (id3<0) return;
    picRegWrite(ch,id3, (val>>24) & 0xff);
}

//===========================================================================
// picRegValU32() - get up to 32 bit unsigned reg val
//===========================================================================
unsigned int picRegValU32(picChip *chip, int id0, int id1, int id2, int id3)
{
    picChip *ch = chip ? chip : picCurChip;
    int val;

    ASSERT(ch);
    val  = (picRegRead(ch,id0) & 0xff);
    if (id1<0) return val;
    val |= (picRegRead(ch,id1) & 0xff) << 8;
    if (id2<0) return val;
    val |= (picRegRead(ch,id2) & 0xff) << 16;
    if (id3<0) return val;
    val |= (picRegRead(ch,id3) & 0xff) << 24;
    return val;
}

//===========================================================================
// picRegValS32() - get up to 32 bit signed reg val
//===========================================================================
signed int picRegValS32(picChip *chip, int id0, int id1, int id2, int id3)
{
    picChip *ch = chip ? chip : picCurChip;
    int val;
    int mask;

    ASSERT(ch);
    ASSERT(sizeof(val) == 4);
    do {
        val  = (picRegRead(ch,id0) & 0xff);
        mask = 0x80;
        if (id1<0) break;
        val |= (picRegRead(ch,id1) & 0xff) << 8;
        mask = 0x8000;
        if (id2<0) break;
        val |= (picRegRead(ch,id2) & 0xff) << 16;
        mask = 0x8000;
        if (id3<0) break;
        val |= (picRegRead(ch,id3) & 0xff) << 24;
        return val;
    } while(0);

    if (val & mask) {
        val = -((-val) & (mask | (mask-1)));
    }
    return val;
}

//===========================================================================
// picRegX32() - get up to 32 bit reg unknown bits
//===========================================================================
unsigned int picRegX32(picChip *chip, int id0, int id1, int id2, int id3)
{
    picChip *ch = chip ? chip : picCurChip;
    int val;

    ASSERT(ch);
    val  = (picRegRead(ch,id0) & 0xff00) >> 8;
    if (id1<0) return val;
    val |= (picRegRead(ch,id1) & 0xff00);
    if (id2<0) return val;
    val |= (picRegRead(ch,id2) & 0xff00) << 8;
    if (id3<0) return val;
    val |= (picRegRead(ch,id3) & 0xff00) << 16;
    return val;
}

//===========================================================================
// picRegEraseRange() - erase several register values (for debug)
//===========================================================================
void picRegEraseRange(picChip *chip, int firstId, int lastId)
{
    picChip *ch = chip ? chip : picCurChip;
    ASSERT(ch);
    ASSERT(firstId <= lastId);
    while(firstId <= lastId) {
        picRegWrite(ch,firstId,-1);
        firstId++;
    }
}

//===========================================================================
// picRegErase() - erase register value (for debug)
//===========================================================================
void picRegErase(picChip *chip, int id)
{
    picChip *ch = chip ? chip : picCurChip;
    ASSERT(ch);
    picRegWrite(ch,id,-1);
}

//===========================================================================
// picRegFind() - variable declaration
//===========================================================================
int picRegFind(picChip *chip, const char *name, const char *namespace)
{
    picChip *ch = chip ? chip : picCurChip;
    picReg *r = ch->regs;

    ASSERT(ch);
    for (r = ch->regs; r; r=r->next) {
        if (!strcmp(name, r->name)) {
            picRegNamespace *ns = picNamespaceFind(ch, namespace, 0);
            ns = ns ? ns : r->ns;
            ns->findFunc(ch,r,0);
            return r->id;
        }
    }

    r = picRegCreate(ch, -1, -1, name, 0, 0, namespace);
    picRegErase(ch,r->id);
    ASSERT(r && r->id >= 0);
    return r->id;
}

//===========================================================================
// picFlashBank() - get bank containing the address
//===========================================================================
static short *picFlashBank(picChip *ch, int addr)
{
    int bank = addr >> PIC_FLASH_BANK_BYTES_LOG2;
    short *ptr;
    if ((unsigned long)addr > ch->flashSize) return 0;
    ptr = ch->flash[bank];

    if (!ptr) {
        ptr = malloc(PIC_FLASH_BANK_BYTES * 2);
        memset(ptr,0xff,PIC_FLASH_BANK_BYTES * 2);
        ch->flash[bank] = ptr;
    }

    return ptr;
}

//===========================================================================
// picReadFlash() - read flash memory byte (for debug)
//===========================================================================
int picReadFlash(picChip *chip, int addr)
{
    picChip *ch = chip ? chip : picCurChip;
    short *ptr = picFlashBank(ch,addr);

    ASSERT(ptr);
    if (!ptr) return 0xffff;

    ptr += addr & ((1UL<<PIC_FLASH_BANK_BYTES_LOG2)-1);
    return *ptr;
}

//===========================================================================
// picWriteFlash() - write flash memory byte (immediate - for debug)
//===========================================================================
void picWriteFlash(picChip *chip, int addr, int val)
{
    picChip *ch = chip ? chip : picCurChip;
    short *ptr = picFlashBank(ch,addr);

    ASSERT(ptr);
    if (!ptr) return;

    ptr += addr & ((1UL<<PIC_FLASH_BANK_BYTES_LOG2)-1);
    *ptr = val & 0xff;
}

//===========================================================================
// picReadFlashInstr() - read flash memory byte (from instruction)
//===========================================================================
static int picReadFlashInstr(picChip *ch, int addr)
{
    return picReadFlash(ch,addr);
}

//===========================================================================
// picWriteFlashInstr() - write flash memory byte (from instruction)
//===========================================================================
static void picWriteFlashInstr(picChip *ch, int addr, int val)
{
    ASSERT(!"picWriteFlashInstr() not supported yet");
}

//===========================================================================
// picCalcStatus() - calc status of a result
//===========================================================================
static void picCalcStatus(picChip *ch, int r, int rx, int mask)
{
    int s = ((r>>8) & 0x01) |       // C
            ((r>>3) & 0x10) |       // N
            ((r&0xff) ? 0 : ST_Z);  // Z
    
    mask &= 0x1f;
    s &= mask;
    mask |= mask<<8;
    if (rx) {
        s |= mask & 0x1f00;
    }
    ch->ram[STATUS] = 
        (ch->ram[STATUS] & ~mask) |
        (s                   &  mask);
}

//===========================================================================
// picCalcAdd() - calc sum
//===========================================================================
static int picCalcAdd(
                picChip *ch,
                int a, int b,
                int neg,
                int use_carry,
                int rx)
{
    int ah,bh;
    int r,rh,s;
    int c = neg ? 1 : 0;
    b = neg ? ~b : b;
    a &= 0xff;
    b &= 0xff;
    ah = a & 0xf;
    bh = b & 0xf;
    if (use_carry) {
        c   = ch->ram[STATUS] & 1;
        rx |= ch->ram[STATUS] & (ST_C<<8);
    }
    r  = a  + b  + c;
    rh = ah + bh + c;
    s  =    ((r>>8) & 0x01) |       // C
            ((r>>3) & 0x10) |       // N
            ((r&0xff) ? 0 : ST_Z) | // Z
            ((((a ^ ~b) & (a ^ r)) & 0x80) >> 4) |  // OV
            ((rh>>3) & 0x2);        // DC

    r &= 0xff;

    if (rx) {
        s |= 0x1f00;
    }
    ch->ram[STATUS] = s;

    return r;
}

#define PIC_TESTS       1
#if PIC_TESTS
//===========================================================================
// picTestAdd() - test adds
//===========================================================================
static void picTestAdd(void)
{
    picChip *ch = picChipCreate("test","pic18f2525");
    int a,b,ic,in;
    int  r, c, ov, z, n;
    int gr,gc,gov,gz,gn;

    for (a=0; a<0x100; a++) {
    for (b=0; b<0x100; b++) {
    for (ic=0; ic<3;     ic++) {
    for (in=0; in<2;     in++) {
        ch->ram[STATUS] = ic;
        r = picCalcAdd(ch,a,b,in,ic!=2,0);
        gov = 0;
        if (in) {
            switch(ic) {
                case 0: gr = (a-b-1) & 0xff;
                        if (a>=b+1) gr |= 0x100;
                        break;
                case 1:
                case 2: gr = (a-b) & 0xff;
                        if (a>=b) gr |= 0x100;
                        break;
                default: ASSERT(0);
            }
        } else {
            gr = (a+b+(ic&1));
        }
        gc  = (gr & 0x100) ? 1 : 0;
        gr &= 0xff;
        gn  = (gr & 0x080) ? 1 : 0;
        gz  = (gr) ? 0 : 1;

        c  = (ch->ram[STATUS] & ST_C) ? 1 : 0;
        n  = (ch->ram[STATUS] & ST_N) ? 1 : 0;
        z  = (ch->ram[STATUS] & ST_Z) ? 1 : 0;
        ov = (ch->ram[STATUS] & ST_OV) ? 1 : 0;
        gr &= 0xff;

        if (r != gr ||
            c != gc ||
            z != gz ||
            n != gn) {
            printf("a= %02x\n",a);
            printf("b= %02x  neg=%d   c=%d\n",b,in,ic);
            printf("r=%02x  %02x\n",r,gr);
            printf("c=%2x  %2x\n",c,gc);
            printf("z=%2x  %2x\n",z,gz);
            printf("n=%2x  %2x\n",n,gn);
        }
        ASSERT(r == gr);
        ASSERT(c == gc);
        ASSERT(z == gz);
        ASSERT(n == gn);
        //ASSERT(ov == gov);
    }}}}
}
#endif

//===========================================================================
// picOpTrace() - print trace info for an opcode
//===========================================================================
void picOpTrace(
            picChip *ch,
            const char *file,
            int line,
            int op,
            int regId,
            int dst,
            int imm,
            int oldf,
            int result,
            int resultx,
            const char *dbstr)
{
            

    if (ch->trace) {
        const char *rn = regId==-1 ? "" : picRegName(ch,regId,25);
        int stat = picRegValU(ch,STATUS);
        int statx = picRegX(ch,STATUS);
        printf("%s:%-5d ",
                file,line);
        if (dst == PICDST_W || dst == PICDST_F || dst == PICDST_READF) {
            if (imm != -1) {
                printf("  %-27s=%02x%s ",
                    "immediate",
                    imm,
                    " ");
            } else if (regId != -1) {
                printf("  f=%-25s=%02x%s ",
                        rn,
                        oldf&0xff,
                        oldf&~0xff?"?":" ");
            } else {
                printf("  %31s ","");
            }
            printf(" w=%02x%s  %-6s  ",
                    ch->ram[WREG]&0xff,
                    ch->ram[WREG]&~0xff?"?":" ",
                    picOpcodeName(ch,op));
            if (dst == PICDST_W) {
                printf("%s%02x->%-25s",
                    (resultx)?"?":" ",
                    (result)&0xff,
                    "w");
            } else if (dst == PICDST_F) {
                printf("%s%02x->%-25s",
                    (resultx)?"?":" ",
                    (result)&0xff,
                    rn);
            } else {
                printf("%-30s",dbstr?dbstr:"");
                dbstr = 0;
            }
        } else {
            printf("  %31s  w=%02x%s  %-6s  %-30s",
                    "",
                    ch->ram[WREG]&0xff,
                    ch->ram[WREG]&~0xff?"?":" ",
                    picOpcodeName(ch,op),
                    dbstr?dbstr:"");
            dbstr = 0;
        }
        printf("  S=%02x %s%s%s%s%s %s",
            stat&0xff,
            statx&ST_C ?"?":stat&ST_C ?"C":"c",
            statx&ST_DC?"?":stat&ST_DC?"D":"d",
            statx&ST_Z ?"?":stat&ST_Z ?"Z":"z",
            statx&ST_OV?"?":stat&ST_OV?"V":"v",
            statx&ST_N ?"?":stat&ST_N ?"N":"n",
            ch->skip ? "<<SKIP-NEXT>>" : "");
            
        if (regId >= INDF0 && regId <= PLUSW0) {
            printf("  using FSR0=%02x%02x",
                picRegValU(ch,FSR0H),
                picRegValU(ch,FSR0L));
        }
        if (regId >= INDF1 && regId <= PLUSW1) {
            printf("  using FSR1=%02x%02x",
                picRegValU(ch,FSR1H),
                picRegValU(ch,FSR1L));
        }
        if (regId >= INDF2 && regId <= PLUSW2) {
            printf("  using FSR2=%02x%02x",
                picRegValU(ch,FSR2H),
                picRegValU(ch,FSR2L));
        }
        if (dbstr) {
            printf(" %s",dbstr);
        }

        printf("  \n");
    }
}

//===========================================================================
// picInstDB() - run 1 instruction
//===========================================================================
int picInstDB(int regId, int dst, picOpcode op, const char *file, int line,
                                                    const char *dbstr)
{
    picChip *ch = picCurChip;
    int rx, fx, wx;
    int r,  f;
    int w = ch->ram[WREG];
    int s = ch->ram[STATUS];
    int s_ok = 0;
    int bit;
    int oldf;
    int imm = -1;
    char dbstr2[30];

    if (op == PIC_LABEL) {
        if (ch->trace) {
            printf("          %s:\n",dbstr?dbstr:"");
        }
        return 1;
    }
    ch->cycle++;
    if (ch->skip) {
        if (op != PIC_MOVFFa &&
            op != PIC_LFSRa) {
            ch->skip = 0;
        }
        if (ch->trace) {
            printf("%s:%-5d  <skip %s>\n", 
                file,line,
                picOpcodeName(ch,op));
        }
        return 0;
    }


    switch(op) {
        case PIC_NOP:
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return 0;

        case PIC_MOVWF:
            break;

        case PIC_BCF:
        case PIC_BSF:
        case PIC_BTFSC:
        case PIC_BTFSS:
        case PIC_BTG:
            s_ok = 1;
            ASSERT(dst >= PICDST_BIT0 && dst <= PICDST_BIT0+7);
            bit = 1<<(dst - PICDST_BIT0);
            ASSERT(bit > 0 && bit < 0x100);
            dst = PICDST_F;
            // fall through


        case PIC_ADDWF:
        case PIC_ADDWFC:
        case PIC_ANDWF:
        case PIC_CLRF:
        case PIC_COMF:
        case PIC_CPFSEQ:
        case PIC_CPFSGT:
        case PIC_CPFSLT:
        case PIC_DECF:
        case PIC_DECFSZ:
        case PIC_DCFSNZ:
        case PIC_INCF:
        case PIC_INCFSZ:
        case PIC_INFSNZ:
        case PIC_IORWF:
        case PIC_MOVF:
        case PIC_MOVFFa:
        case PIC_MOVFFb:
        case PIC_MULWF:
        case PIC_NEGF:
        case PIC_RLCF:
        case PIC_RLNCF:
        case PIC_RRCF:
        case PIC_RRNCF:
        case PIC_SETF:
        case PIC_SUBFWB:
        case PIC_SUBWF:
        case PIC_SUBWFB:
        case PIC_SWAPF:
        case PIC_TSTFSZ:
        case PIC_XORWF:
            f = picRegRead(ch,regId);
            break;

        case PIC_BC:
            ASSERT((ch->ram[STATUS] & (ST_C<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ch->ram[STATUS] & ST_C;
        case PIC_BNC:
            ASSERT((ch->ram[STATUS] & (ST_C<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ~ch->ram[STATUS] & ST_C;
        case PIC_BN:
            ASSERT((ch->ram[STATUS] & (ST_N<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ch->ram[STATUS] & ST_N;
        case PIC_BNN:
            ASSERT((ch->ram[STATUS] & (ST_N<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ~ch->ram[STATUS] & ST_N;
        case PIC_BOV:
            ASSERT((ch->ram[STATUS] & (ST_OV<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ch->ram[STATUS] & ST_OV;
        case PIC_BNOV:
            ASSERT((ch->ram[STATUS] & (ST_OV<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ~ch->ram[STATUS] & ST_OV;
        case PIC_BNZ:
            ASSERT((ch->ram[STATUS] & (ST_Z<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ~ch->ram[STATUS] & ST_Z;
        case PIC_BZ:
            ASSERT((ch->ram[STATUS] & (ST_Z<<8)) == 0);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return ch->ram[STATUS] & ST_Z;

        case PIC_BRA:
        case PIC_GOTO:
        case PIC_CALL:
        case PIC_RCALL:
        case PIC_RETURN:
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return 1;

        case PIC_DAW:
        case PIC_CLRWDT:
        case PIC_POP:
        case PIC_PUSH:
        case PIC_RETFIE:
        case PIC_SLEEP:
            ASSERT(!"Unimplemented op");
            return 0;

        case PIC_RESET:
            picChipReset(ch, PIC_RESET_INSTRUCTION);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 
                            0, -1, -1, 0, 0, dbstr);
            }
            return 1;

        case PIC_RETLW:
        case PIC_ADDLW:
        case PIC_ANDLW:
        case PIC_IORLW:
        case PIC_MOVLW:
        case PIC_MULLW:
        case PIC_SUBLW:
        case PIC_XORLW:
            ASSERT((dst & ~0xffUL) == 0 || ((dst+0x100) & ~0xffUL) == 0);
            f = dst & 0xff;
            dst = PICDST_W;
            regId = -1;
            imm = f;
            break;

        case PIC_MOVLB:
            //
            // BSR != 0 is not supported in red/write funcs yet
            //
            ASSERT(dst == 0);
            picRegSet(ch, BSR, dst);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, BSR, 
                            PICDST_F, ch->ram[BSR], -1, ch->ram[BSR], 0, dbstr);
            }
            return 1;

        case PIC_LFSRa:
            ASSERT( regId == FSR0L ||
                    regId == FSR1L ||
                    regId == FSR2L);
            //
            // dst holds immediate value
            //
            f = ch->ram[regId];
            ch->movff_tmp = ch->ram[regId+FSR0H-FSR0L];
            picRegSet32(ch, regId, regId+FSR0H-FSR0L, -1, -1, dst);
            break;

        case PIC_LFSRb:
            ASSERT( regId == FSR0H ||
                    regId == FSR1H ||
                    regId == FSR2H);
            f = ch->movff_tmp;
            break;

        case PIC_TBLRD_PREINC:
        case PIC_TBLWT_PREINC:
            r = picRegValU32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1);
            r++;
            picRegSet32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1, r);
            break;
            
        case PIC_TBLRD_POSTINC:
        case PIC_TBLWT_POSTINC:
            r = picRegValU32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1);
            picRegSet32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1, r+1);
            break;

        case PIC_TBLRD_POSTDEC:
        case PIC_TBLWT_POSTDEC:
            r = picRegValU32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1);
            picRegSet32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1, r-1);
            break;

        case PIC_TBLRD:
        case PIC_TBLWT:
            r = picRegValU32(ch, TBLPTRL, TBLPTRH, TBLPTRU, -1);
            break;

        default:
            ASSERT(!"bad opcode");
            return 0;
    }
    
    oldf = f;
    r = f;
    rx = wx = fx = 0;
    if ((w | f) & ~0xffUL) {
        rx = ~0xffUL;
        wx = rx & w;
        fx = rx & f;
        w = w & 0xff;
        f = f & 0xff;
    }


    switch(op) {
        case PIC_NOP:
            break;

        case PIC_ADDLW:     r = picCalcAdd(ch, f, w, 0,0, rx); break;
        case PIC_ADDWF:     r = picCalcAdd(ch, f, w, 0,0, rx); break;
        case PIC_ADDWFC:    r = picCalcAdd(ch, f, w, 0,1, rx); break;
        case PIC_SUBFWB:    r = picCalcAdd(ch, w, f, 1,1, rx); break;
        case PIC_SUBWFB:    r = picCalcAdd(ch, f, w, 1,1, rx); break;
        case PIC_SUBWF:     r = picCalcAdd(ch, f, w, 1,0, rx); break;
        case PIC_SUBLW:     r = picCalcAdd(ch, f, w, 1,0, rx); break;

        case PIC_DECF:      rx = fx;
                            r = picCalcAdd(ch, f, 1, 1, 0, rx);
                            break;
        case PIC_INCF:      rx = fx;
                            r = picCalcAdd(ch, f, 1, 0, 0, rx);
                            break;

        case PIC_NEGF:      rx = fx;
                            r = picCalcAdd(ch, 0, f, 1, 0, rx);
                            dst = PICDST_F;
                            break;

        case PIC_DECFSZ:    r = (f - 1) & 0xff;
                            ch->skip = (r==0);
                            rx = fx;
                            ASSERT(!rx);
                            break;
        case PIC_DCFSNZ:    r = (f - 1) & 0xff;
                            ch->skip = (r!=0);
                            rx = fx;
                            ASSERT(!rx);
                            break;
        case PIC_INCFSZ:    r = (f + 1) & 0xff;
                            ch->skip = (r==0);
                            rx = fx;
                            ASSERT(!rx);
                            break;
        case PIC_INFSNZ:    r = (f + 1) & 0xff;
                            ch->skip = (r!=0);
                            rx = fx;
                            ASSERT(!rx);
                            break;

        case PIC_ANDLW:
        case PIC_ANDWF:     r = w & f;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;
        case PIC_IORLW:
        case PIC_IORWF:     r = w | f;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;
        case PIC_XORLW:
        case PIC_XORWF:     r = w ^ f;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;
        case PIC_MOVF:      r = f; rx = fx;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;

        case PIC_LFSRa:     
        case PIC_LFSRb:     
                            r = ch->ram[regId];
                            rx = 0;
                            dst = PICDST_F;
                            break;

        case PIC_COMF:      r = ~f; rx = fx;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;
        case PIC_CLRF:      r = rx = 0;
                            s |= ST_Z;
                            s |= ST_Z<<8;   // suspicious - do not depend on it
                            ch->ram[STATUS] = s;
                            dst = PICDST_F;
                            break;
        case PIC_SETF:      r = 0xff; rx = 0;
                            dst = PICDST_F;
                            break;

        case PIC_RLCF:      r = (f << 1) | (s & 1);
                            s = (s & ~1UL) | ((r >> 8) & 1);
                            rx = 0;
                            if (fx | (s&0x0100)) {
                                rx  = 0xff00;
                                s  |= 0x0100;
                            }
                            r &= 0xff;
                            ch->ram[STATUS] = s;
                            break;
                            
        case PIC_RRCF:      r = (f >> 1) | ((s & 1) << 7);
                            s = (s & ~1UL) | (f & 1);
                            rx = 0;
                            if (fx | (s&0x0100)) {
                                rx  = 0xff00;
                                s  |= 0x0100;
                            }
                            ch->ram[STATUS] = s;
                            break;
                            
        case PIC_RLNCF:     r  = ((f  << 1) | (f  >> 7)) & 0xff;
                            rx = ((fx << 1) | (fx >> 7)) & 0xff00;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;
                            
        case PIC_RRNCF:     r  = ((f  >> 1) | (f  << 7)) & 0xff;
                            rx = ((fx >> 1) | (fx << 7)) & 0xff00;
                            picCalcStatus(ch, r, rx, ST_Z|ST_N);
                            break;
                            
        case PIC_SWAPF:     r  = ((f  >> 4) | (f  << 4)) & 0xff;
                            rx = ((fx >> 4) | (fx << 4)) & 0xff00;
                            break;

        case PIC_CPFSEQ:    ASSERT(!rx);
                            ch->skip = (f == w);
                            dst = PICDST_READF;
                            break;
        case PIC_CPFSGT:    ASSERT(!rx);
                            ch->skip = (f >  w);
                            dst = PICDST_READF;
                            break;
        case PIC_CPFSLT:    ASSERT(!rx);
                            ch->skip = (f <  w);
                            dst = PICDST_READF;
                            break;
        case PIC_TSTFSZ:    ASSERT(!fx);
                            ch->skip = (f ==  0);
                            dst = PICDST_READF;
                            break;

        case PIC_MOVFFa:    ch->movff_tmp = f | fx;
                            dst = PICDST_READF;
                            break;
        case PIC_MOVFFb:    r  = ch->movff_tmp;
                            rx = r & 0xff00;
                            r  = r & 0xff;
                            dst = PICDST_F;
                            break;
        case PIC_MOVWF:     r = w; rx = wx;
                            dst = PICDST_F;
                            break;

        case PIC_MULLW:
        case PIC_MULWF:     r = w * f;
                            ch->ram[PRODH] = rx | (r >> 8);
                            ch->ram[PRODL] = rx | (r & 0xff);
                            dst = PICDST_READF;
                            if (ch->trace) {
                                snprintf(dbstr2,sizeof(dbstr2),
                                    "%02x%02x->PROD",
                                    ch->ram[PRODH],
                                    ch->ram[PRODL]);
                                dbstr = dbstr2;
                            }
                            break;
                            
        case PIC_BCF:       r  = f & ~bit;
                            rx = fx & ~bit;
                            break;
        case PIC_BSF:       r  = f |  bit;
                            rx = fx & ~bit;
                            break;
        case PIC_BTG:       r  = f ^  bit;
                            rx = fx;
                            break;

        case PIC_BTFSC:     ASSERT(!(bit & fx));
                            ch->skip = (~f & bit);
                            dst = PICDST_READF;
                            break;

        case PIC_BTFSS:     ASSERT(!(bit & fx));
                            ch->skip = (f & bit);
                            dst = PICDST_READF;
                            break;

        case PIC_CLRWDT:
        case PIC_DAW:
        case PIC_POP:
        case PIC_PUSH:
        case PIC_SLEEP:
            ASSERT(!"Unsupported");
            return 0;

        case PIC_TBLRD:
        case PIC_TBLRD_POSTINC:
        case PIC_TBLRD_POSTDEC:
        case PIC_TBLRD_PREINC:
            ch->ram[TABLAT] = picReadFlashInstr(ch,r);
            if (ch->trace) {
                printf("%s:%-5d TABLE READ rom[%06x]: %02x\n",
                    file,line,
                    r,ch->ram[TABLAT]);
            }
            if (ch->trace) {
                picOpTrace(ch, file, line, op, TABLAT, 0, -1, -1,
                    ch->ram[TABLAT],ch->ram[TABLAT]&~0xff, dbstr);
            }
            return 1;

        case PIC_TBLWT:
        case PIC_TBLWT_POSTINC:
        case PIC_TBLWT_POSTDEC:
        case PIC_TBLWT_PREINC:
            picWriteFlashInstr(ch,r,ch->ram[TABLAT]);
            if (ch->trace) {
                picOpTrace(ch, file, line, op, -1, 0, -1, 
                                        ch->ram[TABLAT],
                                        ch->ram[TABLAT],
                                        ch->ram[TABLAT]&~0xff, dbstr);
            }
            return 1;

        case PIC_MOVLW:
        case PIC_RETLW:     r = f; rx = fx;
                            break;

        default:
            ASSERT(!"bad opcode");
            return 0;
    }

    //
    // most instructions should not be used with status reg
    //
    ASSERT(regId != STATUS || s_ok);

    //
    // BSR is not supported yet in picRegRead, picRegWrite, etc.
    //
    ASSERT(regId != BSR);
            
    if (ch->trace) {
        picOpTrace(ch, file, line, op, regId, dst, imm, oldf, r, rx, dbstr);
    }

    switch(dst) {
        case PICDST_READF:
        case PICDST_NONE:   break;
        case PICDST_W:      ch->ram[WREG] = r | rx;
                            if (regId == WREG) regId = -1;
                            break;
        case PICDST_F:      f = r; fx = rx;
                            ASSERT(regId >= 0);
                            break;
        default:
            ASSERT(!"bad dst");
            return 0;
    }

    if (regId >= 0) {
        picRegWrite(ch, regId, f | fx);
    }

    return 1;
}

//###########################################################################
//############################### DEBUG CODE ################################
//###########################################################################


//===========================================================================
// picTrace() - enable/disable tracing
//===========================================================================
int picTrace(int enable)
{
    int old = 0;
    if (!picCurChip) return -1;
    old = picCurChip->trace;
    picCurChip->trace = enable;
    return old;
}

//===========================================================================
// picGetCycle() - get cycle count
//===========================================================================
int picGetCycle(void)
{
    if (!picCurChip) return -1;
    return picCurChip->cycle;
}

//===========================================================================
// picSetCycle() - set cycle count
//===========================================================================
void picSetCycle(int cyc)
{
    if (!picCurChip) return;
    picCurChip->cycle = cyc;
}

//===========================================================================
// pr() - print register
//===========================================================================
int pr(int id)
{
    int x;
    int val = -1;
    if (!picCurChip) return -1;
    val = picRegValU(picCurChip,id);
    x   = picRegX(picCurChip,id);
    printf("%20s = %02x",
        picRegName(picCurChip,id,0),
        val);
    if (x) {
        printf("  UNKNOWN BITS: %02x",x&0xff);
    }
    printf("\n");
    return val;
}

//===========================================================================
// prr() - print register range
//===========================================================================
int prr(int first,int last)
{
    int val;
    int start = 1;
    char x[17];
    char *xp = x;
    
    if (last<first) {
        printf("first>last\n");
        return -1;
    }
    for(;first<=last; first++) {
        if (start || (first & 0xf) == 0) {
            if (!start) {
                *xp = 0;
                printf("   %s\n",x);
            }
            printf("%06x: ",first);
            start=0;
            xp = x;
        }
        val = picRegValU(picCurChip,first);
        printf("%02x ",val&0xff);
        *(xp++) = (val & ~0xff) ? '?' : '.';
    }
    printf("\n");
    return 0;
}

//===========================================================================
// pfsr() - print fsr
//===========================================================================
int pfsr(int id)
{
    int val,h,l,reg;
    if (!picCurChip) return -1;
    switch(id) {
        case 0: reg = FSR0L; break;
        case 1: reg = FSR1L; break;
        case 2: reg = FSR2L; break;
        default:
            printf("bad fsr %d\n",id);
            return -1;
    }
    h = picRegValU(0,reg+FSR0H-FSR0L);
    l = picRegValU(0,reg);
    val = picRegValU(0,(h<<8)+l);

    printf("FSR%d = 0x%02x%02x *=0x%02x\n",id,h,l,val);
    return val;
}

//===========================================================================
// picTest() - run test suite
//===========================================================================
void picTest(void)
{
#if PIC_TESTS
    picTestAdd();
    //printf("picTest() pass!");
#endif
}

This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:28:42 PDT 2007