* src/pic16/pcode.c: added helpers defmapInsertAfter (insert a new item
[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 #if defined(__BORLANDC__) || defined(_MSC_VER)
36 #define STRCASECMP stricmp
37 #define inline
38 #else
39 #define STRCASECMP strcasecmp
40 #endif
41
42 #define DUMP_DF_GRAPHS 0
43
44 /****************************************************************/
45 /****************************************************************/
46
47 static peepCommand peepCommands[] = {
48
49   {NOTBITSKIP, "_NOTBITSKIP_"},
50   {BITSKIP, "_BITSKIP_"},
51   {INVERTBITSKIP, "_INVERTBITSKIP_"},
52
53   {-1, NULL}
54 };
55
56
57
58 // Eventually this will go into device dependent files:
59 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
64 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
66
67 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
68 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
69 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
70
71 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
72 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
74 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
75
76 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
77
78 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
84
85 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
86 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
90
91 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
92 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
96
97 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
98 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
102
103 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
104 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
105
106 /* EEPROM registers */
107 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
111
112 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
114 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
115
116 pCodeOpReg *pic16_stackpnt_lo;
117 pCodeOpReg *pic16_stackpnt_hi;
118 pCodeOpReg *pic16_stack_postinc;
119 pCodeOpReg *pic16_stack_postdec;
120 pCodeOpReg *pic16_stack_preinc;
121 pCodeOpReg *pic16_stack_plusw;
122
123 pCodeOpReg *pic16_framepnt_lo;
124 pCodeOpReg *pic16_framepnt_hi;
125 pCodeOpReg *pic16_frame_postinc;
126 pCodeOpReg *pic16_frame_postdec;
127 pCodeOpReg *pic16_frame_preinc;
128 pCodeOpReg *pic16_frame_plusw;
129
130 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
131 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
132
133 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
134 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
135
136
137 static int mnemonics_initialized = 0;
138
139
140 static hTab *pic16MnemonicsHash = NULL;
141 static hTab *pic16pCodePeepCommandsHash = NULL;
142
143 static pFile *the_pFile = NULL;
144 static pBlock *pb_dead_pcodes = NULL;
145
146 /* Hardcoded flags to change the behavior of the PIC port */
147 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
148 static int functionInlining = 1;      /* inline functions if nonzero */
149 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
150
151 int pic16_pcode_verbose = 0;
152
153 //static int GpCodeSequenceNumber = 1;
154 static int GpcFlowSeq = 1;
155
156 extern void pic16_RemoveUnusedRegisters(void);
157 extern void pic16_RegsUnMapLiveRanges(void);
158 extern void pic16_BuildFlowTree(pBlock *pb);
159 extern void pic16_pCodeRegOptimizeRegUsage(int level);
160 extern int pic16_picIsInitialized(void);
161 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
162 extern int mnem2key(char const *mnem);
163
164 /****************************************************************/
165 /*                      Forward declarations                    */
166 /****************************************************************/
167
168 void pic16_unlinkpCode(pCode *pc);
169 #if 0
170 static void genericAnalyze(pCode *pc);
171 static void AnalyzeGOTO(pCode *pc);
172 static void AnalyzeSKIP(pCode *pc);
173 static void AnalyzeRETURN(pCode *pc);
174 #endif
175
176 static void genericDestruct(pCode *pc);
177 static void genericPrint(FILE *of,pCode *pc);
178
179 static void pCodePrintLabel(FILE *of, pCode *pc);
180 static void pCodePrintFunction(FILE *of, pCode *pc);
181 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
182 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
183 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
184 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
185 int pic16_pCodePeepMatchRule(pCode *pc);
186 static void pBlockStats(FILE *of, pBlock *pb);
187 static pBlock *newpBlock(void);
188 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
189 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
190 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
191 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
192 void OptimizeLocalRegs(void);
193 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
194
195 char *dumpPicOptype(PIC_OPTYPE type);
196
197 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
198 pCodeOp *pic16_popGetLit(int);
199 pCodeOp *pic16_popGetWithString(char *);
200 extern int inWparamList(char *s);
201
202 /** data flow optimization helpers **/
203 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
204 static void pic16_vcg_dump (FILE *of, pBlock *pb);
205 static void pic16_vcg_dump_default (pBlock *pb);
206 #endif
207 static int pic16_pCodeIsAlive (pCode *pc);
208 static void pic16_df_stats ();
209 static void pic16_createDF (pBlock *pb);
210 static int pic16_removeUnusedRegistersDF ();
211 static void pic16_destructDF (pBlock *pb);
212 static void releaseStack ();
213
214 /****************************************************************/
215 /*                    PIC Instructions                          */
216 /****************************************************************/
217
218 pCodeInstruction pic16_pciADDWF = {
219   {PC_OPCODE, NULL, NULL, 0, NULL, 
220    //   genericAnalyze,
221    genericDestruct,
222    genericPrint},
223   POC_ADDWF,
224   "ADDWF",
225   2,
226   NULL, // from branch
227   NULL, // to branch
228   NULL, // label
229   NULL, // operand
230   NULL, // flow block
231   NULL, // C source 
232   3,    // num ops
233   1,0,  // dest, bit instruction
234   0,0,  // branch, skip
235   0,    // literal operand
236   1,    // RAM access bit
237   0,    // fast call/return mode select bit
238   0,    // second memory operand
239   0,    // second literal operand
240   POC_NOP,
241   (PCC_W | PCC_REGISTER),   // inCond
242   (PCC_REGISTER | PCC_STATUS), // outCond
243   PCI_MAGIC
244 };
245
246 pCodeInstruction pic16_pciADDFW = {
247   {PC_OPCODE, NULL, NULL, 0, NULL, 
248    //   genericAnalyze,
249    genericDestruct,
250    genericPrint},
251   POC_ADDFW,
252   "ADDWF",
253   2,
254   NULL, // from branch
255   NULL, // to branch
256   NULL, // label
257   NULL, // operand
258   NULL, // flow block
259   NULL, // C source 
260   3,    // num ops
261   0,0,  // dest, bit instruction
262   0,0,  // branch, skip
263   0,    // literal operand
264   1,    // RAM access bit
265   0,    // fast call/return mode select bit
266   0,    // second memory operand
267   0,    // second literal operand
268   POC_NOP,
269   (PCC_W | PCC_REGISTER),   // inCond
270   (PCC_W | PCC_STATUS), // outCond
271   PCI_MAGIC
272 };
273
274 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
275   {PC_OPCODE, NULL, NULL, 0, NULL, 
276    //   genericAnalyze,
277    genericDestruct,
278    genericPrint},
279   POC_ADDWFC,
280   "ADDWFC",
281   2,
282   NULL, // from branch
283   NULL, // to branch
284   NULL, // label
285   NULL, // operand
286   NULL, // flow block
287   NULL, // C source 
288   3,    // num ops
289   1,0,  // dest, bit instruction
290   0,0,  // branch, skip
291   0,    // literal operand
292   1,    // RAM access bit
293   0,    // fast call/return mode select bit
294   0,    // second memory operand
295   0,    // second literal operand
296   POC_NOP,
297   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
298   (PCC_REGISTER | PCC_STATUS), // outCond
299   PCI_MAGIC
300 };
301
302 pCodeInstruction pic16_pciADDFWC = {
303   {PC_OPCODE, NULL, NULL, 0, NULL, 
304    //   genericAnalyze,
305    genericDestruct,
306    genericPrint},
307   POC_ADDFWC,
308   "ADDWFC",
309   2,
310   NULL, // from branch
311   NULL, // to branch
312   NULL, // label
313   NULL, // operand
314   NULL, // flow block
315   NULL, // C source 
316   3,    // num ops
317   0,0,  // dest, bit instruction
318   0,0,  // branch, skip
319   0,    // literal operand
320   1,    // RAM access bit
321   0,    // fast call/return mode select bit
322   0,    // second memory operand
323   0,    // second literal operand
324   POC_NOP,
325   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
326   (PCC_W | PCC_STATUS), // outCond
327   PCI_MAGIC
328 };
329
330 pCodeInstruction pic16_pciADDLW = {
331   {PC_OPCODE, NULL, NULL, 0, NULL, 
332    //   genericAnalyze,
333    genericDestruct,
334    genericPrint},
335   POC_ADDLW,
336   "ADDLW",
337   2,
338   NULL, // from branch
339   NULL, // to branch
340   NULL, // label
341   NULL, // operand
342   NULL, // flow block
343   NULL, // C source 
344   1,    // num ops
345   0,0,  // dest, bit instruction
346   0,0,  // branch, skip
347   1,    // literal operand
348   0,    // RAM access bit
349   0,    // fast call/return mode select bit
350   0,    // second memory operand
351   0,    // second literal operand
352   POC_NOP,
353   (PCC_W | PCC_LITERAL),   // inCond
354   (PCC_W | PCC_STATUS), // outCond
355   PCI_MAGIC
356 };
357
358 pCodeInstruction pic16_pciANDLW = {
359   {PC_OPCODE, NULL, NULL, 0, NULL, 
360    //   genericAnalyze,
361    genericDestruct,
362    genericPrint},
363   POC_ANDLW,
364   "ANDLW",
365   2,
366   NULL, // from branch
367   NULL, // to branch
368   NULL, // label
369   NULL, // operand
370   NULL, // flow block
371   NULL, // C source 
372   1,    // num ops
373   0,0,  // dest, bit instruction
374   0,0,  // branch, skip
375   1,    // literal operand
376   0,    // RAM access bit
377   0,    // fast call/return mode select bit
378   0,    // second memory operand
379   0,    // second literal operand
380   POC_NOP,
381   (PCC_W | PCC_LITERAL),   // inCond
382   (PCC_W | PCC_Z | PCC_N), // outCond
383   PCI_MAGIC
384 };
385
386 pCodeInstruction pic16_pciANDWF = {
387   {PC_OPCODE, NULL, NULL, 0, NULL, 
388    //   genericAnalyze,
389    genericDestruct,
390    genericPrint},
391   POC_ANDWF,
392   "ANDWF",
393   2,
394   NULL, // from branch
395   NULL, // to branch
396   NULL, // label
397   NULL, // operand
398   NULL, // flow block
399   NULL, // C source 
400   3,    // num ops
401   1,0,  // dest, bit instruction
402   0,0,  // branch, skip
403   0,    // literal operand
404   1,    // RAM access bit
405   0,    // fast call/return mode select bit
406   0,    // second memory operand
407   0,    // second literal operand
408   POC_NOP,
409   (PCC_W | PCC_REGISTER),   // inCond
410   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
411   PCI_MAGIC
412 };
413
414 pCodeInstruction pic16_pciANDFW = {
415   {PC_OPCODE, NULL, NULL, 0, NULL, 
416    //   genericAnalyze,
417    genericDestruct,
418    genericPrint},
419   POC_ANDFW,
420   "ANDWF",
421   2,
422   NULL, // from branch
423   NULL, // to branch
424   NULL, // label
425   NULL, // operand
426   NULL, // flow block
427   NULL, // C source 
428   3,    // num ops
429   0,0,  // dest, bit instruction
430   0,0,  // branch, skip
431   0,    // literal operand
432   1,    // RAM access bit
433   0,    // fast call/return mode select bit
434   0,    // second memory operand
435   0,    // second literal operand
436   POC_NOP,
437   (PCC_W | PCC_REGISTER),   // inCond
438   (PCC_W | PCC_Z | PCC_N) // outCond
439 };
440
441 pCodeInstruction pic16_pciBC = { // mdubuc - New
442   {PC_OPCODE, NULL, NULL, 0, NULL, 
443    //   genericAnalyze,
444    genericDestruct,
445    genericPrint},
446   POC_BC,
447   "BC",
448   2,
449   NULL, // from branch
450   NULL, // to branch
451   NULL, // label
452   NULL, // operand
453   NULL, // flow block
454   NULL, // C source 
455   1,    // num ops
456   0,0,  // dest, bit instruction
457   1,0,  // branch, skip
458   0,    // literal operand
459   0,    // RAM access bit
460   0,    // fast call/return mode select bit
461   0,    // second memory operand
462   0,    // second literal operand
463   POC_NOP,
464   (PCC_REL_ADDR | PCC_C),   // inCond
465   PCC_NONE,    // outCond
466   PCI_MAGIC
467 };
468
469 pCodeInstruction pic16_pciBCF = {
470   {PC_OPCODE, NULL, NULL, 0, NULL, 
471    //   genericAnalyze,
472    genericDestruct,
473    genericPrint},
474   POC_BCF,
475   "BCF",
476   2,
477   NULL, // from branch
478   NULL, // to branch
479   NULL, // label
480   NULL, // operand
481   NULL, // flow block
482   NULL, // C source 
483   3,    // num ops
484   1,1,  // dest, bit instruction
485   0,0,  // branch, skip
486   0,    // literal operand
487   1,    // RAM access bit
488   0,    // fast call/return mode select bit
489   0,    // second memory operand
490   0,    // second literal operand
491   POC_BSF,
492   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
493   PCC_REGISTER, // outCond
494   PCI_MAGIC
495 };
496
497 pCodeInstruction pic16_pciBN = { // mdubuc - New
498   {PC_OPCODE, NULL, NULL, 0, NULL, 
499    //   genericAnalyze,
500    genericDestruct,
501    genericPrint},
502   POC_BN,
503   "BN",
504   2,
505   NULL, // from branch
506   NULL, // to branch
507   NULL, // label
508   NULL, // operand
509   NULL, // flow block
510   NULL, // C source 
511   1,    // num ops
512   0,0,  // dest, bit instruction
513   1,0,  // branch, skip
514   0,    // literal operand
515   0,    // RAM access bit
516   0,    // fast call/return mode select bit
517   0,    // second memory operand
518   0,    // second literal operand
519   POC_NOP,
520   (PCC_REL_ADDR | PCC_N),   // inCond
521   PCC_NONE   , // outCond
522   PCI_MAGIC
523 };
524
525 pCodeInstruction pic16_pciBNC = { // mdubuc - New
526   {PC_OPCODE, NULL, NULL, 0, NULL, 
527    //   genericAnalyze,
528    genericDestruct,
529    genericPrint},
530   POC_BNC,
531   "BNC",
532   2,
533   NULL, // from branch
534   NULL, // to branch
535   NULL, // label
536   NULL, // operand
537   NULL, // flow block
538   NULL, // C source 
539   1,    // num ops
540   0,0,  // dest, bit instruction
541   1,0,  // branch, skip
542   0,    // literal operand
543   0,    // RAM access bit
544   0,    // fast call/return mode select bit
545   0,    // second memory operand
546   0,    // second literal operand
547   POC_NOP,
548   (PCC_REL_ADDR | PCC_C),   // inCond
549   PCC_NONE   , // outCond
550   PCI_MAGIC
551 };
552
553 pCodeInstruction pic16_pciBNN = { // mdubuc - New
554   {PC_OPCODE, NULL, NULL, 0, NULL, 
555    //   genericAnalyze,
556    genericDestruct,
557    genericPrint},
558   POC_BNN,
559   "BNN",
560   2,
561   NULL, // from branch
562   NULL, // to branch
563   NULL, // label
564   NULL, // operand
565   NULL, // flow block
566   NULL, // C source 
567   1,    // num ops
568   0,0,  // dest, bit instruction
569   1,0,  // branch, skip
570   0,    // literal operand
571   0,    // RAM access bit
572   0,    // fast call/return mode select bit
573   0,    // second memory operand
574   0,    // second literal operand
575   POC_NOP,
576   (PCC_REL_ADDR | PCC_N),   // inCond
577   PCC_NONE   , // outCond
578   PCI_MAGIC
579 };
580
581 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
582   {PC_OPCODE, NULL, NULL, 0, NULL, 
583    //   genericAnalyze,
584    genericDestruct,
585    genericPrint},
586   POC_BNOV,
587   "BNOV",
588   2,
589   NULL, // from branch
590   NULL, // to branch
591   NULL, // label
592   NULL, // operand
593   NULL, // flow block
594   NULL, // C source 
595   1,    // num ops
596   0,0,  // dest, bit instruction
597   1,0,  // branch, skip
598   0,    // literal operand
599   0,    // RAM access bit
600   0,    // fast call/return mode select bit
601   0,    // second memory operand
602   0,    // second literal operand
603   POC_NOP,
604   (PCC_REL_ADDR | PCC_OV),   // inCond
605   PCC_NONE   , // outCond
606   PCI_MAGIC
607 };
608
609 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
610   {PC_OPCODE, NULL, NULL, 0, NULL, 
611    //   genericAnalyze,
612    genericDestruct,
613    genericPrint},
614   POC_BNZ,
615   "BNZ",
616   2,
617   NULL, // from branch
618   NULL, // to branch
619   NULL, // label
620   NULL, // operand
621   NULL, // flow block
622   NULL, // C source 
623   1,    // num ops
624   0,0,  // dest, bit instruction
625   1,0,  // branch, skip
626   0,    // literal operand
627   0,    // RAM access bit
628   0,    // fast call/return mode select bit
629   0,    // second memory operand
630   0,    // second literal operand
631   POC_NOP,
632   (PCC_REL_ADDR | PCC_Z),   // inCond
633   PCC_NONE   , // outCond
634   PCI_MAGIC
635 };
636
637 pCodeInstruction pic16_pciBOV = { // mdubuc - New
638   {PC_OPCODE, NULL, NULL, 0, NULL, 
639    //   genericAnalyze,
640    genericDestruct,
641    genericPrint},
642   POC_BOV,
643   "BOV",
644   2,
645   NULL, // from branch
646   NULL, // to branch
647   NULL, // label
648   NULL, // operand
649   NULL, // flow block
650   NULL, // C source 
651   1,    // num ops
652   0,0,  // dest, bit instruction
653   1,0,  // branch, skip
654   0,    // literal operand
655   0,    // RAM access bit
656   0,    // fast call/return mode select bit
657   0,    // second memory operand
658   0,    // second literal operand
659   POC_NOP,
660   (PCC_REL_ADDR | PCC_OV),   // inCond
661   PCC_NONE , // outCond
662   PCI_MAGIC
663 };
664
665 pCodeInstruction pic16_pciBRA = { // mdubuc - New
666   {PC_OPCODE, NULL, NULL, 0, NULL, 
667    //   genericAnalyze,
668    genericDestruct,
669    genericPrint},
670   POC_BRA,
671   "BRA",
672   2,
673   NULL, // from branch
674   NULL, // to branch
675   NULL, // label
676   NULL, // operand
677   NULL, // flow block
678   NULL, // C source 
679   1,    // num ops
680   0,0,  // dest, bit instruction
681   1,0,  // branch, skip
682   0,    // literal operand
683   0,    // RAM access bit
684   0,    // fast call/return mode select bit
685   0,    // second memory operand
686   0,    // second literal operand
687   POC_NOP,
688   PCC_REL_ADDR,   // inCond
689   PCC_NONE   , // outCond
690   PCI_MAGIC
691 };
692
693 pCodeInstruction pic16_pciBSF = {
694   {PC_OPCODE, NULL, NULL, 0, NULL, 
695    //   genericAnalyze,
696    genericDestruct,
697    genericPrint},
698   POC_BSF,
699   "BSF",
700   2,
701   NULL, // from branch
702   NULL, // to branch
703   NULL, // label
704   NULL, // operand
705   NULL, // flow block
706   NULL, // C source 
707   3,    // num ops
708   1,1,  // dest, bit instruction
709   0,0,  // branch, skip
710   0,    // literal operand
711   1,    // RAM access bit
712   0,    // fast call/return mode select bit
713   0,    // second memory operand
714   0,    // second literal operand
715   POC_BCF,
716   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
717   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
718   PCI_MAGIC
719 };
720
721 pCodeInstruction pic16_pciBTFSC = {
722   {PC_OPCODE, NULL, NULL, 0, NULL, 
723    //   AnalyzeSKIP,
724    genericDestruct,
725    genericPrint},
726   POC_BTFSC,
727   "BTFSC",
728   2,
729   NULL, // from branch
730   NULL, // to branch
731   NULL, // label
732   NULL, // operand
733   NULL, // flow block
734   NULL, // C source 
735   3,    // num ops
736   0,1,  // dest, bit instruction
737   1,1,  // branch, skip
738   0,    // literal operand
739   1,    // RAM access bit
740   0,    // fast call/return mode select bit
741   0,    // second memory operand
742   0,    // second literal operand
743   POC_BTFSS,
744   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
745   PCC_EXAMINE_PCOP, // outCond
746   PCI_MAGIC
747 };
748
749 pCodeInstruction pic16_pciBTFSS = {
750   {PC_OPCODE, NULL, NULL, 0, NULL, 
751    //   AnalyzeSKIP,
752    genericDestruct,
753    genericPrint},
754   POC_BTFSS,
755   "BTFSS",
756   2,
757   NULL, // from branch
758   NULL, // to branch
759   NULL, // label
760   NULL, // operand
761   NULL, // flow block
762   NULL, // C source 
763   3,    // num ops
764   0,1,  // dest, bit instruction
765   1,1,  // branch, skip
766   0,    // literal operand
767   1,    // RAM access bit
768   0,    // fast call/return mode select bit
769   0,    // second memory operand
770   0,    // second literal operand
771   POC_BTFSC,
772   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
773   PCC_EXAMINE_PCOP, // outCond
774   PCI_MAGIC
775 };
776
777 pCodeInstruction pic16_pciBTG = { // mdubuc - New
778   {PC_OPCODE, NULL, NULL, 0, NULL, 
779    //   genericAnalyze,
780    genericDestruct,
781    genericPrint},
782   POC_BTG,
783   "BTG",
784   2,
785   NULL, // from branch
786   NULL, // to branch
787   NULL, // label
788   NULL, // operand
789   NULL, // flow block
790   NULL, // C source 
791   3,    // num ops
792   0,1,  // dest, bit instruction
793   0,0,  // branch, skip
794   0,    // literal operand
795   1,    // RAM access bit
796   0,    // fast call/return mode select bit
797   0,    // second memory operand
798   0,    // second literal operand
799   POC_NOP,
800   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
801   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
802   PCI_MAGIC
803 };
804
805 pCodeInstruction pic16_pciBZ = { // mdubuc - New
806   {PC_OPCODE, NULL, NULL, 0, NULL, 
807    //   genericAnalyze,
808    genericDestruct,
809    genericPrint},
810   POC_BZ,
811   "BZ",
812   2,
813   NULL, // from branch
814   NULL, // to branch
815   NULL, // label
816   NULL, // operand
817   NULL, // flow block
818   NULL, // C source 
819   1,    // num ops
820   0,0,  // dest, bit instruction
821   1,0,  // branch, skip
822   0,    // literal operand
823   0,    // RAM access bit
824   0,    // fast call/return mode select bit
825   0,    // second memory operand
826   0,    // second literal operand
827   POC_NOP,
828   (PCC_REL_ADDR | PCC_Z),   // inCond
829   PCC_NONE, // outCond
830   PCI_MAGIC
831 };
832
833 pCodeInstruction pic16_pciCALL = {
834   {PC_OPCODE, NULL, NULL, 0, NULL, 
835    //   genericAnalyze,
836    genericDestruct,
837    genericPrint},
838   POC_CALL,
839   "CALL",
840   4,
841   NULL, // from branch
842   NULL, // to branch
843   NULL, // label
844   NULL, // operand
845   NULL, // flow block
846   NULL, // C source 
847   2,    // num ops
848   0,0,  // dest, bit instruction
849   1,0,  // branch, skip
850   0,    // literal operand
851   0,    // RAM access bit
852   1,    // fast call/return mode select bit
853   0,    // second memory operand
854   0,    // second literal operand
855   POC_NOP,
856   PCC_NONE, // inCond
857   PCC_NONE, // outCond
858   PCI_MAGIC
859 };
860
861 pCodeInstruction pic16_pciCOMF = {
862   {PC_OPCODE, NULL, NULL, 0, NULL, 
863    //   genericAnalyze,
864    genericDestruct,
865    genericPrint},
866   POC_COMF,
867   "COMF",
868   2,
869   NULL, // from branch
870   NULL, // to branch
871   NULL, // label
872   NULL, // operand
873   NULL, // flow block
874   NULL, // C source 
875   3,    // num ops
876   1,0,  // dest, bit instruction
877   0,0,  // branch, skip
878   0,    // literal operand
879   1,    // RAM access bit
880   0,    // fast call/return mode select bit
881   0,    // second memory operand
882   0,    // second literal operand
883   POC_NOP,
884   PCC_REGISTER,  // inCond
885   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
886   PCI_MAGIC
887 };
888
889 pCodeInstruction pic16_pciCOMFW = {
890   {PC_OPCODE, NULL, NULL, 0, NULL, 
891    //   genericAnalyze,
892    genericDestruct,
893    genericPrint},
894   POC_COMFW,
895   "COMF",
896   2,
897   NULL, // from branch
898   NULL, // to branch
899   NULL, // label
900   NULL, // operand
901   NULL, // flow block
902   NULL, // C source 
903   3,    // num ops
904   0,0,  // dest, bit instruction
905   0,0,  // branch, skip
906   0,    // literal operand
907   1,    // RAM access bit
908   0,    // fast call/return mode select bit
909   0,    // second memory operand
910   0,    // second literal operand
911   POC_NOP,
912   PCC_REGISTER,  // inCond
913   (PCC_W | PCC_Z | PCC_N) , // outCond
914   PCI_MAGIC
915 };
916
917 pCodeInstruction pic16_pciCLRF = {
918   {PC_OPCODE, NULL, NULL, 0, NULL, 
919    //   genericAnalyze,
920    genericDestruct,
921    genericPrint},
922   POC_CLRF,
923   "CLRF",
924   2,
925   NULL, // from branch
926   NULL, // to branch
927   NULL, // label
928   NULL, // operand
929   NULL, // flow block
930   NULL, // C source 
931   2,    // num ops
932   0,0,  // dest, bit instruction
933   0,0,  // branch, skip
934   0,    // literal operand
935   1,    // RAM access bit
936   0,    // fast call/return mode select bit
937   0,    // second memory operand
938   0,    // second literal operand
939   POC_NOP,
940   PCC_NONE, // inCond
941   (PCC_REGISTER | PCC_Z), // outCond
942   PCI_MAGIC
943 };
944
945 pCodeInstruction pic16_pciCLRWDT = {
946   {PC_OPCODE, NULL, NULL, 0, NULL, 
947    //   genericAnalyze,
948    genericDestruct,
949    genericPrint},
950   POC_CLRWDT,
951   "CLRWDT",
952   2,
953   NULL, // from branch
954   NULL, // to branch
955   NULL, // label
956   NULL, // operand
957   NULL, // flow block
958   NULL, // C source 
959   0,    // num ops
960   0,0,  // dest, bit instruction
961   0,0,  // branch, skip
962   0,    // literal operand
963   0,    // RAM access bit
964   0,    // fast call/return mode select bit
965   0,    // second memory operand
966   0,    // second literal operand
967   POC_NOP,
968   PCC_NONE, // inCond
969   PCC_NONE , // outCond
970   PCI_MAGIC
971 };
972
973 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
974   {PC_OPCODE, NULL, NULL, 0, NULL, 
975    //   genericAnalyze,
976    genericDestruct,
977    genericPrint},
978   POC_CPFSEQ,
979   "CPFSEQ",
980   2,
981   NULL, // from branch
982   NULL, // to branch
983   NULL, // label
984   NULL, // operand
985   NULL, // flow block
986   NULL, // C source 
987   2,    // num ops
988   0,0,  // dest, bit instruction
989   1,1,  // branch, skip
990   0,    // literal operand
991   1,    // RAM access bit
992   0,    // fast call/return mode select bit
993   0,    // second memory operand
994   0,    // second literal operand
995   POC_NOP,
996   (PCC_W | PCC_REGISTER), // inCond
997   PCC_NONE , // outCond
998   PCI_MAGIC
999 };
1000
1001 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1002   {PC_OPCODE, NULL, NULL, 0, NULL, 
1003    //   genericAnalyze,
1004    genericDestruct,
1005    genericPrint},
1006   POC_CPFSGT,
1007   "CPFSGT",
1008   2,
1009   NULL, // from branch
1010   NULL, // to branch
1011   NULL, // label
1012   NULL, // operand
1013   NULL, // flow block
1014   NULL, // C source 
1015   2,    // num ops
1016   0,0,  // dest, bit instruction
1017   1,1,  // branch, skip
1018   0,    // literal operand
1019   1,    // RAM access bit
1020   0,    // fast call/return mode select bit
1021   0,    // second memory operand
1022   0,    // second literal operand
1023   POC_NOP,
1024   (PCC_W | PCC_REGISTER), // inCond
1025   PCC_NONE , // outCond
1026   PCI_MAGIC
1027 };
1028
1029 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1030   {PC_OPCODE, NULL, NULL, 0, NULL, 
1031    //   genericAnalyze,
1032    genericDestruct,
1033    genericPrint},
1034   POC_CPFSLT,
1035   "CPFSLT",
1036   2,
1037   NULL, // from branch
1038   NULL, // to branch
1039   NULL, // label
1040   NULL, // operand
1041   NULL, // flow block
1042   NULL, // C source 
1043   2,    // num ops
1044   1,0,  // dest, bit instruction
1045   1,1,  // branch, skip
1046   0,    // literal operand
1047   1,    // RAM access bit
1048   0,    // fast call/return mode select bit
1049   0,    // second memory operand
1050   0,    // second literal operand
1051   POC_NOP,
1052   (PCC_W | PCC_REGISTER), // inCond
1053   PCC_NONE , // outCond
1054   PCI_MAGIC
1055 };
1056
1057 pCodeInstruction pic16_pciDAW = {
1058   {PC_OPCODE, NULL, NULL, 0, NULL, 
1059    //   genericAnalyze,
1060    genericDestruct,
1061    genericPrint},
1062   POC_DAW,
1063   "DAW",
1064   2,
1065   NULL, // from branch
1066   NULL, // to branch
1067   NULL, // label
1068   NULL, // operand
1069   NULL, // flow block
1070   NULL, // C source 
1071   0,    // num ops
1072   0,0,  // dest, bit instruction
1073   0,0,  // branch, skip
1074   0,    // literal operand
1075   0,    // RAM access bit
1076   0,    // fast call/return mode select bit
1077   0,    // second memory operand
1078   0,    // second literal operand
1079   POC_NOP,
1080   PCC_W, // inCond
1081   (PCC_W | PCC_C), // outCond
1082   PCI_MAGIC
1083 };
1084
1085 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1086   {PC_OPCODE, NULL, NULL, 0, NULL, 
1087    //   genericAnalyze,
1088    genericDestruct,
1089    genericPrint},
1090   POC_DCFSNZ,
1091   "DCFSNZ",
1092   2,
1093   NULL, // from branch
1094   NULL, // to branch
1095   NULL, // label
1096   NULL, // operand
1097   NULL, // flow block
1098   NULL, // C source 
1099   3,    // num ops
1100   1,0,  // dest, bit instruction
1101   1,1,  // branch, skip
1102   0,    // literal operand
1103   1,    // RAM access bit
1104   0,    // fast call/return mode select bit
1105   0,    // second memory operand
1106   0,    // second literal operand
1107   POC_NOP,
1108   PCC_REGISTER, // inCond
1109   PCC_REGISTER , // outCond
1110   PCI_MAGIC
1111 };
1112
1113 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1114   {PC_OPCODE, NULL, NULL, 0, NULL, 
1115    //   genericAnalyze,
1116    genericDestruct,
1117    genericPrint},
1118   POC_DCFSNZW,
1119   "DCFSNZ",
1120   2,
1121   NULL, // from branch
1122   NULL, // to branch
1123   NULL, // label
1124   NULL, // operand
1125   NULL, // flow block
1126   NULL, // C source 
1127   3,    // num ops
1128   0,0,  // dest, bit instruction
1129   1,1,  // branch, skip
1130   0,    // literal operand
1131   1,    // RAM access bit
1132   0,    // fast call/return mode select bit
1133   0,    // second memory operand
1134   0,    // second literal operand
1135   POC_NOP,
1136   PCC_REGISTER, // inCond
1137   PCC_W , // outCond
1138   PCI_MAGIC
1139 };
1140
1141 pCodeInstruction pic16_pciDECF = {
1142   {PC_OPCODE, NULL, NULL, 0, NULL, 
1143    //   genericAnalyze,
1144    genericDestruct,
1145    genericPrint},
1146   POC_DECF,
1147   "DECF",
1148   2,
1149   NULL, // from branch
1150   NULL, // to branch
1151   NULL, // label
1152   NULL, // operand
1153   NULL, // flow block
1154   NULL, // C source 
1155   3,    // num ops
1156   1,0,  // dest, bit instruction
1157   0,0,  // branch, skip
1158   0,    // literal operand
1159   1,    // RAM access bit
1160   0,    // fast call/return mode select bit
1161   0,    // second memory operand
1162   0,    // second literal operand
1163   POC_NOP,
1164   PCC_REGISTER,   // inCond
1165   (PCC_REGISTER | PCC_STATUS)  , // outCond
1166   PCI_MAGIC
1167 };
1168
1169 pCodeInstruction pic16_pciDECFW = {
1170   {PC_OPCODE, NULL, NULL, 0, NULL, 
1171    //   genericAnalyze,
1172    genericDestruct,
1173    genericPrint},
1174   POC_DECFW,
1175   "DECF",
1176   2,
1177   NULL, // from branch
1178   NULL, // to branch
1179   NULL, // label
1180   NULL, // operand
1181   NULL, // flow block
1182   NULL, // C source 
1183   3,    // num ops
1184   0,0,  // dest, bit instruction
1185   0,0,  // branch, skip
1186   0,    // literal operand
1187   1,    // RAM access bit
1188   0,    // fast call/return mode select bit
1189   0,    // second memory operand
1190   0,    // second literal operand
1191   POC_NOP,
1192   PCC_REGISTER,   // inCond
1193   (PCC_W | PCC_STATUS)  , // outCond
1194   PCI_MAGIC
1195 };
1196
1197 pCodeInstruction pic16_pciDECFSZ = {
1198   {PC_OPCODE, NULL, NULL, 0, NULL, 
1199    //   AnalyzeSKIP,
1200    genericDestruct,
1201    genericPrint},
1202   POC_DECFSZ,
1203   "DECFSZ",
1204   2,
1205   NULL, // from branch
1206   NULL, // to branch
1207   NULL, // label
1208   NULL, // operand
1209   NULL, // flow block
1210   NULL, // C source 
1211   3,    // num ops
1212   1,0,  // dest, bit instruction
1213   1,1,  // branch, skip
1214   0,    // literal operand
1215   1,    // RAM access bit
1216   0,    // fast call/return mode select bit
1217   0,    // second memory operand
1218   0,    // second literal operand
1219   POC_NOP,
1220   PCC_REGISTER,   // inCond
1221   PCC_REGISTER   , // outCond
1222   PCI_MAGIC
1223 };
1224
1225 pCodeInstruction pic16_pciDECFSZW = {
1226   {PC_OPCODE, NULL, NULL, 0, NULL, 
1227    //   AnalyzeSKIP,
1228    genericDestruct,
1229    genericPrint},
1230   POC_DECFSZW,
1231   "DECFSZ",
1232   2,
1233   NULL, // from branch
1234   NULL, // to branch
1235   NULL, // label
1236   NULL, // operand
1237   NULL, // flow block
1238   NULL, // C source 
1239   3,    // num ops
1240   0,0,  // dest, bit instruction
1241   1,1,  // branch, skip
1242   0,    // literal operand
1243   1,    // RAM access bit
1244   0,    // fast call/return mode select bit
1245   0,    // second memory operand
1246   0,    // second literal operand
1247   POC_NOP,
1248   PCC_REGISTER,   // inCond
1249   PCC_W          , // outCond
1250   PCI_MAGIC
1251 };
1252
1253 pCodeInstruction pic16_pciGOTO = {
1254   {PC_OPCODE, NULL, NULL, 0, NULL, 
1255    //   AnalyzeGOTO,
1256    genericDestruct,
1257    genericPrint},
1258   POC_GOTO,
1259   "GOTO",
1260   4,
1261   NULL, // from branch
1262   NULL, // to branch
1263   NULL, // label
1264   NULL, // operand
1265   NULL, // flow block
1266   NULL, // C source 
1267   1,    // num ops
1268   0,0,  // dest, bit instruction
1269   1,0,  // branch, skip
1270   0,    // literal operand
1271   0,    // RAM access bit
1272   0,    // fast call/return mode select bit
1273   0,    // second memory operand
1274   0,    // second literal operand
1275   POC_NOP,
1276   PCC_REL_ADDR,   // inCond
1277   PCC_NONE   , // outCond
1278   PCI_MAGIC
1279 };
1280
1281 pCodeInstruction pic16_pciINCF = {
1282   {PC_OPCODE, NULL, NULL, 0, NULL, 
1283    //   genericAnalyze,
1284    genericDestruct,
1285    genericPrint},
1286   POC_INCF,
1287   "INCF",
1288   2,
1289   NULL, // from branch
1290   NULL, // to branch
1291   NULL, // label
1292   NULL, // operand
1293   NULL, // flow block
1294   NULL, // C source 
1295   3,    // num ops
1296   1,0,  // dest, bit instruction
1297   0,0,  // branch, skip
1298   0,    // literal operand
1299   1,    // RAM access bit
1300   0,    // fast call/return mode select bit
1301   0,    // second memory operand
1302   0,    // second literal operand
1303   POC_NOP,
1304   PCC_REGISTER,   // inCond
1305   (PCC_REGISTER | PCC_STATUS), // outCond
1306   PCI_MAGIC
1307 };
1308
1309 pCodeInstruction pic16_pciINCFW = {
1310   {PC_OPCODE, NULL, NULL, 0, NULL, 
1311    //   genericAnalyze,
1312    genericDestruct,
1313    genericPrint},
1314   POC_INCFW,
1315   "INCF",
1316   2,
1317   NULL, // from branch
1318   NULL, // to branch
1319   NULL, // label
1320   NULL, // operand
1321   NULL, // flow block
1322   NULL, // C source 
1323   3,    // num ops
1324   0,0,  // dest, bit instruction
1325   0,0,  // branch, skip
1326   0,    // literal operand
1327   1,    // RAM access bit
1328   0,    // fast call/return mode select bit
1329   0,    // second memory operand
1330   0,    // second literal operand
1331   POC_NOP,
1332   PCC_REGISTER,   // inCond
1333   (PCC_W | PCC_STATUS)  , // outCond
1334   PCI_MAGIC
1335 };
1336
1337 pCodeInstruction pic16_pciINCFSZ = {
1338   {PC_OPCODE, NULL, NULL, 0, NULL, 
1339    //   AnalyzeSKIP,
1340    genericDestruct,
1341    genericPrint},
1342   POC_INCFSZ,
1343   "INCFSZ",
1344   2,
1345   NULL, // from branch
1346   NULL, // to branch
1347   NULL, // label
1348   NULL, // operand
1349   NULL, // flow block
1350   NULL, // C source 
1351   3,    // num ops
1352   1,0,  // dest, bit instruction
1353   1,1,  // branch, skip
1354   0,    // literal operand
1355   1,    // RAM access bit
1356   0,    // fast call/return mode select bit
1357   0,    // second memory operand
1358   0,    // second literal operand
1359   POC_INFSNZ,
1360   PCC_REGISTER,   // inCond
1361   PCC_REGISTER   , // outCond
1362   PCI_MAGIC
1363 };
1364
1365 pCodeInstruction pic16_pciINCFSZW = {
1366   {PC_OPCODE, NULL, NULL, 0, NULL, 
1367    //   AnalyzeSKIP,
1368    genericDestruct,
1369    genericPrint},
1370   POC_INCFSZW,
1371   "INCFSZ",
1372   2,
1373   NULL, // from branch
1374   NULL, // to branch
1375   NULL, // label
1376   NULL, // operand
1377   NULL, // flow block
1378   NULL, // C source 
1379   3,    // num ops
1380   0,0,  // dest, bit instruction
1381   1,1,  // branch, skip
1382   0,    // literal operand
1383   1,    // RAM access bit
1384   0,    // fast call/return mode select bit
1385   0,    // second memory operand
1386   0,    // second literal operand
1387   POC_INFSNZW,
1388   PCC_REGISTER,   // inCond
1389   PCC_W          , // outCond
1390   PCI_MAGIC
1391 };
1392
1393 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1394   {PC_OPCODE, NULL, NULL, 0, NULL, 
1395    //   AnalyzeSKIP,
1396    genericDestruct,
1397    genericPrint},
1398   POC_INFSNZ,
1399   "INFSNZ",
1400   2,
1401   NULL, // from branch
1402   NULL, // to branch
1403   NULL, // label
1404   NULL, // operand
1405   NULL, // flow block
1406   NULL, // C source 
1407   3,    // num ops
1408   1,0,  // dest, bit instruction
1409   1,1,  // branch, skip
1410   0,    // literal operand
1411   1,    // RAM access bit
1412   0,    // fast call/return mode select bit
1413   0,    // second memory operand
1414   0,    // second literal operand
1415   POC_INCFSZ,
1416   PCC_REGISTER,   // inCond
1417   PCC_REGISTER   , // outCond
1418   PCI_MAGIC
1419 };
1420
1421 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1422   {PC_OPCODE, NULL, NULL, 0, NULL, 
1423    //   AnalyzeSKIP,
1424    genericDestruct,
1425    genericPrint},
1426   POC_INFSNZW,
1427   "INFSNZ",
1428   2,
1429   NULL, // from branch
1430   NULL, // to branch
1431   NULL, // label
1432   NULL, // operand
1433   NULL, // flow block
1434   NULL, // C source 
1435   3,    // num ops
1436   0,0,  // dest, bit instruction
1437   1,1,  // branch, skip
1438   0,    // literal operand
1439   1,    // RAM access bit
1440   0,    // fast call/return mode select bit
1441   0,    // second memory operand
1442   0,    // second literal operand
1443   POC_INCFSZW,
1444   PCC_REGISTER,   // inCond
1445   PCC_W          , // outCond
1446   PCI_MAGIC
1447 };
1448
1449 pCodeInstruction pic16_pciIORWF = {
1450   {PC_OPCODE, NULL, NULL, 0, NULL, 
1451    //   genericAnalyze,
1452    genericDestruct,
1453    genericPrint},
1454   POC_IORWF,
1455   "IORWF",
1456   2,
1457   NULL, // from branch
1458   NULL, // to branch
1459   NULL, // label
1460   NULL, // operand
1461   NULL, // flow block
1462   NULL, // C source 
1463   3,    // num ops
1464   1,0,  // dest, bit instruction
1465   0,0,  // branch, skip
1466   0,    // literal operand
1467   1,    // RAM access bit
1468   0,    // fast call/return mode select bit
1469   0,    // second memory operand
1470   0,    // second literal operand
1471   POC_NOP,
1472   (PCC_W | PCC_REGISTER),   // inCond
1473   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1474   PCI_MAGIC
1475 };
1476
1477 pCodeInstruction pic16_pciIORFW = {
1478   {PC_OPCODE, NULL, NULL, 0, NULL, 
1479    //   genericAnalyze,
1480    genericDestruct,
1481    genericPrint},
1482   POC_IORFW,
1483   "IORWF",
1484   2,
1485   NULL, // from branch
1486   NULL, // to branch
1487   NULL, // label
1488   NULL, // operand
1489   NULL, // flow block
1490   NULL, // C source 
1491   3,    // num ops
1492   0,0,  // dest, bit instruction
1493   0,0,  // branch, skip
1494   0,    // literal operand
1495   1,    // RAM access bit
1496   0,    // fast call/return mode select bit
1497   0,    // second memory operand
1498   0,    // second literal operand
1499   POC_NOP,
1500   (PCC_W | PCC_REGISTER),   // inCond
1501   (PCC_W | PCC_Z | PCC_N), // outCond
1502   PCI_MAGIC
1503 };
1504
1505 pCodeInstruction pic16_pciIORLW = {
1506   {PC_OPCODE, NULL, NULL, 0, NULL, 
1507    //   genericAnalyze,
1508    genericDestruct,
1509    genericPrint},
1510   POC_IORLW,
1511   "IORLW",
1512   2,
1513   NULL, // from branch
1514   NULL, // to branch
1515   NULL, // label
1516   NULL, // operand
1517   NULL, // flow block
1518   NULL, // C source 
1519   1,    // num ops
1520   0,0,  // dest, bit instruction
1521   0,0,  // branch, skip
1522   1,    // literal operand
1523   0,    // RAM access bit
1524   0,    // fast call/return mode select bit
1525   0,    // second memory operand
1526   0,    // second literal operand
1527   POC_NOP,
1528   (PCC_W | PCC_LITERAL),   // inCond
1529   (PCC_W | PCC_Z | PCC_N), // outCond
1530   PCI_MAGIC
1531 };
1532
1533 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1534   {PC_OPCODE, NULL, NULL, 0, NULL, 
1535    //   genericAnalyze,
1536    genericDestruct,
1537    genericPrint},
1538   POC_LFSR,
1539   "LFSR",
1540   4,
1541   NULL, // from branch
1542   NULL, // to branch
1543   NULL, // label
1544   NULL, // operand
1545   NULL, // flow block
1546   NULL, // C source 
1547   2,    // num ops
1548   0,0,  // dest, bit instruction
1549   0,0,  // branch, skip
1550   1,    // literal operand
1551   0,    // RAM access bit
1552   0,    // fast call/return mode select bit
1553   0,    // second memory operand
1554   1,    // second literal operand
1555   POC_NOP,
1556   PCC_LITERAL, // inCond
1557   PCC_NONE, // outCond
1558   PCI_MAGIC
1559 };
1560
1561 pCodeInstruction pic16_pciMOVF = {
1562   {PC_OPCODE, NULL, NULL, 0, NULL, 
1563    //   genericAnalyze,
1564    genericDestruct,
1565    genericPrint},
1566   POC_MOVF,
1567   "MOVF",
1568   2,
1569   NULL, // from branch
1570   NULL, // to branch
1571   NULL, // label
1572   NULL, // operand
1573   NULL, // flow block
1574   NULL, // C source 
1575   3,    // num ops
1576   1,0,  // dest, bit instruction
1577   0,0,  // branch, skip
1578   0,    // literal operand
1579   1,    // RAM access bit
1580   0,    // fast call/return mode select bit
1581   0,    // second memory operand
1582   0,    // second literal operand
1583   POC_NOP,
1584   PCC_REGISTER,   // inCond
1585   (PCC_Z | PCC_N), // outCond
1586   PCI_MAGIC
1587 };
1588
1589 pCodeInstruction pic16_pciMOVFW = {
1590   {PC_OPCODE, NULL, NULL, 0, NULL, 
1591    //   genericAnalyze,
1592    genericDestruct,
1593    genericPrint},
1594   POC_MOVFW,
1595   "MOVF",
1596   2,
1597   NULL, // from branch
1598   NULL, // to branch
1599   NULL, // label
1600   NULL, // operand
1601   NULL, // flow block
1602   NULL, // C source 
1603   3,    // num ops
1604   0,0,  // dest, bit instruction
1605   0,0,  // branch, skip
1606   0,    // literal operand
1607   1,    // RAM access bit
1608   0,    // fast call/return mode select bit
1609   0,    // second memory operand
1610   0,    // second literal operand
1611   POC_NOP,
1612   PCC_REGISTER,   // inCond
1613   (PCC_W | PCC_N | PCC_Z), // outCond
1614   PCI_MAGIC
1615 };
1616
1617 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1618   {PC_OPCODE, NULL, NULL, 0, NULL, 
1619    //   genericAnalyze,
1620    genericDestruct,
1621    genericPrint},
1622   POC_MOVFF,
1623   "MOVFF",
1624   4,
1625   NULL, // from branch
1626   NULL, // to branch
1627   NULL, // label
1628   NULL, // operand
1629   NULL, // flow block
1630   NULL, // C source 
1631   2,    // num ops
1632   0,0,  // dest, bit instruction
1633   0,0,  // branch, skip
1634   0,    // literal operand
1635   0,    // RAM access bit
1636   0,    // fast call/return mode select bit
1637   1,    // second memory operand
1638   0,    // second literal operand
1639   POC_NOP,
1640   PCC_REGISTER,   // inCond
1641   PCC_REGISTER2, // outCond
1642   PCI_MAGIC
1643 };
1644
1645 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1646   {PC_OPCODE, NULL, NULL, 0, NULL, 
1647    genericDestruct,
1648    genericPrint},
1649   POC_MOVLB,
1650   "MOVLB",
1651   2,
1652   NULL, // from branch
1653   NULL, // to branch
1654   NULL, // label
1655   NULL, // operand
1656   NULL, // flow block
1657   NULL, // C source 
1658   1,    // num ops
1659   0,0,  // dest, bit instruction
1660   0,0,  // branch, skip
1661   1,    // literal operand
1662   0,    // RAM access bit
1663   0,    // fast call/return mode select bit
1664   0,    // second memory operand
1665   0,    // second literal operand
1666   POC_NOP,
1667   (PCC_NONE | PCC_LITERAL),   // inCond
1668   PCC_REGISTER, // outCond - BSR
1669   PCI_MAGIC
1670 };
1671
1672 pCodeInstruction pic16_pciMOVLW = {
1673   {PC_OPCODE, NULL, NULL, 0, NULL, 
1674    genericDestruct,
1675    genericPrint},
1676   POC_MOVLW,
1677   "MOVLW",
1678   2,
1679   NULL, // from branch
1680   NULL, // to branch
1681   NULL, // label
1682   NULL, // operand
1683   NULL, // flow block
1684   NULL, // C source 
1685   1,    // num ops
1686   0,0,  // dest, bit instruction
1687   0,0,  // branch, skip
1688   1,    // literal operand
1689   0,    // RAM access bit
1690   0,    // fast call/return mode select bit
1691   0,    // second memory operand
1692   0,    // second literal operand
1693   POC_NOP,
1694   (PCC_NONE | PCC_LITERAL),   // inCond
1695   PCC_W, // outCond
1696   PCI_MAGIC
1697 };
1698
1699 pCodeInstruction pic16_pciMOVWF = {
1700   {PC_OPCODE, NULL, NULL, 0, NULL, 
1701    //   genericAnalyze,
1702    genericDestruct,
1703    genericPrint},
1704   POC_MOVWF,
1705   "MOVWF",
1706   2,
1707   NULL, // from branch
1708   NULL, // to branch
1709   NULL, // label
1710   NULL, // operand
1711   NULL, // flow block
1712   NULL, // C source 
1713   2,    // num ops
1714   0,0,  // dest, bit instruction
1715   0,0,  // branch, skip
1716   0,    // literal operand
1717   1,    // RAM access bit
1718   0,    // fast call/return mode select bit
1719   0,    // second memory operand
1720   0,    // second literal operand
1721   POC_NOP,
1722   PCC_W,   // inCond
1723   PCC_REGISTER, // outCond
1724   PCI_MAGIC
1725 };
1726
1727 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1728   {PC_OPCODE, NULL, NULL, 0, NULL, 
1729    genericDestruct,
1730    genericPrint},
1731   POC_MULLW,
1732   "MULLW",
1733   2,
1734   NULL, // from branch
1735   NULL, // to branch
1736   NULL, // label
1737   NULL, // operand
1738   NULL, // flow block
1739   NULL, // C source 
1740   1,    // num ops
1741   0,0,  // dest, bit instruction
1742   0,0,  // branch, skip
1743   1,    // literal operand
1744   0,    // RAM access bit
1745   0,    // fast call/return mode select bit
1746   0,    // second memory operand
1747   0,    // second literal operand
1748   POC_NOP,
1749   (PCC_W | PCC_LITERAL),   // inCond
1750   PCC_NONE, // outCond - PROD
1751   PCI_MAGIC
1752 };
1753
1754 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1755   {PC_OPCODE, NULL, NULL, 0, NULL, 
1756    genericDestruct,
1757    genericPrint},
1758   POC_MULWF,
1759   "MULWF",
1760   2,
1761   NULL, // from branch
1762   NULL, // to branch
1763   NULL, // label
1764   NULL, // operand
1765   NULL, // flow block
1766   NULL, // C source 
1767   2,    // num ops
1768   0,0,  // dest, bit instruction
1769   0,0,  // branch, skip
1770   0,    // literal operand
1771   1,    // RAM access bit
1772   0,    // fast call/return mode select bit
1773   0,    // second memory operand
1774   0,    // second literal operand
1775   POC_NOP,
1776   (PCC_W | PCC_REGISTER),   // inCond
1777   PCC_REGISTER, // outCond - PROD
1778   PCI_MAGIC
1779 };
1780
1781 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1782   {PC_OPCODE, NULL, NULL, 0, NULL, 
1783    genericDestruct,
1784    genericPrint},
1785   POC_NEGF,
1786   "NEGF",
1787   2,
1788   NULL, // from branch
1789   NULL, // to branch
1790   NULL, // label
1791   NULL, // operand
1792   NULL, // flow block
1793   NULL, // C source 
1794   2,    // num ops
1795   0,0,  // dest, bit instruction
1796   0,0,  // branch, skip
1797   0,    // literal operand
1798   1,    // RAM access bit
1799   0,    // fast call/return mode select bit
1800   0,    // second memory operand
1801   0,    // second literal operand
1802   POC_NOP,
1803   PCC_REGISTER, // inCond
1804   (PCC_REGISTER | PCC_STATUS), // outCond
1805   PCI_MAGIC
1806 };
1807
1808 pCodeInstruction pic16_pciNOP = {
1809   {PC_OPCODE, NULL, NULL, 0, NULL, 
1810    genericDestruct,
1811    genericPrint},
1812   POC_NOP,
1813   "NOP",
1814   2,
1815   NULL, // from branch
1816   NULL, // to branch
1817   NULL, // label
1818   NULL, // operand
1819   NULL, // flow block
1820   NULL, // C source 
1821   0,    // num ops
1822   0,0,  // dest, bit instruction
1823   0,0,  // branch, skip
1824   0,    // literal operand
1825   0,    // RAM access bit
1826   0,    // fast call/return mode select bit
1827   0,    // second memory operand
1828   0,    // second literal operand
1829   POC_NOP,
1830   PCC_NONE,   // inCond
1831   PCC_NONE, // outCond
1832   PCI_MAGIC
1833 };
1834
1835 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1836   {PC_OPCODE, NULL, NULL, 0, NULL, 
1837    genericDestruct,
1838    genericPrint},
1839   POC_POP,
1840   "POP",
1841   2,
1842   NULL, // from branch
1843   NULL, // to branch
1844   NULL, // label
1845   NULL, // operand
1846   NULL, // flow block
1847   NULL, // C source 
1848   0,    // num ops
1849   0,0,  // dest, bit instruction
1850   0,0,  // branch, skip
1851   0,    // literal operand
1852   0,    // RAM access bit
1853   0,    // fast call/return mode select bit
1854   0,    // second memory operand
1855   0,    // second literal operand
1856   POC_NOP,
1857   PCC_NONE,  // inCond
1858   PCC_NONE  , // outCond
1859   PCI_MAGIC
1860 };
1861
1862 pCodeInstruction pic16_pciPUSH = {
1863   {PC_OPCODE, NULL, NULL, 0, NULL, 
1864    genericDestruct,
1865    genericPrint},
1866   POC_PUSH,
1867   "PUSH",
1868   2,
1869   NULL, // from branch
1870   NULL, // to branch
1871   NULL, // label
1872   NULL, // operand
1873   NULL, // flow block
1874   NULL, // C source 
1875   0,    // num ops
1876   0,0,  // dest, bit instruction
1877   0,0,  // branch, skip
1878   0,    // literal operand
1879   0,    // RAM access bit
1880   0,    // fast call/return mode select bit
1881   0,    // second memory operand
1882   0,    // second literal operand
1883   POC_NOP,
1884   PCC_NONE,  // inCond
1885   PCC_NONE  , // outCond
1886   PCI_MAGIC
1887 };
1888
1889 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1890   {PC_OPCODE, NULL, NULL, 0, NULL, 
1891    genericDestruct,
1892    genericPrint},
1893   POC_RCALL,
1894   "RCALL",
1895   2,
1896   NULL, // from branch
1897   NULL, // to branch
1898   NULL, // label
1899   NULL, // operand
1900   NULL, // flow block
1901   NULL, // C source 
1902   1,    // num ops
1903   0,0,  // dest, bit instruction
1904   1,0,  // branch, skip
1905   0,    // literal operand
1906   0,    // RAM access bit
1907   0,    // fast call/return mode select bit
1908   0,    // second memory operand
1909   0,    // second literal operand
1910   POC_NOP,
1911   PCC_REL_ADDR,  // inCond
1912   PCC_NONE  , // outCond
1913   PCI_MAGIC
1914 };
1915
1916 pCodeInstruction pic16_pciRETFIE = {
1917   {PC_OPCODE, NULL, NULL, 0, NULL, 
1918    //   AnalyzeRETURN,
1919    genericDestruct,
1920    genericPrint},
1921   POC_RETFIE,
1922   "RETFIE",
1923   2,
1924   NULL, // from branch
1925   NULL, // to branch
1926   NULL, // label
1927   NULL, // operand
1928   NULL, // flow block
1929   NULL, // C source 
1930   1,    // num ops
1931   0,0,  // dest, bit instruction
1932   1,0,  // branch, skip
1933   0,    // literal operand
1934   0,    // RAM access bit
1935   1,    // fast call/return mode select bit
1936   0,    // second memory operand
1937   0,    // second literal operand
1938   POC_NOP,
1939   PCC_NONE,   // inCond
1940   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1941   PCI_MAGIC
1942 };
1943
1944 pCodeInstruction pic16_pciRETLW = {
1945   {PC_OPCODE, NULL, NULL, 0, NULL, 
1946    //   AnalyzeRETURN,
1947    genericDestruct,
1948    genericPrint},
1949   POC_RETLW,
1950   "RETLW",
1951   2,
1952   NULL, // from branch
1953   NULL, // to branch
1954   NULL, // label
1955   NULL, // operand
1956   NULL, // flow block
1957   NULL, // C source 
1958   1,    // num ops
1959   0,0,  // dest, bit instruction
1960   1,0,  // branch, skip
1961   1,    // literal operand
1962   0,    // RAM access bit
1963   0,    // fast call/return mode select bit
1964   0,    // second memory operand
1965   0,    // second literal operand
1966   POC_NOP,
1967   PCC_LITERAL,   // inCond
1968   PCC_W, // outCond
1969   PCI_MAGIC
1970 };
1971
1972 pCodeInstruction pic16_pciRETURN = {
1973   {PC_OPCODE, NULL, NULL, 0, NULL, 
1974    //   AnalyzeRETURN,
1975    genericDestruct,
1976    genericPrint},
1977   POC_RETURN,
1978   "RETURN",
1979   2,
1980   NULL, // from branch
1981   NULL, // to branch
1982   NULL, // label
1983   NULL, // operand
1984   NULL, // flow block
1985   NULL, // C source 
1986   1,    // num ops
1987   0,0,  // dest, bit instruction
1988   1,0,  // branch, skip
1989   0,    // literal operand
1990   0,    // RAM access bit
1991   1,    // fast call/return mode select bit
1992   0,    // second memory operand
1993   0,    // second literal operand
1994   POC_NOP,
1995   PCC_NONE,   // inCond
1996   PCC_NONE, // outCond
1997   PCI_MAGIC
1998 };
1999 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2000   {PC_OPCODE, NULL, NULL, 0, NULL, 
2001    //   genericAnalyze,
2002    genericDestruct,
2003    genericPrint},
2004   POC_RLCF,
2005   "RLCF",
2006   2,
2007   NULL, // from branch
2008   NULL, // to branch
2009   NULL, // label
2010   NULL, // operand
2011   NULL, // flow block
2012   NULL, // C source 
2013   3,    // num ops
2014   1,0,  // dest, bit instruction
2015   0,0,  // branch, skip
2016   0,    // literal operand
2017   1,    // RAM access bit
2018   0,    // fast call/return mode select bit
2019   0,    // second memory operand
2020   0,    // second literal operand
2021   POC_NOP,
2022   (PCC_C | PCC_REGISTER),   // inCond
2023   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2024   PCI_MAGIC
2025 };
2026
2027 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2028   {PC_OPCODE, NULL, NULL, 0, NULL, 
2029    //   genericAnalyze,
2030    genericDestruct,
2031    genericPrint},
2032   POC_RLCFW,
2033   "RLCF",
2034   2,
2035   NULL, // from branch
2036   NULL, // to branch
2037   NULL, // label
2038   NULL, // operand
2039   NULL, // flow block
2040   NULL, // C source 
2041   3,    // num ops
2042   0,0,  // dest, bit instruction
2043   0,0,  // branch, skip
2044   0,    // literal operand
2045   1,    // RAM access bit
2046   0,    // fast call/return mode select bit
2047   0,    // second memory operand
2048   0,    // second literal operand
2049   POC_NOP,
2050   (PCC_C | PCC_REGISTER),   // inCond
2051   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2052   PCI_MAGIC
2053 };
2054
2055 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2056   {PC_OPCODE, NULL, NULL, 0, NULL, 
2057    //   genericAnalyze,
2058    genericDestruct,
2059    genericPrint},
2060   POC_RLNCF,
2061   "RLNCF",
2062   2,
2063   NULL, // from branch
2064   NULL, // to branch
2065   NULL, // label
2066   NULL, // operand
2067   NULL, // flow block
2068   NULL, // C source 
2069   3,    // num ops
2070   1,0,  // dest, bit instruction
2071   0,0,  // branch, skip
2072   0,    // literal operand
2073   1,    // RAM access bit
2074   0,    // fast call/return mode select bit
2075   0,    // second memory operand
2076   0,    // second literal operand
2077   POC_NOP,
2078   PCC_REGISTER,   // inCond
2079   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2080   PCI_MAGIC
2081 };
2082 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2083   {PC_OPCODE, NULL, NULL, 0, NULL, 
2084    //   genericAnalyze,
2085    genericDestruct,
2086    genericPrint},
2087   POC_RLNCFW,
2088   "RLNCF",
2089   2,
2090   NULL, // from branch
2091   NULL, // to branch
2092   NULL, // label
2093   NULL, // operand
2094   NULL, // flow block
2095   NULL, // C source 
2096   3,    // num ops
2097   0,0,  // dest, bit instruction
2098   0,0,  // branch, skip
2099   0,    // literal operand
2100   1,    // RAM access bit
2101   0,    // fast call/return mode select bit
2102   0,    // second memory operand
2103   0,    // second literal operand
2104   POC_NOP,
2105   PCC_REGISTER,   // inCond
2106   (PCC_W | PCC_Z | PCC_N), // outCond
2107   PCI_MAGIC
2108 };
2109 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2110   {PC_OPCODE, NULL, NULL, 0, NULL, 
2111    //   genericAnalyze,
2112    genericDestruct,
2113    genericPrint},
2114   POC_RRCF,
2115   "RRCF",
2116   2,
2117   NULL, // from branch
2118   NULL, // to branch
2119   NULL, // label
2120   NULL, // operand
2121   NULL, // flow block
2122   NULL, // C source 
2123   3,    // num ops
2124   1,0,  // dest, bit instruction
2125   0,0,  // branch, skip
2126   0,    // literal operand
2127   1,    // RAM access bit
2128   0,    // fast call/return mode select bit
2129   0,    // second memory operand
2130   0,    // second literal operand
2131   POC_NOP,
2132   (PCC_C | PCC_REGISTER),   // inCond
2133   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2134   PCI_MAGIC
2135 };
2136 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2137   {PC_OPCODE, NULL, NULL, 0, NULL, 
2138    //   genericAnalyze,
2139    genericDestruct,
2140    genericPrint},
2141   POC_RRCFW,
2142   "RRCF",
2143   2,
2144   NULL, // from branch
2145   NULL, // to branch
2146   NULL, // label
2147   NULL, // operand
2148   NULL, // flow block
2149   NULL, // C source 
2150   3,    // num ops
2151   0,0,  // dest, bit instruction
2152   0,0,  // branch, skip
2153   0,    // literal operand
2154   1,    // RAM access bit
2155   0,    // fast call/return mode select bit
2156   0,    // second memory operand
2157   0,    // second literal operand
2158   POC_NOP,
2159   (PCC_C | PCC_REGISTER),   // inCond
2160   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2161   PCI_MAGIC
2162 };
2163 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2164   {PC_OPCODE, NULL, NULL, 0, NULL, 
2165    //   genericAnalyze,
2166    genericDestruct,
2167    genericPrint},
2168   POC_RRNCF,
2169   "RRNCF",
2170   2,
2171   NULL, // from branch
2172   NULL, // to branch
2173   NULL, // label
2174   NULL, // operand
2175   NULL, // flow block
2176   NULL, // C source 
2177   3,    // num ops
2178   1,0,  // dest, bit instruction
2179   0,0,  // branch, skip
2180   0,    // literal operand
2181   1,    // RAM access bit
2182   0,    // fast call/return mode select bit
2183   0,    // second memory operand
2184   0,    // second literal operand
2185   POC_NOP,
2186   PCC_REGISTER,   // inCond
2187   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2188   PCI_MAGIC
2189 };
2190
2191 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2192   {PC_OPCODE, NULL, NULL, 0, NULL, 
2193    //   genericAnalyze,
2194    genericDestruct,
2195    genericPrint},
2196   POC_RRNCFW,
2197   "RRNCF",
2198   2,
2199   NULL, // from branch
2200   NULL, // to branch
2201   NULL, // label
2202   NULL, // operand
2203   NULL, // flow block
2204   NULL, // C source 
2205   3,    // num ops
2206   0,0,  // dest, bit instruction
2207   0,0,  // branch, skip
2208   0,    // literal operand
2209   1,    // RAM access bit
2210   0,    // fast call/return mode select bit
2211   0,    // second memory operand
2212   0,    // second literal operand
2213   POC_NOP,
2214   PCC_REGISTER,   // inCond
2215   (PCC_W | PCC_Z | PCC_N), // outCond
2216   PCI_MAGIC
2217 };
2218
2219 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2220   {PC_OPCODE, NULL, NULL, 0, NULL, 
2221    //   genericAnalyze,
2222    genericDestruct,
2223    genericPrint},
2224   POC_SETF,
2225   "SETF",
2226   2,
2227   NULL, // from branch
2228   NULL, // to branch
2229   NULL, // label
2230   NULL, // operand
2231   NULL, // flow block
2232   NULL, // C source 
2233   2,    // num ops
2234   0,0,  // dest, bit instruction
2235   0,0,  // branch, skip
2236   0,    // literal operand
2237   1,    // RAM access bit
2238   0,    // fast call/return mode select bit
2239   0,    // second memory operand
2240   0,    // second literal operand
2241   POC_NOP,
2242   PCC_NONE,  // inCond
2243   PCC_REGISTER  , // outCond
2244   PCI_MAGIC
2245 };
2246
2247 pCodeInstruction pic16_pciSUBLW = {
2248   {PC_OPCODE, NULL, NULL, 0, NULL, 
2249    //   genericAnalyze,
2250    genericDestruct,
2251    genericPrint},
2252   POC_SUBLW,
2253   "SUBLW",
2254   2,
2255   NULL, // from branch
2256   NULL, // to branch
2257   NULL, // label
2258   NULL, // operand
2259   NULL, // flow block
2260   NULL, // C source 
2261   1,    // num ops
2262   0,0,  // dest, bit instruction
2263   0,0,  // branch, skip
2264   1,    // literal operand
2265   0,    // RAM access bit
2266   0,    // fast call/return mode select bit
2267   0,    // second memory operand
2268   0,    // second literal operand
2269   POC_NOP,
2270   (PCC_W | PCC_LITERAL),   // inCond
2271   (PCC_W | PCC_STATUS), // outCond
2272   PCI_MAGIC
2273 };
2274
2275 pCodeInstruction pic16_pciSUBFWB = {
2276   {PC_OPCODE, NULL, NULL, 0, NULL, 
2277    //   genericAnalyze,
2278    genericDestruct,
2279    genericPrint},
2280   POC_SUBFWB,
2281   "SUBFWB",
2282   2,
2283   NULL, // from branch
2284   NULL, // to branch
2285   NULL, // label
2286   NULL, // operand
2287   NULL, // flow block
2288   NULL, // C source 
2289   3,    // num ops
2290   1,0,  // dest, bit instruction
2291   0,0,  // branch, skip
2292   0,    // literal operand
2293   1,    // RAM access bit
2294   0,    // fast call/return mode select bit
2295   0,    // second memory operand
2296   0,    // second literal operand
2297   POC_NOP,
2298   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2299   (PCC_W | PCC_STATUS), // outCond
2300   PCI_MAGIC
2301 };
2302
2303 pCodeInstruction pic16_pciSUBWF = {
2304   {PC_OPCODE, NULL, NULL, 0, NULL, 
2305    //   genericAnalyze,
2306    genericDestruct,
2307    genericPrint},
2308   POC_SUBWF,
2309   "SUBWF",
2310   2,
2311   NULL, // from branch
2312   NULL, // to branch
2313   NULL, // label
2314   NULL, // operand
2315   NULL, // flow block
2316   NULL, // C source 
2317   3,    // num ops
2318   1,0,  // dest, bit instruction
2319   0,0,  // branch, skip
2320   0,    // literal operand
2321   1,    // RAM access bit
2322   0,    // fast call/return mode select bit
2323   0,    // second memory operand
2324   0,    // second literal operand
2325   POC_NOP,
2326   (PCC_W | PCC_REGISTER),   // inCond
2327   (PCC_REGISTER | PCC_STATUS), // outCond
2328   PCI_MAGIC
2329 };
2330
2331 pCodeInstruction pic16_pciSUBFW = {
2332   {PC_OPCODE, NULL, NULL, 0, NULL, 
2333    //   genericAnalyze,
2334    genericDestruct,
2335    genericPrint},
2336   POC_SUBFW,
2337   "SUBWF",
2338   2,
2339   NULL, // from branch
2340   NULL, // to branch
2341   NULL, // label
2342   NULL, // operand
2343   NULL, // flow block
2344   NULL, // C source 
2345   3,    // num ops
2346   0,0,  // dest, bit instruction
2347   0,0,  // branch, skip
2348   0,    // literal operand
2349   1,    // RAM access bit
2350   0,    // fast call/return mode select bit
2351   0,    // second memory operand
2352   0,    // second literal operand
2353   POC_NOP,
2354   (PCC_W | PCC_REGISTER),   // inCond
2355   (PCC_W | PCC_STATUS), // outCond
2356   PCI_MAGIC
2357 };
2358
2359 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2360   {PC_OPCODE, NULL, NULL, 0, NULL, 
2361    //   genericAnalyze,
2362    genericDestruct,
2363    genericPrint},
2364   POC_SUBFWB_D1,
2365   "SUBFWB",
2366   2,
2367   NULL, // from branch
2368   NULL, // to branch
2369   NULL, // label
2370   NULL, // operand
2371   NULL, // flow block
2372   NULL, // C source 
2373   3,    // num ops
2374   1,0,  // dest, bit instruction
2375   0,0,  // branch, skip
2376   0,    // literal operand
2377   1,    // RAM access bit
2378   0,    // fast call/return mode select bit
2379   0,    // second memory operand
2380   0,    // second literal operand
2381   POC_NOP,
2382   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2383   (PCC_REGISTER | PCC_STATUS), // outCond
2384   PCI_MAGIC
2385 };
2386
2387 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2388   {PC_OPCODE, NULL, NULL, 0, NULL, 
2389    //   genericAnalyze,
2390    genericDestruct,
2391    genericPrint},
2392   POC_SUBFWB_D0,
2393   "SUBFWB",
2394   2,
2395   NULL, // from branch
2396   NULL, // to branch
2397   NULL, // label
2398   NULL, // operand
2399   NULL, // flow block
2400   NULL, // C source 
2401   3,    // num ops
2402   0,0,  // dest, bit instruction
2403   0,0,  // branch, skip
2404   0,    // literal operand
2405   1,    // RAM access bit
2406   0,    // fast call/return mode select bit
2407   0,    // second memory operand
2408   0,    // second literal operand
2409   POC_NOP,
2410   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2411   (PCC_W | PCC_STATUS), // outCond
2412   PCI_MAGIC
2413 };
2414
2415 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2416   {PC_OPCODE, NULL, NULL, 0, NULL, 
2417    //   genericAnalyze,
2418    genericDestruct,
2419    genericPrint},
2420   POC_SUBWFB_D1,
2421   "SUBWFB",
2422   2,
2423   NULL, // from branch
2424   NULL, // to branch
2425   NULL, // label
2426   NULL, // operand
2427   NULL, // flow block
2428   NULL, // C source 
2429   3,    // num ops
2430   1,0,  // dest, bit instruction
2431   0,0,  // branch, skip
2432   0,    // literal operand
2433   1,    // RAM access bit
2434   0,    // fast call/return mode select bit
2435   0,    // second memory operand
2436   0,    // second literal operand
2437   POC_NOP,
2438   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2439   (PCC_REGISTER | PCC_STATUS), // outCond
2440   PCI_MAGIC
2441 };
2442
2443 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2444   {PC_OPCODE, NULL, NULL, 0, NULL, 
2445    //   genericAnalyze,
2446    genericDestruct,
2447    genericPrint},
2448   POC_SUBWFB_D0,
2449   "SUBWFB",
2450   2,
2451   NULL, // from branch
2452   NULL, // to branch
2453   NULL, // label
2454   NULL, // operand
2455   NULL, // flow block
2456   NULL, // C source 
2457   3,    // num ops
2458   0,0,  // dest, bit instruction
2459   0,0,  // branch, skip
2460   0,    // literal operand
2461   1,    // RAM access bit
2462   0,    // fast call/return mode select bit
2463   0,    // second memory operand
2464   0,    // second literal operand
2465   POC_NOP,
2466   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2467   (PCC_W | PCC_STATUS), // outCond
2468   PCI_MAGIC
2469 };
2470
2471 pCodeInstruction pic16_pciSWAPF = {
2472   {PC_OPCODE, NULL, NULL, 0, NULL, 
2473    //   genericAnalyze,
2474    genericDestruct,
2475    genericPrint},
2476   POC_SWAPF,
2477   "SWAPF",
2478   2,
2479   NULL, // from branch
2480   NULL, // to branch
2481   NULL, // label
2482   NULL, // operand
2483   NULL, // flow block
2484   NULL, // C source 
2485   3,    // num ops
2486   1,0,  // dest, bit instruction
2487   0,0,  // branch, skip
2488   0,    // literal operand
2489   1,    // RAM access bit
2490   0,    // fast call/return mode select bit
2491   0,    // second memory operand
2492   0,    // second literal operand
2493   POC_NOP,
2494   (PCC_REGISTER),   // inCond
2495   (PCC_REGISTER), // outCond
2496   PCI_MAGIC
2497 };
2498
2499 pCodeInstruction pic16_pciSWAPFW = {
2500   {PC_OPCODE, NULL, NULL, 0, NULL, 
2501    //   genericAnalyze,
2502    genericDestruct,
2503    genericPrint},
2504   POC_SWAPFW,
2505   "SWAPF",
2506   2,
2507   NULL, // from branch
2508   NULL, // to branch
2509   NULL, // label
2510   NULL, // operand
2511   NULL, // flow block
2512   NULL, // C source 
2513   3,    // num ops
2514   0,0,  // dest, bit instruction
2515   0,0,  // branch, skip
2516   0,    // literal operand
2517   1,    // RAM access bit
2518   0,    // fast call/return mode select bit
2519   0,    // second memory operand
2520   0,    // second literal operand
2521   POC_NOP,
2522   (PCC_REGISTER),   // inCond
2523   (PCC_W), // outCond
2524   PCI_MAGIC
2525 };
2526
2527 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2528   {PC_OPCODE, NULL, NULL, 0, NULL, 
2529    genericDestruct,
2530    genericPrint},
2531   POC_TBLRD,
2532   "TBLRD*",
2533   2,
2534   NULL, // from branch
2535   NULL, // to branch
2536   NULL, // label
2537   NULL, // operand
2538   NULL, // flow block
2539   NULL, // C source 
2540   0,    // num ops
2541   0,0,  // dest, bit instruction
2542   0,0,  // branch, skip
2543   0,    // literal operand
2544   0,    // RAM access bit
2545   0,    // fast call/return mode select bit
2546   0,    // second memory operand
2547   0,    // second literal operand
2548   POC_NOP,
2549   PCC_NONE,  // inCond
2550   PCC_NONE  , // outCond
2551   PCI_MAGIC
2552 };
2553
2554 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2555   {PC_OPCODE, NULL, NULL, 0, NULL, 
2556    genericDestruct,
2557    genericPrint},
2558   POC_TBLRD_POSTINC,
2559   "TBLRD*+",
2560   2,
2561   NULL, // from branch
2562   NULL, // to branch
2563   NULL, // label
2564   NULL, // operand
2565   NULL, // flow block
2566   NULL, // C source 
2567   0,    // num ops
2568   0,0,  // dest, bit instruction
2569   0,0,  // branch, skip
2570   0,    // literal operand
2571   0,    // RAM access bit
2572   0,    // fast call/return mode select bit
2573   0,    // second memory operand
2574   0,    // second literal operand
2575   POC_NOP,
2576   PCC_NONE,  // inCond
2577   PCC_NONE  , // outCond
2578   PCI_MAGIC
2579 };
2580
2581 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2582   {PC_OPCODE, NULL, NULL, 0, NULL, 
2583    genericDestruct,
2584    genericPrint},
2585   POC_TBLRD_POSTDEC,
2586   "TBLRD*-",
2587   2,
2588   NULL, // from branch
2589   NULL, // to branch
2590   NULL, // label
2591   NULL, // operand
2592   NULL, // flow block
2593   NULL, // C source 
2594   0,    // num ops
2595   0,0,  // dest, bit instruction
2596   0,0,  // branch, skip
2597   0,    // literal operand
2598   0,    // RAM access bit
2599   0,    // fast call/return mode select bit
2600   0,    // second memory operand
2601   0,    // second literal operand
2602   POC_NOP,
2603   PCC_NONE,  // inCond
2604   PCC_NONE  , // outCond
2605   PCI_MAGIC
2606 };
2607
2608 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2609   {PC_OPCODE, NULL, NULL, 0, NULL, 
2610    genericDestruct,
2611    genericPrint},
2612   POC_TBLRD_PREINC,
2613   "TBLRD+*",
2614   2,
2615   NULL, // from branch
2616   NULL, // to branch
2617   NULL, // label
2618   NULL, // operand
2619   NULL, // flow block
2620   NULL, // C source 
2621   0,    // num ops
2622   0,0,  // dest, bit instruction
2623   0,0,  // branch, skip
2624   0,    // literal operand
2625   0,    // RAM access bit
2626   0,    // fast call/return mode select bit
2627   0,    // second memory operand
2628   0,    // second literal operand
2629   POC_NOP,
2630   PCC_NONE,  // inCond
2631   PCC_NONE  , // outCond
2632   PCI_MAGIC
2633 };
2634
2635 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2636   {PC_OPCODE, NULL, NULL, 0, NULL, 
2637    genericDestruct,
2638    genericPrint},
2639   POC_TBLWT,
2640   "TBLWT*",
2641   2,
2642   NULL, // from branch
2643   NULL, // to branch
2644   NULL, // label
2645   NULL, // operand
2646   NULL, // flow block
2647   NULL, // C source 
2648   0,    // num ops
2649   0,0,  // dest, bit instruction
2650   0,0,  // branch, skip
2651   0,    // literal operand
2652   0,    // RAM access bit
2653   0,    // fast call/return mode select bit
2654   0,    // second memory operand
2655   0,    // second literal operand
2656   POC_NOP,
2657   PCC_NONE,  // inCond
2658   PCC_NONE  , // outCond
2659   PCI_MAGIC
2660 };
2661
2662 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2663   {PC_OPCODE, NULL, NULL, 0, NULL, 
2664    genericDestruct,
2665    genericPrint},
2666   POC_TBLWT_POSTINC,
2667   "TBLWT*+",
2668   2,
2669   NULL, // from branch
2670   NULL, // to branch
2671   NULL, // label
2672   NULL, // operand
2673   NULL, // flow block
2674   NULL, // C source 
2675   0,    // num ops
2676   0,0,  // dest, bit instruction
2677   0,0,  // branch, skip
2678   0,    // literal operand
2679   0,    // RAM access bit
2680   0,    // fast call/return mode select bit
2681   0,    // second memory operand
2682   0,    // second literal operand
2683   POC_NOP,
2684   PCC_NONE,  // inCond
2685   PCC_NONE  , // outCond
2686   PCI_MAGIC
2687 };
2688
2689 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2690   {PC_OPCODE, NULL, NULL, 0, NULL, 
2691    genericDestruct,
2692    genericPrint},
2693   POC_TBLWT_POSTDEC,
2694   "TBLWT*-",
2695   2,
2696   NULL, // from branch
2697   NULL, // to branch
2698   NULL, // label
2699   NULL, // operand
2700   NULL, // flow block
2701   NULL, // C source 
2702   0,    // num ops
2703   0,0,  // dest, bit instruction
2704   0,0,  // branch, skip
2705   0,    // literal operand
2706   0,    // RAM access bit
2707   0,    // fast call/return mode select bit
2708   0,    // second memory operand
2709   0,    // second literal operand
2710   POC_NOP,
2711   PCC_NONE,  // inCond
2712   PCC_NONE  , // outCond
2713   PCI_MAGIC
2714 };
2715
2716 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2717   {PC_OPCODE, NULL, NULL, 0, NULL, 
2718    genericDestruct,
2719    genericPrint},
2720   POC_TBLWT_PREINC,
2721   "TBLWT+*",
2722   2,
2723   NULL, // from branch
2724   NULL, // to branch
2725   NULL, // label
2726   NULL, // operand
2727   NULL, // flow block
2728   NULL, // C source 
2729   0,    // num ops
2730   0,0,  // dest, bit instruction
2731   0,0,  // branch, skip
2732   0,    // literal operand
2733   0,    // RAM access bit
2734   0,    // fast call/return mode select bit
2735   0,    // second memory operand
2736   0,    // second literal operand
2737   POC_NOP,
2738   PCC_NONE,  // inCond
2739   PCC_NONE  , // outCond
2740   PCI_MAGIC
2741 };
2742
2743 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2744   {PC_OPCODE, NULL, NULL, 0, NULL, 
2745    //   genericAnalyze,
2746    genericDestruct,
2747    genericPrint},
2748   POC_TSTFSZ,
2749   "TSTFSZ",
2750   2,
2751   NULL, // from branch
2752   NULL, // to branch
2753   NULL, // label
2754   NULL, // operand
2755   NULL, // flow block
2756   NULL, // C source 
2757   2,    // num ops
2758   0,0,  // dest, bit instruction
2759   1,1,  // branch, skip
2760   0,    // literal operand
2761   1,    // RAM access bit
2762   0,    // fast call/return mode select bit
2763   0,    // second memory operand
2764   0,    // second literal operand
2765   POC_NOP,
2766   PCC_REGISTER,   // inCond
2767   PCC_NONE, // outCond
2768   PCI_MAGIC
2769 };
2770
2771 pCodeInstruction pic16_pciXORWF = {
2772   {PC_OPCODE, NULL, NULL, 0, NULL, 
2773    //   genericAnalyze,
2774    genericDestruct,
2775    genericPrint},
2776   POC_XORWF,
2777   "XORWF",
2778   2,
2779   NULL, // from branch
2780   NULL, // to branch
2781   NULL, // label
2782   NULL, // operand
2783   NULL, // flow block
2784   NULL, // C source 
2785   3,    // num ops
2786   1,0,  // dest, bit instruction
2787   0,0,  // branch, skip
2788   0,    // literal operand
2789   1,    // RAM access bit
2790   0,    // fast call/return mode select bit
2791   0,    // second memory operand
2792   0,    // second literal operand
2793   POC_NOP,
2794   (PCC_W | PCC_REGISTER),   // inCond
2795   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2796   PCI_MAGIC
2797 };
2798
2799 pCodeInstruction pic16_pciXORFW = {
2800   {PC_OPCODE, NULL, NULL, 0, NULL, 
2801    //   genericAnalyze,
2802    genericDestruct,
2803    genericPrint},
2804   POC_XORFW,
2805   "XORWF",
2806   2,
2807   NULL, // from branch
2808   NULL, // to branch
2809   NULL, // label
2810   NULL, // operand
2811   NULL, // flow block
2812   NULL, // C source 
2813   3,    // num ops
2814   0,0,  // dest, bit instruction
2815   0,0,  // branch, skip
2816   0,    // literal operand
2817   1,    // RAM access bit
2818   0,    // fast call/return mode select bit
2819   0,    // second memory operand
2820   0,    // second literal operand
2821   POC_NOP,
2822   (PCC_W | PCC_REGISTER),   // inCond
2823   (PCC_W | PCC_Z | PCC_N), // outCond
2824   PCI_MAGIC
2825 };
2826
2827 pCodeInstruction pic16_pciXORLW = {
2828   {PC_OPCODE, NULL, NULL, 0, NULL, 
2829    //   genericAnalyze,
2830    genericDestruct,
2831    genericPrint},
2832   POC_XORLW,
2833   "XORLW",
2834   2,
2835   NULL, // from branch
2836   NULL, // to branch
2837   NULL, // label
2838   NULL, // operand
2839   NULL, // flow block
2840   NULL, // C source 
2841   1,    // num ops
2842   0,0,  // dest, bit instruction
2843   0,0,  // branch, skip
2844   1,    // literal operand
2845   1,    // RAM access bit
2846   0,    // fast call/return mode select bit
2847   0,    // second memory operand
2848   0,    // second literal operand
2849   POC_NOP,
2850   (PCC_W | PCC_LITERAL),   // inCond
2851   (PCC_W | PCC_Z | PCC_N), // outCond
2852   PCI_MAGIC
2853 };
2854
2855
2856 pCodeInstruction pic16_pciBANKSEL = {
2857   {PC_OPCODE, NULL, NULL, 0, NULL, 
2858    genericDestruct,
2859    genericPrint},
2860   POC_BANKSEL,
2861   "BANKSEL",
2862   2,
2863   NULL, // from branch
2864   NULL, // to branch
2865   NULL, // label
2866   NULL, // operand
2867   NULL, // flow block
2868   NULL, // C source 
2869   0,    // num ops
2870   0,0,  // dest, bit instruction
2871   0,0,  // branch, skip
2872   0,    // literal operand
2873   0,    // RAM access bit
2874   0,    // fast call/return mode select bit
2875   0,    // second memory operand
2876   0,    // second literal operand
2877   POC_NOP,
2878   PCC_NONE,   // inCond
2879   PCC_NONE, // outCond
2880   PCI_MAGIC
2881 };
2882
2883
2884 #define MAX_PIC16MNEMONICS 100
2885 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2886
2887 //#define USE_VSNPRINTF
2888 #if OPT_DISABLE_PIC
2889
2890 #ifdef USE_VSNPRINTF
2891   // Alas, vsnprintf is not ANSI standard, and does not exist
2892   // on Solaris (and probably other non-Gnu flavored Unixes).
2893
2894 /*-----------------------------------------------------------------*/
2895 /* SAFE_snprintf - like snprintf except the string pointer is      */
2896 /*                 after the string has been printed to. This is   */
2897 /*                 useful for printing to string as though if it   */
2898 /*                 were a stream.                                  */
2899 /*-----------------------------------------------------------------*/
2900 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2901 {
2902   va_list val;
2903   int len;
2904
2905   if(!str || !*str)
2906     return;
2907
2908   va_start(val, format);
2909
2910   vsnprintf(*str, *size, format, val);
2911
2912   va_end (val);
2913
2914   len = strlen(*str);
2915   if(len > *size) {
2916     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2917     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2918   }
2919
2920   *str += len;
2921   *size -= len;
2922
2923 }
2924
2925 #else
2926 // This version is *not* safe, despite the name.
2927
2928 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2929 {
2930   va_list val;
2931   int len;
2932   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2933
2934   if(!str || !*str)
2935     return;
2936
2937   va_start(val, format);
2938
2939   vsprintf(buffer, format, val);
2940   va_end (val);
2941
2942   len = strlen(buffer);
2943   if(len > *size) {
2944     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2945     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2946   }
2947
2948   strcpy(*str, buffer);
2949   *str += len;
2950   *size -= len;
2951
2952 }
2953
2954 #endif    //  USE_VSNPRINTF
2955 #endif
2956
2957 extern set *externs;
2958 extern  void pic16_initStack(int base_address, int size);
2959 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2960 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2961 extern void pic16_init_pic(char *);
2962
2963 void  pic16_pCodeInitRegisters(void)
2964 {
2965   static int initialized=0;
2966
2967         if(initialized)
2968                 return;
2969         
2970         initialized = 1;
2971
2972 //      pic16_initStack(0xfff, 8);
2973         pic16_init_pic(port->processor);
2974
2975         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2976         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2977         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2978         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2979         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2980         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2981         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2982
2983         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2984         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2985         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2986
2987         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2988         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2989         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2990         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2991
2992         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2993         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2994         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2995         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2996         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2997         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2998
2999         pic16_stackpnt_lo = &pic16_pc_fsr1l;
3000         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3001         pic16_stack_postdec = &pic16_pc_postdec1;
3002         pic16_stack_postinc = &pic16_pc_postinc1;
3003         pic16_stack_preinc = &pic16_pc_preinc1;
3004         pic16_stack_plusw = &pic16_pc_plusw1;
3005         
3006         pic16_framepnt_lo = &pic16_pc_fsr2l;
3007         pic16_framepnt_hi = &pic16_pc_fsr2h;
3008         pic16_frame_postdec = &pic16_pc_postdec2;
3009         pic16_frame_postinc = &pic16_pc_postinc2;
3010         pic16_frame_preinc = &pic16_pc_preinc2;
3011         pic16_frame_plusw = &pic16_pc_plusw2;
3012
3013         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3014         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3015         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3016         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3017         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3018         
3019         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3020         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3021         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3022         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3023         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3024
3025         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3026         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3027         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3028         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3029         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3030         
3031         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3032         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3033
3034
3035         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3036         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3037         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3038         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3039
3040         
3041         pic16_pc_status.rIdx = IDX_STATUS;
3042         pic16_pc_intcon.rIdx = IDX_INTCON;
3043         pic16_pc_pcl.rIdx = IDX_PCL;
3044         pic16_pc_pclath.rIdx = IDX_PCLATH;
3045         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3046         pic16_pc_wreg.rIdx = IDX_WREG;
3047         pic16_pc_bsr.rIdx = IDX_BSR;
3048
3049         pic16_pc_tosl.rIdx = IDX_TOSL;
3050         pic16_pc_tosh.rIdx = IDX_TOSH;
3051         pic16_pc_tosu.rIdx = IDX_TOSU;
3052
3053         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3054         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3055         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3056         pic16_pc_tablat.rIdx = IDX_TABLAT;
3057
3058         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3059         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3060         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3061         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3062         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3063         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3064         pic16_pc_indf0.rIdx = IDX_INDF0;
3065         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3066         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3067         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3068         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3069         pic16_pc_indf1.rIdx = IDX_INDF1;
3070         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3071         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3072         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3073         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3074         pic16_pc_indf2.rIdx = IDX_INDF2;
3075         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3076         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3077         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3078         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3079         pic16_pc_prodl.rIdx = IDX_PRODL;
3080         pic16_pc_prodh.rIdx = IDX_PRODH;
3081         
3082         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3083         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3084         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3085         
3086         pic16_pc_kzero.rIdx = IDX_KZ;
3087         pic16_pc_wsave.rIdx = IDX_WSAVE;
3088         pic16_pc_ssave.rIdx = IDX_SSAVE;
3089
3090         pic16_pc_eecon1.rIdx = IDX_EECON1;
3091         pic16_pc_eecon2.rIdx = IDX_EECON2;
3092         pic16_pc_eedata.rIdx = IDX_EEDATA;
3093         pic16_pc_eeadr.rIdx = IDX_EEADR;
3094         
3095         
3096         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3097         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3098
3099         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3100         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3101
3102         /* probably should put this in a separate initialization routine */
3103         pb_dead_pcodes = newpBlock();
3104
3105 }
3106
3107 #if OPT_DISABLE_PIC
3108 /*-----------------------------------------------------------------*/
3109 /*  mnem2key - convert a pic mnemonic into a hash key              */
3110 /*   (BTW - this spreads the mnemonics quite well)                 */
3111 /*                                                                 */
3112 /*-----------------------------------------------------------------*/
3113
3114 int mnem2key(char const *mnem)
3115 {
3116   int key = 0;
3117
3118   if(!mnem)
3119     return 0;
3120
3121   while(*mnem) {
3122
3123     key += toupper(*mnem++) +1;
3124
3125   }
3126
3127   return (key & 0x1f);
3128
3129 }
3130 #endif
3131
3132 void pic16initMnemonics(void)
3133 {
3134   int i = 0;
3135   int key;
3136   //  char *str;
3137   pCodeInstruction *pci;
3138
3139   if(mnemonics_initialized)
3140     return;
3141
3142   // NULL out the array before making the assignments
3143   // since we check the array contents below this initialization.
3144
3145   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3146     pic16Mnemonics[i] = NULL;
3147   }
3148
3149   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3150   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3151   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3152   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3153   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3154   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3155   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3156   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3157   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3158   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3159   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3160   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3161   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3162   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3163   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3164   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3165   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3166   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3167   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3168   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3169   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3170   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3171   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3172   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3173   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3174   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3175   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3176   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3177   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3178   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3179   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3180   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3181   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3182   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3183   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3184   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3185   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3186   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3187   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3188   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3189   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3190   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3191   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3192   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3193   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3194   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3195   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3196   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3197   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3198   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3199   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3200   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3201   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3202   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3203   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3204   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3205   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3206   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3207   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3208   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3209   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3210   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3211   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3212   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3213   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3214   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3215   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3216   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3217   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3218   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3219   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3220   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3221   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3222   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3223   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3224   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3225   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3226   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3227   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3228   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3229   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3230   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3231   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3232   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3233   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3234   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3235   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3236   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3237   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3238   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3239   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3240   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3241   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3242   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3243
3244   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3245     if(pic16Mnemonics[i])
3246       hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3247   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3248
3249   while(pci) {
3250     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3251     pci = hTabNextItem(pic16MnemonicsHash, &key);
3252   }
3253
3254   mnemonics_initialized = 1;
3255 }
3256
3257 int pic16_getpCodePeepCommand(char *cmd);
3258
3259 int pic16_getpCode(char *mnem,unsigned dest)
3260 {
3261
3262   pCodeInstruction *pci;
3263   int key = mnem2key(mnem);
3264
3265   if(!mnemonics_initialized)
3266     pic16initMnemonics();
3267
3268   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3269
3270   while(pci) {
3271
3272     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3273       if((pci->num_ops <= 1)
3274         || (pci->isModReg == dest)
3275         || (pci->isBitInst)
3276         || (pci->num_ops <= 2 && pci->isAccess)
3277         || (pci->num_ops <= 2 && pci->isFastCall)
3278         || (pci->num_ops <= 2 && pci->is2MemOp)
3279         || (pci->num_ops <= 2 && pci->is2LitOp) )
3280         return(pci->op);
3281     }
3282
3283     pci = hTabNextItemWK (pic16MnemonicsHash);
3284   
3285   }
3286
3287   return -1;
3288 }
3289
3290 /*-----------------------------------------------------------------*
3291  * pic16initpCodePeepCommands
3292  *
3293  *-----------------------------------------------------------------*/
3294 void pic16initpCodePeepCommands(void)
3295 {
3296
3297   int key, i;
3298   peepCommand *pcmd;
3299
3300   i = 0;
3301   do {
3302     hTabAddItem(&pic16pCodePeepCommandsHash, 
3303                 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3304     i++;
3305   } while (peepCommands[i].cmd);
3306
3307   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3308
3309   while(pcmd) {
3310     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3311     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3312   }
3313
3314 }
3315
3316 /*-----------------------------------------------------------------
3317  *
3318  *
3319  *-----------------------------------------------------------------*/
3320
3321 int pic16_getpCodePeepCommand(char *cmd)
3322 {
3323
3324   peepCommand *pcmd;
3325   int key = mnem2key(cmd);
3326
3327
3328   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3329
3330   while(pcmd) {
3331     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3332     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3333       return pcmd->id;
3334     }
3335
3336     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3337   
3338   }
3339
3340   return -1;
3341 }
3342
3343 static char getpBlock_dbName(pBlock *pb)
3344 {
3345   if(!pb)
3346     return 0;
3347
3348   if(pb->cmemmap)
3349     return pb->cmemmap->dbName;
3350
3351   return pb->dbName;
3352 }
3353 void pic16_pBlockConvert2ISR(pBlock *pb)
3354 {
3355         if(!pb)return;
3356
3357         if(pb->cmemmap)pb->cmemmap = NULL;
3358
3359         pb->dbName = 'I';
3360
3361         if(pic16_pcode_verbose)
3362                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3363 }
3364
3365 void pic16_pBlockConvert2Absolute(pBlock *pb)
3366 {
3367         if(!pb)return;
3368         if(pb->cmemmap)pb->cmemmap = NULL;
3369         
3370         pb->dbName = 'A';
3371         
3372         if(pic16_pcode_verbose)
3373                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3374 }
3375   
3376 /*-----------------------------------------------------------------*/
3377 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3378 /*                   instances to the front of the doubly linked   */
3379 /*                   list of pBlocks                               */
3380 /*-----------------------------------------------------------------*/
3381
3382 void pic16_movepBlock2Head(char dbName)
3383 {
3384   pBlock *pb;
3385
3386
3387   /* this can happen in sources without code,
3388    * only variable definitions */
3389   if(!the_pFile)return;
3390
3391   pb = the_pFile->pbHead;
3392
3393   while(pb) {
3394
3395     if(getpBlock_dbName(pb) == dbName) {
3396       pBlock *pbn = pb->next;
3397       pb->next = the_pFile->pbHead;
3398       the_pFile->pbHead->prev = pb;
3399       the_pFile->pbHead = pb;
3400
3401       if(pb->prev)
3402         pb->prev->next = pbn;
3403
3404       // If the pBlock that we just moved was the last
3405       // one in the link of all of the pBlocks, then we
3406       // need to point the tail to the block just before
3407       // the one we moved.
3408       // Note: if pb->next is NULL, then pb must have 
3409       // been the last pBlock in the chain.
3410
3411       if(pbn)
3412         pbn->prev = pb->prev;
3413       else
3414         the_pFile->pbTail = pb->prev;
3415
3416       pb = pbn;
3417
3418     } else
3419       pb = pb->next;
3420
3421   }
3422
3423 }
3424
3425 void pic16_copypCode(FILE *of, char dbName)
3426 {
3427   pBlock *pb;
3428
3429         if(!of || !the_pFile)
3430                 return;
3431
3432         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3433                 if(getpBlock_dbName(pb) == dbName) {
3434 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3435                         pBlockStats(of,pb);
3436                         pic16_printpBlock(of,pb);
3437                 }
3438         }
3439
3440 }
3441 void pic16_pcode_test(void)
3442 {
3443
3444   DFPRINTF((stderr,"pcode is alive!\n"));
3445
3446   //initMnemonics();
3447
3448   if(the_pFile) {
3449
3450     pBlock *pb;
3451     FILE *pFile;
3452     char buffer[100];
3453
3454     /* create the file name */
3455     strcpy(buffer,dstFileName);
3456     strcat(buffer,".p");
3457
3458     if( !(pFile = fopen(buffer, "w" ))) {
3459       werror(E_FILE_OPEN_ERR,buffer);
3460       exit(1);
3461     }
3462
3463     fprintf(pFile,"pcode dump\n\n");
3464
3465     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3466       fprintf(pFile,"\n\tNew pBlock\n\n");
3467       if(pb->cmemmap)
3468         fprintf(pFile,"%s",pb->cmemmap->sname);
3469       else
3470         fprintf(pFile,"internal pblock");
3471
3472       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3473       pic16_printpBlock(pFile,pb);
3474     }
3475   }
3476 }
3477
3478
3479 unsigned long pic16_countInstructions(void)
3480 {
3481   pBlock *pb;
3482   pCode *pc;
3483   unsigned long isize=0;
3484
3485     if(!the_pFile)return -1;
3486     
3487     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3488       for(pc = pb->pcHead; pc; pc = pc->next) {
3489         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3490       }
3491     }
3492   return (isize);
3493 }
3494
3495
3496 /*-----------------------------------------------------------------*/
3497 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3498 /*      ister, RegCond will return the bit being referenced.       */
3499 /*                                                                 */
3500 /* fixme - why not just OR in the pcop bit field                   */
3501 /*-----------------------------------------------------------------*/
3502
3503 static int RegCond(pCodeOp *pcop)
3504 {
3505
3506   if(!pcop)
3507     return 0;
3508
3509   if(!pcop->name)return 0;
3510
3511   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3512     switch(PCORB(pcop)->bit) {
3513     case PIC_C_BIT:
3514       return PCC_C;
3515     case PIC_DC_BIT:
3516         return PCC_DC;
3517     case PIC_Z_BIT:
3518       return PCC_Z;
3519     }
3520
3521   }
3522
3523   return 0;
3524 }
3525
3526 /*-----------------------------------------------------------------*/
3527 /* pic16_newpCode - create and return a newly initialized pCode          */
3528 /*                                                                 */
3529 /*  fixme - rename this                                            */
3530 /*                                                                 */
3531 /* The purpose of this routine is to create a new Instruction      */
3532 /* pCode. This is called by gen.c while the assembly code is being */
3533 /* generated.                                                      */
3534 /*                                                                 */
3535 /* Inouts:                                                         */
3536 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3537 /*                  (note that the op is analogous to but not the  */
3538 /*                  same thing as the opcode of the instruction.)  */
3539 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3540 /*                                                                 */
3541 /* Outputs:                                                        */
3542 /*  a pointer to the new malloc'd pCode is returned.               */
3543 /*                                                                 */
3544 /*                                                                 */
3545 /*                                                                 */
3546 /*-----------------------------------------------------------------*/
3547 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3548 {
3549   pCodeInstruction *pci ;
3550
3551   if(!mnemonics_initialized)
3552     pic16initMnemonics();
3553     
3554   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3555
3556   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3557     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3558     pci->pcop = pcop;
3559
3560     if(pci->inCond & PCC_EXAMINE_PCOP)
3561       pci->inCond  |= RegCond(pcop);
3562
3563     if(pci->outCond & PCC_EXAMINE_PCOP)
3564       pci->outCond  |= RegCond(pcop);
3565
3566     pci->pc.prev = pci->pc.next = NULL;
3567     return (pCode *)pci;
3568   }
3569
3570   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3571   exit(1);
3572
3573   return NULL;
3574 }       
3575
3576 /*-----------------------------------------------------------------*/
3577 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3578 /*                                                                 */
3579 /* Wild pcodes are used during the peep hole optimizer to serve    */
3580 /* as place holders for any instruction. When a snippet of code is */
3581 /* compared to a peep hole rule, the wild card opcode will match   */
3582 /* any instruction. However, the optional operand and label are    */
3583 /* additional qualifiers that must also be matched before the      */
3584 /* line (of assembly code) is declared matched. Note that the      */
3585 /* operand may be wild too.                                        */
3586 /*                                                                 */
3587 /*   Note, a wild instruction is specified just like a wild var:   */
3588 /*      %4     ; A wild instruction,                               */
3589 /*  See the peeph.def file for additional examples                 */
3590 /*                                                                 */
3591 /*-----------------------------------------------------------------*/
3592
3593 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3594 {
3595
3596   pCodeWild *pcw;
3597     
3598   pcw = Safe_calloc(1,sizeof(pCodeWild));
3599
3600   pcw->pci.pc.type = PC_WILD;
3601   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3602   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3603   pcw->pci.pc.pb = NULL;
3604
3605   //  pcw->pci.pc.analyze = genericAnalyze;
3606   pcw->pci.pc.destruct = genericDestruct;
3607   pcw->pci.pc.print = genericPrint;
3608
3609   pcw->id = pCodeID;              // this is the 'n' in %n
3610   pcw->operand = optional_operand;
3611   pcw->label   = optional_label;
3612
3613   pcw->mustBeBitSkipInst = 0;
3614   pcw->mustNotBeBitSkipInst = 0;
3615   pcw->invertBitSkipInst = 0;
3616
3617   return ( (pCode *)pcw);
3618   
3619 }
3620
3621  /*-----------------------------------------------------------------*/
3622 /* newPcodeInlineP - create a new pCode from a char string           */
3623 /*-----------------------------------------------------------------*/
3624
3625
3626 pCode *pic16_newpCodeInlineP(char *cP)
3627 {
3628
3629   pCodeComment *pcc ;
3630     
3631   pcc = Safe_calloc(1,sizeof(pCodeComment));
3632
3633   pcc->pc.type = PC_INLINE;
3634   pcc->pc.prev = pcc->pc.next = NULL;
3635   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3636   pcc->pc.pb = NULL;
3637
3638   //  pcc->pc.analyze = genericAnalyze;
3639   pcc->pc.destruct = genericDestruct;
3640   pcc->pc.print = genericPrint;
3641
3642   if(cP)
3643     pcc->comment = Safe_strdup(cP);
3644   else
3645     pcc->comment = NULL;
3646
3647   return ( (pCode *)pcc);
3648
3649 }
3650
3651 /*-----------------------------------------------------------------*/
3652 /* newPcodeCharP - create a new pCode from a char string           */
3653 /*-----------------------------------------------------------------*/
3654
3655 pCode *pic16_newpCodeCharP(char *cP)
3656 {
3657
3658   pCodeComment *pcc ;
3659     
3660   pcc = Safe_calloc(1,sizeof(pCodeComment));
3661
3662   pcc->pc.type = PC_COMMENT;
3663   pcc->pc.prev = pcc->pc.next = NULL;
3664   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3665   pcc->pc.pb = NULL;
3666
3667   //  pcc->pc.analyze = genericAnalyze;
3668   pcc->pc.destruct = genericDestruct;
3669   pcc->pc.print = genericPrint;
3670
3671   if(cP)
3672     pcc->comment = Safe_strdup(cP);
3673   else
3674     pcc->comment = NULL;
3675
3676   return ( (pCode *)pcc);
3677
3678 }
3679
3680 /*-----------------------------------------------------------------*/
3681 /* pic16_newpCodeFunction -                                              */
3682 /*-----------------------------------------------------------------*/
3683
3684
3685 pCode *pic16_newpCodeFunction(char *mod,char *f)
3686 {
3687   pCodeFunction *pcf;
3688
3689   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3690
3691   pcf->pc.type = PC_FUNCTION;
3692   pcf->pc.prev = pcf->pc.next = NULL;
3693   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3694   pcf->pc.pb = NULL;
3695
3696   //  pcf->pc.analyze = genericAnalyze;
3697   pcf->pc.destruct = genericDestruct;
3698   pcf->pc.print = pCodePrintFunction;
3699
3700   pcf->ncalled = 0;
3701   pcf->absblock = 0;
3702   
3703   if(mod) {
3704     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3705     strcpy(pcf->modname,mod);
3706   } else
3707     pcf->modname = NULL;
3708
3709   if(f) {
3710     pcf->fname = Safe_calloc(1,strlen(f)+1);
3711     strcpy(pcf->fname,f);
3712   } else
3713     pcf->fname = NULL;
3714
3715   pcf->stackusage = 0;
3716
3717   return ( (pCode *)pcf);
3718 }
3719
3720 /*-----------------------------------------------------------------*/
3721 /* pic16_newpCodeFlow                                                    */
3722 /*-----------------------------------------------------------------*/
3723 static void destructpCodeFlow(pCode *pc)
3724 {
3725   if(!pc || !isPCFL(pc))
3726     return;
3727
3728 /*
3729   if(PCFL(pc)->from)
3730   if(PCFL(pc)->to)
3731 */
3732   pic16_unlinkpCode(pc);
3733
3734   deleteSet(&PCFL(pc)->registers);
3735   deleteSet(&PCFL(pc)->from);
3736   deleteSet(&PCFL(pc)->to);
3737
3738   /* Instead of deleting the memory used by this pCode, mark
3739    * the object as bad so that if there's a pointer to this pCode
3740    * dangling around somewhere then (hopefully) when the type is
3741    * checked we'll catch it.
3742    */
3743
3744   pc->type = PC_BAD;
3745   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3746
3747 //  Safe_free(pc);
3748
3749 }
3750
3751 pCode *pic16_newpCodeFlow(void )
3752 {
3753   pCodeFlow *pcflow;
3754
3755   //_ALLOC(pcflow,sizeof(pCodeFlow));
3756   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3757
3758   pcflow->pc.type = PC_FLOW;
3759   pcflow->pc.prev = pcflow->pc.next = NULL;
3760   pcflow->pc.pb = NULL;
3761
3762   //  pcflow->pc.analyze = genericAnalyze;
3763   pcflow->pc.destruct = destructpCodeFlow;
3764   pcflow->pc.print = genericPrint;
3765
3766   pcflow->pc.seq = GpcFlowSeq++;
3767
3768   pcflow->from = pcflow->to = NULL;
3769
3770   pcflow->inCond = PCC_NONE;
3771   pcflow->outCond = PCC_NONE;
3772
3773   pcflow->firstBank = -1;
3774   pcflow->lastBank = -1;
3775
3776   pcflow->FromConflicts = 0;
3777   pcflow->ToConflicts = 0;
3778
3779   pcflow->end = NULL;
3780
3781   pcflow->registers = newSet();
3782
3783   return ( (pCode *)pcflow);
3784
3785 }
3786
3787 /*-----------------------------------------------------------------*/
3788 /*-----------------------------------------------------------------*/
3789 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3790 {
3791   pCodeFlowLink *pcflowLink;
3792
3793   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3794
3795   pcflowLink->pcflow = pcflow;
3796   pcflowLink->bank_conflict = 0;
3797
3798   return pcflowLink;
3799 }
3800
3801 /*-----------------------------------------------------------------*/
3802 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3803 /*-----------------------------------------------------------------*/
3804
3805 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3806 {
3807
3808   pCodeCSource *pccs;
3809     
3810   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3811
3812   pccs->pc.type = PC_CSOURCE;
3813   pccs->pc.prev = pccs->pc.next = NULL;
3814   pccs->pc.pb = NULL;
3815
3816   pccs->pc.destruct = genericDestruct;
3817   pccs->pc.print = genericPrint;
3818
3819   pccs->line_number = ln;
3820   if(l)
3821     pccs->line = Safe_strdup(l);
3822   else
3823     pccs->line = NULL;
3824
3825   if(f)
3826     pccs->file_name = Safe_strdup(f);
3827   else
3828     pccs->file_name = NULL;
3829
3830   return ( (pCode *)pccs);
3831
3832 }
3833
3834
3835 /*******************************************************************/
3836 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3837 /*                      added by VR 6-Jun-2003                     */
3838 /*******************************************************************/
3839
3840 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3841 {
3842   pCodeAsmDir *pcad;
3843   va_list ap;
3844   char buffer[512];
3845   char *lbp=buffer;
3846   
3847         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3848         pcad->pci.pc.type = PC_ASMDIR;
3849         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3850         pcad->pci.pc.pb = NULL;
3851         pcad->pci.isize = 2;
3852         pcad->pci.pc.destruct = genericDestruct;
3853         pcad->pci.pc.print = genericPrint;
3854
3855         if(asdir && *asdir) {
3856                 
3857                 while(isspace(*asdir))asdir++;  // strip any white space from the beginning
3858                 
3859                 pcad->directive = Safe_strdup( asdir );
3860         }
3861         
3862         va_start(ap, argfmt);
3863         
3864         memset(buffer, 0, sizeof(buffer));
3865         if(argfmt && *argfmt)
3866                 vsprintf(buffer, argfmt, ap);
3867         
3868         va_end(ap);
3869         
3870         while(isspace(*lbp))lbp++;
3871         
3872         if(lbp && *lbp)
3873                 pcad->arg = Safe_strdup( lbp );
3874
3875   return ((pCode *)pcad);
3876 }
3877
3878 /*-----------------------------------------------------------------*/
3879 /* pCodeLabelDestruct - free memory used by a label.               */
3880 /*-----------------------------------------------------------------*/
3881 static void pCodeLabelDestruct(pCode *pc)
3882 {
3883
3884   if(!pc)
3885     return;
3886
3887 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3888 //    Safe_free(PCL(pc)->label);
3889
3890   /* Instead of deleting the memory used by this pCode, mark
3891    * the object as bad so that if there's a pointer to this pCode
3892    * dangling around somewhere then (hopefully) when the type is
3893    * checked we'll catch it.
3894    */
3895
3896   pc->type = PC_BAD;
3897   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3898
3899 //  Safe_free(pc);
3900
3901 }
3902
3903 pCode *pic16_newpCodeLabel(char *name, int key)
3904 {
3905
3906   char *s = buffer;
3907   pCodeLabel *pcl;
3908     
3909   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3910
3911   pcl->pc.type = PC_LABEL;
3912   pcl->pc.prev = pcl->pc.next = NULL;
3913   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3914   pcl->pc.pb = NULL;
3915
3916   //  pcl->pc.analyze = genericAnalyze;
3917   pcl->pc.destruct = pCodeLabelDestruct;
3918   pcl->pc.print = pCodePrintLabel;
3919
3920   pcl->key = key;
3921   pcl->force = 0;
3922   
3923   pcl->label = NULL;
3924   if(key>0) {
3925     sprintf(s,"_%05d_DS_",key);
3926   } else
3927     s = name;
3928
3929   if(s)
3930     pcl->label = Safe_strdup(s);
3931
3932 //  if(pic16_pcode_verbose)
3933 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3934
3935
3936   return ( (pCode *)pcl);
3937
3938 }
3939
3940 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3941 {
3942   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3943   
3944         pcl->force = 1;
3945   
3946   return ( (pCode *)pcl );
3947 }
3948
3949 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3950 {
3951   pCodeInfo *pci;
3952
3953     pci = Safe_calloc(1, sizeof(pCodeInfo));
3954     pci->pci.pc.type = PC_INFO;
3955     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3956     pci->pci.pc.pb = NULL;
3957     pci->pci.label = NULL;
3958         
3959     pci->pci.pc.destruct = genericDestruct;
3960     pci->pci.pc.print = genericPrint;
3961     
3962     pci->type = type;
3963     pci->oper1 = pcop;
3964   
3965   return ((pCode *)pci);
3966 }
3967
3968
3969 /*-----------------------------------------------------------------*/
3970 /* newpBlock - create and return a pointer to a new pBlock         */
3971 /*-----------------------------------------------------------------*/
3972 static pBlock *newpBlock(void)
3973 {
3974
3975   pBlock *PpB;
3976
3977   PpB = Safe_calloc(1,sizeof(pBlock) );
3978   PpB->next = PpB->prev = NULL;
3979
3980   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3981   PpB->tregisters = NULL;
3982   PpB->visited = 0;
3983   PpB->FlowTree = NULL;
3984
3985   return PpB;
3986
3987 }
3988
3989 /*-----------------------------------------------------------------*/
3990 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3991 /*-----------------------------------------------------------------*
3992  *
3993  *  This function will create a new pBlock and the pointer to the
3994  *  pCode that is passed in will be the first pCode in the block.
3995  *-----------------------------------------------------------------*/
3996
3997
3998 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3999 {
4000
4001   pBlock *pB  = newpBlock();
4002
4003   pB->pcHead  = pB->pcTail = pc;
4004   pB->cmemmap = cm;
4005   pB->dbName  = c;
4006
4007   return pB;
4008 }
4009
4010
4011
4012 /*-----------------------------------------------------------------*/
4013 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4014 /*  Note, a negative key means that the label is part of wild card */
4015 /*  (and hence a wild card label) used in the pCodePeep            */
4016 /*   optimizations).                                               */
4017 /*-----------------------------------------------------------------*/
4018
4019 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4020 {
4021   char *s=NULL;
4022   static int label_key=-1;
4023
4024   pCodeOp *pcop;
4025
4026   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4027   pcop->type = PO_LABEL;
4028
4029   pcop->name = NULL;
4030
4031   if(key>0)
4032     sprintf(s=buffer,"_%05d_DS_",key);
4033   else 
4034     s = name, key = label_key--;
4035
4036   if(s)
4037     pcop->name = Safe_strdup(s);
4038
4039   ((pCodeOpLabel *)pcop)->key = key;
4040
4041   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4042   return pcop;
4043 }
4044
4045 /*-----------------------------------------------------------------*/
4046 /*-----------------------------------------------------------------*/
4047 pCodeOp *pic16_newpCodeOpLit(int lit)
4048 {
4049   char *s = buffer;
4050   pCodeOp *pcop;
4051
4052
4053   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4054   pcop->type = PO_LITERAL;
4055
4056   pcop->name = NULL;
4057   //if(lit>=0)
4058     sprintf(s,"0x%02hhx", (unsigned char)lit);
4059   //else
4060   //  sprintf(s, "%i", lit);
4061   
4062   if(s)
4063     pcop->name = Safe_strdup(s);
4064
4065   ((pCodeOpLit *)pcop)->lit = lit;
4066
4067   return pcop;
4068 }
4069
4070 /*-----------------------------------------------------------------*/
4071 /*-----------------------------------------------------------------*/
4072 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4073 {
4074   char *s = buffer, tbuf[256], *tb=tbuf;
4075   pCodeOp *pcop;
4076
4077
4078   tb = pic16_get_op(arg2, NULL, 0);
4079   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4080   pcop->type = PO_LITERAL;
4081
4082   pcop->name = NULL;
4083   //if(lit>=0) {
4084     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4085     if(s)
4086       pcop->name = Safe_strdup(s);
4087   //}
4088
4089   ((pCodeOpLit2 *)pcop)->lit = lit;
4090   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4091
4092   return pcop;
4093 }
4094
4095 /*-----------------------------------------------------------------*/
4096 /*-----------------------------------------------------------------*/
4097 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4098 {
4099   pCodeOp *pcop;
4100
4101         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4102         pcop->type = PO_IMMEDIATE;
4103         if(name) {
4104                 regs *r = pic16_dirregWithName(name);
4105                 pcop->name = Safe_strdup(name);
4106                 PCOI(pcop)->r = r;
4107                 
4108                 if(r) {
4109 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4110                         PCOI(pcop)->rIdx = r->rIdx;
4111                 } else {
4112 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4113                         PCOI(pcop)->rIdx = -1;
4114                 }
4115 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4116         } else {
4117                 pcop->name = NULL;
4118         }
4119
4120         PCOI(pcop)->index = index;
4121         PCOI(pcop)->offset = offset;
4122         PCOI(pcop)->_const = code_space;
4123
4124   return pcop;
4125 }
4126
4127 /*-----------------------------------------------------------------*/
4128 /*-----------------------------------------------------------------*/
4129 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4130 {
4131   char *s = buffer;
4132   pCodeOp *pcop;
4133
4134
4135   if(!pcwb || !subtype) {
4136     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4137     exit(1);
4138   }
4139
4140   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4141   pcop->type = PO_WILD;
4142   sprintf(s,"%%%d",id);
4143   pcop->name = Safe_strdup(s);
4144
4145   PCOW(pcop)->id = id;
4146   PCOW(pcop)->pcwb = pcwb;
4147   PCOW(pcop)->subtype = subtype;
4148   PCOW(pcop)->matched = NULL;
4149
4150   PCOW(pcop)->pcop2 = NULL;
4151   
4152   return pcop;
4153 }
4154
4155 /*-----------------------------------------------------------------*/
4156 /*-----------------------------------------------------------------*/
4157 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4158 {
4159   char *s = buffer;
4160   pCodeOp *pcop;
4161
4162
4163         if(!pcwb || !subtype || !subtype2) {
4164                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4165                 exit(1);
4166         }
4167
4168         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4169         pcop->type = PO_WILD;
4170         sprintf(s,"%%%d",id);
4171         pcop->name = Safe_strdup(s);
4172
4173         PCOW(pcop)->id = id;
4174         PCOW(pcop)->pcwb = pcwb;
4175         PCOW(pcop)->subtype = subtype;
4176         PCOW(pcop)->matched = NULL;
4177
4178         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4179
4180         if(!subtype2->name) {
4181                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4182                 PCOW2(pcop)->pcop.type = PO_WILD;
4183                 sprintf(s, "%%%d", id2);
4184                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4185                 PCOW2(pcop)->id = id2;
4186                 PCOW2(pcop)->subtype = subtype2;
4187
4188 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4189 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4190         } else {
4191                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4192
4193 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4194 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4195         }
4196   
4197
4198
4199   return pcop;
4200 }
4201
4202
4203 /*-----------------------------------------------------------------*/
4204 /*-----------------------------------------------------------------*/
4205 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4206 {
4207   pCodeOp *pcop;
4208   
4209   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4210   pcop->type = PO_GPR_BIT;
4211   if(s)
4212     pcop->name = Safe_strdup(s);   
4213   else
4214     pcop->name = NULL;
4215
4216   PCORB(pcop)->bit = bit;
4217   PCORB(pcop)->inBitSpace = inBitSpace;
4218   PCORB(pcop)->subtype = subt;
4219
4220   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4221   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4222 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4223 //  PCOR(pcop)->rIdx = 0;
4224   return pcop;
4225 }
4226
4227
4228 /*-----------------------------------------------------------------*
4229  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4230  *
4231  * If rIdx >=0 then a specific register from the set of registers
4232  * will be selected. If rIdx <0, then a new register will be searched
4233  * for.
4234  *-----------------------------------------------------------------*/
4235
4236 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4237 {
4238   pCodeOp *pcop;
4239
4240   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4241
4242   pcop->name = NULL;
4243
4244   if(rIdx >= 0) {
4245     PCOR(pcop)->rIdx = rIdx;
4246     PCOR(pcop)->r = pic16_regWithIdx(rIdx);
4247   } else {
4248     PCOR(pcop)->r = pic16_findFreeReg(REG_GPR);
4249
4250     if(PCOR(pcop)->r)
4251       PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4252     else {
4253         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4254                 __FUNCTION__, __LINE__);
4255         exit(-1);
4256     }
4257   }
4258
4259   pcop->type = PCOR(pcop)->r->pc_type;
4260
4261   return pcop;
4262 }
4263
4264 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4265 {
4266   pCodeOp *pcop;
4267   regs *r;
4268   
4269     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4270     pcop->name = NULL;
4271     
4272     r = pic16_findFreeReg(REG_GPR);
4273
4274     while(r) {
4275       if(!bitVectBitValue(bv, r->rIdx)) {
4276         PCOR(pcop)->r = r;
4277         PCOR(pcop)->rIdx = r->rIdx;
4278         pcop->type = r->pc_type;
4279         return (pcop);
4280       }
4281       
4282       r = pic16_findFreeRegNext(REG_GPR, r);
4283     }
4284   
4285   return NULL;
4286 }
4287
4288       
4289
4290 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4291 {
4292   pCodeOp *pcop;
4293   regs *r;
4294
4295         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4296         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4297         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4298         pcop->type = PCOR(pcop)->r->pc_type;
4299         pcop->name = PCOR(pcop)->r->name;
4300
4301 //      if(pic16_pcode_verbose) {
4302 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4303 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4304 //      }
4305
4306   return pcop;
4307 }
4308
4309 /*-----------------------------------------------------------------*/
4310 /*-----------------------------------------------------------------*/
4311 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4312 {
4313   pCodeOpOpt *pcop;
4314
4315         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4316         
4317         pcop->type = type;
4318         pcop->key = Safe_strdup( key );
4319
4320   return (PCOP(pcop));
4321 }
4322
4323 /*-----------------------------------------------------------------*/
4324 /*-----------------------------------------------------------------*/
4325 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4326 {
4327   pCodeOpLocalReg *pcop;
4328
4329         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4330         
4331         pcop->type = type;
4332
4333   return (PCOP(pcop));
4334 }
4335
4336
4337 /*-----------------------------------------------------------------*/
4338 /*-----------------------------------------------------------------*/
4339
4340 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4341 {
4342   pCodeOp *pcop;
4343
4344   switch(type) {
4345   case PO_BIT:
4346   case PO_GPR_BIT:
4347     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4348     break;
4349
4350   case PO_LITERAL:
4351     pcop = pic16_newpCodeOpLit(-1);
4352     break;
4353
4354   case PO_LABEL:
4355     pcop = pic16_newpCodeOpLabel(NULL,-1);
4356     break;
4357   case PO_GPR_TEMP:
4358     pcop = pic16_newpCodeOpReg(-1);
4359     break;
4360
4361   case PO_GPR_REGISTER:
4362     if(name)
4363       pcop = pic16_newpCodeOpRegFromStr(name);
4364     else
4365       pcop = pic16_newpCodeOpReg(-1);
4366     break;
4367
4368   default:
4369     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4370     pcop->type = type;
4371     if(name)
4372       pcop->name = Safe_strdup(name);   
4373     else
4374       pcop->name = NULL;
4375   }
4376
4377   return pcop;
4378 }
4379
4380 #define DB_ITEMS_PER_LINE       8
4381
4382 typedef struct DBdata
4383   {
4384     int count;
4385     char buffer[256];
4386   } DBdata;
4387
4388 struct DBdata DBd;
4389 static int DBd_init = -1;
4390
4391 /*-----------------------------------------------------------------*/
4392 /*    Initialiase "DB" data buffer                                 */
4393 /*-----------------------------------------------------------------*/
4394 void pic16_initDB(void)
4395 {
4396         DBd_init = -1;
4397 }
4398
4399
4400 /*-----------------------------------------------------------------*/
4401 /*    Flush pending "DB" data to a pBlock                          */
4402 /*                                                                 */
4403 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4404 /*-----------------------------------------------------------------*/
4405 void pic16_flushDB(char ptype, void *p)
4406 {
4407         if (DBd.count>0) {
4408                 if(ptype == 'p')
4409                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4410                 else
4411                 if(ptype == 'f')
4412                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4413                 else {
4414                         /* sanity check */
4415                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4416                 }
4417
4418                 DBd.count = 0;
4419                 DBd.buffer[0] = '\0';
4420         }
4421 }
4422
4423
4424 /*-----------------------------------------------------------------*/
4425 /*    Add "DB" directives to a pBlock                              */
4426 /*-----------------------------------------------------------------*/
4427 void pic16_emitDB(char c, char ptype, void *p)
4428 {
4429   int l;
4430
4431         if (DBd_init<0) {
4432          // we need to initialize
4433                 DBd_init = 0;
4434                 DBd.count = 0;
4435                 DBd.buffer[0] = '\0';
4436         }
4437
4438         l = strlen(DBd.buffer);
4439         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4440
4441 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4442         
4443         DBd.count++;
4444         if (DBd.count>= DB_ITEMS_PER_LINE)
4445                 pic16_flushDB(ptype, p);
4446 }
4447
4448 void pic16_emitDS(char *s, char ptype, void *p)
4449 {
4450   int l;
4451
4452         if (DBd_init<0) {
4453          // we need to initialize
4454                 DBd_init = 0;
4455                 DBd.count = 0;
4456                 DBd.buffer[0] = '\0';
4457         }
4458
4459         l = strlen(DBd.buffer);
4460         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4461
4462 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4463
4464         DBd.count++;    //=strlen(s);
4465         if (DBd.count>=16)
4466                 pic16_flushDB(ptype, p);
4467 }
4468
4469
4470 /*-----------------------------------------------------------------*/
4471 /*-----------------------------------------------------------------*/
4472 void pic16_pCodeConstString(char *name, char *value)
4473 {
4474   pBlock *pb;
4475
4476   //  fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4477
4478   if(!name || !value)
4479     return;
4480
4481   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4482
4483   pic16_addpBlock(pb);
4484
4485 //  sprintf(buffer,"; %s = ", name);
4486 //  strcat(buffer, value);
4487 //  fputs(buffer, stderr);
4488
4489 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4490   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4491
4492   do {
4493         pic16_emitDB(*value, 'p', (void *)pb);
4494   }while (*value++);
4495   pic16_flushDB('p', (void *)pb);
4496 }
4497
4498 /*-----------------------------------------------------------------*/
4499 /*-----------------------------------------------------------------*/
4500 #if 0
4501 static void pCodeReadCodeTable(void)
4502 {
4503   pBlock *pb;
4504
4505   fprintf(stderr, " %s\n",__FUNCTION__);
4506
4507   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4508
4509   pic16_addpBlock(pb);
4510
4511   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4512   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4513   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4514   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4515
4516   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4517   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4518   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4519   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4520
4521
4522 }
4523 #endif
4524 /*-----------------------------------------------------------------*/
4525 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4526 /*-----------------------------------------------------------------*/
4527 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4528 {
4529
4530   if(!pc)
4531     return;
4532
4533   if(!pb->pcHead) {
4534     /* If this is the first pcode to be added to a block that
4535      * was initialized with a NULL pcode, then go ahead and
4536      * make this pcode the head and tail */
4537     pb->pcHead  = pb->pcTail = pc;
4538   } else {
4539     //    if(pb->pcTail)
4540     pb->pcTail->next = pc;
4541
4542     pc->prev = pb->pcTail;
4543     pc->pb = pb;
4544
4545     pb->pcTail = pc;
4546   }
4547 }
4548
4549 /*-----------------------------------------------------------------*/
4550 /* pic16_addpBlock - place a pBlock into the pFile                 */
4551 /*-----------------------------------------------------------------*/
4552 void pic16_addpBlock(pBlock *pb)
4553 {
4554   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4555
4556   if(!the_pFile) {
4557     /* First time called, we'll pass through here. */
4558     //_ALLOC(the_pFile,sizeof(pFile));
4559     the_pFile = Safe_calloc(1,sizeof(pFile));
4560     the_pFile->pbHead = the_pFile->pbTail = pb;
4561     the_pFile->functions = NULL;
4562     return;
4563   }
4564
4565   the_pFile->pbTail->next = pb;
4566   pb->prev = the_pFile->pbTail;
4567   pb->next = NULL;
4568   the_pFile->pbTail = pb;
4569 }
4570
4571 /*-----------------------------------------------------------------*/
4572 /* removepBlock - remove a pBlock from the pFile                   */
4573 /*-----------------------------------------------------------------*/
4574 static void removepBlock(pBlock *pb)
4575 {
4576   pBlock *pbs;
4577
4578   if(!the_pFile)
4579     return;
4580
4581
4582   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4583
4584   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4585     if(pbs == pb) {
4586
4587       if(pbs == the_pFile->pbHead)
4588         the_pFile->pbHead = pbs->next;
4589
4590       if (pbs == the_pFile->pbTail) 
4591         the_pFile->pbTail = pbs->prev;
4592
4593       if(pbs->next)
4594         pbs->next->prev = pbs->prev;
4595
4596       if(pbs->prev)
4597         pbs->prev->next = pbs->next;
4598
4599       return;
4600
4601     }
4602   }
4603
4604   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4605
4606 }
4607
4608 /*-----------------------------------------------------------------*/
4609 /* printpCode - write the contents of a pCode to a file            */
4610 /*-----------------------------------------------------------------*/
4611 static void printpCode(FILE *of, pCode *pc)
4612 {
4613
4614   if(!pc || !of)
4615     return;
4616
4617   if(pc->print) {
4618     pc->print(of,pc);
4619     return;
4620   }
4621
4622   fprintf(of,"warning - unable to print pCode\n");
4623 }
4624
4625 /*-----------------------------------------------------------------*/
4626 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4627 /*-----------------------------------------------------------------*/
4628 void pic16_printpBlock(FILE *of, pBlock *pb)
4629 {
4630   pCode *pc;
4631
4632         if(!pb)return;
4633
4634         if(!of)of=stderr;
4635
4636         for(pc = pb->pcHead; pc; pc = pc->next) {
4637                 if(isPCF(pc) && PCF(pc)->fname) {
4638                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4639                         if(pb->dbName == 'A') {
4640                           absSym *ab;
4641                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4642 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4643                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4644 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4645                                                 if(ab->address != -1)
4646                                                   fprintf(of, "\t0X%06X", ab->address);
4647                                                 break;
4648                                         }
4649                                 }
4650                         }
4651                         fprintf(of, "\n");
4652                 }
4653                 printpCode(of,pc);
4654         }
4655 }
4656
4657 /*-----------------------------------------------------------------*/
4658 /*                                                                 */
4659 /*       pCode processing                                          */
4660 /*                                                                 */
4661 /*                                                                 */
4662 /*                                                                 */
4663 /*-----------------------------------------------------------------*/
4664 pCode * pic16_findNextInstruction(pCode *pci);
4665 pCode * pic16_findPrevInstruction(pCode *pci);
4666
4667 void pic16_unlinkpCode(pCode *pc)
4668 {
4669   pCode *prev;
4670
4671   if(pc) {
4672 #ifdef PCODE_DEBUG
4673     fprintf(stderr,"Unlinking: ");
4674     printpCode(stderr, pc);
4675 #endif
4676     if(pc->prev) 
4677       pc->prev->next = pc->next;
4678     if(pc->next)
4679       pc->next->prev = pc->prev;
4680
4681     /* move C source line down (or up) */
4682     if (isPCI(pc) && PCI(pc)->cline) {
4683       prev = pic16_findNextInstruction (pc->next);
4684       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4685         PCI(prev)->cline = PCI(pc)->cline;
4686       } else {
4687         prev = pic16_findPrevInstruction (pc->prev);
4688         if (prev && isPCI(prev) && !PCI(prev)->cline)
4689           PCI(prev)->cline = PCI(pc)->cline;
4690       }
4691     }
4692     pc->prev = pc->next = NULL;
4693   }
4694 }
4695
4696 /*-----------------------------------------------------------------*/
4697 /*-----------------------------------------------------------------*/
4698
4699 static void genericDestruct(pCode *pc)
4700 {
4701
4702   pic16_unlinkpCode(pc);
4703
4704   if(isPCI(pc)) {
4705     /* For instructions, tell the register (if there's one used)
4706      * that it's no longer needed */
4707     regs *reg = pic16_getRegFromInstruction(pc);
4708     if(reg)
4709       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4710
4711         if(PCI(pc)->is2MemOp) {
4712                 reg = pic16_getRegFromInstruction2(pc);
4713                 if(reg)
4714                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4715         }
4716   }
4717
4718   /* Instead of deleting the memory used by this pCode, mark
4719    * the object as bad so that if there's a pointer to this pCode
4720    * dangling around somewhere then (hopefully) when the type is
4721    * checked we'll catch it.
4722    */
4723
4724   pc->type = PC_BAD;
4725   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4726
4727   //Safe_free(pc);
4728 }
4729
4730
4731 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4732 /*-----------------------------------------------------------------*/
4733 /*-----------------------------------------------------------------*/
4734 /* modifiers for constant immediate */
4735 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4736
4737 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4738 {
4739   regs *r;
4740   static char b[128];
4741   char *s;
4742   int use_buffer = 1;    // copy the string to the passed buffer pointer
4743
4744         if(!buffer) {
4745                 buffer = b;
4746                 size = sizeof(b);
4747                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4748         } 
4749
4750         if(pcop) {
4751                 switch(pcop->type) {
4752                         case PO_W:
4753                         case PO_WREG:
4754                         case PO_PRODL:
4755                         case PO_PRODH:
4756                         case PO_INDF0:
4757                         case PO_FSR0:
4758                                 if(use_buffer) {
4759                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4760                                         return buffer;
4761                                 }
4762                                 return PCOR(pcop)->r->name;
4763                                 break;
4764                         case PO_GPR_TEMP:
4765                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4766                                 if(use_buffer) {
4767                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4768                                         return buffer;
4769                                 }
4770                                 return r->name;
4771
4772                         case PO_IMMEDIATE:
4773                                 s = buffer;
4774                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4775                                         if(PCOI(pcop)->index) {
4776                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4777                                                         immdmod[ PCOI(pcop)->offset ],
4778                                                         pcop->name,
4779                                                         PCOI(pcop)->index);
4780                                         } else {
4781                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4782                                                         immdmod[ PCOI(pcop)->offset ],
4783                                                         pcop->name);
4784                                         }
4785                                 } else {
4786                                         if(PCOI(pcop)->index) {
4787                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4788                                                         immdmod[ 0 ],
4789                                                         pcop->name,
4790                                                         PCOI(pcop)->index);
4791                                         } else {
4792                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4793                                                         immdmod[ 0 ],
4794                                                         pcop->name);
4795                                         }
4796                                 }
4797                                 return buffer;
4798
4799                         case PO_GPR_REGISTER:
4800                         case PO_DIR:
4801                                 s = buffer;
4802 //                              size = sizeof(buffer);
4803                                 if( PCOR(pcop)->instance) {
4804                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4805                                                 pcop->name,
4806                                                 PCOR(pcop)->instance );
4807                                 } else {
4808                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4809                                 }
4810                                 return buffer;
4811                         case PO_GPR_BIT:
4812                                 s = buffer;
4813                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4814                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4815                                 } else {
4816                                         if(PCORB(pcop)->pcor.instance)
4817                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4818                                         else
4819                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4820                                 }
4821
4822                                 return (buffer);
4823                         default:
4824                                 if(pcop->name) {
4825                                         if(use_buffer) {
4826                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4827                                                 return buffer;
4828                                         }
4829                                 return pcop->name;
4830                                 }
4831
4832                 }
4833         }
4834
4835   return "NO operand1";
4836 }
4837
4838 /*-----------------------------------------------------------------*/
4839 /* pic16_get_op2 - variant to support two memory operand commands  */
4840 /*-----------------------------------------------------------------*/
4841 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4842 {
4843   regs *r;
4844   static char b[128];
4845   char *s;
4846   int use_buffer = 1;    // copy the string to the passed buffer pointer
4847
4848         if(!buffer) {
4849                 buffer = b;
4850                 size = sizeof(b);
4851                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4852         } 
4853
4854 #if 0
4855         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",
4856                 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4857                 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4858 #endif
4859
4860         if(pcop) {
4861                 switch(PCOR2(pcop)->pcop2->type) {
4862                         case PO_W:
4863                         case PO_WREG:
4864                         case PO_PRODL:
4865                         case PO_PRODH:
4866                         case PO_INDF0:
4867                         case PO_FSR0:
4868                                 if(use_buffer) {
4869                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4870                                         return buffer;
4871                                 }
4872                                 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4873                                 break;
4874                         case PO_GPR_TEMP:
4875                                 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4876
4877                                 if(use_buffer) {
4878                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4879                                         return buffer;
4880                                 }
4881                                 return r->name;
4882
4883                         case PO_IMMEDIATE:
4884                                         assert( 0 );
4885                                 break;
4886 #if 0
4887                                 s = buffer;
4888
4889                                 if(PCOI(pcop)->_const) {
4890                                         if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4891                                                 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4892                                                         pcop->name,
4893                                                         PCOI(pcop)->index,
4894                                                         8 * PCOI(pcop)->offset );
4895                                         } else
4896                                                 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4897                                 } else {
4898                                         if( PCOI(pcop)->index) {
4899                                                 SAFE_snprintf(&s,&size,"(%s + %d)",
4900                                                         pcop->name,
4901                                                         PCOI(pcop)->index );
4902                                         } else {
4903                                                 if(PCOI(pcop)->offset)
4904                                                         SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4905                                                 else
4906                                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4907                                         }
4908                                 }
4909                                 return buffer;
4910 #endif
4911                         case PO_DIR:
4912                                 s = buffer;
4913                                 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4914                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4915                                                 PCOR(PCOR2(pcop)->pcop2)->r->name,
4916                                                 PCOR(PCOR2(pcop)->pcop2)->instance );
4917                                 } else {
4918                                         SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4919                                 }
4920                                 return buffer;
4921
4922                         default:
4923                                 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4924                                         if(use_buffer) {
4925                                                 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4926                                                 return buffer;
4927                                         }
4928                                         return PCOR(PCOR2(pcop)->pcop2)->r->name;
4929                                 }
4930                 }
4931         }
4932
4933   return "NO operand2";
4934 }
4935
4936 /*-----------------------------------------------------------------*/
4937 /*-----------------------------------------------------------------*/
4938 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4939 {
4940
4941   if(pcc )
4942     return pic16_get_op(pcc->pcop,NULL,0);
4943
4944   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
4945    *   return ("ERROR Null: "__FUNCTION__);
4946    */
4947   return ("ERROR Null: pic16_get_op_from_instruction");
4948
4949 }
4950
4951 /*-----------------------------------------------------------------*/
4952 /*-----------------------------------------------------------------*/
4953 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4954 {
4955
4956   fprintf(of,"pcodeopprint- not implemented\n");
4957 }
4958
4959 /*-----------------------------------------------------------------*/
4960 /* pic16_pCode2str - convert a pCode instruction to string               */
4961 /*-----------------------------------------------------------------*/
4962 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4963 {
4964   char *s = str;
4965   regs *r;
4966
4967 #if 0
4968         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4969                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4970                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4971 //              exit(-1);
4972         }
4973 #endif
4974
4975   switch(pc->type) {
4976
4977   case PC_OPCODE:
4978     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4979
4980     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4981
4982         if(PCI(pc)->is2MemOp) {
4983                 SAFE_snprintf(&s,&size, "%s, %s", 
4984                 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
4985                 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
4986                 break;
4987         }
4988
4989         if(PCI(pc)->is2LitOp) {
4990                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4991                 break;
4992         }
4993
4994       if(PCI(pc)->isBitInst) {
4995         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4996           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4997             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
4998                           PCI(pc)->pcop->name ,
4999                           PCI(pc)->pcop->name );
5000           else
5001             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5002 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5003                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5004                           
5005         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5006           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5007         } else
5008           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5009         //PCI(pc)->pcop->t.bit );
5010       } else {
5011
5012         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5013           if( PCI(pc)->num_ops == 3)
5014             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5015           else
5016             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5017
5018         }
5019         else 
5020         {
5021           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5022         }
5023       }
5024         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5025           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5026             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5027
5028           r = pic16_getRegFromInstruction(pc);
5029 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5030 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5031
5032           if(r && !r->accessBank)SAFE_snprintf(&s,&size,", %s", (!pic16_mplab_comp?"B":"BANKED"));
5033         }
5034 //      
5035
5036     }
5037     break;
5038
5039   case PC_COMMENT:
5040     /* assuming that comment ends with a \n */
5041     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5042     break;
5043
5044   case PC_INFO:
5045     SAFE_snprintf(&s,&size,"; info ==>");
5046     switch( PCINF(pc)->type ) {
5047       case INF_OPTIMIZATION:
5048           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5049           break;
5050       case INF_LOCALREGS:
5051           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5052           break;
5053     }; break;
5054
5055   case PC_INLINE:
5056     /* assuming that inline code ends with a \n */
5057     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5058     break;
5059
5060   case PC_LABEL:
5061     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5062     break;
5063   case PC_FUNCTION:
5064     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5065     break;
5066   case PC_WILD:
5067     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5068     break;
5069   case PC_FLOW:
5070     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5071     break;
5072   case PC_CSOURCE:
5073 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5074       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5075         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5076     break;
5077   case PC_ASMDIR:
5078         if(PCAD(pc)->directive) {
5079                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5080         } else
5081         if(PCAD(pc)->arg) {
5082                 /* special case to handle inline labels without a tab */
5083                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5084         }
5085         break;
5086
5087   case PC_BAD:
5088     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5089     break;
5090   }
5091
5092   return str;
5093
5094 }
5095
5096 /*-----------------------------------------------------------------*/
5097 /* genericPrint - the contents of a pCode to a file                */
5098 /*-----------------------------------------------------------------*/
5099 static void genericPrint(FILE *of, pCode *pc)
5100 {
5101
5102   if(!pc || !of)
5103     return;
5104
5105   switch(pc->type) {
5106   case PC_COMMENT:
5107 //    fputs(((pCodeComment *)pc)->comment, of);
5108     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5109     break;
5110
5111   case PC_INFO:
5112     {
5113       pBranch *pbl = PCI(pc)->label;
5114       while(pbl && pbl->pc) {
5115         if(pbl->pc->type == PC_LABEL)
5116           pCodePrintLabel(of, pbl->pc);
5117         pbl = pbl->next;
5118       }
5119     }
5120           
5121     if(pic16_pcode_verbose) {
5122       fprintf(of, "; info ==>");
5123       switch(((pCodeInfo *)pc)->type) {
5124         case INF_OPTIMIZATION:
5125               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5126               break;
5127         case INF_LOCALREGS:
5128               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5129               break;
5130         }
5131     };
5132     
5133     break;
5134
5135   case PC_INLINE:
5136     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5137      break;
5138
5139   case PC_OPCODE:
5140     // If the opcode has a label, print that first
5141     {
5142       pBranch *pbl = PCI(pc)->label;
5143       while(pbl && pbl->pc) {
5144         if(pbl->pc->type == PC_LABEL)
5145           pCodePrintLabel(of, pbl->pc);
5146         pbl = pbl->next;
5147       }
5148     }
5149
5150     if(PCI(pc)->cline) 
5151       genericPrint(of,PCODE(PCI(pc)->cline));
5152
5153     {
5154       char str[256];
5155       
5156       pic16_pCode2str(str, 256, pc);
5157
5158       fprintf(of,"%s",str);
5159       /* Debug */
5160       if(pic16_debug_verbose) {
5161         fprintf(of, "\t;key=%03x",pc->seq);
5162         if(PCI(pc)->pcflow)
5163           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5164       }
5165     }
5166     fprintf(of, "\n");
5167     break;
5168       
5169   case PC_WILD:
5170     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5171     if(PCW(pc)->pci.label)
5172       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5173
5174     if(PCW(pc)->operand) {
5175       fprintf(of,";\toperand  ");
5176       pCodeOpPrint(of,PCW(pc)->operand );
5177     }
5178     break;
5179
5180   case PC_FLOW:
5181     if(pic16_debug_verbose) {
5182       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5183       if(PCFL(pc)->ancestor)
5184         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5185       fprintf(of,"\n");
5186
5187     }
5188     break;
5189
5190   case PC_CSOURCE:
5191 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5192     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5193         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5194          
5195     break;
5196
5197   case PC_ASMDIR:
5198         {
5199           pBranch *pbl = PCAD(pc)->pci.label;
5200                 while(pbl && pbl->pc) {
5201                         if(pbl->pc->type == PC_LABEL)
5202                                 pCodePrintLabel(of, pbl->pc);
5203                         pbl = pbl->next;
5204                 }
5205         }
5206         if(PCAD(pc)->directive) {
5207                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5208         } else
5209         if(PCAD(pc)->arg) {
5210                 /* special case to handle inline labels without tab */
5211                 fprintf(of, "%s\n", PCAD(pc)->arg);
5212         }
5213         break;
5214         
5215   case PC_LABEL:
5216   default:
5217     fprintf(of,"unknown pCode type %d\n",pc->type);
5218   }
5219
5220 }
5221
5222 /*-----------------------------------------------------------------*/
5223 /* pCodePrintFunction - prints function begin/end                  */
5224 /*-----------------------------------------------------------------*/
5225
5226 static void pCodePrintFunction(FILE *of, pCode *pc)
5227 {
5228
5229   if(!pc || !of)
5230     return;
5231
5232 #if 0
5233   if( ((pCodeFunction *)pc)->modname) 
5234     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5235 #endif
5236
5237   if(!PCF(pc)->absblock) {
5238       if(PCF(pc)->fname) {
5239       pBranch *exits = PCF(pc)->to;
5240       int i=0;
5241
5242       fprintf(of,"%s:", PCF(pc)->fname);
5243     
5244       if(pic16_pcode_verbose)
5245         fprintf(of, "\t;Function start");
5246     
5247       fprintf(of, "\n");
5248     
5249       while(exits) {
5250         i++;
5251         exits = exits->next;
5252       }
5253       //if(i) i--;
5254
5255       if(pic16_pcode_verbose)
5256         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5257     
5258     } else {
5259         if((PCF(pc)->from && 
5260                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5261                 PCF(PCF(pc)->from->pc)->fname) ) {
5262
5263                 if(pic16_pcode_verbose)
5264                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5265         } else {
5266                 if(pic16_pcode_verbose)
5267                         fprintf(of,"; exit point [can't find entry point]\n");
5268         }
5269         fprintf(of, "\n");
5270     }
5271   }
5272 }
5273 /*-----------------------------------------------------------------*/
5274 /* pCodePrintLabel - prints label                                  */
5275 /*-----------------------------------------------------------------*/
5276
5277 static void pCodePrintLabel(FILE *of, pCode *pc)
5278 {
5279
5280   if(!pc || !of)
5281     return;
5282
5283   if(PCL(pc)->label) 
5284     fprintf(of,"%s:\n",PCL(pc)->label);
5285   else if (PCL(pc)->key >=0) 
5286     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5287   else
5288     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5289
5290 }
5291 /*-----------------------------------------------------------------*/
5292 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5293 /*                         remove it if it is found.               */
5294 /*-----------------------------------------------------------------*/
5295 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5296 {
5297   pBranch *b, *bprev;
5298
5299
5300   bprev = NULL;
5301
5302   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5303     b = PCI(pcl)->label;
5304   else {
5305     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5306     exit(1);
5307
5308   }
5309
5310   //fprintf (stderr, "%s \n",__FUNCTION__);
5311   //pcl->print(stderr,pcl);
5312   //pc->print(stderr,pc);
5313   while(b) {
5314     if(b->pc == pc) {
5315       //fprintf (stderr, "found label\n");
5316       //pc->print(stderr, pc);
5317
5318       /* Found a label */
5319       if(bprev) {
5320         bprev->next = b->next;  /* Not first pCode in chain */
5321 //      Safe_free(b);
5322       } else {
5323         pc->destruct(pc);
5324         PCI(pcl)->label = b->next;   /* First pCode in chain */
5325 //      Safe_free(b);
5326       }
5327       return;  /* A label can't occur more than once */
5328     }
5329     bprev = b;
5330     b = b->next;
5331   }
5332
5333 }
5334
5335 /*-----------------------------------------------------------------*/
5336 /*-----------------------------------------------------------------*/
5337 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5338 {
5339   pBranch *b;
5340
5341   if(!h)
5342     return n;
5343
5344   if(h == n)
5345     return n;
5346
5347   b = h;
5348   while(b->next)
5349     b = b->next;
5350
5351   b->next = n;
5352
5353   return h;
5354   
5355 }  
5356 /*-----------------------------------------------------------------*/
5357 /* pBranchLink - given two pcodes, this function will link them    */
5358 /*               together through their pBranches                  */
5359 /*-----------------------------------------------------------------*/
5360 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5361 {
5362   pBranch *b;
5363
5364   // Declare a new branch object for the 'from' pCode.
5365
5366   //_ALLOC(b,sizeof(pBranch));
5367   b = Safe_calloc(1,sizeof(pBranch));
5368   b->pc = PCODE(t);             // The link to the 'to' pCode.
5369   b->next = NULL;
5370
5371   f->to = pic16_pBranchAppend(f->to,b);
5372
5373   // Now do the same for the 'to' pCode.
5374
5375   //_ALLOC(b,sizeof(pBranch));
5376   b = Safe_calloc(1,sizeof(pBranch));
5377   b->pc = PCODE(f);
5378   b->next = NULL;
5379
5380   t->from = pic16_pBranchAppend(t->from,b);
5381   
5382 }
5383
5384 #if 1
5385 /*-----------------------------------------------------------------*/
5386 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5387 /*               a pCode                                           */
5388 /*-----------------------------------------------------------------*/
5389 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5390 {
5391   while(pb) {
5392
5393     if(pb->pc == pc)
5394       return pb;
5395
5396     pb = pb->next;
5397   }
5398
5399   return NULL;
5400 }
5401
5402 /*-----------------------------------------------------------------*/
5403 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5404 /*-----------------------------------------------------------------*/
5405 void pic16_pCodeUnlink(pCode *pc)
5406 {
5407   pBranch *pb1,*pb2;
5408   pCode *pc1;
5409
5410   if(!pc->prev || !pc->next) {
5411     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5412     exit(1);
5413   }
5414   
5415   /* move C source line down (or up) */
5416   if (isPCI(pc) && PCI(pc)->cline) {
5417     pc1 = pic16_findNextInstruction (pc->next);
5418     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5419       PCI(pc1)->cline = PCI(pc)->cline;
5420     } else {
5421       pc1 = pic16_findPrevInstruction (pc->prev);
5422       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5423         PCI(pc1)->cline = PCI(pc)->cline;
5424     }
5425   }
5426
5427   /* first remove the pCode from the chain */
5428   pc->prev->next = pc->next;
5429   pc->next->prev = pc->prev;
5430
5431   pc->prev = pc->next = NULL;
5432
5433   /* Now for the hard part... */
5434
5435   /* Remove the branches */
5436
5437   pb1 = PCI(pc)->from;
5438   while(pb1) {
5439     pc1 = pb1->pc;    /* Get the pCode that branches to the
5440                        * one we're unlinking */
5441
5442     /* search for the link back to this pCode (the one we're
5443      * unlinking) */
5444     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5445       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5446
5447       /* if the pCode we're unlinking contains multiple 'to'
5448        * branches (e.g. this a skip instruction) then we need
5449        * to copy these extra branches to the chain. */
5450       if(PCI(pc)->to->next)
5451         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5452     }
5453     
5454     pb1 = pb1->next;
5455   }
5456
5457
5458 }
5459 #endif
5460 /*-----------------------------------------------------------------*/
5461 /*-----------------------------------------------------------------*/
5462 #if 0
5463 static void genericAnalyze(pCode *pc)
5464 {
5465   switch(pc->type) {
5466   case PC_WILD:
5467   case PC_COMMENT:
5468     return;
5469   case PC_LABEL:
5470   case PC_FUNCTION:
5471   case PC_OPCODE:
5472     {
5473       // Go through the pCodes that are in pCode chain and link
5474       // them together through the pBranches. Note, the pCodes
5475       // are linked together as a contiguous stream like the 
5476       // assembly source code lines. The linking here mimics this
5477       // except that comments are not linked in.
5478       // 
5479       pCode *npc = pc->next;
5480       while(npc) {
5481         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5482           pBranchLink(pc,npc);
5483           return;
5484         } else
5485           npc = npc->next;
5486       }
5487       /* reached the end of the pcode chain without finding
5488        * an instruction we could link to. */
5489     }
5490     break;
5491   case PC_FLOW:
5492     fprintf(stderr,"analyze PC_FLOW\n");
5493
5494     return;
5495   case PC_BAD:
5496     fprintf(stderr,,";A bad pCode is being used\n");
5497
5498   }
5499 }
5500 #endif
5501
5502 /*-----------------------------------------------------------------*/
5503 /*-----------------------------------------------------------------*/
5504 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5505 {
5506   pBranch *pbr;
5507
5508   if(pc->type == PC_LABEL) {
5509     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5510       return TRUE;
5511   }
5512   if((pc->type == PC_OPCODE)
5513         || (pc->type == PC_ASMDIR)
5514         ) {
5515     pbr = PCI(pc)->label;
5516     while(pbr) {
5517       if(pbr->pc->type == PC_LABEL) {
5518         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5519           return TRUE;
5520       }
5521       pbr = pbr->next;
5522     }
5523   }
5524
5525   return FALSE;
5526 }
5527
5528 /*-----------------------------------------------------------------*/
5529 /*-----------------------------------------------------------------*/
5530 static int checkLabel(pCode *pc)
5531 {
5532   pBranch *pbr;
5533
5534   if(pc && isPCI(pc)) {
5535     pbr = PCI(pc)->label;
5536     while(pbr) {
5537       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5538         return TRUE;
5539
5540       pbr = pbr->next;
5541     }
5542   }
5543
5544   return FALSE;
5545 }
5546
5547 /*-----------------------------------------------------------------*/
5548 /* findLabelinpBlock - Search the pCode for a particular label     */
5549 /*-----------------------------------------------------------------*/
5550 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5551 {
5552   pCode  *pc;
5553
5554   if(!pb)
5555     return NULL;
5556
5557   for(pc = pb->pcHead; pc; pc = pc->next) 
5558     if(compareLabel(pc,pcop_label))
5559       return pc;
5560     
5561   return NULL;
5562 }
5563 #if 0
5564 /*-----------------------------------------------------------------*/
5565 /* findLabel - Search the pCode for a particular label             */
5566 /*-----------------------------------------------------------------*/
5567 static pCode * findLabel(pCodeOpLabel *pcop_label)
5568 {
5569   pBlock *pb;
5570   pCode  *pc;
5571
5572   if(!the_pFile)
5573     return NULL;
5574
5575   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5576     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5577       return pc;
5578   }
5579
5580   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5581   return NULL;
5582 }
5583 #endif
5584 /*-----------------------------------------------------------------*/
5585 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5586 /*                 in the linked list                              */
5587 /*-----------------------------------------------------------------*/
5588 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5589 {
5590
5591   while(pc) {
5592     if(pc->type == pct)
5593       return pc;
5594
5595     pc = pc->next;
5596   }
5597
5598   return NULL;
5599 }
5600
5601 /*-----------------------------------------------------------------*/
5602 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5603 /*                 in the linked list                              */
5604 /*-----------------------------------------------------------------*/
5605 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5606 {
5607
5608   while(pc) {
5609     if(pc->type == pct)
5610       return pc;
5611
5612     pc = pc->prev;
5613   }
5614
5615   return NULL;
5616 }
5617
5618
5619 //#define PCODE_DEBUG
5620 /*-----------------------------------------------------------------*/
5621 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5622 /*                       in the linked list                        */
5623 /*-----------------------------------------------------------------*/
5624 pCode * pic16_findNextInstruction(pCode *pci)
5625 {
5626   pCode *pc = pci;
5627
5628   while(pc) {
5629     if((pc->type == PC_OPCODE)
5630         || (pc->type == PC_WILD)
5631         || (pc->type == PC_ASMDIR)
5632         )
5633       return pc;
5634
5635 #ifdef PCODE_DEBUG
5636     fprintf(stderr,"pic16_findNextInstruction:  ");
5637     printpCode(stderr, pc);
5638 #endif
5639     pc = pc->next;
5640   }
5641
5642   //fprintf(stderr,"Couldn't find instruction\n");
5643   return NULL;
5644 }
5645
5646 /*-----------------------------------------------------------------*/
5647 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5648 /*                       in the linked list                        */
5649 /*-----------------------------------------------------------------*/
5650 pCode * pic16_findPrevInstruction(pCode *pci)
5651 {
5652   pCode *pc = pci;
5653
5654   while(pc) {
5655
5656     if((pc->type == PC_OPCODE)
5657         || (pc->type == PC_WILD)
5658         || (pc->type == PC_ASMDIR)
5659         )
5660       return pc;
5661       
5662
5663 #ifdef PCODE_DEBUG
5664     fprintf(stderr,"pic16_findPrevInstruction:  ");
5665     printpCode(stderr, pc);
5666 #endif
5667     pc = pc->prev;
5668   }
5669
5670   //fprintf(stderr,"Couldn't find instruction\n");
5671   return NULL;
5672 }
5673
5674 #undef PCODE_DEBUG
5675
5676 #if 0
5677 /*-----------------------------------------------------------------*/
5678 /* findFunctionEnd - given a pCode find the end of the function    */
5679 /*                   that contains it                              */
5680 /*-----------------------------------------------------------------*/
5681 static pCode * findFunctionEnd(pCode *pc)
5682 {
5683
5684   while(pc) {
5685     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5686       return pc;
5687
5688     pc = pc->next;
5689   }
5690
5691   fprintf(stderr,"Couldn't find function end\n");
5692   return NULL;
5693 }
5694 #endif
5695 #if 0
5696 /*-----------------------------------------------------------------*/
5697 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5698 /*                instruction with which it is associated.         */
5699 /*-----------------------------------------------------------------*/
5700 static void AnalyzeLabel(pCode *pc)
5701 {
5702
5703   pic16_pCodeUnlink(pc);
5704
5705 }
5706 #endif
5707
5708 #if 0
5709 static void AnalyzeGOTO(pCode *pc)
5710 {
5711
5712   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5713
5714 }
5715
5716 static void AnalyzeSKIP(pCode *pc)
5717 {
5718
5719   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5720   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5721
5722 }
5723
5724 static void AnalyzeRETURN(pCode *pc)
5725 {
5726
5727   //  branch_link(pc,findFunctionEnd(pc->next));
5728
5729 }
5730
5731 #endif
5732
5733 /*-------------------------------------------------------------------*/
5734 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5735 /*                            if one is present. This is the common  */
5736 /*                            part of pic16_getRegFromInstruction(2) */
5737 /*-------------------------------------------------------------------*/
5738
5739 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5740   if (!pcop) return NULL;
5741   
5742   switch(pcop->type) {
5743   case PO_PRODL:
5744   case PO_PRODH:
5745   case PO_INDF0:
5746   case PO_FSR0:
5747   case PO_W:
5748   case PO_WREG:
5749   case PO_STATUS:
5750   case PO_INTCON:
5751   case PO_PCL:
5752   case PO_PCLATH:
5753   case PO_PCLATU:
5754   case PO_BSR:
5755     return PCOR(pcop)->r;
5756
5757   case PO_SFR_REGISTER:
5758     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5759     return PCOR(pcop)->r;
5760
5761   case PO_BIT:
5762   case PO_GPR_TEMP:
5763 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5764     return PCOR(pcop)->r;
5765
5766   case PO_IMMEDIATE:
5767 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5768
5769     if(PCOI(pcop)->r)
5770       return (PCOI(pcop)->r);
5771     else
5772       return NULL;
5773     
5774   case PO_GPR_BIT:
5775     return PCOR(pcop)->r;
5776
5777   case PO_GPR_REGISTER:
5778   case PO_DIR:
5779 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5780     return PCOR(pcop)->r;
5781
5782   case PO_LITERAL:
5783     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5784     break;
5785
5786   case PO_REL_ADDR:
5787   case PO_LABEL:
5788     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5789     break;
5790     
5791   case PO_CRY:
5792   case PO_STR:
5793     /* this should never turn up */
5794     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5795     break;
5796     
5797   case PO_WILD:
5798     break;
5799     
5800   default:
5801         fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5802 //      assert( 0 );
5803         break;
5804   }
5805
5806   return NULL;
5807 }
5808
5809 /*-----------------------------------------------------------------*/
5810 /*-----------------------------------------------------------------*/
5811 regs * pic16_getRegFromInstruction(pCode *pc)
5812 {
5813
5814   if(!pc                   || 
5815      !isPCI(pc)            ||
5816      !PCI(pc)->pcop        ||
5817      PCI(pc)->num_ops == 0 ||
5818      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5819     return NULL;
5820
5821 #if 0
5822   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5823         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5824 #endif
5825
5826   return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5827 }
5828
5829 /*-------------------------------------------------------------------------------*/
5830 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5831 /*-------------------------------------------------------------------------------*/
5832 regs * pic16_getRegFromInstruction2(pCode *pc)
5833 {
5834
5835   if(!pc                   || 
5836      !isPCI(pc)            ||
5837      !PCI(pc)->pcop        ||
5838      PCI(pc)->num_ops == 0 ||
5839      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5840     return NULL;
5841
5842
5843 #if 0
5844   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5845         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5846 #endif
5847
5848   return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5849 }
5850
5851 /*-----------------------------------------------------------------*/
5852 /*-----------------------------------------------------------------*/
5853
5854 static void AnalyzepBlock(pBlock *pb)
5855 {
5856   pCode *pc;
5857
5858   if(!pb)
5859     return;
5860
5861   /* Find all of the registers used in this pBlock 
5862    * by looking at each instruction and examining it's
5863    * operands
5864    */
5865   for(pc = pb->pcHead; pc; pc = pc->next) {
5866
5867     /* Is this an instruction with operands? */
5868     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5869
5870       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5871
5872         /* Loop through all of the registers declared so far in
5873            this block and see if we find this one there */
5874
5875         regs *r = setFirstItem(pb->tregisters);
5876
5877         while(r) {
5878           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5879             PCOR(PCI(pc)->pcop)->r = r;
5880             break;
5881           }
5882           r = setNextItem(pb->tregisters);
5883         }
5884
5885         if(!r) {
5886           /* register wasn't found */
5887           //r = Safe_calloc(1, sizeof(regs));
5888           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5889           //addSet(&pb->tregisters, r);
5890           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5891           //PCOR(PCI(pc)->pcop)->r = r;
5892           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5893         }/* else 
5894           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5895          */
5896       }
5897       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5898         if(PCOR(PCI(pc)->pcop)->r) {
5899           pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
5900           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5901         } else {
5902           if(PCI(pc)->pcop->name)
5903             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5904           else
5905             fprintf(stderr,"ERROR: NULL register\n");
5906         }
5907       }
5908     }
5909
5910
5911   }
5912 }
5913
5914 /*-----------------------------------------------------------------*/
5915 /* */
5916 /*-----------------------------------------------------------------*/
5917 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5918
5919 static void InsertpFlow(pCode *pc, pCode **pflow)
5920 {
5921   if(*pflow)
5922     PCFL(*pflow)->end = pc;
5923
5924   if(!pc || !pc->next)
5925     return;
5926
5927   *pflow = pic16_newpCodeFlow();
5928   pic16_pCodeInsertAfter(pc, *pflow);
5929 }
5930
5931 /*-----------------------------------------------------------------*/
5932 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5933 /*                         the flow blocks.                        */
5934 /*
5935  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5936  * point the instruction flow changes. 
5937  */
5938 /*-----------------------------------------------------------------*/
5939 void pic16_BuildFlow(pBlock *pb)
5940 {
5941   pCode *pc;
5942   pCode *last_pci=NULL;
5943   pCode *pflow=NULL;
5944   int seq = 0;
5945
5946   if(!pb)
5947     return;
5948
5949   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5950   /* Insert a pCodeFlow object at the beginning of a pBlock */
5951
5952   InsertpFlow(pb->pcHead, &pflow);
5953
5954   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5955   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5956   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5957   //pb->pcHead = pflow;        /* Make the Flow object the head */
5958   //pflow->pb = pb;
5959
5960   for( pc = pic16_findNextInstruction(pb->pcHead);
5961        pc != NULL;
5962        pc=pic16_findNextInstruction(pc)) { 
5963
5964     pc->seq = seq++;
5965     PCI(pc)->pcflow = PCFL(pflow);
5966
5967     //fprintf(stderr," build: ");
5968     //pflow->print(stderr,pflow);
5969
5970     if (checkLabel(pc)) { 
5971
5972       /* This instruction marks the beginning of a
5973        * new flow segment */
5974
5975       pc->seq = 0;
5976       seq = 1;
5977
5978       /* If the previous pCode is not a flow object, then 
5979        * insert a new flow object. (This check prevents 
5980        * two consecutive flow objects from being insert in
5981        * the case where a skip instruction preceeds an
5982        * instruction containing a label.) */
5983
5984       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5985         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5986
5987       PCI(pc)->pcflow = PCFL(pflow);
5988       
5989     }
5990
5991     if( PCI(pc)->isSkip) {
5992
5993       /* The two instructions immediately following this one 
5994        * mark the beginning of a new flow segment */
5995
5996       while(pc && PCI(pc)->isSkip) {
5997
5998         PCI(pc)->pcflow = PCFL(pflow);
5999         pc->seq = seq-1;
6000         seq = 1;
6001
6002         InsertpFlow(pc, &pflow);
6003         pc=pic16_findNextInstruction(pc->next);
6004       }
6005
6006       seq = 0;
6007
6008       if(!pc)
6009         break;
6010
6011       PCI(pc)->pcflow = PCFL(pflow);
6012       pc->seq = 0;
6013       InsertpFlow(pc, &pflow);
6014
6015     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6016
6017       InsertpFlow(pc, &pflow);
6018       seq = 0;
6019
6020     }
6021     last_pci = pc;
6022     pc = pc->next;
6023   }
6024
6025   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6026   if(pflow)
6027     PCFL(pflow)->end = pb->pcTail;
6028 }
6029
6030 /*-------------------------------------------------------------------*/
6031 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6032 /*                           the flow blocks.                        */
6033 /*
6034  * unBuildFlow removes pCodeFlow objects from a pCode chain
6035  */
6036 /*-----------------------------------------------------------------*/
6037 static void unBuildFlow(pBlock *pb)
6038 {
6039   pCode *pc,*pcnext;
6040
6041   if(!pb)
6042     return;
6043
6044   pc = pb->pcHead;
6045
6046   while(pc) {
6047     pcnext = pc->next;
6048
6049     if(isPCI(pc)) {
6050
6051       pc->seq = 0;
6052       if(PCI(pc)->pcflow) {
6053         //Safe_free(PCI(pc)->pcflow);
6054         PCI(pc)->pcflow = NULL;
6055       }
6056
6057     } else if(isPCFL(pc) )
6058       pc->destruct(pc);
6059
6060     pc = pcnext;
6061   }
6062
6063
6064 }
6065 #if 0
6066 /*-----------------------------------------------------------------*/
6067 /*-----------------------------------------------------------------*/
6068 static void dumpCond(int cond)
6069 {
6070
6071   static char *pcc_str[] = {
6072     //"PCC_NONE",
6073     "PCC_REGISTER",
6074     "PCC_C",
6075     "PCC_Z",
6076     "PCC_DC",
6077     "PCC_OV",
6078     "PCC_N",
6079     "PCC_W",
6080     "PCC_EXAMINE_PCOP",
6081     "PCC_LITERAL",
6082     "PCC_REL_ADDR"
6083   };
6084
6085   int ncond = sizeof(pcc_str) / sizeof(char *);
6086   int i,j;
6087
6088   fprintf(stderr, "0x%04X\n",cond);
6089
6090   for(i=0,j=1; i<ncond; i++, j<<=1)
6091     if(cond & j)
6092       fprintf(stderr, "  %s\n",pcc_str[i]);
6093
6094 }
6095 #endif
6096
6097 #if 0
6098 /*-----------------------------------------------------------------*/
6099 /*-----------------------------------------------------------------*/
6100 static void FlowStats(pCodeFlow *pcflow)
6101 {
6102
6103   pCode *pc;
6104
6105   if(!isPCFL(pcflow))
6106     return;
6107
6108   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6109
6110   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6111
6112   if(!pc) {
6113     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6114     return;
6115   }
6116
6117
6118   fprintf(stderr, "  FlowStats inCond: ");
6119   dumpCond(pcflow->inCond);
6120   fprintf(stderr, "  FlowStats outCond: ");
6121   dumpCond(pcflow->outCond);
6122
6123 }
6124 #endif
6125 /*-----------------------------------------------------------------*
6126  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6127  *    if it affects the banking bits. 
6128  * 
6129  * return: -1 == Banking bits are unaffected by this pCode.
6130  *
6131  * return: > 0 == Banking bits are affected.
6132  *
6133  *  If the banking bits are affected, then the returned value describes
6134  * which bits are affected and how they're affected. The lower half
6135  * of the integer maps to the bits that are affected, the upper half
6136  * to whether they're set or cleared.
6137  *
6138  *-----------------------------------------------------------------*/
6139
6140 static int isBankInstruction(pCode *pc)
6141 {
6142   regs *reg;
6143   int bank = -1;
6144
6145   if(!isPCI(pc))
6146     return 0;
6147
6148   if( PCI(pc)->op == POC_MOVLB ||
6149       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6150     bank = PCOL(pc)->lit;
6151   }
6152
6153   return 1;
6154 }
6155
6156
6157 /*-----------------------------------------------------------------*/
6158 /*-----------------------------------------------------------------*/
6159 static void FillFlow(pCodeFlow *pcflow)
6160 {
6161
6162   pCode *pc;
6163   int cur_bank;
6164
6165   if(!isPCFL(pcflow))
6166     return;
6167
6168   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6169
6170   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6171
6172   if(!pc) {
6173     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6174     return;
6175   }
6176
6177   cur_bank = -1;
6178
6179   do {
6180     isBankInstruction(pc);
6181     pc = pc->next;
6182   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6183
6184 /*
6185   if(!pc ) {
6186     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6187   } else {
6188     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6189     pc->print(stderr,pc);
6190   }
6191
6192   fprintf(stderr, "  FillFlow inCond: ");
6193   dumpCond(pcflow->inCond);
6194   fprintf(stderr, "  FillFlow outCond: ");
6195   dumpCond(pcflow->outCond);
6196 */
6197 }
6198
6199 /*-----------------------------------------------------------------*/
6200 /*-----------------------------------------------------------------*/
6201 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6202 {
6203   pCodeFlowLink *fromLink, *toLink;
6204
6205   if(!from || !to || !to->pcflow || !from->pcflow)
6206     return;
6207
6208   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6209   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6210
6211   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6212   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6213
6214 }
6215
6216 pCode *pic16_getJumptabpCode (pCode *pc) {
6217   pCode *pcinf;
6218
6219   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6220   //pc->print (stderr, pc);
6221   pcinf = pc;
6222   while (pcinf) {
6223     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6224     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6225       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6226       case OPT_JUMPTABLE_BEGIN:
6227         /* leading begin of jump table -- in one */
6228         pcinf = pic16_findPrevInstruction (pcinf);
6229         return pcinf;
6230         break;
6231         
6232       case OPT_JUMPTABLE_END:
6233         /* leading end of jumptable -- not in one */
6234         return NULL;
6235         break;
6236         
6237       default:
6238         /* ignore all other PCInfos */
6239         break;
6240       }
6241     }
6242     pcinf = pcinf->prev;
6243   }
6244
6245   /* no PCInfo found -- not in a jumptable */
6246   return NULL;
6247 }
6248
6249 /*-----------------------------------------------------------------*
6250  * void LinkFlow(pBlock *pb)
6251  *
6252  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6253  * non-branching segments. In LinkFlow, we determine the execution
6254  * order of these segments. For example, if one of the segments ends
6255  * with a skip, then we know that there are two possible flow segments
6256  * to which control may be passed.
6257  *-----------------------------------------------------------------*/
6258 static void LinkFlow(pBlock *pb)
6259 {
6260   pCode *pc=NULL;
6261   pCode *pcflow;
6262   pCode *pct;
6263   pCode *jumptab_pre = NULL;
6264
6265   //fprintf(stderr,"linkflow \n");
6266
6267   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6268        pcflow != NULL;
6269        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6270
6271     if(!isPCFL(pcflow))
6272       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6273
6274     //fprintf(stderr," link: ");
6275     //pcflow->print(stderr,pcflow);
6276
6277     //FillFlow(PCFL(pcflow));
6278
6279     pc = PCFL(pcflow)->end;
6280
6281     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6282     if(isPCI_SKIP(pc)) {
6283 //      fprintf(stderr, "ends with skip\n");
6284 //      pc->print(stderr,pc);
6285
6286       pct=pic16_findNextInstruction(pc->next);
6287       LinkFlow_pCode(PCI(pc),PCI(pct));
6288       pct=pic16_findNextInstruction(pct->next);
6289       LinkFlow_pCode(PCI(pc),PCI(pct));
6290       continue;
6291     }
6292
6293     if(isPCI_BRANCH(pc)) {
6294       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6295
6296       /* handle GOTOs in jumptables */
6297       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6298         /* link to previous flow */
6299         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6300         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6301       }
6302
6303       switch (PCI(pc)->op) {
6304       case POC_GOTO:
6305       case POC_BRA:
6306       case POC_RETURN:
6307       case POC_RETLW:
6308       case POC_RETFIE:
6309               /* unconditional branches -- do not link to next instruction */
6310               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6311               break;
6312               
6313       case POC_CALL:
6314       case POC_RCALL:
6315               /* unconditional calls -- link to next instruction */
6316               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6317               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6318               break;
6319               
6320       case POC_BC:
6321       case POC_BN:
6322       case POC_BNC:
6323       case POC_BNN:
6324       case POC_BNOV:
6325       case POC_BNZ:
6326       case POC_BOV:
6327       case POC_BZ:
6328               /* conditional branches -- also link to next instruction */
6329               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6330               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6331               break;
6332               
6333       default:
6334               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6335               assert (0 && "unhandled branching instruction");
6336               break;
6337       }
6338
6339       //fprintf(stderr, "ends with branch\n  ");
6340       //pc->print(stderr,pc);
6341
6342       if(!(pcol && isPCOLAB(pcol))) {
6343         if((PCI(pc)->op != POC_RETLW)
6344                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6345         
6346                 /* continue if label is '$' which assembler knows how to parse */
6347                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6348
6349                 if(pic16_pcode_verbose) {
6350                         pc->print(stderr,pc);
6351                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6352                 }
6353         }
6354         continue;
6355       }
6356
6357       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6358         LinkFlow_pCode(PCI(pc),PCI(pct));
6359       else
6360         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6361                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6362
6363 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6364
6365       continue;
6366     }
6367
6368     if(isPCI(pc)) {
6369       //fprintf(stderr, "ends with non-branching instruction:\n");
6370       //pc->print(stderr,pc);
6371
6372       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6373
6374       continue;
6375     }
6376
6377     if(pc) {
6378       //fprintf(stderr, "ends with unknown\n");
6379       //pc->print(stderr,pc);
6380       continue;
6381     }
6382
6383     //fprintf(stderr, "ends with nothing: ERROR\n");
6384     
6385   }
6386 }
6387 /*-----------------------------------------------------------------*/
6388 /*-----------------------------------------------------------------*/
6389
6390 /*-----------------------------------------------------------------*/
6391 /*-----------------------------------------------------------------*/
6392 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6393 {
6394
6395   if(!pc || !pcflow)
6396     return 0;
6397
6398   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6399     return 0;
6400
6401   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6402     return 1;
6403
6404   return 0;
6405 }
6406
6407
6408
6409
6410
6411 /*-----------------------------------------------------------------*/
6412 /* insertBankSwitch - inserts a bank switch statement in the       */
6413 /*                    assembly listing                             */
6414 /*                                                                 */
6415 /* position == 0: insert before                                    */
6416 /* position == 1: insert after pc                                  */
6417 /* position == 2: like 0 but previous was a skip instruction       */
6418 /*-----------------------------------------------------------------*/
6419 pCodeOp *pic16_popGetLabel(unsigned int key);
6420 extern int pic16_labelOffset;
6421
6422 static void insertBankSwitch(unsigned char position, pCode *pc)
6423 {
6424   pCode *new_pc;
6425
6426         if(!pc)
6427                 return;
6428
6429         /* emit BANKSEL [symbol] */
6430
6431
6432         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6433         
6434 //      position = 0;           // position is always before (sanity check!)
6435
6436 #if 0
6437         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6438         pc->print(stderr, pc);
6439 #endif
6440
6441         switch(position) {
6442                 case 1: {
6443                         /* insert the bank switch after this pc instruction */
6444                         pCode *pcnext = pic16_findNextInstruction(pc);
6445
6446                                 pic16_pCodeInsertAfter(pc, new_pc);
6447                                 if(pcnext)pc = pcnext;
6448                 }; break;
6449                 
6450                 case 0:
6451                         /* insert the bank switch BEFORE this pc instruction */
6452                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6453                         break;
6454
6455                 case 2: {
6456                           symbol *tlbl;
6457                           pCode *pcnext, *pcprev, *npci, *ppc;
6458                           PIC_OPCODE ipci;
6459                           int ofs1=0, ofs2=0, len=0;
6460                           
6461                         /* just like 0, but previous was a skip instruction,
6462                          * so some care should be taken */
6463                           
6464                                 pic16_labelOffset += 10000;
6465                                 tlbl = newiTempLabel(NULL);
6466                                 
6467                                 /* invert skip instruction */
6468                                 pcprev = pic16_findPrevInstruction(pc->prev);
6469                                 ipci = PCI(pcprev)->inverted_op;
6470                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6471
6472 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6473
6474                                 /* copy info from old pCode */
6475                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6476                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6477                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6478                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6479                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6480                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6481                                 
6482                                 /* unlink old pCode */
6483                                 ppc = pcprev->prev;
6484                                 ppc->next = pcprev->next;
6485                                 pcprev->next->prev = ppc;
6486                                 pic16_pCodeInsertAfter(ppc, npci);
6487                                 
6488                                 /* extra instructions to handle invertion */
6489                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6490                                 pic16_pCodeInsertAfter(npci, pcnext);
6491                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6492                                 
6493                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6494                                 pic16_pCodeInsertAfter(pc, pcnext);
6495                         }; break;
6496         }
6497         
6498
6499         /* Move the label, if there is one */
6500         if(PCI(pc)->label) {
6501 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6502 //                      __FILE__, __LINE__, pc, new_pc);
6503                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6504                 PCI(pc)->label = NULL;
6505         }
6506 }
6507
6508
6509 /*-----------------------------------------------------------------*/
6510 /*int compareBankFlow - compare the banking requirements between   */
6511 /*  flow objects. */
6512 /*-----------------------------------------------------------------*/
6513 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6514 {
6515
6516   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6517     return 0;
6518
6519   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6520     return 0;
6521
6522   if(pcflow->firstBank == -1)
6523     return 0;
6524
6525
6526   if(pcflowLink->pcflow->firstBank == -1) {
6527     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6528                                         pcflowLink->pcflow->to : 
6529                                         pcflowLink->pcflow->from);
6530     return compareBankFlow(pcflow, pctl, toORfrom);
6531   }
6532
6533   if(toORfrom) {
6534     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6535       return 0;
6536
6537     pcflowLink->bank_conflict++;
6538     pcflowLink->pcflow->FromConflicts++;
6539     pcflow->ToConflicts++;
6540   } else {
6541     
6542     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6543       return 0;
6544
6545     pcflowLink->bank_conflict++;
6546     pcflowLink->pcflow->ToConflicts++;
6547     pcflow->FromConflicts++;
6548
6549   }
6550   /*
6551   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6552           pcflowLink->pcflow->pc.seq,
6553           pcflowLink->pcflow->FromConflicts,
6554           pcflowLink->pcflow->ToConflicts);
6555   */
6556   return 1;
6557
6558 }
6559
6560 #if 0
6561 /*-----------------------------------------------------------------*/
6562 /*-----------------------------------------------------------------*/
6563 static void DumpFlow(pBlock *pb)
6564 {
6565   pCode *pc=NULL;
6566   pCode *pcflow;
6567   pCodeFlowLink *pcfl;
6568
6569
6570   fprintf(stderr,"Dump flow \n");
6571   pb->pcHead->print(stderr, pb->pcHead);
6572
6573   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6574   pcflow->print(stderr,pcflow);
6575
6576   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6577        pcflow != NULL;
6578        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6579
6580     if(!isPCFL(pcflow)) {
6581       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6582       continue;
6583     }
6584     fprintf(stderr,"dumping: ");
6585     pcflow->print(stderr,pcflow);
6586     FlowStats(PCFL(pcflow));
6587
6588     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6589
6590       pc = PCODE(pcfl->pcflow);
6591
6592       fprintf(stderr, "    from seq %d:\n",pc->seq);
6593       if(!isPCFL(pc)) {
6594         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6595         pc->print(stderr,pc);
6596       }
6597
6598     }
6599
6600     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6601
6602       pc = PCODE(pcfl->pcflow);
6603
6604       fprintf(stderr, "    to seq %d:\n",pc->seq);
6605       if(!isPCFL(pc)) {
6606         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6607         pc->print(stderr,pc);
6608       }
6609
6610     }
6611
6612   }
6613
6614 }
6615 #endif
6616 /*-----------------------------------------------------------------*/
6617 /*-----------------------------------------------------------------*/
6618 static int OptimizepBlock(pBlock *pb)
6619 {
6620   pCode *pc, *pcprev;
6621   int matches =0;
6622
6623   if(!pb || !peepOptimizing)
6624     return 0;
6625
6626   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6627 /*
6628   for(pc = pb->pcHead; pc; pc = pc->next)
6629     matches += pic16_pCodePeepMatchRule(pc);
6630 */
6631
6632   pc = pic16_findNextInstruction(pb->pcHead);
6633   if(!pc)
6634     return 0;
6635
6636   pcprev = pc->prev;
6637   do {
6638
6639
6640     if(pic16_pCodePeepMatchRule(pc)) {
6641
6642       matches++;
6643
6644       if(pcprev)
6645         pc = pic16_findNextInstruction(pcprev->next);
6646       else 
6647         pc = pic16_findNextInstruction(pb->pcHead);
6648     } else
6649       pc = pic16_findNextInstruction(pc->next);
6650   } while(pc);
6651
6652   if(matches)
6653     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6654   return matches;
6655
6656 }
6657
6658 /*-----------------------------------------------------------------*/
6659 /*-----------------------------------------------------------------*/
6660 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6661 {
6662   pCode *pc;
6663
6664   for(pc = pcs; pc; pc = pc->next) {
6665
6666     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6667        (PCI(pc)->pcop) && 
6668        (PCI(pc)->pcop->type == PO_LABEL) &&
6669        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6670       return pc;
6671   }
6672  
6673
6674   return NULL;
6675 }
6676
6677 /*-----------------------------------------------------------------*/
6678 /*-----------------------------------------------------------------*/
6679 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6680 {
6681
6682   char *s=NULL;
6683
6684   if(isPCI(pc) && 
6685      (PCI(pc)->pcop) && 
6686      (PCI(pc)->pcop->type == PO_LABEL)) {
6687
6688     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6689
6690 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6691 //    if(pcol->pcop.name)
6692 //      Safe_free(pcol->pcop.name);
6693
6694     /* If the key is negative, then we (probably) have a label to
6695      * a function and the name is already defined */
6696        
6697     if(pcl->key>0)
6698       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6699     else 
6700       s = pcl->label;
6701
6702     //sprintf(buffer,"_%05d_DS_",pcl->key);
6703     if(!s) {
6704       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6705     }
6706     pcol->pcop.name = Safe_strdup(s);
6707     pcol->key = pcl->key;
6708     //pc->print(stderr,pc);
6709
6710   }
6711
6712
6713 }
6714
6715 /*-----------------------------------------------------------------*/
6716 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6717 /*                            pCode chain if they're not used.     */
6718 /*-----------------------------------------------------------------*/
6719 static void pBlockRemoveUnusedLabels(pBlock *pb)
6720 {
6721   pCode *pc; pCodeLabel *pcl;
6722
6723   if(!pb)
6724     return;
6725
6726   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6727
6728     pBranch *pbr = PCI(pc)->label;
6729     if(pbr && pbr->next) {
6730       pCode *pcd = pb->pcHead;
6731
6732 //      fprintf(stderr, "multiple labels\n");
6733 //      pc->print(stderr,pc);
6734
6735       pbr = pbr->next;
6736       while(pbr) {
6737
6738         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6739           //fprintf(stderr,"Used by:\n");
6740           //pcd->print(stderr,pcd);
6741
6742           exchangeLabels(PCL(pbr->pc),pcd);
6743
6744           pcd = pcd->next;
6745         }
6746         pbr = pbr->next;
6747       }
6748     }
6749   }
6750
6751   for(pc = pb->pcHead; pc; pc = pc->next) {
6752
6753     if(isPCL(pc)) // pc->type == PC_LABEL)
6754       pcl = PCL(pc);
6755     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6756       pcl = PCL(PCI(pc)->label->pc);
6757     else continue;
6758
6759 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6760
6761     /* This pCode is a label, so search the pBlock to see if anyone
6762      * refers to it */
6763
6764     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6765         && (!pcl->force)) {
6766     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6767       /* Couldn't find an instruction that refers to this label
6768        * So, unlink the pCode label from it's pCode chain
6769        * and destroy the label */
6770 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6771
6772       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6773       if(pc->type == PC_LABEL) {
6774         pic16_unlinkpCode(pc);
6775         pCodeLabelDestruct(pc);
6776       } else {
6777         unlinkpCodeFromBranch(pc, PCODE(pcl));
6778         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6779           Safe_free(pc->label);
6780         }*/
6781       }
6782
6783     }
6784   }
6785
6786 }
6787
6788
6789 /*-----------------------------------------------------------------*/
6790 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6791 /*                     chain and put them into pBranches that are  */
6792 /*                     associated with the appropriate pCode       */
6793 /*                     instructions.                               */
6794 /*-----------------------------------------------------------------*/
6795 void pic16_pBlockMergeLabels(pBlock *pb)
6796 {
6797   pBranch *pbr;
6798   pCode *pc, *pcnext=NULL;
6799
6800   if(!pb)
6801     return;
6802
6803   /* First, Try to remove any unused labels */
6804   //pBlockRemoveUnusedLabels(pb);
6805
6806   /* Now loop through the pBlock and merge the labels with the opcodes */
6807
6808   pc = pb->pcHead;
6809   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6810
6811   while(pc) {
6812     pCode *pcn = pc->next;
6813
6814     if(pc->type == PC_LABEL) {
6815
6816 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6817 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6818
6819       if((pcnext = pic16_findNextInstruction(pc) )) {
6820
6821 //              pcnext->print(stderr, pcnext);
6822
6823         // Unlink the pCode label from it's pCode chain
6824         pic16_unlinkpCode(pc);
6825         
6826 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6827         // And link it into the instruction's pBranch labels. (Note, since
6828         // it's possible to have multiple labels associated with one instruction
6829         // we must provide a means to accomodate the additional labels. Thus
6830         // the labels are placed into the singly-linked list "label" as 
6831         // opposed to being a single member of the pCodeInstruction.)
6832
6833         //_ALLOC(pbr,sizeof(pBranch));
6834 #if 1
6835         pbr = Safe_calloc(1,sizeof(pBranch));
6836         pbr->pc = pc;
6837         pbr->next = NULL;
6838
6839         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6840 #endif
6841       } else {
6842         if(pic16_pcode_verbose)
6843         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6844       }
6845     } else if(pc->type == PC_CSOURCE) {
6846
6847       /* merge the source line symbolic info into the next instruction */
6848       if((pcnext = pic16_findNextInstruction(pc) )) {
6849
6850         // Unlink the pCode label from it's pCode chain
6851         pic16_unlinkpCode(pc);
6852         PCI(pcnext)->cline = PCCS(pc);
6853         //fprintf(stderr, "merging CSRC\n");
6854         //genericPrint(stderr,pcnext);
6855       }
6856
6857     }
6858     pc = pcn;
6859   }
6860   pBlockRemoveUnusedLabels(pb);
6861
6862 }
6863
6864 /*-----------------------------------------------------------------*/
6865 /*-----------------------------------------------------------------*/
6866 static int OptimizepCode(char dbName)
6867 {
6868 #define MAX_PASSES 4
6869
6870   int matches = 0;
6871   int passes = 0;
6872   pBlock *pb;
6873
6874   if(!the_pFile)
6875     return 0;
6876
6877   DFPRINTF((stderr," Optimizing pCode\n"));
6878
6879   do {
6880     matches = 0;
6881     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6882       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6883         matches += OptimizepBlock(pb);
6884     }
6885   }
6886   while(matches && ++passes < MAX_PASSES);
6887
6888   return matches;
6889 }
6890
6891
6892
6893 const char *pic16_pCodeOpType(pCodeOp *pcop);
6894 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6895
6896
6897 /*-----------------------------------------------------------------*/
6898 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6899 /*-----------------------------------------------------------------*/
6900
6901 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6902 {
6903   pCodeOp *pcop=NULL;
6904
6905 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6906
6907   if(pc->name) {
6908         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6909   } else {
6910     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6911   }
6912
6913   assert(pcop != NULL);
6914
6915   if( !( (pcop->type == PO_LABEL) ||
6916          (pcop->type == PO_LITERAL) ||
6917          (pcop->type == PO_STR) ))
6918     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6919     PCOR(pcop)->r->wasUsed = 1;
6920     PCOR(pcop)->instance = PCOR(pc)->instance;
6921
6922   return pcop;
6923 }
6924
6925
6926 /*----------------------------------------------------------------------*
6927  * pic16_areRegsSame - check to see if the names of two registers match *
6928  *----------------------------------------------------------------------*/
6929 int pic16_areRegsSame(regs *r1, regs *r2)
6930 {
6931         if(!strcmp(r1->name, r2->name))return 1;
6932
6933   return 0;
6934 }
6935
6936
6937 /*-----------------------------------------------------------------*/
6938 /*-----------------------------------------------------------------*/
6939 static void pic16_FixRegisterBanking(pBlock *pb)
6940 {
6941   pCode *pc=NULL;
6942   pCode *pcprev=NULL;
6943   regs *reg, *prevreg;
6944   unsigned char flag=0;
6945   
6946         if(!pb)
6947                 return;
6948
6949         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6950         if(!pc)return;
6951
6952         /* loop through all of the flow blocks with in one pblock */
6953
6954 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6955
6956         prevreg = NULL;
6957         do {
6958                 /* at this point, pc should point to a PC_FLOW object */
6959                 /* for each flow block, determine the register banking 
6960                  * requirements */
6961
6962                 
6963                 /* if label, then might come from other point, force banksel */
6964                 if(isPCL(pc))prevreg = NULL;
6965                 
6966                 if(!isPCI(pc))goto loop;
6967
6968                 if(PCI(pc)->label)prevreg = NULL;
6969
6970                 if(PCI(pc)->is2MemOp)goto loop;
6971
6972                 /* if goto, then force banksel */
6973 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6974        
6975                 reg = pic16_getRegFromInstruction(pc);
6976
6977 #if 0
6978                 pc->print(stderr, pc);
6979                 fprintf(stderr, "reg = %p\n", reg);
6980
6981                 if(reg) {
6982                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6983                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6984                                 reg->address,reg->isBitField, reg->isFixed);
6985                 }
6986 #endif
6987
6988                 /* now make some tests to make sure that instruction needs bank switch */
6989
6990                 /* if no register exists, and if not a bit opcode goto loop */
6991                 if(!reg) {
6992                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6993                 }
6994                  
6995                 if(isPCI_SKIP(pc)) {
6996 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6997 //                prevreg = NULL;
6998                 }
6999                 if(reg && isACCESS_BANK(reg))goto loop;
7000
7001                 if(!isBankInstruction(pc))goto loop;
7002
7003                 if(isPCI_LIT(pc))goto loop;
7004          
7005                 if(PCI(pc)->op == POC_CALL)goto loop;
7006
7007                 /* Examine the instruction before this one to make sure it is
7008                  * not a skip type instruction */
7009                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7010
7011                 flag = 0;               /* add before this instruction */
7012                 
7013                 /* if previous instruction is a skip one, then set flag
7014                  * to 2 and call insertBankSwitch */
7015                 if(pcprev && isPCI_SKIP(pcprev)) {
7016                   flag=2;       //goto loop
7017 //                prevreg = NULL;
7018                 }
7019                  
7020                 if(pic16_options.opt_banksel>0) {
7021                   char op1[128], op2[128];
7022                   
7023                     if(prevreg) {
7024                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7025                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7026                       if(!strcmp(op1, op2))goto loop;
7027                     }
7028                 }
7029                 prevreg = reg;
7030                 insertBankSwitch(flag, pc);
7031
7032 //              fprintf(stderr, "BANK SWITCH inserted\n");
7033                 
7034 loop:
7035                 pcprev = pc;
7036                 pc = pc->next;
7037         } while (pc);
7038 }
7039
7040 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7041
7042 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7043 int instrSize (pCode *pc)
7044 {
7045   if (!pc) return 0;
7046
7047   if (isPCAD(pc)) {
7048     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7049     return 4; // assumes only regular instructions using <= 4 bytes
7050   }
7051
7052   if (isPCI(pc)) return PCI(pc)->isize;
7053
7054   return 0;
7055 }
7056
7057 /* Returns 1 if pc is referenced by the given label (either
7058  * pc is the label itself or is an instruction with an attached
7059  * label).
7060  * Returns 0 if pc is not preceeded by the specified label.
7061  */
7062 int isLabel (pCode *pc, char *label)
7063 {
7064   if (!pc) return 0;
7065
7066   // label attached to the pCode?  
7067   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7068     pBranch *lab = NULL;
7069     lab = PCI(pc)->label;
7070
7071     while (lab) {
7072       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7073         return 1;
7074       }
7075       lab = lab->next;
7076     } // while
7077   } // if
7078
7079   // is inline assembly label?
7080   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7081     // do not compare trailing ':'
7082     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7083       return 1;
7084     }
7085   } // if
7086   
7087   // is pCodeLabel?
7088   if (isPCL(pc)) {
7089       if (strcmp(PCL(pc)->label,label) == 0) {
7090       return 1;
7091     }
7092   } // if
7093   
7094   // no label/no label attached/wrong label(s)
7095   return 0;
7096 }
7097
7098 /* Returns the distance to the given label in terms of words.
7099  * Labels are searched only within -max .. max words from pc.
7100  * Returns max if the label could not be found or
7101  * its distance from pc in (-max..+max).
7102  */
7103 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7104   int dist = instrSize(pc);
7105   pCode *curr = pc;
7106
7107   // search backwards
7108   while (dist < max && curr && !isLabel (curr, label)) {
7109     curr = curr->prev;
7110     dist += instrSize(curr); // sizeof (instruction)
7111   } // while
7112   if (curr && dist < max) {
7113     if (target != NULL) *target = curr;
7114     return -dist;
7115   }
7116
7117   dist = 0;
7118   curr = pic16_findNextInstruction (pc->next);
7119   //search forwards
7120   while (dist < max && curr && !isLabel (curr, label)) {
7121     dist += instrSize(curr); // sizeof (instruction)
7122     curr = curr->next;
7123   } // while
7124   if (curr && dist < max) {
7125     if (target != NULL) *target = curr;
7126     return dist;
7127   }
7128
7129   if (target != NULL) *target = NULL;
7130   return max;
7131 }
7132
7133 /* Returns -1 if pc does NOT denote an instruction like
7134  * BTFS[SC] STATUS,i
7135  * Otherwise we return 
7136  *   (a) 0x10 + i for BTFSS
7137  *   (b) 0x00 + i for BTFSC
7138  */
7139 int isSkipOnStatus (pCode *pc)
7140 {
7141   int res = -1;
7142   pCodeOp *pcop;
7143   if (!pc || !isPCI(pc)) return -1;
7144   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7145   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7146   else return -1;
7147
7148   pcop = PCI(pc)->pcop;
7149
7150   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7151     return res + ((pCodeOpRegBit *)pcop)->bit;
7152   }
7153
7154   return -1;
7155 }
7156
7157 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7158  * returns 0 otherwise. */
7159 int isConditionalBranch (pCode *pc)
7160 {
7161   if (!pc || !isPCI_BRANCH(pc)) return 0;
7162
7163   switch (PCI(pc)->op) {
7164   case POC_BC:
7165   case POC_BZ:
7166   case POC_BOV:
7167   case POC_BN:
7168   case POC_BNC:
7169   case POC_BNZ:
7170   case POC_BNOV:
7171   case POC_BNN:
7172     return 1;
7173
7174   default:
7175     break;
7176   } // switch
7177
7178   return 0;
7179 }
7180
7181 /* Returns 1 if pc has a label attached to it.
7182  * This can be either a label stored in the pCode itself (.label)
7183  * or a label making up its own pCode preceding this pc.
7184  * Returns 0 if pc cannot be reached directly via a label.
7185  */
7186 int hasNoLabel (pCode *pc)
7187 {
7188   pCode *prev;
7189   if (!pc) return 1;
7190
7191   // are there any label pCodes between pc and the previous instruction?
7192   prev = pic16_findPrevInstruction (pc->prev);
7193   while (pc && pc != prev) {
7194     // pCode with attached label?
7195     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7196         && PCI(pc)->label) {
7197       return 0;
7198     }
7199     // is inline assembly label?
7200     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7201     if (isPCW(pc) && PCW(pc)->label) return 0;
7202
7203     // pCodeLabel?
7204     if (isPCL(pc)) return 0;
7205
7206     pc = pc->prev;
7207   } // if
7208
7209   // no label found
7210   return 1;
7211 }
7212
7213 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7214   char buf[512];
7215   va_list va;
7216
7217   va_start (va, fmt);
7218   vsprintf (buf, fmt, va);
7219   va_end (va);
7220
7221   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7222 }
7223
7224 /* Replaces the old pCode with the new one, moving the labels,
7225  * C source line and probably flow information to the new pCode.
7226  */
7227 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7228   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7229     return;
7230
7231   /* first move all labels from old to new */
7232   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7233   PCI(oldPC)->label = NULL;
7234   
7235 #if 0
7236   /* move C source line (if possible) */
7237   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7238     PCI(newPC)->cline = PCI(oldPC)->cline;
7239 #endif
7240
7241   /* keep flow information intact */
7242   newPC->seq = oldPC->seq;
7243   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7244   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7245     PCI(newPC)->pcflow->end = newPC;
7246   }
7247
7248   /* insert a comment stating which pCode has been replaced */
7249 #if 1
7250   if (pic16_pcode_verbose || pic16_debug_verbose) {
7251     char pc_str[256];
7252     pic16_pCode2str (pc_str, 256, oldPC);
7253     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7254   }
7255 #endif
7256   
7257   /* insert new pCode into pBlock */
7258   pic16_pCodeInsertAfter (oldPC, newPC);
7259   pic16_unlinkpCode (oldPC);
7260   
7261   /* destruct replaced pCode */
7262   oldPC->destruct (oldPC);
7263 }
7264
7265 /* Returns the inverted conditional branch (if any) or NULL.
7266  * pcop must be set to the new jump target.
7267  */
7268 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7269 {
7270   pCode *newBcc;
7271
7272   if (!bcc || !isPCI(bcc)) return NULL;
7273
7274   switch (PCI(bcc)->op) {
7275   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7276   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7277   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7278   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7279   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7280   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7281   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7282   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7283   default:
7284     newBcc = NULL;
7285   }
7286   return newBcc;
7287 }
7288
7289 #define MAX_DIST_GOTO         0x7FFFFFFF
7290 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7291 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7292 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7293 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7294
7295 /* Follows GOTO/BRA instructions to their target instructions, stores the
7296  * final destination (not a GOTO or BRA instruction) in target and returns
7297  * the distance from the original pc to *target.
7298  */
7299 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7300         pCode *curr = pc;
7301         pCode *last = NULL;
7302         pCodeOp *lastPCOP = NULL;
7303         int dist = 0;
7304         int depth = 0;
7305
7306         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7307
7308         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7309         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7310                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7311                 last = curr;
7312                 lastPCOP = PCI(curr)->pcop;
7313                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7314                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7315         } // while
7316
7317         if (target) *target = last;
7318         if (pcop) *pcop = lastPCOP;
7319         return dist;
7320 }
7321
7322 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7323  * Otherwise the first pCode after the jumptable (after
7324  * the OPT_JUMPTABLE_END tag) is returned.
7325  */
7326 pCode *skipJumptables (pCode *pc, int *isJumptable)
7327 {
7328   *isJumptable = 0;
7329   if (!pc) return NULL;
7330   
7331   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7332     *isJumptable = 1;
7333     //fprintf (stderr, "SKIPPING jumptable\n");
7334     do {
7335       //pc->print(stderr, pc);
7336       pc = pc->next;
7337     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7338                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7339     //fprintf (stderr, "<<JUMPTAB:\n");
7340     // skip OPT_END as well
7341     if (pc) pc = pc->next;
7342   } // while
7343
7344   return pc;
7345 }
7346
7347 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7348 {
7349   int isJumptab;
7350   *isJumptable = 0;
7351   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7352     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7353     pc = skipJumptables (pc, &isJumptab);
7354     if (isJumptab) {
7355         // pc is the first pCode after the jumptable
7356         *isJumptable = 1;
7357     } else {
7358         // pc has not been changed by skipJumptables()
7359         pc = pc->next;
7360     }
7361   } // while
7362   
7363   return pc;
7364 }
7365
7366 /* Turn GOTOs into BRAs if distance between GOTO and label
7367  * is less than 1024 bytes.
7368  *
7369  * This method is especially useful if GOTOs after BTFS[SC]
7370  * can be turned into BRAs as GOTO would cost another NOP
7371  * if skipped.
7372  */
7373 void pic16_OptimizeJumps ()
7374 {
7375   pCode *pc;
7376   pCode *pc_prev = NULL;
7377   pCode *pc_next = NULL;
7378   pBlock *pb;
7379   pCode *target;
7380   int change, iteration, isJumptab;
7381   int isHandled = 0;
7382   char *label;
7383   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7384   
7385   if (!the_pFile) return;
7386   
7387   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7388   
7389   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7390     int matchedInvertRule = 1;
7391     iteration = 1;
7392     do {
7393       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7394       change = 0;
7395       pc = pic16_findNextInstruction (pb->pcHead);
7396     
7397       while (pc) {
7398         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7399         if (isJumptab) {
7400                 // skip jumptable, i.e. start over with no pc_prev!     
7401                 pc_prev = NULL;
7402                 pc = pc_next;
7403                 continue;
7404         } // if
7405
7406         /* (1) resolve chained jumps
7407          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7408          * (a) leave dead code in and
7409          * (b) skip over the dead code with an (unneccessary) jump.
7410          */
7411         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7412           pCodeOp *lastTargetOp = NULL;
7413           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7414           int maxDist = MAX_DIST_BCC;
7415           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7416           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7417           
7418           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7419           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7420               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7421             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7422             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7423             PCI(pc)->pcop->name = lastTargetOp->name;
7424             change++;
7425             opt_gotochain++;
7426           } // if
7427         } // if
7428
7429
7430         if (IS_GOTO(pc)) {
7431           int dist;
7432           int condBraType = isSkipOnStatus(pc_prev);
7433           label = PCI(pc)->pcop->name;
7434           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7435           if (dist < 0) dist = -dist;
7436           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7437           isHandled = 0;
7438           
7439           
7440           /* (2) remove "GOTO label; label:" */
7441           if (isLabel (pc_next, label)) {
7442             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7443             // first remove all preceeding SKIP instructions
7444             while (pc_prev && isPCI_SKIP(pc_prev)) {
7445               // attach labels on this instruction to pc_next
7446               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7447               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7448               PCI(pc_prev)->label = NULL;
7449               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7450               pic16_unlinkpCode (pc_prev);
7451               pc_prev = pic16_findPrevInstruction (pc);
7452             } // while
7453             // now remove the redundant goto itself
7454             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7455             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7456             pic16_unlinkpCode (pc);
7457             pc = pic16_findPrevInstruction(pc_next->prev);
7458             isHandled = 1; // do not perform further optimizations
7459             opt_gotonext++;
7460             change++;
7461           } // if
7462           
7463           
7464           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7465           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7466             if (dist < MAX_DIST_BCC) {
7467               pCode *bcc = NULL;
7468               switch (condBraType) {
7469               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7470                 // no BDC on DIGIT CARRY available
7471               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7472               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7473               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7474               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7475                 // no BNDC on DIGIT CARRY available
7476               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7477               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7478               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7479               default:
7480                 // no replacement possible
7481                 bcc = NULL;
7482                 break;
7483               } // switch
7484               if (bcc) {
7485                 // ATTENTION: keep labels attached to BTFSx!
7486                 // HINT: GOTO is label free (checked above)
7487                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7488                 isHandled = 1; // do not perform further optimizations
7489                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7490                 pic16_pCodeReplace (pc_prev, bcc);
7491                 pc->destruct(pc);
7492                 pc = bcc;
7493                 opt_cond++;
7494                 change++;
7495               } // if
7496             } else {
7497               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7498               cond_toofar++;
7499             } // if
7500           } // if
7501
7502           if (!isHandled) {
7503             // (4) eliminate the following (common) tripel:
7504             //           <pred.>;
7505             //  labels1: Bcc label2;
7506             //           GOTO somewhere;    ; <-- instruction referenced by pc
7507             //  label2:  <cont.>
7508             // and replace it by
7509             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7510             //  label2:  <cont.>
7511             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7512             //            to <cont.> instead
7513             // ATTENTION: This optimization is only valid if <pred.> is
7514             //            not a skip operation!
7515             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7516             // ATTENTION: no label may be attached to the GOTO instruction!
7517             if (isConditionalBranch(pc_prev)
7518                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7519                 && (dist < MAX_DIST_BCC)
7520                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7521                 && hasNoLabel(pc)) {
7522               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7523             
7524               if (newBcc) {
7525                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7526                 isHandled = 1; // do not perform further optimizations
7527                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7528                 pic16_pCodeReplace (pc_prev, newBcc);
7529                 pc->destruct(pc);
7530                 pc = newBcc;
7531                 opt_reorder++;
7532                 change++;
7533                 matchedInvertRule++;
7534               }
7535             }
7536           }
7537           
7538           /* (5) now just turn GOTO into BRA */ 
7539           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7540             if (dist < MAX_DIST_BRA) {
7541               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7542               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7543               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7544               pic16_pCodeReplace (pc, newBra);
7545               pc = newBra;
7546               opt++;
7547               change++;
7548             } else {
7549               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7550               toofar++;
7551             }
7552           } // if (!isHandled)
7553         } // if
7554
7555         pc_prev = pc;
7556         pc = pc_next;
7557       } // while (pc)
7558       
7559       pBlockRemoveUnusedLabels (pb);
7560       
7561       // This line enables goto chain resolution!
7562       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7563
7564       iteration++;
7565     } while (change); /* fixpoint iteration per pBlock */
7566   } // for (pb)
7567   
7568   // emit some statistics concerning goto-optimization
7569 #if 0
7570   if (pic16_debug_verbose || pic16_pcode_verbose) {
7571     fprintf (stderr, "optimize-goto:\n"
7572              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7573              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7574              "\t%5d conditional \"skipping\" jumps inverted\n"
7575              "\t%5d GOTOs to next instruction removed\n"
7576              "\t%5d chained GOTOs resolved\n",
7577              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7578   } // if
7579 #endif
7580   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7581 }
7582
7583 #undef IS_GOTO
7584 #undef MAX_JUMPCHAIN_DEPTH
7585 #undef MAX_DIST_GOTO
7586 #undef MAX_DIST_BRA
7587 #undef MAX_DIST_BCC
7588
7589 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7590
7591 static void pBlockDestruct(pBlock *pb)
7592 {
7593
7594   if(!pb)
7595     return;
7596
7597
7598 //  Safe_free(pb);
7599
7600 }
7601
7602 /*-----------------------------------------------------------------*/
7603 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7604 /*                                  name dbName and combine them   */
7605 /*                                  into one block                 */
7606 /*-----------------------------------------------------------------*/
7607 static void mergepBlocks(char dbName)
7608 {
7609
7610   pBlock *pb, *pbmerged = NULL,*pbn;
7611
7612   pb = the_pFile->pbHead;
7613
7614   //fprintf(stderr," merging blocks named %c\n",dbName);
7615   while(pb) {
7616
7617     pbn = pb->next;
7618     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7619     if( getpBlock_dbName(pb) == dbName) {
7620
7621       //fprintf(stderr," merged block %c\n",dbName);
7622
7623       if(!pbmerged) {
7624         pbmerged = pb;
7625       } else {
7626         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7627         /* pic16_addpCode2pBlock doesn't handle the tail: */
7628         pbmerged->pcTail = pb->pcTail;
7629
7630         pb->prev->next = pbn;
7631         if(pbn) 
7632           pbn->prev = pb->prev;
7633
7634
7635         pBlockDestruct(pb);
7636       }
7637       //pic16_printpBlock(stderr, pbmerged);
7638     } 
7639     pb = pbn;
7640   }
7641
7642 }
7643
7644 /*-----------------------------------------------------------------*/
7645 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7646 /*                                                                 */
7647 /* level 0 == minimal optimization                                 */
7648 /*   optimize registers that are used only by two instructions     */
7649 /* level 1 == maximal optimization                                 */
7650 /*   optimize by looking at pairs of instructions that use the     */
7651 /*   register.                                                     */
7652 /*-----------------------------------------------------------------*/
7653
7654 static void AnalyzeFlow(int level)
7655 {
7656   static int times_called=0;
7657   pBlock *pb;
7658
7659     if(!the_pFile) {
7660       /* remove unused allocated registers before exiting */
7661       pic16_RemoveUnusedRegisters();
7662       return;
7663     }
7664
7665
7666     /* if this is not the first time this function has been called,
7667      * then clean up old flow information */
7668     if(times_called++) {
7669       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7670         unBuildFlow(pb);
7671         pic16_RegsUnMapLiveRanges();
7672     }
7673     GpcFlowSeq = 1;
7674
7675     /* Phase 2 - Flow Analysis - Register Banking
7676      *
7677      * In this phase, the individual flow blocks are examined
7678      * and register banking is fixed.
7679      */
7680
7681 #if 0
7682     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7683       pic16_FixRegisterBanking(pb);
7684 #endif
7685
7686     /* Phase 2 - Flow Analysis
7687      *
7688      * In this phase, the pCode is partition into pCodeFlow 
7689      * blocks. The flow blocks mark the points where a continuous
7690      * stream of instructions changes flow (e.g. because of
7691      * a call or goto or whatever).
7692      */
7693
7694     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7695       pic16_BuildFlow(pb);
7696
7697
7698     /* Phase 2 - Flow Analysis - linking flow blocks
7699      *
7700      * In this phase, the individual flow blocks are examined
7701      * to determine their order of excution.
7702      */
7703
7704     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7705       LinkFlow(pb);
7706
7707 #if 1
7708         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7709                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7710                         pic16_createDF (pb);
7711 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7712                         pic16_vcg_dump_default (pb);
7713 #endif
7714                         //pic16_destructDF (pb);
7715                 }
7716
7717                 pic16_df_stats ();
7718                 if (0) releaseStack (); // releasing is costly...
7719         }
7720 #endif
7721
7722     /* Phase 3 - Flow Analysis - Flow Tree
7723      *
7724      * In this phase, the individual flow blocks are examined
7725      * to determine their order of execution.
7726      */
7727
7728     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7729       pic16_BuildFlowTree(pb);
7730
7731
7732     /* Phase x - Flow Analysis - Used Banks
7733      *
7734      * In this phase, the individual flow blocks are examined
7735      * to determine the Register Banks they use
7736      */
7737
7738 #if 0
7739     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7740       FixBankFlow(pb);
7741 #endif
7742
7743
7744     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7745       pic16_pCodeRegMapLiveRanges(pb);
7746
7747     pic16_RemoveUnusedRegisters();
7748     pic16_removeUnusedRegistersDF ();
7749
7750   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7751     pic16_pCodeRegOptimizeRegUsage(level);
7752
7753
7754 #if 0
7755     if(!options.nopeep)
7756       OptimizepCode('*');
7757 #endif
7758
7759 #if 0
7760     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7761       DumpFlow(pb);
7762 #endif
7763
7764     /* debug stuff */ 
7765     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7766       pCode *pcflow;
7767       
7768         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7769           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7770           pcflow = pcflow->next) {
7771             FillFlow(PCFL(pcflow));
7772         }
7773     }
7774
7775 #if 0
7776     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7777       pCode *pcflow;
7778
7779         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7780           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7781           pcflow = pcflow->next) {
7782             FlowStats(PCFL(pcflow));
7783         }
7784     }
7785 #endif
7786 }
7787
7788 /* VR -- no need to analyze banking in flow, but left here :
7789  *      1. because it may be used in the future for other purposes
7790  *      2. because if omitted we'll miss some optimization done here
7791  *
7792  * Perhaps I should rename it to something else
7793  */
7794
7795 /*-----------------------------------------------------------------*/
7796 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7797 /*                  assigned to the registers.                     */
7798 /*                                                                 */
7799 /*-----------------------------------------------------------------*/
7800
7801 void pic16_AnalyzeBanking(void)
7802 {
7803   pBlock  *pb;
7804
7805     /* Phase x - Flow Analysis - Used Banks
7806      *
7807      * In this phase, the individual flow blocks are examined
7808      * to determine the Register Banks they use
7809      */
7810
7811     AnalyzeFlow(0);
7812     AnalyzeFlow(1);
7813
7814     if(!options.nopeep)
7815       OptimizepCode('*');
7816
7817
7818     if(!the_pFile)return;
7819
7820     if(!pic16_options.no_banksel) {
7821       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7822 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7823         pic16_FixRegisterBanking(pb);
7824       }
7825     }
7826 }
7827
7828 /*-----------------------------------------------------------------*/
7829 /* buildCallTree - Look at the flow and extract all of the calls.  */
7830 /*-----------------------------------------------------------------*/
7831 static set *register_usage(pBlock *pb);
7832
7833 static void buildCallTree(void    )
7834 {
7835   pBranch *pbr;
7836   pBlock  *pb;
7837   pCode   *pc;
7838   regs *r;
7839   
7840   if(!the_pFile)
7841     return;
7842
7843
7844
7845   /* Now build the call tree.
7846      First we examine all of the pCodes for functions.
7847      Keep in mind that the function boundaries coincide
7848      with pBlock boundaries. 
7849
7850      The algorithm goes something like this:
7851      We have two nested loops. The outer loop iterates
7852      through all of the pBlocks/functions. The inner
7853      loop iterates through all of the pCodes for
7854      a given pBlock. When we begin iterating through
7855      a pBlock, the variable pc_fstart, pCode of the start
7856      of a function, is cleared. We then search for pCodes
7857      of type PC_FUNCTION. When one is encountered, we
7858      initialize pc_fstart to this and at the same time
7859      associate a new pBranch object that signifies a 
7860      branch entry. If a return is found, then this signifies
7861      a function exit point. We'll link the pCodes of these
7862      returns to the matching pc_fstart.
7863
7864      When we're done, a doubly linked list of pBranches
7865      will exist. The head of this list is stored in
7866      `the_pFile', which is the meta structure for all
7867      of the pCode. Look at the pic16_printCallTree function
7868      on how the pBranches are linked together.
7869
7870    */
7871   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7872     pCode *pc_fstart=NULL;
7873     for(pc = pb->pcHead; pc; pc = pc->next) {
7874
7875         if(isPCI(pc) && pc_fstart) {
7876                 if(PCI(pc)->is2MemOp) {
7877                         r = pic16_getRegFromInstruction2(pc);
7878                         if(r && !strcmp(r->name, "POSTDEC1"))
7879                                 PCF(pc_fstart)->stackusage++;
7880                 } else {
7881                         r = pic16_getRegFromInstruction(pc);
7882                         if(r && !strcmp(r->name, "PREINC1"))
7883                                 PCF(pc_fstart)->stackusage--;
7884                 }
7885         }
7886
7887       if(isPCF(pc)) {
7888         if (PCF(pc)->fname) {
7889         char buf[16];
7890
7891           sprintf(buf, "%smain", port->fun_prefix);
7892           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7893             //fprintf(stderr," found main \n");
7894             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7895             pb->dbName = 'M';
7896           }
7897
7898           pbr = Safe_calloc(1,sizeof(pBranch));
7899           pbr->pc = pc_fstart = pc;
7900           pbr->next = NULL;
7901
7902           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7903
7904           // Here's a better way of doing the same:
7905           addSet(&pb->function_entries, pc);
7906
7907         } else {
7908           // Found an exit point in a function, e.g. return
7909           // (Note, there may be more than one return per function)
7910           if(pc_fstart)
7911             pBranchLink(PCF(pc_fstart), PCF(pc));
7912
7913           addSet(&pb->function_exits, pc);
7914         }
7915       } else if(isCALL(pc)) {
7916         addSet(&pb->function_calls,pc);
7917       }
7918     }
7919   }
7920
7921
7922 #if 0
7923   /* This is not needed because currently all register used
7924    * by a function are stored in stack -- VR */
7925    
7926   /* Re-allocate the registers so that there are no collisions
7927    * between local variables when one function call another */
7928
7929   // this is weird...
7930   //  pic16_deallocateAllRegs();
7931
7932   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7933     if(!pb->visited)
7934       register_usage(pb);
7935   }
7936 #endif
7937
7938 }
7939
7940 /*-----------------------------------------------------------------*/
7941 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7942 /*                all of the logical connections.                  */
7943 /*                                                                 */
7944 /* Essentially what's done here is that the pCode flow is          */
7945 /* determined.                                                     */
7946 /*-----------------------------------------------------------------*/
7947
7948 void pic16_AnalyzepCode(char dbName)
7949 {
7950   pBlock *pb;
7951   int i,changes;
7952
7953   if(!the_pFile)
7954     return;
7955
7956   mergepBlocks('D');
7957
7958
7959   /* Phase 1 - Register allocation and peep hole optimization
7960    *
7961    * The first part of the analysis is to determine the registers
7962    * that are used in the pCode. Once that is done, the peep rules
7963    * are applied to the code. We continue to loop until no more
7964    * peep rule optimizations are found (or until we exceed the
7965    * MAX_PASSES threshold). 
7966    *
7967    * When done, the required registers will be determined.
7968    *
7969    */
7970   i = 0;
7971   do {
7972
7973     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7974     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7975
7976     /* First, merge the labels with the instructions */
7977     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7978       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7979
7980         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7981         //fprintf(stderr," analyze and merging block %c\n",dbName);
7982         pic16_pBlockMergeLabels(pb);
7983         AnalyzepBlock(pb);
7984       } else {
7985         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7986       }
7987     }
7988
7989         if(!options.nopeep)
7990                 changes = OptimizepCode(dbName);
7991         else changes = 0;
7992
7993   } while(changes && (i++ < MAX_PASSES));
7994
7995   
7996   buildCallTree();
7997 }
7998
7999
8000 /* convert a series of movff's of local regs to stack, with a single call to
8001  * a support functions which does the same thing via loop */
8002 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8003 {
8004   pBranch *pbr;
8005   pCode *pc, *pct;
8006   char *fname[]={"__lr_store", "__lr_restore"};
8007
8008 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8009
8010     pct = pic16_findNextInstruction(pcstart->next);
8011     do {
8012       pc = pct;
8013       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8014 //      pc->print(stderr, pc);
8015       if(isPCI(pc) && PCI(pc)->label) {
8016         pbr = PCI(pc)->label;
8017         while(pbr && pbr->pc) {
8018           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8019           pbr = pbr->next;
8020         }
8021
8022 //        pc->print(stderr, pc);
8023         /* unlink pCode */
8024         pc->prev->next = pct;
8025         pct->prev = pc->prev;
8026 //        pc->next = NULL;
8027 //        pc->prev = NULL;
8028       }
8029     } while ((pc) && (pc != pcend));
8030
8031     /* unlink movff instructions */
8032     pcstart->next = pcend;
8033     pcend->prev = pcstart;
8034
8035     pc = pcstart;
8036 //    if(!entry) {
8037 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8038 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8039 //    }
8040                 
8041     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8042     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8043     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8044
8045 //    if(!entry) {
8046 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8047 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8048 //    }
8049
8050     
8051     {
8052       symbol *sym;
8053
8054         sym = newSymbol( fname[ entry?0:1 ], 0 );
8055         strcpy(sym->rname, fname[ entry?0:1 ]);
8056         checkAddSym(&externs, sym);
8057         
8058 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8059     }
8060
8061 }
8062
8063 /*-----------------------------------------------------------------*/
8064 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8065 /*    local registers to a support function call                   */
8066 /*-----------------------------------------------------------------*/
8067 void pic16_OptimizeLocalRegs(void)
8068 {
8069   pBlock  *pb;
8070   pCode   *pc;
8071   pCodeInfo *pci;
8072   pCodeOpLocalReg *pclr;
8073   int regCount=0;
8074   int inRegCount=0;
8075   regs *r, *lastr=NULL, *firstr=NULL;
8076   pCode *pcstart=NULL, *pcend=NULL;
8077   int inEntry=0;
8078   char *curFunc=NULL;
8079
8080         /* Overview:
8081          *   local_regs begin mark
8082          *      MOVFF r0x01, POSTDEC1
8083          *      MOVFF r0x02, POSTDEC1
8084          *      ...
8085          *      ...
8086          *      MOVFF r0x0n, POSTDEC1
8087          *   local_regs end mark
8088          *
8089          * convert the above to the below:
8090          *      MOVLW   starting_register_index
8091          *      MOVWF   PRODL
8092          *      MOVLW   register_count
8093          *      call    __save_registers_in_stack
8094          */
8095
8096     if(!the_pFile)
8097       return;
8098
8099     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8100       inRegCount = regCount = 0;
8101       firstr = lastr = NULL;
8102       for(pc = pb->pcHead; pc; pc = pc->next) {
8103
8104         /* hold current function name */
8105         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8106         
8107         if(pc && (pc->type == PC_INFO)) {
8108           pci = PCINF(pc);
8109
8110           if(pci->type == INF_LOCALREGS) {
8111             pclr = PCOLR(pci->oper1);
8112             
8113             if((pclr->type == LR_ENTRY_BEGIN)
8114               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8115             else inEntry = 0;
8116             
8117             switch(pclr->type) {
8118               case LR_ENTRY_BEGIN:
8119               case LR_EXIT_BEGIN:
8120                         inRegCount = 1; regCount = 0;
8121                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8122                         firstr = lastr = NULL;
8123                         break;
8124               
8125               case LR_ENTRY_END:
8126               case LR_EXIT_END:
8127                         inRegCount = -1;
8128                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8129
8130 #if 1
8131                         if(curFunc && inWparamList(curFunc+1)) {
8132                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8133                                         filename, curFunc);
8134                         } else {
8135                           if(regCount>2) {
8136                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8137                               firstr, inEntry);
8138                           }
8139                         }
8140 #endif
8141                         firstr = lastr = NULL;
8142                         break;
8143             }
8144             
8145             if(inRegCount == -1) {
8146 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8147               regCount = 0;
8148               inRegCount = 0;
8149             }
8150           }
8151         } else {
8152           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8153             if(inEntry)
8154               r = pic16_getRegFromInstruction(pc);
8155             else
8156               r = pic16_getRegFromInstruction2(pc);
8157             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8158               if(!firstr)firstr = r;
8159               regCount++;
8160 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8161             }
8162           }
8163         }
8164       }
8165     }
8166 }
8167               
8168             
8169
8170
8171
8172 /*-----------------------------------------------------------------*/
8173 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8174 /*                   function                                      */
8175 /*-----------------------------------------------------------------*/
8176 static bool ispCodeFunction(pCode *pc)
8177 {
8178
8179   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8180     return 1;
8181
8182   return 0;
8183 }
8184
8185 /*-----------------------------------------------------------------*/
8186 /* findFunction - Search for a function by name (given the name)   */
8187 /*                in the set of all functions that are in a pBlock */
8188 /* (note - I expect this to change because I'm planning to limit   */
8189 /*  pBlock's to just one function declaration                      */
8190 /*-----------------------------------------------------------------*/
8191 static pCode *findFunction(char *fname)
8192 {
8193   pBlock *pb;
8194   pCode *pc;
8195   if(!fname)
8196     return NULL;
8197
8198   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8199
8200     pc = setFirstItem(pb->function_entries);
8201     while(pc) {
8202     
8203       if((pc->type == PC_FUNCTION) &&
8204          (PCF(pc)->fname) && 
8205          (strcmp(fname, PCF(pc)->fname)==0))
8206         return pc;
8207
8208       pc = setNextItem(pb->function_entries);
8209
8210     }
8211
8212   }
8213   return NULL;
8214 }
8215
8216 static void MarkUsedRegisters(set *regset)
8217 {
8218
8219   regs *r1,*r2;
8220
8221   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8222 //      fprintf(stderr, "marking register = %s\t", r1->name);
8223     r2 = pic16_regWithIdx(r1->rIdx);
8224 //      fprintf(stderr, "to register = %s\n", r2->name);
8225     r2->isFree = 0;
8226     r2->wasUsed = 1;
8227   }
8228 }
8229
8230 static void pBlockStats(FILE *of, pBlock *pb)
8231 {
8232
8233   pCode *pc;
8234   regs  *r;
8235
8236         if(!pic16_pcode_verbose)return;
8237         
8238   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8239
8240   // for now just print the first element of each set
8241   pc = setFirstItem(pb->function_entries);
8242   if(pc) {
8243     fprintf(of,";entry:  ");
8244     pc->print(of,pc);
8245   }
8246   pc = setFirstItem(pb->function_exits);
8247   if(pc) {
8248     fprintf(of,";has an exit\n");
8249     //pc->print(of,pc);
8250   }
8251
8252   pc = setFirstItem(pb->function_calls);
8253   if(pc) {
8254     fprintf(of,";functions called:\n");
8255
8256     while(pc) {
8257       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8258         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8259       }
8260       pc = setNextItem(pb->function_calls);
8261     }
8262   }
8263
8264   r = setFirstItem(pb->tregisters);
8265   if(r) {
8266     int n = elementsInSet(pb->tregisters);
8267
8268     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8269
8270     while (r) {
8271       fprintf(of,   ";   %s\n",r->name);
8272       r = setNextItem(pb->tregisters);
8273     }
8274   }
8275   
8276   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8277 }
8278
8279 /*-----------------------------------------------------------------*/
8280 /*-----------------------------------------------------------------*/
8281 #if 0
8282 static void sequencepCode(void)
8283 {
8284   pBlock *pb;
8285   pCode *pc;
8286
8287
8288   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8289
8290     pb->seq = GpCodeSequenceNumber+1;
8291
8292     for( pc = pb->pcHead; pc; pc = pc->next)
8293       pc->seq = ++GpCodeSequenceNumber;
8294   }
8295
8296 }
8297 #endif
8298
8299 /*-----------------------------------------------------------------*/
8300 /*-----------------------------------------------------------------*/
8301 static set *register_usage(pBlock *pb)
8302 {
8303   pCode *pc,*pcn;
8304   set *registers=NULL;
8305   set *registersInCallPath = NULL;
8306
8307   /* check recursion */
8308
8309   pc = setFirstItem(pb->function_entries);
8310
8311   if(!pc)
8312     return registers;
8313
8314   pb->visited = 1;
8315
8316   if(pc->type != PC_FUNCTION)
8317     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8318
8319   pc = setFirstItem(pb->function_calls);
8320   for( ; pc; pc = setNextItem(pb->function_calls)) {
8321
8322     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8323       char *dest = pic16_get_op_from_instruction(PCI(pc));
8324
8325       pcn = findFunction(dest);
8326       if(pcn) 
8327         registersInCallPath = register_usage(pcn->pb);
8328     } else
8329       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8330
8331   }
8332
8333 #ifdef PCODE_DEBUG
8334   pBlockStats(stderr,pb);  // debug
8335 #endif
8336
8337   // Mark the registers in this block as used.
8338
8339   MarkUsedRegisters(pb->tregisters);
8340   if(registersInCallPath) {
8341     /* registers were used in the functions this pBlock has called */
8342     /* so now, we need to see if these collide with the ones we are */
8343     /* using here */
8344
8345     regs *r1,*r2, *newreg;
8346
8347     DFPRINTF((stderr,"comparing registers\n"));
8348
8349     r1 = setFirstItem(registersInCallPath);
8350     while(r1) {
8351
8352       r2 = setFirstItem(pb->tregisters);
8353
8354       while(r2 && (r1->type != REG_STK)) {
8355
8356         if(r2->rIdx == r1->rIdx) {
8357           newreg = pic16_findFreeReg(REG_GPR);
8358
8359
8360           if(!newreg) {
8361             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8362             exit(1);
8363           }
8364
8365           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8366                   r1->rIdx, newreg->rIdx));
8367           r2->rIdx = newreg->rIdx;
8368           //if(r2->name) Safe_free(r2->name);
8369           if(newreg->name)
8370             r2->name = Safe_strdup(newreg->name);
8371           else
8372             r2->name = NULL;
8373           newreg->isFree = 0;
8374           newreg->wasUsed = 1;
8375         }
8376         r2 = setNextItem(pb->tregisters);
8377       }
8378
8379       r1 = setNextItem(registersInCallPath);
8380     }
8381
8382     /* Collisions have been resolved. Now free the registers in the call path */
8383     r1 = setFirstItem(registersInCallPath);
8384     while(r1) {
8385       if(r1->type != REG_STK) {
8386         newreg = pic16_regWithIdx(r1->rIdx);
8387         newreg->isFree = 1;
8388       }
8389       r1 = setNextItem(registersInCallPath);
8390     }
8391
8392   }// else
8393   //    MarkUsedRegisters(pb->registers);
8394
8395   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8396 #ifdef PCODE_DEBUG
8397   if(registers) 
8398     DFPRINTF((stderr,"returning regs\n"));
8399   else
8400     DFPRINTF((stderr,"not returning regs\n"));
8401
8402   DFPRINTF((stderr,"pBlock after register optim.\n"));
8403   pBlockStats(stderr,pb);  // debug
8404 #endif
8405
8406   return registers;
8407 }
8408
8409 /*-----------------------------------------------------------------*/
8410 /* pct2 - writes the call tree to a file                           */
8411 /*                                                                 */
8412 /*-----------------------------------------------------------------*/
8413 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8414 {
8415   pCode *pc,*pcn;
8416   int i;
8417   //  set *registersInCallPath = NULL;
8418
8419   if(!of)
8420     return;
8421
8422   if(indent > 10) {
8423         fprintf(of, "recursive function\n");
8424     return; //recursion ?
8425   }
8426
8427   pc = setFirstItem(pb->function_entries);
8428
8429   if(!pc)
8430     return;
8431
8432   pb->visited = 0;
8433
8434   for(i=0;i<indent;i++)   // Indentation
8435         fputs("+   ", of);
8436   fputs("+- ", of);
8437
8438   if(pc->type == PC_FUNCTION) {
8439     usedstack += PCF(pc)->stackusage;
8440     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8441   } else return;  // ???
8442
8443
8444   pc = setFirstItem(pb->function_calls);
8445   for( ; pc; pc = setNextItem(pb->function_calls)) {
8446
8447     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8448       char *dest = pic16_get_op_from_instruction(PCI(pc));
8449
8450       pcn = findFunction(dest);
8451       if(pcn) 
8452         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8453     } else
8454       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8455
8456   }
8457
8458
8459 }
8460
8461
8462 /*-----------------------------------------------------------------*/
8463 /* pic16_printCallTree - writes the call tree to a file                  */
8464 /*                                                                 */
8465 /*-----------------------------------------------------------------*/
8466
8467 void pic16_printCallTree(FILE *of)
8468 {
8469   pBranch *pbr;
8470   pBlock  *pb;
8471   pCode   *pc;
8472
8473   if(!the_pFile)
8474     return;
8475
8476   if(!of)
8477     of = stderr;
8478
8479   fprintf(of, "\npBlock statistics\n");
8480   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8481     pBlockStats(of,pb);
8482
8483
8484   fprintf(of,"Call Tree\n");
8485   pbr = the_pFile->functions;
8486   while(pbr) {
8487     if(pbr->pc) {
8488       pc = pbr->pc;
8489       if(!ispCodeFunction(pc))
8490         fprintf(of,"bug in call tree");
8491
8492
8493       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8494
8495       while(pc->next && !ispCodeFunction(pc->next)) {
8496         pc = pc->next;
8497         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8498           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8499       }
8500     }
8501
8502     pbr = pbr->next;
8503   }
8504
8505
8506   fprintf(of,"\n**************\n\na better call tree\n");
8507   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8508 //    if(pb->visited)
8509       pct2(of,pb,0,0);
8510   }
8511
8512   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8513     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8514   }
8515 }
8516
8517
8518
8519 /*-----------------------------------------------------------------*/
8520 /*                                                                 */
8521 /*-----------------------------------------------------------------*/
8522
8523 static void InlineFunction(pBlock *pb)
8524 {
8525   pCode *pc;
8526   pCode *pc_call;
8527
8528   if(!pb)
8529     return;
8530
8531   pc = setFirstItem(pb->function_calls);
8532
8533   for( ; pc; pc = setNextItem(pb->function_calls)) {
8534
8535     if(isCALL(pc)) {
8536       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8537       pCode *pct;
8538       pCode *pce;
8539
8540       pBranch *pbr;
8541
8542       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8543         
8544         //fprintf(stderr,"Cool can inline:\n");
8545         //pcn->print(stderr,pcn);
8546
8547         //fprintf(stderr,"recursive call Inline\n");
8548         InlineFunction(pcn->pb);
8549         //fprintf(stderr,"return from recursive call Inline\n");
8550
8551         /*
8552           At this point, *pc points to a CALL mnemonic, and
8553           *pcn points to the function that is being called.
8554
8555           To in-line this call, we need to remove the CALL
8556           and RETURN(s), and link the function pCode in with
8557           the CALLee pCode.
8558
8559         */
8560
8561
8562         /* Remove the CALL */
8563         pc_call = pc;
8564         pc = pc->prev;
8565
8566         /* remove callee pBlock from the pBlock linked list */
8567         removepBlock(pcn->pb);
8568
8569         pce = pcn;
8570         while(pce) {
8571           pce->pb = pb;
8572           pce = pce->next;
8573         }
8574
8575         /* Remove the Function pCode */
8576         pct = pic16_findNextInstruction(pcn->next);
8577
8578         /* Link the function with the callee */
8579         pc->next = pcn->next;
8580         pcn->next->prev = pc;
8581         
8582         /* Convert the function name into a label */
8583
8584         pbr = Safe_calloc(1,sizeof(pBranch));
8585         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8586         pbr->next = NULL;
8587         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8588         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8589
8590         /* turn all of the return's except the last into goto's */
8591         /* check case for 2 instruction pBlocks */
8592         pce = pic16_findNextInstruction(pcn->next);
8593         while(pce) {
8594           pCode *pce_next = pic16_findNextInstruction(pce->next);
8595
8596           if(pce_next == NULL) {
8597             /* found the last return */
8598             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8599
8600             //fprintf(stderr,"found last return\n");
8601             //pce->print(stderr,pce);
8602             pce->prev->next = pc_call->next;
8603             pc_call->next->prev = pce->prev;
8604             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8605                                                       PCI(pce)->label);
8606           }
8607
8608           pce = pce_next;
8609         }
8610
8611
8612       }
8613     } else
8614       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8615
8616   }
8617
8618 }
8619
8620 /*-----------------------------------------------------------------*/
8621 /*                                                                 */
8622 /*-----------------------------------------------------------------*/
8623
8624 void pic16_InlinepCode(void)
8625 {
8626
8627   pBlock  *pb;
8628   pCode   *pc;
8629
8630   if(!the_pFile)
8631     return;
8632
8633   if(!functionInlining)
8634     return;
8635
8636   /* Loop through all of the function definitions and count the
8637    * number of times each one is called */
8638   //fprintf(stderr,"inlining %d\n",__LINE__);
8639
8640   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8641
8642     pc = setFirstItem(pb->function_calls);
8643
8644     for( ; pc; pc = setNextItem(pb->function_calls)) {
8645
8646       if(isCALL(pc)) {
8647         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8648         if(pcn && isPCF(pcn)) {
8649           PCF(pcn)->ncalled++;
8650         }
8651       } else
8652         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8653
8654     }
8655   }
8656
8657   //fprintf(stderr,"inlining %d\n",__LINE__);
8658
8659   /* Now, Loop through the function definitions again, but this
8660    * time inline those functions that have only been called once. */
8661   
8662   InlineFunction(the_pFile->pbHead);
8663   //fprintf(stderr,"inlining %d\n",__LINE__);
8664
8665   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8666     unBuildFlow(pb);
8667
8668 }
8669
8670 char *pic_optype_names[]={
8671         "PO_NONE",         // No operand e.g. NOP
8672         "PO_W",              // The working register (as a destination)
8673         "PO_WREG",           // The working register (as a file register)
8674         "PO_STATUS",         // The 'STATUS' register
8675         "PO_BSR",            // The 'BSR' register
8676         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8677                              // of three)
8678         "PO_INDF0",          // The Indirect register
8679         "PO_INTCON",         // Interrupt Control register
8680         "PO_GPR_REGISTER",   // A general purpose register
8681         "PO_GPR_BIT",        // A bit of a general purpose register
8682         "PO_GPR_TEMP",       // A general purpose temporary register
8683         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8684         "PO_PCL",            // Program counter Low register
8685         "PO_PCLATH",         // Program counter Latch high register
8686         "PO_PCLATU",         // Program counter Latch upper register
8687         "PO_PRODL",          // Product Register Low
8688         "PO_PRODH",          // Product Register High
8689         "PO_LITERAL",        // A constant
8690         "PO_REL_ADDR",       // A relative address
8691         "PO_IMMEDIATE",      //  (8051 legacy)
8692         "PO_DIR",            // Direct memory (8051 legacy)
8693         "PO_CRY",            // bit memory (8051 legacy)
8694         "PO_BIT",            // bit operand.
8695         "PO_STR",            //  (8051 legacy)
8696         "PO_LABEL",
8697         "PO_WILD"            // Wild card operand in peep optimizer
8698 };
8699
8700
8701 char *dumpPicOptype(PIC_OPTYPE type)
8702 {
8703         return (pic_optype_names[ type ]);
8704 }
8705
8706
8707 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8708 #include "graph.h"
8709
8710 #define MAX_COMMON_BANK_SIZE    32
8711 #define FIRST_PSEUDO_BANK_NR  1000
8712
8713 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8714 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8715 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8716 Graph *adj = NULL;
8717
8718 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8719
8720 typedef struct {
8721   pseudoBankNr bank;  // number assigned to this pseudoBank
8722   unsigned int size;  // number of operands assigned to this bank
8723   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8724 } pseudoBank;
8725
8726 /*----------------------------------------------------------------------*/
8727 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8728 /*----------------------------------------------------------------------*/
8729 unsigned int hashSymbol (const char *str)
8730 {
8731   unsigned int res = 0;
8732   if (!str) return 0;
8733
8734   while (*str) {
8735     res ^= (*str);
8736     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8737     str++;
8738   } // while
8739
8740   return res;
8741 }
8742
8743 /*-----------------------------------------------------------------------*/
8744 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8745 /*-----------------------------------------------------------------------*/
8746 int compareSymbol (const void *sym1, const void *sym2)
8747 {
8748   char *s1 = (char*) sym1;
8749   char *s2 = (char*) sym2;
8750   
8751   return (strcmp (s1,s2) == 0);
8752 }
8753
8754 /*-----------------------------------------------------------------------*/
8755 /* comparePre - return 1 iff p1 == p2                                    */
8756 /*-----------------------------------------------------------------------*/
8757 int comparePtr (const void *p1, const void *p2)
8758 {
8759   return (p1 == p2);
8760 }
8761
8762 /*----------------------------------------------------------*/
8763 /* getSymbolFromOperand - return a pointer to the symbol in */
8764 /*                        the given operand and its length  */
8765 /*----------------------------------------------------------*/
8766 char *getSymbolFromOperand (char *op, unsigned int *len)
8767 {
8768   char *sym, *curr;
8769   *len = 0;
8770
8771   if (!op) return NULL;
8772
8773   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8774   sym = op;
8775   if (*sym == '(') sym++;
8776
8777   curr = sym;
8778   while (((*curr >= 'A') && (*curr <= 'Z'))
8779          || ((*curr >= 'a') && (*curr <= 'z'))
8780          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8781          || (*curr == '_')) {
8782     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8783     curr++;
8784     (*len)++;
8785   } // while
8786
8787   return sym;
8788 }
8789
8790 /*--------------------------------------------------------------------------*/
8791 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8792 /*--------------------------------------------------------------------------*/
8793 char *getSymFromBank (pseudoBankNr bank)
8794 {
8795   assert (bank2sym);
8796
8797   if (bank < 0) return "<INVALID BANK NR>";
8798   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8799 }
8800
8801 /*-----------------------------------------------------------------------*/
8802 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8803 /*                           bank number (uses hTab sym2bank), if the    */
8804 /*                           symbol is not yet assigned a pseudo bank it */
8805 /*                           is assigned one here                        */
8806 /*-----------------------------------------------------------------------*/
8807 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8808 {
8809   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8810   pseudoBankNr bank;
8811   unsigned int hash;
8812
8813   assert (sym2bank);
8814
8815   hash = hashSymbol (op) % sym2bank->size;
8816   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8817   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8818
8819   if (bank == UNKNOWN_BANK) {
8820     // create a pseudo bank for the operand
8821     bank = next_bank++;
8822     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8823     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8824     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8825     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8826   } else {
8827     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8828   } // if
8829
8830   assert (bank >= 0);
8831
8832   return bank;
8833 }
8834
8835 /*--------------------------------------------------------------------*/
8836 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8837 /*--------------------------------------------------------------------*/
8838 int isBanksel (pCode *pc)
8839 {
8840   if (!pc) return 0;
8841
8842   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8843     // BANKSEL <variablename>  or  MOVLB <banknr>
8844     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8845     return 1;
8846   }
8847
8848   // check for inline assembler BANKSELs
8849   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8850                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8851     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8852     return 1;
8853   }
8854
8855   // assume pc is no BANKSEL instruction
8856   return 0;
8857 }
8858
8859 /*---------------------------------------------------------------------------------*/
8860 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8861 /*                  This method can not guarantee to find all modifications of the */
8862 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8863 /*                  generated plus some cases.                                     */
8864 /*---------------------------------------------------------------------------------*/
8865 int invalidatesBSR(pCode *pc)
8866 {
8867   // assembler directives invalidate BSR (well, they might, we don't know)
8868   if (isPCAD(pc)) return 1;
8869
8870   // only ASMDIRs and pCodeInstructions can invalidate BSR
8871   if (!isPCI(pc)) return 0;
8872
8873   // we have a pCodeInstruction
8874
8875   // check for BSR modifying instructions
8876   switch (PCI(pc)->op) {
8877   case POC_CALL:
8878   case POC_RCALL:
8879   case POC_MOVLB:
8880   case POC_RETFIE:  // might be used as CALL replacement
8881   case POC_RETLW:   // might be used as CALL replacement
8882   case POC_RETURN:  // might be used as CALL replacement
8883   case POC_BANKSEL:
8884     return 1;
8885     break;
8886
8887   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8888     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8889     break;
8890   } // switch
8891
8892   // no change of BSR possible/probable
8893   return 0;
8894 }
8895
8896 /*------------------------------------------------------------*/
8897 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8898 /*                      the symbol referenced in this BANKSEL */
8899 /*------------------------------------------------------------*/
8900 pseudoBankNr getBankFromBanksel (pCode *pc)
8901 {
8902   char *sym;
8903   int data = (int)NULL;
8904
8905   if (!pc) return INVALID_BANK;
8906   
8907   if (isPCAD(pc) && PCAD(pc)->directive) {
8908     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8909       // get symbolname from PCAD(pc)->arg
8910       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8911       sym = PCAD(pc)->arg;
8912       data = getPseudoBankNrFromOperand (sym);
8913       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8914     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8915       // get (literal) bank number from PCAD(pc)->arg
8916       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8917       assert (0 && "not yet implemented - turn off banksel optimization for now");
8918     }
8919   } else if (isPCI(pc)) {
8920     if (PCI(pc)->op == POC_BANKSEL) {
8921       // get symbolname from PCI(pc)->pcop->name (?)
8922       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8923       sym = PCI(pc)->pcop->name;
8924       data = getPseudoBankNrFromOperand (sym);
8925       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8926     } else if (PCI(pc)->op == POC_MOVLB) {
8927       // get (literal) bank number from PCI(pc)->pcop->name
8928       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8929       assert (0 && "not yet implemented - turn off banksel optimization for now");
8930     }
8931   }
8932   
8933   if (data == 0)
8934     // no assigned bank could be found
8935     return UNKNOWN_BANK;
8936   else
8937     return data;
8938 }
8939
8940 /*------------------------------------------------------------------------------*/
8941 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8942 /*------------------------------------------------------------------------------*/
8943 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8944 {
8945   pseudoBank *data;
8946
8947   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8948
8949   do {
8950     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8951     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8952     if (data) {
8953       if (data->bank != bank)
8954         bank = data->bank;
8955       else
8956         data = NULL;
8957     }
8958   } while (data);
8959   
8960   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8961   return bank;
8962 }
8963
8964 /*------------------------------------------------------------------*/
8965 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8966 /*                        bank is selected at a given pCode         */
8967 /*------------------------------------------------------------------*/
8968
8969 /* Create a graph with pseudo banks as its nodes and switches between
8970  * these as edges (with the edge weight representing the absolute
8971  * number of BANKSELs from one to the other).
8972  * Removes redundand BANKSELs instead iff mod == 1.
8973  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8974  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8975  * pseudo BSR.
8976  * TODO: check ALL instructions operands if they modify BSR directly...
8977  *
8978  * pb - the pBlock to annotate
8979  * mod  - select either graph creation (0) or BANKSEL removal (1)
8980  */
8981 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8982 {
8983   pCode *pc, *pc_next;
8984   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8985   int isBankselect = 0;
8986   unsigned int banksels=0;
8987   
8988   if (!pb) return 0;
8989
8990   pc = pic16_findNextInstruction(pb->pcHead);
8991   while (pc) {
8992     isBankselect = isBanksel (pc);
8993     pc_next = pic16_findNextInstruction (pc->next);
8994
8995     if (!hasNoLabel (pc)) {
8996       // we don't know our predecessors -- assume different BSRs
8997       prevBSR = UNKNOWN_BANK;
8998       pseudoBSR = UNKNOWN_BANK;
8999       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9000     } // if
9001
9002     // check if this is a BANKSEL instruction
9003     if (isBankselect) {
9004       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9005       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9006       if (mod) {
9007         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9008           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9009           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9010           pic16_unlinkpCode (pc);
9011           banksels++;
9012         }
9013       } else {
9014         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9015         banksels++;
9016       }
9017     } // if
9018
9019     if (!isBankselect && invalidatesBSR(pc)) {
9020       // check if this instruction invalidates the pseudoBSR
9021       pseudoBSR = UNKNOWN_BANK;
9022       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9023     } // if
9024
9025     prevBSR = pseudoBSR;
9026     pc = pc_next;
9027   } // while
9028
9029   return banksels;
9030 }
9031
9032 /*------------------------------------------------------------------------------------*/
9033 /* assignToSameBank - returns 0 on success or an error code                           */
9034 /*  1 - common bank would be too large                                                */
9035 /*  2 - assignment to fixed (absolute) bank not performed                             */
9036 /*                                                                                    */
9037 /* This functions assumes that unsplittable operands are already assigned to the same */
9038 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9039 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9040 /* TODO: Symbols with an abslute address must be handled specially!                   */
9041 /*------------------------------------------------------------------------------------*/
9042 int assignToSameBank (int bank0, int bank1, int doAbs)
9043 {
9044   int eff0, eff1, dummy;
9045   pseudoBank *pbank0, *pbank1;
9046   hashtItem *hitem;
9047
9048   eff0 = getEffectiveBank (bank0);
9049   eff1 = getEffectiveBank (bank1);
9050
9051   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9052
9053   // nothing to do if already same bank
9054   if (eff0 == eff1) return 0;
9055
9056   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9057     return 2;
9058
9059   // ensure eff0 < eff1
9060   if (eff0 > eff1) {
9061     // swap eff0 and eff1
9062     dummy = eff0;
9063     eff0 = eff1;
9064     eff1 = dummy;
9065     dummy = bank0;
9066     bank0 = bank1;
9067     bank1 = dummy;
9068   } // if
9069
9070   // now assign bank eff1 to bank eff0
9071   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9072   if (!pbank0) {
9073     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9074     pbank0->bank = eff0;
9075     pbank0->size = 1;
9076     pbank0->ref = 1;
9077     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9078   } // if
9079
9080   pbank1 = NULL;
9081   hitem = hTabSearch (coerce, eff1 % coerce->size);
9082   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9083     hitem = hitem->next;
9084
9085   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9086
9087 #if 0
9088   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9089            pbank0->bank, pbank0->size,
9090            getSymFromBank (eff0), getSymFromBank (eff1));
9091 #endif
9092
9093   if (pbank1) {
9094     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9095 #if 0
9096       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9097                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9098                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9099                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9100 #endif
9101       return 1;
9102     } // if
9103     pbank0->size += pbank1->size;
9104     pbank1->ref--;
9105     if (pbank1->ref == 0) Safe_free (pbank1);
9106   } else {
9107     pbank0->size++;
9108   } // if
9109
9110   if (hitem)
9111     hitem->item = pbank0;
9112   else  
9113     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9114   pbank0->ref++;
9115
9116   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9117
9118   return 0;
9119 }
9120
9121 /*----------------------------------------------------------------*/
9122 /* mergeGraphNodes - combines two nodes into one and modifies all */
9123 /*                   edges to and from the nodes accordingly      */
9124 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9125 /* then also (B,A) must be an edge (possibly with weight 0).      */
9126 /*----------------------------------------------------------------*/
9127 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9128 {
9129   GraphEdge *edge, *backedge, *nextedge;
9130   GraphNode *node;
9131   int backweight;
9132
9133   assert (node1 && node2);
9134   assert (node1 != node2);
9135   
9136   // add all edges starting at node2 to node1
9137   edge = node2->edge;
9138   while (edge) {
9139     nextedge = edge->next;
9140     node = edge->node;
9141     backedge = getGEdge (node, node2);
9142     if (backedge)
9143       backweight = backedge->weight;
9144     else
9145       backweight = 0;
9146     // insert edges (node1,node) and (node,node1)
9147     addGEdge2 (node1, node, edge->weight, backweight);
9148     // remove edges (node, node2) and (node2, node)
9149     remGEdge (node2, node);
9150     remGEdge (node, node2);
9151     edge = nextedge;
9152   } // while
9153   
9154   // now node2 should not be referenced by any other GraphNode...
9155   //remGNode (adj, node2->data, node2->hash);
9156 }
9157
9158 /*----------------------------------------------------------------*/
9159 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9160 /*----------------------------------------------------------------*/
9161 void showGraph (Graph *g)
9162 {
9163   GraphNode *node;
9164   GraphEdge *edge;
9165   pseudoBankNr bankNr;
9166   pseudoBank *pbank;
9167   unsigned int size;
9168
9169   node = g->node;
9170   while (node) {
9171     edge = node->edge;
9172     bankNr = getEffectiveBank (node->hash);
9173     assert (bankNr >= 0);
9174     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9175     if (pbank) {
9176       bankNr = pbank->bank;
9177       size = pbank->size;
9178     } else {
9179       size = 1;
9180     }
9181     
9182     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9183
9184     while (edge) {
9185       if (edge->weight > 0)
9186         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9187       edge = edge->next;
9188     } // while (edge)
9189     node = node->next;
9190   } // while (node)
9191 }
9192
9193 /*---------------------------------------------------------------*/
9194 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9195 /*---------------------------------------------------------------*/
9196 void pic16_OptimizeBanksel ()
9197 {
9198   GraphNode *node, *node1, *node1next;
9199
9200 #if 0
9201   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9202   GraphEdge *edge, *backedge;
9203   GraphEdge *max;
9204   int maxWeight, weight, mergeMore, absMaxWeight;
9205   pseudoBankNr curr0, curr1;
9206 #endif
9207   pseudoBank *pbank;
9208   pseudoBankNr bankNr;
9209   char *base_symbol0, *base_symbol1;
9210   int len0, len1;
9211   pBlock *pb;
9212   set *set;
9213   regs *reg;
9214   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9215
9216   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9217
9218   if (!the_pFile || !the_pFile->pbHead) return;
9219
9220   adj = newGraph (NULL);
9221   sym2bank = newHashTable ( 255 );
9222   bank2sym = newHashTable ( 255 );
9223   coerce = newHashTable ( 255 );
9224
9225   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9226   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9227     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9228   } // for pb
9229
9230 #if 1
9231   // assign symbols with absolute addresses to their respective bank nrs
9232   set = pic16_fix_udata;
9233   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9234     bankNr = reg->address >> 8;
9235     node = getOrAddGNode (adj, NULL, bankNr);
9236     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9237     assignToSameBank (node->hash, bankNr, 1);
9238     
9239     assert (bankNr >= 0);
9240     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9241     if (!pbank) {
9242       pbank = Safe_calloc (1, sizeof (pseudoBank));
9243       pbank->bank = reg->address >> 8; //FIXED_BANK;
9244       pbank->size = 1;
9245       pbank->ref = 1;
9246       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9247     } else {
9248       assert (pbank->bank == (reg->address >> 8));
9249       pbank->bank = reg->address >> 8; //FIXED_BANK;
9250     }
9251     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9252   } // for reg
9253 #endif
9254
9255 #if 1
9256   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9257   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9258   node = adj->node;
9259   while (node) {
9260     if (node->hash < 0) { node = node->next; continue; }
9261     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9262     node1 = node->next;
9263     while (node1) {
9264       if (node1->hash < 0) { node1 = node1->next; continue; }
9265       node1next = node1->next;
9266       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9267       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9268         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9269         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9270         if (assignToSameBank (node->hash, node1->hash, 0)) {
9271           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9272           assert (0 && "Could not assign a symbol to a bank!");
9273         }
9274         mergeGraphNodes (node, node1);
9275         /*
9276         if (node->hash < node1->hash)
9277           mergeGraphNodes (node, node1);
9278         else
9279           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9280         */
9281       } // if
9282       node1 = node1next;
9283     } // while (node1)
9284     node = node->next;
9285   } // while (node)
9286 #endif
9287
9288 #if 0
9289   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9290   // assign tightly coupled operands to the same (pseudo) bank
9291   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9292   mergeMore = 1;
9293   absMaxWeight = 0;
9294   while (mergeMore) {
9295     node = adj->node;
9296     max = NULL;
9297     maxWeight = 0;
9298     while (node) {
9299       curr0 = getEffectiveBank (node->hash);
9300       if (curr0 < 0) { node = node->next; continue; }
9301       edge = node->edge;
9302       while (edge) {
9303         assert (edge->src == node);
9304         backedge = getGEdge (edge->node, edge->src);
9305         weight = edge->weight + (backedge ? backedge->weight : 0);
9306         curr1 = getEffectiveBank (edge->node->hash);
9307         if (curr1 < 0) { edge = edge->next; continue; }
9308
9309         // merging is only useful if the items are not assigned to the same bank already...
9310         if (curr0 != curr1 && weight > maxWeight) {
9311           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9312           maxWeight = weight;
9313           max = edge;
9314         } // if
9315         edge = edge->next;
9316       } // while
9317       node = node->next;
9318     } // while
9319     
9320     if (maxWeight > 0) {
9321 #if 0
9322       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9323                max->src->hash, getSymFromBank (max->src->hash),
9324                max->node->hash, getSymFromBank (max->node->hash));
9325 #endif
9326
9327       node = getGNode (adj, max->src->data, max->src->hash);
9328       node1 = getGNode (adj, max->node->data, max->node->hash);
9329
9330       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9331         if (max->src->hash < max->node->hash)
9332           mergeGraphNodes (node, node1);
9333         else
9334           mergeGraphNodes (node1, node);
9335       } else {
9336         remGEdge (node, node1);
9337         remGEdge (node1, node);
9338         //mergeMore = 0;
9339       }
9340
9341     } else {
9342       mergeMore = 0;
9343     }
9344   } // while
9345 #endif
9346
9347 #if 1  
9348   // remove redundant BANKSELs
9349   //fprintf (stderr, "removing redundant BANKSELs\n");
9350   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9351     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9352   } // for pb
9353 #endif
9354
9355 #if 0
9356   fprintf (stderr, "display graph\n");
9357   showGraph ();
9358 #endif
9359
9360   deleteGraph (adj);
9361   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9362 }
9363
9364 /*** END of stuff belonging to the BANKSEL optimization ***/
9365
9366
9367
9368 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9369
9370 typedef unsigned int symbol_t;
9371 typedef unsigned int valnum_t;
9372 //typedef unsigned int hash_t;
9373
9374 #ifndef INT_TO_PTR
9375 #define INT_TO_PTR(x) (((char *) 0) + (x))
9376 #endif
9377
9378 #ifndef PTR_TO_INT
9379 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9380 #endif
9381
9382 /* statistics */
9383 static unsigned int pic16_df_removed_pcodes = 0;
9384 static unsigned int pic16_df_saved_bytes = 0;
9385 static unsigned int df_findall_sameflow = 0;
9386 static unsigned int df_findall_otherflow = 0;
9387 static unsigned int df_findall_in_vals = 0;
9388
9389 static void pic16_df_stats () {
9390   return;
9391   if (pic16_debug_verbose || pic16_pcode_verbose) {
9392     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9393     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9394     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9395   }
9396 }
9397
9398 /* Remove a pCode iff possible:
9399  * - previous pCode is no SKIP
9400  * - pc has no label
9401  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9402 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9403   pCode *pcprev, *pcnext;
9404   char buf[256], *total=NULL;
9405   int len;
9406   
9407   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9408
9409   pcprev = pic16_findPrevInstruction (pc->prev);
9410   pcnext = pic16_findNextInstruction (pc->next);
9411   
9412   /* if previous instruction is a skip -- do not remove */
9413   if (pcprev && isPCI_SKIP(pcprev)) return 0;
9414
9415   /* move labels to next instruction (if possible) */
9416   if (PCI(pc)->label && !pcnext) return 0;
9417
9418   if (PCI(pc)->label) {
9419     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9420     //pc->print (stderr, pc);
9421     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9422     PCI(pc)->label = NULL;
9423   }
9424   
9425   /* update statistics */
9426   pic16_df_removed_pcodes++;
9427   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9428   
9429   /* remove the pCode */
9430   pic16_pCode2str (buf, 256, pc);
9431   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9432   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9433     len = strlen (buf) + strlen (comment) + 10;
9434     total = (char *) Safe_malloc (len);
9435     SNPRINTF (total, len, "%s: %s", comment, buf);
9436     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9437     Safe_free (total);
9438   }
9439
9440   /* actually unlink it from the pBlock -- also remove from to/from lists */
9441   pic16_pCodeUnlink (pc);
9442
9443   /* remove the pCode -- release registers */
9444   pc->destruct (pc);
9445
9446   /* report success */
9447   return 1;
9448 }
9449
9450
9451 /* ======================================================================== */
9452 /* === SYMBOL HANDLING ==================================================== */
9453 /* ======================================================================== */
9454
9455 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9456 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9457 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9458
9459 /** Calculate a hash for a given string.
9460  * If len == 0 the string is assumed to be NUL terminated. */
9461 static hash_t symbolHash (const char *str, unsigned int len) {
9462   hash_t hash = 0;
9463   if (!len) {
9464     while (*str) {
9465       hash = (hash << 2) ^ *str;
9466       str++;
9467     } // while
9468   } else {
9469     while (len--) {
9470       hash = (hash << 2) ^ *str;
9471       str++;
9472     }
9473   }
9474   return hash;
9475 }
9476
9477 /** Return 1 iff strings v1 and v2 are identical. */
9478 static int symcmp (const void *v1, const void *v2) {
9479   return !strcmp ((const char *) v1, (const char *) v2);
9480 }
9481
9482 /** Return 1 iff pointers v1 and v2 are identical. */
9483 static int ptrcmp (const void *v1, const void *v2) {
9484   return (v1 == v2);
9485 }
9486
9487 enum {  SPO_WREG=0x1000,
9488         SPO_STATUS,
9489         SPO_PRODL,
9490         SPO_PRODH,
9491         SPO_INDF0,
9492         SPO_POSTDEC0,
9493         SPO_POSTINC0,
9494         SPO_PREINC0,
9495         SPO_PLUSW0,
9496         SPO_INDF1,
9497         SPO_POSTDEC1,
9498         SPO_POSTINC1,
9499         SPO_PREINC1,
9500         SPO_PLUSW1,
9501         SPO_INDF2,
9502         SPO_POSTDEC2,
9503         SPO_POSTINC2,
9504         SPO_PREINC2,
9505         SPO_PLUSW2,
9506         SPO_STKPTR,
9507         SPO_TOSL,
9508         SPO_TOSH,
9509         SPO_TOSU,
9510         SPO_BSR,
9511         SPO_FSR0L,
9512         SPO_FSR0H,
9513         SPO_FSR1L,
9514         SPO_FSR1H,
9515         SPO_FSR2L,
9516         SPO_FSR2H,
9517         SPO_PCL,
9518         SPO_PCLATH,
9519         SPO_PCLATU,
9520         SPO_TABLAT,
9521         SPO_TBLPTRL,
9522         SPO_TBLPTRH,
9523         SPO_TBLPTRU,
9524         SPO_LAST
9525 };
9526
9527 /* Return the unique symbol_t for the given string. */
9528 static symbol_t symFromStr (const char *str) {
9529   hash_t hash;
9530   char *res;
9531   symbol_t sym;
9532
9533   if (!map_symToStr) {
9534     int i;
9535     struct { char *name; symbol_t sym; } predefsyms[] = {
9536         {"WREG", SPO_WREG},
9537         {"STATUS", SPO_STATUS},
9538         {"PRODL", SPO_PRODL},
9539         {"PRODH", SPO_PRODH},
9540         {"INDF0", SPO_INDF0},
9541         {"POSTDEC0", SPO_POSTDEC0},
9542         {"POSTINC0", SPO_POSTINC0},
9543         {"PREINC0", SPO_PREINC0},
9544         {"PLUSW0", SPO_PLUSW0},
9545         {"INDF1", SPO_INDF1},
9546         {"POSTDEC1", SPO_POSTDEC1},
9547         {"POSTINC1", SPO_POSTINC1},
9548         {"PREINC1", SPO_PREINC1},
9549         {"PLUSW1", SPO_PLUSW1},
9550         {"INDF2", SPO_INDF2},
9551         {"POSTDEC2", SPO_POSTDEC2},
9552         {"POSTINC2", SPO_POSTINC2},
9553         {"PREINC2", SPO_PREINC2},
9554         {"PLUSW2", SPO_PLUSW2},
9555         {"STKPTR", SPO_STKPTR},
9556         {"TOSL", SPO_TOSL},
9557         {"TOSH", SPO_TOSH},
9558         {"TOSU", SPO_TOSU},
9559         {"BSR", SPO_BSR},
9560         {"FSR0L", SPO_FSR0L},
9561         {"FSR0H", SPO_FSR0H},
9562         {"FSR1L", SPO_FSR1L},
9563         {"FSR1H", SPO_FSR1H},
9564         {"FSR2L", SPO_FSR2L},
9565         {"FSR2H", SPO_FSR2H},
9566         {"PCL", SPO_PCL},
9567         {"PCLATH", SPO_PCLATH},
9568         {"PCLATU", SPO_PCLATU},
9569         {"TABLAT", SPO_TABLAT},
9570         {"TBLPTRL", SPO_TBLPTRL},
9571         {"TBLPTRH", SPO_TBLPTRH},
9572         {"TBLPTRU", SPO_TBLPTRU},
9573         {NULL, 0}
9574     };
9575
9576     map_strToSym = newHashTable (128);
9577     map_symToStr = newHashTable (128);
9578
9579     for (i=0; predefsyms[i].name; i++) {
9580       char *name;
9581
9582       /* enter new symbol */
9583       sym = predefsyms[i].sym;
9584       name = predefsyms[i].name;
9585       res = Safe_strdup (name);
9586       hash = symbolHash (name, 0);
9587
9588       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9589       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9590     } // for i
9591   }
9592
9593   hash = symbolHash (str, 0) % map_strToSym->size;
9594   
9595   /* find symbol in table */
9596   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9597   if (sym) {
9598     //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9599     return sym;
9600   }
9601
9602   /* enter new symbol */
9603   sym = nextSymbol++;
9604   res = Safe_strdup (str);
9605
9606   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9607   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9608
9609   //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9610   
9611   return sym;
9612 }
9613
9614 #if 1
9615 static const char *strFromSym (symbol_t sym) {
9616   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9617 }
9618 #endif
9619
9620 /* ======================================================================== */
9621 /* === DEFINITION MAP HANDLING ============================================ */
9622 /* ======================================================================== */
9623
9624 /* A defmap provides information about which symbol is defined by which pCode.
9625  * The most recent definitions are prepended to the list, so that the most
9626  * recent definition can be found by forward scanning the list.
9627  * pc2: MOVFF r0x00, r0x01
9628  * pc1: INCF r0x01
9629  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9630  *
9631  * We attach one defmap to each flow object, and each pCode will occur at
9632  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9633  * used to find definitions for a pCode in its own defmap that precede pCode.
9634  */
9635
9636 typedef struct defmap_s {
9637   symbol_t sym;                 /** symbol this item refers to */
9638   union {
9639     struct {
9640       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9641       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9642       int isRead:1;             /** sym/mask is read */
9643       int isWrite:1;            /** sym/mask is written */
9644     } access;
9645     int accessmethod;
9646   } acc;
9647   pCode *pc;                    /** pCode this symbol is refrenced at */
9648   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9649   valnum_t val;                 /** new unique number for this value (if isWrite) */
9650   struct defmap_s *prev, *next; /** link to previous an next definition */
9651 } defmap_t;
9652
9653 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9654 static int defmap_free_count = 0;               /** number of released defmap items */
9655
9656 /* Returns a defmap_t with the specified data; this will be the new list head.
9657  * next - pointer to the current list head */
9658 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9659   defmap_t *map;
9660   
9661   if (defmap_free) {
9662     map = defmap_free;
9663     defmap_free = map->next;
9664     --defmap_free_count;
9665   } else {
9666     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9667   }
9668   map->sym = sym;
9669   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9670   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9671   map->acc.access.isRead = (isRead != 0);
9672   map->acc.access.isWrite = (isWrite != 0);
9673   map->pc = pc;
9674   map->in_val = 0;
9675   map->val = (isWrite ? val : 0);
9676   map->prev = NULL;
9677   map->next = next;
9678   if (next) next->prev = map;
9679   
9680   return map;
9681 }
9682
9683 /* Returns a copy of the single defmap item. */
9684 static defmap_t *copyDefmap (defmap_t *map) {
9685   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9686   memcpy (res, map, sizeof (defmap_t));
9687   res->next = NULL;
9688   res->prev = NULL;
9689   return res;
9690 }
9691
9692 /* Insert a defmap item after the specified one. */
9693 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9694   if (!ref || !newItem) return 1;
9695
9696   newItem->next = ref->next;
9697   newItem->prev = ref;
9698   ref->next = newItem;
9699   if (newItem->next) newItem->next->prev = newItem;
9700   
9701   return 0;
9702 }
9703
9704 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9705  * item is copied before insertion into chain and therefore left untouched.
9706  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9707 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9708   defmap_t *dummy;
9709   dummy = *head;
9710   while (dummy && (dummy->sym != item->sym
9711                           || dummy->pc != item->pc
9712                           || dummy->acc.accessmethod != item->acc.accessmethod
9713                           || dummy->val != item->val
9714                           || dummy->in_val != item->in_val)) {
9715     dummy = dummy->next;
9716   } // while
9717
9718   /* item already present? */
9719   if (dummy) return 0;
9720   
9721   /* otherwise: insert copy of item */
9722   dummy = copyDefmap (item);
9723   dummy->next = *head;
9724   if (*head) (*head)->prev = dummy;
9725   *head = dummy;
9726
9727   return 1;
9728 }
9729
9730 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9731 static void deleteDefmap (defmap_t *map) {
9732   if (!map) return;
9733   
9734   /* unlink from chain -- fails for the first item (head is not updated!) */
9735   if (map->next) map->next->prev = map->prev;
9736   if (map->prev) map->prev->next = map->next;
9737
9738   /* clear map */
9739   memset (map, 0, sizeof (defmap_t));
9740
9741   /* save for future use */
9742   map->next = defmap_free;
9743   defmap_free = map;
9744   ++defmap_free_count;
9745 }
9746
9747 /* Release all defmaps referenced from map. */
9748 static void deleteDefmapChain (defmap_t **_map) {
9749   defmap_t *map, *next;
9750
9751   if (!_map) return;
9752
9753   map = *_map;
9754   
9755   /* find list head */
9756   while (map && map->prev) map = map->prev;
9757
9758   /* delete all items */
9759   while (map) {
9760     next = map->next;
9761     deleteDefmap (map);
9762     map = next;
9763   } // while
9764
9765   *_map = NULL;
9766 }
9767
9768 /* Free all defmap items. */
9769 static void freeDefmap (defmap_t **_map) {
9770   defmap_t *next;
9771   defmap_t *map;
9772
9773   if (!_map) return;
9774
9775   map = (*_map);
9776   
9777   /* find list head */
9778   while (map->prev) map = map->prev;
9779
9780   /* release all items */
9781   while (map) {
9782     next = map->next;
9783     Safe_free (map);
9784     map = next;
9785   }
9786
9787   (*_map) = NULL;
9788 }
9789
9790 /* Returns the most recent definition for the given symbol preceeding pc.
9791  * If no definition is found, NULL is returned. 
9792  * If pc == NULL the whole list is scanned. */
9793 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9794   defmap_t *curr = map;
9795
9796   if (pc) {
9797     /* skip all definitions up to pc */
9798     while (curr && (curr->pc != pc)) curr = curr->next;
9799
9800     /* pc not in the list -- scan the whole list for definitions */
9801     if (!curr) {
9802       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9803       curr = map;
9804     } else {
9805       /* skip all definitions performed by pc */
9806       while (curr && (curr->pc == pc)) curr = curr->next;
9807     }
9808   } // if (pc)
9809
9810   /* find definition for sym */
9811   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9812     curr = curr->next;
9813   }
9814
9815   return curr;
9816 }
9817
9818 #if 0
9819 /* Returns the first use (read) of the given symbol AFTER pc.
9820  * If no such use is found, NULL is returned.
9821  * If pc == NULL the whole list is scanned. */
9822 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9823   defmap_t *curr = map, *prev = NULL;
9824   
9825   if (pc) {
9826     /* skip all definitions up to pc */
9827     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9828
9829     /* pc not in the list -- scan the whole list for definitions */
9830     if (!curr) {
9831       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9832       curr = prev;
9833     }
9834   } else {
9835     /* find end of list */
9836     while (curr && curr->next) curr = curr->next;
9837   } // if (pc)
9838
9839   /* find use of sym (scan list backwards) */
9840   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9841
9842   return curr;
9843 }
9844 #endif
9845
9846 /* Return the defmap entry for sym AT pc. 
9847  * If none is found, NULL is returned.
9848  * If more than one entry is found an assertion is triggered. */
9849 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9850   defmap_t *res = NULL;
9851
9852   /* find entries for pc */
9853   while (map && map->pc != pc) map = map->next;
9854
9855   /* find first entry for sym @ pc */
9856   while (map && map->pc == pc && map->sym != sym) map = map->next;
9857
9858   /* no entry found */
9859   if (!map) return NULL;
9860
9861   /* check for more entries */
9862   res = map;
9863   map = map->next;
9864   while (map && map->pc == pc) {
9865     /* more than one entry for sym @ pc found? */
9866     assert (map->sym != sym);
9867     map = map->next;
9868   }
9869
9870   /* return single entry for sym @ pc */
9871   return res;
9872 }
9873
9874 /* Modifies the definition of sym at pCode to newval.
9875  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9876  */
9877 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9878   defmap_t *m  = map;
9879
9880   /* find definitions of pc */
9881   while (m && m->pc != pc) m = m->next;
9882
9883   /* find definition of sym at pc */
9884   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9885   
9886   /* no definition found */
9887   if (!m) return 1;
9888
9889   /* redefine */
9890   m->val = newval;
9891
9892   /* update following uses of sym */
9893   while (m && m->pc == pc) m = m->prev;
9894   while (m) {
9895     if (m->sym == sym) {
9896       m->in_val = newval;
9897       if (m->acc.access.isWrite) m = NULL;
9898     } // if
9899     if (m) m = m->prev;
9900   } // while
9901   
9902   return 0;
9903 }
9904
9905 /* ======================================================================== */
9906 /* === STACK ROUTINES ===================================================== */
9907 /* ======================================================================== */
9908
9909 typedef struct stack_s {
9910   void *data;
9911   struct stack_s *next;
9912 } stackitem_t;
9913
9914 typedef stackitem_t *stack_t;
9915 static stackitem_t *free_stackitems = NULL;
9916
9917 /* Create a stack with one item. */
9918 static stack_t *newStack () {
9919   stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9920   *s = NULL;
9921   return s;
9922 }
9923
9924 /* Remove a stack -- its items are only marked free. */
9925 static void deleteStack (stack_t *s) {
9926   stackitem_t *i;
9927
9928   while (*s) {
9929     i = *s;
9930     *s = (*s)->next;
9931     i->next = free_stackitems;
9932     free_stackitems = i;
9933   } // while
9934   Safe_free (s);
9935 }
9936
9937 /* Release all stackitems. */
9938 static void releaseStack () {
9939   stackitem_t *i;
9940   
9941   while (free_stackitems) {
9942     i = free_stackitems->next;
9943     Safe_free(free_stackitems);
9944     free_stackitems = i;
9945   } // while
9946 }
9947
9948 static void stackPush (stack_t *stack, void *data) {
9949   stackitem_t *i;
9950   
9951   if (free_stackitems) {
9952     i = free_stackitems;
9953     free_stackitems = free_stackitems->next;
9954   } else {
9955     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9956   }
9957   i->data = data;
9958   i->next = *stack;
9959   *stack = i;
9960 }
9961
9962 static void *stackPop (stack_t *stack) {
9963   void *data;
9964   stackitem_t *i;
9965   
9966   if (stack && *stack) {
9967     data = (*stack)->data;
9968     i = *stack;
9969     *stack = (*stack)->next;
9970     i->next = free_stackitems;
9971     free_stackitems = i;
9972     return data;
9973   } else {
9974     return NULL;
9975   }
9976 }
9977
9978 #if 0
9979 static int stackContains (stack_t *s, void *data) {
9980   stackitem_t *i;
9981   if (!s) return 0;
9982   i = *s;
9983   while (i) {
9984     if (i->data == data) return 1;
9985     i = i->next;
9986   } // while
9987
9988   /* not found */
9989   return 0;
9990 }
9991 #endif
9992
9993 static int stackIsEmpty (stack_t *s) {
9994   return (*s == NULL);
9995 }
9996
9997
9998 typedef struct {
9999   pCodeFlow *flow;
10000   defmap_t *lastdef;
10001 } state_t;
10002
10003 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10004   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10005   s->flow = flow;
10006   s->lastdef = lastdef;
10007   return s;
10008 }
10009
10010 static void deleteState (state_t *s) {
10011   Safe_free (s);
10012 }
10013
10014 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
10015   stackitem_t *i;
10016
10017   /* scan working list for state */
10018   if (todo) {
10019     i = *todo;
10020     while (i) {
10021       /* is i == state? -- state not new */
10022       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10023       i = i->next;
10024     } // while
10025   }
10026
10027   if (done) {
10028     i = *done;
10029     while (i) {
10030       /* is i == state? -- state not new */
10031       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10032       i = i->next;
10033     } // while
10034   }
10035
10036   /* not found -- state is new */
10037   return 1;
10038 }
10039
10040 static inline valnum_t newValnum ();
10041
10042 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10043   pCode *pc;
10044
10045   if (!pb) return "<unknown function>";
10046
10047   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10048   if (pc && isPCF(pc)) return PCF(pc)->fname;
10049   else return "<unknown function>";
10050 }
10051
10052 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10053   defmap_t *map;
10054   pCodeFlow *pcfl;
10055
10056   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10057
10058   /* find initial value (assigning pc == NULL) */
10059   map = PCFL(pcfl)->in_vals;
10060   while (map && map->sym != sym) map = map->next;
10061
10062   /* initial value already present? */
10063   if (map) {
10064     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10065     return map;
10066   }
10067
10068   /* create a new initial value */
10069   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10070   PCFL(pcfl)->in_vals = map;
10071   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10072   return map;
10073
10074 #if 0
10075   /* insert map as last item in pcfl's defmap */
10076   if (!prev) prev = PCFL(pcfl)->defmap;
10077   if (!prev) {
10078     PCFL(pcfl)->defmap = map;
10079   } else {
10080     while (prev->next) prev = prev->next;
10081     prev->next = map;
10082     map->prev = prev;
10083   }
10084
10085   return map;
10086 #endif
10087 }
10088
10089 /* Find all reaching definitions for sym at pc. 
10090  * A new (!) list of definitions is returned.
10091  * Returns the number of reaching definitions found.
10092  * The defining defmap entries are returned in *chain.
10093  */
10094 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10095   defmap_t *map;
10096   defmap_t *res;
10097
10098   pCodeFlow *curr;
10099   pCodeFlowLink *succ;
10100   state_t *state;
10101   stack_t *todo;        /** stack of state_t */
10102   stack_t *done;        /** stack of state_t */
10103
10104   int firstState, n_defs;
10105   
10106   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10107   assert (chain);
10108
10109   /* initialize return list */
10110   *chain = NULL;
10111
10112   /* wildcard symbol? */
10113   if (!sym) return 0;
10114   
10115   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10116   
10117   map = PCI(pc)->pcflow->defmap;
10118
10119   res = defmapFindDef (map, sym, pc);
10120   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10121
10122 #define USE_PRECALCED_INVALS 1
10123 #if USE_PRECALCED_INVALS
10124   if (!res && PCI(pc)->pcflow->in_vals) {
10125     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10126     if (res) {
10127       //fprintf  (stderr, "found def in init values\n");
10128       df_findall_in_vals++;
10129     }
10130   }
10131 #endif
10132
10133   if (res) {
10134     // found a single definition (in pc's flow)
10135     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10136     defmapAddCopyIfNew (chain, res);
10137     df_findall_sameflow++;
10138     return 1;
10139   }
10140
10141 #if USE_PRECALCED_INVALS
10142   else {
10143     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10144     return 1;
10145   }
10146
10147 #endif
10148   
10149 #define FORWARD_FLOW_ANALYSIS 1
10150 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10151   /* no definition found in pc's flow preceeding pc */
10152   todo = newStack ();
10153   done = newStack ();
10154   n_defs = 0; firstState = 1;
10155   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10156
10157   while (!stackIsEmpty (todo)) {
10158     state = (state_t *) stackPop (todo);
10159     stackPush (done, state);
10160     curr = state->flow;
10161     res = state->lastdef;
10162     //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);
10163
10164     /* there are no definitions BEFORE pc in pc's flow (see above) */
10165     if (curr == PCI(pc)->pcflow) {
10166       if (!res) {
10167         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10168         res = pic16_pBlockAddInval (pc->pb, sym);
10169         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10170         res = NULL;
10171       } else {
10172         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10173         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10174       }
10175     }
10176
10177     /* save last definition of sym in this flow as initial def in successors */
10178     res = defmapFindDef (curr->defmap, sym, NULL);
10179     if (!res) res = state->lastdef;
10180     
10181     /* add successors to working list */
10182     state = newState (NULL, NULL);
10183     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10184     while (succ) {
10185       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10186       state->flow = succ->pcflow;
10187       state->lastdef = res;
10188       if (stateIsNew (state, todo, done)) {
10189         stackPush (todo, state);
10190         state = newState (NULL, NULL);
10191       } // if
10192       succ = (pCodeFlowLink *) setNextItem (curr->to);
10193     } // while
10194     deleteState (state);
10195   } // while
10196
10197 #else // !FORWARD_FLOW_ANALYSIS 
10198
10199   /* no definition found in pc's flow preceeding pc */
10200   todo = newStack ();
10201   done = newStack ();
10202   n_defs = 0; firstState = 1;
10203   stackPush (todo, newState (PCI(pc)->pcflow, res));
10204
10205   while (!stackIsEmpty (todo)) {
10206     state = (state_t *) stackPop (todo);
10207     curr = state->flow;
10208
10209     if (firstState) {
10210       firstState = 0;
10211       /* only check predecessor flows */
10212     } else {
10213       /* get (last) definition of sym in this flow */
10214       res = defmapFindDef (curr->defmap, sym, NULL);
10215     }
10216
10217     if (res) {
10218       /* definition found */
10219       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10220       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10221     } else {
10222       /* no definition found -- check predecessor flows */
10223       state = newState (NULL, NULL);
10224       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10225
10226       /* if no flow predecessor available -- sym might be uninitialized */
10227       if (!succ) {
10228         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10229         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10230         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10231         deleteDefmap (res); res = NULL;
10232       }
10233       
10234       while (succ) {
10235         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10236         state->flow = succ->pcflow;
10237         state->lastdef = res;
10238         if (stateIsNew (state, todo, done)) {
10239           stackPush (todo, state);
10240           state = newState (NULL, NULL);
10241         } // if
10242         succ = (pCodeFlowLink *) setNextItem (curr->from);
10243       } // while
10244       deleteState (state);
10245     }
10246   } // while
10247
10248 #endif
10249
10250   /* clean up done stack */
10251   while (!stackIsEmpty(done)) {
10252     deleteState ((state_t *) stackPop (done));
10253   } // while
10254   deleteStack (done);
10255
10256   /* return number of items in result set */
10257   if (n_defs == 0) {
10258     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10259   } else if (n_defs == 1) {
10260     assert (*chain);
10261     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10262   } else if (n_defs > 0) {
10263     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10264 #if 0
10265     res = *chain;
10266     while (res) {
10267       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10268       res = res->next;
10269     } // while
10270 #endif
10271   }
10272   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10273   df_findall_otherflow++;
10274   return n_defs;
10275 }
10276
10277 /* ======================================================================== */
10278 /* === VALUE NUMBER HANDLING ============================================== */
10279 /* ======================================================================== */
10280
10281 static valnum_t nextValnum = 0x1000;
10282 static hTab *map_symToValnum = NULL;
10283
10284 /** Return a new value number. */
10285 static inline valnum_t newValnum () {
10286   return (nextValnum += 4);
10287 }
10288
10289 static valnum_t valnumFromStr (const char *str) {
10290   symbol_t sym;
10291   valnum_t val;
10292   void *res;
10293   
10294   sym = symFromStr (str);
10295
10296   if (!map_symToValnum) {
10297     map_symToValnum = newHashTable (128);
10298   } // if
10299
10300   /* literal already known? */
10301   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10302
10303   /* return existing valnum */
10304   if (res) return (valnum_t) PTR_TO_INT(res);
10305   
10306   /* create new valnum */
10307   val = newValnum();
10308   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10309   return val;
10310 }
10311
10312 /* Create a valnum for a literal. */
10313 static valnum_t valnumFromLit (unsigned int lit) {
10314   return ((valnum_t) 0x100 + (lit & 0x0FF));
10315 }
10316
10317 /* Return the (positive) literal value represented by val
10318  * or -1 iff val is no known literal's valnum. */
10319 static int litFromValnum (valnum_t val) {
10320   if (val >= 0x100 && val < 0x200) {
10321     /* valnum is a (known) literal */
10322     return val & 0x00FF;
10323   } else {
10324     /* valnum is not a known literal */
10325     return -1;
10326   }
10327 }
10328
10329 #if 0
10330 /* Sanity check - all flows in a block must be reachable from initial flow. */
10331 static int verifyAllFlowsReachable (pBlock *pb) {
10332   set *reached;
10333   set *flowInBlock;
10334   set *checked;
10335   pCode *pc;
10336   pCodeFlow *pcfl;
10337   pCodeFlowLink *succ;
10338   int res;
10339
10340   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10341
10342   reached = NULL;
10343   flowInBlock = NULL;
10344   checked = NULL;
10345   /* mark initial flow as reached (and "not needs to be reached") */
10346   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10347   assert (pc);
10348   addSetHead (&reached, pc);
10349   addSetHead (&checked, pc);
10350   
10351   /* mark all further flows in block as "need to be reached" */
10352   pc = pb->pcHead;
10353   do {
10354     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10355     pc = pic16_findNextInstruction (pc->next);
10356   } while (pc);
10357
10358   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10359     /* mark as reached and "not need to be reached" */
10360     deleteSetItem (&reached, pcfl);
10361     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10362     
10363     /* flow is no longer considered unreachable */
10364     deleteSetItem (&flowInBlock, pcfl);
10365
10366     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10367       if (!isinSet (checked, succ->pcflow)) {
10368         /* flow has never been reached before */
10369         addSetHead (&reached, succ->pcflow);
10370         addSetHead (&checked, succ->pcflow);
10371       } // if
10372     } // for succ
10373   } // while
10374
10375   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10376
10377   /* by now every flow should have been reached
10378    * --> flowInBlock should be empty */
10379   res = (flowInBlock == NULL);
10380
10381 #if 1
10382   if (flowInBlock) {
10383           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10384     while (flowInBlock) {
10385       pcfl = indexSet (flowInBlock, 0);
10386       fprintf (stderr, "not reached: flow %p\n", pcfl);
10387       deleteSetItem (&flowInBlock, pcfl);
10388     } // while
10389   }
10390 #endif
10391   
10392   /* clean up */
10393   deleteSet (&reached);
10394   deleteSet (&flowInBlock);
10395   deleteSet (&checked);
10396   
10397   /* if we reached every flow, succ is NULL by now... */
10398   //assert (res); // will fire on unreachable code...
10399   return (res);
10400 }
10401 #endif
10402
10403 /* Checks a flow for accesses to sym AFTER pc.
10404  * 
10405  * Returns -1 if the symbol is read in this flow (before redefinition),
10406  * returns 0 if the symbol is redefined in this flow or
10407  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10408  */
10409 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10410   defmap_t *map, *mappc;
10411
10412   /* find pc or start of definitions */
10413   map = pcfl->defmap;
10414   while (map && (map->pc != pc) && map->next) map = map->next;
10415   /* if we found pc -- ignore it */
10416   while (map && map->pc == pc) map = map->prev;
10417
10418   /* scan list backwards (first definition first) */
10419   while (map && mask) {
10420 //    if (map->sym == sym) {
10421       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10422       mappc = map;
10423       /* scan list for reads at this pc first */
10424       while (map && map->pc == mappc->pc) {
10425         /* is the symbol (partially) read? */
10426         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10427           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10428           return -1;
10429         }
10430         map = map->prev;
10431       } // while
10432       map = mappc;
10433
10434       while (map && map->pc == mappc->pc) {
10435         /* honor (partial) redefinitions of sym */
10436         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10437           mask &= ~map->acc.access.mask;
10438           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10439         }
10440         map = map->prev;
10441       } // while
10442 //    } // if
10443     /* map already points to the first defmap for the next pCode */
10444     //map = mappc->prev;
10445   } // while
10446
10447   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10448    * is still alive; return the appropriate mask of alive bits */
10449   return mask;
10450 }
10451
10452 /* Check whether a symbol is alive (AFTER pc). */
10453 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10454   int mask, visit;
10455   defmap_t *map;
10456   stack_t *todo, *done;
10457   state_t *state;
10458   pCodeFlow *pcfl;
10459   pCodeFlowLink *succ;
10460
10461   mask = 0x00ff;
10462   
10463   assert (isPCI(pc));
10464   pcfl = PCI(pc)->pcflow;
10465   map = pcfl->defmap;
10466
10467   todo = newStack ();
10468   done = newStack ();
10469   
10470   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10471   stackPush (todo, state);
10472   visit = 0;
10473   
10474   while (!stackIsEmpty (todo)) {
10475     state = (state_t *) stackPop (todo);
10476     pcfl = state->flow;
10477     mask = PTR_TO_INT(state->lastdef);
10478     if (visit) stackPush (done, state); else deleteState(state);
10479     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10480     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10481     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10482     visit++;
10483
10484     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10485     if (mask == 0) continue;
10486
10487     /* symbol is (partially) read before redefinition in flow */
10488     if (mask == -1) break;
10489
10490     /* symbol is neither read nor completely redefined -- check successor flows */
10491     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10492       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10493       if (stateIsNew (state, todo, done)) {
10494         stackPush (todo, state);
10495       } else {
10496         deleteState (state);
10497       }
10498     } // for
10499   } // while
10500
10501   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10502   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10503
10504   /* symbol is read in at least one flow -- is alive */
10505   if (mask == -1) return 1;
10506
10507   /* symbol is read in no flow */
10508   return 0;
10509 }
10510
10511 /* Returns whether access to the given symbol has side effects. */
10512 static int pic16_symIsSpecial (symbol_t sym) {
10513   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10514   switch (sym) {
10515   case SPO_INDF0:
10516   case SPO_PLUSW0:
10517   case SPO_POSTINC0:
10518   case SPO_POSTDEC0:
10519   case SPO_PREINC0:
10520   case SPO_INDF1:
10521   case SPO_PLUSW1:
10522   case SPO_POSTINC1:
10523   case SPO_POSTDEC1:
10524   case SPO_PREINC1:
10525   case SPO_INDF2:
10526   case SPO_PLUSW2:
10527   case SPO_POSTINC2:
10528   case SPO_POSTDEC2:
10529   case SPO_PREINC2:
10530   case SPO_PCL:
10531           return 1;
10532   default:
10533           /* no special effects known */
10534           return 0;
10535   } // switch
10536
10537   return 0;
10538 }
10539
10540 /* Check whether a register should be considered local (to the current function) or not. */
10541 static int pic16_regIsLocal (regs *r) {
10542   symbol_t sym;
10543   if (r) {
10544     sym = symFromStr (r->name);
10545     switch (sym) {
10546     case SPO_WREG:
10547     case SPO_FSR0L: // used in ptrget/ptrput
10548     case SPO_FSR0H: // ... as well
10549     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10550     case SPO_FSR1H: // ... as well
10551     case SPO_FSR2L: // used as frame pointer
10552     case SPO_FSR2H: // ... as well
10553     case SPO_PRODL: // used to return values from functions
10554     case SPO_PRODH: // ... as well
10555       /* these registers (and some more...) are considered local */
10556       return 1;
10557       break;
10558     default:
10559       /* for unknown regs: check is marked local, leave if not */
10560       if (r->isLocal) {
10561         return 1;
10562       } else {
10563         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10564         return 0;
10565       }
10566     } // switch
10567   } // if
10568
10569   /* if in doubt, assume non-local... */
10570   return 0;
10571 }
10572
10573 /* Check all symbols touched by pc whether their newly assigned values are read.
10574  * Returns 0 if no symbol is used later on, 1 otherwise. */
10575 static int pic16_pCodeIsAlive (pCode *pc) {
10576   pCodeInstruction *pci;
10577   defmap_t *map, *lastpc;
10578   regs *checkreg;
10579   
10580   /* we can only handle PCIs */
10581   if (!isPCI(pc)) return 1;
10582
10583   //pc->print (stderr, pc);
10584
10585   pci = PCI(pc);
10586   assert (pci && pci->pcflow && pci->pcflow->defmap);
10587
10588   /* NEVER remove instructions with implicit side effects */
10589   switch (pci->op) {
10590   case POC_TBLRD:
10591   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10592   case POC_TBLRD_POSTDEC:
10593   case POC_TBLRD_PREINC:
10594   case POC_TBLWT:               /* modify program memory */
10595   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10596   case POC_TBLWT_POSTDEC:
10597   case POC_TBLWT_PREINC:
10598   case POC_CLRWDT:              /* clear watchdog timer */
10599   case POC_PUSH:                /* should be safe to remove though... */
10600   case POC_POP:                 /* should be safe to remove though... */
10601   case POC_CALL:
10602   case POC_RCALL:
10603   case POC_RETFIE:
10604   case POC_RETURN:
10605     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10606     return 1;
10607
10608   default:
10609     /* no special instruction */
10610     break;
10611   } // switch
10612
10613   /* prevent us from removing assignments to non-local variables */
10614   checkreg = NULL;
10615   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10616   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10617
10618   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10619     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10620     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10621     //pc->print (stderr, pc);
10622     return 1;
10623   }
10624   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10625     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10626     return 1;
10627   }
10628   
10629 #if 1
10630   /* OVERKILL: prevent us from removing reads from non-local variables 
10631    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10632    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10633   checkreg = NULL;
10634   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10635   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10636
10637   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10638     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10639     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10640     //pc->print (stderr, pc);
10641     return 1;
10642   }
10643   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10644     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10645     return 1;
10646   }
10647 #endif
10648   
10649   /* now check that the defined symbols are not used */
10650   map = pci->pcflow->defmap;
10651   
10652   /* find items for pc */
10653   while (map && map->pc != pc) map = map->next;
10654
10655   /* no entries found? something is fishy with DF analysis... -- play safe */
10656   if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10657
10658   /* remember first item assigned to pc for later use */
10659   lastpc = map;
10660   
10661   /* check all symbols being modified by pc */
10662   while (map && map->pc == pc) {
10663     if (map->sym == 0) { map = map->next; continue; }
10664
10665     /* keep pc if it references special symbols (like POSTDEC0) */
10666 #if 0
10667     {
10668       char buf[256];
10669       pic16_pCode2str (buf, 256, pc);
10670       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10671     }
10672 #endif
10673     if (pic16_symIsSpecial (map->sym)) {
10674       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10675       return 1;
10676     }
10677     if (map->acc.access.isWrite) {
10678       if (pic16_isAlive (map->sym, pc)) {
10679         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10680         return 1;
10681       }
10682     }
10683     map = map->next;
10684   } // while
10685
10686   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10687 #if 0
10688   {
10689     char buf[256];
10690     pic16_pCode2str (buf, 256, pc);
10691     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10692   }
10693 #endif
10694   return 0;
10695 }
10696
10697 /* Adds implied operands to the list.
10698  * sym - operand being accessed in the pCode
10699  * list - list to append the operand
10700  * isRead - set to 1 iff sym is read in pCode
10701  * listRead - set to 1 iff all operands being read are to be listed
10702  *
10703  * Returns 0 for "normal" operands, 1 for special operands.
10704  */
10705 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10706   /* check whether accessing REG accesses other REGs as well */
10707   switch (sym) {
10708   case SPO_INDF0:
10709     /* reads FSR0x */
10710     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10711     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10712     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10713     break;
10714     
10715   case SPO_PLUSW0:
10716     /* reads FSR0x and WREG */
10717     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10718     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10719     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10720     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10721     break;
10722     
10723   case SPO_POSTDEC0:
10724   case SPO_POSTINC0:
10725   case SPO_PREINC0:
10726     /* reads/modifies FSR0x */
10727     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10728     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10729     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10730     break;
10731
10732   case SPO_INDF1:
10733     /* reads FSR1x */
10734     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10735     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10736     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10737     break;
10738     
10739   case SPO_PLUSW1:
10740     /* reads FSR1x and WREG */
10741     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10742     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10743     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10744     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10745     break;
10746     
10747   case SPO_POSTDEC1:
10748   case SPO_POSTINC1:
10749   case SPO_PREINC1:
10750     /* reads/modifies FSR1x */
10751     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10752     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10753     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10754     break;
10755
10756   case SPO_INDF2:
10757     /* reads FSR2x */
10758     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10759     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10760     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10761     break;
10762     
10763   case SPO_PLUSW2:
10764     /* reads FSR2x and WREG */
10765     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10766     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10767     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10768     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10769     break;
10770     
10771   case SPO_POSTDEC2:
10772   case SPO_POSTINC2:
10773   case SPO_PREINC2:
10774     /* reads/modifies FSR2x */
10775     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10776     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10777     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10778     break;
10779
10780   case SPO_PCL:
10781     /* modifies PCLATH and PCLATU */
10782     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10783     if (isRead) {
10784       /* reading PCL updates PCLATx */
10785       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10786       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10787     }
10788     if (isWrite) {
10789       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10790       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10791       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10792     }
10793     break;
10794
10795   default:
10796     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10797     /* nothing special */
10798     return 0;
10799     break;
10800   }
10801
10802   /* has been a special operand */
10803   return 1;
10804 }
10805
10806 static symbol_t pic16_fsrsym_idx[][2] = {
10807     {SPO_FSR0L, SPO_FSR0H},
10808     {SPO_FSR1L, SPO_FSR1H},
10809     {SPO_FSR2L, SPO_FSR2H}
10810 };
10811
10812 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10813 static void mergeDefmapSymbols (defmap_t *list) { 
10814   defmap_t *ref, *curr, *temp;
10815
10816   /* now make sure that each symbol occurs at most once per pc */
10817   ref = list;
10818   while (ref && (ref->pc == list->pc)) {
10819     curr = ref->next;
10820     while (curr && (curr->pc == list->pc)) {
10821       if (curr->sym == ref->sym) {
10822         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10823         /* found a symbol occuring twice... merge the two */
10824         if (curr->acc.access.isRead) {
10825           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10826           ref->acc.access.isRead = 1;
10827           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10828         }
10829         if (curr->acc.access.isWrite) {
10830           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10831           ref->acc.access.isWrite = 1;
10832           ref->acc.access.mask |= curr->acc.access.mask;
10833         }
10834         temp = curr;
10835         curr = curr->next;
10836         deleteDefmap (temp);
10837         continue; // do not skip curr!
10838       } // if
10839       curr = curr->next;
10840     } // while
10841     ref = ref->next;
10842   } // while
10843 }
10844
10845 /** Prepend list with the reads and definitions performed by pc. */
10846 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10847   pCodeInstruction *pci;
10848   int cond, inCond, outCond;
10849   int mask = 0xff, smask;
10850   int isSpecial, isSpecial2;
10851   symbol_t sym, sym2;
10852   char *name;
10853
10854   if (isPCAD(pc)) {
10855     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10856     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10857     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10858     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10859     return list;
10860   }
10861   assert (isPCI(pc));
10862   pci = PCI(pc);
10863   
10864   /* handle bit instructions */
10865   if (pci->isBitInst) {
10866     assert (pci->pcop->type == PO_GPR_BIT);
10867     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10868   }
10869
10870   /* handle (additional) implicit arguments */
10871   switch (pci->op) {
10872   case POC_LFSR:
10873     {
10874       int lit;
10875       valnum_t val;
10876       lit = PCOL(pci->pcop)->lit;
10877       assert (lit >= 0 && lit < 3);
10878       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10879       val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10880       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10881       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10882       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...
10883     }
10884     break;
10885
10886   case POC_MOVLB: // BSR
10887   case POC_BANKSEL: // BSR
10888     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10889     break;
10890
10891   case POC_MULWF: // PRODx
10892   case POC_MULLW: // PRODx
10893     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10894     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10895     break;
10896
10897   case POC_POP: // TOS, STKPTR
10898     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10899     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10900     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10901     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10902     break;
10903     
10904   case POC_PUSH: // STKPTR
10905     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10906     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10907     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10908     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10909     break;
10910     
10911   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10912   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10913     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10914     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10915     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10916     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10917
10918     /* needs correctly set-up stack pointer */
10919     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10920     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10921     break;
10922
10923   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10924     /* pseudo read on (possible) return values */
10925     // WREG is handled below via outCond
10926     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10927     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10928     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10929
10930     /* caller's stack pointers must be restored */
10931     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10932     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10933     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10934     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10935     break;
10936
10937   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10938   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10939     /* pseudo read on (possible) return values */
10940     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10941     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10942     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10943     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10944
10945     /* caller's stack pointers must be restored */
10946     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10947     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10948     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10949     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10950     break;
10951     
10952   case POC_TBLRD:
10953     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10954     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10955     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10956     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10957     break;
10958     
10959   case POC_TBLRD_POSTINC:
10960   case POC_TBLRD_POSTDEC:
10961   case POC_TBLRD_PREINC:
10962     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10963     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10964     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10965     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10966     break;
10967     
10968   case POC_TBLWT:
10969     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10970     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10971     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10972     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10973     break;
10974     
10975   case POC_TBLWT_POSTINC:
10976   case POC_TBLWT_POSTDEC:
10977   case POC_TBLWT_PREINC:
10978     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10979     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10980     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10981     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10982     break;
10983     
10984   default:
10985     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10986     break;
10987   } // switch
10988
10989   /* handle explicit arguments */
10990   inCond = pci->inCond;
10991   outCond = pci->outCond;
10992   cond = inCond | outCond;
10993   if (cond & PCC_W) {
10994     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10995   } // if
10996
10997   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10998   if (inCond & PCC_STATUS) {
10999     smask = 0;
11000     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11001     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11002     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11003     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11004     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11005
11006     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11007     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11008   } // if
11009   
11010   if (outCond & PCC_STATUS) {
11011     smask = 0;
11012     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11013     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11014     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11015     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11016     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11017
11018     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11019     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11020   } // if
11021   
11022   isSpecial = isSpecial2 = 0;
11023   sym = sym2 = 0;
11024   if (cond & PCC_REGISTER) {
11025     name = pic16_get_op (pci->pcop, NULL, 0);
11026     sym = symFromStr (name);
11027     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11028     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11029   }
11030
11031   if (cond & PCC_REGISTER2) {
11032     name = pic16_get_op2 (pci->pcop, NULL, 0);
11033     sym2 = symFromStr (name);
11034     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11035     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11036   }
11037
11038  
11039   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11040   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11041
11042   mergeDefmapSymbols (list);
11043   
11044   return list;
11045 }
11046
11047 #if 0
11048 static void printDefmap (defmap_t *map) {
11049   defmap_t *curr;
11050
11051   curr = map;
11052   fprintf (stderr, "defmap @ %p:\n", curr);
11053   while (curr) {
11054     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11055                     curr->acc.access.isRead ? "R" : " ",
11056                     curr->acc.access.isWrite ? "W": " ",
11057                     curr->in_val, curr->val,
11058                     curr->acc.access.in_mask, curr->acc.access.mask,
11059                     strFromSym(curr->sym), curr->sym,
11060                     curr->pc);
11061     curr = curr->next;
11062   } // while
11063   fprintf (stderr, "<EOL>\n");
11064 }
11065 #endif
11066
11067 /* Add "additional" definitions to uniq.
11068  * 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.
11069  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11070  *
11071  * If symbols defined in additional are not present in uniq, a definition is created.
11072  * Otherwise the present definition is altered to reflect the newer assignments.
11073  *
11074  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11075  *       before     `------- noted in additional --------'      after
11076  *
11077  * I assume that each symbol occurs AT MOST ONCE in uniq.
11078  *
11079  */
11080 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11081   defmap_t *curr;
11082   defmap_t *old;
11083   int change = 0;
11084
11085   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11086   /* find tail of additional list (holds the first assignment) */
11087   curr = additional;
11088   while (curr && curr->next) curr = curr->next;
11089
11090   /* update uniq */
11091   do {
11092     /* find next assignment in additionals */
11093     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11094
11095     if (!curr) break;
11096
11097     /* find item in uniq */
11098     old = *uniq;
11099     //printDefmap (*uniq);
11100     while (old && (old->sym != curr->sym)) old = old->next;
11101
11102     if (old) {
11103       /* definition found -- replace */
11104       if (old->val != curr->val) {
11105         old->val = curr->val;
11106         change++;
11107       } // if
11108     } else {
11109       /* new definition */
11110       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11111       change++;
11112     }
11113
11114     curr = curr->prev;
11115   } while (1);
11116
11117   /* return 0 iff uniq remained unchanged */
11118   return change;
11119 }
11120
11121 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11122  * lists of its predecessor flows. 
11123  * Initially *combined should be NULL, alt_in will be copied to combined.
11124  * If *combined != NULL, combined will be altered:
11125  * - for symbols defined in *combined but not in alt_in,
11126  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11127  * - for symbols defined in alt_in but not in *combined,
11128  *   a 0 definition is created (value unknown, either INIT or alt).
11129  * - for symbols defined in both, *combined is:
11130  *   > left unchanged if *combined->val == alt_in->val or
11131  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11132  * 
11133  * I assume that each symbol occurs AT MOST ONCE in each list!
11134  */
11135 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11136   defmap_t *curr;
11137   defmap_t *old;
11138   int change = 0;
11139   valnum_t val;
11140
11141   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11142   
11143   if (!(*combined)) {
11144     return defmapUpdateUniqueSym (combined, alt_in);
11145   } // if
11146   
11147   /* merge the two */
11148   curr = alt_in;
11149   while (curr) {
11150     /* find symbols definition in *combined */
11151     old = *combined;
11152     while (old && (old->sym != curr->sym)) old = old->next;
11153
11154     if (old) {
11155       /* definition found */
11156       if (old->val && (old->val != curr->val)) {
11157         old->val = 0; /* value unknown */
11158         change++;
11159       }
11160     } else {
11161       /* no definition found -- can be either INIT or alt_in's value */
11162       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11163       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11164       if (val != curr->val) change++;
11165     }
11166
11167     curr = curr->next;
11168   } // while (curr)
11169
11170   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11171   old = *combined;
11172   while (old) {
11173     if (old->val != 0) {
11174       /* find definition in alt_in */
11175       curr = alt_in;
11176       while (curr && curr->sym != old->sym) curr = curr->next;
11177       if (!curr) {
11178         /* symbol defined in *combined only -- can be either INIT or *combined */
11179         val = pic16_pBlockAddInval (pb, old->sym)->val;
11180         if (old->val != val) {
11181           old->val = 0;
11182           change++;
11183         }
11184       } // if
11185     } // if
11186
11187     old = old->next;
11188   } // while
11189
11190   return change;
11191 }
11192
11193 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11194   defmap_t *curr1, *curr2;
11195   symbol_t sym;
11196   
11197   /* identical maps are equal */
11198   if (map1 == map2) return 0;
11199
11200   if (!map1) return -1;
11201   if (!map2) return 1;
11202
11203   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11204   
11205   /* check length */
11206   curr1 = map1;
11207   curr2 = map2;
11208   while (curr1 && curr2) {
11209     curr1 = curr1->next;
11210     curr2 = curr2->next;
11211   } // while
11212
11213   /* one of them longer? */
11214   if (curr1) return 1;
11215   if (curr2) return -1;
11216
11217   /* both lists are of equal length -- compare (in O(n^2)) */
11218   curr1 = map1;
11219   while (curr1) {
11220     sym = curr1->sym;
11221     curr2 = map2;
11222     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11223     if (!curr2) return 1; // symbol not found in curr2
11224     if (curr2->val != curr1->val) return 1; // values differ
11225
11226     /* compare next symbol */
11227     curr1 = curr1->next;
11228   } // while
11229
11230   /* no difference found */
11231   return 0;
11232 }
11233
11234
11235 /* Prepare a list of all reaching definitions per flow.
11236  * This is done using a forward dataflow analysis.
11237  */
11238 static void createReachingDefinitions (pBlock *pb) {
11239   defmap_t *out_vals, *in_vals;
11240   pCode *pc;
11241   pCodeFlow *pcfl;
11242   pCodeFlowLink *link;
11243   set *todo;
11244   set *blacklist;
11245
11246   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11247   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11248     if (isPCFL(pc)) {
11249       deleteDefmapChain (&PCFL(pc)->in_vals);
11250       deleteDefmapChain (&PCFL(pc)->out_vals);
11251       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11252     } // if
11253   } // for
11254   
11255   pc = pic16_findNextInstruction (pb->pcHead);
11256   todo = NULL; blacklist = NULL;
11257   addSetHead (&todo, PCI(pc)->pcflow);
11258
11259   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11260   while (elementsInSet (todo)) {
11261     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11262     pcfl = PCFL(indexSet (todo, 0));
11263     deleteSetItem (&todo, pcfl);
11264     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11265     in_vals = NULL;
11266     out_vals = NULL;
11267
11268     if (isinSet (blacklist, pcfl)) {
11269             fprintf (stderr, "ignoring blacklisted flow\n");
11270       continue;
11271     }
11272     
11273     /* create in_vals from predecessors out_vals */
11274     link = setFirstItem (pcfl->from);
11275     while (link) {
11276       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11277       link = setNextItem (pcfl->from);
11278     } // while
11279
11280     //printDefmap (in_vals); 
11281     //printDefmap (pcfl->in_vals); 
11282
11283     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11284       //fprintf (stderr, "in_vals changed\n");
11285       /* in_vals changed -- update out_vals */
11286       deleteDefmapChain (&pcfl->in_vals);
11287       pcfl->in_vals = in_vals;
11288
11289       /* create out_val from in_val and defmap */
11290       out_vals = NULL;
11291       defmapUpdateUniqueSym (&out_vals, in_vals);
11292       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11293
11294       /* is out_vals different from pcfl->out_vals */
11295       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11296         //fprintf (stderr, "out_vals changed\n");
11297         deleteDefmapChain (&pcfl->out_vals);
11298         pcfl->out_vals = out_vals;
11299
11300         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11301           addSet (&blacklist, pcfl);
11302         } // if
11303         
11304         /* reschedule all successors */
11305         link = setFirstItem (pcfl->to);
11306         while (link) {
11307           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11308           addSetIfnotP (&todo, link->pcflow);
11309           link = setNextItem (pcfl->to);
11310         } // while
11311       } else {
11312         deleteDefmapChain (&out_vals);        
11313       }// if
11314     } else {
11315       deleteDefmapChain (&in_vals);         
11316     } // if
11317   } // while
11318 }
11319
11320 #if 0
11321 static void showAllDefs (symbol_t sym, pCode *pc) {
11322   defmap_t *map;
11323   int count;
11324
11325   assert (isPCI(pc));
11326   count = defmapFindAll (sym, pc, &map);
11327
11328   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11329   while (map) {
11330 #if 1
11331     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11332 #else
11333     { char buf[256];
11334     pic16_pCode2str (buf, 256, map->pc);
11335     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11336 #endif
11337     map = map->next;
11338   }
11339   deleteDefmapChain (&map);
11340 }
11341 #endif
11342
11343 /* safepCodeUnlink and remove pc from defmap. */
11344 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11345   defmap_t *map, *next, **head;
11346   int res, ispci;
11347   
11348   ispci = isPCI(pc);
11349   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11350   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11351   res = pic16_safepCodeUnlink (pc, comment);
11352
11353   if (res && map) {
11354     /* remove pc from defmap */
11355     while (map) {
11356       next = map->next;
11357       if (map->pc == pc) {
11358         if (!map->prev && head) *head = map->next;
11359         deleteDefmap (map);
11360       } // if
11361       map = next;
11362     }
11363   }
11364
11365   return res;
11366 }
11367       
11368 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11369   defmap_t *map;
11370   /* This breaks the defmap chain's references to pCodes... fix it! */
11371   map = PCI(pc)->pcflow->defmap;
11372
11373   while (map && map->pc != pc) map = map->next;
11374   
11375   while (map && map->pc == pc) {
11376     map->pc = newpc;
11377     map = map->next;
11378   } // while
11379 }
11380
11381 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11382  * write accesses (isRead == 0). */
11383 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11384   defmap_t *map, *map_start;
11385   defmap_t *copy;
11386   if (!isPCI(pc)) return;
11387   if (sym == newsym) return;
11388   
11389   map = PCI(pc)->pcflow->defmap;
11390
11391   while (map && map->pc != pc) map = map->next;
11392   map_start = map;
11393   while (map && map->pc == pc) {
11394     if (map->sym == sym) {
11395       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11396       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11397         /* only one kind of access handled... this is easy */
11398         map->sym = newsym;
11399       } else {
11400         /* must copy defmap entry before replacing symbol... */
11401         copy = copyDefmap (map);
11402         if (isRead) {
11403           map->acc.access.isRead = 0;
11404           copy->acc.access.isWrite = 0;
11405         } else {
11406           map->acc.access.isWrite = 0;
11407           copy->acc.access.isRead = 0;
11408         }
11409         copy->sym = newsym;
11410         /* insert copy into defmap chain */
11411         defmapInsertAfter (map, copy);
11412       }
11413     }
11414     map = map->next;
11415   } // while
11416
11417   /* as this might introduce multiple defmap entries for newsym... */
11418   mergeDefmapSymbols (map_start);
11419 }
11420
11421 /* Assign "better" valnums to results. */
11422 static void assignValnums (pCode *pc) {
11423   pCodeInstruction *pci;
11424   pCode *newpc;
11425   symbol_t sym1, sym2;
11426   int cond, isSpecial1, isSpecial2, count, mask, lit;
11427   defmap_t *list, *val, *oldval, *dummy;
11428   regs *reg1 = NULL, *reg2 = NULL;
11429   valnum_t litnum;
11430
11431   /* only works for pCodeInstructions... */
11432   if (!isPCI(pc)) return;
11433
11434   pci = PCI(pc);
11435   cond = pci->inCond | pci->outCond;
11436   list = pci->pcflow->defmap;
11437   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11438
11439   if (cond & PCC_REGISTER) {
11440     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11441     reg1 = pic16_getRegFromInstruction (pc);
11442     isSpecial1 = pic16_symIsSpecial (sym1);
11443   }
11444   if (cond & PCC_REGISTER2) {
11445     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11446     reg2 = pic16_getRegFromInstruction (pc);
11447     isSpecial2 = pic16_symIsSpecial (sym2);
11448   }
11449
11450   /* determine input values */
11451   val = list;
11452   while (val && val->pc != pc) val = val->next;
11453   //list = val; /* might save some time later... */
11454   while (val && val->pc == pc) {
11455     val->in_val = 0;
11456     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11457       /* get valnum for sym */
11458       count = defmapFindAll (val->sym, pc, &oldval);
11459       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11460       if (count == 1) {
11461         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11462           val->in_val = oldval->val;
11463         } else {
11464           val->in_val = 0;
11465         }
11466       } else if (count == 0) {
11467         /* no definition found */
11468         val->in_val = 0;
11469       } else {
11470         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11471         assert (oldval);
11472         dummy = oldval->next;
11473         mask = oldval->acc.access.mask;
11474         val->in_val = oldval->val;
11475         while (dummy && (dummy->val == val->in_val)) {
11476           mask &= dummy->acc.access.mask;
11477           dummy = dummy->next;
11478         } // while
11479
11480         /* found other values or to restictive mask */
11481         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11482           val->in_val = 0;
11483         }
11484       }
11485       if (count > 0) deleteDefmapChain (&oldval);
11486     } // if
11487     val = val->next;
11488   }
11489
11490   /* handle valnum assignment */
11491   switch (pci->op) {
11492   case POC_CLRF: /* modifies STATUS (Z) */
11493     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11494       oldval = defmapCurr (list, sym1, pc);
11495       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11496         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11497         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11498       }
11499       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11500     }
11501     break;
11502
11503   case POC_SETF: /* SETF does not touch STATUS */
11504     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11505       oldval = defmapCurr (list, sym1, pc);
11506       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11507         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11508         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11509       }
11510       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11511     }
11512     break;
11513     
11514   case POC_MOVLW: /* does not touch STATUS */
11515     oldval = defmapCurr (list, SPO_WREG, pc);
11516     if (pci->pcop->type == PO_LITERAL) {
11517       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11518       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11519     } else {
11520       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11521       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11522     }
11523     if (oldval && oldval->in_val == litnum) {
11524       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11525       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11526     }
11527     defmapUpdate (list, SPO_WREG, pc, litnum);
11528     break;
11529
11530   case POC_ANDLW: /* modifies STATUS (Z,N) */
11531   case POC_IORLW: /* modifies STATUS (Z,N) */
11532   case POC_XORLW: /* modifies STATUS (Z,N) */
11533     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11534     if (pci->pcop->type == PO_LITERAL) {
11535       int vallit = -1;
11536       lit = (unsigned char) PCOL(pci->pcop)->lit;
11537       val = defmapCurr (list, SPO_WREG, pc);
11538       if (val) vallit = litFromValnum (val->in_val);
11539       if (vallit != -1) {
11540         /* xxxLW <literal>, WREG contains a known literal */
11541         fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11542         if (pci->op == POC_ANDLW) {
11543           lit &= vallit;
11544         } else if (pci->op == POC_IORLW) {
11545           lit |= vallit;
11546         } else if (pci->op == POC_XORLW) {
11547           lit ^= vallit;
11548         } else {
11549           assert (0 && "invalid operation");
11550         }
11551         if (vallit == lit) {
11552           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11553           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11554         }
11555         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11556       } // if
11557     }
11558     break;
11559
11560   case POC_LFSR:
11561     {
11562       /* check if old value matches new value */
11563       int lit;
11564       int ok = 1;
11565       assert (pci->pcop->type == PO_LITERAL);
11566       
11567       lit = PCOL(pci->pcop)->lit;
11568       
11569       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11570       
11571       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11572         fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11573       } else {
11574         /* cannot remove this LFSR */
11575         ok = 0;      
11576       } // if
11577       
11578       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11579       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11580         fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11581       } else {
11582         ok = 0;
11583       } // if
11584
11585       if (ok) {
11586         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11587       }
11588     }
11589     break;
11590     
11591   case POC_MOVWF: /* does not touch flags */
11592     /* find value of WREG */
11593     val = defmapCurr (list, SPO_WREG, pc);
11594     oldval = defmapCurr (list, sym1, pc);
11595     if (val) lit = litFromValnum (val->in_val);
11596     else lit = -1;
11597     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11598     
11599     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11600       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11601       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11602       if (lit == 0) {
11603         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11604       } else {
11605         assert (lit == 0x0ff);
11606         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11607       }
11608       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11609       pic16_pCodeReplace (pc, newpc);
11610       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11611       pic16_fixDefmap (pc, newpc);
11612       pc = newpc;
11613         
11614       /* This breaks the defmap chain's references to pCodes... fix it! */
11615       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11616       if (!val->acc.access.isWrite) {
11617         deleteDefmap (val);     // delete reference to WREG as in value
11618         val = NULL;
11619       } else {
11620         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11621       }
11622       oldval = PCI(pc)->pcflow->defmap;
11623       while (oldval) {
11624         if (oldval->pc == pc) oldval->pc = newpc;
11625           oldval = oldval->next;
11626       } // while
11627     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11628       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11629       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11630     }
11631     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11632     break;
11633     
11634   case POC_MOVFW: /* modifies STATUS (Z,N) */
11635     /* find value of REG */
11636     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11637       val = defmapCurr (list, sym1, pc);
11638       oldval = defmapCurr (list, SPO_WREG, pc);
11639       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11640         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11641         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11642       }
11643       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11644     }
11645     break;
11646
11647   case POC_MOVFF: /* does not touch STATUS */
11648     /* find value of REG */
11649     val = defmapCurr (list, sym1, pc);
11650     oldval = defmapCurr (list, sym2, pc);
11651     if (val) lit = litFromValnum (val->in_val);
11652     else lit = -1;
11653     newpc = NULL;
11654     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11655       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11656       if (lit == 0) {
11657         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11658       } else if (lit == 0x00ff) {
11659         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11660       } else {
11661         newpc = NULL;
11662       }
11663       if (newpc) {
11664         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11665         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11666         pic16_pCodeReplace (pc, newpc); 
11667         defmapReplaceSymRef (pc, sym1, 0, 1);
11668         pic16_fixDefmap (pc, newpc);
11669         pc = newpc;
11670         break; // do not process instruction as MOVFF...
11671       }
11672     } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11673       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11674         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11675         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11676       } else {
11677         if (!pic16_isAlive (sym1, pc)) {
11678           defmap_t *copy = NULL;
11679           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11680            * This should help eliminate
11681            *   MOVFF A,B
11682            *   <do something not changing A or using B>
11683            *   MOVFF B,C
11684            *   <B is not alive anymore>
11685            * and turn it into
11686            *   <do something not changing A or using B>
11687            *   MOVFF A,C
11688            */
11689
11690           /* scan defmap for symbols storing sym1's value */
11691           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11692           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11693             /* unique reaching definition for sym found */
11694             if (copy->val && copy->val == val->in_val) {
11695               //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);
11696               if (copy->sym == SPO_WREG) {
11697                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11698               } else {
11699                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11700 //                      /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11701                         pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11702                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11703               }
11704               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11705               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11706               pic16_pCodeReplace (pc, newpc); 
11707               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11708               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11709               pic16_fixDefmap (pc, newpc);
11710               pc = newpc;
11711             }
11712           }
11713           deleteDefmapChain (&copy);
11714         }
11715       }
11716       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11717     }
11718     break;
11719
11720   default:
11721     /* cannot optimize */
11722     break;
11723   } // switch
11724 }
11725
11726 static void pic16_destructDF (pBlock *pb) {
11727   pCode *pc, *next;
11728
11729   /* remove old defmaps */
11730   pc = pic16_findNextInstruction (pb->pcHead);
11731   while (pc) {
11732     next = pic16_findNextInstruction (pc->next);
11733
11734     assert (isPCI(pc) || isPCAD(pc));
11735     assert (PCI(pc)->pcflow);
11736     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11737     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11738     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11739     
11740     pc = next;
11741   } // while
11742   
11743   if (defmap_free || defmap_free_count) {
11744     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11745     freeDefmap (&defmap_free);
11746     defmap_free_count = 0;
11747   }
11748 }
11749
11750 /* Checks whether a pBlock contains ASMDIRs. */
11751 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11752   pCode *pc;
11753
11754   pc = pic16_findNextInstruction (pb->pcHead);
11755   while (pc) {
11756     if (isPCAD(pc)) return 1;
11757
11758     pc = pic16_findNextInstruction (pc->next);
11759   } // while
11760
11761   /* no PCADs found */
11762   return 0;
11763 }
11764
11765 #if 1
11766 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11767 static int pic16_removeUnusedRegistersDF () {
11768   pCode *pc, *pc2;
11769   pBlock *pb;
11770   regs *reg1, *reg2, *reg3;
11771   set *seenRegs = NULL;
11772   int cond, i;
11773   int islocal, change = 0;
11774
11775   /* no pBlocks? */
11776   if (!the_pFile || !the_pFile->pbHead) return 0;
11777   
11778   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11779     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11780 #if 1
11781     /* find set of using pCodes per register */
11782     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11783                     pc = pic16_findNextInstruction(pc->next)) {
11784
11785       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11786       reg1 = reg2 = NULL;
11787       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11788       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11789
11790       if (reg1) {
11791         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11792         addSetIfnotP (&seenRegs, reg1);
11793         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11794       }
11795       if (reg2) {
11796         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11797         addSetIfnotP (&seenRegs, reg2);
11798         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11799       }
11800     } // for pc
11801 #endif
11802     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11803       /* may not use pic16_regIsLocal() here -- in interrupt routines
11804        * WREG, PRODx, FSR0x must be saved */
11805       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11806       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11807         pc = pc2 = NULL;
11808         for (i=0; i < 2; i++) {
11809           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11810           if (!pc2) pc2 = pc;
11811           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11812           reg2 = pic16_getRegFromInstruction (pc);
11813           reg3 = pic16_getRegFromInstruction2 (pc);
11814           if (!reg2 || !reg3
11815               || (reg2->rIdx != pic16_stack_preinc->rIdx
11816                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11817           if (i == 1) {
11818             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11819             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11820             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11821             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11822           }
11823         } // for
11824       } // if
11825       deleteSet (&reg1->reglives.usedpCodes);
11826     } // for reg1
11827
11828     deleteSet (&seenRegs);
11829   } // for pb
11830
11831   return change;
11832 }
11833 #endif
11834
11835 /* Set up pCodeFlow's defmap_ts. 
11836  * Needs correctly set up to/from fields. */
11837 static void pic16_createDF (pBlock *pb) {
11838   pCode *pc, *next;
11839   int change=0;
11840
11841   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11842
11843   pic16_destructDF (pb);
11844
11845   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11846   if (pic16_pBlockHasAsmdirs (pb)) {
11847     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11848     return;
11849   }
11850
11851   /* integrity check -- we need to reach all flows to guarantee
11852    * correct data flow analysis (reaching definitions, aliveness) */
11853 #if 0
11854   if (!verifyAllFlowsReachable (pb)) {
11855     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11856     return;
11857   }
11858 #endif
11859   
11860   /* establish new defmaps */
11861   pc = pic16_findNextInstruction (pb->pcHead);
11862   while (pc) {
11863     next = pic16_findNextInstruction (pc->next);
11864
11865     assert (PCI(pc)->pcflow);
11866     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11867
11868     pc = next;
11869   } // while
11870
11871   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11872   createReachingDefinitions (pb);
11873   
11874 #if 1
11875   /* assign better valnums */
11876   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11877   pc = pic16_findNextInstruction (pb->pcHead);
11878   while (pc) {
11879     next = pic16_findNextInstruction (pc->next);
11880
11881     assert (PCI(pc)->pcflow);
11882     assignValnums (pc);
11883
11884     pc = next;
11885   } // while
11886 #endif
11887
11888 #if 1
11889   /* remove dead pCodes */
11890   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11891   do {
11892     change = 0;
11893     pc = pic16_findNextInstruction (pb->pcHead);
11894     while (pc) {
11895       next = pic16_findNextInstruction (pc->next);
11896
11897       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11898         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11899       }
11900
11901       pc = next;
11902     } // while
11903   } while (change);
11904 #endif
11905 }
11906
11907
11908 /* ======================================================================= */
11909 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11910 /* ======================================================================= */
11911
11912 #if 0
11913
11914 /* connect pCode f anf t via their to/from pBranches */
11915 static void pic16_pCodeLink (pCode *f, pCode *t) {
11916   pBranch *br;
11917   pCodeInstruction *_f, *_t;
11918
11919   if (!f || !t) return;
11920
11921 #if 0
11922   fprintf (stderr, "linking:\n");
11923   f->print(stderr, f);
11924   f->print(stderr, t);
11925 #endif
11926
11927   assert (isPCI(f) || isPCAD(f));
11928   assert (isPCI(t) || isPCAD(t));
11929   _f = PCI(f);
11930   _t = PCI(t);
11931   
11932   /* define t to be CF successor of f */
11933   br = Safe_malloc (sizeof (pBranch));
11934   br->pc = t;
11935   br->next = NULL;
11936   _f->to = pic16_pBranchAppend (_f->to, br);
11937
11938   /* define f to be CF predecessor of t */
11939   br = Safe_malloc (sizeof (pBranch));
11940   br->pc = f;
11941   br->next = NULL;
11942   _t->from = pic16_pBranchAppend (_t->from, br);
11943
11944   /* also update pcflow information */
11945   if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11946     //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11947     LinkFlow_pCode (_f, _t);
11948   } // if
11949 }
11950
11951 static void pic16_destructCF (pBlock *pb) {
11952   pCode *pc;
11953   pBranch *br;
11954
11955   /* remove old CF information */
11956   pc = pb->pcHead;
11957   while (pc) {
11958     if (isPCI(pc)) {
11959       while (PCI(pc)->to) {
11960         br = PCI(pc)->to->next;
11961         Safe_free (PCI(pc)->to);
11962         PCI(pc)->to = br;
11963       } // while
11964       while (PCI(pc)->from) {
11965         br = PCI(pc)->from->next;
11966         Safe_free (PCI(pc)->from);
11967         PCI(pc)->from = br;
11968       }
11969     } else if (isPCFL(pc)) {
11970       deleteSet (&PCFL(pc)->to);
11971       deleteSet (&PCFL(pc)->from);
11972     }
11973     pc = pc->next;
11974   }
11975   
11976   releaseStack ();
11977 }
11978
11979 /* Set up pCodeInstruction's to and from pBranches. */
11980 static void pic16_createCF (pBlock *pb) {
11981   pCode *pc;
11982   pCode *next, *dest;
11983   char *label;
11984
11985   //fprintf (stderr, "creating CF for %p\n", pb);
11986
11987   pic16_destructCF (pb);
11988
11989   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11990   if (pic16_pBlockHasAsmdirs (pb)) {
11991     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11992     return;
11993   }
11994
11995   pc = pic16_findNextInstruction(pb->pcHead);
11996   while (pc) {
11997     next = pic16_findNextInstruction(pc->next);
11998     if (isPCI_SKIP(pc)) {
11999       pic16_pCodeLink(pc, next);
12000       pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
12001     } else if (isPCI_BRANCH(pc)) {
12002       // Bcc, BRA, CALL, GOTO
12003       if (PCI(pc)->pcop) {
12004         switch (PCI(pc)->pcop->type) {
12005         case PO_LABEL:
12006           label = PCOLAB(PCI(pc)->pcop)->pcop.name;
12007           dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
12008           break;
12009         
12010         case PO_STR:
12011           /* needed for GOTO ___irq_handler */
12012           label = PCI(pc)->pcop->name;
12013           dest = NULL;
12014           break;
12015
12016         default:
12017           assert (0 && "invalid label format");
12018           break;
12019         } // switch
12020       } else {
12021         label = "NO PCOP";
12022         dest = NULL;
12023       }
12024
12025       switch (PCI(pc)->op) {
12026       case POC_BRA:
12027       case POC_GOTO:
12028         if (dest != NULL) { 
12029           pic16_pCodeLink(pc, dest);
12030         } else {
12031           //fprintf (stderr, "jump target \"%s\" not found!\n", label);
12032         }
12033         break;
12034       case POC_CALL:
12035       case POC_RETURN:
12036       case POC_RETFIE:
12037         pic16_pCodeLink(pc, next);
12038         break;
12039       case POC_BC:
12040       case POC_BNC:
12041       case POC_BZ:
12042       case POC_BNZ:
12043       case POC_BN:
12044       case POC_BNN:
12045       case POC_BOV:
12046       case POC_BNOV:
12047         if (dest != NULL) { 
12048           pic16_pCodeLink(pc, dest);
12049         } else {
12050           //fprintf (stderr, "jump target \"%s\"not found!\n", label);
12051         }
12052         pic16_pCodeLink(pc, next);
12053         break;
12054       default:
12055         fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
12056         assert (0 && "unhandled branch instruction");
12057         break;
12058       } // switch
12059     } else {
12060       pic16_pCodeLink (pc, next);
12061     }
12062     pc = next;
12063   } // while
12064 }
12065 #endif
12066
12067 /* ======================================================================== */
12068 /* === VCG DUMPER ROUTINES ================================================ */
12069 /* ======================================================================== */
12070 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12071 hTab *dumpedNodes = NULL;
12072
12073 /** Dump VCG header into of. */
12074 static void pic16_vcg_init (FILE *of) {
12075   /* graph defaults */
12076   fprintf (of, "graph:{\n");
12077   fprintf (of, "title:\"graph1\"\n");
12078   fprintf (of, "label:\"graph1\"\n");
12079   fprintf (of, "color:white\n");
12080   fprintf (of, "textcolor:black\n");
12081   fprintf (of, "bordercolor:black\n");
12082   fprintf (of, "borderwidth:1\n");
12083   fprintf (of, "textmode:center\n");
12084
12085   fprintf (of, "layoutalgorithm:dfs\n");
12086   fprintf (of, "late_edge_labels:yes\n");
12087   fprintf (of, "display_edge_labels:yes\n");
12088   fprintf (of, "dirty_edge_labels:yes\n");
12089   fprintf (of, "finetuning:yes\n");
12090   fprintf (of, "ignoresingles:no\n");
12091   fprintf (of, "straight_phase:yes\n");
12092   fprintf (of, "priority_phase:yes\n");
12093   fprintf (of, "manhattan_edges:yes\n");
12094   fprintf (of, "smanhattan_edges:no\n");
12095   fprintf (of, "nearedges:no\n");
12096   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12097   fprintf (of, "port_sharing:no\n");
12098   fprintf (of, "arrowmode:free\n"); // fixed|free
12099   fprintf (of, "crossingphase2:yes\n");
12100   fprintf (of, "crossingoptimization:yes\n");
12101   fprintf (of, "edges:yes\n");
12102   fprintf (of, "nodes:yes\n");
12103   fprintf (of, "splines:no\n");
12104   
12105   /* node defaults */
12106   fprintf (of, "node.color:lightyellow\n");
12107   fprintf (of, "node.textcolor:black\n");
12108   fprintf (of, "node.textmode:center\n");
12109   fprintf (of, "node.shape:box\n");
12110   fprintf (of, "node.bordercolor:black\n");
12111   fprintf (of, "node.borderwidth:1\n");
12112
12113   /* edge defaults */
12114   fprintf (of, "edge.textcolor:black\n");
12115   fprintf (of, "edge.color:black\n");
12116   fprintf (of, "edge.thickness:1\n");
12117   fprintf (of, "edge.arrowcolor:black\n");
12118   fprintf (of, "edge.backarrowcolor:black\n");
12119   fprintf (of, "edge.arrowsize:15\n");
12120   fprintf (of, "edge.backarrowsize:15\n");
12121   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12122   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12123   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12124   
12125   fprintf (of, "\n");
12126
12127   /* prepare data structures */
12128   if (dumpedNodes) {
12129     hTabDeleteAll (dumpedNodes);
12130     dumpedNodes = NULL;
12131   }
12132   dumpedNodes = newHashTable (128);
12133 }
12134
12135 /** Dump VCG footer into of. */
12136 static void pic16_vcg_close (FILE *of) {
12137   fprintf (of, "}\n");
12138 }
12139
12140 #define BUF_SIZE 128
12141 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12142
12143 #if 0
12144 static int ptrcmp (const void *p1, const void *p2) {
12145   return p1 == p2;
12146 }
12147 #endif
12148
12149 /** Dump a pCode node as VCG to of. */
12150 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12151   char buf[BUF_SIZE];
12152
12153   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12154     // dumped already
12155     return;
12156   }
12157   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12158   //fprintf (stderr, "dumping %p\n", pc);
12159  
12160   /* only dump pCodeInstructions and Flow nodes */
12161   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12162     
12163   /* emit node */
12164   fprintf (of, "node:{");
12165   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12166   fprintf (of, "label:\"%s\n", pcTitle(pc));
12167   if (isPCFL(pc)) {
12168     fprintf (of, "<PCFLOW>");
12169   } else if (isPCI(pc) || isPCAD(pc)) {
12170     pc->print (of, pc);
12171   } else {
12172     fprintf (of, "<!PCI>");
12173   }
12174   fprintf (of, "\" ");
12175   fprintf (of, "}\n");
12176   
12177   if (1 && isPCFL(pc)) {
12178     defmap_t *map, *prev;
12179     unsigned int i;
12180     map = PCFL(pc)->defmap;
12181     i=0;
12182     while (map) {
12183       if (map->sym != 0) {
12184         i++;
12185       
12186         /* emit definition node */
12187         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12188         fprintf (of, "label:\"");
12189
12190         prev = map;
12191         do {
12192           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));
12193           prev = map;
12194           map = map->next;
12195         } while (map && prev->pc == map->pc);
12196         map = prev;
12197         
12198         fprintf (of, "\" ");
12199       
12200         fprintf (of, "color:green ");
12201         fprintf (of, "}\n");
12202
12203         /* emit edge to previous definition */
12204         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12205         if (i == 1) {
12206           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12207         } else {
12208           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12209         }
12210         fprintf (of, "color:green ");
12211         fprintf (of, "}\n");
12212
12213         if (map->pc) {
12214           pic16_vcg_dumpnode (map->pc, of);
12215           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12216           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12217         }
12218       }
12219       map = map->next;
12220     } // while
12221   }
12222
12223   /* emit additional nodes (e.g. operands) */
12224 }
12225
12226 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12227 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12228   char buf[BUF_SIZE];
12229   pCodeInstruction *pci;
12230   pBranch *curr;
12231   int i;
12232   
12233   if (1 && isPCFL(pc)) {
12234     /* emit edges to flow successors */
12235     void *pcfl;
12236     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12237     pcfl = setFirstItem (PCFL(pc)->to);
12238     while (pcfl) {
12239       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12240       pic16_vcg_dumpnode (pc, of);
12241       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12242       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12243       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12244       pcfl = setNextItem (PCFL(pc)->to);
12245     } // while
12246   } // if
12247   
12248   if (!isPCI(pc) && !isPCAD(pc)) return;
12249
12250   pci = PCI(pc);
12251   
12252   /* emit control flow edges (forward only) */
12253   curr = pci->to;
12254   i=0;
12255   while (curr) {
12256     pic16_vcg_dumpnode (curr->pc, of);
12257     fprintf (of, "edge:{");
12258     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12259     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12260     fprintf (of, "color:red ");
12261     fprintf (of, "}\n");
12262     curr = curr->next;
12263   } // while
12264
12265 #if 1
12266   /* dump "flow" edge (link pCode according to pBlock order) */
12267   {
12268     pCode *pcnext;
12269     pcnext = pic16_findNextInstruction (pc->next);
12270     if (pcnext) {
12271       pic16_vcg_dumpnode (pcnext, of);
12272       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12273       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12274     }
12275   }
12276 #endif
12277   
12278 #if 0
12279   /* emit flow */
12280   if (pci->pcflow) {
12281     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12282     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12283     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12284   }
12285 #endif
12286   
12287   /* emit data flow edges (backward only) */
12288   /* TODO: gather data flow information... */
12289 }
12290
12291 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12292   pCode *pc;
12293
12294   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12295   if (pic16_pBlockHasAsmdirs (pb)) {
12296     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12297     return;
12298   }
12299
12300   for (pc=pb->pcHead; pc; pc = pc->next) {
12301     pic16_vcg_dumpnode (pc, of);
12302   } // for pc
12303   
12304   for (pc=pb->pcHead; pc; pc = pc->next) {
12305     pic16_vcg_dumpedges (pc, of);
12306   } // for pc
12307 }
12308
12309 static void pic16_vcg_dump_default (pBlock *pb) {
12310   FILE *of;
12311   char buf[BUF_SIZE];
12312   pCode *pc;
12313
12314   /* get function name */
12315   pc = pb->pcHead;
12316   while (pc && !isPCF(pc)) pc = pc->next;
12317   if (pc) {
12318     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12319   } else {
12320     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12321   }
12322
12323   //fprintf (stderr, "now dumping %s\n", buf);
12324   of = fopen (buf, "w");
12325   pic16_vcg_init (of);
12326   pic16_vcg_dump (of, pb);
12327   pic16_vcg_close (of);
12328   fclose (of);
12329 }
12330 #endif
12331
12332 /*** END of helpers for pCode dataflow optimizations ***/