* src/pic16/pcode.c (pic16_pCodeReplace): also update pcflow->end
[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   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7244     PCI(newPC)->pcflow->end = newPC;
7245   }
7246
7247   /* insert a comment stating which pCode has been replaced */
7248 #if 1
7249   if (pic16_pcode_verbose || pic16_debug_verbose) {
7250     char pc_str[256];
7251     pic16_pCode2str (pc_str, 256, oldPC);
7252     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7253   }
7254 #endif
7255   
7256   /* insert new pCode into pBlock */
7257   pic16_pCodeInsertAfter (oldPC, newPC);
7258   pic16_unlinkpCode (oldPC);
7259   
7260   /* destruct replaced pCode */
7261   oldPC->destruct (oldPC);
7262 }
7263
7264 /* Returns the inverted conditional branch (if any) or NULL.
7265  * pcop must be set to the new jump target.
7266  */
7267 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7268 {
7269   pCode *newBcc;
7270
7271   if (!bcc || !isPCI(bcc)) return NULL;
7272
7273   switch (PCI(bcc)->op) {
7274   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7275   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7276   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7277   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7278   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7279   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7280   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7281   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7282   default:
7283     newBcc = NULL;
7284   }
7285   return newBcc;
7286 }
7287
7288 #define MAX_DIST_GOTO         0x7FFFFFFF
7289 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7290 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7291 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7292 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7293
7294 /* Follows GOTO/BRA instructions to their target instructions, stores the
7295  * final destination (not a GOTO or BRA instruction) in target and returns
7296  * the distance from the original pc to *target.
7297  */
7298 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7299         pCode *curr = pc;
7300         pCode *last = NULL;
7301         pCodeOp *lastPCOP = NULL;
7302         int dist = 0;
7303         int depth = 0;
7304
7305         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7306
7307         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7308         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7309                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7310                 last = curr;
7311                 lastPCOP = PCI(curr)->pcop;
7312                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7313                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7314         } // while
7315
7316         if (target) *target = last;
7317         if (pcop) *pcop = lastPCOP;
7318         return dist;
7319 }
7320
7321 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7322  * Otherwise the first pCode after the jumptable (after
7323  * the OPT_JUMPTABLE_END tag) is returned.
7324  */
7325 pCode *skipJumptables (pCode *pc, int *isJumptable)
7326 {
7327   *isJumptable = 0;
7328   if (!pc) return NULL;
7329   
7330   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7331     *isJumptable = 1;
7332     //fprintf (stderr, "SKIPPING jumptable\n");
7333     do {
7334       //pc->print(stderr, pc);
7335       pc = pc->next;
7336     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7337                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7338     //fprintf (stderr, "<<JUMPTAB:\n");
7339     // skip OPT_END as well
7340     if (pc) pc = pc->next;
7341   } // while
7342
7343   return pc;
7344 }
7345
7346 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7347 {
7348   int isJumptab;
7349   *isJumptable = 0;
7350   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7351     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7352     pc = skipJumptables (pc, &isJumptab);
7353     if (isJumptab) {
7354         // pc is the first pCode after the jumptable
7355         *isJumptable = 1;
7356     } else {
7357         // pc has not been changed by skipJumptables()
7358         pc = pc->next;
7359     }
7360   } // while
7361   
7362   return pc;
7363 }
7364
7365 /* Turn GOTOs into BRAs if distance between GOTO and label
7366  * is less than 1024 bytes.
7367  *
7368  * This method is especially useful if GOTOs after BTFS[SC]
7369  * can be turned into BRAs as GOTO would cost another NOP
7370  * if skipped.
7371  */
7372 void pic16_OptimizeJumps ()
7373 {
7374   pCode *pc;
7375   pCode *pc_prev = NULL;
7376   pCode *pc_next = NULL;
7377   pBlock *pb;
7378   pCode *target;
7379   int change, iteration, isJumptab;
7380   int isHandled = 0;
7381   char *label;
7382   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7383   
7384   if (!the_pFile) return;
7385   
7386   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7387   
7388   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7389     int matchedInvertRule = 1;
7390     iteration = 1;
7391     do {
7392       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7393       change = 0;
7394       pc = pic16_findNextInstruction (pb->pcHead);
7395     
7396       while (pc) {
7397         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7398         if (isJumptab) {
7399                 // skip jumptable, i.e. start over with no pc_prev!     
7400                 pc_prev = NULL;
7401                 pc = pc_next;
7402                 continue;
7403         } // if
7404
7405         /* (1) resolve chained jumps
7406          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7407          * (a) leave dead code in and
7408          * (b) skip over the dead code with an (unneccessary) jump.
7409          */
7410         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7411           pCodeOp *lastTargetOp = NULL;
7412           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7413           int maxDist = MAX_DIST_BCC;
7414           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7415           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7416           
7417           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7418           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7419               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7420             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7421             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7422             PCI(pc)->pcop->name = lastTargetOp->name;
7423             change++;
7424             opt_gotochain++;
7425           } // if
7426         } // if
7427
7428
7429         if (IS_GOTO(pc)) {
7430           int dist;
7431           int condBraType = isSkipOnStatus(pc_prev);
7432           label = PCI(pc)->pcop->name;
7433           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7434           if (dist < 0) dist = -dist;
7435           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7436           isHandled = 0;
7437           
7438           
7439           /* (2) remove "GOTO label; label:" */
7440           if (isLabel (pc_next, label)) {
7441             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7442             // first remove all preceeding SKIP instructions
7443             while (pc_prev && isPCI_SKIP(pc_prev)) {
7444               // attach labels on this instruction to pc_next
7445               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7446               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7447               PCI(pc_prev)->label = NULL;
7448               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7449               pic16_unlinkpCode (pc_prev);
7450               pc_prev = pic16_findPrevInstruction (pc);
7451             } // while
7452             // now remove the redundant goto itself
7453             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7454             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7455             pic16_unlinkpCode (pc);
7456             pc = pic16_findPrevInstruction(pc_next->prev);
7457             isHandled = 1; // do not perform further optimizations
7458             opt_gotonext++;
7459             change++;
7460           } // if
7461           
7462           
7463           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7464           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7465             if (dist < MAX_DIST_BCC) {
7466               pCode *bcc = NULL;
7467               switch (condBraType) {
7468               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7469                 // no BDC on DIGIT CARRY available
7470               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7471               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7472               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7473               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7474                 // no BNDC on DIGIT CARRY available
7475               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7476               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7477               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7478               default:
7479                 // no replacement possible
7480                 bcc = NULL;
7481                 break;
7482               } // switch
7483               if (bcc) {
7484                 // ATTENTION: keep labels attached to BTFSx!
7485                 // HINT: GOTO is label free (checked above)
7486                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7487                 isHandled = 1; // do not perform further optimizations
7488                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7489                 pic16_pCodeReplace (pc_prev, bcc);
7490                 pc->destruct(pc);
7491                 pc = bcc;
7492                 opt_cond++;
7493                 change++;
7494               } // if
7495             } else {
7496               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7497               cond_toofar++;
7498             } // if
7499           } // if
7500
7501           if (!isHandled) {
7502             // (4) eliminate the following (common) tripel:
7503             //           <pred.>;
7504             //  labels1: Bcc label2;
7505             //           GOTO somewhere;    ; <-- instruction referenced by pc
7506             //  label2:  <cont.>
7507             // and replace it by
7508             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7509             //  label2:  <cont.>
7510             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7511             //            to <cont.> instead
7512             // ATTENTION: This optimization is only valid if <pred.> is
7513             //            not a skip operation!
7514             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7515             // ATTENTION: no label may be attached to the GOTO instruction!
7516             if (isConditionalBranch(pc_prev)
7517                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7518                 && (dist < MAX_DIST_BCC)
7519                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7520                 && hasNoLabel(pc)) {
7521               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7522             
7523               if (newBcc) {
7524                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7525                 isHandled = 1; // do not perform further optimizations
7526                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7527                 pic16_pCodeReplace (pc_prev, newBcc);
7528                 pc->destruct(pc);
7529                 pc = newBcc;
7530                 opt_reorder++;
7531                 change++;
7532                 matchedInvertRule++;
7533               }
7534             }
7535           }
7536           
7537           /* (5) now just turn GOTO into BRA */ 
7538           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7539             if (dist < MAX_DIST_BRA) {
7540               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7541               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7542               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7543               pic16_pCodeReplace (pc, newBra);
7544               pc = newBra;
7545               opt++;
7546               change++;
7547             } else {
7548               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7549               toofar++;
7550             }
7551           } // if (!isHandled)
7552         } // if
7553
7554         pc_prev = pc;
7555         pc = pc_next;
7556       } // while (pc)
7557       
7558       pBlockRemoveUnusedLabels (pb);
7559       
7560       // This line enables goto chain resolution!
7561       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7562
7563       iteration++;
7564     } while (change); /* fixpoint iteration per pBlock */
7565   } // for (pb)
7566   
7567   // emit some statistics concerning goto-optimization
7568 #if 0
7569   if (pic16_debug_verbose || pic16_pcode_verbose) {
7570     fprintf (stderr, "optimize-goto:\n"
7571              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7572              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7573              "\t%5d conditional \"skipping\" jumps inverted\n"
7574              "\t%5d GOTOs to next instruction removed\n"
7575              "\t%5d chained GOTOs resolved\n",
7576              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7577   } // if
7578 #endif
7579   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7580 }
7581
7582 #undef IS_GOTO
7583 #undef MAX_JUMPCHAIN_DEPTH
7584 #undef MAX_DIST_GOTO
7585 #undef MAX_DIST_BRA
7586 #undef MAX_DIST_BCC
7587
7588 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7589
7590 static void pBlockDestruct(pBlock *pb)
7591 {
7592
7593   if(!pb)
7594     return;
7595
7596
7597 //  Safe_free(pb);
7598
7599 }
7600
7601 /*-----------------------------------------------------------------*/
7602 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7603 /*                                  name dbName and combine them   */
7604 /*                                  into one block                 */
7605 /*-----------------------------------------------------------------*/
7606 static void mergepBlocks(char dbName)
7607 {
7608
7609   pBlock *pb, *pbmerged = NULL,*pbn;
7610
7611   pb = the_pFile->pbHead;
7612
7613   //fprintf(stderr," merging blocks named %c\n",dbName);
7614   while(pb) {
7615
7616     pbn = pb->next;
7617     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7618     if( getpBlock_dbName(pb) == dbName) {
7619
7620       //fprintf(stderr," merged block %c\n",dbName);
7621
7622       if(!pbmerged) {
7623         pbmerged = pb;
7624       } else {
7625         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7626         /* pic16_addpCode2pBlock doesn't handle the tail: */
7627         pbmerged->pcTail = pb->pcTail;
7628
7629         pb->prev->next = pbn;
7630         if(pbn) 
7631           pbn->prev = pb->prev;
7632
7633
7634         pBlockDestruct(pb);
7635       }
7636       //pic16_printpBlock(stderr, pbmerged);
7637     } 
7638     pb = pbn;
7639   }
7640
7641 }
7642
7643 /*-----------------------------------------------------------------*/
7644 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7645 /*                                                                 */
7646 /* level 0 == minimal optimization                                 */
7647 /*   optimize registers that are used only by two instructions     */
7648 /* level 1 == maximal optimization                                 */
7649 /*   optimize by looking at pairs of instructions that use the     */
7650 /*   register.                                                     */
7651 /*-----------------------------------------------------------------*/
7652
7653 static void AnalyzeFlow(int level)
7654 {
7655   static int times_called=0;
7656   pBlock *pb;
7657
7658     if(!the_pFile) {
7659       /* remove unused allocated registers before exiting */
7660       pic16_RemoveUnusedRegisters();
7661       return;
7662     }
7663
7664
7665     /* if this is not the first time this function has been called,
7666      * then clean up old flow information */
7667     if(times_called++) {
7668       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7669         unBuildFlow(pb);
7670         pic16_RegsUnMapLiveRanges();
7671     }
7672     GpcFlowSeq = 1;
7673
7674     /* Phase 2 - Flow Analysis - Register Banking
7675      *
7676      * In this phase, the individual flow blocks are examined
7677      * and register banking is fixed.
7678      */
7679
7680 #if 0
7681     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7682       pic16_FixRegisterBanking(pb);
7683 #endif
7684
7685     /* Phase 2 - Flow Analysis
7686      *
7687      * In this phase, the pCode is partition into pCodeFlow 
7688      * blocks. The flow blocks mark the points where a continuous
7689      * stream of instructions changes flow (e.g. because of
7690      * a call or goto or whatever).
7691      */
7692
7693     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7694       pic16_BuildFlow(pb);
7695
7696
7697     /* Phase 2 - Flow Analysis - linking flow blocks
7698      *
7699      * In this phase, the individual flow blocks are examined
7700      * to determine their order of excution.
7701      */
7702
7703     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7704       LinkFlow(pb);
7705
7706 #if 1
7707         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7708                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7709                         pic16_createDF (pb);
7710 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7711                         pic16_vcg_dump_default (pb);
7712 #endif
7713                         //pic16_destructDF (pb);
7714                 }
7715
7716                 pic16_df_stats ();
7717                 if (0) releaseStack (); // releasing is costly...
7718         }
7719 #endif
7720
7721     /* Phase 3 - Flow Analysis - Flow Tree
7722      *
7723      * In this phase, the individual flow blocks are examined
7724      * to determine their order of execution.
7725      */
7726
7727     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7728       pic16_BuildFlowTree(pb);
7729
7730
7731     /* Phase x - Flow Analysis - Used Banks
7732      *
7733      * In this phase, the individual flow blocks are examined
7734      * to determine the Register Banks they use
7735      */
7736
7737 #if 0
7738     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7739       FixBankFlow(pb);
7740 #endif
7741
7742
7743     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7744       pic16_pCodeRegMapLiveRanges(pb);
7745
7746     pic16_RemoveUnusedRegisters();
7747     pic16_removeUnusedRegistersDF ();
7748
7749   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7750     pic16_pCodeRegOptimizeRegUsage(level);
7751
7752
7753 #if 0
7754     if(!options.nopeep)
7755       OptimizepCode('*');
7756 #endif
7757
7758 #if 0
7759     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7760       DumpFlow(pb);
7761 #endif
7762
7763     /* debug stuff */ 
7764     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7765       pCode *pcflow;
7766       
7767         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7768           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7769           pcflow = pcflow->next) {
7770             FillFlow(PCFL(pcflow));
7771         }
7772     }
7773
7774 #if 0
7775     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7776       pCode *pcflow;
7777
7778         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7779           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7780           pcflow = pcflow->next) {
7781             FlowStats(PCFL(pcflow));
7782         }
7783     }
7784 #endif
7785 }
7786
7787 /* VR -- no need to analyze banking in flow, but left here :
7788  *      1. because it may be used in the future for other purposes
7789  *      2. because if omitted we'll miss some optimization done here
7790  *
7791  * Perhaps I should rename it to something else
7792  */
7793
7794 /*-----------------------------------------------------------------*/
7795 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7796 /*                  assigned to the registers.                     */
7797 /*                                                                 */
7798 /*-----------------------------------------------------------------*/
7799
7800 void pic16_AnalyzeBanking(void)
7801 {
7802   pBlock  *pb;
7803
7804     /* Phase x - Flow Analysis - Used Banks
7805      *
7806      * In this phase, the individual flow blocks are examined
7807      * to determine the Register Banks they use
7808      */
7809
7810     AnalyzeFlow(0);
7811     AnalyzeFlow(1);
7812
7813     if(!options.nopeep)
7814       OptimizepCode('*');
7815
7816
7817     if(!the_pFile)return;
7818
7819     if(!pic16_options.no_banksel) {
7820       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7821 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7822         pic16_FixRegisterBanking(pb);
7823       }
7824     }
7825 }
7826
7827 /*-----------------------------------------------------------------*/
7828 /* buildCallTree - Look at the flow and extract all of the calls.  */
7829 /*-----------------------------------------------------------------*/
7830 static set *register_usage(pBlock *pb);
7831
7832 static void buildCallTree(void    )
7833 {
7834   pBranch *pbr;
7835   pBlock  *pb;
7836   pCode   *pc;
7837   regs *r;
7838   
7839   if(!the_pFile)
7840     return;
7841
7842
7843
7844   /* Now build the call tree.
7845      First we examine all of the pCodes for functions.
7846      Keep in mind that the function boundaries coincide
7847      with pBlock boundaries. 
7848
7849      The algorithm goes something like this:
7850      We have two nested loops. The outer loop iterates
7851      through all of the pBlocks/functions. The inner
7852      loop iterates through all of the pCodes for
7853      a given pBlock. When we begin iterating through
7854      a pBlock, the variable pc_fstart, pCode of the start
7855      of a function, is cleared. We then search for pCodes
7856      of type PC_FUNCTION. When one is encountered, we
7857      initialize pc_fstart to this and at the same time
7858      associate a new pBranch object that signifies a 
7859      branch entry. If a return is found, then this signifies
7860      a function exit point. We'll link the pCodes of these
7861      returns to the matching pc_fstart.
7862
7863      When we're done, a doubly linked list of pBranches
7864      will exist. The head of this list is stored in
7865      `the_pFile', which is the meta structure for all
7866      of the pCode. Look at the pic16_printCallTree function
7867      on how the pBranches are linked together.
7868
7869    */
7870   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7871     pCode *pc_fstart=NULL;
7872     for(pc = pb->pcHead; pc; pc = pc->next) {
7873
7874         if(isPCI(pc) && pc_fstart) {
7875                 if(PCI(pc)->is2MemOp) {
7876                         r = pic16_getRegFromInstruction2(pc);
7877                         if(r && !strcmp(r->name, "POSTDEC1"))
7878                                 PCF(pc_fstart)->stackusage++;
7879                 } else {
7880                         r = pic16_getRegFromInstruction(pc);
7881                         if(r && !strcmp(r->name, "PREINC1"))
7882                                 PCF(pc_fstart)->stackusage--;
7883                 }
7884         }
7885
7886       if(isPCF(pc)) {
7887         if (PCF(pc)->fname) {
7888         char buf[16];
7889
7890           sprintf(buf, "%smain", port->fun_prefix);
7891           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7892             //fprintf(stderr," found main \n");
7893             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7894             pb->dbName = 'M';
7895           }
7896
7897           pbr = Safe_calloc(1,sizeof(pBranch));
7898           pbr->pc = pc_fstart = pc;
7899           pbr->next = NULL;
7900
7901           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7902
7903           // Here's a better way of doing the same:
7904           addSet(&pb->function_entries, pc);
7905
7906         } else {
7907           // Found an exit point in a function, e.g. return
7908           // (Note, there may be more than one return per function)
7909           if(pc_fstart)
7910             pBranchLink(PCF(pc_fstart), PCF(pc));
7911
7912           addSet(&pb->function_exits, pc);
7913         }
7914       } else if(isCALL(pc)) {
7915         addSet(&pb->function_calls,pc);
7916       }
7917     }
7918   }
7919
7920
7921 #if 0
7922   /* This is not needed because currently all register used
7923    * by a function are stored in stack -- VR */
7924    
7925   /* Re-allocate the registers so that there are no collisions
7926    * between local variables when one function call another */
7927
7928   // this is weird...
7929   //  pic16_deallocateAllRegs();
7930
7931   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7932     if(!pb->visited)
7933       register_usage(pb);
7934   }
7935 #endif
7936
7937 }
7938
7939 /*-----------------------------------------------------------------*/
7940 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7941 /*                all of the logical connections.                  */
7942 /*                                                                 */
7943 /* Essentially what's done here is that the pCode flow is          */
7944 /* determined.                                                     */
7945 /*-----------------------------------------------------------------*/
7946
7947 void pic16_AnalyzepCode(char dbName)
7948 {
7949   pBlock *pb;
7950   int i,changes;
7951
7952   if(!the_pFile)
7953     return;
7954
7955   mergepBlocks('D');
7956
7957
7958   /* Phase 1 - Register allocation and peep hole optimization
7959    *
7960    * The first part of the analysis is to determine the registers
7961    * that are used in the pCode. Once that is done, the peep rules
7962    * are applied to the code. We continue to loop until no more
7963    * peep rule optimizations are found (or until we exceed the
7964    * MAX_PASSES threshold). 
7965    *
7966    * When done, the required registers will be determined.
7967    *
7968    */
7969   i = 0;
7970   do {
7971
7972     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7973     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7974
7975     /* First, merge the labels with the instructions */
7976     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7977       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7978
7979         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7980         //fprintf(stderr," analyze and merging block %c\n",dbName);
7981         pic16_pBlockMergeLabels(pb);
7982         AnalyzepBlock(pb);
7983       } else {
7984         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7985       }
7986     }
7987
7988         if(!options.nopeep)
7989                 changes = OptimizepCode(dbName);
7990         else changes = 0;
7991
7992   } while(changes && (i++ < MAX_PASSES));
7993
7994   
7995   buildCallTree();
7996 }
7997
7998
7999 /* convert a series of movff's of local regs to stack, with a single call to
8000  * a support functions which does the same thing via loop */
8001 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8002 {
8003   pBranch *pbr;
8004   pCode *pc, *pct;
8005   char *fname[]={"__lr_store", "__lr_restore"};
8006
8007 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8008
8009     pct = pic16_findNextInstruction(pcstart->next);
8010     do {
8011       pc = pct;
8012       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8013 //      pc->print(stderr, pc);
8014       if(isPCI(pc) && PCI(pc)->label) {
8015         pbr = PCI(pc)->label;
8016         while(pbr && pbr->pc) {
8017           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8018           pbr = pbr->next;
8019         }
8020
8021 //        pc->print(stderr, pc);
8022         /* unlink pCode */
8023         pc->prev->next = pct;
8024         pct->prev = pc->prev;
8025 //        pc->next = NULL;
8026 //        pc->prev = NULL;
8027       }
8028     } while ((pc) && (pc != pcend));
8029
8030     /* unlink movff instructions */
8031     pcstart->next = pcend;
8032     pcend->prev = pcstart;
8033
8034     pc = pcstart;
8035 //    if(!entry) {
8036 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8037 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8038 //    }
8039                 
8040     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8041     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8042     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8043
8044 //    if(!entry) {
8045 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8046 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8047 //    }
8048
8049     
8050     {
8051       symbol *sym;
8052
8053         sym = newSymbol( fname[ entry?0:1 ], 0 );
8054         strcpy(sym->rname, fname[ entry?0:1 ]);
8055         checkAddSym(&externs, sym);
8056         
8057 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8058     }
8059
8060 }
8061
8062 /*-----------------------------------------------------------------*/
8063 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8064 /*    local registers to a support function call                   */
8065 /*-----------------------------------------------------------------*/
8066 void pic16_OptimizeLocalRegs(void)
8067 {
8068   pBlock  *pb;
8069   pCode   *pc;
8070   pCodeInfo *pci;
8071   pCodeOpLocalReg *pclr;
8072   int regCount=0;
8073   int inRegCount=0;
8074   regs *r, *lastr=NULL, *firstr=NULL;
8075   pCode *pcstart=NULL, *pcend=NULL;
8076   int inEntry=0;
8077   char *curFunc=NULL;
8078
8079         /* Overview:
8080          *   local_regs begin mark
8081          *      MOVFF r0x01, POSTDEC1
8082          *      MOVFF r0x02, POSTDEC1
8083          *      ...
8084          *      ...
8085          *      MOVFF r0x0n, POSTDEC1
8086          *   local_regs end mark
8087          *
8088          * convert the above to the below:
8089          *      MOVLW   starting_register_index
8090          *      MOVWF   PRODL
8091          *      MOVLW   register_count
8092          *      call    __save_registers_in_stack
8093          */
8094
8095     if(!the_pFile)
8096       return;
8097
8098     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8099       inRegCount = regCount = 0;
8100       firstr = lastr = NULL;
8101       for(pc = pb->pcHead; pc; pc = pc->next) {
8102
8103         /* hold current function name */
8104         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8105         
8106         if(pc && (pc->type == PC_INFO)) {
8107           pci = PCINF(pc);
8108
8109           if(pci->type == INF_LOCALREGS) {
8110             pclr = PCOLR(pci->oper1);
8111             
8112             if((pclr->type == LR_ENTRY_BEGIN)
8113               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8114             else inEntry = 0;
8115             
8116             switch(pclr->type) {
8117               case LR_ENTRY_BEGIN:
8118               case LR_EXIT_BEGIN:
8119                         inRegCount = 1; regCount = 0;
8120                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8121                         firstr = lastr = NULL;
8122                         break;
8123               
8124               case LR_ENTRY_END:
8125               case LR_EXIT_END:
8126                         inRegCount = -1;
8127                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8128
8129 #if 1
8130                         if(curFunc && inWparamList(curFunc+1)) {
8131                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8132                                         filename, curFunc);
8133                         } else {
8134                           if(regCount>2) {
8135                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8136                               firstr, inEntry);
8137                           }
8138                         }
8139 #endif
8140                         firstr = lastr = NULL;
8141                         break;
8142             }
8143             
8144             if(inRegCount == -1) {
8145 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8146               regCount = 0;
8147               inRegCount = 0;
8148             }
8149           }
8150         } else {
8151           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8152             if(inEntry)
8153               r = pic16_getRegFromInstruction(pc);
8154             else
8155               r = pic16_getRegFromInstruction2(pc);
8156             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8157               if(!firstr)firstr = r;
8158               regCount++;
8159 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8160             }
8161           }
8162         }
8163       }
8164     }
8165 }
8166               
8167             
8168
8169
8170
8171 /*-----------------------------------------------------------------*/
8172 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8173 /*                   function                                      */
8174 /*-----------------------------------------------------------------*/
8175 static bool ispCodeFunction(pCode *pc)
8176 {
8177
8178   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8179     return 1;
8180
8181   return 0;
8182 }
8183
8184 /*-----------------------------------------------------------------*/
8185 /* findFunction - Search for a function by name (given the name)   */
8186 /*                in the set of all functions that are in a pBlock */
8187 /* (note - I expect this to change because I'm planning to limit   */
8188 /*  pBlock's to just one function declaration                      */
8189 /*-----------------------------------------------------------------*/
8190 static pCode *findFunction(char *fname)
8191 {
8192   pBlock *pb;
8193   pCode *pc;
8194   if(!fname)
8195     return NULL;
8196
8197   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8198
8199     pc = setFirstItem(pb->function_entries);
8200     while(pc) {
8201     
8202       if((pc->type == PC_FUNCTION) &&
8203          (PCF(pc)->fname) && 
8204          (strcmp(fname, PCF(pc)->fname)==0))
8205         return pc;
8206
8207       pc = setNextItem(pb->function_entries);
8208
8209     }
8210
8211   }
8212   return NULL;
8213 }
8214
8215 static void MarkUsedRegisters(set *regset)
8216 {
8217
8218   regs *r1,*r2;
8219
8220   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8221 //      fprintf(stderr, "marking register = %s\t", r1->name);
8222     r2 = pic16_regWithIdx(r1->rIdx);
8223 //      fprintf(stderr, "to register = %s\n", r2->name);
8224     r2->isFree = 0;
8225     r2->wasUsed = 1;
8226   }
8227 }
8228
8229 static void pBlockStats(FILE *of, pBlock *pb)
8230 {
8231
8232   pCode *pc;
8233   regs  *r;
8234
8235         if(!pic16_pcode_verbose)return;
8236         
8237   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8238
8239   // for now just print the first element of each set
8240   pc = setFirstItem(pb->function_entries);
8241   if(pc) {
8242     fprintf(of,";entry:  ");
8243     pc->print(of,pc);
8244   }
8245   pc = setFirstItem(pb->function_exits);
8246   if(pc) {
8247     fprintf(of,";has an exit\n");
8248     //pc->print(of,pc);
8249   }
8250
8251   pc = setFirstItem(pb->function_calls);
8252   if(pc) {
8253     fprintf(of,";functions called:\n");
8254
8255     while(pc) {
8256       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8257         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8258       }
8259       pc = setNextItem(pb->function_calls);
8260     }
8261   }
8262
8263   r = setFirstItem(pb->tregisters);
8264   if(r) {
8265     int n = elementsInSet(pb->tregisters);
8266
8267     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8268
8269     while (r) {
8270       fprintf(of,   ";   %s\n",r->name);
8271       r = setNextItem(pb->tregisters);
8272     }
8273   }
8274   
8275   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8276 }
8277
8278 /*-----------------------------------------------------------------*/
8279 /*-----------------------------------------------------------------*/
8280 #if 0
8281 static void sequencepCode(void)
8282 {
8283   pBlock *pb;
8284   pCode *pc;
8285
8286
8287   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8288
8289     pb->seq = GpCodeSequenceNumber+1;
8290
8291     for( pc = pb->pcHead; pc; pc = pc->next)
8292       pc->seq = ++GpCodeSequenceNumber;
8293   }
8294
8295 }
8296 #endif
8297
8298 /*-----------------------------------------------------------------*/
8299 /*-----------------------------------------------------------------*/
8300 static set *register_usage(pBlock *pb)
8301 {
8302   pCode *pc,*pcn;
8303   set *registers=NULL;
8304   set *registersInCallPath = NULL;
8305
8306   /* check recursion */
8307
8308   pc = setFirstItem(pb->function_entries);
8309
8310   if(!pc)
8311     return registers;
8312
8313   pb->visited = 1;
8314
8315   if(pc->type != PC_FUNCTION)
8316     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8317
8318   pc = setFirstItem(pb->function_calls);
8319   for( ; pc; pc = setNextItem(pb->function_calls)) {
8320
8321     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8322       char *dest = pic16_get_op_from_instruction(PCI(pc));
8323
8324       pcn = findFunction(dest);
8325       if(pcn) 
8326         registersInCallPath = register_usage(pcn->pb);
8327     } else
8328       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8329
8330   }
8331
8332 #ifdef PCODE_DEBUG
8333   pBlockStats(stderr,pb);  // debug
8334 #endif
8335
8336   // Mark the registers in this block as used.
8337
8338   MarkUsedRegisters(pb->tregisters);
8339   if(registersInCallPath) {
8340     /* registers were used in the functions this pBlock has called */
8341     /* so now, we need to see if these collide with the ones we are */
8342     /* using here */
8343
8344     regs *r1,*r2, *newreg;
8345
8346     DFPRINTF((stderr,"comparing registers\n"));
8347
8348     r1 = setFirstItem(registersInCallPath);
8349     while(r1) {
8350
8351       r2 = setFirstItem(pb->tregisters);
8352
8353       while(r2 && (r1->type != REG_STK)) {
8354
8355         if(r2->rIdx == r1->rIdx) {
8356           newreg = pic16_findFreeReg(REG_GPR);
8357
8358
8359           if(!newreg) {
8360             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8361             exit(1);
8362           }
8363
8364           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8365                   r1->rIdx, newreg->rIdx));
8366           r2->rIdx = newreg->rIdx;
8367           //if(r2->name) Safe_free(r2->name);
8368           if(newreg->name)
8369             r2->name = Safe_strdup(newreg->name);
8370           else
8371             r2->name = NULL;
8372           newreg->isFree = 0;
8373           newreg->wasUsed = 1;
8374         }
8375         r2 = setNextItem(pb->tregisters);
8376       }
8377
8378       r1 = setNextItem(registersInCallPath);
8379     }
8380
8381     /* Collisions have been resolved. Now free the registers in the call path */
8382     r1 = setFirstItem(registersInCallPath);
8383     while(r1) {
8384       if(r1->type != REG_STK) {
8385         newreg = pic16_regWithIdx(r1->rIdx);
8386         newreg->isFree = 1;
8387       }
8388       r1 = setNextItem(registersInCallPath);
8389     }
8390
8391   }// else
8392   //    MarkUsedRegisters(pb->registers);
8393
8394   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8395 #ifdef PCODE_DEBUG
8396   if(registers) 
8397     DFPRINTF((stderr,"returning regs\n"));
8398   else
8399     DFPRINTF((stderr,"not returning regs\n"));
8400
8401   DFPRINTF((stderr,"pBlock after register optim.\n"));
8402   pBlockStats(stderr,pb);  // debug
8403 #endif
8404
8405   return registers;
8406 }
8407
8408 /*-----------------------------------------------------------------*/
8409 /* pct2 - writes the call tree to a file                           */
8410 /*                                                                 */
8411 /*-----------------------------------------------------------------*/
8412 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8413 {
8414   pCode *pc,*pcn;
8415   int i;
8416   //  set *registersInCallPath = NULL;
8417
8418   if(!of)
8419     return;
8420
8421   if(indent > 10) {
8422         fprintf(of, "recursive function\n");
8423     return; //recursion ?
8424   }
8425
8426   pc = setFirstItem(pb->function_entries);
8427
8428   if(!pc)
8429     return;
8430
8431   pb->visited = 0;
8432
8433   for(i=0;i<indent;i++)   // Indentation
8434         fputs("+   ", of);
8435   fputs("+- ", of);
8436
8437   if(pc->type == PC_FUNCTION) {
8438     usedstack += PCF(pc)->stackusage;
8439     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8440   } else return;  // ???
8441
8442
8443   pc = setFirstItem(pb->function_calls);
8444   for( ; pc; pc = setNextItem(pb->function_calls)) {
8445
8446     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8447       char *dest = pic16_get_op_from_instruction(PCI(pc));
8448
8449       pcn = findFunction(dest);
8450       if(pcn) 
8451         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8452     } else
8453       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8454
8455   }
8456
8457
8458 }
8459
8460
8461 /*-----------------------------------------------------------------*/
8462 /* pic16_printCallTree - writes the call tree to a file                  */
8463 /*                                                                 */
8464 /*-----------------------------------------------------------------*/
8465
8466 void pic16_printCallTree(FILE *of)
8467 {
8468   pBranch *pbr;
8469   pBlock  *pb;
8470   pCode   *pc;
8471
8472   if(!the_pFile)
8473     return;
8474
8475   if(!of)
8476     of = stderr;
8477
8478   fprintf(of, "\npBlock statistics\n");
8479   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8480     pBlockStats(of,pb);
8481
8482
8483   fprintf(of,"Call Tree\n");
8484   pbr = the_pFile->functions;
8485   while(pbr) {
8486     if(pbr->pc) {
8487       pc = pbr->pc;
8488       if(!ispCodeFunction(pc))
8489         fprintf(of,"bug in call tree");
8490
8491
8492       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8493
8494       while(pc->next && !ispCodeFunction(pc->next)) {
8495         pc = pc->next;
8496         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8497           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8498       }
8499     }
8500
8501     pbr = pbr->next;
8502   }
8503
8504
8505   fprintf(of,"\n**************\n\na better call tree\n");
8506   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8507 //    if(pb->visited)
8508       pct2(of,pb,0,0);
8509   }
8510
8511   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8512     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8513   }
8514 }
8515
8516
8517
8518 /*-----------------------------------------------------------------*/
8519 /*                                                                 */
8520 /*-----------------------------------------------------------------*/
8521
8522 static void InlineFunction(pBlock *pb)
8523 {
8524   pCode *pc;
8525   pCode *pc_call;
8526
8527   if(!pb)
8528     return;
8529
8530   pc = setFirstItem(pb->function_calls);
8531
8532   for( ; pc; pc = setNextItem(pb->function_calls)) {
8533
8534     if(isCALL(pc)) {
8535       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8536       pCode *pct;
8537       pCode *pce;
8538
8539       pBranch *pbr;
8540
8541       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8542         
8543         //fprintf(stderr,"Cool can inline:\n");
8544         //pcn->print(stderr,pcn);
8545
8546         //fprintf(stderr,"recursive call Inline\n");
8547         InlineFunction(pcn->pb);
8548         //fprintf(stderr,"return from recursive call Inline\n");
8549
8550         /*
8551           At this point, *pc points to a CALL mnemonic, and
8552           *pcn points to the function that is being called.
8553
8554           To in-line this call, we need to remove the CALL
8555           and RETURN(s), and link the function pCode in with
8556           the CALLee pCode.
8557
8558         */
8559
8560
8561         /* Remove the CALL */
8562         pc_call = pc;
8563         pc = pc->prev;
8564
8565         /* remove callee pBlock from the pBlock linked list */
8566         removepBlock(pcn->pb);
8567
8568         pce = pcn;
8569         while(pce) {
8570           pce->pb = pb;
8571           pce = pce->next;
8572         }
8573
8574         /* Remove the Function pCode */
8575         pct = pic16_findNextInstruction(pcn->next);
8576
8577         /* Link the function with the callee */
8578         pc->next = pcn->next;
8579         pcn->next->prev = pc;
8580         
8581         /* Convert the function name into a label */
8582
8583         pbr = Safe_calloc(1,sizeof(pBranch));
8584         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8585         pbr->next = NULL;
8586         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8587         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8588
8589         /* turn all of the return's except the last into goto's */
8590         /* check case for 2 instruction pBlocks */
8591         pce = pic16_findNextInstruction(pcn->next);
8592         while(pce) {
8593           pCode *pce_next = pic16_findNextInstruction(pce->next);
8594
8595           if(pce_next == NULL) {
8596             /* found the last return */
8597             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8598
8599             //fprintf(stderr,"found last return\n");
8600             //pce->print(stderr,pce);
8601             pce->prev->next = pc_call->next;
8602             pc_call->next->prev = pce->prev;
8603             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8604                                                       PCI(pce)->label);
8605           }
8606
8607           pce = pce_next;
8608         }
8609
8610
8611       }
8612     } else
8613       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8614
8615   }
8616
8617 }
8618
8619 /*-----------------------------------------------------------------*/
8620 /*                                                                 */
8621 /*-----------------------------------------------------------------*/
8622
8623 void pic16_InlinepCode(void)
8624 {
8625
8626   pBlock  *pb;
8627   pCode   *pc;
8628
8629   if(!the_pFile)
8630     return;
8631
8632   if(!functionInlining)
8633     return;
8634
8635   /* Loop through all of the function definitions and count the
8636    * number of times each one is called */
8637   //fprintf(stderr,"inlining %d\n",__LINE__);
8638
8639   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8640
8641     pc = setFirstItem(pb->function_calls);
8642
8643     for( ; pc; pc = setNextItem(pb->function_calls)) {
8644
8645       if(isCALL(pc)) {
8646         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8647         if(pcn && isPCF(pcn)) {
8648           PCF(pcn)->ncalled++;
8649         }
8650       } else
8651         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8652
8653     }
8654   }
8655
8656   //fprintf(stderr,"inlining %d\n",__LINE__);
8657
8658   /* Now, Loop through the function definitions again, but this
8659    * time inline those functions that have only been called once. */
8660   
8661   InlineFunction(the_pFile->pbHead);
8662   //fprintf(stderr,"inlining %d\n",__LINE__);
8663
8664   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8665     unBuildFlow(pb);
8666
8667 }
8668
8669 char *pic_optype_names[]={
8670         "PO_NONE",         // No operand e.g. NOP
8671         "PO_W",              // The working register (as a destination)
8672         "PO_WREG",           // The working register (as a file register)
8673         "PO_STATUS",         // The 'STATUS' register
8674         "PO_BSR",            // The 'BSR' register
8675         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8676                              // of three)
8677         "PO_INDF0",          // The Indirect register
8678         "PO_INTCON",         // Interrupt Control register
8679         "PO_GPR_REGISTER",   // A general purpose register
8680         "PO_GPR_BIT",        // A bit of a general purpose register
8681         "PO_GPR_TEMP",       // A general purpose temporary register
8682         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8683         "PO_PCL",            // Program counter Low register
8684         "PO_PCLATH",         // Program counter Latch high register
8685         "PO_PCLATU",         // Program counter Latch upper register
8686         "PO_PRODL",          // Product Register Low
8687         "PO_PRODH",          // Product Register High
8688         "PO_LITERAL",        // A constant
8689         "PO_REL_ADDR",       // A relative address
8690         "PO_IMMEDIATE",      //  (8051 legacy)
8691         "PO_DIR",            // Direct memory (8051 legacy)
8692         "PO_CRY",            // bit memory (8051 legacy)
8693         "PO_BIT",            // bit operand.
8694         "PO_STR",            //  (8051 legacy)
8695         "PO_LABEL",
8696         "PO_WILD"            // Wild card operand in peep optimizer
8697 };
8698
8699
8700 char *dumpPicOptype(PIC_OPTYPE type)
8701 {
8702         return (pic_optype_names[ type ]);
8703 }
8704
8705
8706 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8707 #include "graph.h"
8708
8709 #define MAX_COMMON_BANK_SIZE    32
8710 #define FIRST_PSEUDO_BANK_NR  1000
8711
8712 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8713 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8714 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8715 Graph *adj = NULL;
8716
8717 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8718
8719 typedef struct {
8720   pseudoBankNr bank;  // number assigned to this pseudoBank
8721   unsigned int size;  // number of operands assigned to this bank
8722   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8723 } pseudoBank;
8724
8725 /*----------------------------------------------------------------------*/
8726 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8727 /*----------------------------------------------------------------------*/
8728 unsigned int hashSymbol (const char *str)
8729 {
8730   unsigned int res = 0;
8731   if (!str) return 0;
8732
8733   while (*str) {
8734     res ^= (*str);
8735     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8736     str++;
8737   } // while
8738
8739   return res;
8740 }
8741
8742 /*-----------------------------------------------------------------------*/
8743 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8744 /*-----------------------------------------------------------------------*/
8745 int compareSymbol (const void *sym1, const void *sym2)
8746 {
8747   char *s1 = (char*) sym1;
8748   char *s2 = (char*) sym2;
8749   
8750   return (strcmp (s1,s2) == 0);
8751 }
8752
8753 /*-----------------------------------------------------------------------*/
8754 /* comparePre - return 1 iff p1 == p2                                    */
8755 /*-----------------------------------------------------------------------*/
8756 int comparePtr (const void *p1, const void *p2)
8757 {
8758   return (p1 == p2);
8759 }
8760
8761 /*----------------------------------------------------------*/
8762 /* getSymbolFromOperand - return a pointer to the symbol in */
8763 /*                        the given operand and its length  */
8764 /*----------------------------------------------------------*/
8765 char *getSymbolFromOperand (char *op, unsigned int *len)
8766 {
8767   char *sym, *curr;
8768   *len = 0;
8769
8770   if (!op) return NULL;
8771
8772   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8773   sym = op;
8774   if (*sym == '(') sym++;
8775
8776   curr = sym;
8777   while (((*curr >= 'A') && (*curr <= 'Z'))
8778          || ((*curr >= 'a') && (*curr <= 'z'))
8779          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8780          || (*curr == '_')) {
8781     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8782     curr++;
8783     (*len)++;
8784   } // while
8785
8786   return sym;
8787 }
8788
8789 /*--------------------------------------------------------------------------*/
8790 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8791 /*--------------------------------------------------------------------------*/
8792 char *getSymFromBank (pseudoBankNr bank)
8793 {
8794   assert (bank2sym);
8795
8796   if (bank < 0) return "<INVALID BANK NR>";
8797   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8798 }
8799
8800 /*-----------------------------------------------------------------------*/
8801 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8802 /*                           bank number (uses hTab sym2bank), if the    */
8803 /*                           symbol is not yet assigned a pseudo bank it */
8804 /*                           is assigned one here                        */
8805 /*-----------------------------------------------------------------------*/
8806 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8807 {
8808   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8809   pseudoBankNr bank;
8810   unsigned int hash;
8811
8812   assert (sym2bank);
8813
8814   hash = hashSymbol (op) % sym2bank->size;
8815   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8816   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8817
8818   if (bank == UNKNOWN_BANK) {
8819     // create a pseudo bank for the operand
8820     bank = next_bank++;
8821     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8822     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8823     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8824     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8825   } else {
8826     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8827   } // if
8828
8829   assert (bank >= 0);
8830
8831   return bank;
8832 }
8833
8834 /*--------------------------------------------------------------------*/
8835 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8836 /*--------------------------------------------------------------------*/
8837 int isBanksel (pCode *pc)
8838 {
8839   if (!pc) return 0;
8840
8841   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8842     // BANKSEL <variablename>  or  MOVLB <banknr>
8843     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8844     return 1;
8845   }
8846
8847   // check for inline assembler BANKSELs
8848   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8849                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8850     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8851     return 1;
8852   }
8853
8854   // assume pc is no BANKSEL instruction
8855   return 0;
8856 }
8857
8858 /*---------------------------------------------------------------------------------*/
8859 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8860 /*                  This method can not guarantee to find all modifications of the */
8861 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8862 /*                  generated plus some cases.                                     */
8863 /*---------------------------------------------------------------------------------*/
8864 int invalidatesBSR(pCode *pc)
8865 {
8866   // assembler directives invalidate BSR (well, they might, we don't know)
8867   if (isPCAD(pc)) return 1;
8868
8869   // only ASMDIRs and pCodeInstructions can invalidate BSR
8870   if (!isPCI(pc)) return 0;
8871
8872   // we have a pCodeInstruction
8873
8874   // check for BSR modifying instructions
8875   switch (PCI(pc)->op) {
8876   case POC_CALL:
8877   case POC_RCALL:
8878   case POC_MOVLB:
8879   case POC_RETFIE:  // might be used as CALL replacement
8880   case POC_RETLW:   // might be used as CALL replacement
8881   case POC_RETURN:  // might be used as CALL replacement
8882   case POC_BANKSEL:
8883     return 1;
8884     break;
8885
8886   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8887     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8888     break;
8889   } // switch
8890
8891   // no change of BSR possible/probable
8892   return 0;
8893 }
8894
8895 /*------------------------------------------------------------*/
8896 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8897 /*                      the symbol referenced in this BANKSEL */
8898 /*------------------------------------------------------------*/
8899 pseudoBankNr getBankFromBanksel (pCode *pc)
8900 {
8901   char *sym;
8902   int data = (int)NULL;
8903
8904   if (!pc) return INVALID_BANK;
8905   
8906   if (isPCAD(pc) && PCAD(pc)->directive) {
8907     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8908       // get symbolname from PCAD(pc)->arg
8909       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8910       sym = PCAD(pc)->arg;
8911       data = getPseudoBankNrFromOperand (sym);
8912       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8913     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8914       // get (literal) bank number from PCAD(pc)->arg
8915       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8916       assert (0 && "not yet implemented - turn off banksel optimization for now");
8917     }
8918   } else if (isPCI(pc)) {
8919     if (PCI(pc)->op == POC_BANKSEL) {
8920       // get symbolname from PCI(pc)->pcop->name (?)
8921       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8922       sym = PCI(pc)->pcop->name;
8923       data = getPseudoBankNrFromOperand (sym);
8924       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8925     } else if (PCI(pc)->op == POC_MOVLB) {
8926       // get (literal) bank number from PCI(pc)->pcop->name
8927       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8928       assert (0 && "not yet implemented - turn off banksel optimization for now");
8929     }
8930   }
8931   
8932   if (data == 0)
8933     // no assigned bank could be found
8934     return UNKNOWN_BANK;
8935   else
8936     return data;
8937 }
8938
8939 /*------------------------------------------------------------------------------*/
8940 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8941 /*------------------------------------------------------------------------------*/
8942 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8943 {
8944   pseudoBank *data;
8945
8946   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8947
8948   do {
8949     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8950     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8951     if (data) {
8952       if (data->bank != bank)
8953         bank = data->bank;
8954       else
8955         data = NULL;
8956     }
8957   } while (data);
8958   
8959   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8960   return bank;
8961 }
8962
8963 /*------------------------------------------------------------------*/
8964 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8965 /*                        bank is selected at a given pCode         */
8966 /*------------------------------------------------------------------*/
8967
8968 /* Create a graph with pseudo banks as its nodes and switches between
8969  * these as edges (with the edge weight representing the absolute
8970  * number of BANKSELs from one to the other).
8971  * Removes redundand BANKSELs instead iff mod == 1.
8972  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8973  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8974  * pseudo BSR.
8975  * TODO: check ALL instructions operands if they modify BSR directly...
8976  *
8977  * pb - the pBlock to annotate
8978  * mod  - select either graph creation (0) or BANKSEL removal (1)
8979  */
8980 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8981 {
8982   pCode *pc, *pc_next;
8983   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8984   int isBankselect = 0;
8985   unsigned int banksels=0;
8986   
8987   if (!pb) return 0;
8988
8989   pc = pic16_findNextInstruction(pb->pcHead);
8990   while (pc) {
8991     isBankselect = isBanksel (pc);
8992     pc_next = pic16_findNextInstruction (pc->next);
8993
8994     if (!hasNoLabel (pc)) {
8995       // we don't know our predecessors -- assume different BSRs
8996       prevBSR = UNKNOWN_BANK;
8997       pseudoBSR = UNKNOWN_BANK;
8998       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8999     } // if
9000
9001     // check if this is a BANKSEL instruction
9002     if (isBankselect) {
9003       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9004       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9005       if (mod) {
9006         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9007           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9008           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9009           pic16_unlinkpCode (pc);
9010           banksels++;
9011         }
9012       } else {
9013         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9014         banksels++;
9015       }
9016     } // if
9017
9018     if (!isBankselect && invalidatesBSR(pc)) {
9019       // check if this instruction invalidates the pseudoBSR
9020       pseudoBSR = UNKNOWN_BANK;
9021       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9022     } // if
9023
9024     prevBSR = pseudoBSR;
9025     pc = pc_next;
9026   } // while
9027
9028   return banksels;
9029 }
9030
9031 /*------------------------------------------------------------------------------------*/
9032 /* assignToSameBank - returns 0 on success or an error code                           */
9033 /*  1 - common bank would be too large                                                */
9034 /*  2 - assignment to fixed (absolute) bank not performed                             */
9035 /*                                                                                    */
9036 /* This functions assumes that unsplittable operands are already assigned to the same */
9037 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9038 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9039 /* TODO: Symbols with an abslute address must be handled specially!                   */
9040 /*------------------------------------------------------------------------------------*/
9041 int assignToSameBank (int bank0, int bank1, int doAbs)
9042 {
9043   int eff0, eff1, dummy;
9044   pseudoBank *pbank0, *pbank1;
9045   hashtItem *hitem;
9046
9047   eff0 = getEffectiveBank (bank0);
9048   eff1 = getEffectiveBank (bank1);
9049
9050   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9051
9052   // nothing to do if already same bank
9053   if (eff0 == eff1) return 0;
9054
9055   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9056     return 2;
9057
9058   // ensure eff0 < eff1
9059   if (eff0 > eff1) {
9060     // swap eff0 and eff1
9061     dummy = eff0;
9062     eff0 = eff1;
9063     eff1 = dummy;
9064     dummy = bank0;
9065     bank0 = bank1;
9066     bank1 = dummy;
9067   } // if
9068
9069   // now assign bank eff1 to bank eff0
9070   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9071   if (!pbank0) {
9072     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9073     pbank0->bank = eff0;
9074     pbank0->size = 1;
9075     pbank0->ref = 1;
9076     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9077   } // if
9078
9079   pbank1 = NULL;
9080   hitem = hTabSearch (coerce, eff1 % coerce->size);
9081   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9082     hitem = hitem->next;
9083
9084   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9085
9086 #if 0
9087   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9088            pbank0->bank, pbank0->size,
9089            getSymFromBank (eff0), getSymFromBank (eff1));
9090 #endif
9091
9092   if (pbank1) {
9093     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9094 #if 0
9095       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9096                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9097                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9098                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9099 #endif
9100       return 1;
9101     } // if
9102     pbank0->size += pbank1->size;
9103     pbank1->ref--;
9104     if (pbank1->ref == 0) Safe_free (pbank1);
9105   } else {
9106     pbank0->size++;
9107   } // if
9108
9109   if (hitem)
9110     hitem->item = pbank0;
9111   else  
9112     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9113   pbank0->ref++;
9114
9115   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9116
9117   return 0;
9118 }
9119
9120 /*----------------------------------------------------------------*/
9121 /* mergeGraphNodes - combines two nodes into one and modifies all */
9122 /*                   edges to and from the nodes accordingly      */
9123 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9124 /* then also (B,A) must be an edge (possibly with weight 0).      */
9125 /*----------------------------------------------------------------*/
9126 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9127 {
9128   GraphEdge *edge, *backedge, *nextedge;
9129   GraphNode *node;
9130   int backweight;
9131
9132   assert (node1 && node2);
9133   assert (node1 != node2);
9134   
9135   // add all edges starting at node2 to node1
9136   edge = node2->edge;
9137   while (edge) {
9138     nextedge = edge->next;
9139     node = edge->node;
9140     backedge = getGEdge (node, node2);
9141     if (backedge)
9142       backweight = backedge->weight;
9143     else
9144       backweight = 0;
9145     // insert edges (node1,node) and (node,node1)
9146     addGEdge2 (node1, node, edge->weight, backweight);
9147     // remove edges (node, node2) and (node2, node)
9148     remGEdge (node2, node);
9149     remGEdge (node, node2);
9150     edge = nextedge;
9151   } // while
9152   
9153   // now node2 should not be referenced by any other GraphNode...
9154   //remGNode (adj, node2->data, node2->hash);
9155 }
9156
9157 /*----------------------------------------------------------------*/
9158 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9159 /*----------------------------------------------------------------*/
9160 void showGraph (Graph *g)
9161 {
9162   GraphNode *node;
9163   GraphEdge *edge;
9164   pseudoBankNr bankNr;
9165   pseudoBank *pbank;
9166   unsigned int size;
9167
9168   node = g->node;
9169   while (node) {
9170     edge = node->edge;
9171     bankNr = getEffectiveBank (node->hash);
9172     assert (bankNr >= 0);
9173     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9174     if (pbank) {
9175       bankNr = pbank->bank;
9176       size = pbank->size;
9177     } else {
9178       size = 1;
9179     }
9180     
9181     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9182
9183     while (edge) {
9184       if (edge->weight > 0)
9185         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9186       edge = edge->next;
9187     } // while (edge)
9188     node = node->next;
9189   } // while (node)
9190 }
9191
9192 /*---------------------------------------------------------------*/
9193 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9194 /*---------------------------------------------------------------*/
9195 void pic16_OptimizeBanksel ()
9196 {
9197   GraphNode *node, *node1, *node1next;
9198
9199 #if 0
9200   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9201   GraphEdge *edge, *backedge;
9202   GraphEdge *max;
9203   int maxWeight, weight, mergeMore, absMaxWeight;
9204   pseudoBankNr curr0, curr1;
9205 #endif
9206   pseudoBank *pbank;
9207   pseudoBankNr bankNr;
9208   char *base_symbol0, *base_symbol1;
9209   int len0, len1;
9210   pBlock *pb;
9211   set *set;
9212   regs *reg;
9213   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9214
9215   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9216
9217   if (!the_pFile || !the_pFile->pbHead) return;
9218
9219   adj = newGraph (NULL);
9220   sym2bank = newHashTable ( 255 );
9221   bank2sym = newHashTable ( 255 );
9222   coerce = newHashTable ( 255 );
9223
9224   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9225   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9226     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9227   } // for pb
9228
9229 #if 1
9230   // assign symbols with absolute addresses to their respective bank nrs
9231   set = pic16_fix_udata;
9232   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9233     bankNr = reg->address >> 8;
9234     node = getOrAddGNode (adj, NULL, bankNr);
9235     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9236     assignToSameBank (node->hash, bankNr, 1);
9237     
9238     assert (bankNr >= 0);
9239     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9240     if (!pbank) {
9241       pbank = Safe_calloc (1, sizeof (pseudoBank));
9242       pbank->bank = reg->address >> 8; //FIXED_BANK;
9243       pbank->size = 1;
9244       pbank->ref = 1;
9245       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9246     } else {
9247       assert (pbank->bank == (reg->address >> 8));
9248       pbank->bank = reg->address >> 8; //FIXED_BANK;
9249     }
9250     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9251   } // for reg
9252 #endif
9253
9254 #if 1
9255   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9256   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9257   node = adj->node;
9258   while (node) {
9259     if (node->hash < 0) { node = node->next; continue; }
9260     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9261     node1 = node->next;
9262     while (node1) {
9263       if (node1->hash < 0) { node1 = node1->next; continue; }
9264       node1next = node1->next;
9265       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9266       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9267         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9268         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9269         if (assignToSameBank (node->hash, node1->hash, 0)) {
9270           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9271           assert (0 && "Could not assign a symbol to a bank!");
9272         }
9273         mergeGraphNodes (node, node1);
9274         /*
9275         if (node->hash < node1->hash)
9276           mergeGraphNodes (node, node1);
9277         else
9278           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9279         */
9280       } // if
9281       node1 = node1next;
9282     } // while (node1)
9283     node = node->next;
9284   } // while (node)
9285 #endif
9286
9287 #if 0
9288   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9289   // assign tightly coupled operands to the same (pseudo) bank
9290   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9291   mergeMore = 1;
9292   absMaxWeight = 0;
9293   while (mergeMore) {
9294     node = adj->node;
9295     max = NULL;
9296     maxWeight = 0;
9297     while (node) {
9298       curr0 = getEffectiveBank (node->hash);
9299       if (curr0 < 0) { node = node->next; continue; }
9300       edge = node->edge;
9301       while (edge) {
9302         assert (edge->src == node);
9303         backedge = getGEdge (edge->node, edge->src);
9304         weight = edge->weight + (backedge ? backedge->weight : 0);
9305         curr1 = getEffectiveBank (edge->node->hash);
9306         if (curr1 < 0) { edge = edge->next; continue; }
9307
9308         // merging is only useful if the items are not assigned to the same bank already...
9309         if (curr0 != curr1 && weight > maxWeight) {
9310           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9311           maxWeight = weight;
9312           max = edge;
9313         } // if
9314         edge = edge->next;
9315       } // while
9316       node = node->next;
9317     } // while
9318     
9319     if (maxWeight > 0) {
9320 #if 0
9321       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9322                max->src->hash, getSymFromBank (max->src->hash),
9323                max->node->hash, getSymFromBank (max->node->hash));
9324 #endif
9325
9326       node = getGNode (adj, max->src->data, max->src->hash);
9327       node1 = getGNode (adj, max->node->data, max->node->hash);
9328
9329       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9330         if (max->src->hash < max->node->hash)
9331           mergeGraphNodes (node, node1);
9332         else
9333           mergeGraphNodes (node1, node);
9334       } else {
9335         remGEdge (node, node1);
9336         remGEdge (node1, node);
9337         //mergeMore = 0;
9338       }
9339
9340     } else {
9341       mergeMore = 0;
9342     }
9343   } // while
9344 #endif
9345
9346 #if 1  
9347   // remove redundant BANKSELs
9348   //fprintf (stderr, "removing redundant BANKSELs\n");
9349   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9350     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9351   } // for pb
9352 #endif
9353
9354 #if 0
9355   fprintf (stderr, "display graph\n");
9356   showGraph ();
9357 #endif
9358
9359   deleteGraph (adj);
9360   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9361 }
9362
9363 /*** END of stuff belonging to the BANKSEL optimization ***/
9364
9365
9366
9367 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9368
9369 typedef unsigned int symbol_t;
9370 typedef unsigned int valnum_t;
9371 //typedef unsigned int hash_t;
9372
9373 #ifndef INT_TO_PTR
9374 #define INT_TO_PTR(x) (((char *) 0) + (x))
9375 #endif
9376
9377 #ifndef PTR_TO_INT
9378 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9379 #endif
9380
9381 /* statistics */
9382 static unsigned int pic16_df_removed_pcodes = 0;
9383 static unsigned int pic16_df_saved_bytes = 0;
9384 static unsigned int df_findall_sameflow = 0;
9385 static unsigned int df_findall_otherflow = 0;
9386 static unsigned int df_findall_in_vals = 0;
9387
9388 static void pic16_df_stats () {
9389   return;
9390   if (pic16_debug_verbose || pic16_pcode_verbose) {
9391     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9392     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9393     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9394   }
9395 }
9396
9397 /* Remove a pCode iff possible:
9398  * - previous pCode is no SKIP
9399  * - pc has no label
9400  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9401 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9402   pCode *pcprev, *pcnext;
9403   char buf[256], *total=NULL;
9404   int len;
9405   
9406   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9407
9408   pcprev = pic16_findPrevInstruction (pc->prev);
9409   pcnext = pic16_findNextInstruction (pc->next);
9410   
9411   /* if previous instruction is a skip -- do not remove */
9412   if (pcprev && isPCI_SKIP(pcprev)) return 0;
9413
9414   /* move labels to next instruction (if possible) */
9415   if (PCI(pc)->label && !pcnext) return 0;
9416
9417   if (PCI(pc)->label) {
9418     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9419     //pc->print (stderr, pc);
9420     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9421     PCI(pc)->label = NULL;
9422   }
9423   
9424   /* update statistics */
9425   pic16_df_removed_pcodes++;
9426   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9427   
9428   /* remove the pCode */
9429   pic16_pCode2str (buf, 256, pc);
9430   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9431   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9432     len = strlen (buf) + strlen (comment) + 10;
9433     total = (char *) Safe_malloc (len);
9434     snprintf (total, len, "%s: %s", comment, buf);
9435     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9436     Safe_free (total);
9437   }
9438
9439   /* actually unlink it from the pBlock -- also remove from to/from lists */
9440   pic16_pCodeUnlink (pc);
9441
9442   /* remove the pCode -- release registers */
9443   pc->destruct (pc);
9444
9445   /* report success */
9446   return 1;
9447 }
9448
9449
9450 /* ======================================================================== */
9451 /* === SYMBOL HANDLING ==================================================== */
9452 /* ======================================================================== */
9453
9454 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9455 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9456 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9457
9458 /** Calculate a hash for a given string.
9459  * If len == 0 the string is assumed to be NUL terminated. */
9460 static hash_t symbolHash (const char *str, unsigned int len) {
9461   hash_t hash = 0;
9462   if (!len) {
9463     while (*str) {
9464       hash = (hash << 2) ^ *str;
9465       str++;
9466     } // while
9467   } else {
9468     while (len--) {
9469       hash = (hash << 2) ^ *str;
9470       str++;
9471     }
9472   }
9473   return hash;
9474 }
9475
9476 /** Return 1 iff strings v1 and v2 are identical. */
9477 static int symcmp (const void *v1, const void *v2) {
9478   return !strcmp ((const char *) v1, (const char *) v2);
9479 }
9480
9481 /** Return 1 iff pointers v1 and v2 are identical. */
9482 static int ptrcmp (const void *v1, const void *v2) {
9483   return (v1 == v2);
9484 }
9485
9486 enum {  SPO_WREG=0x1000,
9487         SPO_STATUS,
9488         SPO_PRODL,
9489         SPO_PRODH,
9490         SPO_INDF0,
9491         SPO_POSTDEC0,
9492         SPO_POSTINC0,
9493         SPO_PREINC0,
9494         SPO_PLUSW0,
9495         SPO_INDF1,
9496         SPO_POSTDEC1,
9497         SPO_POSTINC1,
9498         SPO_PREINC1,
9499         SPO_PLUSW1,
9500         SPO_INDF2,
9501         SPO_POSTDEC2,
9502         SPO_POSTINC2,
9503         SPO_PREINC2,
9504         SPO_PLUSW2,
9505         SPO_STKPTR,
9506         SPO_TOSL,
9507         SPO_TOSH,
9508         SPO_TOSU,
9509         SPO_BSR,
9510         SPO_FSR0L,
9511         SPO_FSR0H,
9512         SPO_FSR1L,
9513         SPO_FSR1H,
9514         SPO_FSR2L,
9515         SPO_FSR2H,
9516         SPO_PCL,
9517         SPO_PCLATH,
9518         SPO_PCLATU,
9519         SPO_TABLAT,
9520         SPO_TBLPTRL,
9521         SPO_TBLPTRH,
9522         SPO_TBLPTRU,
9523         SPO_LAST
9524 };
9525
9526 /* Return the unique symbol_t for the given string. */
9527 static symbol_t symFromStr (const char *str) {
9528   hash_t hash;
9529   char *res;
9530   symbol_t sym;
9531
9532   if (!map_symToStr) {
9533     int i;
9534     map_strToSym = newHashTable (128);
9535     map_symToStr = newHashTable (128);
9536
9537     struct { char *name; symbol_t sym; } predefsyms[] = {
9538         {"WREG", SPO_WREG},
9539         {"STATUS", SPO_STATUS},
9540         {"PRODL", SPO_PRODL},
9541         {"PRODH", SPO_PRODH},
9542         {"INDF0", SPO_INDF0},
9543         {"POSTDEC0", SPO_POSTDEC0},
9544         {"POSTINC0", SPO_POSTINC0},
9545         {"PREINC0", SPO_PREINC0},
9546         {"PLUSW0", SPO_PLUSW0},
9547         {"INDF1", SPO_INDF1},
9548         {"POSTDEC1", SPO_POSTDEC1},
9549         {"POSTINC1", SPO_POSTINC1},
9550         {"PREINC1", SPO_PREINC1},
9551         {"PLUSW1", SPO_PLUSW1},
9552         {"INDF2", SPO_INDF2},
9553         {"POSTDEC2", SPO_POSTDEC2},
9554         {"POSTINC2", SPO_POSTINC2},
9555         {"PREINC2", SPO_PREINC2},
9556         {"PLUSW2", SPO_PLUSW2},
9557         {"STKPTR", SPO_STKPTR},
9558         {"TOSL", SPO_TOSL},
9559         {"TOSH", SPO_TOSH},
9560         {"TOSU", SPO_TOSU},
9561         {"BSR", SPO_BSR},
9562         {"FSR0L", SPO_FSR0L},
9563         {"FSR0H", SPO_FSR0H},
9564         {"FSR1L", SPO_FSR1L},
9565         {"FSR1H", SPO_FSR1H},
9566         {"FSR2L", SPO_FSR2L},
9567         {"FSR2H", SPO_FSR2H},
9568         {"PCL", SPO_PCL},
9569         {"PCLATH", SPO_PCLATH},
9570         {"PCLATU", SPO_PCLATU},
9571         {"TABLAT", SPO_TABLAT},
9572         {"TBLPTRL", SPO_TBLPTRL},
9573         {"TBLPTRH", SPO_TBLPTRH},
9574         {"TBLPTRU", SPO_TBLPTRU},
9575         {NULL, 0}
9576     };
9577
9578     for (i=0; predefsyms[i].name; i++) {
9579       char *name;
9580
9581       /* enter new symbol */
9582       sym = predefsyms[i].sym;
9583       name = predefsyms[i].name;
9584       res = Safe_strdup (name);
9585       hash = symbolHash (name, 0);
9586
9587       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9588       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9589     } // for i
9590   }
9591
9592   hash = symbolHash (str, 0) % map_strToSym->size;
9593   
9594   /* find symbol in table */
9595   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9596   if (sym) {
9597     //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9598     return sym;
9599   }
9600
9601   /* enter new symbol */
9602   sym = nextSymbol++;
9603   res = Safe_strdup (str);
9604
9605   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9606   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9607
9608   //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9609   
9610   return sym;
9611 }
9612
9613 #if 1
9614 static const char *strFromSym (symbol_t sym) {
9615   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9616 }
9617 #endif
9618
9619 /* ======================================================================== */
9620 /* === DEFINITION MAP HANDLING ============================================ */
9621 /* ======================================================================== */
9622
9623 /* A defmap provides information about which symbol is defined by which pCode.
9624  * The most recent definitions are prepended to the list, so that the most
9625  * recent definition can be found by forward scanning the list.
9626  * pc2: MOVFF r0x00, r0x01
9627  * pc1: INCF r0x01
9628  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9629  *
9630  * We attach one defmap to each flow object, and each pCode will occur at
9631  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9632  * used to find definitions for a pCode in its own defmap that precede pCode.
9633  */
9634
9635 typedef struct defmap_s {
9636   symbol_t sym;                 /** symbol this item refers to */
9637   union {
9638     struct {
9639       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9640       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9641       int isRead:1;             /** sym/mask is read */
9642       int isWrite:1;            /** sym/mask is written */
9643     } access;
9644     int accessmethod;
9645   };
9646   pCode *pc;                    /** pCode this symbol is refrenced at */
9647   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9648   valnum_t val;                 /** new unique number for this value (if isWrite) */
9649   struct defmap_s *prev, *next; /** link to previous an next definition */
9650 } defmap_t;
9651
9652 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9653 static int defmap_free_count = 0;               /** number of released defmap items */
9654
9655 /* Returns a defmap_t with the specified data; this will be the new list head.
9656  * next - pointer to the current list head */
9657 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9658   defmap_t *map;
9659   
9660   if (defmap_free) {
9661     map = defmap_free;
9662     defmap_free = map->next;
9663     --defmap_free_count;
9664   } else {
9665     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9666   }
9667   map->sym = sym;
9668   map->access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9669   map->access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9670   map->access.isRead = (isRead != 0);
9671   map->access.isWrite = (isWrite != 0);
9672   map->pc = pc;
9673   map->in_val = 0;
9674   map->val = (isWrite ? val : 0);
9675   map->prev = NULL;
9676   map->next = next;
9677   if (next) next->prev = map;
9678   
9679   return map;
9680 }
9681
9682 /* Returns a copy of the single defmap item. */
9683 static defmap_t *copyDefmap (defmap_t *map) {
9684   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9685   memcpy (res, map, sizeof (defmap_t));
9686   res->next = NULL;
9687   res->prev = NULL;
9688   return res;
9689 }
9690
9691 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9692  * item is copied before insertion into chain and therefore left untouched.
9693  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9694 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9695   defmap_t *dummy;
9696   dummy = *head;
9697   while (dummy && (dummy->sym != item->sym
9698                           || dummy->pc != item->pc
9699                           || dummy->accessmethod != item->accessmethod
9700                           || dummy->val != item->val
9701                           || dummy->in_val != item->in_val)) {
9702     dummy = dummy->next;
9703   } // while
9704
9705   /* item already present? */
9706   if (dummy) return 0;
9707   
9708   /* otherwise: insert copy of item */
9709   dummy = copyDefmap (item);
9710   dummy->next = *head;
9711   if (*head) (*head)->prev = dummy;
9712   *head = dummy;
9713
9714   return 1;
9715 }
9716
9717 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9718 static void deleteDefmap (defmap_t *map) {
9719   if (!map) return;
9720   
9721   /* unlink from chain -- fails for the first item (head is not updated!) */
9722   if (map->next) map->next->prev = map->prev;
9723   if (map->prev) map->prev->next = map->next;
9724
9725   /* clear map */
9726   memset (map, 0, sizeof (defmap_t));
9727
9728   /* save for future use */
9729   map->next = defmap_free;
9730   defmap_free = map;
9731   ++defmap_free_count;
9732 }
9733
9734 /* Release all defmaps referenced from map. */
9735 static void deleteDefmapChain (defmap_t **_map) {
9736   defmap_t *map, *next;
9737
9738   if (!_map) return;
9739
9740   map = *_map;
9741   
9742   /* find list head */
9743   while (map && map->prev) map = map->prev;
9744
9745   /* delete all items */
9746   while (map) {
9747     next = map->next;
9748     deleteDefmap (map);
9749     map = next;
9750   } // while
9751
9752   *_map = NULL;
9753 }
9754
9755 /* Free all defmap items. */
9756 static void freeDefmap (defmap_t **_map) {
9757   defmap_t *next;
9758   defmap_t *map;
9759
9760   if (!_map) return;
9761
9762   map = (*_map);
9763   
9764   /* find list head */
9765   while (map->prev) map = map->prev;
9766
9767   /* release all items */
9768   while (map) {
9769     next = map->next;
9770     Safe_free (map);
9771     map = next;
9772   }
9773
9774   (*_map) = NULL;
9775 }
9776
9777 /* Returns the most recent definition for the given symbol preceeding pc.
9778  * If no definition is found, NULL is returned. 
9779  * If pc == NULL the whole list is scanned. */
9780 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9781   defmap_t *curr = map;
9782
9783   if (pc) {
9784     /* skip all definitions up to pc */
9785     while (curr && (curr->pc != pc)) curr = curr->next;
9786
9787     /* pc not in the list -- scan the whole list for definitions */
9788     if (!curr) {
9789       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9790       curr = map;
9791     } else {
9792       /* skip all definitions performed by pc */
9793       while (curr && (curr->pc == pc)) curr = curr->next;
9794     }
9795   } // if (pc)
9796
9797   /* find definition for sym */
9798   while (curr && (!curr->access.isWrite || (curr->sym != sym))) {
9799     curr = curr->next;
9800   }
9801
9802   return curr;
9803 }
9804
9805 #if 0
9806 /* Returns the first use (read) of the given symbol AFTER pc.
9807  * If no such use is found, NULL is returned.
9808  * If pc == NULL the whole list is scanned. */
9809 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9810   defmap_t *curr = map, *prev = NULL;
9811   
9812   if (pc) {
9813     /* skip all definitions up to pc */
9814     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9815
9816     /* pc not in the list -- scan the whole list for definitions */
9817     if (!curr) {
9818       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9819       curr = prev;
9820     }
9821   } else {
9822     /* find end of list */
9823     while (curr && curr->next) curr = curr->next;
9824   } // if (pc)
9825
9826   /* find use of sym (scan list backwards) */
9827   while (curr && (!curr->access.isRead || (curr->sym != sym))) curr = curr->prev;
9828
9829   return curr;
9830 }
9831 #endif
9832
9833 /* Return the defmap entry for sym AT pc. 
9834  * If none is found, NULL is returned.
9835  * If more than one entry is found an assertion is triggered. */
9836 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9837   defmap_t *res = NULL;
9838
9839   /* find entries for pc */
9840   while (map && map->pc != pc) map = map->next;
9841
9842   /* find first entry for sym @ pc */
9843   while (map && map->pc == pc && map->sym != sym) map = map->next;
9844
9845   /* no entry found */
9846   if (!map) return NULL;
9847
9848   /* check for more entries */
9849   res = map;
9850   map = map->next;
9851   while (map && map->pc == pc) {
9852     /* more than one entry for sym @ pc found? */
9853     assert (map->sym != sym);
9854     map = map->next;
9855   }
9856
9857   /* return single entry for sym @ pc */
9858   return res;
9859 }
9860
9861 /* Modifies the definition of sym at pCode to newval.
9862  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9863  */
9864 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9865   defmap_t *m  = map;
9866
9867   /* find definitions of pc */
9868   while (m && m->pc != pc) m = m->next;
9869
9870   /* find definition of sym at pc */
9871   while (m && m->pc == pc && (!m->access.isWrite || (m->sym != sym))) m = m->next;
9872   
9873   /* no definition found */
9874   if (!m) return 1;
9875
9876   /* redefine */
9877   m->val = newval;
9878
9879   /* update following uses of sym */
9880   while (m && m->pc == pc) m = m->prev;
9881   while (m) {
9882     if (m->sym == sym) {
9883       m->in_val = newval;
9884       if (m->access.isWrite) m = NULL;
9885     } // if
9886     if (m) m = m->prev;
9887   } // while
9888   
9889   return 0;
9890 }
9891
9892 /* ======================================================================== */
9893 /* === STACK ROUTINES ===================================================== */
9894 /* ======================================================================== */
9895
9896 typedef struct stack_s {
9897   void *data;
9898   struct stack_s *next;
9899 } stackitem_t;
9900
9901 typedef stackitem_t *stack_t;
9902 static stackitem_t *free_stackitems = NULL;
9903
9904 /* Create a stack with one item. */
9905 static stack_t *newStack () {
9906   stack_t *s = (stack_t *) Safe_malloc (sizeof (stack_t));
9907   *s = NULL;
9908   return s;
9909 }
9910
9911 /* Remove a stack -- its items are only marked free. */
9912 static void deleteStack (stack_t *s) {
9913   stackitem_t *i;
9914
9915   while (*s) {
9916     i = *s;
9917     *s = (*s)->next;
9918     i->next = free_stackitems;
9919     free_stackitems = i;
9920   } // while
9921   Safe_free (s);
9922 }
9923
9924 /* Release all stackitems. */
9925 static void releaseStack () {
9926   stackitem_t *i;
9927   
9928   while (free_stackitems) {
9929     i = free_stackitems->next;
9930     Safe_free(free_stackitems);
9931     free_stackitems = i;
9932   } // while
9933 }
9934
9935 static void stackPush (stack_t *stack, void *data) {
9936   stackitem_t *i;
9937   
9938   if (free_stackitems) {
9939     i = free_stackitems;
9940     free_stackitems = free_stackitems->next;
9941   } else {
9942     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9943   }
9944   i->data = data;
9945   i->next = *stack;
9946   *stack = i;
9947 }
9948
9949 static void *stackPop (stack_t *stack) {
9950   void *data;
9951   stackitem_t *i;
9952   
9953   if (stack && *stack) {
9954     data = (*stack)->data;
9955     i = *stack;
9956     *stack = (*stack)->next;
9957     i->next = free_stackitems;
9958     free_stackitems = i;
9959     return data;
9960   } else {
9961     return NULL;
9962   }
9963 }
9964
9965 #if 0
9966 static int stackContains (stack_t *s, void *data) {
9967   stackitem_t *i;
9968   if (!s) return 0;
9969   i = *s;
9970   while (i) {
9971     if (i->data == data) return 1;
9972     i = i->next;
9973   } // while
9974
9975   /* not found */
9976   return 0;
9977 }
9978 #endif
9979
9980 static int stackIsEmpty (stack_t *s) {
9981   return (*s == NULL);
9982 }
9983
9984
9985 typedef struct {
9986   pCodeFlow *flow;
9987   defmap_t *lastdef;
9988 } state_t;
9989
9990 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9991   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9992   s->flow = flow;
9993   s->lastdef = lastdef;
9994   return s;
9995 }
9996
9997 static void deleteState (state_t *s) {
9998   Safe_free (s);
9999 }
10000
10001 static int stateIsNew (state_t *state, stack_t *todo, stack_t *done) {
10002   stackitem_t *i;
10003
10004   /* scan working list for state */
10005   if (todo) {
10006     i = *todo;
10007     while (i) {
10008       /* is i == state? -- state not new */
10009       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10010       i = i->next;
10011     } // while
10012   }
10013
10014   if (done) {
10015     i = *done;
10016     while (i) {
10017       /* is i == state? -- state not new */
10018       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10019       i = i->next;
10020     } // while
10021   }
10022
10023   /* not found -- state is new */
10024   return 1;
10025 }
10026
10027 static inline valnum_t newValnum ();
10028
10029 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10030   pCode *pc;
10031
10032   if (!pb) return "<unknown function>";
10033
10034   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10035   if (pc && isPCF(pc)) return PCF(pc)->fname;
10036   else return "<unknown function>";
10037 }
10038
10039 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10040   defmap_t *map;
10041   pCodeFlow *pcfl;
10042
10043   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10044
10045   /* find initial value (assigning pc == NULL) */
10046   map = PCFL(pcfl)->in_vals;
10047   while (map && map->sym != sym) map = map->next;
10048
10049   /* initial value already present? */
10050   if (map) {
10051     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10052     return map;
10053   }
10054
10055   /* create a new initial value */
10056   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10057   PCFL(pcfl)->in_vals = map;
10058   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10059   return map;
10060
10061 #if 0
10062   /* insert map as last item in pcfl's defmap */
10063   if (!prev) prev = PCFL(pcfl)->defmap;
10064   if (!prev) {
10065     PCFL(pcfl)->defmap = map;
10066   } else {
10067     while (prev->next) prev = prev->next;
10068     prev->next = map;
10069     map->prev = prev;
10070   }
10071
10072   return map;
10073 #endif
10074 }
10075
10076 /* Find all reaching definitions for sym at pc. 
10077  * A new (!) list of definitions is returned.
10078  * Returns the number of reaching definitions found.
10079  * The defining defmap entries are returned in *chain.
10080  */
10081 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10082   defmap_t *map;
10083   defmap_t *res;
10084
10085   pCodeFlow *curr;
10086   pCodeFlowLink *succ;
10087   state_t *state;
10088   stack_t *todo;        /** stack of state_t */
10089   stack_t *done;        /** stack of state_t */
10090
10091   int firstState, n_defs;
10092   
10093   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10094   assert (chain);
10095
10096   /* initialize return list */
10097   *chain = NULL;
10098
10099   /* wildcard symbol? */
10100   if (!sym) return 0;
10101   
10102   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10103   
10104   map = PCI(pc)->pcflow->defmap;
10105
10106   res = defmapFindDef (map, sym, pc);
10107   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10108
10109 #define USE_PRECALCED_INVALS 1
10110 #if USE_PRECALCED_INVALS
10111   if (!res && PCI(pc)->pcflow->in_vals) {
10112     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10113     if (res) {
10114       //fprintf  (stderr, "found def in init values\n");
10115       df_findall_in_vals++;
10116     }
10117   }
10118 #endif
10119
10120   if (res) {
10121     // found a single definition (in pc's flow)
10122     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10123     defmapAddCopyIfNew (chain, res);
10124     df_findall_sameflow++;
10125     return 1;
10126   }
10127
10128 #if USE_PRECALCED_INVALS
10129   else {
10130     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10131     return 1;
10132   }
10133
10134 #endif
10135   
10136 #define FORWARD_FLOW_ANALYSIS 1
10137 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10138   /* no definition found in pc's flow preceeding pc */
10139   todo = newStack ();
10140   done = newStack ();
10141   n_defs = 0; firstState = 1;
10142   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10143
10144   while (!stackIsEmpty (todo)) {
10145     state = (state_t *) stackPop (todo);
10146     stackPush (done, state);
10147     curr = state->flow;
10148     res = state->lastdef;
10149     //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);
10150
10151     /* there are no definitions BEFORE pc in pc's flow (see above) */
10152     if (curr == PCI(pc)->pcflow) {
10153       if (!res) {
10154         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10155         res = pic16_pBlockAddInval (pc->pb, sym);
10156         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10157         res = NULL;
10158       } else {
10159         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10160         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10161       }
10162     }
10163
10164     /* save last definition of sym in this flow as initial def in successors */
10165     res = defmapFindDef (curr->defmap, sym, NULL);
10166     if (!res) res = state->lastdef;
10167     
10168     /* add successors to working list */
10169     state = newState (NULL, NULL);
10170     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10171     while (succ) {
10172       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10173       state->flow = succ->pcflow;
10174       state->lastdef = res;
10175       if (stateIsNew (state, todo, done)) {
10176         stackPush (todo, state);
10177         state = newState (NULL, NULL);
10178       } // if
10179       succ = (pCodeFlowLink *) setNextItem (curr->to);
10180     } // while
10181     deleteState (state);
10182   } // while
10183
10184 #else // !FORWARD_FLOW_ANALYSIS 
10185
10186   /* no definition found in pc's flow preceeding pc */
10187   todo = newStack ();
10188   done = newStack ();
10189   n_defs = 0; firstState = 1;
10190   stackPush (todo, newState (PCI(pc)->pcflow, res));
10191
10192   while (!stackIsEmpty (todo)) {
10193     state = (state_t *) stackPop (todo);
10194     curr = state->flow;
10195
10196     if (firstState) {
10197       firstState = 0;
10198       /* only check predecessor flows */
10199     } else {
10200       /* get (last) definition of sym in this flow */
10201       res = defmapFindDef (curr->defmap, sym, NULL);
10202     }
10203
10204     if (res) {
10205       /* definition found */
10206       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10207       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10208     } else {
10209       /* no definition found -- check predecessor flows */
10210       state = newState (NULL, NULL);
10211       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10212
10213       /* if no flow predecessor available -- sym might be uninitialized */
10214       if (!succ) {
10215         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10216         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10217         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10218         deleteDefmap (res); res = NULL;
10219       }
10220       
10221       while (succ) {
10222         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10223         state->flow = succ->pcflow;
10224         state->lastdef = res;
10225         if (stateIsNew (state, todo, done)) {
10226           stackPush (todo, state);
10227           state = newState (NULL, NULL);
10228         } // if
10229         succ = (pCodeFlowLink *) setNextItem (curr->from);
10230       } // while
10231       deleteState (state);
10232     }
10233   } // while
10234
10235 #endif
10236
10237   /* clean up done stack */
10238   while (!stackIsEmpty(done)) {
10239     deleteState ((state_t *) stackPop (done));
10240   } // while
10241   deleteStack (done);
10242
10243   /* return number of items in result set */
10244   if (n_defs == 0) {
10245     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10246   } else if (n_defs == 1) {
10247     assert (*chain);
10248     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10249   } else if (n_defs > 0) {
10250     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10251 #if 0
10252     res = *chain;
10253     while (res) {
10254       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10255       res = res->next;
10256     } // while
10257 #endif
10258   }
10259   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10260   df_findall_otherflow++;
10261   return n_defs;
10262 }
10263
10264 /* ======================================================================== */
10265 /* === VALUE NUMBER HANDLING ============================================== */
10266 /* ======================================================================== */
10267
10268 static valnum_t nextValnum = 0x1000;
10269 static hTab *map_symToValnum = NULL;
10270
10271 /** Return a new value number. */
10272 static inline valnum_t newValnum () {
10273   return (nextValnum += 4);
10274 }
10275
10276 static valnum_t valnumFromStr (const char *str) {
10277   symbol_t sym;
10278   valnum_t val;
10279   void *res;
10280   
10281   sym = symFromStr (str);
10282
10283   if (!map_symToValnum) {
10284     map_symToValnum = newHashTable (128);
10285   } // if
10286
10287   /* literal already known? */
10288   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10289
10290   /* return existing valnum */
10291   if (res) return (valnum_t) PTR_TO_INT(res);
10292   
10293   /* create new valnum */
10294   val = newValnum();
10295   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10296   return val;
10297 }
10298
10299 /* Create a valnum for a literal. */
10300 static valnum_t valnumFromLit (unsigned int lit) {
10301   return ((valnum_t) 0x100 + (lit & 0x0FF));
10302 }
10303
10304 /* Return the (positive) literal value represented by val
10305  * or -1 iff val is no known literal's valnum. */
10306 static int litFromValnum (valnum_t val) {
10307   if (val >= 0x100 && val < 0x200) {
10308     /* valnum is a (known) literal */
10309     return val & 0x00FF;
10310   } else {
10311     /* valnum is not a known literal */
10312     return -1;
10313   }
10314 }
10315
10316 #if 0
10317 /* Sanity check - all flows in a block must be reachable from initial flow. */
10318 static int verifyAllFlowsReachable (pBlock *pb) {
10319   set *reached;
10320   set *flowInBlock;
10321   set *checked;
10322   pCode *pc;
10323   pCodeFlow *pcfl;
10324   pCodeFlowLink *succ;
10325   int res;
10326
10327   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10328
10329   reached = NULL;
10330   flowInBlock = NULL;
10331   checked = NULL;
10332   /* mark initial flow as reached (and "not needs to be reached") */
10333   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10334   assert (pc);
10335   addSetHead (&reached, pc);
10336   addSetHead (&checked, pc);
10337   
10338   /* mark all further flows in block as "need to be reached" */
10339   pc = pb->pcHead;
10340   do {
10341     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10342     pc = pic16_findNextInstruction (pc->next);
10343   } while (pc);
10344
10345   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10346     /* mark as reached and "not need to be reached" */
10347     deleteSetItem (&reached, pcfl);
10348     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10349     
10350     /* flow is no longer considered unreachable */
10351     deleteSetItem (&flowInBlock, pcfl);
10352
10353     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10354       if (!isinSet (checked, succ->pcflow)) {
10355         /* flow has never been reached before */
10356         addSetHead (&reached, succ->pcflow);
10357         addSetHead (&checked, succ->pcflow);
10358       } // if
10359     } // for succ
10360   } // while
10361
10362   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10363
10364   /* by now every flow should have been reached
10365    * --> flowInBlock should be empty */
10366   res = (flowInBlock == NULL);
10367
10368 #if 1
10369   if (flowInBlock) {
10370           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10371     while (flowInBlock) {
10372       pcfl = indexSet (flowInBlock, 0);
10373       fprintf (stderr, "not reached: flow %p\n", pcfl);
10374       deleteSetItem (&flowInBlock, pcfl);
10375     } // while
10376   }
10377 #endif
10378   
10379   /* clean up */
10380   deleteSet (&reached);
10381   deleteSet (&flowInBlock);
10382   deleteSet (&checked);
10383   
10384   /* if we reached every flow, succ is NULL by now... */
10385   //assert (res); // will fire on unreachable code...
10386   return (res);
10387 }
10388 #endif
10389
10390 /* Checks a flow for accesses to sym AFTER pc.
10391  * 
10392  * Returns -1 if the symbol is read in this flow (before redefinition),
10393  * returns 0 if the symbol is redefined in this flow or
10394  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10395  */
10396 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10397   defmap_t *map, *mappc;
10398
10399   /* find pc or start of definitions */
10400   map = pcfl->defmap;
10401   while (map && (map->pc != pc) && map->next) map = map->next;
10402   /* if we found pc -- ignore it */
10403   while (map && map->pc == pc) map = map->prev;
10404
10405   /* scan list backwards (first definition first) */
10406   while (map && mask) {
10407 //    if (map->sym == sym) {
10408       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10409       mappc = map;
10410       /* scan list for reads at this pc first */
10411       while (map && map->pc == mappc->pc) {
10412         /* is the symbol (partially) read? */
10413         if ((map->sym == sym) && (map->access.isRead && ((map->access.in_mask & mask) != 0))) {
10414           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10415           return -1;
10416         }
10417         map = map->prev;
10418       } // while
10419       map = mappc;
10420
10421       while (map && map->pc == mappc->pc) {
10422         /* honor (partial) redefinitions of sym */
10423         if ((map->sym == sym) && (map->access.isWrite)) {
10424           mask &= ~map->access.mask;
10425           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10426         }
10427         map = map->prev;
10428       } // while
10429 //    } // if
10430     /* map already points to the first defmap for the next pCode */
10431     //map = mappc->prev;
10432   } // while
10433
10434   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10435    * is still alive; return the appropriate mask of alive bits */
10436   return mask;
10437 }
10438
10439 /* Check whether a symbol is alive (AFTER pc). */
10440 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10441   int mask, visit;
10442   defmap_t *map;
10443   stack_t *todo, *done;
10444   state_t *state;
10445   pCodeFlow *pcfl;
10446   pCodeFlowLink *succ;
10447
10448   mask = 0x00ff;
10449   
10450   assert (isPCI(pc));
10451   pcfl = PCI(pc)->pcflow;
10452   map = pcfl->defmap;
10453
10454   todo = newStack ();
10455   done = newStack ();
10456   
10457   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10458   stackPush (todo, state);
10459   visit = 0;
10460   
10461   while (!stackIsEmpty (todo)) {
10462     state = (state_t *) stackPop (todo);
10463     pcfl = state->flow;
10464     mask = PTR_TO_INT(state->lastdef);
10465     if (visit) stackPush (done, state); else deleteState(state);
10466     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10467     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10468     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10469     visit++;
10470
10471     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10472     if (mask == 0) continue;
10473
10474     /* symbol is (partially) read before redefinition in flow */
10475     if (mask == -1) break;
10476
10477     /* symbol is neither read nor completely redefined -- check successor flows */
10478     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10479       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10480       if (stateIsNew (state, todo, done)) {
10481         stackPush (todo, state);
10482       } else {
10483         deleteState (state);
10484       }
10485     } // for
10486   } // while
10487
10488   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10489   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10490
10491   /* symbol is read in at least one flow -- is alive */
10492   if (mask == -1) return 1;
10493
10494   /* symbol is read in no flow */
10495   return 0;
10496 }
10497
10498 /* Returns whether access to the given symbol has side effects. */
10499 static int pic16_symIsSpecial (symbol_t sym) {
10500   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10501   switch (sym) {
10502   case SPO_INDF0:
10503   case SPO_PLUSW0:
10504   case SPO_POSTINC0:
10505   case SPO_POSTDEC0:
10506   case SPO_PREINC0:
10507   case SPO_INDF1:
10508   case SPO_PLUSW1:
10509   case SPO_POSTINC1:
10510   case SPO_POSTDEC1:
10511   case SPO_PREINC1:
10512   case SPO_INDF2:
10513   case SPO_PLUSW2:
10514   case SPO_POSTINC2:
10515   case SPO_POSTDEC2:
10516   case SPO_PREINC2:
10517   case SPO_PCL:
10518           return 1;
10519   default:
10520           /* no special effects known */
10521           return 0;
10522   } // switch
10523
10524   return 0;
10525 }
10526
10527 /* Check whether a register should be considered local (to the current function) or not. */
10528 static int pic16_regIsLocal (regs *r) {
10529   symbol_t sym;
10530   if (r) {
10531     sym = symFromStr (r->name);
10532     switch (sym) {
10533     case SPO_WREG:
10534     case SPO_FSR0L: // used in ptrget/ptrput
10535     case SPO_FSR0H: // ... as well
10536     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10537     case SPO_FSR1H: // ... as well
10538     case SPO_FSR2L: // used as frame pointer
10539     case SPO_FSR2H: // ... as well
10540     case SPO_PRODL: // used to return values from functions
10541     case SPO_PRODH: // ... as well
10542       /* these registers (and some more...) are considered local */
10543       return 1;
10544       break;
10545     default:
10546       /* for unknown regs: check is marked local, leave if not */
10547       if (r->isLocal) {
10548         return 1;
10549       } else {
10550         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10551         return 0;
10552       }
10553     } // switch
10554   } // if
10555
10556   /* if in doubt, assume non-local... */
10557   return 0;
10558 }
10559
10560 /* Check all symbols touched by pc whether their newly assigned values are read.
10561  * Returns 0 if no symbol is used later on, 1 otherwise. */
10562 static int pic16_pCodeIsAlive (pCode *pc) {
10563   pCodeInstruction *pci;
10564   defmap_t *map, *lastpc;
10565   regs *checkreg;
10566   
10567   /* we can only handle PCIs */
10568   if (!isPCI(pc)) return 1;
10569
10570   //pc->print (stderr, pc);
10571
10572   pci = PCI(pc);
10573   assert (pci && pci->pcflow && pci->pcflow->defmap);
10574
10575   /* NEVER remove instructions with implicit side effects */
10576   switch (pci->op) {
10577   case POC_TBLRD:
10578   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10579   case POC_TBLRD_POSTDEC:
10580   case POC_TBLRD_PREINC:
10581   case POC_TBLWT:               /* modify program memory */
10582   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10583   case POC_TBLWT_POSTDEC:
10584   case POC_TBLWT_PREINC:
10585   case POC_CLRWDT:              /* clear watchdog timer */
10586   case POC_PUSH:                /* should be safe to remove though... */
10587   case POC_POP:                 /* should be safe to remove though... */
10588   case POC_CALL:
10589   case POC_RCALL:
10590   case POC_RETFIE:
10591   case POC_RETURN:
10592     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10593     return 1;
10594
10595   default:
10596     /* no special instruction */
10597     break;
10598   } // switch
10599
10600   /* prevent us from removing assignments to non-local variables */
10601   checkreg = NULL;
10602   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10603   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10604
10605   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10606     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10607     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10608     //pc->print (stderr, pc);
10609     return 1;
10610   }
10611   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10612     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10613     return 1;
10614   }
10615   
10616 #if 1
10617   /* OVERKILL: prevent us from removing reads from non-local variables 
10618    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10619    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10620   checkreg = NULL;
10621   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10622   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10623
10624   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10625     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10626     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10627     //pc->print (stderr, pc);
10628     return 1;
10629   }
10630   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10631     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10632     return 1;
10633   }
10634 #endif
10635   
10636   /* now check that the defined symbols are not used */
10637   map = pci->pcflow->defmap;
10638   
10639   /* find items for pc */
10640   while (map && map->pc != pc) map = map->next;
10641
10642   /* no entries found? something is fishy with DF analysis... -- play safe */
10643   if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10644
10645   /* remember first item assigned to pc for later use */
10646   lastpc = map;
10647   
10648   /* check all symbols being modified by pc */
10649   while (map && map->pc == pc) {
10650     if (map->sym == 0) { map = map->next; continue; }
10651
10652     /* keep pc if it references special symbols (like POSTDEC0) */
10653 #if 0
10654     {
10655       char buf[256];
10656       pic16_pCode2str (buf, 256, pc);
10657       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10658     }
10659 #endif
10660     if (pic16_symIsSpecial (map->sym)) {
10661       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10662       return 1;
10663     }
10664     if (map->access.isWrite) {
10665       if (pic16_isAlive (map->sym, pc)) {
10666         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10667         return 1;
10668       }
10669     }
10670     map = map->next;
10671   } // while
10672
10673   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10674 #if 0
10675   {
10676     char buf[256];
10677     pic16_pCode2str (buf, 256, pc);
10678     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10679   }
10680 #endif
10681   return 0;
10682 }
10683
10684 /* Adds implied operands to the list.
10685  * sym - operand being accessed in the pCode
10686  * list - list to append the operand
10687  * isRead - set to 1 iff sym is read in pCode
10688  * listRead - set to 1 iff all operands being read are to be listed
10689  *
10690  * Returns 0 for "normal" operands, 1 for special operands.
10691  */
10692 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10693   /* check whether accessing REG accesses other REGs as well */
10694   switch (sym) {
10695   case SPO_INDF0:
10696     /* reads FSR0x */
10697     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10698     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10699     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10700     break;
10701     
10702   case SPO_PLUSW0:
10703     /* reads FSR0x and WREG */
10704     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10705     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10706     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10707     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10708     break;
10709     
10710   case SPO_POSTDEC0:
10711   case SPO_POSTINC0:
10712   case SPO_PREINC0:
10713     /* reads/modifies FSR0x */
10714     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10715     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10716     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10717     break;
10718
10719   case SPO_INDF1:
10720     /* reads FSR1x */
10721     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10722     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10723     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10724     break;
10725     
10726   case SPO_PLUSW1:
10727     /* reads FSR1x and WREG */
10728     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10729     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10730     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10731     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10732     break;
10733     
10734   case SPO_POSTDEC1:
10735   case SPO_POSTINC1:
10736   case SPO_PREINC1:
10737     /* reads/modifies FSR1x */
10738     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10739     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10740     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10741     break;
10742
10743   case SPO_INDF2:
10744     /* reads FSR2x */
10745     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10746     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10747     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10748     break;
10749     
10750   case SPO_PLUSW2:
10751     /* reads FSR2x and WREG */
10752     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10753     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10754     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10755     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10756     break;
10757     
10758   case SPO_POSTDEC2:
10759   case SPO_POSTINC2:
10760   case SPO_PREINC2:
10761     /* reads/modifies FSR2x */
10762     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10763     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10764     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10765     break;
10766
10767   case SPO_PCL:
10768     /* modifies PCLATH and PCLATU */
10769     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10770     if (isRead) {
10771       /* reading PCL updates PCLATx */
10772       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10773       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10774     }
10775     if (isWrite) {
10776       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10777       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10778       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10779     }
10780     break;
10781
10782   default:
10783     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10784     /* nothing special */
10785     return 0;
10786     break;
10787   }
10788
10789   /* has been a special operand */
10790   return 1;
10791 }
10792
10793 static symbol_t pic16_fsrsym_idx[][2] = {
10794     {SPO_FSR0L, SPO_FSR0H},
10795     {SPO_FSR1L, SPO_FSR1H},
10796     {SPO_FSR2L, SPO_FSR2H}
10797 };
10798   
10799 /** Prepend list with the reads and definitions performed by pc. */
10800 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10801   pCodeInstruction *pci;
10802   int cond, inCond, outCond;
10803   int mask = 0xff, smask;
10804   int isSpecial, isSpecial2;
10805   symbol_t sym, sym2;
10806   char *name;
10807
10808   if (isPCAD(pc)) {
10809     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10810     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10811     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10812     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10813     return list;
10814   }
10815   assert (isPCI(pc));
10816   pci = PCI(pc);
10817   
10818   /* handle bit instructions */
10819   if (pci->isBitInst) {
10820     assert (pci->pcop->type == PO_GPR_BIT);
10821     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10822   }
10823
10824   /* handle (additional) implicit arguments */
10825   switch (pci->op) {
10826   case POC_LFSR:
10827     {
10828       int lit;
10829       valnum_t val;
10830       lit = PCOL(pci->pcop)->lit;
10831       assert (lit >= 0 && lit < 3);
10832       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10833       val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10834       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10835       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10836       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...
10837     }
10838     break;
10839
10840   case POC_MOVLB: // BSR
10841   case POC_BANKSEL: // BSR
10842     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10843     break;
10844
10845   case POC_MULWF: // PRODx
10846   case POC_MULLW: // PRODx
10847     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10848     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10849     break;
10850
10851   case POC_POP: // TOS, STKPTR
10852     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10853     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10854     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10855     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10856     break;
10857     
10858   case POC_PUSH: // STKPTR
10859     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10860     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10861     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10862     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10863     break;
10864     
10865   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10866   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10867     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10868     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10869     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10870     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10871
10872     /* needs correctly set-up stack pointer */
10873     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10874     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10875     break;
10876
10877   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10878     /* pseudo read on (possible) return values */
10879     // WREG is handled below via outCond
10880     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10881     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10882     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10883
10884     /* caller's stack pointers must be restored */
10885     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10886     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10887     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10888     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10889     break;
10890
10891   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10892   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10893     /* pseudo read on (possible) return values */
10894     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10895     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10896     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10897     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10898
10899     /* caller's stack pointers must be restored */
10900     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10901     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10902     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10903     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10904     break;
10905     
10906   case POC_TBLRD:
10907     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10908     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10909     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10910     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10911     break;
10912     
10913   case POC_TBLRD_POSTINC:
10914   case POC_TBLRD_POSTDEC:
10915   case POC_TBLRD_PREINC:
10916     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10917     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10918     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10919     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10920     break;
10921     
10922   case POC_TBLWT:
10923     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10924     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10925     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10926     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10927     break;
10928     
10929   case POC_TBLWT_POSTINC:
10930   case POC_TBLWT_POSTDEC:
10931   case POC_TBLWT_PREINC:
10932     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10933     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10934     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10935     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10936     break;
10937     
10938   default:
10939     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10940     break;
10941   } // switch
10942
10943   /* handle explicit arguments */
10944   inCond = pci->inCond;
10945   outCond = pci->outCond;
10946   cond = inCond | outCond;
10947   if (cond & PCC_W) {
10948     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10949   } // if
10950
10951   /* keep STATUS read BEFORE STATUS write in the list */
10952   if (inCond & PCC_STATUS) {
10953     smask = 0;
10954     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10955     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10956     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10957     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10958     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10959
10960     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10961     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10962   } // if
10963   
10964   if (outCond & PCC_STATUS) {
10965     smask = 0;
10966     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10967     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10968     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10969     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10970     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10971
10972     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10973     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10974   } // if
10975   
10976   isSpecial = isSpecial2 = 0;
10977   sym = sym2 = 0;
10978   if (cond & PCC_REGISTER) {
10979     name = pic16_get_op (pci->pcop, NULL, 0);
10980     sym = symFromStr (name);
10981     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
10982     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
10983   }
10984
10985   if (cond & PCC_REGISTER2) {
10986     name = pic16_get_op2 (pci->pcop, NULL, 0);
10987     sym2 = symFromStr (name);
10988     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
10989     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
10990   }
10991
10992  
10993   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10994   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
10995   
10996   return list;
10997 }
10998
10999 #if 0
11000 static void printDefmap (defmap_t *map) {
11001   defmap_t *curr;
11002
11003   curr = map;
11004   fprintf (stderr, "defmap @ %p:\n", curr);
11005   while (curr) {
11006     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11007                     curr->access.isRead ? "R" : " ",
11008                     curr->access.isWrite ? "W": " ",
11009                     curr->in_val, curr->val,
11010                     curr->access.in_mask, curr->access.mask,
11011                     strFromSym(curr->sym), curr->sym,
11012                     curr->pc);
11013     curr = curr->next;
11014   } // while
11015   fprintf (stderr, "<EOL>\n");
11016 }
11017 #endif
11018
11019 /* Add "additional" definitions to uniq.
11020  * 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.
11021  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11022  *
11023  * If symbols defined in additional are not present in uniq, a definition is created.
11024  * Otherwise the present definition is altered to reflect the newer assignments.
11025  *
11026  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11027  *       before     `------- noted in additional --------'      after
11028  *
11029  * I assume that each symbol occurs AT MOST ONCE in uniq.
11030  *
11031  */
11032 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11033   defmap_t *curr;
11034   defmap_t *old;
11035   int change = 0;
11036
11037   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11038   /* find tail of additional list (holds the first assignment) */
11039   curr = additional;
11040   while (curr && curr->next) curr = curr->next;
11041
11042   /* update uniq */
11043   do {
11044     /* find next assignment in additionals */
11045     while (curr && !curr->access.isWrite) curr = curr->prev;
11046
11047     if (!curr) break;
11048
11049     /* find item in uniq */
11050     old = *uniq;
11051     //printDefmap (*uniq);
11052     while (old && (old->sym != curr->sym)) old = old->next;
11053
11054     if (old) {
11055       /* definition found -- replace */
11056       if (old->val != curr->val) {
11057         old->val = curr->val;
11058         change++;
11059       } // if
11060     } else {
11061       /* new definition */
11062       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11063       change++;
11064     }
11065
11066     curr = curr->prev;
11067   } while (1);
11068
11069   /* return 0 iff uniq remained unchanged */
11070   return change;
11071 }
11072
11073 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11074  * lists of its predecessor flows. 
11075  * Initially *combined should be NULL, alt_in will be copied to combined.
11076  * If *combined != NULL, combined will be altered:
11077  * - for symbols defined in *combined but not in alt_in,
11078  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11079  * - for symbols defined in alt_in but not in *combined,
11080  *   a 0 definition is created (value unknown, either INIT or alt).
11081  * - for symbols defined in both, *combined is:
11082  *   > left unchanged if *combined->val == alt_in->val or
11083  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11084  * 
11085  * I assume that each symbol occurs AT MOST ONCE in each list!
11086  */
11087 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11088   defmap_t *curr;
11089   defmap_t *old;
11090   int change = 0;
11091   valnum_t val;
11092
11093   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11094   
11095   if (!(*combined)) {
11096     return defmapUpdateUniqueSym (combined, alt_in);
11097   } // if
11098   
11099   /* merge the two */
11100   curr = alt_in;
11101   while (curr) {
11102     /* find symbols definition in *combined */
11103     old = *combined;
11104     while (old && (old->sym != curr->sym)) old = old->next;
11105
11106     if (old) {
11107       /* definition found */
11108       if (old->val && (old->val != curr->val)) {
11109         old->val = 0; /* value unknown */
11110         change++;
11111       }
11112     } else {
11113       /* no definition found -- can be either INIT or alt_in's value */
11114       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11115       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11116       if (val != curr->val) change++;
11117     }
11118
11119     curr = curr->next;
11120   } // while (curr)
11121
11122   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11123   old = *combined;
11124   while (old) {
11125     if (old->val != 0) {
11126       /* find definition in alt_in */
11127       curr = alt_in;
11128       while (curr && curr->sym != old->sym) curr = curr->next;
11129       if (!curr) {
11130         /* symbol defined in *combined only -- can be either INIT or *combined */
11131         val = pic16_pBlockAddInval (pb, old->sym)->val;
11132         if (old->val != val) {
11133           old->val = 0;
11134           change++;
11135         }
11136       } // if
11137     } // if
11138
11139     old = old->next;
11140   } // while
11141
11142   return change;
11143 }
11144
11145 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11146   defmap_t *curr1, *curr2;
11147   symbol_t sym;
11148   
11149   /* identical maps are equal */
11150   if (map1 == map2) return 0;
11151
11152   if (!map1) return -1;
11153   if (!map2) return 1;
11154
11155   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11156   
11157   /* check length */
11158   curr1 = map1;
11159   curr2 = map2;
11160   while (curr1 && curr2) {
11161     curr1 = curr1->next;
11162     curr2 = curr2->next;
11163   } // while
11164
11165   /* one of them longer? */
11166   if (curr1) return 1;
11167   if (curr2) return -1;
11168
11169   /* both lists are of equal length -- compare (in O(n^2)) */
11170   curr1 = map1;
11171   while (curr1) {
11172     sym = curr1->sym;
11173     curr2 = map2;
11174     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11175     if (!curr2) return 1; // symbol not found in curr2
11176     if (curr2->val != curr1->val) return 1; // values differ
11177
11178     /* compare next symbol */
11179     curr1 = curr1->next;
11180   } // while
11181
11182   /* no difference found */
11183   return 0;
11184 }
11185
11186
11187 /* Prepare a list of all reaching definitions per flow.
11188  * This is done using a forward dataflow analysis.
11189  */
11190 static void createReachingDefinitions (pBlock *pb) {
11191   defmap_t *out_vals, *in_vals;
11192   pCode *pc;
11193   pCodeFlow *pcfl;
11194   pCodeFlowLink *link;
11195   set *todo;
11196   set *blacklist;
11197
11198   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11199   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11200     if (isPCFL(pc)) {
11201       deleteDefmapChain (&PCFL(pc)->in_vals);
11202       deleteDefmapChain (&PCFL(pc)->out_vals);
11203       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11204     } // if
11205   } // for
11206   
11207   pc = pic16_findNextInstruction (pb->pcHead);
11208   todo = NULL; blacklist = NULL;
11209   addSetHead (&todo, PCI(pc)->pcflow);
11210
11211   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11212   while (elementsInSet (todo)) {
11213     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11214     pcfl = PCFL(indexSet (todo, 0));
11215     deleteSetItem (&todo, pcfl);
11216     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11217     in_vals = NULL;
11218     out_vals = NULL;
11219
11220     if (isinSet (blacklist, pcfl)) {
11221             fprintf (stderr, "ignoring blacklisted flow\n");
11222       continue;
11223     }
11224     
11225     /* create in_vals from predecessors out_vals */
11226     link = setFirstItem (pcfl->from);
11227     while (link) {
11228       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11229       link = setNextItem (pcfl->from);
11230     } // while
11231
11232     //printDefmap (in_vals); 
11233     //printDefmap (pcfl->in_vals); 
11234
11235     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11236       //fprintf (stderr, "in_vals changed\n");
11237       /* in_vals changed -- update out_vals */
11238       deleteDefmapChain (&pcfl->in_vals);
11239       pcfl->in_vals = in_vals;
11240
11241       /* create out_val from in_val and defmap */
11242       out_vals = NULL;
11243       defmapUpdateUniqueSym (&out_vals, in_vals);
11244       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11245
11246       /* is out_vals different from pcfl->out_vals */
11247       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11248         //fprintf (stderr, "out_vals changed\n");
11249         deleteDefmapChain (&pcfl->out_vals);
11250         pcfl->out_vals = out_vals;
11251
11252         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11253           addSet (&blacklist, pcfl);
11254         } // if
11255         
11256         /* reschedule all successors */
11257         link = setFirstItem (pcfl->to);
11258         while (link) {
11259           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11260           addSetIfnotP (&todo, link->pcflow);
11261           link = setNextItem (pcfl->to);
11262         } // while
11263       } else {
11264         deleteDefmapChain (&out_vals);        
11265       }// if
11266     } else {
11267       deleteDefmapChain (&in_vals);         
11268     } // if
11269   } // while
11270 }
11271
11272 #if 0
11273 static void showAllDefs (symbol_t sym, pCode *pc) {
11274   defmap_t *map;
11275   int count;
11276
11277   assert (isPCI(pc));
11278   count = defmapFindAll (sym, pc, &map);
11279
11280   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11281   while (map) {
11282 #if 1
11283     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11284 #else
11285     { char buf[256];
11286     pic16_pCode2str (buf, 256, map->pc);
11287     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11288 #endif
11289     map = map->next;
11290   }
11291   deleteDefmapChain (&map);
11292 }
11293 #endif
11294
11295 /* safepCodeUnlink and remove pc from defmap. */
11296 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11297   defmap_t *map, *next, **head;
11298   int res, ispci;
11299   
11300   ispci = isPCI(pc);
11301   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11302   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11303   res = pic16_safepCodeUnlink (pc, comment);
11304
11305   if (res && map) {
11306     /* remove pc from defmap */
11307     while (map) {
11308       next = map->next;
11309       if (map->pc == pc) {
11310         if (!map->prev && head) *head = map->next;
11311         deleteDefmap (map);
11312       } // if
11313       map = next;
11314     }
11315   }
11316
11317   return res;
11318 }
11319       
11320 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11321   defmap_t *map;
11322   /* This breaks the defmap chain's references to pCodes... fix it! */
11323   map = PCI(pc)->pcflow->defmap;
11324
11325   while (map && map->pc != pc) map = map->next;
11326   
11327   while (map && map->pc == pc) {
11328     map->pc = newpc;
11329     map = map->next;
11330   } // while
11331 }
11332
11333 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym) {
11334   defmap_t *map;
11335   if (!isPCI(pc)) return;
11336   
11337   map = PCI(pc)->pcflow->defmap;
11338
11339   while (map && map->pc != pc) map = map->next;
11340   while (map && map->pc == pc) {
11341     if (map->sym == sym) map->sym = newsym;
11342     map = map->next;
11343   } // while
11344 }
11345
11346 /* Assign "better" valnums to results. */
11347 static void assignValnums (pCode *pc) {
11348   pCodeInstruction *pci;
11349   pCode *newpc;
11350   symbol_t sym1, sym2;
11351   int cond, isSpecial1, isSpecial2, count, mask, lit;
11352   defmap_t *list, *val, *oldval, *dummy;
11353   regs *reg1 = NULL, *reg2 = NULL;
11354   valnum_t litnum;
11355
11356   /* only works for pCodeInstructions... */
11357   if (!isPCI(pc)) return;
11358
11359   pci = PCI(pc);
11360   cond = pci->inCond | pci->outCond;
11361   list = pci->pcflow->defmap;
11362   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11363
11364   if (cond & PCC_REGISTER) {
11365     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11366     reg1 = pic16_getRegFromInstruction (pc);
11367     isSpecial1 = pic16_symIsSpecial (sym1);
11368   }
11369   if (cond & PCC_REGISTER2) {
11370     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11371     reg2 = pic16_getRegFromInstruction (pc);
11372     isSpecial2 = pic16_symIsSpecial (sym2);
11373   }
11374
11375   /* determine input values */
11376   val = list;
11377   while (val && val->pc != pc) val = val->next;
11378   //list = val; /* might save some time later... */
11379   while (val && val->pc == pc) {
11380     val->in_val = 0;
11381     if (val->sym != 0 && (1 || val->access.isRead)) {
11382       /* get valnum for sym */
11383       count = defmapFindAll (val->sym, pc, &oldval);
11384       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11385       if (count == 1) {
11386         if ((val->access.in_mask & oldval->access.mask) == val->access.in_mask) {
11387           val->in_val = oldval->val;
11388         } else {
11389           val->in_val = 0;
11390         }
11391       } else if (count == 0) {
11392         /* no definition found */
11393         val->in_val = 0;
11394       } else {
11395         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11396         assert (oldval);
11397         dummy = oldval->next;
11398         mask = oldval->access.mask;
11399         val->in_val = oldval->val;
11400         while (dummy && (dummy->val == val->in_val)) {
11401           mask &= dummy->access.mask;
11402           dummy = dummy->next;
11403         } // while
11404
11405         /* found other values or to restictive mask */
11406         if (dummy || ((mask & val->access.in_mask) != val->access.in_mask)) {
11407           val->in_val = 0;
11408         }
11409       }
11410       if (count > 0) deleteDefmapChain (&oldval);
11411     } // if
11412     val = val->next;
11413   }
11414
11415   /* handle valnum assignment */
11416   switch (pci->op) {
11417   case POC_CLRF: /* modifies STATUS (Z) */
11418     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11419       oldval = defmapCurr (list, sym1, pc);
11420       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11421         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11422         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11423       }
11424       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11425     }
11426     break;
11427
11428   case POC_SETF: /* SETF does not touch STATUS */
11429     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11430       oldval = defmapCurr (list, sym1, pc);
11431       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11432         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11433         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11434       }
11435       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11436     }
11437     break;
11438     
11439   case POC_MOVLW: /* does not touch STATUS */
11440     oldval = defmapCurr (list, SPO_WREG, pc);
11441     if (pci->pcop->type == PO_LITERAL) {
11442       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11443       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11444     } else {
11445       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11446       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11447     }
11448     if (oldval && oldval->in_val == litnum) {
11449       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11450       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11451     }
11452     defmapUpdate (list, SPO_WREG, pc, litnum);
11453     break;
11454
11455   case POC_ANDLW: /* modifies STATUS (Z,N) */
11456   case POC_IORLW: /* modifies STATUS (Z,N) */
11457   case POC_XORLW: /* modifies STATUS (Z,N) */
11458     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11459     if (pci->pcop->type == PO_LITERAL) {
11460       lit = (unsigned char) PCOL(pci->pcop)->lit;
11461       int vallit = -1;
11462       val = defmapCurr (list, SPO_WREG, pc);
11463       if (val) vallit = litFromValnum (val->in_val);
11464       if (vallit != -1) {
11465         /* xxxLW <literal>, WREG contains a known literal */
11466         fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11467         if (pci->op == POC_ANDLW) {
11468           lit &= vallit;
11469         } else if (pci->op == POC_IORLW) {
11470           lit |= vallit;
11471         } else if (pci->op == POC_XORLW) {
11472           lit ^= vallit;
11473         } else {
11474           assert (0 && "invalid operation");
11475         }
11476         if (vallit == lit) {
11477           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11478           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11479         }
11480         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11481       } // if
11482     }
11483     break;
11484
11485   case POC_LFSR:
11486     {
11487       /* check if old value matches new value */
11488       int lit;
11489       int ok = 1;
11490       assert (pci->pcop->type == PO_LITERAL);
11491       
11492       lit = PCOL(pci->pcop)->lit;
11493       
11494       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11495       
11496       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11497         fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11498       } else {
11499         /* cannot remove this LFSR */
11500         ok = 0;      
11501       } // if
11502       
11503       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11504       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11505         fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11506       } else {
11507         ok = 0;
11508       } // if
11509
11510       if (ok) {
11511         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11512       }
11513     }
11514     break;
11515     
11516   case POC_MOVWF: /* does not touch flags */
11517     /* find value of WREG */
11518     val = defmapCurr (list, SPO_WREG, pc);
11519     oldval = defmapCurr (list, sym1, pc);
11520     if (val) lit = litFromValnum (val->in_val);
11521     else lit = -1;
11522     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11523     
11524     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11525       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11526       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11527       if (lit == 0) {
11528         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11529       } else {
11530         assert (lit == 0x0ff);
11531         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11532       }
11533       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11534       pic16_pCodeReplace (pc, newpc);
11535       defmapReplaceSymRef (pc, SPO_WREG, 0);
11536       pic16_fixDefmap (pc, newpc);
11537       pc = newpc;
11538         
11539       /* This breaks the defmap chain's references to pCodes... fix it! */
11540       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11541       deleteDefmap (val); // delete reference to WREG as in value
11542       val = NULL;
11543       oldval = PCI(pc)->pcflow->defmap;
11544       while (oldval) {
11545         if (oldval->pc == pc) oldval->pc = newpc;
11546           oldval = oldval->next;
11547       } // while
11548     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11549       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11550       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11551     }
11552     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11553     break;
11554     
11555   case POC_MOVFW: /* modifies STATUS (Z,N) */
11556     /* find value of REG */
11557     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11558       val = defmapCurr (list, sym1, pc);
11559       oldval = defmapCurr (list, SPO_WREG, pc);
11560       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11561         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11562         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11563       }
11564       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11565     }
11566     break;
11567
11568   case POC_MOVFF: /* does not touch STATUS */
11569     /* find value of REG */
11570     val = defmapCurr (list, sym1, pc);
11571     oldval = defmapCurr (list, sym2, pc);
11572     if (val) lit = litFromValnum (val->in_val);
11573     else lit = -1;
11574     newpc = NULL;
11575     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11576       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11577       if (lit == 0) {
11578         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11579       } else if (lit == 0x00ff) {
11580         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11581       } else {
11582         newpc = NULL;
11583       }
11584       if (newpc) {
11585         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11586         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11587         pic16_pCodeReplace (pc, newpc); 
11588         defmapReplaceSymRef (pc, sym1, 0);
11589         pic16_fixDefmap (pc, newpc);
11590         pc = newpc;
11591         break; // do not process instruction as MOVFF...
11592       }
11593     } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11594       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11595         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11596         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11597       } else {
11598         if (!pic16_isAlive (sym1, pc)) {
11599           defmap_t *copy = NULL;
11600           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11601            * This should help eliminate
11602            *   MOVFF A,B
11603            *   <do something not changing A or using B>
11604            *   MOVFF B,C
11605            *   <B is not alive anymore>
11606            * and turn it into
11607            *   <do something not changing A or using B>
11608            *   MOVFF A,C
11609            */
11610
11611           /* scan defmap for symbols storing sym1's value */
11612           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11613           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11614             /* unique reaching definition for sym found */
11615             if (copy->val && copy->val == val->in_val) {
11616               //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);
11617               if (copy->sym == SPO_WREG) {
11618                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11619               } else {
11620                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11621 //                      /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11622                         pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11623                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11624               }
11625               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11626               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11627               pic16_pCodeReplace (pc, newpc); 
11628               assert (val->sym == sym1 && val->access.isRead && !val->access.isWrite);
11629               defmapReplaceSymRef (pc, sym1, copy->sym);
11630               pic16_fixDefmap (pc, newpc);
11631               pc = newpc;
11632             }
11633           }
11634           deleteDefmapChain (&copy);
11635         }
11636       }
11637       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11638     }
11639     break;
11640
11641   default:
11642     /* cannot optimize */
11643     break;
11644   } // switch
11645 }
11646
11647 static void pic16_destructDF (pBlock *pb) {
11648   pCode *pc, *next;
11649
11650   /* remove old defmaps */
11651   pc = pic16_findNextInstruction (pb->pcHead);
11652   while (pc) {
11653     next = pic16_findNextInstruction (pc->next);
11654
11655     assert (isPCI(pc) || isPCAD(pc));
11656     assert (PCI(pc)->pcflow);
11657     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11658     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11659     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11660     
11661     pc = next;
11662   } // while
11663   
11664   if (defmap_free || defmap_free_count) {
11665     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11666     freeDefmap (&defmap_free);
11667     defmap_free_count = 0;
11668   }
11669 }
11670
11671 /* Checks whether a pBlock contains ASMDIRs. */
11672 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11673   pCode *pc;
11674
11675   pc = pic16_findNextInstruction (pb->pcHead);
11676   while (pc) {
11677     if (isPCAD(pc)) return 1;
11678
11679     pc = pic16_findNextInstruction (pc->next);
11680   } // while
11681
11682   /* no PCADs found */
11683   return 0;
11684 }
11685
11686 #if 1
11687 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11688 static int pic16_removeUnusedRegistersDF () {
11689   pCode *pc, *pc2;
11690   pBlock *pb;
11691   regs *reg1, *reg2, *reg3;
11692   set *seenRegs = NULL;
11693   int cond, i;
11694   int islocal, change = 0;
11695
11696   /* no pBlocks? */
11697   if (!the_pFile || !the_pFile->pbHead) return 0;
11698   
11699   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11700     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11701 #if 1
11702     /* find set of using pCodes per register */
11703     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11704                     pc = pic16_findNextInstruction(pc->next)) {
11705
11706       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11707       reg1 = reg2 = NULL;
11708       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11709       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11710
11711       if (reg1) {
11712         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11713         addSetIfnotP (&seenRegs, reg1);
11714         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11715       }
11716       if (reg2) {
11717         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11718         addSetIfnotP (&seenRegs, reg2);
11719         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11720       }
11721     } // for pc
11722 #endif
11723     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11724       /* may not use pic16_regIsLocal() here -- in interrupt routines
11725        * WREG, PRODx, FSR0x must be saved */
11726       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11727       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11728         pc = pc2 = NULL;
11729         for (i=0; i < 2; i++) {
11730           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11731           if (!pc2) pc2 = pc;
11732           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11733           reg2 = pic16_getRegFromInstruction (pc);
11734           reg3 = pic16_getRegFromInstruction2 (pc);
11735           if (!reg2 || !reg3
11736               || (reg2->rIdx != pic16_stack_preinc->rIdx
11737                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11738           if (i == 1) {
11739             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11740             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11741             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11742             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11743           }
11744         } // for
11745       } // if
11746       deleteSet (&reg1->reglives.usedpCodes);
11747     } // for reg1
11748
11749     deleteSet (&seenRegs);
11750   } // for pb
11751
11752   return change;
11753 }
11754 #endif
11755
11756 /* Set up pCodeFlow's defmap_ts. 
11757  * Needs correctly set up to/from fields. */
11758 static void pic16_createDF (pBlock *pb) {
11759   pCode *pc, *next;
11760   int change=0;
11761
11762   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11763
11764   pic16_destructDF (pb);
11765
11766   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11767   if (pic16_pBlockHasAsmdirs (pb)) {
11768     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11769     return;
11770   }
11771
11772   /* integrity check -- we need to reach all flows to guarantee
11773    * correct data flow analysis (reaching definitions, aliveness) */
11774 #if 0
11775   if (!verifyAllFlowsReachable (pb)) {
11776     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11777     return;
11778   }
11779 #endif
11780   
11781   /* establish new defmaps */
11782   pc = pic16_findNextInstruction (pb->pcHead);
11783   while (pc) {
11784     next = pic16_findNextInstruction (pc->next);
11785
11786     assert (PCI(pc)->pcflow);
11787     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11788
11789     pc = next;
11790   } // while
11791
11792   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11793   createReachingDefinitions (pb);
11794   
11795 #if 1
11796   /* assign better valnums */
11797   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11798   pc = pic16_findNextInstruction (pb->pcHead);
11799   while (pc) {
11800     next = pic16_findNextInstruction (pc->next);
11801
11802     assert (PCI(pc)->pcflow);
11803     assignValnums (pc);
11804
11805     pc = next;
11806   } // while
11807 #endif
11808
11809 #if 1
11810   /* remove dead pCodes */
11811   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11812   do {
11813     change = 0;
11814     pc = pic16_findNextInstruction (pb->pcHead);
11815     while (pc) {
11816       next = pic16_findNextInstruction (pc->next);
11817
11818       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11819         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11820       }
11821
11822       pc = next;
11823     } // while
11824   } while (change);
11825 #endif
11826 }
11827
11828
11829 /* ======================================================================= */
11830 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11831 /* ======================================================================= */
11832
11833 #if 0
11834
11835 /* connect pCode f anf t via their to/from pBranches */
11836 static void pic16_pCodeLink (pCode *f, pCode *t) {
11837   pBranch *br;
11838   pCodeInstruction *_f, *_t;
11839
11840   if (!f || !t) return;
11841
11842 #if 0
11843   fprintf (stderr, "linking:\n");
11844   f->print(stderr, f);
11845   f->print(stderr, t);
11846 #endif
11847
11848   assert (isPCI(f) || isPCAD(f));
11849   assert (isPCI(t) || isPCAD(t));
11850   _f = PCI(f);
11851   _t = PCI(t);
11852   
11853   /* define t to be CF successor of f */
11854   br = Safe_malloc (sizeof (pBranch));
11855   br->pc = t;
11856   br->next = NULL;
11857   _f->to = pic16_pBranchAppend (_f->to, br);
11858
11859   /* define f to be CF predecessor of t */
11860   br = Safe_malloc (sizeof (pBranch));
11861   br->pc = f;
11862   br->next = NULL;
11863   _t->from = pic16_pBranchAppend (_t->from, br);
11864
11865   /* also update pcflow information */
11866   if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11867     //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11868     LinkFlow_pCode (_f, _t);
11869   } // if
11870 }
11871
11872 static void pic16_destructCF (pBlock *pb) {
11873   pCode *pc;
11874   pBranch *br;
11875
11876   /* remove old CF information */
11877   pc = pb->pcHead;
11878   while (pc) {
11879     if (isPCI(pc)) {
11880       while (PCI(pc)->to) {
11881         br = PCI(pc)->to->next;
11882         Safe_free (PCI(pc)->to);
11883         PCI(pc)->to = br;
11884       } // while
11885       while (PCI(pc)->from) {
11886         br = PCI(pc)->from->next;
11887         Safe_free (PCI(pc)->from);
11888         PCI(pc)->from = br;
11889       }
11890     } else if (isPCFL(pc)) {
11891       deleteSet (&PCFL(pc)->to);
11892       deleteSet (&PCFL(pc)->from);
11893     }
11894     pc = pc->next;
11895   }
11896   
11897   releaseStack ();
11898 }
11899
11900 /* Set up pCodeInstruction's to and from pBranches. */
11901 static void pic16_createCF (pBlock *pb) {
11902   pCode *pc;
11903   pCode *next, *dest;
11904   char *label;
11905
11906   //fprintf (stderr, "creating CF for %p\n", pb);
11907
11908   pic16_destructCF (pb);
11909
11910   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11911   if (pic16_pBlockHasAsmdirs (pb)) {
11912     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11913     return;
11914   }
11915
11916   pc = pic16_findNextInstruction(pb->pcHead);
11917   while (pc) {
11918     next = pic16_findNextInstruction(pc->next);
11919     if (isPCI_SKIP(pc)) {
11920       pic16_pCodeLink(pc, next);
11921       pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
11922     } else if (isPCI_BRANCH(pc)) {
11923       // Bcc, BRA, CALL, GOTO
11924       if (PCI(pc)->pcop) {
11925         switch (PCI(pc)->pcop->type) {
11926         case PO_LABEL:
11927           label = PCOLAB(PCI(pc)->pcop)->pcop.name;
11928           dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
11929           break;
11930         
11931         case PO_STR:
11932           /* needed for GOTO ___irq_handler */
11933           label = PCI(pc)->pcop->name;
11934           dest = NULL;
11935           break;
11936
11937         default:
11938           assert (0 && "invalid label format");
11939           break;
11940         } // switch
11941       } else {
11942         label = "NO PCOP";
11943         dest = NULL;
11944       }
11945
11946       switch (PCI(pc)->op) {
11947       case POC_BRA:
11948       case POC_GOTO:
11949         if (dest != NULL) { 
11950           pic16_pCodeLink(pc, dest);
11951         } else {
11952           //fprintf (stderr, "jump target \"%s\" not found!\n", label);
11953         }
11954         break;
11955       case POC_CALL:
11956       case POC_RETURN:
11957       case POC_RETFIE:
11958         pic16_pCodeLink(pc, next);
11959         break;
11960       case POC_BC:
11961       case POC_BNC:
11962       case POC_BZ:
11963       case POC_BNZ:
11964       case POC_BN:
11965       case POC_BNN:
11966       case POC_BOV:
11967       case POC_BNOV:
11968         if (dest != NULL) { 
11969           pic16_pCodeLink(pc, dest);
11970         } else {
11971           //fprintf (stderr, "jump target \"%s\"not found!\n", label);
11972         }
11973         pic16_pCodeLink(pc, next);
11974         break;
11975       default:
11976         fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
11977         assert (0 && "unhandled branch instruction");
11978         break;
11979       } // switch
11980     } else {
11981       pic16_pCodeLink (pc, next);
11982     }
11983     pc = next;
11984   } // while
11985 }
11986 #endif
11987
11988 /* ======================================================================== */
11989 /* === VCG DUMPER ROUTINES ================================================ */
11990 /* ======================================================================== */
11991 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11992 hTab *dumpedNodes = NULL;
11993
11994 /** Dump VCG header into of. */
11995 static void pic16_vcg_init (FILE *of) {
11996   /* graph defaults */
11997   fprintf (of, "graph:{\n");
11998   fprintf (of, "title:\"graph1\"\n");
11999   fprintf (of, "label:\"graph1\"\n");
12000   fprintf (of, "color:white\n");
12001   fprintf (of, "textcolor:black\n");
12002   fprintf (of, "bordercolor:black\n");
12003   fprintf (of, "borderwidth:1\n");
12004   fprintf (of, "textmode:center\n");
12005
12006   fprintf (of, "layoutalgorithm:dfs\n");
12007   fprintf (of, "late_edge_labels:yes\n");
12008   fprintf (of, "display_edge_labels:yes\n");
12009   fprintf (of, "dirty_edge_labels:yes\n");
12010   fprintf (of, "finetuning:yes\n");
12011   fprintf (of, "ignoresingles:no\n");
12012   fprintf (of, "straight_phase:yes\n");
12013   fprintf (of, "priority_phase:yes\n");
12014   fprintf (of, "manhattan_edges:yes\n");
12015   fprintf (of, "smanhattan_edges:no\n");
12016   fprintf (of, "nearedges:no\n");
12017   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12018   fprintf (of, "port_sharing:no\n");
12019   fprintf (of, "arrowmode:free\n"); // fixed|free
12020   fprintf (of, "crossingphase2:yes\n");
12021   fprintf (of, "crossingoptimization:yes\n");
12022   fprintf (of, "edges:yes\n");
12023   fprintf (of, "nodes:yes\n");
12024   fprintf (of, "splines:no\n");
12025   
12026   /* node defaults */
12027   fprintf (of, "node.color:lightyellow\n");
12028   fprintf (of, "node.textcolor:black\n");
12029   fprintf (of, "node.textmode:center\n");
12030   fprintf (of, "node.shape:box\n");
12031   fprintf (of, "node.bordercolor:black\n");
12032   fprintf (of, "node.borderwidth:1\n");
12033
12034   /* edge defaults */
12035   fprintf (of, "edge.textcolor:black\n");
12036   fprintf (of, "edge.color:black\n");
12037   fprintf (of, "edge.thickness:1\n");
12038   fprintf (of, "edge.arrowcolor:black\n");
12039   fprintf (of, "edge.backarrowcolor:black\n");
12040   fprintf (of, "edge.arrowsize:15\n");
12041   fprintf (of, "edge.backarrowsize:15\n");
12042   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12043   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12044   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12045   
12046   fprintf (of, "\n");
12047
12048   /* prepare data structures */
12049   if (dumpedNodes) {
12050     hTabDeleteAll (dumpedNodes);
12051     dumpedNodes = NULL;
12052   }
12053   dumpedNodes = newHashTable (128);
12054 }
12055
12056 /** Dump VCG footer into of. */
12057 static void pic16_vcg_close (FILE *of) {
12058   fprintf (of, "}\n");
12059 }
12060
12061 #define BUF_SIZE 128
12062 #define pcTitle(pc) (snprintf (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12063
12064 #if 0
12065 static int ptrcmp (const void *p1, const void *p2) {
12066   return p1 == p2;
12067 }
12068 #endif
12069
12070 /** Dump a pCode node as VCG to of. */
12071 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12072   char buf[BUF_SIZE];
12073
12074   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12075     // dumped already
12076     return;
12077   }
12078   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12079   //fprintf (stderr, "dumping %p\n", pc);
12080  
12081   /* only dump pCodeInstructions and Flow nodes */
12082   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12083     
12084   /* emit node */
12085   fprintf (of, "node:{");
12086   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12087   fprintf (of, "label:\"%s\n", pcTitle(pc));
12088   if (isPCFL(pc)) {
12089     fprintf (of, "<PCFLOW>");
12090   } else if (isPCI(pc) || isPCAD(pc)) {
12091     pc->print (of, pc);
12092   } else {
12093     fprintf (of, "<!PCI>");
12094   }
12095   fprintf (of, "\" ");
12096   fprintf (of, "}\n");
12097   
12098   if (1 && isPCFL(pc)) {
12099     defmap_t *map, *prev;
12100     unsigned int i;
12101     map = PCFL(pc)->defmap;
12102     i=0;
12103     while (map) {
12104       if (map->sym != 0) {
12105         i++;
12106       
12107         /* emit definition node */
12108         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12109         fprintf (of, "label:\"");
12110
12111         prev = map;
12112         do {
12113           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));
12114           prev = map;
12115           map = map->next;
12116         } while (map && prev->pc == map->pc);
12117         map = prev;
12118         
12119         fprintf (of, "\" ");
12120       
12121         fprintf (of, "color:green ");
12122         fprintf (of, "}\n");
12123
12124         /* emit edge to previous definition */
12125         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12126         if (i == 1) {
12127           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12128         } else {
12129           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12130         }
12131         fprintf (of, "color:green ");
12132         fprintf (of, "}\n");
12133
12134         if (map->pc) {
12135           pic16_vcg_dumpnode (map->pc, of);
12136           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12137           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12138         }
12139       }
12140       map = map->next;
12141     } // while
12142   }
12143
12144   /* emit additional nodes (e.g. operands) */
12145 }
12146
12147 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12148 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12149   char buf[BUF_SIZE];
12150   pCodeInstruction *pci;
12151   pBranch *curr;
12152   int i;
12153   
12154   if (1 && isPCFL(pc)) {
12155     /* emit edges to flow successors */
12156     void *pcfl;
12157     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12158     pcfl = setFirstItem (PCFL(pc)->to);
12159     while (pcfl) {
12160       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12161       pic16_vcg_dumpnode (pc, of);
12162       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12163       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12164       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12165       pcfl = setNextItem (PCFL(pc)->to);
12166     } // while
12167   } // if
12168   
12169   if (!isPCI(pc) && !isPCAD(pc)) return;
12170
12171   pci = PCI(pc);
12172   
12173   /* emit control flow edges (forward only) */
12174   curr = pci->to;
12175   i=0;
12176   while (curr) {
12177     pic16_vcg_dumpnode (curr->pc, of);
12178     fprintf (of, "edge:{");
12179     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12180     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12181     fprintf (of, "color:red ");
12182     fprintf (of, "}\n");
12183     curr = curr->next;
12184   } // while
12185
12186 #if 1
12187   /* dump "flow" edge (link pCode according to pBlock order) */
12188   {
12189     pCode *pcnext;
12190     pcnext = pic16_findNextInstruction (pc->next);
12191     if (pcnext) {
12192       pic16_vcg_dumpnode (pcnext, of);
12193       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12194       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12195     }
12196   }
12197 #endif
12198   
12199 #if 0
12200   /* emit flow */
12201   if (pci->pcflow) {
12202     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12203     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12204     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12205   }
12206 #endif
12207   
12208   /* emit data flow edges (backward only) */
12209   /* TODO: gather data flow information... */
12210 }
12211
12212 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12213   pCode *pc;
12214
12215   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12216   if (pic16_pBlockHasAsmdirs (pb)) {
12217     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12218     return;
12219   }
12220
12221   for (pc=pb->pcHead; pc; pc = pc->next) {
12222     pic16_vcg_dumpnode (pc, of);
12223   } // for pc
12224   
12225   for (pc=pb->pcHead; pc; pc = pc->next) {
12226     pic16_vcg_dumpedges (pc, of);
12227   } // for pc
12228 }
12229
12230 static void pic16_vcg_dump_default (pBlock *pb) {
12231   FILE *of;
12232   char buf[BUF_SIZE];
12233   pCode *pc;
12234
12235   /* get function name */
12236   pc = pb->pcHead;
12237   while (pc && !isPCF(pc)) pc = pc->next;
12238   if (pc) {
12239     snprintf (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12240   } else {
12241     snprintf (buf, BUF_SIZE, "pb_%p.vcg", pb);
12242   }
12243
12244   //fprintf (stderr, "now dumping %s\n", buf);
12245   of = fopen (buf, "w");
12246   pic16_vcg_init (of);
12247   pic16_vcg_dump (of, pb);
12248   pic16_vcg_close (of);
12249   fclose (of);
12250 }
12251 #endif
12252
12253 /*** END of helpers for pCode dataflow optimizations ***/