* src/SDCCmain.c (linkEdit): do not test for PIC16 target since, PIC16
[fw/sdcc] / src / pic16 / pcode.c
1 /*-------------------------------------------------------------------------
2
3   pcode.c - post code generation
4
5    Written By -  Scott Dattalo scott@dattalo.com
6    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
7
8    This program is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23 #include <stdio.h>
24
25 #include "common.h"   // Include everything in the SDCC src directory
26 #include "newalloc.h"
27
28
29 #include "main.h"
30 #include "pcode.h"
31 #include "pcodeflow.h"
32 #include "ralloc.h"
33 #include "device.h"
34
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
36
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
38 #define STRCASECMP stricmp
39 #define inline
40 #else
41 #define STRCASECMP strcasecmp
42 #endif
43
44 #define DUMP_DF_GRAPHS 0
45
46 /****************************************************************/
47 /****************************************************************/
48
49 static peepCommand peepCommands[] = {
50
51   {NOTBITSKIP, "_NOTBITSKIP_"},
52   {BITSKIP, "_BITSKIP_"},
53   {INVERTBITSKIP, "_INVERTBITSKIP_"},
54
55   {-1, NULL}
56 };
57
58
59
60 // Eventually this will go into device dependent files:
61 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
66 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
68
69 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
71 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
72
73 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
74 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
75 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
76 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
77
78 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
79
80 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
86
87 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
88 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
92
93 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
94 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
98
99 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
100 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
104
105 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
106 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
107
108 /* EEPROM registers */
109 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
113
114 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
115 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
117
118 pCodeOpReg *pic16_stackpnt_lo;
119 pCodeOpReg *pic16_stackpnt_hi;
120 pCodeOpReg *pic16_stack_postinc;
121 pCodeOpReg *pic16_stack_postdec;
122 pCodeOpReg *pic16_stack_preinc;
123 pCodeOpReg *pic16_stack_plusw;
124
125 pCodeOpReg *pic16_framepnt_lo;
126 pCodeOpReg *pic16_framepnt_hi;
127 pCodeOpReg *pic16_frame_postinc;
128 pCodeOpReg *pic16_frame_postdec;
129 pCodeOpReg *pic16_frame_preinc;
130 pCodeOpReg *pic16_frame_plusw;
131
132 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
133 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
134
135 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
136 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
137
138
139 static int mnemonics_initialized = 0;
140
141
142 static hTab *pic16MnemonicsHash = NULL;
143 static hTab *pic16pCodePeepCommandsHash = NULL;
144
145 static pFile *the_pFile = NULL;
146 static pBlock *pb_dead_pcodes = NULL;
147
148 /* Hardcoded flags to change the behavior of the PIC port */
149 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
150 static int functionInlining = 1;      /* inline functions if nonzero */
151 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
152
153 int pic16_pcode_verbose = 0;
154
155 //static int GpCodeSequenceNumber = 1;
156 static int GpcFlowSeq = 1;
157
158 extern void pic16_RemoveUnusedRegisters(void);
159 extern void pic16_RegsUnMapLiveRanges(void);
160 extern void pic16_BuildFlowTree(pBlock *pb);
161 extern void pic16_pCodeRegOptimizeRegUsage(int level);
162 extern int pic16_picIsInitialized(void);
163 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
164 extern int mnem2key(unsigned char const *mnem);
165
166 /****************************************************************/
167 /*                      Forward declarations                    */
168 /****************************************************************/
169
170 void pic16_unlinkpCode(pCode *pc);
171 #if 0
172 static void genericAnalyze(pCode *pc);
173 static void AnalyzeGOTO(pCode *pc);
174 static void AnalyzeSKIP(pCode *pc);
175 static void AnalyzeRETURN(pCode *pc);
176 #endif
177
178 static void genericDestruct(pCode *pc);
179 static void genericPrint(FILE *of,pCode *pc);
180
181 static void pCodePrintLabel(FILE *of, pCode *pc);
182 static void pCodePrintFunction(FILE *of, pCode *pc);
183 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
184 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
185 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
186 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
187 int pic16_pCodePeepMatchRule(pCode *pc);
188 static void pBlockStats(FILE *of, pBlock *pb);
189 static pBlock *newpBlock(void);
190 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
191 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
192 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
193 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
194 void OptimizeLocalRegs(void);
195 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
196
197 char *dumpPicOptype(PIC_OPTYPE type);
198
199 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
200 pCodeOp *pic16_popGetLit(int);
201 pCodeOp *pic16_popGetWithString(char *);
202 extern int inWparamList(char *s);
203
204 /** data flow optimization helpers **/
205 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
206 static void pic16_vcg_dump (FILE *of, pBlock *pb);
207 static void pic16_vcg_dump_default (pBlock *pb);
208 #endif
209 static int pic16_pCodeIsAlive (pCode *pc);
210 static void pic16_df_stats ();
211 static void pic16_createDF (pBlock *pb);
212 static int pic16_removeUnusedRegistersDF ();
213 static void pic16_destructDF (pBlock *pb);
214 static void releaseStack ();
215
216 /****************************************************************/
217 /*                    PIC Instructions                          */
218 /****************************************************************/
219
220 pCodeInstruction pic16_pciADDWF = {
221   {PC_OPCODE, NULL, NULL, 0, NULL, 
222    //   genericAnalyze,
223    genericDestruct,
224    genericPrint},
225   POC_ADDWF,
226   "ADDWF",
227   2,
228   NULL, // from branch
229   NULL, // to branch
230   NULL, // label
231   NULL, // operand
232   NULL, // flow block
233   NULL, // C source 
234   3,    // num ops
235   1,0,  // dest, bit instruction
236   0,0,  // branch, skip
237   0,    // literal operand
238   1,    // RAM access bit
239   0,    // fast call/return mode select bit
240   0,    // second memory operand
241   0,    // second literal operand
242   POC_NOP,
243   (PCC_W | PCC_REGISTER),   // inCond
244   (PCC_REGISTER | PCC_STATUS), // outCond
245   PCI_MAGIC
246 };
247
248 pCodeInstruction pic16_pciADDFW = {
249   {PC_OPCODE, NULL, NULL, 0, NULL, 
250    //   genericAnalyze,
251    genericDestruct,
252    genericPrint},
253   POC_ADDFW,
254   "ADDWF",
255   2,
256   NULL, // from branch
257   NULL, // to branch
258   NULL, // label
259   NULL, // operand
260   NULL, // flow block
261   NULL, // C source 
262   3,    // num ops
263   0,0,  // dest, bit instruction
264   0,0,  // branch, skip
265   0,    // literal operand
266   1,    // RAM access bit
267   0,    // fast call/return mode select bit
268   0,    // second memory operand
269   0,    // second literal operand
270   POC_NOP,
271   (PCC_W | PCC_REGISTER),   // inCond
272   (PCC_W | PCC_STATUS), // outCond
273   PCI_MAGIC
274 };
275
276 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
277   {PC_OPCODE, NULL, NULL, 0, NULL, 
278    //   genericAnalyze,
279    genericDestruct,
280    genericPrint},
281   POC_ADDWFC,
282   "ADDWFC",
283   2,
284   NULL, // from branch
285   NULL, // to branch
286   NULL, // label
287   NULL, // operand
288   NULL, // flow block
289   NULL, // C source 
290   3,    // num ops
291   1,0,  // dest, bit instruction
292   0,0,  // branch, skip
293   0,    // literal operand
294   1,    // RAM access bit
295   0,    // fast call/return mode select bit
296   0,    // second memory operand
297   0,    // second literal operand
298   POC_NOP,
299   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
300   (PCC_REGISTER | PCC_STATUS), // outCond
301   PCI_MAGIC
302 };
303
304 pCodeInstruction pic16_pciADDFWC = {
305   {PC_OPCODE, NULL, NULL, 0, NULL, 
306    //   genericAnalyze,
307    genericDestruct,
308    genericPrint},
309   POC_ADDFWC,
310   "ADDWFC",
311   2,
312   NULL, // from branch
313   NULL, // to branch
314   NULL, // label
315   NULL, // operand
316   NULL, // flow block
317   NULL, // C source 
318   3,    // num ops
319   0,0,  // dest, bit instruction
320   0,0,  // branch, skip
321   0,    // literal operand
322   1,    // RAM access bit
323   0,    // fast call/return mode select bit
324   0,    // second memory operand
325   0,    // second literal operand
326   POC_NOP,
327   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
328   (PCC_W | PCC_STATUS), // outCond
329   PCI_MAGIC
330 };
331
332 pCodeInstruction pic16_pciADDLW = {
333   {PC_OPCODE, NULL, NULL, 0, NULL, 
334    //   genericAnalyze,
335    genericDestruct,
336    genericPrint},
337   POC_ADDLW,
338   "ADDLW",
339   2,
340   NULL, // from branch
341   NULL, // to branch
342   NULL, // label
343   NULL, // operand
344   NULL, // flow block
345   NULL, // C source 
346   1,    // num ops
347   0,0,  // dest, bit instruction
348   0,0,  // branch, skip
349   1,    // literal operand
350   0,    // RAM access bit
351   0,    // fast call/return mode select bit
352   0,    // second memory operand
353   0,    // second literal operand
354   POC_NOP,
355   (PCC_W | PCC_LITERAL),   // inCond
356   (PCC_W | PCC_STATUS), // outCond
357   PCI_MAGIC
358 };
359
360 pCodeInstruction pic16_pciANDLW = {
361   {PC_OPCODE, NULL, NULL, 0, NULL, 
362    //   genericAnalyze,
363    genericDestruct,
364    genericPrint},
365   POC_ANDLW,
366   "ANDLW",
367   2,
368   NULL, // from branch
369   NULL, // to branch
370   NULL, // label
371   NULL, // operand
372   NULL, // flow block
373   NULL, // C source 
374   1,    // num ops
375   0,0,  // dest, bit instruction
376   0,0,  // branch, skip
377   1,    // literal operand
378   0,    // RAM access bit
379   0,    // fast call/return mode select bit
380   0,    // second memory operand
381   0,    // second literal operand
382   POC_NOP,
383   (PCC_W | PCC_LITERAL),   // inCond
384   (PCC_W | PCC_Z | PCC_N), // outCond
385   PCI_MAGIC
386 };
387
388 pCodeInstruction pic16_pciANDWF = {
389   {PC_OPCODE, NULL, NULL, 0, NULL, 
390    //   genericAnalyze,
391    genericDestruct,
392    genericPrint},
393   POC_ANDWF,
394   "ANDWF",
395   2,
396   NULL, // from branch
397   NULL, // to branch
398   NULL, // label
399   NULL, // operand
400   NULL, // flow block
401   NULL, // C source 
402   3,    // num ops
403   1,0,  // dest, bit instruction
404   0,0,  // branch, skip
405   0,    // literal operand
406   1,    // RAM access bit
407   0,    // fast call/return mode select bit
408   0,    // second memory operand
409   0,    // second literal operand
410   POC_NOP,
411   (PCC_W | PCC_REGISTER),   // inCond
412   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
413   PCI_MAGIC
414 };
415
416 pCodeInstruction pic16_pciANDFW = {
417   {PC_OPCODE, NULL, NULL, 0, NULL, 
418    //   genericAnalyze,
419    genericDestruct,
420    genericPrint},
421   POC_ANDFW,
422   "ANDWF",
423   2,
424   NULL, // from branch
425   NULL, // to branch
426   NULL, // label
427   NULL, // operand
428   NULL, // flow block
429   NULL, // C source 
430   3,    // num ops
431   0,0,  // dest, bit instruction
432   0,0,  // branch, skip
433   0,    // literal operand
434   1,    // RAM access bit
435   0,    // fast call/return mode select bit
436   0,    // second memory operand
437   0,    // second literal operand
438   POC_NOP,
439   (PCC_W | PCC_REGISTER),   // inCond
440   (PCC_W | PCC_Z | PCC_N) // outCond
441 };
442
443 pCodeInstruction pic16_pciBC = { // mdubuc - New
444   {PC_OPCODE, NULL, NULL, 0, NULL, 
445    //   genericAnalyze,
446    genericDestruct,
447    genericPrint},
448   POC_BC,
449   "BC",
450   2,
451   NULL, // from branch
452   NULL, // to branch
453   NULL, // label
454   NULL, // operand
455   NULL, // flow block
456   NULL, // C source 
457   1,    // num ops
458   0,0,  // dest, bit instruction
459   1,0,  // branch, skip
460   0,    // literal operand
461   0,    // RAM access bit
462   0,    // fast call/return mode select bit
463   0,    // second memory operand
464   0,    // second literal operand
465   POC_NOP,
466   (PCC_REL_ADDR | PCC_C),   // inCond
467   PCC_NONE,    // outCond
468   PCI_MAGIC
469 };
470
471 pCodeInstruction pic16_pciBCF = {
472   {PC_OPCODE, NULL, NULL, 0, NULL, 
473    //   genericAnalyze,
474    genericDestruct,
475    genericPrint},
476   POC_BCF,
477   "BCF",
478   2,
479   NULL, // from branch
480   NULL, // to branch
481   NULL, // label
482   NULL, // operand
483   NULL, // flow block
484   NULL, // C source 
485   3,    // num ops
486   1,1,  // dest, bit instruction
487   0,0,  // branch, skip
488   0,    // literal operand
489   1,    // RAM access bit
490   0,    // fast call/return mode select bit
491   0,    // second memory operand
492   0,    // second literal operand
493   POC_BSF,
494   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
495   PCC_REGISTER, // outCond
496   PCI_MAGIC
497 };
498
499 pCodeInstruction pic16_pciBN = { // mdubuc - New
500   {PC_OPCODE, NULL, NULL, 0, NULL, 
501    //   genericAnalyze,
502    genericDestruct,
503    genericPrint},
504   POC_BN,
505   "BN",
506   2,
507   NULL, // from branch
508   NULL, // to branch
509   NULL, // label
510   NULL, // operand
511   NULL, // flow block
512   NULL, // C source 
513   1,    // num ops
514   0,0,  // dest, bit instruction
515   1,0,  // branch, skip
516   0,    // literal operand
517   0,    // RAM access bit
518   0,    // fast call/return mode select bit
519   0,    // second memory operand
520   0,    // second literal operand
521   POC_NOP,
522   (PCC_REL_ADDR | PCC_N),   // inCond
523   PCC_NONE   , // outCond
524   PCI_MAGIC
525 };
526
527 pCodeInstruction pic16_pciBNC = { // mdubuc - New
528   {PC_OPCODE, NULL, NULL, 0, NULL, 
529    //   genericAnalyze,
530    genericDestruct,
531    genericPrint},
532   POC_BNC,
533   "BNC",
534   2,
535   NULL, // from branch
536   NULL, // to branch
537   NULL, // label
538   NULL, // operand
539   NULL, // flow block
540   NULL, // C source 
541   1,    // num ops
542   0,0,  // dest, bit instruction
543   1,0,  // branch, skip
544   0,    // literal operand
545   0,    // RAM access bit
546   0,    // fast call/return mode select bit
547   0,    // second memory operand
548   0,    // second literal operand
549   POC_NOP,
550   (PCC_REL_ADDR | PCC_C),   // inCond
551   PCC_NONE   , // outCond
552   PCI_MAGIC
553 };
554
555 pCodeInstruction pic16_pciBNN = { // mdubuc - New
556   {PC_OPCODE, NULL, NULL, 0, NULL, 
557    //   genericAnalyze,
558    genericDestruct,
559    genericPrint},
560   POC_BNN,
561   "BNN",
562   2,
563   NULL, // from branch
564   NULL, // to branch
565   NULL, // label
566   NULL, // operand
567   NULL, // flow block
568   NULL, // C source 
569   1,    // num ops
570   0,0,  // dest, bit instruction
571   1,0,  // branch, skip
572   0,    // literal operand
573   0,    // RAM access bit
574   0,    // fast call/return mode select bit
575   0,    // second memory operand
576   0,    // second literal operand
577   POC_NOP,
578   (PCC_REL_ADDR | PCC_N),   // inCond
579   PCC_NONE   , // outCond
580   PCI_MAGIC
581 };
582
583 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
584   {PC_OPCODE, NULL, NULL, 0, NULL, 
585    //   genericAnalyze,
586    genericDestruct,
587    genericPrint},
588   POC_BNOV,
589   "BNOV",
590   2,
591   NULL, // from branch
592   NULL, // to branch
593   NULL, // label
594   NULL, // operand
595   NULL, // flow block
596   NULL, // C source 
597   1,    // num ops
598   0,0,  // dest, bit instruction
599   1,0,  // branch, skip
600   0,    // literal operand
601   0,    // RAM access bit
602   0,    // fast call/return mode select bit
603   0,    // second memory operand
604   0,    // second literal operand
605   POC_NOP,
606   (PCC_REL_ADDR | PCC_OV),   // inCond
607   PCC_NONE   , // outCond
608   PCI_MAGIC
609 };
610
611 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
612   {PC_OPCODE, NULL, NULL, 0, NULL, 
613    //   genericAnalyze,
614    genericDestruct,
615    genericPrint},
616   POC_BNZ,
617   "BNZ",
618   2,
619   NULL, // from branch
620   NULL, // to branch
621   NULL, // label
622   NULL, // operand
623   NULL, // flow block
624   NULL, // C source 
625   1,    // num ops
626   0,0,  // dest, bit instruction
627   1,0,  // branch, skip
628   0,    // literal operand
629   0,    // RAM access bit
630   0,    // fast call/return mode select bit
631   0,    // second memory operand
632   0,    // second literal operand
633   POC_NOP,
634   (PCC_REL_ADDR | PCC_Z),   // inCond
635   PCC_NONE   , // outCond
636   PCI_MAGIC
637 };
638
639 pCodeInstruction pic16_pciBOV = { // mdubuc - New
640   {PC_OPCODE, NULL, NULL, 0, NULL, 
641    //   genericAnalyze,
642    genericDestruct,
643    genericPrint},
644   POC_BOV,
645   "BOV",
646   2,
647   NULL, // from branch
648   NULL, // to branch
649   NULL, // label
650   NULL, // operand
651   NULL, // flow block
652   NULL, // C source 
653   1,    // num ops
654   0,0,  // dest, bit instruction
655   1,0,  // branch, skip
656   0,    // literal operand
657   0,    // RAM access bit
658   0,    // fast call/return mode select bit
659   0,    // second memory operand
660   0,    // second literal operand
661   POC_NOP,
662   (PCC_REL_ADDR | PCC_OV),   // inCond
663   PCC_NONE , // outCond
664   PCI_MAGIC
665 };
666
667 pCodeInstruction pic16_pciBRA = { // mdubuc - New
668   {PC_OPCODE, NULL, NULL, 0, NULL, 
669    //   genericAnalyze,
670    genericDestruct,
671    genericPrint},
672   POC_BRA,
673   "BRA",
674   2,
675   NULL, // from branch
676   NULL, // to branch
677   NULL, // label
678   NULL, // operand
679   NULL, // flow block
680   NULL, // C source 
681   1,    // num ops
682   0,0,  // dest, bit instruction
683   1,0,  // branch, skip
684   0,    // literal operand
685   0,    // RAM access bit
686   0,    // fast call/return mode select bit
687   0,    // second memory operand
688   0,    // second literal operand
689   POC_NOP,
690   PCC_REL_ADDR,   // inCond
691   PCC_NONE   , // outCond
692   PCI_MAGIC
693 };
694
695 pCodeInstruction pic16_pciBSF = {
696   {PC_OPCODE, NULL, NULL, 0, NULL, 
697    //   genericAnalyze,
698    genericDestruct,
699    genericPrint},
700   POC_BSF,
701   "BSF",
702   2,
703   NULL, // from branch
704   NULL, // to branch
705   NULL, // label
706   NULL, // operand
707   NULL, // flow block
708   NULL, // C source 
709   3,    // num ops
710   1,1,  // dest, bit instruction
711   0,0,  // branch, skip
712   0,    // literal operand
713   1,    // RAM access bit
714   0,    // fast call/return mode select bit
715   0,    // second memory operand
716   0,    // second literal operand
717   POC_BCF,
718   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
719   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
720   PCI_MAGIC
721 };
722
723 pCodeInstruction pic16_pciBTFSC = {
724   {PC_OPCODE, NULL, NULL, 0, NULL, 
725    //   AnalyzeSKIP,
726    genericDestruct,
727    genericPrint},
728   POC_BTFSC,
729   "BTFSC",
730   2,
731   NULL, // from branch
732   NULL, // to branch
733   NULL, // label
734   NULL, // operand
735   NULL, // flow block
736   NULL, // C source 
737   3,    // num ops
738   0,1,  // dest, bit instruction
739   1,1,  // branch, skip
740   0,    // literal operand
741   1,    // RAM access bit
742   0,    // fast call/return mode select bit
743   0,    // second memory operand
744   0,    // second literal operand
745   POC_BTFSS,
746   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
747   PCC_EXAMINE_PCOP, // outCond
748   PCI_MAGIC
749 };
750
751 pCodeInstruction pic16_pciBTFSS = {
752   {PC_OPCODE, NULL, NULL, 0, NULL, 
753    //   AnalyzeSKIP,
754    genericDestruct,
755    genericPrint},
756   POC_BTFSS,
757   "BTFSS",
758   2,
759   NULL, // from branch
760   NULL, // to branch
761   NULL, // label
762   NULL, // operand
763   NULL, // flow block
764   NULL, // C source 
765   3,    // num ops
766   0,1,  // dest, bit instruction
767   1,1,  // branch, skip
768   0,    // literal operand
769   1,    // RAM access bit
770   0,    // fast call/return mode select bit
771   0,    // second memory operand
772   0,    // second literal operand
773   POC_BTFSC,
774   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
775   PCC_EXAMINE_PCOP, // outCond
776   PCI_MAGIC
777 };
778
779 pCodeInstruction pic16_pciBTG = { // mdubuc - New
780   {PC_OPCODE, NULL, NULL, 0, NULL, 
781    //   genericAnalyze,
782    genericDestruct,
783    genericPrint},
784   POC_BTG,
785   "BTG",
786   2,
787   NULL, // from branch
788   NULL, // to branch
789   NULL, // label
790   NULL, // operand
791   NULL, // flow block
792   NULL, // C source 
793   3,    // num ops
794   0,1,  // dest, bit instruction
795   0,0,  // branch, skip
796   0,    // literal operand
797   1,    // RAM access bit
798   0,    // fast call/return mode select bit
799   0,    // second memory operand
800   0,    // second literal operand
801   POC_NOP,
802   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
803   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
804   PCI_MAGIC
805 };
806
807 pCodeInstruction pic16_pciBZ = { // mdubuc - New
808   {PC_OPCODE, NULL, NULL, 0, NULL, 
809    //   genericAnalyze,
810    genericDestruct,
811    genericPrint},
812   POC_BZ,
813   "BZ",
814   2,
815   NULL, // from branch
816   NULL, // to branch
817   NULL, // label
818   NULL, // operand
819   NULL, // flow block
820   NULL, // C source 
821   1,    // num ops
822   0,0,  // dest, bit instruction
823   1,0,  // branch, skip
824   0,    // literal operand
825   0,    // RAM access bit
826   0,    // fast call/return mode select bit
827   0,    // second memory operand
828   0,    // second literal operand
829   POC_NOP,
830   (PCC_REL_ADDR | PCC_Z),   // inCond
831   PCC_NONE, // outCond
832   PCI_MAGIC
833 };
834
835 pCodeInstruction pic16_pciCALL = {
836   {PC_OPCODE, NULL, NULL, 0, NULL, 
837    //   genericAnalyze,
838    genericDestruct,
839    genericPrint},
840   POC_CALL,
841   "CALL",
842   4,
843   NULL, // from branch
844   NULL, // to branch
845   NULL, // label
846   NULL, // operand
847   NULL, // flow block
848   NULL, // C source 
849   2,    // num ops
850   0,0,  // dest, bit instruction
851   1,0,  // branch, skip
852   0,    // literal operand
853   0,    // RAM access bit
854   1,    // fast call/return mode select bit
855   0,    // second memory operand
856   0,    // second literal operand
857   POC_NOP,
858   PCC_NONE, // inCond
859   PCC_NONE, // outCond
860   PCI_MAGIC
861 };
862
863 pCodeInstruction pic16_pciCOMF = {
864   {PC_OPCODE, NULL, NULL, 0, NULL, 
865    //   genericAnalyze,
866    genericDestruct,
867    genericPrint},
868   POC_COMF,
869   "COMF",
870   2,
871   NULL, // from branch
872   NULL, // to branch
873   NULL, // label
874   NULL, // operand
875   NULL, // flow block
876   NULL, // C source 
877   3,    // num ops
878   1,0,  // dest, bit instruction
879   0,0,  // branch, skip
880   0,    // literal operand
881   1,    // RAM access bit
882   0,    // fast call/return mode select bit
883   0,    // second memory operand
884   0,    // second literal operand
885   POC_NOP,
886   PCC_REGISTER,  // inCond
887   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
888   PCI_MAGIC
889 };
890
891 pCodeInstruction pic16_pciCOMFW = {
892   {PC_OPCODE, NULL, NULL, 0, NULL, 
893    //   genericAnalyze,
894    genericDestruct,
895    genericPrint},
896   POC_COMFW,
897   "COMF",
898   2,
899   NULL, // from branch
900   NULL, // to branch
901   NULL, // label
902   NULL, // operand
903   NULL, // flow block
904   NULL, // C source 
905   3,    // num ops
906   0,0,  // dest, bit instruction
907   0,0,  // branch, skip
908   0,    // literal operand
909   1,    // RAM access bit
910   0,    // fast call/return mode select bit
911   0,    // second memory operand
912   0,    // second literal operand
913   POC_NOP,
914   PCC_REGISTER,  // inCond
915   (PCC_W | PCC_Z | PCC_N) , // outCond
916   PCI_MAGIC
917 };
918
919 pCodeInstruction pic16_pciCLRF = {
920   {PC_OPCODE, NULL, NULL, 0, NULL, 
921    //   genericAnalyze,
922    genericDestruct,
923    genericPrint},
924   POC_CLRF,
925   "CLRF",
926   2,
927   NULL, // from branch
928   NULL, // to branch
929   NULL, // label
930   NULL, // operand
931   NULL, // flow block
932   NULL, // C source 
933   2,    // num ops
934   0,0,  // dest, bit instruction
935   0,0,  // branch, skip
936   0,    // literal operand
937   1,    // RAM access bit
938   0,    // fast call/return mode select bit
939   0,    // second memory operand
940   0,    // second literal operand
941   POC_NOP,
942   PCC_NONE, // inCond
943   (PCC_REGISTER | PCC_Z), // outCond
944   PCI_MAGIC
945 };
946
947 pCodeInstruction pic16_pciCLRWDT = {
948   {PC_OPCODE, NULL, NULL, 0, NULL, 
949    //   genericAnalyze,
950    genericDestruct,
951    genericPrint},
952   POC_CLRWDT,
953   "CLRWDT",
954   2,
955   NULL, // from branch
956   NULL, // to branch
957   NULL, // label
958   NULL, // operand
959   NULL, // flow block
960   NULL, // C source 
961   0,    // num ops
962   0,0,  // dest, bit instruction
963   0,0,  // branch, skip
964   0,    // literal operand
965   0,    // RAM access bit
966   0,    // fast call/return mode select bit
967   0,    // second memory operand
968   0,    // second literal operand
969   POC_NOP,
970   PCC_NONE, // inCond
971   PCC_NONE , // outCond
972   PCI_MAGIC
973 };
974
975 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
976   {PC_OPCODE, NULL, NULL, 0, NULL, 
977    //   genericAnalyze,
978    genericDestruct,
979    genericPrint},
980   POC_CPFSEQ,
981   "CPFSEQ",
982   2,
983   NULL, // from branch
984   NULL, // to branch
985   NULL, // label
986   NULL, // operand
987   NULL, // flow block
988   NULL, // C source 
989   2,    // num ops
990   0,0,  // dest, bit instruction
991   1,1,  // branch, skip
992   0,    // literal operand
993   1,    // RAM access bit
994   0,    // fast call/return mode select bit
995   0,    // second memory operand
996   0,    // second literal operand
997   POC_NOP,
998   (PCC_W | PCC_REGISTER), // inCond
999   PCC_NONE , // outCond
1000   PCI_MAGIC
1001 };
1002
1003 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1004   {PC_OPCODE, NULL, NULL, 0, NULL, 
1005    //   genericAnalyze,
1006    genericDestruct,
1007    genericPrint},
1008   POC_CPFSGT,
1009   "CPFSGT",
1010   2,
1011   NULL, // from branch
1012   NULL, // to branch
1013   NULL, // label
1014   NULL, // operand
1015   NULL, // flow block
1016   NULL, // C source 
1017   2,    // num ops
1018   0,0,  // dest, bit instruction
1019   1,1,  // branch, skip
1020   0,    // literal operand
1021   1,    // RAM access bit
1022   0,    // fast call/return mode select bit
1023   0,    // second memory operand
1024   0,    // second literal operand
1025   POC_NOP,
1026   (PCC_W | PCC_REGISTER), // inCond
1027   PCC_NONE , // outCond
1028   PCI_MAGIC
1029 };
1030
1031 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1032   {PC_OPCODE, NULL, NULL, 0, NULL, 
1033    //   genericAnalyze,
1034    genericDestruct,
1035    genericPrint},
1036   POC_CPFSLT,
1037   "CPFSLT",
1038   2,
1039   NULL, // from branch
1040   NULL, // to branch
1041   NULL, // label
1042   NULL, // operand
1043   NULL, // flow block
1044   NULL, // C source 
1045   2,    // num ops
1046   1,0,  // dest, bit instruction
1047   1,1,  // branch, skip
1048   0,    // literal operand
1049   1,    // RAM access bit
1050   0,    // fast call/return mode select bit
1051   0,    // second memory operand
1052   0,    // second literal operand
1053   POC_NOP,
1054   (PCC_W | PCC_REGISTER), // inCond
1055   PCC_NONE , // outCond
1056   PCI_MAGIC
1057 };
1058
1059 pCodeInstruction pic16_pciDAW = {
1060   {PC_OPCODE, NULL, NULL, 0, NULL, 
1061    //   genericAnalyze,
1062    genericDestruct,
1063    genericPrint},
1064   POC_DAW,
1065   "DAW",
1066   2,
1067   NULL, // from branch
1068   NULL, // to branch
1069   NULL, // label
1070   NULL, // operand
1071   NULL, // flow block
1072   NULL, // C source 
1073   0,    // num ops
1074   0,0,  // dest, bit instruction
1075   0,0,  // branch, skip
1076   0,    // literal operand
1077   0,    // RAM access bit
1078   0,    // fast call/return mode select bit
1079   0,    // second memory operand
1080   0,    // second literal operand
1081   POC_NOP,
1082   PCC_W, // inCond
1083   (PCC_W | PCC_C), // outCond
1084   PCI_MAGIC
1085 };
1086
1087 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1088   {PC_OPCODE, NULL, NULL, 0, NULL, 
1089    //   genericAnalyze,
1090    genericDestruct,
1091    genericPrint},
1092   POC_DCFSNZ,
1093   "DCFSNZ",
1094   2,
1095   NULL, // from branch
1096   NULL, // to branch
1097   NULL, // label
1098   NULL, // operand
1099   NULL, // flow block
1100   NULL, // C source 
1101   3,    // num ops
1102   1,0,  // dest, bit instruction
1103   1,1,  // branch, skip
1104   0,    // literal operand
1105   1,    // RAM access bit
1106   0,    // fast call/return mode select bit
1107   0,    // second memory operand
1108   0,    // second literal operand
1109   POC_NOP,
1110   PCC_REGISTER, // inCond
1111   PCC_REGISTER , // outCond
1112   PCI_MAGIC
1113 };
1114
1115 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1116   {PC_OPCODE, NULL, NULL, 0, NULL, 
1117    //   genericAnalyze,
1118    genericDestruct,
1119    genericPrint},
1120   POC_DCFSNZW,
1121   "DCFSNZ",
1122   2,
1123   NULL, // from branch
1124   NULL, // to branch
1125   NULL, // label
1126   NULL, // operand
1127   NULL, // flow block
1128   NULL, // C source 
1129   3,    // num ops
1130   0,0,  // dest, bit instruction
1131   1,1,  // branch, skip
1132   0,    // literal operand
1133   1,    // RAM access bit
1134   0,    // fast call/return mode select bit
1135   0,    // second memory operand
1136   0,    // second literal operand
1137   POC_NOP,
1138   PCC_REGISTER, // inCond
1139   PCC_W , // outCond
1140   PCI_MAGIC
1141 };
1142
1143 pCodeInstruction pic16_pciDECF = {
1144   {PC_OPCODE, NULL, NULL, 0, NULL, 
1145    //   genericAnalyze,
1146    genericDestruct,
1147    genericPrint},
1148   POC_DECF,
1149   "DECF",
1150   2,
1151   NULL, // from branch
1152   NULL, // to branch
1153   NULL, // label
1154   NULL, // operand
1155   NULL, // flow block
1156   NULL, // C source 
1157   3,    // num ops
1158   1,0,  // dest, bit instruction
1159   0,0,  // branch, skip
1160   0,    // literal operand
1161   1,    // RAM access bit
1162   0,    // fast call/return mode select bit
1163   0,    // second memory operand
1164   0,    // second literal operand
1165   POC_NOP,
1166   PCC_REGISTER,   // inCond
1167   (PCC_REGISTER | PCC_STATUS)  , // outCond
1168   PCI_MAGIC
1169 };
1170
1171 pCodeInstruction pic16_pciDECFW = {
1172   {PC_OPCODE, NULL, NULL, 0, NULL, 
1173    //   genericAnalyze,
1174    genericDestruct,
1175    genericPrint},
1176   POC_DECFW,
1177   "DECF",
1178   2,
1179   NULL, // from branch
1180   NULL, // to branch
1181   NULL, // label
1182   NULL, // operand
1183   NULL, // flow block
1184   NULL, // C source 
1185   3,    // num ops
1186   0,0,  // dest, bit instruction
1187   0,0,  // branch, skip
1188   0,    // literal operand
1189   1,    // RAM access bit
1190   0,    // fast call/return mode select bit
1191   0,    // second memory operand
1192   0,    // second literal operand
1193   POC_NOP,
1194   PCC_REGISTER,   // inCond
1195   (PCC_W | PCC_STATUS)  , // outCond
1196   PCI_MAGIC
1197 };
1198
1199 pCodeInstruction pic16_pciDECFSZ = {
1200   {PC_OPCODE, NULL, NULL, 0, NULL, 
1201    //   AnalyzeSKIP,
1202    genericDestruct,
1203    genericPrint},
1204   POC_DECFSZ,
1205   "DECFSZ",
1206   2,
1207   NULL, // from branch
1208   NULL, // to branch
1209   NULL, // label
1210   NULL, // operand
1211   NULL, // flow block
1212   NULL, // C source 
1213   3,    // num ops
1214   1,0,  // dest, bit instruction
1215   1,1,  // branch, skip
1216   0,    // literal operand
1217   1,    // RAM access bit
1218   0,    // fast call/return mode select bit
1219   0,    // second memory operand
1220   0,    // second literal operand
1221   POC_NOP,
1222   PCC_REGISTER,   // inCond
1223   PCC_REGISTER   , // outCond
1224   PCI_MAGIC
1225 };
1226
1227 pCodeInstruction pic16_pciDECFSZW = {
1228   {PC_OPCODE, NULL, NULL, 0, NULL, 
1229    //   AnalyzeSKIP,
1230    genericDestruct,
1231    genericPrint},
1232   POC_DECFSZW,
1233   "DECFSZ",
1234   2,
1235   NULL, // from branch
1236   NULL, // to branch
1237   NULL, // label
1238   NULL, // operand
1239   NULL, // flow block
1240   NULL, // C source 
1241   3,    // num ops
1242   0,0,  // dest, bit instruction
1243   1,1,  // branch, skip
1244   0,    // literal operand
1245   1,    // RAM access bit
1246   0,    // fast call/return mode select bit
1247   0,    // second memory operand
1248   0,    // second literal operand
1249   POC_NOP,
1250   PCC_REGISTER,   // inCond
1251   PCC_W          , // outCond
1252   PCI_MAGIC
1253 };
1254
1255 pCodeInstruction pic16_pciGOTO = {
1256   {PC_OPCODE, NULL, NULL, 0, NULL, 
1257    //   AnalyzeGOTO,
1258    genericDestruct,
1259    genericPrint},
1260   POC_GOTO,
1261   "GOTO",
1262   4,
1263   NULL, // from branch
1264   NULL, // to branch
1265   NULL, // label
1266   NULL, // operand
1267   NULL, // flow block
1268   NULL, // C source 
1269   1,    // num ops
1270   0,0,  // dest, bit instruction
1271   1,0,  // branch, skip
1272   0,    // literal operand
1273   0,    // RAM access bit
1274   0,    // fast call/return mode select bit
1275   0,    // second memory operand
1276   0,    // second literal operand
1277   POC_NOP,
1278   PCC_REL_ADDR,   // inCond
1279   PCC_NONE   , // outCond
1280   PCI_MAGIC
1281 };
1282
1283 pCodeInstruction pic16_pciINCF = {
1284   {PC_OPCODE, NULL, NULL, 0, NULL, 
1285    //   genericAnalyze,
1286    genericDestruct,
1287    genericPrint},
1288   POC_INCF,
1289   "INCF",
1290   2,
1291   NULL, // from branch
1292   NULL, // to branch
1293   NULL, // label
1294   NULL, // operand
1295   NULL, // flow block
1296   NULL, // C source 
1297   3,    // num ops
1298   1,0,  // dest, bit instruction
1299   0,0,  // branch, skip
1300   0,    // literal operand
1301   1,    // RAM access bit
1302   0,    // fast call/return mode select bit
1303   0,    // second memory operand
1304   0,    // second literal operand
1305   POC_NOP,
1306   PCC_REGISTER,   // inCond
1307   (PCC_REGISTER | PCC_STATUS), // outCond
1308   PCI_MAGIC
1309 };
1310
1311 pCodeInstruction pic16_pciINCFW = {
1312   {PC_OPCODE, NULL, NULL, 0, NULL, 
1313    //   genericAnalyze,
1314    genericDestruct,
1315    genericPrint},
1316   POC_INCFW,
1317   "INCF",
1318   2,
1319   NULL, // from branch
1320   NULL, // to branch
1321   NULL, // label
1322   NULL, // operand
1323   NULL, // flow block
1324   NULL, // C source 
1325   3,    // num ops
1326   0,0,  // dest, bit instruction
1327   0,0,  // branch, skip
1328   0,    // literal operand
1329   1,    // RAM access bit
1330   0,    // fast call/return mode select bit
1331   0,    // second memory operand
1332   0,    // second literal operand
1333   POC_NOP,
1334   PCC_REGISTER,   // inCond
1335   (PCC_W | PCC_STATUS)  , // outCond
1336   PCI_MAGIC
1337 };
1338
1339 pCodeInstruction pic16_pciINCFSZ = {
1340   {PC_OPCODE, NULL, NULL, 0, NULL, 
1341    //   AnalyzeSKIP,
1342    genericDestruct,
1343    genericPrint},
1344   POC_INCFSZ,
1345   "INCFSZ",
1346   2,
1347   NULL, // from branch
1348   NULL, // to branch
1349   NULL, // label
1350   NULL, // operand
1351   NULL, // flow block
1352   NULL, // C source 
1353   3,    // num ops
1354   1,0,  // dest, bit instruction
1355   1,1,  // branch, skip
1356   0,    // literal operand
1357   1,    // RAM access bit
1358   0,    // fast call/return mode select bit
1359   0,    // second memory operand
1360   0,    // second literal operand
1361   POC_INFSNZ,
1362   PCC_REGISTER,   // inCond
1363   PCC_REGISTER   , // outCond
1364   PCI_MAGIC
1365 };
1366
1367 pCodeInstruction pic16_pciINCFSZW = {
1368   {PC_OPCODE, NULL, NULL, 0, NULL, 
1369    //   AnalyzeSKIP,
1370    genericDestruct,
1371    genericPrint},
1372   POC_INCFSZW,
1373   "INCFSZ",
1374   2,
1375   NULL, // from branch
1376   NULL, // to branch
1377   NULL, // label
1378   NULL, // operand
1379   NULL, // flow block
1380   NULL, // C source 
1381   3,    // num ops
1382   0,0,  // dest, bit instruction
1383   1,1,  // branch, skip
1384   0,    // literal operand
1385   1,    // RAM access bit
1386   0,    // fast call/return mode select bit
1387   0,    // second memory operand
1388   0,    // second literal operand
1389   POC_INFSNZW,
1390   PCC_REGISTER,   // inCond
1391   PCC_W          , // outCond
1392   PCI_MAGIC
1393 };
1394
1395 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1396   {PC_OPCODE, NULL, NULL, 0, NULL, 
1397    //   AnalyzeSKIP,
1398    genericDestruct,
1399    genericPrint},
1400   POC_INFSNZ,
1401   "INFSNZ",
1402   2,
1403   NULL, // from branch
1404   NULL, // to branch
1405   NULL, // label
1406   NULL, // operand
1407   NULL, // flow block
1408   NULL, // C source 
1409   3,    // num ops
1410   1,0,  // dest, bit instruction
1411   1,1,  // branch, skip
1412   0,    // literal operand
1413   1,    // RAM access bit
1414   0,    // fast call/return mode select bit
1415   0,    // second memory operand
1416   0,    // second literal operand
1417   POC_INCFSZ,
1418   PCC_REGISTER,   // inCond
1419   PCC_REGISTER   , // outCond
1420   PCI_MAGIC
1421 };
1422
1423 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1424   {PC_OPCODE, NULL, NULL, 0, NULL, 
1425    //   AnalyzeSKIP,
1426    genericDestruct,
1427    genericPrint},
1428   POC_INFSNZW,
1429   "INFSNZ",
1430   2,
1431   NULL, // from branch
1432   NULL, // to branch
1433   NULL, // label
1434   NULL, // operand
1435   NULL, // flow block
1436   NULL, // C source 
1437   3,    // num ops
1438   0,0,  // dest, bit instruction
1439   1,1,  // branch, skip
1440   0,    // literal operand
1441   1,    // RAM access bit
1442   0,    // fast call/return mode select bit
1443   0,    // second memory operand
1444   0,    // second literal operand
1445   POC_INCFSZW,
1446   PCC_REGISTER,   // inCond
1447   PCC_W          , // outCond
1448   PCI_MAGIC
1449 };
1450
1451 pCodeInstruction pic16_pciIORWF = {
1452   {PC_OPCODE, NULL, NULL, 0, NULL, 
1453    //   genericAnalyze,
1454    genericDestruct,
1455    genericPrint},
1456   POC_IORWF,
1457   "IORWF",
1458   2,
1459   NULL, // from branch
1460   NULL, // to branch
1461   NULL, // label
1462   NULL, // operand
1463   NULL, // flow block
1464   NULL, // C source 
1465   3,    // num ops
1466   1,0,  // dest, bit instruction
1467   0,0,  // branch, skip
1468   0,    // literal operand
1469   1,    // RAM access bit
1470   0,    // fast call/return mode select bit
1471   0,    // second memory operand
1472   0,    // second literal operand
1473   POC_NOP,
1474   (PCC_W | PCC_REGISTER),   // inCond
1475   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1476   PCI_MAGIC
1477 };
1478
1479 pCodeInstruction pic16_pciIORFW = {
1480   {PC_OPCODE, NULL, NULL, 0, NULL, 
1481    //   genericAnalyze,
1482    genericDestruct,
1483    genericPrint},
1484   POC_IORFW,
1485   "IORWF",
1486   2,
1487   NULL, // from branch
1488   NULL, // to branch
1489   NULL, // label
1490   NULL, // operand
1491   NULL, // flow block
1492   NULL, // C source 
1493   3,    // num ops
1494   0,0,  // dest, bit instruction
1495   0,0,  // branch, skip
1496   0,    // literal operand
1497   1,    // RAM access bit
1498   0,    // fast call/return mode select bit
1499   0,    // second memory operand
1500   0,    // second literal operand
1501   POC_NOP,
1502   (PCC_W | PCC_REGISTER),   // inCond
1503   (PCC_W | PCC_Z | PCC_N), // outCond
1504   PCI_MAGIC
1505 };
1506
1507 pCodeInstruction pic16_pciIORLW = {
1508   {PC_OPCODE, NULL, NULL, 0, NULL, 
1509    //   genericAnalyze,
1510    genericDestruct,
1511    genericPrint},
1512   POC_IORLW,
1513   "IORLW",
1514   2,
1515   NULL, // from branch
1516   NULL, // to branch
1517   NULL, // label
1518   NULL, // operand
1519   NULL, // flow block
1520   NULL, // C source 
1521   1,    // num ops
1522   0,0,  // dest, bit instruction
1523   0,0,  // branch, skip
1524   1,    // literal operand
1525   0,    // RAM access bit
1526   0,    // fast call/return mode select bit
1527   0,    // second memory operand
1528   0,    // second literal operand
1529   POC_NOP,
1530   (PCC_W | PCC_LITERAL),   // inCond
1531   (PCC_W | PCC_Z | PCC_N), // outCond
1532   PCI_MAGIC
1533 };
1534
1535 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1536   {PC_OPCODE, NULL, NULL, 0, NULL, 
1537    //   genericAnalyze,
1538    genericDestruct,
1539    genericPrint},
1540   POC_LFSR,
1541   "LFSR",
1542   4,
1543   NULL, // from branch
1544   NULL, // to branch
1545   NULL, // label
1546   NULL, // operand
1547   NULL, // flow block
1548   NULL, // C source 
1549   2,    // num ops
1550   0,0,  // dest, bit instruction
1551   0,0,  // branch, skip
1552   1,    // literal operand
1553   0,    // RAM access bit
1554   0,    // fast call/return mode select bit
1555   0,    // second memory operand
1556   1,    // second literal operand
1557   POC_NOP,
1558   PCC_LITERAL, // inCond
1559   PCC_NONE, // outCond
1560   PCI_MAGIC
1561 };
1562
1563 pCodeInstruction pic16_pciMOVF = {
1564   {PC_OPCODE, NULL, NULL, 0, NULL, 
1565    //   genericAnalyze,
1566    genericDestruct,
1567    genericPrint},
1568   POC_MOVF,
1569   "MOVF",
1570   2,
1571   NULL, // from branch
1572   NULL, // to branch
1573   NULL, // label
1574   NULL, // operand
1575   NULL, // flow block
1576   NULL, // C source 
1577   3,    // num ops
1578   1,0,  // dest, bit instruction
1579   0,0,  // branch, skip
1580   0,    // literal operand
1581   1,    // RAM access bit
1582   0,    // fast call/return mode select bit
1583   0,    // second memory operand
1584   0,    // second literal operand
1585   POC_NOP,
1586   PCC_REGISTER,   // inCond
1587   (PCC_Z | PCC_N), // outCond
1588   PCI_MAGIC
1589 };
1590
1591 pCodeInstruction pic16_pciMOVFW = {
1592   {PC_OPCODE, NULL, NULL, 0, NULL, 
1593    //   genericAnalyze,
1594    genericDestruct,
1595    genericPrint},
1596   POC_MOVFW,
1597   "MOVF",
1598   2,
1599   NULL, // from branch
1600   NULL, // to branch
1601   NULL, // label
1602   NULL, // operand
1603   NULL, // flow block
1604   NULL, // C source 
1605   3,    // num ops
1606   0,0,  // dest, bit instruction
1607   0,0,  // branch, skip
1608   0,    // literal operand
1609   1,    // RAM access bit
1610   0,    // fast call/return mode select bit
1611   0,    // second memory operand
1612   0,    // second literal operand
1613   POC_NOP,
1614   PCC_REGISTER,   // inCond
1615   (PCC_W | PCC_N | PCC_Z), // outCond
1616   PCI_MAGIC
1617 };
1618
1619 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1620   {PC_OPCODE, NULL, NULL, 0, NULL, 
1621    //   genericAnalyze,
1622    genericDestruct,
1623    genericPrint},
1624   POC_MOVFF,
1625   "MOVFF",
1626   4,
1627   NULL, // from branch
1628   NULL, // to branch
1629   NULL, // label
1630   NULL, // operand
1631   NULL, // flow block
1632   NULL, // C source 
1633   2,    // num ops
1634   0,0,  // dest, bit instruction
1635   0,0,  // branch, skip
1636   0,    // literal operand
1637   0,    // RAM access bit
1638   0,    // fast call/return mode select bit
1639   1,    // second memory operand
1640   0,    // second literal operand
1641   POC_NOP,
1642   PCC_REGISTER,   // inCond
1643   PCC_REGISTER2, // outCond
1644   PCI_MAGIC
1645 };
1646
1647 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1648   {PC_OPCODE, NULL, NULL, 0, NULL, 
1649    genericDestruct,
1650    genericPrint},
1651   POC_MOVLB,
1652   "MOVLB",
1653   2,
1654   NULL, // from branch
1655   NULL, // to branch
1656   NULL, // label
1657   NULL, // operand
1658   NULL, // flow block
1659   NULL, // C source 
1660   1,    // num ops
1661   0,0,  // dest, bit instruction
1662   0,0,  // branch, skip
1663   1,    // literal operand
1664   0,    // RAM access bit
1665   0,    // fast call/return mode select bit
1666   0,    // second memory operand
1667   0,    // second literal operand
1668   POC_NOP,
1669   (PCC_NONE | PCC_LITERAL),   // inCond
1670   PCC_REGISTER, // outCond - BSR
1671   PCI_MAGIC
1672 };
1673
1674 pCodeInstruction pic16_pciMOVLW = {
1675   {PC_OPCODE, NULL, NULL, 0, NULL, 
1676    genericDestruct,
1677    genericPrint},
1678   POC_MOVLW,
1679   "MOVLW",
1680   2,
1681   NULL, // from branch
1682   NULL, // to branch
1683   NULL, // label
1684   NULL, // operand
1685   NULL, // flow block
1686   NULL, // C source 
1687   1,    // num ops
1688   0,0,  // dest, bit instruction
1689   0,0,  // branch, skip
1690   1,    // literal operand
1691   0,    // RAM access bit
1692   0,    // fast call/return mode select bit
1693   0,    // second memory operand
1694   0,    // second literal operand
1695   POC_NOP,
1696   (PCC_NONE | PCC_LITERAL),   // inCond
1697   PCC_W, // outCond
1698   PCI_MAGIC
1699 };
1700
1701 pCodeInstruction pic16_pciMOVWF = {
1702   {PC_OPCODE, NULL, NULL, 0, NULL, 
1703    //   genericAnalyze,
1704    genericDestruct,
1705    genericPrint},
1706   POC_MOVWF,
1707   "MOVWF",
1708   2,
1709   NULL, // from branch
1710   NULL, // to branch
1711   NULL, // label
1712   NULL, // operand
1713   NULL, // flow block
1714   NULL, // C source 
1715   2,    // num ops
1716   0,0,  // dest, bit instruction
1717   0,0,  // branch, skip
1718   0,    // literal operand
1719   1,    // RAM access bit
1720   0,    // fast call/return mode select bit
1721   0,    // second memory operand
1722   0,    // second literal operand
1723   POC_NOP,
1724   PCC_W,   // inCond
1725   PCC_REGISTER, // outCond
1726   PCI_MAGIC
1727 };
1728
1729 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1730   {PC_OPCODE, NULL, NULL, 0, NULL, 
1731    genericDestruct,
1732    genericPrint},
1733   POC_MULLW,
1734   "MULLW",
1735   2,
1736   NULL, // from branch
1737   NULL, // to branch
1738   NULL, // label
1739   NULL, // operand
1740   NULL, // flow block
1741   NULL, // C source 
1742   1,    // num ops
1743   0,0,  // dest, bit instruction
1744   0,0,  // branch, skip
1745   1,    // literal operand
1746   0,    // RAM access bit
1747   0,    // fast call/return mode select bit
1748   0,    // second memory operand
1749   0,    // second literal operand
1750   POC_NOP,
1751   (PCC_W | PCC_LITERAL),   // inCond
1752   PCC_NONE, // outCond - PROD
1753   PCI_MAGIC
1754 };
1755
1756 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1757   {PC_OPCODE, NULL, NULL, 0, NULL, 
1758    genericDestruct,
1759    genericPrint},
1760   POC_MULWF,
1761   "MULWF",
1762   2,
1763   NULL, // from branch
1764   NULL, // to branch
1765   NULL, // label
1766   NULL, // operand
1767   NULL, // flow block
1768   NULL, // C source 
1769   2,    // num ops
1770   0,0,  // dest, bit instruction
1771   0,0,  // branch, skip
1772   0,    // literal operand
1773   1,    // RAM access bit
1774   0,    // fast call/return mode select bit
1775   0,    // second memory operand
1776   0,    // second literal operand
1777   POC_NOP,
1778   (PCC_W | PCC_REGISTER),   // inCond
1779   PCC_REGISTER, // outCond - PROD
1780   PCI_MAGIC
1781 };
1782
1783 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1784   {PC_OPCODE, NULL, NULL, 0, NULL, 
1785    genericDestruct,
1786    genericPrint},
1787   POC_NEGF,
1788   "NEGF",
1789   2,
1790   NULL, // from branch
1791   NULL, // to branch
1792   NULL, // label
1793   NULL, // operand
1794   NULL, // flow block
1795   NULL, // C source 
1796   2,    // num ops
1797   0,0,  // dest, bit instruction
1798   0,0,  // branch, skip
1799   0,    // literal operand
1800   1,    // RAM access bit
1801   0,    // fast call/return mode select bit
1802   0,    // second memory operand
1803   0,    // second literal operand
1804   POC_NOP,
1805   PCC_REGISTER, // inCond
1806   (PCC_REGISTER | PCC_STATUS), // outCond
1807   PCI_MAGIC
1808 };
1809
1810 pCodeInstruction pic16_pciNOP = {
1811   {PC_OPCODE, NULL, NULL, 0, NULL, 
1812    genericDestruct,
1813    genericPrint},
1814   POC_NOP,
1815   "NOP",
1816   2,
1817   NULL, // from branch
1818   NULL, // to branch
1819   NULL, // label
1820   NULL, // operand
1821   NULL, // flow block
1822   NULL, // C source 
1823   0,    // num ops
1824   0,0,  // dest, bit instruction
1825   0,0,  // branch, skip
1826   0,    // literal operand
1827   0,    // RAM access bit
1828   0,    // fast call/return mode select bit
1829   0,    // second memory operand
1830   0,    // second literal operand
1831   POC_NOP,
1832   PCC_NONE,   // inCond
1833   PCC_NONE, // outCond
1834   PCI_MAGIC
1835 };
1836
1837 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1838   {PC_OPCODE, NULL, NULL, 0, NULL, 
1839    genericDestruct,
1840    genericPrint},
1841   POC_POP,
1842   "POP",
1843   2,
1844   NULL, // from branch
1845   NULL, // to branch
1846   NULL, // label
1847   NULL, // operand
1848   NULL, // flow block
1849   NULL, // C source 
1850   0,    // num ops
1851   0,0,  // dest, bit instruction
1852   0,0,  // branch, skip
1853   0,    // literal operand
1854   0,    // RAM access bit
1855   0,    // fast call/return mode select bit
1856   0,    // second memory operand
1857   0,    // second literal operand
1858   POC_NOP,
1859   PCC_NONE,  // inCond
1860   PCC_NONE  , // outCond
1861   PCI_MAGIC
1862 };
1863
1864 pCodeInstruction pic16_pciPUSH = {
1865   {PC_OPCODE, NULL, NULL, 0, NULL, 
1866    genericDestruct,
1867    genericPrint},
1868   POC_PUSH,
1869   "PUSH",
1870   2,
1871   NULL, // from branch
1872   NULL, // to branch
1873   NULL, // label
1874   NULL, // operand
1875   NULL, // flow block
1876   NULL, // C source 
1877   0,    // num ops
1878   0,0,  // dest, bit instruction
1879   0,0,  // branch, skip
1880   0,    // literal operand
1881   0,    // RAM access bit
1882   0,    // fast call/return mode select bit
1883   0,    // second memory operand
1884   0,    // second literal operand
1885   POC_NOP,
1886   PCC_NONE,  // inCond
1887   PCC_NONE  , // outCond
1888   PCI_MAGIC
1889 };
1890
1891 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1892   {PC_OPCODE, NULL, NULL, 0, NULL, 
1893    genericDestruct,
1894    genericPrint},
1895   POC_RCALL,
1896   "RCALL",
1897   2,
1898   NULL, // from branch
1899   NULL, // to branch
1900   NULL, // label
1901   NULL, // operand
1902   NULL, // flow block
1903   NULL, // C source 
1904   1,    // num ops
1905   0,0,  // dest, bit instruction
1906   1,0,  // branch, skip
1907   0,    // literal operand
1908   0,    // RAM access bit
1909   0,    // fast call/return mode select bit
1910   0,    // second memory operand
1911   0,    // second literal operand
1912   POC_NOP,
1913   PCC_REL_ADDR,  // inCond
1914   PCC_NONE  , // outCond
1915   PCI_MAGIC
1916 };
1917
1918 pCodeInstruction pic16_pciRETFIE = {
1919   {PC_OPCODE, NULL, NULL, 0, NULL, 
1920    //   AnalyzeRETURN,
1921    genericDestruct,
1922    genericPrint},
1923   POC_RETFIE,
1924   "RETFIE",
1925   2,
1926   NULL, // from branch
1927   NULL, // to branch
1928   NULL, // label
1929   NULL, // operand
1930   NULL, // flow block
1931   NULL, // C source 
1932   1,    // num ops
1933   0,0,  // dest, bit instruction
1934   1,0,  // branch, skip
1935   0,    // literal operand
1936   0,    // RAM access bit
1937   1,    // fast call/return mode select bit
1938   0,    // second memory operand
1939   0,    // second literal operand
1940   POC_NOP,
1941   PCC_NONE,   // inCond
1942   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1943   PCI_MAGIC
1944 };
1945
1946 pCodeInstruction pic16_pciRETLW = {
1947   {PC_OPCODE, NULL, NULL, 0, NULL, 
1948    //   AnalyzeRETURN,
1949    genericDestruct,
1950    genericPrint},
1951   POC_RETLW,
1952   "RETLW",
1953   2,
1954   NULL, // from branch
1955   NULL, // to branch
1956   NULL, // label
1957   NULL, // operand
1958   NULL, // flow block
1959   NULL, // C source 
1960   1,    // num ops
1961   0,0,  // dest, bit instruction
1962   1,0,  // branch, skip
1963   1,    // literal operand
1964   0,    // RAM access bit
1965   0,    // fast call/return mode select bit
1966   0,    // second memory operand
1967   0,    // second literal operand
1968   POC_NOP,
1969   PCC_LITERAL,   // inCond
1970   PCC_W, // outCond
1971   PCI_MAGIC
1972 };
1973
1974 pCodeInstruction pic16_pciRETURN = {
1975   {PC_OPCODE, NULL, NULL, 0, NULL, 
1976    //   AnalyzeRETURN,
1977    genericDestruct,
1978    genericPrint},
1979   POC_RETURN,
1980   "RETURN",
1981   2,
1982   NULL, // from branch
1983   NULL, // to branch
1984   NULL, // label
1985   NULL, // operand
1986   NULL, // flow block
1987   NULL, // C source 
1988   1,    // num ops
1989   0,0,  // dest, bit instruction
1990   1,0,  // branch, skip
1991   0,    // literal operand
1992   0,    // RAM access bit
1993   1,    // fast call/return mode select bit
1994   0,    // second memory operand
1995   0,    // second literal operand
1996   POC_NOP,
1997   PCC_NONE,   // inCond
1998   PCC_NONE, // outCond
1999   PCI_MAGIC
2000 };
2001 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2002   {PC_OPCODE, NULL, NULL, 0, NULL, 
2003    //   genericAnalyze,
2004    genericDestruct,
2005    genericPrint},
2006   POC_RLCF,
2007   "RLCF",
2008   2,
2009   NULL, // from branch
2010   NULL, // to branch
2011   NULL, // label
2012   NULL, // operand
2013   NULL, // flow block
2014   NULL, // C source 
2015   3,    // num ops
2016   1,0,  // dest, bit instruction
2017   0,0,  // branch, skip
2018   0,    // literal operand
2019   1,    // RAM access bit
2020   0,    // fast call/return mode select bit
2021   0,    // second memory operand
2022   0,    // second literal operand
2023   POC_NOP,
2024   (PCC_C | PCC_REGISTER),   // inCond
2025   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2026   PCI_MAGIC
2027 };
2028
2029 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2030   {PC_OPCODE, NULL, NULL, 0, NULL, 
2031    //   genericAnalyze,
2032    genericDestruct,
2033    genericPrint},
2034   POC_RLCFW,
2035   "RLCF",
2036   2,
2037   NULL, // from branch
2038   NULL, // to branch
2039   NULL, // label
2040   NULL, // operand
2041   NULL, // flow block
2042   NULL, // C source 
2043   3,    // num ops
2044   0,0,  // dest, bit instruction
2045   0,0,  // branch, skip
2046   0,    // literal operand
2047   1,    // RAM access bit
2048   0,    // fast call/return mode select bit
2049   0,    // second memory operand
2050   0,    // second literal operand
2051   POC_NOP,
2052   (PCC_C | PCC_REGISTER),   // inCond
2053   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2054   PCI_MAGIC
2055 };
2056
2057 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2058   {PC_OPCODE, NULL, NULL, 0, NULL, 
2059    //   genericAnalyze,
2060    genericDestruct,
2061    genericPrint},
2062   POC_RLNCF,
2063   "RLNCF",
2064   2,
2065   NULL, // from branch
2066   NULL, // to branch
2067   NULL, // label
2068   NULL, // operand
2069   NULL, // flow block
2070   NULL, // C source 
2071   3,    // num ops
2072   1,0,  // dest, bit instruction
2073   0,0,  // branch, skip
2074   0,    // literal operand
2075   1,    // RAM access bit
2076   0,    // fast call/return mode select bit
2077   0,    // second memory operand
2078   0,    // second literal operand
2079   POC_NOP,
2080   PCC_REGISTER,   // inCond
2081   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2082   PCI_MAGIC
2083 };
2084 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2085   {PC_OPCODE, NULL, NULL, 0, NULL, 
2086    //   genericAnalyze,
2087    genericDestruct,
2088    genericPrint},
2089   POC_RLNCFW,
2090   "RLNCF",
2091   2,
2092   NULL, // from branch
2093   NULL, // to branch
2094   NULL, // label
2095   NULL, // operand
2096   NULL, // flow block
2097   NULL, // C source 
2098   3,    // num ops
2099   0,0,  // dest, bit instruction
2100   0,0,  // branch, skip
2101   0,    // literal operand
2102   1,    // RAM access bit
2103   0,    // fast call/return mode select bit
2104   0,    // second memory operand
2105   0,    // second literal operand
2106   POC_NOP,
2107   PCC_REGISTER,   // inCond
2108   (PCC_W | PCC_Z | PCC_N), // outCond
2109   PCI_MAGIC
2110 };
2111 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2112   {PC_OPCODE, NULL, NULL, 0, NULL, 
2113    //   genericAnalyze,
2114    genericDestruct,
2115    genericPrint},
2116   POC_RRCF,
2117   "RRCF",
2118   2,
2119   NULL, // from branch
2120   NULL, // to branch
2121   NULL, // label
2122   NULL, // operand
2123   NULL, // flow block
2124   NULL, // C source 
2125   3,    // num ops
2126   1,0,  // dest, bit instruction
2127   0,0,  // branch, skip
2128   0,    // literal operand
2129   1,    // RAM access bit
2130   0,    // fast call/return mode select bit
2131   0,    // second memory operand
2132   0,    // second literal operand
2133   POC_NOP,
2134   (PCC_C | PCC_REGISTER),   // inCond
2135   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2136   PCI_MAGIC
2137 };
2138 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2139   {PC_OPCODE, NULL, NULL, 0, NULL, 
2140    //   genericAnalyze,
2141    genericDestruct,
2142    genericPrint},
2143   POC_RRCFW,
2144   "RRCF",
2145   2,
2146   NULL, // from branch
2147   NULL, // to branch
2148   NULL, // label
2149   NULL, // operand
2150   NULL, // flow block
2151   NULL, // C source 
2152   3,    // num ops
2153   0,0,  // dest, bit instruction
2154   0,0,  // branch, skip
2155   0,    // literal operand
2156   1,    // RAM access bit
2157   0,    // fast call/return mode select bit
2158   0,    // second memory operand
2159   0,    // second literal operand
2160   POC_NOP,
2161   (PCC_C | PCC_REGISTER),   // inCond
2162   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2163   PCI_MAGIC
2164 };
2165 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2166   {PC_OPCODE, NULL, NULL, 0, NULL, 
2167    //   genericAnalyze,
2168    genericDestruct,
2169    genericPrint},
2170   POC_RRNCF,
2171   "RRNCF",
2172   2,
2173   NULL, // from branch
2174   NULL, // to branch
2175   NULL, // label
2176   NULL, // operand
2177   NULL, // flow block
2178   NULL, // C source 
2179   3,    // num ops
2180   1,0,  // dest, bit instruction
2181   0,0,  // branch, skip
2182   0,    // literal operand
2183   1,    // RAM access bit
2184   0,    // fast call/return mode select bit
2185   0,    // second memory operand
2186   0,    // second literal operand
2187   POC_NOP,
2188   PCC_REGISTER,   // inCond
2189   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2190   PCI_MAGIC
2191 };
2192
2193 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2194   {PC_OPCODE, NULL, NULL, 0, NULL, 
2195    //   genericAnalyze,
2196    genericDestruct,
2197    genericPrint},
2198   POC_RRNCFW,
2199   "RRNCF",
2200   2,
2201   NULL, // from branch
2202   NULL, // to branch
2203   NULL, // label
2204   NULL, // operand
2205   NULL, // flow block
2206   NULL, // C source 
2207   3,    // num ops
2208   0,0,  // dest, bit instruction
2209   0,0,  // branch, skip
2210   0,    // literal operand
2211   1,    // RAM access bit
2212   0,    // fast call/return mode select bit
2213   0,    // second memory operand
2214   0,    // second literal operand
2215   POC_NOP,
2216   PCC_REGISTER,   // inCond
2217   (PCC_W | PCC_Z | PCC_N), // outCond
2218   PCI_MAGIC
2219 };
2220
2221 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2222   {PC_OPCODE, NULL, NULL, 0, NULL, 
2223    //   genericAnalyze,
2224    genericDestruct,
2225    genericPrint},
2226   POC_SETF,
2227   "SETF",
2228   2,
2229   NULL, // from branch
2230   NULL, // to branch
2231   NULL, // label
2232   NULL, // operand
2233   NULL, // flow block
2234   NULL, // C source 
2235   2,    // num ops
2236   0,0,  // dest, bit instruction
2237   0,0,  // branch, skip
2238   0,    // literal operand
2239   1,    // RAM access bit
2240   0,    // fast call/return mode select bit
2241   0,    // second memory operand
2242   0,    // second literal operand
2243   POC_NOP,
2244   PCC_NONE,  // inCond
2245   PCC_REGISTER  , // outCond
2246   PCI_MAGIC
2247 };
2248
2249 pCodeInstruction pic16_pciSUBLW = {
2250   {PC_OPCODE, NULL, NULL, 0, NULL, 
2251    //   genericAnalyze,
2252    genericDestruct,
2253    genericPrint},
2254   POC_SUBLW,
2255   "SUBLW",
2256   2,
2257   NULL, // from branch
2258   NULL, // to branch
2259   NULL, // label
2260   NULL, // operand
2261   NULL, // flow block
2262   NULL, // C source 
2263   1,    // num ops
2264   0,0,  // dest, bit instruction
2265   0,0,  // branch, skip
2266   1,    // literal operand
2267   0,    // RAM access bit
2268   0,    // fast call/return mode select bit
2269   0,    // second memory operand
2270   0,    // second literal operand
2271   POC_NOP,
2272   (PCC_W | PCC_LITERAL),   // inCond
2273   (PCC_W | PCC_STATUS), // outCond
2274   PCI_MAGIC
2275 };
2276
2277 pCodeInstruction pic16_pciSUBFWB = {
2278   {PC_OPCODE, NULL, NULL, 0, NULL, 
2279    //   genericAnalyze,
2280    genericDestruct,
2281    genericPrint},
2282   POC_SUBFWB,
2283   "SUBFWB",
2284   2,
2285   NULL, // from branch
2286   NULL, // to branch
2287   NULL, // label
2288   NULL, // operand
2289   NULL, // flow block
2290   NULL, // C source 
2291   3,    // num ops
2292   1,0,  // dest, bit instruction
2293   0,0,  // branch, skip
2294   0,    // literal operand
2295   1,    // RAM access bit
2296   0,    // fast call/return mode select bit
2297   0,    // second memory operand
2298   0,    // second literal operand
2299   POC_NOP,
2300   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2301   (PCC_W | PCC_STATUS), // outCond
2302   PCI_MAGIC
2303 };
2304
2305 pCodeInstruction pic16_pciSUBWF = {
2306   {PC_OPCODE, NULL, NULL, 0, NULL, 
2307    //   genericAnalyze,
2308    genericDestruct,
2309    genericPrint},
2310   POC_SUBWF,
2311   "SUBWF",
2312   2,
2313   NULL, // from branch
2314   NULL, // to branch
2315   NULL, // label
2316   NULL, // operand
2317   NULL, // flow block
2318   NULL, // C source 
2319   3,    // num ops
2320   1,0,  // dest, bit instruction
2321   0,0,  // branch, skip
2322   0,    // literal operand
2323   1,    // RAM access bit
2324   0,    // fast call/return mode select bit
2325   0,    // second memory operand
2326   0,    // second literal operand
2327   POC_NOP,
2328   (PCC_W | PCC_REGISTER),   // inCond
2329   (PCC_REGISTER | PCC_STATUS), // outCond
2330   PCI_MAGIC
2331 };
2332
2333 pCodeInstruction pic16_pciSUBFW = {
2334   {PC_OPCODE, NULL, NULL, 0, NULL, 
2335    //   genericAnalyze,
2336    genericDestruct,
2337    genericPrint},
2338   POC_SUBFW,
2339   "SUBWF",
2340   2,
2341   NULL, // from branch
2342   NULL, // to branch
2343   NULL, // label
2344   NULL, // operand
2345   NULL, // flow block
2346   NULL, // C source 
2347   3,    // num ops
2348   0,0,  // dest, bit instruction
2349   0,0,  // branch, skip
2350   0,    // literal operand
2351   1,    // RAM access bit
2352   0,    // fast call/return mode select bit
2353   0,    // second memory operand
2354   0,    // second literal operand
2355   POC_NOP,
2356   (PCC_W | PCC_REGISTER),   // inCond
2357   (PCC_W | PCC_STATUS), // outCond
2358   PCI_MAGIC
2359 };
2360
2361 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2362   {PC_OPCODE, NULL, NULL, 0, NULL, 
2363    //   genericAnalyze,
2364    genericDestruct,
2365    genericPrint},
2366   POC_SUBFWB_D1,
2367   "SUBFWB",
2368   2,
2369   NULL, // from branch
2370   NULL, // to branch
2371   NULL, // label
2372   NULL, // operand
2373   NULL, // flow block
2374   NULL, // C source 
2375   3,    // num ops
2376   1,0,  // dest, bit instruction
2377   0,0,  // branch, skip
2378   0,    // literal operand
2379   1,    // RAM access bit
2380   0,    // fast call/return mode select bit
2381   0,    // second memory operand
2382   0,    // second literal operand
2383   POC_NOP,
2384   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2385   (PCC_REGISTER | PCC_STATUS), // outCond
2386   PCI_MAGIC
2387 };
2388
2389 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2390   {PC_OPCODE, NULL, NULL, 0, NULL, 
2391    //   genericAnalyze,
2392    genericDestruct,
2393    genericPrint},
2394   POC_SUBFWB_D0,
2395   "SUBFWB",
2396   2,
2397   NULL, // from branch
2398   NULL, // to branch
2399   NULL, // label
2400   NULL, // operand
2401   NULL, // flow block
2402   NULL, // C source 
2403   3,    // num ops
2404   0,0,  // dest, bit instruction
2405   0,0,  // branch, skip
2406   0,    // literal operand
2407   1,    // RAM access bit
2408   0,    // fast call/return mode select bit
2409   0,    // second memory operand
2410   0,    // second literal operand
2411   POC_NOP,
2412   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2413   (PCC_W | PCC_STATUS), // outCond
2414   PCI_MAGIC
2415 };
2416
2417 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2418   {PC_OPCODE, NULL, NULL, 0, NULL, 
2419    //   genericAnalyze,
2420    genericDestruct,
2421    genericPrint},
2422   POC_SUBWFB_D1,
2423   "SUBWFB",
2424   2,
2425   NULL, // from branch
2426   NULL, // to branch
2427   NULL, // label
2428   NULL, // operand
2429   NULL, // flow block
2430   NULL, // C source 
2431   3,    // num ops
2432   1,0,  // dest, bit instruction
2433   0,0,  // branch, skip
2434   0,    // literal operand
2435   1,    // RAM access bit
2436   0,    // fast call/return mode select bit
2437   0,    // second memory operand
2438   0,    // second literal operand
2439   POC_NOP,
2440   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2441   (PCC_REGISTER | PCC_STATUS), // outCond
2442   PCI_MAGIC
2443 };
2444
2445 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2446   {PC_OPCODE, NULL, NULL, 0, NULL, 
2447    //   genericAnalyze,
2448    genericDestruct,
2449    genericPrint},
2450   POC_SUBWFB_D0,
2451   "SUBWFB",
2452   2,
2453   NULL, // from branch
2454   NULL, // to branch
2455   NULL, // label
2456   NULL, // operand
2457   NULL, // flow block
2458   NULL, // C source 
2459   3,    // num ops
2460   0,0,  // dest, bit instruction
2461   0,0,  // branch, skip
2462   0,    // literal operand
2463   1,    // RAM access bit
2464   0,    // fast call/return mode select bit
2465   0,    // second memory operand
2466   0,    // second literal operand
2467   POC_NOP,
2468   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2469   (PCC_W | PCC_STATUS), // outCond
2470   PCI_MAGIC
2471 };
2472
2473 pCodeInstruction pic16_pciSWAPF = {
2474   {PC_OPCODE, NULL, NULL, 0, NULL, 
2475    //   genericAnalyze,
2476    genericDestruct,
2477    genericPrint},
2478   POC_SWAPF,
2479   "SWAPF",
2480   2,
2481   NULL, // from branch
2482   NULL, // to branch
2483   NULL, // label
2484   NULL, // operand
2485   NULL, // flow block
2486   NULL, // C source 
2487   3,    // num ops
2488   1,0,  // dest, bit instruction
2489   0,0,  // branch, skip
2490   0,    // literal operand
2491   1,    // RAM access bit
2492   0,    // fast call/return mode select bit
2493   0,    // second memory operand
2494   0,    // second literal operand
2495   POC_NOP,
2496   (PCC_REGISTER),   // inCond
2497   (PCC_REGISTER), // outCond
2498   PCI_MAGIC
2499 };
2500
2501 pCodeInstruction pic16_pciSWAPFW = {
2502   {PC_OPCODE, NULL, NULL, 0, NULL, 
2503    //   genericAnalyze,
2504    genericDestruct,
2505    genericPrint},
2506   POC_SWAPFW,
2507   "SWAPF",
2508   2,
2509   NULL, // from branch
2510   NULL, // to branch
2511   NULL, // label
2512   NULL, // operand
2513   NULL, // flow block
2514   NULL, // C source 
2515   3,    // num ops
2516   0,0,  // dest, bit instruction
2517   0,0,  // branch, skip
2518   0,    // literal operand
2519   1,    // RAM access bit
2520   0,    // fast call/return mode select bit
2521   0,    // second memory operand
2522   0,    // second literal operand
2523   POC_NOP,
2524   (PCC_REGISTER),   // inCond
2525   (PCC_W), // outCond
2526   PCI_MAGIC
2527 };
2528
2529 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2530   {PC_OPCODE, NULL, NULL, 0, NULL, 
2531    genericDestruct,
2532    genericPrint},
2533   POC_TBLRD,
2534   "TBLRD*",
2535   2,
2536   NULL, // from branch
2537   NULL, // to branch
2538   NULL, // label
2539   NULL, // operand
2540   NULL, // flow block
2541   NULL, // C source 
2542   0,    // num ops
2543   0,0,  // dest, bit instruction
2544   0,0,  // branch, skip
2545   0,    // literal operand
2546   0,    // RAM access bit
2547   0,    // fast call/return mode select bit
2548   0,    // second memory operand
2549   0,    // second literal operand
2550   POC_NOP,
2551   PCC_NONE,  // inCond
2552   PCC_NONE  , // outCond
2553   PCI_MAGIC
2554 };
2555
2556 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2557   {PC_OPCODE, NULL, NULL, 0, NULL, 
2558    genericDestruct,
2559    genericPrint},
2560   POC_TBLRD_POSTINC,
2561   "TBLRD*+",
2562   2,
2563   NULL, // from branch
2564   NULL, // to branch
2565   NULL, // label
2566   NULL, // operand
2567   NULL, // flow block
2568   NULL, // C source 
2569   0,    // num ops
2570   0,0,  // dest, bit instruction
2571   0,0,  // branch, skip
2572   0,    // literal operand
2573   0,    // RAM access bit
2574   0,    // fast call/return mode select bit
2575   0,    // second memory operand
2576   0,    // second literal operand
2577   POC_NOP,
2578   PCC_NONE,  // inCond
2579   PCC_NONE  , // outCond
2580   PCI_MAGIC
2581 };
2582
2583 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2584   {PC_OPCODE, NULL, NULL, 0, NULL, 
2585    genericDestruct,
2586    genericPrint},
2587   POC_TBLRD_POSTDEC,
2588   "TBLRD*-",
2589   2,
2590   NULL, // from branch
2591   NULL, // to branch
2592   NULL, // label
2593   NULL, // operand
2594   NULL, // flow block
2595   NULL, // C source 
2596   0,    // num ops
2597   0,0,  // dest, bit instruction
2598   0,0,  // branch, skip
2599   0,    // literal operand
2600   0,    // RAM access bit
2601   0,    // fast call/return mode select bit
2602   0,    // second memory operand
2603   0,    // second literal operand
2604   POC_NOP,
2605   PCC_NONE,  // inCond
2606   PCC_NONE  , // outCond
2607   PCI_MAGIC
2608 };
2609
2610 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2611   {PC_OPCODE, NULL, NULL, 0, NULL, 
2612    genericDestruct,
2613    genericPrint},
2614   POC_TBLRD_PREINC,
2615   "TBLRD+*",
2616   2,
2617   NULL, // from branch
2618   NULL, // to branch
2619   NULL, // label
2620   NULL, // operand
2621   NULL, // flow block
2622   NULL, // C source 
2623   0,    // num ops
2624   0,0,  // dest, bit instruction
2625   0,0,  // branch, skip
2626   0,    // literal operand
2627   0,    // RAM access bit
2628   0,    // fast call/return mode select bit
2629   0,    // second memory operand
2630   0,    // second literal operand
2631   POC_NOP,
2632   PCC_NONE,  // inCond
2633   PCC_NONE  , // outCond
2634   PCI_MAGIC
2635 };
2636
2637 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2638   {PC_OPCODE, NULL, NULL, 0, NULL, 
2639    genericDestruct,
2640    genericPrint},
2641   POC_TBLWT,
2642   "TBLWT*",
2643   2,
2644   NULL, // from branch
2645   NULL, // to branch
2646   NULL, // label
2647   NULL, // operand
2648   NULL, // flow block
2649   NULL, // C source 
2650   0,    // num ops
2651   0,0,  // dest, bit instruction
2652   0,0,  // branch, skip
2653   0,    // literal operand
2654   0,    // RAM access bit
2655   0,    // fast call/return mode select bit
2656   0,    // second memory operand
2657   0,    // second literal operand
2658   POC_NOP,
2659   PCC_NONE,  // inCond
2660   PCC_NONE  , // outCond
2661   PCI_MAGIC
2662 };
2663
2664 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2665   {PC_OPCODE, NULL, NULL, 0, NULL, 
2666    genericDestruct,
2667    genericPrint},
2668   POC_TBLWT_POSTINC,
2669   "TBLWT*+",
2670   2,
2671   NULL, // from branch
2672   NULL, // to branch
2673   NULL, // label
2674   NULL, // operand
2675   NULL, // flow block
2676   NULL, // C source 
2677   0,    // num ops
2678   0,0,  // dest, bit instruction
2679   0,0,  // branch, skip
2680   0,    // literal operand
2681   0,    // RAM access bit
2682   0,    // fast call/return mode select bit
2683   0,    // second memory operand
2684   0,    // second literal operand
2685   POC_NOP,
2686   PCC_NONE,  // inCond
2687   PCC_NONE  , // outCond
2688   PCI_MAGIC
2689 };
2690
2691 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2692   {PC_OPCODE, NULL, NULL, 0, NULL, 
2693    genericDestruct,
2694    genericPrint},
2695   POC_TBLWT_POSTDEC,
2696   "TBLWT*-",
2697   2,
2698   NULL, // from branch
2699   NULL, // to branch
2700   NULL, // label
2701   NULL, // operand
2702   NULL, // flow block
2703   NULL, // C source 
2704   0,    // num ops
2705   0,0,  // dest, bit instruction
2706   0,0,  // branch, skip
2707   0,    // literal operand
2708   0,    // RAM access bit
2709   0,    // fast call/return mode select bit
2710   0,    // second memory operand
2711   0,    // second literal operand
2712   POC_NOP,
2713   PCC_NONE,  // inCond
2714   PCC_NONE  , // outCond
2715   PCI_MAGIC
2716 };
2717
2718 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2719   {PC_OPCODE, NULL, NULL, 0, NULL, 
2720    genericDestruct,
2721    genericPrint},
2722   POC_TBLWT_PREINC,
2723   "TBLWT+*",
2724   2,
2725   NULL, // from branch
2726   NULL, // to branch
2727   NULL, // label
2728   NULL, // operand
2729   NULL, // flow block
2730   NULL, // C source 
2731   0,    // num ops
2732   0,0,  // dest, bit instruction
2733   0,0,  // branch, skip
2734   0,    // literal operand
2735   0,    // RAM access bit
2736   0,    // fast call/return mode select bit
2737   0,    // second memory operand
2738   0,    // second literal operand
2739   POC_NOP,
2740   PCC_NONE,  // inCond
2741   PCC_NONE  , // outCond
2742   PCI_MAGIC
2743 };
2744
2745 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2746   {PC_OPCODE, NULL, NULL, 0, NULL, 
2747    //   genericAnalyze,
2748    genericDestruct,
2749    genericPrint},
2750   POC_TSTFSZ,
2751   "TSTFSZ",
2752   2,
2753   NULL, // from branch
2754   NULL, // to branch
2755   NULL, // label
2756   NULL, // operand
2757   NULL, // flow block
2758   NULL, // C source 
2759   2,    // num ops
2760   0,0,  // dest, bit instruction
2761   1,1,  // branch, skip
2762   0,    // literal operand
2763   1,    // RAM access bit
2764   0,    // fast call/return mode select bit
2765   0,    // second memory operand
2766   0,    // second literal operand
2767   POC_NOP,
2768   PCC_REGISTER,   // inCond
2769   PCC_NONE, // outCond
2770   PCI_MAGIC
2771 };
2772
2773 pCodeInstruction pic16_pciXORWF = {
2774   {PC_OPCODE, NULL, NULL, 0, NULL, 
2775    //   genericAnalyze,
2776    genericDestruct,
2777    genericPrint},
2778   POC_XORWF,
2779   "XORWF",
2780   2,
2781   NULL, // from branch
2782   NULL, // to branch
2783   NULL, // label
2784   NULL, // operand
2785   NULL, // flow block
2786   NULL, // C source 
2787   3,    // num ops
2788   1,0,  // dest, bit instruction
2789   0,0,  // branch, skip
2790   0,    // literal operand
2791   1,    // RAM access bit
2792   0,    // fast call/return mode select bit
2793   0,    // second memory operand
2794   0,    // second literal operand
2795   POC_NOP,
2796   (PCC_W | PCC_REGISTER),   // inCond
2797   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2798   PCI_MAGIC
2799 };
2800
2801 pCodeInstruction pic16_pciXORFW = {
2802   {PC_OPCODE, NULL, NULL, 0, NULL, 
2803    //   genericAnalyze,
2804    genericDestruct,
2805    genericPrint},
2806   POC_XORFW,
2807   "XORWF",
2808   2,
2809   NULL, // from branch
2810   NULL, // to branch
2811   NULL, // label
2812   NULL, // operand
2813   NULL, // flow block
2814   NULL, // C source 
2815   3,    // num ops
2816   0,0,  // dest, bit instruction
2817   0,0,  // branch, skip
2818   0,    // literal operand
2819   1,    // RAM access bit
2820   0,    // fast call/return mode select bit
2821   0,    // second memory operand
2822   0,    // second literal operand
2823   POC_NOP,
2824   (PCC_W | PCC_REGISTER),   // inCond
2825   (PCC_W | PCC_Z | PCC_N), // outCond
2826   PCI_MAGIC
2827 };
2828
2829 pCodeInstruction pic16_pciXORLW = {
2830   {PC_OPCODE, NULL, NULL, 0, NULL, 
2831    //   genericAnalyze,
2832    genericDestruct,
2833    genericPrint},
2834   POC_XORLW,
2835   "XORLW",
2836   2,
2837   NULL, // from branch
2838   NULL, // to branch
2839   NULL, // label
2840   NULL, // operand
2841   NULL, // flow block
2842   NULL, // C source 
2843   1,    // num ops
2844   0,0,  // dest, bit instruction
2845   0,0,  // branch, skip
2846   1,    // literal operand
2847   1,    // RAM access bit
2848   0,    // fast call/return mode select bit
2849   0,    // second memory operand
2850   0,    // second literal operand
2851   POC_NOP,
2852   (PCC_W | PCC_LITERAL),   // inCond
2853   (PCC_W | PCC_Z | PCC_N), // outCond
2854   PCI_MAGIC
2855 };
2856
2857
2858 pCodeInstruction pic16_pciBANKSEL = {
2859   {PC_OPCODE, NULL, NULL, 0, NULL, 
2860    genericDestruct,
2861    genericPrint},
2862   POC_BANKSEL,
2863   "BANKSEL",
2864   2,
2865   NULL, // from branch
2866   NULL, // to branch
2867   NULL, // label
2868   NULL, // operand
2869   NULL, // flow block
2870   NULL, // C source 
2871   0,    // num ops
2872   0,0,  // dest, bit instruction
2873   0,0,  // branch, skip
2874   0,    // literal operand
2875   0,    // RAM access bit
2876   0,    // fast call/return mode select bit
2877   0,    // second memory operand
2878   0,    // second literal operand
2879   POC_NOP,
2880   PCC_NONE,   // inCond
2881   PCC_NONE, // outCond
2882   PCI_MAGIC
2883 };
2884
2885
2886 #define MAX_PIC16MNEMONICS 100
2887 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2888
2889 //#define USE_VSNPRINTF
2890 #if OPT_DISABLE_PIC
2891
2892 #ifdef USE_VSNPRINTF
2893   // Alas, vsnprintf is not ANSI standard, and does not exist
2894   // on Solaris (and probably other non-Gnu flavored Unixes).
2895
2896 /*-----------------------------------------------------------------*/
2897 /* SAFE_snprintf - like snprintf except the string pointer is      */
2898 /*                 after the string has been printed to. This is   */
2899 /*                 useful for printing to string as though if it   */
2900 /*                 were a stream.                                  */
2901 /*-----------------------------------------------------------------*/
2902 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2903 {
2904   va_list val;
2905   int len;
2906
2907   if(!str || !*str)
2908     return;
2909
2910   va_start(val, format);
2911
2912   vsnprintf(*str, *size, format, val);
2913
2914   va_end (val);
2915
2916   len = strlen(*str);
2917   if(len > *size) {
2918     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2919     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2920   }
2921
2922   *str += len;
2923   *size -= len;
2924
2925 }
2926
2927 #else
2928 // This version is *not* safe, despite the name.
2929
2930 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2931 {
2932   va_list val;
2933   int len;
2934   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2935
2936   if(!str || !*str)
2937     return;
2938
2939   va_start(val, format);
2940
2941   vsprintf(buffer, format, val);
2942   va_end (val);
2943
2944   len = strlen(buffer);
2945   if(len > *size) {
2946     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2947     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2948   }
2949
2950   strcpy(*str, buffer);
2951   *str += len;
2952   *size -= len;
2953
2954 }
2955
2956 #endif    //  USE_VSNPRINTF
2957 #endif
2958
2959 extern set *externs;
2960 extern  void pic16_initStack(int base_address, int size);
2961 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2962 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2963 extern void pic16_init_pic(char *);
2964
2965 void  pic16_pCodeInitRegisters(void)
2966 {
2967   static int initialized=0;
2968
2969         if(initialized)
2970                 return;
2971         
2972         initialized = 1;
2973
2974 //      pic16_initStack(0xfff, 8);
2975         pic16_init_pic(port->processor);
2976
2977         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2978         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2979         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2980         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2981         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2982         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2983         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2984
2985         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2986         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2987         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2988
2989         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2990         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2991         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2992         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2993
2994         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2995         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2996         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2997         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2998         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2999         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3000
3001         pic16_stackpnt_lo = &pic16_pc_fsr1l;
3002         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3003         pic16_stack_postdec = &pic16_pc_postdec1;
3004         pic16_stack_postinc = &pic16_pc_postinc1;
3005         pic16_stack_preinc = &pic16_pc_preinc1;
3006         pic16_stack_plusw = &pic16_pc_plusw1;
3007         
3008         pic16_framepnt_lo = &pic16_pc_fsr2l;
3009         pic16_framepnt_hi = &pic16_pc_fsr2h;
3010         pic16_frame_postdec = &pic16_pc_postdec2;
3011         pic16_frame_postinc = &pic16_pc_postinc2;
3012         pic16_frame_preinc = &pic16_pc_preinc2;
3013         pic16_frame_plusw = &pic16_pc_plusw2;
3014
3015         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3016         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3017         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3018         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3019         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3020         
3021         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3022         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3023         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3024         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3025         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3026
3027         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3028         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3029         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3030         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3031         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3032         
3033         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3034         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3035
3036
3037         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3038         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3039         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3040         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3041
3042         
3043         pic16_pc_status.rIdx = IDX_STATUS;
3044         pic16_pc_intcon.rIdx = IDX_INTCON;
3045         pic16_pc_pcl.rIdx = IDX_PCL;
3046         pic16_pc_pclath.rIdx = IDX_PCLATH;
3047         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3048         pic16_pc_wreg.rIdx = IDX_WREG;
3049         pic16_pc_bsr.rIdx = IDX_BSR;
3050
3051         pic16_pc_tosl.rIdx = IDX_TOSL;
3052         pic16_pc_tosh.rIdx = IDX_TOSH;
3053         pic16_pc_tosu.rIdx = IDX_TOSU;
3054
3055         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3056         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3057         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3058         pic16_pc_tablat.rIdx = IDX_TABLAT;
3059
3060         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3061         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3062         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3063         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3064         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3065         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3066         pic16_pc_indf0.rIdx = IDX_INDF0;
3067         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3068         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3069         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3070         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3071         pic16_pc_indf1.rIdx = IDX_INDF1;
3072         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3073         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3074         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3075         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3076         pic16_pc_indf2.rIdx = IDX_INDF2;
3077         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3078         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3079         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3080         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3081         pic16_pc_prodl.rIdx = IDX_PRODL;
3082         pic16_pc_prodh.rIdx = IDX_PRODH;
3083         
3084         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3085         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3086         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3087         
3088         pic16_pc_kzero.rIdx = IDX_KZ;
3089         pic16_pc_wsave.rIdx = IDX_WSAVE;
3090         pic16_pc_ssave.rIdx = IDX_SSAVE;
3091
3092         pic16_pc_eecon1.rIdx = IDX_EECON1;
3093         pic16_pc_eecon2.rIdx = IDX_EECON2;
3094         pic16_pc_eedata.rIdx = IDX_EEDATA;
3095         pic16_pc_eeadr.rIdx = IDX_EEADR;
3096         
3097         
3098         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3099         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3100
3101         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3102         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3103
3104         /* probably should put this in a separate initialization routine */
3105         pb_dead_pcodes = newpBlock();
3106
3107 }
3108
3109 #if OPT_DISABLE_PIC
3110 /*-----------------------------------------------------------------*/
3111 /*  mnem2key - convert a pic mnemonic into a hash key              */
3112 /*   (BTW - this spreads the mnemonics quite well)                 */
3113 /*                                                                 */
3114 /*-----------------------------------------------------------------*/
3115
3116 int mnem2key(unsigned char const *mnem)
3117 {
3118   int key = 0;
3119
3120   if(!mnem)
3121     return 0;
3122
3123   while(*mnem) {
3124
3125     key += toupper(*mnem++) +1;
3126
3127   }
3128
3129   return (key & 0x1f);
3130
3131 }
3132 #endif
3133
3134 void pic16initMnemonics(void)
3135 {
3136   int i = 0;
3137   int key;
3138   //  char *str;
3139   pCodeInstruction *pci;
3140
3141   if(mnemonics_initialized)
3142     return;
3143
3144   // NULL out the array before making the assignments
3145   // since we check the array contents below this initialization.
3146
3147   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3148     pic16Mnemonics[i] = NULL;
3149   }
3150
3151   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3152   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3153   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3154   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3155   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3156   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3157   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3158   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3159   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3160   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3161   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3162   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3163   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3164   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3165   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3166   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3167   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3168   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3169   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3170   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3171   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3172   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3173   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3174   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3175   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3176   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3177   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3178   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3179   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3180   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3181   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3182   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3183   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3184   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3185   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3186   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3187   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3188   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3189   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3190   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3191   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3192   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3193   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3194   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3195   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3196   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3197   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3198   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3199   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3200   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3201   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3202   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3203   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3204   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3205   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3206   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3207   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3208   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3209   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3210   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3211   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3212   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3213   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3214   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3215   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3216   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3217   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3218   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3219   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3220   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3221   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3222   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3223   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3224   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3225   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3226   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3227   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3228   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3229   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3230   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3231   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3232   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3233   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3234   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3235   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3236   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3237   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3238   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3239   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3240   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3241   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3242   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3243   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3244   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3245
3246   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3247     if(pic16Mnemonics[i])
3248       hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3249   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3250
3251   while(pci) {
3252     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3253     pci = hTabNextItem(pic16MnemonicsHash, &key);
3254   }
3255
3256   mnemonics_initialized = 1;
3257 }
3258
3259 int pic16_getpCodePeepCommand(char *cmd);
3260
3261 int pic16_getpCode(char *mnem,unsigned dest)
3262 {
3263
3264   pCodeInstruction *pci;
3265   int key = mnem2key(mnem);
3266
3267   if(!mnemonics_initialized)
3268     pic16initMnemonics();
3269
3270   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3271
3272   while(pci) {
3273
3274     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3275       if((pci->num_ops <= 1)
3276         || (pci->isModReg == dest)
3277         || (pci->isBitInst)
3278         || (pci->num_ops <= 2 && pci->isAccess)
3279         || (pci->num_ops <= 2 && pci->isFastCall)
3280         || (pci->num_ops <= 2 && pci->is2MemOp)
3281         || (pci->num_ops <= 2 && pci->is2LitOp) )
3282         return(pci->op);
3283     }
3284
3285     pci = hTabNextItemWK (pic16MnemonicsHash);
3286   
3287   }
3288
3289   return -1;
3290 }
3291
3292 /*-----------------------------------------------------------------*
3293  * pic16initpCodePeepCommands
3294  *
3295  *-----------------------------------------------------------------*/
3296 void pic16initpCodePeepCommands(void)
3297 {
3298
3299   int key, i;
3300   peepCommand *pcmd;
3301
3302   i = 0;
3303   do {
3304     hTabAddItem(&pic16pCodePeepCommandsHash, 
3305                 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3306     i++;
3307   } while (peepCommands[i].cmd);
3308
3309   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3310
3311   while(pcmd) {
3312     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3313     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3314   }
3315
3316 }
3317
3318 /*-----------------------------------------------------------------
3319  *
3320  *
3321  *-----------------------------------------------------------------*/
3322
3323 int pic16_getpCodePeepCommand(char *cmd)
3324 {
3325
3326   peepCommand *pcmd;
3327   int key = mnem2key(cmd);
3328
3329
3330   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3331
3332   while(pcmd) {
3333     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3334     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3335       return pcmd->id;
3336     }
3337
3338     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3339   
3340   }
3341
3342   return -1;
3343 }
3344
3345 static char getpBlock_dbName(pBlock *pb)
3346 {
3347   if(!pb)
3348     return 0;
3349
3350   if(pb->cmemmap)
3351     return pb->cmemmap->dbName;
3352
3353   return pb->dbName;
3354 }
3355 void pic16_pBlockConvert2ISR(pBlock *pb)
3356 {
3357         if(!pb)return;
3358
3359         if(pb->cmemmap)pb->cmemmap = NULL;
3360
3361         pb->dbName = 'I';
3362
3363         if(pic16_pcode_verbose)
3364                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3365 }
3366
3367 void pic16_pBlockConvert2Absolute(pBlock *pb)
3368 {
3369         if(!pb)return;
3370         if(pb->cmemmap)pb->cmemmap = NULL;
3371         
3372         pb->dbName = 'A';
3373         
3374         if(pic16_pcode_verbose)
3375                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3376 }
3377   
3378 /*-----------------------------------------------------------------*/
3379 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3380 /*                   instances to the front of the doubly linked   */
3381 /*                   list of pBlocks                               */
3382 /*-----------------------------------------------------------------*/
3383
3384 void pic16_movepBlock2Head(char dbName)
3385 {
3386   pBlock *pb;
3387
3388
3389   /* this can happen in sources without code,
3390    * only variable definitions */
3391   if(!the_pFile)return;
3392
3393   pb = the_pFile->pbHead;
3394
3395   while(pb) {
3396
3397     if(getpBlock_dbName(pb) == dbName) {
3398       pBlock *pbn = pb->next;
3399       pb->next = the_pFile->pbHead;
3400       the_pFile->pbHead->prev = pb;
3401       the_pFile->pbHead = pb;
3402
3403       if(pb->prev)
3404         pb->prev->next = pbn;
3405
3406       // If the pBlock that we just moved was the last
3407       // one in the link of all of the pBlocks, then we
3408       // need to point the tail to the block just before
3409       // the one we moved.
3410       // Note: if pb->next is NULL, then pb must have 
3411       // been the last pBlock in the chain.
3412
3413       if(pbn)
3414         pbn->prev = pb->prev;
3415       else
3416         the_pFile->pbTail = pb->prev;
3417
3418       pb = pbn;
3419
3420     } else
3421       pb = pb->next;
3422
3423   }
3424
3425 }
3426
3427 void pic16_copypCode(FILE *of, char dbName)
3428 {
3429   pBlock *pb;
3430
3431         if(!of || !the_pFile)
3432                 return;
3433
3434         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3435                 if(getpBlock_dbName(pb) == dbName) {
3436 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3437                         pBlockStats(of,pb);
3438                         pic16_printpBlock(of,pb);
3439                 }
3440         }
3441
3442 }
3443 void pic16_pcode_test(void)
3444 {
3445
3446   DFPRINTF((stderr,"pcode is alive!\n"));
3447
3448   //initMnemonics();
3449
3450   if(the_pFile) {
3451
3452     pBlock *pb;
3453     FILE *pFile;
3454     char buffer[100];
3455
3456     /* create the file name */
3457     strcpy(buffer,dstFileName);
3458     strcat(buffer,".p");
3459
3460     if( !(pFile = fopen(buffer, "w" ))) {
3461       werror(E_FILE_OPEN_ERR,buffer);
3462       exit(1);
3463     }
3464
3465     fprintf(pFile,"pcode dump\n\n");
3466
3467     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3468       fprintf(pFile,"\n\tNew pBlock\n\n");
3469       if(pb->cmemmap)
3470         fprintf(pFile,"%s",pb->cmemmap->sname);
3471       else
3472         fprintf(pFile,"internal pblock");
3473
3474       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3475       pic16_printpBlock(pFile,pb);
3476     }
3477   }
3478 }
3479
3480
3481 unsigned long pic16_countInstructions(void)
3482 {
3483   pBlock *pb;
3484   pCode *pc;
3485   unsigned long isize=0;
3486
3487     if(!the_pFile)return -1;
3488     
3489     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3490       for(pc = pb->pcHead; pc; pc = pc->next) {
3491         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3492       }
3493     }
3494   return (isize);
3495 }
3496
3497
3498 /*-----------------------------------------------------------------*/
3499 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3500 /*      ister, RegCond will return the bit being referenced.       */
3501 /*                                                                 */
3502 /* fixme - why not just OR in the pcop bit field                   */
3503 /*-----------------------------------------------------------------*/
3504
3505 static int RegCond(pCodeOp *pcop)
3506 {
3507
3508   if(!pcop)
3509     return 0;
3510
3511   if(!pcop->name)return 0;
3512
3513   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3514     switch(PCORB(pcop)->bit) {
3515     case PIC_C_BIT:
3516       return PCC_C;
3517     case PIC_DC_BIT:
3518         return PCC_DC;
3519     case PIC_Z_BIT:
3520       return PCC_Z;
3521     }
3522
3523   }
3524
3525   return 0;
3526 }
3527
3528 /*-----------------------------------------------------------------*/
3529 /* pic16_newpCode - create and return a newly initialized pCode          */
3530 /*                                                                 */
3531 /*  fixme - rename this                                            */
3532 /*                                                                 */
3533 /* The purpose of this routine is to create a new Instruction      */
3534 /* pCode. This is called by gen.c while the assembly code is being */
3535 /* generated.                                                      */
3536 /*                                                                 */
3537 /* Inouts:                                                         */
3538 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3539 /*                  (note that the op is analogous to but not the  */
3540 /*                  same thing as the opcode of the instruction.)  */
3541 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3542 /*                                                                 */
3543 /* Outputs:                                                        */
3544 /*  a pointer to the new malloc'd pCode is returned.               */
3545 /*                                                                 */
3546 /*                                                                 */
3547 /*                                                                 */
3548 /*-----------------------------------------------------------------*/
3549 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3550 {
3551   pCodeInstruction *pci ;
3552
3553   if(!mnemonics_initialized)
3554     pic16initMnemonics();
3555     
3556   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3557
3558   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3559     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3560     pci->pcop = pcop;
3561
3562     if(pci->inCond & PCC_EXAMINE_PCOP)
3563       pci->inCond  |= RegCond(pcop);
3564
3565     if(pci->outCond & PCC_EXAMINE_PCOP)
3566       pci->outCond  |= RegCond(pcop);
3567
3568     pci->pc.prev = pci->pc.next = NULL;
3569     return (pCode *)pci;
3570   }
3571
3572   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3573   exit(1);
3574
3575   return NULL;
3576 }       
3577
3578 /*-----------------------------------------------------------------*/
3579 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3580 /*                                                                 */
3581 /* Wild pcodes are used during the peep hole optimizer to serve    */
3582 /* as place holders for any instruction. When a snippet of code is */
3583 /* compared to a peep hole rule, the wild card opcode will match   */
3584 /* any instruction. However, the optional operand and label are    */
3585 /* additional qualifiers that must also be matched before the      */
3586 /* line (of assembly code) is declared matched. Note that the      */
3587 /* operand may be wild too.                                        */
3588 /*                                                                 */
3589 /*   Note, a wild instruction is specified just like a wild var:   */
3590 /*      %4     ; A wild instruction,                               */
3591 /*  See the peeph.def file for additional examples                 */
3592 /*                                                                 */
3593 /*-----------------------------------------------------------------*/
3594
3595 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3596 {
3597
3598   pCodeWild *pcw;
3599     
3600   pcw = Safe_calloc(1,sizeof(pCodeWild));
3601
3602   pcw->pci.pc.type = PC_WILD;
3603   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3604   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3605   pcw->pci.pc.pb = NULL;
3606
3607   //  pcw->pci.pc.analyze = genericAnalyze;
3608   pcw->pci.pc.destruct = genericDestruct;
3609   pcw->pci.pc.print = genericPrint;
3610
3611   pcw->id = pCodeID;              // this is the 'n' in %n
3612   pcw->operand = optional_operand;
3613   pcw->label   = optional_label;
3614
3615   pcw->mustBeBitSkipInst = 0;
3616   pcw->mustNotBeBitSkipInst = 0;
3617   pcw->invertBitSkipInst = 0;
3618
3619   return ( (pCode *)pcw);
3620   
3621 }
3622
3623  /*-----------------------------------------------------------------*/
3624 /* newPcodeInlineP - create a new pCode from a char string           */
3625 /*-----------------------------------------------------------------*/
3626
3627
3628 pCode *pic16_newpCodeInlineP(char *cP)
3629 {
3630
3631   pCodeComment *pcc ;
3632     
3633   pcc = Safe_calloc(1,sizeof(pCodeComment));
3634
3635   pcc->pc.type = PC_INLINE;
3636   pcc->pc.prev = pcc->pc.next = NULL;
3637   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3638   pcc->pc.pb = NULL;
3639
3640   //  pcc->pc.analyze = genericAnalyze;
3641   pcc->pc.destruct = genericDestruct;
3642   pcc->pc.print = genericPrint;
3643
3644   if(cP)
3645     pcc->comment = Safe_strdup(cP);
3646   else
3647     pcc->comment = NULL;
3648
3649   return ( (pCode *)pcc);
3650
3651 }
3652
3653 /*-----------------------------------------------------------------*/
3654 /* newPcodeCharP - create a new pCode from a char string           */
3655 /*-----------------------------------------------------------------*/
3656
3657 pCode *pic16_newpCodeCharP(char *cP)
3658 {
3659
3660   pCodeComment *pcc ;
3661     
3662   pcc = Safe_calloc(1,sizeof(pCodeComment));
3663
3664   pcc->pc.type = PC_COMMENT;
3665   pcc->pc.prev = pcc->pc.next = NULL;
3666   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3667   pcc->pc.pb = NULL;
3668
3669   //  pcc->pc.analyze = genericAnalyze;
3670   pcc->pc.destruct = genericDestruct;
3671   pcc->pc.print = genericPrint;
3672
3673   if(cP)
3674     pcc->comment = Safe_strdup(cP);
3675   else
3676     pcc->comment = NULL;
3677
3678   return ( (pCode *)pcc);
3679
3680 }
3681
3682 /*-----------------------------------------------------------------*/
3683 /* pic16_newpCodeFunction -                                              */
3684 /*-----------------------------------------------------------------*/
3685
3686
3687 pCode *pic16_newpCodeFunction(char *mod,char *f)
3688 {
3689   pCodeFunction *pcf;
3690
3691   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3692
3693   pcf->pc.type = PC_FUNCTION;
3694   pcf->pc.prev = pcf->pc.next = NULL;
3695   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3696   pcf->pc.pb = NULL;
3697
3698   //  pcf->pc.analyze = genericAnalyze;
3699   pcf->pc.destruct = genericDestruct;
3700   pcf->pc.print = pCodePrintFunction;
3701
3702   pcf->ncalled = 0;
3703   pcf->absblock = 0;
3704   
3705   if(mod) {
3706     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3707     strcpy(pcf->modname,mod);
3708   } else
3709     pcf->modname = NULL;
3710
3711   if(f) {
3712     pcf->fname = Safe_calloc(1,strlen(f)+1);
3713     strcpy(pcf->fname,f);
3714   } else
3715     pcf->fname = NULL;
3716
3717   pcf->stackusage = 0;
3718
3719   return ( (pCode *)pcf);
3720 }
3721
3722 /*-----------------------------------------------------------------*/
3723 /* pic16_newpCodeFlow                                                    */
3724 /*-----------------------------------------------------------------*/
3725 static void destructpCodeFlow(pCode *pc)
3726 {
3727   if(!pc || !isPCFL(pc))
3728     return;
3729
3730 /*
3731   if(PCFL(pc)->from)
3732   if(PCFL(pc)->to)
3733 */
3734   pic16_unlinkpCode(pc);
3735
3736   deleteSet(&PCFL(pc)->registers);
3737   deleteSet(&PCFL(pc)->from);
3738   deleteSet(&PCFL(pc)->to);
3739
3740   /* Instead of deleting the memory used by this pCode, mark
3741    * the object as bad so that if there's a pointer to this pCode
3742    * dangling around somewhere then (hopefully) when the type is
3743    * checked we'll catch it.
3744    */
3745
3746   pc->type = PC_BAD;
3747   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3748
3749 //  Safe_free(pc);
3750
3751 }
3752
3753 pCode *pic16_newpCodeFlow(void )
3754 {
3755   pCodeFlow *pcflow;
3756
3757   //_ALLOC(pcflow,sizeof(pCodeFlow));
3758   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3759
3760   pcflow->pc.type = PC_FLOW;
3761   pcflow->pc.prev = pcflow->pc.next = NULL;
3762   pcflow->pc.pb = NULL;
3763
3764   //  pcflow->pc.analyze = genericAnalyze;
3765   pcflow->pc.destruct = destructpCodeFlow;
3766   pcflow->pc.print = genericPrint;
3767
3768   pcflow->pc.seq = GpcFlowSeq++;
3769
3770   pcflow->from = pcflow->to = NULL;
3771
3772   pcflow->inCond = PCC_NONE;
3773   pcflow->outCond = PCC_NONE;
3774
3775   pcflow->firstBank = -1;
3776   pcflow->lastBank = -1;
3777
3778   pcflow->FromConflicts = 0;
3779   pcflow->ToConflicts = 0;
3780
3781   pcflow->end = NULL;
3782
3783   pcflow->registers = newSet();
3784
3785   return ( (pCode *)pcflow);
3786
3787 }
3788
3789 /*-----------------------------------------------------------------*/
3790 /*-----------------------------------------------------------------*/
3791 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3792 {
3793   pCodeFlowLink *pcflowLink;
3794
3795   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3796
3797   pcflowLink->pcflow = pcflow;
3798   pcflowLink->bank_conflict = 0;
3799
3800   return pcflowLink;
3801 }
3802
3803 /*-----------------------------------------------------------------*/
3804 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3805 /*-----------------------------------------------------------------*/
3806
3807 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3808 {
3809
3810   pCodeCSource *pccs;
3811     
3812   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3813
3814   pccs->pc.type = PC_CSOURCE;
3815   pccs->pc.prev = pccs->pc.next = NULL;
3816   pccs->pc.pb = NULL;
3817
3818   pccs->pc.destruct = genericDestruct;
3819   pccs->pc.print = genericPrint;
3820
3821   pccs->line_number = ln;
3822   if(l)
3823     pccs->line = Safe_strdup(l);
3824   else
3825     pccs->line = NULL;
3826
3827   if(f)
3828     pccs->file_name = Safe_strdup(f);
3829   else
3830     pccs->file_name = NULL;
3831
3832   return ( (pCode *)pccs);
3833
3834 }
3835
3836
3837 /*******************************************************************/
3838 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3839 /*                      added by VR 6-Jun-2003                     */
3840 /*******************************************************************/
3841
3842 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3843 {
3844   pCodeAsmDir *pcad;
3845   va_list ap;
3846   char buffer[512];
3847   char *lbp=buffer;
3848   
3849         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3850         pcad->pci.pc.type = PC_ASMDIR;
3851         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3852         pcad->pci.pc.pb = NULL;
3853         pcad->pci.isize = 2;
3854         pcad->pci.pc.destruct = genericDestruct;
3855         pcad->pci.pc.print = genericPrint;
3856
3857         if(asdir && *asdir) {
3858                 
3859                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3860                 
3861                 pcad->directive = Safe_strdup( asdir );
3862         }
3863         
3864         va_start(ap, argfmt);
3865         
3866         memset(buffer, 0, sizeof(buffer));
3867         if(argfmt && *argfmt)
3868                 vsprintf(buffer, argfmt, ap);
3869         
3870         va_end(ap);
3871         
3872         while(isspace((unsigned char)*lbp))lbp++;
3873         
3874         if(lbp && *lbp)
3875                 pcad->arg = Safe_strdup( lbp );
3876
3877   return ((pCode *)pcad);
3878 }
3879
3880 /*-----------------------------------------------------------------*/
3881 /* pCodeLabelDestruct - free memory used by a label.               */
3882 /*-----------------------------------------------------------------*/
3883 static void pCodeLabelDestruct(pCode *pc)
3884 {
3885
3886   if(!pc)
3887     return;
3888
3889 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3890 //    Safe_free(PCL(pc)->label);
3891
3892   /* Instead of deleting the memory used by this pCode, mark
3893    * the object as bad so that if there's a pointer to this pCode
3894    * dangling around somewhere then (hopefully) when the type is
3895    * checked we'll catch it.
3896    */
3897
3898   pc->type = PC_BAD;
3899   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3900
3901 //  Safe_free(pc);
3902
3903 }
3904
3905 pCode *pic16_newpCodeLabel(char *name, int key)
3906 {
3907
3908   char *s = buffer;
3909   pCodeLabel *pcl;
3910     
3911   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3912
3913   pcl->pc.type = PC_LABEL;
3914   pcl->pc.prev = pcl->pc.next = NULL;
3915   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3916   pcl->pc.pb = NULL;
3917
3918   //  pcl->pc.analyze = genericAnalyze;
3919   pcl->pc.destruct = pCodeLabelDestruct;
3920   pcl->pc.print = pCodePrintLabel;
3921
3922   pcl->key = key;
3923   pcl->force = 0;
3924   
3925   pcl->label = NULL;
3926   if(key>0) {
3927     sprintf(s,"_%05d_DS_",key);
3928   } else
3929     s = name;
3930
3931   if(s)
3932     pcl->label = Safe_strdup(s);
3933
3934 //  if(pic16_pcode_verbose)
3935 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3936
3937
3938   return ( (pCode *)pcl);
3939
3940 }
3941
3942 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3943 {
3944   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3945   
3946         pcl->force = 1;
3947   
3948   return ( (pCode *)pcl );
3949 }
3950
3951 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3952 {
3953   pCodeInfo *pci;
3954
3955     pci = Safe_calloc(1, sizeof(pCodeInfo));
3956     pci->pci.pc.type = PC_INFO;
3957     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3958     pci->pci.pc.pb = NULL;
3959     pci->pci.label = NULL;
3960         
3961     pci->pci.pc.destruct = genericDestruct;
3962     pci->pci.pc.print = genericPrint;
3963     
3964     pci->type = type;
3965     pci->oper1 = pcop;
3966   
3967   return ((pCode *)pci);
3968 }
3969
3970
3971 /*-----------------------------------------------------------------*/
3972 /* newpBlock - create and return a pointer to a new pBlock         */
3973 /*-----------------------------------------------------------------*/
3974 static pBlock *newpBlock(void)
3975 {
3976
3977   pBlock *PpB;
3978
3979   PpB = Safe_calloc(1,sizeof(pBlock) );
3980   PpB->next = PpB->prev = NULL;
3981
3982   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3983   PpB->tregisters = NULL;
3984   PpB->visited = 0;
3985   PpB->FlowTree = NULL;
3986
3987   return PpB;
3988
3989 }
3990
3991 /*-----------------------------------------------------------------*/
3992 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3993 /*-----------------------------------------------------------------*
3994  *
3995  *  This function will create a new pBlock and the pointer to the
3996  *  pCode that is passed in will be the first pCode in the block.
3997  *-----------------------------------------------------------------*/
3998
3999
4000 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4001 {
4002
4003   pBlock *pB  = newpBlock();
4004
4005   pB->pcHead  = pB->pcTail = pc;
4006   pB->cmemmap = cm;
4007   pB->dbName  = c;
4008
4009   return pB;
4010 }
4011
4012
4013
4014 /*-----------------------------------------------------------------*/
4015 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4016 /*  Note, a negative key means that the label is part of wild card */
4017 /*  (and hence a wild card label) used in the pCodePeep            */
4018 /*   optimizations).                                               */
4019 /*-----------------------------------------------------------------*/
4020
4021 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4022 {
4023   char *s=NULL;
4024   static int label_key=-1;
4025
4026   pCodeOp *pcop;
4027
4028   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4029   pcop->type = PO_LABEL;
4030
4031   pcop->name = NULL;
4032
4033   if(key>0)
4034     sprintf(s=buffer,"_%05d_DS_",key);
4035   else 
4036     s = name, key = label_key--;
4037
4038   if(s)
4039     pcop->name = Safe_strdup(s);
4040
4041   ((pCodeOpLabel *)pcop)->key = key;
4042
4043   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4044   return pcop;
4045 }
4046
4047 /*-----------------------------------------------------------------*/
4048 /*-----------------------------------------------------------------*/
4049 pCodeOp *pic16_newpCodeOpLit(int lit)
4050 {
4051   char *s = buffer;
4052   pCodeOp *pcop;
4053
4054
4055   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4056   pcop->type = PO_LITERAL;
4057
4058   pcop->name = NULL;
4059   //if(lit>=0)
4060     sprintf(s,"0x%02hhx", (unsigned char)lit);
4061   //else
4062   //  sprintf(s, "%i", lit);
4063   
4064   if(s)
4065     pcop->name = Safe_strdup(s);
4066
4067   ((pCodeOpLit *)pcop)->lit = lit;
4068
4069   return pcop;
4070 }
4071
4072 /*-----------------------------------------------------------------*/
4073 /*-----------------------------------------------------------------*/
4074 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4075 {
4076   char *s = buffer, tbuf[256], *tb=tbuf;
4077   pCodeOp *pcop;
4078
4079
4080   tb = pic16_get_op(arg2, NULL, 0);
4081   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4082   pcop->type = PO_LITERAL;
4083
4084   pcop->name = NULL;
4085   //if(lit>=0) {
4086     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4087     if(s)
4088       pcop->name = Safe_strdup(s);
4089   //}
4090
4091   ((pCodeOpLit2 *)pcop)->lit = lit;
4092   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4093
4094   return pcop;
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /*-----------------------------------------------------------------*/
4099 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4100 {
4101   pCodeOp *pcop;
4102
4103         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4104         pcop->type = PO_IMMEDIATE;
4105         if(name) {
4106                 regs *r = pic16_dirregWithName(name);
4107                 pcop->name = Safe_strdup(name);
4108                 PCOI(pcop)->r = r;
4109                 
4110                 if(r) {
4111 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4112                         PCOI(pcop)->rIdx = r->rIdx;
4113                 } else {
4114 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4115                         PCOI(pcop)->rIdx = -1;
4116                 }
4117 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4118         } else {
4119                 pcop->name = NULL;
4120         }
4121
4122         PCOI(pcop)->index = index;
4123         PCOI(pcop)->offset = offset;
4124         PCOI(pcop)->_const = code_space;
4125
4126   return pcop;
4127 }
4128
4129 /*-----------------------------------------------------------------*/
4130 /*-----------------------------------------------------------------*/
4131 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4132 {
4133   char *s = buffer;
4134   pCodeOp *pcop;
4135
4136
4137   if(!pcwb || !subtype) {
4138     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4139     exit(1);
4140   }
4141
4142   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4143   pcop->type = PO_WILD;
4144   sprintf(s,"%%%d",id);
4145   pcop->name = Safe_strdup(s);
4146
4147   PCOW(pcop)->id = id;
4148   PCOW(pcop)->pcwb = pcwb;
4149   PCOW(pcop)->subtype = subtype;
4150   PCOW(pcop)->matched = NULL;
4151
4152   PCOW(pcop)->pcop2 = NULL;
4153   
4154   return pcop;
4155 }
4156
4157 /*-----------------------------------------------------------------*/
4158 /*-----------------------------------------------------------------*/
4159 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4160 {
4161   char *s = buffer;
4162   pCodeOp *pcop;
4163
4164
4165         if(!pcwb || !subtype || !subtype2) {
4166                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4167                 exit(1);
4168         }
4169
4170         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4171         pcop->type = PO_WILD;
4172         sprintf(s,"%%%d",id);
4173         pcop->name = Safe_strdup(s);
4174
4175         PCOW(pcop)->id = id;
4176         PCOW(pcop)->pcwb = pcwb;
4177         PCOW(pcop)->subtype = subtype;
4178         PCOW(pcop)->matched = NULL;
4179
4180         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4181
4182         if(!subtype2->name) {
4183                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4184                 PCOW2(pcop)->pcop.type = PO_WILD;
4185                 sprintf(s, "%%%d", id2);
4186                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4187                 PCOW2(pcop)->id = id2;
4188                 PCOW2(pcop)->subtype = subtype2;
4189
4190 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4191 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4192         } else {
4193                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4194
4195 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4196 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4197         }
4198   
4199
4200
4201   return pcop;
4202 }
4203
4204
4205 /*-----------------------------------------------------------------*/
4206 /*-----------------------------------------------------------------*/
4207 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4208 {
4209   pCodeOp *pcop;
4210   
4211   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4212   pcop->type = PO_GPR_BIT;
4213   if(s)
4214     pcop->name = Safe_strdup(s);   
4215   else
4216     pcop->name = NULL;
4217
4218   PCORB(pcop)->bit = bit;
4219   PCORB(pcop)->inBitSpace = inBitSpace;
4220   PCORB(pcop)->subtype = subt;
4221
4222   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4223   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4224 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4225 //  PCOR(pcop)->rIdx = 0;
4226   return pcop;
4227 }
4228
4229 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4230 {
4231   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4232                                 bit, 0, PO_GPR_REGISTER);
4233 }
4234
4235
4236 /*-----------------------------------------------------------------*
4237  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4238  *
4239  * If rIdx >=0 then a specific register from the set of registers
4240  * will be selected. If rIdx <0, then a new register will be searched
4241  * for.
4242  *-----------------------------------------------------------------*/
4243
4244 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4245 {
4246   pCodeOp *pcop;
4247   regs *r;
4248
4249   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4250
4251   pcop->name = NULL;
4252
4253   if(rIdx >= 0) {
4254         r = pic16_regWithIdx(rIdx);
4255         if(!r)
4256                 r = pic16_allocWithIdx(rIdx);
4257   } else {
4258     r = pic16_findFreeReg(REG_GPR);
4259
4260     if(!r) {
4261         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4262                 __FUNCTION__, __LINE__);
4263         exit(-1);
4264     }
4265   }
4266
4267   PCOR(pcop)->rIdx = rIdx;
4268   PCOR(pcop)->r = r;
4269   pcop->type = PCOR(pcop)->r->pc_type;
4270
4271   return pcop;
4272 }
4273
4274 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4275 {
4276   pCodeOp *pcop;
4277   regs *r;
4278   
4279     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4280     pcop->name = NULL;
4281     
4282     r = pic16_findFreeReg(REG_GPR);
4283
4284     while(r) {
4285       if(!bitVectBitValue(bv, r->rIdx)) {
4286         PCOR(pcop)->r = r;
4287         PCOR(pcop)->rIdx = r->rIdx;
4288         pcop->type = r->pc_type;
4289         return (pcop);
4290       }
4291       
4292       r = pic16_findFreeRegNext(REG_GPR, r);
4293     }
4294   
4295   return NULL;
4296 }
4297
4298       
4299
4300 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4301 {
4302   pCodeOp *pcop;
4303   regs *r;
4304
4305         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4306         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4307         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4308         pcop->type = PCOR(pcop)->r->pc_type;
4309         pcop->name = PCOR(pcop)->r->name;
4310
4311 //      if(pic16_pcode_verbose) {
4312 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4313 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4314 //      }
4315
4316   return pcop;
4317 }
4318
4319 /*-----------------------------------------------------------------*/
4320 /*-----------------------------------------------------------------*/
4321 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4322 {
4323   pCodeOpOpt *pcop;
4324
4325         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4326         
4327         pcop->type = type;
4328         pcop->key = Safe_strdup( key );
4329
4330   return (PCOP(pcop));
4331 }
4332
4333 /*-----------------------------------------------------------------*/
4334 /*-----------------------------------------------------------------*/
4335 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4336 {
4337   pCodeOpLocalReg *pcop;
4338
4339         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4340         
4341         pcop->type = type;
4342
4343   return (PCOP(pcop));
4344 }
4345
4346
4347 /*-----------------------------------------------------------------*/
4348 /*-----------------------------------------------------------------*/
4349
4350 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4351 {
4352   pCodeOp *pcop;
4353
4354   switch(type) {
4355   case PO_BIT:
4356   case PO_GPR_BIT:
4357     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4358     break;
4359
4360   case PO_LITERAL:
4361     pcop = pic16_newpCodeOpLit(-1);
4362     break;
4363
4364   case PO_LABEL:
4365     pcop = pic16_newpCodeOpLabel(NULL,-1);
4366     break;
4367   case PO_GPR_TEMP:
4368     pcop = pic16_newpCodeOpReg(-1);
4369     break;
4370
4371   case PO_GPR_REGISTER:
4372     if(name)
4373       pcop = pic16_newpCodeOpRegFromStr(name);
4374     else
4375       pcop = pic16_newpCodeOpReg(-1);
4376     break;
4377
4378   default:
4379     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4380     pcop->type = type;
4381     if(name)
4382       pcop->name = Safe_strdup(name);   
4383     else
4384       pcop->name = NULL;
4385   }
4386
4387   return pcop;
4388 }
4389
4390 /* This is a multiple of two as gpasm pads DB directives to even length,
4391  * thus the data would be interleaved with \0 bytes...
4392  * This is a multiple of three in order to have arrays of 3-byte pointers
4393  * continuously in memory (without 0-padding at the lines' end).
4394  * This is rather 12 than 6 in order not to split up 4-byte data types
4395  * in arrays right in the middle of a 4-byte word. */
4396 #define DB_ITEMS_PER_LINE       12
4397
4398 typedef struct DBdata
4399   {
4400     int count;
4401     char buffer[512];
4402   } DBdata;
4403
4404 struct DBdata DBd;
4405 static int DBd_init = -1;
4406
4407 /*-----------------------------------------------------------------*/
4408 /*    Initialiase "DB" data buffer                                 */
4409 /*-----------------------------------------------------------------*/
4410 void pic16_initDB(void)
4411 {
4412         DBd_init = -1;
4413 }
4414
4415
4416 /*-----------------------------------------------------------------*/
4417 /*    Flush pending "DB" data to a pBlock                          */
4418 /*                                                                 */
4419 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4420 /*-----------------------------------------------------------------*/
4421 void pic16_flushDB(char ptype, void *p)
4422 {
4423         if (DBd.count>0) {
4424                 if(ptype == 'p')
4425                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4426                 else
4427                 if(ptype == 'f')
4428                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4429                 else {
4430                         /* sanity check */
4431                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4432                 }
4433
4434                 DBd.count = 0;
4435                 DBd.buffer[0] = '\0';
4436         }
4437 }
4438
4439
4440 /*-----------------------------------------------------------------*/
4441 /*    Add "DB" directives to a pBlock                              */
4442 /*-----------------------------------------------------------------*/
4443 void pic16_emitDB(char c, char ptype, void *p)
4444 {
4445   int l;
4446
4447         if (DBd_init<0) {
4448          // we need to initialize
4449                 DBd_init = 0;
4450                 DBd.count = 0;
4451                 DBd.buffer[0] = '\0';
4452         }
4453
4454         l = strlen(DBd.buffer);
4455         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4456
4457 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4458         
4459         DBd.count++;
4460         if (DBd.count>= DB_ITEMS_PER_LINE)
4461                 pic16_flushDB(ptype, p);
4462 }
4463
4464 void pic16_emitDS(char *s, char ptype, void *p)
4465 {
4466   int l;
4467
4468         if (DBd_init<0) {
4469          // we need to initialize
4470                 DBd_init = 0;
4471                 DBd.count = 0;
4472                 DBd.buffer[0] = '\0';
4473         }
4474
4475         l = strlen(DBd.buffer);
4476         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4477
4478 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4479
4480         DBd.count++;    //=strlen(s);
4481         if (DBd.count>=DB_ITEMS_PER_LINE)
4482                 pic16_flushDB(ptype, p);
4483 }
4484
4485
4486 /*-----------------------------------------------------------------*/
4487 /*-----------------------------------------------------------------*/
4488 void pic16_pCodeConstString(char *name, char *value)
4489 {
4490   pBlock *pb;
4491   char *item;
4492   static set *emittedSymbols = NULL;
4493
4494   if(!name || !value)
4495     return;
4496
4497   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4498   if (emittedSymbols) {
4499     /* scan set for name */
4500     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4501     {
4502       if (!strcmp (item,name)) {
4503         //fprintf (stderr, "%s already emitted\n", name);
4504         return;
4505       } // if
4506     } // for
4507   } // if
4508   addSet (&emittedSymbols, Safe_strdup (name));
4509
4510   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4511
4512   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4513
4514   pic16_addpBlock(pb);
4515
4516 //  sprintf(buffer,"; %s = ", name);
4517 //  strcat(buffer, value);
4518 //  fputs(buffer, stderr);
4519
4520 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4521   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4522
4523   do {
4524         pic16_emitDB(*value, 'p', (void *)pb);
4525   }while (*value++);
4526   pic16_flushDB('p', (void *)pb);
4527 }
4528
4529 /*-----------------------------------------------------------------*/
4530 /*-----------------------------------------------------------------*/
4531 #if 0
4532 static void pCodeReadCodeTable(void)
4533 {
4534   pBlock *pb;
4535
4536   fprintf(stderr, " %s\n",__FUNCTION__);
4537
4538   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4539
4540   pic16_addpBlock(pb);
4541
4542   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4543   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4544   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4545   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4546
4547   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4548   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4549   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4550   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4551
4552
4553 }
4554 #endif
4555 /*-----------------------------------------------------------------*/
4556 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4557 /*-----------------------------------------------------------------*/
4558 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4559 {
4560
4561   if(!pc)
4562     return;
4563
4564   if(!pb->pcHead) {
4565     /* If this is the first pcode to be added to a block that
4566      * was initialized with a NULL pcode, then go ahead and
4567      * make this pcode the head and tail */
4568     pb->pcHead  = pb->pcTail = pc;
4569   } else {
4570     //    if(pb->pcTail)
4571     pb->pcTail->next = pc;
4572
4573     pc->prev = pb->pcTail;
4574     pc->pb = pb;
4575
4576     pb->pcTail = pc;
4577   }
4578 }
4579
4580 /*-----------------------------------------------------------------*/
4581 /* pic16_addpBlock - place a pBlock into the pFile                 */
4582 /*-----------------------------------------------------------------*/
4583 void pic16_addpBlock(pBlock *pb)
4584 {
4585   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4586
4587   if(!the_pFile) {
4588     /* First time called, we'll pass through here. */
4589     //_ALLOC(the_pFile,sizeof(pFile));
4590     the_pFile = Safe_calloc(1,sizeof(pFile));
4591     the_pFile->pbHead = the_pFile->pbTail = pb;
4592     the_pFile->functions = NULL;
4593     return;
4594   }
4595
4596   the_pFile->pbTail->next = pb;
4597   pb->prev = the_pFile->pbTail;
4598   pb->next = NULL;
4599   the_pFile->pbTail = pb;
4600 }
4601
4602 /*-----------------------------------------------------------------*/
4603 /* removepBlock - remove a pBlock from the pFile                   */
4604 /*-----------------------------------------------------------------*/
4605 static void removepBlock(pBlock *pb)
4606 {
4607   pBlock *pbs;
4608
4609   if(!the_pFile)
4610     return;
4611
4612
4613   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4614
4615   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4616     if(pbs == pb) {
4617
4618       if(pbs == the_pFile->pbHead)
4619         the_pFile->pbHead = pbs->next;
4620
4621       if (pbs == the_pFile->pbTail) 
4622         the_pFile->pbTail = pbs->prev;
4623
4624       if(pbs->next)
4625         pbs->next->prev = pbs->prev;
4626
4627       if(pbs->prev)
4628         pbs->prev->next = pbs->next;
4629
4630       return;
4631
4632     }
4633   }
4634
4635   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4636
4637 }
4638
4639 /*-----------------------------------------------------------------*/
4640 /* printpCode - write the contents of a pCode to a file            */
4641 /*-----------------------------------------------------------------*/
4642 static void printpCode(FILE *of, pCode *pc)
4643 {
4644
4645   if(!pc || !of)
4646     return;
4647
4648   if(pc->print) {
4649     pc->print(of,pc);
4650     return;
4651   }
4652
4653   fprintf(of,"warning - unable to print pCode\n");
4654 }
4655
4656 /*-----------------------------------------------------------------*/
4657 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4658 /*-----------------------------------------------------------------*/
4659 void pic16_printpBlock(FILE *of, pBlock *pb)
4660 {
4661   pCode *pc;
4662
4663         if(!pb)return;
4664
4665         if(!of)of=stderr;
4666
4667         for(pc = pb->pcHead; pc; pc = pc->next) {
4668                 if(isPCF(pc) && PCF(pc)->fname) {
4669                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4670                         if(pb->dbName == 'A') {
4671                           absSym *ab;
4672                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4673 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4674                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4675 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4676                                                 if(ab->address != -1)
4677                                                   fprintf(of, "\t0X%06X", ab->address);
4678                                                 break;
4679                                         }
4680                                 }
4681                         }
4682                         fprintf(of, "\n");
4683                 }
4684                 printpCode(of,pc);
4685         }
4686 }
4687
4688 /*-----------------------------------------------------------------*/
4689 /*                                                                 */
4690 /*       pCode processing                                          */
4691 /*                                                                 */
4692 /*                                                                 */
4693 /*                                                                 */
4694 /*-----------------------------------------------------------------*/
4695 pCode * pic16_findNextInstruction(pCode *pci);
4696 pCode * pic16_findPrevInstruction(pCode *pci);
4697
4698 void pic16_unlinkpCode(pCode *pc)
4699 {
4700   pCode *prev;
4701
4702   if(pc) {
4703 #ifdef PCODE_DEBUG
4704     fprintf(stderr,"Unlinking: ");
4705     printpCode(stderr, pc);
4706 #endif
4707     if(pc->prev) 
4708       pc->prev->next = pc->next;
4709     if(pc->next)
4710       pc->next->prev = pc->prev;
4711
4712     /* move C source line down (or up) */
4713     if (isPCI(pc) && PCI(pc)->cline) {
4714       prev = pic16_findNextInstruction (pc->next);
4715       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4716         PCI(prev)->cline = PCI(pc)->cline;
4717       } else {
4718         prev = pic16_findPrevInstruction (pc->prev);
4719         if (prev && isPCI(prev) && !PCI(prev)->cline)
4720           PCI(prev)->cline = PCI(pc)->cline;
4721       }
4722     }
4723     pc->prev = pc->next = NULL;
4724   }
4725 }
4726
4727 /*-----------------------------------------------------------------*/
4728 /*-----------------------------------------------------------------*/
4729
4730 static void genericDestruct(pCode *pc)
4731 {
4732
4733   pic16_unlinkpCode(pc);
4734
4735   if(isPCI(pc)) {
4736     /* For instructions, tell the register (if there's one used)
4737      * that it's no longer needed */
4738     regs *reg = pic16_getRegFromInstruction(pc);
4739     if(reg)
4740       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4741
4742         if(PCI(pc)->is2MemOp) {
4743                 reg = pic16_getRegFromInstruction2(pc);
4744                 if(reg)
4745                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4746         }
4747   }
4748
4749   /* Instead of deleting the memory used by this pCode, mark
4750    * the object as bad so that if there's a pointer to this pCode
4751    * dangling around somewhere then (hopefully) when the type is
4752    * checked we'll catch it.
4753    */
4754
4755   pc->type = PC_BAD;
4756   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4757
4758   //Safe_free(pc);
4759 }
4760
4761
4762 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4763 /*-----------------------------------------------------------------*/
4764 /*-----------------------------------------------------------------*/
4765 /* modifiers for constant immediate */
4766 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4767
4768 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4769 {
4770   regs *r;
4771   static char b[128];
4772   char *s;
4773   int use_buffer = 1;    // copy the string to the passed buffer pointer
4774
4775         if(!buffer) {
4776                 buffer = b;
4777                 size = sizeof(b);
4778                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4779         } 
4780
4781         if(pcop) {
4782                 switch(pcop->type) {
4783                         case PO_W:
4784                         case PO_WREG:
4785                         case PO_PRODL:
4786                         case PO_PRODH:
4787                         case PO_INDF0:
4788                         case PO_FSR0:
4789                                 if(use_buffer) {
4790                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4791                                         return buffer;
4792                                 }
4793                                 return PCOR(pcop)->r->name;
4794                                 break;
4795                         case PO_GPR_TEMP:
4796                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4797                                 if(use_buffer) {
4798                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4799                                         return buffer;
4800                                 }
4801                                 return r->name;
4802
4803                         case PO_IMMEDIATE:
4804                                 s = buffer;
4805                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4806                                         if(PCOI(pcop)->index) {
4807                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4808                                                         immdmod[ PCOI(pcop)->offset ],
4809                                                         pcop->name,
4810                                                         PCOI(pcop)->index);
4811                                         } else {
4812                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4813                                                         immdmod[ PCOI(pcop)->offset ],
4814                                                         pcop->name);
4815                                         }
4816                                 } else {
4817                                         if(PCOI(pcop)->index) {
4818                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4819                                                         immdmod[ 0 ],
4820                                                         pcop->name,
4821                                                         PCOI(pcop)->index);
4822                                         } else {
4823                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4824                                                         immdmod[ 0 ],
4825                                                         pcop->name);
4826                                         }
4827                                 }
4828                                 return buffer;
4829
4830                         case PO_GPR_REGISTER:
4831                         case PO_DIR:
4832                                 s = buffer;
4833 //                              size = sizeof(buffer);
4834                                 if( PCOR(pcop)->instance) {
4835                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4836                                                 pcop->name,
4837                                                 PCOR(pcop)->instance );
4838                                 } else {
4839                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4840                                 }
4841                                 return buffer;
4842                         case PO_GPR_BIT:
4843                                 s = buffer;
4844                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4845                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4846                                 } else {
4847                                         if(PCORB(pcop)->pcor.instance)
4848                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4849                                         else
4850                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4851                                 }
4852
4853                                 return (buffer);
4854                         default:
4855                                 if(pcop->name) {
4856                                         if(use_buffer) {
4857                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4858                                                 return buffer;
4859                                         }
4860                                 return pcop->name;
4861                                 }
4862
4863                 }
4864         }
4865
4866   return "NO operand1";
4867 }
4868
4869 /*-----------------------------------------------------------------*/
4870 /* pic16_get_op2 - variant to support two memory operand commands  */
4871 /*-----------------------------------------------------------------*/
4872 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4873 {
4874   regs *r;
4875   static char b[128];
4876   char *s;
4877   int use_buffer = 1;    // copy the string to the passed buffer pointer
4878
4879         if(!buffer) {
4880                 buffer = b;
4881                 size = sizeof(b);
4882                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4883         } 
4884
4885 #if 0
4886         fprintf(stderr, "%s:%d second operand %s is %d\tPO_DIR(%d) PO_GPR_TEMP(%d) PO_IMMEDIATE(%d) PO_INDF0(%d) PO_FSR0(%d)\n",
4887                 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4888                 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4889 #endif
4890
4891         if(pcop) {
4892                 switch(PCOR2(pcop)->pcop2->type) {
4893                         case PO_W:
4894                         case PO_WREG:
4895                         case PO_PRODL:
4896                         case PO_PRODH:
4897                         case PO_INDF0:
4898                         case PO_FSR0:
4899                                 if(use_buffer) {
4900                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4901                                         return buffer;
4902                                 }
4903                                 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4904                                 break;
4905                         case PO_GPR_TEMP:
4906                                 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4907
4908                                 if(use_buffer) {
4909                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4910                                         return buffer;
4911                                 }
4912                                 return r->name;
4913
4914                         case PO_IMMEDIATE:
4915                                         assert( 0 );
4916                                 break;
4917 #if 0
4918                                 s = buffer;
4919
4920                                 if(PCOI(pcop)->_const) {
4921                                         if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4922                                                 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4923                                                         pcop->name,
4924                                                         PCOI(pcop)->index,
4925                                                         8 * PCOI(pcop)->offset );
4926                                         } else
4927                                                 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4928                                 } else {
4929                                         if( PCOI(pcop)->index) {
4930                                                 SAFE_snprintf(&s,&size,"(%s + %d)",
4931                                                         pcop->name,
4932                                                         PCOI(pcop)->index );
4933                                         } else {
4934                                                 if(PCOI(pcop)->offset)
4935                                                         SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4936                                                 else
4937                                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4938                                         }
4939                                 }
4940                                 return buffer;
4941 #endif
4942                         case PO_DIR:
4943                                 s = buffer;
4944                                 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4945                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4946                                                 PCOR(PCOR2(pcop)->pcop2)->r->name,
4947                                                 PCOR(PCOR2(pcop)->pcop2)->instance );
4948                                 } else {
4949                                         SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4950                                 }
4951                                 return buffer;
4952
4953                         default:
4954                                 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4955                                         if(use_buffer) {
4956                                                 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4957                                                 return buffer;
4958                                         }
4959                                         return PCOR(PCOR2(pcop)->pcop2)->r->name;
4960                                 }
4961                 }
4962         }
4963
4964   return "NO operand2";
4965 }
4966
4967 /*-----------------------------------------------------------------*/
4968 /*-----------------------------------------------------------------*/
4969 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4970 {
4971
4972   if(pcc )
4973     return pic16_get_op(pcc->pcop,NULL,0);
4974
4975   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
4976    *   return ("ERROR Null: "__FUNCTION__);
4977    */
4978   return ("ERROR Null: pic16_get_op_from_instruction");
4979
4980 }
4981
4982 /*-----------------------------------------------------------------*/
4983 /*-----------------------------------------------------------------*/
4984 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4985 {
4986
4987   fprintf(of,"pcodeopprint- not implemented\n");
4988 }
4989
4990 /*-----------------------------------------------------------------*/
4991 /* pic16_pCode2str - convert a pCode instruction to string               */
4992 /*-----------------------------------------------------------------*/
4993 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4994 {
4995   char *s = str;
4996   regs *r;
4997
4998 #if 0
4999         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
5000                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
5001                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
5002 //              exit(-1);
5003         }
5004 #endif
5005
5006   switch(pc->type) {
5007
5008   case PC_OPCODE:
5009     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
5010
5011     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
5012
5013         if(PCI(pc)->is2MemOp) {
5014                 SAFE_snprintf(&s,&size, "%s, %s", 
5015                 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
5016                 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
5017                 break;
5018         }
5019
5020         if(PCI(pc)->is2LitOp) {
5021                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
5022                 break;
5023         }
5024
5025       if(PCI(pc)->isBitInst) {
5026         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
5027           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
5028             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
5029                           PCI(pc)->pcop->name ,
5030                           PCI(pc)->pcop->name );
5031           else
5032             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5033 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5034                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5035                           
5036         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5037           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5038         } else
5039           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5040         //PCI(pc)->pcop->t.bit );
5041       } else {
5042
5043         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5044           if( PCI(pc)->num_ops == 3)
5045             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5046           else
5047             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5048
5049         }
5050         else 
5051         {
5052           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5053         }
5054       }
5055         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5056           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5057             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5058
5059           r = pic16_getRegFromInstruction(pc);
5060 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5061 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5062
5063           if(PCI(pc)->isAccess) {
5064             static char *bank_spec[2][2] = {
5065               { "", ", ACCESS" },  /* gpasm uses access bank by default */
5066               { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5067             };
5068              
5069             SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !r->accessBank) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5070           }
5071         }
5072 //      
5073
5074     }
5075     break;
5076
5077   case PC_COMMENT:
5078     /* assuming that comment ends with a \n */
5079     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5080     break;
5081
5082   case PC_INFO:
5083     SAFE_snprintf(&s,&size,"; info ==>");
5084     switch( PCINF(pc)->type ) {
5085       case INF_OPTIMIZATION:
5086           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5087           break;
5088       case INF_LOCALREGS:
5089           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5090           break;
5091     }; break;
5092
5093   case PC_INLINE:
5094     /* assuming that inline code ends with a \n */
5095     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5096     break;
5097
5098   case PC_LABEL:
5099     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5100     break;
5101   case PC_FUNCTION:
5102     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5103     break;
5104   case PC_WILD:
5105     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5106     break;
5107   case PC_FLOW:
5108     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5109     break;
5110   case PC_CSOURCE:
5111 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5112       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5113         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5114     break;
5115   case PC_ASMDIR:
5116         if(PCAD(pc)->directive) {
5117                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5118         } else
5119         if(PCAD(pc)->arg) {
5120                 /* special case to handle inline labels without a tab */
5121                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5122         }
5123         break;
5124
5125   case PC_BAD:
5126     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5127     break;
5128   }
5129
5130   return str;
5131
5132 }
5133
5134 /*-----------------------------------------------------------------*/
5135 /* genericPrint - the contents of a pCode to a file                */
5136 /*-----------------------------------------------------------------*/
5137 static void genericPrint(FILE *of, pCode *pc)
5138 {
5139
5140   if(!pc || !of)
5141     return;
5142
5143   switch(pc->type) {
5144   case PC_COMMENT:
5145 //    fputs(((pCodeComment *)pc)->comment, of);
5146     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5147     break;
5148
5149   case PC_INFO:
5150     {
5151       pBranch *pbl = PCI(pc)->label;
5152       while(pbl && pbl->pc) {
5153         if(pbl->pc->type == PC_LABEL)
5154           pCodePrintLabel(of, pbl->pc);
5155         pbl = pbl->next;
5156       }
5157     }
5158           
5159     if(pic16_pcode_verbose) {
5160       fprintf(of, "; info ==>");
5161       switch(((pCodeInfo *)pc)->type) {
5162         case INF_OPTIMIZATION:
5163               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5164               break;
5165         case INF_LOCALREGS:
5166               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5167               break;
5168         }
5169     };
5170     
5171     break;
5172
5173   case PC_INLINE:
5174     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5175      break;
5176
5177   case PC_OPCODE:
5178     // If the opcode has a label, print that first
5179     {
5180       pBranch *pbl = PCI(pc)->label;
5181       while(pbl && pbl->pc) {
5182         if(pbl->pc->type == PC_LABEL)
5183           pCodePrintLabel(of, pbl->pc);
5184         pbl = pbl->next;
5185       }
5186     }
5187
5188     if(PCI(pc)->cline) 
5189       genericPrint(of,PCODE(PCI(pc)->cline));
5190
5191     {
5192       char str[256];
5193       
5194       pic16_pCode2str(str, 256, pc);
5195
5196       fprintf(of,"%s",str);
5197       /* Debug */
5198       if(pic16_debug_verbose) {
5199         fprintf(of, "\t;key=%03x",pc->seq);
5200         if(PCI(pc)->pcflow)
5201           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5202       }
5203     }
5204     fprintf(of, "\n");
5205     break;
5206       
5207   case PC_WILD:
5208     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5209     if(PCW(pc)->pci.label)
5210       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5211
5212     if(PCW(pc)->operand) {
5213       fprintf(of,";\toperand  ");
5214       pCodeOpPrint(of,PCW(pc)->operand );
5215     }
5216     break;
5217
5218   case PC_FLOW:
5219     if(pic16_debug_verbose) {
5220       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5221       if(PCFL(pc)->ancestor)
5222         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5223       fprintf(of,"\n");
5224
5225     }
5226     break;
5227
5228   case PC_CSOURCE:
5229 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5230     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5231         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5232          
5233     break;
5234
5235   case PC_ASMDIR:
5236         {
5237           pBranch *pbl = PCAD(pc)->pci.label;
5238                 while(pbl && pbl->pc) {
5239                         if(pbl->pc->type == PC_LABEL)
5240                                 pCodePrintLabel(of, pbl->pc);
5241                         pbl = pbl->next;
5242                 }
5243         }
5244         if(PCAD(pc)->directive) {
5245                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5246         } else
5247         if(PCAD(pc)->arg) {
5248                 /* special case to handle inline labels without tab */
5249                 fprintf(of, "%s\n", PCAD(pc)->arg);
5250         }
5251         break;
5252         
5253   case PC_LABEL:
5254   default:
5255     fprintf(of,"unknown pCode type %d\n",pc->type);
5256   }
5257
5258 }
5259
5260 /*-----------------------------------------------------------------*/
5261 /* pCodePrintFunction - prints function begin/end                  */
5262 /*-----------------------------------------------------------------*/
5263
5264 static void pCodePrintFunction(FILE *of, pCode *pc)
5265 {
5266
5267   if(!pc || !of)
5268     return;
5269
5270 #if 0
5271   if( ((pCodeFunction *)pc)->modname) 
5272     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5273 #endif
5274
5275   if(!PCF(pc)->absblock) {
5276       if(PCF(pc)->fname) {
5277       pBranch *exits = PCF(pc)->to;
5278       int i=0;
5279
5280       fprintf(of,"%s:", PCF(pc)->fname);
5281     
5282       if(pic16_pcode_verbose)
5283         fprintf(of, "\t;Function start");
5284     
5285       fprintf(of, "\n");
5286     
5287       while(exits) {
5288         i++;
5289         exits = exits->next;
5290       }
5291       //if(i) i--;
5292
5293       if(pic16_pcode_verbose)
5294         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5295     
5296     } else {
5297         if((PCF(pc)->from && 
5298                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5299                 PCF(PCF(pc)->from->pc)->fname) ) {
5300
5301                 if(pic16_pcode_verbose)
5302                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5303         } else {
5304                 if(pic16_pcode_verbose)
5305                         fprintf(of,"; exit point [can't find entry point]\n");
5306         }
5307         fprintf(of, "\n");
5308     }
5309   }
5310 }
5311 /*-----------------------------------------------------------------*/
5312 /* pCodePrintLabel - prints label                                  */
5313 /*-----------------------------------------------------------------*/
5314
5315 static void pCodePrintLabel(FILE *of, pCode *pc)
5316 {
5317
5318   if(!pc || !of)
5319     return;
5320
5321   if(PCL(pc)->label) 
5322     fprintf(of,"%s:\n",PCL(pc)->label);
5323   else if (PCL(pc)->key >=0) 
5324     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5325   else
5326     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5327
5328 }
5329 /*-----------------------------------------------------------------*/
5330 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5331 /*                         remove it if it is found.               */
5332 /*-----------------------------------------------------------------*/
5333 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5334 {
5335   pBranch *b, *bprev;
5336
5337
5338   bprev = NULL;
5339
5340   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5341     b = PCI(pcl)->label;
5342   else {
5343     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5344     exit(1);
5345
5346   }
5347
5348   //fprintf (stderr, "%s \n",__FUNCTION__);
5349   //pcl->print(stderr,pcl);
5350   //pc->print(stderr,pc);
5351   while(b) {
5352     if(b->pc == pc) {
5353       //fprintf (stderr, "found label\n");
5354       //pc->print(stderr, pc);
5355
5356       /* Found a label */
5357       if(bprev) {
5358         bprev->next = b->next;  /* Not first pCode in chain */
5359 //      Safe_free(b);
5360       } else {
5361         pc->destruct(pc);
5362         PCI(pcl)->label = b->next;   /* First pCode in chain */
5363 //      Safe_free(b);
5364       }
5365       return;  /* A label can't occur more than once */
5366     }
5367     bprev = b;
5368     b = b->next;
5369   }
5370
5371 }
5372
5373 /*-----------------------------------------------------------------*/
5374 /*-----------------------------------------------------------------*/
5375 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5376 {
5377   pBranch *b;
5378
5379   if(!h)
5380     return n;
5381
5382   if(h == n)
5383     return n;
5384
5385   b = h;
5386   while(b->next)
5387     b = b->next;
5388
5389   b->next = n;
5390
5391   return h;
5392   
5393 }  
5394 /*-----------------------------------------------------------------*/
5395 /* pBranchLink - given two pcodes, this function will link them    */
5396 /*               together through their pBranches                  */
5397 /*-----------------------------------------------------------------*/
5398 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5399 {
5400   pBranch *b;
5401
5402   // Declare a new branch object for the 'from' pCode.
5403
5404   //_ALLOC(b,sizeof(pBranch));
5405   b = Safe_calloc(1,sizeof(pBranch));
5406   b->pc = PCODE(t);             // The link to the 'to' pCode.
5407   b->next = NULL;
5408
5409   f->to = pic16_pBranchAppend(f->to,b);
5410
5411   // Now do the same for the 'to' pCode.
5412
5413   //_ALLOC(b,sizeof(pBranch));
5414   b = Safe_calloc(1,sizeof(pBranch));
5415   b->pc = PCODE(f);
5416   b->next = NULL;
5417
5418   t->from = pic16_pBranchAppend(t->from,b);
5419   
5420 }
5421
5422 #if 1
5423 /*-----------------------------------------------------------------*/
5424 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5425 /*               a pCode                                           */
5426 /*-----------------------------------------------------------------*/
5427 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5428 {
5429   while(pb) {
5430
5431     if(pb->pc == pc)
5432       return pb;
5433
5434     pb = pb->next;
5435   }
5436
5437   return NULL;
5438 }
5439
5440 /*-----------------------------------------------------------------*/
5441 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5442 /*-----------------------------------------------------------------*/
5443 void pic16_pCodeUnlink(pCode *pc)
5444 {
5445   pBranch *pb1,*pb2;
5446   pCode *pc1;
5447
5448   if(!pc->prev || !pc->next) {
5449     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5450     exit(1);
5451   }
5452   
5453   /* move C source line down (or up) */
5454   if (isPCI(pc) && PCI(pc)->cline) {
5455     pc1 = pic16_findNextInstruction (pc->next);
5456     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5457       PCI(pc1)->cline = PCI(pc)->cline;
5458     } else {
5459       pc1 = pic16_findPrevInstruction (pc->prev);
5460       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5461         PCI(pc1)->cline = PCI(pc)->cline;
5462     }
5463   }
5464
5465   /* first remove the pCode from the chain */
5466   pc->prev->next = pc->next;
5467   pc->next->prev = pc->prev;
5468
5469   pc->prev = pc->next = NULL;
5470
5471   /* Now for the hard part... */
5472
5473   /* Remove the branches */
5474
5475   pb1 = PCI(pc)->from;
5476   while(pb1) {
5477     pc1 = pb1->pc;    /* Get the pCode that branches to the
5478                        * one we're unlinking */
5479
5480     /* search for the link back to this pCode (the one we're
5481      * unlinking) */
5482     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5483       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5484
5485       /* if the pCode we're unlinking contains multiple 'to'
5486        * branches (e.g. this a skip instruction) then we need
5487        * to copy these extra branches to the chain. */
5488       if(PCI(pc)->to->next)
5489         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5490     }
5491     
5492     pb1 = pb1->next;
5493   }
5494
5495
5496 }
5497 #endif
5498 /*-----------------------------------------------------------------*/
5499 /*-----------------------------------------------------------------*/
5500 #if 0
5501 static void genericAnalyze(pCode *pc)
5502 {
5503   switch(pc->type) {
5504   case PC_WILD:
5505   case PC_COMMENT:
5506     return;
5507   case PC_LABEL:
5508   case PC_FUNCTION:
5509   case PC_OPCODE:
5510     {
5511       // Go through the pCodes that are in pCode chain and link
5512       // them together through the pBranches. Note, the pCodes
5513       // are linked together as a contiguous stream like the 
5514       // assembly source code lines. The linking here mimics this
5515       // except that comments are not linked in.
5516       // 
5517       pCode *npc = pc->next;
5518       while(npc) {
5519         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5520           pBranchLink(pc,npc);
5521           return;
5522         } else
5523           npc = npc->next;
5524       }
5525       /* reached the end of the pcode chain without finding
5526        * an instruction we could link to. */
5527     }
5528     break;
5529   case PC_FLOW:
5530     fprintf(stderr,"analyze PC_FLOW\n");
5531
5532     return;
5533   case PC_BAD:
5534     fprintf(stderr,,";A bad pCode is being used\n");
5535
5536   }
5537 }
5538 #endif
5539
5540 /*-----------------------------------------------------------------*/
5541 /*-----------------------------------------------------------------*/
5542 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5543 {
5544   pBranch *pbr;
5545
5546   if(pc->type == PC_LABEL) {
5547     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5548       return TRUE;
5549   }
5550   if((pc->type == PC_OPCODE)
5551         || (pc->type == PC_ASMDIR)
5552         ) {
5553     pbr = PCI(pc)->label;
5554     while(pbr) {
5555       if(pbr->pc->type == PC_LABEL) {
5556         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5557           return TRUE;
5558       }
5559       pbr = pbr->next;
5560     }
5561   }
5562
5563   return FALSE;
5564 }
5565
5566 /*-----------------------------------------------------------------*/
5567 /*-----------------------------------------------------------------*/
5568 static int checkLabel(pCode *pc)
5569 {
5570   pBranch *pbr;
5571
5572   if(pc && isPCI(pc)) {
5573     pbr = PCI(pc)->label;
5574     while(pbr) {
5575       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5576         return TRUE;
5577
5578       pbr = pbr->next;
5579     }
5580   }
5581
5582   return FALSE;
5583 }
5584
5585 /*-----------------------------------------------------------------*/
5586 /* findLabelinpBlock - Search the pCode for a particular label     */
5587 /*-----------------------------------------------------------------*/
5588 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5589 {
5590   pCode  *pc;
5591
5592   if(!pb)
5593     return NULL;
5594
5595   for(pc = pb->pcHead; pc; pc = pc->next) 
5596     if(compareLabel(pc,pcop_label))
5597       return pc;
5598     
5599   return NULL;
5600 }
5601 #if 0
5602 /*-----------------------------------------------------------------*/
5603 /* findLabel - Search the pCode for a particular label             */
5604 /*-----------------------------------------------------------------*/
5605 static pCode * findLabel(pCodeOpLabel *pcop_label)
5606 {
5607   pBlock *pb;
5608   pCode  *pc;
5609
5610   if(!the_pFile)
5611     return NULL;
5612
5613   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5614     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5615       return pc;
5616   }
5617
5618   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5619   return NULL;
5620 }
5621 #endif
5622 /*-----------------------------------------------------------------*/
5623 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5624 /*                 in the linked list                              */
5625 /*-----------------------------------------------------------------*/
5626 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5627 {
5628
5629   while(pc) {
5630     if(pc->type == pct)
5631       return pc;
5632
5633     pc = pc->next;
5634   }
5635
5636   return NULL;
5637 }
5638
5639 /*-----------------------------------------------------------------*/
5640 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5641 /*                 in the linked list                              */
5642 /*-----------------------------------------------------------------*/
5643 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5644 {
5645
5646   while(pc) {
5647     if(pc->type == pct)
5648       return pc;
5649
5650     pc = pc->prev;
5651   }
5652
5653   return NULL;
5654 }
5655
5656
5657 //#define PCODE_DEBUG
5658 /*-----------------------------------------------------------------*/
5659 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5660 /*                       in the linked list                        */
5661 /*-----------------------------------------------------------------*/
5662 pCode * pic16_findNextInstruction(pCode *pci)
5663 {
5664   pCode *pc = pci;
5665
5666   while(pc) {
5667     if((pc->type == PC_OPCODE)
5668         || (pc->type == PC_WILD)
5669         || (pc->type == PC_ASMDIR)
5670         )
5671       return pc;
5672
5673 #ifdef PCODE_DEBUG
5674     fprintf(stderr,"pic16_findNextInstruction:  ");
5675     printpCode(stderr, pc);
5676 #endif
5677     pc = pc->next;
5678   }
5679
5680   //fprintf(stderr,"Couldn't find instruction\n");
5681   return NULL;
5682 }
5683
5684 /*-----------------------------------------------------------------*/
5685 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5686 /*                       in the linked list                        */
5687 /*-----------------------------------------------------------------*/
5688 pCode * pic16_findPrevInstruction(pCode *pci)
5689 {
5690   pCode *pc = pci;
5691
5692   while(pc) {
5693
5694     if((pc->type == PC_OPCODE)
5695         || (pc->type == PC_WILD)
5696         || (pc->type == PC_ASMDIR)
5697         )
5698       return pc;
5699       
5700
5701 #ifdef PCODE_DEBUG
5702     fprintf(stderr,"pic16_findPrevInstruction:  ");
5703     printpCode(stderr, pc);
5704 #endif
5705     pc = pc->prev;
5706   }
5707
5708   //fprintf(stderr,"Couldn't find instruction\n");
5709   return NULL;
5710 }
5711
5712 #undef PCODE_DEBUG
5713
5714 #if 0
5715 /*-----------------------------------------------------------------*/
5716 /* findFunctionEnd - given a pCode find the end of the function    */
5717 /*                   that contains it                              */
5718 /*-----------------------------------------------------------------*/
5719 static pCode * findFunctionEnd(pCode *pc)
5720 {
5721
5722   while(pc) {
5723     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5724       return pc;
5725
5726     pc = pc->next;
5727   }
5728
5729   fprintf(stderr,"Couldn't find function end\n");
5730   return NULL;
5731 }
5732 #endif
5733 #if 0
5734 /*-----------------------------------------------------------------*/
5735 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5736 /*                instruction with which it is associated.         */
5737 /*-----------------------------------------------------------------*/
5738 static void AnalyzeLabel(pCode *pc)
5739 {
5740
5741   pic16_pCodeUnlink(pc);
5742
5743 }
5744 #endif
5745
5746 #if 0
5747 static void AnalyzeGOTO(pCode *pc)
5748 {
5749
5750   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5751
5752 }
5753
5754 static void AnalyzeSKIP(pCode *pc)
5755 {
5756
5757   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5758   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5759
5760 }
5761
5762 static void AnalyzeRETURN(pCode *pc)
5763 {
5764
5765   //  branch_link(pc,findFunctionEnd(pc->next));
5766
5767 }
5768
5769 #endif
5770
5771 /*-------------------------------------------------------------------*/
5772 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5773 /*                            if one is present. This is the common  */
5774 /*                            part of pic16_getRegFromInstruction(2) */
5775 /*-------------------------------------------------------------------*/
5776
5777 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5778   if (!pcop) return NULL;
5779   
5780   switch(pcop->type) {
5781   case PO_PRODL:
5782   case PO_PRODH:
5783   case PO_INDF0:
5784   case PO_FSR0:
5785   case PO_W:
5786   case PO_WREG:
5787   case PO_STATUS:
5788   case PO_INTCON:
5789   case PO_PCL:
5790   case PO_PCLATH:
5791   case PO_PCLATU:
5792   case PO_BSR:
5793     return PCOR(pcop)->r;
5794
5795   case PO_SFR_REGISTER:
5796     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5797     return PCOR(pcop)->r;
5798
5799   case PO_BIT:
5800   case PO_GPR_TEMP:
5801 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5802     return PCOR(pcop)->r;
5803
5804   case PO_IMMEDIATE:
5805 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5806
5807     if(PCOI(pcop)->r)
5808       return (PCOI(pcop)->r);
5809     else
5810       return NULL;
5811     
5812   case PO_GPR_BIT:
5813     return PCOR(pcop)->r;
5814
5815   case PO_GPR_REGISTER:
5816   case PO_DIR:
5817 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5818     return PCOR(pcop)->r;
5819
5820   case PO_LITERAL:
5821     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5822     break;
5823
5824   case PO_REL_ADDR:
5825   case PO_LABEL:
5826     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5827     break;
5828     
5829   case PO_CRY:
5830   case PO_STR:
5831     /* this should never turn up */
5832     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5833     break;
5834     
5835   case PO_WILD:
5836     break;
5837     
5838   default:
5839         fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5840 //      assert( 0 );
5841         break;
5842   }
5843
5844   return NULL;
5845 }
5846
5847 /*-----------------------------------------------------------------*/
5848 /*-----------------------------------------------------------------*/
5849 regs * pic16_getRegFromInstruction(pCode *pc)
5850 {
5851
5852   if(!pc                   || 
5853      !isPCI(pc)            ||
5854      !PCI(pc)->pcop        ||
5855      PCI(pc)->num_ops == 0 ||
5856      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5857     return NULL;
5858
5859 #if 0
5860   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5861         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5862 #endif
5863
5864   return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5865 }
5866
5867 /*-------------------------------------------------------------------------------*/
5868 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5869 /*-------------------------------------------------------------------------------*/
5870 regs * pic16_getRegFromInstruction2(pCode *pc)
5871 {
5872
5873   if(!pc                   || 
5874      !isPCI(pc)            ||
5875      !PCI(pc)->pcop        ||
5876      PCI(pc)->num_ops == 0 ||
5877      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5878     return NULL;
5879
5880
5881 #if 0
5882   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5883         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5884 #endif
5885
5886   return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5887 }
5888
5889 /*-----------------------------------------------------------------*/
5890 /*-----------------------------------------------------------------*/
5891
5892 static void AnalyzepBlock(pBlock *pb)
5893 {
5894   pCode *pc;
5895
5896   if(!pb)
5897     return;
5898
5899   /* Find all of the registers used in this pBlock 
5900    * by looking at each instruction and examining it's
5901    * operands
5902    */
5903   for(pc = pb->pcHead; pc; pc = pc->next) {
5904
5905     /* Is this an instruction with operands? */
5906     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5907
5908       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5909
5910         /* Loop through all of the registers declared so far in
5911            this block and see if we find this one there */
5912
5913         regs *r = setFirstItem(pb->tregisters);
5914
5915         while(r) {
5916           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5917             PCOR(PCI(pc)->pcop)->r = r;
5918             break;
5919           }
5920           r = setNextItem(pb->tregisters);
5921         }
5922
5923         if(!r) {
5924           /* register wasn't found */
5925           //r = Safe_calloc(1, sizeof(regs));
5926           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5927           //addSet(&pb->tregisters, r);
5928           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5929           //PCOR(PCI(pc)->pcop)->r = r;
5930           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5931         }/* else 
5932           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5933          */
5934       }
5935       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5936         if(PCOR(PCI(pc)->pcop)->r) {
5937           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5938           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5939         } else {
5940           if(PCI(pc)->pcop->name)
5941             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5942           else
5943             fprintf(stderr,"ERROR: NULL register\n");
5944         }
5945       }
5946     }
5947
5948
5949   }
5950 }
5951
5952 /*-----------------------------------------------------------------*/
5953 /* */
5954 /*-----------------------------------------------------------------*/
5955 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5956
5957 static void InsertpFlow(pCode *pc, pCode **pflow)
5958 {
5959   if(*pflow)
5960     PCFL(*pflow)->end = pc;
5961
5962   if(!pc || !pc->next)
5963     return;
5964
5965   *pflow = pic16_newpCodeFlow();
5966   pic16_pCodeInsertAfter(pc, *pflow);
5967 }
5968
5969 /*-----------------------------------------------------------------*/
5970 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5971 /*                         the flow blocks.                        */
5972 /*
5973  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5974  * point the instruction flow changes. 
5975  */
5976 /*-----------------------------------------------------------------*/
5977 void pic16_BuildFlow(pBlock *pb)
5978 {
5979   pCode *pc;
5980   pCode *last_pci=NULL;
5981   pCode *pflow=NULL;
5982   int seq = 0;
5983
5984   if(!pb)
5985     return;
5986
5987   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5988   /* Insert a pCodeFlow object at the beginning of a pBlock */
5989
5990   InsertpFlow(pb->pcHead, &pflow);
5991
5992   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5993   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5994   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5995   //pb->pcHead = pflow;        /* Make the Flow object the head */
5996   //pflow->pb = pb;
5997
5998   for( pc = pic16_findNextInstruction(pb->pcHead);
5999        pc != NULL;
6000        pc=pic16_findNextInstruction(pc)) { 
6001
6002     pc->seq = seq++;
6003     PCI(pc)->pcflow = PCFL(pflow);
6004
6005     //fprintf(stderr," build: ");
6006     //pflow->print(stderr,pflow);
6007
6008     if (checkLabel(pc)) { 
6009
6010       /* This instruction marks the beginning of a
6011        * new flow segment */
6012
6013       pc->seq = 0;
6014       seq = 1;
6015
6016       /* If the previous pCode is not a flow object, then 
6017        * insert a new flow object. (This check prevents 
6018        * two consecutive flow objects from being insert in
6019        * the case where a skip instruction preceeds an
6020        * instruction containing a label.) */
6021
6022       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
6023         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
6024
6025       PCI(pc)->pcflow = PCFL(pflow);
6026       
6027     }
6028
6029     if( PCI(pc)->isSkip) {
6030
6031       /* The two instructions immediately following this one 
6032        * mark the beginning of a new flow segment */
6033
6034       while(pc && PCI(pc)->isSkip) {
6035
6036         PCI(pc)->pcflow = PCFL(pflow);
6037         pc->seq = seq-1;
6038         seq = 1;
6039
6040         InsertpFlow(pc, &pflow);
6041         pc=pic16_findNextInstruction(pc->next);
6042       }
6043
6044       seq = 0;
6045
6046       if(!pc)
6047         break;
6048
6049       PCI(pc)->pcflow = PCFL(pflow);
6050       pc->seq = 0;
6051       InsertpFlow(pc, &pflow);
6052
6053     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6054
6055       InsertpFlow(pc, &pflow);
6056       seq = 0;
6057
6058     }
6059     last_pci = pc;
6060     pc = pc->next;
6061   }
6062
6063   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6064   if(pflow)
6065     PCFL(pflow)->end = pb->pcTail;
6066 }
6067
6068 /*-------------------------------------------------------------------*/
6069 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6070 /*                           the flow blocks.                        */
6071 /*
6072  * unBuildFlow removes pCodeFlow objects from a pCode chain
6073  */
6074 /*-----------------------------------------------------------------*/
6075 static void unBuildFlow(pBlock *pb)
6076 {
6077   pCode *pc,*pcnext;
6078
6079   if(!pb)
6080     return;
6081
6082   pc = pb->pcHead;
6083
6084   while(pc) {
6085     pcnext = pc->next;
6086
6087     if(isPCI(pc)) {
6088
6089       pc->seq = 0;
6090       if(PCI(pc)->pcflow) {
6091         //Safe_free(PCI(pc)->pcflow);
6092         PCI(pc)->pcflow = NULL;
6093       }
6094
6095     } else if(isPCFL(pc) )
6096       pc->destruct(pc);
6097
6098     pc = pcnext;
6099   }
6100
6101
6102 }
6103 #if 0
6104 /*-----------------------------------------------------------------*/
6105 /*-----------------------------------------------------------------*/
6106 static void dumpCond(int cond)
6107 {
6108
6109   static char *pcc_str[] = {
6110     //"PCC_NONE",
6111     "PCC_REGISTER",
6112     "PCC_C",
6113     "PCC_Z",
6114     "PCC_DC",
6115     "PCC_OV",
6116     "PCC_N",
6117     "PCC_W",
6118     "PCC_EXAMINE_PCOP",
6119     "PCC_LITERAL",
6120     "PCC_REL_ADDR"
6121   };
6122
6123   int ncond = sizeof(pcc_str) / sizeof(char *);
6124   int i,j;
6125
6126   fprintf(stderr, "0x%04X\n",cond);
6127
6128   for(i=0,j=1; i<ncond; i++, j<<=1)
6129     if(cond & j)
6130       fprintf(stderr, "  %s\n",pcc_str[i]);
6131
6132 }
6133 #endif
6134
6135 #if 0
6136 /*-----------------------------------------------------------------*/
6137 /*-----------------------------------------------------------------*/
6138 static void FlowStats(pCodeFlow *pcflow)
6139 {
6140
6141   pCode *pc;
6142
6143   if(!isPCFL(pcflow))
6144     return;
6145
6146   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6147
6148   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6149
6150   if(!pc) {
6151     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6152     return;
6153   }
6154
6155
6156   fprintf(stderr, "  FlowStats inCond: ");
6157   dumpCond(pcflow->inCond);
6158   fprintf(stderr, "  FlowStats outCond: ");
6159   dumpCond(pcflow->outCond);
6160
6161 }
6162 #endif
6163 /*-----------------------------------------------------------------*
6164  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6165  *    if it affects the banking bits. 
6166  * 
6167  * return: -1 == Banking bits are unaffected by this pCode.
6168  *
6169  * return: > 0 == Banking bits are affected.
6170  *
6171  *  If the banking bits are affected, then the returned value describes
6172  * which bits are affected and how they're affected. The lower half
6173  * of the integer maps to the bits that are affected, the upper half
6174  * to whether they're set or cleared.
6175  *
6176  *-----------------------------------------------------------------*/
6177
6178 static int isBankInstruction(pCode *pc)
6179 {
6180   regs *reg;
6181   int bank = -1;
6182
6183   if(!isPCI(pc))
6184     return 0;
6185
6186   if( PCI(pc)->op == POC_MOVLB ||
6187       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6188     bank = PCOL(pc)->lit;
6189   }
6190
6191   return 1;
6192 }
6193
6194
6195 /*-----------------------------------------------------------------*/
6196 /*-----------------------------------------------------------------*/
6197 static void FillFlow(pCodeFlow *pcflow)
6198 {
6199
6200   pCode *pc;
6201   int cur_bank;
6202
6203   if(!isPCFL(pcflow))
6204     return;
6205
6206   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6207
6208   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6209
6210   if(!pc) {
6211     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6212     return;
6213   }
6214
6215   cur_bank = -1;
6216
6217   do {
6218     isBankInstruction(pc);
6219     pc = pc->next;
6220   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6221
6222 /*
6223   if(!pc ) {
6224     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6225   } else {
6226     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6227     pc->print(stderr,pc);
6228   }
6229
6230   fprintf(stderr, "  FillFlow inCond: ");
6231   dumpCond(pcflow->inCond);
6232   fprintf(stderr, "  FillFlow outCond: ");
6233   dumpCond(pcflow->outCond);
6234 */
6235 }
6236
6237 /*-----------------------------------------------------------------*/
6238 /*-----------------------------------------------------------------*/
6239 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6240 {
6241   pCodeFlowLink *fromLink, *toLink;
6242
6243   if(!from || !to || !to->pcflow || !from->pcflow)
6244     return;
6245
6246   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6247   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6248
6249   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6250   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6251
6252 }
6253
6254 pCode *pic16_getJumptabpCode (pCode *pc) {
6255   pCode *pcinf;
6256
6257   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6258   //pc->print (stderr, pc);
6259   pcinf = pc;
6260   while (pcinf) {
6261     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6262     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6263       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6264       case OPT_JUMPTABLE_BEGIN:
6265         /* leading begin of jump table -- in one */
6266         pcinf = pic16_findPrevInstruction (pcinf);
6267         return pcinf;
6268         break;
6269         
6270       case OPT_JUMPTABLE_END:
6271         /* leading end of jumptable -- not in one */
6272         return NULL;
6273         break;
6274         
6275       default:
6276         /* ignore all other PCInfos */
6277         break;
6278       }
6279     }
6280     pcinf = pcinf->prev;
6281   }
6282
6283   /* no PCInfo found -- not in a jumptable */
6284   return NULL;
6285 }
6286
6287 /*-----------------------------------------------------------------*
6288  * void LinkFlow(pBlock *pb)
6289  *
6290  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6291  * non-branching segments. In LinkFlow, we determine the execution
6292  * order of these segments. For example, if one of the segments ends
6293  * with a skip, then we know that there are two possible flow segments
6294  * to which control may be passed.
6295  *-----------------------------------------------------------------*/
6296 static void LinkFlow(pBlock *pb)
6297 {
6298   pCode *pc=NULL;
6299   pCode *pcflow;
6300   pCode *pct;
6301   pCode *jumptab_pre = NULL;
6302
6303   //fprintf(stderr,"linkflow \n");
6304
6305   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6306        pcflow != NULL;
6307        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6308
6309     if(!isPCFL(pcflow))
6310       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6311
6312     //fprintf(stderr," link: ");
6313     //pcflow->print(stderr,pcflow);
6314
6315     //FillFlow(PCFL(pcflow));
6316
6317     pc = PCFL(pcflow)->end;
6318
6319     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6320     if(isPCI_SKIP(pc)) {
6321 //      fprintf(stderr, "ends with skip\n");
6322 //      pc->print(stderr,pc);
6323
6324       pct=pic16_findNextInstruction(pc->next);
6325       LinkFlow_pCode(PCI(pc),PCI(pct));
6326       pct=pic16_findNextInstruction(pct->next);
6327       LinkFlow_pCode(PCI(pc),PCI(pct));
6328       continue;
6329     }
6330
6331     if(isPCI_BRANCH(pc)) {
6332       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6333
6334       /* handle GOTOs in jumptables */
6335       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6336         /* link to previous flow */
6337         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6338         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6339       }
6340
6341       switch (PCI(pc)->op) {
6342       case POC_GOTO:
6343       case POC_BRA:
6344       case POC_RETURN:
6345       case POC_RETLW:
6346       case POC_RETFIE:
6347               /* unconditional branches -- do not link to next instruction */
6348               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6349               break;
6350               
6351       case POC_CALL:
6352       case POC_RCALL:
6353               /* unconditional calls -- link to next instruction */
6354               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6355               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6356               break;
6357               
6358       case POC_BC:
6359       case POC_BN:
6360       case POC_BNC:
6361       case POC_BNN:
6362       case POC_BNOV:
6363       case POC_BNZ:
6364       case POC_BOV:
6365       case POC_BZ:
6366               /* conditional branches -- also link to next instruction */
6367               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6368               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6369               break;
6370               
6371       default:
6372               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6373               assert (0 && "unhandled branching instruction");
6374               break;
6375       }
6376
6377       //fprintf(stderr, "ends with branch\n  ");
6378       //pc->print(stderr,pc);
6379
6380       if(!(pcol && isPCOLAB(pcol))) {
6381         if((PCI(pc)->op != POC_RETLW)
6382                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6383         
6384                 /* continue if label is '$' which assembler knows how to parse */
6385                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6386
6387                 if(pic16_pcode_verbose) {
6388                         pc->print(stderr,pc);
6389                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6390                 }
6391         }
6392         continue;
6393       }
6394
6395       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6396         LinkFlow_pCode(PCI(pc),PCI(pct));
6397       else
6398         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6399                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6400
6401 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6402
6403       continue;
6404     }
6405
6406     if(isPCI(pc)) {
6407       //fprintf(stderr, "ends with non-branching instruction:\n");
6408       //pc->print(stderr,pc);
6409
6410       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6411
6412       continue;
6413     }
6414
6415     if(pc) {
6416       //fprintf(stderr, "ends with unknown\n");
6417       //pc->print(stderr,pc);
6418       continue;
6419     }
6420
6421     //fprintf(stderr, "ends with nothing: ERROR\n");
6422     
6423   }
6424 }
6425 /*-----------------------------------------------------------------*/
6426 /*-----------------------------------------------------------------*/
6427
6428 /*-----------------------------------------------------------------*/
6429 /*-----------------------------------------------------------------*/
6430 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6431 {
6432
6433   if(!pc || !pcflow)
6434     return 0;
6435
6436   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6437     return 0;
6438
6439   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6440     return 1;
6441
6442   return 0;
6443 }
6444
6445
6446
6447
6448
6449 /*-----------------------------------------------------------------*/
6450 /* insertBankSwitch - inserts a bank switch statement in the       */
6451 /*                    assembly listing                             */
6452 /*                                                                 */
6453 /* position == 0: insert before                                    */
6454 /* position == 1: insert after pc                                  */
6455 /* position == 2: like 0 but previous was a skip instruction       */
6456 /*-----------------------------------------------------------------*/
6457 pCodeOp *pic16_popGetLabel(unsigned int key);
6458 extern int pic16_labelOffset;
6459
6460 static void insertBankSwitch(unsigned char position, pCode *pc)
6461 {
6462   pCode *new_pc;
6463
6464         if(!pc)
6465                 return;
6466
6467         /* emit BANKSEL [symbol] */
6468
6469
6470         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6471         
6472 //      position = 0;           // position is always before (sanity check!)
6473
6474 #if 0
6475         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6476         pc->print(stderr, pc);
6477 #endif
6478
6479         switch(position) {
6480                 case 1: {
6481                         /* insert the bank switch after this pc instruction */
6482                         pCode *pcnext = pic16_findNextInstruction(pc);
6483
6484                                 pic16_pCodeInsertAfter(pc, new_pc);
6485                                 if(pcnext)pc = pcnext;
6486                 }; break;
6487                 
6488                 case 0:
6489                         /* insert the bank switch BEFORE this pc instruction */
6490                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6491                         break;
6492
6493                 case 2: {
6494                           symbol *tlbl;
6495                           pCode *pcnext, *pcprev, *npci, *ppc;
6496                           PIC_OPCODE ipci;
6497                           int ofs1=0, ofs2=0, len=0;
6498                           
6499                         /* just like 0, but previous was a skip instruction,
6500                          * so some care should be taken */
6501                           
6502                                 pic16_labelOffset += 10000;
6503                                 tlbl = newiTempLabel(NULL);
6504                                 
6505                                 /* invert skip instruction */
6506                                 pcprev = pic16_findPrevInstruction(pc->prev);
6507                                 ipci = PCI(pcprev)->inverted_op;
6508                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6509
6510 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6511
6512                                 /* copy info from old pCode */
6513                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6514                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6515                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6516                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6517                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6518                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6519                                 
6520                                 /* unlink old pCode */
6521                                 ppc = pcprev->prev;
6522                                 ppc->next = pcprev->next;
6523                                 pcprev->next->prev = ppc;
6524                                 pic16_pCodeInsertAfter(ppc, npci);
6525                                 
6526                                 /* extra instructions to handle invertion */
6527                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6528                                 pic16_pCodeInsertAfter(npci, pcnext);
6529                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6530                                 
6531                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6532                                 pic16_pCodeInsertAfter(pc, pcnext);
6533                         }; break;
6534         }
6535         
6536
6537         /* Move the label, if there is one */
6538         if(PCI(pc)->label) {
6539 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6540 //                      __FILE__, __LINE__, pc, new_pc);
6541                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6542                 PCI(pc)->label = NULL;
6543         }
6544 }
6545
6546
6547 /*-----------------------------------------------------------------*/
6548 /*int compareBankFlow - compare the banking requirements between   */
6549 /*  flow objects. */
6550 /*-----------------------------------------------------------------*/
6551 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6552 {
6553
6554   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6555     return 0;
6556
6557   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6558     return 0;
6559
6560   if(pcflow->firstBank == -1)
6561     return 0;
6562
6563
6564   if(pcflowLink->pcflow->firstBank == -1) {
6565     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6566                                         pcflowLink->pcflow->to : 
6567                                         pcflowLink->pcflow->from);
6568     return compareBankFlow(pcflow, pctl, toORfrom);
6569   }
6570
6571   if(toORfrom) {
6572     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6573       return 0;
6574
6575     pcflowLink->bank_conflict++;
6576     pcflowLink->pcflow->FromConflicts++;
6577     pcflow->ToConflicts++;
6578   } else {
6579     
6580     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6581       return 0;
6582
6583     pcflowLink->bank_conflict++;
6584     pcflowLink->pcflow->ToConflicts++;
6585     pcflow->FromConflicts++;
6586
6587   }
6588   /*
6589   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6590           pcflowLink->pcflow->pc.seq,
6591           pcflowLink->pcflow->FromConflicts,
6592           pcflowLink->pcflow->ToConflicts);
6593   */
6594   return 1;
6595
6596 }
6597
6598 #if 0
6599 /*-----------------------------------------------------------------*/
6600 /*-----------------------------------------------------------------*/
6601 static void DumpFlow(pBlock *pb)
6602 {
6603   pCode *pc=NULL;
6604   pCode *pcflow;
6605   pCodeFlowLink *pcfl;
6606
6607
6608   fprintf(stderr,"Dump flow \n");
6609   pb->pcHead->print(stderr, pb->pcHead);
6610
6611   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6612   pcflow->print(stderr,pcflow);
6613
6614   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6615        pcflow != NULL;
6616        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6617
6618     if(!isPCFL(pcflow)) {
6619       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6620       continue;
6621     }
6622     fprintf(stderr,"dumping: ");
6623     pcflow->print(stderr,pcflow);
6624     FlowStats(PCFL(pcflow));
6625
6626     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6627
6628       pc = PCODE(pcfl->pcflow);
6629
6630       fprintf(stderr, "    from seq %d:\n",pc->seq);
6631       if(!isPCFL(pc)) {
6632         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6633         pc->print(stderr,pc);
6634       }
6635
6636     }
6637
6638     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6639
6640       pc = PCODE(pcfl->pcflow);
6641
6642       fprintf(stderr, "    to seq %d:\n",pc->seq);
6643       if(!isPCFL(pc)) {
6644         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6645         pc->print(stderr,pc);
6646       }
6647
6648     }
6649
6650   }
6651
6652 }
6653 #endif
6654 /*-----------------------------------------------------------------*/
6655 /*-----------------------------------------------------------------*/
6656 static int OptimizepBlock(pBlock *pb)
6657 {
6658   pCode *pc, *pcprev;
6659   int matches =0;
6660
6661   if(!pb || !peepOptimizing)
6662     return 0;
6663
6664   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6665 /*
6666   for(pc = pb->pcHead; pc; pc = pc->next)
6667     matches += pic16_pCodePeepMatchRule(pc);
6668 */
6669
6670   pc = pic16_findNextInstruction(pb->pcHead);
6671   if(!pc)
6672     return 0;
6673
6674   pcprev = pc->prev;
6675   do {
6676
6677
6678     if(pic16_pCodePeepMatchRule(pc)) {
6679
6680       matches++;
6681
6682       if(pcprev)
6683         pc = pic16_findNextInstruction(pcprev->next);
6684       else 
6685         pc = pic16_findNextInstruction(pb->pcHead);
6686     } else
6687       pc = pic16_findNextInstruction(pc->next);
6688   } while(pc);
6689
6690   if(matches)
6691     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6692   return matches;
6693
6694 }
6695
6696 /*-----------------------------------------------------------------*/
6697 /*-----------------------------------------------------------------*/
6698 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6699 {
6700   pCode *pc;
6701
6702   for(pc = pcs; pc; pc = pc->next) {
6703
6704     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6705        (PCI(pc)->pcop) && 
6706        (PCI(pc)->pcop->type == PO_LABEL) &&
6707        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6708       return pc;
6709   }
6710  
6711
6712   return NULL;
6713 }
6714
6715 /*-----------------------------------------------------------------*/
6716 /*-----------------------------------------------------------------*/
6717 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6718 {
6719
6720   char *s=NULL;
6721
6722   if(isPCI(pc) && 
6723      (PCI(pc)->pcop) && 
6724      (PCI(pc)->pcop->type == PO_LABEL)) {
6725
6726     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6727
6728 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6729 //    if(pcol->pcop.name)
6730 //      Safe_free(pcol->pcop.name);
6731
6732     /* If the key is negative, then we (probably) have a label to
6733      * a function and the name is already defined */
6734        
6735     if(pcl->key>0)
6736       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6737     else 
6738       s = pcl->label;
6739
6740     //sprintf(buffer,"_%05d_DS_",pcl->key);
6741     if(!s) {
6742       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6743     }
6744     pcol->pcop.name = Safe_strdup(s);
6745     pcol->key = pcl->key;
6746     //pc->print(stderr,pc);
6747
6748   }
6749
6750
6751 }
6752
6753 /*-----------------------------------------------------------------*/
6754 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6755 /*                            pCode chain if they're not used.     */
6756 /*-----------------------------------------------------------------*/
6757 static void pBlockRemoveUnusedLabels(pBlock *pb)
6758 {
6759   pCode *pc; pCodeLabel *pcl;
6760
6761   if(!pb)
6762     return;
6763
6764   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6765
6766     pBranch *pbr = PCI(pc)->label;
6767     if(pbr && pbr->next) {
6768       pCode *pcd = pb->pcHead;
6769
6770 //      fprintf(stderr, "multiple labels\n");
6771 //      pc->print(stderr,pc);
6772
6773       pbr = pbr->next;
6774       while(pbr) {
6775
6776         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6777           //fprintf(stderr,"Used by:\n");
6778           //pcd->print(stderr,pcd);
6779
6780           exchangeLabels(PCL(pbr->pc),pcd);
6781
6782           pcd = pcd->next;
6783         }
6784         pbr = pbr->next;
6785       }
6786     }
6787   }
6788
6789   for(pc = pb->pcHead; pc; pc = pc->next) {
6790
6791     if(isPCL(pc)) // pc->type == PC_LABEL)
6792       pcl = PCL(pc);
6793     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6794       pcl = PCL(PCI(pc)->label->pc);
6795     else continue;
6796
6797 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6798
6799     /* This pCode is a label, so search the pBlock to see if anyone
6800      * refers to it */
6801
6802     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6803         && (!pcl->force)) {
6804     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6805       /* Couldn't find an instruction that refers to this label
6806        * So, unlink the pCode label from it's pCode chain
6807        * and destroy the label */
6808 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6809
6810       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6811       if(pc->type == PC_LABEL) {
6812         pic16_unlinkpCode(pc);
6813         pCodeLabelDestruct(pc);
6814       } else {
6815         unlinkpCodeFromBranch(pc, PCODE(pcl));
6816         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6817           Safe_free(pc->label);
6818         }*/
6819       }
6820
6821     }
6822   }
6823
6824 }
6825
6826
6827 /*-----------------------------------------------------------------*/
6828 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6829 /*                     chain and put them into pBranches that are  */
6830 /*                     associated with the appropriate pCode       */
6831 /*                     instructions.                               */
6832 /*-----------------------------------------------------------------*/
6833 void pic16_pBlockMergeLabels(pBlock *pb)
6834 {
6835   pBranch *pbr;
6836   pCode *pc, *pcnext=NULL;
6837
6838   if(!pb)
6839     return;
6840
6841   /* First, Try to remove any unused labels */
6842   //pBlockRemoveUnusedLabels(pb);
6843
6844   /* Now loop through the pBlock and merge the labels with the opcodes */
6845
6846   pc = pb->pcHead;
6847   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6848
6849   while(pc) {
6850     pCode *pcn = pc->next;
6851
6852     if(pc->type == PC_LABEL) {
6853
6854 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6855 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6856
6857       if((pcnext = pic16_findNextInstruction(pc) )) {
6858
6859 //              pcnext->print(stderr, pcnext);
6860
6861         // Unlink the pCode label from it's pCode chain
6862         pic16_unlinkpCode(pc);
6863         
6864 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6865         // And link it into the instruction's pBranch labels. (Note, since
6866         // it's possible to have multiple labels associated with one instruction
6867         // we must provide a means to accomodate the additional labels. Thus
6868         // the labels are placed into the singly-linked list "label" as 
6869         // opposed to being a single member of the pCodeInstruction.)
6870
6871         //_ALLOC(pbr,sizeof(pBranch));
6872 #if 1
6873         pbr = Safe_calloc(1,sizeof(pBranch));
6874         pbr->pc = pc;
6875         pbr->next = NULL;
6876
6877         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6878 #endif
6879       } else {
6880         if(pic16_pcode_verbose)
6881         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6882       }
6883     } else if(pc->type == PC_CSOURCE) {
6884
6885       /* merge the source line symbolic info into the next instruction */
6886       if((pcnext = pic16_findNextInstruction(pc) )) {
6887
6888         // Unlink the pCode label from it's pCode chain
6889         pic16_unlinkpCode(pc);
6890         PCI(pcnext)->cline = PCCS(pc);
6891         //fprintf(stderr, "merging CSRC\n");
6892         //genericPrint(stderr,pcnext);
6893       }
6894
6895     }
6896     pc = pcn;
6897   }
6898   pBlockRemoveUnusedLabels(pb);
6899
6900 }
6901
6902 /*-----------------------------------------------------------------*/
6903 /*-----------------------------------------------------------------*/
6904 static int OptimizepCode(char dbName)
6905 {
6906 #define MAX_PASSES 4
6907
6908   int matches = 0;
6909   int passes = 0;
6910   pBlock *pb;
6911
6912   if(!the_pFile)
6913     return 0;
6914
6915   DFPRINTF((stderr," Optimizing pCode\n"));
6916
6917   do {
6918     matches = 0;
6919     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6920       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6921         matches += OptimizepBlock(pb);
6922     }
6923   }
6924   while(matches && ++passes < MAX_PASSES);
6925
6926   return matches;
6927 }
6928
6929
6930
6931 const char *pic16_pCodeOpType(pCodeOp *pcop);
6932 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6933
6934
6935 /*-----------------------------------------------------------------*/
6936 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6937 /*-----------------------------------------------------------------*/
6938
6939 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6940 {
6941   pCodeOp *pcop=NULL;
6942
6943 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6944
6945   if(pc->name) {
6946         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6947   } else {
6948     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6949   }
6950
6951   assert(pcop != NULL);
6952
6953   if( !( (pcop->type == PO_LABEL) ||
6954          (pcop->type == PO_LITERAL) ||
6955          (pcop->type == PO_STR) ))
6956     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6957     PCOR(pcop)->r->wasUsed = 1;
6958     PCOR(pcop)->instance = PCOR(pc)->instance;
6959
6960   return pcop;
6961 }
6962
6963
6964 /*----------------------------------------------------------------------*
6965  * pic16_areRegsSame - check to see if the names of two registers match *
6966  *----------------------------------------------------------------------*/
6967 int pic16_areRegsSame(regs *r1, regs *r2)
6968 {
6969         if(!strcmp(r1->name, r2->name))return 1;
6970
6971   return 0;
6972 }
6973
6974
6975 /*-----------------------------------------------------------------*/
6976 /*-----------------------------------------------------------------*/
6977 static void pic16_FixRegisterBanking(pBlock *pb)
6978 {
6979   pCode *pc=NULL;
6980   pCode *pcprev=NULL;
6981   regs *reg, *prevreg;
6982   unsigned char flag=0;
6983   
6984         if(!pb)
6985                 return;
6986
6987         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6988         if(!pc)return;
6989
6990         /* loop through all of the flow blocks with in one pblock */
6991
6992 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6993
6994         prevreg = NULL;
6995         do {
6996                 /* at this point, pc should point to a PC_FLOW object */
6997                 /* for each flow block, determine the register banking 
6998                  * requirements */
6999
7000                 
7001                 /* if label, then might come from other point, force banksel */
7002                 if(isPCL(pc))prevreg = NULL;
7003                 
7004                 if(!isPCI(pc))goto loop;
7005
7006                 if(PCI(pc)->label)prevreg = NULL;
7007
7008                 if(PCI(pc)->is2MemOp)goto loop;
7009
7010                 /* if goto, then force banksel */
7011 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
7012        
7013                 reg = pic16_getRegFromInstruction(pc);
7014
7015 #if 0
7016                 pc->print(stderr, pc);
7017                 fprintf(stderr, "reg = %p\n", reg);
7018
7019                 if(reg) {
7020                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
7021                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
7022                                 reg->address,reg->isBitField, reg->isFixed);
7023                 }
7024 #endif
7025
7026                 /* now make some tests to make sure that instruction needs bank switch */
7027
7028                 /* if no register exists, and if not a bit opcode goto loop */
7029                 if(!reg) {
7030                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
7031                 }
7032                  
7033                 if(isPCI_SKIP(pc)) {
7034 //                      fprintf(stderr, "instruction is SKIP instruction\n");
7035 //                prevreg = NULL;
7036                 }
7037                 if(reg && isACCESS_BANK(reg))goto loop;
7038
7039                 if(!isBankInstruction(pc))goto loop;
7040
7041                 if(isPCI_LIT(pc))goto loop;
7042          
7043                 if(PCI(pc)->op == POC_CALL)goto loop;
7044
7045                 /* Examine the instruction before this one to make sure it is
7046                  * not a skip type instruction */
7047                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7048
7049                 flag = 0;               /* add before this instruction */
7050                 
7051                 /* if previous instruction is a skip one, then set flag
7052                  * to 2 and call insertBankSwitch */
7053                 if(pcprev && isPCI_SKIP(pcprev)) {
7054                   flag=2;       //goto loop
7055 //                prevreg = NULL;
7056                 }
7057                  
7058                 if(pic16_options.opt_banksel>0) {
7059                   char op1[128], op2[128];
7060                   
7061                     if(prevreg) {
7062                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7063                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7064                       if(!strcmp(op1, op2))goto loop;
7065                     }
7066                 }
7067                 prevreg = reg;
7068                 insertBankSwitch(flag, pc);
7069
7070 //              fprintf(stderr, "BANK SWITCH inserted\n");
7071                 
7072 loop:
7073                 pcprev = pc;
7074                 pc = pc->next;
7075         } while (pc);
7076 }
7077
7078 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7079
7080 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7081 int instrSize (pCode *pc)
7082 {
7083   if (!pc) return 0;
7084
7085   if (isPCAD(pc)) {
7086     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7087     return 4; // assumes only regular instructions using <= 4 bytes
7088   }
7089
7090   if (isPCI(pc)) return PCI(pc)->isize;
7091
7092   return 0;
7093 }
7094
7095 /* Returns 1 if pc is referenced by the given label (either
7096  * pc is the label itself or is an instruction with an attached
7097  * label).
7098  * Returns 0 if pc is not preceeded by the specified label.
7099  */
7100 int isLabel (pCode *pc, char *label)
7101 {
7102   if (!pc) return 0;
7103
7104   // label attached to the pCode?  
7105   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7106     pBranch *lab = NULL;
7107     lab = PCI(pc)->label;
7108
7109     while (lab) {
7110       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7111         return 1;
7112       }
7113       lab = lab->next;
7114     } // while
7115   } // if
7116
7117   // is inline assembly label?
7118   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7119     // do not compare trailing ':'
7120     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7121       return 1;
7122     }
7123   } // if
7124   
7125   // is pCodeLabel?
7126   if (isPCL(pc)) {
7127       if (strcmp(PCL(pc)->label,label) == 0) {
7128       return 1;
7129     }
7130   } // if
7131   
7132   // no label/no label attached/wrong label(s)
7133   return 0;
7134 }
7135
7136 /* Returns the distance to the given label in terms of words.
7137  * Labels are searched only within -max .. max words from pc.
7138  * Returns max if the label could not be found or
7139  * its distance from pc in (-max..+max).
7140  */
7141 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7142   int dist = instrSize(pc);
7143   pCode *curr = pc;
7144
7145   // search backwards
7146   while (dist < max && curr && !isLabel (curr, label)) {
7147     curr = curr->prev;
7148     dist += instrSize(curr); // sizeof (instruction)
7149   } // while
7150   if (curr && dist < max) {
7151     if (target != NULL) *target = curr;
7152     return -dist;
7153   }
7154
7155   dist = 0;
7156   curr = pic16_findNextInstruction (pc->next);
7157   //search forwards
7158   while (dist < max && curr && !isLabel (curr, label)) {
7159     dist += instrSize(curr); // sizeof (instruction)
7160     curr = curr->next;
7161   } // while
7162   if (curr && dist < max) {
7163     if (target != NULL) *target = curr;
7164     return dist;
7165   }
7166
7167   if (target != NULL) *target = NULL;
7168   return max;
7169 }
7170
7171 /* Returns -1 if pc does NOT denote an instruction like
7172  * BTFS[SC] STATUS,i
7173  * Otherwise we return 
7174  *   (a) 0x10 + i for BTFSS
7175  *   (b) 0x00 + i for BTFSC
7176  */
7177 int isSkipOnStatus (pCode *pc)
7178 {
7179   int res = -1;
7180   pCodeOp *pcop;
7181   if (!pc || !isPCI(pc)) return -1;
7182   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7183   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7184   else return -1;
7185
7186   pcop = PCI(pc)->pcop;
7187
7188   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7189     return res + ((pCodeOpRegBit *)pcop)->bit;
7190   }
7191
7192   return -1;
7193 }
7194
7195 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7196  * returns 0 otherwise. */
7197 int isConditionalBranch (pCode *pc)
7198 {
7199   if (!pc || !isPCI_BRANCH(pc)) return 0;
7200
7201   switch (PCI(pc)->op) {
7202   case POC_BC:
7203   case POC_BZ:
7204   case POC_BOV:
7205   case POC_BN:
7206   case POC_BNC:
7207   case POC_BNZ:
7208   case POC_BNOV:
7209   case POC_BNN:
7210     return 1;
7211
7212   default:
7213     break;
7214   } // switch
7215
7216   return 0;
7217 }
7218
7219 /* Returns 1 if pc has a label attached to it.
7220  * This can be either a label stored in the pCode itself (.label)
7221  * or a label making up its own pCode preceding this pc.
7222  * Returns 0 if pc cannot be reached directly via a label.
7223  */
7224 int hasNoLabel (pCode *pc)
7225 {
7226   pCode *prev;
7227   if (!pc) return 1;
7228
7229   // are there any label pCodes between pc and the previous instruction?
7230   prev = pic16_findPrevInstruction (pc->prev);
7231   while (pc && pc != prev) {
7232     // pCode with attached label?
7233     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7234         && PCI(pc)->label) {
7235       return 0;
7236     }
7237     // is inline assembly label?
7238     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7239     if (isPCW(pc) && PCW(pc)->label) return 0;
7240
7241     // pCodeLabel?
7242     if (isPCL(pc)) return 0;
7243
7244     pc = pc->prev;
7245   } // if
7246
7247   // no label found
7248   return 1;
7249 }
7250
7251 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7252   char buf[512];
7253   va_list va;
7254
7255   va_start (va, fmt);
7256   vsprintf (buf, fmt, va);
7257   va_end (va);
7258
7259   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7260 }
7261
7262 /* Replaces the old pCode with the new one, moving the labels,
7263  * C source line and probably flow information to the new pCode.
7264  */
7265 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7266   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7267     return;
7268
7269   /* first move all labels from old to new */
7270   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7271   PCI(oldPC)->label = NULL;
7272   
7273 #if 0
7274   /* move C source line (if possible) */
7275   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7276     PCI(newPC)->cline = PCI(oldPC)->cline;
7277 #endif
7278
7279   /* keep flow information intact */
7280   newPC->seq = oldPC->seq;
7281   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7282   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7283     PCI(newPC)->pcflow->end = newPC;
7284   }
7285
7286   /* insert a comment stating which pCode has been replaced */
7287 #if 1
7288   if (pic16_pcode_verbose || pic16_debug_verbose) {
7289     char pc_str[256];
7290     pic16_pCode2str (pc_str, 256, oldPC);
7291     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7292   }
7293 #endif
7294   
7295   /* insert new pCode into pBlock */
7296   pic16_pCodeInsertAfter (oldPC, newPC);
7297   pic16_unlinkpCode (oldPC);
7298   
7299   /* destruct replaced pCode */
7300   oldPC->destruct (oldPC);
7301 }
7302
7303 /* Returns the inverted conditional branch (if any) or NULL.
7304  * pcop must be set to the new jump target.
7305  */
7306 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7307 {
7308   pCode *newBcc;
7309
7310   if (!bcc || !isPCI(bcc)) return NULL;
7311
7312   switch (PCI(bcc)->op) {
7313   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7314   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7315   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7316   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7317   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7318   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7319   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7320   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7321   default:
7322     newBcc = NULL;
7323   }
7324   return newBcc;
7325 }
7326
7327 #define MAX_DIST_GOTO         0x7FFFFFFF
7328 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7329 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7330 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7331 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7332
7333 /* Follows GOTO/BRA instructions to their target instructions, stores the
7334  * final destination (not a GOTO or BRA instruction) in target and returns
7335  * the distance from the original pc to *target.
7336  */
7337 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7338         pCode *curr = pc;
7339         pCode *last = NULL;
7340         pCodeOp *lastPCOP = NULL;
7341         int dist = 0;
7342         int depth = 0;
7343
7344         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7345
7346         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7347         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7348                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7349                 last = curr;
7350                 lastPCOP = PCI(curr)->pcop;
7351                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7352                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7353         } // while
7354
7355         if (target) *target = last;
7356         if (pcop) *pcop = lastPCOP;
7357         return dist;
7358 }
7359
7360 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7361  * Otherwise the first pCode after the jumptable (after
7362  * the OPT_JUMPTABLE_END tag) is returned.
7363  */
7364 pCode *skipJumptables (pCode *pc, int *isJumptable)
7365 {
7366   *isJumptable = 0;
7367   if (!pc) return NULL;
7368   
7369   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7370     *isJumptable = 1;
7371     //fprintf (stderr, "SKIPPING jumptable\n");
7372     do {
7373       //pc->print(stderr, pc);
7374       pc = pc->next;
7375     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7376                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7377     //fprintf (stderr, "<<JUMPTAB:\n");
7378     // skip OPT_END as well
7379     if (pc) pc = pc->next;
7380   } // while
7381
7382   return pc;
7383 }
7384
7385 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7386 {
7387   int isJumptab;
7388   *isJumptable = 0;
7389   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7390     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7391     pc = skipJumptables (pc, &isJumptab);
7392     if (isJumptab) {
7393         // pc is the first pCode after the jumptable
7394         *isJumptable = 1;
7395     } else {
7396         // pc has not been changed by skipJumptables()
7397         pc = pc->next;
7398     }
7399   } // while
7400   
7401   return pc;
7402 }
7403
7404 /* Turn GOTOs into BRAs if distance between GOTO and label
7405  * is less than 1024 bytes.
7406  *
7407  * This method is especially useful if GOTOs after BTFS[SC]
7408  * can be turned into BRAs as GOTO would cost another NOP
7409  * if skipped.
7410  */
7411 void pic16_OptimizeJumps ()
7412 {
7413   pCode *pc;
7414   pCode *pc_prev = NULL;
7415   pCode *pc_next = NULL;
7416   pBlock *pb;
7417   pCode *target;
7418   int change, iteration, isJumptab;
7419   int isHandled = 0;
7420   char *label;
7421   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7422   
7423   if (!the_pFile) return;
7424   
7425   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7426   
7427   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7428     int matchedInvertRule = 1;
7429     iteration = 1;
7430     do {
7431       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7432       change = 0;
7433       pc = pic16_findNextInstruction (pb->pcHead);
7434     
7435       while (pc) {
7436         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7437         if (isJumptab) {
7438                 // skip jumptable, i.e. start over with no pc_prev!     
7439                 pc_prev = NULL;
7440                 pc = pc_next;
7441                 continue;
7442         } // if
7443
7444         /* (1) resolve chained jumps
7445          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7446          * (a) leave dead code in and
7447          * (b) skip over the dead code with an (unneccessary) jump.
7448          */
7449         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7450           pCodeOp *lastTargetOp = NULL;
7451           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7452           int maxDist = MAX_DIST_BCC;
7453           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7454           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7455           
7456           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7457           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7458               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7459             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7460             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7461             PCI(pc)->pcop->name = lastTargetOp->name;
7462             change++;
7463             opt_gotochain++;
7464           } // if
7465         } // if
7466
7467
7468         if (IS_GOTO(pc)) {
7469           int dist;
7470           int condBraType = isSkipOnStatus(pc_prev);
7471           label = PCI(pc)->pcop->name;
7472           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7473           if (dist < 0) dist = -dist;
7474           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7475           isHandled = 0;
7476           
7477           
7478           /* (2) remove "GOTO label; label:" */
7479           if (isLabel (pc_next, label)) {
7480             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7481             // first remove all preceeding SKIP instructions
7482             while (pc_prev && isPCI_SKIP(pc_prev)) {
7483               // attach labels on this instruction to pc_next
7484               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7485               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7486               PCI(pc_prev)->label = NULL;
7487               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7488               pic16_unlinkpCode (pc_prev);
7489               pc_prev = pic16_findPrevInstruction (pc);
7490             } // while
7491             // now remove the redundant goto itself
7492             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7493             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7494             pic16_unlinkpCode (pc);
7495             pc = pic16_findPrevInstruction(pc_next->prev);
7496             isHandled = 1; // do not perform further optimizations
7497             opt_gotonext++;
7498             change++;
7499           } // if
7500           
7501           
7502           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7503           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7504             if (dist < MAX_DIST_BCC) {
7505               pCode *bcc = NULL;
7506               switch (condBraType) {
7507               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7508                 // no BDC on DIGIT CARRY available
7509               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7510               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7511               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7512               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7513                 // no BNDC on DIGIT CARRY available
7514               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7515               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7516               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7517               default:
7518                 // no replacement possible
7519                 bcc = NULL;
7520                 break;
7521               } // switch
7522               if (bcc) {
7523                 // ATTENTION: keep labels attached to BTFSx!
7524                 // HINT: GOTO is label free (checked above)
7525                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7526                 isHandled = 1; // do not perform further optimizations
7527                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7528                 pic16_pCodeReplace (pc_prev, bcc);
7529                 pc->destruct(pc);
7530                 pc = bcc;
7531                 opt_cond++;
7532                 change++;
7533               } // if
7534             } else {
7535               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7536               cond_toofar++;
7537             } // if
7538           } // if
7539
7540           if (!isHandled) {
7541             // (4) eliminate the following (common) tripel:
7542             //           <pred.>;
7543             //  labels1: Bcc label2;
7544             //           GOTO somewhere;    ; <-- instruction referenced by pc
7545             //  label2:  <cont.>
7546             // and replace it by
7547             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7548             //  label2:  <cont.>
7549             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7550             //            to <cont.> instead
7551             // ATTENTION: This optimization is only valid if <pred.> is
7552             //            not a skip operation!
7553             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7554             // ATTENTION: no label may be attached to the GOTO instruction!
7555             if (isConditionalBranch(pc_prev)
7556                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7557                 && (dist < MAX_DIST_BCC)
7558                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7559                 && hasNoLabel(pc)) {
7560               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7561             
7562               if (newBcc) {
7563                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7564                 isHandled = 1; // do not perform further optimizations
7565                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7566                 pic16_pCodeReplace (pc_prev, newBcc);
7567                 pc->destruct(pc);
7568                 pc = newBcc;
7569                 opt_reorder++;
7570                 change++;
7571                 matchedInvertRule++;
7572               }
7573             }
7574           }
7575           
7576           /* (5) now just turn GOTO into BRA */ 
7577           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7578             if (dist < MAX_DIST_BRA) {
7579               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7580               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7581               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7582               pic16_pCodeReplace (pc, newBra);
7583               pc = newBra;
7584               opt++;
7585               change++;
7586             } else {
7587               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7588               toofar++;
7589             }
7590           } // if (!isHandled)
7591         } // if
7592
7593         pc_prev = pc;
7594         pc = pc_next;
7595       } // while (pc)
7596       
7597       pBlockRemoveUnusedLabels (pb);
7598       
7599       // This line enables goto chain resolution!
7600       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7601
7602       iteration++;
7603     } while (change); /* fixpoint iteration per pBlock */
7604   } // for (pb)
7605   
7606   // emit some statistics concerning goto-optimization
7607 #if 0
7608   if (pic16_debug_verbose || pic16_pcode_verbose) {
7609     fprintf (stderr, "optimize-goto:\n"
7610              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7611              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7612              "\t%5d conditional \"skipping\" jumps inverted\n"
7613              "\t%5d GOTOs to next instruction removed\n"
7614              "\t%5d chained GOTOs resolved\n",
7615              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7616   } // if
7617 #endif
7618   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7619 }
7620
7621 #undef IS_GOTO
7622 #undef MAX_JUMPCHAIN_DEPTH
7623 #undef MAX_DIST_GOTO
7624 #undef MAX_DIST_BRA
7625 #undef MAX_DIST_BCC
7626
7627 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7628
7629 static void pBlockDestruct(pBlock *pb)
7630 {
7631
7632   if(!pb)
7633     return;
7634
7635
7636 //  Safe_free(pb);
7637
7638 }
7639
7640 /*-----------------------------------------------------------------*/
7641 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7642 /*                                  name dbName and combine them   */
7643 /*                                  into one block                 */
7644 /*-----------------------------------------------------------------*/
7645 static void mergepBlocks(char dbName)
7646 {
7647
7648   pBlock *pb, *pbmerged = NULL,*pbn;
7649
7650   pb = the_pFile->pbHead;
7651
7652   //fprintf(stderr," merging blocks named %c\n",dbName);
7653   while(pb) {
7654
7655     pbn = pb->next;
7656     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7657     if( getpBlock_dbName(pb) == dbName) {
7658
7659       //fprintf(stderr," merged block %c\n",dbName);
7660
7661       if(!pbmerged) {
7662         pbmerged = pb;
7663       } else {
7664         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7665         /* pic16_addpCode2pBlock doesn't handle the tail: */
7666         pbmerged->pcTail = pb->pcTail;
7667
7668         pb->prev->next = pbn;
7669         if(pbn) 
7670           pbn->prev = pb->prev;
7671
7672
7673         pBlockDestruct(pb);
7674       }
7675       //pic16_printpBlock(stderr, pbmerged);
7676     } 
7677     pb = pbn;
7678   }
7679
7680 }
7681
7682 /*-----------------------------------------------------------------*/
7683 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7684 /*                                                                 */
7685 /* level 0 == minimal optimization                                 */
7686 /*   optimize registers that are used only by two instructions     */
7687 /* level 1 == maximal optimization                                 */
7688 /*   optimize by looking at pairs of instructions that use the     */
7689 /*   register.                                                     */
7690 /*-----------------------------------------------------------------*/
7691
7692 static void AnalyzeFlow(int level)
7693 {
7694   static int times_called=0;
7695   pBlock *pb;
7696
7697     if(!the_pFile) {
7698       /* remove unused allocated registers before exiting */
7699       pic16_RemoveUnusedRegisters();
7700       return;
7701     }
7702
7703
7704     /* if this is not the first time this function has been called,
7705      * then clean up old flow information */
7706     if(times_called++) {
7707       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7708         unBuildFlow(pb);
7709         pic16_RegsUnMapLiveRanges();
7710     }
7711     GpcFlowSeq = 1;
7712
7713     /* Phase 2 - Flow Analysis - Register Banking
7714      *
7715      * In this phase, the individual flow blocks are examined
7716      * and register banking is fixed.
7717      */
7718
7719 #if 0
7720     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7721       pic16_FixRegisterBanking(pb);
7722 #endif
7723
7724     /* Phase 2 - Flow Analysis
7725      *
7726      * In this phase, the pCode is partition into pCodeFlow 
7727      * blocks. The flow blocks mark the points where a continuous
7728      * stream of instructions changes flow (e.g. because of
7729      * a call or goto or whatever).
7730      */
7731
7732     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7733       pic16_BuildFlow(pb);
7734
7735
7736     /* Phase 2 - Flow Analysis - linking flow blocks
7737      *
7738      * In this phase, the individual flow blocks are examined
7739      * to determine their order of excution.
7740      */
7741
7742     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7743       LinkFlow(pb);
7744
7745 #if 1
7746         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7747                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7748                         pic16_createDF (pb);
7749 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7750                         pic16_vcg_dump_default (pb);
7751 #endif
7752                         //pic16_destructDF (pb);
7753                 }
7754
7755                 pic16_df_stats ();
7756                 if (0) releaseStack (); // releasing is costly...
7757         }
7758 #endif
7759
7760     /* Phase 3 - Flow Analysis - Flow Tree
7761      *
7762      * In this phase, the individual flow blocks are examined
7763      * to determine their order of execution.
7764      */
7765
7766     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7767       pic16_BuildFlowTree(pb);
7768
7769
7770     /* Phase x - Flow Analysis - Used Banks
7771      *
7772      * In this phase, the individual flow blocks are examined
7773      * to determine the Register Banks they use
7774      */
7775
7776 #if 0
7777     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7778       FixBankFlow(pb);
7779 #endif
7780
7781
7782     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7783       pic16_pCodeRegMapLiveRanges(pb);
7784
7785     pic16_RemoveUnusedRegisters();
7786     pic16_removeUnusedRegistersDF ();
7787
7788   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7789     pic16_pCodeRegOptimizeRegUsage(level);
7790
7791
7792 #if 0
7793     if(!options.nopeep)
7794       OptimizepCode('*');
7795 #endif
7796
7797 #if 0
7798     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7799       DumpFlow(pb);
7800 #endif
7801
7802     /* debug stuff */ 
7803     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7804       pCode *pcflow;
7805       
7806         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7807           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7808           pcflow = pcflow->next) {
7809             FillFlow(PCFL(pcflow));
7810         }
7811     }
7812
7813 #if 0
7814     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7815       pCode *pcflow;
7816
7817         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7818           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7819           pcflow = pcflow->next) {
7820             FlowStats(PCFL(pcflow));
7821         }
7822     }
7823 #endif
7824 }
7825
7826 /* VR -- no need to analyze banking in flow, but left here :
7827  *      1. because it may be used in the future for other purposes
7828  *      2. because if omitted we'll miss some optimization done here
7829  *
7830  * Perhaps I should rename it to something else
7831  */
7832
7833 /*-----------------------------------------------------------------*/
7834 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7835 /*                  assigned to the registers.                     */
7836 /*                                                                 */
7837 /*-----------------------------------------------------------------*/
7838
7839 void pic16_AnalyzeBanking(void)
7840 {
7841   pBlock  *pb;
7842
7843     /* Phase x - Flow Analysis - Used Banks
7844      *
7845      * In this phase, the individual flow blocks are examined
7846      * to determine the Register Banks they use
7847      */
7848
7849     AnalyzeFlow(0);
7850     AnalyzeFlow(1);
7851
7852     if(!options.nopeep)
7853       OptimizepCode('*');
7854
7855
7856     if(!the_pFile)return;
7857
7858     if(!pic16_options.no_banksel) {
7859       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7860 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7861         pic16_FixRegisterBanking(pb);
7862       }
7863     }
7864 }
7865
7866 /*-----------------------------------------------------------------*/
7867 /* buildCallTree - Look at the flow and extract all of the calls.  */
7868 /*-----------------------------------------------------------------*/
7869 static set *register_usage(pBlock *pb);
7870
7871 static void buildCallTree(void    )
7872 {
7873   pBranch *pbr;
7874   pBlock  *pb;
7875   pCode   *pc;
7876   regs *r;
7877   
7878   if(!the_pFile)
7879     return;
7880
7881
7882
7883   /* Now build the call tree.
7884      First we examine all of the pCodes for functions.
7885      Keep in mind that the function boundaries coincide
7886      with pBlock boundaries. 
7887
7888      The algorithm goes something like this:
7889      We have two nested loops. The outer loop iterates
7890      through all of the pBlocks/functions. The inner
7891      loop iterates through all of the pCodes for
7892      a given pBlock. When we begin iterating through
7893      a pBlock, the variable pc_fstart, pCode of the start
7894      of a function, is cleared. We then search for pCodes
7895      of type PC_FUNCTION. When one is encountered, we
7896      initialize pc_fstart to this and at the same time
7897      associate a new pBranch object that signifies a 
7898      branch entry. If a return is found, then this signifies
7899      a function exit point. We'll link the pCodes of these
7900      returns to the matching pc_fstart.
7901
7902      When we're done, a doubly linked list of pBranches
7903      will exist. The head of this list is stored in
7904      `the_pFile', which is the meta structure for all
7905      of the pCode. Look at the pic16_printCallTree function
7906      on how the pBranches are linked together.
7907
7908    */
7909   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7910     pCode *pc_fstart=NULL;
7911     for(pc = pb->pcHead; pc; pc = pc->next) {
7912
7913         if(isPCI(pc) && pc_fstart) {
7914                 if(PCI(pc)->is2MemOp) {
7915                         r = pic16_getRegFromInstruction2(pc);
7916                         if(r && !strcmp(r->name, "POSTDEC1"))
7917                                 PCF(pc_fstart)->stackusage++;
7918                 } else {
7919                         r = pic16_getRegFromInstruction(pc);
7920                         if(r && !strcmp(r->name, "PREINC1"))
7921                                 PCF(pc_fstart)->stackusage--;
7922                 }
7923         }
7924
7925       if(isPCF(pc)) {
7926         if (PCF(pc)->fname) {
7927         char buf[16];
7928
7929           sprintf(buf, "%smain", port->fun_prefix);
7930           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7931             //fprintf(stderr," found main \n");
7932             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7933             pb->dbName = 'M';
7934           }
7935
7936           pbr = Safe_calloc(1,sizeof(pBranch));
7937           pbr->pc = pc_fstart = pc;
7938           pbr->next = NULL;
7939
7940           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7941
7942           // Here's a better way of doing the same:
7943           addSet(&pb->function_entries, pc);
7944
7945         } else {
7946           // Found an exit point in a function, e.g. return
7947           // (Note, there may be more than one return per function)
7948           if(pc_fstart)
7949             pBranchLink(PCF(pc_fstart), PCF(pc));
7950
7951           addSet(&pb->function_exits, pc);
7952         }
7953       } else if(isCALL(pc)) {
7954         addSet(&pb->function_calls,pc);
7955       }
7956     }
7957   }
7958
7959
7960 #if 0
7961   /* This is not needed because currently all register used
7962    * by a function are stored in stack -- VR */
7963    
7964   /* Re-allocate the registers so that there are no collisions
7965    * between local variables when one function call another */
7966
7967   // this is weird...
7968   //  pic16_deallocateAllRegs();
7969
7970   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7971     if(!pb->visited)
7972       register_usage(pb);
7973   }
7974 #endif
7975
7976 }
7977
7978 /*-----------------------------------------------------------------*/
7979 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7980 /*                all of the logical connections.                  */
7981 /*                                                                 */
7982 /* Essentially what's done here is that the pCode flow is          */
7983 /* determined.                                                     */
7984 /*-----------------------------------------------------------------*/
7985
7986 void pic16_AnalyzepCode(char dbName)
7987 {
7988   pBlock *pb;
7989   int i,changes;
7990
7991   if(!the_pFile)
7992     return;
7993
7994   mergepBlocks('D');
7995
7996
7997   /* Phase 1 - Register allocation and peep hole optimization
7998    *
7999    * The first part of the analysis is to determine the registers
8000    * that are used in the pCode. Once that is done, the peep rules
8001    * are applied to the code. We continue to loop until no more
8002    * peep rule optimizations are found (or until we exceed the
8003    * MAX_PASSES threshold). 
8004    *
8005    * When done, the required registers will be determined.
8006    *
8007    */
8008   i = 0;
8009   do {
8010
8011     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
8012     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
8013
8014     /* First, merge the labels with the instructions */
8015     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8016       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
8017
8018         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
8019         //fprintf(stderr," analyze and merging block %c\n",dbName);
8020         pic16_pBlockMergeLabels(pb);
8021         AnalyzepBlock(pb);
8022       } else {
8023         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
8024       }
8025     }
8026
8027         if(!options.nopeep)
8028                 changes = OptimizepCode(dbName);
8029         else changes = 0;
8030
8031   } while(changes && (i++ < MAX_PASSES));
8032
8033   
8034   buildCallTree();
8035 }
8036
8037
8038 /* convert a series of movff's of local regs to stack, with a single call to
8039  * a support functions which does the same thing via loop */
8040 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8041 {
8042   pBranch *pbr;
8043   pCode *pc, *pct;
8044   char *fname[]={"__lr_store", "__lr_restore"};
8045
8046 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8047
8048     pct = pic16_findNextInstruction(pcstart->next);
8049     do {
8050       pc = pct;
8051       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8052 //      pc->print(stderr, pc);
8053       if(isPCI(pc) && PCI(pc)->label) {
8054         pbr = PCI(pc)->label;
8055         while(pbr && pbr->pc) {
8056           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8057           pbr = pbr->next;
8058         }
8059
8060 //        pc->print(stderr, pc);
8061         /* unlink pCode */
8062         pc->prev->next = pct;
8063         pct->prev = pc->prev;
8064 //        pc->next = NULL;
8065 //        pc->prev = NULL;
8066       }
8067     } while ((pc) && (pc != pcend));
8068
8069     /* unlink movff instructions */
8070     pcstart->next = pcend;
8071     pcend->prev = pcstart;
8072
8073     pc = pcstart;
8074 //    if(!entry) {
8075 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8076 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8077 //    }
8078                 
8079     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8080     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8081     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8082
8083 //    if(!entry) {
8084 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8085 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8086 //    }
8087
8088     
8089     {
8090       symbol *sym;
8091
8092         sym = newSymbol( fname[ entry?0:1 ], 0 );
8093         strcpy(sym->rname, fname[ entry?0:1 ]);
8094         checkAddSym(&externs, sym);
8095         
8096 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8097     }
8098
8099 }
8100
8101 /*-----------------------------------------------------------------*/
8102 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8103 /*    local registers to a support function call                   */
8104 /*-----------------------------------------------------------------*/
8105 void pic16_OptimizeLocalRegs(void)
8106 {
8107   pBlock  *pb;
8108   pCode   *pc;
8109   pCodeInfo *pci;
8110   pCodeOpLocalReg *pclr;
8111   int regCount=0;
8112   int inRegCount=0;
8113   regs *r, *lastr=NULL, *firstr=NULL;
8114   pCode *pcstart=NULL, *pcend=NULL;
8115   int inEntry=0;
8116   char *curFunc=NULL;
8117
8118         /* Overview:
8119          *   local_regs begin mark
8120          *      MOVFF r0x01, POSTDEC1
8121          *      MOVFF r0x02, POSTDEC1
8122          *      ...
8123          *      ...
8124          *      MOVFF r0x0n, POSTDEC1
8125          *   local_regs end mark
8126          *
8127          * convert the above to the below:
8128          *      MOVLW   starting_register_index
8129          *      MOVWF   PRODL
8130          *      MOVLW   register_count
8131          *      call    __save_registers_in_stack
8132          */
8133
8134     if(!the_pFile)
8135       return;
8136
8137     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8138       inRegCount = regCount = 0;
8139       firstr = lastr = NULL;
8140       for(pc = pb->pcHead; pc; pc = pc->next) {
8141
8142         /* hold current function name */
8143         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8144         
8145         if(pc && (pc->type == PC_INFO)) {
8146           pci = PCINF(pc);
8147
8148           if(pci->type == INF_LOCALREGS) {
8149             pclr = PCOLR(pci->oper1);
8150             
8151             if((pclr->type == LR_ENTRY_BEGIN)
8152               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8153             else inEntry = 0;
8154             
8155             switch(pclr->type) {
8156               case LR_ENTRY_BEGIN:
8157               case LR_EXIT_BEGIN:
8158                         inRegCount = 1; regCount = 0;
8159                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8160                         firstr = lastr = NULL;
8161                         break;
8162               
8163               case LR_ENTRY_END:
8164               case LR_EXIT_END:
8165                         inRegCount = -1;
8166                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8167
8168 #if 1
8169                         if(curFunc && inWparamList(curFunc+1)) {
8170                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8171                                         filename, curFunc);
8172                         } else {
8173                           if(regCount>2) {
8174                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8175                               firstr, inEntry);
8176                           }
8177                         }
8178 #endif
8179                         firstr = lastr = NULL;
8180                         break;
8181             }
8182             
8183             if(inRegCount == -1) {
8184 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8185               regCount = 0;
8186               inRegCount = 0;
8187             }
8188           }
8189         } else {
8190           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8191             if(inEntry)
8192               r = pic16_getRegFromInstruction(pc);
8193             else
8194               r = pic16_getRegFromInstruction2(pc);
8195             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8196               if(!firstr)firstr = r;
8197               regCount++;
8198 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8199             }
8200           }
8201         }
8202       }
8203     }
8204 }
8205               
8206             
8207
8208
8209
8210 /*-----------------------------------------------------------------*/
8211 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8212 /*                   function                                      */
8213 /*-----------------------------------------------------------------*/
8214 static bool ispCodeFunction(pCode *pc)
8215 {
8216
8217   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8218     return 1;
8219
8220   return 0;
8221 }
8222
8223 /*-----------------------------------------------------------------*/
8224 /* findFunction - Search for a function by name (given the name)   */
8225 /*                in the set of all functions that are in a pBlock */
8226 /* (note - I expect this to change because I'm planning to limit   */
8227 /*  pBlock's to just one function declaration                      */
8228 /*-----------------------------------------------------------------*/
8229 static pCode *findFunction(char *fname)
8230 {
8231   pBlock *pb;
8232   pCode *pc;
8233   if(!fname)
8234     return NULL;
8235
8236   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8237
8238     pc = setFirstItem(pb->function_entries);
8239     while(pc) {
8240     
8241       if((pc->type == PC_FUNCTION) &&
8242          (PCF(pc)->fname) && 
8243          (strcmp(fname, PCF(pc)->fname)==0))
8244         return pc;
8245
8246       pc = setNextItem(pb->function_entries);
8247
8248     }
8249
8250   }
8251   return NULL;
8252 }
8253
8254 static void MarkUsedRegisters(set *regset)
8255 {
8256
8257   regs *r1,*r2;
8258
8259   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8260 //      fprintf(stderr, "marking register = %s\t", r1->name);
8261     r2 = pic16_regWithIdx(r1->rIdx);
8262 //      fprintf(stderr, "to register = %s\n", r2->name);
8263     r2->isFree = 0;
8264     r2->wasUsed = 1;
8265   }
8266 }
8267
8268 static void pBlockStats(FILE *of, pBlock *pb)
8269 {
8270
8271   pCode *pc;
8272   regs  *r;
8273
8274         if(!pic16_pcode_verbose)return;
8275         
8276   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8277
8278   // for now just print the first element of each set
8279   pc = setFirstItem(pb->function_entries);
8280   if(pc) {
8281     fprintf(of,";entry:  ");
8282     pc->print(of,pc);
8283   }
8284   pc = setFirstItem(pb->function_exits);
8285   if(pc) {
8286     fprintf(of,";has an exit\n");
8287     //pc->print(of,pc);
8288   }
8289
8290   pc = setFirstItem(pb->function_calls);
8291   if(pc) {
8292     fprintf(of,";functions called:\n");
8293
8294     while(pc) {
8295       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8296         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8297       }
8298       pc = setNextItem(pb->function_calls);
8299     }
8300   }
8301
8302   r = setFirstItem(pb->tregisters);
8303   if(r) {
8304     int n = elementsInSet(pb->tregisters);
8305
8306     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8307
8308     while (r) {
8309       fprintf(of,   ";   %s\n",r->name);
8310       r = setNextItem(pb->tregisters);
8311     }
8312   }
8313   
8314   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8315 }
8316
8317 /*-----------------------------------------------------------------*/
8318 /*-----------------------------------------------------------------*/
8319 #if 0
8320 static void sequencepCode(void)
8321 {
8322   pBlock *pb;
8323   pCode *pc;
8324
8325
8326   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8327
8328     pb->seq = GpCodeSequenceNumber+1;
8329
8330     for( pc = pb->pcHead; pc; pc = pc->next)
8331       pc->seq = ++GpCodeSequenceNumber;
8332   }
8333
8334 }
8335 #endif
8336
8337 /*-----------------------------------------------------------------*/
8338 /*-----------------------------------------------------------------*/
8339 static set *register_usage(pBlock *pb)
8340 {
8341   pCode *pc,*pcn;
8342   set *registers=NULL;
8343   set *registersInCallPath = NULL;
8344
8345   /* check recursion */
8346
8347   pc = setFirstItem(pb->function_entries);
8348
8349   if(!pc)
8350     return registers;
8351
8352   pb->visited = 1;
8353
8354   if(pc->type != PC_FUNCTION)
8355     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8356
8357   pc = setFirstItem(pb->function_calls);
8358   for( ; pc; pc = setNextItem(pb->function_calls)) {
8359
8360     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8361       char *dest = pic16_get_op_from_instruction(PCI(pc));
8362
8363       pcn = findFunction(dest);
8364       if(pcn) 
8365         registersInCallPath = register_usage(pcn->pb);
8366     } else
8367       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8368
8369   }
8370
8371 #ifdef PCODE_DEBUG
8372   pBlockStats(stderr,pb);  // debug
8373 #endif
8374
8375   // Mark the registers in this block as used.
8376
8377   MarkUsedRegisters(pb->tregisters);
8378   if(registersInCallPath) {
8379     /* registers were used in the functions this pBlock has called */
8380     /* so now, we need to see if these collide with the ones we are */
8381     /* using here */
8382
8383     regs *r1,*r2, *newreg;
8384
8385     DFPRINTF((stderr,"comparing registers\n"));
8386
8387     r1 = setFirstItem(registersInCallPath);
8388     while(r1) {
8389
8390       r2 = setFirstItem(pb->tregisters);
8391
8392       while(r2 && (r1->type != REG_STK)) {
8393
8394         if(r2->rIdx == r1->rIdx) {
8395           newreg = pic16_findFreeReg(REG_GPR);
8396
8397
8398           if(!newreg) {
8399             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8400             exit(1);
8401           }
8402
8403           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8404                   r1->rIdx, newreg->rIdx));
8405           r2->rIdx = newreg->rIdx;
8406           //if(r2->name) Safe_free(r2->name);
8407           if(newreg->name)
8408             r2->name = Safe_strdup(newreg->name);
8409           else
8410             r2->name = NULL;
8411           newreg->isFree = 0;
8412           newreg->wasUsed = 1;
8413         }
8414         r2 = setNextItem(pb->tregisters);
8415       }
8416
8417       r1 = setNextItem(registersInCallPath);
8418     }
8419
8420     /* Collisions have been resolved. Now free the registers in the call path */
8421     r1 = setFirstItem(registersInCallPath);
8422     while(r1) {
8423       if(r1->type != REG_STK) {
8424         newreg = pic16_regWithIdx(r1->rIdx);
8425         newreg->isFree = 1;
8426       }
8427       r1 = setNextItem(registersInCallPath);
8428     }
8429
8430   }// else
8431   //    MarkUsedRegisters(pb->registers);
8432
8433   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8434 #ifdef PCODE_DEBUG
8435   if(registers) 
8436     DFPRINTF((stderr,"returning regs\n"));
8437   else
8438     DFPRINTF((stderr,"not returning regs\n"));
8439
8440   DFPRINTF((stderr,"pBlock after register optim.\n"));
8441   pBlockStats(stderr,pb);  // debug
8442 #endif
8443
8444   return registers;
8445 }
8446
8447 /*-----------------------------------------------------------------*/
8448 /* pct2 - writes the call tree to a file                           */
8449 /*                                                                 */
8450 /*-----------------------------------------------------------------*/
8451 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8452 {
8453   pCode *pc,*pcn;
8454   int i;
8455   //  set *registersInCallPath = NULL;
8456
8457   if(!of)
8458     return;
8459
8460   if(indent > 10) {
8461         fprintf(of, "recursive function\n");
8462     return; //recursion ?
8463   }
8464
8465   pc = setFirstItem(pb->function_entries);
8466
8467   if(!pc)
8468     return;
8469
8470   pb->visited = 0;
8471
8472   for(i=0;i<indent;i++)   // Indentation
8473         fputs("+   ", of);
8474   fputs("+- ", of);
8475
8476   if(pc->type == PC_FUNCTION) {
8477     usedstack += PCF(pc)->stackusage;
8478     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8479   } else return;  // ???
8480
8481
8482   pc = setFirstItem(pb->function_calls);
8483   for( ; pc; pc = setNextItem(pb->function_calls)) {
8484
8485     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8486       char *dest = pic16_get_op_from_instruction(PCI(pc));
8487
8488       pcn = findFunction(dest);
8489       if(pcn) 
8490         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8491     } else
8492       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8493
8494   }
8495
8496
8497 }
8498
8499
8500 /*-----------------------------------------------------------------*/
8501 /* pic16_printCallTree - writes the call tree to a file                  */
8502 /*                                                                 */
8503 /*-----------------------------------------------------------------*/
8504
8505 void pic16_printCallTree(FILE *of)
8506 {
8507   pBranch *pbr;
8508   pBlock  *pb;
8509   pCode   *pc;
8510
8511   if(!the_pFile)
8512     return;
8513
8514   if(!of)
8515     of = stderr;
8516
8517   fprintf(of, "\npBlock statistics\n");
8518   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8519     pBlockStats(of,pb);
8520
8521
8522   fprintf(of,"Call Tree\n");
8523   pbr = the_pFile->functions;
8524   while(pbr) {
8525     if(pbr->pc) {
8526       pc = pbr->pc;
8527       if(!ispCodeFunction(pc))
8528         fprintf(of,"bug in call tree");
8529
8530
8531       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8532
8533       while(pc->next && !ispCodeFunction(pc->next)) {
8534         pc = pc->next;
8535         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8536           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8537       }
8538     }
8539
8540     pbr = pbr->next;
8541   }
8542
8543
8544   fprintf(of,"\n**************\n\na better call tree\n");
8545   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8546 //    if(pb->visited)
8547       pct2(of,pb,0,0);
8548   }
8549
8550   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8551     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8552   }
8553 }
8554
8555
8556
8557 /*-----------------------------------------------------------------*/
8558 /*                                                                 */
8559 /*-----------------------------------------------------------------*/
8560
8561 static void InlineFunction(pBlock *pb)
8562 {
8563   pCode *pc;
8564   pCode *pc_call;
8565
8566   if(!pb)
8567     return;
8568
8569   pc = setFirstItem(pb->function_calls);
8570
8571   for( ; pc; pc = setNextItem(pb->function_calls)) {
8572
8573     if(isCALL(pc)) {
8574       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8575       pCode *pct;
8576       pCode *pce;
8577
8578       pBranch *pbr;
8579
8580       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8581         
8582         //fprintf(stderr,"Cool can inline:\n");
8583         //pcn->print(stderr,pcn);
8584
8585         //fprintf(stderr,"recursive call Inline\n");
8586         InlineFunction(pcn->pb);
8587         //fprintf(stderr,"return from recursive call Inline\n");
8588
8589         /*
8590           At this point, *pc points to a CALL mnemonic, and
8591           *pcn points to the function that is being called.
8592
8593           To in-line this call, we need to remove the CALL
8594           and RETURN(s), and link the function pCode in with
8595           the CALLee pCode.
8596
8597         */
8598
8599
8600         /* Remove the CALL */
8601         pc_call = pc;
8602         pc = pc->prev;
8603
8604         /* remove callee pBlock from the pBlock linked list */
8605         removepBlock(pcn->pb);
8606
8607         pce = pcn;
8608         while(pce) {
8609           pce->pb = pb;
8610           pce = pce->next;
8611         }
8612
8613         /* Remove the Function pCode */
8614         pct = pic16_findNextInstruction(pcn->next);
8615
8616         /* Link the function with the callee */
8617         pc->next = pcn->next;
8618         pcn->next->prev = pc;
8619         
8620         /* Convert the function name into a label */
8621
8622         pbr = Safe_calloc(1,sizeof(pBranch));
8623         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8624         pbr->next = NULL;
8625         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8626         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8627
8628         /* turn all of the return's except the last into goto's */
8629         /* check case for 2 instruction pBlocks */
8630         pce = pic16_findNextInstruction(pcn->next);
8631         while(pce) {
8632           pCode *pce_next = pic16_findNextInstruction(pce->next);
8633
8634           if(pce_next == NULL) {
8635             /* found the last return */
8636             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8637
8638             //fprintf(stderr,"found last return\n");
8639             //pce->print(stderr,pce);
8640             pce->prev->next = pc_call->next;
8641             pc_call->next->prev = pce->prev;
8642             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8643                                                       PCI(pce)->label);
8644           }
8645
8646           pce = pce_next;
8647         }
8648
8649
8650       }
8651     } else
8652       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8653
8654   }
8655
8656 }
8657
8658 /*-----------------------------------------------------------------*/
8659 /*                                                                 */
8660 /*-----------------------------------------------------------------*/
8661
8662 void pic16_InlinepCode(void)
8663 {
8664
8665   pBlock  *pb;
8666   pCode   *pc;
8667
8668   if(!the_pFile)
8669     return;
8670
8671   if(!functionInlining)
8672     return;
8673
8674   /* Loop through all of the function definitions and count the
8675    * number of times each one is called */
8676   //fprintf(stderr,"inlining %d\n",__LINE__);
8677
8678   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8679
8680     pc = setFirstItem(pb->function_calls);
8681
8682     for( ; pc; pc = setNextItem(pb->function_calls)) {
8683
8684       if(isCALL(pc)) {
8685         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8686         if(pcn && isPCF(pcn)) {
8687           PCF(pcn)->ncalled++;
8688         }
8689       } else
8690         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8691
8692     }
8693   }
8694
8695   //fprintf(stderr,"inlining %d\n",__LINE__);
8696
8697   /* Now, Loop through the function definitions again, but this
8698    * time inline those functions that have only been called once. */
8699   
8700   InlineFunction(the_pFile->pbHead);
8701   //fprintf(stderr,"inlining %d\n",__LINE__);
8702
8703   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8704     unBuildFlow(pb);
8705
8706 }
8707
8708 char *pic_optype_names[]={
8709         "PO_NONE",         // No operand e.g. NOP
8710         "PO_W",              // The working register (as a destination)
8711         "PO_WREG",           // The working register (as a file register)
8712         "PO_STATUS",         // The 'STATUS' register
8713         "PO_BSR",            // The 'BSR' register
8714         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8715                              // of three)
8716         "PO_INDF0",          // The Indirect register
8717         "PO_INTCON",         // Interrupt Control register
8718         "PO_GPR_REGISTER",   // A general purpose register
8719         "PO_GPR_BIT",        // A bit of a general purpose register
8720         "PO_GPR_TEMP",       // A general purpose temporary register
8721         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8722         "PO_PCL",            // Program counter Low register
8723         "PO_PCLATH",         // Program counter Latch high register
8724         "PO_PCLATU",         // Program counter Latch upper register
8725         "PO_PRODL",          // Product Register Low
8726         "PO_PRODH",          // Product Register High
8727         "PO_LITERAL",        // A constant
8728         "PO_REL_ADDR",       // A relative address
8729         "PO_IMMEDIATE",      //  (8051 legacy)
8730         "PO_DIR",            // Direct memory (8051 legacy)
8731         "PO_CRY",            // bit memory (8051 legacy)
8732         "PO_BIT",            // bit operand.
8733         "PO_STR",            //  (8051 legacy)
8734         "PO_LABEL",
8735         "PO_WILD"            // Wild card operand in peep optimizer
8736 };
8737
8738
8739 char *dumpPicOptype(PIC_OPTYPE type)
8740 {
8741         return (pic_optype_names[ type ]);
8742 }
8743
8744
8745 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8746 #include "graph.h"
8747
8748 #define MAX_COMMON_BANK_SIZE    32
8749 #define FIRST_PSEUDO_BANK_NR  1000
8750
8751 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8752 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8753 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8754 Graph *adj = NULL;
8755
8756 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8757
8758 typedef struct {
8759   pseudoBankNr bank;  // number assigned to this pseudoBank
8760   unsigned int size;  // number of operands assigned to this bank
8761   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8762 } pseudoBank;
8763
8764 /*----------------------------------------------------------------------*/
8765 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8766 /*----------------------------------------------------------------------*/
8767 unsigned int hashSymbol (const char *str)
8768 {
8769   unsigned int res = 0;
8770   if (!str) return 0;
8771
8772   while (*str) {
8773     res ^= (*str);
8774     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8775     str++;
8776   } // while
8777
8778   return res;
8779 }
8780
8781 /*-----------------------------------------------------------------------*/
8782 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8783 /*-----------------------------------------------------------------------*/
8784 int compareSymbol (const void *sym1, const void *sym2)
8785 {
8786   char *s1 = (char*) sym1;
8787   char *s2 = (char*) sym2;
8788   
8789   return (strcmp (s1,s2) == 0);
8790 }
8791
8792 /*-----------------------------------------------------------------------*/
8793 /* comparePre - return 1 iff p1 == p2                                    */
8794 /*-----------------------------------------------------------------------*/
8795 int comparePtr (const void *p1, const void *p2)
8796 {
8797   return (p1 == p2);
8798 }
8799
8800 /*----------------------------------------------------------*/
8801 /* getSymbolFromOperand - return a pointer to the symbol in */
8802 /*                        the given operand and its length  */
8803 /*----------------------------------------------------------*/
8804 char *getSymbolFromOperand (char *op, unsigned int *len)
8805 {
8806   char *sym, *curr;
8807   *len = 0;
8808
8809   if (!op) return NULL;
8810
8811   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8812   sym = op;
8813   if (*sym == '(') sym++;
8814
8815   curr = sym;
8816   while (((*curr >= 'A') && (*curr <= 'Z'))
8817          || ((*curr >= 'a') && (*curr <= 'z'))
8818          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8819          || (*curr == '_')) {
8820     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8821     curr++;
8822     (*len)++;
8823   } // while
8824
8825   return sym;
8826 }
8827
8828 /*--------------------------------------------------------------------------*/
8829 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8830 /*--------------------------------------------------------------------------*/
8831 char *getSymFromBank (pseudoBankNr bank)
8832 {
8833   assert (bank2sym);
8834
8835   if (bank < 0) return "<INVALID BANK NR>";
8836   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8837 }
8838
8839 /*-----------------------------------------------------------------------*/
8840 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8841 /*                           bank number (uses hTab sym2bank), if the    */
8842 /*                           symbol is not yet assigned a pseudo bank it */
8843 /*                           is assigned one here                        */
8844 /*-----------------------------------------------------------------------*/
8845 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8846 {
8847   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8848   pseudoBankNr bank;
8849   unsigned int hash;
8850
8851   assert (sym2bank);
8852
8853   hash = hashSymbol (op) % sym2bank->size;
8854   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8855   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8856
8857   if (bank == UNKNOWN_BANK) {
8858     // create a pseudo bank for the operand
8859     bank = next_bank++;
8860     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8861     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8862     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8863     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8864   } else {
8865     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8866   } // if
8867
8868   assert (bank >= 0);
8869
8870   return bank;
8871 }
8872
8873 /*--------------------------------------------------------------------*/
8874 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8875 /*--------------------------------------------------------------------*/
8876 int isBanksel (pCode *pc)
8877 {
8878   if (!pc) return 0;
8879
8880   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8881     // BANKSEL <variablename>  or  MOVLB <banknr>
8882     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8883     return 1;
8884   }
8885
8886   // check for inline assembler BANKSELs
8887   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8888                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8889     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8890     return 1;
8891   }
8892
8893   // assume pc is no BANKSEL instruction
8894   return 0;
8895 }
8896
8897 /*---------------------------------------------------------------------------------*/
8898 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8899 /*                  This method can not guarantee to find all modifications of the */
8900 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8901 /*                  generated plus some cases.                                     */
8902 /*---------------------------------------------------------------------------------*/
8903 int invalidatesBSR(pCode *pc)
8904 {
8905   // assembler directives invalidate BSR (well, they might, we don't know)
8906   if (isPCAD(pc)) return 1;
8907
8908   // only ASMDIRs and pCodeInstructions can invalidate BSR
8909   if (!isPCI(pc)) return 0;
8910
8911   // we have a pCodeInstruction
8912
8913   // check for BSR modifying instructions
8914   switch (PCI(pc)->op) {
8915   case POC_CALL:
8916   case POC_RCALL:
8917   case POC_MOVLB:
8918   case POC_RETFIE:  // might be used as CALL replacement
8919   case POC_RETLW:   // might be used as CALL replacement
8920   case POC_RETURN:  // might be used as CALL replacement
8921   case POC_BANKSEL:
8922     return 1;
8923     break;
8924
8925   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8926     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8927     break;
8928   } // switch
8929
8930   // no change of BSR possible/probable
8931   return 0;
8932 }
8933
8934 /*------------------------------------------------------------*/
8935 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8936 /*                      the symbol referenced in this BANKSEL */
8937 /*------------------------------------------------------------*/
8938 pseudoBankNr getBankFromBanksel (pCode *pc)
8939 {
8940   char *sym;
8941   int data = (int)NULL;
8942
8943   if (!pc) return INVALID_BANK;
8944   
8945   if (isPCAD(pc) && PCAD(pc)->directive) {
8946     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8947       // get symbolname from PCAD(pc)->arg
8948       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8949       sym = PCAD(pc)->arg;
8950       data = getPseudoBankNrFromOperand (sym);
8951       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8952     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8953       // get (literal) bank number from PCAD(pc)->arg
8954       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8955       assert (0 && "not yet implemented - turn off banksel optimization for now");
8956     }
8957   } else if (isPCI(pc)) {
8958     if (PCI(pc)->op == POC_BANKSEL) {
8959       // get symbolname from PCI(pc)->pcop->name (?)
8960       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8961       sym = PCI(pc)->pcop->name;
8962       data = getPseudoBankNrFromOperand (sym);
8963       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8964     } else if (PCI(pc)->op == POC_MOVLB) {
8965       // get (literal) bank number from PCI(pc)->pcop->name
8966       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8967       assert (0 && "not yet implemented - turn off banksel optimization for now");
8968     }
8969   }
8970   
8971   if (data == 0)
8972     // no assigned bank could be found
8973     return UNKNOWN_BANK;
8974   else
8975     return data;
8976 }
8977
8978 /*------------------------------------------------------------------------------*/
8979 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8980 /*------------------------------------------------------------------------------*/
8981 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8982 {
8983   pseudoBank *data;
8984
8985   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8986
8987   do {
8988     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8989     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8990     if (data) {
8991       if (data->bank != bank)
8992         bank = data->bank;
8993       else
8994         data = NULL;
8995     }
8996   } while (data);
8997   
8998   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8999   return bank;
9000 }
9001
9002 /*------------------------------------------------------------------*/
9003 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
9004 /*                        bank is selected at a given pCode         */
9005 /*------------------------------------------------------------------*/
9006
9007 /* Create a graph with pseudo banks as its nodes and switches between
9008  * these as edges (with the edge weight representing the absolute
9009  * number of BANKSELs from one to the other).
9010  * Removes redundand BANKSELs instead iff mod == 1.
9011  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
9012  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
9013  * pseudo BSR.
9014  * TODO: check ALL instructions operands if they modify BSR directly...
9015  *
9016  * pb - the pBlock to annotate
9017  * mod  - select either graph creation (0) or BANKSEL removal (1)
9018  */
9019 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
9020 {
9021   pCode *pc, *pc_next;
9022   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
9023   int isBankselect = 0;
9024   unsigned int banksels=0;
9025   
9026   if (!pb) return 0;
9027
9028   pc = pic16_findNextInstruction(pb->pcHead);
9029   while (pc) {
9030     isBankselect = isBanksel (pc);
9031     pc_next = pic16_findNextInstruction (pc->next);
9032
9033     if (!hasNoLabel (pc)) {
9034       // we don't know our predecessors -- assume different BSRs
9035       prevBSR = UNKNOWN_BANK;
9036       pseudoBSR = UNKNOWN_BANK;
9037       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9038     } // if
9039
9040     // check if this is a BANKSEL instruction
9041     if (isBankselect) {
9042       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9043       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9044       if (mod) {
9045         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9046           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9047           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9048           pic16_unlinkpCode (pc);
9049           banksels++;
9050         }
9051       } else {
9052         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9053         banksels++;
9054       }
9055     } // if
9056
9057     if (!isBankselect && invalidatesBSR(pc)) {
9058       // check if this instruction invalidates the pseudoBSR
9059       pseudoBSR = UNKNOWN_BANK;
9060       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9061     } // if
9062
9063     prevBSR = pseudoBSR;
9064     pc = pc_next;
9065   } // while
9066
9067   return banksels;
9068 }
9069
9070 /*------------------------------------------------------------------------------------*/
9071 /* assignToSameBank - returns 0 on success or an error code                           */
9072 /*  1 - common bank would be too large                                                */
9073 /*  2 - assignment to fixed (absolute) bank not performed                             */
9074 /*                                                                                    */
9075 /* This functions assumes that unsplittable operands are already assigned to the same */
9076 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9077 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9078 /* TODO: Symbols with an abslute address must be handled specially!                   */
9079 /*------------------------------------------------------------------------------------*/
9080 int assignToSameBank (int bank0, int bank1, int doAbs)
9081 {
9082   int eff0, eff1, dummy;
9083   pseudoBank *pbank0, *pbank1;
9084   hashtItem *hitem;
9085
9086   eff0 = getEffectiveBank (bank0);
9087   eff1 = getEffectiveBank (bank1);
9088
9089   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9090
9091   // nothing to do if already same bank
9092   if (eff0 == eff1) return 0;
9093
9094   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9095     return 2;
9096
9097   // ensure eff0 < eff1
9098   if (eff0 > eff1) {
9099     // swap eff0 and eff1
9100     dummy = eff0;
9101     eff0 = eff1;
9102     eff1 = dummy;
9103     dummy = bank0;
9104     bank0 = bank1;
9105     bank1 = dummy;
9106   } // if
9107
9108   // now assign bank eff1 to bank eff0
9109   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9110   if (!pbank0) {
9111     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9112     pbank0->bank = eff0;
9113     pbank0->size = 1;
9114     pbank0->ref = 1;
9115     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9116   } // if
9117
9118   pbank1 = NULL;
9119   hitem = hTabSearch (coerce, eff1 % coerce->size);
9120   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9121     hitem = hitem->next;
9122
9123   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9124
9125 #if 0
9126   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9127            pbank0->bank, pbank0->size,
9128            getSymFromBank (eff0), getSymFromBank (eff1));
9129 #endif
9130
9131   if (pbank1) {
9132     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9133 #if 0
9134       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9135                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9136                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9137                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9138 #endif
9139       return 1;
9140     } // if
9141     pbank0->size += pbank1->size;
9142     pbank1->ref--;
9143     if (pbank1->ref == 0) Safe_free (pbank1);
9144   } else {
9145     pbank0->size++;
9146   } // if
9147
9148   if (hitem)
9149     hitem->item = pbank0;
9150   else  
9151     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9152   pbank0->ref++;
9153
9154   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9155
9156   return 0;
9157 }
9158
9159 /*----------------------------------------------------------------*/
9160 /* mergeGraphNodes - combines two nodes into one and modifies all */
9161 /*                   edges to and from the nodes accordingly      */
9162 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9163 /* then also (B,A) must be an edge (possibly with weight 0).      */
9164 /*----------------------------------------------------------------*/
9165 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9166 {
9167   GraphEdge *edge, *backedge, *nextedge;
9168   GraphNode *node;
9169   int backweight;
9170
9171   assert (node1 && node2);
9172   assert (node1 != node2);
9173   
9174   // add all edges starting at node2 to node1
9175   edge = node2->edge;
9176   while (edge) {
9177     nextedge = edge->next;
9178     node = edge->node;
9179     backedge = getGEdge (node, node2);
9180     if (backedge)
9181       backweight = backedge->weight;
9182     else
9183       backweight = 0;
9184     // insert edges (node1,node) and (node,node1)
9185     addGEdge2 (node1, node, edge->weight, backweight);
9186     // remove edges (node, node2) and (node2, node)
9187     remGEdge (node2, node);
9188     remGEdge (node, node2);
9189     edge = nextedge;
9190   } // while
9191   
9192   // now node2 should not be referenced by any other GraphNode...
9193   //remGNode (adj, node2->data, node2->hash);
9194 }
9195
9196 /*----------------------------------------------------------------*/
9197 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9198 /*----------------------------------------------------------------*/
9199 void showGraph (Graph *g)
9200 {
9201   GraphNode *node;
9202   GraphEdge *edge;
9203   pseudoBankNr bankNr;
9204   pseudoBank *pbank;
9205   unsigned int size;
9206
9207   node = g->node;
9208   while (node) {
9209     edge = node->edge;
9210     bankNr = getEffectiveBank (node->hash);
9211     assert (bankNr >= 0);
9212     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9213     if (pbank) {
9214       bankNr = pbank->bank;
9215       size = pbank->size;
9216     } else {
9217       size = 1;
9218     }
9219     
9220     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9221
9222     while (edge) {
9223       if (edge->weight > 0)
9224         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9225       edge = edge->next;
9226     } // while (edge)
9227     node = node->next;
9228   } // while (node)
9229 }
9230
9231 /*---------------------------------------------------------------*/
9232 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9233 /*---------------------------------------------------------------*/
9234 void pic16_OptimizeBanksel ()
9235 {
9236   GraphNode *node, *node1, *node1next;
9237
9238 #if 0
9239   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9240   GraphEdge *edge, *backedge;
9241   GraphEdge *max;
9242   int maxWeight, weight, mergeMore, absMaxWeight;
9243   pseudoBankNr curr0, curr1;
9244 #endif
9245   pseudoBank *pbank;
9246   pseudoBankNr bankNr;
9247   char *base_symbol0, *base_symbol1;
9248   int len0, len1;
9249   pBlock *pb;
9250   set *set;
9251   regs *reg;
9252   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9253
9254   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9255
9256   if (!the_pFile || !the_pFile->pbHead) return;
9257
9258   adj = newGraph (NULL);
9259   sym2bank = newHashTable ( 255 );
9260   bank2sym = newHashTable ( 255 );
9261   coerce = newHashTable ( 255 );
9262
9263   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9264   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9265     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9266   } // for pb
9267
9268 #if 1
9269   // assign symbols with absolute addresses to their respective bank nrs
9270   set = pic16_fix_udata;
9271   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9272     bankNr = reg->address >> 8;
9273     node = getOrAddGNode (adj, NULL, bankNr);
9274     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9275     assignToSameBank (node->hash, bankNr, 1);
9276     
9277     assert (bankNr >= 0);
9278     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9279     if (!pbank) {
9280       pbank = Safe_calloc (1, sizeof (pseudoBank));
9281       pbank->bank = reg->address >> 8; //FIXED_BANK;
9282       pbank->size = 1;
9283       pbank->ref = 1;
9284       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9285     } else {
9286       assert (pbank->bank == (reg->address >> 8));
9287       pbank->bank = reg->address >> 8; //FIXED_BANK;
9288     }
9289     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9290   } // for reg
9291 #endif
9292
9293 #if 1
9294   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9295   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9296   node = adj->node;
9297   while (node) {
9298     if (node->hash < 0) { node = node->next; continue; }
9299     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9300     node1 = node->next;
9301     while (node1) {
9302       if (node1->hash < 0) { node1 = node1->next; continue; }
9303       node1next = node1->next;
9304       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9305       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9306         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9307         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9308         if (assignToSameBank (node->hash, node1->hash, 0)) {
9309           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9310           assert (0 && "Could not assign a symbol to a bank!");
9311         }
9312         mergeGraphNodes (node, node1);
9313         /*
9314         if (node->hash < node1->hash)
9315           mergeGraphNodes (node, node1);
9316         else
9317           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9318         */
9319       } // if
9320       node1 = node1next;
9321     } // while (node1)
9322     node = node->next;
9323   } // while (node)
9324 #endif
9325
9326 #if 0
9327   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9328   // assign tightly coupled operands to the same (pseudo) bank
9329   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9330   mergeMore = 1;
9331   absMaxWeight = 0;
9332   while (mergeMore) {
9333     node = adj->node;
9334     max = NULL;
9335     maxWeight = 0;
9336     while (node) {
9337       curr0 = getEffectiveBank (node->hash);
9338       if (curr0 < 0) { node = node->next; continue; }
9339       edge = node->edge;
9340       while (edge) {
9341         assert (edge->src == node);
9342         backedge = getGEdge (edge->node, edge->src);
9343         weight = edge->weight + (backedge ? backedge->weight : 0);
9344         curr1 = getEffectiveBank (edge->node->hash);
9345         if (curr1 < 0) { edge = edge->next; continue; }
9346
9347         // merging is only useful if the items are not assigned to the same bank already...
9348         if (curr0 != curr1 && weight > maxWeight) {
9349           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9350           maxWeight = weight;
9351           max = edge;
9352         } // if
9353         edge = edge->next;
9354       } // while
9355       node = node->next;
9356     } // while
9357     
9358     if (maxWeight > 0) {
9359 #if 0
9360       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9361                max->src->hash, getSymFromBank (max->src->hash),
9362                max->node->hash, getSymFromBank (max->node->hash));
9363 #endif
9364
9365       node = getGNode (adj, max->src->data, max->src->hash);
9366       node1 = getGNode (adj, max->node->data, max->node->hash);
9367
9368       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9369         if (max->src->hash < max->node->hash)
9370           mergeGraphNodes (node, node1);
9371         else
9372           mergeGraphNodes (node1, node);
9373       } else {
9374         remGEdge (node, node1);
9375         remGEdge (node1, node);
9376         //mergeMore = 0;
9377       }
9378
9379     } else {
9380       mergeMore = 0;
9381     }
9382   } // while
9383 #endif
9384
9385 #if 1  
9386   // remove redundant BANKSELs
9387   //fprintf (stderr, "removing redundant BANKSELs\n");
9388   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9389     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9390   } // for pb
9391 #endif
9392
9393 #if 0
9394   fprintf (stderr, "display graph\n");
9395   showGraph ();
9396 #endif
9397
9398   deleteGraph (adj);
9399   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9400 }
9401
9402 /*** END of stuff belonging to the BANKSEL optimization ***/
9403
9404
9405
9406 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9407
9408 typedef unsigned int symbol_t;
9409 typedef unsigned int valnum_t;
9410 //typedef unsigned int hash_t;
9411
9412 #ifndef INT_TO_PTR
9413 #define INT_TO_PTR(x) (((char *) 0) + (x))
9414 #endif
9415
9416 #ifndef PTR_TO_INT
9417 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9418 #endif
9419
9420 static int pic16_regIsLocal (regs *r);
9421 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9422
9423 /* statistics */
9424 static unsigned int pic16_df_removed_pcodes = 0;
9425 static unsigned int pic16_df_saved_bytes = 0;
9426 static unsigned int df_findall_sameflow = 0;
9427 static unsigned int df_findall_otherflow = 0;
9428 static unsigned int df_findall_in_vals = 0;
9429
9430 static void pic16_df_stats () {
9431   return;
9432   if (pic16_debug_verbose || pic16_pcode_verbose) {
9433     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9434     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9435     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9436   }
9437 }
9438
9439 /* Remove a pCode iff possible:
9440  * - previous pCode is no SKIP
9441  * - pc has no label
9442  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9443 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9444   pCode *pcprev, *pcnext;
9445   char buf[256], *total=NULL;
9446   int len;
9447   
9448   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9449
9450   pcprev = pic16_findPrevInstruction (pc->prev);
9451   pcnext = pic16_findNextInstruction (pc->next);
9452   
9453   /* move labels to next instruction (if possible) */
9454   if (PCI(pc)->label && !pcnext) return 0;
9455
9456   /* if this is a SKIP with side-effects -- do not remove */
9457   /* XXX: might try to replace this one with the side-effect only version */
9458   if (isPCI_SKIP(pc)
9459         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9460   {
9461     pCode *newpc;
9462     switch (PCI(pc)->op)
9463     {
9464     case POC_INCFSZ:
9465     case POC_INFSNZ:
9466       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9467       pic16_pCodeReplace( pc, newpc );
9468       return 1;
9469       break;
9470     case POC_INCFSZW:
9471       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9472       pic16_pCodeReplace( pc, newpc );
9473       return 1;
9474       break;
9475     case POC_DECFSZ:
9476     case POC_DCFSNZ:
9477       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9478       pic16_pCodeReplace( pc, newpc );
9479       return 1;
9480       break;
9481     case POC_DECFSZW:
9482       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9483       pic16_pCodeReplace( pc, newpc );
9484       return 1;
9485       break;
9486     default:
9487       return 0;
9488     }
9489     return 0;
9490   }
9491
9492   /* if previous instruction is a skip -- do not remove */
9493   if (pcprev && isPCI_SKIP(pcprev)) {
9494     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9495       /* preceeding SKIP could not be removed -- keep this instruction! */
9496       return 0;
9497     }
9498   }
9499
9500   if (PCI(pc)->label) {
9501     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9502     //pc->print (stderr, pc);
9503     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9504     PCI(pc)->label = NULL;
9505   }
9506   
9507   /* update statistics */
9508   pic16_df_removed_pcodes++;
9509   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9510   
9511   /* remove the pCode */
9512   pic16_pCode2str (buf, 256, pc);
9513   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9514   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9515     len = strlen (buf) + strlen (comment) + 10;
9516     total = (char *) Safe_malloc (len);
9517     SNPRINTF (total, len, "%s: %s", comment, buf);
9518     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9519     Safe_free (total);
9520   }
9521
9522   /* actually unlink it from the pBlock -- also remove from to/from lists */
9523   pic16_pCodeUnlink (pc);
9524
9525   /* remove the pCode -- release registers */
9526   pc->destruct (pc);
9527
9528   /* report success */
9529   return 1;
9530 }
9531
9532
9533 /* ======================================================================== */
9534 /* === SYMBOL HANDLING ==================================================== */
9535 /* ======================================================================== */
9536
9537 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9538 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9539 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9540
9541 /** Calculate a hash for a given string.
9542  * If len == 0 the string is assumed to be NUL terminated. */
9543 static hash_t symbolHash (const char *str, unsigned int len) {
9544   hash_t hash = 0;
9545   if (!len) {
9546     while (*str) {
9547       hash = (hash << 2) ^ *str;
9548       str++;
9549     } // while
9550   } else {
9551     while (len--) {
9552       hash = (hash << 2) ^ *str;
9553       str++;
9554     }
9555   }
9556   return hash;
9557 }
9558
9559 /** Return 1 iff strings v1 and v2 are identical. */
9560 static int symcmp (const void *v1, const void *v2) {
9561   return !strcmp ((const char *) v1, (const char *) v2);
9562 }
9563
9564 /** Return 1 iff pointers v1 and v2 are identical. */
9565 static int ptrcmp (const void *v1, const void *v2) {
9566   return (v1 == v2);
9567 }
9568
9569 enum {  SPO_WREG=0x1000,
9570         SPO_STATUS,
9571         SPO_PRODL,
9572         SPO_PRODH,
9573         SPO_INDF0,
9574         SPO_POSTDEC0,
9575         SPO_POSTINC0,
9576         SPO_PREINC0,
9577         SPO_PLUSW0,
9578         SPO_INDF1,
9579         SPO_POSTDEC1,
9580         SPO_POSTINC1,
9581         SPO_PREINC1,
9582         SPO_PLUSW1,
9583         SPO_INDF2,
9584         SPO_POSTDEC2,
9585         SPO_POSTINC2,
9586         SPO_PREINC2,
9587         SPO_PLUSW2,
9588         SPO_STKPTR,
9589         SPO_TOSL,
9590         SPO_TOSH,
9591         SPO_TOSU,
9592         SPO_BSR,
9593         SPO_FSR0L,
9594         SPO_FSR0H,
9595         SPO_FSR1L,
9596         SPO_FSR1H,
9597         SPO_FSR2L,
9598         SPO_FSR2H,
9599         SPO_PCL,
9600         SPO_PCLATH,
9601         SPO_PCLATU,
9602         SPO_TABLAT,
9603         SPO_TBLPTRL,
9604         SPO_TBLPTRH,
9605         SPO_TBLPTRU,
9606         SPO_LAST
9607 };
9608
9609 /* Return the unique symbol_t for the given string. */
9610 static symbol_t symFromStr (const char *str) {
9611   hash_t hash;
9612   char *res;
9613   symbol_t sym;
9614
9615   if (!map_symToStr) {
9616     int i;
9617     struct { char *name; symbol_t sym; } predefsyms[] = {
9618         {"WREG", SPO_WREG},
9619         {"STATUS", SPO_STATUS},
9620         {"PRODL", SPO_PRODL},
9621         {"PRODH", SPO_PRODH},
9622         {"INDF0", SPO_INDF0},
9623         {"POSTDEC0", SPO_POSTDEC0},
9624         {"POSTINC0", SPO_POSTINC0},
9625         {"PREINC0", SPO_PREINC0},
9626         {"PLUSW0", SPO_PLUSW0},
9627         {"INDF1", SPO_INDF1},
9628         {"POSTDEC1", SPO_POSTDEC1},
9629         {"POSTINC1", SPO_POSTINC1},
9630         {"PREINC1", SPO_PREINC1},
9631         {"PLUSW1", SPO_PLUSW1},
9632         {"INDF2", SPO_INDF2},
9633         {"POSTDEC2", SPO_POSTDEC2},
9634         {"POSTINC2", SPO_POSTINC2},
9635         {"PREINC2", SPO_PREINC2},
9636         {"PLUSW2", SPO_PLUSW2},
9637         {"STKPTR", SPO_STKPTR},
9638         {"TOSL", SPO_TOSL},
9639         {"TOSH", SPO_TOSH},
9640         {"TOSU", SPO_TOSU},
9641         {"BSR", SPO_BSR},
9642         {"FSR0L", SPO_FSR0L},
9643         {"FSR0H", SPO_FSR0H},
9644         {"FSR1L", SPO_FSR1L},
9645         {"FSR1H", SPO_FSR1H},
9646         {"FSR2L", SPO_FSR2L},
9647         {"FSR2H", SPO_FSR2H},
9648         {"PCL", SPO_PCL},
9649         {"PCLATH", SPO_PCLATH},
9650         {"PCLATU", SPO_PCLATU},
9651         {"TABLAT", SPO_TABLAT},
9652         {"TBLPTRL", SPO_TBLPTRL},
9653         {"TBLPTRH", SPO_TBLPTRH},
9654         {"TBLPTRU", SPO_TBLPTRU},
9655         {NULL, 0}
9656     };
9657
9658     map_strToSym = newHashTable (128);
9659     map_symToStr = newHashTable (128);
9660
9661     for (i=0; predefsyms[i].name; i++) {
9662       char *name;
9663
9664       /* enter new symbol */
9665       sym = predefsyms[i].sym;
9666       name = predefsyms[i].name;
9667       res = Safe_strdup (name);
9668       hash = symbolHash (name, 0);
9669
9670       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9671       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9672     } // for i
9673   }
9674
9675   hash = symbolHash (str, 0) % map_strToSym->size;
9676   
9677   /* find symbol in table */
9678   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9679   if (sym) {
9680     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9681     return sym;
9682   }
9683
9684   /* enter new symbol */
9685   sym = nextSymbol++;
9686   res = Safe_strdup (str);
9687
9688   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9689   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9690
9691   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9692   
9693   return sym;
9694 }
9695
9696 #if 1
9697 static const char *strFromSym (symbol_t sym) {
9698   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9699 }
9700 #endif
9701
9702 /* ======================================================================== */
9703 /* === DEFINITION MAP HANDLING ============================================ */
9704 /* ======================================================================== */
9705
9706 /* A defmap provides information about which symbol is defined by which pCode.
9707  * The most recent definitions are prepended to the list, so that the most
9708  * recent definition can be found by forward scanning the list.
9709  * pc2: MOVFF r0x00, r0x01
9710  * pc1: INCF r0x01
9711  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9712  *
9713  * We attach one defmap to each flow object, and each pCode will occur at
9714  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9715  * used to find definitions for a pCode in its own defmap that precede pCode.
9716  */
9717
9718 typedef struct defmap_s {
9719   symbol_t sym;                 /** symbol this item refers to */
9720   union {
9721     struct {
9722       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9723       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9724       int isRead:1;             /** sym/mask is read */
9725       int isWrite:1;            /** sym/mask is written */
9726     } access;
9727     int accessmethod;
9728   } acc;
9729   pCode *pc;                    /** pCode this symbol is refrenced at */
9730   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9731   valnum_t val;                 /** new unique number for this value (if isWrite) */
9732   struct defmap_s *prev, *next; /** link to previous an next definition */
9733 } defmap_t;
9734
9735 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9736 static int defmap_free_count = 0;               /** number of released defmap items */
9737
9738 /* Returns a defmap_t with the specified data; this will be the new list head.
9739  * next - pointer to the current list head */
9740 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9741   defmap_t *map;
9742   
9743   if (defmap_free) {
9744     map = defmap_free;
9745     defmap_free = map->next;
9746     --defmap_free_count;
9747   } else {
9748     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9749   }
9750   map->sym = sym;
9751   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9752   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9753   map->acc.access.isRead = (isRead != 0);
9754   map->acc.access.isWrite = (isWrite != 0);
9755   map->pc = pc;
9756   map->in_val = 0;
9757   map->val = (isWrite ? val : 0);
9758   map->prev = NULL;
9759   map->next = next;
9760   if (next) next->prev = map;
9761   
9762   return map;
9763 }
9764
9765 /* Returns a copy of the single defmap item. */
9766 static defmap_t *copyDefmap (defmap_t *map) {
9767   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9768   memcpy (res, map, sizeof (defmap_t));
9769   res->next = NULL;
9770   res->prev = NULL;
9771   return res;
9772 }
9773
9774 /* Insert a defmap item after the specified one. */
9775 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9776   if (!ref || !newItem) return 1;
9777
9778   newItem->next = ref->next;
9779   newItem->prev = ref;
9780   ref->next = newItem;
9781   if (newItem->next) newItem->next->prev = newItem;
9782   
9783   return 0;
9784 }
9785
9786 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9787  * item is copied before insertion into chain and therefore left untouched.
9788  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9789 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9790   defmap_t *dummy;
9791   dummy = *head;
9792   while (dummy && (dummy->sym != item->sym
9793                           || dummy->pc != item->pc
9794                           || dummy->acc.accessmethod != item->acc.accessmethod
9795                           || dummy->val != item->val
9796                           || dummy->in_val != item->in_val)) {
9797     dummy = dummy->next;
9798   } // while
9799
9800   /* item already present? */
9801   if (dummy) return 0;
9802   
9803   /* otherwise: insert copy of item */
9804   dummy = copyDefmap (item);
9805   dummy->next = *head;
9806   if (*head) (*head)->prev = dummy;
9807   *head = dummy;
9808
9809   return 1;
9810 }
9811
9812 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9813 static void deleteDefmap (defmap_t *map) {
9814   if (!map) return;
9815   
9816   /* unlink from chain -- fails for the first item (head is not updated!) */
9817   if (map->next) map->next->prev = map->prev;
9818   if (map->prev) map->prev->next = map->next;
9819
9820   /* clear map */
9821   memset (map, 0, sizeof (defmap_t));
9822
9823   /* save for future use */
9824   map->next = defmap_free;
9825   defmap_free = map;
9826   ++defmap_free_count;
9827 }
9828
9829 /* Release all defmaps referenced from map. */
9830 static void deleteDefmapChain (defmap_t **_map) {
9831   defmap_t *map, *next;
9832
9833   if (!_map) return;
9834
9835   map = *_map;
9836   
9837   /* find list head */
9838   while (map && map->prev) map = map->prev;
9839
9840   /* delete all items */
9841   while (map) {
9842     next = map->next;
9843     deleteDefmap (map);
9844     map = next;
9845   } // while
9846
9847   *_map = NULL;
9848 }
9849
9850 /* Free all defmap items. */
9851 static void freeDefmap (defmap_t **_map) {
9852   defmap_t *next;
9853   defmap_t *map;
9854
9855   if (!_map) return;
9856
9857   map = (*_map);
9858   
9859   /* find list head */
9860   while (map->prev) map = map->prev;
9861
9862   /* release all items */
9863   while (map) {
9864     next = map->next;
9865     Safe_free (map);
9866     map = next;
9867   }
9868
9869   (*_map) = NULL;
9870 }
9871
9872 /* Returns the most recent definition for the given symbol preceeding pc.
9873  * If no definition is found, NULL is returned. 
9874  * If pc == NULL the whole list is scanned. */
9875 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9876   defmap_t *curr = map;
9877
9878   if (pc) {
9879     /* skip all definitions up to pc */
9880     while (curr && (curr->pc != pc)) curr = curr->next;
9881
9882     /* pc not in the list -- scan the whole list for definitions */
9883     if (!curr) {
9884       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9885       curr = map;
9886     } else {
9887       /* skip all definitions performed by pc */
9888       while (curr && (curr->pc == pc)) curr = curr->next;
9889     }
9890   } // if (pc)
9891
9892   /* find definition for sym */
9893   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9894     curr = curr->next;
9895   }
9896
9897   return curr;
9898 }
9899
9900 #if 0
9901 /* Returns the first use (read) of the given symbol AFTER pc.
9902  * If no such use is found, NULL is returned.
9903  * If pc == NULL the whole list is scanned. */
9904 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9905   defmap_t *curr = map, *prev = NULL;
9906   
9907   if (pc) {
9908     /* skip all definitions up to pc */
9909     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9910
9911     /* pc not in the list -- scan the whole list for definitions */
9912     if (!curr) {
9913       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9914       curr = prev;
9915     }
9916   } else {
9917     /* find end of list */
9918     while (curr && curr->next) curr = curr->next;
9919   } // if (pc)
9920
9921   /* find use of sym (scan list backwards) */
9922   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9923
9924   return curr;
9925 }
9926 #endif
9927
9928 /* Return the defmap entry for sym AT pc. 
9929  * If none is found, NULL is returned.
9930  * If more than one entry is found an assertion is triggered. */
9931 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9932   defmap_t *res = NULL;
9933
9934   /* find entries for pc */
9935   while (map && map->pc != pc) map = map->next;
9936
9937   /* find first entry for sym @ pc */
9938   while (map && map->pc == pc && map->sym != sym) map = map->next;
9939
9940   /* no entry found */
9941   if (!map) return NULL;
9942
9943   /* check for more entries */
9944   res = map;
9945   map = map->next;
9946   while (map && map->pc == pc) {
9947     /* more than one entry for sym @ pc found? */
9948     assert (map->sym != sym);
9949     map = map->next;
9950   }
9951
9952   /* return single entry for sym @ pc */
9953   return res;
9954 }
9955
9956 /* Modifies the definition of sym at pCode to newval.
9957  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9958  */
9959 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9960   defmap_t *m  = map;
9961
9962   /* find definitions of pc */
9963   while (m && m->pc != pc) m = m->next;
9964
9965   /* find definition of sym at pc */
9966   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9967   
9968   /* no definition found */
9969   if (!m) return 1;
9970
9971   /* redefine */
9972   m->val = newval;
9973
9974   /* update following uses of sym */
9975   while (m && m->pc == pc) m = m->prev;
9976   while (m) {
9977     if (m->sym == sym) {
9978       m->in_val = newval;
9979       if (m->acc.access.isWrite) m = NULL;
9980     } // if
9981     if (m) m = m->prev;
9982   } // while
9983   
9984   return 0;
9985 }
9986
9987 /* ======================================================================== */
9988 /* === STACK ROUTINES ===================================================== */
9989 /* ======================================================================== */
9990
9991 typedef struct stack_s {
9992   void *data;
9993   struct stack_s *next;
9994 } stackitem_t;
9995
9996 typedef stackitem_t *dynstack_t;
9997 static stackitem_t *free_stackitems = NULL;
9998
9999 /* Create a stack with one item. */
10000 static dynstack_t *newStack () {
10001   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
10002   *s = NULL;
10003   return s;
10004 }
10005
10006 /* Remove a stack -- its items are only marked free. */
10007 static void deleteStack (dynstack_t *s) {
10008   stackitem_t *i;
10009
10010   while (*s) {
10011     i = *s;
10012     *s = (*s)->next;
10013     i->next = free_stackitems;
10014     free_stackitems = i;
10015   } // while
10016   Safe_free (s);
10017 }
10018
10019 /* Release all stackitems. */
10020 static void releaseStack () {
10021   stackitem_t *i;
10022   
10023   while (free_stackitems) {
10024     i = free_stackitems->next;
10025     Safe_free(free_stackitems);
10026     free_stackitems = i;
10027   } // while
10028 }
10029
10030 static void stackPush (dynstack_t *stack, void *data) {
10031   stackitem_t *i;
10032   
10033   if (free_stackitems) {
10034     i = free_stackitems;
10035     free_stackitems = free_stackitems->next;
10036   } else {
10037     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10038   }
10039   i->data = data;
10040   i->next = *stack;
10041   *stack = i;
10042 }
10043
10044 static void *stackPop (dynstack_t *stack) {
10045   void *data;
10046   stackitem_t *i;
10047   
10048   if (stack && *stack) {
10049     data = (*stack)->data;
10050     i = *stack;
10051     *stack = (*stack)->next;
10052     i->next = free_stackitems;
10053     free_stackitems = i;
10054     return data;
10055   } else {
10056     return NULL;
10057   }
10058 }
10059
10060 #if 0
10061 static int stackContains (dynstack_t *s, void *data) {
10062   stackitem_t *i;
10063   if (!s) return 0;
10064   i = *s;
10065   while (i) {
10066     if (i->data == data) return 1;
10067     i = i->next;
10068   } // while
10069
10070   /* not found */
10071   return 0;
10072 }
10073 #endif
10074
10075 static int stackIsEmpty (dynstack_t *s) {
10076   return (*s == NULL);
10077 }
10078
10079
10080 typedef struct {
10081   pCodeFlow *flow;
10082   defmap_t *lastdef;
10083 } state_t;
10084
10085 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10086   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10087   s->flow = flow;
10088   s->lastdef = lastdef;
10089   return s;
10090 }
10091
10092 static void deleteState (state_t *s) {
10093   Safe_free (s);
10094 }
10095
10096 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10097   stackitem_t *i;
10098
10099   /* scan working list for state */
10100   if (todo) {
10101     i = *todo;
10102     while (i) {
10103       /* is i == state? -- state not new */
10104       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10105       i = i->next;
10106     } // while
10107   }
10108
10109   if (done) {
10110     i = *done;
10111     while (i) {
10112       /* is i == state? -- state not new */
10113       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10114       i = i->next;
10115     } // while
10116   }
10117
10118   /* not found -- state is new */
10119   return 1;
10120 }
10121
10122 static inline valnum_t newValnum ();
10123
10124 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10125   pCode *pc;
10126
10127   if (!pb) return "<unknown function>";
10128
10129   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10130   if (pc && isPCF(pc)) return PCF(pc)->fname;
10131   else return "<unknown function>";
10132 }
10133
10134 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10135   defmap_t *map;
10136   pCodeFlow *pcfl;
10137
10138   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10139
10140   /* find initial value (assigning pc == NULL) */
10141   map = PCFL(pcfl)->in_vals;
10142   while (map && map->sym != sym) map = map->next;
10143
10144   /* initial value already present? */
10145   if (map) {
10146     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10147     return map;
10148   }
10149
10150   /* create a new initial value */
10151   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10152   PCFL(pcfl)->in_vals = map;
10153   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10154   return map;
10155
10156 #if 0
10157   /* insert map as last item in pcfl's defmap */
10158   if (!prev) prev = PCFL(pcfl)->defmap;
10159   if (!prev) {
10160     PCFL(pcfl)->defmap = map;
10161   } else {
10162     while (prev->next) prev = prev->next;
10163     prev->next = map;
10164     map->prev = prev;
10165   }
10166
10167   return map;
10168 #endif
10169 }
10170
10171 /* Find all reaching definitions for sym at pc. 
10172  * A new (!) list of definitions is returned.
10173  * Returns the number of reaching definitions found.
10174  * The defining defmap entries are returned in *chain.
10175  */
10176 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10177   defmap_t *map;
10178   defmap_t *res;
10179
10180   pCodeFlow *curr;
10181   pCodeFlowLink *succ;
10182   state_t *state;
10183   dynstack_t *todo;     /** stack of state_t */
10184   dynstack_t *done;     /** stack of state_t */
10185
10186   int firstState, n_defs;
10187   
10188   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10189   assert (chain);
10190
10191   /* initialize return list */
10192   *chain = NULL;
10193
10194   /* wildcard symbol? */
10195   if (!sym) return 0;
10196   
10197   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10198   
10199   map = PCI(pc)->pcflow->defmap;
10200
10201   res = defmapFindDef (map, sym, pc);
10202   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10203
10204 #define USE_PRECALCED_INVALS 1
10205 #if USE_PRECALCED_INVALS
10206   if (!res && PCI(pc)->pcflow->in_vals) {
10207     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10208     if (res) {
10209       //fprintf  (stderr, "found def in init values\n");
10210       df_findall_in_vals++;
10211     }
10212   }
10213 #endif
10214
10215   if (res) {
10216     // found a single definition (in pc's flow)
10217     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10218     defmapAddCopyIfNew (chain, res);
10219     df_findall_sameflow++;
10220     return 1;
10221   }
10222
10223 #if USE_PRECALCED_INVALS
10224   else {
10225     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10226     return 1;
10227   }
10228
10229 #endif
10230   
10231 #define FORWARD_FLOW_ANALYSIS 1
10232 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10233   /* no definition found in pc's flow preceeding pc */
10234   todo = newStack ();
10235   done = newStack ();
10236   n_defs = 0; firstState = 1;
10237   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10238
10239   while (!stackIsEmpty (todo)) {
10240     state = (state_t *) stackPop (todo);
10241     stackPush (done, state);
10242     curr = state->flow;
10243     res = state->lastdef;
10244     //fprintf (stderr, "searching def of sym %s in pcFlow %p (lastdef %x @ %p)\n", strFromSym(sym), curr, res ? res->val : 0, res ? res->pc : NULL);
10245
10246     /* there are no definitions BEFORE pc in pc's flow (see above) */
10247     if (curr == PCI(pc)->pcflow) {
10248       if (!res) {
10249         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10250         res = pic16_pBlockAddInval (pc->pb, sym);
10251         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10252         res = NULL;
10253       } else {
10254         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10255         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10256       }
10257     }
10258
10259     /* save last definition of sym in this flow as initial def in successors */
10260     res = defmapFindDef (curr->defmap, sym, NULL);
10261     if (!res) res = state->lastdef;
10262     
10263     /* add successors to working list */
10264     state = newState (NULL, NULL);
10265     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10266     while (succ) {
10267       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10268       state->flow = succ->pcflow;
10269       state->lastdef = res;
10270       if (stateIsNew (state, todo, done)) {
10271         stackPush (todo, state);
10272         state = newState (NULL, NULL);
10273       } // if
10274       succ = (pCodeFlowLink *) setNextItem (curr->to);
10275     } // while
10276     deleteState (state);
10277   } // while
10278
10279 #else // !FORWARD_FLOW_ANALYSIS 
10280
10281   /* no definition found in pc's flow preceeding pc */
10282   todo = newStack ();
10283   done = newStack ();
10284   n_defs = 0; firstState = 1;
10285   stackPush (todo, newState (PCI(pc)->pcflow, res));
10286
10287   while (!stackIsEmpty (todo)) {
10288     state = (state_t *) stackPop (todo);
10289     curr = state->flow;
10290
10291     if (firstState) {
10292       firstState = 0;
10293       /* only check predecessor flows */
10294     } else {
10295       /* get (last) definition of sym in this flow */
10296       res = defmapFindDef (curr->defmap, sym, NULL);
10297     }
10298
10299     if (res) {
10300       /* definition found */
10301       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10302       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10303     } else {
10304       /* no definition found -- check predecessor flows */
10305       state = newState (NULL, NULL);
10306       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10307
10308       /* if no flow predecessor available -- sym might be uninitialized */
10309       if (!succ) {
10310         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10311         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10312         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10313         deleteDefmap (res); res = NULL;
10314       }
10315       
10316       while (succ) {
10317         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10318         state->flow = succ->pcflow;
10319         state->lastdef = res;
10320         if (stateIsNew (state, todo, done)) {
10321           stackPush (todo, state);
10322           state = newState (NULL, NULL);
10323         } // if
10324         succ = (pCodeFlowLink *) setNextItem (curr->from);
10325       } // while
10326       deleteState (state);
10327     }
10328   } // while
10329
10330 #endif
10331
10332   /* clean up done stack */
10333   while (!stackIsEmpty(done)) {
10334     deleteState ((state_t *) stackPop (done));
10335   } // while
10336   deleteStack (done);
10337
10338   /* return number of items in result set */
10339   if (n_defs == 0) {
10340     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10341   } else if (n_defs == 1) {
10342     assert (*chain);
10343     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10344   } else if (n_defs > 0) {
10345     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10346 #if 0
10347     res = *chain;
10348     while (res) {
10349       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10350       res = res->next;
10351     } // while
10352 #endif
10353   }
10354   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10355   df_findall_otherflow++;
10356   return n_defs;
10357 }
10358
10359 /* ======================================================================== */
10360 /* === VALUE NUMBER HANDLING ============================================== */
10361 /* ======================================================================== */
10362
10363 static valnum_t nextValnum = 0x1000;
10364 static hTab *map_symToValnum = NULL;
10365
10366 /** Return a new value number. */
10367 static inline valnum_t newValnum () {
10368   return (nextValnum += 4);
10369 }
10370
10371 static valnum_t valnumFromStr (const char *str) {
10372   symbol_t sym;
10373   valnum_t val;
10374   void *res;
10375   
10376   sym = symFromStr (str);
10377
10378   if (!map_symToValnum) {
10379     map_symToValnum = newHashTable (128);
10380   } // if
10381
10382   /* literal already known? */
10383   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10384
10385   /* return existing valnum */
10386   if (res) return (valnum_t) PTR_TO_INT(res);
10387   
10388   /* create new valnum */
10389   val = newValnum();
10390   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10391   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10392   return val;
10393 }
10394
10395 /* Create a valnum for a literal. */
10396 static valnum_t valnumFromLit (unsigned int lit) {
10397   return ((valnum_t) 0x100 + (lit & 0x0FF));
10398 }
10399
10400 /* Return the (positive) literal value represented by val
10401  * or -1 iff val is no known literal's valnum. */
10402 static int litFromValnum (valnum_t val) {
10403   if (val >= 0x100 && val < 0x200) {
10404     /* valnum is a (known) literal */
10405     return val & 0x00FF;
10406   } else {
10407     /* valnum is not a known literal */
10408     return -1;
10409   }
10410 }
10411
10412 #if 0
10413 /* Sanity check - all flows in a block must be reachable from initial flow. */
10414 static int verifyAllFlowsReachable (pBlock *pb) {
10415   set *reached;
10416   set *flowInBlock;
10417   set *checked;
10418   pCode *pc;
10419   pCodeFlow *pcfl;
10420   pCodeFlowLink *succ;
10421   int res;
10422
10423   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10424
10425   reached = NULL;
10426   flowInBlock = NULL;
10427   checked = NULL;
10428   /* mark initial flow as reached (and "not needs to be reached") */
10429   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10430   assert (pc);
10431   addSetHead (&reached, pc);
10432   addSetHead (&checked, pc);
10433   
10434   /* mark all further flows in block as "need to be reached" */
10435   pc = pb->pcHead;
10436   do {
10437     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10438     pc = pic16_findNextInstruction (pc->next);
10439   } while (pc);
10440
10441   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10442     /* mark as reached and "not need to be reached" */
10443     deleteSetItem (&reached, pcfl);
10444     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10445     
10446     /* flow is no longer considered unreachable */
10447     deleteSetItem (&flowInBlock, pcfl);
10448
10449     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10450       if (!isinSet (checked, succ->pcflow)) {
10451         /* flow has never been reached before */
10452         addSetHead (&reached, succ->pcflow);
10453         addSetHead (&checked, succ->pcflow);
10454       } // if
10455     } // for succ
10456   } // while
10457
10458   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10459
10460   /* by now every flow should have been reached
10461    * --> flowInBlock should be empty */
10462   res = (flowInBlock == NULL);
10463
10464 #if 1
10465   if (flowInBlock) {
10466           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10467     while (flowInBlock) {
10468       pcfl = indexSet (flowInBlock, 0);
10469       fprintf (stderr, "not reached: flow %p\n", pcfl);
10470       deleteSetItem (&flowInBlock, pcfl);
10471     } // while
10472   }
10473 #endif
10474   
10475   /* clean up */
10476   deleteSet (&reached);
10477   deleteSet (&flowInBlock);
10478   deleteSet (&checked);
10479   
10480   /* if we reached every flow, succ is NULL by now... */
10481   //assert (res); // will fire on unreachable code...
10482   return (res);
10483 }
10484 #endif
10485
10486 /* Checks a flow for accesses to sym AFTER pc.
10487  * 
10488  * Returns -1 if the symbol is read in this flow (before redefinition),
10489  * returns 0 if the symbol is redefined in this flow or
10490  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10491  */
10492 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10493   defmap_t *map, *mappc;
10494
10495   /* find pc or start of definitions */
10496   map = pcfl->defmap;
10497   while (map && (map->pc != pc) && map->next) map = map->next;
10498   /* if we found pc -- ignore it */
10499   while (map && map->pc == pc) map = map->prev;
10500
10501   /* scan list backwards (first definition first) */
10502   while (map && mask) {
10503 //    if (map->sym == sym) {
10504       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10505       mappc = map;
10506       /* scan list for reads at this pc first */
10507       while (map && map->pc == mappc->pc) {
10508         /* is the symbol (partially) read? */
10509         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10510           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10511           return -1;
10512         }
10513         map = map->prev;
10514       } // while
10515       map = mappc;
10516
10517       while (map && map->pc == mappc->pc) {
10518         /* honor (partial) redefinitions of sym */
10519         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10520           mask &= ~map->acc.access.mask;
10521           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10522         }
10523         map = map->prev;
10524       } // while
10525 //    } // if
10526     /* map already points to the first defmap for the next pCode */
10527     //map = mappc->prev;
10528   } // while
10529
10530   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10531    * is still alive; return the appropriate mask of alive bits */
10532   return mask;
10533 }
10534
10535 /* Check whether a symbol is alive (AFTER pc). */
10536 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10537   int mask, visit;
10538   defmap_t *map;
10539   dynstack_t *todo, *done;
10540   state_t *state;
10541   pCodeFlow *pcfl;
10542   pCodeFlowLink *succ;
10543
10544   mask = 0x00ff;
10545   
10546   assert (isPCI(pc));
10547   pcfl = PCI(pc)->pcflow;
10548   map = pcfl->defmap;
10549
10550   todo = newStack ();
10551   done = newStack ();
10552   
10553   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10554   stackPush (todo, state);
10555   visit = 0;
10556   
10557   while (!stackIsEmpty (todo)) {
10558     state = (state_t *) stackPop (todo);
10559     pcfl = state->flow;
10560     mask = PTR_TO_INT(state->lastdef);
10561     if (visit) stackPush (done, state); else deleteState(state);
10562     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10563     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10564     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10565     visit++;
10566
10567     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10568     if (mask == 0) continue;
10569
10570     /* symbol is (partially) read before redefinition in flow */
10571     if (mask == -1) break;
10572
10573     /* symbol is neither read nor completely redefined -- check successor flows */
10574     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10575       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10576       if (stateIsNew (state, todo, done)) {
10577         stackPush (todo, state);
10578       } else {
10579         deleteState (state);
10580       }
10581     } // for
10582   } // while
10583
10584   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10585   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10586
10587   /* symbol is read in at least one flow -- is alive */
10588   if (mask == -1) return 1;
10589
10590   /* symbol is read in no flow */
10591   return 0;
10592 }
10593
10594 /* Returns whether access to the given symbol has side effects. */
10595 static int pic16_symIsSpecial (symbol_t sym) {
10596   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10597   switch (sym) {
10598   case SPO_INDF0:
10599   case SPO_PLUSW0:
10600   case SPO_POSTINC0:
10601   case SPO_POSTDEC0:
10602   case SPO_PREINC0:
10603   case SPO_INDF1:
10604   case SPO_PLUSW1:
10605   case SPO_POSTINC1:
10606   case SPO_POSTDEC1:
10607   case SPO_PREINC1:
10608   case SPO_INDF2:
10609   case SPO_PLUSW2:
10610   case SPO_POSTINC2:
10611   case SPO_POSTDEC2:
10612   case SPO_PREINC2:
10613   case SPO_PCL:
10614           return 1;
10615   default:
10616           /* no special effects known */
10617           return 0;
10618   } // switch
10619
10620   return 0;
10621 }
10622
10623 /* Check whether a register should be considered local (to the current function) or not. */
10624 static int pic16_regIsLocal (regs *r) {
10625   symbol_t sym;
10626   if (r) {
10627     if (r->type == REG_TMP) return 1;
10628
10629     sym = symFromStr (r->name);
10630     switch (sym) {
10631     case SPO_WREG:
10632     case SPO_FSR0L: // used in ptrget/ptrput
10633     case SPO_FSR0H: // ... as well
10634     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10635     case SPO_FSR1H: // ... as well
10636     case SPO_FSR2L: // used as frame pointer
10637     case SPO_FSR2H: // ... as well
10638     case SPO_PRODL: // used to return values from functions
10639     case SPO_PRODH: // ... as well
10640       /* these registers (and some more...) are considered local */
10641       return 1;
10642       break;
10643     default:
10644       /* for unknown regs: check is marked local, leave if not */
10645       if (r->isLocal) {
10646         return 1;
10647       } else {
10648         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10649         return 0;
10650       }
10651     } // switch
10652   } // if
10653
10654   /* if in doubt, assume non-local... */
10655   return 0;
10656 }
10657
10658 /* Check all symbols touched by pc whether their newly assigned values are read.
10659  * Returns 0 if no symbol is used later on, 1 otherwise. */
10660 static int pic16_pCodeIsAlive (pCode *pc) {
10661   pCodeInstruction *pci;
10662   defmap_t *map, *lastpc;
10663   regs *checkreg;
10664   
10665   /* we can only handle PCIs */
10666   if (!isPCI(pc)) return 1;
10667
10668   //pc->print (stderr, pc);
10669
10670   pci = PCI(pc);
10671   assert (pci && pci->pcflow && pci->pcflow->defmap);
10672
10673   /* NEVER remove instructions with implicit side effects */
10674   switch (pci->op) {
10675   case POC_TBLRD:
10676   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10677   case POC_TBLRD_POSTDEC:
10678   case POC_TBLRD_PREINC:
10679   case POC_TBLWT:               /* modify program memory */
10680   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10681   case POC_TBLWT_POSTDEC:
10682   case POC_TBLWT_PREINC:
10683   case POC_CLRWDT:              /* clear watchdog timer */
10684   case POC_PUSH:                /* should be safe to remove though... */
10685   case POC_POP:                 /* should be safe to remove though... */
10686   case POC_CALL:
10687   case POC_RCALL:
10688   case POC_RETFIE:
10689   case POC_RETURN:
10690     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10691     return 1;
10692
10693   default:
10694     /* no special instruction */
10695     break;
10696   } // switch
10697
10698   /* prevent us from removing assignments to non-local variables */
10699   checkreg = NULL;
10700   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10701   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10702
10703   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10704     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10705     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10706     //pc->print (stderr, pc);
10707     return 1;
10708   }
10709   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10710     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10711     return 1;
10712   }
10713   
10714 #if 1
10715   /* OVERKILL: prevent us from removing reads from non-local variables 
10716    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10717    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10718   checkreg = NULL;
10719   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10720   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10721
10722   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10723     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10724     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10725     //pc->print (stderr, pc);
10726     return 1;
10727   }
10728   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10729     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10730     return 1;
10731   }
10732 #endif
10733   
10734   /* now check that the defined symbols are not used */
10735   map = pci->pcflow->defmap;
10736   
10737   /* find items for pc */
10738   while (map && map->pc != pc) map = map->next;
10739
10740   /* no entries found? something is fishy with DF analysis... -- play safe */
10741   if (!map) {
10742     if (pic16_pcode_verbose) {
10743       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10744     }
10745     return 1;
10746   }
10747
10748   /* remember first item assigned to pc for later use */
10749   lastpc = map;
10750   
10751   /* check all symbols being modified by pc */
10752   while (map && map->pc == pc) {
10753     if (map->sym == 0) { map = map->next; continue; }
10754
10755     /* keep pc if it references special symbols (like POSTDEC0) */
10756 #if 0
10757     {
10758       char buf[256];
10759       pic16_pCode2str (buf, 256, pc);
10760       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10761     }
10762 #endif
10763     if (pic16_symIsSpecial (map->sym)) {
10764       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10765       return 1;
10766     }
10767     if (map->acc.access.isWrite) {
10768       if (pic16_isAlive (map->sym, pc)) {
10769         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10770         return 1;
10771       }
10772     }
10773     map = map->next;
10774   } // while
10775
10776   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10777 #if 0
10778   {
10779     char buf[256];
10780     pic16_pCode2str (buf, 256, pc);
10781     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10782   }
10783 #endif
10784   return 0;
10785 }
10786
10787 /* Adds implied operands to the list.
10788  * sym - operand being accessed in the pCode
10789  * list - list to append the operand
10790  * isRead - set to 1 iff sym is read in pCode
10791  * listRead - set to 1 iff all operands being read are to be listed
10792  *
10793  * Returns 0 for "normal" operands, 1 for special operands.
10794  */
10795 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10796   /* check whether accessing REG accesses other REGs as well */
10797   switch (sym) {
10798   case SPO_INDF0:
10799     /* reads FSR0x */
10800     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10801     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10802     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10803     break;
10804     
10805   case SPO_PLUSW0:
10806     /* reads FSR0x and WREG */
10807     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10808     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10809     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10810     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10811     break;
10812     
10813   case SPO_POSTDEC0:
10814   case SPO_POSTINC0:
10815   case SPO_PREINC0:
10816     /* reads/modifies FSR0x */
10817     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10818     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10819     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10820     break;
10821
10822   case SPO_INDF1:
10823     /* reads FSR1x */
10824     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10825     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10826     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10827     break;
10828     
10829   case SPO_PLUSW1:
10830     /* reads FSR1x and WREG */
10831     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10832     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10833     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10834     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10835     break;
10836     
10837   case SPO_POSTDEC1:
10838   case SPO_POSTINC1:
10839   case SPO_PREINC1:
10840     /* reads/modifies FSR1x */
10841     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10842     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10843     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10844     break;
10845
10846   case SPO_INDF2:
10847     /* reads FSR2x */
10848     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10849     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10850     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10851     break;
10852     
10853   case SPO_PLUSW2:
10854     /* reads FSR2x and WREG */
10855     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10856     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10857     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10858     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10859     break;
10860     
10861   case SPO_POSTDEC2:
10862   case SPO_POSTINC2:
10863   case SPO_PREINC2:
10864     /* reads/modifies FSR2x */
10865     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10866     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10867     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10868     break;
10869
10870   case SPO_PCL:
10871     /* modifies PCLATH and PCLATU */
10872     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10873     if (isRead) {
10874       /* reading PCL updates PCLATx */
10875       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10876       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10877     }
10878     if (isWrite) {
10879       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10880       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10881       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10882     }
10883     break;
10884
10885   default:
10886     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10887     /* nothing special */
10888     return 0;
10889     break;
10890   }
10891
10892   /* has been a special operand */
10893   return 1;
10894 }
10895
10896 static symbol_t pic16_fsrsym_idx[][2] = {
10897     {SPO_FSR0L, SPO_FSR0H},
10898     {SPO_FSR1L, SPO_FSR1H},
10899     {SPO_FSR2L, SPO_FSR2H}
10900 };
10901
10902 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10903 static void mergeDefmapSymbols (defmap_t *list) { 
10904   defmap_t *ref, *curr, *temp;
10905
10906   /* now make sure that each symbol occurs at most once per pc */
10907   ref = list;
10908   while (ref && (ref->pc == list->pc)) {
10909     curr = ref->next;
10910     while (curr && (curr->pc == list->pc)) {
10911       if (curr->sym == ref->sym) {
10912         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10913         /* found a symbol occuring twice... merge the two */
10914         if (curr->acc.access.isRead) {
10915           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10916           ref->acc.access.isRead = 1;
10917           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10918         }
10919         if (curr->acc.access.isWrite) {
10920           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10921           ref->acc.access.isWrite = 1;
10922           ref->acc.access.mask |= curr->acc.access.mask;
10923         }
10924         temp = curr;
10925         curr = curr->next;
10926         deleteDefmap (temp);
10927         continue; // do not skip curr!
10928       } // if
10929       curr = curr->next;
10930     } // while
10931     ref = ref->next;
10932   } // while
10933 }
10934
10935 /** Prepend list with the reads and definitions performed by pc. */
10936 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10937   pCodeInstruction *pci;
10938   int cond, inCond, outCond;
10939   int mask = 0xff, smask;
10940   int isSpecial, isSpecial2;
10941   symbol_t sym, sym2;
10942   char *name;
10943
10944   if (isPCAD(pc)) {
10945     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10946     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10947     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10948     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10949     return list;
10950   }
10951   assert (isPCI(pc));
10952   pci = PCI(pc);
10953   
10954   /* handle bit instructions */
10955   if (pci->isBitInst) {
10956     assert (pci->pcop->type == PO_GPR_BIT);
10957     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10958   }
10959
10960   /* handle (additional) implicit arguments */
10961   switch (pci->op) {
10962   case POC_LFSR:
10963     {
10964       int lit;
10965       valnum_t val;
10966       lit = PCOL(pci->pcop)->lit;
10967       assert (lit >= 0 && lit < 3);
10968       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10969       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10970       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10971       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10972       list = newDefmap (pic16_fsrsym_idx[lit][1], 0x00, 0xff, 0, 1, pc, val+1, list); // val+1 is guaranteed not be used as a valnum...
10973     }
10974     break;
10975
10976   case POC_MOVLB: // BSR
10977   case POC_BANKSEL: // BSR
10978     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10979     break;
10980
10981   case POC_MULWF: // PRODx
10982   case POC_MULLW: // PRODx
10983     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10984     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10985     break;
10986
10987   case POC_POP: // TOS, STKPTR
10988     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10989     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10990     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10991     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10992     break;
10993     
10994   case POC_PUSH: // STKPTR
10995     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10996     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10997     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10998     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10999     break;
11000     
11001   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
11002   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
11003     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11004     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11005     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11006     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11007
11008     /* needs correctly set-up stack pointer */
11009     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11010     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11011     break;
11012
11013   case POC_RETLW: // return values: WREG, PRODx, FSR0L
11014     /* pseudo read on (possible) return values */
11015     // WREG is handled below via outCond
11016     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11017     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11018     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11019
11020     /* caller's stack pointers must be restored */
11021     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11022     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11023     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11024     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11025     break;
11026
11027   case POC_RETURN: // return values; WREG, PRODx, FSR0L
11028   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
11029     /* pseudo read on (possible) return values */
11030     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
11031     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11032     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11033     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11034
11035     /* caller's stack pointers must be restored */
11036     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11037     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11038     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11039     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11040     break;
11041     
11042   case POC_TBLRD:
11043     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11044     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11045     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11046     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11047     break;
11048     
11049   case POC_TBLRD_POSTINC:
11050   case POC_TBLRD_POSTDEC:
11051   case POC_TBLRD_PREINC:
11052     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11053     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11054     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11055     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11056     break;
11057     
11058   case POC_TBLWT:
11059     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11060     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11061     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11062     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11063     break;
11064     
11065   case POC_TBLWT_POSTINC:
11066   case POC_TBLWT_POSTDEC:
11067   case POC_TBLWT_PREINC:
11068     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11069     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11070     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11071     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11072     break;
11073     
11074   default:
11075     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11076     break;
11077   } // switch
11078
11079   /* handle explicit arguments */
11080   inCond = pci->inCond;
11081   outCond = pci->outCond;
11082   cond = inCond | outCond;
11083   if (cond & PCC_W) {
11084     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11085   } // if
11086
11087   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11088   if (inCond & PCC_STATUS) {
11089     smask = 0;
11090     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11091     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11092     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11093     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11094     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11095
11096     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11097     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11098   } // if
11099   
11100   if (outCond & PCC_STATUS) {
11101     smask = 0;
11102     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11103     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11104     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11105     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11106     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11107
11108     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11109     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11110   } // if
11111   
11112   isSpecial = isSpecial2 = 0;
11113   sym = sym2 = 0;
11114   if (cond & PCC_REGISTER) {
11115     name = pic16_get_op (pci->pcop, NULL, 0);
11116     sym = symFromStr (name);
11117     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11118     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11119   }
11120
11121   if (cond & PCC_REGISTER2) {
11122     name = pic16_get_op2 (pci->pcop, NULL, 0);
11123     sym2 = symFromStr (name);
11124     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11125     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11126   }
11127
11128  
11129   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11130   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11131
11132   mergeDefmapSymbols (list);
11133   
11134   return list;
11135 }
11136
11137 #if 0
11138 static void printDefmap (defmap_t *map) {
11139   defmap_t *curr;
11140
11141   curr = map;
11142   fprintf (stderr, "defmap @ %p:\n", curr);
11143   while (curr) {
11144     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11145                     curr->acc.access.isRead ? "R" : " ",
11146                     curr->acc.access.isWrite ? "W": " ",
11147                     curr->in_val, curr->val,
11148                     curr->acc.access.in_mask, curr->acc.access.mask,
11149                     strFromSym(curr->sym), curr->sym,
11150                     curr->pc);
11151     curr = curr->next;
11152   } // while
11153   fprintf (stderr, "<EOL>\n");
11154 }
11155 #endif
11156
11157 /* Add "additional" definitions to uniq.
11158  * This can be used to merge the in_values and the flow's defmap to create an in_value-list for the flow's successors.
11159  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11160  *
11161  * If symbols defined in additional are not present in uniq, a definition is created.
11162  * Otherwise the present definition is altered to reflect the newer assignments.
11163  *
11164  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11165  *       before     `------- noted in additional --------'      after
11166  *
11167  * I assume that each symbol occurs AT MOST ONCE in uniq.
11168  *
11169  */
11170 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11171   defmap_t *curr;
11172   defmap_t *old;
11173   int change = 0;
11174
11175   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11176   /* find tail of additional list (holds the first assignment) */
11177   curr = additional;
11178   while (curr && curr->next) curr = curr->next;
11179
11180   /* update uniq */
11181   do {
11182     /* find next assignment in additionals */
11183     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11184
11185     if (!curr) break;
11186
11187     /* find item in uniq */
11188     old = *uniq;
11189     //printDefmap (*uniq);
11190     while (old && (old->sym != curr->sym)) old = old->next;
11191
11192     if (old) {
11193       /* definition found -- replace */
11194       if (old->val != curr->val) {
11195         old->val = curr->val;
11196         change++;
11197       } // if
11198     } else {
11199       /* new definition */
11200       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11201       change++;
11202     }
11203
11204     curr = curr->prev;
11205   } while (1);
11206
11207   /* return 0 iff uniq remained unchanged */
11208   return change;
11209 }
11210
11211 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11212  * lists of its predecessor flows. 
11213  * Initially *combined should be NULL, alt_in will be copied to combined.
11214  * If *combined != NULL, combined will be altered:
11215  * - for symbols defined in *combined but not in alt_in,
11216  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11217  * - for symbols defined in alt_in but not in *combined,
11218  *   a 0 definition is created (value unknown, either INIT or alt).
11219  * - for symbols defined in both, *combined is:
11220  *   > left unchanged if *combined->val == alt_in->val or
11221  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11222  * 
11223  * I assume that each symbol occurs AT MOST ONCE in each list!
11224  */
11225 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11226   defmap_t *curr;
11227   defmap_t *old;
11228   int change = 0;
11229   valnum_t val;
11230
11231   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11232   
11233   if (!(*combined)) {
11234     return defmapUpdateUniqueSym (combined, alt_in);
11235   } // if
11236   
11237   /* merge the two */
11238   curr = alt_in;
11239   while (curr) {
11240     /* find symbols definition in *combined */
11241     old = *combined;
11242     while (old && (old->sym != curr->sym)) old = old->next;
11243
11244     if (old) {
11245       /* definition found */
11246       if (old->val && (old->val != curr->val)) {
11247         old->val = 0; /* value unknown */
11248         change++;
11249       }
11250     } else {
11251       /* no definition found -- can be either INIT or alt_in's value */
11252       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11253       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11254       if (val != curr->val) change++;
11255     }
11256
11257     curr = curr->next;
11258   } // while (curr)
11259
11260   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11261   old = *combined;
11262   while (old) {
11263     if (old->val != 0) {
11264       /* find definition in alt_in */
11265       curr = alt_in;
11266       while (curr && curr->sym != old->sym) curr = curr->next;
11267       if (!curr) {
11268         /* symbol defined in *combined only -- can be either INIT or *combined */
11269         val = pic16_pBlockAddInval (pb, old->sym)->val;
11270         if (old->val != val) {
11271           old->val = 0;
11272           change++;
11273         }
11274       } // if
11275     } // if
11276
11277     old = old->next;
11278   } // while
11279
11280   return change;
11281 }
11282
11283 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11284   defmap_t *curr1, *curr2;
11285   symbol_t sym;
11286   
11287   /* identical maps are equal */
11288   if (map1 == map2) return 0;
11289
11290   if (!map1) return -1;
11291   if (!map2) return 1;
11292
11293   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11294   
11295   /* check length */
11296   curr1 = map1;
11297   curr2 = map2;
11298   while (curr1 && curr2) {
11299     curr1 = curr1->next;
11300     curr2 = curr2->next;
11301   } // while
11302
11303   /* one of them longer? */
11304   if (curr1) return 1;
11305   if (curr2) return -1;
11306
11307   /* both lists are of equal length -- compare (in O(n^2)) */
11308   curr1 = map1;
11309   while (curr1) {
11310     sym = curr1->sym;
11311     curr2 = map2;
11312     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11313     if (!curr2) return 1; // symbol not found in curr2
11314     if (curr2->val != curr1->val) return 1; // values differ
11315
11316     /* compare next symbol */
11317     curr1 = curr1->next;
11318   } // while
11319
11320   /* no difference found */
11321   return 0;
11322 }
11323
11324
11325 /* Prepare a list of all reaching definitions per flow.
11326  * This is done using a forward dataflow analysis.
11327  */
11328 static void createReachingDefinitions (pBlock *pb) {
11329   defmap_t *out_vals, *in_vals;
11330   pCode *pc;
11331   pCodeFlow *pcfl;
11332   pCodeFlowLink *link;
11333   set *todo;
11334   set *blacklist;
11335
11336   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11337   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11338     if (isPCFL(pc)) {
11339       deleteDefmapChain (&PCFL(pc)->in_vals);
11340       deleteDefmapChain (&PCFL(pc)->out_vals);
11341       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11342     } // if
11343   } // for
11344   
11345   pc = pic16_findNextInstruction (pb->pcHead);
11346   todo = NULL; blacklist = NULL;
11347   addSetHead (&todo, PCI(pc)->pcflow);
11348
11349   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11350   while (elementsInSet (todo)) {
11351     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11352     pcfl = PCFL(indexSet (todo, 0));
11353     deleteSetItem (&todo, pcfl);
11354     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11355     in_vals = NULL;
11356     out_vals = NULL;
11357
11358     if (isinSet (blacklist, pcfl)) {
11359             fprintf (stderr, "ignoring blacklisted flow\n");
11360       continue;
11361     }
11362     
11363     /* create in_vals from predecessors out_vals */
11364     link = setFirstItem (pcfl->from);
11365     while (link) {
11366       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11367       link = setNextItem (pcfl->from);
11368     } // while
11369
11370     //printDefmap (in_vals); 
11371     //printDefmap (pcfl->in_vals); 
11372
11373     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11374       //fprintf (stderr, "in_vals changed\n");
11375       /* in_vals changed -- update out_vals */
11376       deleteDefmapChain (&pcfl->in_vals);
11377       pcfl->in_vals = in_vals;
11378
11379       /* create out_val from in_val and defmap */
11380       out_vals = NULL;
11381       defmapUpdateUniqueSym (&out_vals, in_vals);
11382       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11383
11384       /* is out_vals different from pcfl->out_vals */
11385       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11386         //fprintf (stderr, "out_vals changed\n");
11387         deleteDefmapChain (&pcfl->out_vals);
11388         pcfl->out_vals = out_vals;
11389
11390         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11391           addSet (&blacklist, pcfl);
11392         } // if
11393         
11394         /* reschedule all successors */
11395         link = setFirstItem (pcfl->to);
11396         while (link) {
11397           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11398           addSetIfnotP (&todo, link->pcflow);
11399           link = setNextItem (pcfl->to);
11400         } // while
11401       } else {
11402         deleteDefmapChain (&out_vals);        
11403       }// if
11404     } else {
11405       deleteDefmapChain (&in_vals);         
11406     } // if
11407   } // while
11408 }
11409
11410 #if 0
11411 static void showAllDefs (symbol_t sym, pCode *pc) {
11412   defmap_t *map;
11413   int count;
11414
11415   assert (isPCI(pc));
11416   count = defmapFindAll (sym, pc, &map);
11417
11418   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11419   while (map) {
11420 #if 1
11421     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11422 #else
11423     { char buf[256];
11424     pic16_pCode2str (buf, 256, map->pc);
11425     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11426 #endif
11427     map = map->next;
11428   }
11429   deleteDefmapChain (&map);
11430 }
11431 #endif
11432
11433 /* safepCodeUnlink and remove pc from defmap. */
11434 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11435   defmap_t *map, *next, **head;
11436   int res, ispci;
11437   
11438   ispci = isPCI(pc);
11439   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11440   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11441   res = pic16_safepCodeUnlink (pc, comment);
11442
11443   if (res && map) {
11444     /* remove pc from defmap */
11445     while (map) {
11446       next = map->next;
11447       if (map->pc == pc) {
11448         if (!map->prev && head) *head = map->next;
11449         deleteDefmap (map);
11450       } // if
11451       map = next;
11452     }
11453   }
11454
11455   return res;
11456 }
11457       
11458 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11459   defmap_t *map;
11460   /* This breaks the defmap chain's references to pCodes... fix it! */
11461   map = PCI(pc)->pcflow->defmap;
11462
11463   while (map && map->pc != pc) map = map->next;
11464   
11465   while (map && map->pc == pc) {
11466     map->pc = newpc;
11467     map = map->next;
11468   } // while
11469 }
11470
11471 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11472  * write accesses (isRead == 0). */
11473 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11474   defmap_t *map, *map_start;
11475   defmap_t *copy;
11476   if (!isPCI(pc)) return;
11477   if (sym == newsym) return;
11478   
11479   map = PCI(pc)->pcflow->defmap;
11480
11481   while (map && map->pc != pc) map = map->next;
11482   map_start = map;
11483   while (map && map->pc == pc) {
11484     if (map->sym == sym) {
11485       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11486       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11487         /* only one kind of access handled... this is easy */
11488         map->sym = newsym;
11489       } else {
11490         /* must copy defmap entry before replacing symbol... */
11491         copy = copyDefmap (map);
11492         if (isRead) {
11493           map->acc.access.isRead = 0;
11494           copy->acc.access.isWrite = 0;
11495         } else {
11496           map->acc.access.isWrite = 0;
11497           copy->acc.access.isRead = 0;
11498         }
11499         copy->sym = newsym;
11500         /* insert copy into defmap chain */
11501         defmapInsertAfter (map, copy);
11502       }
11503     }
11504     map = map->next;
11505   } // while
11506
11507   /* as this might introduce multiple defmap entries for newsym... */
11508   mergeDefmapSymbols (map_start);
11509 }
11510
11511 /* Assign "better" valnums to results. */
11512 static void assignValnums (pCode *pc) {
11513   pCodeInstruction *pci;
11514   pCode *newpc;
11515   symbol_t sym1, sym2;
11516   int cond, isSpecial1, isSpecial2, count, mask, lit;
11517   defmap_t *list, *val, *oldval, *dummy;
11518   regs *reg1 = NULL, *reg2 = NULL;
11519   valnum_t litnum;
11520
11521   /* only works for pCodeInstructions... */
11522   if (!isPCI(pc)) return;
11523
11524   pci = PCI(pc);
11525   cond = pci->inCond | pci->outCond;
11526   list = pci->pcflow->defmap;
11527   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11528
11529   if (cond & PCC_REGISTER) {
11530     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11531     reg1 = pic16_getRegFromInstruction (pc);
11532     isSpecial1 = pic16_symIsSpecial (sym1);
11533   }
11534   if (cond & PCC_REGISTER2) {
11535     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11536     reg2 = pic16_getRegFromInstruction (pc);
11537     isSpecial2 = pic16_symIsSpecial (sym2);
11538   }
11539
11540   /* determine input values */
11541   val = list;
11542   while (val && val->pc != pc) val = val->next;
11543   //list = val; /* might save some time later... */
11544   while (val && val->pc == pc) {
11545     val->in_val = 0;
11546     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11547       /* get valnum for sym */
11548       count = defmapFindAll (val->sym, pc, &oldval);
11549       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11550       if (count == 1) {
11551         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11552           val->in_val = oldval->val;
11553         } else {
11554           val->in_val = 0;
11555         }
11556       } else if (count == 0) {
11557         /* no definition found */
11558         val->in_val = 0;
11559       } else {
11560         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11561         assert (oldval);
11562         dummy = oldval->next;
11563         mask = oldval->acc.access.mask;
11564         val->in_val = oldval->val;
11565         while (dummy && (dummy->val == val->in_val)) {
11566           mask &= dummy->acc.access.mask;
11567           dummy = dummy->next;
11568         } // while
11569
11570         /* found other values or to restictive mask */
11571         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11572           val->in_val = 0;
11573         }
11574       }
11575       if (count > 0) deleteDefmapChain (&oldval);
11576     } // if
11577     val = val->next;
11578   }
11579
11580   /* handle valnum assignment */
11581   switch (pci->op) {
11582   case POC_CLRF: /* modifies STATUS (Z) */
11583     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11584       oldval = defmapCurr (list, sym1, pc);
11585       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11586         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11587         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11588       }
11589       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11590     }
11591     break;
11592
11593   case POC_SETF: /* SETF does not touch STATUS */
11594     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11595       oldval = defmapCurr (list, sym1, pc);
11596       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11597         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11598         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11599       }
11600       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11601     }
11602     break;
11603     
11604   case POC_MOVLW: /* does not touch STATUS */
11605     oldval = defmapCurr (list, SPO_WREG, pc);
11606     if (pci->pcop->type == PO_LITERAL) {
11607       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11608       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11609     } else {
11610       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11611       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11612     }
11613     if (oldval && oldval->in_val == litnum) {
11614       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11615       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11616     }
11617     defmapUpdate (list, SPO_WREG, pc, litnum);
11618     break;
11619
11620   case POC_ANDLW: /* modifies STATUS (Z,N) */
11621   case POC_IORLW: /* modifies STATUS (Z,N) */
11622   case POC_XORLW: /* modifies STATUS (Z,N) */
11623     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11624     if (pci->pcop->type == PO_LITERAL) {
11625       int vallit = -1;
11626       lit = (unsigned char) PCOL(pci->pcop)->lit;
11627       val = defmapCurr (list, SPO_WREG, pc);
11628       if (val) vallit = litFromValnum (val->in_val);
11629       if (vallit != -1) {
11630         /* xxxLW <literal>, WREG contains a known literal */
11631         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11632         if (pci->op == POC_ANDLW) {
11633           lit &= vallit;
11634         } else if (pci->op == POC_IORLW) {
11635           lit |= vallit;
11636         } else if (pci->op == POC_XORLW) {
11637           lit ^= vallit;
11638         } else {
11639           assert (0 && "invalid operation");
11640         }
11641         if (vallit == lit) {
11642           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11643           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11644         }
11645         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11646       } // if
11647     }
11648     break;
11649
11650   case POC_LFSR:
11651     {
11652       /* check if old value matches new value */
11653       int lit;
11654       int ok = 1;
11655       assert (pci->pcop->type == PO_LITERAL);
11656       
11657       lit = PCOL(pci->pcop)->lit;
11658       
11659       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11660       
11661       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11662         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11663       } else {
11664         /* cannot remove this LFSR */
11665         ok = 0;      
11666       } // if
11667       
11668       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11669       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11670         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11671       } else {
11672         ok = 0;
11673       } // if
11674
11675       if (ok) {
11676         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11677       }
11678     }
11679     break;
11680     
11681   case POC_MOVWF: /* does not touch flags */
11682     /* find value of WREG */
11683     val = defmapCurr (list, SPO_WREG, pc);
11684     oldval = defmapCurr (list, sym1, pc);
11685     if (val) lit = litFromValnum (val->in_val);
11686     else lit = -1;
11687     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11688     
11689     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11690       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11691       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11692       if (lit == 0) {
11693         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11694       } else {
11695         assert (lit == 0x0ff);
11696         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11697       }
11698       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11699       pic16_pCodeReplace (pc, newpc);
11700       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11701       pic16_fixDefmap (pc, newpc);
11702       pc = newpc;
11703         
11704       /* This breaks the defmap chain's references to pCodes... fix it! */
11705       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11706       if (!val->acc.access.isWrite) {
11707         deleteDefmap (val);     // delete reference to WREG as in value
11708         val = NULL;
11709       } else {
11710         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11711       }
11712       oldval = PCI(pc)->pcflow->defmap;
11713       while (oldval) {
11714         if (oldval->pc == pc) oldval->pc = newpc;
11715           oldval = oldval->next;
11716       } // while
11717     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11718       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11719       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11720     }
11721     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11722     break;
11723     
11724   case POC_MOVFW: /* modifies STATUS (Z,N) */
11725     /* find value of REG */
11726     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11727       val = defmapCurr (list, sym1, pc);
11728       oldval = defmapCurr (list, SPO_WREG, pc);
11729       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11730         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11731         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11732       }
11733       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11734     }
11735     break;
11736
11737   case POC_MOVFF: /* does not touch STATUS */
11738     /* find value of REG */
11739     val = defmapCurr (list, sym1, pc);
11740     oldval = defmapCurr (list, sym2, pc);
11741     if (val) lit = litFromValnum (val->in_val);
11742     else lit = -1;
11743     newpc = NULL;
11744     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11745       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11746       if (lit == 0) {
11747         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11748       } else if (lit == 0x00ff) {
11749         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11750       } else {
11751         newpc = NULL;
11752       }
11753       if (newpc) {
11754         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11755         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11756         pic16_pCodeReplace (pc, newpc); 
11757         defmapReplaceSymRef (pc, sym1, 0, 1);
11758         pic16_fixDefmap (pc, newpc);
11759         pc = newpc;
11760         break; // do not process instruction as MOVFF...
11761       }
11762     } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11763       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11764         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11765         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11766       } else {
11767         if (!pic16_isAlive (sym1, pc)) {
11768           defmap_t *copy = NULL;
11769           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11770            * This should help eliminate
11771            *   MOVFF A,B
11772            *   <do something not changing A or using B>
11773            *   MOVFF B,C
11774            *   <B is not alive anymore>
11775            * and turn it into
11776            *   <do something not changing A or using B>
11777            *   MOVFF A,C
11778            */
11779
11780           /* scan defmap for symbols storing sym1's value */
11781           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11782           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11783             /* unique reaching definition for sym found */
11784             if (copy->val && copy->val == val->in_val) {
11785               //fprintf (stderr, "found replacement symbol for %s (val %x) <-- %s (assigned %x @ %p)\n", strFromSym(sym1), val->in_val, strFromSym(copy->sym), copy->val, copy->pc);
11786               if (copy->sym == SPO_WREG) {
11787                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11788               } else {
11789                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11790 //                      /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11791                         pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11792                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11793               }
11794               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11795               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11796               pic16_pCodeReplace (pc, newpc); 
11797               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11798               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11799               pic16_fixDefmap (pc, newpc);
11800               pc = newpc;
11801             }
11802           }
11803           deleteDefmapChain (&copy);
11804         }
11805       }
11806       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11807     }
11808     break;
11809
11810   default:
11811     /* cannot optimize */
11812     break;
11813   } // switch
11814 }
11815
11816 static void pic16_destructDF (pBlock *pb) {
11817   pCode *pc, *next;
11818
11819   /* remove old defmaps */
11820   pc = pic16_findNextInstruction (pb->pcHead);
11821   while (pc) {
11822     next = pic16_findNextInstruction (pc->next);
11823
11824     assert (isPCI(pc) || isPCAD(pc));
11825     assert (PCI(pc)->pcflow);
11826     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11827     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11828     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11829     
11830     pc = next;
11831   } // while
11832   
11833   if (defmap_free || defmap_free_count) {
11834     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11835     freeDefmap (&defmap_free);
11836     defmap_free_count = 0;
11837   }
11838 }
11839
11840 /* Checks whether a pBlock contains ASMDIRs. */
11841 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11842   pCode *pc;
11843
11844   pc = pic16_findNextInstruction (pb->pcHead);
11845   while (pc) {
11846     if (isPCAD(pc)) return 1;
11847
11848     pc = pic16_findNextInstruction (pc->next);
11849   } // while
11850
11851   /* no PCADs found */
11852   return 0;
11853 }
11854
11855 #if 1
11856 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11857 static int pic16_removeUnusedRegistersDF () {
11858   pCode *pc, *pc2;
11859   pBlock *pb;
11860   regs *reg1, *reg2, *reg3;
11861   set *seenRegs = NULL;
11862   int cond, i;
11863   int islocal, change = 0;
11864
11865   /* no pBlocks? */
11866   if (!the_pFile || !the_pFile->pbHead) return 0;
11867   
11868   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11869     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11870 #if 1
11871     /* find set of using pCodes per register */
11872     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11873                     pc = pic16_findNextInstruction(pc->next)) {
11874
11875       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11876       reg1 = reg2 = NULL;
11877       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11878       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11879
11880       if (reg1) {
11881         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11882         addSetIfnotP (&seenRegs, reg1);
11883         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11884       }
11885       if (reg2) {
11886         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11887         addSetIfnotP (&seenRegs, reg2);
11888         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11889       }
11890     } // for pc
11891 #endif
11892     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11893       /* may not use pic16_regIsLocal() here -- in interrupt routines
11894        * WREG, PRODx, FSR0x must be saved */
11895       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11896       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11897         pc = pc2 = NULL;
11898         for (i=0; i < 2; i++) {
11899           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11900           if (!pc2) pc2 = pc;
11901           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11902           reg2 = pic16_getRegFromInstruction (pc);
11903           reg3 = pic16_getRegFromInstruction2 (pc);
11904           if (!reg2 || !reg3
11905               || (reg2->rIdx != pic16_stack_preinc->rIdx
11906                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11907           if (i == 1) {
11908             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11909             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11910             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11911             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11912           }
11913         } // for
11914       } // if
11915       deleteSet (&reg1->reglives.usedpCodes);
11916     } // for reg1
11917
11918     deleteSet (&seenRegs);
11919   } // for pb
11920
11921   return change;
11922 }
11923 #endif
11924
11925 /* Set up pCodeFlow's defmap_ts. 
11926  * Needs correctly set up to/from fields. */
11927 static void pic16_createDF (pBlock *pb) {
11928   pCode *pc, *next;
11929   int change=0;
11930
11931   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11932
11933   pic16_destructDF (pb);
11934
11935   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11936   if (pic16_pBlockHasAsmdirs (pb)) {
11937     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11938     return;
11939   }
11940
11941   /* integrity check -- we need to reach all flows to guarantee
11942    * correct data flow analysis (reaching definitions, aliveness) */
11943 #if 0
11944   if (!verifyAllFlowsReachable (pb)) {
11945     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11946     return;
11947   }
11948 #endif
11949   
11950   /* establish new defmaps */
11951   pc = pic16_findNextInstruction (pb->pcHead);
11952   while (pc) {
11953     next = pic16_findNextInstruction (pc->next);
11954
11955     assert (PCI(pc)->pcflow);
11956     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11957
11958     pc = next;
11959   } // while
11960
11961   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11962   createReachingDefinitions (pb);
11963   
11964 #if 1
11965   /* assign better valnums */
11966   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11967   pc = pic16_findNextInstruction (pb->pcHead);
11968   while (pc) {
11969     next = pic16_findNextInstruction (pc->next);
11970
11971     assert (PCI(pc)->pcflow);
11972     assignValnums (pc);
11973
11974     pc = next;
11975   } // while
11976 #endif
11977
11978 #if 1
11979   /* remove dead pCodes */
11980   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11981   do {
11982     change = 0;
11983     pc = pic16_findNextInstruction (pb->pcHead);
11984     while (pc) {
11985       next = pic16_findNextInstruction (pc->next);
11986
11987       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11988         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11989       }
11990
11991       pc = next;
11992     } // while
11993   } while (change);
11994 #endif
11995 }
11996
11997 /* ======================================================================== */
11998 /* === VCG DUMPER ROUTINES ================================================ */
11999 /* ======================================================================== */
12000 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12001 hTab *dumpedNodes = NULL;
12002
12003 /** Dump VCG header into of. */
12004 static void pic16_vcg_init (FILE *of) {
12005   /* graph defaults */
12006   fprintf (of, "graph:{\n");
12007   fprintf (of, "title:\"graph1\"\n");
12008   fprintf (of, "label:\"graph1\"\n");
12009   fprintf (of, "color:white\n");
12010   fprintf (of, "textcolor:black\n");
12011   fprintf (of, "bordercolor:black\n");
12012   fprintf (of, "borderwidth:1\n");
12013   fprintf (of, "textmode:center\n");
12014
12015   fprintf (of, "layoutalgorithm:dfs\n");
12016   fprintf (of, "late_edge_labels:yes\n");
12017   fprintf (of, "display_edge_labels:yes\n");
12018   fprintf (of, "dirty_edge_labels:yes\n");
12019   fprintf (of, "finetuning:yes\n");
12020   fprintf (of, "ignoresingles:no\n");
12021   fprintf (of, "straight_phase:yes\n");
12022   fprintf (of, "priority_phase:yes\n");
12023   fprintf (of, "manhattan_edges:yes\n");
12024   fprintf (of, "smanhattan_edges:no\n");
12025   fprintf (of, "nearedges:no\n");
12026   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12027   fprintf (of, "port_sharing:no\n");
12028   fprintf (of, "arrowmode:free\n"); // fixed|free
12029   fprintf (of, "crossingphase2:yes\n");
12030   fprintf (of, "crossingoptimization:yes\n");
12031   fprintf (of, "edges:yes\n");
12032   fprintf (of, "nodes:yes\n");
12033   fprintf (of, "splines:no\n");
12034   
12035   /* node defaults */
12036   fprintf (of, "node.color:lightyellow\n");
12037   fprintf (of, "node.textcolor:black\n");
12038   fprintf (of, "node.textmode:center\n");
12039   fprintf (of, "node.shape:box\n");
12040   fprintf (of, "node.bordercolor:black\n");
12041   fprintf (of, "node.borderwidth:1\n");
12042
12043   /* edge defaults */
12044   fprintf (of, "edge.textcolor:black\n");
12045   fprintf (of, "edge.color:black\n");
12046   fprintf (of, "edge.thickness:1\n");
12047   fprintf (of, "edge.arrowcolor:black\n");
12048   fprintf (of, "edge.backarrowcolor:black\n");
12049   fprintf (of, "edge.arrowsize:15\n");
12050   fprintf (of, "edge.backarrowsize:15\n");
12051   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12052   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12053   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12054   
12055   fprintf (of, "\n");
12056
12057   /* prepare data structures */
12058   if (dumpedNodes) {
12059     hTabDeleteAll (dumpedNodes);
12060     dumpedNodes = NULL;
12061   }
12062   dumpedNodes = newHashTable (128);
12063 }
12064
12065 /** Dump VCG footer into of. */
12066 static void pic16_vcg_close (FILE *of) {
12067   fprintf (of, "}\n");
12068 }
12069
12070 #define BUF_SIZE 128
12071 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12072
12073 #if 0
12074 static int ptrcmp (const void *p1, const void *p2) {
12075   return p1 == p2;
12076 }
12077 #endif
12078
12079 /** Dump a pCode node as VCG to of. */
12080 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12081   char buf[BUF_SIZE];
12082
12083   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12084     // dumped already
12085     return;
12086   }
12087   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12088   //fprintf (stderr, "dumping %p\n", pc);
12089  
12090   /* only dump pCodeInstructions and Flow nodes */
12091   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12092     
12093   /* emit node */
12094   fprintf (of, "node:{");
12095   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12096   fprintf (of, "label:\"%s\n", pcTitle(pc));
12097   if (isPCFL(pc)) {
12098     fprintf (of, "<PCFLOW>");
12099   } else if (isPCI(pc) || isPCAD(pc)) {
12100     pc->print (of, pc);
12101   } else {
12102     fprintf (of, "<!PCI>");
12103   }
12104   fprintf (of, "\" ");
12105   fprintf (of, "}\n");
12106   
12107   if (1 && isPCFL(pc)) {
12108     defmap_t *map, *prev;
12109     unsigned int i;
12110     map = PCFL(pc)->defmap;
12111     i=0;
12112     while (map) {
12113       if (map->sym != 0) {
12114         i++;
12115       
12116         /* emit definition node */
12117         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12118         fprintf (of, "label:\"");
12119
12120         prev = map;
12121         do {
12122           fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->acc.access.isRead ? 'R' : ' ', map->acc.access.isWrite ? 'W' : ' ', map->in_val, map->val, map->acc.access.in_mask, map->acc.access.mask, strFromSym (map->sym));
12123           prev = map;
12124           map = map->next;
12125         } while (map && prev->pc == map->pc);
12126         map = prev;
12127         
12128         fprintf (of, "\" ");
12129       
12130         fprintf (of, "color:green ");
12131         fprintf (of, "}\n");
12132
12133         /* emit edge to previous definition */
12134         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12135         if (i == 1) {
12136           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12137         } else {
12138           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12139         }
12140         fprintf (of, "color:green ");
12141         fprintf (of, "}\n");
12142
12143         if (map->pc) {
12144           pic16_vcg_dumpnode (map->pc, of);
12145           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12146           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12147         }
12148       }
12149       map = map->next;
12150     } // while
12151   }
12152
12153   /* emit additional nodes (e.g. operands) */
12154 }
12155
12156 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12157 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12158   char buf[BUF_SIZE];
12159   pCodeInstruction *pci;
12160   pBranch *curr;
12161   int i;
12162   
12163   if (1 && isPCFL(pc)) {
12164     /* emit edges to flow successors */
12165     void *pcfl;
12166     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12167     pcfl = setFirstItem (PCFL(pc)->to);
12168     while (pcfl) {
12169       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12170       pic16_vcg_dumpnode (pc, of);
12171       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12172       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12173       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12174       pcfl = setNextItem (PCFL(pc)->to);
12175     } // while
12176   } // if
12177   
12178   if (!isPCI(pc) && !isPCAD(pc)) return;
12179
12180   pci = PCI(pc);
12181   
12182   /* emit control flow edges (forward only) */
12183   curr = pci->to;
12184   i=0;
12185   while (curr) {
12186     pic16_vcg_dumpnode (curr->pc, of);
12187     fprintf (of, "edge:{");
12188     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12189     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12190     fprintf (of, "color:red ");
12191     fprintf (of, "}\n");
12192     curr = curr->next;
12193   } // while
12194
12195 #if 1
12196   /* dump "flow" edge (link pCode according to pBlock order) */
12197   {
12198     pCode *pcnext;
12199     pcnext = pic16_findNextInstruction (pc->next);
12200     if (pcnext) {
12201       pic16_vcg_dumpnode (pcnext, of);
12202       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12203       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12204     }
12205   }
12206 #endif
12207   
12208 #if 0
12209   /* emit flow */
12210   if (pci->pcflow) {
12211     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12212     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12213     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12214   }
12215 #endif
12216   
12217   /* emit data flow edges (backward only) */
12218   /* TODO: gather data flow information... */
12219 }
12220
12221 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12222   pCode *pc;
12223
12224   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12225   if (pic16_pBlockHasAsmdirs (pb)) {
12226     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12227     return;
12228   }
12229
12230   for (pc=pb->pcHead; pc; pc = pc->next) {
12231     pic16_vcg_dumpnode (pc, of);
12232   } // for pc
12233   
12234   for (pc=pb->pcHead; pc; pc = pc->next) {
12235     pic16_vcg_dumpedges (pc, of);
12236   } // for pc
12237 }
12238
12239 static void pic16_vcg_dump_default (pBlock *pb) {
12240   FILE *of;
12241   char buf[BUF_SIZE];
12242   pCode *pc;
12243
12244   /* get function name */
12245   pc = pb->pcHead;
12246   while (pc && !isPCF(pc)) pc = pc->next;
12247   if (pc) {
12248     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12249   } else {
12250     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12251   }
12252
12253   //fprintf (stderr, "now dumping %s\n", buf);
12254   of = fopen (buf, "w");
12255   pic16_vcg_init (of);
12256   pic16_vcg_dump (of, pb);
12257   pic16_vcg_close (of);
12258   fclose (of);
12259 }
12260 #endif
12261
12262 /*** END of helpers for pCode dataflow optimizations ***/