* src/SDCCasm.[ch]: renamed from asm[ch], use dbuf_getline(), ...
[fw/sdcc] / src / pic16 / pcode.c
1 /*-------------------------------------------------------------------------
2
3   pcode.c - post code generation
4
5    Written By -  Scott Dattalo scott@dattalo.com
6    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
7
8    This program is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23 #include <stdio.h>
24
25 #include "common.h"   // Include everything in the SDCC src directory
26 #include "newalloc.h"
27
28
29 #include "main.h"
30 #include "pcode.h"
31 #include "pcodeflow.h"
32 #include "ralloc.h"
33 #include "device.h"
34
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
36
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
38 #define inline
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(unsigned 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(unsigned 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((const unsigned char *)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((unsigned char *)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((const unsigned char *)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((unsigned char *)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 /*-----------------------------------------------------------------*/
3527 /* pic16_newpCode - create and return a newly initialized pCode          */
3528 /*                                                                 */
3529 /*  fixme - rename this                                            */
3530 /*                                                                 */
3531 /* The purpose of this routine is to create a new Instruction      */
3532 /* pCode. This is called by gen.c while the assembly code is being */
3533 /* generated.                                                      */
3534 /*                                                                 */
3535 /* Inouts:                                                         */
3536 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3537 /*                  (note that the op is analogous to but not the  */
3538 /*                  same thing as the opcode of the instruction.)  */
3539 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3540 /*                                                                 */
3541 /* Outputs:                                                        */
3542 /*  a pointer to the new malloc'd pCode is returned.               */
3543 /*                                                                 */
3544 /*                                                                 */
3545 /*                                                                 */
3546 /*-----------------------------------------------------------------*/
3547 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3548 {
3549   pCodeInstruction *pci ;
3550
3551   if(!mnemonics_initialized)
3552     pic16initMnemonics();
3553     
3554   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3555
3556   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3557     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3558     pci->pcop = pcop;
3559
3560     if(pci->inCond & PCC_EXAMINE_PCOP)
3561       pci->inCond  |= RegCond(pcop);
3562
3563     if(pci->outCond & PCC_EXAMINE_PCOP)
3564       pci->outCond  |= RegCond(pcop);
3565
3566     pci->pc.prev = pci->pc.next = NULL;
3567     return (pCode *)pci;
3568   }
3569
3570   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3571   exit(1);
3572
3573   return NULL;
3574 }       
3575
3576 /*-----------------------------------------------------------------*/
3577 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3578 /*                                                                 */
3579 /* Wild pcodes are used during the peep hole optimizer to serve    */
3580 /* as place holders for any instruction. When a snippet of code is */
3581 /* compared to a peep hole rule, the wild card opcode will match   */
3582 /* any instruction. However, the optional operand and label are    */
3583 /* additional qualifiers that must also be matched before the      */
3584 /* line (of assembly code) is declared matched. Note that the      */
3585 /* operand may be wild too.                                        */
3586 /*                                                                 */
3587 /*   Note, a wild instruction is specified just like a wild var:   */
3588 /*      %4     ; A wild instruction,                               */
3589 /*  See the peeph.def file for additional examples                 */
3590 /*                                                                 */
3591 /*-----------------------------------------------------------------*/
3592
3593 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3594 {
3595
3596   pCodeWild *pcw;
3597     
3598   pcw = Safe_calloc(1,sizeof(pCodeWild));
3599
3600   pcw->pci.pc.type = PC_WILD;
3601   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3602   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3603   pcw->pci.pc.pb = NULL;
3604
3605   //  pcw->pci.pc.analyze = genericAnalyze;
3606   pcw->pci.pc.destruct = genericDestruct;
3607   pcw->pci.pc.print = genericPrint;
3608
3609   pcw->id = pCodeID;              // this is the 'n' in %n
3610   pcw->operand = optional_operand;
3611   pcw->label   = optional_label;
3612
3613   pcw->mustBeBitSkipInst = 0;
3614   pcw->mustNotBeBitSkipInst = 0;
3615   pcw->invertBitSkipInst = 0;
3616
3617   return ( (pCode *)pcw);
3618   
3619 }
3620
3621  /*-----------------------------------------------------------------*/
3622 /* newPcodeInlineP - create a new pCode from a char string           */
3623 /*-----------------------------------------------------------------*/
3624
3625
3626 pCode *pic16_newpCodeInlineP(char *cP)
3627 {
3628
3629   pCodeComment *pcc ;
3630     
3631   pcc = Safe_calloc(1,sizeof(pCodeComment));
3632
3633   pcc->pc.type = PC_INLINE;
3634   pcc->pc.prev = pcc->pc.next = NULL;
3635   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3636   pcc->pc.pb = NULL;
3637
3638   //  pcc->pc.analyze = genericAnalyze;
3639   pcc->pc.destruct = genericDestruct;
3640   pcc->pc.print = genericPrint;
3641
3642   if(cP)
3643     pcc->comment = Safe_strdup(cP);
3644   else
3645     pcc->comment = NULL;
3646
3647   return ( (pCode *)pcc);
3648
3649 }
3650
3651 /*-----------------------------------------------------------------*/
3652 /* newPcodeCharP - create a new pCode from a char string           */
3653 /*-----------------------------------------------------------------*/
3654
3655 pCode *pic16_newpCodeCharP(char *cP)
3656 {
3657
3658   pCodeComment *pcc ;
3659     
3660   pcc = Safe_calloc(1,sizeof(pCodeComment));
3661
3662   pcc->pc.type = PC_COMMENT;
3663   pcc->pc.prev = pcc->pc.next = NULL;
3664   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3665   pcc->pc.pb = NULL;
3666
3667   //  pcc->pc.analyze = genericAnalyze;
3668   pcc->pc.destruct = genericDestruct;
3669   pcc->pc.print = genericPrint;
3670
3671   if(cP)
3672     pcc->comment = Safe_strdup(cP);
3673   else
3674     pcc->comment = NULL;
3675
3676   return ( (pCode *)pcc);
3677
3678 }
3679
3680 /*-----------------------------------------------------------------*/
3681 /* pic16_newpCodeFunction -                                              */
3682 /*-----------------------------------------------------------------*/
3683
3684
3685 pCode *pic16_newpCodeFunction(char *mod,char *f)
3686 {
3687   pCodeFunction *pcf;
3688
3689   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3690
3691   pcf->pc.type = PC_FUNCTION;
3692   pcf->pc.prev = pcf->pc.next = NULL;
3693   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3694   pcf->pc.pb = NULL;
3695
3696   //  pcf->pc.analyze = genericAnalyze;
3697   pcf->pc.destruct = genericDestruct;
3698   pcf->pc.print = pCodePrintFunction;
3699
3700   pcf->ncalled = 0;
3701   pcf->absblock = 0;
3702   
3703   if(mod) {
3704     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3705     strcpy(pcf->modname,mod);
3706   } else
3707     pcf->modname = NULL;
3708
3709   if(f) {
3710     pcf->fname = Safe_calloc(1,strlen(f)+1);
3711     strcpy(pcf->fname,f);
3712   } else
3713     pcf->fname = NULL;
3714
3715   pcf->stackusage = 0;
3716
3717   return ( (pCode *)pcf);
3718 }
3719
3720 /*-----------------------------------------------------------------*/
3721 /* pic16_newpCodeFlow                                                    */
3722 /*-----------------------------------------------------------------*/
3723 static void destructpCodeFlow(pCode *pc)
3724 {
3725   if(!pc || !isPCFL(pc))
3726     return;
3727
3728 /*
3729   if(PCFL(pc)->from)
3730   if(PCFL(pc)->to)
3731 */
3732   pic16_unlinkpCode(pc);
3733
3734   deleteSet(&PCFL(pc)->registers);
3735   deleteSet(&PCFL(pc)->from);
3736   deleteSet(&PCFL(pc)->to);
3737
3738   /* Instead of deleting the memory used by this pCode, mark
3739    * the object as bad so that if there's a pointer to this pCode
3740    * dangling around somewhere then (hopefully) when the type is
3741    * checked we'll catch it.
3742    */
3743
3744   pc->type = PC_BAD;
3745   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3746
3747 //  Safe_free(pc);
3748
3749 }
3750
3751 pCode *pic16_newpCodeFlow(void )
3752 {
3753   pCodeFlow *pcflow;
3754
3755   //_ALLOC(pcflow,sizeof(pCodeFlow));
3756   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3757
3758   pcflow->pc.type = PC_FLOW;
3759   pcflow->pc.prev = pcflow->pc.next = NULL;
3760   pcflow->pc.pb = NULL;
3761
3762   //  pcflow->pc.analyze = genericAnalyze;
3763   pcflow->pc.destruct = destructpCodeFlow;
3764   pcflow->pc.print = genericPrint;
3765
3766   pcflow->pc.seq = GpcFlowSeq++;
3767
3768   pcflow->from = pcflow->to = NULL;
3769
3770   pcflow->inCond = PCC_NONE;
3771   pcflow->outCond = PCC_NONE;
3772
3773   pcflow->firstBank = -1;
3774   pcflow->lastBank = -1;
3775
3776   pcflow->FromConflicts = 0;
3777   pcflow->ToConflicts = 0;
3778
3779   pcflow->end = NULL;
3780
3781   pcflow->registers = newSet();
3782
3783   return ( (pCode *)pcflow);
3784
3785 }
3786
3787 /*-----------------------------------------------------------------*/
3788 /*-----------------------------------------------------------------*/
3789 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3790 {
3791   pCodeFlowLink *pcflowLink;
3792
3793   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3794
3795   pcflowLink->pcflow = pcflow;
3796   pcflowLink->bank_conflict = 0;
3797
3798   return pcflowLink;
3799 }
3800
3801 /*-----------------------------------------------------------------*/
3802 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3803 /*-----------------------------------------------------------------*/
3804
3805 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3806 {
3807
3808   pCodeCSource *pccs;
3809     
3810   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3811
3812   pccs->pc.type = PC_CSOURCE;
3813   pccs->pc.prev = pccs->pc.next = NULL;
3814   pccs->pc.pb = NULL;
3815
3816   pccs->pc.destruct = genericDestruct;
3817   pccs->pc.print = genericPrint;
3818
3819   pccs->line_number = ln;
3820   if(l)
3821     pccs->line = Safe_strdup(l);
3822   else
3823     pccs->line = NULL;
3824
3825   if(f)
3826     pccs->file_name = Safe_strdup(f);
3827   else
3828     pccs->file_name = NULL;
3829
3830   return ( (pCode *)pccs);
3831
3832 }
3833
3834
3835 /*******************************************************************/
3836 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3837 /*                      added by VR 6-Jun-2003                     */
3838 /*******************************************************************/
3839
3840 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3841 {
3842   pCodeAsmDir *pcad;
3843   va_list ap;
3844   char buffer[512];
3845   char *lbp=buffer;
3846   
3847         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3848         pcad->pci.pc.type = PC_ASMDIR;
3849         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3850         pcad->pci.pc.pb = NULL;
3851         pcad->pci.isize = 2;
3852         pcad->pci.pc.destruct = genericDestruct;
3853         pcad->pci.pc.print = genericPrint;
3854
3855         if(asdir && *asdir) {
3856                 
3857                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3858                 
3859                 pcad->directive = Safe_strdup( asdir );
3860         }
3861         
3862         va_start(ap, argfmt);
3863         
3864         memset(buffer, 0, sizeof(buffer));
3865         if(argfmt && *argfmt)
3866                 vsprintf(buffer, argfmt, ap);
3867         
3868         va_end(ap);
3869         
3870         while(isspace((unsigned char)*lbp))lbp++;
3871         
3872         if(lbp && *lbp)
3873                 pcad->arg = Safe_strdup( lbp );
3874
3875   return ((pCode *)pcad);
3876 }
3877
3878 /*-----------------------------------------------------------------*/
3879 /* pCodeLabelDestruct - free memory used by a label.               */
3880 /*-----------------------------------------------------------------*/
3881 static void pCodeLabelDestruct(pCode *pc)
3882 {
3883
3884   if(!pc)
3885     return;
3886
3887 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3888 //    Safe_free(PCL(pc)->label);
3889
3890   /* Instead of deleting the memory used by this pCode, mark
3891    * the object as bad so that if there's a pointer to this pCode
3892    * dangling around somewhere then (hopefully) when the type is
3893    * checked we'll catch it.
3894    */
3895
3896   pc->type = PC_BAD;
3897   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3898
3899 //  Safe_free(pc);
3900
3901 }
3902
3903 pCode *pic16_newpCodeLabel(char *name, int key)
3904 {
3905
3906   char *s = buffer;
3907   pCodeLabel *pcl;
3908     
3909   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3910
3911   pcl->pc.type = PC_LABEL;
3912   pcl->pc.prev = pcl->pc.next = NULL;
3913   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3914   pcl->pc.pb = NULL;
3915
3916   //  pcl->pc.analyze = genericAnalyze;
3917   pcl->pc.destruct = pCodeLabelDestruct;
3918   pcl->pc.print = pCodePrintLabel;
3919
3920   pcl->key = key;
3921   pcl->force = 0;
3922   
3923   pcl->label = NULL;
3924   if(key>0) {
3925     sprintf(s,"_%05d_DS_",key);
3926   } else
3927     s = name;
3928
3929   if(s)
3930     pcl->label = Safe_strdup(s);
3931
3932 //  if(pic16_pcode_verbose)
3933 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3934
3935
3936   return ( (pCode *)pcl);
3937
3938 }
3939
3940 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3941 {
3942   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3943   
3944         pcl->force = 1;
3945   
3946   return ( (pCode *)pcl );
3947 }
3948
3949 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3950 {
3951   pCodeInfo *pci;
3952
3953     pci = Safe_calloc(1, sizeof(pCodeInfo));
3954     pci->pci.pc.type = PC_INFO;
3955     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3956     pci->pci.pc.pb = NULL;
3957     pci->pci.label = NULL;
3958         
3959     pci->pci.pc.destruct = genericDestruct;
3960     pci->pci.pc.print = genericPrint;
3961     
3962     pci->type = type;
3963     pci->oper1 = pcop;
3964   
3965   return ((pCode *)pci);
3966 }
3967
3968
3969 /*-----------------------------------------------------------------*/
3970 /* newpBlock - create and return a pointer to a new pBlock         */
3971 /*-----------------------------------------------------------------*/
3972 static pBlock *newpBlock(void)
3973 {
3974
3975   pBlock *PpB;
3976
3977   PpB = Safe_calloc(1,sizeof(pBlock) );
3978   PpB->next = PpB->prev = NULL;
3979
3980   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3981   PpB->tregisters = NULL;
3982   PpB->visited = 0;
3983   PpB->FlowTree = NULL;
3984
3985   return PpB;
3986
3987 }
3988
3989 /*-----------------------------------------------------------------*/
3990 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3991 /*-----------------------------------------------------------------*
3992  *
3993  *  This function will create a new pBlock and the pointer to the
3994  *  pCode that is passed in will be the first pCode in the block.
3995  *-----------------------------------------------------------------*/
3996
3997
3998 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3999 {
4000
4001   pBlock *pB  = newpBlock();
4002
4003   pB->pcHead  = pB->pcTail = pc;
4004   pB->cmemmap = cm;
4005   pB->dbName  = c;
4006
4007   return pB;
4008 }
4009
4010
4011
4012 /*-----------------------------------------------------------------*/
4013 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4014 /*  Note, a negative key means that the label is part of wild card */
4015 /*  (and hence a wild card label) used in the pCodePeep            */
4016 /*   optimizations).                                               */
4017 /*-----------------------------------------------------------------*/
4018
4019 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4020 {
4021   char *s=NULL;
4022   static int label_key=-1;
4023
4024   pCodeOp *pcop;
4025
4026   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4027   pcop->type = PO_LABEL;
4028
4029   pcop->name = NULL;
4030
4031   if(key>0)
4032     sprintf(s=buffer,"_%05d_DS_",key);
4033   else 
4034     s = name, key = label_key--;
4035
4036   if(s)
4037     pcop->name = Safe_strdup(s);
4038
4039   ((pCodeOpLabel *)pcop)->key = key;
4040
4041   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4042   return pcop;
4043 }
4044
4045 /*-----------------------------------------------------------------*/
4046 /*-----------------------------------------------------------------*/
4047 pCodeOp *pic16_newpCodeOpLit(int lit)
4048 {
4049   char *s = buffer;
4050   pCodeOp *pcop;
4051
4052
4053   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4054   pcop->type = PO_LITERAL;
4055
4056   pcop->name = NULL;
4057   //if(lit>=0)
4058     sprintf(s,"0x%02hhx", (unsigned char)lit);
4059   //else
4060   //  sprintf(s, "%i", lit);
4061   
4062   if(s)
4063     pcop->name = Safe_strdup(s);
4064
4065   ((pCodeOpLit *)pcop)->lit = lit;
4066
4067   return pcop;
4068 }
4069
4070 /* Allow for 12 bit literals, required for LFSR */
4071 pCodeOp *pic16_newpCodeOpLit12(int lit)
4072 {
4073   char *s = buffer;
4074   pCodeOp *pcop;
4075
4076
4077   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4078   pcop->type = PO_LITERAL;
4079
4080   pcop->name = NULL;
4081   //if(lit>=0)
4082     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4083   //else
4084   //  sprintf(s, "%i", lit);
4085   
4086   if(s)
4087     pcop->name = Safe_strdup(s);
4088
4089   ((pCodeOpLit *)pcop)->lit = lit;
4090
4091   return pcop;
4092 }
4093
4094 /*-----------------------------------------------------------------*/
4095 /*-----------------------------------------------------------------*/
4096 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4097 {
4098   char *s = buffer, tbuf[256], *tb=tbuf;
4099   pCodeOp *pcop;
4100
4101
4102   tb = pic16_get_op(arg2, NULL, 0);
4103   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4104   pcop->type = PO_LITERAL;
4105
4106   pcop->name = NULL;
4107   //if(lit>=0) {
4108     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4109     if(s)
4110       pcop->name = Safe_strdup(s);
4111   //}
4112
4113   ((pCodeOpLit2 *)pcop)->lit = lit;
4114   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4115
4116   return pcop;
4117 }
4118
4119 /*-----------------------------------------------------------------*/
4120 /*-----------------------------------------------------------------*/
4121 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4122 {
4123   pCodeOp *pcop;
4124
4125         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4126         pcop->type = PO_IMMEDIATE;
4127         if(name) {
4128                 regs *r = pic16_dirregWithName(name);
4129                 pcop->name = Safe_strdup(name);
4130                 PCOI(pcop)->r = r;
4131                 
4132                 if(r) {
4133 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4134                         PCOI(pcop)->rIdx = r->rIdx;
4135                 } else {
4136 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4137                         PCOI(pcop)->rIdx = -1;
4138                 }
4139 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4140         } else {
4141                 pcop->name = NULL;
4142                 PCOI(pcop)->rIdx = -1;
4143         }
4144
4145         PCOI(pcop)->index = index;
4146         PCOI(pcop)->offset = offset;
4147         PCOI(pcop)->_const = code_space;
4148
4149   return pcop;
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /*-----------------------------------------------------------------*/
4154 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4155 {
4156   char *s = buffer;
4157   pCodeOp *pcop;
4158
4159
4160   if(!pcwb || !subtype) {
4161     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4162     exit(1);
4163   }
4164
4165   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4166   pcop->type = PO_WILD;
4167   sprintf(s,"%%%d",id);
4168   pcop->name = Safe_strdup(s);
4169
4170   PCOW(pcop)->id = id;
4171   PCOW(pcop)->pcwb = pcwb;
4172   PCOW(pcop)->subtype = subtype;
4173   PCOW(pcop)->matched = NULL;
4174
4175   PCOW(pcop)->pcop2 = NULL;
4176   
4177   return pcop;
4178 }
4179
4180 /*-----------------------------------------------------------------*/
4181 /*-----------------------------------------------------------------*/
4182 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4183 {
4184   char *s = buffer;
4185   pCodeOp *pcop;
4186
4187
4188         if(!pcwb || !subtype || !subtype2) {
4189                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4190                 exit(1);
4191         }
4192
4193         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4194         pcop->type = PO_WILD;
4195         sprintf(s,"%%%d",id);
4196         pcop->name = Safe_strdup(s);
4197
4198         PCOW(pcop)->id = id;
4199         PCOW(pcop)->pcwb = pcwb;
4200         PCOW(pcop)->subtype = subtype;
4201         PCOW(pcop)->matched = NULL;
4202
4203         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4204
4205         if(!subtype2->name) {
4206                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4207                 PCOW2(pcop)->pcop.type = PO_WILD;
4208                 sprintf(s, "%%%d", id2);
4209                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4210                 PCOW2(pcop)->id = id2;
4211                 PCOW2(pcop)->subtype = subtype2;
4212
4213 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4214 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4215         } else {
4216                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4217
4218 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4219 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4220         }
4221   
4222
4223
4224   return pcop;
4225 }
4226
4227
4228 /*-----------------------------------------------------------------*/
4229 /*-----------------------------------------------------------------*/
4230 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4231 {
4232   pCodeOp *pcop;
4233   
4234   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4235   pcop->type = PO_GPR_BIT;
4236   if(s)
4237     pcop->name = Safe_strdup(s);   
4238   else
4239     pcop->name = NULL;
4240
4241   PCORB(pcop)->bit = bit;
4242   PCORB(pcop)->inBitSpace = inBitSpace;
4243   PCORB(pcop)->subtype = subt;
4244
4245   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4246   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4247 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4248 //  PCOR(pcop)->rIdx = 0;
4249   return pcop;
4250 }
4251
4252 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4253 {
4254   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4255                                 bit, 0, PO_GPR_REGISTER);
4256 }
4257
4258
4259 /*-----------------------------------------------------------------*
4260  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4261  *
4262  * If rIdx >=0 then a specific register from the set of registers
4263  * will be selected. If rIdx <0, then a new register will be searched
4264  * for.
4265  *-----------------------------------------------------------------*/
4266
4267 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4268 {
4269   pCodeOp *pcop;
4270   regs *r;
4271
4272   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4273
4274   pcop->name = NULL;
4275
4276   if(rIdx >= 0) {
4277         r = pic16_regWithIdx(rIdx);
4278         if(!r)
4279                 r = pic16_allocWithIdx(rIdx);
4280   } else {
4281     r = pic16_findFreeReg(REG_GPR);
4282
4283     if(!r) {
4284         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4285                 __FUNCTION__, __LINE__);
4286         exit(EXIT_FAILURE);
4287     }
4288   }
4289
4290   PCOR(pcop)->rIdx = rIdx;
4291   PCOR(pcop)->r = r;
4292   pcop->type = PCOR(pcop)->r->pc_type;
4293
4294   return pcop;
4295 }
4296
4297 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4298 {
4299   pCodeOp *pcop;
4300   regs *r;
4301   
4302     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4303     pcop->name = NULL;
4304     
4305     r = pic16_findFreeReg(REG_GPR);
4306
4307     while(r) {
4308       if(!bitVectBitValue(bv, r->rIdx)) {
4309         PCOR(pcop)->r = r;
4310         PCOR(pcop)->rIdx = r->rIdx;
4311         pcop->type = r->pc_type;
4312         return (pcop);
4313       }
4314       
4315       r = pic16_findFreeRegNext(REG_GPR, r);
4316     }
4317   
4318   return NULL;
4319 }
4320
4321       
4322
4323 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4324 {
4325   pCodeOp *pcop;
4326   regs *r;
4327
4328         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4329         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4330         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4331         pcop->type = PCOR(pcop)->r->pc_type;
4332         pcop->name = PCOR(pcop)->r->name;
4333
4334 //      if(pic16_pcode_verbose) {
4335 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4336 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4337 //      }
4338
4339   return pcop;
4340 }
4341
4342 /*-----------------------------------------------------------------*/
4343 /*-----------------------------------------------------------------*/
4344 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4345 {
4346   pCodeOpOpt *pcop;
4347
4348         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4349         
4350         pcop->type = type;
4351         pcop->key = Safe_strdup( key );
4352
4353   return (PCOP(pcop));
4354 }
4355
4356 /*-----------------------------------------------------------------*/
4357 /*-----------------------------------------------------------------*/
4358 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4359 {
4360   pCodeOpLocalReg *pcop;
4361
4362         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4363         
4364         pcop->type = type;
4365
4366   return (PCOP(pcop));
4367 }
4368
4369
4370 /*-----------------------------------------------------------------*/
4371 /*-----------------------------------------------------------------*/
4372
4373 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4374 {
4375   pCodeOp *pcop;
4376
4377   switch(type) {
4378   case PO_BIT:
4379   case PO_GPR_BIT:
4380     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4381     break;
4382
4383   case PO_LITERAL:
4384     pcop = pic16_newpCodeOpLit(-1);
4385     break;
4386
4387   case PO_LABEL:
4388     pcop = pic16_newpCodeOpLabel(NULL,-1);
4389     break;
4390   case PO_GPR_TEMP:
4391     pcop = pic16_newpCodeOpReg(-1);
4392     break;
4393
4394   case PO_GPR_REGISTER:
4395     if(name)
4396       pcop = pic16_newpCodeOpRegFromStr(name);
4397     else
4398       pcop = pic16_newpCodeOpReg(-1);
4399     break;
4400     
4401   case PO_TWO_OPS:
4402     assert( !"Cannot create PO_TWO_OPS from string!" );
4403     pcop = NULL;
4404     break;
4405
4406   default:
4407     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4408     pcop->type = type;
4409     if(name)
4410       pcop->name = Safe_strdup(name);   
4411     else
4412       pcop->name = NULL;
4413   }
4414
4415   return pcop;
4416 }
4417
4418 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4419 {
4420   pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4421   pcop2->pcop.type = PO_TWO_OPS;
4422   pcop2->pcopL = src;
4423   pcop2->pcopR = dst;
4424   return PCOP(pcop2);
4425 }
4426
4427 /* This is a multiple of two as gpasm pads DB directives to even length,
4428  * thus the data would be interleaved with \0 bytes...
4429  * This is a multiple of three in order to have arrays of 3-byte pointers
4430  * continuously in memory (without 0-padding at the lines' end).
4431  * This is rather 12 than 6 in order not to split up 4-byte data types
4432  * in arrays right in the middle of a 4-byte word. */
4433 #define DB_ITEMS_PER_LINE       12
4434
4435 typedef struct DBdata
4436   {
4437     int count;
4438     char buffer[512];
4439   } DBdata;
4440
4441 struct DBdata DBd;
4442 static int DBd_init = -1;
4443
4444 /*-----------------------------------------------------------------*/
4445 /*    Initialiase "DB" data buffer                                 */
4446 /*-----------------------------------------------------------------*/
4447 void pic16_initDB(void)
4448 {
4449         DBd_init = -1;
4450 }
4451
4452
4453 /*-----------------------------------------------------------------*/
4454 /*    Flush pending "DB" data to a pBlock                          */
4455 /*                                                                 */
4456 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4457 /*-----------------------------------------------------------------*/
4458 void pic16_flushDB(char ptype, void *p)
4459 {
4460         if (DBd.count>0) {
4461                 if(ptype == 'p')
4462                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4463                 else
4464                 if(ptype == 'f')
4465                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4466                 else {
4467                         /* sanity check */
4468                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4469                 }
4470
4471                 DBd.count = 0;
4472                 DBd.buffer[0] = '\0';
4473         }
4474 }
4475
4476
4477 /*-----------------------------------------------------------------*/
4478 /*    Add "DB" directives to a pBlock                              */
4479 /*-----------------------------------------------------------------*/
4480 void pic16_emitDB(int c, char ptype, void *p)
4481 {
4482   int l;
4483
4484         if (DBd_init<0) {
4485          // we need to initialize
4486                 DBd_init = 0;
4487                 DBd.count = 0;
4488                 DBd.buffer[0] = '\0';
4489         }
4490
4491         l = strlen(DBd.buffer);
4492         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4493
4494 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4495         
4496         DBd.count++;
4497         if (DBd.count>= DB_ITEMS_PER_LINE)
4498                 pic16_flushDB(ptype, p);
4499 }
4500
4501 void pic16_emitDS(char *s, char ptype, void *p)
4502 {
4503   int l;
4504
4505         if (DBd_init<0) {
4506          // we need to initialize
4507                 DBd_init = 0;
4508                 DBd.count = 0;
4509                 DBd.buffer[0] = '\0';
4510         }
4511
4512         l = strlen(DBd.buffer);
4513         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4514
4515 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4516
4517         DBd.count++;    //=strlen(s);
4518         if (DBd.count>=DB_ITEMS_PER_LINE)
4519                 pic16_flushDB(ptype, p);
4520 }
4521
4522
4523 /*-----------------------------------------------------------------*/
4524 /*-----------------------------------------------------------------*/
4525 void pic16_pCodeConstString(char *name, char *value)
4526 {
4527   pBlock *pb;
4528   char *item;
4529   static set *emittedSymbols = NULL;
4530
4531   if(!name || !value)
4532     return;
4533
4534   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4535   if (emittedSymbols) {
4536     /* scan set for name */
4537     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4538     {
4539       if (!strcmp (item,name)) {
4540         //fprintf (stderr, "%s already emitted\n", name);
4541         return;
4542       } // if
4543     } // for
4544   } // if
4545   addSet (&emittedSymbols, Safe_strdup (name));
4546
4547   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4548
4549   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4550
4551   pic16_addpBlock(pb);
4552
4553 //  sprintf(buffer,"; %s = ", name);
4554 //  strcat(buffer, value);
4555 //  fputs(buffer, stderr);
4556
4557 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4558   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4559
4560   do {
4561         pic16_emitDB(*value, 'p', (void *)pb);
4562   }while (*value++);
4563   pic16_flushDB('p', (void *)pb);
4564 }
4565
4566 /*-----------------------------------------------------------------*/
4567 /*-----------------------------------------------------------------*/
4568 #if 0
4569 static void pCodeReadCodeTable(void)
4570 {
4571   pBlock *pb;
4572
4573   fprintf(stderr, " %s\n",__FUNCTION__);
4574
4575   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4576
4577   pic16_addpBlock(pb);
4578
4579   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4580   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4581   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4582   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4583
4584   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4585   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4586   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4587   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4588
4589
4590 }
4591 #endif
4592 /*-----------------------------------------------------------------*/
4593 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4594 /*-----------------------------------------------------------------*/
4595 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4596 {
4597
4598   if(!pc)
4599     return;
4600
4601   if(!pb->pcHead) {
4602     /* If this is the first pcode to be added to a block that
4603      * was initialized with a NULL pcode, then go ahead and
4604      * make this pcode the head and tail */
4605     pb->pcHead  = pb->pcTail = pc;
4606   } else {
4607     //    if(pb->pcTail)
4608     pb->pcTail->next = pc;
4609
4610     pc->prev = pb->pcTail;
4611     pc->pb = pb;
4612
4613     pb->pcTail = pc;
4614   }
4615 }
4616
4617 /*-----------------------------------------------------------------*/
4618 /* pic16_addpBlock - place a pBlock into the pFile                 */
4619 /*-----------------------------------------------------------------*/
4620 void pic16_addpBlock(pBlock *pb)
4621 {
4622   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4623
4624   if(!the_pFile) {
4625     /* First time called, we'll pass through here. */
4626     //_ALLOC(the_pFile,sizeof(pFile));
4627     the_pFile = Safe_calloc(1,sizeof(pFile));
4628     the_pFile->pbHead = the_pFile->pbTail = pb;
4629     the_pFile->functions = NULL;
4630     return;
4631   }
4632
4633   the_pFile->pbTail->next = pb;
4634   pb->prev = the_pFile->pbTail;
4635   pb->next = NULL;
4636   the_pFile->pbTail = pb;
4637 }
4638
4639 /*-----------------------------------------------------------------*/
4640 /* removepBlock - remove a pBlock from the pFile                   */
4641 /*-----------------------------------------------------------------*/
4642 static void removepBlock(pBlock *pb)
4643 {
4644   pBlock *pbs;
4645
4646   if(!the_pFile)
4647     return;
4648
4649
4650   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4651
4652   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4653     if(pbs == pb) {
4654
4655       if(pbs == the_pFile->pbHead)
4656         the_pFile->pbHead = pbs->next;
4657
4658       if (pbs == the_pFile->pbTail) 
4659         the_pFile->pbTail = pbs->prev;
4660
4661       if(pbs->next)
4662         pbs->next->prev = pbs->prev;
4663
4664       if(pbs->prev)
4665         pbs->prev->next = pbs->next;
4666
4667       return;
4668
4669     }
4670   }
4671
4672   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4673
4674 }
4675
4676 /*-----------------------------------------------------------------*/
4677 /* printpCode - write the contents of a pCode to a file            */
4678 /*-----------------------------------------------------------------*/
4679 static void printpCode(FILE *of, pCode *pc)
4680 {
4681
4682   if(!pc || !of)
4683     return;
4684
4685   if(pc->print) {
4686     pc->print(of,pc);
4687     return;
4688   }
4689
4690   fprintf(of,"warning - unable to print pCode\n");
4691 }
4692
4693 /*-----------------------------------------------------------------*/
4694 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4695 /*-----------------------------------------------------------------*/
4696 void pic16_printpBlock(FILE *of, pBlock *pb)
4697 {
4698   pCode *pc;
4699
4700         if(!pb)return;
4701
4702         if(!of)of=stderr;
4703
4704         for(pc = pb->pcHead; pc; pc = pc->next) {
4705                 if(isPCF(pc) && PCF(pc)->fname) {
4706                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4707                         if(pb->dbName == 'A') {
4708                           absSym *ab;
4709                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4710 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4711                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4712 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4713                                                 if(ab->address != -1)
4714                                                   fprintf(of, "\t0X%06X", ab->address);
4715                                                 break;
4716                                         }
4717                                 }
4718                         }
4719                         fprintf(of, "\n");
4720                 }
4721                 printpCode(of,pc);
4722         }
4723 }
4724
4725 /*-----------------------------------------------------------------*/
4726 /*                                                                 */
4727 /*       pCode processing                                          */
4728 /*                                                                 */
4729 /*                                                                 */
4730 /*                                                                 */
4731 /*-----------------------------------------------------------------*/
4732 pCode * pic16_findNextInstruction(pCode *pci);
4733 pCode * pic16_findPrevInstruction(pCode *pci);
4734
4735 void pic16_unlinkpCode(pCode *pc)
4736 {
4737   pCode *prev;
4738
4739   if(pc) {
4740 #ifdef PCODE_DEBUG
4741     fprintf(stderr,"Unlinking: ");
4742     printpCode(stderr, pc);
4743 #endif
4744     if(pc->prev) 
4745       pc->prev->next = pc->next;
4746     if(pc->next)
4747       pc->next->prev = pc->prev;
4748
4749     /* move C source line down (or up) */
4750     if (isPCI(pc) && PCI(pc)->cline) {
4751       prev = pic16_findNextInstruction (pc->next);
4752       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4753         PCI(prev)->cline = PCI(pc)->cline;
4754       } else {
4755         prev = pic16_findPrevInstruction (pc->prev);
4756         if (prev && isPCI(prev) && !PCI(prev)->cline)
4757           PCI(prev)->cline = PCI(pc)->cline;
4758       }
4759     }
4760     pc->prev = pc->next = NULL;
4761   }
4762 }
4763
4764 /*-----------------------------------------------------------------*/
4765 /*-----------------------------------------------------------------*/
4766
4767 static void genericDestruct(pCode *pc)
4768 {
4769
4770   pic16_unlinkpCode(pc);
4771
4772   if(isPCI(pc)) {
4773     /* For instructions, tell the register (if there's one used)
4774      * that it's no longer needed */
4775     regs *reg = pic16_getRegFromInstruction(pc);
4776     if(reg)
4777       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4778
4779         if(PCI(pc)->is2MemOp) {
4780                 reg = pic16_getRegFromInstruction2(pc);
4781                 if(reg)
4782                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4783         }
4784   }
4785
4786   /* Instead of deleting the memory used by this pCode, mark
4787    * the object as bad so that if there's a pointer to this pCode
4788    * dangling around somewhere then (hopefully) when the type is
4789    * checked we'll catch it.
4790    */
4791
4792   pc->type = PC_BAD;
4793   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4794
4795   //Safe_free(pc);
4796 }
4797
4798
4799 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4800 /*-----------------------------------------------------------------*/
4801 /*-----------------------------------------------------------------*/
4802 /* modifiers for constant immediate */
4803 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4804
4805 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4806 {
4807   regs *r;
4808   static char b[128];
4809   char *s;
4810   int use_buffer = 1;    // copy the string to the passed buffer pointer
4811
4812         if(!buffer) {
4813                 buffer = b;
4814                 size = sizeof(b);
4815                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4816         } 
4817
4818         if(pcop) {
4819
4820                 switch(pcop->type) {
4821                         case PO_W:
4822                         case PO_WREG:
4823                         case PO_PRODL:
4824                         case PO_PRODH:
4825                         case PO_INDF0:
4826                         case PO_FSR0:
4827                                 if(use_buffer) {
4828                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4829                                         return (buffer);
4830                                 }
4831                                 return (PCOR(pcop)->r->name);
4832                                 break;
4833                         case PO_GPR_TEMP:
4834                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4835                                 if(use_buffer) {
4836                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4837                                         return (buffer);
4838                                 }
4839                                 return (r->name);
4840
4841                         case PO_IMMEDIATE:
4842                                 s = buffer;
4843                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4844                                         if(PCOI(pcop)->index) {
4845                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4846                                                         immdmod[ PCOI(pcop)->offset ],
4847                                                         pcop->name,
4848                                                         PCOI(pcop)->index);
4849                                         } else {
4850                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4851                                                         immdmod[ PCOI(pcop)->offset ],
4852                                                         pcop->name);
4853                                         }
4854                                 } else {
4855                                         if(PCOI(pcop)->index) {
4856                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4857                                                         immdmod[ 0 ],
4858                                                         pcop->name,
4859                                                         PCOI(pcop)->index);
4860                                         } else {
4861                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4862                                                         immdmod[ 0 ],
4863                                                         pcop->name);
4864                                         }
4865                                 }
4866                                 return (buffer);
4867
4868                         case PO_GPR_REGISTER:
4869                         case PO_DIR:
4870                                 s = buffer;
4871 //                              size = sizeof(buffer);
4872                                 if( PCOR(pcop)->instance) {
4873                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4874                                                 pcop->name,
4875                                                 PCOR(pcop)->instance );
4876                                 } else {
4877                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4878                                 }
4879                                 return (buffer);
4880                         case PO_GPR_BIT:
4881                                 s = buffer;
4882                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4883                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4884                                 } else {
4885                                         if(PCORB(pcop)->pcor.instance)
4886                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4887                                         else
4888                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4889                                 }
4890
4891                                 return (buffer);
4892                         case PO_TWO_OPS:
4893                                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4894                                 
4895                         default:
4896                                 if(pcop->name) {
4897                                         if(use_buffer) {
4898                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4899                                                 return (buffer);
4900                                         }
4901                                 return (pcop->name);
4902                                 }
4903
4904                 }
4905                 return ("unhandled type for op1");
4906         }
4907
4908   return ("NO operand1");
4909 }
4910
4911 /*-----------------------------------------------------------------*/
4912 /* pic16_get_op2 - variant to support two memory operand commands  */
4913 /*-----------------------------------------------------------------*/
4914 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4915 {
4916
4917   if(pcop && pcop->type == PO_TWO_OPS) {
4918     return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4919   }
4920
4921   return "NO operand2";
4922 }
4923
4924 /*-----------------------------------------------------------------*/
4925 /*-----------------------------------------------------------------*/
4926 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4927 {
4928
4929   if(pcc )
4930     return pic16_get_op(pcc->pcop,NULL,0);
4931
4932   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
4933    *   return ("ERROR Null: "__FUNCTION__);
4934    */
4935   return ("ERROR Null: pic16_get_op_from_instruction");
4936
4937 }
4938
4939 /*-----------------------------------------------------------------*/
4940 /*-----------------------------------------------------------------*/
4941 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4942 {
4943
4944   fprintf(of,"pcodeopprint- not implemented\n");
4945 }
4946
4947 /*-----------------------------------------------------------------*/
4948 /* pic16_pCode2str - convert a pCode instruction to string               */
4949 /*-----------------------------------------------------------------*/
4950 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4951 {
4952   char *s = str;
4953   regs *r;
4954
4955 #if 0
4956         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4957                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4958                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4959 //              exit(EXIT_FAILURE);
4960         }
4961 #endif
4962
4963   switch(pc->type) {
4964
4965   case PC_OPCODE:
4966     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4967
4968     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4969
4970         //if(PCI(pc)->is2MemOp)
4971         if (PCI(pc)->pcop->type == PO_TWO_OPS)
4972         {
4973                 /* split into two phases due to static buffer in pic16_get_op() */
4974                 SAFE_snprintf(&s,&size, "%s", 
4975                         pic16_get_op((PCI(pc)->pcop), NULL, 0));
4976                 SAFE_snprintf(&s, &size, ", %s",
4977                         pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4978                 break;
4979         }
4980
4981         if(PCI(pc)->is2LitOp) {
4982                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4983                 break;
4984         }
4985
4986       if(PCI(pc)->isBitInst) {
4987         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4988           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4989             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
4990                           PCI(pc)->pcop->name ,
4991                           PCI(pc)->pcop->name );
4992           else
4993             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4994 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
4995                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4996                           
4997         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4998           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4999         } else
5000           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5001         //PCI(pc)->pcop->t.bit );
5002       } else {
5003
5004         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5005           if( PCI(pc)->num_ops == 3)
5006             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5007           else
5008             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5009
5010         }
5011         else 
5012         {
5013           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5014         }
5015       }
5016         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5017           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5018             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5019
5020           r = pic16_getRegFromInstruction(pc);
5021 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5022 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?isACCESS_BANK(r):-1);
5023
5024           if(PCI(pc)->isAccess) {
5025             static char *bank_spec[2][2] = {
5026               { "", ", ACCESS" },  /* gpasm uses access bank by default */
5027               { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5028             };
5029              
5030             SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5031           }
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   case PO_TWO_OPS:
5800     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5801     break;
5802     
5803   default:
5804         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5805 //      assert( 0 );
5806         break;
5807   }
5808
5809   return NULL;
5810 }
5811
5812 /*-----------------------------------------------------------------*/
5813 /*-----------------------------------------------------------------*/
5814 regs * pic16_getRegFromInstruction(pCode *pc)
5815 {
5816   if(!pc                   || 
5817      !isPCI(pc)            ||
5818      !PCI(pc)->pcop        ||
5819      PCI(pc)->num_ops == 0 ||
5820      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5821     return NULL;
5822
5823 #if 0
5824   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5825         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5826 #endif
5827
5828   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5829 }
5830
5831 /*-------------------------------------------------------------------------------*/
5832 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5833 /*-------------------------------------------------------------------------------*/
5834 regs * pic16_getRegFromInstruction2(pCode *pc)
5835 {
5836
5837   if(!pc                   || 
5838      !isPCI(pc)            ||
5839      !PCI(pc)->pcop        ||
5840      PCI(pc)->num_ops == 0 ||
5841      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5842     return NULL;
5843
5844   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5845     return NULL;
5846
5847 #if 0
5848   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5849         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5850 #endif
5851
5852   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5853 }
5854
5855 /*-----------------------------------------------------------------*/
5856 /*-----------------------------------------------------------------*/
5857
5858 static void AnalyzepBlock(pBlock *pb)
5859 {
5860   pCode *pc;
5861
5862   if(!pb)
5863     return;
5864
5865   /* Find all of the registers used in this pBlock 
5866    * by looking at each instruction and examining it's
5867    * operands
5868    */
5869   for(pc = pb->pcHead; pc; pc = pc->next) {
5870
5871     /* Is this an instruction with operands? */
5872     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5873
5874       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5875
5876         /* Loop through all of the registers declared so far in
5877            this block and see if we find this one there */
5878
5879         regs *r = setFirstItem(pb->tregisters);
5880
5881         while(r) {
5882           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5883             PCOR(PCI(pc)->pcop)->r = r;
5884             break;
5885           }
5886           r = setNextItem(pb->tregisters);
5887         }
5888
5889         if(!r) {
5890           /* register wasn't found */
5891           //r = Safe_calloc(1, sizeof(regs));
5892           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5893           //addSet(&pb->tregisters, r);
5894           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5895           //PCOR(PCI(pc)->pcop)->r = r;
5896           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5897         }/* else 
5898           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5899          */
5900       }
5901       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5902         if(PCOR(PCI(pc)->pcop)->r) {
5903           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5904           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5905         } else {
5906           if(PCI(pc)->pcop->name)
5907             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5908           else
5909             fprintf(stderr,"ERROR: NULL register\n");
5910         }
5911       }
5912     }
5913
5914
5915   }
5916 }
5917
5918 /*-----------------------------------------------------------------*/
5919 /* */
5920 /*-----------------------------------------------------------------*/
5921 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5922
5923 static void InsertpFlow(pCode *pc, pCode **pflow)
5924 {
5925   if(*pflow)
5926     PCFL(*pflow)->end = pc;
5927
5928   if(!pc || !pc->next)
5929     return;
5930
5931   *pflow = pic16_newpCodeFlow();
5932   pic16_pCodeInsertAfter(pc, *pflow);
5933 }
5934
5935 /*-----------------------------------------------------------------*/
5936 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5937 /*                         the flow blocks.                        */
5938 /*
5939  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5940  * point the instruction flow changes. 
5941  */
5942 /*-----------------------------------------------------------------*/
5943 void pic16_BuildFlow(pBlock *pb)
5944 {
5945   pCode *pc;
5946   pCode *last_pci=NULL;
5947   pCode *pflow=NULL;
5948   int seq = 0;
5949
5950   if(!pb)
5951     return;
5952
5953   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5954   /* Insert a pCodeFlow object at the beginning of a pBlock */
5955
5956   InsertpFlow(pb->pcHead, &pflow);
5957
5958   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5959   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5960   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5961   //pb->pcHead = pflow;        /* Make the Flow object the head */
5962   //pflow->pb = pb;
5963
5964   for( pc = pic16_findNextInstruction(pb->pcHead);
5965        pc != NULL;
5966        pc=pic16_findNextInstruction(pc)) { 
5967
5968     pc->seq = seq++;
5969     PCI(pc)->pcflow = PCFL(pflow);
5970
5971     //fprintf(stderr," build: ");
5972     //pflow->print(stderr,pflow);
5973
5974     if (checkLabel(pc)) { 
5975
5976       /* This instruction marks the beginning of a
5977        * new flow segment */
5978
5979       pc->seq = 0;
5980       seq = 1;
5981
5982       /* If the previous pCode is not a flow object, then 
5983        * insert a new flow object. (This check prevents 
5984        * two consecutive flow objects from being insert in
5985        * the case where a skip instruction preceeds an
5986        * instruction containing a label.) */
5987
5988       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5989         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5990
5991       PCI(pc)->pcflow = PCFL(pflow);
5992       
5993     }
5994
5995     if( PCI(pc)->isSkip) {
5996
5997       /* The two instructions immediately following this one 
5998        * mark the beginning of a new flow segment */
5999
6000       while(pc && PCI(pc)->isSkip) {
6001
6002         PCI(pc)->pcflow = PCFL(pflow);
6003         pc->seq = seq-1;
6004         seq = 1;
6005
6006         InsertpFlow(pc, &pflow);
6007         pc=pic16_findNextInstruction(pc->next);
6008       }
6009
6010       seq = 0;
6011
6012       if(!pc)
6013         break;
6014
6015       PCI(pc)->pcflow = PCFL(pflow);
6016       pc->seq = 0;
6017       InsertpFlow(pc, &pflow);
6018
6019     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6020
6021       InsertpFlow(pc, &pflow);
6022       seq = 0;
6023
6024     }
6025     last_pci = pc;
6026     pc = pc->next;
6027   }
6028
6029   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6030   if(pflow)
6031     PCFL(pflow)->end = pb->pcTail;
6032 }
6033
6034 /*-------------------------------------------------------------------*/
6035 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6036 /*                           the flow blocks.                        */
6037 /*
6038  * unBuildFlow removes pCodeFlow objects from a pCode chain
6039  */
6040 /*-----------------------------------------------------------------*/
6041 static void unBuildFlow(pBlock *pb)
6042 {
6043   pCode *pc,*pcnext;
6044
6045   if(!pb)
6046     return;
6047
6048   pc = pb->pcHead;
6049
6050   while(pc) {
6051     pcnext = pc->next;
6052
6053     if(isPCI(pc)) {
6054
6055       pc->seq = 0;
6056       if(PCI(pc)->pcflow) {
6057         //Safe_free(PCI(pc)->pcflow);
6058         PCI(pc)->pcflow = NULL;
6059       }
6060
6061     } else if(isPCFL(pc) )
6062       pc->destruct(pc);
6063
6064     pc = pcnext;
6065   }
6066
6067
6068 }
6069 #if 0
6070 /*-----------------------------------------------------------------*/
6071 /*-----------------------------------------------------------------*/
6072 static void dumpCond(int cond)
6073 {
6074
6075   static char *pcc_str[] = {
6076     //"PCC_NONE",
6077     "PCC_REGISTER",
6078     "PCC_C",
6079     "PCC_Z",
6080     "PCC_DC",
6081     "PCC_OV",
6082     "PCC_N",
6083     "PCC_W",
6084     "PCC_EXAMINE_PCOP",
6085     "PCC_LITERAL",
6086     "PCC_REL_ADDR"
6087   };
6088
6089   int ncond = sizeof(pcc_str) / sizeof(char *);
6090   int i,j;
6091
6092   fprintf(stderr, "0x%04X\n",cond);
6093
6094   for(i=0,j=1; i<ncond; i++, j<<=1)
6095     if(cond & j)
6096       fprintf(stderr, "  %s\n",pcc_str[i]);
6097
6098 }
6099 #endif
6100
6101 #if 0
6102 /*-----------------------------------------------------------------*/
6103 /*-----------------------------------------------------------------*/
6104 static void FlowStats(pCodeFlow *pcflow)
6105 {
6106
6107   pCode *pc;
6108
6109   if(!isPCFL(pcflow))
6110     return;
6111
6112   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6113
6114   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6115
6116   if(!pc) {
6117     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6118     return;
6119   }
6120
6121
6122   fprintf(stderr, "  FlowStats inCond: ");
6123   dumpCond(pcflow->inCond);
6124   fprintf(stderr, "  FlowStats outCond: ");
6125   dumpCond(pcflow->outCond);
6126
6127 }
6128 #endif
6129 /*-----------------------------------------------------------------*
6130  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6131  *    if it affects the banking bits. 
6132  * 
6133  * return: -1 == Banking bits are unaffected by this pCode.
6134  *
6135  * return: > 0 == Banking bits are affected.
6136  *
6137  *  If the banking bits are affected, then the returned value describes
6138  * which bits are affected and how they're affected. The lower half
6139  * of the integer maps to the bits that are affected, the upper half
6140  * to whether they're set or cleared.
6141  *
6142  *-----------------------------------------------------------------*/
6143
6144 static int isBankInstruction(pCode *pc)
6145 {
6146   regs *reg;
6147   int bank = -1;
6148
6149   if(!isPCI(pc))
6150     return 0;
6151
6152   if( PCI(pc)->op == POC_MOVLB ||
6153       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6154     bank = PCOL(pc)->lit;
6155   }
6156
6157   return 1;
6158 }
6159
6160
6161 /*-----------------------------------------------------------------*/
6162 /*-----------------------------------------------------------------*/
6163 static void FillFlow(pCodeFlow *pcflow)
6164 {
6165
6166   pCode *pc;
6167   int cur_bank;
6168
6169   if(!isPCFL(pcflow))
6170     return;
6171
6172   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6173
6174   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6175
6176   if(!pc) {
6177     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6178     return;
6179   }
6180
6181   cur_bank = -1;
6182
6183   do {
6184     isBankInstruction(pc);
6185     pc = pc->next;
6186   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6187
6188 /*
6189   if(!pc ) {
6190     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6191   } else {
6192     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6193     pc->print(stderr,pc);
6194   }
6195
6196   fprintf(stderr, "  FillFlow inCond: ");
6197   dumpCond(pcflow->inCond);
6198   fprintf(stderr, "  FillFlow outCond: ");
6199   dumpCond(pcflow->outCond);
6200 */
6201 }
6202
6203 /*-----------------------------------------------------------------*/
6204 /*-----------------------------------------------------------------*/
6205 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6206 {
6207   pCodeFlowLink *fromLink, *toLink;
6208
6209   if(!from || !to || !to->pcflow || !from->pcflow)
6210     return;
6211
6212   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6213   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6214
6215   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6216   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6217
6218 }
6219
6220 pCode *pic16_getJumptabpCode (pCode *pc) {
6221   pCode *pcinf;
6222
6223   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6224   //pc->print (stderr, pc);
6225   pcinf = pc;
6226   while (pcinf) {
6227     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6228     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6229       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6230       case OPT_JUMPTABLE_BEGIN:
6231         /* leading begin of jump table -- in one */
6232         pcinf = pic16_findPrevInstruction (pcinf);
6233         return pcinf;
6234         break;
6235         
6236       case OPT_JUMPTABLE_END:
6237         /* leading end of jumptable -- not in one */
6238         return NULL;
6239         break;
6240         
6241       default:
6242         /* ignore all other PCInfos */
6243         break;
6244       }
6245     }
6246     pcinf = pcinf->prev;
6247   }
6248
6249   /* no PCInfo found -- not in a jumptable */
6250   return NULL;
6251 }
6252
6253 /*-----------------------------------------------------------------*
6254  * void LinkFlow(pBlock *pb)
6255  *
6256  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6257  * non-branching segments. In LinkFlow, we determine the execution
6258  * order of these segments. For example, if one of the segments ends
6259  * with a skip, then we know that there are two possible flow segments
6260  * to which control may be passed.
6261  *-----------------------------------------------------------------*/
6262 static void LinkFlow(pBlock *pb)
6263 {
6264   pCode *pc=NULL;
6265   pCode *pcflow;
6266   pCode *pct;
6267   pCode *jumptab_pre = NULL;
6268
6269   //fprintf(stderr,"linkflow \n");
6270
6271   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6272        pcflow != NULL;
6273        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6274
6275     if(!isPCFL(pcflow))
6276       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6277
6278     //fprintf(stderr," link: ");
6279     //pcflow->print(stderr,pcflow);
6280
6281     //FillFlow(PCFL(pcflow));
6282
6283     pc = PCFL(pcflow)->end;
6284
6285     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6286     if(isPCI_SKIP(pc)) {
6287 //      fprintf(stderr, "ends with skip\n");
6288 //      pc->print(stderr,pc);
6289
6290       pct=pic16_findNextInstruction(pc->next);
6291       LinkFlow_pCode(PCI(pc),PCI(pct));
6292       pct=pic16_findNextInstruction(pct->next);
6293       LinkFlow_pCode(PCI(pc),PCI(pct));
6294       continue;
6295     }
6296
6297     if(isPCI_BRANCH(pc)) {
6298       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6299
6300       /* handle GOTOs in jumptables */
6301       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6302         /* link to previous flow */
6303         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6304         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6305       }
6306
6307       switch (PCI(pc)->op) {
6308       case POC_GOTO:
6309       case POC_BRA:
6310       case POC_RETURN:
6311       case POC_RETLW:
6312       case POC_RETFIE:
6313               /* unconditional branches -- do not link to next instruction */
6314               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6315               break;
6316               
6317       case POC_CALL:
6318       case POC_RCALL:
6319               /* unconditional calls -- link to next instruction */
6320               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6321               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6322               break;
6323               
6324       case POC_BC:
6325       case POC_BN:
6326       case POC_BNC:
6327       case POC_BNN:
6328       case POC_BNOV:
6329       case POC_BNZ:
6330       case POC_BOV:
6331       case POC_BZ:
6332               /* conditional branches -- also link to next instruction */
6333               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6334               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6335               break;
6336               
6337       default:
6338               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6339               assert (0 && "unhandled branching instruction");
6340               break;
6341       }
6342
6343       //fprintf(stderr, "ends with branch\n  ");
6344       //pc->print(stderr,pc);
6345
6346       if(!(pcol && isPCOLAB(pcol))) {
6347         if((PCI(pc)->op != POC_RETLW)
6348                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6349         
6350                 /* continue if label is '$' which assembler knows how to parse */
6351                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6352
6353                 if(pic16_pcode_verbose) {
6354                         pc->print(stderr,pc);
6355                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6356                 }
6357         }
6358         continue;
6359       }
6360
6361       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6362         LinkFlow_pCode(PCI(pc),PCI(pct));
6363       else
6364         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6365                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6366
6367 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6368
6369       continue;
6370     }
6371
6372     if(isPCI(pc)) {
6373       //fprintf(stderr, "ends with non-branching instruction:\n");
6374       //pc->print(stderr,pc);
6375
6376       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6377
6378       continue;
6379     }
6380
6381     if(pc) {
6382       //fprintf(stderr, "ends with unknown\n");
6383       //pc->print(stderr,pc);
6384       continue;
6385     }
6386
6387     //fprintf(stderr, "ends with nothing: ERROR\n");
6388     
6389   }
6390 }
6391 /*-----------------------------------------------------------------*/
6392 /*-----------------------------------------------------------------*/
6393
6394 /*-----------------------------------------------------------------*/
6395 /*-----------------------------------------------------------------*/
6396 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6397 {
6398
6399   if(!pc || !pcflow)
6400     return 0;
6401
6402   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6403     return 0;
6404
6405   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6406     return 1;
6407
6408   return 0;
6409 }
6410
6411
6412
6413
6414
6415 /*-----------------------------------------------------------------*/
6416 /* insertBankSwitch - inserts a bank switch statement in the       */
6417 /*                    assembly listing                             */
6418 /*                                                                 */
6419 /* position == 0: insert before                                    */
6420 /* position == 1: insert after pc                                  */
6421 /* position == 2: like 0 but previous was a skip instruction       */
6422 /*-----------------------------------------------------------------*/
6423 pCodeOp *pic16_popGetLabel(unsigned int key);
6424 extern int pic16_labelOffset;
6425
6426 static void insertBankSwitch(unsigned char position, pCode *pc)
6427 {
6428   pCode *new_pc;
6429
6430         if(!pc)
6431                 return;
6432
6433         /* emit BANKSEL [symbol] */
6434
6435
6436         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6437         
6438 //      position = 0;           // position is always before (sanity check!)
6439
6440 #if 0
6441         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6442         pc->print(stderr, pc);
6443 #endif
6444
6445         switch(position) {
6446                 case 1: {
6447                         /* insert the bank switch after this pc instruction */
6448                         pCode *pcnext = pic16_findNextInstruction(pc);
6449
6450                                 pic16_pCodeInsertAfter(pc, new_pc);
6451                                 if(pcnext)pc = pcnext;
6452                 }; break;
6453                 
6454                 case 0:
6455                         /* insert the bank switch BEFORE this pc instruction */
6456                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6457                         break;
6458
6459                 case 2: {
6460                           symbol *tlbl;
6461                           pCode *pcnext, *pcprev, *npci, *ppc;
6462                           PIC_OPCODE ipci;
6463                           int ofs1=0, ofs2=0, len=0;
6464                           
6465                         /* just like 0, but previous was a skip instruction,
6466                          * so some care should be taken */
6467                           
6468                                 pic16_labelOffset += 10000;
6469                                 tlbl = newiTempLabel(NULL);
6470                                 
6471                                 /* invert skip instruction */
6472                                 pcprev = pic16_findPrevInstruction(pc->prev);
6473                                 ipci = PCI(pcprev)->inverted_op;
6474                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6475
6476 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6477
6478                                 /* copy info from old pCode */
6479                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6480                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6481                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6482                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6483                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6484                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6485                                 
6486                                 /* unlink old pCode */
6487                                 ppc = pcprev->prev;
6488                                 ppc->next = pcprev->next;
6489                                 pcprev->next->prev = ppc;
6490                                 pic16_pCodeInsertAfter(ppc, npci);
6491                                 
6492                                 /* extra instructions to handle invertion */
6493                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6494                                 pic16_pCodeInsertAfter(npci, pcnext);
6495                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6496                                 
6497                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6498                                 pic16_pCodeInsertAfter(pc, pcnext);
6499                         }; break;
6500         }
6501         
6502
6503         /* Move the label, if there is one */
6504         if(PCI(pc)->label) {
6505 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6506 //                      __FILE__, __LINE__, pc, new_pc);
6507                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6508                 PCI(pc)->label = NULL;
6509         }
6510 }
6511
6512
6513 /*-----------------------------------------------------------------*/
6514 /*int compareBankFlow - compare the banking requirements between   */
6515 /*  flow objects. */
6516 /*-----------------------------------------------------------------*/
6517 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6518 {
6519
6520   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6521     return 0;
6522
6523   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6524     return 0;
6525
6526   if(pcflow->firstBank == -1)
6527     return 0;
6528
6529
6530   if(pcflowLink->pcflow->firstBank == -1) {
6531     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6532                                         pcflowLink->pcflow->to : 
6533                                         pcflowLink->pcflow->from);
6534     return compareBankFlow(pcflow, pctl, toORfrom);
6535   }
6536
6537   if(toORfrom) {
6538     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6539       return 0;
6540
6541     pcflowLink->bank_conflict++;
6542     pcflowLink->pcflow->FromConflicts++;
6543     pcflow->ToConflicts++;
6544   } else {
6545     
6546     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6547       return 0;
6548
6549     pcflowLink->bank_conflict++;
6550     pcflowLink->pcflow->ToConflicts++;
6551     pcflow->FromConflicts++;
6552
6553   }
6554   /*
6555   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6556           pcflowLink->pcflow->pc.seq,
6557           pcflowLink->pcflow->FromConflicts,
6558           pcflowLink->pcflow->ToConflicts);
6559   */
6560   return 1;
6561
6562 }
6563
6564 #if 0
6565 /*-----------------------------------------------------------------*/
6566 /*-----------------------------------------------------------------*/
6567 static void DumpFlow(pBlock *pb)
6568 {
6569   pCode *pc=NULL;
6570   pCode *pcflow;
6571   pCodeFlowLink *pcfl;
6572
6573
6574   fprintf(stderr,"Dump flow \n");
6575   pb->pcHead->print(stderr, pb->pcHead);
6576
6577   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6578   pcflow->print(stderr,pcflow);
6579
6580   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6581        pcflow != NULL;
6582        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6583
6584     if(!isPCFL(pcflow)) {
6585       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6586       continue;
6587     }
6588     fprintf(stderr,"dumping: ");
6589     pcflow->print(stderr,pcflow);
6590     FlowStats(PCFL(pcflow));
6591
6592     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6593
6594       pc = PCODE(pcfl->pcflow);
6595
6596       fprintf(stderr, "    from seq %d:\n",pc->seq);
6597       if(!isPCFL(pc)) {
6598         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6599         pc->print(stderr,pc);
6600       }
6601
6602     }
6603
6604     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6605
6606       pc = PCODE(pcfl->pcflow);
6607
6608       fprintf(stderr, "    to seq %d:\n",pc->seq);
6609       if(!isPCFL(pc)) {
6610         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6611         pc->print(stderr,pc);
6612       }
6613
6614     }
6615
6616   }
6617
6618 }
6619 #endif
6620 /*-----------------------------------------------------------------*/
6621 /*-----------------------------------------------------------------*/
6622 static int OptimizepBlock(pBlock *pb)
6623 {
6624   pCode *pc, *pcprev;
6625   int matches =0;
6626
6627   if(!pb || !peepOptimizing)
6628     return 0;
6629
6630   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6631 /*
6632   for(pc = pb->pcHead; pc; pc = pc->next)
6633     matches += pic16_pCodePeepMatchRule(pc);
6634 */
6635
6636   pc = pic16_findNextInstruction(pb->pcHead);
6637   if(!pc)
6638     return 0;
6639
6640   pcprev = pc->prev;
6641   do {
6642
6643
6644     if(pic16_pCodePeepMatchRule(pc)) {
6645
6646       matches++;
6647
6648       if(pcprev)
6649         pc = pic16_findNextInstruction(pcprev->next);
6650       else 
6651         pc = pic16_findNextInstruction(pb->pcHead);
6652     } else
6653       pc = pic16_findNextInstruction(pc->next);
6654   } while(pc);
6655
6656   if(matches)
6657     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6658   return matches;
6659
6660 }
6661
6662 /*-----------------------------------------------------------------*/
6663 /*-----------------------------------------------------------------*/
6664 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6665 {
6666   pCode *pc;
6667
6668   for(pc = pcs; pc; pc = pc->next) {
6669
6670     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6671        (PCI(pc)->pcop) && 
6672        (PCI(pc)->pcop->type == PO_LABEL) &&
6673        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6674       return pc;
6675   }
6676  
6677
6678   return NULL;
6679 }
6680
6681 /*-----------------------------------------------------------------*/
6682 /*-----------------------------------------------------------------*/
6683 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6684 {
6685
6686   char *s=NULL;
6687
6688   if(isPCI(pc) && 
6689      (PCI(pc)->pcop) && 
6690      (PCI(pc)->pcop->type == PO_LABEL)) {
6691
6692     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6693
6694 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6695 //    if(pcol->pcop.name)
6696 //      Safe_free(pcol->pcop.name);
6697
6698     /* If the key is negative, then we (probably) have a label to
6699      * a function and the name is already defined */
6700        
6701     if(pcl->key>0)
6702       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6703     else 
6704       s = pcl->label;
6705
6706     //sprintf(buffer,"_%05d_DS_",pcl->key);
6707     if(!s) {
6708       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6709     }
6710     pcol->pcop.name = Safe_strdup(s);
6711     pcol->key = pcl->key;
6712     //pc->print(stderr,pc);
6713
6714   }
6715
6716
6717 }
6718
6719 /*-----------------------------------------------------------------*/
6720 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6721 /*                            pCode chain if they're not used.     */
6722 /*-----------------------------------------------------------------*/
6723 static void pBlockRemoveUnusedLabels(pBlock *pb)
6724 {
6725   pCode *pc; pCodeLabel *pcl;
6726
6727   if(!pb || !pb->pcHead)
6728     return;
6729
6730   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6731
6732     pBranch *pbr = PCI(pc)->label;
6733     if(pbr && pbr->next) {
6734       pCode *pcd = pb->pcHead;
6735
6736 //      fprintf(stderr, "multiple labels\n");
6737 //      pc->print(stderr,pc);
6738
6739       pbr = pbr->next;
6740       while(pbr) {
6741
6742         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6743           //fprintf(stderr,"Used by:\n");
6744           //pcd->print(stderr,pcd);
6745
6746           exchangeLabels(PCL(pbr->pc),pcd);
6747
6748           pcd = pcd->next;
6749         }
6750         pbr = pbr->next;
6751       }
6752     }
6753   }
6754
6755   for(pc = pb->pcHead; pc; pc = pc->next) {
6756
6757     if(isPCL(pc)) // pc->type == PC_LABEL)
6758       pcl = PCL(pc);
6759     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6760       pcl = PCL(PCI(pc)->label->pc);
6761     else continue;
6762
6763 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6764
6765     /* This pCode is a label, so search the pBlock to see if anyone
6766      * refers to it */
6767
6768     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6769         && (!pcl->force)) {
6770     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6771       /* Couldn't find an instruction that refers to this label
6772        * So, unlink the pCode label from it's pCode chain
6773        * and destroy the label */
6774 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6775
6776       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6777       if(pc->type == PC_LABEL) {
6778         pic16_unlinkpCode(pc);
6779         pCodeLabelDestruct(pc);
6780       } else {
6781         unlinkpCodeFromBranch(pc, PCODE(pcl));
6782         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6783           Safe_free(pc->label);
6784         }*/
6785       }
6786
6787     }
6788   }
6789
6790 }
6791
6792
6793 /*-----------------------------------------------------------------*/
6794 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6795 /*                     chain and put them into pBranches that are  */
6796 /*                     associated with the appropriate pCode       */
6797 /*                     instructions.                               */
6798 /*-----------------------------------------------------------------*/
6799 void pic16_pBlockMergeLabels(pBlock *pb)
6800 {
6801   pBranch *pbr;
6802   pCode *pc, *pcnext=NULL;
6803
6804   if(!pb)
6805     return;
6806
6807   /* First, Try to remove any unused labels */
6808   //pBlockRemoveUnusedLabels(pb);
6809
6810   /* Now loop through the pBlock and merge the labels with the opcodes */
6811
6812   pc = pb->pcHead;
6813   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6814
6815   while(pc) {
6816     pCode *pcn = pc->next;
6817
6818     if(pc->type == PC_LABEL) {
6819
6820 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6821 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6822
6823       if((pcnext = pic16_findNextInstruction(pc) )) {
6824
6825 //              pcnext->print(stderr, pcnext);
6826
6827         // Unlink the pCode label from it's pCode chain
6828         pic16_unlinkpCode(pc);
6829         
6830 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6831         // And link it into the instruction's pBranch labels. (Note, since
6832         // it's possible to have multiple labels associated with one instruction
6833         // we must provide a means to accomodate the additional labels. Thus
6834         // the labels are placed into the singly-linked list "label" as 
6835         // opposed to being a single member of the pCodeInstruction.)
6836
6837         //_ALLOC(pbr,sizeof(pBranch));
6838 #if 1
6839         pbr = Safe_calloc(1,sizeof(pBranch));
6840         pbr->pc = pc;
6841         pbr->next = NULL;
6842
6843         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6844 #endif
6845       } else {
6846         if(pic16_pcode_verbose)
6847         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6848       }
6849     } else if(pc->type == PC_CSOURCE) {
6850
6851       /* merge the source line symbolic info into the next instruction */
6852       if((pcnext = pic16_findNextInstruction(pc) )) {
6853
6854         // Unlink the pCode label from it's pCode chain
6855         pic16_unlinkpCode(pc);
6856         PCI(pcnext)->cline = PCCS(pc);
6857         //fprintf(stderr, "merging CSRC\n");
6858         //genericPrint(stderr,pcnext);
6859       }
6860
6861     }
6862     pc = pcn;
6863   }
6864   pBlockRemoveUnusedLabels(pb);
6865
6866 }
6867
6868 /*-----------------------------------------------------------------*/
6869 /*-----------------------------------------------------------------*/
6870 static int OptimizepCode(char dbName)
6871 {
6872 #define MAX_PASSES 4
6873
6874   int matches = 0;
6875   int passes = 0;
6876   pBlock *pb;
6877
6878   if(!the_pFile)
6879     return 0;
6880
6881   DFPRINTF((stderr," Optimizing pCode\n"));
6882
6883   do {
6884     matches = 0;
6885     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6886       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6887         matches += OptimizepBlock(pb);
6888     }
6889   }
6890   while(matches && ++passes < MAX_PASSES);
6891
6892   return matches;
6893 }
6894
6895
6896
6897 const char *pic16_pCodeOpType(pCodeOp *pcop);
6898 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6899
6900
6901 /*-----------------------------------------------------------------*/
6902 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6903 /*-----------------------------------------------------------------*/
6904
6905 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6906 {
6907   pCodeOp *pcop=NULL;
6908
6909 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6910
6911   if(pc->name) {
6912         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6913   } else {
6914     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6915   }
6916
6917   assert(pcop != NULL);
6918
6919   if( !( (pcop->type == PO_LABEL) ||
6920          (pcop->type == PO_LITERAL) ||
6921          (pcop->type == PO_STR) ))
6922     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6923     PCOR(pcop)->r->wasUsed = 1;
6924     PCOR(pcop)->instance = PCOR(pc)->instance;
6925
6926   return pcop;
6927 }
6928
6929
6930 /*----------------------------------------------------------------------*
6931  * pic16_areRegsSame - check to see if the names of two registers match *
6932  *----------------------------------------------------------------------*/
6933 int pic16_areRegsSame(regs *r1, regs *r2)
6934 {
6935         if(!strcmp(r1->name, r2->name))return 1;
6936
6937   return 0;
6938 }
6939
6940
6941 /*-----------------------------------------------------------------*/
6942 /*-----------------------------------------------------------------*/
6943 static void pic16_FixRegisterBanking(pBlock *pb)
6944 {
6945   pCode *pc=NULL;
6946   pCode *pcprev=NULL;
6947   regs *reg, *prevreg;
6948   unsigned char flag=0;
6949   
6950         if(!pb)
6951                 return;
6952
6953         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6954         if(!pc)return;
6955
6956         /* loop through all of the flow blocks with in one pblock */
6957
6958 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6959
6960         prevreg = NULL;
6961         do {
6962                 /* at this point, pc should point to a PC_FLOW object */
6963                 /* for each flow block, determine the register banking 
6964                  * requirements */
6965
6966                 
6967                 /* if label, then might come from other point, force banksel */
6968                 if(isPCL(pc))prevreg = NULL;
6969                 
6970                 if(!isPCI(pc))goto loop;
6971
6972                 if(PCI(pc)->label)prevreg = NULL;
6973
6974                 if(PCI(pc)->is2MemOp)goto loop;
6975
6976                 /* if goto, then force banksel */
6977 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6978        
6979                 reg = pic16_getRegFromInstruction(pc);
6980
6981 #if 0
6982                 pc->print(stderr, pc);
6983                 fprintf(stderr, "reg = %p\n", reg);
6984
6985                 if(reg) {
6986                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6987                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6988                                 reg->address,reg->isBitField, reg->isFixed);
6989                 }
6990 #endif
6991
6992                 /* now make some tests to make sure that instruction needs bank switch */
6993
6994                 /* if no register exists, and if not a bit opcode goto loop */
6995                 if(!reg) {
6996                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6997                 }
6998                  
6999                 if(isPCI_SKIP(pc)) {
7000 //                      fprintf(stderr, "instruction is SKIP instruction\n");
7001 //                prevreg = NULL;
7002                 }
7003                 if(reg && isACCESS_BANK(reg))goto loop;
7004
7005                 if(!isBankInstruction(pc))goto loop;
7006
7007                 if(isPCI_LIT(pc))goto loop;
7008          
7009                 if(PCI(pc)->op == POC_CALL)goto loop;
7010
7011                 /* Examine the instruction before this one to make sure it is
7012                  * not a skip type instruction */
7013                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7014
7015                 flag = 0;               /* add before this instruction */
7016                 
7017                 /* if previous instruction is a skip one, then set flag
7018                  * to 2 and call insertBankSwitch */
7019                 if(pcprev && isPCI_SKIP(pcprev)) {
7020                   flag=2;       //goto loop
7021 //                prevreg = NULL;
7022                 }
7023                  
7024                 if(pic16_options.opt_banksel>0) {
7025                   char op1[128], op2[128];
7026                   
7027                     if(prevreg) {
7028                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7029                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7030                       if(!strcmp(op1, op2))goto loop;
7031                     }
7032                 }
7033                 prevreg = reg;
7034                 insertBankSwitch(flag, pc);
7035
7036 //              fprintf(stderr, "BANK SWITCH inserted\n");
7037                 
7038 loop:
7039                 pcprev = pc;
7040                 pc = pc->next;
7041         } while (pc);
7042 }
7043
7044 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7045
7046 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7047 int instrSize (pCode *pc)
7048 {
7049   if (!pc) return 0;
7050
7051   if (isPCAD(pc)) {
7052     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7053     return 4; // assumes only regular instructions using <= 4 bytes
7054   }
7055
7056   if (isPCI(pc)) return PCI(pc)->isize;
7057
7058   return 0;
7059 }
7060
7061 /* Returns 1 if pc is referenced by the given label (either
7062  * pc is the label itself or is an instruction with an attached
7063  * label).
7064  * Returns 0 if pc is not preceeded by the specified label.
7065  */
7066 int isLabel (pCode *pc, char *label)
7067 {
7068   if (!pc) return 0;
7069
7070   // label attached to the pCode?  
7071   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7072     pBranch *lab = NULL;
7073     lab = PCI(pc)->label;
7074
7075     while (lab) {
7076       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7077         return 1;
7078       }
7079       lab = lab->next;
7080     } // while
7081   } // if
7082
7083   // is inline assembly label?
7084   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7085     // do not compare trailing ':'
7086     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7087       return 1;
7088     }
7089   } // if
7090   
7091   // is pCodeLabel?
7092   if (isPCL(pc)) {
7093       if (strcmp(PCL(pc)->label,label) == 0) {
7094       return 1;
7095     }
7096   } // if
7097   
7098   // no label/no label attached/wrong label(s)
7099   return 0;
7100 }
7101
7102 /* Returns the distance to the given label in terms of words.
7103  * Labels are searched only within -max .. max words from pc.
7104  * Returns max if the label could not be found or
7105  * its distance from pc in (-max..+max).
7106  */
7107 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7108   int dist = instrSize(pc);
7109   pCode *curr = pc;
7110
7111   // search backwards
7112   while (dist < max && curr && !isLabel (curr, label)) {
7113     curr = curr->prev;
7114     dist += instrSize(curr); // sizeof (instruction)
7115   } // while
7116   if (curr && dist < max) {
7117     if (target != NULL) *target = curr;
7118     return -dist;
7119   }
7120
7121   dist = 0;
7122   curr = pic16_findNextInstruction (pc->next);
7123   //search forwards
7124   while (dist < max && curr && !isLabel (curr, label)) {
7125     dist += instrSize(curr); // sizeof (instruction)
7126     curr = curr->next;
7127   } // while
7128   if (curr && dist < max) {
7129     if (target != NULL) *target = curr;
7130     return dist;
7131   }
7132
7133   if (target != NULL) *target = NULL;
7134   return max;
7135 }
7136
7137 /* Returns -1 if pc does NOT denote an instruction like
7138  * BTFS[SC] STATUS,i
7139  * Otherwise we return 
7140  *   (a) 0x10 + i for BTFSS
7141  *   (b) 0x00 + i for BTFSC
7142  */
7143 int isSkipOnStatus (pCode *pc)
7144 {
7145   int res = -1;
7146   pCodeOp *pcop;
7147   if (!pc || !isPCI(pc)) return -1;
7148   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7149   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7150   else return -1;
7151
7152   pcop = PCI(pc)->pcop;
7153
7154   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7155     return res + ((pCodeOpRegBit *)pcop)->bit;
7156   }
7157
7158   return -1;
7159 }
7160
7161 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7162  * returns 0 otherwise. */
7163 int isConditionalBranch (pCode *pc)
7164 {
7165   if (!pc || !isPCI_BRANCH(pc)) return 0;
7166
7167   switch (PCI(pc)->op) {
7168   case POC_BC:
7169   case POC_BZ:
7170   case POC_BOV:
7171   case POC_BN:
7172   case POC_BNC:
7173   case POC_BNZ:
7174   case POC_BNOV:
7175   case POC_BNN:
7176     return 1;
7177
7178   default:
7179     break;
7180   } // switch
7181
7182   return 0;
7183 }
7184
7185 /* Returns 1 if pc has a label attached to it.
7186  * This can be either a label stored in the pCode itself (.label)
7187  * or a label making up its own pCode preceding this pc.
7188  * Returns 0 if pc cannot be reached directly via a label.
7189  */
7190 int hasNoLabel (pCode *pc)
7191 {
7192   pCode *prev;
7193   if (!pc) return 1;
7194
7195   // are there any label pCodes between pc and the previous instruction?
7196   prev = pic16_findPrevInstruction (pc->prev);
7197   while (pc && pc != prev) {
7198     // pCode with attached label?
7199     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7200         && PCI(pc)->label) {
7201       return 0;
7202     }
7203     // is inline assembly label?
7204     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7205     if (isPCW(pc) && PCW(pc)->label) return 0;
7206
7207     // pCodeLabel?
7208     if (isPCL(pc)) return 0;
7209
7210     pc = pc->prev;
7211   } // if
7212
7213   // no label found
7214   return 1;
7215 }
7216
7217 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7218   char buf[512];
7219   va_list va;
7220
7221   va_start (va, fmt);
7222   vsprintf (buf, fmt, va);
7223   va_end (va);
7224
7225   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7226 }
7227
7228 /* Replaces the old pCode with the new one, moving the labels,
7229  * C source line and probably flow information to the new pCode.
7230  */
7231 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7232   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7233     return;
7234
7235   /* first move all labels from old to new */
7236   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7237   PCI(oldPC)->label = NULL;
7238   
7239 #if 0
7240   /* move C source line (if possible) */
7241   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7242     PCI(newPC)->cline = PCI(oldPC)->cline;
7243 #endif
7244
7245   /* keep flow information intact */
7246   newPC->seq = oldPC->seq;
7247   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7248   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7249     PCI(newPC)->pcflow->end = newPC;
7250   }
7251
7252   /* insert a comment stating which pCode has been replaced */
7253 #if 1
7254   if (pic16_pcode_verbose || pic16_debug_verbose) {
7255     char pc_str[256];
7256     pic16_pCode2str (pc_str, 256, oldPC);
7257     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7258   }
7259 #endif
7260   
7261   /* insert new pCode into pBlock */
7262   pic16_pCodeInsertAfter (oldPC, newPC);
7263   pic16_unlinkpCode (oldPC);
7264   
7265   /* destruct replaced pCode */
7266   oldPC->destruct (oldPC);
7267 }
7268
7269 /* Returns the inverted conditional branch (if any) or NULL.
7270  * pcop must be set to the new jump target.
7271  */
7272 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7273 {
7274   pCode *newBcc;
7275
7276   if (!bcc || !isPCI(bcc)) return NULL;
7277
7278   switch (PCI(bcc)->op) {
7279   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7280   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7281   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7282   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7283   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7284   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7285   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7286   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7287   default:
7288     newBcc = NULL;
7289   }
7290   return newBcc;
7291 }
7292
7293 #define MAX_DIST_GOTO         0x7FFFFFFF
7294 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7295 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7296 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7297 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7298
7299 /* Follows GOTO/BRA instructions to their target instructions, stores the
7300  * final destination (not a GOTO or BRA instruction) in target and returns
7301  * the distance from the original pc to *target.
7302  */
7303 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7304         pCode *curr = pc;
7305         pCode *last = NULL;
7306         pCodeOp *lastPCOP = NULL;
7307         int dist = 0;
7308         int depth = 0;
7309
7310         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7311
7312         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7313         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7314                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7315                 last = curr;
7316                 lastPCOP = PCI(curr)->pcop;
7317                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7318                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7319         } // while
7320
7321         if (target) *target = last;
7322         if (pcop) *pcop = lastPCOP;
7323         return dist;
7324 }
7325
7326 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7327  * Otherwise the first pCode after the jumptable (after
7328  * the OPT_JUMPTABLE_END tag) is returned.
7329  */
7330 pCode *skipJumptables (pCode *pc, int *isJumptable)
7331 {
7332   *isJumptable = 0;
7333   if (!pc) return NULL;
7334   
7335   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7336     *isJumptable = 1;
7337     //fprintf (stderr, "SKIPPING jumptable\n");
7338     do {
7339       //pc->print(stderr, pc);
7340       pc = pc->next;
7341     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7342                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7343     //fprintf (stderr, "<<JUMPTAB:\n");
7344     // skip OPT_END as well
7345     if (pc) pc = pc->next;
7346   } // while
7347
7348   return pc;
7349 }
7350
7351 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7352 {
7353   int isJumptab;
7354   *isJumptable = 0;
7355   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7356     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7357     pc = skipJumptables (pc, &isJumptab);
7358     if (isJumptab) {
7359         // pc is the first pCode after the jumptable
7360         *isJumptable = 1;
7361     } else {
7362         // pc has not been changed by skipJumptables()
7363         pc = pc->next;
7364     }
7365   } // while
7366   
7367   return pc;
7368 }
7369
7370 /* Turn GOTOs into BRAs if distance between GOTO and label
7371  * is less than 1024 bytes.
7372  *
7373  * This method is especially useful if GOTOs after BTFS[SC]
7374  * can be turned into BRAs as GOTO would cost another NOP
7375  * if skipped.
7376  */
7377 void pic16_OptimizeJumps ()
7378 {
7379   pCode *pc;
7380   pCode *pc_prev = NULL;
7381   pCode *pc_next = NULL;
7382   pBlock *pb;
7383   pCode *target;
7384   int change, iteration, isJumptab;
7385   int isHandled = 0;
7386   char *label;
7387   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7388   
7389   if (!the_pFile) return;
7390   
7391   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7392   
7393   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7394     int matchedInvertRule = 1;
7395     iteration = 1;
7396     do {
7397       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7398       change = 0;
7399       pc = pic16_findNextInstruction (pb->pcHead);
7400     
7401       while (pc) {
7402         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7403         if (isJumptab) {
7404                 // skip jumptable, i.e. start over with no pc_prev!     
7405                 pc_prev = NULL;
7406                 pc = pc_next;
7407                 continue;
7408         } // if
7409
7410         /* (1) resolve chained jumps
7411          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7412          * (a) leave dead code in and
7413          * (b) skip over the dead code with an (unneccessary) jump.
7414          */
7415         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7416           pCodeOp *lastTargetOp = NULL;
7417           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7418           int maxDist = MAX_DIST_BCC;
7419           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7420           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7421           
7422           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7423           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7424               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7425             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7426             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7427             PCI(pc)->pcop->name = lastTargetOp->name;
7428             change++;
7429             opt_gotochain++;
7430           } // if
7431         } // if
7432
7433
7434         if (IS_GOTO(pc)) {
7435           int dist;
7436           int condBraType = isSkipOnStatus(pc_prev);
7437           label = PCI(pc)->pcop->name;
7438           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7439           if (dist < 0) dist = -dist;
7440           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7441           isHandled = 0;
7442           
7443           
7444           /* (2) remove "GOTO label; label:" */
7445           if (isLabel (pc_next, label)) {
7446             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7447             // first remove all preceeding SKIP instructions
7448             while (pc_prev && isPCI_SKIP(pc_prev)) {
7449               // attach labels on this instruction to pc_next
7450               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7451               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7452               PCI(pc_prev)->label = NULL;
7453               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7454               pic16_unlinkpCode (pc_prev);
7455               pc_prev = pic16_findPrevInstruction (pc);
7456             } // while
7457             // now remove the redundant goto itself
7458             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7459             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7460             pic16_unlinkpCode (pc);
7461             pc = pic16_findPrevInstruction(pc_next->prev);
7462             isHandled = 1; // do not perform further optimizations
7463             opt_gotonext++;
7464             change++;
7465           } // if
7466           
7467           
7468           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7469           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7470             if (dist < MAX_DIST_BCC) {
7471               pCode *bcc = NULL;
7472               switch (condBraType) {
7473               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7474                 // no BDC on DIGIT CARRY available
7475               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7476               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7477               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7478               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7479                 // no BNDC on DIGIT CARRY available
7480               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7481               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7482               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7483               default:
7484                 // no replacement possible
7485                 bcc = NULL;
7486                 break;
7487               } // switch
7488               if (bcc) {
7489                 // ATTENTION: keep labels attached to BTFSx!
7490                 // HINT: GOTO is label free (checked above)
7491                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7492                 isHandled = 1; // do not perform further optimizations
7493                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7494                 pic16_pCodeReplace (pc_prev, bcc);
7495                 pc->destruct(pc);
7496                 pc = bcc;
7497                 opt_cond++;
7498                 change++;
7499               } // if
7500             } else {
7501               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7502               cond_toofar++;
7503             } // if
7504           } // if
7505
7506           if (!isHandled) {
7507             // (4) eliminate the following (common) tripel:
7508             //           <pred.>;
7509             //  labels1: Bcc label2;
7510             //           GOTO somewhere;    ; <-- instruction referenced by pc
7511             //  label2:  <cont.>
7512             // and replace it by
7513             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7514             //  label2:  <cont.>
7515             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7516             //            to <cont.> instead
7517             // ATTENTION: This optimization is only valid if <pred.> is
7518             //            not a skip operation!
7519             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7520             // ATTENTION: no label may be attached to the GOTO instruction!
7521             if (isConditionalBranch(pc_prev)
7522                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7523                 && (dist < MAX_DIST_BCC)
7524                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7525                 && hasNoLabel(pc)) {
7526               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7527             
7528               if (newBcc) {
7529                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7530                 isHandled = 1; // do not perform further optimizations
7531                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7532                 pic16_pCodeReplace (pc_prev, newBcc);
7533                 pc->destruct(pc);
7534                 pc = newBcc;
7535                 opt_reorder++;
7536                 change++;
7537                 matchedInvertRule++;
7538               }
7539             }
7540           }
7541           
7542           /* (5) now just turn GOTO into BRA */ 
7543           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7544             if (dist < MAX_DIST_BRA) {
7545               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7546               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7547               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7548               pic16_pCodeReplace (pc, newBra);
7549               pc = newBra;
7550               opt++;
7551               change++;
7552             } else {
7553               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7554               toofar++;
7555             }
7556           } // if (!isHandled)
7557         } // if
7558
7559         pc_prev = pc;
7560         pc = pc_next;
7561       } // while (pc)
7562       
7563       pBlockRemoveUnusedLabels (pb);
7564       
7565       // This line enables goto chain resolution!
7566       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7567
7568       iteration++;
7569     } while (change); /* fixpoint iteration per pBlock */
7570   } // for (pb)
7571   
7572   // emit some statistics concerning goto-optimization
7573 #if 0
7574   if (pic16_debug_verbose || pic16_pcode_verbose) {
7575     fprintf (stderr, "optimize-goto:\n"
7576              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7577              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7578              "\t%5d conditional \"skipping\" jumps inverted\n"
7579              "\t%5d GOTOs to next instruction removed\n"
7580              "\t%5d chained GOTOs resolved\n",
7581              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7582   } // if
7583 #endif
7584   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7585 }
7586
7587 #undef IS_GOTO
7588 #undef MAX_JUMPCHAIN_DEPTH
7589 #undef MAX_DIST_GOTO
7590 #undef MAX_DIST_BRA
7591 #undef MAX_DIST_BCC
7592
7593 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7594
7595 static void pBlockDestruct(pBlock *pb)
7596 {
7597
7598   if(!pb)
7599     return;
7600
7601
7602 //  Safe_free(pb);
7603
7604 }
7605
7606 /*-----------------------------------------------------------------*/
7607 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7608 /*                                  name dbName and combine them   */
7609 /*                                  into one block                 */
7610 /*-----------------------------------------------------------------*/
7611 static void mergepBlocks(char dbName)
7612 {
7613
7614   pBlock *pb, *pbmerged = NULL,*pbn;
7615
7616   pb = the_pFile->pbHead;
7617
7618   //fprintf(stderr," merging blocks named %c\n",dbName);
7619   while(pb) {
7620
7621     pbn = pb->next;
7622     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7623     if( getpBlock_dbName(pb) == dbName) {
7624
7625       //fprintf(stderr," merged block %c\n",dbName);
7626
7627       if(!pbmerged) {
7628         pbmerged = pb;
7629       } else {
7630         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7631         /* pic16_addpCode2pBlock doesn't handle the tail: */
7632         pbmerged->pcTail = pb->pcTail;
7633
7634         pb->prev->next = pbn;
7635         if(pbn) 
7636           pbn->prev = pb->prev;
7637
7638
7639         pBlockDestruct(pb);
7640       }
7641       //pic16_printpBlock(stderr, pbmerged);
7642     } 
7643     pb = pbn;
7644   }
7645
7646 }
7647
7648 /*-----------------------------------------------------------------*/
7649 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7650 /*                                                                 */
7651 /* level 0 == minimal optimization                                 */
7652 /*   optimize registers that are used only by two instructions     */
7653 /* level 1 == maximal optimization                                 */
7654 /*   optimize by looking at pairs of instructions that use the     */
7655 /*   register.                                                     */
7656 /*-----------------------------------------------------------------*/
7657
7658 static void AnalyzeFlow(int level)
7659 {
7660   static int times_called=0;
7661   pBlock *pb;
7662
7663     if(!the_pFile) {
7664       /* remove unused allocated registers before exiting */
7665       pic16_RemoveUnusedRegisters();
7666       return;
7667     }
7668
7669
7670     /* if this is not the first time this function has been called,
7671      * then clean up old flow information */
7672     if(times_called++) {
7673       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7674         unBuildFlow(pb);
7675         pic16_RegsUnMapLiveRanges();
7676     }
7677     GpcFlowSeq = 1;
7678
7679     /* Phase 2 - Flow Analysis - Register Banking
7680      *
7681      * In this phase, the individual flow blocks are examined
7682      * and register banking is fixed.
7683      */
7684
7685 #if 0
7686     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7687       pic16_FixRegisterBanking(pb);
7688 #endif
7689
7690     /* Phase 2 - Flow Analysis
7691      *
7692      * In this phase, the pCode is partition into pCodeFlow 
7693      * blocks. The flow blocks mark the points where a continuous
7694      * stream of instructions changes flow (e.g. because of
7695      * a call or goto or whatever).
7696      */
7697
7698     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7699       pic16_BuildFlow(pb);
7700
7701
7702     /* Phase 2 - Flow Analysis - linking flow blocks
7703      *
7704      * In this phase, the individual flow blocks are examined
7705      * to determine their order of excution.
7706      */
7707
7708     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7709       LinkFlow(pb);
7710
7711 #if 1
7712         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7713                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7714                         pic16_createDF (pb);
7715 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7716                         pic16_vcg_dump_default (pb);
7717 #endif
7718                         //pic16_destructDF (pb);
7719                 }
7720
7721                 pic16_df_stats ();
7722                 if (0) releaseStack (); // releasing is costly...
7723         }
7724 #endif
7725
7726     /* Phase 3 - Flow Analysis - Flow Tree
7727      *
7728      * In this phase, the individual flow blocks are examined
7729      * to determine their order of execution.
7730      */
7731
7732     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7733       pic16_BuildFlowTree(pb);
7734
7735
7736     /* Phase x - Flow Analysis - Used Banks
7737      *
7738      * In this phase, the individual flow blocks are examined
7739      * to determine the Register Banks they use
7740      */
7741
7742 #if 0
7743     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7744       FixBankFlow(pb);
7745 #endif
7746
7747
7748     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7749       pic16_pCodeRegMapLiveRanges(pb);
7750
7751     pic16_RemoveUnusedRegisters();
7752     pic16_removeUnusedRegistersDF ();
7753
7754   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7755     pic16_pCodeRegOptimizeRegUsage(level);
7756
7757
7758 #if 0
7759     if(!options.nopeep)
7760       OptimizepCode('*');
7761 #endif
7762
7763 #if 0
7764     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7765       DumpFlow(pb);
7766 #endif
7767
7768     /* debug stuff */ 
7769     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7770       pCode *pcflow;
7771       
7772         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7773           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7774           pcflow = pcflow->next) {
7775             FillFlow(PCFL(pcflow));
7776         }
7777     }
7778
7779 #if 0
7780     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7781       pCode *pcflow;
7782
7783         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7784           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7785           pcflow = pcflow->next) {
7786             FlowStats(PCFL(pcflow));
7787         }
7788     }
7789 #endif
7790 }
7791
7792 /* VR -- no need to analyze banking in flow, but left here :
7793  *      1. because it may be used in the future for other purposes
7794  *      2. because if omitted we'll miss some optimization done here
7795  *
7796  * Perhaps I should rename it to something else
7797  */
7798
7799 /*-----------------------------------------------------------------*/
7800 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7801 /*                  assigned to the registers.                     */
7802 /*                                                                 */
7803 /*-----------------------------------------------------------------*/
7804
7805 void pic16_AnalyzeBanking(void)
7806 {
7807   pBlock  *pb;
7808
7809     /* Phase x - Flow Analysis - Used Banks
7810      *
7811      * In this phase, the individual flow blocks are examined
7812      * to determine the Register Banks they use
7813      */
7814
7815     AnalyzeFlow(0);
7816     AnalyzeFlow(1);
7817
7818     if(!options.nopeep)
7819       OptimizepCode('*');
7820
7821
7822     if(!the_pFile)return;
7823
7824     if(!pic16_options.no_banksel) {
7825       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7826 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7827         pic16_FixRegisterBanking(pb);
7828       }
7829     }
7830 }
7831
7832 /*-----------------------------------------------------------------*/
7833 /* buildCallTree - Look at the flow and extract all of the calls.  */
7834 /*-----------------------------------------------------------------*/
7835 static set *register_usage(pBlock *pb);
7836
7837 static void buildCallTree(void    )
7838 {
7839   pBranch *pbr;
7840   pBlock  *pb;
7841   pCode   *pc;
7842   regs *r;
7843   
7844   if(!the_pFile)
7845     return;
7846
7847
7848
7849   /* Now build the call tree.
7850      First we examine all of the pCodes for functions.
7851      Keep in mind that the function boundaries coincide
7852      with pBlock boundaries. 
7853
7854      The algorithm goes something like this:
7855      We have two nested loops. The outer loop iterates
7856      through all of the pBlocks/functions. The inner
7857      loop iterates through all of the pCodes for
7858      a given pBlock. When we begin iterating through
7859      a pBlock, the variable pc_fstart, pCode of the start
7860      of a function, is cleared. We then search for pCodes
7861      of type PC_FUNCTION. When one is encountered, we
7862      initialize pc_fstart to this and at the same time
7863      associate a new pBranch object that signifies a 
7864      branch entry. If a return is found, then this signifies
7865      a function exit point. We'll link the pCodes of these
7866      returns to the matching pc_fstart.
7867
7868      When we're done, a doubly linked list of pBranches
7869      will exist. The head of this list is stored in
7870      `the_pFile', which is the meta structure for all
7871      of the pCode. Look at the pic16_printCallTree function
7872      on how the pBranches are linked together.
7873
7874    */
7875   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7876     pCode *pc_fstart=NULL;
7877     for(pc = pb->pcHead; pc; pc = pc->next) {
7878
7879         if(isPCI(pc) && pc_fstart) {
7880                 if(PCI(pc)->is2MemOp) {
7881                         r = pic16_getRegFromInstruction2(pc);
7882                         if(r && !strcmp(r->name, "POSTDEC1"))
7883                                 PCF(pc_fstart)->stackusage++;
7884                 } else {
7885                         r = pic16_getRegFromInstruction(pc);
7886                         if(r && !strcmp(r->name, "PREINC1"))
7887                                 PCF(pc_fstart)->stackusage--;
7888                 }
7889         }
7890
7891       if(isPCF(pc)) {
7892         if (PCF(pc)->fname) {
7893         char buf[16];
7894
7895           sprintf(buf, "%smain", port->fun_prefix);
7896           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7897             //fprintf(stderr," found main \n");
7898             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7899             pb->dbName = 'M';
7900           }
7901
7902           pbr = Safe_calloc(1,sizeof(pBranch));
7903           pbr->pc = pc_fstart = pc;
7904           pbr->next = NULL;
7905
7906           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7907
7908           // Here's a better way of doing the same:
7909           addSet(&pb->function_entries, pc);
7910
7911         } else {
7912           // Found an exit point in a function, e.g. return
7913           // (Note, there may be more than one return per function)
7914           if(pc_fstart)
7915             pBranchLink(PCF(pc_fstart), PCF(pc));
7916
7917           addSet(&pb->function_exits, pc);
7918         }
7919       } else if(isCALL(pc)) {
7920         addSet(&pb->function_calls,pc);
7921       }
7922     }
7923   }
7924
7925
7926 #if 0
7927   /* This is not needed because currently all register used
7928    * by a function are stored in stack -- VR */
7929    
7930   /* Re-allocate the registers so that there are no collisions
7931    * between local variables when one function call another */
7932
7933   // this is weird...
7934   //  pic16_deallocateAllRegs();
7935
7936   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7937     if(!pb->visited)
7938       register_usage(pb);
7939   }
7940 #endif
7941
7942 }
7943
7944 /*-----------------------------------------------------------------*/
7945 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7946 /*                all of the logical connections.                  */
7947 /*                                                                 */
7948 /* Essentially what's done here is that the pCode flow is          */
7949 /* determined.                                                     */
7950 /*-----------------------------------------------------------------*/
7951
7952 void pic16_AnalyzepCode(char dbName)
7953 {
7954   pBlock *pb;
7955   int i,changes;
7956
7957   if(!the_pFile)
7958     return;
7959
7960   mergepBlocks('D');
7961
7962
7963   /* Phase 1 - Register allocation and peep hole optimization
7964    *
7965    * The first part of the analysis is to determine the registers
7966    * that are used in the pCode. Once that is done, the peep rules
7967    * are applied to the code. We continue to loop until no more
7968    * peep rule optimizations are found (or until we exceed the
7969    * MAX_PASSES threshold). 
7970    *
7971    * When done, the required registers will be determined.
7972    *
7973    */
7974   i = 0;
7975   do {
7976
7977     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7978     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7979
7980     /* First, merge the labels with the instructions */
7981     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7982       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7983
7984         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7985         //fprintf(stderr," analyze and merging block %c\n",dbName);
7986         pic16_pBlockMergeLabels(pb);
7987         AnalyzepBlock(pb);
7988       } else {
7989         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7990       }
7991     }
7992
7993         if(!options.nopeep)
7994                 changes = OptimizepCode(dbName);
7995         else changes = 0;
7996
7997   } while(changes && (i++ < MAX_PASSES));
7998
7999   
8000   buildCallTree();
8001 }
8002
8003
8004 /* convert a series of movff's of local regs to stack, with a single call to
8005  * a support functions which does the same thing via loop */
8006 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8007 {
8008   pBranch *pbr;
8009   pCode *pc, *pct;
8010   char *fname[]={"__lr_store", "__lr_restore"};
8011
8012 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8013
8014     pct = pic16_findNextInstruction(pcstart->next);
8015     do {
8016       pc = pct;
8017       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8018 //      pc->print(stderr, pc);
8019       if(isPCI(pc) && PCI(pc)->label) {
8020         pbr = PCI(pc)->label;
8021         while(pbr && pbr->pc) {
8022           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8023           pbr = pbr->next;
8024         }
8025
8026 //        pc->print(stderr, pc);
8027         /* unlink pCode */
8028         pc->prev->next = pct;
8029         pct->prev = pc->prev;
8030 //        pc->next = NULL;
8031 //        pc->prev = NULL;
8032       }
8033     } while ((pc) && (pc != pcend));
8034
8035     /* unlink movff instructions */
8036     pcstart->next = pcend;
8037     pcend->prev = pcstart;
8038
8039     pc = pcstart;
8040 //    if(!entry) {
8041 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8042 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8043 //    }
8044                 
8045     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8046     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8047     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8048
8049 //    if(!entry) {
8050 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8051 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8052 //    }
8053
8054     
8055     {
8056       symbol *sym;
8057
8058         sym = newSymbol( fname[ entry?0:1 ], 0 );
8059         strcpy(sym->rname, fname[ entry?0:1 ]);
8060         checkAddSym(&externs, sym);
8061         
8062 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8063     }
8064
8065 }
8066
8067 /*-----------------------------------------------------------------*/
8068 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8069 /*    local registers to a support function call                   */
8070 /*-----------------------------------------------------------------*/
8071 void pic16_OptimizeLocalRegs(void)
8072 {
8073   pBlock  *pb;
8074   pCode   *pc;
8075   pCodeInfo *pci;
8076   pCodeOpLocalReg *pclr;
8077   int regCount=0;
8078   int inRegCount=0;
8079   regs *r, *lastr=NULL, *firstr=NULL;
8080   pCode *pcstart=NULL, *pcend=NULL;
8081   int inEntry=0;
8082   char *curFunc=NULL;
8083
8084         /* Overview:
8085          *   local_regs begin mark
8086          *      MOVFF r0x01, POSTDEC1
8087          *      MOVFF r0x02, POSTDEC1
8088          *      ...
8089          *      ...
8090          *      MOVFF r0x0n, POSTDEC1
8091          *   local_regs end mark
8092          *
8093          * convert the above to the below:
8094          *      MOVLW   starting_register_index
8095          *      MOVWF   PRODL
8096          *      MOVLW   register_count
8097          *      call    __save_registers_in_stack
8098          */
8099
8100     if(!the_pFile)
8101       return;
8102
8103     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8104       inRegCount = regCount = 0;
8105       firstr = lastr = NULL;
8106       for(pc = pb->pcHead; pc; pc = pc->next) {
8107
8108         /* hold current function name */
8109         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8110         
8111         if(pc && (pc->type == PC_INFO)) {
8112           pci = PCINF(pc);
8113
8114           if(pci->type == INF_LOCALREGS) {
8115             pclr = PCOLR(pci->oper1);
8116             
8117             if((pclr->type == LR_ENTRY_BEGIN)
8118               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8119             else inEntry = 0;
8120             
8121             switch(pclr->type) {
8122               case LR_ENTRY_BEGIN:
8123               case LR_EXIT_BEGIN:
8124                         inRegCount = 1; regCount = 0;
8125                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8126                         firstr = lastr = NULL;
8127                         break;
8128               
8129               case LR_ENTRY_END:
8130               case LR_EXIT_END:
8131                         inRegCount = -1;
8132                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8133
8134 #if 1
8135                         if(curFunc && inWparamList(curFunc+1)) {
8136                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8137                                         filename, curFunc);
8138                         } else {
8139                           if(regCount>2) {
8140                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8141                               firstr, inEntry);
8142                           }
8143                         }
8144 #endif
8145                         firstr = lastr = NULL;
8146                         break;
8147             }
8148             
8149             if(inRegCount == -1) {
8150 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8151               regCount = 0;
8152               inRegCount = 0;
8153             }
8154           }
8155         } else {
8156           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8157             if(inEntry)
8158               r = pic16_getRegFromInstruction(pc);
8159             else
8160               r = pic16_getRegFromInstruction2(pc);
8161             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8162               if(!firstr)firstr = r;
8163               regCount++;
8164 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8165             }
8166           }
8167         }
8168       }
8169     }
8170 }
8171               
8172             
8173
8174
8175
8176 /*-----------------------------------------------------------------*/
8177 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8178 /*                   function                                      */
8179 /*-----------------------------------------------------------------*/
8180 static bool ispCodeFunction(pCode *pc)
8181 {
8182
8183   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8184     return 1;
8185
8186   return 0;
8187 }
8188
8189 /*-----------------------------------------------------------------*/
8190 /* findFunction - Search for a function by name (given the name)   */
8191 /*                in the set of all functions that are in a pBlock */
8192 /* (note - I expect this to change because I'm planning to limit   */
8193 /*  pBlock's to just one function declaration                      */
8194 /*-----------------------------------------------------------------*/
8195 static pCode *findFunction(char *fname)
8196 {
8197   pBlock *pb;
8198   pCode *pc;
8199   if(!fname)
8200     return NULL;
8201
8202   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8203
8204     pc = setFirstItem(pb->function_entries);
8205     while(pc) {
8206     
8207       if((pc->type == PC_FUNCTION) &&
8208          (PCF(pc)->fname) && 
8209          (strcmp(fname, PCF(pc)->fname)==0))
8210         return pc;
8211
8212       pc = setNextItem(pb->function_entries);
8213
8214     }
8215
8216   }
8217   return NULL;
8218 }
8219
8220 static void MarkUsedRegisters(set *regset)
8221 {
8222
8223   regs *r1,*r2;
8224
8225   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8226 //      fprintf(stderr, "marking register = %s\t", r1->name);
8227     r2 = pic16_regWithIdx(r1->rIdx);
8228 //      fprintf(stderr, "to register = %s\n", r2->name);
8229     r2->isFree = 0;
8230     r2->wasUsed = 1;
8231   }
8232 }
8233
8234 static void pBlockStats(FILE *of, pBlock *pb)
8235 {
8236
8237   pCode *pc;
8238   regs  *r;
8239
8240         if(!pic16_pcode_verbose)return;
8241         
8242   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8243
8244   // for now just print the first element of each set
8245   pc = setFirstItem(pb->function_entries);
8246   if(pc) {
8247     fprintf(of,";entry:  ");
8248     pc->print(of,pc);
8249   }
8250   pc = setFirstItem(pb->function_exits);
8251   if(pc) {
8252     fprintf(of,";has an exit\n");
8253     //pc->print(of,pc);
8254   }
8255
8256   pc = setFirstItem(pb->function_calls);
8257   if(pc) {
8258     fprintf(of,";functions called:\n");
8259
8260     while(pc) {
8261       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8262         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8263       }
8264       pc = setNextItem(pb->function_calls);
8265     }
8266   }
8267
8268   r = setFirstItem(pb->tregisters);
8269   if(r) {
8270     int n = elementsInSet(pb->tregisters);
8271
8272     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8273
8274     while (r) {
8275       fprintf(of,   ";   %s\n",r->name);
8276       r = setNextItem(pb->tregisters);
8277     }
8278   }
8279   
8280   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8281 }
8282
8283 /*-----------------------------------------------------------------*/
8284 /*-----------------------------------------------------------------*/
8285 #if 0
8286 static void sequencepCode(void)
8287 {
8288   pBlock *pb;
8289   pCode *pc;
8290
8291
8292   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8293
8294     pb->seq = GpCodeSequenceNumber+1;
8295
8296     for( pc = pb->pcHead; pc; pc = pc->next)
8297       pc->seq = ++GpCodeSequenceNumber;
8298   }
8299
8300 }
8301 #endif
8302
8303 /*-----------------------------------------------------------------*/
8304 /*-----------------------------------------------------------------*/
8305 static set *register_usage(pBlock *pb)
8306 {
8307   pCode *pc,*pcn;
8308   set *registers=NULL;
8309   set *registersInCallPath = NULL;
8310
8311   /* check recursion */
8312
8313   pc = setFirstItem(pb->function_entries);
8314
8315   if(!pc)
8316     return registers;
8317
8318   pb->visited = 1;
8319
8320   if(pc->type != PC_FUNCTION)
8321     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8322
8323   pc = setFirstItem(pb->function_calls);
8324   for( ; pc; pc = setNextItem(pb->function_calls)) {
8325
8326     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8327       char *dest = pic16_get_op_from_instruction(PCI(pc));
8328
8329       pcn = findFunction(dest);
8330       if(pcn) 
8331         registersInCallPath = register_usage(pcn->pb);
8332     } else
8333       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8334
8335   }
8336
8337 #ifdef PCODE_DEBUG
8338   pBlockStats(stderr,pb);  // debug
8339 #endif
8340
8341   // Mark the registers in this block as used.
8342
8343   MarkUsedRegisters(pb->tregisters);
8344   if(registersInCallPath) {
8345     /* registers were used in the functions this pBlock has called */
8346     /* so now, we need to see if these collide with the ones we are */
8347     /* using here */
8348
8349     regs *r1,*r2, *newreg;
8350
8351     DFPRINTF((stderr,"comparing registers\n"));
8352
8353     r1 = setFirstItem(registersInCallPath);
8354     while(r1) {
8355
8356       r2 = setFirstItem(pb->tregisters);
8357
8358       while(r2 && (r1->type != REG_STK)) {
8359
8360         if(r2->rIdx == r1->rIdx) {
8361           newreg = pic16_findFreeReg(REG_GPR);
8362
8363
8364           if(!newreg) {
8365             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8366             exit(1);
8367           }
8368
8369           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8370                   r1->rIdx, newreg->rIdx));
8371           r2->rIdx = newreg->rIdx;
8372           //if(r2->name) Safe_free(r2->name);
8373           if(newreg->name)
8374             r2->name = Safe_strdup(newreg->name);
8375           else
8376             r2->name = NULL;
8377           newreg->isFree = 0;
8378           newreg->wasUsed = 1;
8379         }
8380         r2 = setNextItem(pb->tregisters);
8381       }
8382
8383       r1 = setNextItem(registersInCallPath);
8384     }
8385
8386     /* Collisions have been resolved. Now free the registers in the call path */
8387     r1 = setFirstItem(registersInCallPath);
8388     while(r1) {
8389       if(r1->type != REG_STK) {
8390         newreg = pic16_regWithIdx(r1->rIdx);
8391         newreg->isFree = 1;
8392       }
8393       r1 = setNextItem(registersInCallPath);
8394     }
8395
8396   }// else
8397   //    MarkUsedRegisters(pb->registers);
8398
8399   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8400 #ifdef PCODE_DEBUG
8401   if(registers) 
8402     DFPRINTF((stderr,"returning regs\n"));
8403   else
8404     DFPRINTF((stderr,"not returning regs\n"));
8405
8406   DFPRINTF((stderr,"pBlock after register optim.\n"));
8407   pBlockStats(stderr,pb);  // debug
8408 #endif
8409
8410   return registers;
8411 }
8412
8413 /*-----------------------------------------------------------------*/
8414 /* pct2 - writes the call tree to a file                           */
8415 /*                                                                 */
8416 /*-----------------------------------------------------------------*/
8417 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8418 {
8419   pCode *pc,*pcn;
8420   int i;
8421   //  set *registersInCallPath = NULL;
8422
8423   if(!of)
8424     return;
8425
8426   if(indent > 10) {
8427         fprintf(of, "recursive function\n");
8428     return; //recursion ?
8429   }
8430
8431   pc = setFirstItem(pb->function_entries);
8432
8433   if(!pc)
8434     return;
8435
8436   pb->visited = 0;
8437
8438   for(i=0;i<indent;i++)   // Indentation
8439         fputs("+   ", of);
8440   fputs("+- ", of);
8441
8442   if(pc->type == PC_FUNCTION) {
8443     usedstack += PCF(pc)->stackusage;
8444     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8445   } else return;  // ???
8446
8447
8448   pc = setFirstItem(pb->function_calls);
8449   for( ; pc; pc = setNextItem(pb->function_calls)) {
8450
8451     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8452       char *dest = pic16_get_op_from_instruction(PCI(pc));
8453
8454       pcn = findFunction(dest);
8455       if(pcn) 
8456         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8457     } else
8458       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8459
8460   }
8461
8462
8463 }
8464
8465
8466 /*-----------------------------------------------------------------*/
8467 /* pic16_printCallTree - writes the call tree to a file                  */
8468 /*                                                                 */
8469 /*-----------------------------------------------------------------*/
8470
8471 void pic16_printCallTree(FILE *of)
8472 {
8473   pBranch *pbr;
8474   pBlock  *pb;
8475   pCode   *pc;
8476
8477   if(!the_pFile)
8478     return;
8479
8480   if(!of)
8481     of = stderr;
8482
8483   fprintf(of, "\npBlock statistics\n");
8484   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8485     pBlockStats(of,pb);
8486
8487
8488   fprintf(of,"Call Tree\n");
8489   pbr = the_pFile->functions;
8490   while(pbr) {
8491     if(pbr->pc) {
8492       pc = pbr->pc;
8493       if(!ispCodeFunction(pc))
8494         fprintf(of,"bug in call tree");
8495
8496
8497       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8498
8499       while(pc->next && !ispCodeFunction(pc->next)) {
8500         pc = pc->next;
8501         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8502           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8503       }
8504     }
8505
8506     pbr = pbr->next;
8507   }
8508
8509
8510   fprintf(of,"\n**************\n\na better call tree\n");
8511   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8512 //    if(pb->visited)
8513       pct2(of,pb,0,0);
8514   }
8515
8516   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8517     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8518   }
8519 }
8520
8521
8522
8523 /*-----------------------------------------------------------------*/
8524 /*                                                                 */
8525 /*-----------------------------------------------------------------*/
8526
8527 static void InlineFunction(pBlock *pb)
8528 {
8529   pCode *pc;
8530   pCode *pc_call;
8531
8532   if(!pb)
8533     return;
8534
8535   pc = setFirstItem(pb->function_calls);
8536
8537   for( ; pc; pc = setNextItem(pb->function_calls)) {
8538
8539     if(isCALL(pc)) {
8540       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8541       pCode *pct;
8542       pCode *pce;
8543
8544       pBranch *pbr;
8545
8546       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8547         
8548         //fprintf(stderr,"Cool can inline:\n");
8549         //pcn->print(stderr,pcn);
8550
8551         //fprintf(stderr,"recursive call Inline\n");
8552         InlineFunction(pcn->pb);
8553         //fprintf(stderr,"return from recursive call Inline\n");
8554
8555         /*
8556           At this point, *pc points to a CALL mnemonic, and
8557           *pcn points to the function that is being called.
8558
8559           To in-line this call, we need to remove the CALL
8560           and RETURN(s), and link the function pCode in with
8561           the CALLee pCode.
8562
8563         */
8564
8565
8566         /* Remove the CALL */
8567         pc_call = pc;
8568         pc = pc->prev;
8569
8570         /* remove callee pBlock from the pBlock linked list */
8571         removepBlock(pcn->pb);
8572
8573         pce = pcn;
8574         while(pce) {
8575           pce->pb = pb;
8576           pce = pce->next;
8577         }
8578
8579         /* Remove the Function pCode */
8580         pct = pic16_findNextInstruction(pcn->next);
8581
8582         /* Link the function with the callee */
8583         pc->next = pcn->next;
8584         pcn->next->prev = pc;
8585         
8586         /* Convert the function name into a label */
8587
8588         pbr = Safe_calloc(1,sizeof(pBranch));
8589         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8590         pbr->next = NULL;
8591         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8592         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8593
8594         /* turn all of the return's except the last into goto's */
8595         /* check case for 2 instruction pBlocks */
8596         pce = pic16_findNextInstruction(pcn->next);
8597         while(pce) {
8598           pCode *pce_next = pic16_findNextInstruction(pce->next);
8599
8600           if(pce_next == NULL) {
8601             /* found the last return */
8602             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8603
8604             //fprintf(stderr,"found last return\n");
8605             //pce->print(stderr,pce);
8606             pce->prev->next = pc_call->next;
8607             pc_call->next->prev = pce->prev;
8608             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8609                                                       PCI(pce)->label);
8610           }
8611
8612           pce = pce_next;
8613         }
8614
8615
8616       }
8617     } else
8618       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8619
8620   }
8621
8622 }
8623
8624 /*-----------------------------------------------------------------*/
8625 /*                                                                 */
8626 /*-----------------------------------------------------------------*/
8627
8628 void pic16_InlinepCode(void)
8629 {
8630
8631   pBlock  *pb;
8632   pCode   *pc;
8633
8634   if(!the_pFile)
8635     return;
8636
8637   if(!functionInlining)
8638     return;
8639
8640   /* Loop through all of the function definitions and count the
8641    * number of times each one is called */
8642   //fprintf(stderr,"inlining %d\n",__LINE__);
8643
8644   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8645
8646     pc = setFirstItem(pb->function_calls);
8647
8648     for( ; pc; pc = setNextItem(pb->function_calls)) {
8649
8650       if(isCALL(pc)) {
8651         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8652         if(pcn && isPCF(pcn)) {
8653           PCF(pcn)->ncalled++;
8654         }
8655       } else
8656         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8657
8658     }
8659   }
8660
8661   //fprintf(stderr,"inlining %d\n",__LINE__);
8662
8663   /* Now, Loop through the function definitions again, but this
8664    * time inline those functions that have only been called once. */
8665   
8666   InlineFunction(the_pFile->pbHead);
8667   //fprintf(stderr,"inlining %d\n",__LINE__);
8668
8669   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8670     unBuildFlow(pb);
8671
8672 }
8673
8674 char *pic_optype_names[]={
8675         "PO_NONE",         // No operand e.g. NOP
8676         "PO_W",              // The working register (as a destination)
8677         "PO_WREG",           // The working register (as a file register)
8678         "PO_STATUS",         // The 'STATUS' register
8679         "PO_BSR",            // The 'BSR' register
8680         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8681                              // of three)
8682         "PO_INDF0",          // The Indirect register
8683         "PO_INTCON",         // Interrupt Control register
8684         "PO_GPR_REGISTER",   // A general purpose register
8685         "PO_GPR_BIT",        // A bit of a general purpose register
8686         "PO_GPR_TEMP",       // A general purpose temporary register
8687         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8688         "PO_PCL",            // Program counter Low register
8689         "PO_PCLATH",         // Program counter Latch high register
8690         "PO_PCLATU",         // Program counter Latch upper register
8691         "PO_PRODL",          // Product Register Low
8692         "PO_PRODH",          // Product Register High
8693         "PO_LITERAL",        // A constant
8694         "PO_REL_ADDR",       // A relative address
8695         "PO_IMMEDIATE",      //  (8051 legacy)
8696         "PO_DIR",            // Direct memory (8051 legacy)
8697         "PO_CRY",            // bit memory (8051 legacy)
8698         "PO_BIT",            // bit operand.
8699         "PO_STR",            //  (8051 legacy)
8700         "PO_LABEL",
8701         "PO_WILD",           // Wild card operand in peep optimizer
8702         "PO_TWO_OPS"         // combine two operands
8703 };
8704
8705
8706 char *dumpPicOptype(PIC_OPTYPE type)
8707 {
8708         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8709         return (pic_optype_names[ type ]);
8710 }
8711
8712
8713 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8714 #include "graph.h"
8715
8716 #define MAX_COMMON_BANK_SIZE    32
8717 #define FIRST_PSEUDO_BANK_NR  1000
8718
8719 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8720 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8721 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8722 Graph *adj = NULL;
8723
8724 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8725
8726 typedef struct {
8727   pseudoBankNr bank;  // number assigned to this pseudoBank
8728   unsigned int size;  // number of operands assigned to this bank
8729   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8730 } pseudoBank;
8731
8732 /*----------------------------------------------------------------------*/
8733 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8734 /*----------------------------------------------------------------------*/
8735 unsigned int hashSymbol (const char *str)
8736 {
8737   unsigned int res = 0;
8738   if (!str) return 0;
8739
8740   while (*str) {
8741     res ^= (*str);
8742     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8743     str++;
8744   } // while
8745
8746   return res;
8747 }
8748
8749 /*-----------------------------------------------------------------------*/
8750 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8751 /*-----------------------------------------------------------------------*/
8752 int compareSymbol (const void *sym1, const void *sym2)
8753 {
8754   char *s1 = (char*) sym1;
8755   char *s2 = (char*) sym2;
8756   
8757   return (strcmp (s1,s2) == 0);
8758 }
8759
8760 /*-----------------------------------------------------------------------*/
8761 /* comparePre - return 1 iff p1 == p2                                    */
8762 /*-----------------------------------------------------------------------*/
8763 int comparePtr (const void *p1, const void *p2)
8764 {
8765   return (p1 == p2);
8766 }
8767
8768 /*----------------------------------------------------------*/
8769 /* getSymbolFromOperand - return a pointer to the symbol in */
8770 /*                        the given operand and its length  */
8771 /*----------------------------------------------------------*/
8772 char *getSymbolFromOperand (char *op, int *len)
8773 {
8774   char *sym, *curr;
8775   *len = 0;
8776
8777   if (!op) return NULL;
8778
8779   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8780   sym = op;
8781   if (*sym == '(') sym++;
8782
8783   curr = sym;
8784   while (((*curr >= 'A') && (*curr <= 'Z'))
8785          || ((*curr >= 'a') && (*curr <= 'z'))
8786          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8787          || (*curr == '_')) {
8788     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8789     curr++;
8790     (*len)++;
8791   } // while
8792
8793   return sym;
8794 }
8795
8796 /*--------------------------------------------------------------------------*/
8797 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8798 /*--------------------------------------------------------------------------*/
8799 char *getSymFromBank (pseudoBankNr bank)
8800 {
8801   assert (bank2sym);
8802
8803   if (bank < 0) return "<INVALID BANK NR>";
8804   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8805 }
8806
8807 /*-----------------------------------------------------------------------*/
8808 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8809 /*                           bank number (uses hTab sym2bank), if the    */
8810 /*                           symbol is not yet assigned a pseudo bank it */
8811 /*                           is assigned one here                        */
8812 /*-----------------------------------------------------------------------*/
8813 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8814 {
8815   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8816   pseudoBankNr bank;
8817   unsigned int hash;
8818
8819   assert (sym2bank);
8820
8821   hash = hashSymbol (op) % sym2bank->size;
8822   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8823   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8824
8825   if (bank == UNKNOWN_BANK) {
8826     // create a pseudo bank for the operand
8827     bank = next_bank++;
8828     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8829     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8830     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8831     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8832   } else {
8833     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8834   } // if
8835
8836   assert (bank >= 0);
8837
8838   return bank;
8839 }
8840
8841 /*--------------------------------------------------------------------*/
8842 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8843 /*--------------------------------------------------------------------*/
8844 int isBanksel (pCode *pc)
8845 {
8846   if (!pc) return 0;
8847
8848   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8849     // BANKSEL <variablename>  or  MOVLB <banknr>
8850     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8851     return 1;
8852   }
8853
8854   // check for inline assembler BANKSELs
8855   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8856                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8857     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8858     return 1;
8859   }
8860
8861   // assume pc is no BANKSEL instruction
8862   return 0;
8863 }
8864
8865 /*---------------------------------------------------------------------------------*/
8866 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8867 /*                  This method can not guarantee to find all modifications of the */
8868 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8869 /*                  generated plus some cases.                                     */
8870 /*---------------------------------------------------------------------------------*/
8871 int invalidatesBSR(pCode *pc)
8872 {
8873   // assembler directives invalidate BSR (well, they might, we don't know)
8874   if (isPCAD(pc)) return 1;
8875
8876   // only ASMDIRs and pCodeInstructions can invalidate BSR
8877   if (!isPCI(pc)) return 0;
8878
8879   // we have a pCodeInstruction
8880
8881   // check for BSR modifying instructions
8882   switch (PCI(pc)->op) {
8883   case POC_CALL:
8884   case POC_RCALL:
8885   case POC_MOVLB:
8886   case POC_RETFIE:  // might be used as CALL replacement
8887   case POC_RETLW:   // might be used as CALL replacement
8888   case POC_RETURN:  // might be used as CALL replacement
8889   case POC_BANKSEL:
8890     return 1;
8891     break;
8892
8893   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8894     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8895     break;
8896   } // switch
8897
8898   // no change of BSR possible/probable
8899   return 0;
8900 }
8901
8902 /*------------------------------------------------------------*/
8903 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8904 /*                      the symbol referenced in this BANKSEL */
8905 /*------------------------------------------------------------*/
8906 pseudoBankNr getBankFromBanksel (pCode *pc)
8907 {
8908   char *sym;
8909   int data = (int)NULL;
8910
8911   if (!pc) return INVALID_BANK;
8912   
8913   if (isPCAD(pc) && PCAD(pc)->directive) {
8914     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8915       // get symbolname from PCAD(pc)->arg
8916       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8917       sym = PCAD(pc)->arg;
8918       data = getPseudoBankNrFromOperand (sym);
8919       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8920     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8921       // get (literal) bank number from PCAD(pc)->arg
8922       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8923       assert (0 && "not yet implemented - turn off banksel optimization for now");
8924     }
8925   } else if (isPCI(pc)) {
8926     if (PCI(pc)->op == POC_BANKSEL) {
8927       // get symbolname from PCI(pc)->pcop->name (?)
8928       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8929       sym = PCI(pc)->pcop->name;
8930       data = getPseudoBankNrFromOperand (sym);
8931       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8932     } else if (PCI(pc)->op == POC_MOVLB) {
8933       // get (literal) bank number from PCI(pc)->pcop->name
8934       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8935       assert (0 && "not yet implemented - turn off banksel optimization for now");
8936     }
8937   }
8938   
8939   if (data == 0)
8940     // no assigned bank could be found
8941     return UNKNOWN_BANK;
8942   else
8943     return data;
8944 }
8945
8946 /*------------------------------------------------------------------------------*/
8947 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8948 /*------------------------------------------------------------------------------*/
8949 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8950 {
8951   pseudoBank *data;
8952
8953   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8954
8955   do {
8956     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8957     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8958     if (data) {
8959       if (data->bank != bank)
8960         bank = data->bank;
8961       else
8962         data = NULL;
8963     }
8964   } while (data);
8965   
8966   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8967   return bank;
8968 }
8969
8970 /*------------------------------------------------------------------*/
8971 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8972 /*                        bank is selected at a given pCode         */
8973 /*------------------------------------------------------------------*/
8974
8975 /* Create a graph with pseudo banks as its nodes and switches between
8976  * these as edges (with the edge weight representing the absolute
8977  * number of BANKSELs from one to the other).
8978  * Removes redundand BANKSELs instead iff mod == 1.
8979  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8980  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8981  * pseudo BSR.
8982  * TODO: check ALL instructions operands if they modify BSR directly...
8983  *
8984  * pb - the pBlock to annotate
8985  * mod  - select either graph creation (0) or BANKSEL removal (1)
8986  */
8987 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8988 {
8989   pCode *pc, *pc_next;
8990   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8991   int isBankselect = 0;
8992   unsigned int banksels=0;
8993   
8994   if (!pb) return 0;
8995
8996   pc = pic16_findNextInstruction(pb->pcHead);
8997   while (pc) {
8998     isBankselect = isBanksel (pc);
8999     pc_next = pic16_findNextInstruction (pc->next);
9000
9001     if (!hasNoLabel (pc)) {
9002       // we don't know our predecessors -- assume different BSRs
9003       prevBSR = UNKNOWN_BANK;
9004       pseudoBSR = UNKNOWN_BANK;
9005       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9006     } // if
9007
9008     // check if this is a BANKSEL instruction
9009     if (isBankselect) {
9010       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9011       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9012       if (mod) {
9013         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9014           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9015           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9016           pic16_unlinkpCode (pc);
9017           banksels++;
9018         }
9019       } else {
9020         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9021         banksels++;
9022       }
9023     } // if
9024
9025     if (!isBankselect && invalidatesBSR(pc)) {
9026       // check if this instruction invalidates the pseudoBSR
9027       pseudoBSR = UNKNOWN_BANK;
9028       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9029     } // if
9030
9031     prevBSR = pseudoBSR;
9032     pc = pc_next;
9033   } // while
9034
9035   return banksels;
9036 }
9037
9038 /*------------------------------------------------------------------------------------*/
9039 /* assignToSameBank - returns 0 on success or an error code                           */
9040 /*  1 - common bank would be too large                                                */
9041 /*  2 - assignment to fixed (absolute) bank not performed                             */
9042 /*                                                                                    */
9043 /* This functions assumes that unsplittable operands are already assigned to the same */
9044 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9045 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9046 /* TODO: Symbols with an abslute address must be handled specially!                   */
9047 /*------------------------------------------------------------------------------------*/
9048 int assignToSameBank (int bank0, int bank1, int doAbs)
9049 {
9050   int eff0, eff1, dummy;
9051   pseudoBank *pbank0, *pbank1;
9052   hashtItem *hitem;
9053
9054   eff0 = getEffectiveBank (bank0);
9055   eff1 = getEffectiveBank (bank1);
9056
9057   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9058
9059   // nothing to do if already same bank
9060   if (eff0 == eff1) return 0;
9061
9062   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9063     return 2;
9064
9065   // ensure eff0 < eff1
9066   if (eff0 > eff1) {
9067     // swap eff0 and eff1
9068     dummy = eff0;
9069     eff0 = eff1;
9070     eff1 = dummy;
9071     dummy = bank0;
9072     bank0 = bank1;
9073     bank1 = dummy;
9074   } // if
9075
9076   // now assign bank eff1 to bank eff0
9077   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9078   if (!pbank0) {
9079     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9080     pbank0->bank = eff0;
9081     pbank0->size = 1;
9082     pbank0->ref = 1;
9083     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9084   } // if
9085
9086   pbank1 = NULL;
9087   hitem = hTabSearch (coerce, eff1 % coerce->size);
9088   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9089     hitem = hitem->next;
9090
9091   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9092
9093 #if 0
9094   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9095            pbank0->bank, pbank0->size,
9096            getSymFromBank (eff0), getSymFromBank (eff1));
9097 #endif
9098
9099   if (pbank1) {
9100     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9101 #if 0
9102       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9103                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9104                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9105                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9106 #endif
9107       return 1;
9108     } // if
9109     pbank0->size += pbank1->size;
9110     pbank1->ref--;
9111     if (pbank1->ref == 0) Safe_free (pbank1);
9112   } else {
9113     pbank0->size++;
9114   } // if
9115
9116   if (hitem)
9117     hitem->item = pbank0;
9118   else  
9119     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9120   pbank0->ref++;
9121
9122   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9123
9124   return 0;
9125 }
9126
9127 /*----------------------------------------------------------------*/
9128 /* mergeGraphNodes - combines two nodes into one and modifies all */
9129 /*                   edges to and from the nodes accordingly      */
9130 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9131 /* then also (B,A) must be an edge (possibly with weight 0).      */
9132 /*----------------------------------------------------------------*/
9133 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9134 {
9135   GraphEdge *edge, *backedge, *nextedge;
9136   GraphNode *node;
9137   int backweight;
9138
9139   assert (node1 && node2);
9140   assert (node1 != node2);
9141   
9142   // add all edges starting at node2 to node1
9143   edge = node2->edge;
9144   while (edge) {
9145     nextedge = edge->next;
9146     node = edge->node;
9147     backedge = getGEdge (node, node2);
9148     if (backedge)
9149       backweight = backedge->weight;
9150     else
9151       backweight = 0;
9152     // insert edges (node1,node) and (node,node1)
9153     addGEdge2 (node1, node, edge->weight, backweight);
9154     // remove edges (node, node2) and (node2, node)
9155     remGEdge (node2, node);
9156     remGEdge (node, node2);
9157     edge = nextedge;
9158   } // while
9159   
9160   // now node2 should not be referenced by any other GraphNode...
9161   //remGNode (adj, node2->data, node2->hash);
9162 }
9163
9164 /*----------------------------------------------------------------*/
9165 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9166 /*----------------------------------------------------------------*/
9167 void showGraph (Graph *g)
9168 {
9169   GraphNode *node;
9170   GraphEdge *edge;
9171   pseudoBankNr bankNr;
9172   pseudoBank *pbank;
9173   unsigned int size;
9174
9175   node = g->node;
9176   while (node) {
9177     edge = node->edge;
9178     bankNr = getEffectiveBank (node->hash);
9179     assert (bankNr >= 0);
9180     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9181     if (pbank) {
9182       bankNr = pbank->bank;
9183       size = pbank->size;
9184     } else {
9185       size = 1;
9186     }
9187     
9188     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9189
9190     while (edge) {
9191       if (edge->weight > 0)
9192         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9193       edge = edge->next;
9194     } // while (edge)
9195     node = node->next;
9196   } // while (node)
9197 }
9198
9199 /*---------------------------------------------------------------*/
9200 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9201 /*---------------------------------------------------------------*/
9202 void pic16_OptimizeBanksel ()
9203 {
9204   GraphNode *node, *node1, *node1next;
9205
9206 #if 0
9207   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9208   GraphEdge *edge, *backedge;
9209   GraphEdge *max;
9210   int maxWeight, weight, mergeMore, absMaxWeight;
9211   pseudoBankNr curr0, curr1;
9212 #endif
9213   pseudoBank *pbank;
9214   pseudoBankNr bankNr;
9215   char *base_symbol0, *base_symbol1;
9216   int len0, len1;
9217   pBlock *pb;
9218   set *set;
9219   regs *reg;
9220   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9221
9222   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9223
9224   if (!the_pFile || !the_pFile->pbHead) return;
9225
9226   adj = newGraph (NULL);
9227   sym2bank = newHashTable ( 255 );
9228   bank2sym = newHashTable ( 255 );
9229   coerce = newHashTable ( 255 );
9230
9231   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9232   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9233     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9234   } // for pb
9235
9236 #if 1
9237   // assign symbols with absolute addresses to their respective bank nrs
9238   set = pic16_fix_udata;
9239   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9240     bankNr = reg->address >> 8;
9241     node = getOrAddGNode (adj, NULL, bankNr);
9242     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9243     assignToSameBank (node->hash, bankNr, 1);
9244     
9245     assert (bankNr >= 0);
9246     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9247     if (!pbank) {
9248       pbank = Safe_calloc (1, sizeof (pseudoBank));
9249       pbank->bank = reg->address >> 8; //FIXED_BANK;
9250       pbank->size = 1;
9251       pbank->ref = 1;
9252       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9253     } else {
9254       assert (pbank->bank == (reg->address >> 8));
9255       pbank->bank = reg->address >> 8; //FIXED_BANK;
9256     }
9257     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9258   } // for reg
9259 #endif
9260
9261 #if 1
9262   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9263   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9264   node = adj->node;
9265   while (node) {
9266     if (node->hash < 0) { node = node->next; continue; }
9267     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9268     node1 = node->next;
9269     while (node1) {
9270       if (node1->hash < 0) { node1 = node1->next; continue; }
9271       node1next = node1->next;
9272       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9273       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9274         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9275         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9276         if (assignToSameBank (node->hash, node1->hash, 0)) {
9277           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9278           assert (0 && "Could not assign a symbol to a bank!");
9279         }
9280         mergeGraphNodes (node, node1);
9281         /*
9282         if (node->hash < node1->hash)
9283           mergeGraphNodes (node, node1);
9284         else
9285           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9286         */
9287       } // if
9288       node1 = node1next;
9289     } // while (node1)
9290     node = node->next;
9291   } // while (node)
9292 #endif
9293
9294 #if 0
9295   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9296   // assign tightly coupled operands to the same (pseudo) bank
9297   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9298   mergeMore = 1;
9299   absMaxWeight = 0;
9300   while (mergeMore) {
9301     node = adj->node;
9302     max = NULL;
9303     maxWeight = 0;
9304     while (node) {
9305       curr0 = getEffectiveBank (node->hash);
9306       if (curr0 < 0) { node = node->next; continue; }
9307       edge = node->edge;
9308       while (edge) {
9309         assert (edge->src == node);
9310         backedge = getGEdge (edge->node, edge->src);
9311         weight = edge->weight + (backedge ? backedge->weight : 0);
9312         curr1 = getEffectiveBank (edge->node->hash);
9313         if (curr1 < 0) { edge = edge->next; continue; }
9314
9315         // merging is only useful if the items are not assigned to the same bank already...
9316         if (curr0 != curr1 && weight > maxWeight) {
9317           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9318           maxWeight = weight;
9319           max = edge;
9320         } // if
9321         edge = edge->next;
9322       } // while
9323       node = node->next;
9324     } // while
9325     
9326     if (maxWeight > 0) {
9327 #if 0
9328       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9329                max->src->hash, getSymFromBank (max->src->hash),
9330                max->node->hash, getSymFromBank (max->node->hash));
9331 #endif
9332
9333       node = getGNode (adj, max->src->data, max->src->hash);
9334       node1 = getGNode (adj, max->node->data, max->node->hash);
9335
9336       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9337         if (max->src->hash < max->node->hash)
9338           mergeGraphNodes (node, node1);
9339         else
9340           mergeGraphNodes (node1, node);
9341       } else {
9342         remGEdge (node, node1);
9343         remGEdge (node1, node);
9344         //mergeMore = 0;
9345       }
9346
9347     } else {
9348       mergeMore = 0;
9349     }
9350   } // while
9351 #endif
9352
9353 #if 1  
9354   // remove redundant BANKSELs
9355   //fprintf (stderr, "removing redundant BANKSELs\n");
9356   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9357     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9358   } // for pb
9359 #endif
9360
9361 #if 0
9362   fprintf (stderr, "display graph\n");
9363   showGraph ();
9364 #endif
9365
9366   deleteGraph (adj);
9367   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9368 }
9369
9370 /*** END of stuff belonging to the BANKSEL optimization ***/
9371
9372
9373
9374 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9375
9376 typedef unsigned int symbol_t;
9377 typedef unsigned int valnum_t;
9378 //typedef unsigned int hash_t;
9379
9380 #ifndef INT_TO_PTR
9381 #define INT_TO_PTR(x) (((char *) 0) + (x))
9382 #endif
9383
9384 #ifndef PTR_TO_INT
9385 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9386 #endif
9387
9388 static int pic16_regIsLocal (regs *r);
9389 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9390
9391 /* statistics */
9392 static unsigned int pic16_df_removed_pcodes = 0;
9393 static unsigned int pic16_df_saved_bytes = 0;
9394 static unsigned int df_findall_sameflow = 0;
9395 static unsigned int df_findall_otherflow = 0;
9396 static unsigned int df_findall_in_vals = 0;
9397
9398 static void pic16_df_stats () {
9399   return;
9400   if (pic16_debug_verbose || pic16_pcode_verbose) {
9401     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9402     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9403     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9404   }
9405 }
9406
9407 /* Remove a pCode iff possible:
9408  * - previous pCode is no SKIP
9409  * - pc has no label
9410  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9411 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9412   pCode *pcprev, *pcnext;
9413   char buf[256], *total=NULL;
9414   int len;
9415   
9416   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9417
9418   pcprev = pic16_findPrevInstruction (pc->prev);
9419   pcnext = pic16_findNextInstruction (pc->next);
9420   
9421   /* move labels to next instruction (if possible) */
9422   if (PCI(pc)->label && !pcnext) return 0;
9423
9424   /* if this is a SKIP with side-effects -- do not remove */
9425   /* XXX: might try to replace this one with the side-effect only version */
9426   if (isPCI_SKIP(pc)
9427         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9428   {
9429     pCode *newpc;
9430     switch (PCI(pc)->op)
9431     {
9432     case POC_INCFSZ:
9433     case POC_INFSNZ:
9434       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9435       pic16_pCodeReplace( pc, newpc );
9436       return 1;
9437       break;
9438     case POC_INCFSZW:
9439       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9440       pic16_pCodeReplace( pc, newpc );
9441       return 1;
9442       break;
9443     case POC_DECFSZ:
9444     case POC_DCFSNZ:
9445       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9446       pic16_pCodeReplace( pc, newpc );
9447       return 1;
9448       break;
9449     case POC_DECFSZW:
9450       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9451       pic16_pCodeReplace( pc, newpc );
9452       return 1;
9453       break;
9454     default:
9455       return 0;
9456     }
9457     return 0;
9458   }
9459
9460   /* if previous instruction is a skip -- do not remove */
9461   if (pcprev && isPCI_SKIP(pcprev)) {
9462     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9463       /* preceeding SKIP could not be removed -- keep this instruction! */
9464       return 0;
9465     }
9466   }
9467
9468   if (PCI(pc)->label) {
9469     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9470     //pc->print (stderr, pc);
9471     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9472     PCI(pc)->label = NULL;
9473   }
9474   
9475   /* update statistics */
9476   pic16_df_removed_pcodes++;
9477   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9478   
9479   /* remove the pCode */
9480   pic16_pCode2str (buf, 256, pc);
9481   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9482   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9483     len = strlen (buf) + strlen (comment) + 10;
9484     total = (char *) Safe_malloc (len);
9485     SNPRINTF (total, len, "%s: %s", comment, buf);
9486     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9487     Safe_free (total);
9488   }
9489
9490   /* actually unlink it from the pBlock -- also remove from to/from lists */
9491   pic16_pCodeUnlink (pc);
9492
9493   /* remove the pCode -- release registers */
9494   pc->destruct (pc);
9495
9496   /* report success */
9497   return 1;
9498 }
9499
9500
9501 /* ======================================================================== */
9502 /* === SYMBOL HANDLING ==================================================== */
9503 /* ======================================================================== */
9504
9505 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9506 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9507 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9508
9509 /** Calculate a hash for a given string.
9510  * If len == 0 the string is assumed to be NUL terminated. */
9511 static hash_t symbolHash (const char *str, unsigned int len) {
9512   hash_t hash = 0;
9513   if (!len) {
9514     while (*str) {
9515       hash = (hash << 2) ^ *str;
9516       str++;
9517     } // while
9518   } else {
9519     while (len--) {
9520       hash = (hash << 2) ^ *str;
9521       str++;
9522     }
9523   }
9524   return hash;
9525 }
9526
9527 /** Return 1 iff strings v1 and v2 are identical. */
9528 static int symcmp (const void *v1, const void *v2) {
9529   return !strcmp ((const char *) v1, (const char *) v2);
9530 }
9531
9532 /** Return 1 iff pointers v1 and v2 are identical. */
9533 static int ptrcmp (const void *v1, const void *v2) {
9534   return (v1 == v2);
9535 }
9536
9537 enum {  SPO_WREG=0x1000,
9538         SPO_STATUS,
9539         SPO_PRODL,
9540         SPO_PRODH,
9541         SPO_INDF0,
9542         SPO_POSTDEC0,
9543         SPO_POSTINC0,
9544         SPO_PREINC0,
9545         SPO_PLUSW0,
9546         SPO_INDF1,
9547         SPO_POSTDEC1,
9548         SPO_POSTINC1,
9549         SPO_PREINC1,
9550         SPO_PLUSW1,
9551         SPO_INDF2,
9552         SPO_POSTDEC2,
9553         SPO_POSTINC2,
9554         SPO_PREINC2,
9555         SPO_PLUSW2,
9556         SPO_STKPTR,
9557         SPO_TOSL,
9558         SPO_TOSH,
9559         SPO_TOSU,
9560         SPO_BSR,
9561         SPO_FSR0L,
9562         SPO_FSR0H,
9563         SPO_FSR1L,
9564         SPO_FSR1H,
9565         SPO_FSR2L,
9566         SPO_FSR2H,
9567         SPO_PCL,
9568         SPO_PCLATH,
9569         SPO_PCLATU,
9570         SPO_TABLAT,
9571         SPO_TBLPTRL,
9572         SPO_TBLPTRH,
9573         SPO_TBLPTRU,
9574         SPO_LAST
9575 };
9576
9577 /* Return the unique symbol_t for the given string. */
9578 static symbol_t symFromStr (const char *str) {
9579   hash_t hash;
9580   char *res;
9581   symbol_t sym;
9582
9583   if (!map_symToStr) {
9584     int i;
9585     struct { char *name; symbol_t sym; } predefsyms[] = {
9586         {"WREG", SPO_WREG},
9587         {"STATUS", SPO_STATUS},
9588         {"PRODL", SPO_PRODL},
9589         {"PRODH", SPO_PRODH},
9590         {"INDF0", SPO_INDF0},
9591         {"POSTDEC0", SPO_POSTDEC0},
9592         {"POSTINC0", SPO_POSTINC0},
9593         {"PREINC0", SPO_PREINC0},
9594         {"PLUSW0", SPO_PLUSW0},
9595         {"INDF1", SPO_INDF1},
9596         {"POSTDEC1", SPO_POSTDEC1},
9597         {"POSTINC1", SPO_POSTINC1},
9598         {"PREINC1", SPO_PREINC1},
9599         {"PLUSW1", SPO_PLUSW1},
9600         {"INDF2", SPO_INDF2},
9601         {"POSTDEC2", SPO_POSTDEC2},
9602         {"POSTINC2", SPO_POSTINC2},
9603         {"PREINC2", SPO_PREINC2},
9604         {"PLUSW2", SPO_PLUSW2},
9605         {"STKPTR", SPO_STKPTR},
9606         {"TOSL", SPO_TOSL},
9607         {"TOSH", SPO_TOSH},
9608         {"TOSU", SPO_TOSU},
9609         {"BSR", SPO_BSR},
9610         {"FSR0L", SPO_FSR0L},
9611         {"FSR0H", SPO_FSR0H},
9612         {"FSR1L", SPO_FSR1L},
9613         {"FSR1H", SPO_FSR1H},
9614         {"FSR2L", SPO_FSR2L},
9615         {"FSR2H", SPO_FSR2H},
9616         {"PCL", SPO_PCL},
9617         {"PCLATH", SPO_PCLATH},
9618         {"PCLATU", SPO_PCLATU},
9619         {"TABLAT", SPO_TABLAT},
9620         {"TBLPTRL", SPO_TBLPTRL},
9621         {"TBLPTRH", SPO_TBLPTRH},
9622         {"TBLPTRU", SPO_TBLPTRU},
9623         {NULL, 0}
9624     };
9625
9626     map_strToSym = newHashTable (128);
9627     map_symToStr = newHashTable (128);
9628
9629     for (i=0; predefsyms[i].name; i++) {
9630       char *name;
9631
9632       /* enter new symbol */
9633       sym = predefsyms[i].sym;
9634       name = predefsyms[i].name;
9635       res = Safe_strdup (name);
9636       hash = symbolHash (name, 0);
9637
9638       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9639       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9640     } // for i
9641   }
9642
9643   hash = symbolHash (str, 0) % map_strToSym->size;
9644   
9645   /* find symbol in table */
9646   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9647   if (sym) {
9648     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9649     return sym;
9650   }
9651
9652   /* enter new symbol */
9653   sym = nextSymbol++;
9654   res = Safe_strdup (str);
9655
9656   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9657   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9658
9659   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9660   
9661   return sym;
9662 }
9663
9664 #if 1
9665 static const char *strFromSym (symbol_t sym) {
9666   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9667 }
9668 #endif
9669
9670 /* ======================================================================== */
9671 /* === DEFINITION MAP HANDLING ============================================ */
9672 /* ======================================================================== */
9673
9674 /* A defmap provides information about which symbol is defined by which pCode.
9675  * The most recent definitions are prepended to the list, so that the most
9676  * recent definition can be found by forward scanning the list.
9677  * pc2: MOVFF r0x00, r0x01
9678  * pc1: INCF r0x01
9679  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9680  *
9681  * We attach one defmap to each flow object, and each pCode will occur at
9682  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9683  * used to find definitions for a pCode in its own defmap that precede pCode.
9684  */
9685
9686 typedef struct defmap_s {
9687   symbol_t sym;                 /** symbol this item refers to */
9688   union {
9689     struct {
9690       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9691       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9692       int isRead:1;             /** sym/mask is read */
9693       int isWrite:1;            /** sym/mask is written */
9694     } access;
9695     int accessmethod;
9696   } acc;
9697   pCode *pc;                    /** pCode this symbol is refrenced at */
9698   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9699   valnum_t val;                 /** new unique number for this value (if isWrite) */
9700   struct defmap_s *prev, *next; /** link to previous an next definition */
9701 } defmap_t;
9702
9703 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9704 static int defmap_free_count = 0;               /** number of released defmap items */
9705
9706 /* Returns a defmap_t with the specified data; this will be the new list head.
9707  * next - pointer to the current list head */
9708 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9709   defmap_t *map;
9710   
9711   if (defmap_free) {
9712     map = defmap_free;
9713     defmap_free = map->next;
9714     --defmap_free_count;
9715   } else {
9716     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9717   }
9718   map->sym = sym;
9719   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9720   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9721   map->acc.access.isRead = (isRead != 0);
9722   map->acc.access.isWrite = (isWrite != 0);
9723   map->pc = pc;
9724   map->in_val = 0;
9725   map->val = (isWrite ? val : 0);
9726   map->prev = NULL;
9727   map->next = next;
9728   if (next) next->prev = map;
9729   
9730   return map;
9731 }
9732
9733 /* Returns a copy of the single defmap item. */
9734 static defmap_t *copyDefmap (defmap_t *map) {
9735   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9736   memcpy (res, map, sizeof (defmap_t));
9737   res->next = NULL;
9738   res->prev = NULL;
9739   return res;
9740 }
9741
9742 /* Insert a defmap item after the specified one. */
9743 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9744   if (!ref || !newItem) return 1;
9745
9746   newItem->next = ref->next;
9747   newItem->prev = ref;
9748   ref->next = newItem;
9749   if (newItem->next) newItem->next->prev = newItem;
9750   
9751   return 0;
9752 }
9753
9754 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9755  * item is copied before insertion into chain and therefore left untouched.
9756  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9757 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9758   defmap_t *dummy;
9759   dummy = *head;
9760   while (dummy && (dummy->sym != item->sym
9761                           || dummy->pc != item->pc
9762                           || dummy->acc.accessmethod != item->acc.accessmethod
9763                           || dummy->val != item->val
9764                           || dummy->in_val != item->in_val)) {
9765     dummy = dummy->next;
9766   } // while
9767
9768   /* item already present? */
9769   if (dummy) return 0;
9770   
9771   /* otherwise: insert copy of item */
9772   dummy = copyDefmap (item);
9773   dummy->next = *head;
9774   if (*head) (*head)->prev = dummy;
9775   *head = dummy;
9776
9777   return 1;
9778 }
9779
9780 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9781 static void deleteDefmap (defmap_t *map) {
9782   if (!map) return;
9783   
9784   /* unlink from chain -- fails for the first item (head is not updated!) */
9785   if (map->next) map->next->prev = map->prev;
9786   if (map->prev) map->prev->next = map->next;
9787
9788   /* clear map */
9789   memset (map, 0, sizeof (defmap_t));
9790
9791   /* save for future use */
9792   map->next = defmap_free;
9793   defmap_free = map;
9794   ++defmap_free_count;
9795 }
9796
9797 /* Release all defmaps referenced from map. */
9798 static void deleteDefmapChain (defmap_t **_map) {
9799   defmap_t *map, *next;
9800
9801   if (!_map) return;
9802
9803   map = *_map;
9804   
9805   /* find list head */
9806   while (map && map->prev) map = map->prev;
9807
9808   /* delete all items */
9809   while (map) {
9810     next = map->next;
9811     deleteDefmap (map);
9812     map = next;
9813   } // while
9814
9815   *_map = NULL;
9816 }
9817
9818 /* Free all defmap items. */
9819 static void freeDefmap (defmap_t **_map) {
9820   defmap_t *next;
9821   defmap_t *map;
9822
9823   if (!_map) return;
9824
9825   map = (*_map);
9826   
9827   /* find list head */
9828   while (map->prev) map = map->prev;
9829
9830   /* release all items */
9831   while (map) {
9832     next = map->next;
9833     Safe_free (map);
9834     map = next;
9835   }
9836
9837   (*_map) = NULL;
9838 }
9839
9840 /* Returns the most recent definition for the given symbol preceeding pc.
9841  * If no definition is found, NULL is returned. 
9842  * If pc == NULL the whole list is scanned. */
9843 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9844   defmap_t *curr = map;
9845
9846   if (pc) {
9847     /* skip all definitions up to pc */
9848     while (curr && (curr->pc != pc)) curr = curr->next;
9849
9850     /* pc not in the list -- scan the whole list for definitions */
9851     if (!curr) {
9852       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9853       curr = map;
9854     } else {
9855       /* skip all definitions performed by pc */
9856       while (curr && (curr->pc == pc)) curr = curr->next;
9857     }
9858   } // if (pc)
9859
9860   /* find definition for sym */
9861   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9862     curr = curr->next;
9863   }
9864
9865   return curr;
9866 }
9867
9868 #if 0
9869 /* Returns the first use (read) of the given symbol AFTER pc.
9870  * If no such use is found, NULL is returned.
9871  * If pc == NULL the whole list is scanned. */
9872 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9873   defmap_t *curr = map, *prev = NULL;
9874   
9875   if (pc) {
9876     /* skip all definitions up to pc */
9877     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9878
9879     /* pc not in the list -- scan the whole list for definitions */
9880     if (!curr) {
9881       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9882       curr = prev;
9883     }
9884   } else {
9885     /* find end of list */
9886     while (curr && curr->next) curr = curr->next;
9887   } // if (pc)
9888
9889   /* find use of sym (scan list backwards) */
9890   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9891
9892   return curr;
9893 }
9894 #endif
9895
9896 /* Return the defmap entry for sym AT pc. 
9897  * If none is found, NULL is returned.
9898  * If more than one entry is found an assertion is triggered. */
9899 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9900   defmap_t *res = NULL;
9901
9902   /* find entries for pc */
9903   while (map && map->pc != pc) map = map->next;
9904
9905   /* find first entry for sym @ pc */
9906   while (map && map->pc == pc && map->sym != sym) map = map->next;
9907
9908   /* no entry found */
9909   if (!map) return NULL;
9910
9911   /* check for more entries */
9912   res = map;
9913   map = map->next;
9914   while (map && map->pc == pc) {
9915     /* more than one entry for sym @ pc found? */
9916     assert (map->sym != sym);
9917     map = map->next;
9918   }
9919
9920   /* return single entry for sym @ pc */
9921   return res;
9922 }
9923
9924 /* Modifies the definition of sym at pCode to newval.
9925  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9926  */
9927 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9928   defmap_t *m  = map;
9929
9930   /* find definitions of pc */
9931   while (m && m->pc != pc) m = m->next;
9932
9933   /* find definition of sym at pc */
9934   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9935   
9936   /* no definition found */
9937   if (!m) return 1;
9938
9939   /* redefine */
9940   m->val = newval;
9941
9942   /* update following uses of sym */
9943   while (m && m->pc == pc) m = m->prev;
9944   while (m) {
9945     if (m->sym == sym) {
9946       m->in_val = newval;
9947       if (m->acc.access.isWrite) m = NULL;
9948     } // if
9949     if (m) m = m->prev;
9950   } // while
9951   
9952   return 0;
9953 }
9954
9955 /* ======================================================================== */
9956 /* === STACK ROUTINES ===================================================== */
9957 /* ======================================================================== */
9958
9959 typedef struct stack_s {
9960   void *data;
9961   struct stack_s *next;
9962 } stackitem_t;
9963
9964 typedef stackitem_t *dynstack_t;
9965 static stackitem_t *free_stackitems = NULL;
9966
9967 /* Create a stack with one item. */
9968 static dynstack_t *newStack () {
9969   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9970   *s = NULL;
9971   return s;
9972 }
9973
9974 /* Remove a stack -- its items are only marked free. */
9975 static void deleteStack (dynstack_t *s) {
9976   stackitem_t *i;
9977
9978   while (*s) {
9979     i = *s;
9980     *s = (*s)->next;
9981     i->next = free_stackitems;
9982     free_stackitems = i;
9983   } // while
9984   Safe_free (s);
9985 }
9986
9987 /* Release all stackitems. */
9988 static void releaseStack () {
9989   stackitem_t *i;
9990   
9991   while (free_stackitems) {
9992     i = free_stackitems->next;
9993     Safe_free(free_stackitems);
9994     free_stackitems = i;
9995   } // while
9996 }
9997
9998 static void stackPush (dynstack_t *stack, void *data) {
9999   stackitem_t *i;
10000   
10001   if (free_stackitems) {
10002     i = free_stackitems;
10003     free_stackitems = free_stackitems->next;
10004   } else {
10005     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10006   }
10007   i->data = data;
10008   i->next = *stack;
10009   *stack = i;
10010 }
10011
10012 static void *stackPop (dynstack_t *stack) {
10013   void *data;
10014   stackitem_t *i;
10015   
10016   if (stack && *stack) {
10017     data = (*stack)->data;
10018     i = *stack;
10019     *stack = (*stack)->next;
10020     i->next = free_stackitems;
10021     free_stackitems = i;
10022     return data;
10023   } else {
10024     return NULL;
10025   }
10026 }
10027
10028 #if 0
10029 static int stackContains (dynstack_t *s, void *data) {
10030   stackitem_t *i;
10031   if (!s) return 0;
10032   i = *s;
10033   while (i) {
10034     if (i->data == data) return 1;
10035     i = i->next;
10036   } // while
10037
10038   /* not found */
10039   return 0;
10040 }
10041 #endif
10042
10043 static int stackIsEmpty (dynstack_t *s) {
10044   return (*s == NULL);
10045 }
10046
10047
10048 typedef struct {
10049   pCodeFlow *flow;
10050   defmap_t *lastdef;
10051 } state_t;
10052
10053 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10054   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10055   s->flow = flow;
10056   s->lastdef = lastdef;
10057   return s;
10058 }
10059
10060 static void deleteState (state_t *s) {
10061   Safe_free (s);
10062 }
10063
10064 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10065   stackitem_t *i;
10066
10067   /* scan working list for state */
10068   if (todo) {
10069     i = *todo;
10070     while (i) {
10071       /* is i == state? -- state not new */
10072       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10073       i = i->next;
10074     } // while
10075   }
10076
10077   if (done) {
10078     i = *done;
10079     while (i) {
10080       /* is i == state? -- state not new */
10081       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10082       i = i->next;
10083     } // while
10084   }
10085
10086   /* not found -- state is new */
10087   return 1;
10088 }
10089
10090 static inline valnum_t newValnum ();
10091
10092 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10093   pCode *pc;
10094
10095   if (!pb) return "<unknown function>";
10096
10097   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10098   if (pc && isPCF(pc)) return PCF(pc)->fname;
10099   else return "<unknown function>";
10100 }
10101
10102 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10103   defmap_t *map;
10104   pCodeFlow *pcfl;
10105
10106   assert(pb);
10107
10108   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10109
10110   /* find initial value (assigning pc == NULL) */
10111   map = PCFL(pcfl)->in_vals;
10112   while (map && map->sym != sym) map = map->next;
10113
10114   /* initial value already present? */
10115   if (map) {
10116     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10117     return map;
10118   }
10119
10120   /* create a new initial value */
10121   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10122   PCFL(pcfl)->in_vals = map;
10123   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10124   return map;
10125
10126 #if 0
10127   /* insert map as last item in pcfl's defmap */
10128   if (!prev) prev = PCFL(pcfl)->defmap;
10129   if (!prev) {
10130     PCFL(pcfl)->defmap = map;
10131   } else {
10132     while (prev->next) prev = prev->next;
10133     prev->next = map;
10134     map->prev = prev;
10135   }
10136
10137   return map;
10138 #endif
10139 }
10140
10141 /* Find all reaching definitions for sym at pc. 
10142  * A new (!) list of definitions is returned.
10143  * Returns the number of reaching definitions found.
10144  * The defining defmap entries are returned in *chain.
10145  */
10146 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10147   defmap_t *map;
10148   defmap_t *res;
10149
10150   pCodeFlow *curr;
10151   pCodeFlowLink *succ;
10152   state_t *state;
10153   dynstack_t *todo;     /** stack of state_t */
10154   dynstack_t *done;     /** stack of state_t */
10155
10156   int firstState, n_defs;
10157   
10158   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10159   assert (chain);
10160
10161   /* initialize return list */
10162   *chain = NULL;
10163
10164   /* wildcard symbol? */
10165   if (!sym) return 0;
10166   
10167   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10168   
10169   map = PCI(pc)->pcflow->defmap;
10170
10171   res = defmapFindDef (map, sym, pc);
10172   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10173
10174 #define USE_PRECALCED_INVALS 1
10175 #if USE_PRECALCED_INVALS
10176   if (!res && PCI(pc)->pcflow->in_vals) {
10177     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10178     if (res) {
10179       //fprintf  (stderr, "found def in init values\n");
10180       df_findall_in_vals++;
10181     }
10182   }
10183 #endif
10184
10185   if (res) {
10186     // found a single definition (in pc's flow)
10187     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10188     defmapAddCopyIfNew (chain, res);
10189     df_findall_sameflow++;
10190     return 1;
10191   }
10192
10193 #if USE_PRECALCED_INVALS
10194   else {
10195     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10196     return 1;
10197   }
10198
10199 #endif
10200   
10201 #define FORWARD_FLOW_ANALYSIS 1
10202 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10203   /* no definition found in pc's flow preceeding pc */
10204   todo = newStack ();
10205   done = newStack ();
10206   n_defs = 0; firstState = 1;
10207   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10208
10209   while (!stackIsEmpty (todo)) {
10210     state = (state_t *) stackPop (todo);
10211     stackPush (done, state);
10212     curr = state->flow;
10213     res = state->lastdef;
10214     //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);
10215
10216     /* there are no definitions BEFORE pc in pc's flow (see above) */
10217     if (curr == PCI(pc)->pcflow) {
10218       if (!res) {
10219         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10220         res = pic16_pBlockAddInval (pc->pb, sym);
10221         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10222         res = NULL;
10223       } else {
10224         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10225         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10226       }
10227     }
10228
10229     /* save last definition of sym in this flow as initial def in successors */
10230     res = defmapFindDef (curr->defmap, sym, NULL);
10231     if (!res) res = state->lastdef;
10232     
10233     /* add successors to working list */
10234     state = newState (NULL, NULL);
10235     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10236     while (succ) {
10237       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10238       state->flow = succ->pcflow;
10239       state->lastdef = res;
10240       if (stateIsNew (state, todo, done)) {
10241         stackPush (todo, state);
10242         state = newState (NULL, NULL);
10243       } // if
10244       succ = (pCodeFlowLink *) setNextItem (curr->to);
10245     } // while
10246     deleteState (state);
10247   } // while
10248
10249 #else // !FORWARD_FLOW_ANALYSIS 
10250
10251   /* no definition found in pc's flow preceeding pc */
10252   todo = newStack ();
10253   done = newStack ();
10254   n_defs = 0; firstState = 1;
10255   stackPush (todo, newState (PCI(pc)->pcflow, res));
10256
10257   while (!stackIsEmpty (todo)) {
10258     state = (state_t *) stackPop (todo);
10259     curr = state->flow;
10260
10261     if (firstState) {
10262       firstState = 0;
10263       /* only check predecessor flows */
10264     } else {
10265       /* get (last) definition of sym in this flow */
10266       res = defmapFindDef (curr->defmap, sym, NULL);
10267     }
10268
10269     if (res) {
10270       /* definition found */
10271       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10272       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10273     } else {
10274       /* no definition found -- check predecessor flows */
10275       state = newState (NULL, NULL);
10276       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10277
10278       /* if no flow predecessor available -- sym might be uninitialized */
10279       if (!succ) {
10280         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10281         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10282         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10283         deleteDefmap (res); res = NULL;
10284       }
10285       
10286       while (succ) {
10287         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10288         state->flow = succ->pcflow;
10289         state->lastdef = res;
10290         if (stateIsNew (state, todo, done)) {
10291           stackPush (todo, state);
10292           state = newState (NULL, NULL);
10293         } // if
10294         succ = (pCodeFlowLink *) setNextItem (curr->from);
10295       } // while
10296       deleteState (state);
10297     }
10298   } // while
10299
10300 #endif
10301
10302   /* clean up done stack */
10303   while (!stackIsEmpty(done)) {
10304     deleteState ((state_t *) stackPop (done));
10305   } // while
10306   deleteStack (done);
10307
10308   /* return number of items in result set */
10309   if (n_defs == 0) {
10310     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10311   } else if (n_defs == 1) {
10312     assert (*chain);
10313     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10314   } else if (n_defs > 0) {
10315     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10316 #if 0
10317     res = *chain;
10318     while (res) {
10319       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10320       res = res->next;
10321     } // while
10322 #endif
10323   }
10324   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10325   df_findall_otherflow++;
10326   return n_defs;
10327 }
10328
10329 /* ======================================================================== */
10330 /* === VALUE NUMBER HANDLING ============================================== */
10331 /* ======================================================================== */
10332
10333 static valnum_t nextValnum = 0x1000;
10334 static hTab *map_symToValnum = NULL;
10335
10336 /** Return a new value number. */
10337 static inline valnum_t newValnum () {
10338   return (nextValnum += 4);
10339 }
10340
10341 static valnum_t valnumFromStr (const char *str) {
10342   symbol_t sym;
10343   valnum_t val;
10344   void *res;
10345   
10346   sym = symFromStr (str);
10347
10348   if (!map_symToValnum) {
10349     map_symToValnum = newHashTable (128);
10350   } // if
10351
10352   /* literal already known? */
10353   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10354
10355   /* return existing valnum */
10356   if (res) return (valnum_t) PTR_TO_INT(res);
10357   
10358   /* create new valnum */
10359   val = newValnum();
10360   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10361   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10362   return val;
10363 }
10364
10365 /* Create a valnum for a literal. */
10366 static valnum_t valnumFromLit (unsigned int lit) {
10367   return ((valnum_t) 0x100 + (lit & 0x0FF));
10368 }
10369
10370 /* Return the (positive) literal value represented by val
10371  * or -1 iff val is no known literal's valnum. */
10372 static int litFromValnum (valnum_t val) {
10373   if (val >= 0x100 && val < 0x200) {
10374     /* valnum is a (known) literal */
10375     return val & 0x00FF;
10376   } else {
10377     /* valnum is not a known literal */
10378     return -1;
10379   }
10380 }
10381
10382 #if 0
10383 /* Sanity check - all flows in a block must be reachable from initial flow. */
10384 static int verifyAllFlowsReachable (pBlock *pb) {
10385   set *reached;
10386   set *flowInBlock;
10387   set *checked;
10388   pCode *pc;
10389   pCodeFlow *pcfl;
10390   pCodeFlowLink *succ;
10391   int res;
10392
10393   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10394
10395   reached = NULL;
10396   flowInBlock = NULL;
10397   checked = NULL;
10398   /* mark initial flow as reached (and "not needs to be reached") */
10399   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10400   assert (pc);
10401   addSetHead (&reached, pc);
10402   addSetHead (&checked, pc);
10403   
10404   /* mark all further flows in block as "need to be reached" */
10405   pc = pb->pcHead;
10406   do {
10407     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10408     pc = pic16_findNextInstruction (pc->next);
10409   } while (pc);
10410
10411   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10412     /* mark as reached and "not need to be reached" */
10413     deleteSetItem (&reached, pcfl);
10414     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10415     
10416     /* flow is no longer considered unreachable */
10417     deleteSetItem (&flowInBlock, pcfl);
10418
10419     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10420       if (!isinSet (checked, succ->pcflow)) {
10421         /* flow has never been reached before */
10422         addSetHead (&reached, succ->pcflow);
10423         addSetHead (&checked, succ->pcflow);
10424       } // if
10425     } // for succ
10426   } // while
10427
10428   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10429
10430   /* by now every flow should have been reached
10431    * --> flowInBlock should be empty */
10432   res = (flowInBlock == NULL);
10433
10434 #if 1
10435   if (flowInBlock) {
10436           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10437     while (flowInBlock) {
10438       pcfl = indexSet (flowInBlock, 0);
10439       fprintf (stderr, "not reached: flow %p\n", pcfl);
10440       deleteSetItem (&flowInBlock, pcfl);
10441     } // while
10442   }
10443 #endif
10444   
10445   /* clean up */
10446   deleteSet (&reached);
10447   deleteSet (&flowInBlock);
10448   deleteSet (&checked);
10449   
10450   /* if we reached every flow, succ is NULL by now... */
10451   //assert (res); // will fire on unreachable code...
10452   return (res);
10453 }
10454 #endif
10455
10456 /* Checks a flow for accesses to sym AFTER pc.
10457  * 
10458  * Returns -1 if the symbol is read in this flow (before redefinition),
10459  * returns 0 if the symbol is redefined in this flow or
10460  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10461  */
10462 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10463   defmap_t *map, *mappc;
10464
10465   /* find pc or start of definitions */
10466   map = pcfl->defmap;
10467   while (map && (map->pc != pc) && map->next) map = map->next;
10468   /* if we found pc -- ignore it */
10469   while (map && map->pc == pc) map = map->prev;
10470
10471   /* scan list backwards (first definition first) */
10472   while (map && mask) {
10473 //    if (map->sym == sym) {
10474       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10475       mappc = map;
10476       /* scan list for reads at this pc first */
10477       while (map && map->pc == mappc->pc) {
10478         /* is the symbol (partially) read? */
10479         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10480           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10481           return -1;
10482         }
10483         map = map->prev;
10484       } // while
10485       map = mappc;
10486
10487       while (map && map->pc == mappc->pc) {
10488         /* honor (partial) redefinitions of sym */
10489         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10490           mask &= ~map->acc.access.mask;
10491           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10492         }
10493         map = map->prev;
10494       } // while
10495 //    } // if
10496     /* map already points to the first defmap for the next pCode */
10497     //map = mappc->prev;
10498   } // while
10499
10500   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10501    * is still alive; return the appropriate mask of alive bits */
10502   return mask;
10503 }
10504
10505 /* Check whether a symbol is alive (AFTER pc). */
10506 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10507   int mask, visit;
10508   defmap_t *map;
10509   dynstack_t *todo, *done;
10510   state_t *state;
10511   pCodeFlow *pcfl;
10512   pCodeFlowLink *succ;
10513
10514   mask = 0x00ff;
10515   
10516   assert (isPCI(pc));
10517   pcfl = PCI(pc)->pcflow;
10518   map = pcfl->defmap;
10519
10520   todo = newStack ();
10521   done = newStack ();
10522   
10523   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10524   stackPush (todo, state);
10525   visit = 0;
10526   
10527   while (!stackIsEmpty (todo)) {
10528     state = (state_t *) stackPop (todo);
10529     pcfl = state->flow;
10530     mask = PTR_TO_INT(state->lastdef);
10531     if (visit) stackPush (done, state); else deleteState(state);
10532     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10533     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10534     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10535     visit++;
10536
10537     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10538     if (mask == 0) continue;
10539
10540     /* symbol is (partially) read before redefinition in flow */
10541     if (mask == -1) break;
10542
10543     /* symbol is neither read nor completely redefined -- check successor flows */
10544     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10545       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10546       if (stateIsNew (state, todo, done)) {
10547         stackPush (todo, state);
10548       } else {
10549         deleteState (state);
10550       }
10551     } // for
10552   } // while
10553
10554   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10555   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10556
10557   /* symbol is read in at least one flow -- is alive */
10558   if (mask == -1) return 1;
10559
10560   /* symbol is read in no flow */
10561   return 0;
10562 }
10563
10564 /* Returns whether access to the given symbol has side effects. */
10565 static int pic16_symIsSpecial (symbol_t sym) {
10566   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10567   switch (sym) {
10568   case SPO_INDF0:
10569   case SPO_PLUSW0:
10570   case SPO_POSTINC0:
10571   case SPO_POSTDEC0:
10572   case SPO_PREINC0:
10573   case SPO_INDF1:
10574   case SPO_PLUSW1:
10575   case SPO_POSTINC1:
10576   case SPO_POSTDEC1:
10577   case SPO_PREINC1:
10578   case SPO_INDF2:
10579   case SPO_PLUSW2:
10580   case SPO_POSTINC2:
10581   case SPO_POSTDEC2:
10582   case SPO_PREINC2:
10583   case SPO_PCL:
10584           return 1;
10585   default:
10586           /* no special effects known */
10587           return 0;
10588   } // switch
10589
10590   return 0;
10591 }
10592
10593 /* Check whether a register should be considered local (to the current function) or not. */
10594 static int pic16_regIsLocal (regs *r) {
10595   symbol_t sym;
10596   if (r) {
10597     if (r->type == REG_TMP) return 1;
10598
10599     sym = symFromStr (r->name);
10600     switch (sym) {
10601     case SPO_WREG:
10602     case SPO_FSR0L: // used in ptrget/ptrput
10603     case SPO_FSR0H: // ... as well
10604     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10605     case SPO_FSR1H: // ... as well
10606     case SPO_FSR2L: // used as frame pointer
10607     case SPO_FSR2H: // ... as well
10608     case SPO_PRODL: // used to return values from functions
10609     case SPO_PRODH: // ... as well
10610       /* these registers (and some more...) are considered local */
10611       return 1;
10612       break;
10613     default:
10614       /* for unknown regs: check is marked local, leave if not */
10615       if (r->isLocal) {
10616         return 1;
10617       } else {
10618         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10619         return 0;
10620       }
10621     } // switch
10622   } // if
10623
10624   /* if in doubt, assume non-local... */
10625   return 0;
10626 }
10627
10628 /* Check all symbols touched by pc whether their newly assigned values are read.
10629  * Returns 0 if no symbol is used later on, 1 otherwise. */
10630 static int pic16_pCodeIsAlive (pCode *pc) {
10631   pCodeInstruction *pci;
10632   defmap_t *map, *lastpc;
10633   regs *checkreg;
10634   
10635   /* we can only handle PCIs */
10636   if (!isPCI(pc)) return 1;
10637
10638   //pc->print (stderr, pc);
10639
10640   pci = PCI(pc);
10641   assert (pci && pci->pcflow && pci->pcflow->defmap);
10642
10643   /* NEVER remove instructions with implicit side effects */
10644   switch (pci->op) {
10645   case POC_TBLRD:
10646   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10647   case POC_TBLRD_POSTDEC:
10648   case POC_TBLRD_PREINC:
10649   case POC_TBLWT:               /* modify program memory */
10650   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10651   case POC_TBLWT_POSTDEC:
10652   case POC_TBLWT_PREINC:
10653   case POC_CLRWDT:              /* clear watchdog timer */
10654   case POC_PUSH:                /* should be safe to remove though... */
10655   case POC_POP:                 /* should be safe to remove though... */
10656   case POC_CALL:
10657   case POC_RCALL:
10658   case POC_RETFIE:
10659   case POC_RETURN:
10660     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10661     return 1;
10662
10663   default:
10664     /* no special instruction */
10665     break;
10666   } // switch
10667
10668   /* prevent us from removing assignments to non-local variables */
10669   checkreg = NULL;
10670   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10671   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10672
10673   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10674     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10675     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10676     //pc->print (stderr, pc);
10677     return 1;
10678   }
10679   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10680     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10681     return 1;
10682   }
10683   
10684 #if 1
10685   /* OVERKILL: prevent us from removing reads from non-local variables 
10686    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10687    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10688   checkreg = NULL;
10689   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10690   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10691
10692   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10693     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10694     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10695     //pc->print (stderr, pc);
10696     return 1;
10697   }
10698   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10699     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10700     return 1;
10701   }
10702 #endif
10703   
10704   /* now check that the defined symbols are not used */
10705   map = pci->pcflow->defmap;
10706   
10707   /* find items for pc */
10708   while (map && map->pc != pc) map = map->next;
10709
10710   /* no entries found? something is fishy with DF analysis... -- play safe */
10711   if (!map) {
10712     if (pic16_pcode_verbose) {
10713       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10714     }
10715     return 1;
10716   }
10717
10718   /* remember first item assigned to pc for later use */
10719   lastpc = map;
10720   
10721   /* check all symbols being modified by pc */
10722   while (map && map->pc == pc) {
10723     if (map->sym == 0) { map = map->next; continue; }
10724
10725     /* keep pc if it references special symbols (like POSTDEC0) */
10726 #if 0
10727     {
10728       char buf[256];
10729       pic16_pCode2str (buf, 256, pc);
10730       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10731     }
10732 #endif
10733     if (pic16_symIsSpecial (map->sym)) {
10734       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10735       return 1;
10736     }
10737     if (map->acc.access.isWrite) {
10738       if (pic16_isAlive (map->sym, pc)) {
10739         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10740         return 1;
10741       }
10742     }
10743     map = map->next;
10744   } // while
10745
10746   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10747 #if 0
10748   {
10749     char buf[256];
10750     pic16_pCode2str (buf, 256, pc);
10751     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10752   }
10753 #endif
10754   return 0;
10755 }
10756
10757 /* Adds implied operands to the list.
10758  * sym - operand being accessed in the pCode
10759  * list - list to append the operand
10760  * isRead - set to 1 iff sym is read in pCode
10761  * listRead - set to 1 iff all operands being read are to be listed
10762  *
10763  * Returns 0 for "normal" operands, 1 for special operands.
10764  */
10765 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10766   /* check whether accessing REG accesses other REGs as well */
10767   switch (sym) {
10768   case SPO_INDF0:
10769     /* reads FSR0x */
10770     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10771     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10772     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10773     break;
10774     
10775   case SPO_PLUSW0:
10776     /* reads FSR0x and WREG */
10777     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10778     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10779     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10780     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10781     break;
10782     
10783   case SPO_POSTDEC0:
10784   case SPO_POSTINC0:
10785   case SPO_PREINC0:
10786     /* reads/modifies FSR0x */
10787     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10788     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10789     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10790     break;
10791
10792   case SPO_INDF1:
10793     /* reads FSR1x */
10794     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10795     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10796     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10797     break;
10798     
10799   case SPO_PLUSW1:
10800     /* reads FSR1x and WREG */
10801     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10802     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10803     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10804     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10805     break;
10806     
10807   case SPO_POSTDEC1:
10808   case SPO_POSTINC1:
10809   case SPO_PREINC1:
10810     /* reads/modifies FSR1x */
10811     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10812     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10813     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10814     break;
10815
10816   case SPO_INDF2:
10817     /* reads FSR2x */
10818     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10819     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10820     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10821     break;
10822     
10823   case SPO_PLUSW2:
10824     /* reads FSR2x and WREG */
10825     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10826     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10827     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10828     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10829     break;
10830     
10831   case SPO_POSTDEC2:
10832   case SPO_POSTINC2:
10833   case SPO_PREINC2:
10834     /* reads/modifies FSR2x */
10835     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10836     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10837     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10838     break;
10839
10840   case SPO_PCL:
10841     /* modifies PCLATH and PCLATU */
10842     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10843     if (isRead) {
10844       /* reading PCL updates PCLATx */
10845       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10846       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10847     }
10848     if (isWrite) {
10849       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10850       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10851       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10852     }
10853     break;
10854
10855   default:
10856     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10857     /* nothing special */
10858     return 0;
10859     break;
10860   }
10861
10862   /* has been a special operand */
10863   return 1;
10864 }
10865
10866 static symbol_t pic16_fsrsym_idx[][2] = {
10867     {SPO_FSR0L, SPO_FSR0H},
10868     {SPO_FSR1L, SPO_FSR1H},
10869     {SPO_FSR2L, SPO_FSR2H}
10870 };
10871
10872 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10873 static void mergeDefmapSymbols (defmap_t *list) { 
10874   defmap_t *ref, *curr, *temp;
10875
10876   /* now make sure that each symbol occurs at most once per pc */
10877   ref = list;
10878   while (ref && (ref->pc == list->pc)) {
10879     curr = ref->next;
10880     while (curr && (curr->pc == list->pc)) {
10881       if (curr->sym == ref->sym) {
10882         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10883         /* found a symbol occuring twice... merge the two */
10884         if (curr->acc.access.isRead) {
10885           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10886           ref->acc.access.isRead = 1;
10887           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10888         }
10889         if (curr->acc.access.isWrite) {
10890           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10891           ref->acc.access.isWrite = 1;
10892           ref->acc.access.mask |= curr->acc.access.mask;
10893         }
10894         temp = curr;
10895         curr = curr->next;
10896         deleteDefmap (temp);
10897         continue; // do not skip curr!
10898       } // if
10899       curr = curr->next;
10900     } // while
10901     ref = ref->next;
10902   } // while
10903 }
10904
10905 /** Prepend list with the reads and definitions performed by pc. */
10906 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10907   pCodeInstruction *pci;
10908   int cond, inCond, outCond;
10909   int mask = 0xff, smask;
10910   int isSpecial, isSpecial2;
10911   symbol_t sym, sym2;
10912   char *name;
10913
10914   if (isPCAD(pc)) {
10915     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10916     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10917     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10918     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10919     return list;
10920   }
10921   assert (isPCI(pc));
10922   pci = PCI(pc);
10923   
10924   /* handle bit instructions */
10925   if (pci->isBitInst) {
10926     assert (pci->pcop->type == PO_GPR_BIT);
10927     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10928   }
10929
10930   /* handle (additional) implicit arguments */
10931   switch (pci->op) {
10932   case POC_LFSR:
10933     {
10934       int lit;
10935       valnum_t val;
10936       lit = PCOL(pci->pcop)->lit;
10937       assert (lit >= 0 && lit < 3);
10938       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10939       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10940       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10941       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10942       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...
10943     }
10944     break;
10945
10946   case POC_MOVLB: // BSR
10947   case POC_BANKSEL: // BSR
10948     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10949     break;
10950
10951   case POC_MULWF: // PRODx
10952   case POC_MULLW: // PRODx
10953     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10954     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10955     break;
10956
10957   case POC_POP: // TOS, STKPTR
10958     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10959     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10960     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10961     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10962     break;
10963     
10964   case POC_PUSH: // STKPTR
10965     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10966     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10967     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10968     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10969     break;
10970     
10971   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10972   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10973     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10974     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10975     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10976     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10977
10978     /* needs correctly set-up stack pointer */
10979     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10980     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10981     break;
10982
10983   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10984     /* pseudo read on (possible) return values */
10985     // WREG is handled below via outCond
10986     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10987     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10988     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10989
10990     /* caller's stack pointers must be restored */
10991     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10992     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10993     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10994     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10995     break;
10996
10997   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10998   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10999     /* pseudo read on (possible) return values */
11000     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
11001     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11002     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11003     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11004
11005     /* caller's stack pointers must be restored */
11006     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11007     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11008     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11009     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11010     break;
11011     
11012   case POC_TBLRD:
11013     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11014     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11015     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11016     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11017     break;
11018     
11019   case POC_TBLRD_POSTINC:
11020   case POC_TBLRD_POSTDEC:
11021   case POC_TBLRD_PREINC:
11022     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11023     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11024     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11025     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11026     break;
11027     
11028   case POC_TBLWT:
11029     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11030     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11031     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11032     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11033     break;
11034     
11035   case POC_TBLWT_POSTINC:
11036   case POC_TBLWT_POSTDEC:
11037   case POC_TBLWT_PREINC:
11038     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11039     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11040     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11041     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11042     break;
11043     
11044   default:
11045     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11046     break;
11047   } // switch
11048
11049   /* handle explicit arguments */
11050   inCond = pci->inCond;
11051   outCond = pci->outCond;
11052   cond = inCond | outCond;
11053   if (cond & PCC_W) {
11054     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11055   } // if
11056
11057   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11058   if (inCond & PCC_STATUS) {
11059     smask = 0;
11060     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11061     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11062     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11063     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11064     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11065
11066     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11067     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11068   } // if
11069   
11070   if (outCond & PCC_STATUS) {
11071     smask = 0;
11072     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11073     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11074     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11075     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11076     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11077
11078     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11079     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11080   } // if
11081   
11082   isSpecial = isSpecial2 = 0;
11083   sym = sym2 = 0;
11084   if (cond & PCC_REGISTER) {
11085     name = pic16_get_op (pci->pcop, NULL, 0);
11086     sym = symFromStr (name);
11087     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11088     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11089   }
11090
11091   if (cond & PCC_REGISTER2) {
11092     name = pic16_get_op2 (pci->pcop, NULL, 0);
11093     sym2 = symFromStr (name);
11094     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11095     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11096   }
11097
11098  
11099   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11100   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11101
11102   mergeDefmapSymbols (list);
11103   
11104   return list;
11105 }
11106
11107 #if 0
11108 static void printDefmap (defmap_t *map) {
11109   defmap_t *curr;
11110
11111   curr = map;
11112   fprintf (stderr, "defmap @ %p:\n", curr);
11113   while (curr) {
11114     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11115                     curr->acc.access.isRead ? "R" : " ",
11116                     curr->acc.access.isWrite ? "W": " ",
11117                     curr->in_val, curr->val,
11118                     curr->acc.access.in_mask, curr->acc.access.mask,
11119                     strFromSym(curr->sym), curr->sym,
11120                     curr->pc);
11121     curr = curr->next;
11122   } // while
11123   fprintf (stderr, "<EOL>\n");
11124 }
11125 #endif
11126
11127 /* Add "additional" definitions to uniq.
11128  * 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.
11129  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11130  *
11131  * If symbols defined in additional are not present in uniq, a definition is created.
11132  * Otherwise the present definition is altered to reflect the newer assignments.
11133  *
11134  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11135  *       before     `------- noted in additional --------'      after
11136  *
11137  * I assume that each symbol occurs AT MOST ONCE in uniq.
11138  *
11139  */
11140 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11141   defmap_t *curr;
11142   defmap_t *old;
11143   int change = 0;
11144
11145   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11146   /* find tail of additional list (holds the first assignment) */
11147   curr = additional;
11148   while (curr && curr->next) curr = curr->next;
11149
11150   /* update uniq */
11151   do {
11152     /* find next assignment in additionals */
11153     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11154
11155     if (!curr) break;
11156
11157     /* find item in uniq */
11158     old = *uniq;
11159     //printDefmap (*uniq);
11160     while (old && (old->sym != curr->sym)) old = old->next;
11161
11162     if (old) {
11163       /* definition found -- replace */
11164       if (old->val != curr->val) {
11165         old->val = curr->val;
11166         change++;
11167       } // if
11168     } else {
11169       /* new definition */
11170       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11171       change++;
11172     }
11173
11174     curr = curr->prev;
11175   } while (1);
11176
11177   /* return 0 iff uniq remained unchanged */
11178   return change;
11179 }
11180
11181 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11182  * lists of its predecessor flows. 
11183  * Initially *combined should be NULL, alt_in will be copied to combined.
11184  * If *combined != NULL, combined will be altered:
11185  * - for symbols defined in *combined but not in alt_in,
11186  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11187  * - for symbols defined in alt_in but not in *combined,
11188  *   a 0 definition is created (value unknown, either INIT or alt).
11189  * - for symbols defined in both, *combined is:
11190  *   > left unchanged if *combined->val == alt_in->val or
11191  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11192  * 
11193  * I assume that each symbol occurs AT MOST ONCE in each list!
11194  */
11195 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11196   defmap_t *curr;
11197   defmap_t *old;
11198   int change = 0;
11199   valnum_t val;
11200
11201   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11202   
11203   if (!(*combined)) {
11204     return defmapUpdateUniqueSym (combined, alt_in);
11205   } // if
11206   
11207   /* merge the two */
11208   curr = alt_in;
11209   while (curr) {
11210     /* find symbols definition in *combined */
11211     old = *combined;
11212     while (old && (old->sym != curr->sym)) old = old->next;
11213
11214     if (old) {
11215       /* definition found */
11216       if (old->val && (old->val != curr->val)) {
11217         old->val = 0; /* value unknown */
11218         change++;
11219       }
11220     } else {
11221       /* no definition found -- can be either INIT or alt_in's value */
11222       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11223       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11224       if (val != curr->val) change++;
11225     }
11226
11227     curr = curr->next;
11228   } // while (curr)
11229
11230   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11231   old = *combined;
11232   while (old) {
11233     if (old->val != 0) {
11234       /* find definition in alt_in */
11235       curr = alt_in;
11236       while (curr && curr->sym != old->sym) curr = curr->next;
11237       if (!curr) {
11238         /* symbol defined in *combined only -- can be either INIT or *combined */
11239         val = pic16_pBlockAddInval (pb, old->sym)->val;
11240         if (old->val != val) {
11241           old->val = 0;
11242           change++;
11243         }
11244       } // if
11245     } // if
11246
11247     old = old->next;
11248   } // while
11249
11250   return change;
11251 }
11252
11253 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11254   defmap_t *curr1, *curr2;
11255   symbol_t sym;
11256   
11257   /* identical maps are equal */
11258   if (map1 == map2) return 0;
11259
11260   if (!map1) return -1;
11261   if (!map2) return 1;
11262
11263   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11264   
11265   /* check length */
11266   curr1 = map1;
11267   curr2 = map2;
11268   while (curr1 && curr2) {
11269     curr1 = curr1->next;
11270     curr2 = curr2->next;
11271   } // while
11272
11273   /* one of them longer? */
11274   if (curr1) return 1;
11275   if (curr2) return -1;
11276
11277   /* both lists are of equal length -- compare (in O(n^2)) */
11278   curr1 = map1;
11279   while (curr1) {
11280     sym = curr1->sym;
11281     curr2 = map2;
11282     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11283     if (!curr2) return 1; // symbol not found in curr2
11284     if (curr2->val != curr1->val) return 1; // values differ
11285
11286     /* compare next symbol */
11287     curr1 = curr1->next;
11288   } // while
11289
11290   /* no difference found */
11291   return 0;
11292 }
11293
11294
11295 /* Prepare a list of all reaching definitions per flow.
11296  * This is done using a forward dataflow analysis.
11297  */
11298 static void createReachingDefinitions (pBlock *pb) {
11299   defmap_t *out_vals, *in_vals;
11300   pCode *pc;
11301   pCodeFlow *pcfl;
11302   pCodeFlowLink *link;
11303   set *todo;
11304   set *blacklist;
11305
11306   if (!pb) return;
11307
11308   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11309   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11310     if (isPCFL(pc)) {
11311       deleteDefmapChain (&PCFL(pc)->in_vals);
11312       deleteDefmapChain (&PCFL(pc)->out_vals);
11313       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11314     } // if
11315   } // for
11316   
11317   pc = pic16_findNextInstruction (pb->pcHead);
11318   todo = NULL; blacklist = NULL;
11319   addSetHead (&todo, PCI(pc)->pcflow);
11320
11321   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11322   while (elementsInSet (todo)) {
11323     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11324     pcfl = PCFL(indexSet (todo, 0));
11325     deleteSetItem (&todo, pcfl);
11326     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11327     in_vals = NULL;
11328     out_vals = NULL;
11329
11330     if (isinSet (blacklist, pcfl)) {
11331             fprintf (stderr, "ignoring blacklisted flow\n");
11332       continue;
11333     }
11334     
11335     /* create in_vals from predecessors out_vals */
11336     link = setFirstItem (pcfl->from);
11337     while (link) {
11338       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11339       link = setNextItem (pcfl->from);
11340     } // while
11341
11342     //printDefmap (in_vals); 
11343     //printDefmap (pcfl->in_vals); 
11344
11345     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11346       //fprintf (stderr, "in_vals changed\n");
11347       /* in_vals changed -- update out_vals */
11348       deleteDefmapChain (&pcfl->in_vals);
11349       pcfl->in_vals = in_vals;
11350
11351       /* create out_val from in_val and defmap */
11352       out_vals = NULL;
11353       defmapUpdateUniqueSym (&out_vals, in_vals);
11354       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11355
11356       /* is out_vals different from pcfl->out_vals */
11357       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11358         //fprintf (stderr, "out_vals changed\n");
11359         deleteDefmapChain (&pcfl->out_vals);
11360         pcfl->out_vals = out_vals;
11361
11362         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11363           addSet (&blacklist, pcfl);
11364         } // if
11365         
11366         /* reschedule all successors */
11367         link = setFirstItem (pcfl->to);
11368         while (link) {
11369           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11370           addSetIfnotP (&todo, link->pcflow);
11371           link = setNextItem (pcfl->to);
11372         } // while
11373       } else {
11374         deleteDefmapChain (&out_vals);        
11375       }// if
11376     } else {
11377       deleteDefmapChain (&in_vals);         
11378     } // if
11379   } // while
11380 }
11381
11382 #if 0
11383 static void showAllDefs (symbol_t sym, pCode *pc) {
11384   defmap_t *map;
11385   int count;
11386
11387   assert (isPCI(pc));
11388   count = defmapFindAll (sym, pc, &map);
11389
11390   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11391   while (map) {
11392 #if 1
11393     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11394 #else
11395     { char buf[256];
11396     pic16_pCode2str (buf, 256, map->pc);
11397     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11398 #endif
11399     map = map->next;
11400   }
11401   deleteDefmapChain (&map);
11402 }
11403 #endif
11404
11405 /* safepCodeUnlink and remove pc from defmap. */
11406 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11407   defmap_t *map, *next, **head;
11408   int res, ispci;
11409   
11410   ispci = isPCI(pc);
11411   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11412   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11413   res = pic16_safepCodeUnlink (pc, comment);
11414
11415   if (res && map) {
11416     /* remove pc from defmap */
11417     while (map) {
11418       next = map->next;
11419       if (map->pc == pc) {
11420         if (!map->prev && head) *head = map->next;
11421         deleteDefmap (map);
11422       } // if
11423       map = next;
11424     }
11425   }
11426
11427   return res;
11428 }
11429       
11430 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11431   defmap_t *map;
11432   /* This breaks the defmap chain's references to pCodes... fix it! */
11433   map = PCI(pc)->pcflow->defmap;
11434
11435   while (map && map->pc != pc) map = map->next;
11436   
11437   while (map && map->pc == pc) {
11438     map->pc = newpc;
11439     map = map->next;
11440   } // while
11441 }
11442
11443 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11444  * write accesses (isRead == 0). */
11445 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11446   defmap_t *map, *map_start;
11447   defmap_t *copy;
11448   if (!isPCI(pc)) return;
11449   if (sym == newsym) return;
11450   
11451   map = PCI(pc)->pcflow->defmap;
11452
11453   while (map && map->pc != pc) map = map->next;
11454   map_start = map;
11455   while (map && map->pc == pc) {
11456     if (map->sym == sym) {
11457       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11458       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11459         /* only one kind of access handled... this is easy */
11460         map->sym = newsym;
11461       } else {
11462         /* must copy defmap entry before replacing symbol... */
11463         copy = copyDefmap (map);
11464         if (isRead) {
11465           map->acc.access.isRead = 0;
11466           copy->acc.access.isWrite = 0;
11467         } else {
11468           map->acc.access.isWrite = 0;
11469           copy->acc.access.isRead = 0;
11470         }
11471         copy->sym = newsym;
11472         /* insert copy into defmap chain */
11473         defmapInsertAfter (map, copy);
11474       }
11475     }
11476     map = map->next;
11477   } // while
11478
11479   /* as this might introduce multiple defmap entries for newsym... */
11480   mergeDefmapSymbols (map_start);
11481 }
11482
11483 /* Assign "better" valnums to results. */
11484 static void assignValnums (pCode *pc) {
11485   pCodeInstruction *pci;
11486   pCode *newpc;
11487   symbol_t sym1, sym2;
11488   int cond, isSpecial1, isSpecial2, count, mask, lit;
11489   defmap_t *list, *val, *oldval, *dummy;
11490   regs *reg1 = NULL, *reg2 = NULL;
11491   valnum_t litnum;
11492
11493   /* only works for pCodeInstructions... */
11494   if (!isPCI(pc)) return;
11495
11496   pci = PCI(pc);
11497   cond = pci->inCond | pci->outCond;
11498   list = pci->pcflow->defmap;
11499   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11500
11501   if (cond & PCC_REGISTER) {
11502     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11503     reg1 = pic16_getRegFromInstruction (pc);
11504     isSpecial1 = pic16_symIsSpecial (sym1);
11505   }
11506   if (cond & PCC_REGISTER2) {
11507     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11508     reg2 = pic16_getRegFromInstruction (pc);
11509     isSpecial2 = pic16_symIsSpecial (sym2);
11510   }
11511
11512   /* determine input values */
11513   val = list;
11514   while (val && val->pc != pc) val = val->next;
11515   //list = val; /* might save some time later... */
11516   while (val && val->pc == pc) {
11517     val->in_val = 0;
11518     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11519       /* get valnum for sym */
11520       count = defmapFindAll (val->sym, pc, &oldval);
11521       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11522       if (count == 1) {
11523         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11524           val->in_val = oldval->val;
11525         } else {
11526           val->in_val = 0;
11527         }
11528       } else if (count == 0) {
11529         /* no definition found */
11530         val->in_val = 0;
11531       } else {
11532         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11533         assert (oldval);
11534         dummy = oldval->next;
11535         mask = oldval->acc.access.mask;
11536         val->in_val = oldval->val;
11537         while (dummy && (dummy->val == val->in_val)) {
11538           mask &= dummy->acc.access.mask;
11539           dummy = dummy->next;
11540         } // while
11541
11542         /* found other values or to restictive mask */
11543         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11544           val->in_val = 0;
11545         }
11546       }
11547       if (count > 0) deleteDefmapChain (&oldval);
11548     } // if
11549     val = val->next;
11550   }
11551
11552   /* handle valnum assignment */
11553   switch (pci->op) {
11554   case POC_CLRF: /* modifies STATUS (Z) */
11555     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11556       oldval = defmapCurr (list, sym1, pc);
11557       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11558         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11559         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11560       }
11561       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11562     }
11563     break;
11564
11565   case POC_SETF: /* SETF does not touch STATUS */
11566     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11567       oldval = defmapCurr (list, sym1, pc);
11568       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11569         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11570         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11571       }
11572       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11573     }
11574     break;
11575     
11576   case POC_MOVLW: /* does not touch STATUS */
11577     oldval = defmapCurr (list, SPO_WREG, pc);
11578     if (pci->pcop->type == PO_LITERAL) {
11579       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11580       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11581     } else {
11582       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11583       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11584     }
11585     if (oldval && oldval->in_val == litnum) {
11586       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11587       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11588     }
11589     defmapUpdate (list, SPO_WREG, pc, litnum);
11590     break;
11591
11592   case POC_ANDLW: /* modifies STATUS (Z,N) */
11593   case POC_IORLW: /* modifies STATUS (Z,N) */
11594   case POC_XORLW: /* modifies STATUS (Z,N) */
11595     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11596     if (pci->pcop->type == PO_LITERAL) {
11597       int vallit = -1;
11598       lit = (unsigned char) PCOL(pci->pcop)->lit;
11599       val = defmapCurr (list, SPO_WREG, pc);
11600       if (val) vallit = litFromValnum (val->in_val);
11601       if (vallit != -1) {
11602         /* xxxLW <literal>, WREG contains a known literal */
11603         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11604         if (pci->op == POC_ANDLW) {
11605           lit &= vallit;
11606         } else if (pci->op == POC_IORLW) {
11607           lit |= vallit;
11608         } else if (pci->op == POC_XORLW) {
11609           lit ^= vallit;
11610         } else {
11611           assert (0 && "invalid operation");
11612         }
11613         if (vallit == lit) {
11614           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11615           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11616         }
11617         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11618       } // if
11619     }
11620     break;
11621
11622   case POC_LFSR:
11623     {
11624       /* check if old value matches new value */
11625       int lit;
11626       int ok = 1;
11627       assert (pci->pcop->type == PO_LITERAL);
11628       
11629       lit = PCOL(pci->pcop)->lit;
11630       
11631       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11632       
11633       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11634         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11635       } else {
11636         /* cannot remove this LFSR */
11637         ok = 0;      
11638       } // if
11639       
11640       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11641       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11642         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11643       } else {
11644         ok = 0;
11645       } // if
11646
11647       if (ok) {
11648         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11649       }
11650     }
11651     break;
11652     
11653   case POC_MOVWF: /* does not touch flags */
11654     /* find value of WREG */
11655     val = defmapCurr (list, SPO_WREG, pc);
11656     oldval = defmapCurr (list, sym1, pc);
11657     if (val) lit = litFromValnum (val->in_val);
11658     else lit = -1;
11659     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11660     
11661     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11662       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11663       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11664       if (lit == 0) {
11665         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11666       } else {
11667         assert (lit == 0x0ff);
11668         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11669       }
11670       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11671       pic16_pCodeReplace (pc, newpc);
11672       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11673       pic16_fixDefmap (pc, newpc);
11674       pc = newpc;
11675         
11676       /* This breaks the defmap chain's references to pCodes... fix it! */
11677       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11678       if (!val->acc.access.isWrite) {
11679         deleteDefmap (val);     // delete reference to WREG as in value
11680         val = NULL;
11681       } else {
11682         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11683       }
11684       oldval = PCI(pc)->pcflow->defmap;
11685       while (oldval) {
11686         if (oldval->pc == pc) oldval->pc = newpc;
11687           oldval = oldval->next;
11688       } // while
11689     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11690       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11691       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11692     }
11693     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11694     break;
11695     
11696   case POC_MOVFW: /* modifies STATUS (Z,N) */
11697     /* find value of REG */
11698     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11699       val = defmapCurr (list, sym1, pc);
11700       oldval = defmapCurr (list, SPO_WREG, pc);
11701       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11702         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11703         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11704       }
11705       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11706     }
11707     break;
11708
11709   case POC_MOVFF: /* does not touch STATUS */
11710     /* find value of REG */
11711     val = defmapCurr (list, sym1, pc);
11712     oldval = defmapCurr (list, sym2, pc);
11713     if (val) lit = litFromValnum (val->in_val);
11714     else lit = -1;
11715     newpc = NULL;
11716     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11717       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11718       if (lit == 0) {
11719         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11720       } else if (lit == 0x00ff) {
11721         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11722       } else {
11723         newpc = NULL;
11724       }
11725       if (newpc) {
11726         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11727         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11728         pic16_pCodeReplace (pc, newpc); 
11729         defmapReplaceSymRef (pc, sym1, 0, 1);
11730         pic16_fixDefmap (pc, newpc);
11731         pc = newpc;
11732         break; // do not process instruction as MOVFF...
11733       }
11734     } else if (!isSpecial1 && !isSpecial2
11735                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11736                 && val && oldval && (val->in_val != 0)) {
11737       if (val->in_val == oldval->in_val) {
11738         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11739         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11740       } else {
11741         if (!pic16_isAlive (sym1, pc)) {
11742           defmap_t *copy = NULL;
11743           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11744            * This should help eliminate
11745            *   MOVFF A,B
11746            *   <do something not changing A or using B>
11747            *   MOVFF B,C
11748            *   <B is not alive anymore>
11749            * and turn it into
11750            *   <do something not changing A or using B>
11751            *   MOVFF A,C
11752            */
11753
11754           /* scan defmap for symbols storing sym1's value */
11755           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11756           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11757             /* unique reaching definition for sym found */
11758             if (copy->val && copy->val == val->in_val) {
11759               //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);
11760               if (copy->sym == SPO_WREG) {
11761                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11762               } else {
11763                 pCodeOp *pcop = NULL;
11764                 /* the code below fails if we try to replace
11765                  *   MOVFF PRODL, r0x03
11766                  *   MOVFF r0x03, PCLATU
11767                  * with
11768                  *   MOVFF PRODL, PCLATU
11769                  * as copy(PRODL) contains has pc==NULL, by name fails...
11770                  */
11771                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11772                 
11773                 if (copy->pc && PCI(copy->pc)->pcop)
11774                   pcop = PCI(copy->pc)->pcop;
11775 #if 0
11776                 /* This code is broken--see above. */
11777                 else
11778                 {
11779                   const char *symname = strFromSym(copy->sym);
11780                   
11781                   assert( symname );
11782                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11783                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11784                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11785                 }
11786 #endif
11787                 assert( pcop );
11788                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11789                         pcop,
11790                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11791               }
11792               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11793               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11794               pic16_pCodeReplace (pc, newpc); 
11795               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11796               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11797               pic16_fixDefmap (pc, newpc);
11798               pc = newpc;
11799             }
11800           }
11801           deleteDefmapChain (&copy);
11802         }
11803       }
11804       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11805     }
11806     break;
11807
11808   default:
11809     /* cannot optimize */
11810     break;
11811   } // switch
11812 }
11813
11814 static void pic16_destructDF (pBlock *pb) {
11815   pCode *pc, *next;
11816
11817   if (!pb) return;
11818
11819   /* remove old defmaps */
11820   pc = pic16_findNextInstruction (pb->pcHead);
11821   while (pc) {
11822     next = pic16_findNextInstruction (pc->next);
11823
11824     assert (isPCI(pc) || isPCAD(pc));
11825     assert (PCI(pc)->pcflow);
11826     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11827     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11828     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11829     
11830     pc = next;
11831   } // while
11832   
11833   if (defmap_free || defmap_free_count) {
11834     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11835     freeDefmap (&defmap_free);
11836     defmap_free_count = 0;
11837   }
11838 }
11839
11840 /* Checks whether a pBlock contains ASMDIRs. */
11841 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11842   pCode *pc;
11843
11844   if (!pb) return 0;
11845
11846   pc = pic16_findNextInstruction (pb->pcHead);
11847   while (pc) {
11848     if (isPCAD(pc)) return 1;
11849
11850     pc = pic16_findNextInstruction (pc->next);
11851   } // while
11852
11853   /* no PCADs found */
11854   return 0;
11855 }
11856
11857 #if 1
11858 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11859 static int pic16_removeUnusedRegistersDF () {
11860   pCode *pc, *pc2;
11861   pBlock *pb;
11862   regs *reg1, *reg2, *reg3;
11863   set *seenRegs = NULL;
11864   int cond, i;
11865   int islocal, change = 0;
11866
11867   /* no pBlocks? */
11868   if (!the_pFile || !the_pFile->pbHead) return 0;
11869   
11870   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11871     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11872 #if 1
11873     /* find set of using pCodes per register */
11874     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11875                     pc = pic16_findNextInstruction(pc->next)) {
11876
11877       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11878       reg1 = reg2 = NULL;
11879       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11880       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11881
11882       if (reg1) {
11883         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11884         addSetIfnotP (&seenRegs, reg1);
11885         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11886       }
11887       if (reg2) {
11888         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11889         addSetIfnotP (&seenRegs, reg2);
11890         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11891       }
11892     } // for pc
11893 #endif
11894     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11895       /* may not use pic16_regIsLocal() here -- in interrupt routines
11896        * WREG, PRODx, FSR0x must be saved */
11897       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11898       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11899         pc = pc2 = NULL;
11900         for (i=0; i < 2; i++) {
11901           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11902           if (!pc2) pc2 = pc;
11903           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11904           reg2 = pic16_getRegFromInstruction (pc);
11905           reg3 = pic16_getRegFromInstruction2 (pc);
11906           if (!reg2 || !reg3
11907               || (reg2->rIdx != pic16_stack_preinc->rIdx
11908                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11909           if (i == 1) {
11910             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11911             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11912             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11913             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11914           }
11915         } // for
11916       } // if
11917       deleteSet (&reg1->reglives.usedpCodes);
11918     } // for reg1
11919
11920     deleteSet (&seenRegs);
11921   } // for pb
11922
11923   return change;
11924 }
11925 #endif
11926
11927 /* Set up pCodeFlow's defmap_ts. 
11928  * Needs correctly set up to/from fields. */
11929 static void pic16_createDF (pBlock *pb) {
11930   pCode *pc, *next;
11931   int change=0;
11932
11933   if (!pb) return;
11934
11935   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11936
11937   pic16_destructDF (pb);
11938
11939   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11940   if (pic16_pBlockHasAsmdirs (pb)) {
11941     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11942     return;
11943   }
11944
11945   /* integrity check -- we need to reach all flows to guarantee
11946    * correct data flow analysis (reaching definitions, aliveness) */
11947 #if 0
11948   if (!verifyAllFlowsReachable (pb)) {
11949     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11950     return;
11951   }
11952 #endif
11953   
11954   /* establish new defmaps */
11955   pc = pic16_findNextInstruction (pb->pcHead);
11956   while (pc) {
11957     next = pic16_findNextInstruction (pc->next);
11958
11959     assert (PCI(pc)->pcflow);
11960     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11961
11962     pc = next;
11963   } // while
11964
11965   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11966   createReachingDefinitions (pb);
11967   
11968 #if 1
11969   /* assign better valnums */
11970   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11971   pc = pic16_findNextInstruction (pb->pcHead);
11972   while (pc) {
11973     next = pic16_findNextInstruction (pc->next);
11974
11975     assert (PCI(pc)->pcflow);
11976     assignValnums (pc);
11977
11978     pc = next;
11979   } // while
11980 #endif
11981
11982 #if 1
11983   /* remove dead pCodes */
11984   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11985   do {
11986     change = 0;
11987     pc = pic16_findNextInstruction (pb->pcHead);
11988     while (pc) {
11989       next = pic16_findNextInstruction (pc->next);
11990
11991       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11992         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11993       }
11994
11995       pc = next;
11996     } // while
11997   } while (change);
11998 #endif
11999 }
12000
12001 /* ======================================================================== */
12002 /* === VCG DUMPER ROUTINES ================================================ */
12003 /* ======================================================================== */
12004 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12005 hTab *dumpedNodes = NULL;
12006
12007 /** Dump VCG header into of. */
12008 static void pic16_vcg_init (FILE *of) {
12009   /* graph defaults */
12010   fprintf (of, "graph:{\n");
12011   fprintf (of, "title:\"graph1\"\n");
12012   fprintf (of, "label:\"graph1\"\n");
12013   fprintf (of, "color:white\n");
12014   fprintf (of, "textcolor:black\n");
12015   fprintf (of, "bordercolor:black\n");
12016   fprintf (of, "borderwidth:1\n");
12017   fprintf (of, "textmode:center\n");
12018
12019   fprintf (of, "layoutalgorithm:dfs\n");
12020   fprintf (of, "late_edge_labels:yes\n");
12021   fprintf (of, "display_edge_labels:yes\n");
12022   fprintf (of, "dirty_edge_labels:yes\n");
12023   fprintf (of, "finetuning:yes\n");
12024   fprintf (of, "ignoresingles:no\n");
12025   fprintf (of, "straight_phase:yes\n");
12026   fprintf (of, "priority_phase:yes\n");
12027   fprintf (of, "manhattan_edges:yes\n");
12028   fprintf (of, "smanhattan_edges:no\n");
12029   fprintf (of, "nearedges:no\n");
12030   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12031   fprintf (of, "port_sharing:no\n");
12032   fprintf (of, "arrowmode:free\n"); // fixed|free
12033   fprintf (of, "crossingphase2:yes\n");
12034   fprintf (of, "crossingoptimization:yes\n");
12035   fprintf (of, "edges:yes\n");
12036   fprintf (of, "nodes:yes\n");
12037   fprintf (of, "splines:no\n");
12038   
12039   /* node defaults */
12040   fprintf (of, "node.color:lightyellow\n");
12041   fprintf (of, "node.textcolor:black\n");
12042   fprintf (of, "node.textmode:center\n");
12043   fprintf (of, "node.shape:box\n");
12044   fprintf (of, "node.bordercolor:black\n");
12045   fprintf (of, "node.borderwidth:1\n");
12046
12047   /* edge defaults */
12048   fprintf (of, "edge.textcolor:black\n");
12049   fprintf (of, "edge.color:black\n");
12050   fprintf (of, "edge.thickness:1\n");
12051   fprintf (of, "edge.arrowcolor:black\n");
12052   fprintf (of, "edge.backarrowcolor:black\n");
12053   fprintf (of, "edge.arrowsize:15\n");
12054   fprintf (of, "edge.backarrowsize:15\n");
12055   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12056   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12057   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12058   
12059   fprintf (of, "\n");
12060
12061   /* prepare data structures */
12062   if (dumpedNodes) {
12063     hTabDeleteAll (dumpedNodes);
12064     dumpedNodes = NULL;
12065   }
12066   dumpedNodes = newHashTable (128);
12067 }
12068
12069 /** Dump VCG footer into of. */
12070 static void pic16_vcg_close (FILE *of) {
12071   fprintf (of, "}\n");
12072 }
12073
12074 #define BUF_SIZE 128
12075 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12076
12077 #if 0
12078 static int ptrcmp (const void *p1, const void *p2) {
12079   return p1 == p2;
12080 }
12081 #endif
12082
12083 /** Dump a pCode node as VCG to of. */
12084 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12085   char buf[BUF_SIZE];
12086
12087   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12088     // dumped already
12089     return;
12090   }
12091   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12092   //fprintf (stderr, "dumping %p\n", pc);
12093  
12094   /* only dump pCodeInstructions and Flow nodes */
12095   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12096     
12097   /* emit node */
12098   fprintf (of, "node:{");
12099   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12100   fprintf (of, "label:\"%s\n", pcTitle(pc));
12101   if (isPCFL(pc)) {
12102     fprintf (of, "<PCFLOW>");
12103   } else if (isPCI(pc) || isPCAD(pc)) {
12104     pc->print (of, pc);
12105   } else {
12106     fprintf (of, "<!PCI>");
12107   }
12108   fprintf (of, "\" ");
12109   fprintf (of, "}\n");
12110   
12111   if (1 && isPCFL(pc)) {
12112     defmap_t *map, *prev;
12113     unsigned int i;
12114     map = PCFL(pc)->defmap;
12115     i=0;
12116     while (map) {
12117       if (map->sym != 0) {
12118         i++;
12119       
12120         /* emit definition node */
12121         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12122         fprintf (of, "label:\"");
12123
12124         prev = map;
12125         do {
12126           fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->acc.access.isRead ? 'R' : ' ', map->acc.access.isWrite ? 'W' : ' ', map->in_val, map->val, map->acc.access.in_mask, map->acc.access.mask, strFromSym (map->sym));
12127           prev = map;
12128           map = map->next;
12129         } while (map && prev->pc == map->pc);
12130         map = prev;
12131         
12132         fprintf (of, "\" ");
12133       
12134         fprintf (of, "color:green ");
12135         fprintf (of, "}\n");
12136
12137         /* emit edge to previous definition */
12138         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12139         if (i == 1) {
12140           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12141         } else {
12142           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12143         }
12144         fprintf (of, "color:green ");
12145         fprintf (of, "}\n");
12146
12147         if (map->pc) {
12148           pic16_vcg_dumpnode (map->pc, of);
12149           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12150           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12151         }
12152       }
12153       map = map->next;
12154     } // while
12155   }
12156
12157   /* emit additional nodes (e.g. operands) */
12158 }
12159
12160 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12161 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12162   char buf[BUF_SIZE];
12163   pCodeInstruction *pci;
12164   pBranch *curr;
12165   int i;
12166   
12167   if (1 && isPCFL(pc)) {
12168     /* emit edges to flow successors */
12169     void *pcfl;
12170     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12171     pcfl = setFirstItem (PCFL(pc)->to);
12172     while (pcfl) {
12173       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12174       pic16_vcg_dumpnode (pc, of);
12175       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12176       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12177       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12178       pcfl = setNextItem (PCFL(pc)->to);
12179     } // while
12180   } // if
12181   
12182   if (!isPCI(pc) && !isPCAD(pc)) return;
12183
12184   pci = PCI(pc);
12185   
12186   /* emit control flow edges (forward only) */
12187   curr = pci->to;
12188   i=0;
12189   while (curr) {
12190     pic16_vcg_dumpnode (curr->pc, of);
12191     fprintf (of, "edge:{");
12192     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12193     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12194     fprintf (of, "color:red ");
12195     fprintf (of, "}\n");
12196     curr = curr->next;
12197   } // while
12198
12199 #if 1
12200   /* dump "flow" edge (link pCode according to pBlock order) */
12201   {
12202     pCode *pcnext;
12203     pcnext = pic16_findNextInstruction (pc->next);
12204     if (pcnext) {
12205       pic16_vcg_dumpnode (pcnext, of);
12206       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12207       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12208     }
12209   }
12210 #endif
12211   
12212 #if 0
12213   /* emit flow */
12214   if (pci->pcflow) {
12215     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12216     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12217     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12218   }
12219 #endif
12220   
12221   /* emit data flow edges (backward only) */
12222   /* TODO: gather data flow information... */
12223 }
12224
12225 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12226   pCode *pc;
12227
12228   if (!pb) return;
12229
12230   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12231   if (pic16_pBlockHasAsmdirs (pb)) {
12232     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12233     return;
12234   }
12235
12236   for (pc=pb->pcHead; pc; pc = pc->next) {
12237     pic16_vcg_dumpnode (pc, of);
12238   } // for pc
12239   
12240   for (pc=pb->pcHead; pc; pc = pc->next) {
12241     pic16_vcg_dumpedges (pc, of);
12242   } // for pc
12243 }
12244
12245 static void pic16_vcg_dump_default (pBlock *pb) {
12246   FILE *of;
12247   char buf[BUF_SIZE];
12248   pCode *pc;
12249
12250   if (!pb) return;
12251
12252   /* get function name */
12253   pc = pb->pcHead;
12254   while (pc && !isPCF(pc)) pc = pc->next;
12255   if (pc) {
12256     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12257   } else {
12258     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12259   }
12260
12261   //fprintf (stderr, "now dumping %s\n", buf);
12262   of = fopen (buf, "w");
12263   pic16_vcg_init (of);
12264   pic16_vcg_dump (of, pb);
12265   pic16_vcg_close (of);
12266   fclose (of);
12267 }
12268 #endif
12269
12270 /*** END of helpers for pCode dataflow optimizations ***/