* device/include/stdarg.h: changed SDCC specific keywords to double
[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[50];
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   };
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->access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9670   map->access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9671   map->access.isRead = (isRead != 0);
9672   map->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 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9693  * item is copied before insertion into chain and therefore left untouched.
9694  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9695 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9696   defmap_t *dummy;
9697   dummy = *head;
9698   while (dummy && (dummy->sym != item->sym
9699                           || dummy->pc != item->pc
9700                           || dummy->accessmethod != item->accessmethod
9701                           || dummy->val != item->val
9702                           || dummy->in_val != item->in_val)) {
9703     dummy = dummy->next;
9704   } // while
9705
9706   /* item already present? */
9707   if (dummy) return 0;
9708   
9709   /* otherwise: insert copy of item */
9710   dummy = copyDefmap (item);
9711   dummy->next = *head;
9712   if (*head) (*head)->prev = dummy;
9713   *head = dummy;
9714
9715   return 1;
9716 }
9717
9718 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9719 static void deleteDefmap (defmap_t *map) {
9720   if (!map) return;
9721   
9722   /* unlink from chain -- fails for the first item (head is not updated!) */
9723   if (map->next) map->next->prev = map->prev;
9724   if (map->prev) map->prev->next = map->next;
9725
9726   /* clear map */
9727   memset (map, 0, sizeof (defmap_t));
9728
9729   /* save for future use */
9730   map->next = defmap_free;
9731   defmap_free = map;
9732   ++defmap_free_count;
9733 }
9734
9735 /* Release all defmaps referenced from map. */
9736 static void deleteDefmapChain (defmap_t **_map) {
9737   defmap_t *map, *next;
9738
9739   if (!_map) return;
9740
9741   map = *_map;
9742   
9743   /* find list head */
9744   while (map && map->prev) map = map->prev;
9745
9746   /* delete all items */
9747   while (map) {
9748     next = map->next;
9749     deleteDefmap (map);
9750     map = next;
9751   } // while
9752
9753   *_map = NULL;
9754 }
9755
9756 /* Free all defmap items. */
9757 static void freeDefmap (defmap_t **_map) {
9758   defmap_t *next;
9759   defmap_t *map;
9760
9761   if (!_map) return;
9762
9763   map = (*_map);
9764   
9765   /* find list head */
9766   while (map->prev) map = map->prev;
9767
9768   /* release all items */
9769   while (map) {
9770     next = map->next;
9771     Safe_free (map);
9772     map = next;
9773   }
9774
9775   (*_map) = NULL;
9776 }
9777
9778 /* Returns the most recent definition for the given symbol preceeding pc.
9779  * If no definition is found, NULL is returned. 
9780  * If pc == NULL the whole list is scanned. */
9781 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9782   defmap_t *curr = map;
9783
9784   if (pc) {
9785     /* skip all definitions up to pc */
9786     while (curr && (curr->pc != pc)) curr = curr->next;
9787
9788     /* pc not in the list -- scan the whole list for definitions */
9789     if (!curr) {
9790       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9791       curr = map;
9792     } else {
9793       /* skip all definitions performed by pc */
9794       while (curr && (curr->pc == pc)) curr = curr->next;
9795     }
9796   } // if (pc)
9797
9798   /* find definition for sym */
9799   while (curr && (!curr->access.isWrite || (curr->sym != sym))) {
9800     curr = curr->next;
9801   }
9802
9803   return curr;
9804 }
9805
9806 #if 0
9807 /* Returns the first use (read) of the given symbol AFTER pc.
9808  * If no such use is found, NULL is returned.
9809  * If pc == NULL the whole list is scanned. */
9810 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9811   defmap_t *curr = map, *prev = NULL;
9812   
9813   if (pc) {
9814     /* skip all definitions up to pc */
9815     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9816
9817     /* pc not in the list -- scan the whole list for definitions */
9818     if (!curr) {
9819       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9820       curr = prev;
9821     }
9822   } else {
9823     /* find end of list */
9824     while (curr && curr->next) curr = curr->next;
9825   } // if (pc)
9826
9827   /* find use of sym (scan list backwards) */
9828   while (curr && (!curr->access.isRead || (curr->sym != sym))) curr = curr->prev;
9829
9830   return curr;
9831 }
9832 #endif
9833
9834 /* Return the defmap entry for sym AT pc. 
9835  * If none is found, NULL is returned.
9836  * If more than one entry is found an assertion is triggered. */
9837 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9838   defmap_t *res = NULL;
9839
9840   /* find entries for pc */
9841   while (map && map->pc != pc) map = map->next;
9842
9843   /* find first entry for sym @ pc */
9844   while (map && map->pc == pc && map->sym != sym) map = map->next;
9845
9846   /* no entry found */
9847   if (!map) return NULL;
9848
9849   /* check for more entries */
9850   res = map;
9851   map = map->next;
9852   while (map && map->pc == pc) {
9853     /* more than one entry for sym @ pc found? */
9854     assert (map->sym != sym);
9855     map = map->next;
9856   }
9857
9858   /* return single entry for sym @ pc */
9859   return res;
9860 }
9861
9862 /* Modifies the definition of sym at pCode to newval.
9863  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9864  */
9865 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9866   defmap_t *m  = map;
9867
9868   /* find definitions of pc */
9869   while (m && m->pc != pc) m = m->next;
9870
9871   /* find definition of sym at pc */
9872   while (m && m->pc == pc && (!m->access.isWrite || (m->sym != sym))) m = m->next;
9873   
9874   /* no definition found */
9875   if (!m) return 1;
9876
9877   /* redefine */
9878   m->val = newval;
9879
9880   /* update following uses of sym */
9881   while (m && m->pc == pc) m = m->prev;
9882   while (m) {
9883     if (m->sym == sym) {
9884       m->in_val = newval;
9885       if (m->access.isWrite) m = NULL;
9886     } // if
9887     if (m) m = m->prev;
9888   } // while
9889   
9890   return 0;
9891 }
9892
9893 /* ======================================================================== */
9894 /* === STACK ROUTINES ===================================================== */
9895 /* ======================================================================== */
9896
9897 typedef struct stack_s {
9898   void *data;
9899   struct stack_s *next;
9900 } stackitem_t;
9901
9902 typedef stackitem_t *stack_t;
9903 static stackitem_t *free_stackitems = NULL;
9904
9905 /* Create a stack with one item. */
9906 static stack_t *newStack () {
9907   stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9908   *s = NULL;
9909   return s;
9910 }
9911
9912 /* Remove a stack -- its items are only marked free. */
9913 static void deleteStack (stack_t *s) {
9914   stackitem_t *i;
9915
9916   while (*s) {
9917     i = *s;
9918     *s = (*s)->next;
9919     i->next = free_stackitems;
9920     free_stackitems = i;
9921   } // while
9922   Safe_free (s);
9923 }
9924
9925 /* Release all stackitems. */
9926 static void releaseStack () {
9927   stackitem_t *i;
9928   
9929   while (free_stackitems) {
9930     i = free_stackitems->next;
9931     Safe_free(free_stackitems);
9932     free_stackitems = i;
9933   } // while
9934 }
9935
9936 static void stackPush (stack_t *stack, void *data) {
9937   stackitem_t *i;
9938   
9939   if (free_stackitems) {
9940     i = free_stackitems;
9941     free_stackitems = free_stackitems->next;
9942   } else {
9943     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9944   }
9945   i->data = data;
9946   i->next = *stack;
9947   *stack = i;
9948 }
9949
9950 static void *stackPop (stack_t *stack) {
9951   void *data;
9952   stackitem_t *i;
9953   
9954   if (stack && *stack) {
9955     data = (*stack)->data;
9956     i = *stack;
9957     *stack = (*stack)->next;
9958     i->next = free_stackitems;
9959     free_stackitems = i;
9960     return data;
9961   } else {
9962     return NULL;
9963   }
9964 }
9965
9966 #if 0
9967 static int stackContains (stack_t *s, void *data) {
9968   stackitem_t *i;
9969   if (!s) return 0;
9970   i = *s;
9971   while (i) {
9972     if (i->data == data) return 1;
9973     i = i->next;
9974   } // while
9975
9976   /* not found */
9977   return 0;
9978 }
9979 #endif
9980
9981 static int stackIsEmpty (stack_t *s) {
9982   return (*s == NULL);
9983 }
9984
9985
9986 typedef struct {
9987   pCodeFlow *flow;
9988   defmap_t *lastdef;
9989 } state_t;
9990
9991 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9992   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9993   s->flow = flow;
9994   s->lastdef = lastdef;
9995   return s;
9996 }
9997
9998 static void deleteState (state_t *s) {
9999   Safe_free (s);
10000 }
10001
10002 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
10003   stackitem_t *i;
10004
10005   /* scan working list for state */
10006   if (todo) {
10007     i = *todo;
10008     while (i) {
10009       /* is i == state? -- state not new */
10010       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10011       i = i->next;
10012     } // while
10013   }
10014
10015   if (done) {
10016     i = *done;
10017     while (i) {
10018       /* is i == state? -- state not new */
10019       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10020       i = i->next;
10021     } // while
10022   }
10023
10024   /* not found -- state is new */
10025   return 1;
10026 }
10027
10028 static inline valnum_t newValnum ();
10029
10030 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10031   pCode *pc;
10032
10033   if (!pb) return "<unknown function>";
10034
10035   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10036   if (pc && isPCF(pc)) return PCF(pc)->fname;
10037   else return "<unknown function>";
10038 }
10039
10040 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10041   defmap_t *map;
10042   pCodeFlow *pcfl;
10043
10044   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10045
10046   /* find initial value (assigning pc == NULL) */
10047   map = PCFL(pcfl)->in_vals;
10048   while (map && map->sym != sym) map = map->next;
10049
10050   /* initial value already present? */
10051   if (map) {
10052     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10053     return map;
10054   }
10055
10056   /* create a new initial value */
10057   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10058   PCFL(pcfl)->in_vals = map;
10059   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10060   return map;
10061
10062 #if 0
10063   /* insert map as last item in pcfl's defmap */
10064   if (!prev) prev = PCFL(pcfl)->defmap;
10065   if (!prev) {
10066     PCFL(pcfl)->defmap = map;
10067   } else {
10068     while (prev->next) prev = prev->next;
10069     prev->next = map;
10070     map->prev = prev;
10071   }
10072
10073   return map;
10074 #endif
10075 }
10076
10077 /* Find all reaching definitions for sym at pc. 
10078  * A new (!) list of definitions is returned.
10079  * Returns the number of reaching definitions found.
10080  * The defining defmap entries are returned in *chain.
10081  */
10082 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10083   defmap_t *map;
10084   defmap_t *res;
10085
10086   pCodeFlow *curr;
10087   pCodeFlowLink *succ;
10088   state_t *state;
10089   stack_t *todo;        /** stack of state_t */
10090   stack_t *done;        /** stack of state_t */
10091
10092   int firstState, n_defs;
10093   
10094   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10095   assert (chain);
10096
10097   /* initialize return list */
10098   *chain = NULL;
10099
10100   /* wildcard symbol? */
10101   if (!sym) return 0;
10102   
10103   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10104   
10105   map = PCI(pc)->pcflow->defmap;
10106
10107   res = defmapFindDef (map, sym, pc);
10108   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10109
10110 #define USE_PRECALCED_INVALS 1
10111 #if USE_PRECALCED_INVALS
10112   if (!res && PCI(pc)->pcflow->in_vals) {
10113     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10114     if (res) {
10115       //fprintf  (stderr, "found def in init values\n");
10116       df_findall_in_vals++;
10117     }
10118   }
10119 #endif
10120
10121   if (res) {
10122     // found a single definition (in pc's flow)
10123     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10124     defmapAddCopyIfNew (chain, res);
10125     df_findall_sameflow++;
10126     return 1;
10127   }
10128
10129 #if USE_PRECALCED_INVALS
10130   else {
10131     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10132     return 1;
10133   }
10134
10135 #endif
10136   
10137 #define FORWARD_FLOW_ANALYSIS 1
10138 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10139   /* no definition found in pc's flow preceeding pc */
10140   todo = newStack ();
10141   done = newStack ();
10142   n_defs = 0; firstState = 1;
10143   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10144
10145   while (!stackIsEmpty (todo)) {
10146     state = (state_t *) stackPop (todo);
10147     stackPush (done, state);
10148     curr = state->flow;
10149     res = state->lastdef;
10150     //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);
10151
10152     /* there are no definitions BEFORE pc in pc's flow (see above) */
10153     if (curr == PCI(pc)->pcflow) {
10154       if (!res) {
10155         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10156         res = pic16_pBlockAddInval (pc->pb, sym);
10157         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10158         res = NULL;
10159       } else {
10160         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10161         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10162       }
10163     }
10164
10165     /* save last definition of sym in this flow as initial def in successors */
10166     res = defmapFindDef (curr->defmap, sym, NULL);
10167     if (!res) res = state->lastdef;
10168     
10169     /* add successors to working list */
10170     state = newState (NULL, NULL);
10171     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10172     while (succ) {
10173       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10174       state->flow = succ->pcflow;
10175       state->lastdef = res;
10176       if (stateIsNew (state, todo, done)) {
10177         stackPush (todo, state);
10178         state = newState (NULL, NULL);
10179       } // if
10180       succ = (pCodeFlowLink *) setNextItem (curr->to);
10181     } // while
10182     deleteState (state);
10183   } // while
10184
10185 #else // !FORWARD_FLOW_ANALYSIS 
10186
10187   /* no definition found in pc's flow preceeding pc */
10188   todo = newStack ();
10189   done = newStack ();
10190   n_defs = 0; firstState = 1;
10191   stackPush (todo, newState (PCI(pc)->pcflow, res));
10192
10193   while (!stackIsEmpty (todo)) {
10194     state = (state_t *) stackPop (todo);
10195     curr = state->flow;
10196
10197     if (firstState) {
10198       firstState = 0;
10199       /* only check predecessor flows */
10200     } else {
10201       /* get (last) definition of sym in this flow */
10202       res = defmapFindDef (curr->defmap, sym, NULL);
10203     }
10204
10205     if (res) {
10206       /* definition found */
10207       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10208       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10209     } else {
10210       /* no definition found -- check predecessor flows */
10211       state = newState (NULL, NULL);
10212       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10213
10214       /* if no flow predecessor available -- sym might be uninitialized */
10215       if (!succ) {
10216         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10217         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10218         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10219         deleteDefmap (res); res = NULL;
10220       }
10221       
10222       while (succ) {
10223         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10224         state->flow = succ->pcflow;
10225         state->lastdef = res;
10226         if (stateIsNew (state, todo, done)) {
10227           stackPush (todo, state);
10228           state = newState (NULL, NULL);
10229         } // if
10230         succ = (pCodeFlowLink *) setNextItem (curr->from);
10231       } // while
10232       deleteState (state);
10233     }
10234   } // while
10235
10236 #endif
10237
10238   /* clean up done stack */
10239   while (!stackIsEmpty(done)) {
10240     deleteState ((state_t *) stackPop (done));
10241   } // while
10242   deleteStack (done);
10243
10244   /* return number of items in result set */
10245   if (n_defs == 0) {
10246     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10247   } else if (n_defs == 1) {
10248     assert (*chain);
10249     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10250   } else if (n_defs > 0) {
10251     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10252 #if 0
10253     res = *chain;
10254     while (res) {
10255       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10256       res = res->next;
10257     } // while
10258 #endif
10259   }
10260   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10261   df_findall_otherflow++;
10262   return n_defs;
10263 }
10264
10265 /* ======================================================================== */
10266 /* === VALUE NUMBER HANDLING ============================================== */
10267 /* ======================================================================== */
10268
10269 static valnum_t nextValnum = 0x1000;
10270 static hTab *map_symToValnum = NULL;
10271
10272 /** Return a new value number. */
10273 static inline valnum_t newValnum () {
10274   return (nextValnum += 4);
10275 }
10276
10277 static valnum_t valnumFromStr (const char *str) {
10278   symbol_t sym;
10279   valnum_t val;
10280   void *res;
10281   
10282   sym = symFromStr (str);
10283
10284   if (!map_symToValnum) {
10285     map_symToValnum = newHashTable (128);
10286   } // if
10287
10288   /* literal already known? */
10289   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10290
10291   /* return existing valnum */
10292   if (res) return (valnum_t) PTR_TO_INT(res);
10293   
10294   /* create new valnum */
10295   val = newValnum();
10296   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10297   return val;
10298 }
10299
10300 /* Create a valnum for a literal. */
10301 static valnum_t valnumFromLit (unsigned int lit) {
10302   return ((valnum_t) 0x100 + (lit & 0x0FF));
10303 }
10304
10305 /* Return the (positive) literal value represented by val
10306  * or -1 iff val is no known literal's valnum. */
10307 static int litFromValnum (valnum_t val) {
10308   if (val >= 0x100 && val < 0x200) {
10309     /* valnum is a (known) literal */
10310     return val & 0x00FF;
10311   } else {
10312     /* valnum is not a known literal */
10313     return -1;
10314   }
10315 }
10316
10317 #if 0
10318 /* Sanity check - all flows in a block must be reachable from initial flow. */
10319 static int verifyAllFlowsReachable (pBlock *pb) {
10320   set *reached;
10321   set *flowInBlock;
10322   set *checked;
10323   pCode *pc;
10324   pCodeFlow *pcfl;
10325   pCodeFlowLink *succ;
10326   int res;
10327
10328   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10329
10330   reached = NULL;
10331   flowInBlock = NULL;
10332   checked = NULL;
10333   /* mark initial flow as reached (and "not needs to be reached") */
10334   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10335   assert (pc);
10336   addSetHead (&reached, pc);
10337   addSetHead (&checked, pc);
10338   
10339   /* mark all further flows in block as "need to be reached" */
10340   pc = pb->pcHead;
10341   do {
10342     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10343     pc = pic16_findNextInstruction (pc->next);
10344   } while (pc);
10345
10346   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10347     /* mark as reached and "not need to be reached" */
10348     deleteSetItem (&reached, pcfl);
10349     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10350     
10351     /* flow is no longer considered unreachable */
10352     deleteSetItem (&flowInBlock, pcfl);
10353
10354     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10355       if (!isinSet (checked, succ->pcflow)) {
10356         /* flow has never been reached before */
10357         addSetHead (&reached, succ->pcflow);
10358         addSetHead (&checked, succ->pcflow);
10359       } // if
10360     } // for succ
10361   } // while
10362
10363   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10364
10365   /* by now every flow should have been reached
10366    * --> flowInBlock should be empty */
10367   res = (flowInBlock == NULL);
10368
10369 #if 1
10370   if (flowInBlock) {
10371           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10372     while (flowInBlock) {
10373       pcfl = indexSet (flowInBlock, 0);
10374       fprintf (stderr, "not reached: flow %p\n", pcfl);
10375       deleteSetItem (&flowInBlock, pcfl);
10376     } // while
10377   }
10378 #endif
10379   
10380   /* clean up */
10381   deleteSet (&reached);
10382   deleteSet (&flowInBlock);
10383   deleteSet (&checked);
10384   
10385   /* if we reached every flow, succ is NULL by now... */
10386   //assert (res); // will fire on unreachable code...
10387   return (res);
10388 }
10389 #endif
10390
10391 /* Checks a flow for accesses to sym AFTER pc.
10392  * 
10393  * Returns -1 if the symbol is read in this flow (before redefinition),
10394  * returns 0 if the symbol is redefined in this flow or
10395  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10396  */
10397 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10398   defmap_t *map, *mappc;
10399
10400   /* find pc or start of definitions */
10401   map = pcfl->defmap;
10402   while (map && (map->pc != pc) && map->next) map = map->next;
10403   /* if we found pc -- ignore it */
10404   while (map && map->pc == pc) map = map->prev;
10405
10406   /* scan list backwards (first definition first) */
10407   while (map && mask) {
10408 //    if (map->sym == sym) {
10409       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10410       mappc = map;
10411       /* scan list for reads at this pc first */
10412       while (map && map->pc == mappc->pc) {
10413         /* is the symbol (partially) read? */
10414         if ((map->sym == sym) && (map->access.isRead && ((map->access.in_mask & mask) != 0))) {
10415           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10416           return -1;
10417         }
10418         map = map->prev;
10419       } // while
10420       map = mappc;
10421
10422       while (map && map->pc == mappc->pc) {
10423         /* honor (partial) redefinitions of sym */
10424         if ((map->sym == sym) && (map->access.isWrite)) {
10425           mask &= ~map->access.mask;
10426           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10427         }
10428         map = map->prev;
10429       } // while
10430 //    } // if
10431     /* map already points to the first defmap for the next pCode */
10432     //map = mappc->prev;
10433   } // while
10434
10435   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10436    * is still alive; return the appropriate mask of alive bits */
10437   return mask;
10438 }
10439
10440 /* Check whether a symbol is alive (AFTER pc). */
10441 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10442   int mask, visit;
10443   defmap_t *map;
10444   stack_t *todo, *done;
10445   state_t *state;
10446   pCodeFlow *pcfl;
10447   pCodeFlowLink *succ;
10448
10449   mask = 0x00ff;
10450   
10451   assert (isPCI(pc));
10452   pcfl = PCI(pc)->pcflow;
10453   map = pcfl->defmap;
10454
10455   todo = newStack ();
10456   done = newStack ();
10457   
10458   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10459   stackPush (todo, state);
10460   visit = 0;
10461   
10462   while (!stackIsEmpty (todo)) {
10463     state = (state_t *) stackPop (todo);
10464     pcfl = state->flow;
10465     mask = PTR_TO_INT(state->lastdef);
10466     if (visit) stackPush (done, state); else deleteState(state);
10467     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10468     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10469     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10470     visit++;
10471
10472     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10473     if (mask == 0) continue;
10474
10475     /* symbol is (partially) read before redefinition in flow */
10476     if (mask == -1) break;
10477
10478     /* symbol is neither read nor completely redefined -- check successor flows */
10479     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10480       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10481       if (stateIsNew (state, todo, done)) {
10482         stackPush (todo, state);
10483       } else {
10484         deleteState (state);
10485       }
10486     } // for
10487   } // while
10488
10489   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10490   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10491
10492   /* symbol is read in at least one flow -- is alive */
10493   if (mask == -1) return 1;
10494
10495   /* symbol is read in no flow */
10496   return 0;
10497 }
10498
10499 /* Returns whether access to the given symbol has side effects. */
10500 static int pic16_symIsSpecial (symbol_t sym) {
10501   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10502   switch (sym) {
10503   case SPO_INDF0:
10504   case SPO_PLUSW0:
10505   case SPO_POSTINC0:
10506   case SPO_POSTDEC0:
10507   case SPO_PREINC0:
10508   case SPO_INDF1:
10509   case SPO_PLUSW1:
10510   case SPO_POSTINC1:
10511   case SPO_POSTDEC1:
10512   case SPO_PREINC1:
10513   case SPO_INDF2:
10514   case SPO_PLUSW2:
10515   case SPO_POSTINC2:
10516   case SPO_POSTDEC2:
10517   case SPO_PREINC2:
10518   case SPO_PCL:
10519           return 1;
10520   default:
10521           /* no special effects known */
10522           return 0;
10523   } // switch
10524
10525   return 0;
10526 }
10527
10528 /* Check whether a register should be considered local (to the current function) or not. */
10529 static int pic16_regIsLocal (regs *r) {
10530   symbol_t sym;
10531   if (r) {
10532     sym = symFromStr (r->name);
10533     switch (sym) {
10534     case SPO_WREG:
10535     case SPO_FSR0L: // used in ptrget/ptrput
10536     case SPO_FSR0H: // ... as well
10537     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10538     case SPO_FSR1H: // ... as well
10539     case SPO_FSR2L: // used as frame pointer
10540     case SPO_FSR2H: // ... as well
10541     case SPO_PRODL: // used to return values from functions
10542     case SPO_PRODH: // ... as well
10543       /* these registers (and some more...) are considered local */
10544       return 1;
10545       break;
10546     default:
10547       /* for unknown regs: check is marked local, leave if not */
10548       if (r->isLocal) {
10549         return 1;
10550       } else {
10551         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10552         return 0;
10553       }
10554     } // switch
10555   } // if
10556
10557   /* if in doubt, assume non-local... */
10558   return 0;
10559 }
10560
10561 /* Check all symbols touched by pc whether their newly assigned values are read.
10562  * Returns 0 if no symbol is used later on, 1 otherwise. */
10563 static int pic16_pCodeIsAlive (pCode *pc) {
10564   pCodeInstruction *pci;
10565   defmap_t *map, *lastpc;
10566   regs *checkreg;
10567   
10568   /* we can only handle PCIs */
10569   if (!isPCI(pc)) return 1;
10570
10571   //pc->print (stderr, pc);
10572
10573   pci = PCI(pc);
10574   assert (pci && pci->pcflow && pci->pcflow->defmap);
10575
10576   /* NEVER remove instructions with implicit side effects */
10577   switch (pci->op) {
10578   case POC_TBLRD:
10579   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10580   case POC_TBLRD_POSTDEC:
10581   case POC_TBLRD_PREINC:
10582   case POC_TBLWT:               /* modify program memory */
10583   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10584   case POC_TBLWT_POSTDEC:
10585   case POC_TBLWT_PREINC:
10586   case POC_CLRWDT:              /* clear watchdog timer */
10587   case POC_PUSH:                /* should be safe to remove though... */
10588   case POC_POP:                 /* should be safe to remove though... */
10589   case POC_CALL:
10590   case POC_RCALL:
10591   case POC_RETFIE:
10592   case POC_RETURN:
10593     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10594     return 1;
10595
10596   default:
10597     /* no special instruction */
10598     break;
10599   } // switch
10600
10601   /* prevent us from removing assignments to non-local variables */
10602   checkreg = NULL;
10603   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10604   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10605
10606   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10607     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10608     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10609     //pc->print (stderr, pc);
10610     return 1;
10611   }
10612   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10613     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10614     return 1;
10615   }
10616   
10617 #if 1
10618   /* OVERKILL: prevent us from removing reads from non-local variables 
10619    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10620    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10621   checkreg = NULL;
10622   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10623   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10624
10625   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10626     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10627     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10628     //pc->print (stderr, pc);
10629     return 1;
10630   }
10631   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10632     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10633     return 1;
10634   }
10635 #endif
10636   
10637   /* now check that the defined symbols are not used */
10638   map = pci->pcflow->defmap;
10639   
10640   /* find items for pc */
10641   while (map && map->pc != pc) map = map->next;
10642
10643   /* no entries found? something is fishy with DF analysis... -- play safe */
10644   if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10645
10646   /* remember first item assigned to pc for later use */
10647   lastpc = map;
10648   
10649   /* check all symbols being modified by pc */
10650   while (map && map->pc == pc) {
10651     if (map->sym == 0) { map = map->next; continue; }
10652
10653     /* keep pc if it references special symbols (like POSTDEC0) */
10654 #if 0
10655     {
10656       char buf[256];
10657       pic16_pCode2str (buf, 256, pc);
10658       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10659     }
10660 #endif
10661     if (pic16_symIsSpecial (map->sym)) {
10662       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10663       return 1;
10664     }
10665     if (map->access.isWrite) {
10666       if (pic16_isAlive (map->sym, pc)) {
10667         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10668         return 1;
10669       }
10670     }
10671     map = map->next;
10672   } // while
10673
10674   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10675 #if 0
10676   {
10677     char buf[256];
10678     pic16_pCode2str (buf, 256, pc);
10679     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10680   }
10681 #endif
10682   return 0;
10683 }
10684
10685 /* Adds implied operands to the list.
10686  * sym - operand being accessed in the pCode
10687  * list - list to append the operand
10688  * isRead - set to 1 iff sym is read in pCode
10689  * listRead - set to 1 iff all operands being read are to be listed
10690  *
10691  * Returns 0 for "normal" operands, 1 for special operands.
10692  */
10693 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10694   /* check whether accessing REG accesses other REGs as well */
10695   switch (sym) {
10696   case SPO_INDF0:
10697     /* reads FSR0x */
10698     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10699     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10700     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10701     break;
10702     
10703   case SPO_PLUSW0:
10704     /* reads FSR0x and WREG */
10705     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10706     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10707     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10708     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10709     break;
10710     
10711   case SPO_POSTDEC0:
10712   case SPO_POSTINC0:
10713   case SPO_PREINC0:
10714     /* reads/modifies FSR0x */
10715     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10716     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10717     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10718     break;
10719
10720   case SPO_INDF1:
10721     /* reads FSR1x */
10722     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10723     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10724     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10725     break;
10726     
10727   case SPO_PLUSW1:
10728     /* reads FSR1x and WREG */
10729     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10730     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10731     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10732     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10733     break;
10734     
10735   case SPO_POSTDEC1:
10736   case SPO_POSTINC1:
10737   case SPO_PREINC1:
10738     /* reads/modifies FSR1x */
10739     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10740     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10741     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10742     break;
10743
10744   case SPO_INDF2:
10745     /* reads FSR2x */
10746     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10747     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10748     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10749     break;
10750     
10751   case SPO_PLUSW2:
10752     /* reads FSR2x and WREG */
10753     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10754     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10755     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10756     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10757     break;
10758     
10759   case SPO_POSTDEC2:
10760   case SPO_POSTINC2:
10761   case SPO_PREINC2:
10762     /* reads/modifies FSR2x */
10763     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10764     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10765     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10766     break;
10767
10768   case SPO_PCL:
10769     /* modifies PCLATH and PCLATU */
10770     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10771     if (isRead) {
10772       /* reading PCL updates PCLATx */
10773       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10774       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10775     }
10776     if (isWrite) {
10777       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10778       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10779       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10780     }
10781     break;
10782
10783   default:
10784     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10785     /* nothing special */
10786     return 0;
10787     break;
10788   }
10789
10790   /* has been a special operand */
10791   return 1;
10792 }
10793
10794 static symbol_t pic16_fsrsym_idx[][2] = {
10795     {SPO_FSR0L, SPO_FSR0H},
10796     {SPO_FSR1L, SPO_FSR1H},
10797     {SPO_FSR2L, SPO_FSR2H}
10798 };
10799   
10800 /** Prepend list with the reads and definitions performed by pc. */
10801 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10802   pCodeInstruction *pci;
10803   int cond, inCond, outCond;
10804   int mask = 0xff, smask;
10805   int isSpecial, isSpecial2;
10806   symbol_t sym, sym2;
10807   char *name;
10808
10809   if (isPCAD(pc)) {
10810     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10811     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10812     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10813     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10814     return list;
10815   }
10816   assert (isPCI(pc));
10817   pci = PCI(pc);
10818   
10819   /* handle bit instructions */
10820   if (pci->isBitInst) {
10821     assert (pci->pcop->type == PO_GPR_BIT);
10822     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10823   }
10824
10825   /* handle (additional) implicit arguments */
10826   switch (pci->op) {
10827   case POC_LFSR:
10828     {
10829       int lit;
10830       valnum_t val;
10831       lit = PCOL(pci->pcop)->lit;
10832       assert (lit >= 0 && lit < 3);
10833       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10834       val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10835       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10836       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10837       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...
10838     }
10839     break;
10840
10841   case POC_MOVLB: // BSR
10842   case POC_BANKSEL: // BSR
10843     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10844     break;
10845
10846   case POC_MULWF: // PRODx
10847   case POC_MULLW: // PRODx
10848     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10849     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10850     break;
10851
10852   case POC_POP: // TOS, STKPTR
10853     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10854     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10855     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10856     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10857     break;
10858     
10859   case POC_PUSH: // STKPTR
10860     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10861     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10862     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10863     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10864     break;
10865     
10866   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10867   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10868     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10869     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10870     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10871     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10872
10873     /* needs correctly set-up stack pointer */
10874     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10875     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10876     break;
10877
10878   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10879     /* pseudo read on (possible) return values */
10880     // WREG is handled below via outCond
10881     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10882     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10883     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10884
10885     /* caller's stack pointers must be restored */
10886     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10887     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10888     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10889     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10890     break;
10891
10892   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10893   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10894     /* pseudo read on (possible) return values */
10895     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10896     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10897     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10898     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10899
10900     /* caller's stack pointers must be restored */
10901     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10902     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10903     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10904     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10905     break;
10906     
10907   case POC_TBLRD:
10908     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10909     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10910     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10911     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10912     break;
10913     
10914   case POC_TBLRD_POSTINC:
10915   case POC_TBLRD_POSTDEC:
10916   case POC_TBLRD_PREINC:
10917     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10918     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10919     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10920     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10921     break;
10922     
10923   case POC_TBLWT:
10924     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10925     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10926     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10927     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10928     break;
10929     
10930   case POC_TBLWT_POSTINC:
10931   case POC_TBLWT_POSTDEC:
10932   case POC_TBLWT_PREINC:
10933     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10934     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10935     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10936     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10937     break;
10938     
10939   default:
10940     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10941     break;
10942   } // switch
10943
10944   /* handle explicit arguments */
10945   inCond = pci->inCond;
10946   outCond = pci->outCond;
10947   cond = inCond | outCond;
10948   if (cond & PCC_W) {
10949     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10950   } // if
10951
10952   /* keep STATUS read BEFORE STATUS write in the list */
10953   if (inCond & PCC_STATUS) {
10954     smask = 0;
10955     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10956     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10957     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10958     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10959     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10960
10961     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10962     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10963   } // if
10964   
10965   if (outCond & PCC_STATUS) {
10966     smask = 0;
10967     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10968     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10969     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10970     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10971     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10972
10973     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10974     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10975   } // if
10976   
10977   isSpecial = isSpecial2 = 0;
10978   sym = sym2 = 0;
10979   if (cond & PCC_REGISTER) {
10980     name = pic16_get_op (pci->pcop, NULL, 0);
10981     sym = symFromStr (name);
10982     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
10983     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
10984   }
10985
10986   if (cond & PCC_REGISTER2) {
10987     name = pic16_get_op2 (pci->pcop, NULL, 0);
10988     sym2 = symFromStr (name);
10989     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
10990     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
10991   }
10992
10993  
10994   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10995   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
10996   
10997   return list;
10998 }
10999
11000 #if 0
11001 static void printDefmap (defmap_t *map) {
11002   defmap_t *curr;
11003
11004   curr = map;
11005   fprintf (stderr, "defmap @ %p:\n", curr);
11006   while (curr) {
11007     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11008                     curr->access.isRead ? "R" : " ",
11009                     curr->access.isWrite ? "W": " ",
11010                     curr->in_val, curr->val,
11011                     curr->access.in_mask, curr->access.mask,
11012                     strFromSym(curr->sym), curr->sym,
11013                     curr->pc);
11014     curr = curr->next;
11015   } // while
11016   fprintf (stderr, "<EOL>\n");
11017 }
11018 #endif
11019
11020 /* Add "additional" definitions to uniq.
11021  * 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.
11022  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11023  *
11024  * If symbols defined in additional are not present in uniq, a definition is created.
11025  * Otherwise the present definition is altered to reflect the newer assignments.
11026  *
11027  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11028  *       before     `------- noted in additional --------'      after
11029  *
11030  * I assume that each symbol occurs AT MOST ONCE in uniq.
11031  *
11032  */
11033 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11034   defmap_t *curr;
11035   defmap_t *old;
11036   int change = 0;
11037
11038   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11039   /* find tail of additional list (holds the first assignment) */
11040   curr = additional;
11041   while (curr && curr->next) curr = curr->next;
11042
11043   /* update uniq */
11044   do {
11045     /* find next assignment in additionals */
11046     while (curr && !curr->access.isWrite) curr = curr->prev;
11047
11048     if (!curr) break;
11049
11050     /* find item in uniq */
11051     old = *uniq;
11052     //printDefmap (*uniq);
11053     while (old && (old->sym != curr->sym)) old = old->next;
11054
11055     if (old) {
11056       /* definition found -- replace */
11057       if (old->val != curr->val) {
11058         old->val = curr->val;
11059         change++;
11060       } // if
11061     } else {
11062       /* new definition */
11063       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11064       change++;
11065     }
11066
11067     curr = curr->prev;
11068   } while (1);
11069
11070   /* return 0 iff uniq remained unchanged */
11071   return change;
11072 }
11073
11074 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11075  * lists of its predecessor flows. 
11076  * Initially *combined should be NULL, alt_in will be copied to combined.
11077  * If *combined != NULL, combined will be altered:
11078  * - for symbols defined in *combined but not in alt_in,
11079  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11080  * - for symbols defined in alt_in but not in *combined,
11081  *   a 0 definition is created (value unknown, either INIT or alt).
11082  * - for symbols defined in both, *combined is:
11083  *   > left unchanged if *combined->val == alt_in->val or
11084  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11085  * 
11086  * I assume that each symbol occurs AT MOST ONCE in each list!
11087  */
11088 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11089   defmap_t *curr;
11090   defmap_t *old;
11091   int change = 0;
11092   valnum_t val;
11093
11094   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11095   
11096   if (!(*combined)) {
11097     return defmapUpdateUniqueSym (combined, alt_in);
11098   } // if
11099   
11100   /* merge the two */
11101   curr = alt_in;
11102   while (curr) {
11103     /* find symbols definition in *combined */
11104     old = *combined;
11105     while (old && (old->sym != curr->sym)) old = old->next;
11106
11107     if (old) {
11108       /* definition found */
11109       if (old->val && (old->val != curr->val)) {
11110         old->val = 0; /* value unknown */
11111         change++;
11112       }
11113     } else {
11114       /* no definition found -- can be either INIT or alt_in's value */
11115       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11116       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11117       if (val != curr->val) change++;
11118     }
11119
11120     curr = curr->next;
11121   } // while (curr)
11122
11123   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11124   old = *combined;
11125   while (old) {
11126     if (old->val != 0) {
11127       /* find definition in alt_in */
11128       curr = alt_in;
11129       while (curr && curr->sym != old->sym) curr = curr->next;
11130       if (!curr) {
11131         /* symbol defined in *combined only -- can be either INIT or *combined */
11132         val = pic16_pBlockAddInval (pb, old->sym)->val;
11133         if (old->val != val) {
11134           old->val = 0;
11135           change++;
11136         }
11137       } // if
11138     } // if
11139
11140     old = old->next;
11141   } // while
11142
11143   return change;
11144 }
11145
11146 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11147   defmap_t *curr1, *curr2;
11148   symbol_t sym;
11149   
11150   /* identical maps are equal */
11151   if (map1 == map2) return 0;
11152
11153   if (!map1) return -1;
11154   if (!map2) return 1;
11155
11156   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11157   
11158   /* check length */
11159   curr1 = map1;
11160   curr2 = map2;
11161   while (curr1 && curr2) {
11162     curr1 = curr1->next;
11163     curr2 = curr2->next;
11164   } // while
11165
11166   /* one of them longer? */
11167   if (curr1) return 1;
11168   if (curr2) return -1;
11169
11170   /* both lists are of equal length -- compare (in O(n^2)) */
11171   curr1 = map1;
11172   while (curr1) {
11173     sym = curr1->sym;
11174     curr2 = map2;
11175     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11176     if (!curr2) return 1; // symbol not found in curr2
11177     if (curr2->val != curr1->val) return 1; // values differ
11178
11179     /* compare next symbol */
11180     curr1 = curr1->next;
11181   } // while
11182
11183   /* no difference found */
11184   return 0;
11185 }
11186
11187
11188 /* Prepare a list of all reaching definitions per flow.
11189  * This is done using a forward dataflow analysis.
11190  */
11191 static void createReachingDefinitions (pBlock *pb) {
11192   defmap_t *out_vals, *in_vals;
11193   pCode *pc;
11194   pCodeFlow *pcfl;
11195   pCodeFlowLink *link;
11196   set *todo;
11197   set *blacklist;
11198
11199   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11200   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11201     if (isPCFL(pc)) {
11202       deleteDefmapChain (&PCFL(pc)->in_vals);
11203       deleteDefmapChain (&PCFL(pc)->out_vals);
11204       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11205     } // if
11206   } // for
11207   
11208   pc = pic16_findNextInstruction (pb->pcHead);
11209   todo = NULL; blacklist = NULL;
11210   addSetHead (&todo, PCI(pc)->pcflow);
11211
11212   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11213   while (elementsInSet (todo)) {
11214     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11215     pcfl = PCFL(indexSet (todo, 0));
11216     deleteSetItem (&todo, pcfl);
11217     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11218     in_vals = NULL;
11219     out_vals = NULL;
11220
11221     if (isinSet (blacklist, pcfl)) {
11222             fprintf (stderr, "ignoring blacklisted flow\n");
11223       continue;
11224     }
11225     
11226     /* create in_vals from predecessors out_vals */
11227     link = setFirstItem (pcfl->from);
11228     while (link) {
11229       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11230       link = setNextItem (pcfl->from);
11231     } // while
11232
11233     //printDefmap (in_vals); 
11234     //printDefmap (pcfl->in_vals); 
11235
11236     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11237       //fprintf (stderr, "in_vals changed\n");
11238       /* in_vals changed -- update out_vals */
11239       deleteDefmapChain (&pcfl->in_vals);
11240       pcfl->in_vals = in_vals;
11241
11242       /* create out_val from in_val and defmap */
11243       out_vals = NULL;
11244       defmapUpdateUniqueSym (&out_vals, in_vals);
11245       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11246
11247       /* is out_vals different from pcfl->out_vals */
11248       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11249         //fprintf (stderr, "out_vals changed\n");
11250         deleteDefmapChain (&pcfl->out_vals);
11251         pcfl->out_vals = out_vals;
11252
11253         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11254           addSet (&blacklist, pcfl);
11255         } // if
11256         
11257         /* reschedule all successors */
11258         link = setFirstItem (pcfl->to);
11259         while (link) {
11260           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11261           addSetIfnotP (&todo, link->pcflow);
11262           link = setNextItem (pcfl->to);
11263         } // while
11264       } else {
11265         deleteDefmapChain (&out_vals);        
11266       }// if
11267     } else {
11268       deleteDefmapChain (&in_vals);         
11269     } // if
11270   } // while
11271 }
11272
11273 #if 0
11274 static void showAllDefs (symbol_t sym, pCode *pc) {
11275   defmap_t *map;
11276   int count;
11277
11278   assert (isPCI(pc));
11279   count = defmapFindAll (sym, pc, &map);
11280
11281   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11282   while (map) {
11283 #if 1
11284     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11285 #else
11286     { char buf[256];
11287     pic16_pCode2str (buf, 256, map->pc);
11288     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11289 #endif
11290     map = map->next;
11291   }
11292   deleteDefmapChain (&map);
11293 }
11294 #endif
11295
11296 /* safepCodeUnlink and remove pc from defmap. */
11297 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11298   defmap_t *map, *next, **head;
11299   int res, ispci;
11300   
11301   ispci = isPCI(pc);
11302   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11303   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11304   res = pic16_safepCodeUnlink (pc, comment);
11305
11306   if (res && map) {
11307     /* remove pc from defmap */
11308     while (map) {
11309       next = map->next;
11310       if (map->pc == pc) {
11311         if (!map->prev && head) *head = map->next;
11312         deleteDefmap (map);
11313       } // if
11314       map = next;
11315     }
11316   }
11317
11318   return res;
11319 }
11320       
11321 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11322   defmap_t *map;
11323   /* This breaks the defmap chain's references to pCodes... fix it! */
11324   map = PCI(pc)->pcflow->defmap;
11325
11326   while (map && map->pc != pc) map = map->next;
11327   
11328   while (map && map->pc == pc) {
11329     map->pc = newpc;
11330     map = map->next;
11331   } // while
11332 }
11333
11334 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
11335   defmap_t *map;
11336   if (!isPCI(pc)) return;
11337   
11338   map = PCI(pc)->pcflow->defmap;
11339
11340   while (map && map->pc != pc) map = map->next;
11341   while (map && map->pc == pc) {
11342     if (map->sym == sym) map->sym = newsym;
11343     map = map->next;
11344   } // while
11345 }
11346
11347 /* Assign "better" valnums to results. */
11348 static void assignValnums (pCode *pc) {
11349   pCodeInstruction *pci;
11350   pCode *newpc;
11351   symbol_t sym1, sym2;
11352   int cond, isSpecial1, isSpecial2, count, mask, lit;
11353   defmap_t *list, *val, *oldval, *dummy;
11354   regs *reg1 = NULL, *reg2 = NULL;
11355   valnum_t litnum;
11356
11357   /* only works for pCodeInstructions... */
11358   if (!isPCI(pc)) return;
11359
11360   pci = PCI(pc);
11361   cond = pci->inCond | pci->outCond;
11362   list = pci->pcflow->defmap;
11363   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11364
11365   if (cond & PCC_REGISTER) {
11366     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11367     reg1 = pic16_getRegFromInstruction (pc);
11368     isSpecial1 = pic16_symIsSpecial (sym1);
11369   }
11370   if (cond & PCC_REGISTER2) {
11371     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11372     reg2 = pic16_getRegFromInstruction (pc);
11373     isSpecial2 = pic16_symIsSpecial (sym2);
11374   }
11375
11376   /* determine input values */
11377   val = list;
11378   while (val && val->pc != pc) val = val->next;
11379   //list = val; /* might save some time later... */
11380   while (val && val->pc == pc) {
11381     val->in_val = 0;
11382     if (val->sym != 0 && (1 || val->access.isRead)) {
11383       /* get valnum for sym */
11384       count = defmapFindAll (val->sym, pc, &oldval);
11385       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11386       if (count == 1) {
11387         if ((val->access.in_mask & oldval->access.mask) == val->access.in_mask) {
11388           val->in_val = oldval->val;
11389         } else {
11390           val->in_val = 0;
11391         }
11392       } else if (count == 0) {
11393         /* no definition found */
11394         val->in_val = 0;
11395       } else {
11396         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11397         assert (oldval);
11398         dummy = oldval->next;
11399         mask = oldval->access.mask;
11400         val->in_val = oldval->val;
11401         while (dummy && (dummy->val == val->in_val)) {
11402           mask &= dummy->access.mask;
11403           dummy = dummy->next;
11404         } // while
11405
11406         /* found other values or to restictive mask */
11407         if (dummy || ((mask & val->access.in_mask) != val->access.in_mask)) {
11408           val->in_val = 0;
11409         }
11410       }
11411       if (count > 0) deleteDefmapChain (&oldval);
11412     } // if
11413     val = val->next;
11414   }
11415
11416   /* handle valnum assignment */
11417   switch (pci->op) {
11418   case POC_CLRF: /* modifies STATUS (Z) */
11419     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11420       oldval = defmapCurr (list, sym1, pc);
11421       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11422         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11423         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11424       }
11425       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11426     }
11427     break;
11428
11429   case POC_SETF: /* SETF does not touch STATUS */
11430     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11431       oldval = defmapCurr (list, sym1, pc);
11432       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11433         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11434         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11435       }
11436       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11437     }
11438     break;
11439     
11440   case POC_MOVLW: /* does not touch STATUS */
11441     oldval = defmapCurr (list, SPO_WREG, pc);
11442     if (pci->pcop->type == PO_LITERAL) {
11443       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11444       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11445     } else {
11446       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11447       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11448     }
11449     if (oldval && oldval->in_val == litnum) {
11450       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11451       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11452     }
11453     defmapUpdate (list, SPO_WREG, pc, litnum);
11454     break;
11455
11456   case POC_ANDLW: /* modifies STATUS (Z,N) */
11457   case POC_IORLW: /* modifies STATUS (Z,N) */
11458   case POC_XORLW: /* modifies STATUS (Z,N) */
11459     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11460     if (pci->pcop->type == PO_LITERAL) {
11461       int vallit = -1;
11462       lit = (unsigned char) PCOL(pci->pcop)->lit;
11463       val = defmapCurr (list, SPO_WREG, pc);
11464       if (val) vallit = litFromValnum (val->in_val);
11465       if (vallit != -1) {
11466         /* xxxLW <literal>, WREG contains a known literal */
11467         fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11468         if (pci->op == POC_ANDLW) {
11469           lit &= vallit;
11470         } else if (pci->op == POC_IORLW) {
11471           lit |= vallit;
11472         } else if (pci->op == POC_XORLW) {
11473           lit ^= vallit;
11474         } else {
11475           assert (0 && "invalid operation");
11476         }
11477         if (vallit == lit) {
11478           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11479           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11480         }
11481         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11482       } // if
11483     }
11484     break;
11485
11486   case POC_LFSR:
11487     {
11488       /* check if old value matches new value */
11489       int lit;
11490       int ok = 1;
11491       assert (pci->pcop->type == PO_LITERAL);
11492       
11493       lit = PCOL(pci->pcop)->lit;
11494       
11495       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11496       
11497       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11498         fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11499       } else {
11500         /* cannot remove this LFSR */
11501         ok = 0;      
11502       } // if
11503       
11504       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11505       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11506         fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11507       } else {
11508         ok = 0;
11509       } // if
11510
11511       if (ok) {
11512         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11513       }
11514     }
11515     break;
11516     
11517   case POC_MOVWF: /* does not touch flags */
11518     /* find value of WREG */
11519     val = defmapCurr (list, SPO_WREG, pc);
11520     oldval = defmapCurr (list, sym1, pc);
11521     if (val) lit = litFromValnum (val->in_val);
11522     else lit = -1;
11523     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11524     
11525     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11526       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11527       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11528       if (lit == 0) {
11529         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11530       } else {
11531         assert (lit == 0x0ff);
11532         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11533       }
11534       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11535       pic16_pCodeReplace (pc, newpc);
11536       defmapReplaceSymRef (pc, SPO_WREG, 0);
11537       pic16_fixDefmap (pc, newpc);
11538       pc = newpc;
11539         
11540       /* This breaks the defmap chain's references to pCodes... fix it! */
11541       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11542       deleteDefmap (val); // delete reference to WREG as in value
11543       val = NULL;
11544       oldval = PCI(pc)->pcflow->defmap;
11545       while (oldval) {
11546         if (oldval->pc == pc) oldval->pc = newpc;
11547           oldval = oldval->next;
11548       } // while
11549     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11550       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11551       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11552     }
11553     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11554     break;
11555     
11556   case POC_MOVFW: /* modifies STATUS (Z,N) */
11557     /* find value of REG */
11558     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11559       val = defmapCurr (list, sym1, pc);
11560       oldval = defmapCurr (list, SPO_WREG, pc);
11561       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11562         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11563         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11564       }
11565       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11566     }
11567     break;
11568
11569   case POC_MOVFF: /* does not touch STATUS */
11570     /* find value of REG */
11571     val = defmapCurr (list, sym1, pc);
11572     oldval = defmapCurr (list, sym2, pc);
11573     if (val) lit = litFromValnum (val->in_val);
11574     else lit = -1;
11575     newpc = NULL;
11576     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11577       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11578       if (lit == 0) {
11579         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11580       } else if (lit == 0x00ff) {
11581         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11582       } else {
11583         newpc = NULL;
11584       }
11585       if (newpc) {
11586         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11587         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11588         pic16_pCodeReplace (pc, newpc); 
11589         defmapReplaceSymRef (pc, sym1, 0);
11590         pic16_fixDefmap (pc, newpc);
11591         pc = newpc;
11592         break; // do not process instruction as MOVFF...
11593       }
11594     } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11595       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11596         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11597         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11598       } else {
11599         if (!pic16_isAlive (sym1, pc)) {
11600           defmap_t *copy = NULL;
11601           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11602            * This should help eliminate
11603            *   MOVFF A,B
11604            *   <do something not changing A or using B>
11605            *   MOVFF B,C
11606            *   <B is not alive anymore>
11607            * and turn it into
11608            *   <do something not changing A or using B>
11609            *   MOVFF A,C
11610            */
11611
11612           /* scan defmap for symbols storing sym1's value */
11613           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11614           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11615             /* unique reaching definition for sym found */
11616             if (copy->val && copy->val == val->in_val) {
11617               //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);
11618               if (copy->sym == SPO_WREG) {
11619                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11620               } else {
11621                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11622 //                      /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11623                         pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11624                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11625               }
11626               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11627               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11628               pic16_pCodeReplace (pc, newpc); 
11629               assert (val->sym == sym1 && val->access.isRead && !val->access.isWrite);
11630               defmapReplaceSymRef (pc, sym1, copy->sym);
11631               pic16_fixDefmap (pc, newpc);
11632               pc = newpc;
11633             }
11634           }
11635           deleteDefmapChain (&copy);
11636         }
11637       }
11638       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11639     }
11640     break;
11641
11642   default:
11643     /* cannot optimize */
11644     break;
11645   } // switch
11646 }
11647
11648 static void pic16_destructDF (pBlock *pb) {
11649   pCode *pc, *next;
11650
11651   /* remove old defmaps */
11652   pc = pic16_findNextInstruction (pb->pcHead);
11653   while (pc) {
11654     next = pic16_findNextInstruction (pc->next);
11655
11656     assert (isPCI(pc) || isPCAD(pc));
11657     assert (PCI(pc)->pcflow);
11658     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11659     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11660     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11661     
11662     pc = next;
11663   } // while
11664   
11665   if (defmap_free || defmap_free_count) {
11666     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11667     freeDefmap (&defmap_free);
11668     defmap_free_count = 0;
11669   }
11670 }
11671
11672 /* Checks whether a pBlock contains ASMDIRs. */
11673 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11674   pCode *pc;
11675
11676   pc = pic16_findNextInstruction (pb->pcHead);
11677   while (pc) {
11678     if (isPCAD(pc)) return 1;
11679
11680     pc = pic16_findNextInstruction (pc->next);
11681   } // while
11682
11683   /* no PCADs found */
11684   return 0;
11685 }
11686
11687 #if 1
11688 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11689 static int pic16_removeUnusedRegistersDF () {
11690   pCode *pc, *pc2;
11691   pBlock *pb;
11692   regs *reg1, *reg2, *reg3;
11693   set *seenRegs = NULL;
11694   int cond, i;
11695   int islocal, change = 0;
11696
11697   /* no pBlocks? */
11698   if (!the_pFile || !the_pFile->pbHead) return 0;
11699   
11700   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11701     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11702 #if 1
11703     /* find set of using pCodes per register */
11704     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11705                     pc = pic16_findNextInstruction(pc->next)) {
11706
11707       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11708       reg1 = reg2 = NULL;
11709       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11710       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11711
11712       if (reg1) {
11713         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11714         addSetIfnotP (&seenRegs, reg1);
11715         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11716       }
11717       if (reg2) {
11718         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11719         addSetIfnotP (&seenRegs, reg2);
11720         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11721       }
11722     } // for pc
11723 #endif
11724     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11725       /* may not use pic16_regIsLocal() here -- in interrupt routines
11726        * WREG, PRODx, FSR0x must be saved */
11727       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11728       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11729         pc = pc2 = NULL;
11730         for (i=0; i < 2; i++) {
11731           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11732           if (!pc2) pc2 = pc;
11733           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11734           reg2 = pic16_getRegFromInstruction (pc);
11735           reg3 = pic16_getRegFromInstruction2 (pc);
11736           if (!reg2 || !reg3
11737               || (reg2->rIdx != pic16_stack_preinc->rIdx
11738                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11739           if (i == 1) {
11740             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11741             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11742             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11743             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11744           }
11745         } // for
11746       } // if
11747       deleteSet (&reg1->reglives.usedpCodes);
11748     } // for reg1
11749
11750     deleteSet (&seenRegs);
11751   } // for pb
11752
11753   return change;
11754 }
11755 #endif
11756
11757 /* Set up pCodeFlow's defmap_ts. 
11758  * Needs correctly set up to/from fields. */
11759 static void pic16_createDF (pBlock *pb) {
11760   pCode *pc, *next;
11761   int change=0;
11762
11763   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11764
11765   pic16_destructDF (pb);
11766
11767   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11768   if (pic16_pBlockHasAsmdirs (pb)) {
11769     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11770     return;
11771   }
11772
11773   /* integrity check -- we need to reach all flows to guarantee
11774    * correct data flow analysis (reaching definitions, aliveness) */
11775 #if 0
11776   if (!verifyAllFlowsReachable (pb)) {
11777     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11778     return;
11779   }
11780 #endif
11781   
11782   /* establish new defmaps */
11783   pc = pic16_findNextInstruction (pb->pcHead);
11784   while (pc) {
11785     next = pic16_findNextInstruction (pc->next);
11786
11787     assert (PCI(pc)->pcflow);
11788     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11789
11790     pc = next;
11791   } // while
11792
11793   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11794   createReachingDefinitions (pb);
11795   
11796 #if 1
11797   /* assign better valnums */
11798   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11799   pc = pic16_findNextInstruction (pb->pcHead);
11800   while (pc) {
11801     next = pic16_findNextInstruction (pc->next);
11802
11803     assert (PCI(pc)->pcflow);
11804     assignValnums (pc);
11805
11806     pc = next;
11807   } // while
11808 #endif
11809
11810 #if 1
11811   /* remove dead pCodes */
11812   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11813   do {
11814     change = 0;
11815     pc = pic16_findNextInstruction (pb->pcHead);
11816     while (pc) {
11817       next = pic16_findNextInstruction (pc->next);
11818
11819       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11820         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11821       }
11822
11823       pc = next;
11824     } // while
11825   } while (change);
11826 #endif
11827 }
11828
11829
11830 /* ======================================================================= */
11831 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11832 /* ======================================================================= */
11833
11834 #if 0
11835
11836 /* connect pCode f anf t via their to/from pBranches */
11837 static void pic16_pCodeLink (pCode *f, pCode *t) {
11838   pBranch *br;
11839   pCodeInstruction *_f, *_t;
11840
11841   if (!f || !t) return;
11842
11843 #if 0
11844   fprintf (stderr, "linking:\n");
11845   f->print(stderr, f);
11846   f->print(stderr, t);
11847 #endif
11848
11849   assert (isPCI(f) || isPCAD(f));
11850   assert (isPCI(t) || isPCAD(t));
11851   _f = PCI(f);
11852   _t = PCI(t);
11853   
11854   /* define t to be CF successor of f */
11855   br = Safe_malloc (sizeof (pBranch));
11856   br->pc = t;
11857   br->next = NULL;
11858   _f->to = pic16_pBranchAppend (_f->to, br);
11859
11860   /* define f to be CF predecessor of t */
11861   br = Safe_malloc (sizeof (pBranch));
11862   br->pc = f;
11863   br->next = NULL;
11864   _t->from = pic16_pBranchAppend (_t->from, br);
11865
11866   /* also update pcflow information */
11867   if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11868     //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11869     LinkFlow_pCode (_f, _t);
11870   } // if
11871 }
11872
11873 static void pic16_destructCF (pBlock *pb) {
11874   pCode *pc;
11875   pBranch *br;
11876
11877   /* remove old CF information */
11878   pc = pb->pcHead;
11879   while (pc) {
11880     if (isPCI(pc)) {
11881       while (PCI(pc)->to) {
11882         br = PCI(pc)->to->next;
11883         Safe_free (PCI(pc)->to);
11884         PCI(pc)->to = br;
11885       } // while
11886       while (PCI(pc)->from) {
11887         br = PCI(pc)->from->next;
11888         Safe_free (PCI(pc)->from);
11889         PCI(pc)->from = br;
11890       }
11891     } else if (isPCFL(pc)) {
11892       deleteSet (&PCFL(pc)->to);
11893       deleteSet (&PCFL(pc)->from);
11894     }
11895     pc = pc->next;
11896   }
11897   
11898   releaseStack ();
11899 }
11900
11901 /* Set up pCodeInstruction's to and from pBranches. */
11902 static void pic16_createCF (pBlock *pb) {
11903   pCode *pc;
11904   pCode *next, *dest;
11905   char *label;
11906
11907   //fprintf (stderr, "creating CF for %p\n", pb);
11908
11909   pic16_destructCF (pb);
11910
11911   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11912   if (pic16_pBlockHasAsmdirs (pb)) {
11913     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11914     return;
11915   }
11916
11917   pc = pic16_findNextInstruction(pb->pcHead);
11918   while (pc) {
11919     next = pic16_findNextInstruction(pc->next);
11920     if (isPCI_SKIP(pc)) {
11921       pic16_pCodeLink(pc, next);
11922       pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
11923     } else if (isPCI_BRANCH(pc)) {
11924       // Bcc, BRA, CALL, GOTO
11925       if (PCI(pc)->pcop) {
11926         switch (PCI(pc)->pcop->type) {
11927         case PO_LABEL:
11928           label = PCOLAB(PCI(pc)->pcop)->pcop.name;
11929           dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
11930           break;
11931         
11932         case PO_STR:
11933           /* needed for GOTO ___irq_handler */
11934           label = PCI(pc)->pcop->name;
11935           dest = NULL;
11936           break;
11937
11938         default:
11939           assert (0 && "invalid label format");
11940           break;
11941         } // switch
11942       } else {
11943         label = "NO PCOP";
11944         dest = NULL;
11945       }
11946
11947       switch (PCI(pc)->op) {
11948       case POC_BRA:
11949       case POC_GOTO:
11950         if (dest != NULL) { 
11951           pic16_pCodeLink(pc, dest);
11952         } else {
11953           //fprintf (stderr, "jump target \"%s\" not found!\n", label);
11954         }
11955         break;
11956       case POC_CALL:
11957       case POC_RETURN:
11958       case POC_RETFIE:
11959         pic16_pCodeLink(pc, next);
11960         break;
11961       case POC_BC:
11962       case POC_BNC:
11963       case POC_BZ:
11964       case POC_BNZ:
11965       case POC_BN:
11966       case POC_BNN:
11967       case POC_BOV:
11968       case POC_BNOV:
11969         if (dest != NULL) { 
11970           pic16_pCodeLink(pc, dest);
11971         } else {
11972           //fprintf (stderr, "jump target \"%s\"not found!\n", label);
11973         }
11974         pic16_pCodeLink(pc, next);
11975         break;
11976       default:
11977         fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
11978         assert (0 && "unhandled branch instruction");
11979         break;
11980       } // switch
11981     } else {
11982       pic16_pCodeLink (pc, next);
11983     }
11984     pc = next;
11985   } // while
11986 }
11987 #endif
11988
11989 /* ======================================================================== */
11990 /* === VCG DUMPER ROUTINES ================================================ */
11991 /* ======================================================================== */
11992 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11993 hTab *dumpedNodes = NULL;
11994
11995 /** Dump VCG header into of. */
11996 static void pic16_vcg_init (FILE *of) {
11997   /* graph defaults */
11998   fprintf (of, "graph:{\n");
11999   fprintf (of, "title:\"graph1\"\n");
12000   fprintf (of, "label:\"graph1\"\n");
12001   fprintf (of, "color:white\n");
12002   fprintf (of, "textcolor:black\n");
12003   fprintf (of, "bordercolor:black\n");
12004   fprintf (of, "borderwidth:1\n");
12005   fprintf (of, "textmode:center\n");
12006
12007   fprintf (of, "layoutalgorithm:dfs\n");
12008   fprintf (of, "late_edge_labels:yes\n");
12009   fprintf (of, "display_edge_labels:yes\n");
12010   fprintf (of, "dirty_edge_labels:yes\n");
12011   fprintf (of, "finetuning:yes\n");
12012   fprintf (of, "ignoresingles:no\n");
12013   fprintf (of, "straight_phase:yes\n");
12014   fprintf (of, "priority_phase:yes\n");
12015   fprintf (of, "manhattan_edges:yes\n");
12016   fprintf (of, "smanhattan_edges:no\n");
12017   fprintf (of, "nearedges:no\n");
12018   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12019   fprintf (of, "port_sharing:no\n");
12020   fprintf (of, "arrowmode:free\n"); // fixed|free
12021   fprintf (of, "crossingphase2:yes\n");
12022   fprintf (of, "crossingoptimization:yes\n");
12023   fprintf (of, "edges:yes\n");
12024   fprintf (of, "nodes:yes\n");
12025   fprintf (of, "splines:no\n");
12026   
12027   /* node defaults */
12028   fprintf (of, "node.color:lightyellow\n");
12029   fprintf (of, "node.textcolor:black\n");
12030   fprintf (of, "node.textmode:center\n");
12031   fprintf (of, "node.shape:box\n");
12032   fprintf (of, "node.bordercolor:black\n");
12033   fprintf (of, "node.borderwidth:1\n");
12034
12035   /* edge defaults */
12036   fprintf (of, "edge.textcolor:black\n");
12037   fprintf (of, "edge.color:black\n");
12038   fprintf (of, "edge.thickness:1\n");
12039   fprintf (of, "edge.arrowcolor:black\n");
12040   fprintf (of, "edge.backarrowcolor:black\n");
12041   fprintf (of, "edge.arrowsize:15\n");
12042   fprintf (of, "edge.backarrowsize:15\n");
12043   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12044   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12045   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12046   
12047   fprintf (of, "\n");
12048
12049   /* prepare data structures */
12050   if (dumpedNodes) {
12051     hTabDeleteAll (dumpedNodes);
12052     dumpedNodes = NULL;
12053   }
12054   dumpedNodes = newHashTable (128);
12055 }
12056
12057 /** Dump VCG footer into of. */
12058 static void pic16_vcg_close (FILE *of) {
12059   fprintf (of, "}\n");
12060 }
12061
12062 #define BUF_SIZE 128
12063 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12064
12065 #if 0
12066 static int ptrcmp (const void *p1, const void *p2) {
12067   return p1 == p2;
12068 }
12069 #endif
12070
12071 /** Dump a pCode node as VCG to of. */
12072 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12073   char buf[BUF_SIZE];
12074
12075   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12076     // dumped already
12077     return;
12078   }
12079   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12080   //fprintf (stderr, "dumping %p\n", pc);
12081  
12082   /* only dump pCodeInstructions and Flow nodes */
12083   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12084     
12085   /* emit node */
12086   fprintf (of, "node:{");
12087   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12088   fprintf (of, "label:\"%s\n", pcTitle(pc));
12089   if (isPCFL(pc)) {
12090     fprintf (of, "<PCFLOW>");
12091   } else if (isPCI(pc) || isPCAD(pc)) {
12092     pc->print (of, pc);
12093   } else {
12094     fprintf (of, "<!PCI>");
12095   }
12096   fprintf (of, "\" ");
12097   fprintf (of, "}\n");
12098   
12099   if (1 && isPCFL(pc)) {
12100     defmap_t *map, *prev;
12101     unsigned int i;
12102     map = PCFL(pc)->defmap;
12103     i=0;
12104     while (map) {
12105       if (map->sym != 0) {
12106         i++;
12107       
12108         /* emit definition node */
12109         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12110         fprintf (of, "label:\"");
12111
12112         prev = map;
12113         do {
12114           fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->access.isRead ? 'R' : ' ', map->access.isWrite ? 'W' : ' ', map->in_val, map->val, map->access.in_mask, map->access.mask, strFromSym (map->sym));
12115           prev = map;
12116           map = map->next;
12117         } while (map && prev->pc == map->pc);
12118         map = prev;
12119         
12120         fprintf (of, "\" ");
12121       
12122         fprintf (of, "color:green ");
12123         fprintf (of, "}\n");
12124
12125         /* emit edge to previous definition */
12126         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12127         if (i == 1) {
12128           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12129         } else {
12130           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12131         }
12132         fprintf (of, "color:green ");
12133         fprintf (of, "}\n");
12134
12135         if (map->pc) {
12136           pic16_vcg_dumpnode (map->pc, of);
12137           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12138           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12139         }
12140       }
12141       map = map->next;
12142     } // while
12143   }
12144
12145   /* emit additional nodes (e.g. operands) */
12146 }
12147
12148 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12149 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12150   char buf[BUF_SIZE];
12151   pCodeInstruction *pci;
12152   pBranch *curr;
12153   int i;
12154   
12155   if (1 && isPCFL(pc)) {
12156     /* emit edges to flow successors */
12157     void *pcfl;
12158     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12159     pcfl = setFirstItem (PCFL(pc)->to);
12160     while (pcfl) {
12161       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12162       pic16_vcg_dumpnode (pc, of);
12163       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12164       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12165       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12166       pcfl = setNextItem (PCFL(pc)->to);
12167     } // while
12168   } // if
12169   
12170   if (!isPCI(pc) && !isPCAD(pc)) return;
12171
12172   pci = PCI(pc);
12173   
12174   /* emit control flow edges (forward only) */
12175   curr = pci->to;
12176   i=0;
12177   while (curr) {
12178     pic16_vcg_dumpnode (curr->pc, of);
12179     fprintf (of, "edge:{");
12180     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12181     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12182     fprintf (of, "color:red ");
12183     fprintf (of, "}\n");
12184     curr = curr->next;
12185   } // while
12186
12187 #if 1
12188   /* dump "flow" edge (link pCode according to pBlock order) */
12189   {
12190     pCode *pcnext;
12191     pcnext = pic16_findNextInstruction (pc->next);
12192     if (pcnext) {
12193       pic16_vcg_dumpnode (pcnext, of);
12194       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12195       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12196     }
12197   }
12198 #endif
12199   
12200 #if 0
12201   /* emit flow */
12202   if (pci->pcflow) {
12203     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12204     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12205     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12206   }
12207 #endif
12208   
12209   /* emit data flow edges (backward only) */
12210   /* TODO: gather data flow information... */
12211 }
12212
12213 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12214   pCode *pc;
12215
12216   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12217   if (pic16_pBlockHasAsmdirs (pb)) {
12218     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12219     return;
12220   }
12221
12222   for (pc=pb->pcHead; pc; pc = pc->next) {
12223     pic16_vcg_dumpnode (pc, of);
12224   } // for pc
12225   
12226   for (pc=pb->pcHead; pc; pc = pc->next) {
12227     pic16_vcg_dumpedges (pc, of);
12228   } // for pc
12229 }
12230
12231 static void pic16_vcg_dump_default (pBlock *pb) {
12232   FILE *of;
12233   char buf[BUF_SIZE];
12234   pCode *pc;
12235
12236   /* get function name */
12237   pc = pb->pcHead;
12238   while (pc && !isPCF(pc)) pc = pc->next;
12239   if (pc) {
12240     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12241   } else {
12242     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12243   }
12244
12245   //fprintf (stderr, "now dumping %s\n", buf);
12246   of = fopen (buf, "w");
12247   pic16_vcg_init (of);
12248   pic16_vcg_dump (of, pb);
12249   pic16_vcg_close (of);
12250   fclose (of);
12251 }
12252 #endif
12253
12254 /*** END of helpers for pCode dataflow optimizations ***/