08a439af3e513863d9b69a3225507ccf8308fdd0
[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 #else
38 #define STRCASECMP strcasecmp
39 #endif
40
41 #define DUMP_DF_GRAPHS 0
42
43 /****************************************************************/
44 /****************************************************************/
45
46 static peepCommand peepCommands[] = {
47
48   {NOTBITSKIP, "_NOTBITSKIP_"},
49   {BITSKIP, "_BITSKIP_"},
50   {INVERTBITSKIP, "_INVERTBITSKIP_"},
51
52   {-1, NULL}
53 };
54
55
56
57 // Eventually this will go into device dependent files:
58 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
59 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
63 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
65
66 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
67 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
68 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
69
70 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
71 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
72 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
74
75 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
76
77 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
78 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
83
84 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
85 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
86 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
89
90 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
91 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
92 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
95
96 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
97 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
98 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
101
102 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
104
105 /* EEPROM registers */
106 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
107 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
110
111 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
112 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
114
115 pCodeOpReg *pic16_stackpnt_lo;
116 pCodeOpReg *pic16_stackpnt_hi;
117 pCodeOpReg *pic16_stack_postinc;
118 pCodeOpReg *pic16_stack_postdec;
119 pCodeOpReg *pic16_stack_preinc;
120 pCodeOpReg *pic16_stack_plusw;
121
122 pCodeOpReg *pic16_framepnt_lo;
123 pCodeOpReg *pic16_framepnt_hi;
124 pCodeOpReg *pic16_frame_postinc;
125 pCodeOpReg *pic16_frame_postdec;
126 pCodeOpReg *pic16_frame_preinc;
127 pCodeOpReg *pic16_frame_plusw;
128
129 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
130 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
131
132 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
133 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
134
135
136 static int mnemonics_initialized = 0;
137
138
139 static hTab *pic16MnemonicsHash = NULL;
140 static hTab *pic16pCodePeepCommandsHash = NULL;
141
142 static pFile *the_pFile = NULL;
143 static pBlock *pb_dead_pcodes = NULL;
144
145 /* Hardcoded flags to change the behavior of the PIC port */
146 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
147 static int functionInlining = 1;      /* inline functions if nonzero */
148 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
149
150 int pic16_pcode_verbose = 0;
151
152 //static int GpCodeSequenceNumber = 1;
153 static int GpcFlowSeq = 1;
154
155 extern void pic16_RemoveUnusedRegisters(void);
156 extern void pic16_RegsUnMapLiveRanges(void);
157 extern void pic16_BuildFlowTree(pBlock *pb);
158 extern void pic16_pCodeRegOptimizeRegUsage(int level);
159 extern int pic16_picIsInitialized(void);
160 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
161 extern int mnem2key(char const *mnem);
162
163 /****************************************************************/
164 /*                      Forward declarations                    */
165 /****************************************************************/
166
167 void pic16_unlinkpCode(pCode *pc);
168 #if 0
169 static void genericAnalyze(pCode *pc);
170 static void AnalyzeGOTO(pCode *pc);
171 static void AnalyzeSKIP(pCode *pc);
172 static void AnalyzeRETURN(pCode *pc);
173 #endif
174
175 static void genericDestruct(pCode *pc);
176 static void genericPrint(FILE *of,pCode *pc);
177
178 static void pCodePrintLabel(FILE *of, pCode *pc);
179 static void pCodePrintFunction(FILE *of, pCode *pc);
180 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
181 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
182 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
183 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
184 int pic16_pCodePeepMatchRule(pCode *pc);
185 static void pBlockStats(FILE *of, pBlock *pb);
186 static pBlock *newpBlock(void);
187 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
188 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
189 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
190 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
191 void OptimizeLocalRegs(void);
192 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
193
194 char *dumpPicOptype(PIC_OPTYPE type);
195
196 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
197 pCodeOp *pic16_popGetLit(int);
198 pCodeOp *pic16_popGetWithString(char *);
199 extern int inWparamList(char *s);
200
201 /** data flow optimization helpers **/
202 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
203 static void pic16_vcg_dump (FILE *of, pBlock *pb);
204 static void pic16_vcg_dump_default (pBlock *pb);
205 #endif
206 static int pic16_pCodeIsAlive (pCode *pc);
207 static void pic16_df_stats ();
208 static void pic16_createDF (pBlock *pb);
209 static int pic16_removeUnusedRegistersDF ();
210 static void pic16_destructDF (pBlock *pb);
211 static void releaseStack ();
212
213 /****************************************************************/
214 /*                    PIC Instructions                          */
215 /****************************************************************/
216
217 pCodeInstruction pic16_pciADDWF = {
218   {PC_OPCODE, NULL, NULL, 0, NULL, 
219    //   genericAnalyze,
220    genericDestruct,
221    genericPrint},
222   POC_ADDWF,
223   "ADDWF",
224   2,
225   NULL, // from branch
226   NULL, // to branch
227   NULL, // label
228   NULL, // operand
229   NULL, // flow block
230   NULL, // C source 
231   3,    // num ops
232   1,0,  // dest, bit instruction
233   0,0,  // branch, skip
234   0,    // literal operand
235   1,    // RAM access bit
236   0,    // fast call/return mode select bit
237   0,    // second memory operand
238   0,    // second literal operand
239   POC_NOP,
240   (PCC_W | PCC_REGISTER),   // inCond
241   (PCC_REGISTER | PCC_STATUS), // outCond
242   PCI_MAGIC
243 };
244
245 pCodeInstruction pic16_pciADDFW = {
246   {PC_OPCODE, NULL, NULL, 0, NULL, 
247    //   genericAnalyze,
248    genericDestruct,
249    genericPrint},
250   POC_ADDFW,
251   "ADDWF",
252   2,
253   NULL, // from branch
254   NULL, // to branch
255   NULL, // label
256   NULL, // operand
257   NULL, // flow block
258   NULL, // C source 
259   3,    // num ops
260   0,0,  // dest, bit instruction
261   0,0,  // branch, skip
262   0,    // literal operand
263   1,    // RAM access bit
264   0,    // fast call/return mode select bit
265   0,    // second memory operand
266   0,    // second literal operand
267   POC_NOP,
268   (PCC_W | PCC_REGISTER),   // inCond
269   (PCC_W | PCC_STATUS), // outCond
270   PCI_MAGIC
271 };
272
273 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
274   {PC_OPCODE, NULL, NULL, 0, NULL, 
275    //   genericAnalyze,
276    genericDestruct,
277    genericPrint},
278   POC_ADDWFC,
279   "ADDWFC",
280   2,
281   NULL, // from branch
282   NULL, // to branch
283   NULL, // label
284   NULL, // operand
285   NULL, // flow block
286   NULL, // C source 
287   3,    // num ops
288   1,0,  // dest, bit instruction
289   0,0,  // branch, skip
290   0,    // literal operand
291   1,    // RAM access bit
292   0,    // fast call/return mode select bit
293   0,    // second memory operand
294   0,    // second literal operand
295   POC_NOP,
296   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
297   (PCC_REGISTER | PCC_STATUS), // outCond
298   PCI_MAGIC
299 };
300
301 pCodeInstruction pic16_pciADDFWC = {
302   {PC_OPCODE, NULL, NULL, 0, NULL, 
303    //   genericAnalyze,
304    genericDestruct,
305    genericPrint},
306   POC_ADDFWC,
307   "ADDWFC",
308   2,
309   NULL, // from branch
310   NULL, // to branch
311   NULL, // label
312   NULL, // operand
313   NULL, // flow block
314   NULL, // C source 
315   3,    // num ops
316   0,0,  // dest, bit instruction
317   0,0,  // branch, skip
318   0,    // literal operand
319   1,    // RAM access bit
320   0,    // fast call/return mode select bit
321   0,    // second memory operand
322   0,    // second literal operand
323   POC_NOP,
324   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
325   (PCC_W | PCC_STATUS), // outCond
326   PCI_MAGIC
327 };
328
329 pCodeInstruction pic16_pciADDLW = {
330   {PC_OPCODE, NULL, NULL, 0, NULL, 
331    //   genericAnalyze,
332    genericDestruct,
333    genericPrint},
334   POC_ADDLW,
335   "ADDLW",
336   2,
337   NULL, // from branch
338   NULL, // to branch
339   NULL, // label
340   NULL, // operand
341   NULL, // flow block
342   NULL, // C source 
343   1,    // num ops
344   0,0,  // dest, bit instruction
345   0,0,  // branch, skip
346   1,    // literal operand
347   0,    // RAM access bit
348   0,    // fast call/return mode select bit
349   0,    // second memory operand
350   0,    // second literal operand
351   POC_NOP,
352   (PCC_W | PCC_LITERAL),   // inCond
353   (PCC_W | PCC_STATUS), // outCond
354   PCI_MAGIC
355 };
356
357 pCodeInstruction pic16_pciANDLW = {
358   {PC_OPCODE, NULL, NULL, 0, NULL, 
359    //   genericAnalyze,
360    genericDestruct,
361    genericPrint},
362   POC_ANDLW,
363   "ANDLW",
364   2,
365   NULL, // from branch
366   NULL, // to branch
367   NULL, // label
368   NULL, // operand
369   NULL, // flow block
370   NULL, // C source 
371   1,    // num ops
372   0,0,  // dest, bit instruction
373   0,0,  // branch, skip
374   1,    // literal operand
375   0,    // RAM access bit
376   0,    // fast call/return mode select bit
377   0,    // second memory operand
378   0,    // second literal operand
379   POC_NOP,
380   (PCC_W | PCC_LITERAL),   // inCond
381   (PCC_W | PCC_Z | PCC_N), // outCond
382   PCI_MAGIC
383 };
384
385 pCodeInstruction pic16_pciANDWF = {
386   {PC_OPCODE, NULL, NULL, 0, NULL, 
387    //   genericAnalyze,
388    genericDestruct,
389    genericPrint},
390   POC_ANDWF,
391   "ANDWF",
392   2,
393   NULL, // from branch
394   NULL, // to branch
395   NULL, // label
396   NULL, // operand
397   NULL, // flow block
398   NULL, // C source 
399   3,    // num ops
400   1,0,  // dest, bit instruction
401   0,0,  // branch, skip
402   0,    // literal operand
403   1,    // RAM access bit
404   0,    // fast call/return mode select bit
405   0,    // second memory operand
406   0,    // second literal operand
407   POC_NOP,
408   (PCC_W | PCC_REGISTER),   // inCond
409   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
410   PCI_MAGIC
411 };
412
413 pCodeInstruction pic16_pciANDFW = {
414   {PC_OPCODE, NULL, NULL, 0, NULL, 
415    //   genericAnalyze,
416    genericDestruct,
417    genericPrint},
418   POC_ANDFW,
419   "ANDWF",
420   2,
421   NULL, // from branch
422   NULL, // to branch
423   NULL, // label
424   NULL, // operand
425   NULL, // flow block
426   NULL, // C source 
427   3,    // num ops
428   0,0,  // dest, bit instruction
429   0,0,  // branch, skip
430   0,    // literal operand
431   1,    // RAM access bit
432   0,    // fast call/return mode select bit
433   0,    // second memory operand
434   0,    // second literal operand
435   POC_NOP,
436   (PCC_W | PCC_REGISTER),   // inCond
437   (PCC_W | PCC_Z | PCC_N) // outCond
438 };
439
440 pCodeInstruction pic16_pciBC = { // mdubuc - New
441   {PC_OPCODE, NULL, NULL, 0, NULL, 
442    //   genericAnalyze,
443    genericDestruct,
444    genericPrint},
445   POC_BC,
446   "BC",
447   2,
448   NULL, // from branch
449   NULL, // to branch
450   NULL, // label
451   NULL, // operand
452   NULL, // flow block
453   NULL, // C source 
454   1,    // num ops
455   0,0,  // dest, bit instruction
456   1,0,  // branch, skip
457   0,    // literal operand
458   0,    // RAM access bit
459   0,    // fast call/return mode select bit
460   0,    // second memory operand
461   0,    // second literal operand
462   POC_NOP,
463   (PCC_REL_ADDR | PCC_C),   // inCond
464   PCC_NONE,    // outCond
465   PCI_MAGIC
466 };
467
468 pCodeInstruction pic16_pciBCF = {
469   {PC_OPCODE, NULL, NULL, 0, NULL, 
470    //   genericAnalyze,
471    genericDestruct,
472    genericPrint},
473   POC_BCF,
474   "BCF",
475   2,
476   NULL, // from branch
477   NULL, // to branch
478   NULL, // label
479   NULL, // operand
480   NULL, // flow block
481   NULL, // C source 
482   3,    // num ops
483   1,1,  // dest, bit instruction
484   0,0,  // branch, skip
485   0,    // literal operand
486   1,    // RAM access bit
487   0,    // fast call/return mode select bit
488   0,    // second memory operand
489   0,    // second literal operand
490   POC_BSF,
491   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
492   PCC_REGISTER, // outCond
493   PCI_MAGIC
494 };
495
496 pCodeInstruction pic16_pciBN = { // mdubuc - New
497   {PC_OPCODE, NULL, NULL, 0, NULL, 
498    //   genericAnalyze,
499    genericDestruct,
500    genericPrint},
501   POC_BN,
502   "BN",
503   2,
504   NULL, // from branch
505   NULL, // to branch
506   NULL, // label
507   NULL, // operand
508   NULL, // flow block
509   NULL, // C source 
510   1,    // num ops
511   0,0,  // dest, bit instruction
512   1,0,  // branch, skip
513   0,    // literal operand
514   0,    // RAM access bit
515   0,    // fast call/return mode select bit
516   0,    // second memory operand
517   0,    // second literal operand
518   POC_NOP,
519   (PCC_REL_ADDR | PCC_N),   // inCond
520   PCC_NONE   , // outCond
521   PCI_MAGIC
522 };
523
524 pCodeInstruction pic16_pciBNC = { // mdubuc - New
525   {PC_OPCODE, NULL, NULL, 0, NULL, 
526    //   genericAnalyze,
527    genericDestruct,
528    genericPrint},
529   POC_BNC,
530   "BNC",
531   2,
532   NULL, // from branch
533   NULL, // to branch
534   NULL, // label
535   NULL, // operand
536   NULL, // flow block
537   NULL, // C source 
538   1,    // num ops
539   0,0,  // dest, bit instruction
540   1,0,  // branch, skip
541   0,    // literal operand
542   0,    // RAM access bit
543   0,    // fast call/return mode select bit
544   0,    // second memory operand
545   0,    // second literal operand
546   POC_NOP,
547   (PCC_REL_ADDR | PCC_C),   // inCond
548   PCC_NONE   , // outCond
549   PCI_MAGIC
550 };
551
552 pCodeInstruction pic16_pciBNN = { // mdubuc - New
553   {PC_OPCODE, NULL, NULL, 0, NULL, 
554    //   genericAnalyze,
555    genericDestruct,
556    genericPrint},
557   POC_BNN,
558   "BNN",
559   2,
560   NULL, // from branch
561   NULL, // to branch
562   NULL, // label
563   NULL, // operand
564   NULL, // flow block
565   NULL, // C source 
566   1,    // num ops
567   0,0,  // dest, bit instruction
568   1,0,  // branch, skip
569   0,    // literal operand
570   0,    // RAM access bit
571   0,    // fast call/return mode select bit
572   0,    // second memory operand
573   0,    // second literal operand
574   POC_NOP,
575   (PCC_REL_ADDR | PCC_N),   // inCond
576   PCC_NONE   , // outCond
577   PCI_MAGIC
578 };
579
580 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
581   {PC_OPCODE, NULL, NULL, 0, NULL, 
582    //   genericAnalyze,
583    genericDestruct,
584    genericPrint},
585   POC_BNOV,
586   "BNOV",
587   2,
588   NULL, // from branch
589   NULL, // to branch
590   NULL, // label
591   NULL, // operand
592   NULL, // flow block
593   NULL, // C source 
594   1,    // num ops
595   0,0,  // dest, bit instruction
596   1,0,  // branch, skip
597   0,    // literal operand
598   0,    // RAM access bit
599   0,    // fast call/return mode select bit
600   0,    // second memory operand
601   0,    // second literal operand
602   POC_NOP,
603   (PCC_REL_ADDR | PCC_OV),   // inCond
604   PCC_NONE   , // outCond
605   PCI_MAGIC
606 };
607
608 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
609   {PC_OPCODE, NULL, NULL, 0, NULL, 
610    //   genericAnalyze,
611    genericDestruct,
612    genericPrint},
613   POC_BNZ,
614   "BNZ",
615   2,
616   NULL, // from branch
617   NULL, // to branch
618   NULL, // label
619   NULL, // operand
620   NULL, // flow block
621   NULL, // C source 
622   1,    // num ops
623   0,0,  // dest, bit instruction
624   1,0,  // branch, skip
625   0,    // literal operand
626   0,    // RAM access bit
627   0,    // fast call/return mode select bit
628   0,    // second memory operand
629   0,    // second literal operand
630   POC_NOP,
631   (PCC_REL_ADDR | PCC_Z),   // inCond
632   PCC_NONE   , // outCond
633   PCI_MAGIC
634 };
635
636 pCodeInstruction pic16_pciBOV = { // mdubuc - New
637   {PC_OPCODE, NULL, NULL, 0, NULL, 
638    //   genericAnalyze,
639    genericDestruct,
640    genericPrint},
641   POC_BOV,
642   "BOV",
643   2,
644   NULL, // from branch
645   NULL, // to branch
646   NULL, // label
647   NULL, // operand
648   NULL, // flow block
649   NULL, // C source 
650   1,    // num ops
651   0,0,  // dest, bit instruction
652   1,0,  // branch, skip
653   0,    // literal operand
654   0,    // RAM access bit
655   0,    // fast call/return mode select bit
656   0,    // second memory operand
657   0,    // second literal operand
658   POC_NOP,
659   (PCC_REL_ADDR | PCC_OV),   // inCond
660   PCC_NONE , // outCond
661   PCI_MAGIC
662 };
663
664 pCodeInstruction pic16_pciBRA = { // mdubuc - New
665   {PC_OPCODE, NULL, NULL, 0, NULL, 
666    //   genericAnalyze,
667    genericDestruct,
668    genericPrint},
669   POC_BRA,
670   "BRA",
671   2,
672   NULL, // from branch
673   NULL, // to branch
674   NULL, // label
675   NULL, // operand
676   NULL, // flow block
677   NULL, // C source 
678   1,    // num ops
679   0,0,  // dest, bit instruction
680   1,0,  // branch, skip
681   0,    // literal operand
682   0,    // RAM access bit
683   0,    // fast call/return mode select bit
684   0,    // second memory operand
685   0,    // second literal operand
686   POC_NOP,
687   PCC_REL_ADDR,   // inCond
688   PCC_NONE   , // outCond
689   PCI_MAGIC
690 };
691
692 pCodeInstruction pic16_pciBSF = {
693   {PC_OPCODE, NULL, NULL, 0, NULL, 
694    //   genericAnalyze,
695    genericDestruct,
696    genericPrint},
697   POC_BSF,
698   "BSF",
699   2,
700   NULL, // from branch
701   NULL, // to branch
702   NULL, // label
703   NULL, // operand
704   NULL, // flow block
705   NULL, // C source 
706   3,    // num ops
707   1,1,  // dest, bit instruction
708   0,0,  // branch, skip
709   0,    // literal operand
710   1,    // RAM access bit
711   0,    // fast call/return mode select bit
712   0,    // second memory operand
713   0,    // second literal operand
714   POC_BCF,
715   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
716   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
717   PCI_MAGIC
718 };
719
720 pCodeInstruction pic16_pciBTFSC = {
721   {PC_OPCODE, NULL, NULL, 0, NULL, 
722    //   AnalyzeSKIP,
723    genericDestruct,
724    genericPrint},
725   POC_BTFSC,
726   "BTFSC",
727   2,
728   NULL, // from branch
729   NULL, // to branch
730   NULL, // label
731   NULL, // operand
732   NULL, // flow block
733   NULL, // C source 
734   3,    // num ops
735   0,1,  // dest, bit instruction
736   1,1,  // branch, skip
737   0,    // literal operand
738   1,    // RAM access bit
739   0,    // fast call/return mode select bit
740   0,    // second memory operand
741   0,    // second literal operand
742   POC_BTFSS,
743   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
744   PCC_EXAMINE_PCOP, // outCond
745   PCI_MAGIC
746 };
747
748 pCodeInstruction pic16_pciBTFSS = {
749   {PC_OPCODE, NULL, NULL, 0, NULL, 
750    //   AnalyzeSKIP,
751    genericDestruct,
752    genericPrint},
753   POC_BTFSS,
754   "BTFSS",
755   2,
756   NULL, // from branch
757   NULL, // to branch
758   NULL, // label
759   NULL, // operand
760   NULL, // flow block
761   NULL, // C source 
762   3,    // num ops
763   0,1,  // dest, bit instruction
764   1,1,  // branch, skip
765   0,    // literal operand
766   1,    // RAM access bit
767   0,    // fast call/return mode select bit
768   0,    // second memory operand
769   0,    // second literal operand
770   POC_BTFSC,
771   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
772   PCC_EXAMINE_PCOP, // outCond
773   PCI_MAGIC
774 };
775
776 pCodeInstruction pic16_pciBTG = { // mdubuc - New
777   {PC_OPCODE, NULL, NULL, 0, NULL, 
778    //   genericAnalyze,
779    genericDestruct,
780    genericPrint},
781   POC_BTG,
782   "BTG",
783   2,
784   NULL, // from branch
785   NULL, // to branch
786   NULL, // label
787   NULL, // operand
788   NULL, // flow block
789   NULL, // C source 
790   3,    // num ops
791   0,1,  // dest, bit instruction
792   0,0,  // branch, skip
793   0,    // literal operand
794   1,    // RAM access bit
795   0,    // fast call/return mode select bit
796   0,    // second memory operand
797   0,    // second literal operand
798   POC_NOP,
799   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
800   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
801   PCI_MAGIC
802 };
803
804 pCodeInstruction pic16_pciBZ = { // mdubuc - New
805   {PC_OPCODE, NULL, NULL, 0, NULL, 
806    //   genericAnalyze,
807    genericDestruct,
808    genericPrint},
809   POC_BZ,
810   "BZ",
811   2,
812   NULL, // from branch
813   NULL, // to branch
814   NULL, // label
815   NULL, // operand
816   NULL, // flow block
817   NULL, // C source 
818   1,    // num ops
819   0,0,  // dest, bit instruction
820   1,0,  // branch, skip
821   0,    // literal operand
822   0,    // RAM access bit
823   0,    // fast call/return mode select bit
824   0,    // second memory operand
825   0,    // second literal operand
826   POC_NOP,
827   (PCC_REL_ADDR | PCC_Z),   // inCond
828   PCC_NONE, // outCond
829   PCI_MAGIC
830 };
831
832 pCodeInstruction pic16_pciCALL = {
833   {PC_OPCODE, NULL, NULL, 0, NULL, 
834    //   genericAnalyze,
835    genericDestruct,
836    genericPrint},
837   POC_CALL,
838   "CALL",
839   4,
840   NULL, // from branch
841   NULL, // to branch
842   NULL, // label
843   NULL, // operand
844   NULL, // flow block
845   NULL, // C source 
846   2,    // num ops
847   0,0,  // dest, bit instruction
848   1,0,  // branch, skip
849   0,    // literal operand
850   0,    // RAM access bit
851   1,    // fast call/return mode select bit
852   0,    // second memory operand
853   0,    // second literal operand
854   POC_NOP,
855   PCC_NONE, // inCond
856   PCC_NONE, // outCond
857   PCI_MAGIC
858 };
859
860 pCodeInstruction pic16_pciCOMF = {
861   {PC_OPCODE, NULL, NULL, 0, NULL, 
862    //   genericAnalyze,
863    genericDestruct,
864    genericPrint},
865   POC_COMF,
866   "COMF",
867   2,
868   NULL, // from branch
869   NULL, // to branch
870   NULL, // label
871   NULL, // operand
872   NULL, // flow block
873   NULL, // C source 
874   3,    // num ops
875   1,0,  // dest, bit instruction
876   0,0,  // branch, skip
877   0,    // literal operand
878   1,    // RAM access bit
879   0,    // fast call/return mode select bit
880   0,    // second memory operand
881   0,    // second literal operand
882   POC_NOP,
883   PCC_REGISTER,  // inCond
884   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
885   PCI_MAGIC
886 };
887
888 pCodeInstruction pic16_pciCOMFW = {
889   {PC_OPCODE, NULL, NULL, 0, NULL, 
890    //   genericAnalyze,
891    genericDestruct,
892    genericPrint},
893   POC_COMFW,
894   "COMF",
895   2,
896   NULL, // from branch
897   NULL, // to branch
898   NULL, // label
899   NULL, // operand
900   NULL, // flow block
901   NULL, // C source 
902   3,    // num ops
903   0,0,  // dest, bit instruction
904   0,0,  // branch, skip
905   0,    // literal operand
906   1,    // RAM access bit
907   0,    // fast call/return mode select bit
908   0,    // second memory operand
909   0,    // second literal operand
910   POC_NOP,
911   PCC_REGISTER,  // inCond
912   (PCC_W | PCC_Z | PCC_N) , // outCond
913   PCI_MAGIC
914 };
915
916 pCodeInstruction pic16_pciCLRF = {
917   {PC_OPCODE, NULL, NULL, 0, NULL, 
918    //   genericAnalyze,
919    genericDestruct,
920    genericPrint},
921   POC_CLRF,
922   "CLRF",
923   2,
924   NULL, // from branch
925   NULL, // to branch
926   NULL, // label
927   NULL, // operand
928   NULL, // flow block
929   NULL, // C source 
930   2,    // num ops
931   0,0,  // dest, bit instruction
932   0,0,  // branch, skip
933   0,    // literal operand
934   1,    // RAM access bit
935   0,    // fast call/return mode select bit
936   0,    // second memory operand
937   0,    // second literal operand
938   POC_NOP,
939   PCC_NONE, // inCond
940   (PCC_REGISTER | PCC_Z), // outCond
941   PCI_MAGIC
942 };
943
944 pCodeInstruction pic16_pciCLRWDT = {
945   {PC_OPCODE, NULL, NULL, 0, NULL, 
946    //   genericAnalyze,
947    genericDestruct,
948    genericPrint},
949   POC_CLRWDT,
950   "CLRWDT",
951   2,
952   NULL, // from branch
953   NULL, // to branch
954   NULL, // label
955   NULL, // operand
956   NULL, // flow block
957   NULL, // C source 
958   0,    // num ops
959   0,0,  // dest, bit instruction
960   0,0,  // branch, skip
961   0,    // literal operand
962   0,    // RAM access bit
963   0,    // fast call/return mode select bit
964   0,    // second memory operand
965   0,    // second literal operand
966   POC_NOP,
967   PCC_NONE, // inCond
968   PCC_NONE , // outCond
969   PCI_MAGIC
970 };
971
972 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
973   {PC_OPCODE, NULL, NULL, 0, NULL, 
974    //   genericAnalyze,
975    genericDestruct,
976    genericPrint},
977   POC_CPFSEQ,
978   "CPFSEQ",
979   2,
980   NULL, // from branch
981   NULL, // to branch
982   NULL, // label
983   NULL, // operand
984   NULL, // flow block
985   NULL, // C source 
986   2,    // num ops
987   0,0,  // dest, bit instruction
988   1,1,  // branch, skip
989   0,    // literal operand
990   1,    // RAM access bit
991   0,    // fast call/return mode select bit
992   0,    // second memory operand
993   0,    // second literal operand
994   POC_NOP,
995   (PCC_W | PCC_REGISTER), // inCond
996   PCC_NONE , // outCond
997   PCI_MAGIC
998 };
999
1000 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1001   {PC_OPCODE, NULL, NULL, 0, NULL, 
1002    //   genericAnalyze,
1003    genericDestruct,
1004    genericPrint},
1005   POC_CPFSGT,
1006   "CPFSGT",
1007   2,
1008   NULL, // from branch
1009   NULL, // to branch
1010   NULL, // label
1011   NULL, // operand
1012   NULL, // flow block
1013   NULL, // C source 
1014   2,    // num ops
1015   0,0,  // dest, bit instruction
1016   1,1,  // branch, skip
1017   0,    // literal operand
1018   1,    // RAM access bit
1019   0,    // fast call/return mode select bit
1020   0,    // second memory operand
1021   0,    // second literal operand
1022   POC_NOP,
1023   (PCC_W | PCC_REGISTER), // inCond
1024   PCC_NONE , // outCond
1025   PCI_MAGIC
1026 };
1027
1028 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1029   {PC_OPCODE, NULL, NULL, 0, NULL, 
1030    //   genericAnalyze,
1031    genericDestruct,
1032    genericPrint},
1033   POC_CPFSLT,
1034   "CPFSLT",
1035   2,
1036   NULL, // from branch
1037   NULL, // to branch
1038   NULL, // label
1039   NULL, // operand
1040   NULL, // flow block
1041   NULL, // C source 
1042   2,    // num ops
1043   1,0,  // dest, bit instruction
1044   1,1,  // branch, skip
1045   0,    // literal operand
1046   1,    // RAM access bit
1047   0,    // fast call/return mode select bit
1048   0,    // second memory operand
1049   0,    // second literal operand
1050   POC_NOP,
1051   (PCC_W | PCC_REGISTER), // inCond
1052   PCC_NONE , // outCond
1053   PCI_MAGIC
1054 };
1055
1056 pCodeInstruction pic16_pciDAW = {
1057   {PC_OPCODE, NULL, NULL, 0, NULL, 
1058    //   genericAnalyze,
1059    genericDestruct,
1060    genericPrint},
1061   POC_DAW,
1062   "DAW",
1063   2,
1064   NULL, // from branch
1065   NULL, // to branch
1066   NULL, // label
1067   NULL, // operand
1068   NULL, // flow block
1069   NULL, // C source 
1070   0,    // num ops
1071   0,0,  // dest, bit instruction
1072   0,0,  // branch, skip
1073   0,    // literal operand
1074   0,    // RAM access bit
1075   0,    // fast call/return mode select bit
1076   0,    // second memory operand
1077   0,    // second literal operand
1078   POC_NOP,
1079   PCC_W, // inCond
1080   (PCC_W | PCC_C), // outCond
1081   PCI_MAGIC
1082 };
1083
1084 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1085   {PC_OPCODE, NULL, NULL, 0, NULL, 
1086    //   genericAnalyze,
1087    genericDestruct,
1088    genericPrint},
1089   POC_DCFSNZ,
1090   "DCFSNZ",
1091   2,
1092   NULL, // from branch
1093   NULL, // to branch
1094   NULL, // label
1095   NULL, // operand
1096   NULL, // flow block
1097   NULL, // C source 
1098   3,    // num ops
1099   1,0,  // dest, bit instruction
1100   1,1,  // branch, skip
1101   0,    // literal operand
1102   1,    // RAM access bit
1103   0,    // fast call/return mode select bit
1104   0,    // second memory operand
1105   0,    // second literal operand
1106   POC_NOP,
1107   PCC_REGISTER, // inCond
1108   PCC_REGISTER , // outCond
1109   PCI_MAGIC
1110 };
1111
1112 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1113   {PC_OPCODE, NULL, NULL, 0, NULL, 
1114    //   genericAnalyze,
1115    genericDestruct,
1116    genericPrint},
1117   POC_DCFSNZW,
1118   "DCFSNZ",
1119   2,
1120   NULL, // from branch
1121   NULL, // to branch
1122   NULL, // label
1123   NULL, // operand
1124   NULL, // flow block
1125   NULL, // C source 
1126   3,    // num ops
1127   0,0,  // dest, bit instruction
1128   1,1,  // branch, skip
1129   0,    // literal operand
1130   1,    // RAM access bit
1131   0,    // fast call/return mode select bit
1132   0,    // second memory operand
1133   0,    // second literal operand
1134   POC_NOP,
1135   PCC_REGISTER, // inCond
1136   PCC_W , // outCond
1137   PCI_MAGIC
1138 };
1139
1140 pCodeInstruction pic16_pciDECF = {
1141   {PC_OPCODE, NULL, NULL, 0, NULL, 
1142    //   genericAnalyze,
1143    genericDestruct,
1144    genericPrint},
1145   POC_DECF,
1146   "DECF",
1147   2,
1148   NULL, // from branch
1149   NULL, // to branch
1150   NULL, // label
1151   NULL, // operand
1152   NULL, // flow block
1153   NULL, // C source 
1154   3,    // num ops
1155   1,0,  // dest, bit instruction
1156   0,0,  // branch, skip
1157   0,    // literal operand
1158   1,    // RAM access bit
1159   0,    // fast call/return mode select bit
1160   0,    // second memory operand
1161   0,    // second literal operand
1162   POC_NOP,
1163   PCC_REGISTER,   // inCond
1164   (PCC_REGISTER | PCC_STATUS)  , // outCond
1165   PCI_MAGIC
1166 };
1167
1168 pCodeInstruction pic16_pciDECFW = {
1169   {PC_OPCODE, NULL, NULL, 0, NULL, 
1170    //   genericAnalyze,
1171    genericDestruct,
1172    genericPrint},
1173   POC_DECFW,
1174   "DECF",
1175   2,
1176   NULL, // from branch
1177   NULL, // to branch
1178   NULL, // label
1179   NULL, // operand
1180   NULL, // flow block
1181   NULL, // C source 
1182   3,    // num ops
1183   0,0,  // dest, bit instruction
1184   0,0,  // branch, skip
1185   0,    // literal operand
1186   1,    // RAM access bit
1187   0,    // fast call/return mode select bit
1188   0,    // second memory operand
1189   0,    // second literal operand
1190   POC_NOP,
1191   PCC_REGISTER,   // inCond
1192   (PCC_W | PCC_STATUS)  , // outCond
1193   PCI_MAGIC
1194 };
1195
1196 pCodeInstruction pic16_pciDECFSZ = {
1197   {PC_OPCODE, NULL, NULL, 0, NULL, 
1198    //   AnalyzeSKIP,
1199    genericDestruct,
1200    genericPrint},
1201   POC_DECFSZ,
1202   "DECFSZ",
1203   2,
1204   NULL, // from branch
1205   NULL, // to branch
1206   NULL, // label
1207   NULL, // operand
1208   NULL, // flow block
1209   NULL, // C source 
1210   3,    // num ops
1211   1,0,  // dest, bit instruction
1212   1,1,  // branch, skip
1213   0,    // literal operand
1214   1,    // RAM access bit
1215   0,    // fast call/return mode select bit
1216   0,    // second memory operand
1217   0,    // second literal operand
1218   POC_NOP,
1219   PCC_REGISTER,   // inCond
1220   PCC_REGISTER   , // outCond
1221   PCI_MAGIC
1222 };
1223
1224 pCodeInstruction pic16_pciDECFSZW = {
1225   {PC_OPCODE, NULL, NULL, 0, NULL, 
1226    //   AnalyzeSKIP,
1227    genericDestruct,
1228    genericPrint},
1229   POC_DECFSZW,
1230   "DECFSZ",
1231   2,
1232   NULL, // from branch
1233   NULL, // to branch
1234   NULL, // label
1235   NULL, // operand
1236   NULL, // flow block
1237   NULL, // C source 
1238   3,    // num ops
1239   0,0,  // dest, bit instruction
1240   1,1,  // branch, skip
1241   0,    // literal operand
1242   1,    // RAM access bit
1243   0,    // fast call/return mode select bit
1244   0,    // second memory operand
1245   0,    // second literal operand
1246   POC_NOP,
1247   PCC_REGISTER,   // inCond
1248   PCC_W          , // outCond
1249   PCI_MAGIC
1250 };
1251
1252 pCodeInstruction pic16_pciGOTO = {
1253   {PC_OPCODE, NULL, NULL, 0, NULL, 
1254    //   AnalyzeGOTO,
1255    genericDestruct,
1256    genericPrint},
1257   POC_GOTO,
1258   "GOTO",
1259   4,
1260   NULL, // from branch
1261   NULL, // to branch
1262   NULL, // label
1263   NULL, // operand
1264   NULL, // flow block
1265   NULL, // C source 
1266   1,    // num ops
1267   0,0,  // dest, bit instruction
1268   1,0,  // branch, skip
1269   0,    // literal operand
1270   0,    // RAM access bit
1271   0,    // fast call/return mode select bit
1272   0,    // second memory operand
1273   0,    // second literal operand
1274   POC_NOP,
1275   PCC_REL_ADDR,   // inCond
1276   PCC_NONE   , // outCond
1277   PCI_MAGIC
1278 };
1279
1280 pCodeInstruction pic16_pciINCF = {
1281   {PC_OPCODE, NULL, NULL, 0, NULL, 
1282    //   genericAnalyze,
1283    genericDestruct,
1284    genericPrint},
1285   POC_INCF,
1286   "INCF",
1287   2,
1288   NULL, // from branch
1289   NULL, // to branch
1290   NULL, // label
1291   NULL, // operand
1292   NULL, // flow block
1293   NULL, // C source 
1294   3,    // num ops
1295   1,0,  // dest, bit instruction
1296   0,0,  // branch, skip
1297   0,    // literal operand
1298   1,    // RAM access bit
1299   0,    // fast call/return mode select bit
1300   0,    // second memory operand
1301   0,    // second literal operand
1302   POC_NOP,
1303   PCC_REGISTER,   // inCond
1304   (PCC_REGISTER | PCC_STATUS), // outCond
1305   PCI_MAGIC
1306 };
1307
1308 pCodeInstruction pic16_pciINCFW = {
1309   {PC_OPCODE, NULL, NULL, 0, NULL, 
1310    //   genericAnalyze,
1311    genericDestruct,
1312    genericPrint},
1313   POC_INCFW,
1314   "INCF",
1315   2,
1316   NULL, // from branch
1317   NULL, // to branch
1318   NULL, // label
1319   NULL, // operand
1320   NULL, // flow block
1321   NULL, // C source 
1322   3,    // num ops
1323   0,0,  // dest, bit instruction
1324   0,0,  // branch, skip
1325   0,    // literal operand
1326   1,    // RAM access bit
1327   0,    // fast call/return mode select bit
1328   0,    // second memory operand
1329   0,    // second literal operand
1330   POC_NOP,
1331   PCC_REGISTER,   // inCond
1332   (PCC_W | PCC_STATUS)  , // outCond
1333   PCI_MAGIC
1334 };
1335
1336 pCodeInstruction pic16_pciINCFSZ = {
1337   {PC_OPCODE, NULL, NULL, 0, NULL, 
1338    //   AnalyzeSKIP,
1339    genericDestruct,
1340    genericPrint},
1341   POC_INCFSZ,
1342   "INCFSZ",
1343   2,
1344   NULL, // from branch
1345   NULL, // to branch
1346   NULL, // label
1347   NULL, // operand
1348   NULL, // flow block
1349   NULL, // C source 
1350   3,    // num ops
1351   1,0,  // dest, bit instruction
1352   1,1,  // branch, skip
1353   0,    // literal operand
1354   1,    // RAM access bit
1355   0,    // fast call/return mode select bit
1356   0,    // second memory operand
1357   0,    // second literal operand
1358   POC_INFSNZ,
1359   PCC_REGISTER,   // inCond
1360   PCC_REGISTER   , // outCond
1361   PCI_MAGIC
1362 };
1363
1364 pCodeInstruction pic16_pciINCFSZW = {
1365   {PC_OPCODE, NULL, NULL, 0, NULL, 
1366    //   AnalyzeSKIP,
1367    genericDestruct,
1368    genericPrint},
1369   POC_INCFSZW,
1370   "INCFSZ",
1371   2,
1372   NULL, // from branch
1373   NULL, // to branch
1374   NULL, // label
1375   NULL, // operand
1376   NULL, // flow block
1377   NULL, // C source 
1378   3,    // num ops
1379   0,0,  // dest, bit instruction
1380   1,1,  // branch, skip
1381   0,    // literal operand
1382   1,    // RAM access bit
1383   0,    // fast call/return mode select bit
1384   0,    // second memory operand
1385   0,    // second literal operand
1386   POC_INFSNZW,
1387   PCC_REGISTER,   // inCond
1388   PCC_W          , // outCond
1389   PCI_MAGIC
1390 };
1391
1392 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1393   {PC_OPCODE, NULL, NULL, 0, NULL, 
1394    //   AnalyzeSKIP,
1395    genericDestruct,
1396    genericPrint},
1397   POC_INFSNZ,
1398   "INFSNZ",
1399   2,
1400   NULL, // from branch
1401   NULL, // to branch
1402   NULL, // label
1403   NULL, // operand
1404   NULL, // flow block
1405   NULL, // C source 
1406   3,    // num ops
1407   1,0,  // dest, bit instruction
1408   1,1,  // branch, skip
1409   0,    // literal operand
1410   1,    // RAM access bit
1411   0,    // fast call/return mode select bit
1412   0,    // second memory operand
1413   0,    // second literal operand
1414   POC_INCFSZ,
1415   PCC_REGISTER,   // inCond
1416   PCC_REGISTER   , // outCond
1417   PCI_MAGIC
1418 };
1419
1420 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1421   {PC_OPCODE, NULL, NULL, 0, NULL, 
1422    //   AnalyzeSKIP,
1423    genericDestruct,
1424    genericPrint},
1425   POC_INFSNZW,
1426   "INFSNZ",
1427   2,
1428   NULL, // from branch
1429   NULL, // to branch
1430   NULL, // label
1431   NULL, // operand
1432   NULL, // flow block
1433   NULL, // C source 
1434   3,    // num ops
1435   0,0,  // dest, bit instruction
1436   1,1,  // branch, skip
1437   0,    // literal operand
1438   1,    // RAM access bit
1439   0,    // fast call/return mode select bit
1440   0,    // second memory operand
1441   0,    // second literal operand
1442   POC_INCFSZW,
1443   PCC_REGISTER,   // inCond
1444   PCC_W          , // outCond
1445   PCI_MAGIC
1446 };
1447
1448 pCodeInstruction pic16_pciIORWF = {
1449   {PC_OPCODE, NULL, NULL, 0, NULL, 
1450    //   genericAnalyze,
1451    genericDestruct,
1452    genericPrint},
1453   POC_IORWF,
1454   "IORWF",
1455   2,
1456   NULL, // from branch
1457   NULL, // to branch
1458   NULL, // label
1459   NULL, // operand
1460   NULL, // flow block
1461   NULL, // C source 
1462   3,    // num ops
1463   1,0,  // dest, bit instruction
1464   0,0,  // branch, skip
1465   0,    // literal operand
1466   1,    // RAM access bit
1467   0,    // fast call/return mode select bit
1468   0,    // second memory operand
1469   0,    // second literal operand
1470   POC_NOP,
1471   (PCC_W | PCC_REGISTER),   // inCond
1472   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1473   PCI_MAGIC
1474 };
1475
1476 pCodeInstruction pic16_pciIORFW = {
1477   {PC_OPCODE, NULL, NULL, 0, NULL, 
1478    //   genericAnalyze,
1479    genericDestruct,
1480    genericPrint},
1481   POC_IORFW,
1482   "IORWF",
1483   2,
1484   NULL, // from branch
1485   NULL, // to branch
1486   NULL, // label
1487   NULL, // operand
1488   NULL, // flow block
1489   NULL, // C source 
1490   3,    // num ops
1491   0,0,  // dest, bit instruction
1492   0,0,  // branch, skip
1493   0,    // literal operand
1494   1,    // RAM access bit
1495   0,    // fast call/return mode select bit
1496   0,    // second memory operand
1497   0,    // second literal operand
1498   POC_NOP,
1499   (PCC_W | PCC_REGISTER),   // inCond
1500   (PCC_W | PCC_Z | PCC_N), // outCond
1501   PCI_MAGIC
1502 };
1503
1504 pCodeInstruction pic16_pciIORLW = {
1505   {PC_OPCODE, NULL, NULL, 0, NULL, 
1506    //   genericAnalyze,
1507    genericDestruct,
1508    genericPrint},
1509   POC_IORLW,
1510   "IORLW",
1511   2,
1512   NULL, // from branch
1513   NULL, // to branch
1514   NULL, // label
1515   NULL, // operand
1516   NULL, // flow block
1517   NULL, // C source 
1518   1,    // num ops
1519   0,0,  // dest, bit instruction
1520   0,0,  // branch, skip
1521   1,    // literal operand
1522   0,    // RAM access bit
1523   0,    // fast call/return mode select bit
1524   0,    // second memory operand
1525   0,    // second literal operand
1526   POC_NOP,
1527   (PCC_W | PCC_LITERAL),   // inCond
1528   (PCC_W | PCC_Z | PCC_N), // outCond
1529   PCI_MAGIC
1530 };
1531
1532 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1533   {PC_OPCODE, NULL, NULL, 0, NULL, 
1534    //   genericAnalyze,
1535    genericDestruct,
1536    genericPrint},
1537   POC_LFSR,
1538   "LFSR",
1539   4,
1540   NULL, // from branch
1541   NULL, // to branch
1542   NULL, // label
1543   NULL, // operand
1544   NULL, // flow block
1545   NULL, // C source 
1546   2,    // num ops
1547   0,0,  // dest, bit instruction
1548   0,0,  // branch, skip
1549   1,    // literal operand
1550   0,    // RAM access bit
1551   0,    // fast call/return mode select bit
1552   0,    // second memory operand
1553   1,    // second literal operand
1554   POC_NOP,
1555   PCC_LITERAL, // inCond
1556   PCC_NONE, // outCond
1557   PCI_MAGIC
1558 };
1559
1560 pCodeInstruction pic16_pciMOVF = {
1561   {PC_OPCODE, NULL, NULL, 0, NULL, 
1562    //   genericAnalyze,
1563    genericDestruct,
1564    genericPrint},
1565   POC_MOVF,
1566   "MOVF",
1567   2,
1568   NULL, // from branch
1569   NULL, // to branch
1570   NULL, // label
1571   NULL, // operand
1572   NULL, // flow block
1573   NULL, // C source 
1574   3,    // num ops
1575   1,0,  // dest, bit instruction
1576   0,0,  // branch, skip
1577   0,    // literal operand
1578   1,    // RAM access bit
1579   0,    // fast call/return mode select bit
1580   0,    // second memory operand
1581   0,    // second literal operand
1582   POC_NOP,
1583   PCC_REGISTER,   // inCond
1584   (PCC_Z | PCC_N), // outCond
1585   PCI_MAGIC
1586 };
1587
1588 pCodeInstruction pic16_pciMOVFW = {
1589   {PC_OPCODE, NULL, NULL, 0, NULL, 
1590    //   genericAnalyze,
1591    genericDestruct,
1592    genericPrint},
1593   POC_MOVFW,
1594   "MOVF",
1595   2,
1596   NULL, // from branch
1597   NULL, // to branch
1598   NULL, // label
1599   NULL, // operand
1600   NULL, // flow block
1601   NULL, // C source 
1602   3,    // num ops
1603   0,0,  // dest, bit instruction
1604   0,0,  // branch, skip
1605   0,    // literal operand
1606   1,    // RAM access bit
1607   0,    // fast call/return mode select bit
1608   0,    // second memory operand
1609   0,    // second literal operand
1610   POC_NOP,
1611   PCC_REGISTER,   // inCond
1612   (PCC_W | PCC_N | PCC_Z), // outCond
1613   PCI_MAGIC
1614 };
1615
1616 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1617   {PC_OPCODE, NULL, NULL, 0, NULL, 
1618    //   genericAnalyze,
1619    genericDestruct,
1620    genericPrint},
1621   POC_MOVFF,
1622   "MOVFF",
1623   4,
1624   NULL, // from branch
1625   NULL, // to branch
1626   NULL, // label
1627   NULL, // operand
1628   NULL, // flow block
1629   NULL, // C source 
1630   2,    // num ops
1631   0,0,  // dest, bit instruction
1632   0,0,  // branch, skip
1633   0,    // literal operand
1634   0,    // RAM access bit
1635   0,    // fast call/return mode select bit
1636   1,    // second memory operand
1637   0,    // second literal operand
1638   POC_NOP,
1639   PCC_REGISTER,   // inCond
1640   PCC_REGISTER2, // outCond
1641   PCI_MAGIC
1642 };
1643
1644 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1645   {PC_OPCODE, NULL, NULL, 0, NULL, 
1646    genericDestruct,
1647    genericPrint},
1648   POC_MOVLB,
1649   "MOVLB",
1650   2,
1651   NULL, // from branch
1652   NULL, // to branch
1653   NULL, // label
1654   NULL, // operand
1655   NULL, // flow block
1656   NULL, // C source 
1657   1,    // num ops
1658   0,0,  // dest, bit instruction
1659   0,0,  // branch, skip
1660   1,    // literal operand
1661   0,    // RAM access bit
1662   0,    // fast call/return mode select bit
1663   0,    // second memory operand
1664   0,    // second literal operand
1665   POC_NOP,
1666   (PCC_NONE | PCC_LITERAL),   // inCond
1667   PCC_REGISTER, // outCond - BSR
1668   PCI_MAGIC
1669 };
1670
1671 pCodeInstruction pic16_pciMOVLW = {
1672   {PC_OPCODE, NULL, NULL, 0, NULL, 
1673    genericDestruct,
1674    genericPrint},
1675   POC_MOVLW,
1676   "MOVLW",
1677   2,
1678   NULL, // from branch
1679   NULL, // to branch
1680   NULL, // label
1681   NULL, // operand
1682   NULL, // flow block
1683   NULL, // C source 
1684   1,    // num ops
1685   0,0,  // dest, bit instruction
1686   0,0,  // branch, skip
1687   1,    // literal operand
1688   0,    // RAM access bit
1689   0,    // fast call/return mode select bit
1690   0,    // second memory operand
1691   0,    // second literal operand
1692   POC_NOP,
1693   (PCC_NONE | PCC_LITERAL),   // inCond
1694   PCC_W, // outCond
1695   PCI_MAGIC
1696 };
1697
1698 pCodeInstruction pic16_pciMOVWF = {
1699   {PC_OPCODE, NULL, NULL, 0, NULL, 
1700    //   genericAnalyze,
1701    genericDestruct,
1702    genericPrint},
1703   POC_MOVWF,
1704   "MOVWF",
1705   2,
1706   NULL, // from branch
1707   NULL, // to branch
1708   NULL, // label
1709   NULL, // operand
1710   NULL, // flow block
1711   NULL, // C source 
1712   2,    // num ops
1713   0,0,  // dest, bit instruction
1714   0,0,  // branch, skip
1715   0,    // literal operand
1716   1,    // RAM access bit
1717   0,    // fast call/return mode select bit
1718   0,    // second memory operand
1719   0,    // second literal operand
1720   POC_NOP,
1721   PCC_W,   // inCond
1722   PCC_REGISTER, // outCond
1723   PCI_MAGIC
1724 };
1725
1726 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1727   {PC_OPCODE, NULL, NULL, 0, NULL, 
1728    genericDestruct,
1729    genericPrint},
1730   POC_MULLW,
1731   "MULLW",
1732   2,
1733   NULL, // from branch
1734   NULL, // to branch
1735   NULL, // label
1736   NULL, // operand
1737   NULL, // flow block
1738   NULL, // C source 
1739   1,    // num ops
1740   0,0,  // dest, bit instruction
1741   0,0,  // branch, skip
1742   1,    // literal operand
1743   0,    // RAM access bit
1744   0,    // fast call/return mode select bit
1745   0,    // second memory operand
1746   0,    // second literal operand
1747   POC_NOP,
1748   (PCC_W | PCC_LITERAL),   // inCond
1749   PCC_NONE, // outCond - PROD
1750   PCI_MAGIC
1751 };
1752
1753 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1754   {PC_OPCODE, NULL, NULL, 0, NULL, 
1755    genericDestruct,
1756    genericPrint},
1757   POC_MULWF,
1758   "MULWF",
1759   2,
1760   NULL, // from branch
1761   NULL, // to branch
1762   NULL, // label
1763   NULL, // operand
1764   NULL, // flow block
1765   NULL, // C source 
1766   2,    // num ops
1767   0,0,  // dest, bit instruction
1768   0,0,  // branch, skip
1769   0,    // literal operand
1770   1,    // RAM access bit
1771   0,    // fast call/return mode select bit
1772   0,    // second memory operand
1773   0,    // second literal operand
1774   POC_NOP,
1775   (PCC_W | PCC_REGISTER),   // inCond
1776   PCC_REGISTER, // outCond - PROD
1777   PCI_MAGIC
1778 };
1779
1780 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1781   {PC_OPCODE, NULL, NULL, 0, NULL, 
1782    genericDestruct,
1783    genericPrint},
1784   POC_NEGF,
1785   "NEGF",
1786   2,
1787   NULL, // from branch
1788   NULL, // to branch
1789   NULL, // label
1790   NULL, // operand
1791   NULL, // flow block
1792   NULL, // C source 
1793   2,    // num ops
1794   0,0,  // dest, bit instruction
1795   0,0,  // branch, skip
1796   0,    // literal operand
1797   1,    // RAM access bit
1798   0,    // fast call/return mode select bit
1799   0,    // second memory operand
1800   0,    // second literal operand
1801   POC_NOP,
1802   PCC_REGISTER, // inCond
1803   (PCC_REGISTER | PCC_STATUS), // outCond
1804   PCI_MAGIC
1805 };
1806
1807 pCodeInstruction pic16_pciNOP = {
1808   {PC_OPCODE, NULL, NULL, 0, NULL, 
1809    genericDestruct,
1810    genericPrint},
1811   POC_NOP,
1812   "NOP",
1813   2,
1814   NULL, // from branch
1815   NULL, // to branch
1816   NULL, // label
1817   NULL, // operand
1818   NULL, // flow block
1819   NULL, // C source 
1820   0,    // num ops
1821   0,0,  // dest, bit instruction
1822   0,0,  // branch, skip
1823   0,    // literal operand
1824   0,    // RAM access bit
1825   0,    // fast call/return mode select bit
1826   0,    // second memory operand
1827   0,    // second literal operand
1828   POC_NOP,
1829   PCC_NONE,   // inCond
1830   PCC_NONE, // outCond
1831   PCI_MAGIC
1832 };
1833
1834 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1835   {PC_OPCODE, NULL, NULL, 0, NULL, 
1836    genericDestruct,
1837    genericPrint},
1838   POC_POP,
1839   "POP",
1840   2,
1841   NULL, // from branch
1842   NULL, // to branch
1843   NULL, // label
1844   NULL, // operand
1845   NULL, // flow block
1846   NULL, // C source 
1847   0,    // num ops
1848   0,0,  // dest, bit instruction
1849   0,0,  // branch, skip
1850   0,    // literal operand
1851   0,    // RAM access bit
1852   0,    // fast call/return mode select bit
1853   0,    // second memory operand
1854   0,    // second literal operand
1855   POC_NOP,
1856   PCC_NONE,  // inCond
1857   PCC_NONE  , // outCond
1858   PCI_MAGIC
1859 };
1860
1861 pCodeInstruction pic16_pciPUSH = {
1862   {PC_OPCODE, NULL, NULL, 0, NULL, 
1863    genericDestruct,
1864    genericPrint},
1865   POC_PUSH,
1866   "PUSH",
1867   2,
1868   NULL, // from branch
1869   NULL, // to branch
1870   NULL, // label
1871   NULL, // operand
1872   NULL, // flow block
1873   NULL, // C source 
1874   0,    // num ops
1875   0,0,  // dest, bit instruction
1876   0,0,  // branch, skip
1877   0,    // literal operand
1878   0,    // RAM access bit
1879   0,    // fast call/return mode select bit
1880   0,    // second memory operand
1881   0,    // second literal operand
1882   POC_NOP,
1883   PCC_NONE,  // inCond
1884   PCC_NONE  , // outCond
1885   PCI_MAGIC
1886 };
1887
1888 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1889   {PC_OPCODE, NULL, NULL, 0, NULL, 
1890    genericDestruct,
1891    genericPrint},
1892   POC_RCALL,
1893   "RCALL",
1894   2,
1895   NULL, // from branch
1896   NULL, // to branch
1897   NULL, // label
1898   NULL, // operand
1899   NULL, // flow block
1900   NULL, // C source 
1901   1,    // num ops
1902   0,0,  // dest, bit instruction
1903   1,0,  // branch, skip
1904   0,    // literal operand
1905   0,    // RAM access bit
1906   0,    // fast call/return mode select bit
1907   0,    // second memory operand
1908   0,    // second literal operand
1909   POC_NOP,
1910   PCC_REL_ADDR,  // inCond
1911   PCC_NONE  , // outCond
1912   PCI_MAGIC
1913 };
1914
1915 pCodeInstruction pic16_pciRETFIE = {
1916   {PC_OPCODE, NULL, NULL, 0, NULL, 
1917    //   AnalyzeRETURN,
1918    genericDestruct,
1919    genericPrint},
1920   POC_RETFIE,
1921   "RETFIE",
1922   2,
1923   NULL, // from branch
1924   NULL, // to branch
1925   NULL, // label
1926   NULL, // operand
1927   NULL, // flow block
1928   NULL, // C source 
1929   1,    // num ops
1930   0,0,  // dest, bit instruction
1931   1,0,  // branch, skip
1932   0,    // literal operand
1933   0,    // RAM access bit
1934   1,    // fast call/return mode select bit
1935   0,    // second memory operand
1936   0,    // second literal operand
1937   POC_NOP,
1938   PCC_NONE,   // inCond
1939   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1940   PCI_MAGIC
1941 };
1942
1943 pCodeInstruction pic16_pciRETLW = {
1944   {PC_OPCODE, NULL, NULL, 0, NULL, 
1945    //   AnalyzeRETURN,
1946    genericDestruct,
1947    genericPrint},
1948   POC_RETLW,
1949   "RETLW",
1950   2,
1951   NULL, // from branch
1952   NULL, // to branch
1953   NULL, // label
1954   NULL, // operand
1955   NULL, // flow block
1956   NULL, // C source 
1957   1,    // num ops
1958   0,0,  // dest, bit instruction
1959   1,0,  // branch, skip
1960   1,    // literal operand
1961   0,    // RAM access bit
1962   0,    // fast call/return mode select bit
1963   0,    // second memory operand
1964   0,    // second literal operand
1965   POC_NOP,
1966   PCC_LITERAL,   // inCond
1967   PCC_W, // outCond
1968   PCI_MAGIC
1969 };
1970
1971 pCodeInstruction pic16_pciRETURN = {
1972   {PC_OPCODE, NULL, NULL, 0, NULL, 
1973    //   AnalyzeRETURN,
1974    genericDestruct,
1975    genericPrint},
1976   POC_RETURN,
1977   "RETURN",
1978   2,
1979   NULL, // from branch
1980   NULL, // to branch
1981   NULL, // label
1982   NULL, // operand
1983   NULL, // flow block
1984   NULL, // C source 
1985   1,    // num ops
1986   0,0,  // dest, bit instruction
1987   1,0,  // branch, skip
1988   0,    // literal operand
1989   0,    // RAM access bit
1990   1,    // fast call/return mode select bit
1991   0,    // second memory operand
1992   0,    // second literal operand
1993   POC_NOP,
1994   PCC_NONE,   // inCond
1995   PCC_NONE, // outCond
1996   PCI_MAGIC
1997 };
1998 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1999   {PC_OPCODE, NULL, NULL, 0, NULL, 
2000    //   genericAnalyze,
2001    genericDestruct,
2002    genericPrint},
2003   POC_RLCF,
2004   "RLCF",
2005   2,
2006   NULL, // from branch
2007   NULL, // to branch
2008   NULL, // label
2009   NULL, // operand
2010   NULL, // flow block
2011   NULL, // C source 
2012   3,    // num ops
2013   1,0,  // dest, bit instruction
2014   0,0,  // branch, skip
2015   0,    // literal operand
2016   1,    // RAM access bit
2017   0,    // fast call/return mode select bit
2018   0,    // second memory operand
2019   0,    // second literal operand
2020   POC_NOP,
2021   (PCC_C | PCC_REGISTER),   // inCond
2022   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2023   PCI_MAGIC
2024 };
2025
2026 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2027   {PC_OPCODE, NULL, NULL, 0, NULL, 
2028    //   genericAnalyze,
2029    genericDestruct,
2030    genericPrint},
2031   POC_RLCFW,
2032   "RLCF",
2033   2,
2034   NULL, // from branch
2035   NULL, // to branch
2036   NULL, // label
2037   NULL, // operand
2038   NULL, // flow block
2039   NULL, // C source 
2040   3,    // num ops
2041   0,0,  // dest, bit instruction
2042   0,0,  // branch, skip
2043   0,    // literal operand
2044   1,    // RAM access bit
2045   0,    // fast call/return mode select bit
2046   0,    // second memory operand
2047   0,    // second literal operand
2048   POC_NOP,
2049   (PCC_C | PCC_REGISTER),   // inCond
2050   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2051   PCI_MAGIC
2052 };
2053
2054 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2055   {PC_OPCODE, NULL, NULL, 0, NULL, 
2056    //   genericAnalyze,
2057    genericDestruct,
2058    genericPrint},
2059   POC_RLNCF,
2060   "RLNCF",
2061   2,
2062   NULL, // from branch
2063   NULL, // to branch
2064   NULL, // label
2065   NULL, // operand
2066   NULL, // flow block
2067   NULL, // C source 
2068   3,    // num ops
2069   1,0,  // dest, bit instruction
2070   0,0,  // branch, skip
2071   0,    // literal operand
2072   1,    // RAM access bit
2073   0,    // fast call/return mode select bit
2074   0,    // second memory operand
2075   0,    // second literal operand
2076   POC_NOP,
2077   PCC_REGISTER,   // inCond
2078   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2079   PCI_MAGIC
2080 };
2081 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2082   {PC_OPCODE, NULL, NULL, 0, NULL, 
2083    //   genericAnalyze,
2084    genericDestruct,
2085    genericPrint},
2086   POC_RLNCFW,
2087   "RLNCF",
2088   2,
2089   NULL, // from branch
2090   NULL, // to branch
2091   NULL, // label
2092   NULL, // operand
2093   NULL, // flow block
2094   NULL, // C source 
2095   3,    // num ops
2096   0,0,  // dest, bit instruction
2097   0,0,  // branch, skip
2098   0,    // literal operand
2099   1,    // RAM access bit
2100   0,    // fast call/return mode select bit
2101   0,    // second memory operand
2102   0,    // second literal operand
2103   POC_NOP,
2104   PCC_REGISTER,   // inCond
2105   (PCC_W | PCC_Z | PCC_N), // outCond
2106   PCI_MAGIC
2107 };
2108 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2109   {PC_OPCODE, NULL, NULL, 0, NULL, 
2110    //   genericAnalyze,
2111    genericDestruct,
2112    genericPrint},
2113   POC_RRCF,
2114   "RRCF",
2115   2,
2116   NULL, // from branch
2117   NULL, // to branch
2118   NULL, // label
2119   NULL, // operand
2120   NULL, // flow block
2121   NULL, // C source 
2122   3,    // num ops
2123   1,0,  // dest, bit instruction
2124   0,0,  // branch, skip
2125   0,    // literal operand
2126   1,    // RAM access bit
2127   0,    // fast call/return mode select bit
2128   0,    // second memory operand
2129   0,    // second literal operand
2130   POC_NOP,
2131   (PCC_C | PCC_REGISTER),   // inCond
2132   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2133   PCI_MAGIC
2134 };
2135 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2136   {PC_OPCODE, NULL, NULL, 0, NULL, 
2137    //   genericAnalyze,
2138    genericDestruct,
2139    genericPrint},
2140   POC_RRCFW,
2141   "RRCF",
2142   2,
2143   NULL, // from branch
2144   NULL, // to branch
2145   NULL, // label
2146   NULL, // operand
2147   NULL, // flow block
2148   NULL, // C source 
2149   3,    // num ops
2150   0,0,  // dest, bit instruction
2151   0,0,  // branch, skip
2152   0,    // literal operand
2153   1,    // RAM access bit
2154   0,    // fast call/return mode select bit
2155   0,    // second memory operand
2156   0,    // second literal operand
2157   POC_NOP,
2158   (PCC_C | PCC_REGISTER),   // inCond
2159   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2160   PCI_MAGIC
2161 };
2162 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2163   {PC_OPCODE, NULL, NULL, 0, NULL, 
2164    //   genericAnalyze,
2165    genericDestruct,
2166    genericPrint},
2167   POC_RRNCF,
2168   "RRNCF",
2169   2,
2170   NULL, // from branch
2171   NULL, // to branch
2172   NULL, // label
2173   NULL, // operand
2174   NULL, // flow block
2175   NULL, // C source 
2176   3,    // num ops
2177   1,0,  // dest, bit instruction
2178   0,0,  // branch, skip
2179   0,    // literal operand
2180   1,    // RAM access bit
2181   0,    // fast call/return mode select bit
2182   0,    // second memory operand
2183   0,    // second literal operand
2184   POC_NOP,
2185   PCC_REGISTER,   // inCond
2186   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2187   PCI_MAGIC
2188 };
2189
2190 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2191   {PC_OPCODE, NULL, NULL, 0, NULL, 
2192    //   genericAnalyze,
2193    genericDestruct,
2194    genericPrint},
2195   POC_RRNCFW,
2196   "RRNCF",
2197   2,
2198   NULL, // from branch
2199   NULL, // to branch
2200   NULL, // label
2201   NULL, // operand
2202   NULL, // flow block
2203   NULL, // C source 
2204   3,    // num ops
2205   0,0,  // dest, bit instruction
2206   0,0,  // branch, skip
2207   0,    // literal operand
2208   1,    // RAM access bit
2209   0,    // fast call/return mode select bit
2210   0,    // second memory operand
2211   0,    // second literal operand
2212   POC_NOP,
2213   PCC_REGISTER,   // inCond
2214   (PCC_W | PCC_Z | PCC_N), // outCond
2215   PCI_MAGIC
2216 };
2217
2218 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2219   {PC_OPCODE, NULL, NULL, 0, NULL, 
2220    //   genericAnalyze,
2221    genericDestruct,
2222    genericPrint},
2223   POC_SETF,
2224   "SETF",
2225   2,
2226   NULL, // from branch
2227   NULL, // to branch
2228   NULL, // label
2229   NULL, // operand
2230   NULL, // flow block
2231   NULL, // C source 
2232   2,    // num ops
2233   0,0,  // dest, bit instruction
2234   0,0,  // branch, skip
2235   0,    // literal operand
2236   1,    // RAM access bit
2237   0,    // fast call/return mode select bit
2238   0,    // second memory operand
2239   0,    // second literal operand
2240   POC_NOP,
2241   PCC_NONE,  // inCond
2242   PCC_REGISTER  , // outCond
2243   PCI_MAGIC
2244 };
2245
2246 pCodeInstruction pic16_pciSUBLW = {
2247   {PC_OPCODE, NULL, NULL, 0, NULL, 
2248    //   genericAnalyze,
2249    genericDestruct,
2250    genericPrint},
2251   POC_SUBLW,
2252   "SUBLW",
2253   2,
2254   NULL, // from branch
2255   NULL, // to branch
2256   NULL, // label
2257   NULL, // operand
2258   NULL, // flow block
2259   NULL, // C source 
2260   1,    // num ops
2261   0,0,  // dest, bit instruction
2262   0,0,  // branch, skip
2263   1,    // literal operand
2264   0,    // RAM access bit
2265   0,    // fast call/return mode select bit
2266   0,    // second memory operand
2267   0,    // second literal operand
2268   POC_NOP,
2269   (PCC_W | PCC_LITERAL),   // inCond
2270   (PCC_W | PCC_STATUS), // outCond
2271   PCI_MAGIC
2272 };
2273
2274 pCodeInstruction pic16_pciSUBFWB = {
2275   {PC_OPCODE, NULL, NULL, 0, NULL, 
2276    //   genericAnalyze,
2277    genericDestruct,
2278    genericPrint},
2279   POC_SUBFWB,
2280   "SUBFWB",
2281   2,
2282   NULL, // from branch
2283   NULL, // to branch
2284   NULL, // label
2285   NULL, // operand
2286   NULL, // flow block
2287   NULL, // C source 
2288   3,    // num ops
2289   1,0,  // dest, bit instruction
2290   0,0,  // branch, skip
2291   0,    // literal operand
2292   1,    // RAM access bit
2293   0,    // fast call/return mode select bit
2294   0,    // second memory operand
2295   0,    // second literal operand
2296   POC_NOP,
2297   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2298   (PCC_W | PCC_STATUS), // outCond
2299   PCI_MAGIC
2300 };
2301
2302 pCodeInstruction pic16_pciSUBWF = {
2303   {PC_OPCODE, NULL, NULL, 0, NULL, 
2304    //   genericAnalyze,
2305    genericDestruct,
2306    genericPrint},
2307   POC_SUBWF,
2308   "SUBWF",
2309   2,
2310   NULL, // from branch
2311   NULL, // to branch
2312   NULL, // label
2313   NULL, // operand
2314   NULL, // flow block
2315   NULL, // C source 
2316   3,    // num ops
2317   1,0,  // dest, bit instruction
2318   0,0,  // branch, skip
2319   0,    // literal operand
2320   1,    // RAM access bit
2321   0,    // fast call/return mode select bit
2322   0,    // second memory operand
2323   0,    // second literal operand
2324   POC_NOP,
2325   (PCC_W | PCC_REGISTER),   // inCond
2326   (PCC_REGISTER | PCC_STATUS), // outCond
2327   PCI_MAGIC
2328 };
2329
2330 pCodeInstruction pic16_pciSUBFW = {
2331   {PC_OPCODE, NULL, NULL, 0, NULL, 
2332    //   genericAnalyze,
2333    genericDestruct,
2334    genericPrint},
2335   POC_SUBFW,
2336   "SUBWF",
2337   2,
2338   NULL, // from branch
2339   NULL, // to branch
2340   NULL, // label
2341   NULL, // operand
2342   NULL, // flow block
2343   NULL, // C source 
2344   3,    // num ops
2345   0,0,  // dest, bit instruction
2346   0,0,  // branch, skip
2347   0,    // literal operand
2348   1,    // RAM access bit
2349   0,    // fast call/return mode select bit
2350   0,    // second memory operand
2351   0,    // second literal operand
2352   POC_NOP,
2353   (PCC_W | PCC_REGISTER),   // inCond
2354   (PCC_W | PCC_STATUS), // outCond
2355   PCI_MAGIC
2356 };
2357
2358 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2359   {PC_OPCODE, NULL, NULL, 0, NULL, 
2360    //   genericAnalyze,
2361    genericDestruct,
2362    genericPrint},
2363   POC_SUBFWB_D1,
2364   "SUBFWB",
2365   2,
2366   NULL, // from branch
2367   NULL, // to branch
2368   NULL, // label
2369   NULL, // operand
2370   NULL, // flow block
2371   NULL, // C source 
2372   3,    // num ops
2373   1,0,  // dest, bit instruction
2374   0,0,  // branch, skip
2375   0,    // literal operand
2376   1,    // RAM access bit
2377   0,    // fast call/return mode select bit
2378   0,    // second memory operand
2379   0,    // second literal operand
2380   POC_NOP,
2381   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2382   (PCC_REGISTER | PCC_STATUS), // outCond
2383   PCI_MAGIC
2384 };
2385
2386 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2387   {PC_OPCODE, NULL, NULL, 0, NULL, 
2388    //   genericAnalyze,
2389    genericDestruct,
2390    genericPrint},
2391   POC_SUBFWB_D0,
2392   "SUBFWB",
2393   2,
2394   NULL, // from branch
2395   NULL, // to branch
2396   NULL, // label
2397   NULL, // operand
2398   NULL, // flow block
2399   NULL, // C source 
2400   3,    // num ops
2401   0,0,  // dest, bit instruction
2402   0,0,  // branch, skip
2403   0,    // literal operand
2404   1,    // RAM access bit
2405   0,    // fast call/return mode select bit
2406   0,    // second memory operand
2407   0,    // second literal operand
2408   POC_NOP,
2409   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2410   (PCC_W | PCC_STATUS), // outCond
2411   PCI_MAGIC
2412 };
2413
2414 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2415   {PC_OPCODE, NULL, NULL, 0, NULL, 
2416    //   genericAnalyze,
2417    genericDestruct,
2418    genericPrint},
2419   POC_SUBWFB_D1,
2420   "SUBWFB",
2421   2,
2422   NULL, // from branch
2423   NULL, // to branch
2424   NULL, // label
2425   NULL, // operand
2426   NULL, // flow block
2427   NULL, // C source 
2428   3,    // num ops
2429   1,0,  // dest, bit instruction
2430   0,0,  // branch, skip
2431   0,    // literal operand
2432   1,    // RAM access bit
2433   0,    // fast call/return mode select bit
2434   0,    // second memory operand
2435   0,    // second literal operand
2436   POC_NOP,
2437   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2438   (PCC_REGISTER | PCC_STATUS), // outCond
2439   PCI_MAGIC
2440 };
2441
2442 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2443   {PC_OPCODE, NULL, NULL, 0, NULL, 
2444    //   genericAnalyze,
2445    genericDestruct,
2446    genericPrint},
2447   POC_SUBWFB_D0,
2448   "SUBWFB",
2449   2,
2450   NULL, // from branch
2451   NULL, // to branch
2452   NULL, // label
2453   NULL, // operand
2454   NULL, // flow block
2455   NULL, // C source 
2456   3,    // num ops
2457   0,0,  // dest, bit instruction
2458   0,0,  // branch, skip
2459   0,    // literal operand
2460   1,    // RAM access bit
2461   0,    // fast call/return mode select bit
2462   0,    // second memory operand
2463   0,    // second literal operand
2464   POC_NOP,
2465   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2466   (PCC_W | PCC_STATUS), // outCond
2467   PCI_MAGIC
2468 };
2469
2470 pCodeInstruction pic16_pciSWAPF = {
2471   {PC_OPCODE, NULL, NULL, 0, NULL, 
2472    //   genericAnalyze,
2473    genericDestruct,
2474    genericPrint},
2475   POC_SWAPF,
2476   "SWAPF",
2477   2,
2478   NULL, // from branch
2479   NULL, // to branch
2480   NULL, // label
2481   NULL, // operand
2482   NULL, // flow block
2483   NULL, // C source 
2484   3,    // num ops
2485   1,0,  // dest, bit instruction
2486   0,0,  // branch, skip
2487   0,    // literal operand
2488   1,    // RAM access bit
2489   0,    // fast call/return mode select bit
2490   0,    // second memory operand
2491   0,    // second literal operand
2492   POC_NOP,
2493   (PCC_REGISTER),   // inCond
2494   (PCC_REGISTER), // outCond
2495   PCI_MAGIC
2496 };
2497
2498 pCodeInstruction pic16_pciSWAPFW = {
2499   {PC_OPCODE, NULL, NULL, 0, NULL, 
2500    //   genericAnalyze,
2501    genericDestruct,
2502    genericPrint},
2503   POC_SWAPFW,
2504   "SWAPF",
2505   2,
2506   NULL, // from branch
2507   NULL, // to branch
2508   NULL, // label
2509   NULL, // operand
2510   NULL, // flow block
2511   NULL, // C source 
2512   3,    // num ops
2513   0,0,  // dest, bit instruction
2514   0,0,  // branch, skip
2515   0,    // literal operand
2516   1,    // RAM access bit
2517   0,    // fast call/return mode select bit
2518   0,    // second memory operand
2519   0,    // second literal operand
2520   POC_NOP,
2521   (PCC_REGISTER),   // inCond
2522   (PCC_W), // outCond
2523   PCI_MAGIC
2524 };
2525
2526 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2527   {PC_OPCODE, NULL, NULL, 0, NULL, 
2528    genericDestruct,
2529    genericPrint},
2530   POC_TBLRD,
2531   "TBLRD*",
2532   2,
2533   NULL, // from branch
2534   NULL, // to branch
2535   NULL, // label
2536   NULL, // operand
2537   NULL, // flow block
2538   NULL, // C source 
2539   0,    // num ops
2540   0,0,  // dest, bit instruction
2541   0,0,  // branch, skip
2542   0,    // literal operand
2543   0,    // RAM access bit
2544   0,    // fast call/return mode select bit
2545   0,    // second memory operand
2546   0,    // second literal operand
2547   POC_NOP,
2548   PCC_NONE,  // inCond
2549   PCC_NONE  , // outCond
2550   PCI_MAGIC
2551 };
2552
2553 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2554   {PC_OPCODE, NULL, NULL, 0, NULL, 
2555    genericDestruct,
2556    genericPrint},
2557   POC_TBLRD_POSTINC,
2558   "TBLRD*+",
2559   2,
2560   NULL, // from branch
2561   NULL, // to branch
2562   NULL, // label
2563   NULL, // operand
2564   NULL, // flow block
2565   NULL, // C source 
2566   0,    // num ops
2567   0,0,  // dest, bit instruction
2568   0,0,  // branch, skip
2569   0,    // literal operand
2570   0,    // RAM access bit
2571   0,    // fast call/return mode select bit
2572   0,    // second memory operand
2573   0,    // second literal operand
2574   POC_NOP,
2575   PCC_NONE,  // inCond
2576   PCC_NONE  , // outCond
2577   PCI_MAGIC
2578 };
2579
2580 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2581   {PC_OPCODE, NULL, NULL, 0, NULL, 
2582    genericDestruct,
2583    genericPrint},
2584   POC_TBLRD_POSTDEC,
2585   "TBLRD*-",
2586   2,
2587   NULL, // from branch
2588   NULL, // to branch
2589   NULL, // label
2590   NULL, // operand
2591   NULL, // flow block
2592   NULL, // C source 
2593   0,    // num ops
2594   0,0,  // dest, bit instruction
2595   0,0,  // branch, skip
2596   0,    // literal operand
2597   0,    // RAM access bit
2598   0,    // fast call/return mode select bit
2599   0,    // second memory operand
2600   0,    // second literal operand
2601   POC_NOP,
2602   PCC_NONE,  // inCond
2603   PCC_NONE  , // outCond
2604   PCI_MAGIC
2605 };
2606
2607 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2608   {PC_OPCODE, NULL, NULL, 0, NULL, 
2609    genericDestruct,
2610    genericPrint},
2611   POC_TBLRD_PREINC,
2612   "TBLRD+*",
2613   2,
2614   NULL, // from branch
2615   NULL, // to branch
2616   NULL, // label
2617   NULL, // operand
2618   NULL, // flow block
2619   NULL, // C source 
2620   0,    // num ops
2621   0,0,  // dest, bit instruction
2622   0,0,  // branch, skip
2623   0,    // literal operand
2624   0,    // RAM access bit
2625   0,    // fast call/return mode select bit
2626   0,    // second memory operand
2627   0,    // second literal operand
2628   POC_NOP,
2629   PCC_NONE,  // inCond
2630   PCC_NONE  , // outCond
2631   PCI_MAGIC
2632 };
2633
2634 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2635   {PC_OPCODE, NULL, NULL, 0, NULL, 
2636    genericDestruct,
2637    genericPrint},
2638   POC_TBLWT,
2639   "TBLWT*",
2640   2,
2641   NULL, // from branch
2642   NULL, // to branch
2643   NULL, // label
2644   NULL, // operand
2645   NULL, // flow block
2646   NULL, // C source 
2647   0,    // num ops
2648   0,0,  // dest, bit instruction
2649   0,0,  // branch, skip
2650   0,    // literal operand
2651   0,    // RAM access bit
2652   0,    // fast call/return mode select bit
2653   0,    // second memory operand
2654   0,    // second literal operand
2655   POC_NOP,
2656   PCC_NONE,  // inCond
2657   PCC_NONE  , // outCond
2658   PCI_MAGIC
2659 };
2660
2661 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2662   {PC_OPCODE, NULL, NULL, 0, NULL, 
2663    genericDestruct,
2664    genericPrint},
2665   POC_TBLWT_POSTINC,
2666   "TBLWT*+",
2667   2,
2668   NULL, // from branch
2669   NULL, // to branch
2670   NULL, // label
2671   NULL, // operand
2672   NULL, // flow block
2673   NULL, // C source 
2674   0,    // num ops
2675   0,0,  // dest, bit instruction
2676   0,0,  // branch, skip
2677   0,    // literal operand
2678   0,    // RAM access bit
2679   0,    // fast call/return mode select bit
2680   0,    // second memory operand
2681   0,    // second literal operand
2682   POC_NOP,
2683   PCC_NONE,  // inCond
2684   PCC_NONE  , // outCond
2685   PCI_MAGIC
2686 };
2687
2688 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2689   {PC_OPCODE, NULL, NULL, 0, NULL, 
2690    genericDestruct,
2691    genericPrint},
2692   POC_TBLWT_POSTDEC,
2693   "TBLWT*-",
2694   2,
2695   NULL, // from branch
2696   NULL, // to branch
2697   NULL, // label
2698   NULL, // operand
2699   NULL, // flow block
2700   NULL, // C source 
2701   0,    // num ops
2702   0,0,  // dest, bit instruction
2703   0,0,  // branch, skip
2704   0,    // literal operand
2705   0,    // RAM access bit
2706   0,    // fast call/return mode select bit
2707   0,    // second memory operand
2708   0,    // second literal operand
2709   POC_NOP,
2710   PCC_NONE,  // inCond
2711   PCC_NONE  , // outCond
2712   PCI_MAGIC
2713 };
2714
2715 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2716   {PC_OPCODE, NULL, NULL, 0, NULL, 
2717    genericDestruct,
2718    genericPrint},
2719   POC_TBLWT_PREINC,
2720   "TBLWT+*",
2721   2,
2722   NULL, // from branch
2723   NULL, // to branch
2724   NULL, // label
2725   NULL, // operand
2726   NULL, // flow block
2727   NULL, // C source 
2728   0,    // num ops
2729   0,0,  // dest, bit instruction
2730   0,0,  // branch, skip
2731   0,    // literal operand
2732   0,    // RAM access bit
2733   0,    // fast call/return mode select bit
2734   0,    // second memory operand
2735   0,    // second literal operand
2736   POC_NOP,
2737   PCC_NONE,  // inCond
2738   PCC_NONE  , // outCond
2739   PCI_MAGIC
2740 };
2741
2742 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2743   {PC_OPCODE, NULL, NULL, 0, NULL, 
2744    //   genericAnalyze,
2745    genericDestruct,
2746    genericPrint},
2747   POC_TSTFSZ,
2748   "TSTFSZ",
2749   2,
2750   NULL, // from branch
2751   NULL, // to branch
2752   NULL, // label
2753   NULL, // operand
2754   NULL, // flow block
2755   NULL, // C source 
2756   2,    // num ops
2757   0,0,  // dest, bit instruction
2758   1,1,  // branch, skip
2759   0,    // literal operand
2760   1,    // RAM access bit
2761   0,    // fast call/return mode select bit
2762   0,    // second memory operand
2763   0,    // second literal operand
2764   POC_NOP,
2765   PCC_REGISTER,   // inCond
2766   PCC_NONE, // outCond
2767   PCI_MAGIC
2768 };
2769
2770 pCodeInstruction pic16_pciXORWF = {
2771   {PC_OPCODE, NULL, NULL, 0, NULL, 
2772    //   genericAnalyze,
2773    genericDestruct,
2774    genericPrint},
2775   POC_XORWF,
2776   "XORWF",
2777   2,
2778   NULL, // from branch
2779   NULL, // to branch
2780   NULL, // label
2781   NULL, // operand
2782   NULL, // flow block
2783   NULL, // C source 
2784   3,    // num ops
2785   1,0,  // dest, bit instruction
2786   0,0,  // branch, skip
2787   0,    // literal operand
2788   1,    // RAM access bit
2789   0,    // fast call/return mode select bit
2790   0,    // second memory operand
2791   0,    // second literal operand
2792   POC_NOP,
2793   (PCC_W | PCC_REGISTER),   // inCond
2794   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2795   PCI_MAGIC
2796 };
2797
2798 pCodeInstruction pic16_pciXORFW = {
2799   {PC_OPCODE, NULL, NULL, 0, NULL, 
2800    //   genericAnalyze,
2801    genericDestruct,
2802    genericPrint},
2803   POC_XORFW,
2804   "XORWF",
2805   2,
2806   NULL, // from branch
2807   NULL, // to branch
2808   NULL, // label
2809   NULL, // operand
2810   NULL, // flow block
2811   NULL, // C source 
2812   3,    // num ops
2813   0,0,  // dest, bit instruction
2814   0,0,  // branch, skip
2815   0,    // literal operand
2816   1,    // RAM access bit
2817   0,    // fast call/return mode select bit
2818   0,    // second memory operand
2819   0,    // second literal operand
2820   POC_NOP,
2821   (PCC_W | PCC_REGISTER),   // inCond
2822   (PCC_W | PCC_Z | PCC_N), // outCond
2823   PCI_MAGIC
2824 };
2825
2826 pCodeInstruction pic16_pciXORLW = {
2827   {PC_OPCODE, NULL, NULL, 0, NULL, 
2828    //   genericAnalyze,
2829    genericDestruct,
2830    genericPrint},
2831   POC_XORLW,
2832   "XORLW",
2833   2,
2834   NULL, // from branch
2835   NULL, // to branch
2836   NULL, // label
2837   NULL, // operand
2838   NULL, // flow block
2839   NULL, // C source 
2840   1,    // num ops
2841   0,0,  // dest, bit instruction
2842   0,0,  // branch, skip
2843   1,    // literal operand
2844   1,    // RAM access bit
2845   0,    // fast call/return mode select bit
2846   0,    // second memory operand
2847   0,    // second literal operand
2848   POC_NOP,
2849   (PCC_W | PCC_LITERAL),   // inCond
2850   (PCC_W | PCC_Z | PCC_N), // outCond
2851   PCI_MAGIC
2852 };
2853
2854
2855 pCodeInstruction pic16_pciBANKSEL = {
2856   {PC_OPCODE, NULL, NULL, 0, NULL, 
2857    genericDestruct,
2858    genericPrint},
2859   POC_BANKSEL,
2860   "BANKSEL",
2861   2,
2862   NULL, // from branch
2863   NULL, // to branch
2864   NULL, // label
2865   NULL, // operand
2866   NULL, // flow block
2867   NULL, // C source 
2868   0,    // num ops
2869   0,0,  // dest, bit instruction
2870   0,0,  // branch, skip
2871   0,    // literal operand
2872   0,    // RAM access bit
2873   0,    // fast call/return mode select bit
2874   0,    // second memory operand
2875   0,    // second literal operand
2876   POC_NOP,
2877   PCC_NONE,   // inCond
2878   PCC_NONE, // outCond
2879   PCI_MAGIC
2880 };
2881
2882
2883 #define MAX_PIC16MNEMONICS 100
2884 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2885
2886 //#define USE_VSNPRINTF
2887 #if OPT_DISABLE_PIC
2888
2889 #ifdef USE_VSNPRINTF
2890   // Alas, vsnprintf is not ANSI standard, and does not exist
2891   // on Solaris (and probably other non-Gnu flavored Unixes).
2892
2893 /*-----------------------------------------------------------------*/
2894 /* SAFE_snprintf - like snprintf except the string pointer is      */
2895 /*                 after the string has been printed to. This is   */
2896 /*                 useful for printing to string as though if it   */
2897 /*                 were a stream.                                  */
2898 /*-----------------------------------------------------------------*/
2899 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2900 {
2901   va_list val;
2902   int len;
2903
2904   if(!str || !*str)
2905     return;
2906
2907   va_start(val, format);
2908
2909   vsnprintf(*str, *size, format, val);
2910
2911   va_end (val);
2912
2913   len = strlen(*str);
2914   if(len > *size) {
2915     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2916     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2917   }
2918
2919   *str += len;
2920   *size -= len;
2921
2922 }
2923
2924 #else
2925 // This version is *not* safe, despite the name.
2926
2927 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2928 {
2929   va_list val;
2930   int len;
2931   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2932
2933   if(!str || !*str)
2934     return;
2935
2936   va_start(val, format);
2937
2938   vsprintf(buffer, format, val);
2939   va_end (val);
2940
2941   len = strlen(buffer);
2942   if(len > *size) {
2943     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2944     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2945   }
2946
2947   strcpy(*str, buffer);
2948   *str += len;
2949   *size -= len;
2950
2951 }
2952
2953 #endif    //  USE_VSNPRINTF
2954 #endif
2955
2956 extern set *externs;
2957 extern  void pic16_initStack(int base_address, int size);
2958 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2959 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2960 extern void pic16_init_pic(char *);
2961
2962 void  pic16_pCodeInitRegisters(void)
2963 {
2964   static int initialized=0;
2965
2966         if(initialized)
2967                 return;
2968         
2969         initialized = 1;
2970
2971 //      pic16_initStack(0xfff, 8);
2972         pic16_init_pic(port->processor);
2973
2974         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2975         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2976         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2977         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2978         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2979         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2980         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2981
2982         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2983         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2984         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2985
2986         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2987         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2988         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2989         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2990
2991         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2992         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2993         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2994         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2995         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2996         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2997
2998         pic16_stackpnt_lo = &pic16_pc_fsr1l;
2999         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3000         pic16_stack_postdec = &pic16_pc_postdec1;
3001         pic16_stack_postinc = &pic16_pc_postinc1;
3002         pic16_stack_preinc = &pic16_pc_preinc1;
3003         pic16_stack_plusw = &pic16_pc_plusw1;
3004         
3005         pic16_framepnt_lo = &pic16_pc_fsr2l;
3006         pic16_framepnt_hi = &pic16_pc_fsr2h;
3007         pic16_frame_postdec = &pic16_pc_postdec2;
3008         pic16_frame_postinc = &pic16_pc_postinc2;
3009         pic16_frame_preinc = &pic16_pc_preinc2;
3010         pic16_frame_plusw = &pic16_pc_plusw2;
3011
3012         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3013         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3014         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3015         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3016         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3017         
3018         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3019         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3020         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3021         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3022         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3023
3024         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3025         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3026         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3027         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3028         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3029         
3030         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3031         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3032
3033
3034         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3035         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3036         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3037         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3038
3039         
3040         pic16_pc_status.rIdx = IDX_STATUS;
3041         pic16_pc_intcon.rIdx = IDX_INTCON;
3042         pic16_pc_pcl.rIdx = IDX_PCL;
3043         pic16_pc_pclath.rIdx = IDX_PCLATH;
3044         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3045         pic16_pc_wreg.rIdx = IDX_WREG;
3046         pic16_pc_bsr.rIdx = IDX_BSR;
3047
3048         pic16_pc_tosl.rIdx = IDX_TOSL;
3049         pic16_pc_tosh.rIdx = IDX_TOSH;
3050         pic16_pc_tosu.rIdx = IDX_TOSU;
3051
3052         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3053         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3054         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3055         pic16_pc_tablat.rIdx = IDX_TABLAT;
3056
3057         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3058         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3059         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3060         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3061         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3062         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3063         pic16_pc_indf0.rIdx = IDX_INDF0;
3064         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3065         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3066         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3067         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3068         pic16_pc_indf1.rIdx = IDX_INDF1;
3069         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3070         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3071         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3072         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3073         pic16_pc_indf2.rIdx = IDX_INDF2;
3074         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3075         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3076         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3077         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3078         pic16_pc_prodl.rIdx = IDX_PRODL;
3079         pic16_pc_prodh.rIdx = IDX_PRODH;
3080         
3081         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3082         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3083         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3084         
3085         pic16_pc_kzero.rIdx = IDX_KZ;
3086         pic16_pc_wsave.rIdx = IDX_WSAVE;
3087         pic16_pc_ssave.rIdx = IDX_SSAVE;
3088
3089         pic16_pc_eecon1.rIdx = IDX_EECON1;
3090         pic16_pc_eecon2.rIdx = IDX_EECON2;
3091         pic16_pc_eedata.rIdx = IDX_EEDATA;
3092         pic16_pc_eeadr.rIdx = IDX_EEADR;
3093         
3094         
3095         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3096         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3097
3098         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3099         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3100
3101         /* probably should put this in a separate initialization routine */
3102         pb_dead_pcodes = newpBlock();
3103
3104 }
3105
3106 #if OPT_DISABLE_PIC
3107 /*-----------------------------------------------------------------*/
3108 /*  mnem2key - convert a pic mnemonic into a hash key              */
3109 /*   (BTW - this spreads the mnemonics quite well)                 */
3110 /*                                                                 */
3111 /*-----------------------------------------------------------------*/
3112
3113 int mnem2key(char const *mnem)
3114 {
3115   int key = 0;
3116
3117   if(!mnem)
3118     return 0;
3119
3120   while(*mnem) {
3121
3122     key += toupper(*mnem++) +1;
3123
3124   }
3125
3126   return (key & 0x1f);
3127
3128 }
3129 #endif
3130
3131 void pic16initMnemonics(void)
3132 {
3133   int i = 0;
3134   int key;
3135   //  char *str;
3136   pCodeInstruction *pci;
3137
3138   if(mnemonics_initialized)
3139     return;
3140
3141   // NULL out the array before making the assignments
3142   // since we check the array contents below this initialization.
3143
3144   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3145     pic16Mnemonics[i] = NULL;
3146   }
3147
3148   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3149   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3150   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3151   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3152   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3153   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3154   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3155   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3156   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3157   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3158   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3159   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3160   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3161   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3162   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3163   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3164   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3165   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3166   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3167   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3168   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3169   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3170   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3171   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3172   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3173   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3174   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3175   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3176   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3177   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3178   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3179   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3180   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3181   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3182   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3183   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3184   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3185   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3186   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3187   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3188   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3189   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3190   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3191   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3192   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3193   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3194   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3195   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3196   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3197   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3198   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3199   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3200   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3201   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3202   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3203   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3204   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3205   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3206   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3207   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3208   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3209   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3210   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3211   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3212   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3213   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3214   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3215   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3216   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3217   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3218   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3219   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3220   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3221   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3222   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3223   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3224   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3225   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3226   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3227   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3228   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3229   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3230   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3231   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3232   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3233   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3234   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3235   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3236   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3237   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3238   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3239   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3240   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3241   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3242
3243   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3244     if(pic16Mnemonics[i])
3245       hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3246   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3247
3248   while(pci) {
3249     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3250     pci = hTabNextItem(pic16MnemonicsHash, &key);
3251   }
3252
3253   mnemonics_initialized = 1;
3254 }
3255
3256 int pic16_getpCodePeepCommand(char *cmd);
3257
3258 int pic16_getpCode(char *mnem,unsigned dest)
3259 {
3260
3261   pCodeInstruction *pci;
3262   int key = mnem2key(mnem);
3263
3264   if(!mnemonics_initialized)
3265     pic16initMnemonics();
3266
3267   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3268
3269   while(pci) {
3270
3271     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3272       if((pci->num_ops <= 1)
3273         || (pci->isModReg == dest)
3274         || (pci->isBitInst)
3275         || (pci->num_ops <= 2 && pci->isAccess)
3276         || (pci->num_ops <= 2 && pci->isFastCall)
3277         || (pci->num_ops <= 2 && pci->is2MemOp)
3278         || (pci->num_ops <= 2 && pci->is2LitOp) )
3279         return(pci->op);
3280     }
3281
3282     pci = hTabNextItemWK (pic16MnemonicsHash);
3283   
3284   }
3285
3286   return -1;
3287 }
3288
3289 /*-----------------------------------------------------------------*
3290  * pic16initpCodePeepCommands
3291  *
3292  *-----------------------------------------------------------------*/
3293 void pic16initpCodePeepCommands(void)
3294 {
3295
3296   int key, i;
3297   peepCommand *pcmd;
3298
3299   i = 0;
3300   do {
3301     hTabAddItem(&pic16pCodePeepCommandsHash, 
3302                 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3303     i++;
3304   } while (peepCommands[i].cmd);
3305
3306   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3307
3308   while(pcmd) {
3309     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3310     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3311   }
3312
3313 }
3314
3315 /*-----------------------------------------------------------------
3316  *
3317  *
3318  *-----------------------------------------------------------------*/
3319
3320 int pic16_getpCodePeepCommand(char *cmd)
3321 {
3322
3323   peepCommand *pcmd;
3324   int key = mnem2key(cmd);
3325
3326
3327   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3328
3329   while(pcmd) {
3330     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3331     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3332       return pcmd->id;
3333     }
3334
3335     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3336   
3337   }
3338
3339   return -1;
3340 }
3341
3342 static char getpBlock_dbName(pBlock *pb)
3343 {
3344   if(!pb)
3345     return 0;
3346
3347   if(pb->cmemmap)
3348     return pb->cmemmap->dbName;
3349
3350   return pb->dbName;
3351 }
3352 void pic16_pBlockConvert2ISR(pBlock *pb)
3353 {
3354         if(!pb)return;
3355
3356         if(pb->cmemmap)pb->cmemmap = NULL;
3357
3358         pb->dbName = 'I';
3359
3360         if(pic16_pcode_verbose)
3361                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3362 }
3363
3364 void pic16_pBlockConvert2Absolute(pBlock *pb)
3365 {
3366         if(!pb)return;
3367         if(pb->cmemmap)pb->cmemmap = NULL;
3368         
3369         pb->dbName = 'A';
3370         
3371         if(pic16_pcode_verbose)
3372                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3373 }
3374   
3375 /*-----------------------------------------------------------------*/
3376 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3377 /*                   instances to the front of the doubly linked   */
3378 /*                   list of pBlocks                               */
3379 /*-----------------------------------------------------------------*/
3380
3381 void pic16_movepBlock2Head(char dbName)
3382 {
3383   pBlock *pb;
3384
3385
3386   /* this can happen in sources without code,
3387    * only variable definitions */
3388   if(!the_pFile)return;
3389
3390   pb = the_pFile->pbHead;
3391
3392   while(pb) {
3393
3394     if(getpBlock_dbName(pb) == dbName) {
3395       pBlock *pbn = pb->next;
3396       pb->next = the_pFile->pbHead;
3397       the_pFile->pbHead->prev = pb;
3398       the_pFile->pbHead = pb;
3399
3400       if(pb->prev)
3401         pb->prev->next = pbn;
3402
3403       // If the pBlock that we just moved was the last
3404       // one in the link of all of the pBlocks, then we
3405       // need to point the tail to the block just before
3406       // the one we moved.
3407       // Note: if pb->next is NULL, then pb must have 
3408       // been the last pBlock in the chain.
3409
3410       if(pbn)
3411         pbn->prev = pb->prev;
3412       else
3413         the_pFile->pbTail = pb->prev;
3414
3415       pb = pbn;
3416
3417     } else
3418       pb = pb->next;
3419
3420   }
3421
3422 }
3423
3424 void pic16_copypCode(FILE *of, char dbName)
3425 {
3426   pBlock *pb;
3427
3428         if(!of || !the_pFile)
3429                 return;
3430
3431         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3432                 if(getpBlock_dbName(pb) == dbName) {
3433 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3434                         pBlockStats(of,pb);
3435                         pic16_printpBlock(of,pb);
3436                 }
3437         }
3438
3439 }
3440 void pic16_pcode_test(void)
3441 {
3442
3443   DFPRINTF((stderr,"pcode is alive!\n"));
3444
3445   //initMnemonics();
3446
3447   if(the_pFile) {
3448
3449     pBlock *pb;
3450     FILE *pFile;
3451     char buffer[100];
3452
3453     /* create the file name */
3454     strcpy(buffer,dstFileName);
3455     strcat(buffer,".p");
3456
3457     if( !(pFile = fopen(buffer, "w" ))) {
3458       werror(E_FILE_OPEN_ERR,buffer);
3459       exit(1);
3460     }
3461
3462     fprintf(pFile,"pcode dump\n\n");
3463
3464     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3465       fprintf(pFile,"\n\tNew pBlock\n\n");
3466       if(pb->cmemmap)
3467         fprintf(pFile,"%s",pb->cmemmap->sname);
3468       else
3469         fprintf(pFile,"internal pblock");
3470
3471       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3472       pic16_printpBlock(pFile,pb);
3473     }
3474   }
3475 }
3476
3477
3478 unsigned long pic16_countInstructions(void)
3479 {
3480   pBlock *pb;
3481   pCode *pc;
3482   unsigned long isize=0;
3483
3484     if(!the_pFile)return -1;
3485     
3486     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3487       for(pc = pb->pcHead; pc; pc = pc->next) {
3488         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3489       }
3490     }
3491   return (isize);
3492 }
3493
3494
3495 /*-----------------------------------------------------------------*/
3496 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3497 /*      ister, RegCond will return the bit being referenced.       */
3498 /*                                                                 */
3499 /* fixme - why not just OR in the pcop bit field                   */
3500 /*-----------------------------------------------------------------*/
3501
3502 static int RegCond(pCodeOp *pcop)
3503 {
3504
3505   if(!pcop)
3506     return 0;
3507
3508   if(!pcop->name)return 0;
3509
3510   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3511     switch(PCORB(pcop)->bit) {
3512     case PIC_C_BIT:
3513       return PCC_C;
3514     case PIC_DC_BIT:
3515         return PCC_DC;
3516     case PIC_Z_BIT:
3517       return PCC_Z;
3518     }
3519
3520   }
3521
3522   return 0;
3523 }
3524
3525 /*-----------------------------------------------------------------*/
3526 /* pic16_newpCode - create and return a newly initialized pCode          */
3527 /*                                                                 */
3528 /*  fixme - rename this                                            */
3529 /*                                                                 */
3530 /* The purpose of this routine is to create a new Instruction      */
3531 /* pCode. This is called by gen.c while the assembly code is being */
3532 /* generated.                                                      */
3533 /*                                                                 */
3534 /* Inouts:                                                         */
3535 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3536 /*                  (note that the op is analogous to but not the  */
3537 /*                  same thing as the opcode of the instruction.)  */
3538 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3539 /*                                                                 */
3540 /* Outputs:                                                        */
3541 /*  a pointer to the new malloc'd pCode is returned.               */
3542 /*                                                                 */
3543 /*                                                                 */
3544 /*                                                                 */
3545 /*-----------------------------------------------------------------*/
3546 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3547 {
3548   pCodeInstruction *pci ;
3549
3550   if(!mnemonics_initialized)
3551     pic16initMnemonics();
3552     
3553   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3554
3555   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3556     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3557     pci->pcop = pcop;
3558
3559     if(pci->inCond & PCC_EXAMINE_PCOP)
3560       pci->inCond  |= RegCond(pcop);
3561
3562     if(pci->outCond & PCC_EXAMINE_PCOP)
3563       pci->outCond  |= RegCond(pcop);
3564
3565     pci->pc.prev = pci->pc.next = NULL;
3566     return (pCode *)pci;
3567   }
3568
3569   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3570   exit(1);
3571
3572   return NULL;
3573 }       
3574
3575 /*-----------------------------------------------------------------*/
3576 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3577 /*                                                                 */
3578 /* Wild pcodes are used during the peep hole optimizer to serve    */
3579 /* as place holders for any instruction. When a snippet of code is */
3580 /* compared to a peep hole rule, the wild card opcode will match   */
3581 /* any instruction. However, the optional operand and label are    */
3582 /* additional qualifiers that must also be matched before the      */
3583 /* line (of assembly code) is declared matched. Note that the      */
3584 /* operand may be wild too.                                        */
3585 /*                                                                 */
3586 /*   Note, a wild instruction is specified just like a wild var:   */
3587 /*      %4     ; A wild instruction,                               */
3588 /*  See the peeph.def file for additional examples                 */
3589 /*                                                                 */
3590 /*-----------------------------------------------------------------*/
3591
3592 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3593 {
3594
3595   pCodeWild *pcw;
3596     
3597   pcw = Safe_calloc(1,sizeof(pCodeWild));
3598
3599   pcw->pci.pc.type = PC_WILD;
3600   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3601   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3602   pcw->pci.pc.pb = NULL;
3603
3604   //  pcw->pci.pc.analyze = genericAnalyze;
3605   pcw->pci.pc.destruct = genericDestruct;
3606   pcw->pci.pc.print = genericPrint;
3607
3608   pcw->id = pCodeID;              // this is the 'n' in %n
3609   pcw->operand = optional_operand;
3610   pcw->label   = optional_label;
3611
3612   pcw->mustBeBitSkipInst = 0;
3613   pcw->mustNotBeBitSkipInst = 0;
3614   pcw->invertBitSkipInst = 0;
3615
3616   return ( (pCode *)pcw);
3617   
3618 }
3619
3620  /*-----------------------------------------------------------------*/
3621 /* newPcodeInlineP - create a new pCode from a char string           */
3622 /*-----------------------------------------------------------------*/
3623
3624
3625 pCode *pic16_newpCodeInlineP(char *cP)
3626 {
3627
3628   pCodeComment *pcc ;
3629     
3630   pcc = Safe_calloc(1,sizeof(pCodeComment));
3631
3632   pcc->pc.type = PC_INLINE;
3633   pcc->pc.prev = pcc->pc.next = NULL;
3634   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3635   pcc->pc.pb = NULL;
3636
3637   //  pcc->pc.analyze = genericAnalyze;
3638   pcc->pc.destruct = genericDestruct;
3639   pcc->pc.print = genericPrint;
3640
3641   if(cP)
3642     pcc->comment = Safe_strdup(cP);
3643   else
3644     pcc->comment = NULL;
3645
3646   return ( (pCode *)pcc);
3647
3648 }
3649
3650 /*-----------------------------------------------------------------*/
3651 /* newPcodeCharP - create a new pCode from a char string           */
3652 /*-----------------------------------------------------------------*/
3653
3654 pCode *pic16_newpCodeCharP(char *cP)
3655 {
3656
3657   pCodeComment *pcc ;
3658     
3659   pcc = Safe_calloc(1,sizeof(pCodeComment));
3660
3661   pcc->pc.type = PC_COMMENT;
3662   pcc->pc.prev = pcc->pc.next = NULL;
3663   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3664   pcc->pc.pb = NULL;
3665
3666   //  pcc->pc.analyze = genericAnalyze;
3667   pcc->pc.destruct = genericDestruct;
3668   pcc->pc.print = genericPrint;
3669
3670   if(cP)
3671     pcc->comment = Safe_strdup(cP);
3672   else
3673     pcc->comment = NULL;
3674
3675   return ( (pCode *)pcc);
3676
3677 }
3678
3679 /*-----------------------------------------------------------------*/
3680 /* pic16_newpCodeFunction -                                              */
3681 /*-----------------------------------------------------------------*/
3682
3683
3684 pCode *pic16_newpCodeFunction(char *mod,char *f)
3685 {
3686   pCodeFunction *pcf;
3687
3688   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3689
3690   pcf->pc.type = PC_FUNCTION;
3691   pcf->pc.prev = pcf->pc.next = NULL;
3692   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3693   pcf->pc.pb = NULL;
3694
3695   //  pcf->pc.analyze = genericAnalyze;
3696   pcf->pc.destruct = genericDestruct;
3697   pcf->pc.print = pCodePrintFunction;
3698
3699   pcf->ncalled = 0;
3700   pcf->absblock = 0;
3701   
3702   if(mod) {
3703     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3704     strcpy(pcf->modname,mod);
3705   } else
3706     pcf->modname = NULL;
3707
3708   if(f) {
3709     pcf->fname = Safe_calloc(1,strlen(f)+1);
3710     strcpy(pcf->fname,f);
3711   } else
3712     pcf->fname = NULL;
3713
3714   pcf->stackusage = 0;
3715
3716   return ( (pCode *)pcf);
3717 }
3718
3719 /*-----------------------------------------------------------------*/
3720 /* pic16_newpCodeFlow                                                    */
3721 /*-----------------------------------------------------------------*/
3722 static void destructpCodeFlow(pCode *pc)
3723 {
3724   if(!pc || !isPCFL(pc))
3725     return;
3726
3727 /*
3728   if(PCFL(pc)->from)
3729   if(PCFL(pc)->to)
3730 */
3731   pic16_unlinkpCode(pc);
3732
3733   deleteSet(&PCFL(pc)->registers);
3734   deleteSet(&PCFL(pc)->from);
3735   deleteSet(&PCFL(pc)->to);
3736
3737   /* Instead of deleting the memory used by this pCode, mark
3738    * the object as bad so that if there's a pointer to this pCode
3739    * dangling around somewhere then (hopefully) when the type is
3740    * checked we'll catch it.
3741    */
3742
3743   pc->type = PC_BAD;
3744   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3745
3746 //  Safe_free(pc);
3747
3748 }
3749
3750 pCode *pic16_newpCodeFlow(void )
3751 {
3752   pCodeFlow *pcflow;
3753
3754   //_ALLOC(pcflow,sizeof(pCodeFlow));
3755   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3756
3757   pcflow->pc.type = PC_FLOW;
3758   pcflow->pc.prev = pcflow->pc.next = NULL;
3759   pcflow->pc.pb = NULL;
3760
3761   //  pcflow->pc.analyze = genericAnalyze;
3762   pcflow->pc.destruct = destructpCodeFlow;
3763   pcflow->pc.print = genericPrint;
3764
3765   pcflow->pc.seq = GpcFlowSeq++;
3766
3767   pcflow->from = pcflow->to = NULL;
3768
3769   pcflow->inCond = PCC_NONE;
3770   pcflow->outCond = PCC_NONE;
3771
3772   pcflow->firstBank = -1;
3773   pcflow->lastBank = -1;
3774
3775   pcflow->FromConflicts = 0;
3776   pcflow->ToConflicts = 0;
3777
3778   pcflow->end = NULL;
3779
3780   pcflow->registers = newSet();
3781
3782   return ( (pCode *)pcflow);
3783
3784 }
3785
3786 /*-----------------------------------------------------------------*/
3787 /*-----------------------------------------------------------------*/
3788 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3789 {
3790   pCodeFlowLink *pcflowLink;
3791
3792   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3793
3794   pcflowLink->pcflow = pcflow;
3795   pcflowLink->bank_conflict = 0;
3796
3797   return pcflowLink;
3798 }
3799
3800 /*-----------------------------------------------------------------*/
3801 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3802 /*-----------------------------------------------------------------*/
3803
3804 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3805 {
3806
3807   pCodeCSource *pccs;
3808     
3809   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3810
3811   pccs->pc.type = PC_CSOURCE;
3812   pccs->pc.prev = pccs->pc.next = NULL;
3813   pccs->pc.pb = NULL;
3814
3815   pccs->pc.destruct = genericDestruct;
3816   pccs->pc.print = genericPrint;
3817
3818   pccs->line_number = ln;
3819   if(l)
3820     pccs->line = Safe_strdup(l);
3821   else
3822     pccs->line = NULL;
3823
3824   if(f)
3825     pccs->file_name = Safe_strdup(f);
3826   else
3827     pccs->file_name = NULL;
3828
3829   return ( (pCode *)pccs);
3830
3831 }
3832
3833
3834 /*******************************************************************/
3835 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3836 /*                      added by VR 6-Jun-2003                     */
3837 /*******************************************************************/
3838
3839 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3840 {
3841   pCodeAsmDir *pcad;
3842   va_list ap;
3843   char buffer[512];
3844   char *lbp=buffer;
3845   
3846         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3847         pcad->pci.pc.type = PC_ASMDIR;
3848         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3849         pcad->pci.pc.pb = NULL;
3850         pcad->pci.isize = 2;
3851         pcad->pci.pc.destruct = genericDestruct;
3852         pcad->pci.pc.print = genericPrint;
3853
3854         if(asdir && *asdir) {
3855                 
3856                 while(isspace(*asdir))asdir++;  // strip any white space from the beginning
3857                 
3858                 pcad->directive = Safe_strdup( asdir );
3859         }
3860         
3861         va_start(ap, argfmt);
3862         
3863         memset(buffer, 0, sizeof(buffer));
3864         if(argfmt && *argfmt)
3865                 vsprintf(buffer, argfmt, ap);
3866         
3867         va_end(ap);
3868         
3869         while(isspace(*lbp))lbp++;
3870         
3871         if(lbp && *lbp)
3872                 pcad->arg = Safe_strdup( lbp );
3873
3874   return ((pCode *)pcad);
3875 }
3876
3877 /*-----------------------------------------------------------------*/
3878 /* pCodeLabelDestruct - free memory used by a label.               */
3879 /*-----------------------------------------------------------------*/
3880 static void pCodeLabelDestruct(pCode *pc)
3881 {
3882
3883   if(!pc)
3884     return;
3885
3886 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3887 //    Safe_free(PCL(pc)->label);
3888
3889   /* Instead of deleting the memory used by this pCode, mark
3890    * the object as bad so that if there's a pointer to this pCode
3891    * dangling around somewhere then (hopefully) when the type is
3892    * checked we'll catch it.
3893    */
3894
3895   pc->type = PC_BAD;
3896   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3897
3898 //  Safe_free(pc);
3899
3900 }
3901
3902 pCode *pic16_newpCodeLabel(char *name, int key)
3903 {
3904
3905   char *s = buffer;
3906   pCodeLabel *pcl;
3907     
3908   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3909
3910   pcl->pc.type = PC_LABEL;
3911   pcl->pc.prev = pcl->pc.next = NULL;
3912   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3913   pcl->pc.pb = NULL;
3914
3915   //  pcl->pc.analyze = genericAnalyze;
3916   pcl->pc.destruct = pCodeLabelDestruct;
3917   pcl->pc.print = pCodePrintLabel;
3918
3919   pcl->key = key;
3920   pcl->force = 0;
3921   
3922   pcl->label = NULL;
3923   if(key>0) {
3924     sprintf(s,"_%05d_DS_",key);
3925   } else
3926     s = name;
3927
3928   if(s)
3929     pcl->label = Safe_strdup(s);
3930
3931 //  if(pic16_pcode_verbose)
3932 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3933
3934
3935   return ( (pCode *)pcl);
3936
3937 }
3938
3939 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3940 {
3941   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3942   
3943         pcl->force = 1;
3944   
3945   return ( (pCode *)pcl );
3946 }
3947
3948 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3949 {
3950   pCodeInfo *pci;
3951
3952     pci = Safe_calloc(1, sizeof(pCodeInfo));
3953     pci->pci.pc.type = PC_INFO;
3954     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3955     pci->pci.pc.pb = NULL;
3956     pci->pci.label = NULL;
3957         
3958     pci->pci.pc.destruct = genericDestruct;
3959     pci->pci.pc.print = genericPrint;
3960     
3961     pci->type = type;
3962     pci->oper1 = pcop;
3963   
3964   return ((pCode *)pci);
3965 }
3966
3967
3968 /*-----------------------------------------------------------------*/
3969 /* newpBlock - create and return a pointer to a new pBlock         */
3970 /*-----------------------------------------------------------------*/
3971 static pBlock *newpBlock(void)
3972 {
3973
3974   pBlock *PpB;
3975
3976   PpB = Safe_calloc(1,sizeof(pBlock) );
3977   PpB->next = PpB->prev = NULL;
3978
3979   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3980   PpB->tregisters = NULL;
3981   PpB->visited = 0;
3982   PpB->FlowTree = NULL;
3983
3984   return PpB;
3985
3986 }
3987
3988 /*-----------------------------------------------------------------*/
3989 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3990 /*-----------------------------------------------------------------*
3991  *
3992  *  This function will create a new pBlock and the pointer to the
3993  *  pCode that is passed in will be the first pCode in the block.
3994  *-----------------------------------------------------------------*/
3995
3996
3997 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3998 {
3999
4000   pBlock *pB  = newpBlock();
4001
4002   pB->pcHead  = pB->pcTail = pc;
4003   pB->cmemmap = cm;
4004   pB->dbName  = c;
4005
4006   return pB;
4007 }
4008
4009
4010
4011 /*-----------------------------------------------------------------*/
4012 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4013 /*  Note, a negative key means that the label is part of wild card */
4014 /*  (and hence a wild card label) used in the pCodePeep            */
4015 /*   optimizations).                                               */
4016 /*-----------------------------------------------------------------*/
4017
4018 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4019 {
4020   char *s=NULL;
4021   static int label_key=-1;
4022
4023   pCodeOp *pcop;
4024
4025   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4026   pcop->type = PO_LABEL;
4027
4028   pcop->name = NULL;
4029
4030   if(key>0)
4031     sprintf(s=buffer,"_%05d_DS_",key);
4032   else 
4033     s = name, key = label_key--;
4034
4035   if(s)
4036     pcop->name = Safe_strdup(s);
4037
4038   ((pCodeOpLabel *)pcop)->key = key;
4039
4040   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4041   return pcop;
4042 }
4043
4044 /*-----------------------------------------------------------------*/
4045 /*-----------------------------------------------------------------*/
4046 pCodeOp *pic16_newpCodeOpLit(int lit)
4047 {
4048   char *s = buffer;
4049   pCodeOp *pcop;
4050
4051
4052   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4053   pcop->type = PO_LITERAL;
4054
4055   pcop->name = NULL;
4056   //if(lit>=0)
4057     sprintf(s,"0x%02hhx", (unsigned char)lit);
4058   //else
4059   //  sprintf(s, "%i", lit);
4060   
4061   if(s)
4062     pcop->name = Safe_strdup(s);
4063
4064   ((pCodeOpLit *)pcop)->lit = lit;
4065
4066   return pcop;
4067 }
4068
4069 /*-----------------------------------------------------------------*/
4070 /*-----------------------------------------------------------------*/
4071 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4072 {
4073   char *s = buffer, tbuf[256], *tb=tbuf;
4074   pCodeOp *pcop;
4075
4076
4077   tb = pic16_get_op(arg2, NULL, 0);
4078   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4079   pcop->type = PO_LITERAL;
4080
4081   pcop->name = NULL;
4082   //if(lit>=0) {
4083     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4084     if(s)
4085       pcop->name = Safe_strdup(s);
4086   //}
4087
4088   ((pCodeOpLit2 *)pcop)->lit = lit;
4089   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4090
4091   return pcop;
4092 }
4093
4094 /*-----------------------------------------------------------------*/
4095 /*-----------------------------------------------------------------*/
4096 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4097 {
4098   pCodeOp *pcop;
4099
4100         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4101         pcop->type = PO_IMMEDIATE;
4102         if(name) {
4103                 regs *r = pic16_dirregWithName(name);
4104                 pcop->name = Safe_strdup(name);
4105                 PCOI(pcop)->r = r;
4106                 
4107                 if(r) {
4108 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4109                         PCOI(pcop)->rIdx = r->rIdx;
4110                 } else {
4111 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4112                         PCOI(pcop)->rIdx = -1;
4113                 }
4114 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4115         } else {
4116                 pcop->name = NULL;
4117         }
4118
4119         PCOI(pcop)->index = index;
4120         PCOI(pcop)->offset = offset;
4121         PCOI(pcop)->_const = code_space;
4122
4123   return pcop;
4124 }
4125
4126 /*-----------------------------------------------------------------*/
4127 /*-----------------------------------------------------------------*/
4128 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4129 {
4130   char *s = buffer;
4131   pCodeOp *pcop;
4132
4133
4134   if(!pcwb || !subtype) {
4135     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4136     exit(1);
4137   }
4138
4139   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4140   pcop->type = PO_WILD;
4141   sprintf(s,"%%%d",id);
4142   pcop->name = Safe_strdup(s);
4143
4144   PCOW(pcop)->id = id;
4145   PCOW(pcop)->pcwb = pcwb;
4146   PCOW(pcop)->subtype = subtype;
4147   PCOW(pcop)->matched = NULL;
4148
4149   PCOW(pcop)->pcop2 = NULL;
4150   
4151   return pcop;
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /*-----------------------------------------------------------------*/
4156 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4157 {
4158   char *s = buffer;
4159   pCodeOp *pcop;
4160
4161
4162         if(!pcwb || !subtype || !subtype2) {
4163                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4164                 exit(1);
4165         }
4166
4167         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4168         pcop->type = PO_WILD;
4169         sprintf(s,"%%%d",id);
4170         pcop->name = Safe_strdup(s);
4171
4172         PCOW(pcop)->id = id;
4173         PCOW(pcop)->pcwb = pcwb;
4174         PCOW(pcop)->subtype = subtype;
4175         PCOW(pcop)->matched = NULL;
4176
4177         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4178
4179         if(!subtype2->name) {
4180                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4181                 PCOW2(pcop)->pcop.type = PO_WILD;
4182                 sprintf(s, "%%%d", id2);
4183                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4184                 PCOW2(pcop)->id = id2;
4185                 PCOW2(pcop)->subtype = subtype2;
4186
4187 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4188 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4189         } else {
4190                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4191
4192 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4193 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4194         }
4195   
4196
4197
4198   return pcop;
4199 }
4200
4201
4202 /*-----------------------------------------------------------------*/
4203 /*-----------------------------------------------------------------*/
4204 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4205 {
4206   pCodeOp *pcop;
4207   
4208   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4209   pcop->type = PO_GPR_BIT;
4210   if(s)
4211     pcop->name = Safe_strdup(s);   
4212   else
4213     pcop->name = NULL;
4214
4215   PCORB(pcop)->bit = bit;
4216   PCORB(pcop)->inBitSpace = inBitSpace;
4217   PCORB(pcop)->subtype = subt;
4218
4219   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4220   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4221 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4222 //  PCOR(pcop)->rIdx = 0;
4223   return pcop;
4224 }
4225
4226
4227 /*-----------------------------------------------------------------*
4228  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4229  *
4230  * If rIdx >=0 then a specific register from the set of registers
4231  * will be selected. If rIdx <0, then a new register will be searched
4232  * for.
4233  *-----------------------------------------------------------------*/
4234
4235 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4236 {
4237   pCodeOp *pcop;
4238
4239   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4240
4241   pcop->name = NULL;
4242
4243   if(rIdx >= 0) {
4244     PCOR(pcop)->rIdx = rIdx;
4245     PCOR(pcop)->r = pic16_regWithIdx(rIdx);
4246   } else {
4247     PCOR(pcop)->r = pic16_findFreeReg(REG_GPR);
4248
4249     if(PCOR(pcop)->r)
4250       PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4251     else {
4252         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4253                 __FUNCTION__, __LINE__);
4254         exit(-1);
4255     }
4256   }
4257
4258   pcop->type = PCOR(pcop)->r->pc_type;
4259
4260   return pcop;
4261 }
4262
4263 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4264 {
4265   pCodeOp *pcop;
4266   regs *r;
4267   
4268     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4269     pcop->name = NULL;
4270     
4271     r = pic16_findFreeReg(REG_GPR);
4272
4273     while(r) {
4274       if(!bitVectBitValue(bv, r->rIdx)) {
4275         PCOR(pcop)->r = r;
4276         PCOR(pcop)->rIdx = r->rIdx;
4277         pcop->type = r->pc_type;
4278         return (pcop);
4279       }
4280       
4281       r = pic16_findFreeRegNext(REG_GPR, r);
4282     }
4283   
4284   return NULL;
4285 }
4286
4287       
4288
4289 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4290 {
4291   pCodeOp *pcop;
4292   regs *r;
4293
4294         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4295         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4296         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4297         pcop->type = PCOR(pcop)->r->pc_type;
4298         pcop->name = PCOR(pcop)->r->name;
4299
4300 //      if(pic16_pcode_verbose) {
4301 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4302 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4303 //      }
4304
4305   return pcop;
4306 }
4307
4308 /*-----------------------------------------------------------------*/
4309 /*-----------------------------------------------------------------*/
4310 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4311 {
4312   pCodeOpOpt *pcop;
4313
4314         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4315         
4316         pcop->type = type;
4317         pcop->key = Safe_strdup( key );
4318
4319   return (PCOP(pcop));
4320 }
4321
4322 /*-----------------------------------------------------------------*/
4323 /*-----------------------------------------------------------------*/
4324 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4325 {
4326   pCodeOpLocalReg *pcop;
4327
4328         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4329         
4330         pcop->type = type;
4331
4332   return (PCOP(pcop));
4333 }
4334
4335
4336 /*-----------------------------------------------------------------*/
4337 /*-----------------------------------------------------------------*/
4338
4339 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4340 {
4341   pCodeOp *pcop;
4342
4343   switch(type) {
4344   case PO_BIT:
4345   case PO_GPR_BIT:
4346     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4347     break;
4348
4349   case PO_LITERAL:
4350     pcop = pic16_newpCodeOpLit(-1);
4351     break;
4352
4353   case PO_LABEL:
4354     pcop = pic16_newpCodeOpLabel(NULL,-1);
4355     break;
4356   case PO_GPR_TEMP:
4357     pcop = pic16_newpCodeOpReg(-1);
4358     break;
4359
4360   case PO_GPR_REGISTER:
4361     if(name)
4362       pcop = pic16_newpCodeOpRegFromStr(name);
4363     else
4364       pcop = pic16_newpCodeOpReg(-1);
4365     break;
4366
4367   default:
4368     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4369     pcop->type = type;
4370     if(name)
4371       pcop->name = Safe_strdup(name);   
4372     else
4373       pcop->name = NULL;
4374   }
4375
4376   return pcop;
4377 }
4378
4379 #define DB_ITEMS_PER_LINE       8
4380
4381 typedef struct DBdata
4382   {
4383     int count;
4384     char buffer[256];
4385   } DBdata;
4386
4387 struct DBdata DBd;
4388 static int DBd_init = -1;
4389
4390 /*-----------------------------------------------------------------*/
4391 /*    Initialiase "DB" data buffer                                 */
4392 /*-----------------------------------------------------------------*/
4393 void pic16_initDB(void)
4394 {
4395         DBd_init = -1;
4396 }
4397
4398
4399 /*-----------------------------------------------------------------*/
4400 /*    Flush pending "DB" data to a pBlock                          */
4401 /*                                                                 */
4402 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4403 /*-----------------------------------------------------------------*/
4404 void pic16_flushDB(char ptype, void *p)
4405 {
4406         if (DBd.count>0) {
4407                 if(ptype == 'p')
4408                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4409                 else
4410                 if(ptype == 'f')
4411                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4412                 else {
4413                         /* sanity check */
4414                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4415                 }
4416
4417                 DBd.count = 0;
4418                 DBd.buffer[0] = '\0';
4419         }
4420 }
4421
4422
4423 /*-----------------------------------------------------------------*/
4424 /*    Add "DB" directives to a pBlock                              */
4425 /*-----------------------------------------------------------------*/
4426 void pic16_emitDB(char c, char ptype, void *p)
4427 {
4428   int l;
4429
4430         if (DBd_init<0) {
4431          // we need to initialize
4432                 DBd_init = 0;
4433                 DBd.count = 0;
4434                 DBd.buffer[0] = '\0';
4435         }
4436
4437         l = strlen(DBd.buffer);
4438         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4439
4440 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4441         
4442         DBd.count++;
4443         if (DBd.count>= DB_ITEMS_PER_LINE)
4444                 pic16_flushDB(ptype, p);
4445 }
4446
4447 void pic16_emitDS(char *s, char ptype, void *p)
4448 {
4449   int l;
4450
4451         if (DBd_init<0) {
4452          // we need to initialize
4453                 DBd_init = 0;
4454                 DBd.count = 0;
4455                 DBd.buffer[0] = '\0';
4456         }
4457
4458         l = strlen(DBd.buffer);
4459         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4460
4461 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4462
4463         DBd.count++;    //=strlen(s);
4464         if (DBd.count>=16)
4465                 pic16_flushDB(ptype, p);
4466 }
4467
4468
4469 /*-----------------------------------------------------------------*/
4470 /*-----------------------------------------------------------------*/
4471 void pic16_pCodeConstString(char *name, char *value)
4472 {
4473   pBlock *pb;
4474
4475   //  fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4476
4477   if(!name || !value)
4478     return;
4479
4480   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4481
4482   pic16_addpBlock(pb);
4483
4484 //  sprintf(buffer,"; %s = ", name);
4485 //  strcat(buffer, value);
4486 //  fputs(buffer, stderr);
4487
4488 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4489   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4490
4491   do {
4492         pic16_emitDB(*value, 'p', (void *)pb);
4493   }while (*value++);
4494   pic16_flushDB('p', (void *)pb);
4495 }
4496
4497 /*-----------------------------------------------------------------*/
4498 /*-----------------------------------------------------------------*/
4499 #if 0
4500 static void pCodeReadCodeTable(void)
4501 {
4502   pBlock *pb;
4503
4504   fprintf(stderr, " %s\n",__FUNCTION__);
4505
4506   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4507
4508   pic16_addpBlock(pb);
4509
4510   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4511   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4512   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4513   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4514
4515   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4516   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4517   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4518   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4519
4520
4521 }
4522 #endif
4523 /*-----------------------------------------------------------------*/
4524 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4525 /*-----------------------------------------------------------------*/
4526 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4527 {
4528
4529   if(!pc)
4530     return;
4531
4532   if(!pb->pcHead) {
4533     /* If this is the first pcode to be added to a block that
4534      * was initialized with a NULL pcode, then go ahead and
4535      * make this pcode the head and tail */
4536     pb->pcHead  = pb->pcTail = pc;
4537   } else {
4538     //    if(pb->pcTail)
4539     pb->pcTail->next = pc;
4540
4541     pc->prev = pb->pcTail;
4542     pc->pb = pb;
4543
4544     pb->pcTail = pc;
4545   }
4546 }
4547
4548 /*-----------------------------------------------------------------*/
4549 /* pic16_addpBlock - place a pBlock into the pFile                 */
4550 /*-----------------------------------------------------------------*/
4551 void pic16_addpBlock(pBlock *pb)
4552 {
4553   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4554
4555   if(!the_pFile) {
4556     /* First time called, we'll pass through here. */
4557     //_ALLOC(the_pFile,sizeof(pFile));
4558     the_pFile = Safe_calloc(1,sizeof(pFile));
4559     the_pFile->pbHead = the_pFile->pbTail = pb;
4560     the_pFile->functions = NULL;
4561     return;
4562   }
4563
4564   the_pFile->pbTail->next = pb;
4565   pb->prev = the_pFile->pbTail;
4566   pb->next = NULL;
4567   the_pFile->pbTail = pb;
4568 }
4569
4570 /*-----------------------------------------------------------------*/
4571 /* removepBlock - remove a pBlock from the pFile                   */
4572 /*-----------------------------------------------------------------*/
4573 static void removepBlock(pBlock *pb)
4574 {
4575   pBlock *pbs;
4576
4577   if(!the_pFile)
4578     return;
4579
4580
4581   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4582
4583   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4584     if(pbs == pb) {
4585
4586       if(pbs == the_pFile->pbHead)
4587         the_pFile->pbHead = pbs->next;
4588
4589       if (pbs == the_pFile->pbTail) 
4590         the_pFile->pbTail = pbs->prev;
4591
4592       if(pbs->next)
4593         pbs->next->prev = pbs->prev;
4594
4595       if(pbs->prev)
4596         pbs->prev->next = pbs->next;
4597
4598       return;
4599
4600     }
4601   }
4602
4603   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4604
4605 }
4606
4607 /*-----------------------------------------------------------------*/
4608 /* printpCode - write the contents of a pCode to a file            */
4609 /*-----------------------------------------------------------------*/
4610 static void printpCode(FILE *of, pCode *pc)
4611 {
4612
4613   if(!pc || !of)
4614     return;
4615
4616   if(pc->print) {
4617     pc->print(of,pc);
4618     return;
4619   }
4620
4621   fprintf(of,"warning - unable to print pCode\n");
4622 }
4623
4624 /*-----------------------------------------------------------------*/
4625 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4626 /*-----------------------------------------------------------------*/
4627 void pic16_printpBlock(FILE *of, pBlock *pb)
4628 {
4629   pCode *pc;
4630
4631         if(!pb)return;
4632
4633         if(!of)of=stderr;
4634
4635         for(pc = pb->pcHead; pc; pc = pc->next) {
4636                 if(isPCF(pc) && PCF(pc)->fname) {
4637                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4638                         if(pb->dbName == 'A') {
4639                           absSym *ab;
4640                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4641 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4642                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4643 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4644                                                 if(ab->address != -1)
4645                                                   fprintf(of, "\t0X%06X", ab->address);
4646                                                 break;
4647                                         }
4648                                 }
4649                         }
4650                         fprintf(of, "\n");
4651                 }
4652                 printpCode(of,pc);
4653         }
4654 }
4655
4656 /*-----------------------------------------------------------------*/
4657 /*                                                                 */
4658 /*       pCode processing                                          */
4659 /*                                                                 */
4660 /*                                                                 */
4661 /*                                                                 */
4662 /*-----------------------------------------------------------------*/
4663 pCode * pic16_findNextInstruction(pCode *pci);
4664 pCode * pic16_findPrevInstruction(pCode *pci);
4665
4666 void pic16_unlinkpCode(pCode *pc)
4667 {
4668   pCode *prev;
4669
4670   if(pc) {
4671 #ifdef PCODE_DEBUG
4672     fprintf(stderr,"Unlinking: ");
4673     printpCode(stderr, pc);
4674 #endif
4675     if(pc->prev) 
4676       pc->prev->next = pc->next;
4677     if(pc->next)
4678       pc->next->prev = pc->prev;
4679
4680     /* move C source line down (or up) */
4681     if (isPCI(pc) && PCI(pc)->cline) {
4682       prev = pic16_findNextInstruction (pc->next);
4683       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4684         PCI(prev)->cline = PCI(pc)->cline;
4685       } else {
4686         prev = pic16_findPrevInstruction (pc->prev);
4687         if (prev && isPCI(prev) && !PCI(prev)->cline)
4688           PCI(prev)->cline = PCI(pc)->cline;
4689       }
4690     }
4691     pc->prev = pc->next = NULL;
4692   }
4693 }
4694
4695 /*-----------------------------------------------------------------*/
4696 /*-----------------------------------------------------------------*/
4697
4698 static void genericDestruct(pCode *pc)
4699 {
4700
4701   pic16_unlinkpCode(pc);
4702
4703   if(isPCI(pc)) {
4704     /* For instructions, tell the register (if there's one used)
4705      * that it's no longer needed */
4706     regs *reg = pic16_getRegFromInstruction(pc);
4707     if(reg)
4708       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4709
4710         if(PCI(pc)->is2MemOp) {
4711                 reg = pic16_getRegFromInstruction2(pc);
4712                 if(reg)
4713                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4714         }
4715   }
4716
4717   /* Instead of deleting the memory used by this pCode, mark
4718    * the object as bad so that if there's a pointer to this pCode
4719    * dangling around somewhere then (hopefully) when the type is
4720    * checked we'll catch it.
4721    */
4722
4723   pc->type = PC_BAD;
4724   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4725
4726   //Safe_free(pc);
4727 }
4728
4729
4730 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4731 /*-----------------------------------------------------------------*/
4732 /*-----------------------------------------------------------------*/
4733 /* modifiers for constant immediate */
4734 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4735
4736 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4737 {
4738   regs *r;
4739   static char b[128];
4740   char *s;
4741   int use_buffer = 1;    // copy the string to the passed buffer pointer
4742
4743         if(!buffer) {
4744                 buffer = b;
4745                 size = sizeof(b);
4746                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4747         } 
4748
4749         if(pcop) {
4750                 switch(pcop->type) {
4751                         case PO_W:
4752                         case PO_WREG:
4753                         case PO_PRODL:
4754                         case PO_PRODH:
4755                         case PO_INDF0:
4756                         case PO_FSR0:
4757                                 if(use_buffer) {
4758                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4759                                         return buffer;
4760                                 }
4761                                 return PCOR(pcop)->r->name;
4762                                 break;
4763                         case PO_GPR_TEMP:
4764                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4765                                 if(use_buffer) {
4766                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4767                                         return buffer;
4768                                 }
4769                                 return r->name;
4770
4771                         case PO_IMMEDIATE:
4772                                 s = buffer;
4773                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4774                                         if(PCOI(pcop)->index) {
4775                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4776                                                         immdmod[ PCOI(pcop)->offset ],
4777                                                         pcop->name,
4778                                                         PCOI(pcop)->index);
4779                                         } else {
4780                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4781                                                         immdmod[ PCOI(pcop)->offset ],
4782                                                         pcop->name);
4783                                         }
4784                                 } else {
4785                                         if(PCOI(pcop)->index) {
4786                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4787                                                         immdmod[ 0 ],
4788                                                         pcop->name,
4789                                                         PCOI(pcop)->index);
4790                                         } else {
4791                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4792                                                         immdmod[ 0 ],
4793                                                         pcop->name);
4794                                         }
4795                                 }
4796                                 return buffer;
4797
4798                         case PO_GPR_REGISTER:
4799                         case PO_DIR:
4800                                 s = buffer;
4801 //                              size = sizeof(buffer);
4802                                 if( PCOR(pcop)->instance) {
4803                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4804                                                 pcop->name,
4805                                                 PCOR(pcop)->instance );
4806                                 } else {
4807                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4808                                 }
4809                                 return buffer;
4810                         case PO_GPR_BIT:
4811                                 s = buffer;
4812                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4813                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4814                                 } else {
4815                                         if(PCORB(pcop)->pcor.instance)
4816                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4817                                         else
4818                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4819                                 }
4820
4821                                 return (buffer);
4822                         default:
4823                                 if(pcop->name) {
4824                                         if(use_buffer) {
4825                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4826                                                 return buffer;
4827                                         }
4828                                 return pcop->name;
4829                                 }
4830
4831                 }
4832         }
4833
4834   return "NO operand1";
4835 }
4836
4837 /*-----------------------------------------------------------------*/
4838 /* pic16_get_op2 - variant to support two memory operand commands  */
4839 /*-----------------------------------------------------------------*/
4840 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4841 {
4842   regs *r;
4843   static char b[50];
4844   char *s;
4845   int use_buffer = 1;    // copy the string to the passed buffer pointer
4846
4847         if(!buffer) {
4848                 buffer = b;
4849                 size = sizeof(b);
4850                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4851         } 
4852
4853 #if 0
4854         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",
4855                 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4856                 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4857 #endif
4858
4859         if(pcop) {
4860                 switch(PCOR2(pcop)->pcop2->type) {
4861                         case PO_W:
4862                         case PO_WREG:
4863                         case PO_PRODL:
4864                         case PO_PRODH:
4865                         case PO_INDF0:
4866                         case PO_FSR0:
4867                                 if(use_buffer) {
4868                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4869                                         return buffer;
4870                                 }
4871                                 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4872                                 break;
4873                         case PO_GPR_TEMP:
4874                                 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4875
4876                                 if(use_buffer) {
4877                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4878                                         return buffer;
4879                                 }
4880                                 return r->name;
4881
4882                         case PO_IMMEDIATE:
4883                                         assert( 0 );
4884                                 break;
4885 #if 0
4886                                 s = buffer;
4887
4888                                 if(PCOI(pcop)->_const) {
4889                                         if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4890                                                 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4891                                                         pcop->name,
4892                                                         PCOI(pcop)->index,
4893                                                         8 * PCOI(pcop)->offset );
4894                                         } else
4895                                                 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4896                                 } else {
4897                                         if( PCOI(pcop)->index) {
4898                                                 SAFE_snprintf(&s,&size,"(%s + %d)",
4899                                                         pcop->name,
4900                                                         PCOI(pcop)->index );
4901                                         } else {
4902                                                 if(PCOI(pcop)->offset)
4903                                                         SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4904                                                 else
4905                                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4906                                         }
4907                                 }
4908                                 return buffer;
4909 #endif
4910                         case PO_DIR:
4911                                 s = buffer;
4912                                 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4913                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4914                                                 PCOR(PCOR2(pcop)->pcop2)->r->name,
4915                                                 PCOR(PCOR2(pcop)->pcop2)->instance );
4916                                 } else {
4917                                         SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4918                                 }
4919                                 return buffer;
4920
4921                         default:
4922                                 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4923                                         if(use_buffer) {
4924                                                 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4925                                                 return buffer;
4926                                         }
4927                                         return PCOR(PCOR2(pcop)->pcop2)->r->name;
4928                                 }
4929                 }
4930         }
4931
4932   return "NO operand2";
4933 }
4934
4935 /*-----------------------------------------------------------------*/
4936 /*-----------------------------------------------------------------*/
4937 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4938 {
4939
4940   if(pcc )
4941     return pic16_get_op(pcc->pcop,NULL,0);
4942
4943   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
4944    *   return ("ERROR Null: "__FUNCTION__);
4945    */
4946   return ("ERROR Null: pic16_get_op_from_instruction");
4947
4948 }
4949
4950 /*-----------------------------------------------------------------*/
4951 /*-----------------------------------------------------------------*/
4952 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4953 {
4954
4955   fprintf(of,"pcodeopprint- not implemented\n");
4956 }
4957
4958 /*-----------------------------------------------------------------*/
4959 /* pic16_pCode2str - convert a pCode instruction to string               */
4960 /*-----------------------------------------------------------------*/
4961 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4962 {
4963   char *s = str;
4964   regs *r;
4965
4966 #if 0
4967         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4968                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4969                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4970 //              exit(-1);
4971         }
4972 #endif
4973
4974   switch(pc->type) {
4975
4976   case PC_OPCODE:
4977     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4978
4979     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4980
4981         if(PCI(pc)->is2MemOp) {
4982                 SAFE_snprintf(&s,&size, "%s, %s", 
4983                 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
4984                 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
4985                 break;
4986         }
4987
4988         if(PCI(pc)->is2LitOp) {
4989                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4990                 break;
4991         }
4992
4993       if(PCI(pc)->isBitInst) {
4994         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4995           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4996             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
4997                           PCI(pc)->pcop->name ,
4998                           PCI(pc)->pcop->name );
4999           else
5000             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5001 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5002                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5003                           
5004         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5005           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5006         } else
5007           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5008         //PCI(pc)->pcop->t.bit );
5009       } else {
5010
5011         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5012           if( PCI(pc)->num_ops == 3)
5013             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5014           else
5015             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5016
5017         }
5018         else 
5019         {
5020           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5021         }
5022       }
5023         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5024           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5025             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5026
5027           r = pic16_getRegFromInstruction(pc);
5028 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5029 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5030
5031           if(r && !r->accessBank)SAFE_snprintf(&s,&size,", %s", (!pic16_mplab_comp?"B":"BANKED"));
5032         }
5033 //      
5034
5035     }
5036     break;
5037
5038   case PC_COMMENT:
5039     /* assuming that comment ends with a \n */
5040     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5041     break;
5042
5043   case PC_INFO:
5044     SAFE_snprintf(&s,&size,"; info ==>");
5045     switch( PCINF(pc)->type ) {
5046       case INF_OPTIMIZATION:
5047           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5048           break;
5049       case INF_LOCALREGS:
5050           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5051           break;
5052     }; break;
5053
5054   case PC_INLINE:
5055     /* assuming that inline code ends with a \n */
5056     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5057     break;
5058
5059   case PC_LABEL:
5060     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5061     break;
5062   case PC_FUNCTION:
5063     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5064     break;
5065   case PC_WILD:
5066     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5067     break;
5068   case PC_FLOW:
5069     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5070     break;
5071   case PC_CSOURCE:
5072 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5073       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5074         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5075     break;
5076   case PC_ASMDIR:
5077         if(PCAD(pc)->directive) {
5078                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5079         } else
5080         if(PCAD(pc)->arg) {
5081                 /* special case to handle inline labels without a tab */
5082                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5083         }
5084         break;
5085
5086   case PC_BAD:
5087     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5088     break;
5089   }
5090
5091   return str;
5092
5093 }
5094
5095 /*-----------------------------------------------------------------*/
5096 /* genericPrint - the contents of a pCode to a file                */
5097 /*-----------------------------------------------------------------*/
5098 static void genericPrint(FILE *of, pCode *pc)
5099 {
5100
5101   if(!pc || !of)
5102     return;
5103
5104   switch(pc->type) {
5105   case PC_COMMENT:
5106 //    fputs(((pCodeComment *)pc)->comment, of);
5107     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5108     break;
5109
5110   case PC_INFO:
5111     {
5112       pBranch *pbl = PCI(pc)->label;
5113       while(pbl && pbl->pc) {
5114         if(pbl->pc->type == PC_LABEL)
5115           pCodePrintLabel(of, pbl->pc);
5116         pbl = pbl->next;
5117       }
5118     }
5119           
5120     if(pic16_pcode_verbose) {
5121       fprintf(of, "; info ==>");
5122       switch(((pCodeInfo *)pc)->type) {
5123         case INF_OPTIMIZATION:
5124               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5125               break;
5126         case INF_LOCALREGS:
5127               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5128               break;
5129         }
5130     };
5131     
5132     break;
5133
5134   case PC_INLINE:
5135     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5136      break;
5137
5138   case PC_OPCODE:
5139     // If the opcode has a label, print that first
5140     {
5141       pBranch *pbl = PCI(pc)->label;
5142       while(pbl && pbl->pc) {
5143         if(pbl->pc->type == PC_LABEL)
5144           pCodePrintLabel(of, pbl->pc);
5145         pbl = pbl->next;
5146       }
5147     }
5148
5149     if(PCI(pc)->cline) 
5150       genericPrint(of,PCODE(PCI(pc)->cline));
5151
5152     {
5153       char str[256];
5154       
5155       pic16_pCode2str(str, 256, pc);
5156
5157       fprintf(of,"%s",str);
5158       /* Debug */
5159       if(pic16_debug_verbose) {
5160         fprintf(of, "\t;key=%03x",pc->seq);
5161         if(PCI(pc)->pcflow)
5162           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5163       }
5164     }
5165     fprintf(of, "\n");
5166     break;
5167       
5168   case PC_WILD:
5169     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5170     if(PCW(pc)->pci.label)
5171       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5172
5173     if(PCW(pc)->operand) {
5174       fprintf(of,";\toperand  ");
5175       pCodeOpPrint(of,PCW(pc)->operand );
5176     }
5177     break;
5178
5179   case PC_FLOW:
5180     if(pic16_debug_verbose) {
5181       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5182       if(PCFL(pc)->ancestor)
5183         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5184       fprintf(of,"\n");
5185
5186     }
5187     break;
5188
5189   case PC_CSOURCE:
5190 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5191     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5192         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5193          
5194     break;
5195
5196   case PC_ASMDIR:
5197         {
5198           pBranch *pbl = PCAD(pc)->pci.label;
5199                 while(pbl && pbl->pc) {
5200                         if(pbl->pc->type == PC_LABEL)
5201                                 pCodePrintLabel(of, pbl->pc);
5202                         pbl = pbl->next;
5203                 }
5204         }
5205         if(PCAD(pc)->directive) {
5206                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5207         } else
5208         if(PCAD(pc)->arg) {
5209                 /* special case to handle inline labels without tab */
5210                 fprintf(of, "%s\n", PCAD(pc)->arg);
5211         }
5212         break;
5213         
5214   case PC_LABEL:
5215   default:
5216     fprintf(of,"unknown pCode type %d\n",pc->type);
5217   }
5218
5219 }
5220
5221 /*-----------------------------------------------------------------*/
5222 /* pCodePrintFunction - prints function begin/end                  */
5223 /*-----------------------------------------------------------------*/
5224
5225 static void pCodePrintFunction(FILE *of, pCode *pc)
5226 {
5227
5228   if(!pc || !of)
5229     return;
5230
5231 #if 0
5232   if( ((pCodeFunction *)pc)->modname) 
5233     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5234 #endif
5235
5236   if(!PCF(pc)->absblock) {
5237       if(PCF(pc)->fname) {
5238       pBranch *exits = PCF(pc)->to;
5239       int i=0;
5240
5241       fprintf(of,"%s:", PCF(pc)->fname);
5242     
5243       if(pic16_pcode_verbose)
5244         fprintf(of, "\t;Function start");
5245     
5246       fprintf(of, "\n");
5247     
5248       while(exits) {
5249         i++;
5250         exits = exits->next;
5251       }
5252       //if(i) i--;
5253
5254       if(pic16_pcode_verbose)
5255         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5256     
5257     } else {
5258         if((PCF(pc)->from && 
5259                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5260                 PCF(PCF(pc)->from->pc)->fname) ) {
5261
5262                 if(pic16_pcode_verbose)
5263                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5264         } else {
5265                 if(pic16_pcode_verbose)
5266                         fprintf(of,"; exit point [can't find entry point]\n");
5267         }
5268         fprintf(of, "\n");
5269     }
5270   }
5271 }
5272 /*-----------------------------------------------------------------*/
5273 /* pCodePrintLabel - prints label                                  */
5274 /*-----------------------------------------------------------------*/
5275
5276 static void pCodePrintLabel(FILE *of, pCode *pc)
5277 {
5278
5279   if(!pc || !of)
5280     return;
5281
5282   if(PCL(pc)->label) 
5283     fprintf(of,"%s:\n",PCL(pc)->label);
5284   else if (PCL(pc)->key >=0) 
5285     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5286   else
5287     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5288
5289 }
5290 /*-----------------------------------------------------------------*/
5291 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5292 /*                         remove it if it is found.               */
5293 /*-----------------------------------------------------------------*/
5294 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5295 {
5296   pBranch *b, *bprev;
5297
5298
5299   bprev = NULL;
5300
5301   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5302     b = PCI(pcl)->label;
5303   else {
5304     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5305     exit(1);
5306
5307   }
5308
5309   //fprintf (stderr, "%s \n",__FUNCTION__);
5310   //pcl->print(stderr,pcl);
5311   //pc->print(stderr,pc);
5312   while(b) {
5313     if(b->pc == pc) {
5314       //fprintf (stderr, "found label\n");
5315       //pc->print(stderr, pc);
5316
5317       /* Found a label */
5318       if(bprev) {
5319         bprev->next = b->next;  /* Not first pCode in chain */
5320 //      Safe_free(b);
5321       } else {
5322         pc->destruct(pc);
5323         PCI(pcl)->label = b->next;   /* First pCode in chain */
5324 //      Safe_free(b);
5325       }
5326       return;  /* A label can't occur more than once */
5327     }
5328     bprev = b;
5329     b = b->next;
5330   }
5331
5332 }
5333
5334 /*-----------------------------------------------------------------*/
5335 /*-----------------------------------------------------------------*/
5336 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5337 {
5338   pBranch *b;
5339
5340   if(!h)
5341     return n;
5342
5343   if(h == n)
5344     return n;
5345
5346   b = h;
5347   while(b->next)
5348     b = b->next;
5349
5350   b->next = n;
5351
5352   return h;
5353   
5354 }  
5355 /*-----------------------------------------------------------------*/
5356 /* pBranchLink - given two pcodes, this function will link them    */
5357 /*               together through their pBranches                  */
5358 /*-----------------------------------------------------------------*/
5359 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5360 {
5361   pBranch *b;
5362
5363   // Declare a new branch object for the 'from' pCode.
5364
5365   //_ALLOC(b,sizeof(pBranch));
5366   b = Safe_calloc(1,sizeof(pBranch));
5367   b->pc = PCODE(t);             // The link to the 'to' pCode.
5368   b->next = NULL;
5369
5370   f->to = pic16_pBranchAppend(f->to,b);
5371
5372   // Now do the same for the 'to' pCode.
5373
5374   //_ALLOC(b,sizeof(pBranch));
5375   b = Safe_calloc(1,sizeof(pBranch));
5376   b->pc = PCODE(f);
5377   b->next = NULL;
5378
5379   t->from = pic16_pBranchAppend(t->from,b);
5380   
5381 }
5382
5383 #if 1
5384 /*-----------------------------------------------------------------*/
5385 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5386 /*               a pCode                                           */
5387 /*-----------------------------------------------------------------*/
5388 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5389 {
5390   while(pb) {
5391
5392     if(pb->pc == pc)
5393       return pb;
5394
5395     pb = pb->next;
5396   }
5397
5398   return NULL;
5399 }
5400
5401 /*-----------------------------------------------------------------*/
5402 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5403 /*-----------------------------------------------------------------*/
5404 void pic16_pCodeUnlink(pCode *pc)
5405 {
5406   pBranch *pb1,*pb2;
5407   pCode *pc1;
5408
5409   if(!pc->prev || !pc->next) {
5410     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5411     exit(1);
5412   }
5413   
5414   /* move C source line down (or up) */
5415   if (isPCI(pc) && PCI(pc)->cline) {
5416     pc1 = pic16_findNextInstruction (pc->next);
5417     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5418       PCI(pc1)->cline = PCI(pc)->cline;
5419     } else {
5420       pc1 = pic16_findPrevInstruction (pc->prev);
5421       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5422         PCI(pc1)->cline = PCI(pc)->cline;
5423     }
5424   }
5425
5426   /* first remove the pCode from the chain */
5427   pc->prev->next = pc->next;
5428   pc->next->prev = pc->prev;
5429
5430   pc->prev = pc->next = NULL;
5431
5432   /* Now for the hard part... */
5433
5434   /* Remove the branches */
5435
5436   pb1 = PCI(pc)->from;
5437   while(pb1) {
5438     pc1 = pb1->pc;    /* Get the pCode that branches to the
5439                        * one we're unlinking */
5440
5441     /* search for the link back to this pCode (the one we're
5442      * unlinking) */
5443     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5444       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5445
5446       /* if the pCode we're unlinking contains multiple 'to'
5447        * branches (e.g. this a skip instruction) then we need
5448        * to copy these extra branches to the chain. */
5449       if(PCI(pc)->to->next)
5450         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5451     }
5452     
5453     pb1 = pb1->next;
5454   }
5455
5456
5457 }
5458 #endif
5459 /*-----------------------------------------------------------------*/
5460 /*-----------------------------------------------------------------*/
5461 #if 0
5462 static void genericAnalyze(pCode *pc)
5463 {
5464   switch(pc->type) {
5465   case PC_WILD:
5466   case PC_COMMENT:
5467     return;
5468   case PC_LABEL:
5469   case PC_FUNCTION:
5470   case PC_OPCODE:
5471     {
5472       // Go through the pCodes that are in pCode chain and link
5473       // them together through the pBranches. Note, the pCodes
5474       // are linked together as a contiguous stream like the 
5475       // assembly source code lines. The linking here mimics this
5476       // except that comments are not linked in.
5477       // 
5478       pCode *npc = pc->next;
5479       while(npc) {
5480         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5481           pBranchLink(pc,npc);
5482           return;
5483         } else
5484           npc = npc->next;
5485       }
5486       /* reached the end of the pcode chain without finding
5487        * an instruction we could link to. */
5488     }
5489     break;
5490   case PC_FLOW:
5491     fprintf(stderr,"analyze PC_FLOW\n");
5492
5493     return;
5494   case PC_BAD:
5495     fprintf(stderr,,";A bad pCode is being used\n");
5496
5497   }
5498 }
5499 #endif
5500
5501 /*-----------------------------------------------------------------*/
5502 /*-----------------------------------------------------------------*/
5503 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5504 {
5505   pBranch *pbr;
5506
5507   if(pc->type == PC_LABEL) {
5508     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5509       return TRUE;
5510   }
5511   if((pc->type == PC_OPCODE)
5512         || (pc->type == PC_ASMDIR)
5513         ) {
5514     pbr = PCI(pc)->label;
5515     while(pbr) {
5516       if(pbr->pc->type == PC_LABEL) {
5517         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5518           return TRUE;
5519       }
5520       pbr = pbr->next;
5521     }
5522   }
5523
5524   return FALSE;
5525 }
5526
5527 /*-----------------------------------------------------------------*/
5528 /*-----------------------------------------------------------------*/
5529 static int checkLabel(pCode *pc)
5530 {
5531   pBranch *pbr;
5532
5533   if(pc && isPCI(pc)) {
5534     pbr = PCI(pc)->label;
5535     while(pbr) {
5536       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5537         return TRUE;
5538
5539       pbr = pbr->next;
5540     }
5541   }
5542
5543   return FALSE;
5544 }
5545
5546 /*-----------------------------------------------------------------*/
5547 /* findLabelinpBlock - Search the pCode for a particular label     */
5548 /*-----------------------------------------------------------------*/
5549 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5550 {
5551   pCode  *pc;
5552
5553   if(!pb)
5554     return NULL;
5555
5556   for(pc = pb->pcHead; pc; pc = pc->next) 
5557     if(compareLabel(pc,pcop_label))
5558       return pc;
5559     
5560   return NULL;
5561 }
5562 #if 0
5563 /*-----------------------------------------------------------------*/
5564 /* findLabel - Search the pCode for a particular label             */
5565 /*-----------------------------------------------------------------*/
5566 static pCode * findLabel(pCodeOpLabel *pcop_label)
5567 {
5568   pBlock *pb;
5569   pCode  *pc;
5570
5571   if(!the_pFile)
5572     return NULL;
5573
5574   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5575     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5576       return pc;
5577   }
5578
5579   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5580   return NULL;
5581 }
5582 #endif
5583 /*-----------------------------------------------------------------*/
5584 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5585 /*                 in the linked list                              */
5586 /*-----------------------------------------------------------------*/
5587 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5588 {
5589
5590   while(pc) {
5591     if(pc->type == pct)
5592       return pc;
5593
5594     pc = pc->next;
5595   }
5596
5597   return NULL;
5598 }
5599
5600 /*-----------------------------------------------------------------*/
5601 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5602 /*                 in the linked list                              */
5603 /*-----------------------------------------------------------------*/
5604 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5605 {
5606
5607   while(pc) {
5608     if(pc->type == pct)
5609       return pc;
5610
5611     pc = pc->prev;
5612   }
5613
5614   return NULL;
5615 }
5616
5617
5618 //#define PCODE_DEBUG
5619 /*-----------------------------------------------------------------*/
5620 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5621 /*                       in the linked list                        */
5622 /*-----------------------------------------------------------------*/
5623 pCode * pic16_findNextInstruction(pCode *pci)
5624 {
5625   pCode *pc = pci;
5626
5627   while(pc) {
5628     if((pc->type == PC_OPCODE)
5629         || (pc->type == PC_WILD)
5630         || (pc->type == PC_ASMDIR)
5631         )
5632       return pc;
5633
5634 #ifdef PCODE_DEBUG
5635     fprintf(stderr,"pic16_findNextInstruction:  ");
5636     printpCode(stderr, pc);
5637 #endif
5638     pc = pc->next;
5639   }
5640
5641   //fprintf(stderr,"Couldn't find instruction\n");
5642   return NULL;
5643 }
5644
5645 /*-----------------------------------------------------------------*/
5646 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5647 /*                       in the linked list                        */
5648 /*-----------------------------------------------------------------*/
5649 pCode * pic16_findPrevInstruction(pCode *pci)
5650 {
5651   pCode *pc = pci;
5652
5653   while(pc) {
5654
5655     if((pc->type == PC_OPCODE)
5656         || (pc->type == PC_WILD)
5657         || (pc->type == PC_ASMDIR)
5658         )
5659       return pc;
5660       
5661
5662 #ifdef PCODE_DEBUG
5663     fprintf(stderr,"pic16_findPrevInstruction:  ");
5664     printpCode(stderr, pc);
5665 #endif
5666     pc = pc->prev;
5667   }
5668
5669   //fprintf(stderr,"Couldn't find instruction\n");
5670   return NULL;
5671 }
5672
5673 #undef PCODE_DEBUG
5674
5675 #if 0
5676 /*-----------------------------------------------------------------*/
5677 /* findFunctionEnd - given a pCode find the end of the function    */
5678 /*                   that contains it                              */
5679 /*-----------------------------------------------------------------*/
5680 static pCode * findFunctionEnd(pCode *pc)
5681 {
5682
5683   while(pc) {
5684     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5685       return pc;
5686
5687     pc = pc->next;
5688   }
5689
5690   fprintf(stderr,"Couldn't find function end\n");
5691   return NULL;
5692 }
5693 #endif
5694 #if 0
5695 /*-----------------------------------------------------------------*/
5696 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5697 /*                instruction with which it is associated.         */
5698 /*-----------------------------------------------------------------*/
5699 static void AnalyzeLabel(pCode *pc)
5700 {
5701
5702   pic16_pCodeUnlink(pc);
5703
5704 }
5705 #endif
5706
5707 #if 0
5708 static void AnalyzeGOTO(pCode *pc)
5709 {
5710
5711   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5712
5713 }
5714
5715 static void AnalyzeSKIP(pCode *pc)
5716 {
5717
5718   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5719   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5720
5721 }
5722
5723 static void AnalyzeRETURN(pCode *pc)
5724 {
5725
5726   //  branch_link(pc,findFunctionEnd(pc->next));
5727
5728 }
5729
5730 #endif
5731
5732 /*-------------------------------------------------------------------*/
5733 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5734 /*                            if one is present. This is the common  */
5735 /*                            part of pic16_getRegFromInstruction(2) */
5736 /*-------------------------------------------------------------------*/
5737
5738 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5739   if (!pcop) return NULL;
5740   
5741   switch(pcop->type) {
5742   case PO_PRODL:
5743   case PO_PRODH:
5744   case PO_INDF0:
5745   case PO_FSR0:
5746   case PO_W:
5747   case PO_WREG:
5748   case PO_STATUS:
5749   case PO_INTCON:
5750   case PO_PCL:
5751   case PO_PCLATH:
5752   case PO_PCLATU:
5753   case PO_BSR:
5754     return PCOR(pcop)->r;
5755
5756   case PO_SFR_REGISTER:
5757     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5758     return PCOR(pcop)->r;
5759
5760   case PO_BIT:
5761   case PO_GPR_TEMP:
5762 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5763     return PCOR(pcop)->r;
5764
5765   case PO_IMMEDIATE:
5766 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5767
5768     if(PCOI(pcop)->r)
5769       return (PCOI(pcop)->r);
5770     else
5771       return NULL;
5772     
5773   case PO_GPR_BIT:
5774     return PCOR(pcop)->r;
5775
5776   case PO_GPR_REGISTER:
5777   case PO_DIR:
5778 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5779     return PCOR(pcop)->r;
5780
5781   case PO_LITERAL:
5782     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5783     break;
5784
5785   case PO_REL_ADDR:
5786   case PO_LABEL:
5787     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5788     break;
5789     
5790   case PO_CRY:
5791   case PO_STR:
5792     /* this should never turn up */
5793     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5794     break;
5795     
5796   case PO_WILD:
5797     break;
5798     
5799   default:
5800         fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5801 //      assert( 0 );
5802         break;
5803   }
5804
5805   return NULL;
5806 }
5807
5808 /*-----------------------------------------------------------------*/
5809 /*-----------------------------------------------------------------*/
5810 regs * pic16_getRegFromInstruction(pCode *pc)
5811 {
5812
5813   if(!pc                   || 
5814      !isPCI(pc)            ||
5815      !PCI(pc)->pcop        ||
5816      PCI(pc)->num_ops == 0 ||
5817      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5818     return NULL;
5819
5820 #if 0
5821   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5822         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5823 #endif
5824
5825   return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5826 }
5827
5828 /*-------------------------------------------------------------------------------*/
5829 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5830 /*-------------------------------------------------------------------------------*/
5831 regs * pic16_getRegFromInstruction2(pCode *pc)
5832 {
5833
5834   if(!pc                   || 
5835      !isPCI(pc)            ||
5836      !PCI(pc)->pcop        ||
5837      PCI(pc)->num_ops == 0 ||
5838      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5839     return NULL;
5840
5841
5842 #if 0
5843   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5844         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5845 #endif
5846
5847   return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5848 }
5849
5850 /*-----------------------------------------------------------------*/
5851 /*-----------------------------------------------------------------*/
5852
5853 static void AnalyzepBlock(pBlock *pb)
5854 {
5855   pCode *pc;
5856
5857   if(!pb)
5858     return;
5859
5860   /* Find all of the registers used in this pBlock 
5861    * by looking at each instruction and examining it's
5862    * operands
5863    */
5864   for(pc = pb->pcHead; pc; pc = pc->next) {
5865
5866     /* Is this an instruction with operands? */
5867     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5868
5869       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5870
5871         /* Loop through all of the registers declared so far in
5872            this block and see if we find this one there */
5873
5874         regs *r = setFirstItem(pb->tregisters);
5875
5876         while(r) {
5877           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5878             PCOR(PCI(pc)->pcop)->r = r;
5879             break;
5880           }
5881           r = setNextItem(pb->tregisters);
5882         }
5883
5884         if(!r) {
5885           /* register wasn't found */
5886           //r = Safe_calloc(1, sizeof(regs));
5887           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5888           //addSet(&pb->tregisters, r);
5889           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5890           //PCOR(PCI(pc)->pcop)->r = r;
5891           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5892         }/* else 
5893           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5894          */
5895       }
5896       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5897         if(PCOR(PCI(pc)->pcop)->r) {
5898           pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
5899           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5900         } else {
5901           if(PCI(pc)->pcop->name)
5902             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5903           else
5904             fprintf(stderr,"ERROR: NULL register\n");
5905         }
5906       }
5907     }
5908
5909
5910   }
5911 }
5912
5913 /*-----------------------------------------------------------------*/
5914 /* */
5915 /*-----------------------------------------------------------------*/
5916 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5917
5918 static void InsertpFlow(pCode *pc, pCode **pflow)
5919 {
5920   if(*pflow)
5921     PCFL(*pflow)->end = pc;
5922
5923   if(!pc || !pc->next)
5924     return;
5925
5926   *pflow = pic16_newpCodeFlow();
5927   pic16_pCodeInsertAfter(pc, *pflow);
5928 }
5929
5930 /*-----------------------------------------------------------------*/
5931 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5932 /*                         the flow blocks.                        */
5933 /*
5934  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5935  * point the instruction flow changes. 
5936  */
5937 /*-----------------------------------------------------------------*/
5938 void pic16_BuildFlow(pBlock *pb)
5939 {
5940   pCode *pc;
5941   pCode *last_pci=NULL;
5942   pCode *pflow=NULL;
5943   int seq = 0;
5944
5945   if(!pb)
5946     return;
5947
5948   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5949   /* Insert a pCodeFlow object at the beginning of a pBlock */
5950
5951   InsertpFlow(pb->pcHead, &pflow);
5952
5953   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5954   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5955   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5956   //pb->pcHead = pflow;        /* Make the Flow object the head */
5957   //pflow->pb = pb;
5958
5959   for( pc = pic16_findNextInstruction(pb->pcHead);
5960        pc != NULL;
5961        pc=pic16_findNextInstruction(pc)) { 
5962
5963     pc->seq = seq++;
5964     PCI(pc)->pcflow = PCFL(pflow);
5965
5966     //fprintf(stderr," build: ");
5967     //pflow->print(stderr,pflow);
5968
5969     if (checkLabel(pc)) { 
5970
5971       /* This instruction marks the beginning of a
5972        * new flow segment */
5973
5974       pc->seq = 0;
5975       seq = 1;
5976
5977       /* If the previous pCode is not a flow object, then 
5978        * insert a new flow object. (This check prevents 
5979        * two consecutive flow objects from being insert in
5980        * the case where a skip instruction preceeds an
5981        * instruction containing a label.) */
5982
5983       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5984         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5985
5986       PCI(pc)->pcflow = PCFL(pflow);
5987       
5988     }
5989
5990     if( PCI(pc)->isSkip) {
5991
5992       /* The two instructions immediately following this one 
5993        * mark the beginning of a new flow segment */
5994
5995       while(pc && PCI(pc)->isSkip) {
5996
5997         PCI(pc)->pcflow = PCFL(pflow);
5998         pc->seq = seq-1;
5999         seq = 1;
6000
6001         InsertpFlow(pc, &pflow);
6002         pc=pic16_findNextInstruction(pc->next);
6003       }
6004
6005       seq = 0;
6006
6007       if(!pc)
6008         break;
6009
6010       PCI(pc)->pcflow = PCFL(pflow);
6011       pc->seq = 0;
6012       InsertpFlow(pc, &pflow);
6013
6014     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6015
6016       InsertpFlow(pc, &pflow);
6017       seq = 0;
6018
6019     }
6020     last_pci = pc;
6021     pc = pc->next;
6022   }
6023
6024   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6025   if(pflow)
6026     PCFL(pflow)->end = pb->pcTail;
6027 }
6028
6029 /*-------------------------------------------------------------------*/
6030 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6031 /*                           the flow blocks.                        */
6032 /*
6033  * unBuildFlow removes pCodeFlow objects from a pCode chain
6034  */
6035 /*-----------------------------------------------------------------*/
6036 static void unBuildFlow(pBlock *pb)
6037 {
6038   pCode *pc,*pcnext;
6039
6040   if(!pb)
6041     return;
6042
6043   pc = pb->pcHead;
6044
6045   while(pc) {
6046     pcnext = pc->next;
6047
6048     if(isPCI(pc)) {
6049
6050       pc->seq = 0;
6051       if(PCI(pc)->pcflow) {
6052         //Safe_free(PCI(pc)->pcflow);
6053         PCI(pc)->pcflow = NULL;
6054       }
6055
6056     } else if(isPCFL(pc) )
6057       pc->destruct(pc);
6058
6059     pc = pcnext;
6060   }
6061
6062
6063 }
6064 #if 0
6065 /*-----------------------------------------------------------------*/
6066 /*-----------------------------------------------------------------*/
6067 static void dumpCond(int cond)
6068 {
6069
6070   static char *pcc_str[] = {
6071     //"PCC_NONE",
6072     "PCC_REGISTER",
6073     "PCC_C",
6074     "PCC_Z",
6075     "PCC_DC",
6076     "PCC_OV",
6077     "PCC_N",
6078     "PCC_W",
6079     "PCC_EXAMINE_PCOP",
6080     "PCC_LITERAL",
6081     "PCC_REL_ADDR"
6082   };
6083
6084   int ncond = sizeof(pcc_str) / sizeof(char *);
6085   int i,j;
6086
6087   fprintf(stderr, "0x%04X\n",cond);
6088
6089   for(i=0,j=1; i<ncond; i++, j<<=1)
6090     if(cond & j)
6091       fprintf(stderr, "  %s\n",pcc_str[i]);
6092
6093 }
6094 #endif
6095
6096 #if 0
6097 /*-----------------------------------------------------------------*/
6098 /*-----------------------------------------------------------------*/
6099 static void FlowStats(pCodeFlow *pcflow)
6100 {
6101
6102   pCode *pc;
6103
6104   if(!isPCFL(pcflow))
6105     return;
6106
6107   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6108
6109   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6110
6111   if(!pc) {
6112     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6113     return;
6114   }
6115
6116
6117   fprintf(stderr, "  FlowStats inCond: ");
6118   dumpCond(pcflow->inCond);
6119   fprintf(stderr, "  FlowStats outCond: ");
6120   dumpCond(pcflow->outCond);
6121
6122 }
6123 #endif
6124 /*-----------------------------------------------------------------*
6125  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6126  *    if it affects the banking bits. 
6127  * 
6128  * return: -1 == Banking bits are unaffected by this pCode.
6129  *
6130  * return: > 0 == Banking bits are affected.
6131  *
6132  *  If the banking bits are affected, then the returned value describes
6133  * which bits are affected and how they're affected. The lower half
6134  * of the integer maps to the bits that are affected, the upper half
6135  * to whether they're set or cleared.
6136  *
6137  *-----------------------------------------------------------------*/
6138
6139 static int isBankInstruction(pCode *pc)
6140 {
6141   regs *reg;
6142   int bank = -1;
6143
6144   if(!isPCI(pc))
6145     return 0;
6146
6147   if( PCI(pc)->op == POC_MOVLB ||
6148       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6149     bank = PCOL(pc)->lit;
6150   }
6151
6152   return 1;
6153 }
6154
6155
6156 /*-----------------------------------------------------------------*/
6157 /*-----------------------------------------------------------------*/
6158 static void FillFlow(pCodeFlow *pcflow)
6159 {
6160
6161   pCode *pc;
6162   int cur_bank;
6163
6164   if(!isPCFL(pcflow))
6165     return;
6166
6167   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6168
6169   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6170
6171   if(!pc) {
6172     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6173     return;
6174   }
6175
6176   cur_bank = -1;
6177
6178   do {
6179     isBankInstruction(pc);
6180     pc = pc->next;
6181   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6182
6183 /*
6184   if(!pc ) {
6185     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6186   } else {
6187     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6188     pc->print(stderr,pc);
6189   }
6190
6191   fprintf(stderr, "  FillFlow inCond: ");
6192   dumpCond(pcflow->inCond);
6193   fprintf(stderr, "  FillFlow outCond: ");
6194   dumpCond(pcflow->outCond);
6195 */
6196 }
6197
6198 /*-----------------------------------------------------------------*/
6199 /*-----------------------------------------------------------------*/
6200 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6201 {
6202   pCodeFlowLink *fromLink, *toLink;
6203
6204   if(!from || !to || !to->pcflow || !from->pcflow)
6205     return;
6206
6207   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6208   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6209
6210   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6211   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6212
6213 }
6214
6215 pCode *pic16_getJumptabpCode (pCode *pc) {
6216   pCode *pcinf;
6217
6218   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6219   //pc->print (stderr, pc);
6220   pcinf = pc;
6221   while (pcinf) {
6222     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6223     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6224       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6225       case OPT_JUMPTABLE_BEGIN:
6226         /* leading begin of jump table -- in one */
6227         pcinf = pic16_findPrevInstruction (pcinf);
6228         return pcinf;
6229         break;
6230         
6231       case OPT_JUMPTABLE_END:
6232         /* leading end of jumptable -- not in one */
6233         return NULL;
6234         break;
6235         
6236       default:
6237         /* ignore all other PCInfos */
6238         break;
6239       }
6240     }
6241     pcinf = pcinf->prev;
6242   }
6243
6244   /* no PCInfo found -- not in a jumptable */
6245   return NULL;
6246 }
6247
6248 /*-----------------------------------------------------------------*
6249  * void LinkFlow(pBlock *pb)
6250  *
6251  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6252  * non-branching segments. In LinkFlow, we determine the execution
6253  * order of these segments. For example, if one of the segments ends
6254  * with a skip, then we know that there are two possible flow segments
6255  * to which control may be passed.
6256  *-----------------------------------------------------------------*/
6257 static void LinkFlow(pBlock *pb)
6258 {
6259   pCode *pc=NULL;
6260   pCode *pcflow;
6261   pCode *pct;
6262   pCode *jumptab_pre = NULL;
6263
6264   //fprintf(stderr,"linkflow \n");
6265
6266   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6267        pcflow != NULL;
6268        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6269
6270     if(!isPCFL(pcflow))
6271       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6272
6273     //fprintf(stderr," link: ");
6274     //pcflow->print(stderr,pcflow);
6275
6276     //FillFlow(PCFL(pcflow));
6277
6278     pc = PCFL(pcflow)->end;
6279
6280     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6281     if(isPCI_SKIP(pc)) {
6282 //      fprintf(stderr, "ends with skip\n");
6283 //      pc->print(stderr,pc);
6284
6285       pct=pic16_findNextInstruction(pc->next);
6286       LinkFlow_pCode(PCI(pc),PCI(pct));
6287       pct=pic16_findNextInstruction(pct->next);
6288       LinkFlow_pCode(PCI(pc),PCI(pct));
6289       continue;
6290     }
6291
6292     if(isPCI_BRANCH(pc)) {
6293       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6294
6295       /* handle GOTOs in jumptables */
6296       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6297         /* link to previous flow */
6298         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6299         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6300       }
6301
6302       switch (PCI(pc)->op) {
6303       case POC_GOTO:
6304       case POC_BRA:
6305       case POC_RETURN:
6306       case POC_RETLW:
6307       case POC_RETFIE:
6308               /* unconditional branches -- do not link to next instruction */
6309               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6310               break;
6311               
6312       case POC_CALL:
6313       case POC_RCALL:
6314               /* unconditional calls -- link to next instruction */
6315               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6316               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6317               break;
6318               
6319       case POC_BC:
6320       case POC_BN:
6321       case POC_BNC:
6322       case POC_BNN:
6323       case POC_BNOV:
6324       case POC_BNZ:
6325       case POC_BOV:
6326       case POC_BZ:
6327               /* conditional branches -- also link to next instruction */
6328               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6329               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6330               break;
6331               
6332       default:
6333               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6334               assert (0 && "unhandled branching instruction");
6335               break;
6336       }
6337
6338       //fprintf(stderr, "ends with branch\n  ");
6339       //pc->print(stderr,pc);
6340
6341       if(!(pcol && isPCOLAB(pcol))) {
6342         if((PCI(pc)->op != POC_RETLW)
6343                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6344         
6345                 /* continue if label is '$' which assembler knows how to parse */
6346                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6347
6348                 if(pic16_pcode_verbose) {
6349                         pc->print(stderr,pc);
6350                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6351                 }
6352         }
6353         continue;
6354       }
6355
6356       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6357         LinkFlow_pCode(PCI(pc),PCI(pct));
6358       else
6359         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6360                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6361
6362 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6363
6364       continue;
6365     }
6366
6367     if(isPCI(pc)) {
6368       //fprintf(stderr, "ends with non-branching instruction:\n");
6369       //pc->print(stderr,pc);
6370
6371       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6372
6373       continue;
6374     }
6375
6376     if(pc) {
6377       //fprintf(stderr, "ends with unknown\n");
6378       //pc->print(stderr,pc);
6379       continue;
6380     }
6381
6382     //fprintf(stderr, "ends with nothing: ERROR\n");
6383     
6384   }
6385 }
6386 /*-----------------------------------------------------------------*/
6387 /*-----------------------------------------------------------------*/
6388
6389 /*-----------------------------------------------------------------*/
6390 /*-----------------------------------------------------------------*/
6391 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6392 {
6393
6394   if(!pc || !pcflow)
6395     return 0;
6396
6397   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6398     return 0;
6399
6400   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6401     return 1;
6402
6403   return 0;
6404 }
6405
6406
6407
6408
6409
6410 /*-----------------------------------------------------------------*/
6411 /* insertBankSwitch - inserts a bank switch statement in the       */
6412 /*                    assembly listing                             */
6413 /*                                                                 */
6414 /* position == 0: insert before                                    */
6415 /* position == 1: insert after pc                                  */
6416 /* position == 2: like 0 but previous was a skip instruction       */
6417 /*-----------------------------------------------------------------*/
6418 pCodeOp *pic16_popGetLabel(unsigned int key);
6419 extern int pic16_labelOffset;
6420
6421 static void insertBankSwitch(unsigned char position, pCode *pc)
6422 {
6423   pCode *new_pc;
6424
6425         if(!pc)
6426                 return;
6427
6428         /* emit BANKSEL [symbol] */
6429
6430
6431         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6432         
6433 //      position = 0;           // position is always before (sanity check!)
6434
6435 #if 0
6436         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6437         pc->print(stderr, pc);
6438 #endif
6439
6440         switch(position) {
6441                 case 1: {
6442                         /* insert the bank switch after this pc instruction */
6443                         pCode *pcnext = pic16_findNextInstruction(pc);
6444
6445                                 pic16_pCodeInsertAfter(pc, new_pc);
6446                                 if(pcnext)pc = pcnext;
6447                 }; break;
6448                 
6449                 case 0:
6450                         /* insert the bank switch BEFORE this pc instruction */
6451                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6452                         break;
6453
6454                 case 2: {
6455                           symbol *tlbl;
6456                           pCode *pcnext, *pcprev, *npci, *ppc;
6457                           PIC_OPCODE ipci;
6458                           int ofs1=0, ofs2=0, len=0;
6459                           
6460                         /* just like 0, but previous was a skip instruction,
6461                          * so some care should be taken */
6462                           
6463                                 pic16_labelOffset += 10000;
6464                                 tlbl = newiTempLabel(NULL);
6465                                 
6466                                 /* invert skip instruction */
6467                                 pcprev = pic16_findPrevInstruction(pc->prev);
6468                                 ipci = PCI(pcprev)->inverted_op;
6469                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6470
6471 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6472
6473                                 /* copy info from old pCode */
6474                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6475                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6476                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6477                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6478                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6479                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6480                                 
6481                                 /* unlink old pCode */
6482                                 ppc = pcprev->prev;
6483                                 ppc->next = pcprev->next;
6484                                 pcprev->next->prev = ppc;
6485                                 pic16_pCodeInsertAfter(ppc, npci);
6486                                 
6487                                 /* extra instructions to handle invertion */
6488                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6489                                 pic16_pCodeInsertAfter(npci, pcnext);
6490                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6491                                 
6492                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6493                                 pic16_pCodeInsertAfter(pc, pcnext);
6494                         }; break;
6495         }
6496         
6497
6498         /* Move the label, if there is one */
6499         if(PCI(pc)->label) {
6500 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6501 //                      __FILE__, __LINE__, pc, new_pc);
6502                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6503                 PCI(pc)->label = NULL;
6504         }
6505 }
6506
6507
6508 /*-----------------------------------------------------------------*/
6509 /*int compareBankFlow - compare the banking requirements between   */
6510 /*  flow objects. */
6511 /*-----------------------------------------------------------------*/
6512 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6513 {
6514
6515   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6516     return 0;
6517
6518   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6519     return 0;
6520
6521   if(pcflow->firstBank == -1)
6522     return 0;
6523
6524
6525   if(pcflowLink->pcflow->firstBank == -1) {
6526     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6527                                         pcflowLink->pcflow->to : 
6528                                         pcflowLink->pcflow->from);
6529     return compareBankFlow(pcflow, pctl, toORfrom);
6530   }
6531
6532   if(toORfrom) {
6533     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6534       return 0;
6535
6536     pcflowLink->bank_conflict++;
6537     pcflowLink->pcflow->FromConflicts++;
6538     pcflow->ToConflicts++;
6539   } else {
6540     
6541     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6542       return 0;
6543
6544     pcflowLink->bank_conflict++;
6545     pcflowLink->pcflow->ToConflicts++;
6546     pcflow->FromConflicts++;
6547
6548   }
6549   /*
6550   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6551           pcflowLink->pcflow->pc.seq,
6552           pcflowLink->pcflow->FromConflicts,
6553           pcflowLink->pcflow->ToConflicts);
6554   */
6555   return 1;
6556
6557 }
6558
6559 #if 0
6560 /*-----------------------------------------------------------------*/
6561 /*-----------------------------------------------------------------*/
6562 static void DumpFlow(pBlock *pb)
6563 {
6564   pCode *pc=NULL;
6565   pCode *pcflow;
6566   pCodeFlowLink *pcfl;
6567
6568
6569   fprintf(stderr,"Dump flow \n");
6570   pb->pcHead->print(stderr, pb->pcHead);
6571
6572   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6573   pcflow->print(stderr,pcflow);
6574
6575   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6576        pcflow != NULL;
6577        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6578
6579     if(!isPCFL(pcflow)) {
6580       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6581       continue;
6582     }
6583     fprintf(stderr,"dumping: ");
6584     pcflow->print(stderr,pcflow);
6585     FlowStats(PCFL(pcflow));
6586
6587     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6588
6589       pc = PCODE(pcfl->pcflow);
6590
6591       fprintf(stderr, "    from seq %d:\n",pc->seq);
6592       if(!isPCFL(pc)) {
6593         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6594         pc->print(stderr,pc);
6595       }
6596
6597     }
6598
6599     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6600
6601       pc = PCODE(pcfl->pcflow);
6602
6603       fprintf(stderr, "    to seq %d:\n",pc->seq);
6604       if(!isPCFL(pc)) {
6605         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6606         pc->print(stderr,pc);
6607       }
6608
6609     }
6610
6611   }
6612
6613 }
6614 #endif
6615 /*-----------------------------------------------------------------*/
6616 /*-----------------------------------------------------------------*/
6617 static int OptimizepBlock(pBlock *pb)
6618 {
6619   pCode *pc, *pcprev;
6620   int matches =0;
6621
6622   if(!pb || !peepOptimizing)
6623     return 0;
6624
6625   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6626 /*
6627   for(pc = pb->pcHead; pc; pc = pc->next)
6628     matches += pic16_pCodePeepMatchRule(pc);
6629 */
6630
6631   pc = pic16_findNextInstruction(pb->pcHead);
6632   if(!pc)
6633     return 0;
6634
6635   pcprev = pc->prev;
6636   do {
6637
6638
6639     if(pic16_pCodePeepMatchRule(pc)) {
6640
6641       matches++;
6642
6643       if(pcprev)
6644         pc = pic16_findNextInstruction(pcprev->next);
6645       else 
6646         pc = pic16_findNextInstruction(pb->pcHead);
6647     } else
6648       pc = pic16_findNextInstruction(pc->next);
6649   } while(pc);
6650
6651   if(matches)
6652     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6653   return matches;
6654
6655 }
6656
6657 /*-----------------------------------------------------------------*/
6658 /*-----------------------------------------------------------------*/
6659 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6660 {
6661   pCode *pc;
6662
6663   for(pc = pcs; pc; pc = pc->next) {
6664
6665     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6666        (PCI(pc)->pcop) && 
6667        (PCI(pc)->pcop->type == PO_LABEL) &&
6668        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6669       return pc;
6670   }
6671  
6672
6673   return NULL;
6674 }
6675
6676 /*-----------------------------------------------------------------*/
6677 /*-----------------------------------------------------------------*/
6678 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6679 {
6680
6681   char *s=NULL;
6682
6683   if(isPCI(pc) && 
6684      (PCI(pc)->pcop) && 
6685      (PCI(pc)->pcop->type == PO_LABEL)) {
6686
6687     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6688
6689 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6690 //    if(pcol->pcop.name)
6691 //      Safe_free(pcol->pcop.name);
6692
6693     /* If the key is negative, then we (probably) have a label to
6694      * a function and the name is already defined */
6695        
6696     if(pcl->key>0)
6697       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6698     else 
6699       s = pcl->label;
6700
6701     //sprintf(buffer,"_%05d_DS_",pcl->key);
6702     if(!s) {
6703       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6704     }
6705     pcol->pcop.name = Safe_strdup(s);
6706     pcol->key = pcl->key;
6707     //pc->print(stderr,pc);
6708
6709   }
6710
6711
6712 }
6713
6714 /*-----------------------------------------------------------------*/
6715 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6716 /*                            pCode chain if they're not used.     */
6717 /*-----------------------------------------------------------------*/
6718 static void pBlockRemoveUnusedLabels(pBlock *pb)
6719 {
6720   pCode *pc; pCodeLabel *pcl;
6721
6722   if(!pb)
6723     return;
6724
6725   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6726
6727     pBranch *pbr = PCI(pc)->label;
6728     if(pbr && pbr->next) {
6729       pCode *pcd = pb->pcHead;
6730
6731 //      fprintf(stderr, "multiple labels\n");
6732 //      pc->print(stderr,pc);
6733
6734       pbr = pbr->next;
6735       while(pbr) {
6736
6737         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6738           //fprintf(stderr,"Used by:\n");
6739           //pcd->print(stderr,pcd);
6740
6741           exchangeLabels(PCL(pbr->pc),pcd);
6742
6743           pcd = pcd->next;
6744         }
6745         pbr = pbr->next;
6746       }
6747     }
6748   }
6749
6750   for(pc = pb->pcHead; pc; pc = pc->next) {
6751
6752     if(isPCL(pc)) // pc->type == PC_LABEL)
6753       pcl = PCL(pc);
6754     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6755       pcl = PCL(PCI(pc)->label->pc);
6756     else continue;
6757
6758 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6759
6760     /* This pCode is a label, so search the pBlock to see if anyone
6761      * refers to it */
6762
6763     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6764         && (!pcl->force)) {
6765     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6766       /* Couldn't find an instruction that refers to this label
6767        * So, unlink the pCode label from it's pCode chain
6768        * and destroy the label */
6769 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6770
6771       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6772       if(pc->type == PC_LABEL) {
6773         pic16_unlinkpCode(pc);
6774         pCodeLabelDestruct(pc);
6775       } else {
6776         unlinkpCodeFromBranch(pc, PCODE(pcl));
6777         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6778           Safe_free(pc->label);
6779         }*/
6780       }
6781
6782     }
6783   }
6784
6785 }
6786
6787
6788 /*-----------------------------------------------------------------*/
6789 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6790 /*                     chain and put them into pBranches that are  */
6791 /*                     associated with the appropriate pCode       */
6792 /*                     instructions.                               */
6793 /*-----------------------------------------------------------------*/
6794 void pic16_pBlockMergeLabels(pBlock *pb)
6795 {
6796   pBranch *pbr;
6797   pCode *pc, *pcnext=NULL;
6798
6799   if(!pb)
6800     return;
6801
6802   /* First, Try to remove any unused labels */
6803   //pBlockRemoveUnusedLabels(pb);
6804
6805   /* Now loop through the pBlock and merge the labels with the opcodes */
6806
6807   pc = pb->pcHead;
6808   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6809
6810   while(pc) {
6811     pCode *pcn = pc->next;
6812
6813     if(pc->type == PC_LABEL) {
6814
6815 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6816 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6817
6818       if((pcnext = pic16_findNextInstruction(pc) )) {
6819
6820 //              pcnext->print(stderr, pcnext);
6821
6822         // Unlink the pCode label from it's pCode chain
6823         pic16_unlinkpCode(pc);
6824         
6825 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6826         // And link it into the instruction's pBranch labels. (Note, since
6827         // it's possible to have multiple labels associated with one instruction
6828         // we must provide a means to accomodate the additional labels. Thus
6829         // the labels are placed into the singly-linked list "label" as 
6830         // opposed to being a single member of the pCodeInstruction.)
6831
6832         //_ALLOC(pbr,sizeof(pBranch));
6833 #if 1
6834         pbr = Safe_calloc(1,sizeof(pBranch));
6835         pbr->pc = pc;
6836         pbr->next = NULL;
6837
6838         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6839 #endif
6840       } else {
6841         if(pic16_pcode_verbose)
6842         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6843       }
6844     } else if(pc->type == PC_CSOURCE) {
6845
6846       /* merge the source line symbolic info into the next instruction */
6847       if((pcnext = pic16_findNextInstruction(pc) )) {
6848
6849         // Unlink the pCode label from it's pCode chain
6850         pic16_unlinkpCode(pc);
6851         PCI(pcnext)->cline = PCCS(pc);
6852         //fprintf(stderr, "merging CSRC\n");
6853         //genericPrint(stderr,pcnext);
6854       }
6855
6856     }
6857     pc = pcn;
6858   }
6859   pBlockRemoveUnusedLabels(pb);
6860
6861 }
6862
6863 /*-----------------------------------------------------------------*/
6864 /*-----------------------------------------------------------------*/
6865 static int OptimizepCode(char dbName)
6866 {
6867 #define MAX_PASSES 4
6868
6869   int matches = 0;
6870   int passes = 0;
6871   pBlock *pb;
6872
6873   if(!the_pFile)
6874     return 0;
6875
6876   DFPRINTF((stderr," Optimizing pCode\n"));
6877
6878   do {
6879     matches = 0;
6880     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6881       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6882         matches += OptimizepBlock(pb);
6883     }
6884   }
6885   while(matches && ++passes < MAX_PASSES);
6886
6887   return matches;
6888 }
6889
6890
6891
6892 const char *pic16_pCodeOpType(pCodeOp *pcop);
6893 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6894
6895
6896 /*-----------------------------------------------------------------*/
6897 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6898 /*-----------------------------------------------------------------*/
6899
6900 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6901 {
6902   pCodeOp *pcop=NULL;
6903
6904 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6905
6906   if(pc->name) {
6907         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6908   } else {
6909     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6910   }
6911
6912   assert(pcop != NULL);
6913
6914   if( !( (pcop->type == PO_LABEL) ||
6915          (pcop->type == PO_LITERAL) ||
6916          (pcop->type == PO_STR) ))
6917     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6918     PCOR(pcop)->r->wasUsed = 1;
6919     PCOR(pcop)->instance = PCOR(pc)->instance;
6920
6921   return pcop;
6922 }
6923
6924
6925 /*----------------------------------------------------------------------*
6926  * pic16_areRegsSame - check to see if the names of two registers match *
6927  *----------------------------------------------------------------------*/
6928 int pic16_areRegsSame(regs *r1, regs *r2)
6929 {
6930         if(!strcmp(r1->name, r2->name))return 1;
6931
6932   return 0;
6933 }
6934
6935
6936 /*-----------------------------------------------------------------*/
6937 /*-----------------------------------------------------------------*/
6938 static void pic16_FixRegisterBanking(pBlock *pb)
6939 {
6940   pCode *pc=NULL;
6941   pCode *pcprev=NULL;
6942   regs *reg, *prevreg;
6943   unsigned char flag=0;
6944   
6945         if(!pb)
6946                 return;
6947
6948         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6949         if(!pc)return;
6950
6951         /* loop through all of the flow blocks with in one pblock */
6952
6953 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6954
6955         prevreg = NULL;
6956         do {
6957                 /* at this point, pc should point to a PC_FLOW object */
6958                 /* for each flow block, determine the register banking 
6959                  * requirements */
6960
6961                 
6962                 /* if label, then might come from other point, force banksel */
6963                 if(isPCL(pc))prevreg = NULL;
6964                 
6965                 if(!isPCI(pc))goto loop;
6966
6967                 if(PCI(pc)->label)prevreg = NULL;
6968
6969                 if(PCI(pc)->is2MemOp)goto loop;
6970
6971                 /* if goto, then force banksel */
6972 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6973        
6974                 reg = pic16_getRegFromInstruction(pc);
6975
6976 #if 0
6977                 pc->print(stderr, pc);
6978                 fprintf(stderr, "reg = %p\n", reg);
6979
6980                 if(reg) {
6981                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6982                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6983                                 reg->address,reg->isBitField, reg->isFixed);
6984                 }
6985 #endif
6986
6987                 /* now make some tests to make sure that instruction needs bank switch */
6988
6989                 /* if no register exists, and if not a bit opcode goto loop */
6990                 if(!reg) {
6991                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6992                 }
6993                  
6994                 if(isPCI_SKIP(pc)) {
6995 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6996 //                prevreg = NULL;
6997                 }
6998                 if(reg && isACCESS_BANK(reg))goto loop;
6999
7000                 if(!isBankInstruction(pc))goto loop;
7001
7002                 if(isPCI_LIT(pc))goto loop;
7003          
7004                 if(PCI(pc)->op == POC_CALL)goto loop;
7005
7006                 /* Examine the instruction before this one to make sure it is
7007                  * not a skip type instruction */
7008                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7009
7010                 flag = 0;               /* add before this instruction */
7011                 
7012                 /* if previous instruction is a skip one, then set flag
7013                  * to 2 and call insertBankSwitch */
7014                 if(pcprev && isPCI_SKIP(pcprev)) {
7015                   flag=2;       //goto loop
7016 //                prevreg = NULL;
7017                 }
7018                  
7019                 if(pic16_options.opt_banksel>0) {
7020                   char op1[128], op2[128];
7021                   
7022                     if(prevreg) {
7023                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7024                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7025                       if(!strcmp(op1, op2))goto loop;
7026                     }
7027                 }
7028                 prevreg = reg;
7029                 insertBankSwitch(flag, pc);
7030
7031 //              fprintf(stderr, "BANK SWITCH inserted\n");
7032                 
7033 loop:
7034                 pcprev = pc;
7035                 pc = pc->next;
7036         } while (pc);
7037 }
7038
7039 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7040
7041 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7042 int instrSize (pCode *pc)
7043 {
7044   if (!pc) return 0;
7045
7046   if (isPCAD(pc)) {
7047     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7048     return 4; // assumes only regular instructions using <= 4 bytes
7049   }
7050
7051   if (isPCI(pc)) return PCI(pc)->isize;
7052
7053   return 0;
7054 }
7055
7056 /* Returns 1 if pc is referenced by the given label (either
7057  * pc is the label itself or is an instruction with an attached
7058  * label).
7059  * Returns 0 if pc is not preceeded by the specified label.
7060  */
7061 int isLabel (pCode *pc, char *label)
7062 {
7063   if (!pc) return 0;
7064
7065   // label attached to the pCode?  
7066   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7067     pBranch *lab = NULL;
7068     lab = PCI(pc)->label;
7069
7070     while (lab) {
7071       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7072         return 1;
7073       }
7074       lab = lab->next;
7075     } // while
7076   } // if
7077
7078   // is inline assembly label?
7079   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7080     // do not compare trailing ':'
7081     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7082       return 1;
7083     }
7084   } // if
7085   
7086   // is pCodeLabel?
7087   if (isPCL(pc)) {
7088       if (strcmp(PCL(pc)->label,label) == 0) {
7089       return 1;
7090     }
7091   } // if
7092   
7093   // no label/no label attached/wrong label(s)
7094   return 0;
7095 }
7096
7097 /* Returns the distance to the given label in terms of words.
7098  * Labels are searched only within -max .. max words from pc.
7099  * Returns max if the label could not be found or
7100  * its distance from pc in (-max..+max).
7101  */
7102 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7103   int dist = instrSize(pc);
7104   pCode *curr = pc;
7105
7106   // search backwards
7107   while (dist < max && curr && !isLabel (curr, label)) {
7108     curr = curr->prev;
7109     dist += instrSize(curr); // sizeof (instruction)
7110   } // while
7111   if (curr && dist < max) {
7112     if (target != NULL) *target = curr;
7113     return -dist;
7114   }
7115
7116   dist = 0;
7117   curr = pic16_findNextInstruction (pc->next);
7118   //search forwards
7119   while (dist < max && curr && !isLabel (curr, label)) {
7120     dist += instrSize(curr); // sizeof (instruction)
7121     curr = curr->next;
7122   } // while
7123   if (curr && dist < max) {
7124     if (target != NULL) *target = curr;
7125     return dist;
7126   }
7127
7128   if (target != NULL) *target = NULL;
7129   return max;
7130 }
7131
7132 /* Returns -1 if pc does NOT denote an instruction like
7133  * BTFS[SC] STATUS,i
7134  * Otherwise we return 
7135  *   (a) 0x10 + i for BTFSS
7136  *   (b) 0x00 + i for BTFSC
7137  */
7138 int isSkipOnStatus (pCode *pc)
7139 {
7140   int res = -1;
7141   pCodeOp *pcop;
7142   if (!pc || !isPCI(pc)) return -1;
7143   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7144   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7145   else return -1;
7146
7147   pcop = PCI(pc)->pcop;
7148
7149   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7150     return res + ((pCodeOpRegBit *)pcop)->bit;
7151   }
7152
7153   return -1;
7154 }
7155
7156 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7157  * returns 0 otherwise. */
7158 int isConditionalBranch (pCode *pc)
7159 {
7160   if (!pc || !isPCI_BRANCH(pc)) return 0;
7161
7162   switch (PCI(pc)->op) {
7163   case POC_BC:
7164   case POC_BZ:
7165   case POC_BOV:
7166   case POC_BN:
7167   case POC_BNC:
7168   case POC_BNZ:
7169   case POC_BNOV:
7170   case POC_BNN:
7171     return 1;
7172
7173   default:
7174     break;
7175   } // switch
7176
7177   return 0;
7178 }
7179
7180 /* Returns 1 if pc has a label attached to it.
7181  * This can be either a label stored in the pCode itself (.label)
7182  * or a label making up its own pCode preceding this pc.
7183  * Returns 0 if pc cannot be reached directly via a label.
7184  */
7185 int hasNoLabel (pCode *pc)
7186 {
7187   pCode *prev;
7188   if (!pc) return 1;
7189
7190   // are there any label pCodes between pc and the previous instruction?
7191   prev = pic16_findPrevInstruction (pc->prev);
7192   while (pc && pc != prev) {
7193     // pCode with attached label?
7194     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7195         && PCI(pc)->label) {
7196       return 0;
7197     }
7198     // is inline assembly label?
7199     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7200     if (isPCW(pc) && PCW(pc)->label) return 0;
7201
7202     // pCodeLabel?
7203     if (isPCL(pc)) return 0;
7204
7205     pc = pc->prev;
7206   } // if
7207
7208   // no label found
7209   return 1;
7210 }
7211
7212 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7213   char buf[512];
7214   va_list va;
7215
7216   va_start (va, fmt);
7217   vsprintf (buf, fmt, va);
7218   va_end (va);
7219
7220   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7221 }
7222
7223 /* Replaces the old pCode with the new one, moving the labels,
7224  * C source line and probably flow information to the new pCode.
7225  */
7226 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7227   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7228     return;
7229
7230   /* first move all labels from old to new */
7231   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7232   PCI(oldPC)->label = NULL;
7233   
7234 #if 0
7235   /* move C source line (if possible) */
7236   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7237     PCI(newPC)->cline = PCI(oldPC)->cline;
7238 #endif
7239
7240   /* keep flow information intact */
7241   newPC->seq = oldPC->seq;
7242   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7243
7244   /* insert a comment stating which pCode has been replaced */
7245 #if 1
7246   if (pic16_pcode_verbose || pic16_debug_verbose) {
7247     char pc_str[256];
7248     pic16_pCode2str (pc_str, 256, oldPC);
7249     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7250   }
7251 #endif
7252   
7253   /* insert new pCode into pBlock */
7254   pic16_pCodeInsertAfter (oldPC, newPC);
7255   pic16_unlinkpCode (oldPC);
7256   
7257   /* destruct replaced pCode */
7258   oldPC->destruct (oldPC);
7259 }
7260
7261 /* Returns the inverted conditional branch (if any) or NULL.
7262  * pcop must be set to the new jump target.
7263  */
7264 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7265 {
7266   pCode *newBcc;
7267
7268   if (!bcc || !isPCI(bcc)) return NULL;
7269
7270   switch (PCI(bcc)->op) {
7271   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7272   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7273   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7274   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7275   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7276   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7277   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7278   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7279   default:
7280     newBcc = NULL;
7281   }
7282   return newBcc;
7283 }
7284
7285 #define MAX_DIST_GOTO         0x7FFFFFFF
7286 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7287 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7288 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7289 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7290
7291 /* Follows GOTO/BRA instructions to their target instructions, stores the
7292  * final destination (not a GOTO or BRA instruction) in target and returns
7293  * the distance from the original pc to *target.
7294  */
7295 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7296         pCode *curr = pc;
7297         pCode *last = NULL;
7298         pCodeOp *lastPCOP = NULL;
7299         int dist = 0;
7300         int depth = 0;
7301
7302         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7303
7304         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7305         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7306                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7307                 last = curr;
7308                 lastPCOP = PCI(curr)->pcop;
7309                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7310                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7311         } // while
7312
7313         if (target) *target = last;
7314         if (pcop) *pcop = lastPCOP;
7315         return dist;
7316 }
7317
7318 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7319  * Otherwise the first pCode after the jumptable (after
7320  * the OPT_JUMPTABLE_END tag) is returned.
7321  */
7322 pCode *skipJumptables (pCode *pc, int *isJumptable)
7323 {
7324   *isJumptable = 0;
7325   if (!pc) return NULL;
7326   
7327   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7328     *isJumptable = 1;
7329     //fprintf (stderr, "SKIPPING jumptable\n");
7330     do {
7331       //pc->print(stderr, pc);
7332       pc = pc->next;
7333     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7334                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7335     //fprintf (stderr, "<<JUMPTAB:\n");
7336     // skip OPT_END as well
7337     if (pc) pc = pc->next;
7338   } // while
7339
7340   return pc;
7341 }
7342
7343 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7344 {
7345   int isJumptab;
7346   *isJumptable = 0;
7347   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7348     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7349     pc = skipJumptables (pc, &isJumptab);
7350     if (isJumptab) {
7351         // pc is the first pCode after the jumptable
7352         *isJumptable = 1;
7353     } else {
7354         // pc has not been changed by skipJumptables()
7355         pc = pc->next;
7356     }
7357   } // while
7358   
7359   return pc;
7360 }
7361
7362 /* Turn GOTOs into BRAs if distance between GOTO and label
7363  * is less than 1024 bytes.
7364  *
7365  * This method is especially useful if GOTOs after BTFS[SC]
7366  * can be turned into BRAs as GOTO would cost another NOP
7367  * if skipped.
7368  */
7369 void pic16_OptimizeJumps ()
7370 {
7371   pCode *pc;
7372   pCode *pc_prev = NULL;
7373   pCode *pc_next = NULL;
7374   pBlock *pb;
7375   pCode *target;
7376   int change, iteration, isJumptab;
7377   int isHandled = 0;
7378   char *label;
7379   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7380   
7381   if (!the_pFile) return;
7382   
7383   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7384   
7385   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7386     int matchedInvertRule = 1;
7387     iteration = 1;
7388     do {
7389       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7390       change = 0;
7391       pc = pic16_findNextInstruction (pb->pcHead);
7392     
7393       while (pc) {
7394         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7395         if (isJumptab) {
7396                 // skip jumptable, i.e. start over with no pc_prev!     
7397                 pc_prev = NULL;
7398                 pc = pc_next;
7399                 continue;
7400         } // if
7401
7402         /* (1) resolve chained jumps
7403          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7404          * (a) leave dead code in and
7405          * (b) skip over the dead code with an (unneccessary) jump.
7406          */
7407         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7408           pCodeOp *lastTargetOp = NULL;
7409           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7410           int maxDist = MAX_DIST_BCC;
7411           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7412           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7413           
7414           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7415           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7416               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7417             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7418             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7419             PCI(pc)->pcop->name = lastTargetOp->name;
7420             change++;
7421             opt_gotochain++;
7422           } // if
7423         } // if
7424
7425
7426         if (IS_GOTO(pc)) {
7427           int dist;
7428           int condBraType = isSkipOnStatus(pc_prev);
7429           label = PCI(pc)->pcop->name;
7430           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7431           if (dist < 0) dist = -dist;
7432           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7433           isHandled = 0;
7434           
7435           
7436           /* (2) remove "GOTO label; label:" */
7437           if (isLabel (pc_next, label)) {
7438             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7439             // first remove all preceeding SKIP instructions
7440             while (pc_prev && isPCI_SKIP(pc_prev)) {
7441               // attach labels on this instruction to pc_next
7442               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7443               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7444               PCI(pc_prev)->label = NULL;
7445               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7446               pic16_unlinkpCode (pc_prev);
7447               pc_prev = pic16_findPrevInstruction (pc);
7448             } // while
7449             // now remove the redundant goto itself
7450             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7451             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7452             pic16_unlinkpCode (pc);
7453             pc = pic16_findPrevInstruction(pc_next->prev);
7454             isHandled = 1; // do not perform further optimizations
7455             opt_gotonext++;
7456             change++;
7457           } // if
7458           
7459           
7460           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7461           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7462             if (dist < MAX_DIST_BCC) {
7463               pCode *bcc = NULL;
7464               switch (condBraType) {
7465               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7466                 // no BDC on DIGIT CARRY available
7467               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7468               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7469               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7470               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7471                 // no BNDC on DIGIT CARRY available
7472               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7473               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7474               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7475               default:
7476                 // no replacement possible
7477                 bcc = NULL;
7478                 break;
7479               } // switch
7480               if (bcc) {
7481                 // ATTENTION: keep labels attached to BTFSx!
7482                 // HINT: GOTO is label free (checked above)
7483                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7484                 isHandled = 1; // do not perform further optimizations
7485                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7486                 pic16_pCodeReplace (pc_prev, bcc);
7487                 pc->destruct(pc);
7488                 pc = bcc;
7489                 opt_cond++;
7490                 change++;
7491               } // if
7492             } else {
7493               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7494               cond_toofar++;
7495             } // if
7496           } // if
7497
7498           if (!isHandled) {
7499             // (4) eliminate the following (common) tripel:
7500             //           <pred.>;
7501             //  labels1: Bcc label2;
7502             //           GOTO somewhere;    ; <-- instruction referenced by pc
7503             //  label2:  <cont.>
7504             // and replace it by
7505             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7506             //  label2:  <cont.>
7507             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7508             //            to <cont.> instead
7509             // ATTENTION: This optimization is only valid if <pred.> is
7510             //            not a skip operation!
7511             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7512             // ATTENTION: no label may be attached to the GOTO instruction!
7513             if (isConditionalBranch(pc_prev)
7514                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7515                 && (dist < MAX_DIST_BCC)
7516                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7517                 && hasNoLabel(pc)) {
7518               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7519             
7520               if (newBcc) {
7521                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7522                 isHandled = 1; // do not perform further optimizations
7523                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7524                 pic16_pCodeReplace (pc_prev, newBcc);
7525                 pc->destruct(pc);
7526                 pc = newBcc;
7527                 opt_reorder++;
7528                 change++;
7529                 matchedInvertRule++;
7530               }
7531             }
7532           }
7533           
7534           /* (5) now just turn GOTO into BRA */ 
7535           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7536             if (dist < MAX_DIST_BRA) {
7537               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7538               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7539               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7540               pic16_pCodeReplace (pc, newBra);
7541               pc = newBra;
7542               opt++;
7543               change++;
7544             } else {
7545               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7546               toofar++;
7547             }
7548           } // if (!isHandled)
7549         } // if
7550
7551         pc_prev = pc;
7552         pc = pc_next;
7553       } // while (pc)
7554       
7555       pBlockRemoveUnusedLabels (pb);
7556       
7557       // This line enables goto chain resolution!
7558       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7559
7560       iteration++;
7561     } while (change); /* fixpoint iteration per pBlock */
7562   } // for (pb)
7563   
7564   // emit some statistics concerning goto-optimization
7565 #if 0
7566   if (pic16_debug_verbose || pic16_pcode_verbose) {
7567     fprintf (stderr, "optimize-goto:\n"
7568              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7569              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7570              "\t%5d conditional \"skipping\" jumps inverted\n"
7571              "\t%5d GOTOs to next instruction removed\n"
7572              "\t%5d chained GOTOs resolved\n",
7573              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7574   } // if
7575 #endif
7576   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7577 }
7578
7579 #undef IS_GOTO
7580 #undef MAX_JUMPCHAIN_DEPTH
7581 #undef MAX_DIST_GOTO
7582 #undef MAX_DIST_BRA
7583 #undef MAX_DIST_BCC
7584
7585 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7586
7587 static void pBlockDestruct(pBlock *pb)
7588 {
7589
7590   if(!pb)
7591     return;
7592
7593
7594 //  Safe_free(pb);
7595
7596 }
7597
7598 /*-----------------------------------------------------------------*/
7599 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7600 /*                                  name dbName and combine them   */
7601 /*                                  into one block                 */
7602 /*-----------------------------------------------------------------*/
7603 static void mergepBlocks(char dbName)
7604 {
7605
7606   pBlock *pb, *pbmerged = NULL,*pbn;
7607
7608   pb = the_pFile->pbHead;
7609
7610   //fprintf(stderr," merging blocks named %c\n",dbName);
7611   while(pb) {
7612
7613     pbn = pb->next;
7614     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7615     if( getpBlock_dbName(pb) == dbName) {
7616
7617       //fprintf(stderr," merged block %c\n",dbName);
7618
7619       if(!pbmerged) {
7620         pbmerged = pb;
7621       } else {
7622         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7623         /* pic16_addpCode2pBlock doesn't handle the tail: */
7624         pbmerged->pcTail = pb->pcTail;
7625
7626         pb->prev->next = pbn;
7627         if(pbn) 
7628           pbn->prev = pb->prev;
7629
7630
7631         pBlockDestruct(pb);
7632       }
7633       //pic16_printpBlock(stderr, pbmerged);
7634     } 
7635     pb = pbn;
7636   }
7637
7638 }
7639
7640 /*-----------------------------------------------------------------*/
7641 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7642 /*                                                                 */
7643 /* level 0 == minimal optimization                                 */
7644 /*   optimize registers that are used only by two instructions     */
7645 /* level 1 == maximal optimization                                 */
7646 /*   optimize by looking at pairs of instructions that use the     */
7647 /*   register.                                                     */
7648 /*-----------------------------------------------------------------*/
7649
7650 static void AnalyzeFlow(int level)
7651 {
7652   static int times_called=0;
7653   pBlock *pb;
7654
7655     if(!the_pFile) {
7656       /* remove unused allocated registers before exiting */
7657       pic16_RemoveUnusedRegisters();
7658       return;
7659     }
7660
7661
7662     /* if this is not the first time this function has been called,
7663      * then clean up old flow information */
7664     if(times_called++) {
7665       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7666         unBuildFlow(pb);
7667         pic16_RegsUnMapLiveRanges();
7668     }
7669     GpcFlowSeq = 1;
7670
7671     /* Phase 2 - Flow Analysis - Register Banking
7672      *
7673      * In this phase, the individual flow blocks are examined
7674      * and register banking is fixed.
7675      */
7676
7677 #if 0
7678     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7679       pic16_FixRegisterBanking(pb);
7680 #endif
7681
7682     /* Phase 2 - Flow Analysis
7683      *
7684      * In this phase, the pCode is partition into pCodeFlow 
7685      * blocks. The flow blocks mark the points where a continuous
7686      * stream of instructions changes flow (e.g. because of
7687      * a call or goto or whatever).
7688      */
7689
7690     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7691       pic16_BuildFlow(pb);
7692
7693
7694     /* Phase 2 - Flow Analysis - linking flow blocks
7695      *
7696      * In this phase, the individual flow blocks are examined
7697      * to determine their order of excution.
7698      */
7699
7700     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7701       LinkFlow(pb);
7702
7703 #if 1
7704         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7705                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7706                         pic16_createDF (pb);
7707 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7708                         pic16_vcg_dump_default (pb);
7709 #endif
7710                         //pic16_destructDF (pb);
7711                 }
7712
7713                 pic16_df_stats ();
7714                 if (0) releaseStack (); // releasing is costly...
7715         }
7716 #endif
7717
7718     /* Phase 3 - Flow Analysis - Flow Tree
7719      *
7720      * In this phase, the individual flow blocks are examined
7721      * to determine their order of execution.
7722      */
7723
7724     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7725       pic16_BuildFlowTree(pb);
7726
7727
7728     /* Phase x - Flow Analysis - Used Banks
7729      *
7730      * In this phase, the individual flow blocks are examined
7731      * to determine the Register Banks they use
7732      */
7733
7734 #if 0
7735     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7736       FixBankFlow(pb);
7737 #endif
7738
7739
7740     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7741       pic16_pCodeRegMapLiveRanges(pb);
7742
7743     pic16_RemoveUnusedRegisters();
7744     pic16_removeUnusedRegistersDF ();
7745
7746   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7747     pic16_pCodeRegOptimizeRegUsage(level);
7748
7749
7750 #if 0
7751     if(!options.nopeep)
7752       OptimizepCode('*');
7753 #endif
7754
7755 #if 0
7756     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7757       DumpFlow(pb);
7758 #endif
7759
7760     /* debug stuff */ 
7761     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7762       pCode *pcflow;
7763       
7764         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7765           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7766           pcflow = pcflow->next) {
7767             FillFlow(PCFL(pcflow));
7768         }
7769     }
7770
7771 #if 0
7772     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7773       pCode *pcflow;
7774
7775         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7776           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7777           pcflow = pcflow->next) {
7778             FlowStats(PCFL(pcflow));
7779         }
7780     }
7781 #endif
7782 }
7783
7784 /* VR -- no need to analyze banking in flow, but left here :
7785  *      1. because it may be used in the future for other purposes
7786  *      2. because if omitted we'll miss some optimization done here
7787  *
7788  * Perhaps I should rename it to something else
7789  */
7790
7791 /*-----------------------------------------------------------------*/
7792 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7793 /*                  assigned to the registers.                     */
7794 /*                                                                 */
7795 /*-----------------------------------------------------------------*/
7796
7797 void pic16_AnalyzeBanking(void)
7798 {
7799   pBlock  *pb;
7800
7801     /* Phase x - Flow Analysis - Used Banks
7802      *
7803      * In this phase, the individual flow blocks are examined
7804      * to determine the Register Banks they use
7805      */
7806
7807     AnalyzeFlow(0);
7808     AnalyzeFlow(1);
7809
7810     if(!options.nopeep)
7811       OptimizepCode('*');
7812
7813
7814     if(!the_pFile)return;
7815
7816     if(!pic16_options.no_banksel) {
7817       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7818 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7819         pic16_FixRegisterBanking(pb);
7820       }
7821     }
7822 }
7823
7824 /*-----------------------------------------------------------------*/
7825 /* buildCallTree - Look at the flow and extract all of the calls.  */
7826 /*-----------------------------------------------------------------*/
7827 static set *register_usage(pBlock *pb);
7828
7829 static void buildCallTree(void    )
7830 {
7831   pBranch *pbr;
7832   pBlock  *pb;
7833   pCode   *pc;
7834   regs *r;
7835   
7836   if(!the_pFile)
7837     return;
7838
7839
7840
7841   /* Now build the call tree.
7842      First we examine all of the pCodes for functions.
7843      Keep in mind that the function boundaries coincide
7844      with pBlock boundaries. 
7845
7846      The algorithm goes something like this:
7847      We have two nested loops. The outer loop iterates
7848      through all of the pBlocks/functions. The inner
7849      loop iterates through all of the pCodes for
7850      a given pBlock. When we begin iterating through
7851      a pBlock, the variable pc_fstart, pCode of the start
7852      of a function, is cleared. We then search for pCodes
7853      of type PC_FUNCTION. When one is encountered, we
7854      initialize pc_fstart to this and at the same time
7855      associate a new pBranch object that signifies a 
7856      branch entry. If a return is found, then this signifies
7857      a function exit point. We'll link the pCodes of these
7858      returns to the matching pc_fstart.
7859
7860      When we're done, a doubly linked list of pBranches
7861      will exist. The head of this list is stored in
7862      `the_pFile', which is the meta structure for all
7863      of the pCode. Look at the pic16_printCallTree function
7864      on how the pBranches are linked together.
7865
7866    */
7867   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7868     pCode *pc_fstart=NULL;
7869     for(pc = pb->pcHead; pc; pc = pc->next) {
7870
7871         if(isPCI(pc) && pc_fstart) {
7872                 if(PCI(pc)->is2MemOp) {
7873                         r = pic16_getRegFromInstruction2(pc);
7874                         if(r && !strcmp(r->name, "POSTDEC1"))
7875                                 PCF(pc_fstart)->stackusage++;
7876                 } else {
7877                         r = pic16_getRegFromInstruction(pc);
7878                         if(r && !strcmp(r->name, "PREINC1"))
7879                                 PCF(pc_fstart)->stackusage--;
7880                 }
7881         }
7882
7883       if(isPCF(pc)) {
7884         if (PCF(pc)->fname) {
7885         char buf[16];
7886
7887           sprintf(buf, "%smain", port->fun_prefix);
7888           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7889             //fprintf(stderr," found main \n");
7890             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7891             pb->dbName = 'M';
7892           }
7893
7894           pbr = Safe_calloc(1,sizeof(pBranch));
7895           pbr->pc = pc_fstart = pc;
7896           pbr->next = NULL;
7897
7898           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7899
7900           // Here's a better way of doing the same:
7901           addSet(&pb->function_entries, pc);
7902
7903         } else {
7904           // Found an exit point in a function, e.g. return
7905           // (Note, there may be more than one return per function)
7906           if(pc_fstart)
7907             pBranchLink(PCF(pc_fstart), PCF(pc));
7908
7909           addSet(&pb->function_exits, pc);
7910         }
7911       } else if(isCALL(pc)) {
7912         addSet(&pb->function_calls,pc);
7913       }
7914     }
7915   }
7916
7917
7918 #if 0
7919   /* This is not needed because currently all register used
7920    * by a function are stored in stack -- VR */
7921    
7922   /* Re-allocate the registers so that there are no collisions
7923    * between local variables when one function call another */
7924
7925   // this is weird...
7926   //  pic16_deallocateAllRegs();
7927
7928   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7929     if(!pb->visited)
7930       register_usage(pb);
7931   }
7932 #endif
7933
7934 }
7935
7936 /*-----------------------------------------------------------------*/
7937 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7938 /*                all of the logical connections.                  */
7939 /*                                                                 */
7940 /* Essentially what's done here is that the pCode flow is          */
7941 /* determined.                                                     */
7942 /*-----------------------------------------------------------------*/
7943
7944 void pic16_AnalyzepCode(char dbName)
7945 {
7946   pBlock *pb;
7947   int i,changes;
7948
7949   if(!the_pFile)
7950     return;
7951
7952   mergepBlocks('D');
7953
7954
7955   /* Phase 1 - Register allocation and peep hole optimization
7956    *
7957    * The first part of the analysis is to determine the registers
7958    * that are used in the pCode. Once that is done, the peep rules
7959    * are applied to the code. We continue to loop until no more
7960    * peep rule optimizations are found (or until we exceed the
7961    * MAX_PASSES threshold). 
7962    *
7963    * When done, the required registers will be determined.
7964    *
7965    */
7966   i = 0;
7967   do {
7968
7969     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7970     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7971
7972     /* First, merge the labels with the instructions */
7973     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7974       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7975
7976         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7977         //fprintf(stderr," analyze and merging block %c\n",dbName);
7978         pic16_pBlockMergeLabels(pb);
7979         AnalyzepBlock(pb);
7980       } else {
7981         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7982       }
7983     }
7984
7985         if(!options.nopeep)
7986                 changes = OptimizepCode(dbName);
7987         else changes = 0;
7988
7989   } while(changes && (i++ < MAX_PASSES));
7990
7991   
7992   buildCallTree();
7993 }
7994
7995
7996 /* convert a series of movff's of local regs to stack, with a single call to
7997  * a support functions which does the same thing via loop */
7998 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7999 {
8000   pBranch *pbr;
8001   pCode *pc, *pct;
8002   char *fname[]={"__lr_store", "__lr_restore"};
8003
8004 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8005
8006     pct = pic16_findNextInstruction(pcstart->next);
8007     do {
8008       pc = pct;
8009       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8010 //      pc->print(stderr, pc);
8011       if(isPCI(pc) && PCI(pc)->label) {
8012         pbr = PCI(pc)->label;
8013         while(pbr && pbr->pc) {
8014           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8015           pbr = pbr->next;
8016         }
8017
8018 //        pc->print(stderr, pc);
8019         /* unlink pCode */
8020         pc->prev->next = pct;
8021         pct->prev = pc->prev;
8022 //        pc->next = NULL;
8023 //        pc->prev = NULL;
8024       }
8025     } while ((pc) && (pc != pcend));
8026
8027     /* unlink movff instructions */
8028     pcstart->next = pcend;
8029     pcend->prev = pcstart;
8030
8031     pc = pcstart;
8032 //    if(!entry) {
8033 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8034 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8035 //    }
8036                 
8037     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8038     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8039     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8040
8041 //    if(!entry) {
8042 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8043 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8044 //    }
8045
8046     
8047     {
8048       symbol *sym;
8049
8050         sym = newSymbol( fname[ entry?0:1 ], 0 );
8051         strcpy(sym->rname, fname[ entry?0:1 ]);
8052         checkAddSym(&externs, sym);
8053         
8054 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8055     }
8056
8057 }
8058
8059 /*-----------------------------------------------------------------*/
8060 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8061 /*    local registers to a support function call                   */
8062 /*-----------------------------------------------------------------*/
8063 void pic16_OptimizeLocalRegs(void)
8064 {
8065   pBlock  *pb;
8066   pCode   *pc;
8067   pCodeInfo *pci;
8068   pCodeOpLocalReg *pclr;
8069   int regCount=0;
8070   int inRegCount=0;
8071   regs *r, *lastr=NULL, *firstr=NULL;
8072   pCode *pcstart=NULL, *pcend=NULL;
8073   int inEntry=0;
8074   char *curFunc=NULL;
8075
8076         /* Overview:
8077          *   local_regs begin mark
8078          *      MOVFF r0x01, POSTDEC1
8079          *      MOVFF r0x02, POSTDEC1
8080          *      ...
8081          *      ...
8082          *      MOVFF r0x0n, POSTDEC1
8083          *   local_regs end mark
8084          *
8085          * convert the above to the below:
8086          *      MOVLW   starting_register_index
8087          *      MOVWF   PRODL
8088          *      MOVLW   register_count
8089          *      call    __save_registers_in_stack
8090          */
8091
8092     if(!the_pFile)
8093       return;
8094
8095     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8096       inRegCount = regCount = 0;
8097       firstr = lastr = NULL;
8098       for(pc = pb->pcHead; pc; pc = pc->next) {
8099
8100         /* hold current function name */
8101         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8102         
8103         if(pc && (pc->type == PC_INFO)) {
8104           pci = PCINF(pc);
8105
8106           if(pci->type == INF_LOCALREGS) {
8107             pclr = PCOLR(pci->oper1);
8108             
8109             if((pclr->type == LR_ENTRY_BEGIN)
8110               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8111             else inEntry = 0;
8112             
8113             switch(pclr->type) {
8114               case LR_ENTRY_BEGIN:
8115               case LR_EXIT_BEGIN:
8116                         inRegCount = 1; regCount = 0;
8117                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8118                         firstr = lastr = NULL;
8119                         break;
8120               
8121               case LR_ENTRY_END:
8122               case LR_EXIT_END:
8123                         inRegCount = -1;
8124                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8125
8126 #if 1
8127                         if(curFunc && inWparamList(curFunc+1)) {
8128                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8129                                         filename, curFunc);
8130                         } else {
8131                           if(regCount>2) {
8132                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8133                               firstr, inEntry);
8134                           }
8135                         }
8136 #endif
8137                         firstr = lastr = NULL;
8138                         break;
8139             }
8140             
8141             if(inRegCount == -1) {
8142 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8143               regCount = 0;
8144               inRegCount = 0;
8145             }
8146           }
8147         } else {
8148           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8149             if(inEntry)
8150               r = pic16_getRegFromInstruction(pc);
8151             else
8152               r = pic16_getRegFromInstruction2(pc);
8153             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8154               if(!firstr)firstr = r;
8155               regCount++;
8156 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8157             }
8158           }
8159         }
8160       }
8161     }
8162 }
8163               
8164             
8165
8166
8167
8168 /*-----------------------------------------------------------------*/
8169 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8170 /*                   function                                      */
8171 /*-----------------------------------------------------------------*/
8172 static bool ispCodeFunction(pCode *pc)
8173 {
8174
8175   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8176     return 1;
8177
8178   return 0;
8179 }
8180
8181 /*-----------------------------------------------------------------*/
8182 /* findFunction - Search for a function by name (given the name)   */
8183 /*                in the set of all functions that are in a pBlock */
8184 /* (note - I expect this to change because I'm planning to limit   */
8185 /*  pBlock's to just one function declaration                      */
8186 /*-----------------------------------------------------------------*/
8187 static pCode *findFunction(char *fname)
8188 {
8189   pBlock *pb;
8190   pCode *pc;
8191   if(!fname)
8192     return NULL;
8193
8194   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8195
8196     pc = setFirstItem(pb->function_entries);
8197     while(pc) {
8198     
8199       if((pc->type == PC_FUNCTION) &&
8200          (PCF(pc)->fname) && 
8201          (strcmp(fname, PCF(pc)->fname)==0))
8202         return pc;
8203
8204       pc = setNextItem(pb->function_entries);
8205
8206     }
8207
8208   }
8209   return NULL;
8210 }
8211
8212 static void MarkUsedRegisters(set *regset)
8213 {
8214
8215   regs *r1,*r2;
8216
8217   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8218 //      fprintf(stderr, "marking register = %s\t", r1->name);
8219     r2 = pic16_regWithIdx(r1->rIdx);
8220 //      fprintf(stderr, "to register = %s\n", r2->name);
8221     r2->isFree = 0;
8222     r2->wasUsed = 1;
8223   }
8224 }
8225
8226 static void pBlockStats(FILE *of, pBlock *pb)
8227 {
8228
8229   pCode *pc;
8230   regs  *r;
8231
8232         if(!pic16_pcode_verbose)return;
8233         
8234   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8235
8236   // for now just print the first element of each set
8237   pc = setFirstItem(pb->function_entries);
8238   if(pc) {
8239     fprintf(of,";entry:  ");
8240     pc->print(of,pc);
8241   }
8242   pc = setFirstItem(pb->function_exits);
8243   if(pc) {
8244     fprintf(of,";has an exit\n");
8245     //pc->print(of,pc);
8246   }
8247
8248   pc = setFirstItem(pb->function_calls);
8249   if(pc) {
8250     fprintf(of,";functions called:\n");
8251
8252     while(pc) {
8253       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8254         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8255       }
8256       pc = setNextItem(pb->function_calls);
8257     }
8258   }
8259
8260   r = setFirstItem(pb->tregisters);
8261   if(r) {
8262     int n = elementsInSet(pb->tregisters);
8263
8264     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8265
8266     while (r) {
8267       fprintf(of,   ";   %s\n",r->name);
8268       r = setNextItem(pb->tregisters);
8269     }
8270   }
8271   
8272   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8273 }
8274
8275 /*-----------------------------------------------------------------*/
8276 /*-----------------------------------------------------------------*/
8277 #if 0
8278 static void sequencepCode(void)
8279 {
8280   pBlock *pb;
8281   pCode *pc;
8282
8283
8284   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8285
8286     pb->seq = GpCodeSequenceNumber+1;
8287
8288     for( pc = pb->pcHead; pc; pc = pc->next)
8289       pc->seq = ++GpCodeSequenceNumber;
8290   }
8291
8292 }
8293 #endif
8294
8295 /*-----------------------------------------------------------------*/
8296 /*-----------------------------------------------------------------*/
8297 static set *register_usage(pBlock *pb)
8298 {
8299   pCode *pc,*pcn;
8300   set *registers=NULL;
8301   set *registersInCallPath = NULL;
8302
8303   /* check recursion */
8304
8305   pc = setFirstItem(pb->function_entries);
8306
8307   if(!pc)
8308     return registers;
8309
8310   pb->visited = 1;
8311
8312   if(pc->type != PC_FUNCTION)
8313     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8314
8315   pc = setFirstItem(pb->function_calls);
8316   for( ; pc; pc = setNextItem(pb->function_calls)) {
8317
8318     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8319       char *dest = pic16_get_op_from_instruction(PCI(pc));
8320
8321       pcn = findFunction(dest);
8322       if(pcn) 
8323         registersInCallPath = register_usage(pcn->pb);
8324     } else
8325       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8326
8327   }
8328
8329 #ifdef PCODE_DEBUG
8330   pBlockStats(stderr,pb);  // debug
8331 #endif
8332
8333   // Mark the registers in this block as used.
8334
8335   MarkUsedRegisters(pb->tregisters);
8336   if(registersInCallPath) {
8337     /* registers were used in the functions this pBlock has called */
8338     /* so now, we need to see if these collide with the ones we are */
8339     /* using here */
8340
8341     regs *r1,*r2, *newreg;
8342
8343     DFPRINTF((stderr,"comparing registers\n"));
8344
8345     r1 = setFirstItem(registersInCallPath);
8346     while(r1) {
8347
8348       r2 = setFirstItem(pb->tregisters);
8349
8350       while(r2 && (r1->type != REG_STK)) {
8351
8352         if(r2->rIdx == r1->rIdx) {
8353           newreg = pic16_findFreeReg(REG_GPR);
8354
8355
8356           if(!newreg) {
8357             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8358             exit(1);
8359           }
8360
8361           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8362                   r1->rIdx, newreg->rIdx));
8363           r2->rIdx = newreg->rIdx;
8364           //if(r2->name) Safe_free(r2->name);
8365           if(newreg->name)
8366             r2->name = Safe_strdup(newreg->name);
8367           else
8368             r2->name = NULL;
8369           newreg->isFree = 0;
8370           newreg->wasUsed = 1;
8371         }
8372         r2 = setNextItem(pb->tregisters);
8373       }
8374
8375       r1 = setNextItem(registersInCallPath);
8376     }
8377
8378     /* Collisions have been resolved. Now free the registers in the call path */
8379     r1 = setFirstItem(registersInCallPath);
8380     while(r1) {
8381       if(r1->type != REG_STK) {
8382         newreg = pic16_regWithIdx(r1->rIdx);
8383         newreg->isFree = 1;
8384       }
8385       r1 = setNextItem(registersInCallPath);
8386     }
8387
8388   }// else
8389   //    MarkUsedRegisters(pb->registers);
8390
8391   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8392 #ifdef PCODE_DEBUG
8393   if(registers) 
8394     DFPRINTF((stderr,"returning regs\n"));
8395   else
8396     DFPRINTF((stderr,"not returning regs\n"));
8397
8398   DFPRINTF((stderr,"pBlock after register optim.\n"));
8399   pBlockStats(stderr,pb);  // debug
8400 #endif
8401
8402   return registers;
8403 }
8404
8405 /*-----------------------------------------------------------------*/
8406 /* pct2 - writes the call tree to a file                           */
8407 /*                                                                 */
8408 /*-----------------------------------------------------------------*/
8409 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8410 {
8411   pCode *pc,*pcn;
8412   int i;
8413   //  set *registersInCallPath = NULL;
8414
8415   if(!of)
8416     return;
8417
8418   if(indent > 10) {
8419         fprintf(of, "recursive function\n");
8420     return; //recursion ?
8421   }
8422
8423   pc = setFirstItem(pb->function_entries);
8424
8425   if(!pc)
8426     return;
8427
8428   pb->visited = 0;
8429
8430   for(i=0;i<indent;i++)   // Indentation
8431         fputs("+   ", of);
8432   fputs("+- ", of);
8433
8434   if(pc->type == PC_FUNCTION) {
8435     usedstack += PCF(pc)->stackusage;
8436     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8437   } else return;  // ???
8438
8439
8440   pc = setFirstItem(pb->function_calls);
8441   for( ; pc; pc = setNextItem(pb->function_calls)) {
8442
8443     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8444       char *dest = pic16_get_op_from_instruction(PCI(pc));
8445
8446       pcn = findFunction(dest);
8447       if(pcn) 
8448         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8449     } else
8450       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8451
8452   }
8453
8454
8455 }
8456
8457
8458 /*-----------------------------------------------------------------*/
8459 /* pic16_printCallTree - writes the call tree to a file                  */
8460 /*                                                                 */
8461 /*-----------------------------------------------------------------*/
8462
8463 void pic16_printCallTree(FILE *of)
8464 {
8465   pBranch *pbr;
8466   pBlock  *pb;
8467   pCode   *pc;
8468
8469   if(!the_pFile)
8470     return;
8471
8472   if(!of)
8473     of = stderr;
8474
8475   fprintf(of, "\npBlock statistics\n");
8476   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8477     pBlockStats(of,pb);
8478
8479
8480   fprintf(of,"Call Tree\n");
8481   pbr = the_pFile->functions;
8482   while(pbr) {
8483     if(pbr->pc) {
8484       pc = pbr->pc;
8485       if(!ispCodeFunction(pc))
8486         fprintf(of,"bug in call tree");
8487
8488
8489       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8490
8491       while(pc->next && !ispCodeFunction(pc->next)) {
8492         pc = pc->next;
8493         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8494           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8495       }
8496     }
8497
8498     pbr = pbr->next;
8499   }
8500
8501
8502   fprintf(of,"\n**************\n\na better call tree\n");
8503   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8504 //    if(pb->visited)
8505       pct2(of,pb,0,0);
8506   }
8507
8508   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8509     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8510   }
8511 }
8512
8513
8514
8515 /*-----------------------------------------------------------------*/
8516 /*                                                                 */
8517 /*-----------------------------------------------------------------*/
8518
8519 static void InlineFunction(pBlock *pb)
8520 {
8521   pCode *pc;
8522   pCode *pc_call;
8523
8524   if(!pb)
8525     return;
8526
8527   pc = setFirstItem(pb->function_calls);
8528
8529   for( ; pc; pc = setNextItem(pb->function_calls)) {
8530
8531     if(isCALL(pc)) {
8532       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8533       pCode *pct;
8534       pCode *pce;
8535
8536       pBranch *pbr;
8537
8538       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8539         
8540         //fprintf(stderr,"Cool can inline:\n");
8541         //pcn->print(stderr,pcn);
8542
8543         //fprintf(stderr,"recursive call Inline\n");
8544         InlineFunction(pcn->pb);
8545         //fprintf(stderr,"return from recursive call Inline\n");
8546
8547         /*
8548           At this point, *pc points to a CALL mnemonic, and
8549           *pcn points to the function that is being called.
8550
8551           To in-line this call, we need to remove the CALL
8552           and RETURN(s), and link the function pCode in with
8553           the CALLee pCode.
8554
8555         */
8556
8557
8558         /* Remove the CALL */
8559         pc_call = pc;
8560         pc = pc->prev;
8561
8562         /* remove callee pBlock from the pBlock linked list */
8563         removepBlock(pcn->pb);
8564
8565         pce = pcn;
8566         while(pce) {
8567           pce->pb = pb;
8568           pce = pce->next;
8569         }
8570
8571         /* Remove the Function pCode */
8572         pct = pic16_findNextInstruction(pcn->next);
8573
8574         /* Link the function with the callee */
8575         pc->next = pcn->next;
8576         pcn->next->prev = pc;
8577         
8578         /* Convert the function name into a label */
8579
8580         pbr = Safe_calloc(1,sizeof(pBranch));
8581         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8582         pbr->next = NULL;
8583         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8584         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8585
8586         /* turn all of the return's except the last into goto's */
8587         /* check case for 2 instruction pBlocks */
8588         pce = pic16_findNextInstruction(pcn->next);
8589         while(pce) {
8590           pCode *pce_next = pic16_findNextInstruction(pce->next);
8591
8592           if(pce_next == NULL) {
8593             /* found the last return */
8594             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8595
8596             //fprintf(stderr,"found last return\n");
8597             //pce->print(stderr,pce);
8598             pce->prev->next = pc_call->next;
8599             pc_call->next->prev = pce->prev;
8600             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8601                                                       PCI(pce)->label);
8602           }
8603
8604           pce = pce_next;
8605         }
8606
8607
8608       }
8609     } else
8610       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8611
8612   }
8613
8614 }
8615
8616 /*-----------------------------------------------------------------*/
8617 /*                                                                 */
8618 /*-----------------------------------------------------------------*/
8619
8620 void pic16_InlinepCode(void)
8621 {
8622
8623   pBlock  *pb;
8624   pCode   *pc;
8625
8626   if(!the_pFile)
8627     return;
8628
8629   if(!functionInlining)
8630     return;
8631
8632   /* Loop through all of the function definitions and count the
8633    * number of times each one is called */
8634   //fprintf(stderr,"inlining %d\n",__LINE__);
8635
8636   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8637
8638     pc = setFirstItem(pb->function_calls);
8639
8640     for( ; pc; pc = setNextItem(pb->function_calls)) {
8641
8642       if(isCALL(pc)) {
8643         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8644         if(pcn && isPCF(pcn)) {
8645           PCF(pcn)->ncalled++;
8646         }
8647       } else
8648         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8649
8650     }
8651   }
8652
8653   //fprintf(stderr,"inlining %d\n",__LINE__);
8654
8655   /* Now, Loop through the function definitions again, but this
8656    * time inline those functions that have only been called once. */
8657   
8658   InlineFunction(the_pFile->pbHead);
8659   //fprintf(stderr,"inlining %d\n",__LINE__);
8660
8661   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8662     unBuildFlow(pb);
8663
8664 }
8665
8666 char *pic_optype_names[]={
8667         "PO_NONE",         // No operand e.g. NOP
8668         "PO_W",              // The working register (as a destination)
8669         "PO_WREG",           // The working register (as a file register)
8670         "PO_STATUS",         // The 'STATUS' register
8671         "PO_BSR",            // The 'BSR' register
8672         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8673                              // of three)
8674         "PO_INDF0",          // The Indirect register
8675         "PO_INTCON",         // Interrupt Control register
8676         "PO_GPR_REGISTER",   // A general purpose register
8677         "PO_GPR_BIT",        // A bit of a general purpose register
8678         "PO_GPR_TEMP",       // A general purpose temporary register
8679         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8680         "PO_PCL",            // Program counter Low register
8681         "PO_PCLATH",         // Program counter Latch high register
8682         "PO_PCLATU",         // Program counter Latch upper register
8683         "PO_PRODL",          // Product Register Low
8684         "PO_PRODH",          // Product Register High
8685         "PO_LITERAL",        // A constant
8686         "PO_REL_ADDR",       // A relative address
8687         "PO_IMMEDIATE",      //  (8051 legacy)
8688         "PO_DIR",            // Direct memory (8051 legacy)
8689         "PO_CRY",            // bit memory (8051 legacy)
8690         "PO_BIT",            // bit operand.
8691         "PO_STR",            //  (8051 legacy)
8692         "PO_LABEL",
8693         "PO_WILD"            // Wild card operand in peep optimizer
8694 };
8695
8696
8697 char *dumpPicOptype(PIC_OPTYPE type)
8698 {
8699         return (pic_optype_names[ type ]);
8700 }
8701
8702
8703 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8704 #include "graph.h"
8705
8706 #define MAX_COMMON_BANK_SIZE    32
8707 #define FIRST_PSEUDO_BANK_NR  1000
8708
8709 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8710 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8711 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8712 Graph *adj = NULL;
8713
8714 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8715
8716 typedef struct {
8717   pseudoBankNr bank;  // number assigned to this pseudoBank
8718   unsigned int size;  // number of operands assigned to this bank
8719   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8720 } pseudoBank;
8721
8722 /*----------------------------------------------------------------------*/
8723 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8724 /*----------------------------------------------------------------------*/
8725 unsigned int hashSymbol (const char *str)
8726 {
8727   unsigned int res = 0;
8728   if (!str) return 0;
8729
8730   while (*str) {
8731     res ^= (*str);
8732     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8733     str++;
8734   } // while
8735
8736   return res;
8737 }
8738
8739 /*-----------------------------------------------------------------------*/
8740 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8741 /*-----------------------------------------------------------------------*/
8742 int compareSymbol (const void *sym1, const void *sym2)
8743 {
8744   char *s1 = (char*) sym1;
8745   char *s2 = (char*) sym2;
8746   
8747   return (strcmp (s1,s2) == 0);
8748 }
8749
8750 /*-----------------------------------------------------------------------*/
8751 /* comparePre - return 1 iff p1 == p2                                    */
8752 /*-----------------------------------------------------------------------*/
8753 int comparePtr (const void *p1, const void *p2)
8754 {
8755   return (p1 == p2);
8756 }
8757
8758 /*----------------------------------------------------------*/
8759 /* getSymbolFromOperand - return a pointer to the symbol in */
8760 /*                        the given operand and its length  */
8761 /*----------------------------------------------------------*/
8762 char *getSymbolFromOperand (char *op, unsigned int *len)
8763 {
8764   char *sym, *curr;
8765   *len = 0;
8766
8767   if (!op) return NULL;
8768
8769   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8770   sym = op;
8771   if (*sym == '(') sym++;
8772
8773   curr = sym;
8774   while (((*curr >= 'A') && (*curr <= 'Z'))
8775          || ((*curr >= 'a') && (*curr <= 'z'))
8776          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8777          || (*curr == '_')) {
8778     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8779     curr++;
8780     (*len)++;
8781   } // while
8782
8783   return sym;
8784 }
8785
8786 /*--------------------------------------------------------------------------*/
8787 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8788 /*--------------------------------------------------------------------------*/
8789 char *getSymFromBank (pseudoBankNr bank)
8790 {
8791   assert (bank2sym);
8792
8793   if (bank < 0) return "<INVALID BANK NR>";
8794   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8795 }
8796
8797 /*-----------------------------------------------------------------------*/
8798 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8799 /*                           bank number (uses hTab sym2bank), if the    */
8800 /*                           symbol is not yet assigned a pseudo bank it */
8801 /*                           is assigned one here                        */
8802 /*-----------------------------------------------------------------------*/
8803 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8804 {
8805   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8806   pseudoBankNr bank;
8807   unsigned int hash;
8808
8809   assert (sym2bank);
8810
8811   hash = hashSymbol (op) % sym2bank->size;
8812   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8813   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8814
8815   if (bank == UNKNOWN_BANK) {
8816     // create a pseudo bank for the operand
8817     bank = next_bank++;
8818     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8819     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8820     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8821     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8822   } else {
8823     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8824   } // if
8825
8826   assert (bank >= 0);
8827
8828   return bank;
8829 }
8830
8831 /*--------------------------------------------------------------------*/
8832 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8833 /*--------------------------------------------------------------------*/
8834 int isBanksel (pCode *pc)
8835 {
8836   if (!pc) return 0;
8837
8838   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8839     // BANKSEL <variablename>  or  MOVLB <banknr>
8840     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8841     return 1;
8842   }
8843
8844   // check for inline assembler BANKSELs
8845   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8846                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8847     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8848     return 1;
8849   }
8850
8851   // assume pc is no BANKSEL instruction
8852   return 0;
8853 }
8854
8855 /*---------------------------------------------------------------------------------*/
8856 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8857 /*                  This method can not guarantee to find all modifications of the */
8858 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8859 /*                  generated plus some cases.                                     */
8860 /*---------------------------------------------------------------------------------*/
8861 int invalidatesBSR(pCode *pc)
8862 {
8863   // assembler directives invalidate BSR (well, they might, we don't know)
8864   if (isPCAD(pc)) return 1;
8865
8866   // only ASMDIRs and pCodeInstructions can invalidate BSR
8867   if (!isPCI(pc)) return 0;
8868
8869   // we have a pCodeInstruction
8870
8871   // check for BSR modifying instructions
8872   switch (PCI(pc)->op) {
8873   case POC_CALL:
8874   case POC_RCALL:
8875   case POC_MOVLB:
8876   case POC_RETFIE:  // might be used as CALL replacement
8877   case POC_RETLW:   // might be used as CALL replacement
8878   case POC_RETURN:  // might be used as CALL replacement
8879   case POC_BANKSEL:
8880     return 1;
8881     break;
8882
8883   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8884     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8885     break;
8886   } // switch
8887
8888   // no change of BSR possible/probable
8889   return 0;
8890 }
8891
8892 /*------------------------------------------------------------*/
8893 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8894 /*                      the symbol referenced in this BANKSEL */
8895 /*------------------------------------------------------------*/
8896 pseudoBankNr getBankFromBanksel (pCode *pc)
8897 {
8898   char *sym;
8899   int data = (int)NULL;
8900
8901   if (!pc) return INVALID_BANK;
8902   
8903   if (isPCAD(pc) && PCAD(pc)->directive) {
8904     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8905       // get symbolname from PCAD(pc)->arg
8906       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8907       sym = PCAD(pc)->arg;
8908       data = getPseudoBankNrFromOperand (sym);
8909       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8910     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8911       // get (literal) bank number from PCAD(pc)->arg
8912       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8913       assert (0 && "not yet implemented - turn off banksel optimization for now");
8914     }
8915   } else if (isPCI(pc)) {
8916     if (PCI(pc)->op == POC_BANKSEL) {
8917       // get symbolname from PCI(pc)->pcop->name (?)
8918       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8919       sym = PCI(pc)->pcop->name;
8920       data = getPseudoBankNrFromOperand (sym);
8921       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8922     } else if (PCI(pc)->op == POC_MOVLB) {
8923       // get (literal) bank number from PCI(pc)->pcop->name
8924       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8925       assert (0 && "not yet implemented - turn off banksel optimization for now");
8926     }
8927   }
8928   
8929   if (data == 0)
8930     // no assigned bank could be found
8931     return UNKNOWN_BANK;
8932   else
8933     return data;
8934 }
8935
8936 /*------------------------------------------------------------------------------*/
8937 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8938 /*------------------------------------------------------------------------------*/
8939 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8940 {
8941   pseudoBank *data;
8942
8943   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8944
8945   do {
8946     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8947     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8948     if (data) {
8949       if (data->bank != bank)
8950         bank = data->bank;
8951       else
8952         data = NULL;
8953     }
8954   } while (data);
8955   
8956   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8957   return bank;
8958 }
8959
8960 /*------------------------------------------------------------------*/
8961 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8962 /*                        bank is selected at a given pCode         */
8963 /*------------------------------------------------------------------*/
8964
8965 /* Create a graph with pseudo banks as its nodes and switches between
8966  * these as edges (with the edge weight representing the absolute
8967  * number of BANKSELs from one to the other).
8968  * Removes redundand BANKSELs instead iff mod == 1.
8969  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8970  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8971  * pseudo BSR.
8972  * TODO: check ALL instructions operands if they modify BSR directly...
8973  *
8974  * pb - the pBlock to annotate
8975  * mod  - select either graph creation (0) or BANKSEL removal (1)
8976  */
8977 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8978 {
8979   pCode *pc, *pc_next;
8980   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8981   int isBankselect = 0;
8982   unsigned int banksels=0;
8983   
8984   if (!pb) return 0;
8985
8986   pc = pic16_findNextInstruction(pb->pcHead);
8987   while (pc) {
8988     isBankselect = isBanksel (pc);
8989     pc_next = pic16_findNextInstruction (pc->next);
8990
8991     if (!hasNoLabel (pc)) {
8992       // we don't know our predecessors -- assume different BSRs
8993       prevBSR = UNKNOWN_BANK;
8994       pseudoBSR = UNKNOWN_BANK;
8995       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8996     } // if
8997
8998     // check if this is a BANKSEL instruction
8999     if (isBankselect) {
9000       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9001       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9002       if (mod) {
9003         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9004           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9005           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9006           pic16_unlinkpCode (pc);
9007           banksels++;
9008         }
9009       } else {
9010         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9011         banksels++;
9012       }
9013     } // if
9014
9015     if (!isBankselect && invalidatesBSR(pc)) {
9016       // check if this instruction invalidates the pseudoBSR
9017       pseudoBSR = UNKNOWN_BANK;
9018       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9019     } // if
9020
9021     prevBSR = pseudoBSR;
9022     pc = pc_next;
9023   } // while
9024
9025   return banksels;
9026 }
9027
9028 /*------------------------------------------------------------------------------------*/
9029 /* assignToSameBank - returns 0 on success or an error code                           */
9030 /*  1 - common bank would be too large                                                */
9031 /*  2 - assignment to fixed (absolute) bank not performed                             */
9032 /*                                                                                    */
9033 /* This functions assumes that unsplittable operands are already assigned to the same */
9034 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9035 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9036 /* TODO: Symbols with an abslute address must be handled specially!                   */
9037 /*------------------------------------------------------------------------------------*/
9038 int assignToSameBank (int bank0, int bank1, int doAbs)
9039 {
9040   int eff0, eff1, dummy;
9041   pseudoBank *pbank0, *pbank1;
9042   hashtItem *hitem;
9043
9044   eff0 = getEffectiveBank (bank0);
9045   eff1 = getEffectiveBank (bank1);
9046
9047   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9048
9049   // nothing to do if already same bank
9050   if (eff0 == eff1) return 0;
9051
9052   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9053     return 2;
9054
9055   // ensure eff0 < eff1
9056   if (eff0 > eff1) {
9057     // swap eff0 and eff1
9058     dummy = eff0;
9059     eff0 = eff1;
9060     eff1 = dummy;
9061     dummy = bank0;
9062     bank0 = bank1;
9063     bank1 = dummy;
9064   } // if
9065
9066   // now assign bank eff1 to bank eff0
9067   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9068   if (!pbank0) {
9069     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9070     pbank0->bank = eff0;
9071     pbank0->size = 1;
9072     pbank0->ref = 1;
9073     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9074   } // if
9075
9076   pbank1 = NULL;
9077   hitem = hTabSearch (coerce, eff1 % coerce->size);
9078   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9079     hitem = hitem->next;
9080
9081   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9082
9083 #if 0
9084   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9085            pbank0->bank, pbank0->size,
9086            getSymFromBank (eff0), getSymFromBank (eff1));
9087 #endif
9088
9089   if (pbank1) {
9090     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9091 #if 0
9092       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9093                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9094                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9095                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9096 #endif
9097       return 1;
9098     } // if
9099     pbank0->size += pbank1->size;
9100     pbank1->ref--;
9101     if (pbank1->ref == 0) Safe_free (pbank1);
9102   } else {
9103     pbank0->size++;
9104   } // if
9105
9106   if (hitem)
9107     hitem->item = pbank0;
9108   else  
9109     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9110   pbank0->ref++;
9111
9112   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9113
9114   return 0;
9115 }
9116
9117 /*----------------------------------------------------------------*/
9118 /* mergeGraphNodes - combines two nodes into one and modifies all */
9119 /*                   edges to and from the nodes accordingly      */
9120 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9121 /* then also (B,A) must be an edge (possibly with weight 0).      */
9122 /*----------------------------------------------------------------*/
9123 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9124 {
9125   GraphEdge *edge, *backedge, *nextedge;
9126   GraphNode *node;
9127   int backweight;
9128
9129   assert (node1 && node2);
9130   assert (node1 != node2);
9131   
9132   // add all edges starting at node2 to node1
9133   edge = node2->edge;
9134   while (edge) {
9135     nextedge = edge->next;
9136     node = edge->node;
9137     backedge = getGEdge (node, node2);
9138     if (backedge)
9139       backweight = backedge->weight;
9140     else
9141       backweight = 0;
9142     // insert edges (node1,node) and (node,node1)
9143     addGEdge2 (node1, node, edge->weight, backweight);
9144     // remove edges (node, node2) and (node2, node)
9145     remGEdge (node2, node);
9146     remGEdge (node, node2);
9147     edge = nextedge;
9148   } // while
9149   
9150   // now node2 should not be referenced by any other GraphNode...
9151   //remGNode (adj, node2->data, node2->hash);
9152 }
9153
9154 /*----------------------------------------------------------------*/
9155 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9156 /*----------------------------------------------------------------*/
9157 void showGraph (Graph *g)
9158 {
9159   GraphNode *node;
9160   GraphEdge *edge;
9161   pseudoBankNr bankNr;
9162   pseudoBank *pbank;
9163   unsigned int size;
9164
9165   node = g->node;
9166   while (node) {
9167     edge = node->edge;
9168     bankNr = getEffectiveBank (node->hash);
9169     assert (bankNr >= 0);
9170     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9171     if (pbank) {
9172       bankNr = pbank->bank;
9173       size = pbank->size;
9174     } else {
9175       size = 1;
9176     }
9177     
9178     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9179
9180     while (edge) {
9181       if (edge->weight > 0)
9182         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9183       edge = edge->next;
9184     } // while (edge)
9185     node = node->next;
9186   } // while (node)
9187 }
9188
9189 /*---------------------------------------------------------------*/
9190 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9191 /*---------------------------------------------------------------*/
9192 void pic16_OptimizeBanksel ()
9193 {
9194   GraphNode *node, *node1, *node1next;
9195
9196 #if 0
9197   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9198   GraphEdge *edge, *backedge;
9199   GraphEdge *max;
9200   int maxWeight, weight, mergeMore, absMaxWeight;
9201   pseudoBankNr curr0, curr1;
9202 #endif
9203   pseudoBank *pbank;
9204   pseudoBankNr bankNr;
9205   char *base_symbol0, *base_symbol1;
9206   int len0, len1;
9207   pBlock *pb;
9208   set *set;
9209   regs *reg;
9210   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9211
9212   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9213
9214   if (!the_pFile || !the_pFile->pbHead) return;
9215
9216   adj = newGraph (NULL);
9217   sym2bank = newHashTable ( 255 );
9218   bank2sym = newHashTable ( 255 );
9219   coerce = newHashTable ( 255 );
9220
9221   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9222   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9223     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9224   } // for pb
9225
9226 #if 1
9227   // assign symbols with absolute addresses to their respective bank nrs
9228   set = pic16_fix_udata;
9229   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9230     bankNr = reg->address >> 8;
9231     node = getOrAddGNode (adj, NULL, bankNr);
9232     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9233     assignToSameBank (node->hash, bankNr, 1);
9234     
9235     assert (bankNr >= 0);
9236     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9237     if (!pbank) {
9238       pbank = Safe_calloc (1, sizeof (pseudoBank));
9239       pbank->bank = reg->address >> 8; //FIXED_BANK;
9240       pbank->size = 1;
9241       pbank->ref = 1;
9242       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9243     } else {
9244       assert (pbank->bank == (reg->address >> 8));
9245       pbank->bank = reg->address >> 8; //FIXED_BANK;
9246     }
9247     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9248   } // for reg
9249 #endif
9250
9251 #if 1
9252   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9253   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9254   node = adj->node;
9255   while (node) {
9256     if (node->hash < 0) { node = node->next; continue; }
9257     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9258     node1 = node->next;
9259     while (node1) {
9260       if (node1->hash < 0) { node1 = node1->next; continue; }
9261       node1next = node1->next;
9262       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9263       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9264         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9265         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9266         if (assignToSameBank (node->hash, node1->hash, 0)) {
9267           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9268           assert (0 && "Could not assign a symbol to a bank!");
9269         }
9270         mergeGraphNodes (node, node1);
9271         /*
9272         if (node->hash < node1->hash)
9273           mergeGraphNodes (node, node1);
9274         else
9275           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9276         */
9277       } // if
9278       node1 = node1next;
9279     } // while (node1)
9280     node = node->next;
9281   } // while (node)
9282 #endif
9283
9284 #if 0
9285   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9286   // assign tightly coupled operands to the same (pseudo) bank
9287   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9288   mergeMore = 1;
9289   absMaxWeight = 0;
9290   while (mergeMore) {
9291     node = adj->node;
9292     max = NULL;
9293     maxWeight = 0;
9294     while (node) {
9295       curr0 = getEffectiveBank (node->hash);
9296       if (curr0 < 0) { node = node->next; continue; }
9297       edge = node->edge;
9298       while (edge) {
9299         assert (edge->src == node);
9300         backedge = getGEdge (edge->node, edge->src);
9301         weight = edge->weight + (backedge ? backedge->weight : 0);
9302         curr1 = getEffectiveBank (edge->node->hash);
9303         if (curr1 < 0) { edge = edge->next; continue; }
9304
9305         // merging is only useful if the items are not assigned to the same bank already...
9306         if (curr0 != curr1 && weight > maxWeight) {
9307           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9308           maxWeight = weight;
9309           max = edge;
9310         } // if
9311         edge = edge->next;
9312       } // while
9313       node = node->next;
9314     } // while
9315     
9316     if (maxWeight > 0) {
9317 #if 0
9318       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9319                max->src->hash, getSymFromBank (max->src->hash),
9320                max->node->hash, getSymFromBank (max->node->hash));
9321 #endif
9322
9323       node = getGNode (adj, max->src->data, max->src->hash);
9324       node1 = getGNode (adj, max->node->data, max->node->hash);
9325
9326       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9327         if (max->src->hash < max->node->hash)
9328           mergeGraphNodes (node, node1);
9329         else
9330           mergeGraphNodes (node1, node);
9331       } else {
9332         remGEdge (node, node1);
9333         remGEdge (node1, node);
9334         //mergeMore = 0;
9335       }
9336
9337     } else {
9338       mergeMore = 0;
9339     }
9340   } // while
9341 #endif
9342
9343 #if 1  
9344   // remove redundant BANKSELs
9345   //fprintf (stderr, "removing redundant BANKSELs\n");
9346   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9347     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9348   } // for pb
9349 #endif
9350
9351 #if 0
9352   fprintf (stderr, "display graph\n");
9353   showGraph ();
9354 #endif
9355
9356   deleteGraph (adj);
9357   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9358 }
9359
9360 /*** END of stuff belonging to the BANKSEL optimization ***/
9361
9362
9363
9364 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9365
9366 typedef unsigned int symbol_t;
9367 typedef unsigned int valnum_t;
9368 //typedef unsigned int hash_t;
9369
9370 #ifndef INT_TO_PTR
9371 #define INT_TO_PTR(x) (((char *) 0) + (x))
9372 #endif
9373
9374 #ifndef PTR_TO_INT
9375 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9376 #endif
9377
9378 /* statistics */
9379 static unsigned int pic16_df_removed_pcodes = 0;
9380 static unsigned int pic16_df_saved_bytes = 0;
9381 static unsigned int df_findall_sameflow = 0;
9382 static unsigned int df_findall_otherflow = 0;
9383 static unsigned int df_findall_in_vals = 0;
9384
9385 static void pic16_df_stats () {
9386   return;
9387   if (pic16_debug_verbose || pic16_pcode_verbose) {
9388     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9389     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9390     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9391   }
9392 }
9393
9394 /* Remove a pCode iff possible:
9395  * - previous pCode is no SKIP
9396  * - pc has no label
9397  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9398 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9399   pCode *pcprev, *pcnext;
9400   char buf[256], *total=NULL;
9401   int len;
9402   
9403   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9404
9405   pcprev = pic16_findPrevInstruction (pc->prev);
9406   pcnext = pic16_findNextInstruction (pc->next);
9407   
9408   /* if previous instruction is a skip -- do not remove */
9409   if (pcprev && isPCI_SKIP(pcprev)) return 0;
9410
9411   /* move labels to next instruction (if possible) */
9412   if (PCI(pc)->label && !pcnext) return 0;
9413
9414   if (PCI(pc)->label) {
9415     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9416     //pc->print (stderr, pc);
9417     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9418     PCI(pc)->label = NULL;
9419   }
9420   
9421   /* update statistics */
9422   pic16_df_removed_pcodes++;
9423   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9424   
9425   /* remove the pCode */
9426   pic16_pCode2str (buf, 256, pc);
9427   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9428   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9429     len = strlen (buf) + strlen (comment) + 10;
9430     total = (char *) Safe_malloc (len);
9431     snprintf (total, len, "%s: %s", comment, buf);
9432     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9433     Safe_free (total);
9434   }
9435
9436   /* actually unlink it from the pBlock -- also remove from to/from lists */
9437   pic16_pCodeUnlink (pc);
9438
9439   /* remove the pCode -- release registers */
9440   pc->destruct (pc);
9441
9442   /* report success */
9443   return 1;
9444 }
9445
9446
9447 /* ======================================================================== */
9448 /* === SYMBOL HANDLING ==================================================== */
9449 /* ======================================================================== */
9450
9451 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9452 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9453 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9454
9455 /** Calculate a hash for a given string.
9456  * If len == 0 the string is assumed to be NUL terminated. */
9457 static hash_t symbolHash (const char *str, unsigned int len) {
9458   hash_t hash = 0;
9459   if (!len) {
9460     while (*str) {
9461       hash = (hash << 2) ^ *str;
9462       str++;
9463     } // while
9464   } else {
9465     while (len--) {
9466       hash = (hash << 2) ^ *str;
9467       str++;
9468     }
9469   }
9470   return hash;
9471 }
9472
9473 /** Return 1 iff strings v1 and v2 are identical. */
9474 static int symcmp (const void *v1, const void *v2) {
9475   return !strcmp ((const char *) v1, (const char *) v2);
9476 }
9477
9478 /** Return 1 iff pointers v1 and v2 are identical. */
9479 static int ptrcmp (const void *v1, const void *v2) {
9480   return (v1 == v2);
9481 }
9482
9483 enum {  SPO_WREG=0x1000,
9484         SPO_STATUS,
9485         SPO_PRODL,
9486         SPO_PRODH,
9487         SPO_INDF0,
9488         SPO_POSTDEC0,
9489         SPO_POSTINC0,
9490         SPO_PREINC0,
9491         SPO_PLUSW0,
9492         SPO_INDF1,
9493         SPO_POSTDEC1,
9494         SPO_POSTINC1,
9495         SPO_PREINC1,
9496         SPO_PLUSW1,
9497         SPO_INDF2,
9498         SPO_POSTDEC2,
9499         SPO_POSTINC2,
9500         SPO_PREINC2,
9501         SPO_PLUSW2,
9502         SPO_STKPTR,
9503         SPO_TOSL,
9504         SPO_TOSH,
9505         SPO_TOSU,
9506         SPO_BSR,
9507         SPO_FSR0L,
9508         SPO_FSR0H,
9509         SPO_FSR1L,
9510         SPO_FSR1H,
9511         SPO_FSR2L,
9512         SPO_FSR2H,
9513         SPO_PCL,
9514         SPO_PCLATH,
9515         SPO_PCLATU,
9516         SPO_TABLAT,
9517         SPO_TBLPTRL,
9518         SPO_TBLPTRH,
9519         SPO_TBLPTRU,
9520         SPO_LAST
9521 };
9522
9523 /* Return the unique symbol_t for the given string. */
9524 static symbol_t symFromStr (const char *str) {
9525   hash_t hash;
9526   char *res;
9527   symbol_t sym;
9528
9529   if (!map_symToStr) {
9530     int i;
9531     map_strToSym = newHashTable (128);
9532     map_symToStr = newHashTable (128);
9533
9534     struct { char *name; symbol_t sym; } predefsyms[] = {
9535         {"WREG", SPO_WREG},
9536         {"STATUS", SPO_STATUS},
9537         {"PRODL", SPO_PRODL},
9538         {"PRODH", SPO_PRODH},
9539         {"INDF0", SPO_INDF0},
9540         {"POSTDEC0", SPO_POSTDEC0},
9541         {"POSTINC0", SPO_POSTINC0},
9542         {"PREINC0", SPO_PREINC0},
9543         {"PLUSW0", SPO_PLUSW0},
9544         {"INDF1", SPO_INDF1},
9545         {"POSTDEC1", SPO_POSTDEC1},
9546         {"POSTINC1", SPO_POSTINC1},
9547         {"PREINC1", SPO_PREINC1},
9548         {"PLUSW1", SPO_PLUSW1},
9549         {"INDF2", SPO_INDF2},
9550         {"POSTDEC2", SPO_POSTDEC2},
9551         {"POSTINC2", SPO_POSTINC2},
9552         {"PREINC2", SPO_PREINC2},
9553         {"PLUSW2", SPO_PLUSW2},
9554         {"STKPTR", SPO_STKPTR},
9555         {"TOSL", SPO_TOSL},
9556         {"TOSH", SPO_TOSH},
9557         {"TOSU", SPO_TOSU},
9558         {"BSR", SPO_BSR},
9559         {"FSR0L", SPO_FSR0L},
9560         {"FSR0H", SPO_FSR0H},
9561         {"FSR1L", SPO_FSR1L},
9562         {"FSR1H", SPO_FSR1H},
9563         {"FSR2L", SPO_FSR2L},
9564         {"FSR2H", SPO_FSR2H},
9565         {"PCL", SPO_PCL},
9566         {"PCLATH", SPO_PCLATH},
9567         {"PCLATU", SPO_PCLATU},
9568         {"TABLAT", SPO_TABLAT},
9569         {"TBLPTRL", SPO_TBLPTRL},
9570         {"TBLPTRH", SPO_TBLPTRH},
9571         {"TBLPTRU", SPO_TBLPTRU},
9572         {NULL, 0}
9573     };
9574
9575     for (i=0; predefsyms[i].name; i++) {
9576       char *name;
9577
9578       /* enter new symbol */
9579       sym = predefsyms[i].sym;
9580       name = predefsyms[i].name;
9581       res = Safe_strdup (name);
9582       hash = symbolHash (name, 0);
9583
9584       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9585       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9586     } // for i
9587   }
9588
9589   hash = symbolHash (str, 0) % map_strToSym->size;
9590   
9591   /* find symbol in table */
9592   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9593   if (sym) {
9594     //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9595     return sym;
9596   }
9597
9598   /* enter new symbol */
9599   sym = nextSymbol++;
9600   res = Safe_strdup (str);
9601
9602   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9603   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9604
9605   //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9606   
9607   return sym;
9608 }
9609
9610 #if 1
9611 static const char *strFromSym (symbol_t sym) {
9612   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9613 }
9614 #endif
9615
9616 /* ======================================================================== */
9617 /* === DEFINITION MAP HANDLING ============================================ */
9618 /* ======================================================================== */
9619
9620 /* A defmap provides information about which symbol is defined by which pCode.
9621  * The most recent definitions are prepended to the list, so that the most
9622  * recent definition can be found by forward scanning the list.
9623  * pc2: MOVFF r0x00, r0x01
9624  * pc1: INCF r0x01
9625  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9626  *
9627  * We attach one defmap to each flow object, and each pCode will occur at
9628  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9629  * used to find definitions for a pCode in its own defmap that precede pCode.
9630  */
9631
9632 typedef struct defmap_s {
9633   symbol_t sym;                 /** symbol this item refers to */
9634   union {
9635     struct {
9636       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9637       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9638       int isRead:1;             /** sym/mask is read */
9639       int isWrite:1;            /** sym/mask is written */
9640     } access;
9641     int accessmethod;
9642   };
9643   pCode *pc;                    /** pCode this symbol is refrenced at */
9644   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9645   valnum_t val;                 /** new unique number for this value (if isWrite) */
9646   struct defmap_s *prev, *next; /** link to previous an next definition */
9647 } defmap_t;
9648
9649 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9650 static int defmap_free_count = 0;               /** number of released defmap items */
9651
9652 /* Returns a defmap_t with the specified data; this will be the new list head.
9653  * next - pointer to the current list head */
9654 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9655   defmap_t *map;
9656   
9657   if (defmap_free) {
9658     map = defmap_free;
9659     defmap_free = map->next;
9660     --defmap_free_count;
9661   } else {
9662     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9663   }
9664   map->sym = sym;
9665   map->access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9666   map->access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9667   map->access.isRead = (isRead != 0);
9668   map->access.isWrite = (isWrite != 0);
9669   map->pc = pc;
9670   map->in_val = 0;
9671   map->val = (isWrite ? val : 0);
9672   map->prev = NULL;
9673   map->next = next;
9674   if (next) next->prev = map;
9675   
9676   return map;
9677 }
9678
9679 /* Returns a copy of the single defmap item. */
9680 static defmap_t *copyDefmap (defmap_t *map) {
9681   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9682   memcpy (res, map, sizeof (defmap_t));
9683   res->next = NULL;
9684   res->prev = NULL;
9685   return res;
9686 }
9687
9688 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9689  * item is copied before insertion into chain and therefore left untouched.
9690  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9691 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9692   defmap_t *dummy;
9693   dummy = *head;
9694   while (dummy && (dummy->sym != item->sym
9695                           || dummy->pc != item->pc
9696                           || dummy->accessmethod != item->accessmethod
9697                           || dummy->val != item->val
9698                           || dummy->in_val != item->in_val)) {
9699     dummy = dummy->next;
9700   } // while
9701
9702   /* item already present? */
9703   if (dummy) return 0;
9704   
9705   /* otherwise: insert copy of item */
9706   dummy = copyDefmap (item);
9707   dummy->next = *head;
9708   if (*head) (*head)->prev = dummy;
9709   *head = dummy;
9710
9711   return 1;
9712 }
9713
9714 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9715 static void deleteDefmap (defmap_t *map) {
9716   if (!map) return;
9717   
9718   /* unlink from chain -- fails for the first item (head is not updated!) */
9719   if (map->next) map->next->prev = map->prev;
9720   if (map->prev) map->prev->next = map->next;
9721
9722   /* clear map */
9723   memset (map, 0, sizeof (defmap_t));
9724
9725   /* save for future use */
9726   map->next = defmap_free;
9727   defmap_free = map;
9728   ++defmap_free_count;
9729 }
9730
9731 /* Release all defmaps referenced from map. */
9732 static void deleteDefmapChain (defmap_t **_map) {
9733   defmap_t *map, *next;
9734
9735   if (!_map) return;
9736
9737   map = *_map;
9738   
9739   /* find list head */
9740   while (map && map->prev) map = map->prev;
9741
9742   /* delete all items */
9743   while (map) {
9744     next = map->next;
9745     deleteDefmap (map);
9746     map = next;
9747   } // while
9748
9749   *_map = NULL;
9750 }
9751
9752 /* Free all defmap items. */
9753 static void freeDefmap (defmap_t **_map) {
9754   defmap_t *next;
9755   defmap_t *map;
9756
9757   if (!_map) return;
9758
9759   map = (*_map);
9760   
9761   /* find list head */
9762   while (map->prev) map = map->prev;
9763
9764   /* release all items */
9765   while (map) {
9766     next = map->next;
9767     Safe_free (map);
9768     map = next;
9769   }
9770
9771   (*_map) = NULL;
9772 }
9773
9774 /* Returns the most recent definition for the given symbol preceeding pc.
9775  * If no definition is found, NULL is returned. 
9776  * If pc == NULL the whole list is scanned. */
9777 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9778   defmap_t *curr = map;
9779
9780   if (pc) {
9781     /* skip all definitions up to pc */
9782     while (curr && (curr->pc != pc)) curr = curr->next;
9783
9784     /* pc not in the list -- scan the whole list for definitions */
9785     if (!curr) {
9786       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9787       curr = map;
9788     } else {
9789       /* skip all definitions performed by pc */
9790       while (curr && (curr->pc == pc)) curr = curr->next;
9791     }
9792   } // if (pc)
9793
9794   /* find definition for sym */
9795   while (curr && (!curr->access.isWrite || (curr->sym != sym))) {
9796     curr = curr->next;
9797   }
9798
9799   return curr;
9800 }
9801
9802 #if 0
9803 /* Returns the first use (read) of the given symbol AFTER pc.
9804  * If no such use is found, NULL is returned.
9805  * If pc == NULL the whole list is scanned. */
9806 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9807   defmap_t *curr = map, *prev = NULL;
9808   
9809   if (pc) {
9810     /* skip all definitions up to pc */
9811     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9812
9813     /* pc not in the list -- scan the whole list for definitions */
9814     if (!curr) {
9815       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9816       curr = prev;
9817     }
9818   } else {
9819     /* find end of list */
9820     while (curr && curr->next) curr = curr->next;
9821   } // if (pc)
9822
9823   /* find use of sym (scan list backwards) */
9824   while (curr && (!curr->access.isRead || (curr->sym != sym))) curr = curr->prev;
9825
9826   return curr;
9827 }
9828 #endif
9829
9830 /* Return the defmap entry for sym AT pc. 
9831  * If none is found, NULL is returned.
9832  * If more than one entry is found an assertion is triggered. */
9833 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9834   defmap_t *res = NULL;
9835
9836   /* find entries for pc */
9837   while (map && map->pc != pc) map = map->next;
9838
9839   /* find first entry for sym @ pc */
9840   while (map && map->pc == pc && map->sym != sym) map = map->next;
9841
9842   /* no entry found */
9843   if (!map) return NULL;
9844
9845   /* check for more entries */
9846   res = map;
9847   map = map->next;
9848   while (map && map->pc == pc) {
9849     /* more than one entry for sym @ pc found? */
9850     assert (map->sym != sym);
9851     map = map->next;
9852   }
9853
9854   /* return single entry for sym @ pc */
9855   return res;
9856 }
9857
9858 /* Modifies the definition of sym at pCode to newval.
9859  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9860  */
9861 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9862   defmap_t *m  = map;
9863
9864   /* find definitions of pc */
9865   while (m && m->pc != pc) m = m->next;
9866
9867   /* find definition of sym at pc */
9868   while (m && m->pc == pc && (!m->access.isWrite || (m->sym != sym))) m = m->next;
9869   
9870   /* no definition found */
9871   if (!m) return 1;
9872
9873   /* redefine */
9874   m->val = newval;
9875
9876   /* update following uses of sym */
9877   while (m && m->pc == pc) m = m->prev;
9878   while (m) {
9879     if (m->sym == sym) {
9880       m->in_val = newval;
9881       if (m->access.isWrite) m = NULL;
9882     } // if
9883     if (m) m = m->prev;
9884   } // while
9885   
9886   return 0;
9887 }
9888
9889 /* ======================================================================== */
9890 /* === STACK ROUTINES ===================================================== */
9891 /* ======================================================================== */
9892
9893 typedef struct stack_s {
9894   void *data;
9895   struct stack_s *next;
9896 } stackitem_t;
9897
9898 typedef stackitem_t *stack_t;
9899 static stackitem_t *free_stackitems = NULL;
9900
9901 /* Create a stack with one item. */
9902 static stack_t *newStack () {
9903   stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9904   *s = NULL;
9905   return s;
9906 }
9907
9908 /* Remove a stack -- its items are only marked free. */
9909 static void deleteStack (stack_t *s) {
9910   stackitem_t *i;
9911
9912   while (*s) {
9913     i = *s;
9914     *s = (*s)->next;
9915     i->next = free_stackitems;
9916     free_stackitems = i;
9917   } // while
9918   Safe_free (s);
9919 }
9920
9921 /* Release all stackitems. */
9922 static void releaseStack () {
9923   stackitem_t *i;
9924   
9925   while (free_stackitems) {
9926     i = free_stackitems->next;
9927     Safe_free(free_stackitems);
9928     free_stackitems = i;
9929   } // while
9930 }
9931
9932 static void stackPush (stack_t *stack, void *data) {
9933   stackitem_t *i;
9934   
9935   if (free_stackitems) {
9936     i = free_stackitems;
9937     free_stackitems = free_stackitems->next;
9938   } else {
9939     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9940   }
9941   i->data = data;
9942   i->next = *stack;
9943   *stack = i;
9944 }
9945
9946 static void *stackPop (stack_t *stack) {
9947   void *data;
9948   stackitem_t *i;
9949   
9950   if (stack && *stack) {
9951     data = (*stack)->data;
9952     i = *stack;
9953     *stack = (*stack)->next;
9954     i->next = free_stackitems;
9955     free_stackitems = i;
9956     return data;
9957   } else {
9958     return NULL;
9959   }
9960 }
9961
9962 #if 0
9963 static int stackContains (stack_t *s, void *data) {
9964   stackitem_t *i;
9965   if (!s) return 0;
9966   i = *s;
9967   while (i) {
9968     if (i->data == data) return 1;
9969     i = i->next;
9970   } // while
9971
9972   /* not found */
9973   return 0;
9974 }
9975 #endif
9976
9977 static int stackIsEmpty (stack_t *s) {
9978   return (*s == NULL);
9979 }
9980
9981
9982 typedef struct {
9983   pCodeFlow *flow;
9984   defmap_t *lastdef;
9985 } state_t;
9986
9987 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9988   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9989   s->flow = flow;
9990   s->lastdef = lastdef;
9991   return s;
9992 }
9993
9994 static void deleteState (state_t *s) {
9995   Safe_free (s);
9996 }
9997
9998 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
9999   stackitem_t *i;
10000
10001   /* scan working list for state */
10002   if (todo) {
10003     i = *todo;
10004     while (i) {
10005       /* is i == state? -- state not new */
10006       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10007       i = i->next;
10008     } // while
10009   }
10010
10011   if (done) {
10012     i = *done;
10013     while (i) {
10014       /* is i == state? -- state not new */
10015       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10016       i = i->next;
10017     } // while
10018   }
10019
10020   /* not found -- state is new */
10021   return 1;
10022 }
10023
10024 static inline valnum_t newValnum ();
10025
10026 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10027   pCode *pc;
10028
10029   if (!pb) return "<unknown function>";
10030
10031   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10032   if (pc && isPCF(pc)) return PCF(pc)->fname;
10033   else return "<unknown function>";
10034 }
10035
10036 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10037   defmap_t *map;
10038   pCodeFlow *pcfl;
10039
10040   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10041
10042   /* find initial value (assigning pc == NULL) */
10043   map = PCFL(pcfl)->in_vals;
10044   while (map && map->sym != sym) map = map->next;
10045
10046   /* initial value already present? */
10047   if (map) {
10048     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10049     return map;
10050   }
10051
10052   /* create a new initial value */
10053   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10054   PCFL(pcfl)->in_vals = map;
10055   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10056   return map;
10057
10058 #if 0
10059   /* insert map as last item in pcfl's defmap */
10060   if (!prev) prev = PCFL(pcfl)->defmap;
10061   if (!prev) {
10062     PCFL(pcfl)->defmap = map;
10063   } else {
10064     while (prev->next) prev = prev->next;
10065     prev->next = map;
10066     map->prev = prev;
10067   }
10068
10069   return map;
10070 #endif
10071 }
10072
10073 /* Find all reaching definitions for sym at pc. 
10074  * A new (!) list of definitions is returned.
10075  * Returns the number of reaching definitions found.
10076  * The defining defmap entries are returned in *chain.
10077  */
10078 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10079   defmap_t *map;
10080   defmap_t *res;
10081
10082   pCodeFlow *curr;
10083   pCodeFlowLink *succ;
10084   state_t *state;
10085   stack_t *todo;        /** stack of state_t */
10086   stack_t *done;        /** stack of state_t */
10087
10088   int firstState, n_defs;
10089   
10090   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10091   assert (chain);
10092
10093   /* initialize return list */
10094   *chain = NULL;
10095
10096   /* wildcard symbol? */
10097   if (!sym) return 0;
10098   
10099   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10100   
10101   map = PCI(pc)->pcflow->defmap;
10102
10103   res = defmapFindDef (map, sym, pc);
10104   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10105
10106 #define USE_PRECALCED_INVALS 1
10107 #if USE_PRECALCED_INVALS
10108   if (!res && PCI(pc)->pcflow->in_vals) {
10109     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10110     if (res) {
10111       //fprintf  (stderr, "found def in init values\n");
10112       df_findall_in_vals++;
10113     }
10114   }
10115 #endif
10116
10117   if (res) {
10118     // found a single definition (in pc's flow)
10119     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10120     defmapAddCopyIfNew (chain, res);
10121     df_findall_sameflow++;
10122     return 1;
10123   }
10124
10125 #if USE_PRECALCED_INVALS
10126   else {
10127     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10128     return 1;
10129   }
10130
10131 #endif
10132   
10133 #define FORWARD_FLOW_ANALYSIS 1
10134 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10135   /* no definition found in pc's flow preceeding pc */
10136   todo = newStack ();
10137   done = newStack ();
10138   n_defs = 0; firstState = 1;
10139   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10140
10141   while (!stackIsEmpty (todo)) {
10142     state = (state_t *) stackPop (todo);
10143     stackPush (done, state);
10144     curr = state->flow;
10145     res = state->lastdef;
10146     //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);
10147
10148     /* there are no definitions BEFORE pc in pc's flow (see above) */
10149     if (curr == PCI(pc)->pcflow) {
10150       if (!res) {
10151         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10152         res = pic16_pBlockAddInval (pc->pb, sym);
10153         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10154         res = NULL;
10155       } else {
10156         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10157         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10158       }
10159     }
10160
10161     /* save last definition of sym in this flow as initial def in successors */
10162     res = defmapFindDef (curr->defmap, sym, NULL);
10163     if (!res) res = state->lastdef;
10164     
10165     /* add successors to working list */
10166     state = newState (NULL, NULL);
10167     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10168     while (succ) {
10169       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10170       state->flow = succ->pcflow;
10171       state->lastdef = res;
10172       if (stateIsNew (state, todo, done)) {
10173         stackPush (todo, state);
10174         state = newState (NULL, NULL);
10175       } // if
10176       succ = (pCodeFlowLink *) setNextItem (curr->to);
10177     } // while
10178     deleteState (state);
10179   } // while
10180
10181 #else // !FORWARD_FLOW_ANALYSIS 
10182
10183   /* no definition found in pc's flow preceeding pc */
10184   todo = newStack ();
10185   done = newStack ();
10186   n_defs = 0; firstState = 1;
10187   stackPush (todo, newState (PCI(pc)->pcflow, res));
10188
10189   while (!stackIsEmpty (todo)) {
10190     state = (state_t *) stackPop (todo);
10191     curr = state->flow;
10192
10193     if (firstState) {
10194       firstState = 0;
10195       /* only check predecessor flows */
10196     } else {
10197       /* get (last) definition of sym in this flow */
10198       res = defmapFindDef (curr->defmap, sym, NULL);
10199     }
10200
10201     if (res) {
10202       /* definition found */
10203       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10204       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10205     } else {
10206       /* no definition found -- check predecessor flows */
10207       state = newState (NULL, NULL);
10208       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10209
10210       /* if no flow predecessor available -- sym might be uninitialized */
10211       if (!succ) {
10212         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10213         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10214         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10215         deleteDefmap (res); res = NULL;
10216       }
10217       
10218       while (succ) {
10219         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10220         state->flow = succ->pcflow;
10221         state->lastdef = res;
10222         if (stateIsNew (state, todo, done)) {
10223           stackPush (todo, state);
10224           state = newState (NULL, NULL);
10225         } // if
10226         succ = (pCodeFlowLink *) setNextItem (curr->from);
10227       } // while
10228       deleteState (state);
10229     }
10230   } // while
10231
10232 #endif
10233
10234   /* clean up done stack */
10235   while (!stackIsEmpty(done)) {
10236     deleteState ((state_t *) stackPop (done));
10237   } // while
10238   deleteStack (done);
10239
10240   /* return number of items in result set */
10241   if (n_defs == 0) {
10242     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10243   } else if (n_defs == 1) {
10244     assert (*chain);
10245     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10246   } else if (n_defs > 0) {
10247     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10248 #if 0
10249     res = *chain;
10250     while (res) {
10251       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10252       res = res->next;
10253     } // while
10254 #endif
10255   }
10256   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10257   df_findall_otherflow++;
10258   return n_defs;
10259 }
10260
10261 /* ======================================================================== */
10262 /* === VALUE NUMBER HANDLING ============================================== */
10263 /* ======================================================================== */
10264
10265 static valnum_t nextValnum = 0x1000;
10266 static hTab *map_symToValnum = NULL;
10267
10268 /** Return a new value number. */
10269 static inline valnum_t newValnum () {
10270   return (nextValnum += 4);
10271 }
10272
10273 static valnum_t valnumFromStr (const char *str) {
10274   symbol_t sym;
10275   valnum_t val;
10276   void *res;
10277   
10278   sym = symFromStr (str);
10279
10280   if (!map_symToValnum) {
10281     map_symToValnum = newHashTable (128);
10282   } // if
10283
10284   /* literal already known? */
10285   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10286
10287   /* return existing valnum */
10288   if (res) return (valnum_t) PTR_TO_INT(res);
10289   
10290   /* create new valnum */
10291   val = newValnum();
10292   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10293   return val;
10294 }
10295
10296 /* Create a valnum for a literal. */
10297 static valnum_t valnumFromLit (unsigned int lit) {
10298   return ((valnum_t) 0x100 + (lit & 0x0FF));
10299 }
10300
10301 /* Return the (positive) literal value represented by val
10302  * or -1 iff val is no known literal's valnum. */
10303 static int litFromValnum (valnum_t val) {
10304   if (val >= 0x100 && val < 0x200) {
10305     /* valnum is a (known) literal */
10306     return val & 0x00FF;
10307   } else {
10308     /* valnum is not a known literal */
10309     return -1;
10310   }
10311 }
10312
10313 #if 0
10314 /* Sanity check - all flows in a block must be reachable from initial flow. */
10315 static int verifyAllFlowsReachable (pBlock *pb) {
10316   set *reached;
10317   set *flowInBlock;
10318   set *checked;
10319   pCode *pc;
10320   pCodeFlow *pcfl;
10321   pCodeFlowLink *succ;
10322   int res;
10323
10324   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10325
10326   reached = NULL;
10327   flowInBlock = NULL;
10328   checked = NULL;
10329   /* mark initial flow as reached (and "not needs to be reached") */
10330   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10331   assert (pc);
10332   addSetHead (&reached, pc);
10333   addSetHead (&checked, pc);
10334   
10335   /* mark all further flows in block as "need to be reached" */
10336   pc = pb->pcHead;
10337   do {
10338     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10339     pc = pic16_findNextInstruction (pc->next);
10340   } while (pc);
10341
10342   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10343     /* mark as reached and "not need to be reached" */
10344     deleteSetItem (&reached, pcfl);
10345     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10346     
10347     /* flow is no longer considered unreachable */
10348     deleteSetItem (&flowInBlock, pcfl);
10349
10350     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10351       if (!isinSet (checked, succ->pcflow)) {
10352         /* flow has never been reached before */
10353         addSetHead (&reached, succ->pcflow);
10354         addSetHead (&checked, succ->pcflow);
10355       } // if
10356     } // for succ
10357   } // while
10358
10359   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10360
10361   /* by now every flow should have been reached
10362    * --> flowInBlock should be empty */
10363   res = (flowInBlock == NULL);
10364
10365 #if 1
10366   if (flowInBlock) {
10367           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10368     while (flowInBlock) {
10369       pcfl = indexSet (flowInBlock, 0);
10370       fprintf (stderr, "not reached: flow %p\n", pcfl);
10371       deleteSetItem (&flowInBlock, pcfl);
10372     } // while
10373   }
10374 #endif
10375   
10376   /* clean up */
10377   deleteSet (&reached);
10378   deleteSet (&flowInBlock);
10379   deleteSet (&checked);
10380   
10381   /* if we reached every flow, succ is NULL by now... */
10382   //assert (res); // will fire on unreachable code...
10383   return (res);
10384 }
10385 #endif
10386
10387 /* Checks a flow for accesses to sym AFTER pc.
10388  * 
10389  * Returns -1 if the symbol is read in this flow (before redefinition),
10390  * returns 0 if the symbol is redefined in this flow or
10391  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10392  */
10393 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10394   defmap_t *map, *mappc;
10395
10396   /* find pc or start of definitions */
10397   map = pcfl->defmap;
10398   while (map && (map->pc != pc) && map->next) map = map->next;
10399   /* if we found pc -- ignore it */
10400   while (map && map->pc == pc) map = map->prev;
10401
10402   /* scan list backwards (first definition first) */
10403   while (map && mask) {
10404 //    if (map->sym == sym) {
10405       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10406       mappc = map;
10407       /* scan list for reads at this pc first */
10408       while (map && map->pc == mappc->pc) {
10409         /* is the symbol (partially) read? */
10410         if ((map->sym == sym) && (map->access.isRead && ((map->access.in_mask & mask) != 0))) {
10411           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10412           return -1;
10413         }
10414         map = map->prev;
10415       } // while
10416       map = mappc;
10417
10418       while (map && map->pc == mappc->pc) {
10419         /* honor (partial) redefinitions of sym */
10420         if ((map->sym == sym) && (map->access.isWrite)) {
10421           mask &= ~map->access.mask;
10422           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10423         }
10424         map = map->prev;
10425       } // while
10426 //    } // if
10427     /* map already points to the first defmap for the next pCode */
10428     //map = mappc->prev;
10429   } // while
10430
10431   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10432    * is still alive; return the appropriate mask of alive bits */
10433   return mask;
10434 }
10435
10436 /* Check whether a symbol is alive (AFTER pc). */
10437 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10438   int mask, visit;
10439   defmap_t *map;
10440   stack_t *todo, *done;
10441   state_t *state;
10442   pCodeFlow *pcfl;
10443   pCodeFlowLink *succ;
10444
10445   mask = 0x00ff;
10446   
10447   assert (isPCI(pc));
10448   pcfl = PCI(pc)->pcflow;
10449   map = pcfl->defmap;
10450
10451   todo = newStack ();
10452   done = newStack ();
10453   
10454   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10455   stackPush (todo, state);
10456   visit = 0;
10457   
10458   while (!stackIsEmpty (todo)) {
10459     state = (state_t *) stackPop (todo);
10460     pcfl = state->flow;
10461     mask = PTR_TO_INT(state->lastdef);
10462     if (visit) stackPush (done, state); else deleteState(state);
10463     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10464     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10465     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10466     visit++;
10467
10468     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10469     if (mask == 0) continue;
10470
10471     /* symbol is (partially) read before redefinition in flow */
10472     if (mask == -1) break;
10473
10474     /* symbol is neither read nor completely redefined -- check successor flows */
10475     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10476       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10477       if (stateIsNew (state, todo, done)) {
10478         stackPush (todo, state);
10479       } else {
10480         deleteState (state);
10481       }
10482     } // for
10483   } // while
10484
10485   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10486   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10487
10488   /* symbol is read in at least one flow -- is alive */
10489   if (mask == -1) return 1;
10490
10491   /* symbol is read in no flow */
10492   return 0;
10493 }
10494
10495 /* Returns whether access to the given symbol has side effects. */
10496 static int pic16_symIsSpecial (symbol_t sym) {
10497   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10498   switch (sym) {
10499   case SPO_INDF0:
10500   case SPO_PLUSW0:
10501   case SPO_POSTINC0:
10502   case SPO_POSTDEC0:
10503   case SPO_PREINC0:
10504   case SPO_INDF1:
10505   case SPO_PLUSW1:
10506   case SPO_POSTINC1:
10507   case SPO_POSTDEC1:
10508   case SPO_PREINC1:
10509   case SPO_INDF2:
10510   case SPO_PLUSW2:
10511   case SPO_POSTINC2:
10512   case SPO_POSTDEC2:
10513   case SPO_PREINC2:
10514   case SPO_PCL:
10515           return 1;
10516   default:
10517           /* no special effects known */
10518           return 0;
10519   } // switch
10520
10521   return 0;
10522 }
10523
10524 /* Check whether a register should be considered local (to the current function) or not. */
10525 static int pic16_regIsLocal (regs *r) {
10526   symbol_t sym;
10527   if (r) {
10528     sym = symFromStr (r->name);
10529     switch (sym) {
10530     case SPO_WREG:
10531     case SPO_FSR0L: // used in ptrget/ptrput
10532     case SPO_FSR0H: // ... as well
10533     case SPO_FSR1L: // used as stack pointer...
10534     case SPO_FSR1H: // ... as well
10535     case SPO_FSR2L: // used as frame pointer
10536     case SPO_FSR2H: // ... as well
10537     case SPO_PRODL: // used to return values from functions
10538     case SPO_PRODH: // ... as well
10539       /* these registers (and some more...) are considered local */
10540       return 1;
10541       break;
10542     default:
10543       /* for unknown regs: check is marked local, leave if not */
10544       if (r->isLocal) {
10545         return 1;
10546       } else {
10547         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10548         return 0;
10549       }
10550     } // switch
10551   } // if
10552
10553   /* if in doubt, assume non-local... */
10554   return 0;
10555 }
10556
10557 /* Check all symbols touched by pc whether their newly assigned values are read.
10558  * Returns 0 if no symbol is used later on, 1 otherwise. */
10559 static int pic16_pCodeIsAlive (pCode *pc) {
10560   pCodeInstruction *pci;
10561   defmap_t *map, *lastpc;
10562   regs *checkreg;
10563   
10564   /* we can only handle PCIs */
10565   if (!isPCI(pc)) return 1;
10566
10567   //pc->print (stderr, pc);
10568
10569   pci = PCI(pc);
10570   assert (pci && pci->pcflow && pci->pcflow->defmap);
10571
10572   /* NEVER remove instructions with implicit side effects */
10573   switch (pci->op) {
10574   case POC_TBLRD:
10575   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10576   case POC_TBLRD_POSTDEC:
10577   case POC_TBLRD_PREINC:
10578   case POC_TBLWT:               /* modify program memory */
10579   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10580   case POC_TBLWT_POSTDEC:
10581   case POC_TBLWT_PREINC:
10582   case POC_CLRWDT:              /* clear watchdog timer */
10583   case POC_PUSH:                /* should be safe to remove though... */
10584   case POC_POP:                 /* should be safe to remove though... */
10585   case POC_CALL:
10586   case POC_RCALL:
10587   case POC_RETFIE:
10588   case POC_RETURN:
10589     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10590     return 1;
10591
10592   default:
10593     /* no special instruction */
10594     break;
10595   } // switch
10596
10597   /* prevent us from removing assignments to non-local variables */
10598   checkreg = NULL;
10599   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10600   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10601
10602   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10603     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10604     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10605     //pc->print (stderr, pc);
10606     return 1;
10607   }
10608   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10609     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10610     return 1;
10611   }
10612   
10613 #if 1
10614   /* OVERKILL: prevent us from removing reads from non-local variables 
10615    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10616    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10617   checkreg = NULL;
10618   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10619   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10620
10621   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10622     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10623     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10624     //pc->print (stderr, pc);
10625     return 1;
10626   }
10627   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10628     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10629     return 1;
10630   }
10631 #endif
10632   
10633   /* now check that the defined symbols are not used */
10634   map = pci->pcflow->defmap;
10635   
10636   /* find items for pc */
10637   while (map && map->pc != pc) map = map->next;
10638
10639   /* no entries found? something is fishy with DF analysis... -- play safe */
10640   if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10641
10642   /* remember first item assigned to pc for later use */
10643   lastpc = map;
10644   
10645   /* check all symbols being modified by pc */
10646   while (map && map->pc == pc) {
10647     if (map->sym == 0) { map = map->next; continue; }
10648
10649     /* keep pc if it references special symbols (like POSTDEC0) */
10650 #if 0
10651     {
10652       char buf[256];
10653       pic16_pCode2str (buf, 256, pc);
10654       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10655     }
10656 #endif
10657     if (pic16_symIsSpecial (map->sym)) {
10658       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10659       return 1;
10660     }
10661     if (map->access.isWrite) {
10662       if (pic16_isAlive (map->sym, pc)) {
10663         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10664         return 1;
10665       }
10666     }
10667     map = map->next;
10668   } // while
10669
10670   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10671 #if 0
10672   {
10673     char buf[256];
10674     pic16_pCode2str (buf, 256, pc);
10675     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10676   }
10677 #endif
10678   return 0;
10679 }
10680
10681 /* Adds implied operands to the list.
10682  * sym - operand being accessed in the pCode
10683  * list - list to append the operand
10684  * isRead - set to 1 iff sym is read in pCode
10685  * listRead - set to 1 iff all operands being read are to be listed
10686  *
10687  * Returns 0 for "normal" operands, 1 for special operands.
10688  */
10689 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10690   /* check whether accessing REG accesses other REGs as well */
10691   switch (sym) {
10692   case SPO_INDF0:
10693     /* reads FSR0x */
10694     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10695     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10696     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10697     break;
10698     
10699   case SPO_PLUSW0:
10700     /* reads FSR0x and WREG */
10701     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10702     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10703     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10704     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10705     break;
10706     
10707   case SPO_POSTDEC0:
10708   case SPO_POSTINC0:
10709   case SPO_PREINC0:
10710     /* reads/modifies FSR0x */
10711     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10712     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10713     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10714     break;
10715
10716   case SPO_INDF1:
10717     /* reads FSR1x */
10718     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10719     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10720     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10721     break;
10722     
10723   case SPO_PLUSW1:
10724     /* reads FSR1x and WREG */
10725     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10726     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10727     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10728     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10729     break;
10730     
10731   case SPO_POSTDEC1:
10732   case SPO_POSTINC1:
10733   case SPO_PREINC1:
10734     /* reads/modifies FSR1x */
10735     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10736     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10737     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10738     break;
10739
10740   case SPO_INDF2:
10741     /* reads FSR2x */
10742     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10743     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10744     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10745     break;
10746     
10747   case SPO_PLUSW2:
10748     /* reads FSR2x and WREG */
10749     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10750     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10751     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10752     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10753     break;
10754     
10755   case SPO_POSTDEC2:
10756   case SPO_POSTINC2:
10757   case SPO_PREINC2:
10758     /* reads/modifies FSR2x */
10759     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10760     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10761     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10762     break;
10763
10764   case SPO_PCL:
10765     /* modifies PCLATH and PCLATU */
10766     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10767     if (isRead) {
10768       /* reading PCL updates PCLATx */
10769       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10770       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10771     }
10772     if (isWrite) {
10773       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10774       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10775       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10776     }
10777     break;
10778
10779   default:
10780     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10781     /* nothing special */
10782     return 0;
10783     break;
10784   }
10785
10786   /* has been a special operand */
10787   return 1;
10788 }
10789
10790 static symbol_t pic16_fsrsym_idx[][2] = {
10791     {SPO_FSR0L, SPO_FSR0H},
10792     {SPO_FSR1L, SPO_FSR1H},
10793     {SPO_FSR2L, SPO_FSR2H}
10794 };
10795   
10796 /** Prepend list with the reads and definitions performed by pc. */
10797 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10798   pCodeInstruction *pci;
10799   int cond, inCond, outCond;
10800   int mask = 0xff, smask;
10801   int isSpecial, isSpecial2;
10802   symbol_t sym, sym2;
10803   char *name;
10804
10805   if (isPCAD(pc)) {
10806     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10807     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10808     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10809     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10810     return list;
10811   }
10812   assert (isPCI(pc));
10813   pci = PCI(pc);
10814   
10815   /* handle bit instructions */
10816   if (pci->isBitInst) {
10817     assert (pci->pcop->type == PO_GPR_BIT);
10818     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10819   }
10820
10821   /* handle (additional) implicit arguments */
10822   switch (pci->op) {
10823   case POC_LFSR:
10824     {
10825       int lit;
10826       valnum_t val;
10827       lit = PCOL(pci->pcop)->lit;
10828       assert (lit >= 0 && lit < 3);
10829       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10830       val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10831       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10832       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10833       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...
10834     }
10835     break;
10836
10837   case POC_MOVLB: // BSR
10838   case POC_BANKSEL: // BSR
10839     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10840     break;
10841
10842   case POC_MULWF: // PRODx
10843   case POC_MULLW: // PRODx
10844     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10845     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10846     break;
10847
10848   case POC_POP: // TOS, STKPTR
10849     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10850     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10851     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10852     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10853     break;
10854     
10855   case POC_PUSH: // STKPTR
10856     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10857     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10858     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10859     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10860     break;
10861     
10862   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10863   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10864     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10865     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10866     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10867     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10868     break;
10869
10870   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10871     /* pseudo read on (possible) return values */
10872     // WREG is handled below via outCond
10873     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10874     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10875     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10876     break;
10877
10878   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10879   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10880     /* pseudo read on (possible) return values */
10881     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10882     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10883     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10884     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10885
10886     /* caller's stack pointers must be restored */
10887     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10888     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10889     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10890     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10891     break;
10892     
10893   case POC_TBLRD:
10894     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10895     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10896     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10897     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10898     break;
10899     
10900   case POC_TBLRD_POSTINC:
10901   case POC_TBLRD_POSTDEC:
10902   case POC_TBLRD_PREINC:
10903     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10904     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10905     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10906     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10907     break;
10908     
10909   case POC_TBLWT:
10910     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10911     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10912     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10913     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10914     break;
10915     
10916   case POC_TBLWT_POSTINC:
10917   case POC_TBLWT_POSTDEC:
10918   case POC_TBLWT_PREINC:
10919     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10920     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10921     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10922     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10923     break;
10924     
10925   default:
10926     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10927     break;
10928   } // switch
10929
10930   /* handle explicit arguments */
10931   inCond = pci->inCond;
10932   outCond = pci->outCond;
10933   cond = inCond | outCond;
10934   if (cond & PCC_W) {
10935     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10936   } // if
10937
10938   /* keep STATUS read BEFORE STATUS write in the list */
10939   if (inCond & PCC_STATUS) {
10940     smask = 0;
10941     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10942     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10943     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10944     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10945     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10946
10947     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10948     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10949   } // if
10950   
10951   if (outCond & PCC_STATUS) {
10952     smask = 0;
10953     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10954     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10955     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10956     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10957     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10958
10959     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10960     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10961   } // if
10962   
10963   isSpecial = isSpecial2 = 0;
10964   sym = sym2 = 0;
10965   if (cond & PCC_REGISTER) {
10966     name = pic16_get_op (pci->pcop, NULL, 0);
10967     sym = symFromStr (name);
10968     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
10969     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
10970   }
10971
10972   if (cond & PCC_REGISTER2) {
10973     name = pic16_get_op2 (pci->pcop, NULL, 0);
10974     sym2 = symFromStr (name);
10975     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
10976     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
10977   }
10978
10979  
10980   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10981   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
10982   
10983   return list;
10984 }
10985
10986 #if 0
10987 static void printDefmap (defmap_t *map) {
10988   defmap_t *curr;
10989
10990   curr = map;
10991   fprintf (stderr, "defmap @ %p:\n", curr);
10992   while (curr) {
10993     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
10994                     curr->access.isRead ? "R" : " ",
10995                     curr->access.isWrite ? "W": " ",
10996                     curr->in_val, curr->val,
10997                     curr->access.in_mask, curr->access.mask,
10998                     strFromSym(curr->sym), curr->sym,
10999                     curr->pc);
11000     curr = curr->next;
11001   } // while
11002   fprintf (stderr, "<EOL>\n");
11003 }
11004 #endif
11005
11006 /* Add "additional" definitions to uniq.
11007  * 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.
11008  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11009  *
11010  * If symbols defined in additional are not present in uniq, a definition is created.
11011  * Otherwise the present definition is altered to reflect the newer assignments.
11012  *
11013  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11014  *       before     `------- noted in additional --------'      after
11015  *
11016  * I assume that each symbol occurs AT MOST ONCE in uniq.
11017  *
11018  */
11019 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11020   defmap_t *curr;
11021   defmap_t *old;
11022   int change = 0;
11023
11024   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11025   /* find tail of additional list (holds the first assignment) */
11026   curr = additional;
11027   while (curr && curr->next) curr = curr->next;
11028
11029   /* update uniq */
11030   do {
11031     /* find next assignment in additionals */
11032     while (curr && !curr->access.isWrite) curr = curr->prev;
11033
11034     if (!curr) break;
11035
11036     /* find item in uniq */
11037     old = *uniq;
11038     //printDefmap (*uniq);
11039     while (old && (old->sym != curr->sym)) old = old->next;
11040
11041     if (old) {
11042       /* definition found -- replace */
11043       if (old->val != curr->val) {
11044         old->val = curr->val;
11045         change++;
11046       } // if
11047     } else {
11048       /* new definition */
11049       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11050       change++;
11051     }
11052
11053     curr = curr->prev;
11054   } while (1);
11055
11056   /* return 0 iff uniq remained unchanged */
11057   return change;
11058 }
11059
11060 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11061  * lists of its predecessor flows. 
11062  * Initially *combined should be NULL, alt_in will be copied to combined.
11063  * If *combined != NULL, combined will be altered:
11064  * - for symbols defined in *combined but not in alt_in,
11065  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11066  * - for symbols defined in alt_in but not in *combined,
11067  *   a 0 definition is created (value unknown, either INIT or alt).
11068  * - for symbols defined in both, *combined is:
11069  *   > left unchanged if *combined->val == alt_in->val or
11070  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11071  * 
11072  * I assume that each symbol occurs AT MOST ONCE in each list!
11073  */
11074 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11075   defmap_t *curr;
11076   defmap_t *old;
11077   int change = 0;
11078   valnum_t val;
11079
11080   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11081   
11082   if (!(*combined)) {
11083     return defmapUpdateUniqueSym (combined, alt_in);
11084   } // if
11085   
11086   /* merge the two */
11087   curr = alt_in;
11088   while (curr) {
11089     /* find symbols definition in *combined */
11090     old = *combined;
11091     while (old && (old->sym != curr->sym)) old = old->next;
11092
11093     if (old) {
11094       /* definition found */
11095       if (old->val && (old->val != curr->val)) {
11096         old->val = 0; /* value unknown */
11097         change++;
11098       }
11099     } else {
11100       /* no definition found -- can be either INIT or alt_in's value */
11101       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11102       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11103       if (val != curr->val) change++;
11104     }
11105
11106     curr = curr->next;
11107   } // while (curr)
11108
11109   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11110   old = *combined;
11111   while (old) {
11112     if (old->val != 0) {
11113       /* find definition in alt_in */
11114       curr = alt_in;
11115       while (curr && curr->sym != old->sym) curr = curr->next;
11116       if (!curr) {
11117         /* symbol defined in *combined only -- can be either INIT or *combined */
11118         val = pic16_pBlockAddInval (pb, old->sym)->val;
11119         if (old->val != val) {
11120           old->val = 0;
11121           change++;
11122         }
11123       } // if
11124     } // if
11125
11126     old = old->next;
11127   } // while
11128
11129   return change;
11130 }
11131
11132 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11133   defmap_t *curr1, *curr2;
11134   symbol_t sym;
11135   
11136   /* identical maps are equal */
11137   if (map1 == map2) return 0;
11138
11139   if (!map1) return -1;
11140   if (!map2) return 1;
11141
11142   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11143   
11144   /* check length */
11145   curr1 = map1;
11146   curr2 = map2;
11147   while (curr1 && curr2) {
11148     curr1 = curr1->next;
11149     curr2 = curr2->next;
11150   } // while
11151
11152   /* one of them longer? */
11153   if (curr1) return 1;
11154   if (curr2) return -1;
11155
11156   /* both lists are of equal length -- compare (in O(n^2)) */
11157   curr1 = map1;
11158   while (curr1) {
11159     sym = curr1->sym;
11160     curr2 = map2;
11161     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11162     if (!curr2) return 1; // symbol not found in curr2
11163     if (curr2->val != curr1->val) return 1; // values differ
11164
11165     /* compare next symbol */
11166     curr1 = curr1->next;
11167   } // while
11168
11169   /* no difference found */
11170   return 0;
11171 }
11172
11173
11174 /* Prepare a list of all reaching definitions per flow.
11175  * This is done using a forward dataflow analysis.
11176  */
11177 static void createReachingDefinitions (pBlock *pb) {
11178   defmap_t *out_vals, *in_vals;
11179   pCode *pc;
11180   pCodeFlow *pcfl;
11181   pCodeFlowLink *link;
11182   set *todo;
11183   set *blacklist;
11184
11185   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11186   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11187     if (isPCFL(pc)) {
11188       deleteDefmapChain (&PCFL(pc)->in_vals);
11189       deleteDefmapChain (&PCFL(pc)->out_vals);
11190       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11191     } // if
11192   } // for
11193   
11194   pc = pic16_findNextInstruction (pb->pcHead);
11195   todo = NULL; blacklist = NULL;
11196   addSetHead (&todo, PCI(pc)->pcflow);
11197
11198   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11199   while (elementsInSet (todo)) {
11200     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11201     pcfl = PCFL(indexSet (todo, 0));
11202     deleteSetItem (&todo, pcfl);
11203     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11204     in_vals = NULL;
11205     out_vals = NULL;
11206
11207     if (isinSet (blacklist, pcfl)) {
11208             fprintf (stderr, "ignoring blacklisted flow\n");
11209       continue;
11210     }
11211     
11212     /* create in_vals from predecessors out_vals */
11213     link = setFirstItem (pcfl->from);
11214     while (link) {
11215       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11216       link = setNextItem (pcfl->from);
11217     } // while
11218
11219     //printDefmap (in_vals); 
11220     //printDefmap (pcfl->in_vals); 
11221
11222     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11223       //fprintf (stderr, "in_vals changed\n");
11224       /* in_vals changed -- update out_vals */
11225       deleteDefmapChain (&pcfl->in_vals);
11226       pcfl->in_vals = in_vals;
11227
11228       /* create out_val from in_val and defmap */
11229       out_vals = NULL;
11230       defmapUpdateUniqueSym (&out_vals, in_vals);
11231       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11232
11233       /* is out_vals different from pcfl->out_vals */
11234       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11235         //fprintf (stderr, "out_vals changed\n");
11236         deleteDefmapChain (&pcfl->out_vals);
11237         pcfl->out_vals = out_vals;
11238
11239         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11240           addSet (&blacklist, pcfl);
11241         } // if
11242         
11243         /* reschedule all successors */
11244         link = setFirstItem (pcfl->to);
11245         while (link) {
11246           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11247           addSetIfnotP (&todo, link->pcflow);
11248           link = setNextItem (pcfl->to);
11249         } // while
11250       } else {
11251         deleteDefmapChain (&out_vals);        
11252       }// if
11253     } else {
11254       deleteDefmapChain (&in_vals);         
11255     } // if
11256   } // while
11257 }
11258
11259 #if 0
11260 static void showAllDefs (symbol_t sym, pCode *pc) {
11261   defmap_t *map;
11262   int count;
11263
11264   assert (isPCI(pc));
11265   count = defmapFindAll (sym, pc, &map);
11266
11267   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11268   while (map) {
11269 #if 1
11270     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11271 #else
11272     { char buf[256];
11273     pic16_pCode2str (buf, 256, map->pc);
11274     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11275 #endif
11276     map = map->next;
11277   }
11278   deleteDefmapChain (&map);
11279 }
11280 #endif
11281
11282 /* safepCodeUnlink and remove pc from defmap. */
11283 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11284   defmap_t *map, *next, **head;
11285   int res, ispci;
11286   
11287   ispci = isPCI(pc);
11288   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11289   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11290   res = pic16_safepCodeUnlink (pc, comment);
11291
11292   if (res && map) {
11293     /* remove pc from defmap */
11294     while (map) {
11295       next = map->next;
11296       if (map->pc == pc) {
11297         if (!map->prev && head) *head = map->next;
11298         deleteDefmap (map);
11299       } // if
11300       map = next;
11301     }
11302   }
11303
11304   return res;
11305 }
11306       
11307 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11308   defmap_t *map;
11309   /* This breaks the defmap chain's references to pCodes... fix it! */
11310   map = PCI(pc)->pcflow->defmap;
11311
11312   while (map && map->pc != pc) map = map->next;
11313   
11314   while (map && map->pc == pc) {
11315     map->pc = newpc;
11316     map = map->next;
11317   } // while
11318 }
11319
11320 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
11321   defmap_t *map;
11322   if (!isPCI(pc)) return;
11323   
11324   map = PCI(pc)->pcflow->defmap;
11325
11326   while (map && map->pc != pc) map = map->next;
11327   while (map && map->pc == pc) {
11328     if (map->sym == sym) map->sym = newsym;
11329     map = map->next;
11330   } // while
11331 }
11332
11333 /* Assign "better" valnums to results. */
11334 static void assignValnums (pCode *pc) {
11335   pCodeInstruction *pci;
11336   pCode *newpc;
11337   symbol_t sym1, sym2;
11338   int cond, isSpecial1, isSpecial2, count, mask, lit;
11339   defmap_t *list, *val, *oldval, *dummy;
11340   regs *reg1 = NULL, *reg2 = NULL;
11341   valnum_t litnum;
11342
11343   /* only works for pCodeInstructions... */
11344   if (!isPCI(pc)) return;
11345
11346   pci = PCI(pc);
11347   cond = pci->inCond | pci->outCond;
11348   list = pci->pcflow->defmap;
11349   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11350
11351   if (cond & PCC_REGISTER) {
11352     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11353     reg1 = pic16_getRegFromInstruction (pc);
11354     isSpecial1 = pic16_symIsSpecial (sym1);
11355   }
11356   if (cond & PCC_REGISTER2) {
11357     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11358     reg2 = pic16_getRegFromInstruction (pc);
11359     isSpecial2 = pic16_symIsSpecial (sym2);
11360   }
11361
11362   /* determine input values */
11363   val = list;
11364   while (val && val->pc != pc) val = val->next;
11365   //list = val; /* might save some time later... */
11366   while (val && val->pc == pc) {
11367     val->in_val = 0;
11368     if (val->sym != 0 && (1 || val->access.isRead)) {
11369       /* get valnum for sym */
11370       count = defmapFindAll (val->sym, pc, &oldval);
11371       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11372       if (count == 1) {
11373         if ((val->access.in_mask & oldval->access.mask) == val->access.in_mask) {
11374           val->in_val = oldval->val;
11375         } else {
11376           val->in_val = 0;
11377         }
11378       } else if (count == 0) {
11379         /* no definition found */
11380         val->in_val = 0;
11381       } else {
11382         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11383         assert (oldval);
11384         dummy = oldval->next;
11385         mask = oldval->access.mask;
11386         val->in_val = oldval->val;
11387         while (dummy && (dummy->val == val->in_val)) {
11388           mask &= dummy->access.mask;
11389           dummy = dummy->next;
11390         } // while
11391
11392         /* found other values or to restictive mask */
11393         if (dummy || ((mask & val->access.in_mask) != val->access.in_mask)) {
11394           val->in_val = 0;
11395         }
11396       }
11397       if (count > 0) deleteDefmapChain (&oldval);
11398     } // if
11399     val = val->next;
11400   }
11401
11402   /* handle valnum assignment */
11403   switch (pci->op) {
11404   case POC_CLRF: /* modifies STATUS (Z) */
11405     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11406       oldval = defmapCurr (list, sym1, pc);
11407       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11408         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11409         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11410       }
11411       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11412     }
11413     break;
11414
11415   case POC_SETF: /* SETF does not touch STATUS */
11416     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11417       oldval = defmapCurr (list, sym1, pc);
11418       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11419         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11420         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11421       }
11422       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11423     }
11424     break;
11425     
11426   case POC_MOVLW: /* does not touch STATUS */
11427     oldval = defmapCurr (list, SPO_WREG, pc);
11428     if (pci->pcop->type == PO_LITERAL) {
11429       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11430       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11431     } else {
11432       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11433       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11434     }
11435     if (oldval && oldval->in_val == litnum) {
11436       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11437       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11438     }
11439     defmapUpdate (list, SPO_WREG, pc, litnum);
11440     break;
11441
11442   case POC_ANDLW: /* modifies STATUS (Z,N) */
11443   case POC_IORLW: /* modifies STATUS (Z,N) */
11444   case POC_XORLW: /* modifies STATUS (Z,N) */
11445     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11446     if (pci->pcop->type == PO_LITERAL) {
11447       lit = (unsigned char) PCOL(pci->pcop)->lit;
11448       int vallit = -1;
11449       val = defmapCurr (list, SPO_WREG, pc);
11450       if (val) vallit = litFromValnum (val->in_val);
11451       if (vallit != -1) {
11452         /* xxxLW <literal>, WREG contains a known literal */
11453         fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11454         if (pci->op == POC_ANDLW) {
11455           lit &= vallit;
11456         } else if (pci->op == POC_IORLW) {
11457           lit |= vallit;
11458         } else if (pci->op == POC_XORLW) {
11459           lit ^= vallit;
11460         } else {
11461           assert (0 && "invalid operation");
11462         }
11463         if (vallit == lit) {
11464           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11465           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11466         }
11467         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11468       } // if
11469     }
11470     break;
11471
11472   case POC_LFSR:
11473     {
11474       /* check if old value matches new value */
11475       int lit;
11476       int ok = 1;
11477       assert (pci->pcop->type == PO_LITERAL);
11478       
11479       lit = PCOL(pci->pcop)->lit;
11480       
11481       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11482       
11483       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11484         fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11485       } else {
11486         /* cannot remove this LFSR */
11487         ok = 0;      
11488       } // if
11489       
11490       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11491       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11492         fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11493       } else {
11494         ok = 0;
11495       } // if
11496
11497       if (ok) {
11498         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11499       }
11500     }
11501     break;
11502     
11503   case POC_MOVWF: /* does not touch flags */
11504     /* find value of WREG */
11505     val = defmapCurr (list, SPO_WREG, pc);
11506     oldval = defmapCurr (list, sym1, pc);
11507     if (val) lit = litFromValnum (val->in_val);
11508     else lit = -1;
11509     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11510     
11511     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11512       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11513       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11514       if (lit == 0) {
11515         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11516       } else {
11517         assert (lit == 0x0ff);
11518         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11519       }
11520       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11521       pic16_pCodeReplace (pc, newpc);
11522       defmapReplaceSymRef (pc, SPO_WREG, 0);
11523       pic16_fixDefmap (pc, newpc);
11524       pc = newpc;
11525         
11526       /* This breaks the defmap chain's references to pCodes... fix it! */
11527       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11528       deleteDefmap (val); // delete reference to WREG as in value
11529       val = NULL;
11530       oldval = PCI(pc)->pcflow->defmap;
11531       while (oldval) {
11532         if (oldval->pc == pc) oldval->pc = newpc;
11533           oldval = oldval->next;
11534       } // while
11535     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11536       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11537       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11538     }
11539     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11540     break;
11541     
11542   case POC_MOVFW: /* modifies STATUS (Z,N) */
11543     /* find value of REG */
11544     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11545       val = defmapCurr (list, sym1, pc);
11546       oldval = defmapCurr (list, SPO_WREG, pc);
11547       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11548         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11549         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11550       }
11551       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11552     }
11553     break;
11554
11555   case POC_MOVFF: /* does not touch STATUS */
11556     /* find value of REG */
11557     val = defmapCurr (list, sym1, pc);
11558     oldval = defmapCurr (list, sym2, pc);
11559     if (val) lit = litFromValnum (val->in_val);
11560     else lit = -1;
11561     newpc = NULL;
11562     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11563       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11564       if (lit == 0) {
11565         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11566       } else if (lit == 0x00ff) {
11567         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11568       } else {
11569         newpc = NULL;
11570       }
11571       if (newpc) {
11572         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11573         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11574         pic16_pCodeReplace (pc, newpc); 
11575         defmapReplaceSymRef (pc, sym1, 0);
11576         pic16_fixDefmap (pc, newpc);
11577         pc = newpc;
11578         break; // do not process instruction as MOVFF...
11579       }
11580     } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11581       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11582         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11583         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11584       } else {
11585         if (!pic16_isAlive (sym1, pc)) {
11586           defmap_t *copy = NULL;
11587           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11588            * This should help eliminate
11589            *   MOVFF A,B
11590            *   <do something not changing A or using B>
11591            *   MOVFF B,C
11592            *   <B is not alive anymore>
11593            * and turn it into
11594            *   <do something not changing A or using B>
11595            *   MOVFF A,C
11596            */
11597
11598           /* scan defmap for symbols storing sym1's value */
11599           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11600           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11601             /* unique reaching definition for sym found */
11602             if (copy->val && copy->val == val->in_val) {
11603               //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);
11604               if (copy->sym == SPO_WREG) {
11605                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11606               } else {
11607                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11608 //                      /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11609                         pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11610                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11611               }
11612               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11613               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11614               pic16_pCodeReplace (pc, newpc); 
11615               assert (val->sym == sym1 && val->access.isRead && !val->access.isWrite);
11616               defmapReplaceSymRef (pc, sym1, copy->sym);
11617               pic16_fixDefmap (pc, newpc);
11618               pc = newpc;
11619             }
11620           }
11621           deleteDefmapChain (&copy);
11622         }
11623       }
11624       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11625     }
11626     break;
11627
11628   default:
11629     /* cannot optimize */
11630     break;
11631   } // switch
11632 }
11633
11634 static void pic16_destructDF (pBlock *pb) {
11635   pCode *pc, *next;
11636
11637   /* remove old defmaps */
11638   pc = pic16_findNextInstruction (pb->pcHead);
11639   while (pc) {
11640     next = pic16_findNextInstruction (pc->next);
11641
11642     assert (isPCI(pc) || isPCAD(pc));
11643     assert (PCI(pc)->pcflow);
11644     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11645     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11646     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11647     
11648     pc = next;
11649   } // while
11650   
11651   if (defmap_free || defmap_free_count) {
11652     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11653     freeDefmap (&defmap_free);
11654     defmap_free_count = 0;
11655   }
11656 }
11657
11658 /* Checks whether a pBlock contains ASMDIRs. */
11659 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11660   pCode *pc;
11661
11662   pc = pic16_findNextInstruction (pb->pcHead);
11663   while (pc) {
11664     if (isPCAD(pc)) return 1;
11665
11666     pc = pic16_findNextInstruction (pc->next);
11667   } // while
11668
11669   /* no PCADs found */
11670   return 0;
11671 }
11672
11673 #if 1
11674 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11675 static int pic16_removeUnusedRegistersDF () {
11676   pCode *pc, *pc2;
11677   pBlock *pb;
11678   regs *reg1, *reg2, *reg3;
11679   set *seenRegs = NULL;
11680   int cond, i;
11681   int islocal, change = 0;
11682
11683   /* no pBlocks? */
11684   if (!the_pFile || !the_pFile->pbHead) return 0;
11685   
11686   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11687     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11688 #if 1
11689     /* find set of using pCodes per register */
11690     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11691                     pc = pic16_findNextInstruction(pc->next)) {
11692
11693       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11694       reg1 = reg2 = NULL;
11695       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11696       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11697
11698       if (reg1) {
11699         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11700         addSetIfnotP (&seenRegs, reg1);
11701         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11702       }
11703       if (reg2) {
11704         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11705         addSetIfnotP (&seenRegs, reg2);
11706         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11707       }
11708     } // for pc
11709 #endif
11710     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11711       /* may not use pic16_regIsLocal() here -- in interrupt routines
11712        * WREG, PRODx, FSR0x must be saved */
11713       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11714       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11715         pc = pc2 = NULL;
11716         for (i=0; i < 2; i++) {
11717           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11718           if (!pc2) pc2 = pc;
11719           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11720           reg2 = pic16_getRegFromInstruction (pc);
11721           reg3 = pic16_getRegFromInstruction2 (pc);
11722           if (!reg2 || !reg3
11723               || (reg2->rIdx != pic16_stack_preinc->rIdx
11724                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11725           if (i == 1) {
11726             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11727             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11728             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11729             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11730           }
11731         } // for
11732       } // if
11733       deleteSet (&reg1->reglives.usedpCodes);
11734     } // for reg1
11735
11736     deleteSet (&seenRegs);
11737   } // for pb
11738
11739   return change;
11740 }
11741 #endif
11742
11743 /* Set up pCodeFlow's defmap_ts. 
11744  * Needs correctly set up to/from fields. */
11745 static void pic16_createDF (pBlock *pb) {
11746   pCode *pc, *next;
11747   int change=0;
11748
11749   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11750
11751   pic16_destructDF (pb);
11752
11753   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11754   if (pic16_pBlockHasAsmdirs (pb)) {
11755     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11756     return;
11757   }
11758
11759   /* integrity check -- we need to reach all flows to guarantee
11760    * correct data flow analysis (reaching definitions, aliveness) */
11761 #if 0
11762   if (!verifyAllFlowsReachable (pb)) {
11763     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11764     return;
11765   }
11766 #endif
11767   
11768   /* establish new defmaps */
11769   pc = pic16_findNextInstruction (pb->pcHead);
11770   while (pc) {
11771     next = pic16_findNextInstruction (pc->next);
11772
11773     assert (PCI(pc)->pcflow);
11774     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11775
11776     pc = next;
11777   } // while
11778
11779   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11780   createReachingDefinitions (pb);
11781   
11782 #if 1
11783   /* assign better valnums */
11784   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11785   pc = pic16_findNextInstruction (pb->pcHead);
11786   while (pc) {
11787     next = pic16_findNextInstruction (pc->next);
11788
11789     assert (PCI(pc)->pcflow);
11790     assignValnums (pc);
11791
11792     pc = next;
11793   } // while
11794 #endif
11795
11796 #if 1
11797   /* remove dead pCodes */
11798   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11799   do {
11800     change = 0;
11801     pc = pic16_findNextInstruction (pb->pcHead);
11802     while (pc) {
11803       next = pic16_findNextInstruction (pc->next);
11804
11805       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11806         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11807       }
11808
11809       pc = next;
11810     } // while
11811   } while (change);
11812 #endif
11813 }
11814
11815
11816 /* ======================================================================= */
11817 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11818 /* ======================================================================= */
11819
11820 #if 0
11821
11822 /* connect pCode f anf t via their to/from pBranches */
11823 static void pic16_pCodeLink (pCode *f, pCode *t) {
11824   pBranch *br;
11825   pCodeInstruction *_f, *_t;
11826
11827   if (!f || !t) return;
11828
11829 #if 0
11830   fprintf (stderr, "linking:\n");
11831   f->print(stderr, f);
11832   f->print(stderr, t);
11833 #endif
11834
11835   assert (isPCI(f) || isPCAD(f));
11836   assert (isPCI(t) || isPCAD(t));
11837   _f = PCI(f);
11838   _t = PCI(t);
11839   
11840   /* define t to be CF successor of f */
11841   br = Safe_malloc (sizeof (pBranch));
11842   br->pc = t;
11843   br->next = NULL;
11844   _f->to = pic16_pBranchAppend (_f->to, br);
11845
11846   /* define f to be CF predecessor of t */
11847   br = Safe_malloc (sizeof (pBranch));
11848   br->pc = f;
11849   br->next = NULL;
11850   _t->from = pic16_pBranchAppend (_t->from, br);
11851
11852   /* also update pcflow information */
11853   if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11854     //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11855     LinkFlow_pCode (_f, _t);
11856   } // if
11857 }
11858
11859 static void pic16_destructCF (pBlock *pb) {
11860   pCode *pc;
11861   pBranch *br;
11862
11863   /* remove old CF information */
11864   pc = pb->pcHead;
11865   while (pc) {
11866     if (isPCI(pc)) {
11867       while (PCI(pc)->to) {
11868         br = PCI(pc)->to->next;
11869         Safe_free (PCI(pc)->to);
11870         PCI(pc)->to = br;
11871       } // while
11872       while (PCI(pc)->from) {
11873         br = PCI(pc)->from->next;
11874         Safe_free (PCI(pc)->from);
11875         PCI(pc)->from = br;
11876       }
11877     } else if (isPCFL(pc)) {
11878       deleteSet (&PCFL(pc)->to);
11879       deleteSet (&PCFL(pc)->from);
11880     }
11881     pc = pc->next;
11882   }
11883   
11884   releaseStack ();
11885 }
11886
11887 /* Set up pCodeInstruction's to and from pBranches. */
11888 static void pic16_createCF (pBlock *pb) {
11889   pCode *pc;
11890   pCode *next, *dest;
11891   char *label;
11892
11893   //fprintf (stderr, "creating CF for %p\n", pb);
11894
11895   pic16_destructCF (pb);
11896
11897   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11898   if (pic16_pBlockHasAsmdirs (pb)) {
11899     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11900     return;
11901   }
11902
11903   pc = pic16_findNextInstruction(pb->pcHead);
11904   while (pc) {
11905     next = pic16_findNextInstruction(pc->next);
11906     if (isPCI_SKIP(pc)) {
11907       pic16_pCodeLink(pc, next);
11908       pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
11909     } else if (isPCI_BRANCH(pc)) {
11910       // Bcc, BRA, CALL, GOTO
11911       if (PCI(pc)->pcop) {
11912         switch (PCI(pc)->pcop->type) {
11913         case PO_LABEL:
11914           label = PCOLAB(PCI(pc)->pcop)->pcop.name;
11915           dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
11916           break;
11917         
11918         case PO_STR:
11919           /* needed for GOTO ___irq_handler */
11920           label = PCI(pc)->pcop->name;
11921           dest = NULL;
11922           break;
11923
11924         default:
11925           assert (0 && "invalid label format");
11926           break;
11927         } // switch
11928       } else {
11929         label = "NO PCOP";
11930         dest = NULL;
11931       }
11932
11933       switch (PCI(pc)->op) {
11934       case POC_BRA:
11935       case POC_GOTO:
11936         if (dest != NULL) { 
11937           pic16_pCodeLink(pc, dest);
11938         } else {
11939           //fprintf (stderr, "jump target \"%s\" not found!\n", label);
11940         }
11941         break;
11942       case POC_CALL:
11943       case POC_RETURN:
11944       case POC_RETFIE:
11945         pic16_pCodeLink(pc, next);
11946         break;
11947       case POC_BC:
11948       case POC_BNC:
11949       case POC_BZ:
11950       case POC_BNZ:
11951       case POC_BN:
11952       case POC_BNN:
11953       case POC_BOV:
11954       case POC_BNOV:
11955         if (dest != NULL) { 
11956           pic16_pCodeLink(pc, dest);
11957         } else {
11958           //fprintf (stderr, "jump target \"%s\"not found!\n", label);
11959         }
11960         pic16_pCodeLink(pc, next);
11961         break;
11962       default:
11963         fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
11964         assert (0 && "unhandled branch instruction");
11965         break;
11966       } // switch
11967     } else {
11968       pic16_pCodeLink (pc, next);
11969     }
11970     pc = next;
11971   } // while
11972 }
11973 #endif
11974
11975 /* ======================================================================== */
11976 /* === VCG DUMPER ROUTINES ================================================ */
11977 /* ======================================================================== */
11978 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11979 hTab *dumpedNodes = NULL;
11980
11981 /** Dump VCG header into of. */
11982 static void pic16_vcg_init (FILE *of) {
11983   /* graph defaults */
11984   fprintf (of, "graph:{\n");
11985   fprintf (of, "title:\"graph1\"\n");
11986   fprintf (of, "label:\"graph1\"\n");
11987   fprintf (of, "color:white\n");
11988   fprintf (of, "textcolor:black\n");
11989   fprintf (of, "bordercolor:black\n");
11990   fprintf (of, "borderwidth:1\n");
11991   fprintf (of, "textmode:center\n");
11992
11993   fprintf (of, "layoutalgorithm:dfs\n");
11994   fprintf (of, "late_edge_labels:yes\n");
11995   fprintf (of, "display_edge_labels:yes\n");
11996   fprintf (of, "dirty_edge_labels:yes\n");
11997   fprintf (of, "finetuning:yes\n");
11998   fprintf (of, "ignoresingles:no\n");
11999   fprintf (of, "straight_phase:yes\n");
12000   fprintf (of, "priority_phase:yes\n");
12001   fprintf (of, "manhattan_edges:yes\n");
12002   fprintf (of, "smanhattan_edges:no\n");
12003   fprintf (of, "nearedges:no\n");
12004   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12005   fprintf (of, "port_sharing:no\n");
12006   fprintf (of, "arrowmode:free\n"); // fixed|free
12007   fprintf (of, "crossingphase2:yes\n");
12008   fprintf (of, "crossingoptimization:yes\n");
12009   fprintf (of, "edges:yes\n");
12010   fprintf (of, "nodes:yes\n");
12011   fprintf (of, "splines:no\n");
12012   
12013   /* node defaults */
12014   fprintf (of, "node.color:lightyellow\n");
12015   fprintf (of, "node.textcolor:black\n");
12016   fprintf (of, "node.textmode:center\n");
12017   fprintf (of, "node.shape:box\n");
12018   fprintf (of, "node.bordercolor:black\n");
12019   fprintf (of, "node.borderwidth:1\n");
12020
12021   /* edge defaults */
12022   fprintf (of, "edge.textcolor:black\n");
12023   fprintf (of, "edge.color:black\n");
12024   fprintf (of, "edge.thickness:1\n");
12025   fprintf (of, "edge.arrowcolor:black\n");
12026   fprintf (of, "edge.backarrowcolor:black\n");
12027   fprintf (of, "edge.arrowsize:15\n");
12028   fprintf (of, "edge.backarrowsize:15\n");
12029   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12030   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12031   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12032   
12033   fprintf (of, "\n");
12034
12035   /* prepare data structures */
12036   if (dumpedNodes) {
12037     hTabDeleteAll (dumpedNodes);
12038     dumpedNodes = NULL;
12039   }
12040   dumpedNodes = newHashTable (128);
12041 }
12042
12043 /** Dump VCG footer into of. */
12044 static void pic16_vcg_close (FILE *of) {
12045   fprintf (of, "}\n");
12046 }
12047
12048 #define BUF_SIZE 128
12049 #define pcTitle(pc) (snprintf (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12050
12051 #if 0
12052 static int ptrcmp (const void *p1, const void *p2) {
12053   return p1 == p2;
12054 }
12055 #endif
12056
12057 /** Dump a pCode node as VCG to of. */
12058 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12059   char buf[BUF_SIZE];
12060
12061   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12062     // dumped already
12063     return;
12064   }
12065   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12066   //fprintf (stderr, "dumping %p\n", pc);
12067  
12068   /* only dump pCodeInstructions and Flow nodes */
12069   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12070     
12071   /* emit node */
12072   fprintf (of, "node:{");
12073   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12074   fprintf (of, "label:\"%s\n", pcTitle(pc));
12075   if (isPCFL(pc)) {
12076     fprintf (of, "<PCFLOW>");
12077   } else if (isPCI(pc) || isPCAD(pc)) {
12078     pc->print (of, pc);
12079   } else {
12080     fprintf (of, "<!PCI>");
12081   }
12082   fprintf (of, "\" ");
12083   fprintf (of, "}\n");
12084   
12085   if (1 && isPCFL(pc)) {
12086     defmap_t *map, *prev;
12087     unsigned int i;
12088     map = PCFL(pc)->defmap;
12089     i=0;
12090     while (map) {
12091       if (map->sym != 0) {
12092         i++;
12093       
12094         /* emit definition node */
12095         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12096         fprintf (of, "label:\"");
12097
12098         prev = map;
12099         do {
12100           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));
12101           prev = map;
12102           map = map->next;
12103         } while (map && prev->pc == map->pc);
12104         map = prev;
12105         
12106         fprintf (of, "\" ");
12107       
12108         fprintf (of, "color:green ");
12109         fprintf (of, "}\n");
12110
12111         /* emit edge to previous definition */
12112         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12113         if (i == 1) {
12114           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12115         } else {
12116           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12117         }
12118         fprintf (of, "color:green ");
12119         fprintf (of, "}\n");
12120
12121         if (map->pc) {
12122           pic16_vcg_dumpnode (map->pc, of);
12123           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12124           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12125         }
12126       }
12127       map = map->next;
12128     } // while
12129   }
12130
12131   /* emit additional nodes (e.g. operands) */
12132 }
12133
12134 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12135 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12136   char buf[BUF_SIZE];
12137   pCodeInstruction *pci;
12138   pBranch *curr;
12139   int i;
12140   
12141   if (1 && isPCFL(pc)) {
12142     /* emit edges to flow successors */
12143     void *pcfl;
12144     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12145     pcfl = setFirstItem (PCFL(pc)->to);
12146     while (pcfl) {
12147       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12148       pic16_vcg_dumpnode (pc, of);
12149       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12150       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12151       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12152       pcfl = setNextItem (PCFL(pc)->to);
12153     } // while
12154   } // if
12155   
12156   if (!isPCI(pc) && !isPCAD(pc)) return;
12157
12158   pci = PCI(pc);
12159   
12160   /* emit control flow edges (forward only) */
12161   curr = pci->to;
12162   i=0;
12163   while (curr) {
12164     pic16_vcg_dumpnode (curr->pc, of);
12165     fprintf (of, "edge:{");
12166     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12167     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12168     fprintf (of, "color:red ");
12169     fprintf (of, "}\n");
12170     curr = curr->next;
12171   } // while
12172
12173 #if 1
12174   /* dump "flow" edge (link pCode according to pBlock order) */
12175   {
12176     pCode *pcnext;
12177     pcnext = pic16_findNextInstruction (pc->next);
12178     if (pcnext) {
12179       pic16_vcg_dumpnode (pcnext, of);
12180       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12181       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12182     }
12183   }
12184 #endif
12185   
12186 #if 0
12187   /* emit flow */
12188   if (pci->pcflow) {
12189     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12190     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12191     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12192   }
12193 #endif
12194   
12195   /* emit data flow edges (backward only) */
12196   /* TODO: gather data flow information... */
12197 }
12198
12199 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12200   pCode *pc;
12201
12202   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12203   if (pic16_pBlockHasAsmdirs (pb)) {
12204     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12205     return;
12206   }
12207
12208   for (pc=pb->pcHead; pc; pc = pc->next) {
12209     pic16_vcg_dumpnode (pc, of);
12210   } // for pc
12211   
12212   for (pc=pb->pcHead; pc; pc = pc->next) {
12213     pic16_vcg_dumpedges (pc, of);
12214   } // for pc
12215 }
12216
12217 static void pic16_vcg_dump_default (pBlock *pb) {
12218   FILE *of;
12219   char buf[BUF_SIZE];
12220   pCode *pc;
12221
12222   /* get function name */
12223   pc = pb->pcHead;
12224   while (pc && !isPCF(pc)) pc = pc->next;
12225   if (pc) {
12226     snprintf (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12227   } else {
12228     snprintf (buf, BUF_SIZE, "pb_%p.vcg", pb);
12229   }
12230
12231   //fprintf (stderr, "now dumping %s\n", buf);
12232   of = fopen (buf, "w");
12233   pic16_vcg_init (of);
12234   pic16_vcg_dump (of, pb);
12235   pic16_vcg_close (of);
12236   fclose (of);
12237 }
12238 #endif
12239
12240 /*** END of helpers for pCode dataflow optimizations ***/