* src\pic16\device.c, src\pic16\glue.c, src\pic16\pcode.c:
[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 void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
160 extern int mnem2key(unsigned char const *mnem);
161
162 /****************************************************************/
163 /*                      Forward declarations                    */
164 /****************************************************************/
165
166 void pic16_unlinkpCode(pCode *pc);
167 #if 0
168 static void genericAnalyze(pCode *pc);
169 static void AnalyzeGOTO(pCode *pc);
170 static void AnalyzeSKIP(pCode *pc);
171 static void AnalyzeRETURN(pCode *pc);
172 #endif
173
174 static void genericDestruct(pCode *pc);
175 static void genericPrint(FILE *of,pCode *pc);
176
177 static void pCodePrintLabel(FILE *of, pCode *pc);
178 static void pCodePrintFunction(FILE *of, pCode *pc);
179 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
180 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
181 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
182 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
183 int pic16_pCodePeepMatchRule(pCode *pc);
184 static void pBlockStats(FILE *of, pBlock *pb);
185 static pBlock *newpBlock(void);
186 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
187 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
188 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
189 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
190 void OptimizeLocalRegs(void);
191 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
192
193 char *dumpPicOptype(PIC_OPTYPE type);
194
195 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
196 pCodeOp *pic16_popGetLit(int);
197 pCodeOp *pic16_popGetWithString(char *);
198 extern int inWparamList(char *s);
199
200 /** data flow optimization helpers **/
201 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
202 static void pic16_vcg_dump (FILE *of, pBlock *pb);
203 static void pic16_vcg_dump_default (pBlock *pb);
204 #endif
205 static int pic16_pCodeIsAlive (pCode *pc);
206 static void pic16_df_stats ();
207 static void pic16_createDF (pBlock *pb);
208 static int pic16_removeUnusedRegistersDF ();
209 static void pic16_destructDF (pBlock *pb);
210 static void releaseStack ();
211
212 /****************************************************************/
213 /*                    PIC Instructions                          */
214 /****************************************************************/
215
216 pCodeInstruction pic16_pciADDWF = {
217   {PC_OPCODE, NULL, NULL, 0, NULL,
218    //   genericAnalyze,
219    genericDestruct,
220    genericPrint},
221   POC_ADDWF,
222   "ADDWF",
223   2,
224   NULL, // from branch
225   NULL, // to branch
226   NULL, // label
227   NULL, // operand
228   NULL, // flow block
229   NULL, // C source
230   3,    // num ops
231   1,0,  // dest, bit instruction
232   0,0,  // branch, skip
233   0,    // literal operand
234   1,    // RAM access bit
235   0,    // fast call/return mode select bit
236   0,    // second memory operand
237   0,    // second literal operand
238   POC_NOP,
239   (PCC_W | PCC_REGISTER),   // inCond
240   (PCC_REGISTER | PCC_STATUS), // outCond
241   PCI_MAGIC
242 };
243
244 pCodeInstruction pic16_pciADDFW = {
245   {PC_OPCODE, NULL, NULL, 0, NULL,
246    //   genericAnalyze,
247    genericDestruct,
248    genericPrint},
249   POC_ADDFW,
250   "ADDWF",
251   2,
252   NULL, // from branch
253   NULL, // to branch
254   NULL, // label
255   NULL, // operand
256   NULL, // flow block
257   NULL, // C source
258   3,    // num ops
259   0,0,  // dest, bit instruction
260   0,0,  // branch, skip
261   0,    // literal operand
262   1,    // RAM access bit
263   0,    // fast call/return mode select bit
264   0,    // second memory operand
265   0,    // second literal operand
266   POC_NOP,
267   (PCC_W | PCC_REGISTER),   // inCond
268   (PCC_W | PCC_STATUS), // outCond
269   PCI_MAGIC
270 };
271
272 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
273   {PC_OPCODE, NULL, NULL, 0, NULL,
274    //   genericAnalyze,
275    genericDestruct,
276    genericPrint},
277   POC_ADDWFC,
278   "ADDWFC",
279   2,
280   NULL, // from branch
281   NULL, // to branch
282   NULL, // label
283   NULL, // operand
284   NULL, // flow block
285   NULL, // C source
286   3,    // num ops
287   1,0,  // dest, bit instruction
288   0,0,  // branch, skip
289   0,    // literal operand
290   1,    // RAM access bit
291   0,    // fast call/return mode select bit
292   0,    // second memory operand
293   0,    // second literal operand
294   POC_NOP,
295   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
296   (PCC_REGISTER | PCC_STATUS), // outCond
297   PCI_MAGIC
298 };
299
300 pCodeInstruction pic16_pciADDFWC = {
301   {PC_OPCODE, NULL, NULL, 0, NULL,
302    //   genericAnalyze,
303    genericDestruct,
304    genericPrint},
305   POC_ADDFWC,
306   "ADDWFC",
307   2,
308   NULL, // from branch
309   NULL, // to branch
310   NULL, // label
311   NULL, // operand
312   NULL, // flow block
313   NULL, // C source
314   3,    // num ops
315   0,0,  // dest, bit instruction
316   0,0,  // branch, skip
317   0,    // literal operand
318   1,    // RAM access bit
319   0,    // fast call/return mode select bit
320   0,    // second memory operand
321   0,    // second literal operand
322   POC_NOP,
323   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
324   (PCC_W | PCC_STATUS), // outCond
325   PCI_MAGIC
326 };
327
328 pCodeInstruction pic16_pciADDLW = {
329   {PC_OPCODE, NULL, NULL, 0, NULL,
330    //   genericAnalyze,
331    genericDestruct,
332    genericPrint},
333   POC_ADDLW,
334   "ADDLW",
335   2,
336   NULL, // from branch
337   NULL, // to branch
338   NULL, // label
339   NULL, // operand
340   NULL, // flow block
341   NULL, // C source
342   1,    // num ops
343   0,0,  // dest, bit instruction
344   0,0,  // branch, skip
345   1,    // literal operand
346   0,    // RAM access bit
347   0,    // fast call/return mode select bit
348   0,    // second memory operand
349   0,    // second literal operand
350   POC_NOP,
351   (PCC_W | PCC_LITERAL),   // inCond
352   (PCC_W | PCC_STATUS), // outCond
353   PCI_MAGIC
354 };
355
356 pCodeInstruction pic16_pciANDLW = {
357   {PC_OPCODE, NULL, NULL, 0, NULL,
358    //   genericAnalyze,
359    genericDestruct,
360    genericPrint},
361   POC_ANDLW,
362   "ANDLW",
363   2,
364   NULL, // from branch
365   NULL, // to branch
366   NULL, // label
367   NULL, // operand
368   NULL, // flow block
369   NULL, // C source
370   1,    // num ops
371   0,0,  // dest, bit instruction
372   0,0,  // branch, skip
373   1,    // literal operand
374   0,    // RAM access bit
375   0,    // fast call/return mode select bit
376   0,    // second memory operand
377   0,    // second literal operand
378   POC_NOP,
379   (PCC_W | PCC_LITERAL),   // inCond
380   (PCC_W | PCC_Z | PCC_N), // outCond
381   PCI_MAGIC
382 };
383
384 pCodeInstruction pic16_pciANDWF = {
385   {PC_OPCODE, NULL, NULL, 0, NULL,
386    //   genericAnalyze,
387    genericDestruct,
388    genericPrint},
389   POC_ANDWF,
390   "ANDWF",
391   2,
392   NULL, // from branch
393   NULL, // to branch
394   NULL, // label
395   NULL, // operand
396   NULL, // flow block
397   NULL, // C source
398   3,    // num ops
399   1,0,  // dest, bit instruction
400   0,0,  // branch, skip
401   0,    // literal operand
402   1,    // RAM access bit
403   0,    // fast call/return mode select bit
404   0,    // second memory operand
405   0,    // second literal operand
406   POC_NOP,
407   (PCC_W | PCC_REGISTER),   // inCond
408   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
409   PCI_MAGIC
410 };
411
412 pCodeInstruction pic16_pciANDFW = {
413   {PC_OPCODE, NULL, NULL, 0, NULL,
414    //   genericAnalyze,
415    genericDestruct,
416    genericPrint},
417   POC_ANDFW,
418   "ANDWF",
419   2,
420   NULL, // from branch
421   NULL, // to branch
422   NULL, // label
423   NULL, // operand
424   NULL, // flow block
425   NULL, // C source
426   3,    // num ops
427   0,0,  // dest, bit instruction
428   0,0,  // branch, skip
429   0,    // literal operand
430   1,    // RAM access bit
431   0,    // fast call/return mode select bit
432   0,    // second memory operand
433   0,    // second literal operand
434   POC_NOP,
435   (PCC_W | PCC_REGISTER),   // inCond
436   (PCC_W | PCC_Z | PCC_N) // outCond
437 };
438
439 pCodeInstruction pic16_pciBC = { // mdubuc - New
440   {PC_OPCODE, NULL, NULL, 0, NULL,
441    //   genericAnalyze,
442    genericDestruct,
443    genericPrint},
444   POC_BC,
445   "BC",
446   2,
447   NULL, // from branch
448   NULL, // to branch
449   NULL, // label
450   NULL, // operand
451   NULL, // flow block
452   NULL, // C source
453   1,    // num ops
454   0,0,  // dest, bit instruction
455   1,0,  // branch, skip
456   0,    // literal operand
457   0,    // RAM access bit
458   0,    // fast call/return mode select bit
459   0,    // second memory operand
460   0,    // second literal operand
461   POC_NOP,
462   (PCC_REL_ADDR | PCC_C),   // inCond
463   PCC_NONE,    // outCond
464   PCI_MAGIC
465 };
466
467 pCodeInstruction pic16_pciBCF = {
468   {PC_OPCODE, NULL, NULL, 0, NULL,
469    //   genericAnalyze,
470    genericDestruct,
471    genericPrint},
472   POC_BCF,
473   "BCF",
474   2,
475   NULL, // from branch
476   NULL, // to branch
477   NULL, // label
478   NULL, // operand
479   NULL, // flow block
480   NULL, // C source
481   3,    // num ops
482   1,1,  // dest, bit instruction
483   0,0,  // branch, skip
484   0,    // literal operand
485   1,    // RAM access bit
486   0,    // fast call/return mode select bit
487   0,    // second memory operand
488   0,    // second literal operand
489   POC_BSF,
490   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
491   PCC_REGISTER, // outCond
492   PCI_MAGIC
493 };
494
495 pCodeInstruction pic16_pciBN = { // mdubuc - New
496   {PC_OPCODE, NULL, NULL, 0, NULL,
497    //   genericAnalyze,
498    genericDestruct,
499    genericPrint},
500   POC_BN,
501   "BN",
502   2,
503   NULL, // from branch
504   NULL, // to branch
505   NULL, // label
506   NULL, // operand
507   NULL, // flow block
508   NULL, // C source
509   1,    // num ops
510   0,0,  // dest, bit instruction
511   1,0,  // branch, skip
512   0,    // literal operand
513   0,    // RAM access bit
514   0,    // fast call/return mode select bit
515   0,    // second memory operand
516   0,    // second literal operand
517   POC_NOP,
518   (PCC_REL_ADDR | PCC_N),   // inCond
519   PCC_NONE   , // outCond
520   PCI_MAGIC
521 };
522
523 pCodeInstruction pic16_pciBNC = { // mdubuc - New
524   {PC_OPCODE, NULL, NULL, 0, NULL,
525    //   genericAnalyze,
526    genericDestruct,
527    genericPrint},
528   POC_BNC,
529   "BNC",
530   2,
531   NULL, // from branch
532   NULL, // to branch
533   NULL, // label
534   NULL, // operand
535   NULL, // flow block
536   NULL, // C source
537   1,    // num ops
538   0,0,  // dest, bit instruction
539   1,0,  // branch, skip
540   0,    // literal operand
541   0,    // RAM access bit
542   0,    // fast call/return mode select bit
543   0,    // second memory operand
544   0,    // second literal operand
545   POC_NOP,
546   (PCC_REL_ADDR | PCC_C),   // inCond
547   PCC_NONE   , // outCond
548   PCI_MAGIC
549 };
550
551 pCodeInstruction pic16_pciBNN = { // mdubuc - New
552   {PC_OPCODE, NULL, NULL, 0, NULL,
553    //   genericAnalyze,
554    genericDestruct,
555    genericPrint},
556   POC_BNN,
557   "BNN",
558   2,
559   NULL, // from branch
560   NULL, // to branch
561   NULL, // label
562   NULL, // operand
563   NULL, // flow block
564   NULL, // C source
565   1,    // num ops
566   0,0,  // dest, bit instruction
567   1,0,  // branch, skip
568   0,    // literal operand
569   0,    // RAM access bit
570   0,    // fast call/return mode select bit
571   0,    // second memory operand
572   0,    // second literal operand
573   POC_NOP,
574   (PCC_REL_ADDR | PCC_N),   // inCond
575   PCC_NONE   , // outCond
576   PCI_MAGIC
577 };
578
579 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
580   {PC_OPCODE, NULL, NULL, 0, NULL,
581    //   genericAnalyze,
582    genericDestruct,
583    genericPrint},
584   POC_BNOV,
585   "BNOV",
586   2,
587   NULL, // from branch
588   NULL, // to branch
589   NULL, // label
590   NULL, // operand
591   NULL, // flow block
592   NULL, // C source
593   1,    // num ops
594   0,0,  // dest, bit instruction
595   1,0,  // branch, skip
596   0,    // literal operand
597   0,    // RAM access bit
598   0,    // fast call/return mode select bit
599   0,    // second memory operand
600   0,    // second literal operand
601   POC_NOP,
602   (PCC_REL_ADDR | PCC_OV),   // inCond
603   PCC_NONE   , // outCond
604   PCI_MAGIC
605 };
606
607 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
608   {PC_OPCODE, NULL, NULL, 0, NULL,
609    //   genericAnalyze,
610    genericDestruct,
611    genericPrint},
612   POC_BNZ,
613   "BNZ",
614   2,
615   NULL, // from branch
616   NULL, // to branch
617   NULL, // label
618   NULL, // operand
619   NULL, // flow block
620   NULL, // C source
621   1,    // num ops
622   0,0,  // dest, bit instruction
623   1,0,  // branch, skip
624   0,    // literal operand
625   0,    // RAM access bit
626   0,    // fast call/return mode select bit
627   0,    // second memory operand
628   0,    // second literal operand
629   POC_NOP,
630   (PCC_REL_ADDR | PCC_Z),   // inCond
631   PCC_NONE   , // outCond
632   PCI_MAGIC
633 };
634
635 pCodeInstruction pic16_pciBOV = { // mdubuc - New
636   {PC_OPCODE, NULL, NULL, 0, NULL,
637    //   genericAnalyze,
638    genericDestruct,
639    genericPrint},
640   POC_BOV,
641   "BOV",
642   2,
643   NULL, // from branch
644   NULL, // to branch
645   NULL, // label
646   NULL, // operand
647   NULL, // flow block
648   NULL, // C source
649   1,    // num ops
650   0,0,  // dest, bit instruction
651   1,0,  // branch, skip
652   0,    // literal operand
653   0,    // RAM access bit
654   0,    // fast call/return mode select bit
655   0,    // second memory operand
656   0,    // second literal operand
657   POC_NOP,
658   (PCC_REL_ADDR | PCC_OV),   // inCond
659   PCC_NONE , // outCond
660   PCI_MAGIC
661 };
662
663 pCodeInstruction pic16_pciBRA = { // mdubuc - New
664   {PC_OPCODE, NULL, NULL, 0, NULL,
665    //   genericAnalyze,
666    genericDestruct,
667    genericPrint},
668   POC_BRA,
669   "BRA",
670   2,
671   NULL, // from branch
672   NULL, // to branch
673   NULL, // label
674   NULL, // operand
675   NULL, // flow block
676   NULL, // C source
677   1,    // num ops
678   0,0,  // dest, bit instruction
679   1,0,  // branch, skip
680   0,    // literal operand
681   0,    // RAM access bit
682   0,    // fast call/return mode select bit
683   0,    // second memory operand
684   0,    // second literal operand
685   POC_NOP,
686   PCC_REL_ADDR,   // inCond
687   PCC_NONE   , // outCond
688   PCI_MAGIC
689 };
690
691 pCodeInstruction pic16_pciBSF = {
692   {PC_OPCODE, NULL, NULL, 0, NULL,
693    //   genericAnalyze,
694    genericDestruct,
695    genericPrint},
696   POC_BSF,
697   "BSF",
698   2,
699   NULL, // from branch
700   NULL, // to branch
701   NULL, // label
702   NULL, // operand
703   NULL, // flow block
704   NULL, // C source
705   3,    // num ops
706   1,1,  // dest, bit instruction
707   0,0,  // branch, skip
708   0,    // literal operand
709   1,    // RAM access bit
710   0,    // fast call/return mode select bit
711   0,    // second memory operand
712   0,    // second literal operand
713   POC_BCF,
714   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
715   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
716   PCI_MAGIC
717 };
718
719 pCodeInstruction pic16_pciBTFSC = {
720   {PC_OPCODE, NULL, NULL, 0, NULL,
721    //   AnalyzeSKIP,
722    genericDestruct,
723    genericPrint},
724   POC_BTFSC,
725   "BTFSC",
726   2,
727   NULL, // from branch
728   NULL, // to branch
729   NULL, // label
730   NULL, // operand
731   NULL, // flow block
732   NULL, // C source
733   3,    // num ops
734   0,1,  // dest, bit instruction
735   1,1,  // branch, skip
736   0,    // literal operand
737   1,    // RAM access bit
738   0,    // fast call/return mode select bit
739   0,    // second memory operand
740   0,    // second literal operand
741   POC_BTFSS,
742   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
743   PCC_EXAMINE_PCOP, // outCond
744   PCI_MAGIC
745 };
746
747 pCodeInstruction pic16_pciBTFSS = {
748   {PC_OPCODE, NULL, NULL, 0, NULL,
749    //   AnalyzeSKIP,
750    genericDestruct,
751    genericPrint},
752   POC_BTFSS,
753   "BTFSS",
754   2,
755   NULL, // from branch
756   NULL, // to branch
757   NULL, // label
758   NULL, // operand
759   NULL, // flow block
760   NULL, // C source
761   3,    // num ops
762   0,1,  // dest, bit instruction
763   1,1,  // branch, skip
764   0,    // literal operand
765   1,    // RAM access bit
766   0,    // fast call/return mode select bit
767   0,    // second memory operand
768   0,    // second literal operand
769   POC_BTFSC,
770   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
771   PCC_EXAMINE_PCOP, // outCond
772   PCI_MAGIC
773 };
774
775 pCodeInstruction pic16_pciBTG = { // mdubuc - New
776   {PC_OPCODE, NULL, NULL, 0, NULL,
777    //   genericAnalyze,
778    genericDestruct,
779    genericPrint},
780   POC_BTG,
781   "BTG",
782   2,
783   NULL, // from branch
784   NULL, // to branch
785   NULL, // label
786   NULL, // operand
787   NULL, // flow block
788   NULL, // C source
789   3,    // num ops
790   0,1,  // dest, bit instruction
791   0,0,  // branch, skip
792   0,    // literal operand
793   1,    // RAM access bit
794   0,    // fast call/return mode select bit
795   0,    // second memory operand
796   0,    // second literal operand
797   POC_NOP,
798   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
799   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
800   PCI_MAGIC
801 };
802
803 pCodeInstruction pic16_pciBZ = { // mdubuc - New
804   {PC_OPCODE, NULL, NULL, 0, NULL,
805    //   genericAnalyze,
806    genericDestruct,
807    genericPrint},
808   POC_BZ,
809   "BZ",
810   2,
811   NULL, // from branch
812   NULL, // to branch
813   NULL, // label
814   NULL, // operand
815   NULL, // flow block
816   NULL, // C source
817   1,    // num ops
818   0,0,  // dest, bit instruction
819   1,0,  // branch, skip
820   0,    // literal operand
821   0,    // RAM access bit
822   0,    // fast call/return mode select bit
823   0,    // second memory operand
824   0,    // second literal operand
825   POC_NOP,
826   (PCC_REL_ADDR | PCC_Z),   // inCond
827   PCC_NONE, // outCond
828   PCI_MAGIC
829 };
830
831 pCodeInstruction pic16_pciCALL = {
832   {PC_OPCODE, NULL, NULL, 0, NULL,
833    //   genericAnalyze,
834    genericDestruct,
835    genericPrint},
836   POC_CALL,
837   "CALL",
838   4,
839   NULL, // from branch
840   NULL, // to branch
841   NULL, // label
842   NULL, // operand
843   NULL, // flow block
844   NULL, // C source
845   2,    // num ops
846   0,0,  // dest, bit instruction
847   1,0,  // branch, skip
848   0,    // literal operand
849   0,    // RAM access bit
850   1,    // fast call/return mode select bit
851   0,    // second memory operand
852   0,    // second literal operand
853   POC_NOP,
854   PCC_NONE, // inCond
855   PCC_NONE, // outCond
856   PCI_MAGIC
857 };
858
859 pCodeInstruction pic16_pciCOMF = {
860   {PC_OPCODE, NULL, NULL, 0, NULL,
861    //   genericAnalyze,
862    genericDestruct,
863    genericPrint},
864   POC_COMF,
865   "COMF",
866   2,
867   NULL, // from branch
868   NULL, // to branch
869   NULL, // label
870   NULL, // operand
871   NULL, // flow block
872   NULL, // C source
873   3,    // num ops
874   1,0,  // dest, bit instruction
875   0,0,  // branch, skip
876   0,    // literal operand
877   1,    // RAM access bit
878   0,    // fast call/return mode select bit
879   0,    // second memory operand
880   0,    // second literal operand
881   POC_NOP,
882   PCC_REGISTER,  // inCond
883   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
884   PCI_MAGIC
885 };
886
887 pCodeInstruction pic16_pciCOMFW = {
888   {PC_OPCODE, NULL, NULL, 0, NULL,
889    //   genericAnalyze,
890    genericDestruct,
891    genericPrint},
892   POC_COMFW,
893   "COMF",
894   2,
895   NULL, // from branch
896   NULL, // to branch
897   NULL, // label
898   NULL, // operand
899   NULL, // flow block
900   NULL, // C source
901   3,    // num ops
902   0,0,  // dest, bit instruction
903   0,0,  // branch, skip
904   0,    // literal operand
905   1,    // RAM access bit
906   0,    // fast call/return mode select bit
907   0,    // second memory operand
908   0,    // second literal operand
909   POC_NOP,
910   PCC_REGISTER,  // inCond
911   (PCC_W | PCC_Z | PCC_N) , // outCond
912   PCI_MAGIC
913 };
914
915 pCodeInstruction pic16_pciCLRF = {
916   {PC_OPCODE, NULL, NULL, 0, NULL,
917    //   genericAnalyze,
918    genericDestruct,
919    genericPrint},
920   POC_CLRF,
921   "CLRF",
922   2,
923   NULL, // from branch
924   NULL, // to branch
925   NULL, // label
926   NULL, // operand
927   NULL, // flow block
928   NULL, // C source
929   2,    // num ops
930   0,0,  // dest, bit instruction
931   0,0,  // branch, skip
932   0,    // literal operand
933   1,    // RAM access bit
934   0,    // fast call/return mode select bit
935   0,    // second memory operand
936   0,    // second literal operand
937   POC_NOP,
938   PCC_NONE, // inCond
939   (PCC_REGISTER | PCC_Z), // outCond
940   PCI_MAGIC
941 };
942
943 pCodeInstruction pic16_pciCLRWDT = {
944   {PC_OPCODE, NULL, NULL, 0, NULL,
945    //   genericAnalyze,
946    genericDestruct,
947    genericPrint},
948   POC_CLRWDT,
949   "CLRWDT",
950   2,
951   NULL, // from branch
952   NULL, // to branch
953   NULL, // label
954   NULL, // operand
955   NULL, // flow block
956   NULL, // C source
957   0,    // num ops
958   0,0,  // dest, bit instruction
959   0,0,  // branch, skip
960   0,    // literal operand
961   0,    // RAM access bit
962   0,    // fast call/return mode select bit
963   0,    // second memory operand
964   0,    // second literal operand
965   POC_NOP,
966   PCC_NONE, // inCond
967   PCC_NONE , // outCond
968   PCI_MAGIC
969 };
970
971 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
972   {PC_OPCODE, NULL, NULL, 0, NULL,
973    //   genericAnalyze,
974    genericDestruct,
975    genericPrint},
976   POC_CPFSEQ,
977   "CPFSEQ",
978   2,
979   NULL, // from branch
980   NULL, // to branch
981   NULL, // label
982   NULL, // operand
983   NULL, // flow block
984   NULL, // C source
985   2,    // num ops
986   0,0,  // dest, bit instruction
987   1,1,  // branch, skip
988   0,    // literal operand
989   1,    // RAM access bit
990   0,    // fast call/return mode select bit
991   0,    // second memory operand
992   0,    // second literal operand
993   POC_NOP,
994   (PCC_W | PCC_REGISTER), // inCond
995   PCC_NONE , // outCond
996   PCI_MAGIC
997 };
998
999 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1000   {PC_OPCODE, NULL, NULL, 0, NULL,
1001    //   genericAnalyze,
1002    genericDestruct,
1003    genericPrint},
1004   POC_CPFSGT,
1005   "CPFSGT",
1006   2,
1007   NULL, // from branch
1008   NULL, // to branch
1009   NULL, // label
1010   NULL, // operand
1011   NULL, // flow block
1012   NULL, // C source
1013   2,    // num ops
1014   0,0,  // dest, bit instruction
1015   1,1,  // branch, skip
1016   0,    // literal operand
1017   1,    // RAM access bit
1018   0,    // fast call/return mode select bit
1019   0,    // second memory operand
1020   0,    // second literal operand
1021   POC_NOP,
1022   (PCC_W | PCC_REGISTER), // inCond
1023   PCC_NONE , // outCond
1024   PCI_MAGIC
1025 };
1026
1027 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1028   {PC_OPCODE, NULL, NULL, 0, NULL,
1029    //   genericAnalyze,
1030    genericDestruct,
1031    genericPrint},
1032   POC_CPFSLT,
1033   "CPFSLT",
1034   2,
1035   NULL, // from branch
1036   NULL, // to branch
1037   NULL, // label
1038   NULL, // operand
1039   NULL, // flow block
1040   NULL, // C source
1041   2,    // num ops
1042   1,0,  // dest, bit instruction
1043   1,1,  // branch, skip
1044   0,    // literal operand
1045   1,    // RAM access bit
1046   0,    // fast call/return mode select bit
1047   0,    // second memory operand
1048   0,    // second literal operand
1049   POC_NOP,
1050   (PCC_W | PCC_REGISTER), // inCond
1051   PCC_NONE , // outCond
1052   PCI_MAGIC
1053 };
1054
1055 pCodeInstruction pic16_pciDAW = {
1056   {PC_OPCODE, NULL, NULL, 0, NULL,
1057    //   genericAnalyze,
1058    genericDestruct,
1059    genericPrint},
1060   POC_DAW,
1061   "DAW",
1062   2,
1063   NULL, // from branch
1064   NULL, // to branch
1065   NULL, // label
1066   NULL, // operand
1067   NULL, // flow block
1068   NULL, // C source
1069   0,    // num ops
1070   0,0,  // dest, bit instruction
1071   0,0,  // branch, skip
1072   0,    // literal operand
1073   0,    // RAM access bit
1074   0,    // fast call/return mode select bit
1075   0,    // second memory operand
1076   0,    // second literal operand
1077   POC_NOP,
1078   PCC_W, // inCond
1079   (PCC_W | PCC_C), // outCond
1080   PCI_MAGIC
1081 };
1082
1083 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1084   {PC_OPCODE, NULL, NULL, 0, NULL,
1085    //   genericAnalyze,
1086    genericDestruct,
1087    genericPrint},
1088   POC_DCFSNZ,
1089   "DCFSNZ",
1090   2,
1091   NULL, // from branch
1092   NULL, // to branch
1093   NULL, // label
1094   NULL, // operand
1095   NULL, // flow block
1096   NULL, // C source
1097   3,    // num ops
1098   1,0,  // dest, bit instruction
1099   1,1,  // branch, skip
1100   0,    // literal operand
1101   1,    // RAM access bit
1102   0,    // fast call/return mode select bit
1103   0,    // second memory operand
1104   0,    // second literal operand
1105   POC_NOP,
1106   PCC_REGISTER, // inCond
1107   PCC_REGISTER , // outCond
1108   PCI_MAGIC
1109 };
1110
1111 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1112   {PC_OPCODE, NULL, NULL, 0, NULL,
1113    //   genericAnalyze,
1114    genericDestruct,
1115    genericPrint},
1116   POC_DCFSNZW,
1117   "DCFSNZ",
1118   2,
1119   NULL, // from branch
1120   NULL, // to branch
1121   NULL, // label
1122   NULL, // operand
1123   NULL, // flow block
1124   NULL, // C source
1125   3,    // num ops
1126   0,0,  // dest, bit instruction
1127   1,1,  // branch, skip
1128   0,    // literal operand
1129   1,    // RAM access bit
1130   0,    // fast call/return mode select bit
1131   0,    // second memory operand
1132   0,    // second literal operand
1133   POC_NOP,
1134   PCC_REGISTER, // inCond
1135   PCC_W , // outCond
1136   PCI_MAGIC
1137 };
1138
1139 pCodeInstruction pic16_pciDECF = {
1140   {PC_OPCODE, NULL, NULL, 0, NULL,
1141    //   genericAnalyze,
1142    genericDestruct,
1143    genericPrint},
1144   POC_DECF,
1145   "DECF",
1146   2,
1147   NULL, // from branch
1148   NULL, // to branch
1149   NULL, // label
1150   NULL, // operand
1151   NULL, // flow block
1152   NULL, // C source
1153   3,    // num ops
1154   1,0,  // dest, bit instruction
1155   0,0,  // branch, skip
1156   0,    // literal operand
1157   1,    // RAM access bit
1158   0,    // fast call/return mode select bit
1159   0,    // second memory operand
1160   0,    // second literal operand
1161   POC_NOP,
1162   PCC_REGISTER,   // inCond
1163   (PCC_REGISTER | PCC_STATUS)  , // outCond
1164   PCI_MAGIC
1165 };
1166
1167 pCodeInstruction pic16_pciDECFW = {
1168   {PC_OPCODE, NULL, NULL, 0, NULL,
1169    //   genericAnalyze,
1170    genericDestruct,
1171    genericPrint},
1172   POC_DECFW,
1173   "DECF",
1174   2,
1175   NULL, // from branch
1176   NULL, // to branch
1177   NULL, // label
1178   NULL, // operand
1179   NULL, // flow block
1180   NULL, // C source
1181   3,    // num ops
1182   0,0,  // dest, bit instruction
1183   0,0,  // branch, skip
1184   0,    // literal operand
1185   1,    // RAM access bit
1186   0,    // fast call/return mode select bit
1187   0,    // second memory operand
1188   0,    // second literal operand
1189   POC_NOP,
1190   PCC_REGISTER,   // inCond
1191   (PCC_W | PCC_STATUS)  , // outCond
1192   PCI_MAGIC
1193 };
1194
1195 pCodeInstruction pic16_pciDECFSZ = {
1196   {PC_OPCODE, NULL, NULL, 0, NULL,
1197    //   AnalyzeSKIP,
1198    genericDestruct,
1199    genericPrint},
1200   POC_DECFSZ,
1201   "DECFSZ",
1202   2,
1203   NULL, // from branch
1204   NULL, // to branch
1205   NULL, // label
1206   NULL, // operand
1207   NULL, // flow block
1208   NULL, // C source
1209   3,    // num ops
1210   1,0,  // dest, bit instruction
1211   1,1,  // branch, skip
1212   0,    // literal operand
1213   1,    // RAM access bit
1214   0,    // fast call/return mode select bit
1215   0,    // second memory operand
1216   0,    // second literal operand
1217   POC_NOP,
1218   PCC_REGISTER,   // inCond
1219   PCC_REGISTER   , // outCond
1220   PCI_MAGIC
1221 };
1222
1223 pCodeInstruction pic16_pciDECFSZW = {
1224   {PC_OPCODE, NULL, NULL, 0, NULL,
1225    //   AnalyzeSKIP,
1226    genericDestruct,
1227    genericPrint},
1228   POC_DECFSZW,
1229   "DECFSZ",
1230   2,
1231   NULL, // from branch
1232   NULL, // to branch
1233   NULL, // label
1234   NULL, // operand
1235   NULL, // flow block
1236   NULL, // C source
1237   3,    // num ops
1238   0,0,  // dest, bit instruction
1239   1,1,  // branch, skip
1240   0,    // literal operand
1241   1,    // RAM access bit
1242   0,    // fast call/return mode select bit
1243   0,    // second memory operand
1244   0,    // second literal operand
1245   POC_NOP,
1246   PCC_REGISTER,   // inCond
1247   PCC_W          , // outCond
1248   PCI_MAGIC
1249 };
1250
1251 pCodeInstruction pic16_pciGOTO = {
1252   {PC_OPCODE, NULL, NULL, 0, NULL,
1253    //   AnalyzeGOTO,
1254    genericDestruct,
1255    genericPrint},
1256   POC_GOTO,
1257   "GOTO",
1258   4,
1259   NULL, // from branch
1260   NULL, // to branch
1261   NULL, // label
1262   NULL, // operand
1263   NULL, // flow block
1264   NULL, // C source
1265   1,    // num ops
1266   0,0,  // dest, bit instruction
1267   1,0,  // branch, skip
1268   0,    // literal operand
1269   0,    // RAM access bit
1270   0,    // fast call/return mode select bit
1271   0,    // second memory operand
1272   0,    // second literal operand
1273   POC_NOP,
1274   PCC_REL_ADDR,   // inCond
1275   PCC_NONE   , // outCond
1276   PCI_MAGIC
1277 };
1278
1279 pCodeInstruction pic16_pciINCF = {
1280   {PC_OPCODE, NULL, NULL, 0, NULL,
1281    //   genericAnalyze,
1282    genericDestruct,
1283    genericPrint},
1284   POC_INCF,
1285   "INCF",
1286   2,
1287   NULL, // from branch
1288   NULL, // to branch
1289   NULL, // label
1290   NULL, // operand
1291   NULL, // flow block
1292   NULL, // C source
1293   3,    // num ops
1294   1,0,  // dest, bit instruction
1295   0,0,  // branch, skip
1296   0,    // literal operand
1297   1,    // RAM access bit
1298   0,    // fast call/return mode select bit
1299   0,    // second memory operand
1300   0,    // second literal operand
1301   POC_NOP,
1302   PCC_REGISTER,   // inCond
1303   (PCC_REGISTER | PCC_STATUS), // outCond
1304   PCI_MAGIC
1305 };
1306
1307 pCodeInstruction pic16_pciINCFW = {
1308   {PC_OPCODE, NULL, NULL, 0, NULL,
1309    //   genericAnalyze,
1310    genericDestruct,
1311    genericPrint},
1312   POC_INCFW,
1313   "INCF",
1314   2,
1315   NULL, // from branch
1316   NULL, // to branch
1317   NULL, // label
1318   NULL, // operand
1319   NULL, // flow block
1320   NULL, // C source
1321   3,    // num ops
1322   0,0,  // dest, bit instruction
1323   0,0,  // branch, skip
1324   0,    // literal operand
1325   1,    // RAM access bit
1326   0,    // fast call/return mode select bit
1327   0,    // second memory operand
1328   0,    // second literal operand
1329   POC_NOP,
1330   PCC_REGISTER,   // inCond
1331   (PCC_W | PCC_STATUS)  , // outCond
1332   PCI_MAGIC
1333 };
1334
1335 pCodeInstruction pic16_pciINCFSZ = {
1336   {PC_OPCODE, NULL, NULL, 0, NULL,
1337    //   AnalyzeSKIP,
1338    genericDestruct,
1339    genericPrint},
1340   POC_INCFSZ,
1341   "INCFSZ",
1342   2,
1343   NULL, // from branch
1344   NULL, // to branch
1345   NULL, // label
1346   NULL, // operand
1347   NULL, // flow block
1348   NULL, // C source
1349   3,    // num ops
1350   1,0,  // dest, bit instruction
1351   1,1,  // branch, skip
1352   0,    // literal operand
1353   1,    // RAM access bit
1354   0,    // fast call/return mode select bit
1355   0,    // second memory operand
1356   0,    // second literal operand
1357   POC_INFSNZ,
1358   PCC_REGISTER,   // inCond
1359   PCC_REGISTER   , // outCond
1360   PCI_MAGIC
1361 };
1362
1363 pCodeInstruction pic16_pciINCFSZW = {
1364   {PC_OPCODE, NULL, NULL, 0, NULL,
1365    //   AnalyzeSKIP,
1366    genericDestruct,
1367    genericPrint},
1368   POC_INCFSZW,
1369   "INCFSZ",
1370   2,
1371   NULL, // from branch
1372   NULL, // to branch
1373   NULL, // label
1374   NULL, // operand
1375   NULL, // flow block
1376   NULL, // C source
1377   3,    // num ops
1378   0,0,  // dest, bit instruction
1379   1,1,  // branch, skip
1380   0,    // literal operand
1381   1,    // RAM access bit
1382   0,    // fast call/return mode select bit
1383   0,    // second memory operand
1384   0,    // second literal operand
1385   POC_INFSNZW,
1386   PCC_REGISTER,   // inCond
1387   PCC_W          , // outCond
1388   PCI_MAGIC
1389 };
1390
1391 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1392   {PC_OPCODE, NULL, NULL, 0, NULL,
1393    //   AnalyzeSKIP,
1394    genericDestruct,
1395    genericPrint},
1396   POC_INFSNZ,
1397   "INFSNZ",
1398   2,
1399   NULL, // from branch
1400   NULL, // to branch
1401   NULL, // label
1402   NULL, // operand
1403   NULL, // flow block
1404   NULL, // C source
1405   3,    // num ops
1406   1,0,  // dest, bit instruction
1407   1,1,  // branch, skip
1408   0,    // literal operand
1409   1,    // RAM access bit
1410   0,    // fast call/return mode select bit
1411   0,    // second memory operand
1412   0,    // second literal operand
1413   POC_INCFSZ,
1414   PCC_REGISTER,   // inCond
1415   PCC_REGISTER   , // outCond
1416   PCI_MAGIC
1417 };
1418
1419 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1420   {PC_OPCODE, NULL, NULL, 0, NULL,
1421    //   AnalyzeSKIP,
1422    genericDestruct,
1423    genericPrint},
1424   POC_INFSNZW,
1425   "INFSNZ",
1426   2,
1427   NULL, // from branch
1428   NULL, // to branch
1429   NULL, // label
1430   NULL, // operand
1431   NULL, // flow block
1432   NULL, // C source
1433   3,    // num ops
1434   0,0,  // dest, bit instruction
1435   1,1,  // branch, skip
1436   0,    // literal operand
1437   1,    // RAM access bit
1438   0,    // fast call/return mode select bit
1439   0,    // second memory operand
1440   0,    // second literal operand
1441   POC_INCFSZW,
1442   PCC_REGISTER,   // inCond
1443   PCC_W          , // outCond
1444   PCI_MAGIC
1445 };
1446
1447 pCodeInstruction pic16_pciIORWF = {
1448   {PC_OPCODE, NULL, NULL, 0, NULL,
1449    //   genericAnalyze,
1450    genericDestruct,
1451    genericPrint},
1452   POC_IORWF,
1453   "IORWF",
1454   2,
1455   NULL, // from branch
1456   NULL, // to branch
1457   NULL, // label
1458   NULL, // operand
1459   NULL, // flow block
1460   NULL, // C source
1461   3,    // num ops
1462   1,0,  // dest, bit instruction
1463   0,0,  // branch, skip
1464   0,    // literal operand
1465   1,    // RAM access bit
1466   0,    // fast call/return mode select bit
1467   0,    // second memory operand
1468   0,    // second literal operand
1469   POC_NOP,
1470   (PCC_W | PCC_REGISTER),   // inCond
1471   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1472   PCI_MAGIC
1473 };
1474
1475 pCodeInstruction pic16_pciIORFW = {
1476   {PC_OPCODE, NULL, NULL, 0, NULL,
1477    //   genericAnalyze,
1478    genericDestruct,
1479    genericPrint},
1480   POC_IORFW,
1481   "IORWF",
1482   2,
1483   NULL, // from branch
1484   NULL, // to branch
1485   NULL, // label
1486   NULL, // operand
1487   NULL, // flow block
1488   NULL, // C source
1489   3,    // num ops
1490   0,0,  // dest, bit instruction
1491   0,0,  // branch, skip
1492   0,    // literal operand
1493   1,    // RAM access bit
1494   0,    // fast call/return mode select bit
1495   0,    // second memory operand
1496   0,    // second literal operand
1497   POC_NOP,
1498   (PCC_W | PCC_REGISTER),   // inCond
1499   (PCC_W | PCC_Z | PCC_N), // outCond
1500   PCI_MAGIC
1501 };
1502
1503 pCodeInstruction pic16_pciIORLW = {
1504   {PC_OPCODE, NULL, NULL, 0, NULL,
1505    //   genericAnalyze,
1506    genericDestruct,
1507    genericPrint},
1508   POC_IORLW,
1509   "IORLW",
1510   2,
1511   NULL, // from branch
1512   NULL, // to branch
1513   NULL, // label
1514   NULL, // operand
1515   NULL, // flow block
1516   NULL, // C source
1517   1,    // num ops
1518   0,0,  // dest, bit instruction
1519   0,0,  // branch, skip
1520   1,    // literal operand
1521   0,    // RAM access bit
1522   0,    // fast call/return mode select bit
1523   0,    // second memory operand
1524   0,    // second literal operand
1525   POC_NOP,
1526   (PCC_W | PCC_LITERAL),   // inCond
1527   (PCC_W | PCC_Z | PCC_N), // outCond
1528   PCI_MAGIC
1529 };
1530
1531 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1532   {PC_OPCODE, NULL, NULL, 0, NULL,
1533    //   genericAnalyze,
1534    genericDestruct,
1535    genericPrint},
1536   POC_LFSR,
1537   "LFSR",
1538   4,
1539   NULL, // from branch
1540   NULL, // to branch
1541   NULL, // label
1542   NULL, // operand
1543   NULL, // flow block
1544   NULL, // C source
1545   2,    // num ops
1546   0,0,  // dest, bit instruction
1547   0,0,  // branch, skip
1548   1,    // literal operand
1549   0,    // RAM access bit
1550   0,    // fast call/return mode select bit
1551   0,    // second memory operand
1552   1,    // second literal operand
1553   POC_NOP,
1554   PCC_LITERAL, // inCond
1555   PCC_NONE, // outCond
1556   PCI_MAGIC
1557 };
1558
1559 pCodeInstruction pic16_pciMOVF = {
1560   {PC_OPCODE, NULL, NULL, 0, NULL,
1561    //   genericAnalyze,
1562    genericDestruct,
1563    genericPrint},
1564   POC_MOVF,
1565   "MOVF",
1566   2,
1567   NULL, // from branch
1568   NULL, // to branch
1569   NULL, // label
1570   NULL, // operand
1571   NULL, // flow block
1572   NULL, // C source
1573   3,    // num ops
1574   1,0,  // dest, bit instruction
1575   0,0,  // branch, skip
1576   0,    // literal operand
1577   1,    // RAM access bit
1578   0,    // fast call/return mode select bit
1579   0,    // second memory operand
1580   0,    // second literal operand
1581   POC_NOP,
1582   PCC_REGISTER,   // inCond
1583   (PCC_Z | PCC_N), // outCond
1584   PCI_MAGIC
1585 };
1586
1587 pCodeInstruction pic16_pciMOVFW = {
1588   {PC_OPCODE, NULL, NULL, 0, NULL,
1589    //   genericAnalyze,
1590    genericDestruct,
1591    genericPrint},
1592   POC_MOVFW,
1593   "MOVF",
1594   2,
1595   NULL, // from branch
1596   NULL, // to branch
1597   NULL, // label
1598   NULL, // operand
1599   NULL, // flow block
1600   NULL, // C source
1601   3,    // num ops
1602   0,0,  // dest, bit instruction
1603   0,0,  // branch, skip
1604   0,    // literal operand
1605   1,    // RAM access bit
1606   0,    // fast call/return mode select bit
1607   0,    // second memory operand
1608   0,    // second literal operand
1609   POC_NOP,
1610   PCC_REGISTER,   // inCond
1611   (PCC_W | PCC_N | PCC_Z), // outCond
1612   PCI_MAGIC
1613 };
1614
1615 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1616   {PC_OPCODE, NULL, NULL, 0, NULL,
1617    //   genericAnalyze,
1618    genericDestruct,
1619    genericPrint},
1620   POC_MOVFF,
1621   "MOVFF",
1622   4,
1623   NULL, // from branch
1624   NULL, // to branch
1625   NULL, // label
1626   NULL, // operand
1627   NULL, // flow block
1628   NULL, // C source
1629   2,    // num ops
1630   0,0,  // dest, bit instruction
1631   0,0,  // branch, skip
1632   0,    // literal operand
1633   0,    // RAM access bit
1634   0,    // fast call/return mode select bit
1635   1,    // second memory operand
1636   0,    // second literal operand
1637   POC_NOP,
1638   PCC_REGISTER,   // inCond
1639   PCC_REGISTER2, // outCond
1640   PCI_MAGIC
1641 };
1642
1643 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1644   {PC_OPCODE, NULL, NULL, 0, NULL,
1645    genericDestruct,
1646    genericPrint},
1647   POC_MOVLB,
1648   "MOVLB",
1649   2,
1650   NULL, // from branch
1651   NULL, // to branch
1652   NULL, // label
1653   NULL, // operand
1654   NULL, // flow block
1655   NULL, // C source
1656   1,    // num ops
1657   0,0,  // dest, bit instruction
1658   0,0,  // branch, skip
1659   1,    // literal operand
1660   0,    // RAM access bit
1661   0,    // fast call/return mode select bit
1662   0,    // second memory operand
1663   0,    // second literal operand
1664   POC_NOP,
1665   (PCC_NONE | PCC_LITERAL),   // inCond
1666   PCC_REGISTER, // outCond - BSR
1667   PCI_MAGIC
1668 };
1669
1670 pCodeInstruction pic16_pciMOVLW = {
1671   {PC_OPCODE, NULL, NULL, 0, NULL,
1672    genericDestruct,
1673    genericPrint},
1674   POC_MOVLW,
1675   "MOVLW",
1676   2,
1677   NULL, // from branch
1678   NULL, // to branch
1679   NULL, // label
1680   NULL, // operand
1681   NULL, // flow block
1682   NULL, // C source
1683   1,    // num ops
1684   0,0,  // dest, bit instruction
1685   0,0,  // branch, skip
1686   1,    // literal operand
1687   0,    // RAM access bit
1688   0,    // fast call/return mode select bit
1689   0,    // second memory operand
1690   0,    // second literal operand
1691   POC_NOP,
1692   (PCC_NONE | PCC_LITERAL),   // inCond
1693   PCC_W, // outCond
1694   PCI_MAGIC
1695 };
1696
1697 pCodeInstruction pic16_pciMOVWF = {
1698   {PC_OPCODE, NULL, NULL, 0, NULL,
1699    //   genericAnalyze,
1700    genericDestruct,
1701    genericPrint},
1702   POC_MOVWF,
1703   "MOVWF",
1704   2,
1705   NULL, // from branch
1706   NULL, // to branch
1707   NULL, // label
1708   NULL, // operand
1709   NULL, // flow block
1710   NULL, // C source
1711   2,    // num ops
1712   0,0,  // dest, bit instruction
1713   0,0,  // branch, skip
1714   0,    // literal operand
1715   1,    // RAM access bit
1716   0,    // fast call/return mode select bit
1717   0,    // second memory operand
1718   0,    // second literal operand
1719   POC_NOP,
1720   PCC_W,   // inCond
1721   PCC_REGISTER, // outCond
1722   PCI_MAGIC
1723 };
1724
1725 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1726   {PC_OPCODE, NULL, NULL, 0, NULL,
1727    genericDestruct,
1728    genericPrint},
1729   POC_MULLW,
1730   "MULLW",
1731   2,
1732   NULL, // from branch
1733   NULL, // to branch
1734   NULL, // label
1735   NULL, // operand
1736   NULL, // flow block
1737   NULL, // C source
1738   1,    // num ops
1739   0,0,  // dest, bit instruction
1740   0,0,  // branch, skip
1741   1,    // literal operand
1742   0,    // RAM access bit
1743   0,    // fast call/return mode select bit
1744   0,    // second memory operand
1745   0,    // second literal operand
1746   POC_NOP,
1747   (PCC_W | PCC_LITERAL),   // inCond
1748   PCC_NONE, // outCond - PROD
1749   PCI_MAGIC
1750 };
1751
1752 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1753   {PC_OPCODE, NULL, NULL, 0, NULL,
1754    genericDestruct,
1755    genericPrint},
1756   POC_MULWF,
1757   "MULWF",
1758   2,
1759   NULL, // from branch
1760   NULL, // to branch
1761   NULL, // label
1762   NULL, // operand
1763   NULL, // flow block
1764   NULL, // C source
1765   2,    // num ops
1766   0,0,  // dest, bit instruction
1767   0,0,  // branch, skip
1768   0,    // literal operand
1769   1,    // RAM access bit
1770   0,    // fast call/return mode select bit
1771   0,    // second memory operand
1772   0,    // second literal operand
1773   POC_NOP,
1774   (PCC_W | PCC_REGISTER),   // inCond
1775   PCC_REGISTER, // outCond - PROD
1776   PCI_MAGIC
1777 };
1778
1779 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1780   {PC_OPCODE, NULL, NULL, 0, NULL,
1781    genericDestruct,
1782    genericPrint},
1783   POC_NEGF,
1784   "NEGF",
1785   2,
1786   NULL, // from branch
1787   NULL, // to branch
1788   NULL, // label
1789   NULL, // operand
1790   NULL, // flow block
1791   NULL, // C source
1792   2,    // num ops
1793   0,0,  // dest, bit instruction
1794   0,0,  // branch, skip
1795   0,    // literal operand
1796   1,    // RAM access bit
1797   0,    // fast call/return mode select bit
1798   0,    // second memory operand
1799   0,    // second literal operand
1800   POC_NOP,
1801   PCC_REGISTER, // inCond
1802   (PCC_REGISTER | PCC_STATUS), // outCond
1803   PCI_MAGIC
1804 };
1805
1806 pCodeInstruction pic16_pciNOP = {
1807   {PC_OPCODE, NULL, NULL, 0, NULL,
1808    genericDestruct,
1809    genericPrint},
1810   POC_NOP,
1811   "NOP",
1812   2,
1813   NULL, // from branch
1814   NULL, // to branch
1815   NULL, // label
1816   NULL, // operand
1817   NULL, // flow block
1818   NULL, // C source
1819   0,    // num ops
1820   0,0,  // dest, bit instruction
1821   0,0,  // branch, skip
1822   0,    // literal operand
1823   0,    // RAM access bit
1824   0,    // fast call/return mode select bit
1825   0,    // second memory operand
1826   0,    // second literal operand
1827   POC_NOP,
1828   PCC_NONE,   // inCond
1829   PCC_NONE, // outCond
1830   PCI_MAGIC
1831 };
1832
1833 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1834   {PC_OPCODE, NULL, NULL, 0, NULL,
1835    genericDestruct,
1836    genericPrint},
1837   POC_POP,
1838   "POP",
1839   2,
1840   NULL, // from branch
1841   NULL, // to branch
1842   NULL, // label
1843   NULL, // operand
1844   NULL, // flow block
1845   NULL, // C source
1846   0,    // num ops
1847   0,0,  // dest, bit instruction
1848   0,0,  // branch, skip
1849   0,    // literal operand
1850   0,    // RAM access bit
1851   0,    // fast call/return mode select bit
1852   0,    // second memory operand
1853   0,    // second literal operand
1854   POC_NOP,
1855   PCC_NONE,  // inCond
1856   PCC_NONE  , // outCond
1857   PCI_MAGIC
1858 };
1859
1860 pCodeInstruction pic16_pciPUSH = {
1861   {PC_OPCODE, NULL, NULL, 0, NULL,
1862    genericDestruct,
1863    genericPrint},
1864   POC_PUSH,
1865   "PUSH",
1866   2,
1867   NULL, // from branch
1868   NULL, // to branch
1869   NULL, // label
1870   NULL, // operand
1871   NULL, // flow block
1872   NULL, // C source
1873   0,    // num ops
1874   0,0,  // dest, bit instruction
1875   0,0,  // branch, skip
1876   0,    // literal operand
1877   0,    // RAM access bit
1878   0,    // fast call/return mode select bit
1879   0,    // second memory operand
1880   0,    // second literal operand
1881   POC_NOP,
1882   PCC_NONE,  // inCond
1883   PCC_NONE  , // outCond
1884   PCI_MAGIC
1885 };
1886
1887 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1888   {PC_OPCODE, NULL, NULL, 0, NULL,
1889    genericDestruct,
1890    genericPrint},
1891   POC_RCALL,
1892   "RCALL",
1893   2,
1894   NULL, // from branch
1895   NULL, // to branch
1896   NULL, // label
1897   NULL, // operand
1898   NULL, // flow block
1899   NULL, // C source
1900   1,    // num ops
1901   0,0,  // dest, bit instruction
1902   1,0,  // branch, skip
1903   0,    // literal operand
1904   0,    // RAM access bit
1905   0,    // fast call/return mode select bit
1906   0,    // second memory operand
1907   0,    // second literal operand
1908   POC_NOP,
1909   PCC_REL_ADDR,  // inCond
1910   PCC_NONE  , // outCond
1911   PCI_MAGIC
1912 };
1913
1914 pCodeInstruction pic16_pciRETFIE = {
1915   {PC_OPCODE, NULL, NULL, 0, NULL,
1916    //   AnalyzeRETURN,
1917    genericDestruct,
1918    genericPrint},
1919   POC_RETFIE,
1920   "RETFIE",
1921   2,
1922   NULL, // from branch
1923   NULL, // to branch
1924   NULL, // label
1925   NULL, // operand
1926   NULL, // flow block
1927   NULL, // C source
1928   1,    // num ops
1929   0,0,  // dest, bit instruction
1930   1,0,  // branch, skip
1931   0,    // literal operand
1932   0,    // RAM access bit
1933   1,    // fast call/return mode select bit
1934   0,    // second memory operand
1935   0,    // second literal operand
1936   POC_NOP,
1937   PCC_NONE,   // inCond
1938   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1939   PCI_MAGIC
1940 };
1941
1942 pCodeInstruction pic16_pciRETLW = {
1943   {PC_OPCODE, NULL, NULL, 0, NULL,
1944    //   AnalyzeRETURN,
1945    genericDestruct,
1946    genericPrint},
1947   POC_RETLW,
1948   "RETLW",
1949   2,
1950   NULL, // from branch
1951   NULL, // to branch
1952   NULL, // label
1953   NULL, // operand
1954   NULL, // flow block
1955   NULL, // C source
1956   1,    // num ops
1957   0,0,  // dest, bit instruction
1958   1,0,  // branch, skip
1959   1,    // literal operand
1960   0,    // RAM access bit
1961   0,    // fast call/return mode select bit
1962   0,    // second memory operand
1963   0,    // second literal operand
1964   POC_NOP,
1965   PCC_LITERAL,   // inCond
1966   PCC_W, // outCond
1967   PCI_MAGIC
1968 };
1969
1970 pCodeInstruction pic16_pciRETURN = {
1971   {PC_OPCODE, NULL, NULL, 0, NULL,
1972    //   AnalyzeRETURN,
1973    genericDestruct,
1974    genericPrint},
1975   POC_RETURN,
1976   "RETURN",
1977   2,
1978   NULL, // from branch
1979   NULL, // to branch
1980   NULL, // label
1981   NULL, // operand
1982   NULL, // flow block
1983   NULL, // C source
1984   1,    // num ops
1985   0,0,  // dest, bit instruction
1986   1,0,  // branch, skip
1987   0,    // literal operand
1988   0,    // RAM access bit
1989   1,    // fast call/return mode select bit
1990   0,    // second memory operand
1991   0,    // second literal operand
1992   POC_NOP,
1993   PCC_NONE,   // inCond
1994   PCC_NONE, // outCond
1995   PCI_MAGIC
1996 };
1997 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1998   {PC_OPCODE, NULL, NULL, 0, NULL,
1999    //   genericAnalyze,
2000    genericDestruct,
2001    genericPrint},
2002   POC_RLCF,
2003   "RLCF",
2004   2,
2005   NULL, // from branch
2006   NULL, // to branch
2007   NULL, // label
2008   NULL, // operand
2009   NULL, // flow block
2010   NULL, // C source
2011   3,    // num ops
2012   1,0,  // dest, bit instruction
2013   0,0,  // branch, skip
2014   0,    // literal operand
2015   1,    // RAM access bit
2016   0,    // fast call/return mode select bit
2017   0,    // second memory operand
2018   0,    // second literal operand
2019   POC_NOP,
2020   (PCC_C | PCC_REGISTER),   // inCond
2021   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2022   PCI_MAGIC
2023 };
2024
2025 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2026   {PC_OPCODE, NULL, NULL, 0, NULL,
2027    //   genericAnalyze,
2028    genericDestruct,
2029    genericPrint},
2030   POC_RLCFW,
2031   "RLCF",
2032   2,
2033   NULL, // from branch
2034   NULL, // to branch
2035   NULL, // label
2036   NULL, // operand
2037   NULL, // flow block
2038   NULL, // C source
2039   3,    // num ops
2040   0,0,  // dest, bit instruction
2041   0,0,  // branch, skip
2042   0,    // literal operand
2043   1,    // RAM access bit
2044   0,    // fast call/return mode select bit
2045   0,    // second memory operand
2046   0,    // second literal operand
2047   POC_NOP,
2048   (PCC_C | PCC_REGISTER),   // inCond
2049   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2050   PCI_MAGIC
2051 };
2052
2053 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2054   {PC_OPCODE, NULL, NULL, 0, NULL,
2055    //   genericAnalyze,
2056    genericDestruct,
2057    genericPrint},
2058   POC_RLNCF,
2059   "RLNCF",
2060   2,
2061   NULL, // from branch
2062   NULL, // to branch
2063   NULL, // label
2064   NULL, // operand
2065   NULL, // flow block
2066   NULL, // C source
2067   3,    // num ops
2068   1,0,  // dest, bit instruction
2069   0,0,  // branch, skip
2070   0,    // literal operand
2071   1,    // RAM access bit
2072   0,    // fast call/return mode select bit
2073   0,    // second memory operand
2074   0,    // second literal operand
2075   POC_NOP,
2076   PCC_REGISTER,   // inCond
2077   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2078   PCI_MAGIC
2079 };
2080 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2081   {PC_OPCODE, NULL, NULL, 0, NULL,
2082    //   genericAnalyze,
2083    genericDestruct,
2084    genericPrint},
2085   POC_RLNCFW,
2086   "RLNCF",
2087   2,
2088   NULL, // from branch
2089   NULL, // to branch
2090   NULL, // label
2091   NULL, // operand
2092   NULL, // flow block
2093   NULL, // C source
2094   3,    // num ops
2095   0,0,  // dest, bit instruction
2096   0,0,  // branch, skip
2097   0,    // literal operand
2098   1,    // RAM access bit
2099   0,    // fast call/return mode select bit
2100   0,    // second memory operand
2101   0,    // second literal operand
2102   POC_NOP,
2103   PCC_REGISTER,   // inCond
2104   (PCC_W | PCC_Z | PCC_N), // outCond
2105   PCI_MAGIC
2106 };
2107 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2108   {PC_OPCODE, NULL, NULL, 0, NULL,
2109    //   genericAnalyze,
2110    genericDestruct,
2111    genericPrint},
2112   POC_RRCF,
2113   "RRCF",
2114   2,
2115   NULL, // from branch
2116   NULL, // to branch
2117   NULL, // label
2118   NULL, // operand
2119   NULL, // flow block
2120   NULL, // C source
2121   3,    // num ops
2122   1,0,  // dest, bit instruction
2123   0,0,  // branch, skip
2124   0,    // literal operand
2125   1,    // RAM access bit
2126   0,    // fast call/return mode select bit
2127   0,    // second memory operand
2128   0,    // second literal operand
2129   POC_NOP,
2130   (PCC_C | PCC_REGISTER),   // inCond
2131   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2132   PCI_MAGIC
2133 };
2134 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2135   {PC_OPCODE, NULL, NULL, 0, NULL,
2136    //   genericAnalyze,
2137    genericDestruct,
2138    genericPrint},
2139   POC_RRCFW,
2140   "RRCF",
2141   2,
2142   NULL, // from branch
2143   NULL, // to branch
2144   NULL, // label
2145   NULL, // operand
2146   NULL, // flow block
2147   NULL, // C source
2148   3,    // num ops
2149   0,0,  // dest, bit instruction
2150   0,0,  // branch, skip
2151   0,    // literal operand
2152   1,    // RAM access bit
2153   0,    // fast call/return mode select bit
2154   0,    // second memory operand
2155   0,    // second literal operand
2156   POC_NOP,
2157   (PCC_C | PCC_REGISTER),   // inCond
2158   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2159   PCI_MAGIC
2160 };
2161 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2162   {PC_OPCODE, NULL, NULL, 0, NULL,
2163    //   genericAnalyze,
2164    genericDestruct,
2165    genericPrint},
2166   POC_RRNCF,
2167   "RRNCF",
2168   2,
2169   NULL, // from branch
2170   NULL, // to branch
2171   NULL, // label
2172   NULL, // operand
2173   NULL, // flow block
2174   NULL, // C source
2175   3,    // num ops
2176   1,0,  // dest, bit instruction
2177   0,0,  // branch, skip
2178   0,    // literal operand
2179   1,    // RAM access bit
2180   0,    // fast call/return mode select bit
2181   0,    // second memory operand
2182   0,    // second literal operand
2183   POC_NOP,
2184   PCC_REGISTER,   // inCond
2185   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2186   PCI_MAGIC
2187 };
2188
2189 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2190   {PC_OPCODE, NULL, NULL, 0, NULL,
2191    //   genericAnalyze,
2192    genericDestruct,
2193    genericPrint},
2194   POC_RRNCFW,
2195   "RRNCF",
2196   2,
2197   NULL, // from branch
2198   NULL, // to branch
2199   NULL, // label
2200   NULL, // operand
2201   NULL, // flow block
2202   NULL, // C source
2203   3,    // num ops
2204   0,0,  // dest, bit instruction
2205   0,0,  // branch, skip
2206   0,    // literal operand
2207   1,    // RAM access bit
2208   0,    // fast call/return mode select bit
2209   0,    // second memory operand
2210   0,    // second literal operand
2211   POC_NOP,
2212   PCC_REGISTER,   // inCond
2213   (PCC_W | PCC_Z | PCC_N), // outCond
2214   PCI_MAGIC
2215 };
2216
2217 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2218   {PC_OPCODE, NULL, NULL, 0, NULL,
2219    //   genericAnalyze,
2220    genericDestruct,
2221    genericPrint},
2222   POC_SETF,
2223   "SETF",
2224   2,
2225   NULL, // from branch
2226   NULL, // to branch
2227   NULL, // label
2228   NULL, // operand
2229   NULL, // flow block
2230   NULL, // C source
2231   2,    // num ops
2232   0,0,  // dest, bit instruction
2233   0,0,  // branch, skip
2234   0,    // literal operand
2235   1,    // RAM access bit
2236   0,    // fast call/return mode select bit
2237   0,    // second memory operand
2238   0,    // second literal operand
2239   POC_NOP,
2240   PCC_NONE,  // inCond
2241   PCC_REGISTER  , // outCond
2242   PCI_MAGIC
2243 };
2244
2245 pCodeInstruction pic16_pciSUBLW = {
2246   {PC_OPCODE, NULL, NULL, 0, NULL,
2247    //   genericAnalyze,
2248    genericDestruct,
2249    genericPrint},
2250   POC_SUBLW,
2251   "SUBLW",
2252   2,
2253   NULL, // from branch
2254   NULL, // to branch
2255   NULL, // label
2256   NULL, // operand
2257   NULL, // flow block
2258   NULL, // C source
2259   1,    // num ops
2260   0,0,  // dest, bit instruction
2261   0,0,  // branch, skip
2262   1,    // literal operand
2263   0,    // RAM access bit
2264   0,    // fast call/return mode select bit
2265   0,    // second memory operand
2266   0,    // second literal operand
2267   POC_NOP,
2268   (PCC_W | PCC_LITERAL),   // inCond
2269   (PCC_W | PCC_STATUS), // outCond
2270   PCI_MAGIC
2271 };
2272
2273 pCodeInstruction pic16_pciSUBFWB = {
2274   {PC_OPCODE, NULL, NULL, 0, NULL,
2275    //   genericAnalyze,
2276    genericDestruct,
2277    genericPrint},
2278   POC_SUBFWB,
2279   "SUBFWB",
2280   2,
2281   NULL, // from branch
2282   NULL, // to branch
2283   NULL, // label
2284   NULL, // operand
2285   NULL, // flow block
2286   NULL, // C source
2287   3,    // num ops
2288   1,0,  // dest, bit instruction
2289   0,0,  // branch, skip
2290   0,    // literal operand
2291   1,    // RAM access bit
2292   0,    // fast call/return mode select bit
2293   0,    // second memory operand
2294   0,    // second literal operand
2295   POC_NOP,
2296   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2297   (PCC_W | PCC_STATUS), // outCond
2298   PCI_MAGIC
2299 };
2300
2301 pCodeInstruction pic16_pciSUBWF = {
2302   {PC_OPCODE, NULL, NULL, 0, NULL,
2303    //   genericAnalyze,
2304    genericDestruct,
2305    genericPrint},
2306   POC_SUBWF,
2307   "SUBWF",
2308   2,
2309   NULL, // from branch
2310   NULL, // to branch
2311   NULL, // label
2312   NULL, // operand
2313   NULL, // flow block
2314   NULL, // C source
2315   3,    // num ops
2316   1,0,  // dest, bit instruction
2317   0,0,  // branch, skip
2318   0,    // literal operand
2319   1,    // RAM access bit
2320   0,    // fast call/return mode select bit
2321   0,    // second memory operand
2322   0,    // second literal operand
2323   POC_NOP,
2324   (PCC_W | PCC_REGISTER),   // inCond
2325   (PCC_REGISTER | PCC_STATUS), // outCond
2326   PCI_MAGIC
2327 };
2328
2329 pCodeInstruction pic16_pciSUBFW = {
2330   {PC_OPCODE, NULL, NULL, 0, NULL,
2331    //   genericAnalyze,
2332    genericDestruct,
2333    genericPrint},
2334   POC_SUBFW,
2335   "SUBWF",
2336   2,
2337   NULL, // from branch
2338   NULL, // to branch
2339   NULL, // label
2340   NULL, // operand
2341   NULL, // flow block
2342   NULL, // C source
2343   3,    // num ops
2344   0,0,  // dest, bit instruction
2345   0,0,  // branch, skip
2346   0,    // literal operand
2347   1,    // RAM access bit
2348   0,    // fast call/return mode select bit
2349   0,    // second memory operand
2350   0,    // second literal operand
2351   POC_NOP,
2352   (PCC_W | PCC_REGISTER),   // inCond
2353   (PCC_W | PCC_STATUS), // outCond
2354   PCI_MAGIC
2355 };
2356
2357 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2358   {PC_OPCODE, NULL, NULL, 0, NULL,
2359    //   genericAnalyze,
2360    genericDestruct,
2361    genericPrint},
2362   POC_SUBFWB_D1,
2363   "SUBFWB",
2364   2,
2365   NULL, // from branch
2366   NULL, // to branch
2367   NULL, // label
2368   NULL, // operand
2369   NULL, // flow block
2370   NULL, // C source
2371   3,    // num ops
2372   1,0,  // dest, bit instruction
2373   0,0,  // branch, skip
2374   0,    // literal operand
2375   1,    // RAM access bit
2376   0,    // fast call/return mode select bit
2377   0,    // second memory operand
2378   0,    // second literal operand
2379   POC_NOP,
2380   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2381   (PCC_REGISTER | PCC_STATUS), // outCond
2382   PCI_MAGIC
2383 };
2384
2385 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2386   {PC_OPCODE, NULL, NULL, 0, NULL,
2387    //   genericAnalyze,
2388    genericDestruct,
2389    genericPrint},
2390   POC_SUBFWB_D0,
2391   "SUBFWB",
2392   2,
2393   NULL, // from branch
2394   NULL, // to branch
2395   NULL, // label
2396   NULL, // operand
2397   NULL, // flow block
2398   NULL, // C source
2399   3,    // num ops
2400   0,0,  // dest, bit instruction
2401   0,0,  // branch, skip
2402   0,    // literal operand
2403   1,    // RAM access bit
2404   0,    // fast call/return mode select bit
2405   0,    // second memory operand
2406   0,    // second literal operand
2407   POC_NOP,
2408   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2409   (PCC_W | PCC_STATUS), // outCond
2410   PCI_MAGIC
2411 };
2412
2413 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2414   {PC_OPCODE, NULL, NULL, 0, NULL,
2415    //   genericAnalyze,
2416    genericDestruct,
2417    genericPrint},
2418   POC_SUBWFB_D1,
2419   "SUBWFB",
2420   2,
2421   NULL, // from branch
2422   NULL, // to branch
2423   NULL, // label
2424   NULL, // operand
2425   NULL, // flow block
2426   NULL, // C source
2427   3,    // num ops
2428   1,0,  // dest, bit instruction
2429   0,0,  // branch, skip
2430   0,    // literal operand
2431   1,    // RAM access bit
2432   0,    // fast call/return mode select bit
2433   0,    // second memory operand
2434   0,    // second literal operand
2435   POC_NOP,
2436   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2437   (PCC_REGISTER | PCC_STATUS), // outCond
2438   PCI_MAGIC
2439 };
2440
2441 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2442   {PC_OPCODE, NULL, NULL, 0, NULL,
2443    //   genericAnalyze,
2444    genericDestruct,
2445    genericPrint},
2446   POC_SUBWFB_D0,
2447   "SUBWFB",
2448   2,
2449   NULL, // from branch
2450   NULL, // to branch
2451   NULL, // label
2452   NULL, // operand
2453   NULL, // flow block
2454   NULL, // C source
2455   3,    // num ops
2456   0,0,  // dest, bit instruction
2457   0,0,  // branch, skip
2458   0,    // literal operand
2459   1,    // RAM access bit
2460   0,    // fast call/return mode select bit
2461   0,    // second memory operand
2462   0,    // second literal operand
2463   POC_NOP,
2464   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2465   (PCC_W | PCC_STATUS), // outCond
2466   PCI_MAGIC
2467 };
2468
2469 pCodeInstruction pic16_pciSWAPF = {
2470   {PC_OPCODE, NULL, NULL, 0, NULL,
2471    //   genericAnalyze,
2472    genericDestruct,
2473    genericPrint},
2474   POC_SWAPF,
2475   "SWAPF",
2476   2,
2477   NULL, // from branch
2478   NULL, // to branch
2479   NULL, // label
2480   NULL, // operand
2481   NULL, // flow block
2482   NULL, // C source
2483   3,    // num ops
2484   1,0,  // dest, bit instruction
2485   0,0,  // branch, skip
2486   0,    // literal operand
2487   1,    // RAM access bit
2488   0,    // fast call/return mode select bit
2489   0,    // second memory operand
2490   0,    // second literal operand
2491   POC_NOP,
2492   (PCC_REGISTER),   // inCond
2493   (PCC_REGISTER), // outCond
2494   PCI_MAGIC
2495 };
2496
2497 pCodeInstruction pic16_pciSWAPFW = {
2498   {PC_OPCODE, NULL, NULL, 0, NULL,
2499    //   genericAnalyze,
2500    genericDestruct,
2501    genericPrint},
2502   POC_SWAPFW,
2503   "SWAPF",
2504   2,
2505   NULL, // from branch
2506   NULL, // to branch
2507   NULL, // label
2508   NULL, // operand
2509   NULL, // flow block
2510   NULL, // C source
2511   3,    // num ops
2512   0,0,  // dest, bit instruction
2513   0,0,  // branch, skip
2514   0,    // literal operand
2515   1,    // RAM access bit
2516   0,    // fast call/return mode select bit
2517   0,    // second memory operand
2518   0,    // second literal operand
2519   POC_NOP,
2520   (PCC_REGISTER),   // inCond
2521   (PCC_W), // outCond
2522   PCI_MAGIC
2523 };
2524
2525 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2526   {PC_OPCODE, NULL, NULL, 0, NULL,
2527    genericDestruct,
2528    genericPrint},
2529   POC_TBLRD,
2530   "TBLRD*",
2531   2,
2532   NULL, // from branch
2533   NULL, // to branch
2534   NULL, // label
2535   NULL, // operand
2536   NULL, // flow block
2537   NULL, // C source
2538   0,    // num ops
2539   0,0,  // dest, bit instruction
2540   0,0,  // branch, skip
2541   0,    // literal operand
2542   0,    // RAM access bit
2543   0,    // fast call/return mode select bit
2544   0,    // second memory operand
2545   0,    // second literal operand
2546   POC_NOP,
2547   PCC_NONE,  // inCond
2548   PCC_NONE  , // outCond
2549   PCI_MAGIC
2550 };
2551
2552 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2553   {PC_OPCODE, NULL, NULL, 0, NULL,
2554    genericDestruct,
2555    genericPrint},
2556   POC_TBLRD_POSTINC,
2557   "TBLRD*+",
2558   2,
2559   NULL, // from branch
2560   NULL, // to branch
2561   NULL, // label
2562   NULL, // operand
2563   NULL, // flow block
2564   NULL, // C source
2565   0,    // num ops
2566   0,0,  // dest, bit instruction
2567   0,0,  // branch, skip
2568   0,    // literal operand
2569   0,    // RAM access bit
2570   0,    // fast call/return mode select bit
2571   0,    // second memory operand
2572   0,    // second literal operand
2573   POC_NOP,
2574   PCC_NONE,  // inCond
2575   PCC_NONE  , // outCond
2576   PCI_MAGIC
2577 };
2578
2579 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2580   {PC_OPCODE, NULL, NULL, 0, NULL,
2581    genericDestruct,
2582    genericPrint},
2583   POC_TBLRD_POSTDEC,
2584   "TBLRD*-",
2585   2,
2586   NULL, // from branch
2587   NULL, // to branch
2588   NULL, // label
2589   NULL, // operand
2590   NULL, // flow block
2591   NULL, // C source
2592   0,    // num ops
2593   0,0,  // dest, bit instruction
2594   0,0,  // branch, skip
2595   0,    // literal operand
2596   0,    // RAM access bit
2597   0,    // fast call/return mode select bit
2598   0,    // second memory operand
2599   0,    // second literal operand
2600   POC_NOP,
2601   PCC_NONE,  // inCond
2602   PCC_NONE  , // outCond
2603   PCI_MAGIC
2604 };
2605
2606 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2607   {PC_OPCODE, NULL, NULL, 0, NULL,
2608    genericDestruct,
2609    genericPrint},
2610   POC_TBLRD_PREINC,
2611   "TBLRD+*",
2612   2,
2613   NULL, // from branch
2614   NULL, // to branch
2615   NULL, // label
2616   NULL, // operand
2617   NULL, // flow block
2618   NULL, // C source
2619   0,    // num ops
2620   0,0,  // dest, bit instruction
2621   0,0,  // branch, skip
2622   0,    // literal operand
2623   0,    // RAM access bit
2624   0,    // fast call/return mode select bit
2625   0,    // second memory operand
2626   0,    // second literal operand
2627   POC_NOP,
2628   PCC_NONE,  // inCond
2629   PCC_NONE  , // outCond
2630   PCI_MAGIC
2631 };
2632
2633 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2634   {PC_OPCODE, NULL, NULL, 0, NULL,
2635    genericDestruct,
2636    genericPrint},
2637   POC_TBLWT,
2638   "TBLWT*",
2639   2,
2640   NULL, // from branch
2641   NULL, // to branch
2642   NULL, // label
2643   NULL, // operand
2644   NULL, // flow block
2645   NULL, // C source
2646   0,    // num ops
2647   0,0,  // dest, bit instruction
2648   0,0,  // branch, skip
2649   0,    // literal operand
2650   0,    // RAM access bit
2651   0,    // fast call/return mode select bit
2652   0,    // second memory operand
2653   0,    // second literal operand
2654   POC_NOP,
2655   PCC_NONE,  // inCond
2656   PCC_NONE  , // outCond
2657   PCI_MAGIC
2658 };
2659
2660 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2661   {PC_OPCODE, NULL, NULL, 0, NULL,
2662    genericDestruct,
2663    genericPrint},
2664   POC_TBLWT_POSTINC,
2665   "TBLWT*+",
2666   2,
2667   NULL, // from branch
2668   NULL, // to branch
2669   NULL, // label
2670   NULL, // operand
2671   NULL, // flow block
2672   NULL, // C source
2673   0,    // num ops
2674   0,0,  // dest, bit instruction
2675   0,0,  // branch, skip
2676   0,    // literal operand
2677   0,    // RAM access bit
2678   0,    // fast call/return mode select bit
2679   0,    // second memory operand
2680   0,    // second literal operand
2681   POC_NOP,
2682   PCC_NONE,  // inCond
2683   PCC_NONE  , // outCond
2684   PCI_MAGIC
2685 };
2686
2687 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2688   {PC_OPCODE, NULL, NULL, 0, NULL,
2689    genericDestruct,
2690    genericPrint},
2691   POC_TBLWT_POSTDEC,
2692   "TBLWT*-",
2693   2,
2694   NULL, // from branch
2695   NULL, // to branch
2696   NULL, // label
2697   NULL, // operand
2698   NULL, // flow block
2699   NULL, // C source
2700   0,    // num ops
2701   0,0,  // dest, bit instruction
2702   0,0,  // branch, skip
2703   0,    // literal operand
2704   0,    // RAM access bit
2705   0,    // fast call/return mode select bit
2706   0,    // second memory operand
2707   0,    // second literal operand
2708   POC_NOP,
2709   PCC_NONE,  // inCond
2710   PCC_NONE  , // outCond
2711   PCI_MAGIC
2712 };
2713
2714 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2715   {PC_OPCODE, NULL, NULL, 0, NULL,
2716    genericDestruct,
2717    genericPrint},
2718   POC_TBLWT_PREINC,
2719   "TBLWT+*",
2720   2,
2721   NULL, // from branch
2722   NULL, // to branch
2723   NULL, // label
2724   NULL, // operand
2725   NULL, // flow block
2726   NULL, // C source
2727   0,    // num ops
2728   0,0,  // dest, bit instruction
2729   0,0,  // branch, skip
2730   0,    // literal operand
2731   0,    // RAM access bit
2732   0,    // fast call/return mode select bit
2733   0,    // second memory operand
2734   0,    // second literal operand
2735   POC_NOP,
2736   PCC_NONE,  // inCond
2737   PCC_NONE  , // outCond
2738   PCI_MAGIC
2739 };
2740
2741 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2742   {PC_OPCODE, NULL, NULL, 0, NULL,
2743    //   genericAnalyze,
2744    genericDestruct,
2745    genericPrint},
2746   POC_TSTFSZ,
2747   "TSTFSZ",
2748   2,
2749   NULL, // from branch
2750   NULL, // to branch
2751   NULL, // label
2752   NULL, // operand
2753   NULL, // flow block
2754   NULL, // C source
2755   2,    // num ops
2756   0,0,  // dest, bit instruction
2757   1,1,  // branch, skip
2758   0,    // literal operand
2759   1,    // RAM access bit
2760   0,    // fast call/return mode select bit
2761   0,    // second memory operand
2762   0,    // second literal operand
2763   POC_NOP,
2764   PCC_REGISTER,   // inCond
2765   PCC_NONE, // outCond
2766   PCI_MAGIC
2767 };
2768
2769 pCodeInstruction pic16_pciXORWF = {
2770   {PC_OPCODE, NULL, NULL, 0, NULL,
2771    //   genericAnalyze,
2772    genericDestruct,
2773    genericPrint},
2774   POC_XORWF,
2775   "XORWF",
2776   2,
2777   NULL, // from branch
2778   NULL, // to branch
2779   NULL, // label
2780   NULL, // operand
2781   NULL, // flow block
2782   NULL, // C source
2783   3,    // num ops
2784   1,0,  // dest, bit instruction
2785   0,0,  // branch, skip
2786   0,    // literal operand
2787   1,    // RAM access bit
2788   0,    // fast call/return mode select bit
2789   0,    // second memory operand
2790   0,    // second literal operand
2791   POC_NOP,
2792   (PCC_W | PCC_REGISTER),   // inCond
2793   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2794   PCI_MAGIC
2795 };
2796
2797 pCodeInstruction pic16_pciXORFW = {
2798   {PC_OPCODE, NULL, NULL, 0, NULL,
2799    //   genericAnalyze,
2800    genericDestruct,
2801    genericPrint},
2802   POC_XORFW,
2803   "XORWF",
2804   2,
2805   NULL, // from branch
2806   NULL, // to branch
2807   NULL, // label
2808   NULL, // operand
2809   NULL, // flow block
2810   NULL, // C source
2811   3,    // num ops
2812   0,0,  // dest, bit instruction
2813   0,0,  // branch, skip
2814   0,    // literal operand
2815   1,    // RAM access bit
2816   0,    // fast call/return mode select bit
2817   0,    // second memory operand
2818   0,    // second literal operand
2819   POC_NOP,
2820   (PCC_W | PCC_REGISTER),   // inCond
2821   (PCC_W | PCC_Z | PCC_N), // outCond
2822   PCI_MAGIC
2823 };
2824
2825 pCodeInstruction pic16_pciXORLW = {
2826   {PC_OPCODE, NULL, NULL, 0, NULL,
2827    //   genericAnalyze,
2828    genericDestruct,
2829    genericPrint},
2830   POC_XORLW,
2831   "XORLW",
2832   2,
2833   NULL, // from branch
2834   NULL, // to branch
2835   NULL, // label
2836   NULL, // operand
2837   NULL, // flow block
2838   NULL, // C source
2839   1,    // num ops
2840   0,0,  // dest, bit instruction
2841   0,0,  // branch, skip
2842   1,    // literal operand
2843   1,    // RAM access bit
2844   0,    // fast call/return mode select bit
2845   0,    // second memory operand
2846   0,    // second literal operand
2847   POC_NOP,
2848   (PCC_W | PCC_LITERAL),   // inCond
2849   (PCC_W | PCC_Z | PCC_N), // outCond
2850   PCI_MAGIC
2851 };
2852
2853
2854 pCodeInstruction pic16_pciBANKSEL = {
2855   {PC_OPCODE, NULL, NULL, 0, NULL,
2856    genericDestruct,
2857    genericPrint},
2858   POC_BANKSEL,
2859   "BANKSEL",
2860   2,
2861   NULL, // from branch
2862   NULL, // to branch
2863   NULL, // label
2864   NULL, // operand
2865   NULL, // flow block
2866   NULL, // C source
2867   0,    // num ops
2868   0,0,  // dest, bit instruction
2869   0,0,  // branch, skip
2870   0,    // literal operand
2871   0,    // RAM access bit
2872   0,    // fast call/return mode select bit
2873   0,    // second memory operand
2874   0,    // second literal operand
2875   POC_NOP,
2876   PCC_NONE,   // inCond
2877   PCC_NONE, // outCond
2878   PCI_MAGIC
2879 };
2880
2881
2882 #define MAX_PIC16MNEMONICS 100
2883 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2884
2885 //#define USE_VSNPRINTF
2886 #if OPT_DISABLE_PIC
2887
2888 #ifdef USE_VSNPRINTF
2889   // Alas, vsnprintf is not ANSI standard, and does not exist
2890   // on Solaris (and probably other non-Gnu flavored Unixes).
2891
2892 /*-----------------------------------------------------------------*/
2893 /* SAFE_snprintf - like snprintf except the string pointer is      */
2894 /*                 after the string has been printed to. This is   */
2895 /*                 useful for printing to string as though if it   */
2896 /*                 were a stream.                                  */
2897 /*-----------------------------------------------------------------*/
2898 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2899 {
2900   va_list val;
2901   int len;
2902
2903   if(!str || !*str)
2904     return;
2905
2906   va_start(val, format);
2907
2908   vsnprintf(*str, *size, format, val);
2909
2910   va_end (val);
2911
2912   len = strlen(*str);
2913   if(len > *size) {
2914     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2915     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2916   }
2917
2918   *str += len;
2919   *size -= len;
2920
2921 }
2922
2923 #else
2924 // This version is *not* safe, despite the name.
2925
2926 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2927 {
2928   va_list val;
2929   int len;
2930   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2931
2932   if(!str || !*str)
2933     return;
2934
2935   va_start(val, format);
2936
2937   vsprintf(buffer, format, val);
2938   va_end (val);
2939
2940   len = strlen(buffer);
2941   if(len > *size) {
2942     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2943     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2944   }
2945
2946   strcpy(*str, buffer);
2947   *str += len;
2948   *size -= len;
2949
2950 }
2951
2952 #endif    //  USE_VSNPRINTF
2953 #endif
2954
2955 extern set *externs;
2956 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2957 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2958
2959 void  pic16_pCodeInitRegisters(void)
2960 {
2961   static int initialized=0;
2962
2963         if(initialized)
2964                 return;
2965
2966         initialized = 1;
2967
2968         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2969         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2970         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2971         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2972         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2973         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2974         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2975
2976         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2977         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2978         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2979
2980         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2981         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2982         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2983         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2984
2985         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2986         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2987         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2988         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2989         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2990         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2991
2992         pic16_stackpnt_lo = &pic16_pc_fsr1l;
2993         pic16_stackpnt_hi = &pic16_pc_fsr1h;
2994         pic16_stack_postdec = &pic16_pc_postdec1;
2995         pic16_stack_postinc = &pic16_pc_postinc1;
2996         pic16_stack_preinc = &pic16_pc_preinc1;
2997         pic16_stack_plusw = &pic16_pc_plusw1;
2998
2999         pic16_framepnt_lo = &pic16_pc_fsr2l;
3000         pic16_framepnt_hi = &pic16_pc_fsr2h;
3001         pic16_frame_postdec = &pic16_pc_postdec2;
3002         pic16_frame_postinc = &pic16_pc_postinc2;
3003         pic16_frame_preinc = &pic16_pc_preinc2;
3004         pic16_frame_plusw = &pic16_pc_plusw2;
3005
3006         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3007         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3008         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3009         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3010         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3011
3012         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3013         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3014         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3015         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3016         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3017
3018         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3019         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3020         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3021         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3022         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3023
3024         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3025         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3026
3027
3028         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3029         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3030         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3031         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3032
3033
3034         pic16_pc_status.rIdx = IDX_STATUS;
3035         pic16_pc_intcon.rIdx = IDX_INTCON;
3036         pic16_pc_pcl.rIdx = IDX_PCL;
3037         pic16_pc_pclath.rIdx = IDX_PCLATH;
3038         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3039         pic16_pc_wreg.rIdx = IDX_WREG;
3040         pic16_pc_bsr.rIdx = IDX_BSR;
3041
3042         pic16_pc_tosl.rIdx = IDX_TOSL;
3043         pic16_pc_tosh.rIdx = IDX_TOSH;
3044         pic16_pc_tosu.rIdx = IDX_TOSU;
3045
3046         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3047         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3048         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3049         pic16_pc_tablat.rIdx = IDX_TABLAT;
3050
3051         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3052         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3053         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3054         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3055         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3056         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3057         pic16_pc_indf0.rIdx = IDX_INDF0;
3058         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3059         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3060         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3061         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3062         pic16_pc_indf1.rIdx = IDX_INDF1;
3063         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3064         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3065         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3066         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3067         pic16_pc_indf2.rIdx = IDX_INDF2;
3068         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3069         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3070         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3071         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3072         pic16_pc_prodl.rIdx = IDX_PRODL;
3073         pic16_pc_prodh.rIdx = IDX_PRODH;
3074
3075         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3076         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3077         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3078
3079         pic16_pc_kzero.rIdx = IDX_KZ;
3080         pic16_pc_wsave.rIdx = IDX_WSAVE;
3081         pic16_pc_ssave.rIdx = IDX_SSAVE;
3082
3083         pic16_pc_eecon1.rIdx = IDX_EECON1;
3084         pic16_pc_eecon2.rIdx = IDX_EECON2;
3085         pic16_pc_eedata.rIdx = IDX_EEDATA;
3086         pic16_pc_eeadr.rIdx = IDX_EEADR;
3087
3088
3089         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3090         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3091
3092         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3093         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3094
3095         /* probably should put this in a separate initialization routine */
3096         pb_dead_pcodes = newpBlock();
3097
3098 }
3099
3100 #if OPT_DISABLE_PIC
3101 /*-----------------------------------------------------------------*/
3102 /*  mnem2key - convert a pic mnemonic into a hash key              */
3103 /*   (BTW - this spreads the mnemonics quite well)                 */
3104 /*                                                                 */
3105 /*-----------------------------------------------------------------*/
3106
3107 int mnem2key(unsigned char const *mnem)
3108 {
3109   int key = 0;
3110
3111   if(!mnem)
3112     return 0;
3113
3114   while(*mnem) {
3115
3116     key += toupper(*mnem++) +1;
3117
3118   }
3119
3120   return (key & 0x1f);
3121
3122 }
3123 #endif
3124
3125 void pic16initMnemonics(void)
3126 {
3127   int i = 0;
3128   int key;
3129   //  char *str;
3130   pCodeInstruction *pci;
3131
3132   if(mnemonics_initialized)
3133     return;
3134
3135   // NULL out the array before making the assignments
3136   // since we check the array contents below this initialization.
3137
3138   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3139     pic16Mnemonics[i] = NULL;
3140   }
3141
3142   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3143   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3144   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3145   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3146   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3147   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3148   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3149   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3150   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3151   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3152   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3153   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3154   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3155   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3156   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3157   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3158   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3159   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3160   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3161   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3162   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3163   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3164   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3165   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3166   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3167   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3168   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3169   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3170   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3171   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3172   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3173   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3174   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3175   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3176   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3177   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3178   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3179   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3180   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3181   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3182   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3183   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3184   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3185   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3186   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3187   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3188   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3189   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3190   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3191   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3192   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3193   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3194   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3195   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3196   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3197   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3198   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3199   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3200   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3201   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3202   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3203   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3204   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3205   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3206   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3207   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3208   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3209   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3210   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3211   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3212   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3213   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3214   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3215   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3216   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3217   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3218   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3219   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3220   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3221   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3222   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3223   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3224   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3225   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3226   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3227   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3228   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3229   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3230   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3231   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3232   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3233   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3234   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3235   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3236
3237   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3238     if(pic16Mnemonics[i])
3239       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3240   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3241
3242   while(pci) {
3243     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3244     pci = hTabNextItem(pic16MnemonicsHash, &key);
3245   }
3246
3247   mnemonics_initialized = 1;
3248 }
3249
3250 int pic16_getpCodePeepCommand(char *cmd);
3251
3252 int pic16_getpCode(char *mnem,unsigned dest)
3253 {
3254
3255   pCodeInstruction *pci;
3256   int key = mnem2key((unsigned char *)mnem);
3257
3258   if(!mnemonics_initialized)
3259     pic16initMnemonics();
3260
3261   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3262
3263   while(pci) {
3264
3265     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3266       if((pci->num_ops <= 1)
3267         || (pci->isModReg == dest)
3268         || (pci->isBitInst)
3269         || (pci->num_ops <= 2 && pci->isAccess)
3270         || (pci->num_ops <= 2 && pci->isFastCall)
3271         || (pci->num_ops <= 2 && pci->is2MemOp)
3272         || (pci->num_ops <= 2 && pci->is2LitOp) )
3273         return(pci->op);
3274     }
3275
3276     pci = hTabNextItemWK (pic16MnemonicsHash);
3277
3278   }
3279
3280   return -1;
3281 }
3282
3283 /*-----------------------------------------------------------------*
3284  * pic16initpCodePeepCommands
3285  *
3286  *-----------------------------------------------------------------*/
3287 void pic16initpCodePeepCommands(void)
3288 {
3289
3290   int key, i;
3291   peepCommand *pcmd;
3292
3293   i = 0;
3294   do {
3295     hTabAddItem(&pic16pCodePeepCommandsHash,
3296                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3297     i++;
3298   } while (peepCommands[i].cmd);
3299
3300   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3301
3302   while(pcmd) {
3303     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3304     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3305   }
3306
3307 }
3308
3309 /*-----------------------------------------------------------------
3310  *
3311  *
3312  *-----------------------------------------------------------------*/
3313
3314 int pic16_getpCodePeepCommand(char *cmd)
3315 {
3316
3317   peepCommand *pcmd;
3318   int key = mnem2key((unsigned char *)cmd);
3319
3320
3321   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3322
3323   while(pcmd) {
3324     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3325     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3326       return pcmd->id;
3327     }
3328
3329     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3330
3331   }
3332
3333   return -1;
3334 }
3335
3336 static char getpBlock_dbName(pBlock *pb)
3337 {
3338   if(!pb)
3339     return 0;
3340
3341   if(pb->cmemmap)
3342     return pb->cmemmap->dbName;
3343
3344   return pb->dbName;
3345 }
3346 void pic16_pBlockConvert2ISR(pBlock *pb)
3347 {
3348         if(!pb)return;
3349
3350         if(pb->cmemmap)pb->cmemmap = NULL;
3351
3352         pb->dbName = 'I';
3353
3354         if(pic16_pcode_verbose)
3355                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3356 }
3357
3358 void pic16_pBlockConvert2Absolute(pBlock *pb)
3359 {
3360         if(!pb)return;
3361         if(pb->cmemmap)pb->cmemmap = NULL;
3362
3363         pb->dbName = 'A';
3364
3365         if(pic16_pcode_verbose)
3366                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3367 }
3368
3369 /*-----------------------------------------------------------------*/
3370 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3371 /*                   instances to the front of the doubly linked   */
3372 /*                   list of pBlocks                               */
3373 /*-----------------------------------------------------------------*/
3374
3375 void pic16_movepBlock2Head(char dbName)
3376 {
3377   pBlock *pb;
3378
3379
3380   /* this can happen in sources without code,
3381    * only variable definitions */
3382   if(!the_pFile)return;
3383
3384   pb = the_pFile->pbHead;
3385
3386   while(pb) {
3387
3388     if(getpBlock_dbName(pb) == dbName) {
3389       pBlock *pbn = pb->next;
3390       pb->next = the_pFile->pbHead;
3391       the_pFile->pbHead->prev = pb;
3392       the_pFile->pbHead = pb;
3393
3394       if(pb->prev)
3395         pb->prev->next = pbn;
3396
3397       // If the pBlock that we just moved was the last
3398       // one in the link of all of the pBlocks, then we
3399       // need to point the tail to the block just before
3400       // the one we moved.
3401       // Note: if pb->next is NULL, then pb must have
3402       // been the last pBlock in the chain.
3403
3404       if(pbn)
3405         pbn->prev = pb->prev;
3406       else
3407         the_pFile->pbTail = pb->prev;
3408
3409       pb = pbn;
3410
3411     } else
3412       pb = pb->next;
3413
3414   }
3415
3416 }
3417
3418 void pic16_copypCode(FILE *of, char dbName)
3419 {
3420   pBlock *pb;
3421
3422         if(!of || !the_pFile)
3423                 return;
3424
3425         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3426                 if(getpBlock_dbName(pb) == dbName) {
3427 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3428                         pBlockStats(of,pb);
3429                         pic16_printpBlock(of,pb);
3430                 }
3431         }
3432
3433 }
3434 void pic16_pcode_test(void)
3435 {
3436
3437   DFPRINTF((stderr,"pcode is alive!\n"));
3438
3439   //initMnemonics();
3440
3441   if(the_pFile) {
3442
3443     pBlock *pb;
3444     FILE *pFile;
3445     char buffer[100];
3446
3447     /* create the file name */
3448     strcpy(buffer,dstFileName);
3449     strcat(buffer,".p");
3450
3451     if( !(pFile = fopen(buffer, "w" ))) {
3452       werror(E_FILE_OPEN_ERR,buffer);
3453       exit(1);
3454     }
3455
3456     fprintf(pFile,"pcode dump\n\n");
3457
3458     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3459       fprintf(pFile,"\n\tNew pBlock\n\n");
3460       if(pb->cmemmap)
3461         fprintf(pFile,"%s",pb->cmemmap->sname);
3462       else
3463         fprintf(pFile,"internal pblock");
3464
3465       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3466       pic16_printpBlock(pFile,pb);
3467     }
3468   }
3469 }
3470
3471
3472 unsigned long pic16_countInstructions(void)
3473 {
3474   pBlock *pb;
3475   pCode *pc;
3476   unsigned long isize=0;
3477
3478     if(!the_pFile)return -1;
3479
3480     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3481       for(pc = pb->pcHead; pc; pc = pc->next) {
3482         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3483       }
3484     }
3485   return (isize);
3486 }
3487
3488
3489 /*-----------------------------------------------------------------*/
3490 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3491 /*      ister, RegCond will return the bit being referenced.       */
3492 /*                                                                 */
3493 /* fixme - why not just OR in the pcop bit field                   */
3494 /*-----------------------------------------------------------------*/
3495
3496 static int RegCond(pCodeOp *pcop)
3497 {
3498
3499   if(!pcop)
3500     return 0;
3501
3502   if(!pcop->name)return 0;
3503
3504   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3505     switch(PCORB(pcop)->bit) {
3506     case PIC_C_BIT:
3507       return PCC_C;
3508     case PIC_DC_BIT:
3509         return PCC_DC;
3510     case PIC_Z_BIT:
3511       return PCC_Z;
3512     }
3513
3514   }
3515
3516   return 0;
3517 }
3518
3519
3520 /*-----------------------------------------------------------------*/
3521 /* pic16_newpCode - create and return a newly initialized pCode          */
3522 /*                                                                 */
3523 /*  fixme - rename this                                            */
3524 /*                                                                 */
3525 /* The purpose of this routine is to create a new Instruction      */
3526 /* pCode. This is called by gen.c while the assembly code is being */
3527 /* generated.                                                      */
3528 /*                                                                 */
3529 /* Inouts:                                                         */
3530 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3531 /*                  (note that the op is analogous to but not the  */
3532 /*                  same thing as the opcode of the instruction.)  */
3533 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3534 /*                                                                 */
3535 /* Outputs:                                                        */
3536 /*  a pointer to the new malloc'd pCode is returned.               */
3537 /*                                                                 */
3538 /*                                                                 */
3539 /*                                                                 */
3540 /*-----------------------------------------------------------------*/
3541 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3542 {
3543   pCodeInstruction *pci ;
3544
3545   if(!mnemonics_initialized)
3546     pic16initMnemonics();
3547
3548   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3549
3550   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3551     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3552     pci->pcop = pcop;
3553
3554     if(pci->inCond & PCC_EXAMINE_PCOP)
3555       pci->inCond  |= RegCond(pcop);
3556
3557     if(pci->outCond & PCC_EXAMINE_PCOP)
3558       pci->outCond  |= RegCond(pcop);
3559
3560     pci->pc.prev = pci->pc.next = NULL;
3561     return (pCode *)pci;
3562   }
3563
3564   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3565   exit(1);
3566
3567   return NULL;
3568 }
3569
3570 /*-----------------------------------------------------------------*/
3571 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3572 /*                                                                 */
3573 /* Wild pcodes are used during the peep hole optimizer to serve    */
3574 /* as place holders for any instruction. When a snippet of code is */
3575 /* compared to a peep hole rule, the wild card opcode will match   */
3576 /* any instruction. However, the optional operand and label are    */
3577 /* additional qualifiers that must also be matched before the      */
3578 /* line (of assembly code) is declared matched. Note that the      */
3579 /* operand may be wild too.                                        */
3580 /*                                                                 */
3581 /*   Note, a wild instruction is specified just like a wild var:   */
3582 /*      %4     ; A wild instruction,                               */
3583 /*  See the peeph.def file for additional examples                 */
3584 /*                                                                 */
3585 /*-----------------------------------------------------------------*/
3586
3587 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3588 {
3589
3590   pCodeWild *pcw;
3591
3592   pcw = Safe_calloc(1,sizeof(pCodeWild));
3593
3594   pcw->pci.pc.type = PC_WILD;
3595   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3596   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3597   pcw->pci.pc.pb = NULL;
3598
3599   //  pcw->pci.pc.analyze = genericAnalyze;
3600   pcw->pci.pc.destruct = genericDestruct;
3601   pcw->pci.pc.print = genericPrint;
3602
3603   pcw->id = pCodeID;              // this is the 'n' in %n
3604   pcw->operand = optional_operand;
3605   pcw->label   = optional_label;
3606
3607   pcw->mustBeBitSkipInst = 0;
3608   pcw->mustNotBeBitSkipInst = 0;
3609   pcw->invertBitSkipInst = 0;
3610
3611   return ( (pCode *)pcw);
3612
3613 }
3614
3615  /*-----------------------------------------------------------------*/
3616 /* newPcodeInlineP - create a new pCode from a char string           */
3617 /*-----------------------------------------------------------------*/
3618
3619
3620 pCode *pic16_newpCodeInlineP(char *cP)
3621 {
3622
3623   pCodeComment *pcc ;
3624
3625   pcc = Safe_calloc(1,sizeof(pCodeComment));
3626
3627   pcc->pc.type = PC_INLINE;
3628   pcc->pc.prev = pcc->pc.next = NULL;
3629   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3630   pcc->pc.pb = NULL;
3631
3632   //  pcc->pc.analyze = genericAnalyze;
3633   pcc->pc.destruct = genericDestruct;
3634   pcc->pc.print = genericPrint;
3635
3636   if(cP)
3637     pcc->comment = Safe_strdup(cP);
3638   else
3639     pcc->comment = NULL;
3640
3641   return ( (pCode *)pcc);
3642
3643 }
3644
3645 /*-----------------------------------------------------------------*/
3646 /* newPcodeCharP - create a new pCode from a char string           */
3647 /*-----------------------------------------------------------------*/
3648
3649 pCode *pic16_newpCodeCharP(char *cP)
3650 {
3651
3652   pCodeComment *pcc ;
3653
3654   pcc = Safe_calloc(1,sizeof(pCodeComment));
3655
3656   pcc->pc.type = PC_COMMENT;
3657   pcc->pc.prev = pcc->pc.next = NULL;
3658   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3659   pcc->pc.pb = NULL;
3660
3661   //  pcc->pc.analyze = genericAnalyze;
3662   pcc->pc.destruct = genericDestruct;
3663   pcc->pc.print = genericPrint;
3664
3665   if(cP)
3666     pcc->comment = Safe_strdup(cP);
3667   else
3668     pcc->comment = NULL;
3669
3670   return ( (pCode *)pcc);
3671
3672 }
3673
3674 /*-----------------------------------------------------------------*/
3675 /* pic16_newpCodeFunction -                                              */
3676 /*-----------------------------------------------------------------*/
3677
3678
3679 pCode *pic16_newpCodeFunction(char *mod,char *f)
3680 {
3681   pCodeFunction *pcf;
3682
3683   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3684
3685   pcf->pc.type = PC_FUNCTION;
3686   pcf->pc.prev = pcf->pc.next = NULL;
3687   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3688   pcf->pc.pb = NULL;
3689
3690   //  pcf->pc.analyze = genericAnalyze;
3691   pcf->pc.destruct = genericDestruct;
3692   pcf->pc.print = pCodePrintFunction;
3693
3694   pcf->ncalled = 0;
3695   pcf->absblock = 0;
3696
3697   if(mod) {
3698     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3699     strcpy(pcf->modname,mod);
3700   } else
3701     pcf->modname = NULL;
3702
3703   if(f) {
3704     pcf->fname = Safe_calloc(1,strlen(f)+1);
3705     strcpy(pcf->fname,f);
3706   } else
3707     pcf->fname = NULL;
3708
3709   pcf->stackusage = 0;
3710
3711   return ( (pCode *)pcf);
3712 }
3713
3714 /*-----------------------------------------------------------------*/
3715 /* pic16_newpCodeFlow                                                    */
3716 /*-----------------------------------------------------------------*/
3717 static void destructpCodeFlow(pCode *pc)
3718 {
3719   if(!pc || !isPCFL(pc))
3720     return;
3721
3722 /*
3723   if(PCFL(pc)->from)
3724   if(PCFL(pc)->to)
3725 */
3726   pic16_unlinkpCode(pc);
3727
3728   deleteSet(&PCFL(pc)->registers);
3729   deleteSet(&PCFL(pc)->from);
3730   deleteSet(&PCFL(pc)->to);
3731
3732   /* Instead of deleting the memory used by this pCode, mark
3733    * the object as bad so that if there's a pointer to this pCode
3734    * dangling around somewhere then (hopefully) when the type is
3735    * checked we'll catch it.
3736    */
3737
3738   pc->type = PC_BAD;
3739   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3740
3741 //  Safe_free(pc);
3742
3743 }
3744
3745 pCode *pic16_newpCodeFlow(void )
3746 {
3747   pCodeFlow *pcflow;
3748
3749   //_ALLOC(pcflow,sizeof(pCodeFlow));
3750   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3751
3752   pcflow->pc.type = PC_FLOW;
3753   pcflow->pc.prev = pcflow->pc.next = NULL;
3754   pcflow->pc.pb = NULL;
3755
3756   //  pcflow->pc.analyze = genericAnalyze;
3757   pcflow->pc.destruct = destructpCodeFlow;
3758   pcflow->pc.print = genericPrint;
3759
3760   pcflow->pc.seq = GpcFlowSeq++;
3761
3762   pcflow->from = pcflow->to = NULL;
3763
3764   pcflow->inCond = PCC_NONE;
3765   pcflow->outCond = PCC_NONE;
3766
3767   pcflow->firstBank = -1;
3768   pcflow->lastBank = -1;
3769
3770   pcflow->FromConflicts = 0;
3771   pcflow->ToConflicts = 0;
3772
3773   pcflow->end = NULL;
3774
3775   pcflow->registers = newSet();
3776
3777   return ( (pCode *)pcflow);
3778
3779 }
3780
3781 /*-----------------------------------------------------------------*/
3782 /*-----------------------------------------------------------------*/
3783 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3784 {
3785   pCodeFlowLink *pcflowLink;
3786
3787   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3788
3789   pcflowLink->pcflow = pcflow;
3790   pcflowLink->bank_conflict = 0;
3791
3792   return pcflowLink;
3793 }
3794
3795 /*-----------------------------------------------------------------*/
3796 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3797 /*-----------------------------------------------------------------*/
3798
3799 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3800 {
3801
3802   pCodeCSource *pccs;
3803
3804   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3805
3806   pccs->pc.type = PC_CSOURCE;
3807   pccs->pc.prev = pccs->pc.next = NULL;
3808   pccs->pc.pb = NULL;
3809
3810   pccs->pc.destruct = genericDestruct;
3811   pccs->pc.print = genericPrint;
3812
3813   pccs->line_number = ln;
3814   if(l)
3815     pccs->line = Safe_strdup(l);
3816   else
3817     pccs->line = NULL;
3818
3819   if(f)
3820     pccs->file_name = Safe_strdup(f);
3821   else
3822     pccs->file_name = NULL;
3823
3824   return ( (pCode *)pccs);
3825
3826 }
3827
3828
3829 /*******************************************************************/
3830 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3831 /*                      added by VR 6-Jun-2003                     */
3832 /*******************************************************************/
3833
3834 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3835 {
3836   pCodeAsmDir *pcad;
3837   va_list ap;
3838   char buffer[512];
3839   char *lbp=buffer;
3840
3841         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3842         pcad->pci.pc.type = PC_ASMDIR;
3843         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3844         pcad->pci.pc.pb = NULL;
3845         pcad->pci.isize = 2;
3846         pcad->pci.pc.destruct = genericDestruct;
3847         pcad->pci.pc.print = genericPrint;
3848
3849         if(asdir && *asdir) {
3850
3851                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3852
3853                 pcad->directive = Safe_strdup( asdir );
3854         }
3855
3856         va_start(ap, argfmt);
3857
3858         memset(buffer, 0, sizeof(buffer));
3859         if(argfmt && *argfmt)
3860                 vsprintf(buffer, argfmt, ap);
3861
3862         va_end(ap);
3863
3864         while(isspace((unsigned char)*lbp))lbp++;
3865
3866         if(lbp && *lbp)
3867                 pcad->arg = Safe_strdup( lbp );
3868
3869   return ((pCode *)pcad);
3870 }
3871
3872 /*-----------------------------------------------------------------*/
3873 /* pCodeLabelDestruct - free memory used by a label.               */
3874 /*-----------------------------------------------------------------*/
3875 static void pCodeLabelDestruct(pCode *pc)
3876 {
3877
3878   if(!pc)
3879     return;
3880
3881 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3882 //    Safe_free(PCL(pc)->label);
3883
3884   /* Instead of deleting the memory used by this pCode, mark
3885    * the object as bad so that if there's a pointer to this pCode
3886    * dangling around somewhere then (hopefully) when the type is
3887    * checked we'll catch it.
3888    */
3889
3890   pc->type = PC_BAD;
3891   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3892
3893 //  Safe_free(pc);
3894
3895 }
3896
3897 pCode *pic16_newpCodeLabel(char *name, int key)
3898 {
3899
3900   char *s = buffer;
3901   pCodeLabel *pcl;
3902
3903   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3904
3905   pcl->pc.type = PC_LABEL;
3906   pcl->pc.prev = pcl->pc.next = NULL;
3907   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3908   pcl->pc.pb = NULL;
3909
3910   //  pcl->pc.analyze = genericAnalyze;
3911   pcl->pc.destruct = pCodeLabelDestruct;
3912   pcl->pc.print = pCodePrintLabel;
3913
3914   pcl->key = key;
3915   pcl->force = 0;
3916
3917   pcl->label = NULL;
3918   if(key>0) {
3919     sprintf(s,"_%05d_DS_",key);
3920   } else
3921     s = name;
3922
3923   if(s)
3924     pcl->label = Safe_strdup(s);
3925
3926 //  if(pic16_pcode_verbose)
3927 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3928
3929
3930   return ( (pCode *)pcl);
3931
3932 }
3933
3934 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3935 {
3936   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3937
3938         pcl->force = 1;
3939
3940   return ( (pCode *)pcl );
3941 }
3942
3943 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3944 {
3945   pCodeInfo *pci;
3946
3947     pci = Safe_calloc(1, sizeof(pCodeInfo));
3948     pci->pci.pc.type = PC_INFO;
3949     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3950     pci->pci.pc.pb = NULL;
3951     pci->pci.label = NULL;
3952
3953     pci->pci.pc.destruct = genericDestruct;
3954     pci->pci.pc.print = genericPrint;
3955
3956     pci->type = type;
3957     pci->oper1 = pcop;
3958
3959   return ((pCode *)pci);
3960 }
3961
3962
3963 /*-----------------------------------------------------------------*/
3964 /* newpBlock - create and return a pointer to a new pBlock         */
3965 /*-----------------------------------------------------------------*/
3966 static pBlock *newpBlock(void)
3967 {
3968
3969   pBlock *PpB;
3970
3971   PpB = Safe_calloc(1,sizeof(pBlock) );
3972   PpB->next = PpB->prev = NULL;
3973
3974   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3975   PpB->tregisters = NULL;
3976   PpB->visited = 0;
3977   PpB->FlowTree = NULL;
3978
3979   return PpB;
3980
3981 }
3982
3983 /*-----------------------------------------------------------------*/
3984 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3985 /*-----------------------------------------------------------------*
3986  *
3987  *  This function will create a new pBlock and the pointer to the
3988  *  pCode that is passed in will be the first pCode in the block.
3989  *-----------------------------------------------------------------*/
3990
3991
3992 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3993 {
3994
3995   pBlock *pB  = newpBlock();
3996
3997   pB->pcHead  = pB->pcTail = pc;
3998   pB->cmemmap = cm;
3999   pB->dbName  = c;
4000
4001   return pB;
4002 }
4003
4004
4005
4006 /*-----------------------------------------------------------------*/
4007 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4008 /*  Note, a negative key means that the label is part of wild card */
4009 /*  (and hence a wild card label) used in the pCodePeep            */
4010 /*   optimizations).                                               */
4011 /*-----------------------------------------------------------------*/
4012
4013 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4014 {
4015   char *s=NULL;
4016   static int label_key=-1;
4017
4018   pCodeOp *pcop;
4019
4020   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4021   pcop->type = PO_LABEL;
4022
4023   pcop->name = NULL;
4024
4025   if(key>0)
4026     sprintf(s=buffer,"_%05d_DS_",key);
4027   else
4028     s = name, key = label_key--;
4029
4030   if(s)
4031     pcop->name = Safe_strdup(s);
4032
4033   ((pCodeOpLabel *)pcop)->key = key;
4034
4035   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4036   return pcop;
4037 }
4038
4039 /*-----------------------------------------------------------------*/
4040 /*-----------------------------------------------------------------*/
4041 pCodeOp *pic16_newpCodeOpLit(int lit)
4042 {
4043   char *s = buffer;
4044   pCodeOp *pcop;
4045
4046
4047   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4048   pcop->type = PO_LITERAL;
4049
4050   pcop->name = NULL;
4051   //if(lit>=0)
4052     sprintf(s,"0x%02hhx", (unsigned char)lit);
4053   //else
4054   //  sprintf(s, "%i", lit);
4055
4056   if(s)
4057     pcop->name = Safe_strdup(s);
4058
4059   ((pCodeOpLit *)pcop)->lit = lit;
4060
4061   return pcop;
4062 }
4063
4064 /* Allow for 12 bit literals, required for LFSR */
4065 pCodeOp *pic16_newpCodeOpLit12(int lit)
4066 {
4067   char *s = buffer;
4068   pCodeOp *pcop;
4069
4070
4071   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4072   pcop->type = PO_LITERAL;
4073
4074   pcop->name = NULL;
4075   //if(lit>=0)
4076     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4077   //else
4078   //  sprintf(s, "%i", lit);
4079
4080   if(s)
4081     pcop->name = Safe_strdup(s);
4082
4083   ((pCodeOpLit *)pcop)->lit = lit;
4084
4085   return pcop;
4086 }
4087
4088 /*-----------------------------------------------------------------*/
4089 /*-----------------------------------------------------------------*/
4090 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4091 {
4092   char *s = buffer, tbuf[256], *tb=tbuf;
4093   pCodeOp *pcop;
4094
4095
4096   tb = pic16_get_op(arg2, NULL, 0);
4097   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4098   pcop->type = PO_LITERAL;
4099
4100   pcop->name = NULL;
4101   //if(lit>=0) {
4102     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4103     if(s)
4104       pcop->name = Safe_strdup(s);
4105   //}
4106
4107   ((pCodeOpLit2 *)pcop)->lit = lit;
4108   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4109
4110   return pcop;
4111 }
4112
4113 /*-----------------------------------------------------------------*/
4114 /*-----------------------------------------------------------------*/
4115 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4116 {
4117   pCodeOp *pcop;
4118
4119         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4120         pcop->type = PO_IMMEDIATE;
4121         if(name) {
4122                 regs *r = pic16_dirregWithName(name);
4123                 pcop->name = Safe_strdup(name);
4124                 PCOI(pcop)->r = r;
4125
4126                 if(r) {
4127 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4128                         PCOI(pcop)->rIdx = r->rIdx;
4129                 } else {
4130 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4131                         PCOI(pcop)->rIdx = -1;
4132                 }
4133 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4134         } else {
4135                 pcop->name = NULL;
4136                 PCOI(pcop)->rIdx = -1;
4137         }
4138
4139         PCOI(pcop)->index = index;
4140         PCOI(pcop)->offset = offset;
4141         PCOI(pcop)->_const = code_space;
4142
4143   return pcop;
4144 }
4145
4146 /*-----------------------------------------------------------------*/
4147 /*-----------------------------------------------------------------*/
4148 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4149 {
4150   char *s = buffer;
4151   pCodeOp *pcop;
4152
4153
4154   if(!pcwb || !subtype) {
4155     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4156     exit(1);
4157   }
4158
4159   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4160   pcop->type = PO_WILD;
4161   sprintf(s,"%%%d",id);
4162   pcop->name = Safe_strdup(s);
4163
4164   PCOW(pcop)->id = id;
4165   PCOW(pcop)->pcwb = pcwb;
4166   PCOW(pcop)->subtype = subtype;
4167   PCOW(pcop)->matched = NULL;
4168
4169   PCOW(pcop)->pcop2 = NULL;
4170
4171   return pcop;
4172 }
4173
4174 /*-----------------------------------------------------------------*/
4175 /*-----------------------------------------------------------------*/
4176 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4177 {
4178   char *s = buffer;
4179   pCodeOp *pcop;
4180
4181
4182         if(!pcwb || !subtype || !subtype2) {
4183                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4184                 exit(1);
4185         }
4186
4187         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4188         pcop->type = PO_WILD;
4189         sprintf(s,"%%%d",id);
4190         pcop->name = Safe_strdup(s);
4191
4192         PCOW(pcop)->id = id;
4193         PCOW(pcop)->pcwb = pcwb;
4194         PCOW(pcop)->subtype = subtype;
4195         PCOW(pcop)->matched = NULL;
4196
4197         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4198
4199         if(!subtype2->name) {
4200                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4201                 PCOW2(pcop)->pcop.type = PO_WILD;
4202                 sprintf(s, "%%%d", id2);
4203                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4204                 PCOW2(pcop)->id = id2;
4205                 PCOW2(pcop)->subtype = subtype2;
4206
4207 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4208 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4209         } else {
4210                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4211
4212 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4213 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4214         }
4215
4216
4217
4218   return pcop;
4219 }
4220
4221
4222 /*-----------------------------------------------------------------*/
4223 /*-----------------------------------------------------------------*/
4224 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4225 {
4226   pCodeOp *pcop;
4227
4228   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4229   pcop->type = PO_GPR_BIT;
4230   if(s)
4231     pcop->name = Safe_strdup(s);
4232   else
4233     pcop->name = NULL;
4234
4235   PCORB(pcop)->bit = bit;
4236   PCORB(pcop)->inBitSpace = inBitSpace;
4237   PCORB(pcop)->subtype = subt;
4238
4239   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4240   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4241 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4242 //  PCOR(pcop)->rIdx = 0;
4243   return pcop;
4244 }
4245
4246 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4247 {
4248   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4249                                 bit, 0, PO_GPR_REGISTER);
4250 }
4251
4252
4253 /*-----------------------------------------------------------------*
4254  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4255  *
4256  * If rIdx >=0 then a specific register from the set of registers
4257  * will be selected. If rIdx <0, then a new register will be searched
4258  * for.
4259  *-----------------------------------------------------------------*/
4260
4261 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4262 {
4263   pCodeOp *pcop;
4264   regs *r;
4265
4266   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4267
4268   pcop->name = NULL;
4269
4270   if(rIdx >= 0) {
4271         r = pic16_regWithIdx(rIdx);
4272         if(!r)
4273                 r = pic16_allocWithIdx(rIdx);
4274   } else {
4275     r = pic16_findFreeReg(REG_GPR);
4276
4277     if(!r) {
4278         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4279                 __FUNCTION__, __LINE__);
4280         exit(EXIT_FAILURE);
4281     }
4282   }
4283
4284   PCOR(pcop)->rIdx = rIdx;
4285   PCOR(pcop)->r = r;
4286   pcop->type = PCOR(pcop)->r->pc_type;
4287
4288   return pcop;
4289 }
4290
4291 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4292 {
4293   pCodeOp *pcop;
4294   regs *r;
4295
4296     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4297     pcop->name = NULL;
4298
4299     r = pic16_findFreeReg(REG_GPR);
4300
4301     while(r) {
4302       if(!bitVectBitValue(bv, r->rIdx)) {
4303         PCOR(pcop)->r = r;
4304         PCOR(pcop)->rIdx = r->rIdx;
4305         pcop->type = r->pc_type;
4306         return (pcop);
4307       }
4308
4309       r = pic16_findFreeRegNext(REG_GPR, r);
4310     }
4311
4312   return NULL;
4313 }
4314
4315
4316
4317 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4318 {
4319   pCodeOp *pcop;
4320   regs *r;
4321
4322         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4323         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4324         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4325         pcop->type = PCOR(pcop)->r->pc_type;
4326         pcop->name = PCOR(pcop)->r->name;
4327
4328 //      if(pic16_pcode_verbose) {
4329 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4330 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4331 //      }
4332
4333   return pcop;
4334 }
4335
4336 /*-----------------------------------------------------------------*/
4337 /*-----------------------------------------------------------------*/
4338 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4339 {
4340   pCodeOpOpt *pcop;
4341
4342         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4343
4344         pcop->type = type;
4345         pcop->key = Safe_strdup( key );
4346
4347   return (PCOP(pcop));
4348 }
4349
4350 /*-----------------------------------------------------------------*/
4351 /*-----------------------------------------------------------------*/
4352 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4353 {
4354   pCodeOpLocalReg *pcop;
4355
4356         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4357
4358         pcop->type = type;
4359
4360   return (PCOP(pcop));
4361 }
4362
4363
4364 /*-----------------------------------------------------------------*/
4365 /*-----------------------------------------------------------------*/
4366
4367 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4368 {
4369   pCodeOp *pcop;
4370
4371   switch(type) {
4372   case PO_BIT:
4373   case PO_GPR_BIT:
4374     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4375     break;
4376
4377   case PO_LITERAL:
4378     pcop = pic16_newpCodeOpLit(-1);
4379     break;
4380
4381   case PO_LABEL:
4382     pcop = pic16_newpCodeOpLabel(NULL,-1);
4383     break;
4384   case PO_GPR_TEMP:
4385     pcop = pic16_newpCodeOpReg(-1);
4386     break;
4387
4388   case PO_GPR_REGISTER:
4389     if(name)
4390       pcop = pic16_newpCodeOpRegFromStr(name);
4391     else
4392       pcop = pic16_newpCodeOpReg(-1);
4393     break;
4394
4395   case PO_TWO_OPS:
4396     assert( !"Cannot create PO_TWO_OPS from string!" );
4397     pcop = NULL;
4398     break;
4399
4400   default:
4401     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4402     pcop->type = type;
4403     if(name)
4404       pcop->name = Safe_strdup(name);
4405     else
4406       pcop->name = NULL;
4407   }
4408
4409   return pcop;
4410 }
4411
4412 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4413 {
4414   pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4415   pcop2->pcop.type = PO_TWO_OPS;
4416   pcop2->pcopL = src;
4417   pcop2->pcopR = dst;
4418   return PCOP(pcop2);
4419 }
4420
4421 /* This is a multiple of two as gpasm pads DB directives to even length,
4422  * thus the data would be interleaved with \0 bytes...
4423  * This is a multiple of three in order to have arrays of 3-byte pointers
4424  * continuously in memory (without 0-padding at the lines' end).
4425  * This is rather 12 than 6 in order not to split up 4-byte data types
4426  * in arrays right in the middle of a 4-byte word. */
4427 #define DB_ITEMS_PER_LINE       12
4428
4429 typedef struct DBdata
4430   {
4431     int count;
4432     char buffer[512];
4433   } DBdata;
4434
4435 struct DBdata DBd;
4436 static int DBd_init = -1;
4437
4438 /*-----------------------------------------------------------------*/
4439 /*    Initialiase "DB" data buffer                                 */
4440 /*-----------------------------------------------------------------*/
4441 void pic16_initDB(void)
4442 {
4443         DBd_init = -1;
4444 }
4445
4446
4447 /*-----------------------------------------------------------------*/
4448 /*    Flush pending "DB" data to a pBlock                          */
4449 /*                                                                 */
4450 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4451 /*-----------------------------------------------------------------*/
4452 void pic16_flushDB(char ptype, void *p)
4453 {
4454         if (DBd.count>0) {
4455                 if(ptype == 'p')
4456                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4457                 else
4458                 if(ptype == 'f')
4459                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4460                 else {
4461                         /* sanity check */
4462                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4463                 }
4464
4465                 DBd.count = 0;
4466                 DBd.buffer[0] = '\0';
4467         }
4468 }
4469
4470
4471 /*-----------------------------------------------------------------*/
4472 /*    Add "DB" directives to a pBlock                              */
4473 /*-----------------------------------------------------------------*/
4474 void pic16_emitDB(int c, char ptype, void *p)
4475 {
4476   int l;
4477
4478         if (DBd_init<0) {
4479          // we need to initialize
4480                 DBd_init = 0;
4481                 DBd.count = 0;
4482                 DBd.buffer[0] = '\0';
4483         }
4484
4485         l = strlen(DBd.buffer);
4486         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4487
4488 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4489
4490         DBd.count++;
4491         if (DBd.count>= DB_ITEMS_PER_LINE)
4492                 pic16_flushDB(ptype, p);
4493 }
4494
4495 void pic16_emitDS(char *s, char ptype, void *p)
4496 {
4497   int l;
4498
4499         if (DBd_init<0) {
4500          // we need to initialize
4501                 DBd_init = 0;
4502                 DBd.count = 0;
4503                 DBd.buffer[0] = '\0';
4504         }
4505
4506         l = strlen(DBd.buffer);
4507         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4508
4509 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4510
4511         DBd.count++;    //=strlen(s);
4512         if (DBd.count>=DB_ITEMS_PER_LINE)
4513                 pic16_flushDB(ptype, p);
4514 }
4515
4516
4517 /*-----------------------------------------------------------------*/
4518 /*-----------------------------------------------------------------*/
4519 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4520 {
4521   pBlock *pb;
4522   char *item;
4523   static set *emittedSymbols = NULL;
4524
4525   if(!name || !value)
4526     return;
4527
4528   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4529   if (emittedSymbols) {
4530     /* scan set for name */
4531     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4532     {
4533       if (!strcmp (item,name)) {
4534         //fprintf (stderr, "%s already emitted\n", name);
4535         return;
4536       } // if
4537     } // for
4538   } // if
4539   addSet (&emittedSymbols, Safe_strdup (name));
4540
4541   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4542
4543   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4544
4545   pic16_addpBlock(pb);
4546
4547 //  sprintf(buffer,"; %s = ", name);
4548 //  strcat(buffer, value);
4549 //  fputs(buffer, stderr);
4550
4551 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4552   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4553
4554   while (length--)
4555     pic16_emitDB(*value++, 'p', (void *)pb);
4556
4557   pic16_flushDB('p', (void *)pb);
4558 }
4559
4560 /*-----------------------------------------------------------------*/
4561 /*-----------------------------------------------------------------*/
4562 #if 0
4563 static void pCodeReadCodeTable(void)
4564 {
4565   pBlock *pb;
4566
4567   fprintf(stderr, " %s\n",__FUNCTION__);
4568
4569   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4570
4571   pic16_addpBlock(pb);
4572
4573   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4574   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4575   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4576   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4577
4578   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4579   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4580   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4581   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4582
4583
4584 }
4585 #endif
4586 /*-----------------------------------------------------------------*/
4587 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4588 /*-----------------------------------------------------------------*/
4589 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4590 {
4591
4592   if(!pc)
4593     return;
4594
4595   if(!pb->pcHead) {
4596     /* If this is the first pcode to be added to a block that
4597      * was initialized with a NULL pcode, then go ahead and
4598      * make this pcode the head and tail */
4599     pb->pcHead  = pb->pcTail = pc;
4600   } else {
4601     //    if(pb->pcTail)
4602     pb->pcTail->next = pc;
4603
4604     pc->prev = pb->pcTail;
4605     pc->pb = pb;
4606
4607     pb->pcTail = pc;
4608   }
4609 }
4610
4611 /*-----------------------------------------------------------------*/
4612 /* pic16_addpBlock - place a pBlock into the pFile                 */
4613 /*-----------------------------------------------------------------*/
4614 void pic16_addpBlock(pBlock *pb)
4615 {
4616   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4617
4618   if(!the_pFile) {
4619     /* First time called, we'll pass through here. */
4620     //_ALLOC(the_pFile,sizeof(pFile));
4621     the_pFile = Safe_calloc(1,sizeof(pFile));
4622     the_pFile->pbHead = the_pFile->pbTail = pb;
4623     the_pFile->functions = NULL;
4624     return;
4625   }
4626
4627   the_pFile->pbTail->next = pb;
4628   pb->prev = the_pFile->pbTail;
4629   pb->next = NULL;
4630   the_pFile->pbTail = pb;
4631 }
4632
4633 /*-----------------------------------------------------------------*/
4634 /* removepBlock - remove a pBlock from the pFile                   */
4635 /*-----------------------------------------------------------------*/
4636 static void removepBlock(pBlock *pb)
4637 {
4638   pBlock *pbs;
4639
4640   if(!the_pFile)
4641     return;
4642
4643
4644   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4645
4646   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4647     if(pbs == pb) {
4648
4649       if(pbs == the_pFile->pbHead)
4650         the_pFile->pbHead = pbs->next;
4651
4652       if (pbs == the_pFile->pbTail)
4653         the_pFile->pbTail = pbs->prev;
4654
4655       if(pbs->next)
4656         pbs->next->prev = pbs->prev;
4657
4658       if(pbs->prev)
4659         pbs->prev->next = pbs->next;
4660
4661       return;
4662
4663     }
4664   }
4665
4666   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4667
4668 }
4669
4670 /*-----------------------------------------------------------------*/
4671 /* printpCode - write the contents of a pCode to a file            */
4672 /*-----------------------------------------------------------------*/
4673 static void printpCode(FILE *of, pCode *pc)
4674 {
4675
4676   if(!pc || !of)
4677     return;
4678
4679   if(pc->print) {
4680     pc->print(of,pc);
4681     return;
4682   }
4683
4684   fprintf(of,"warning - unable to print pCode\n");
4685 }
4686
4687 /*-----------------------------------------------------------------*/
4688 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4689 /*-----------------------------------------------------------------*/
4690 void pic16_printpBlock(FILE *of, pBlock *pb)
4691 {
4692   pCode *pc;
4693
4694         if(!pb)return;
4695
4696         if(!of)of=stderr;
4697
4698         for(pc = pb->pcHead; pc; pc = pc->next) {
4699                 if(isPCF(pc) && PCF(pc)->fname) {
4700                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4701                         if(pb->dbName == 'A') {
4702                           absSym *ab;
4703                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4704 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4705                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4706 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4707                                                 if(ab->address != -1)
4708                                                   fprintf(of, "\t0X%06X", ab->address);
4709                                                 break;
4710                                         }
4711                                 }
4712                         }
4713                         fprintf(of, "\n");
4714                 }
4715                 printpCode(of,pc);
4716         }
4717 }
4718
4719 /*-----------------------------------------------------------------*/
4720 /*                                                                 */
4721 /*       pCode processing                                          */
4722 /*                                                                 */
4723 /*                                                                 */
4724 /*                                                                 */
4725 /*-----------------------------------------------------------------*/
4726 pCode * pic16_findNextInstruction(pCode *pci);
4727 pCode * pic16_findPrevInstruction(pCode *pci);
4728
4729 void pic16_unlinkpCode(pCode *pc)
4730 {
4731   pCode *prev;
4732
4733   if(pc) {
4734 #ifdef PCODE_DEBUG
4735     fprintf(stderr,"Unlinking: ");
4736     printpCode(stderr, pc);
4737 #endif
4738     if(pc->prev)
4739       pc->prev->next = pc->next;
4740     if(pc->next)
4741       pc->next->prev = pc->prev;
4742
4743     /* move C source line down (or up) */
4744     if (isPCI(pc) && PCI(pc)->cline) {
4745       prev = pic16_findNextInstruction (pc->next);
4746       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4747         PCI(prev)->cline = PCI(pc)->cline;
4748       } else {
4749         prev = pic16_findPrevInstruction (pc->prev);
4750         if (prev && isPCI(prev) && !PCI(prev)->cline)
4751           PCI(prev)->cline = PCI(pc)->cline;
4752       }
4753     }
4754     pc->prev = pc->next = NULL;
4755   }
4756 }
4757
4758 /*-----------------------------------------------------------------*/
4759 /*-----------------------------------------------------------------*/
4760
4761 static void genericDestruct(pCode *pc)
4762 {
4763
4764   pic16_unlinkpCode(pc);
4765
4766   if(isPCI(pc)) {
4767     /* For instructions, tell the register (if there's one used)
4768      * that it's no longer needed */
4769     regs *reg = pic16_getRegFromInstruction(pc);
4770     if(reg)
4771       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4772
4773         if(PCI(pc)->is2MemOp) {
4774                 reg = pic16_getRegFromInstruction2(pc);
4775                 if(reg)
4776                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4777         }
4778   }
4779
4780   /* Instead of deleting the memory used by this pCode, mark
4781    * the object as bad so that if there's a pointer to this pCode
4782    * dangling around somewhere then (hopefully) when the type is
4783    * checked we'll catch it.
4784    */
4785
4786   pc->type = PC_BAD;
4787   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4788
4789   //Safe_free(pc);
4790 }
4791
4792
4793 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4794 /*-----------------------------------------------------------------*/
4795 /*-----------------------------------------------------------------*/
4796 /* modifiers for constant immediate */
4797 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4798
4799 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4800 {
4801   regs *r;
4802   static char b[128];
4803   char *s;
4804   int use_buffer = 1;    // copy the string to the passed buffer pointer
4805
4806         if(!buffer) {
4807                 buffer = b;
4808                 size = sizeof(b);
4809                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4810         }
4811
4812         if(pcop) {
4813
4814                 switch(pcop->type) {
4815                         case PO_W:
4816                         case PO_WREG:
4817                         case PO_PRODL:
4818                         case PO_PRODH:
4819                         case PO_INDF0:
4820                         case PO_FSR0:
4821                                 if(use_buffer) {
4822                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4823                                         return (buffer);
4824                                 }
4825                                 return (PCOR(pcop)->r->name);
4826                                 break;
4827                         case PO_GPR_TEMP:
4828                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4829                                 if(use_buffer) {
4830                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4831                                         return (buffer);
4832                                 }
4833                                 return (r->name);
4834
4835                         case PO_IMMEDIATE:
4836                                 s = buffer;
4837                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4838                                         if(PCOI(pcop)->index) {
4839                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4840                                                         immdmod[ PCOI(pcop)->offset ],
4841                                                         pcop->name,
4842                                                         PCOI(pcop)->index);
4843                                         } else {
4844                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4845                                                         immdmod[ PCOI(pcop)->offset ],
4846                                                         pcop->name);
4847                                         }
4848                                 } else {
4849                                         if(PCOI(pcop)->index) {
4850                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4851                                                         immdmod[ 0 ],
4852                                                         pcop->name,
4853                                                         PCOI(pcop)->index);
4854                                         } else {
4855                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4856                                                         immdmod[ 0 ],
4857                                                         pcop->name);
4858                                         }
4859                                 }
4860                                 return (buffer);
4861
4862                         case PO_GPR_REGISTER:
4863                         case PO_DIR:
4864                                 s = buffer;
4865 //                              size = sizeof(buffer);
4866                                 if( PCOR(pcop)->instance) {
4867                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4868                                                 pcop->name,
4869                                                 PCOR(pcop)->instance );
4870                                 } else {
4871                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4872                                 }
4873                                 return (buffer);
4874                         case PO_GPR_BIT:
4875                                 s = buffer;
4876                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4877                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4878                                 } else {
4879                                         if(PCORB(pcop)->pcor.instance)
4880                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4881                                         else
4882                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4883                                 }
4884
4885                                 return (buffer);
4886                         case PO_TWO_OPS:
4887                                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4888
4889                         default:
4890                                 if(pcop->name) {
4891                                         if(use_buffer) {
4892                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4893                                                 return (buffer);
4894                                         }
4895                                 return (pcop->name);
4896                                 }
4897
4898                 }
4899                 return ("unhandled type for op1");
4900         }
4901
4902   return ("NO operand1");
4903 }
4904
4905 /*-----------------------------------------------------------------*/
4906 /* pic16_get_op2 - variant to support two memory operand commands  */
4907 /*-----------------------------------------------------------------*/
4908 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4909 {
4910
4911   if(pcop && pcop->type == PO_TWO_OPS) {
4912     return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4913   }
4914
4915   return "NO operand2";
4916 }
4917
4918 /*-----------------------------------------------------------------*/
4919 /*-----------------------------------------------------------------*/
4920 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4921 {
4922
4923   if(pcc )
4924     return pic16_get_op(pcc->pcop,NULL,0);
4925
4926   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated
4927    *   return ("ERROR Null: "__FUNCTION__);
4928    */
4929   return ("ERROR Null: pic16_get_op_from_instruction");
4930
4931 }
4932
4933 /*-----------------------------------------------------------------*/
4934 /*-----------------------------------------------------------------*/
4935 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4936 {
4937
4938   fprintf(of,"pcodeopprint- not implemented\n");
4939 }
4940
4941 /*-----------------------------------------------------------------*/
4942 /* pic16_pCode2str - convert a pCode instruction to string               */
4943 /*-----------------------------------------------------------------*/
4944 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4945 {
4946   char *s = str;
4947   regs *r;
4948
4949 #if 0
4950         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4951                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4952                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4953 //              exit(EXIT_FAILURE);
4954         }
4955 #endif
4956
4957   switch(pc->type) {
4958
4959   case PC_OPCODE:
4960     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4961
4962     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4963
4964         //if(PCI(pc)->is2MemOp)
4965         if (PCI(pc)->pcop->type == PO_TWO_OPS)
4966         {
4967                 /* split into two phases due to static buffer in pic16_get_op() */
4968                 SAFE_snprintf(&s,&size, "%s",
4969                         pic16_get_op((PCI(pc)->pcop), NULL, 0));
4970                 SAFE_snprintf(&s, &size, ", %s",
4971                         pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4972                 break;
4973         }
4974
4975         if(PCI(pc)->is2LitOp) {
4976                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4977                 break;
4978         }
4979
4980       if(PCI(pc)->isBitInst) {
4981         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4982           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4983             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
4984                           PCI(pc)->pcop->name ,
4985                           PCI(pc)->pcop->name );
4986           else
4987             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4988 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
4989                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4990
4991         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4992           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4993         } else
4994           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4995         //PCI(pc)->pcop->t.bit );
4996       } else {
4997
4998         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4999           if( PCI(pc)->num_ops == 3)
5000             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5001           else
5002             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5003
5004         }
5005         else
5006         {
5007           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5008         }
5009       }
5010         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5011           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5012             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5013
5014           r = pic16_getRegFromInstruction(pc);
5015 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5016 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?isACCESS_BANK(r):-1);
5017
5018           if(PCI(pc)->isAccess) {
5019             static char *bank_spec[2][2] = {
5020               { "", ", ACCESS" },  /* gpasm uses access bank by default */
5021               { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5022             };
5023
5024             SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5025           }
5026         }
5027 //
5028
5029     }
5030     break;
5031
5032   case PC_COMMENT:
5033     /* assuming that comment ends with a \n */
5034     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5035     break;
5036
5037   case PC_INFO:
5038     SAFE_snprintf(&s,&size,"; info ==>");
5039     switch( PCINF(pc)->type ) {
5040       case INF_OPTIMIZATION:
5041           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5042           break;
5043       case INF_LOCALREGS:
5044           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5045           break;
5046     }; break;
5047
5048   case PC_INLINE:
5049     /* assuming that inline code ends with a \n */
5050     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5051     break;
5052
5053   case PC_LABEL:
5054     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5055     break;
5056   case PC_FUNCTION:
5057     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5058     break;
5059   case PC_WILD:
5060     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5061     break;
5062   case PC_FLOW:
5063     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5064     break;
5065   case PC_CSOURCE:
5066 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5067       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5068         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5069     break;
5070   case PC_ASMDIR:
5071         if(PCAD(pc)->directive) {
5072                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5073         } else
5074         if(PCAD(pc)->arg) {
5075                 /* special case to handle inline labels without a tab */
5076                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5077         }
5078         break;
5079
5080   case PC_BAD:
5081     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5082     break;
5083   }
5084
5085   return str;
5086
5087 }
5088
5089 /*-----------------------------------------------------------------*/
5090 /* genericPrint - the contents of a pCode to a file                */
5091 /*-----------------------------------------------------------------*/
5092 static void genericPrint(FILE *of, pCode *pc)
5093 {
5094
5095   if(!pc || !of)
5096     return;
5097
5098   switch(pc->type) {
5099   case PC_COMMENT:
5100 //    fputs(((pCodeComment *)pc)->comment, of);
5101     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5102     break;
5103
5104   case PC_INFO:
5105     {
5106       pBranch *pbl = PCI(pc)->label;
5107       while(pbl && pbl->pc) {
5108         if(pbl->pc->type == PC_LABEL)
5109           pCodePrintLabel(of, pbl->pc);
5110         pbl = pbl->next;
5111       }
5112     }
5113
5114     if(pic16_pcode_verbose) {
5115       fprintf(of, "; info ==>");
5116       switch(((pCodeInfo *)pc)->type) {
5117         case INF_OPTIMIZATION:
5118               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5119               break;
5120         case INF_LOCALREGS:
5121               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5122               break;
5123         }
5124     };
5125
5126     break;
5127
5128   case PC_INLINE:
5129     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5130      break;
5131
5132   case PC_OPCODE:
5133     // If the opcode has a label, print that first
5134     {
5135       pBranch *pbl = PCI(pc)->label;
5136       while(pbl && pbl->pc) {
5137         if(pbl->pc->type == PC_LABEL)
5138           pCodePrintLabel(of, pbl->pc);
5139         pbl = pbl->next;
5140       }
5141     }
5142
5143     if(PCI(pc)->cline)
5144       genericPrint(of,PCODE(PCI(pc)->cline));
5145
5146     {
5147       char str[256];
5148
5149       pic16_pCode2str(str, 256, pc);
5150
5151       fprintf(of,"%s",str);
5152       /* Debug */
5153       if(pic16_debug_verbose) {
5154         fprintf(of, "\t;key=%03x",pc->seq);
5155         if(PCI(pc)->pcflow)
5156           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5157       }
5158     }
5159     fprintf(of, "\n");
5160     break;
5161
5162   case PC_WILD:
5163     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5164     if(PCW(pc)->pci.label)
5165       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5166
5167     if(PCW(pc)->operand) {
5168       fprintf(of,";\toperand  ");
5169       pCodeOpPrint(of,PCW(pc)->operand );
5170     }
5171     break;
5172
5173   case PC_FLOW:
5174     if(pic16_debug_verbose) {
5175       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5176       if(PCFL(pc)->ancestor)
5177         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5178       fprintf(of,"\n");
5179
5180     }
5181     break;
5182
5183   case PC_CSOURCE:
5184 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5185     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5186         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5187
5188     break;
5189
5190   case PC_ASMDIR:
5191         {
5192           pBranch *pbl = PCAD(pc)->pci.label;
5193                 while(pbl && pbl->pc) {
5194                         if(pbl->pc->type == PC_LABEL)
5195                                 pCodePrintLabel(of, pbl->pc);
5196                         pbl = pbl->next;
5197                 }
5198         }
5199         if(PCAD(pc)->directive) {
5200                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5201         } else
5202         if(PCAD(pc)->arg) {
5203                 /* special case to handle inline labels without tab */
5204                 fprintf(of, "%s\n", PCAD(pc)->arg);
5205         }
5206         break;
5207
5208   case PC_LABEL:
5209   default:
5210     fprintf(of,"unknown pCode type %d\n",pc->type);
5211   }
5212
5213 }
5214
5215 /*-----------------------------------------------------------------*/
5216 /* pCodePrintFunction - prints function begin/end                  */
5217 /*-----------------------------------------------------------------*/
5218
5219 static void pCodePrintFunction(FILE *of, pCode *pc)
5220 {
5221
5222   if(!pc || !of)
5223     return;
5224
5225 #if 0
5226   if( ((pCodeFunction *)pc)->modname)
5227     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5228 #endif
5229
5230   if(!PCF(pc)->absblock) {
5231       if(PCF(pc)->fname) {
5232       pBranch *exits = PCF(pc)->to;
5233       int i=0;
5234
5235       fprintf(of,"%s:", PCF(pc)->fname);
5236
5237       if(pic16_pcode_verbose)
5238         fprintf(of, "\t;Function start");
5239
5240       fprintf(of, "\n");
5241
5242       while(exits) {
5243         i++;
5244         exits = exits->next;
5245       }
5246       //if(i) i--;
5247
5248       if(pic16_pcode_verbose)
5249         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5250
5251     } else {
5252         if((PCF(pc)->from &&
5253                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5254                 PCF(PCF(pc)->from->pc)->fname) ) {
5255
5256                 if(pic16_pcode_verbose)
5257                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5258         } else {
5259                 if(pic16_pcode_verbose)
5260                         fprintf(of,"; exit point [can't find entry point]\n");
5261         }
5262         fprintf(of, "\n");
5263     }
5264   }
5265 }
5266 /*-----------------------------------------------------------------*/
5267 /* pCodePrintLabel - prints label                                  */
5268 /*-----------------------------------------------------------------*/
5269
5270 static void pCodePrintLabel(FILE *of, pCode *pc)
5271 {
5272
5273   if(!pc || !of)
5274     return;
5275
5276   if(PCL(pc)->label)
5277     fprintf(of,"%s:\n",PCL(pc)->label);
5278   else if (PCL(pc)->key >=0)
5279     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5280   else
5281     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5282
5283 }
5284 /*-----------------------------------------------------------------*/
5285 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5286 /*                         remove it if it is found.               */
5287 /*-----------------------------------------------------------------*/
5288 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5289 {
5290   pBranch *b, *bprev;
5291
5292
5293   bprev = NULL;
5294
5295   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5296     b = PCI(pcl)->label;
5297   else {
5298     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5299     exit(1);
5300
5301   }
5302
5303   //fprintf (stderr, "%s \n",__FUNCTION__);
5304   //pcl->print(stderr,pcl);
5305   //pc->print(stderr,pc);
5306   while(b) {
5307     if(b->pc == pc) {
5308       //fprintf (stderr, "found label\n");
5309       //pc->print(stderr, pc);
5310
5311       /* Found a label */
5312       if(bprev) {
5313         bprev->next = b->next;  /* Not first pCode in chain */
5314 //      Safe_free(b);
5315       } else {
5316         pc->destruct(pc);
5317         PCI(pcl)->label = b->next;   /* First pCode in chain */
5318 //      Safe_free(b);
5319       }
5320       return;  /* A label can't occur more than once */
5321     }
5322     bprev = b;
5323     b = b->next;
5324   }
5325
5326 }
5327
5328 /*-----------------------------------------------------------------*/
5329 /*-----------------------------------------------------------------*/
5330 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5331 {
5332   pBranch *b;
5333
5334   if(!h)
5335     return n;
5336
5337   if(h == n)
5338     return n;
5339
5340   b = h;
5341   while(b->next)
5342     b = b->next;
5343
5344   b->next = n;
5345
5346   return h;
5347
5348 }
5349 /*-----------------------------------------------------------------*/
5350 /* pBranchLink - given two pcodes, this function will link them    */
5351 /*               together through their pBranches                  */
5352 /*-----------------------------------------------------------------*/
5353 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5354 {
5355   pBranch *b;
5356
5357   // Declare a new branch object for the 'from' pCode.
5358
5359   //_ALLOC(b,sizeof(pBranch));
5360   b = Safe_calloc(1,sizeof(pBranch));
5361   b->pc = PCODE(t);             // The link to the 'to' pCode.
5362   b->next = NULL;
5363
5364   f->to = pic16_pBranchAppend(f->to,b);
5365
5366   // Now do the same for the 'to' pCode.
5367
5368   //_ALLOC(b,sizeof(pBranch));
5369   b = Safe_calloc(1,sizeof(pBranch));
5370   b->pc = PCODE(f);
5371   b->next = NULL;
5372
5373   t->from = pic16_pBranchAppend(t->from,b);
5374
5375 }
5376
5377 #if 1
5378 /*-----------------------------------------------------------------*/
5379 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5380 /*               a pCode                                           */
5381 /*-----------------------------------------------------------------*/
5382 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5383 {
5384   while(pb) {
5385
5386     if(pb->pc == pc)
5387       return pb;
5388
5389     pb = pb->next;
5390   }
5391
5392   return NULL;
5393 }
5394
5395 /*-----------------------------------------------------------------*/
5396 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5397 /*-----------------------------------------------------------------*/
5398 void pic16_pCodeUnlink(pCode *pc)
5399 {
5400   pBranch *pb1,*pb2;
5401   pCode *pc1;
5402
5403   if(!pc->prev || !pc->next) {
5404     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5405     exit(1);
5406   }
5407
5408   /* move C source line down (or up) */
5409   if (isPCI(pc) && PCI(pc)->cline) {
5410     pc1 = pic16_findNextInstruction (pc->next);
5411     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5412       PCI(pc1)->cline = PCI(pc)->cline;
5413     } else {
5414       pc1 = pic16_findPrevInstruction (pc->prev);
5415       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5416         PCI(pc1)->cline = PCI(pc)->cline;
5417     }
5418   }
5419
5420   /* first remove the pCode from the chain */
5421   pc->prev->next = pc->next;
5422   pc->next->prev = pc->prev;
5423
5424   pc->prev = pc->next = NULL;
5425
5426   /* Now for the hard part... */
5427
5428   /* Remove the branches */
5429
5430   pb1 = PCI(pc)->from;
5431   while(pb1) {
5432     pc1 = pb1->pc;    /* Get the pCode that branches to the
5433                        * one we're unlinking */
5434
5435     /* search for the link back to this pCode (the one we're
5436      * unlinking) */
5437     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5438       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5439
5440       /* if the pCode we're unlinking contains multiple 'to'
5441        * branches (e.g. this a skip instruction) then we need
5442        * to copy these extra branches to the chain. */
5443       if(PCI(pc)->to->next)
5444         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5445     }
5446
5447     pb1 = pb1->next;
5448   }
5449
5450
5451 }
5452 #endif
5453 /*-----------------------------------------------------------------*/
5454 /*-----------------------------------------------------------------*/
5455 #if 0
5456 static void genericAnalyze(pCode *pc)
5457 {
5458   switch(pc->type) {
5459   case PC_WILD:
5460   case PC_COMMENT:
5461     return;
5462   case PC_LABEL:
5463   case PC_FUNCTION:
5464   case PC_OPCODE:
5465     {
5466       // Go through the pCodes that are in pCode chain and link
5467       // them together through the pBranches. Note, the pCodes
5468       // are linked together as a contiguous stream like the
5469       // assembly source code lines. The linking here mimics this
5470       // except that comments are not linked in.
5471       //
5472       pCode *npc = pc->next;
5473       while(npc) {
5474         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5475           pBranchLink(pc,npc);
5476           return;
5477         } else
5478           npc = npc->next;
5479       }
5480       /* reached the end of the pcode chain without finding
5481        * an instruction we could link to. */
5482     }
5483     break;
5484   case PC_FLOW:
5485     fprintf(stderr,"analyze PC_FLOW\n");
5486
5487     return;
5488   case PC_BAD:
5489     fprintf(stderr,,";A bad pCode is being used\n");
5490
5491   }
5492 }
5493 #endif
5494
5495 /*-----------------------------------------------------------------*/
5496 /*-----------------------------------------------------------------*/
5497 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5498 {
5499   pBranch *pbr;
5500
5501   if(pc->type == PC_LABEL) {
5502     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5503       return TRUE;
5504   }
5505   if((pc->type == PC_OPCODE)
5506         || (pc->type == PC_ASMDIR)
5507         ) {
5508     pbr = PCI(pc)->label;
5509     while(pbr) {
5510       if(pbr->pc->type == PC_LABEL) {
5511         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5512           return TRUE;
5513       }
5514       pbr = pbr->next;
5515     }
5516   }
5517
5518   return FALSE;
5519 }
5520
5521 /*-----------------------------------------------------------------*/
5522 /*-----------------------------------------------------------------*/
5523 static int checkLabel(pCode *pc)
5524 {
5525   pBranch *pbr;
5526
5527   if(pc && isPCI(pc)) {
5528     pbr = PCI(pc)->label;
5529     while(pbr) {
5530       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5531         return TRUE;
5532
5533       pbr = pbr->next;
5534     }
5535   }
5536
5537   return FALSE;
5538 }
5539
5540 /*-----------------------------------------------------------------*/
5541 /* findLabelinpBlock - Search the pCode for a particular label     */
5542 /*-----------------------------------------------------------------*/
5543 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5544 {
5545   pCode  *pc;
5546
5547   if(!pb)
5548     return NULL;
5549
5550   for(pc = pb->pcHead; pc; pc = pc->next)
5551     if(compareLabel(pc,pcop_label))
5552       return pc;
5553
5554   return NULL;
5555 }
5556 #if 0
5557 /*-----------------------------------------------------------------*/
5558 /* findLabel - Search the pCode for a particular label             */
5559 /*-----------------------------------------------------------------*/
5560 static pCode * findLabel(pCodeOpLabel *pcop_label)
5561 {
5562   pBlock *pb;
5563   pCode  *pc;
5564
5565   if(!the_pFile)
5566     return NULL;
5567
5568   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5569     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5570       return pc;
5571   }
5572
5573   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5574   return NULL;
5575 }
5576 #endif
5577 /*-----------------------------------------------------------------*/
5578 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5579 /*                 in the linked list                              */
5580 /*-----------------------------------------------------------------*/
5581 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5582 {
5583
5584   while(pc) {
5585     if(pc->type == pct)
5586       return pc;
5587
5588     pc = pc->next;
5589   }
5590
5591   return NULL;
5592 }
5593
5594 /*-----------------------------------------------------------------*/
5595 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5596 /*                 in the linked list                              */
5597 /*-----------------------------------------------------------------*/
5598 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5599 {
5600
5601   while(pc) {
5602     if(pc->type == pct)
5603       return pc;
5604
5605     pc = pc->prev;
5606   }
5607
5608   return NULL;
5609 }
5610
5611
5612 //#define PCODE_DEBUG
5613 /*-----------------------------------------------------------------*/
5614 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5615 /*                       in the linked list                        */
5616 /*-----------------------------------------------------------------*/
5617 pCode * pic16_findNextInstruction(pCode *pci)
5618 {
5619   pCode *pc = pci;
5620
5621   while(pc) {
5622     if((pc->type == PC_OPCODE)
5623         || (pc->type == PC_WILD)
5624         || (pc->type == PC_ASMDIR)
5625         )
5626       return pc;
5627
5628 #ifdef PCODE_DEBUG
5629     fprintf(stderr,"pic16_findNextInstruction:  ");
5630     printpCode(stderr, pc);
5631 #endif
5632     pc = pc->next;
5633   }
5634
5635   //fprintf(stderr,"Couldn't find instruction\n");
5636   return NULL;
5637 }
5638
5639 /*-----------------------------------------------------------------*/
5640 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5641 /*                       in the linked list                        */
5642 /*-----------------------------------------------------------------*/
5643 pCode * pic16_findPrevInstruction(pCode *pci)
5644 {
5645   pCode *pc = pci;
5646
5647   while(pc) {
5648
5649     if((pc->type == PC_OPCODE)
5650         || (pc->type == PC_WILD)
5651         || (pc->type == PC_ASMDIR)
5652         )
5653       return pc;
5654
5655
5656 #ifdef PCODE_DEBUG
5657     fprintf(stderr,"pic16_findPrevInstruction:  ");
5658     printpCode(stderr, pc);
5659 #endif
5660     pc = pc->prev;
5661   }
5662
5663   //fprintf(stderr,"Couldn't find instruction\n");
5664   return NULL;
5665 }
5666
5667 #undef PCODE_DEBUG
5668
5669 #if 0
5670 /*-----------------------------------------------------------------*/
5671 /* findFunctionEnd - given a pCode find the end of the function    */
5672 /*                   that contains it                              */
5673 /*-----------------------------------------------------------------*/
5674 static pCode * findFunctionEnd(pCode *pc)
5675 {
5676
5677   while(pc) {
5678     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5679       return pc;
5680
5681     pc = pc->next;
5682   }
5683
5684   fprintf(stderr,"Couldn't find function end\n");
5685   return NULL;
5686 }
5687 #endif
5688 #if 0
5689 /*-----------------------------------------------------------------*/
5690 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5691 /*                instruction with which it is associated.         */
5692 /*-----------------------------------------------------------------*/
5693 static void AnalyzeLabel(pCode *pc)
5694 {
5695
5696   pic16_pCodeUnlink(pc);
5697
5698 }
5699 #endif
5700
5701 #if 0
5702 static void AnalyzeGOTO(pCode *pc)
5703 {
5704
5705   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5706
5707 }
5708
5709 static void AnalyzeSKIP(pCode *pc)
5710 {
5711
5712   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5713   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5714
5715 }
5716
5717 static void AnalyzeRETURN(pCode *pc)
5718 {
5719
5720   //  branch_link(pc,findFunctionEnd(pc->next));
5721
5722 }
5723
5724 #endif
5725
5726 /*-------------------------------------------------------------------*/
5727 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5728 /*                            if one is present. This is the common  */
5729 /*                            part of pic16_getRegFromInstruction(2) */
5730 /*-------------------------------------------------------------------*/
5731
5732 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5733   if (!pcop) return NULL;
5734
5735   switch(pcop->type) {
5736   case PO_PRODL:
5737   case PO_PRODH:
5738   case PO_INDF0:
5739   case PO_FSR0:
5740   case PO_W:
5741   case PO_WREG:
5742   case PO_STATUS:
5743   case PO_INTCON:
5744   case PO_PCL:
5745   case PO_PCLATH:
5746   case PO_PCLATU:
5747   case PO_BSR:
5748     return PCOR(pcop)->r;
5749
5750   case PO_SFR_REGISTER:
5751     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5752     return PCOR(pcop)->r;
5753
5754   case PO_BIT:
5755   case PO_GPR_TEMP:
5756 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5757     return PCOR(pcop)->r;
5758
5759   case PO_IMMEDIATE:
5760 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5761
5762     if(PCOI(pcop)->r)
5763       return (PCOI(pcop)->r);
5764     else
5765       return NULL;
5766
5767   case PO_GPR_BIT:
5768     return PCOR(pcop)->r;
5769
5770   case PO_GPR_REGISTER:
5771   case PO_DIR:
5772 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5773     return PCOR(pcop)->r;
5774
5775   case PO_LITERAL:
5776     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5777     break;
5778
5779   case PO_REL_ADDR:
5780   case PO_LABEL:
5781     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5782     break;
5783
5784   case PO_CRY:
5785   case PO_STR:
5786     /* this should never turn up */
5787     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5788     break;
5789
5790   case PO_WILD:
5791     break;
5792
5793   case PO_TWO_OPS:
5794     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5795     break;
5796
5797   default:
5798         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5799 //      assert( 0 );
5800         break;
5801   }
5802
5803   return NULL;
5804 }
5805
5806 /*-----------------------------------------------------------------*/
5807 /*-----------------------------------------------------------------*/
5808 regs * pic16_getRegFromInstruction(pCode *pc)
5809 {
5810   if(!pc                   ||
5811      !isPCI(pc)            ||
5812      !PCI(pc)->pcop        ||
5813      PCI(pc)->num_ops == 0 ||
5814      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5815     return NULL;
5816
5817 #if 0
5818   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5819         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5820 #endif
5821
5822   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5823 }
5824
5825 /*-------------------------------------------------------------------------------*/
5826 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5827 /*-------------------------------------------------------------------------------*/
5828 regs * pic16_getRegFromInstruction2(pCode *pc)
5829 {
5830
5831   if(!pc                   ||
5832      !isPCI(pc)            ||
5833      !PCI(pc)->pcop        ||
5834      PCI(pc)->num_ops == 0 ||
5835      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5836     return NULL;
5837
5838   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5839     return NULL;
5840
5841 #if 0
5842   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5843         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5844 #endif
5845
5846   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5847 }
5848
5849 /*-----------------------------------------------------------------*/
5850 /*-----------------------------------------------------------------*/
5851
5852 static void AnalyzepBlock(pBlock *pb)
5853 {
5854   pCode *pc;
5855
5856   if(!pb)
5857     return;
5858
5859   /* Find all of the registers used in this pBlock
5860    * by looking at each instruction and examining it's
5861    * operands
5862    */
5863   for(pc = pb->pcHead; pc; pc = pc->next) {
5864
5865     /* Is this an instruction with operands? */
5866     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5867
5868       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5869
5870         /* Loop through all of the registers declared so far in
5871            this block and see if we find this one there */
5872
5873         regs *r = setFirstItem(pb->tregisters);
5874
5875         while(r) {
5876           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5877             PCOR(PCI(pc)->pcop)->r = r;
5878             break;
5879           }
5880           r = setNextItem(pb->tregisters);
5881         }
5882
5883         if(!r) {
5884           /* register wasn't found */
5885           //r = Safe_calloc(1, sizeof(regs));
5886           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5887           //addSet(&pb->tregisters, r);
5888           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5889           //PCOR(PCI(pc)->pcop)->r = r;
5890           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5891         }/* else
5892           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5893          */
5894       }
5895       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5896         if(PCOR(PCI(pc)->pcop)->r) {
5897           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5898           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5899         } else {
5900           if(PCI(pc)->pcop->name)
5901             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5902           else
5903             fprintf(stderr,"ERROR: NULL register\n");
5904         }
5905       }
5906     }
5907
5908
5909   }
5910 }
5911
5912 /*-----------------------------------------------------------------*/
5913 /* */
5914 /*-----------------------------------------------------------------*/
5915 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5916
5917 static void InsertpFlow(pCode *pc, pCode **pflow)
5918 {
5919   if(*pflow)
5920     PCFL(*pflow)->end = pc;
5921
5922   if(!pc || !pc->next)
5923     return;
5924
5925   *pflow = pic16_newpCodeFlow();
5926   pic16_pCodeInsertAfter(pc, *pflow);
5927 }
5928
5929 /*-----------------------------------------------------------------*/
5930 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5931 /*                         the flow blocks.                        */
5932 /*
5933  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5934  * point the instruction flow changes.
5935  */
5936 /*-----------------------------------------------------------------*/
5937 void pic16_BuildFlow(pBlock *pb)
5938 {
5939   pCode *pc;
5940   pCode *last_pci=NULL;
5941   pCode *pflow=NULL;
5942   int seq = 0;
5943
5944   if(!pb)
5945     return;
5946
5947   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5948   /* Insert a pCodeFlow object at the beginning of a pBlock */
5949
5950   InsertpFlow(pb->pcHead, &pflow);
5951
5952   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5953   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5954   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5955   //pb->pcHead = pflow;        /* Make the Flow object the head */
5956   //pflow->pb = pb;
5957
5958   for( pc = pic16_findNextInstruction(pb->pcHead);
5959        pc != NULL;
5960        pc=pic16_findNextInstruction(pc)) {
5961
5962     pc->seq = seq++;
5963     PCI(pc)->pcflow = PCFL(pflow);
5964
5965     //fprintf(stderr," build: ");
5966     //pflow->print(stderr,pflow);
5967
5968     if (checkLabel(pc)) {
5969
5970       /* This instruction marks the beginning of a
5971        * new flow segment */
5972
5973       pc->seq = 0;
5974       seq = 1;
5975
5976       /* If the previous pCode is not a flow object, then
5977        * insert a new flow object. (This check prevents
5978        * two consecutive flow objects from being insert in
5979        * the case where a skip instruction preceeds an
5980        * instruction containing a label.) */
5981
5982       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5983         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5984
5985       PCI(pc)->pcflow = PCFL(pflow);
5986
5987     }
5988
5989     if( PCI(pc)->isSkip) {
5990
5991       /* The two instructions immediately following this one
5992        * mark the beginning of a new flow segment */
5993
5994       while(pc && PCI(pc)->isSkip) {
5995
5996         PCI(pc)->pcflow = PCFL(pflow);
5997         pc->seq = seq-1;
5998         seq = 1;
5999
6000         InsertpFlow(pc, &pflow);
6001         pc=pic16_findNextInstruction(pc->next);
6002       }
6003
6004       seq = 0;
6005
6006       if(!pc)
6007         break;
6008
6009       PCI(pc)->pcflow = PCFL(pflow);
6010       pc->seq = 0;
6011       InsertpFlow(pc, &pflow);
6012
6013     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6014
6015       InsertpFlow(pc, &pflow);
6016       seq = 0;
6017
6018     }
6019     last_pci = pc;
6020     pc = pc->next;
6021   }
6022
6023   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6024   if(pflow)
6025     PCFL(pflow)->end = pb->pcTail;
6026 }
6027
6028 /*-------------------------------------------------------------------*/
6029 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6030 /*                           the flow blocks.                        */
6031 /*
6032  * unBuildFlow removes pCodeFlow objects from a pCode chain
6033  */
6034 /*-----------------------------------------------------------------*/
6035 static void unBuildFlow(pBlock *pb)
6036 {
6037   pCode *pc,*pcnext;
6038
6039   if(!pb)
6040     return;
6041
6042   pc = pb->pcHead;
6043
6044   while(pc) {
6045     pcnext = pc->next;
6046
6047     if(isPCI(pc)) {
6048
6049       pc->seq = 0;
6050       if(PCI(pc)->pcflow) {
6051         //Safe_free(PCI(pc)->pcflow);
6052         PCI(pc)->pcflow = NULL;
6053       }
6054
6055     } else if(isPCFL(pc) )
6056       pc->destruct(pc);
6057
6058     pc = pcnext;
6059   }
6060
6061
6062 }
6063 #if 0
6064 /*-----------------------------------------------------------------*/
6065 /*-----------------------------------------------------------------*/
6066 static void dumpCond(int cond)
6067 {
6068
6069   static char *pcc_str[] = {
6070     //"PCC_NONE",
6071     "PCC_REGISTER",
6072     "PCC_C",
6073     "PCC_Z",
6074     "PCC_DC",
6075     "PCC_OV",
6076     "PCC_N",
6077     "PCC_W",
6078     "PCC_EXAMINE_PCOP",
6079     "PCC_LITERAL",
6080     "PCC_REL_ADDR"
6081   };
6082
6083   int ncond = sizeof(pcc_str) / sizeof(char *);
6084   int i,j;
6085
6086   fprintf(stderr, "0x%04X\n",cond);
6087
6088   for(i=0,j=1; i<ncond; i++, j<<=1)
6089     if(cond & j)
6090       fprintf(stderr, "  %s\n",pcc_str[i]);
6091
6092 }
6093 #endif
6094
6095 #if 0
6096 /*-----------------------------------------------------------------*/
6097 /*-----------------------------------------------------------------*/
6098 static void FlowStats(pCodeFlow *pcflow)
6099 {
6100
6101   pCode *pc;
6102
6103   if(!isPCFL(pcflow))
6104     return;
6105
6106   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6107
6108   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6109
6110   if(!pc) {
6111     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6112     return;
6113   }
6114
6115
6116   fprintf(stderr, "  FlowStats inCond: ");
6117   dumpCond(pcflow->inCond);
6118   fprintf(stderr, "  FlowStats outCond: ");
6119   dumpCond(pcflow->outCond);
6120
6121 }
6122 #endif
6123 /*-----------------------------------------------------------------*
6124  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6125  *    if it affects the banking bits.
6126  *
6127  * return: -1 == Banking bits are unaffected by this pCode.
6128  *
6129  * return: > 0 == Banking bits are affected.
6130  *
6131  *  If the banking bits are affected, then the returned value describes
6132  * which bits are affected and how they're affected. The lower half
6133  * of the integer maps to the bits that are affected, the upper half
6134  * to whether they're set or cleared.
6135  *
6136  *-----------------------------------------------------------------*/
6137
6138 static int isBankInstruction(pCode *pc)
6139 {
6140   regs *reg;
6141   int bank = -1;
6142
6143   if(!isPCI(pc))
6144     return 0;
6145
6146   if( PCI(pc)->op == POC_MOVLB ||
6147       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6148     bank = PCOL(pc)->lit;
6149   }
6150
6151   return 1;
6152 }
6153
6154
6155 /*-----------------------------------------------------------------*/
6156 /*-----------------------------------------------------------------*/
6157 static void FillFlow(pCodeFlow *pcflow)
6158 {
6159
6160   pCode *pc;
6161   int cur_bank;
6162
6163   if(!isPCFL(pcflow))
6164     return;
6165
6166   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6167
6168   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6169
6170   if(!pc) {
6171     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6172     return;
6173   }
6174
6175   cur_bank = -1;
6176
6177   do {
6178     isBankInstruction(pc);
6179     pc = pc->next;
6180   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6181
6182 /*
6183   if(!pc ) {
6184     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6185   } else {
6186     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6187     pc->print(stderr,pc);
6188   }
6189
6190   fprintf(stderr, "  FillFlow inCond: ");
6191   dumpCond(pcflow->inCond);
6192   fprintf(stderr, "  FillFlow outCond: ");
6193   dumpCond(pcflow->outCond);
6194 */
6195 }
6196
6197 /*-----------------------------------------------------------------*/
6198 /*-----------------------------------------------------------------*/
6199 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6200 {
6201   pCodeFlowLink *fromLink, *toLink;
6202
6203   if(!from || !to || !to->pcflow || !from->pcflow)
6204     return;
6205
6206   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6207   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6208
6209   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6210   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6211
6212 }
6213
6214 pCode *pic16_getJumptabpCode (pCode *pc) {
6215   pCode *pcinf;
6216
6217   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6218   //pc->print (stderr, pc);
6219   pcinf = pc;
6220   while (pcinf) {
6221     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6222     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6223       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6224       case OPT_JUMPTABLE_BEGIN:
6225         /* leading begin of jump table -- in one */
6226         pcinf = pic16_findPrevInstruction (pcinf);
6227         return pcinf;
6228         break;
6229
6230       case OPT_JUMPTABLE_END:
6231         /* leading end of jumptable -- not in one */
6232         return NULL;
6233         break;
6234
6235       default:
6236         /* ignore all other PCInfos */
6237         break;
6238       }
6239     }
6240     pcinf = pcinf->prev;
6241   }
6242
6243   /* no PCInfo found -- not in a jumptable */
6244   return NULL;
6245 }
6246
6247 /*-----------------------------------------------------------------*
6248  * void LinkFlow(pBlock *pb)
6249  *
6250  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6251  * non-branching segments. In LinkFlow, we determine the execution
6252  * order of these segments. For example, if one of the segments ends
6253  * with a skip, then we know that there are two possible flow segments
6254  * to which control may be passed.
6255  *-----------------------------------------------------------------*/
6256 static void LinkFlow(pBlock *pb)
6257 {
6258   pCode *pc=NULL;
6259   pCode *pcflow;
6260   pCode *pct;
6261   pCode *jumptab_pre = NULL;
6262
6263   //fprintf(stderr,"linkflow \n");
6264
6265   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6266        pcflow != NULL;
6267        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6268
6269     if(!isPCFL(pcflow))
6270       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6271
6272     //fprintf(stderr," link: ");
6273     //pcflow->print(stderr,pcflow);
6274
6275     //FillFlow(PCFL(pcflow));
6276
6277     pc = PCFL(pcflow)->end;
6278
6279     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6280     if(isPCI_SKIP(pc)) {
6281 //      fprintf(stderr, "ends with skip\n");
6282 //      pc->print(stderr,pc);
6283
6284       pct=pic16_findNextInstruction(pc->next);
6285       LinkFlow_pCode(PCI(pc),PCI(pct));
6286       pct=pic16_findNextInstruction(pct->next);
6287       LinkFlow_pCode(PCI(pc),PCI(pct));
6288       continue;
6289     }
6290
6291     if(isPCI_BRANCH(pc)) {
6292       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6293
6294       /* handle GOTOs in jumptables */
6295       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6296         /* link to previous flow */
6297         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6298         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6299       }
6300
6301       switch (PCI(pc)->op) {
6302       case POC_GOTO:
6303       case POC_BRA:
6304       case POC_RETURN:
6305       case POC_RETLW:
6306       case POC_RETFIE:
6307               /* unconditional branches -- do not link to next instruction */
6308               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6309               break;
6310
6311       case POC_CALL:
6312       case POC_RCALL:
6313               /* unconditional calls -- link to next instruction */
6314               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6315               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6316               break;
6317
6318       case POC_BC:
6319       case POC_BN:
6320       case POC_BNC:
6321       case POC_BNN:
6322       case POC_BNOV:
6323       case POC_BNZ:
6324       case POC_BOV:
6325       case POC_BZ:
6326               /* conditional branches -- also link to next instruction */
6327               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6328               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6329               break;
6330
6331       default:
6332               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6333               assert (0 && "unhandled branching instruction");
6334               break;
6335       }
6336
6337       //fprintf(stderr, "ends with branch\n  ");
6338       //pc->print(stderr,pc);
6339
6340       if(!(pcol && isPCOLAB(pcol))) {
6341         if((PCI(pc)->op != POC_RETLW)
6342                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6343
6344                 /* continue if label is '$' which assembler knows how to parse */
6345                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6346
6347                 if(pic16_pcode_verbose) {
6348                         pc->print(stderr,pc);
6349                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6350                 }
6351         }
6352         continue;
6353       }
6354
6355       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6356         LinkFlow_pCode(PCI(pc),PCI(pct));
6357       else
6358         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6359                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6360
6361 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6362
6363       continue;
6364     }
6365
6366     if(isPCI(pc)) {
6367       //fprintf(stderr, "ends with non-branching instruction:\n");
6368       //pc->print(stderr,pc);
6369
6370       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6371
6372       continue;
6373     }
6374
6375     if(pc) {
6376       //fprintf(stderr, "ends with unknown\n");
6377       //pc->print(stderr,pc);
6378       continue;
6379     }
6380
6381     //fprintf(stderr, "ends with nothing: ERROR\n");
6382
6383   }
6384 }
6385 /*-----------------------------------------------------------------*/
6386 /*-----------------------------------------------------------------*/
6387
6388 /*-----------------------------------------------------------------*/
6389 /*-----------------------------------------------------------------*/
6390 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6391 {
6392
6393   if(!pc || !pcflow)
6394     return 0;
6395
6396   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6397     return 0;
6398
6399   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6400     return 1;
6401
6402   return 0;
6403 }
6404
6405
6406
6407
6408
6409 /*-----------------------------------------------------------------*/
6410 /* insertBankSwitch - inserts a bank switch statement in the       */
6411 /*                    assembly listing                             */
6412 /*                                                                 */
6413 /* position == 0: insert before                                    */
6414 /* position == 1: insert after pc                                  */
6415 /* position == 2: like 0 but previous was a skip instruction       */
6416 /*-----------------------------------------------------------------*/
6417 pCodeOp *pic16_popGetLabel(unsigned int key);
6418 extern int pic16_labelOffset;
6419
6420 static void insertBankSwitch(unsigned char position, pCode *pc)
6421 {
6422   pCode *new_pc;
6423
6424         if(!pc)
6425                 return;
6426
6427         /* emit BANKSEL [symbol] */
6428
6429
6430         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6431
6432 //      position = 0;           // position is always before (sanity check!)
6433
6434 #if 0
6435         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6436         pc->print(stderr, pc);
6437 #endif
6438
6439         switch(position) {
6440                 case 1: {
6441                         /* insert the bank switch after this pc instruction */
6442                         pCode *pcnext = pic16_findNextInstruction(pc);
6443
6444                                 pic16_pCodeInsertAfter(pc, new_pc);
6445                                 if(pcnext)pc = pcnext;
6446                 }; break;
6447
6448                 case 0:
6449                         /* insert the bank switch BEFORE this pc instruction */
6450                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6451                         break;
6452
6453                 case 2: {
6454                           symbol *tlbl;
6455                           pCode *pcnext, *pcprev, *npci, *ppc;
6456                           PIC_OPCODE ipci;
6457                           int ofs1=0, ofs2=0, len=0;
6458
6459                         /* just like 0, but previous was a skip instruction,
6460                          * so some care should be taken */
6461
6462                                 pic16_labelOffset += 10000;
6463                                 tlbl = newiTempLabel(NULL);
6464
6465                                 /* invert skip instruction */
6466                                 pcprev = pic16_findPrevInstruction(pc->prev);
6467                                 ipci = PCI(pcprev)->inverted_op;
6468                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6469
6470 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6471
6472                                 /* copy info from old pCode */
6473                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6474                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6475                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6476                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6477                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6478                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6479
6480                                 /* unlink old pCode */
6481                                 ppc = pcprev->prev;
6482                                 ppc->next = pcprev->next;
6483                                 pcprev->next->prev = ppc;
6484                                 pic16_pCodeInsertAfter(ppc, npci);
6485
6486                                 /* extra instructions to handle invertion */
6487                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6488                                 pic16_pCodeInsertAfter(npci, pcnext);
6489                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6490
6491                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6492                                 pic16_pCodeInsertAfter(pc, pcnext);
6493                         }; break;
6494         }
6495
6496
6497         /* Move the label, if there is one */
6498         if(PCI(pc)->label) {
6499 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6500 //                      __FILE__, __LINE__, pc, new_pc);
6501                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6502                 PCI(pc)->label = NULL;
6503         }
6504 }
6505
6506
6507 /*-----------------------------------------------------------------*/
6508 /*int compareBankFlow - compare the banking requirements between   */
6509 /*  flow objects. */
6510 /*-----------------------------------------------------------------*/
6511 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6512 {
6513
6514   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6515     return 0;
6516
6517   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6518     return 0;
6519
6520   if(pcflow->firstBank == -1)
6521     return 0;
6522
6523
6524   if(pcflowLink->pcflow->firstBank == -1) {
6525     pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6526                                         pcflowLink->pcflow->to :
6527                                         pcflowLink->pcflow->from);
6528     return compareBankFlow(pcflow, pctl, toORfrom);
6529   }
6530
6531   if(toORfrom) {
6532     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6533       return 0;
6534
6535     pcflowLink->bank_conflict++;
6536     pcflowLink->pcflow->FromConflicts++;
6537     pcflow->ToConflicts++;
6538   } else {
6539
6540     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6541       return 0;
6542
6543     pcflowLink->bank_conflict++;
6544     pcflowLink->pcflow->ToConflicts++;
6545     pcflow->FromConflicts++;
6546
6547   }
6548   /*
6549   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6550           pcflowLink->pcflow->pc.seq,
6551           pcflowLink->pcflow->FromConflicts,
6552           pcflowLink->pcflow->ToConflicts);
6553   */
6554   return 1;
6555
6556 }
6557
6558 #if 0
6559 /*-----------------------------------------------------------------*/
6560 /*-----------------------------------------------------------------*/
6561 static void DumpFlow(pBlock *pb)
6562 {
6563   pCode *pc=NULL;
6564   pCode *pcflow;
6565   pCodeFlowLink *pcfl;
6566
6567
6568   fprintf(stderr,"Dump flow \n");
6569   pb->pcHead->print(stderr, pb->pcHead);
6570
6571   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6572   pcflow->print(stderr,pcflow);
6573
6574   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6575        pcflow != NULL;
6576        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6577
6578     if(!isPCFL(pcflow)) {
6579       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6580       continue;
6581     }
6582     fprintf(stderr,"dumping: ");
6583     pcflow->print(stderr,pcflow);
6584     FlowStats(PCFL(pcflow));
6585
6586     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6587
6588       pc = PCODE(pcfl->pcflow);
6589
6590       fprintf(stderr, "    from seq %d:\n",pc->seq);
6591       if(!isPCFL(pc)) {
6592         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6593         pc->print(stderr,pc);
6594       }
6595
6596     }
6597
6598     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6599
6600       pc = PCODE(pcfl->pcflow);
6601
6602       fprintf(stderr, "    to seq %d:\n",pc->seq);
6603       if(!isPCFL(pc)) {
6604         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6605         pc->print(stderr,pc);
6606       }
6607
6608     }
6609
6610   }
6611
6612 }
6613 #endif
6614 /*-----------------------------------------------------------------*/
6615 /*-----------------------------------------------------------------*/
6616 static int OptimizepBlock(pBlock *pb)
6617 {
6618   pCode *pc, *pcprev;
6619   int matches =0;
6620
6621   if(!pb || !peepOptimizing)
6622     return 0;
6623
6624   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6625 /*
6626   for(pc = pb->pcHead; pc; pc = pc->next)
6627     matches += pic16_pCodePeepMatchRule(pc);
6628 */
6629
6630   pc = pic16_findNextInstruction(pb->pcHead);
6631   if(!pc)
6632     return 0;
6633
6634   pcprev = pc->prev;
6635   do {
6636
6637
6638     if(pic16_pCodePeepMatchRule(pc)) {
6639
6640       matches++;
6641
6642       if(pcprev)
6643         pc = pic16_findNextInstruction(pcprev->next);
6644       else
6645         pc = pic16_findNextInstruction(pb->pcHead);
6646     } else
6647       pc = pic16_findNextInstruction(pc->next);
6648   } while(pc);
6649
6650   if(matches)
6651     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6652   return matches;
6653
6654 }
6655
6656 /*-----------------------------------------------------------------*/
6657 /*-----------------------------------------------------------------*/
6658 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6659 {
6660   pCode *pc;
6661
6662   for(pc = pcs; pc; pc = pc->next) {
6663
6664     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6665        (PCI(pc)->pcop) &&
6666        (PCI(pc)->pcop->type == PO_LABEL) &&
6667        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6668       return pc;
6669   }
6670
6671
6672   return NULL;
6673 }
6674
6675 /*-----------------------------------------------------------------*/
6676 /*-----------------------------------------------------------------*/
6677 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6678 {
6679
6680   char *s=NULL;
6681
6682   if(isPCI(pc) &&
6683      (PCI(pc)->pcop) &&
6684      (PCI(pc)->pcop->type == PO_LABEL)) {
6685
6686     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6687
6688 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6689 //    if(pcol->pcop.name)
6690 //      Safe_free(pcol->pcop.name);
6691
6692     /* If the key is negative, then we (probably) have a label to
6693      * a function and the name is already defined */
6694
6695     if(pcl->key>0)
6696       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6697     else
6698       s = pcl->label;
6699
6700     //sprintf(buffer,"_%05d_DS_",pcl->key);
6701     if(!s) {
6702       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6703     }
6704     pcol->pcop.name = Safe_strdup(s);
6705     pcol->key = pcl->key;
6706     //pc->print(stderr,pc);
6707
6708   }
6709
6710
6711 }
6712
6713 /*-----------------------------------------------------------------*/
6714 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6715 /*                            pCode chain if they're not used.     */
6716 /*-----------------------------------------------------------------*/
6717 static void pBlockRemoveUnusedLabels(pBlock *pb)
6718 {
6719   pCode *pc; pCodeLabel *pcl;
6720
6721   if(!pb || !pb->pcHead)
6722     return;
6723
6724   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6725
6726     pBranch *pbr = PCI(pc)->label;
6727     if(pbr && pbr->next) {
6728       pCode *pcd = pb->pcHead;
6729
6730 //      fprintf(stderr, "multiple labels\n");
6731 //      pc->print(stderr,pc);
6732
6733       pbr = pbr->next;
6734       while(pbr) {
6735
6736         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6737           //fprintf(stderr,"Used by:\n");
6738           //pcd->print(stderr,pcd);
6739
6740           exchangeLabels(PCL(pbr->pc),pcd);
6741
6742           pcd = pcd->next;
6743         }
6744         pbr = pbr->next;
6745       }
6746     }
6747   }
6748
6749   for(pc = pb->pcHead; pc; pc = pc->next) {
6750
6751     if(isPCL(pc)) // pc->type == PC_LABEL)
6752       pcl = PCL(pc);
6753     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6754       pcl = PCL(PCI(pc)->label->pc);
6755     else continue;
6756
6757 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6758
6759     /* This pCode is a label, so search the pBlock to see if anyone
6760      * refers to it */
6761
6762     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6763         && (!pcl->force)) {
6764     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6765       /* Couldn't find an instruction that refers to this label
6766        * So, unlink the pCode label from it's pCode chain
6767        * and destroy the label */
6768 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6769
6770       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6771       if(pc->type == PC_LABEL) {
6772         pic16_unlinkpCode(pc);
6773         pCodeLabelDestruct(pc);
6774       } else {
6775         unlinkpCodeFromBranch(pc, PCODE(pcl));
6776         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6777           Safe_free(pc->label);
6778         }*/
6779       }
6780
6781     }
6782   }
6783
6784 }
6785
6786
6787 /*-----------------------------------------------------------------*/
6788 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6789 /*                     chain and put them into pBranches that are  */
6790 /*                     associated with the appropriate pCode       */
6791 /*                     instructions.                               */
6792 /*-----------------------------------------------------------------*/
6793 void pic16_pBlockMergeLabels(pBlock *pb)
6794 {
6795   pBranch *pbr;
6796   pCode *pc, *pcnext=NULL;
6797
6798   if(!pb)
6799     return;
6800
6801   /* First, Try to remove any unused labels */
6802   //pBlockRemoveUnusedLabels(pb);
6803
6804   /* Now loop through the pBlock and merge the labels with the opcodes */
6805
6806   pc = pb->pcHead;
6807   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6808
6809   while(pc) {
6810     pCode *pcn = pc->next;
6811
6812     if(pc->type == PC_LABEL) {
6813
6814 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6815 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6816
6817       if((pcnext = pic16_findNextInstruction(pc) )) {
6818
6819 //              pcnext->print(stderr, pcnext);
6820
6821         // Unlink the pCode label from it's pCode chain
6822         pic16_unlinkpCode(pc);
6823
6824 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6825         // And link it into the instruction's pBranch labels. (Note, since
6826         // it's possible to have multiple labels associated with one instruction
6827         // we must provide a means to accomodate the additional labels. Thus
6828         // the labels are placed into the singly-linked list "label" as
6829         // opposed to being a single member of the pCodeInstruction.)
6830
6831         //_ALLOC(pbr,sizeof(pBranch));
6832 #if 1
6833         pbr = Safe_calloc(1,sizeof(pBranch));
6834         pbr->pc = pc;
6835         pbr->next = NULL;
6836
6837         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6838 #endif
6839       } else {
6840         if(pic16_pcode_verbose)
6841         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6842       }
6843     } else if(pc->type == PC_CSOURCE) {
6844
6845       /* merge the source line symbolic info into the next instruction */
6846       if((pcnext = pic16_findNextInstruction(pc) )) {
6847
6848         // Unlink the pCode label from it's pCode chain
6849         pic16_unlinkpCode(pc);
6850         PCI(pcnext)->cline = PCCS(pc);
6851         //fprintf(stderr, "merging CSRC\n");
6852         //genericPrint(stderr,pcnext);
6853       }
6854
6855     }
6856     pc = pcn;
6857   }
6858   pBlockRemoveUnusedLabels(pb);
6859
6860 }
6861
6862 /*-----------------------------------------------------------------*/
6863 /*-----------------------------------------------------------------*/
6864 static int OptimizepCode(char dbName)
6865 {
6866 #define MAX_PASSES 4
6867
6868   int matches = 0;
6869   int passes = 0;
6870   pBlock *pb;
6871
6872   if(!the_pFile)
6873     return 0;
6874
6875   DFPRINTF((stderr," Optimizing pCode\n"));
6876
6877   do {
6878     matches = 0;
6879     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6880       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6881         matches += OptimizepBlock(pb);
6882     }
6883   }
6884   while(matches && ++passes < MAX_PASSES);
6885
6886   return matches;
6887 }
6888
6889
6890
6891 const char *pic16_pCodeOpType(pCodeOp *pcop);
6892 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6893
6894
6895 /*-----------------------------------------------------------------*/
6896 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6897 /*-----------------------------------------------------------------*/
6898
6899 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6900 {
6901   pCodeOp *pcop=NULL;
6902
6903 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6904
6905   if(pc->name) {
6906         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6907   } else {
6908     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6909   }
6910
6911   assert(pcop != NULL);
6912
6913   if( !( (pcop->type == PO_LABEL) ||
6914          (pcop->type == PO_LITERAL) ||
6915          (pcop->type == PO_STR) ))
6916     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6917     PCOR(pcop)->r->wasUsed = 1;
6918     PCOR(pcop)->instance = PCOR(pc)->instance;
6919
6920   return pcop;
6921 }
6922
6923
6924 /*----------------------------------------------------------------------*
6925  * pic16_areRegsSame - check to see if the names of two registers match *
6926  *----------------------------------------------------------------------*/
6927 int pic16_areRegsSame(regs *r1, regs *r2)
6928 {
6929         if(!strcmp(r1->name, r2->name))return 1;
6930
6931   return 0;
6932 }
6933
6934
6935 /*-----------------------------------------------------------------*/
6936 /*-----------------------------------------------------------------*/
6937 static void pic16_FixRegisterBanking(pBlock *pb)
6938 {
6939   pCode *pc=NULL;
6940   pCode *pcprev=NULL;
6941   regs *reg, *prevreg;
6942   unsigned char flag=0;
6943
6944         if(!pb)
6945                 return;
6946
6947         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6948         if(!pc)return;
6949
6950         /* loop through all of the flow blocks with in one pblock */
6951
6952 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6953
6954         prevreg = NULL;
6955         do {
6956                 /* at this point, pc should point to a PC_FLOW object */
6957                 /* for each flow block, determine the register banking
6958                  * requirements */
6959
6960
6961                 /* if label, then might come from other point, force banksel */
6962                 if(isPCL(pc))prevreg = NULL;
6963
6964                 if(!isPCI(pc))goto loop;
6965
6966                 if(PCI(pc)->label)prevreg = NULL;
6967
6968                 if(PCI(pc)->is2MemOp)goto loop;
6969
6970                 /* if goto, then force banksel */
6971 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6972
6973                 reg = pic16_getRegFromInstruction(pc);
6974
6975 #if 0
6976                 pc->print(stderr, pc);
6977                 fprintf(stderr, "reg = %p\n", reg);
6978
6979                 if(reg) {
6980                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6981                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6982                                 reg->address,reg->isBitField, reg->isFixed);
6983                 }
6984 #endif
6985
6986                 /* now make some tests to make sure that instruction needs bank switch */
6987
6988                 /* if no register exists, and if not a bit opcode goto loop */
6989                 if(!reg) {
6990                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6991                 }
6992
6993                 if(isPCI_SKIP(pc)) {
6994 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6995 //                prevreg = NULL;
6996                 }
6997                 if(reg && isACCESS_BANK(reg))goto loop;
6998
6999                 if(!isBankInstruction(pc))goto loop;
7000
7001                 if(isPCI_LIT(pc))goto loop;
7002
7003                 if(PCI(pc)->op == POC_CALL)goto loop;
7004
7005                 /* Examine the instruction before this one to make sure it is
7006                  * not a skip type instruction */
7007                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7008
7009                 flag = 0;               /* add before this instruction */
7010
7011                 /* if previous instruction is a skip one, then set flag
7012                  * to 2 and call insertBankSwitch */
7013                 if(pcprev && isPCI_SKIP(pcprev)) {
7014                   flag=2;       //goto loop
7015 //                prevreg = NULL;
7016                 }
7017
7018                 if(pic16_options.opt_banksel>0) {
7019                   char op1[128], op2[128];
7020
7021                     if(prevreg) {
7022                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7023                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7024                       if(!strcmp(op1, op2))goto loop;
7025                     }
7026                 }
7027                 prevreg = reg;
7028                 insertBankSwitch(flag, pc);
7029
7030 //              fprintf(stderr, "BANK SWITCH inserted\n");
7031
7032 loop:
7033                 pcprev = pc;
7034                 pc = pc->next;
7035         } while (pc);
7036 }
7037
7038 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7039
7040 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7041 int instrSize (pCode *pc)
7042 {
7043   if (!pc) return 0;
7044
7045   if (isPCAD(pc)) {
7046     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7047     return 4; // assumes only regular instructions using <= 4 bytes
7048   }
7049
7050   if (isPCI(pc)) return PCI(pc)->isize;
7051
7052   return 0;
7053 }
7054
7055 /* Returns 1 if pc is referenced by the given label (either
7056  * pc is the label itself or is an instruction with an attached
7057  * label).
7058  * Returns 0 if pc is not preceeded by the specified label.
7059  */
7060 int isLabel (pCode *pc, char *label)
7061 {
7062   if (!pc) return 0;
7063
7064   // label attached to the pCode?
7065   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7066     pBranch *lab = NULL;
7067     lab = PCI(pc)->label;
7068
7069     while (lab) {
7070       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7071         return 1;
7072       }
7073       lab = lab->next;
7074     } // while
7075   } // if
7076
7077   // is inline assembly label?
7078   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7079     // do not compare trailing ':'
7080     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7081       return 1;
7082     }
7083   } // if
7084
7085   // is pCodeLabel?
7086   if (isPCL(pc)) {
7087       if (strcmp(PCL(pc)->label,label) == 0) {
7088       return 1;
7089     }
7090   } // if
7091
7092   // no label/no label attached/wrong label(s)
7093   return 0;
7094 }
7095
7096 /* Returns the distance to the given label in terms of words.
7097  * Labels are searched only within -max .. max words from pc.
7098  * Returns max if the label could not be found or
7099  * its distance from pc in (-max..+max).
7100  */
7101 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7102   int dist = instrSize(pc);
7103   pCode *curr = pc;
7104
7105   // search backwards
7106   while (dist < max && curr && !isLabel (curr, label)) {
7107     curr = curr->prev;
7108     dist += instrSize(curr); // sizeof (instruction)
7109   } // while
7110   if (curr && dist < max) {
7111     if (target != NULL) *target = curr;
7112     return -dist;
7113   }
7114
7115   dist = 0;
7116   curr = pic16_findNextInstruction (pc->next);
7117   //search forwards
7118   while (dist < max && curr && !isLabel (curr, label)) {
7119     dist += instrSize(curr); // sizeof (instruction)
7120     curr = curr->next;
7121   } // while
7122   if (curr && dist < max) {
7123     if (target != NULL) *target = curr;
7124     return dist;
7125   }
7126
7127   if (target != NULL) *target = NULL;
7128   return max;
7129 }
7130
7131 /* Returns -1 if pc does NOT denote an instruction like
7132  * BTFS[SC] STATUS,i
7133  * Otherwise we return
7134  *   (a) 0x10 + i for BTFSS
7135  *   (b) 0x00 + i for BTFSC
7136  */
7137 int isSkipOnStatus (pCode *pc)
7138 {
7139   int res = -1;
7140   pCodeOp *pcop;
7141   if (!pc || !isPCI(pc)) return -1;
7142   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7143   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7144   else return -1;
7145
7146   pcop = PCI(pc)->pcop;
7147
7148   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7149     return res + ((pCodeOpRegBit *)pcop)->bit;
7150   }
7151
7152   return -1;
7153 }
7154
7155 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7156  * returns 0 otherwise. */
7157 int isConditionalBranch (pCode *pc)
7158 {
7159   if (!pc || !isPCI_BRANCH(pc)) return 0;
7160
7161   switch (PCI(pc)->op) {
7162   case POC_BC:
7163   case POC_BZ:
7164   case POC_BOV:
7165   case POC_BN:
7166   case POC_BNC:
7167   case POC_BNZ:
7168   case POC_BNOV:
7169   case POC_BNN:
7170     return 1;
7171
7172   default:
7173     break;
7174   } // switch
7175
7176   return 0;
7177 }
7178
7179 /* Returns 1 if pc has a label attached to it.
7180  * This can be either a label stored in the pCode itself (.label)
7181  * or a label making up its own pCode preceding this pc.
7182  * Returns 0 if pc cannot be reached directly via a label.
7183  */
7184 int hasNoLabel (pCode *pc)
7185 {
7186   pCode *prev;
7187   if (!pc) return 1;
7188
7189   // are there any label pCodes between pc and the previous instruction?
7190   prev = pic16_findPrevInstruction (pc->prev);
7191   while (pc && pc != prev) {
7192     // pCode with attached label?
7193     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7194         && PCI(pc)->label) {
7195       return 0;
7196     }
7197     // is inline assembly label?
7198     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7199     if (isPCW(pc) && PCW(pc)->label) return 0;
7200
7201     // pCodeLabel?
7202     if (isPCL(pc)) return 0;
7203
7204     pc = pc->prev;
7205   } // if
7206
7207   // no label found
7208   return 1;
7209 }
7210
7211 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7212   char buf[512];
7213   va_list va;
7214
7215   va_start (va, fmt);
7216   vsprintf (buf, fmt, va);
7217   va_end (va);
7218
7219   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7220 }
7221
7222 /* Replaces the old pCode with the new one, moving the labels,
7223  * C source line and probably flow information to the new pCode.
7224  */
7225 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7226   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7227     return;
7228
7229   /* first move all labels from old to new */
7230   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7231   PCI(oldPC)->label = NULL;
7232
7233 #if 0
7234   /* move C source line (if possible) */
7235   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7236     PCI(newPC)->cline = PCI(oldPC)->cline;
7237 #endif
7238
7239   /* keep flow information intact */
7240   newPC->seq = oldPC->seq;
7241   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7242   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7243     PCI(newPC)->pcflow->end = newPC;
7244   }
7245
7246   /* insert a comment stating which pCode has been replaced */
7247 #if 1
7248   if (pic16_pcode_verbose || pic16_debug_verbose) {
7249     char pc_str[256];
7250     pic16_pCode2str (pc_str, 256, oldPC);
7251     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7252   }
7253 #endif
7254
7255   /* insert new pCode into pBlock */
7256   pic16_pCodeInsertAfter (oldPC, newPC);
7257   pic16_unlinkpCode (oldPC);
7258
7259   /* destruct replaced pCode */
7260   oldPC->destruct (oldPC);
7261 }
7262
7263 /* Returns the inverted conditional branch (if any) or NULL.
7264  * pcop must be set to the new jump target.
7265  */
7266 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7267 {
7268   pCode *newBcc;
7269
7270   if (!bcc || !isPCI(bcc)) return NULL;
7271
7272   switch (PCI(bcc)->op) {
7273   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7274   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7275   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7276   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7277   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7278   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7279   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7280   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7281   default:
7282     newBcc = NULL;
7283   }
7284   return newBcc;
7285 }
7286
7287 #define MAX_DIST_GOTO         0x7FFFFFFF
7288 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7289 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7290 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7291 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7292
7293 /* Follows GOTO/BRA instructions to their target instructions, stores the
7294  * final destination (not a GOTO or BRA instruction) in target and returns
7295  * the distance from the original pc to *target.
7296  */
7297 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7298         pCode *curr = pc;
7299         pCode *last = NULL;
7300         pCodeOp *lastPCOP = NULL;
7301         int dist = 0;
7302         int depth = 0;
7303
7304         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7305
7306         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7307         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7308                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7309                 last = curr;
7310                 lastPCOP = PCI(curr)->pcop;
7311                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7312                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7313         } // while
7314
7315         if (target) *target = last;
7316         if (pcop) *pcop = lastPCOP;
7317         return dist;
7318 }
7319
7320 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7321  * Otherwise the first pCode after the jumptable (after
7322  * the OPT_JUMPTABLE_END tag) is returned.
7323  */
7324 pCode *skipJumptables (pCode *pc, int *isJumptable)
7325 {
7326   *isJumptable = 0;
7327   if (!pc) return NULL;
7328
7329   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7330     *isJumptable = 1;
7331     //fprintf (stderr, "SKIPPING jumptable\n");
7332     do {
7333       //pc->print(stderr, pc);
7334       pc = pc->next;
7335     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7336                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7337     //fprintf (stderr, "<<JUMPTAB:\n");
7338     // skip OPT_END as well
7339     if (pc) pc = pc->next;
7340   } // while
7341
7342   return pc;
7343 }
7344
7345 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7346 {
7347   int isJumptab;
7348   *isJumptable = 0;
7349   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7350     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7351     pc = skipJumptables (pc, &isJumptab);
7352     if (isJumptab) {
7353         // pc is the first pCode after the jumptable
7354         *isJumptable = 1;
7355     } else {
7356         // pc has not been changed by skipJumptables()
7357         pc = pc->next;
7358     }
7359   } // while
7360
7361   return pc;
7362 }
7363
7364 /* Turn GOTOs into BRAs if distance between GOTO and label
7365  * is less than 1024 bytes.
7366  *
7367  * This method is especially useful if GOTOs after BTFS[SC]
7368  * can be turned into BRAs as GOTO would cost another NOP
7369  * if skipped.
7370  */
7371 void pic16_OptimizeJumps ()
7372 {
7373   pCode *pc;
7374   pCode *pc_prev = NULL;
7375   pCode *pc_next = NULL;
7376   pBlock *pb;
7377   pCode *target;
7378   int change, iteration, isJumptab;
7379   int isHandled = 0;
7380   char *label;
7381   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7382
7383   if (!the_pFile) return;
7384
7385   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7386
7387   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7388     int matchedInvertRule = 1;
7389     iteration = 1;
7390     do {
7391       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7392       change = 0;
7393       pc = pic16_findNextInstruction (pb->pcHead);
7394
7395       while (pc) {
7396         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7397         if (isJumptab) {
7398                 // skip jumptable, i.e. start over with no pc_prev!
7399                 pc_prev = NULL;
7400                 pc = pc_next;
7401                 continue;
7402         } // if
7403
7404         /* (1) resolve chained jumps
7405          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7406          * (a) leave dead code in and
7407          * (b) skip over the dead code with an (unneccessary) jump.
7408          */
7409         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7410           pCodeOp *lastTargetOp = NULL;
7411           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7412           int maxDist = MAX_DIST_BCC;
7413           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7414           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7415
7416           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7417           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7418               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7419             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7420             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7421             PCI(pc)->pcop->name = lastTargetOp->name;
7422             change++;
7423             opt_gotochain++;
7424           } // if
7425         } // if
7426
7427
7428         if (IS_GOTO(pc)) {
7429           int dist;
7430           int condBraType = isSkipOnStatus(pc_prev);
7431           label = PCI(pc)->pcop->name;
7432           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7433           if (dist < 0) dist = -dist;
7434           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7435           isHandled = 0;
7436
7437
7438           /* (2) remove "GOTO label; label:" */
7439           if (isLabel (pc_next, label)) {
7440             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7441             // first remove all preceeding SKIP instructions
7442             while (pc_prev && isPCI_SKIP(pc_prev)) {
7443               // attach labels on this instruction to pc_next
7444               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7445               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7446               PCI(pc_prev)->label = NULL;
7447               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7448               pic16_unlinkpCode (pc_prev);
7449               pc_prev = pic16_findPrevInstruction (pc);
7450             } // while
7451             // now remove the redundant goto itself
7452             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7453             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7454             pic16_unlinkpCode (pc);
7455             pc = pic16_findPrevInstruction(pc_next->prev);
7456             isHandled = 1; // do not perform further optimizations
7457             opt_gotonext++;
7458             change++;
7459           } // if
7460
7461
7462           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7463           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7464             if (dist < MAX_DIST_BCC) {
7465               pCode *bcc = NULL;
7466               switch (condBraType) {
7467               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7468                 // no BDC on DIGIT CARRY available
7469               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7470               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7471               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7472               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7473                 // no BNDC on DIGIT CARRY available
7474               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7475               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7476               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7477               default:
7478                 // no replacement possible
7479                 bcc = NULL;
7480                 break;
7481               } // switch
7482               if (bcc) {
7483                 // ATTENTION: keep labels attached to BTFSx!
7484                 // HINT: GOTO is label free (checked above)
7485                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7486                 isHandled = 1; // do not perform further optimizations
7487                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7488                 pic16_pCodeReplace (pc_prev, bcc);
7489                 pc->destruct(pc);
7490                 pc = bcc;
7491                 opt_cond++;
7492                 change++;
7493               } // if
7494             } else {
7495               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7496               cond_toofar++;
7497             } // if
7498           } // if
7499
7500           if (!isHandled) {
7501             // (4) eliminate the following (common) tripel:
7502             //           <pred.>;
7503             //  labels1: Bcc label2;
7504             //           GOTO somewhere;    ; <-- instruction referenced by pc
7505             //  label2:  <cont.>
7506             // and replace it by
7507             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7508             //  label2:  <cont.>
7509             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7510             //            to <cont.> instead
7511             // ATTENTION: This optimization is only valid if <pred.> is
7512             //            not a skip operation!
7513             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7514             // ATTENTION: no label may be attached to the GOTO instruction!
7515             if (isConditionalBranch(pc_prev)
7516                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7517                 && (dist < MAX_DIST_BCC)
7518                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7519                 && hasNoLabel(pc)) {
7520               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7521
7522               if (newBcc) {
7523                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7524                 isHandled = 1; // do not perform further optimizations
7525                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7526                 pic16_pCodeReplace (pc_prev, newBcc);
7527                 pc->destruct(pc);
7528                 pc = newBcc;
7529                 opt_reorder++;
7530                 change++;
7531                 matchedInvertRule++;
7532               }
7533             }
7534           }
7535
7536           /* (5) now just turn GOTO into BRA */
7537           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7538             if (dist < MAX_DIST_BRA) {
7539               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7540               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7541               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7542               pic16_pCodeReplace (pc, newBra);
7543               pc = newBra;
7544               opt++;
7545               change++;
7546             } else {
7547               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7548               toofar++;
7549             }
7550           } // if (!isHandled)
7551         } // if
7552
7553         pc_prev = pc;
7554         pc = pc_next;
7555       } // while (pc)
7556
7557       pBlockRemoveUnusedLabels (pb);
7558
7559       // This line enables goto chain resolution!
7560       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7561
7562       iteration++;
7563     } while (change); /* fixpoint iteration per pBlock */
7564   } // for (pb)
7565
7566   // emit some statistics concerning goto-optimization
7567 #if 0
7568   if (pic16_debug_verbose || pic16_pcode_verbose) {
7569     fprintf (stderr, "optimize-goto:\n"
7570              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7571              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7572              "\t%5d conditional \"skipping\" jumps inverted\n"
7573              "\t%5d GOTOs to next instruction removed\n"
7574              "\t%5d chained GOTOs resolved\n",
7575              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7576   } // if
7577 #endif
7578   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7579 }
7580
7581 #undef IS_GOTO
7582 #undef MAX_JUMPCHAIN_DEPTH
7583 #undef MAX_DIST_GOTO
7584 #undef MAX_DIST_BRA
7585 #undef MAX_DIST_BCC
7586
7587 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7588
7589 static void pBlockDestruct(pBlock *pb)
7590 {
7591
7592   if(!pb)
7593     return;
7594
7595
7596 //  Safe_free(pb);
7597
7598 }
7599
7600 /*-----------------------------------------------------------------*/
7601 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7602 /*                                  name dbName and combine them   */
7603 /*                                  into one block                 */
7604 /*-----------------------------------------------------------------*/
7605 static void mergepBlocks(char dbName)
7606 {
7607
7608   pBlock *pb, *pbmerged = NULL,*pbn;
7609
7610   pb = the_pFile->pbHead;
7611
7612   //fprintf(stderr," merging blocks named %c\n",dbName);
7613   while(pb) {
7614
7615     pbn = pb->next;
7616     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7617     if( getpBlock_dbName(pb) == dbName) {
7618
7619       //fprintf(stderr," merged block %c\n",dbName);
7620
7621       if(!pbmerged) {
7622         pbmerged = pb;
7623       } else {
7624         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7625         /* pic16_addpCode2pBlock doesn't handle the tail: */
7626         pbmerged->pcTail = pb->pcTail;
7627
7628         pb->prev->next = pbn;
7629         if(pbn)
7630           pbn->prev = pb->prev;
7631
7632
7633         pBlockDestruct(pb);
7634       }
7635       //pic16_printpBlock(stderr, pbmerged);
7636     }
7637     pb = pbn;
7638   }
7639
7640 }
7641
7642 /*-----------------------------------------------------------------*/
7643 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7644 /*                                                                 */
7645 /* level 0 == minimal optimization                                 */
7646 /*   optimize registers that are used only by two instructions     */
7647 /* level 1 == maximal optimization                                 */
7648 /*   optimize by looking at pairs of instructions that use the     */
7649 /*   register.                                                     */
7650 /*-----------------------------------------------------------------*/
7651
7652 static void AnalyzeFlow(int level)
7653 {
7654   static int times_called=0;
7655   pBlock *pb;
7656
7657     if(!the_pFile) {
7658       /* remove unused allocated registers before exiting */
7659       pic16_RemoveUnusedRegisters();
7660       return;
7661     }
7662
7663
7664     /* if this is not the first time this function has been called,
7665      * then clean up old flow information */
7666     if(times_called++) {
7667       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7668         unBuildFlow(pb);
7669         pic16_RegsUnMapLiveRanges();
7670     }
7671     GpcFlowSeq = 1;
7672
7673     /* Phase 2 - Flow Analysis - Register Banking
7674      *
7675      * In this phase, the individual flow blocks are examined
7676      * and register banking is fixed.
7677      */
7678
7679 #if 0
7680     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7681       pic16_FixRegisterBanking(pb);
7682 #endif
7683
7684     /* Phase 2 - Flow Analysis
7685      *
7686      * In this phase, the pCode is partition into pCodeFlow
7687      * blocks. The flow blocks mark the points where a continuous
7688      * stream of instructions changes flow (e.g. because of
7689      * a call or goto or whatever).
7690      */
7691
7692     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7693       pic16_BuildFlow(pb);
7694
7695
7696     /* Phase 2 - Flow Analysis - linking flow blocks
7697      *
7698      * In this phase, the individual flow blocks are examined
7699      * to determine their order of excution.
7700      */
7701
7702     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7703       LinkFlow(pb);
7704
7705 #if 1
7706         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7707                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7708                         pic16_createDF (pb);
7709 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7710                         pic16_vcg_dump_default (pb);
7711 #endif
7712                         //pic16_destructDF (pb);
7713                 }
7714
7715                 pic16_df_stats ();
7716                 if (0) releaseStack (); // releasing is costly...
7717         }
7718 #endif
7719
7720     /* Phase 3 - Flow Analysis - Flow Tree
7721      *
7722      * In this phase, the individual flow blocks are examined
7723      * to determine their order of execution.
7724      */
7725
7726     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7727       pic16_BuildFlowTree(pb);
7728
7729
7730     /* Phase x - Flow Analysis - Used Banks
7731      *
7732      * In this phase, the individual flow blocks are examined
7733      * to determine the Register Banks they use
7734      */
7735
7736 #if 0
7737     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7738       FixBankFlow(pb);
7739 #endif
7740
7741
7742     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7743       pic16_pCodeRegMapLiveRanges(pb);
7744
7745     pic16_RemoveUnusedRegisters();
7746     pic16_removeUnusedRegistersDF ();
7747
7748   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7749     pic16_pCodeRegOptimizeRegUsage(level);
7750
7751
7752 #if 0
7753     if(!options.nopeep)
7754       OptimizepCode('*');
7755 #endif
7756
7757 #if 0
7758     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7759       DumpFlow(pb);
7760 #endif
7761
7762     /* debug stuff */
7763     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7764       pCode *pcflow;
7765
7766         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7767           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7768           pcflow = pcflow->next) {
7769             FillFlow(PCFL(pcflow));
7770         }
7771     }
7772
7773 #if 0
7774     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7775       pCode *pcflow;
7776
7777         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7778           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7779           pcflow = pcflow->next) {
7780             FlowStats(PCFL(pcflow));
7781         }
7782     }
7783 #endif
7784 }
7785
7786 /* VR -- no need to analyze banking in flow, but left here :
7787  *      1. because it may be used in the future for other purposes
7788  *      2. because if omitted we'll miss some optimization done here
7789  *
7790  * Perhaps I should rename it to something else
7791  */
7792
7793 /*-----------------------------------------------------------------*/
7794 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7795 /*                  assigned to the registers.                     */
7796 /*                                                                 */
7797 /*-----------------------------------------------------------------*/
7798
7799 void pic16_AnalyzeBanking(void)
7800 {
7801   pBlock  *pb;
7802
7803     /* Phase x - Flow Analysis - Used Banks
7804      *
7805      * In this phase, the individual flow blocks are examined
7806      * to determine the Register Banks they use
7807      */
7808
7809     AnalyzeFlow(0);
7810     AnalyzeFlow(1);
7811
7812     if(!options.nopeep)
7813       OptimizepCode('*');
7814
7815
7816     if(!the_pFile)return;
7817
7818     if(!pic16_options.no_banksel) {
7819       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7820 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7821         pic16_FixRegisterBanking(pb);
7822       }
7823     }
7824 }
7825
7826 /*-----------------------------------------------------------------*/
7827 /* buildCallTree - Look at the flow and extract all of the calls.  */
7828 /*-----------------------------------------------------------------*/
7829 static set *register_usage(pBlock *pb);
7830
7831 static void buildCallTree(void    )
7832 {
7833   pBranch *pbr;
7834   pBlock  *pb;
7835   pCode   *pc;
7836   regs *r;
7837
7838   if(!the_pFile)
7839     return;
7840
7841
7842
7843   /* Now build the call tree.
7844      First we examine all of the pCodes for functions.
7845      Keep in mind that the function boundaries coincide
7846      with pBlock boundaries.
7847
7848      The algorithm goes something like this:
7849      We have two nested loops. The outer loop iterates
7850      through all of the pBlocks/functions. The inner
7851      loop iterates through all of the pCodes for
7852      a given pBlock. When we begin iterating through
7853      a pBlock, the variable pc_fstart, pCode of the start
7854      of a function, is cleared. We then search for pCodes
7855      of type PC_FUNCTION. When one is encountered, we
7856      initialize pc_fstart to this and at the same time
7857      associate a new pBranch object that signifies a
7858      branch entry. If a return is found, then this signifies
7859      a function exit point. We'll link the pCodes of these
7860      returns to the matching pc_fstart.
7861
7862      When we're done, a doubly linked list of pBranches
7863      will exist. The head of this list is stored in
7864      `the_pFile', which is the meta structure for all
7865      of the pCode. Look at the pic16_printCallTree function
7866      on how the pBranches are linked together.
7867
7868    */
7869   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7870     pCode *pc_fstart=NULL;
7871     for(pc = pb->pcHead; pc; pc = pc->next) {
7872
7873         if(isPCI(pc) && pc_fstart) {
7874                 if(PCI(pc)->is2MemOp) {
7875                         r = pic16_getRegFromInstruction2(pc);
7876                         if(r && !strcmp(r->name, "POSTDEC1"))
7877                                 PCF(pc_fstart)->stackusage++;
7878                 } else {
7879                         r = pic16_getRegFromInstruction(pc);
7880                         if(r && !strcmp(r->name, "PREINC1"))
7881                                 PCF(pc_fstart)->stackusage--;
7882                 }
7883         }
7884
7885       if(isPCF(pc)) {
7886         if (PCF(pc)->fname) {
7887         char buf[16];
7888
7889           sprintf(buf, "%smain", port->fun_prefix);
7890           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7891             //fprintf(stderr," found main \n");
7892             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7893             pb->dbName = 'M';
7894           }
7895
7896           pbr = Safe_calloc(1,sizeof(pBranch));
7897           pbr->pc = pc_fstart = pc;
7898           pbr->next = NULL;
7899
7900           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7901
7902           // Here's a better way of doing the same:
7903           addSet(&pb->function_entries, pc);
7904
7905         } else {
7906           // Found an exit point in a function, e.g. return
7907           // (Note, there may be more than one return per function)
7908           if(pc_fstart)
7909             pBranchLink(PCF(pc_fstart), PCF(pc));
7910
7911           addSet(&pb->function_exits, pc);
7912         }
7913       } else if(isCALL(pc)) {
7914         addSet(&pb->function_calls,pc);
7915       }
7916     }
7917   }
7918
7919
7920 #if 0
7921   /* This is not needed because currently all register used
7922    * by a function are stored in stack -- VR */
7923
7924   /* Re-allocate the registers so that there are no collisions
7925    * between local variables when one function call another */
7926
7927   // this is weird...
7928   //  pic16_deallocateAllRegs();
7929
7930   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7931     if(!pb->visited)
7932       register_usage(pb);
7933   }
7934 #endif
7935
7936 }
7937
7938 /*-----------------------------------------------------------------*/
7939 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7940 /*                all of the logical connections.                  */
7941 /*                                                                 */
7942 /* Essentially what's done here is that the pCode flow is          */
7943 /* determined.                                                     */
7944 /*-----------------------------------------------------------------*/
7945
7946 void pic16_AnalyzepCode(char dbName)
7947 {
7948   pBlock *pb;
7949   int i,changes;
7950
7951   if(!the_pFile)
7952     return;
7953
7954   mergepBlocks('D');
7955
7956
7957   /* Phase 1 - Register allocation and peep hole optimization
7958    *
7959    * The first part of the analysis is to determine the registers
7960    * that are used in the pCode. Once that is done, the peep rules
7961    * are applied to the code. We continue to loop until no more
7962    * peep rule optimizations are found (or until we exceed the
7963    * MAX_PASSES threshold).
7964    *
7965    * When done, the required registers will be determined.
7966    *
7967    */
7968   i = 0;
7969   do {
7970
7971     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7972     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7973
7974     /* First, merge the labels with the instructions */
7975     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7976       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7977
7978         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7979         //fprintf(stderr," analyze and merging block %c\n",dbName);
7980         pic16_pBlockMergeLabels(pb);
7981         AnalyzepBlock(pb);
7982       } else {
7983         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7984       }
7985     }
7986
7987         if(!options.nopeep)
7988                 changes = OptimizepCode(dbName);
7989         else changes = 0;
7990
7991   } while(changes && (i++ < MAX_PASSES));
7992
7993
7994   buildCallTree();
7995 }
7996
7997
7998 /* convert a series of movff's of local regs to stack, with a single call to
7999  * a support functions which does the same thing via loop */
8000 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8001 {
8002   pBranch *pbr;
8003   pCode *pc, *pct;
8004   char *fname[]={"__lr_store", "__lr_restore"};
8005
8006 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8007
8008     pct = pic16_findNextInstruction(pcstart->next);
8009     do {
8010       pc = pct;
8011       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8012 //      pc->print(stderr, pc);
8013       if(isPCI(pc) && PCI(pc)->label) {
8014         pbr = PCI(pc)->label;
8015         while(pbr && pbr->pc) {
8016           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8017           pbr = pbr->next;
8018         }
8019
8020 //        pc->print(stderr, pc);
8021         /* unlink pCode */
8022         pc->prev->next = pct;
8023         pct->prev = pc->prev;
8024 //        pc->next = NULL;
8025 //        pc->prev = NULL;
8026       }
8027     } while ((pc) && (pc != pcend));
8028
8029     /* unlink movff instructions */
8030     pcstart->next = pcend;
8031     pcend->prev = pcstart;
8032
8033     pc = pcstart;
8034 //    if(!entry) {
8035 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8036 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8037 //    }
8038
8039     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8040     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8041     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8042
8043 //    if(!entry) {
8044 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8045 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8046 //    }
8047
8048
8049     {
8050       symbol *sym;
8051
8052         sym = newSymbol( fname[ entry?0:1 ], 0 );
8053         strcpy(sym->rname, fname[ entry?0:1 ]);
8054         checkAddSym(&externs, sym);
8055
8056 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8057     }
8058
8059 }
8060
8061 /*-----------------------------------------------------------------*/
8062 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8063 /*    local registers to a support function call                   */
8064 /*-----------------------------------------------------------------*/
8065 void pic16_OptimizeLocalRegs(void)
8066 {
8067   pBlock  *pb;
8068   pCode   *pc;
8069   pCodeInfo *pci;
8070   pCodeOpLocalReg *pclr;
8071   int regCount=0;
8072   int inRegCount=0;
8073   regs *r, *lastr=NULL, *firstr=NULL;
8074   pCode *pcstart=NULL, *pcend=NULL;
8075   int inEntry=0;
8076   char *curFunc=NULL;
8077
8078         /* Overview:
8079          *   local_regs begin mark
8080          *      MOVFF r0x01, POSTDEC1
8081          *      MOVFF r0x02, POSTDEC1
8082          *      ...
8083          *      ...
8084          *      MOVFF r0x0n, POSTDEC1
8085          *   local_regs end mark
8086          *
8087          * convert the above to the below:
8088          *      MOVLW   starting_register_index
8089          *      MOVWF   PRODL
8090          *      MOVLW   register_count
8091          *      call    __save_registers_in_stack
8092          */
8093
8094     if(!the_pFile)
8095       return;
8096
8097     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8098       inRegCount = regCount = 0;
8099       firstr = lastr = NULL;
8100       for(pc = pb->pcHead; pc; pc = pc->next) {
8101
8102         /* hold current function name */
8103         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8104
8105         if(pc && (pc->type == PC_INFO)) {
8106           pci = PCINF(pc);
8107
8108           if(pci->type == INF_LOCALREGS) {
8109             pclr = PCOLR(pci->oper1);
8110
8111             if((pclr->type == LR_ENTRY_BEGIN)
8112               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8113             else inEntry = 0;
8114
8115             switch(pclr->type) {
8116               case LR_ENTRY_BEGIN:
8117               case LR_EXIT_BEGIN:
8118                         inRegCount = 1; regCount = 0;
8119                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8120                         firstr = lastr = NULL;
8121                         break;
8122
8123               case LR_ENTRY_END:
8124               case LR_EXIT_END:
8125                         inRegCount = -1;
8126                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8127
8128 #if 1
8129                         if(curFunc && inWparamList(curFunc+1)) {
8130                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8131                                         filename, curFunc);
8132                         } else {
8133                           if(regCount>2) {
8134                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8135                               firstr, inEntry);
8136                           }
8137                         }
8138 #endif
8139                         firstr = lastr = NULL;
8140                         break;
8141             }
8142
8143             if(inRegCount == -1) {
8144 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8145               regCount = 0;
8146               inRegCount = 0;
8147             }
8148           }
8149         } else {
8150           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8151             if(inEntry)
8152               r = pic16_getRegFromInstruction(pc);
8153             else
8154               r = pic16_getRegFromInstruction2(pc);
8155             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8156               if(!firstr)firstr = r;
8157               regCount++;
8158 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8159             }
8160           }
8161         }
8162       }
8163     }
8164 }
8165
8166
8167
8168
8169
8170 /*-----------------------------------------------------------------*/
8171 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8172 /*                   function                                      */
8173 /*-----------------------------------------------------------------*/
8174 static bool ispCodeFunction(pCode *pc)
8175 {
8176
8177   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8178     return 1;
8179
8180   return 0;
8181 }
8182
8183 /*-----------------------------------------------------------------*/
8184 /* findFunction - Search for a function by name (given the name)   */
8185 /*                in the set of all functions that are in a pBlock */
8186 /* (note - I expect this to change because I'm planning to limit   */
8187 /*  pBlock's to just one function declaration                      */
8188 /*-----------------------------------------------------------------*/
8189 static pCode *findFunction(char *fname)
8190 {
8191   pBlock *pb;
8192   pCode *pc;
8193   if(!fname)
8194     return NULL;
8195
8196   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8197
8198     pc = setFirstItem(pb->function_entries);
8199     while(pc) {
8200
8201       if((pc->type == PC_FUNCTION) &&
8202          (PCF(pc)->fname) &&
8203          (strcmp(fname, PCF(pc)->fname)==0))
8204         return pc;
8205
8206       pc = setNextItem(pb->function_entries);
8207
8208     }
8209
8210   }
8211   return NULL;
8212 }
8213
8214 static void MarkUsedRegisters(set *regset)
8215 {
8216
8217   regs *r1,*r2;
8218
8219   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8220 //      fprintf(stderr, "marking register = %s\t", r1->name);
8221     r2 = pic16_regWithIdx(r1->rIdx);
8222 //      fprintf(stderr, "to register = %s\n", r2->name);
8223     r2->isFree = 0;
8224     r2->wasUsed = 1;
8225   }
8226 }
8227
8228 static void pBlockStats(FILE *of, pBlock *pb)
8229 {
8230
8231   pCode *pc;
8232   regs  *r;
8233
8234         if(!pic16_pcode_verbose)return;
8235
8236   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8237
8238   // for now just print the first element of each set
8239   pc = setFirstItem(pb->function_entries);
8240   if(pc) {
8241     fprintf(of,";entry:  ");
8242     pc->print(of,pc);
8243   }
8244   pc = setFirstItem(pb->function_exits);
8245   if(pc) {
8246     fprintf(of,";has an exit\n");
8247     //pc->print(of,pc);
8248   }
8249
8250   pc = setFirstItem(pb->function_calls);
8251   if(pc) {
8252     fprintf(of,";functions called:\n");
8253
8254     while(pc) {
8255       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8256         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8257       }
8258       pc = setNextItem(pb->function_calls);
8259     }
8260   }
8261
8262   r = setFirstItem(pb->tregisters);
8263   if(r) {
8264     int n = elementsInSet(pb->tregisters);
8265
8266     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8267
8268     while (r) {
8269       fprintf(of,   ";   %s\n",r->name);
8270       r = setNextItem(pb->tregisters);
8271     }
8272   }
8273
8274   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8275 }
8276
8277 /*-----------------------------------------------------------------*/
8278 /*-----------------------------------------------------------------*/
8279 #if 0
8280 static void sequencepCode(void)
8281 {
8282   pBlock *pb;
8283   pCode *pc;
8284
8285
8286   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8287
8288     pb->seq = GpCodeSequenceNumber+1;
8289
8290     for( pc = pb->pcHead; pc; pc = pc->next)
8291       pc->seq = ++GpCodeSequenceNumber;
8292   }
8293
8294 }
8295 #endif
8296
8297 /*-----------------------------------------------------------------*/
8298 /*-----------------------------------------------------------------*/
8299 static set *register_usage(pBlock *pb)
8300 {
8301   pCode *pc,*pcn;
8302   set *registers=NULL;
8303   set *registersInCallPath = NULL;
8304
8305   /* check recursion */
8306
8307   pc = setFirstItem(pb->function_entries);
8308
8309   if(!pc)
8310     return registers;
8311
8312   pb->visited = 1;
8313
8314   if(pc->type != PC_FUNCTION)
8315     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8316
8317   pc = setFirstItem(pb->function_calls);
8318   for( ; pc; pc = setNextItem(pb->function_calls)) {
8319
8320     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8321       char *dest = pic16_get_op_from_instruction(PCI(pc));
8322
8323       pcn = findFunction(dest);
8324       if(pcn)
8325         registersInCallPath = register_usage(pcn->pb);
8326     } else
8327       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8328
8329   }
8330
8331 #ifdef PCODE_DEBUG
8332   pBlockStats(stderr,pb);  // debug
8333 #endif
8334
8335   // Mark the registers in this block as used.
8336
8337   MarkUsedRegisters(pb->tregisters);
8338   if(registersInCallPath) {
8339     /* registers were used in the functions this pBlock has called */
8340     /* so now, we need to see if these collide with the ones we are */
8341     /* using here */
8342
8343     regs *r1,*r2, *newreg;
8344
8345     DFPRINTF((stderr,"comparing registers\n"));
8346
8347     r1 = setFirstItem(registersInCallPath);
8348     while(r1) {
8349
8350       r2 = setFirstItem(pb->tregisters);
8351
8352       while(r2 && (r1->type != REG_STK)) {
8353
8354         if(r2->rIdx == r1->rIdx) {
8355           newreg = pic16_findFreeReg(REG_GPR);
8356
8357
8358           if(!newreg) {
8359             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8360             exit(1);
8361           }
8362
8363           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8364                   r1->rIdx, newreg->rIdx));
8365           r2->rIdx = newreg->rIdx;
8366           //if(r2->name) Safe_free(r2->name);
8367           if(newreg->name)
8368             r2->name = Safe_strdup(newreg->name);
8369           else
8370             r2->name = NULL;
8371           newreg->isFree = 0;
8372           newreg->wasUsed = 1;
8373         }
8374         r2 = setNextItem(pb->tregisters);
8375       }
8376
8377       r1 = setNextItem(registersInCallPath);
8378     }
8379
8380     /* Collisions have been resolved. Now free the registers in the call path */
8381     r1 = setFirstItem(registersInCallPath);
8382     while(r1) {
8383       if(r1->type != REG_STK) {
8384         newreg = pic16_regWithIdx(r1->rIdx);
8385         newreg->isFree = 1;
8386       }
8387       r1 = setNextItem(registersInCallPath);
8388     }
8389
8390   }// else
8391   //    MarkUsedRegisters(pb->registers);
8392
8393   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8394 #ifdef PCODE_DEBUG
8395   if(registers)
8396     DFPRINTF((stderr,"returning regs\n"));
8397   else
8398     DFPRINTF((stderr,"not returning regs\n"));
8399
8400   DFPRINTF((stderr,"pBlock after register optim.\n"));
8401   pBlockStats(stderr,pb);  // debug
8402 #endif
8403
8404   return registers;
8405 }
8406
8407 /*-----------------------------------------------------------------*/
8408 /* pct2 - writes the call tree to a file                           */
8409 /*                                                                 */
8410 /*-----------------------------------------------------------------*/
8411 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8412 {
8413   pCode *pc,*pcn;
8414   int i;
8415   //  set *registersInCallPath = NULL;
8416
8417   if(!of)
8418     return;
8419
8420   if(indent > 10) {
8421         fprintf(of, "recursive function\n");
8422     return; //recursion ?
8423   }
8424
8425   pc = setFirstItem(pb->function_entries);
8426
8427   if(!pc)
8428     return;
8429
8430   pb->visited = 0;
8431
8432   for(i=0;i<indent;i++)   // Indentation
8433         fputs("+   ", of);
8434   fputs("+- ", of);
8435
8436   if(pc->type == PC_FUNCTION) {
8437     usedstack += PCF(pc)->stackusage;
8438     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8439   } else return;  // ???
8440
8441
8442   pc = setFirstItem(pb->function_calls);
8443   for( ; pc; pc = setNextItem(pb->function_calls)) {
8444
8445     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8446       char *dest = pic16_get_op_from_instruction(PCI(pc));
8447
8448       pcn = findFunction(dest);
8449       if(pcn)
8450         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8451     } else
8452       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8453
8454   }
8455
8456
8457 }
8458
8459
8460 /*-----------------------------------------------------------------*/
8461 /* pic16_printCallTree - writes the call tree to a file                  */
8462 /*                                                                 */
8463 /*-----------------------------------------------------------------*/
8464
8465 void pic16_printCallTree(FILE *of)
8466 {
8467   pBranch *pbr;
8468   pBlock  *pb;
8469   pCode   *pc;
8470
8471   if(!the_pFile)
8472     return;
8473
8474   if(!of)
8475     of = stderr;
8476
8477   fprintf(of, "\npBlock statistics\n");
8478   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8479     pBlockStats(of,pb);
8480
8481
8482   fprintf(of,"Call Tree\n");
8483   pbr = the_pFile->functions;
8484   while(pbr) {
8485     if(pbr->pc) {
8486       pc = pbr->pc;
8487       if(!ispCodeFunction(pc))
8488         fprintf(of,"bug in call tree");
8489
8490
8491       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8492
8493       while(pc->next && !ispCodeFunction(pc->next)) {
8494         pc = pc->next;
8495         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8496           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8497       }
8498     }
8499
8500     pbr = pbr->next;
8501   }
8502
8503
8504   fprintf(of,"\n**************\n\na better call tree\n");
8505   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8506 //    if(pb->visited)
8507       pct2(of,pb,0,0);
8508   }
8509
8510   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8511     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8512   }
8513 }
8514
8515
8516
8517 /*-----------------------------------------------------------------*/
8518 /*                                                                 */
8519 /*-----------------------------------------------------------------*/
8520
8521 static void InlineFunction(pBlock *pb)
8522 {
8523   pCode *pc;
8524   pCode *pc_call;
8525
8526   if(!pb)
8527     return;
8528
8529   pc = setFirstItem(pb->function_calls);
8530
8531   for( ; pc; pc = setNextItem(pb->function_calls)) {
8532
8533     if(isCALL(pc)) {
8534       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8535       pCode *pct;
8536       pCode *pce;
8537
8538       pBranch *pbr;
8539
8540       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8541
8542         //fprintf(stderr,"Cool can inline:\n");
8543         //pcn->print(stderr,pcn);
8544
8545         //fprintf(stderr,"recursive call Inline\n");
8546         InlineFunction(pcn->pb);
8547         //fprintf(stderr,"return from recursive call Inline\n");
8548
8549         /*
8550           At this point, *pc points to a CALL mnemonic, and
8551           *pcn points to the function that is being called.
8552
8553           To in-line this call, we need to remove the CALL
8554           and RETURN(s), and link the function pCode in with
8555           the CALLee pCode.
8556
8557         */
8558
8559
8560         /* Remove the CALL */
8561         pc_call = pc;
8562         pc = pc->prev;
8563
8564         /* remove callee pBlock from the pBlock linked list */
8565         removepBlock(pcn->pb);
8566
8567         pce = pcn;
8568         while(pce) {
8569           pce->pb = pb;
8570           pce = pce->next;
8571         }
8572
8573         /* Remove the Function pCode */
8574         pct = pic16_findNextInstruction(pcn->next);
8575
8576         /* Link the function with the callee */
8577         pc->next = pcn->next;
8578         pcn->next->prev = pc;
8579
8580         /* Convert the function name into a label */
8581
8582         pbr = Safe_calloc(1,sizeof(pBranch));
8583         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8584         pbr->next = NULL;
8585         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8586         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8587
8588         /* turn all of the return's except the last into goto's */
8589         /* check case for 2 instruction pBlocks */
8590         pce = pic16_findNextInstruction(pcn->next);
8591         while(pce) {
8592           pCode *pce_next = pic16_findNextInstruction(pce->next);
8593
8594           if(pce_next == NULL) {
8595             /* found the last return */
8596             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8597
8598             //fprintf(stderr,"found last return\n");
8599             //pce->print(stderr,pce);
8600             pce->prev->next = pc_call->next;
8601             pc_call->next->prev = pce->prev;
8602             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8603                                                       PCI(pce)->label);
8604           }
8605
8606           pce = pce_next;
8607         }
8608
8609
8610       }
8611     } else
8612       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8613
8614   }
8615
8616 }
8617
8618 /*-----------------------------------------------------------------*/
8619 /*                                                                 */
8620 /*-----------------------------------------------------------------*/
8621
8622 void pic16_InlinepCode(void)
8623 {
8624
8625   pBlock  *pb;
8626   pCode   *pc;
8627
8628   if(!the_pFile)
8629     return;
8630
8631   if(!functionInlining)
8632     return;
8633
8634   /* Loop through all of the function definitions and count the
8635    * number of times each one is called */
8636   //fprintf(stderr,"inlining %d\n",__LINE__);
8637
8638   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8639
8640     pc = setFirstItem(pb->function_calls);
8641
8642     for( ; pc; pc = setNextItem(pb->function_calls)) {
8643
8644       if(isCALL(pc)) {
8645         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8646         if(pcn && isPCF(pcn)) {
8647           PCF(pcn)->ncalled++;
8648         }
8649       } else
8650         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8651
8652     }
8653   }
8654
8655   //fprintf(stderr,"inlining %d\n",__LINE__);
8656
8657   /* Now, Loop through the function definitions again, but this
8658    * time inline those functions that have only been called once. */
8659
8660   InlineFunction(the_pFile->pbHead);
8661   //fprintf(stderr,"inlining %d\n",__LINE__);
8662
8663   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8664     unBuildFlow(pb);
8665
8666 }
8667
8668 char *pic_optype_names[]={
8669         "PO_NONE",         // No operand e.g. NOP
8670         "PO_W",              // The working register (as a destination)
8671         "PO_WREG",           // The working register (as a file register)
8672         "PO_STATUS",         // The 'STATUS' register
8673         "PO_BSR",            // The 'BSR' register
8674         "PO_FSR0",           // The "file select register" (in PIC18 family it's one
8675                              // of three)
8676         "PO_INDF0",          // The Indirect register
8677         "PO_INTCON",         // Interrupt Control register
8678         "PO_GPR_REGISTER",   // A general purpose register
8679         "PO_GPR_BIT",        // A bit of a general purpose register
8680         "PO_GPR_TEMP",       // A general purpose temporary register
8681         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8682         "PO_PCL",            // Program counter Low register
8683         "PO_PCLATH",         // Program counter Latch high register
8684         "PO_PCLATU",         // Program counter Latch upper register
8685         "PO_PRODL",          // Product Register Low
8686         "PO_PRODH",          // Product Register High
8687         "PO_LITERAL",        // A constant
8688         "PO_REL_ADDR",       // A relative address
8689         "PO_IMMEDIATE",      //  (8051 legacy)
8690         "PO_DIR",            // Direct memory (8051 legacy)
8691         "PO_CRY",            // bit memory (8051 legacy)
8692         "PO_BIT",            // bit operand.
8693         "PO_STR",            //  (8051 legacy)
8694         "PO_LABEL",
8695         "PO_WILD",           // Wild card operand in peep optimizer
8696         "PO_TWO_OPS"         // combine two operands
8697 };
8698
8699
8700 char *dumpPicOptype(PIC_OPTYPE type)
8701 {
8702         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8703         return (pic_optype_names[ type ]);
8704 }
8705
8706
8707 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8708 #include "graph.h"
8709
8710 #define MAX_COMMON_BANK_SIZE    32
8711 #define FIRST_PSEUDO_BANK_NR  1000
8712
8713 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8714 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8715 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8716 Graph *adj = NULL;
8717
8718 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8719
8720 typedef struct {
8721   pseudoBankNr bank;  // number assigned to this pseudoBank
8722   unsigned int size;  // number of operands assigned to this bank
8723   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8724 } pseudoBank;
8725
8726 /*----------------------------------------------------------------------*/
8727 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8728 /*----------------------------------------------------------------------*/
8729 unsigned int hashSymbol (const char *str)
8730 {
8731   unsigned int res = 0;
8732   if (!str) return 0;
8733
8734   while (*str) {
8735     res ^= (*str);
8736     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8737     str++;
8738   } // while
8739
8740   return res;
8741 }
8742
8743 /*-----------------------------------------------------------------------*/
8744 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8745 /*-----------------------------------------------------------------------*/
8746 int compareSymbol (const void *sym1, const void *sym2)
8747 {
8748   char *s1 = (char*) sym1;
8749   char *s2 = (char*) sym2;
8750
8751   return (strcmp (s1,s2) == 0);
8752 }
8753
8754 /*-----------------------------------------------------------------------*/
8755 /* comparePre - return 1 iff p1 == p2                                    */
8756 /*-----------------------------------------------------------------------*/
8757 int comparePtr (const void *p1, const void *p2)
8758 {
8759   return (p1 == p2);
8760 }
8761
8762 /*----------------------------------------------------------*/
8763 /* getSymbolFromOperand - return a pointer to the symbol in */
8764 /*                        the given operand and its length  */
8765 /*----------------------------------------------------------*/
8766 char *getSymbolFromOperand (char *op, int *len)
8767 {
8768   char *sym, *curr;
8769   *len = 0;
8770
8771   if (!op) return NULL;
8772
8773   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8774   sym = op;
8775   if (*sym == '(') sym++;
8776
8777   curr = sym;
8778   while (((*curr >= 'A') && (*curr <= 'Z'))
8779          || ((*curr >= 'a') && (*curr <= 'z'))
8780          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8781          || (*curr == '_')) {
8782     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8783     curr++;
8784     (*len)++;
8785   } // while
8786
8787   return sym;
8788 }
8789
8790 /*--------------------------------------------------------------------------*/
8791 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8792 /*--------------------------------------------------------------------------*/
8793 char *getSymFromBank (pseudoBankNr bank)
8794 {
8795   assert (bank2sym);
8796
8797   if (bank < 0) return "<INVALID BANK NR>";
8798   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8799 }
8800
8801 /*-----------------------------------------------------------------------*/
8802 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8803 /*                           bank number (uses hTab sym2bank), if the    */
8804 /*                           symbol is not yet assigned a pseudo bank it */
8805 /*                           is assigned one here                        */
8806 /*-----------------------------------------------------------------------*/
8807 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8808 {
8809   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8810   pseudoBankNr bank;
8811   unsigned int hash;
8812
8813   assert (sym2bank);
8814
8815   hash = hashSymbol (op) % sym2bank->size;
8816   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8817   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8818
8819   if (bank == UNKNOWN_BANK) {
8820     // create a pseudo bank for the operand
8821     bank = next_bank++;
8822     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8823     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8824     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8825     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8826   } else {
8827     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8828   } // if
8829
8830   assert (bank >= 0);
8831
8832   return bank;
8833 }
8834
8835 /*--------------------------------------------------------------------*/
8836 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8837 /*--------------------------------------------------------------------*/
8838 int isBanksel (pCode *pc)
8839 {
8840   if (!pc) return 0;
8841
8842   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8843     // BANKSEL <variablename>  or  MOVLB <banknr>
8844     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8845     return 1;
8846   }
8847
8848   // check for inline assembler BANKSELs
8849   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8850                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8851     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8852     return 1;
8853   }
8854
8855   // assume pc is no BANKSEL instruction
8856   return 0;
8857 }
8858
8859 /*---------------------------------------------------------------------------------*/
8860 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8861 /*                  This method can not guarantee to find all modifications of the */
8862 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8863 /*                  generated plus some cases.                                     */
8864 /*---------------------------------------------------------------------------------*/
8865 int invalidatesBSR(pCode *pc)
8866 {
8867   // assembler directives invalidate BSR (well, they might, we don't know)
8868   if (isPCAD(pc)) return 1;
8869
8870   // only ASMDIRs and pCodeInstructions can invalidate BSR
8871   if (!isPCI(pc)) return 0;
8872
8873   // we have a pCodeInstruction
8874
8875   // check for BSR modifying instructions
8876   switch (PCI(pc)->op) {
8877   case POC_CALL:
8878   case POC_RCALL:
8879   case POC_MOVLB:
8880   case POC_RETFIE:  // might be used as CALL replacement
8881   case POC_RETLW:   // might be used as CALL replacement
8882   case POC_RETURN:  // might be used as CALL replacement
8883   case POC_BANKSEL:
8884     return 1;
8885     break;
8886
8887   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8888     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8889     break;
8890   } // switch
8891
8892   // no change of BSR possible/probable
8893   return 0;
8894 }
8895
8896 /*------------------------------------------------------------*/
8897 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8898 /*                      the symbol referenced in this BANKSEL */
8899 /*------------------------------------------------------------*/
8900 pseudoBankNr getBankFromBanksel (pCode *pc)
8901 {
8902   char *sym;
8903   int data = 0;
8904
8905   if (!pc) return INVALID_BANK;
8906
8907   if (isPCAD(pc) && PCAD(pc)->directive) {
8908     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8909       // get symbolname from PCAD(pc)->arg
8910       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8911       sym = PCAD(pc)->arg;
8912       data = getPseudoBankNrFromOperand (sym);
8913       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8914     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8915       // get (literal) bank number from PCAD(pc)->arg
8916       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8917       assert (0 && "not yet implemented - turn off banksel optimization for now");
8918     }
8919   } else if (isPCI(pc)) {
8920     if (PCI(pc)->op == POC_BANKSEL) {
8921       // get symbolname from PCI(pc)->pcop->name (?)
8922       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8923       sym = PCI(pc)->pcop->name;
8924       data = getPseudoBankNrFromOperand (sym);
8925       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8926     } else if (PCI(pc)->op == POC_MOVLB) {
8927       // get (literal) bank number from PCI(pc)->pcop->name
8928       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8929       assert (0 && "not yet implemented - turn off banksel optimization for now");
8930     }
8931   }
8932
8933   if (data == 0)
8934     // no assigned bank could be found
8935     return UNKNOWN_BANK;
8936   else
8937     return data;
8938 }
8939
8940 /*------------------------------------------------------------------------------*/
8941 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8942 /*------------------------------------------------------------------------------*/
8943 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8944 {
8945   pseudoBank *data;
8946
8947   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8948
8949   do {
8950     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8951     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8952     if (data) {
8953       if (data->bank != bank)
8954         bank = data->bank;
8955       else
8956         data = NULL;
8957     }
8958   } while (data);
8959
8960   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8961   return bank;
8962 }
8963
8964 /*------------------------------------------------------------------*/
8965 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8966 /*                        bank is selected at a given pCode         */
8967 /*------------------------------------------------------------------*/
8968
8969 /* Create a graph with pseudo banks as its nodes and switches between
8970  * these as edges (with the edge weight representing the absolute
8971  * number of BANKSELs from one to the other).
8972  * Removes redundand BANKSELs instead iff mod == 1.
8973  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8974  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8975  * pseudo BSR.
8976  * TODO: check ALL instructions operands if they modify BSR directly...
8977  *
8978  * pb - the pBlock to annotate
8979  * mod  - select either graph creation (0) or BANKSEL removal (1)
8980  */
8981 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8982 {
8983   pCode *pc, *pc_next;
8984   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8985   int isBankselect = 0;
8986   unsigned int banksels=0;
8987
8988   if (!pb) return 0;
8989
8990   pc = pic16_findNextInstruction(pb->pcHead);
8991   while (pc) {
8992     isBankselect = isBanksel (pc);
8993     pc_next = pic16_findNextInstruction (pc->next);
8994
8995     if (!hasNoLabel (pc)) {
8996       // we don't know our predecessors -- assume different BSRs
8997       prevBSR = UNKNOWN_BANK;
8998       pseudoBSR = UNKNOWN_BANK;
8999       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9000     } // if
9001
9002     // check if this is a BANKSEL instruction
9003     if (isBankselect) {
9004       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9005       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9006       if (mod) {
9007         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9008           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9009           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9010           pic16_unlinkpCode (pc);
9011           banksels++;
9012         }
9013       } else {
9014         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9015         banksels++;
9016       }
9017     } // if
9018
9019     if (!isBankselect && invalidatesBSR(pc)) {
9020       // check if this instruction invalidates the pseudoBSR
9021       pseudoBSR = UNKNOWN_BANK;
9022       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9023     } // if
9024
9025     prevBSR = pseudoBSR;
9026     pc = pc_next;
9027   } // while
9028
9029   return banksels;
9030 }
9031
9032 /*------------------------------------------------------------------------------------*/
9033 /* assignToSameBank - returns 0 on success or an error code                           */
9034 /*  1 - common bank would be too large                                                */
9035 /*  2 - assignment to fixed (absolute) bank not performed                             */
9036 /*                                                                                    */
9037 /* This functions assumes that unsplittable operands are already assigned to the same */
9038 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9039 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9040 /* TODO: Symbols with an abslute address must be handled specially!                   */
9041 /*------------------------------------------------------------------------------------*/
9042 int assignToSameBank (int bank0, int bank1, int doAbs)
9043 {
9044   int eff0, eff1, dummy;
9045   pseudoBank *pbank0, *pbank1;
9046   hashtItem *hitem;
9047
9048   eff0 = getEffectiveBank (bank0);
9049   eff1 = getEffectiveBank (bank1);
9050
9051   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9052
9053   // nothing to do if already same bank
9054   if (eff0 == eff1) return 0;
9055
9056   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9057     return 2;
9058
9059   // ensure eff0 < eff1
9060   if (eff0 > eff1) {
9061     // swap eff0 and eff1
9062     dummy = eff0;
9063     eff0 = eff1;
9064     eff1 = dummy;
9065     dummy = bank0;
9066     bank0 = bank1;
9067     bank1 = dummy;
9068   } // if
9069
9070   // now assign bank eff1 to bank eff0
9071   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9072   if (!pbank0) {
9073     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9074     pbank0->bank = eff0;
9075     pbank0->size = 1;
9076     pbank0->ref = 1;
9077     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9078   } // if
9079
9080   pbank1 = NULL;
9081   hitem = hTabSearch (coerce, eff1 % coerce->size);
9082   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9083     hitem = hitem->next;
9084
9085   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9086
9087 #if 0
9088   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9089            pbank0->bank, pbank0->size,
9090            getSymFromBank (eff0), getSymFromBank (eff1));
9091 #endif
9092
9093   if (pbank1) {
9094     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9095 #if 0
9096       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9097                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9098                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9099                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9100 #endif
9101       return 1;
9102     } // if
9103     pbank0->size += pbank1->size;
9104     pbank1->ref--;
9105     if (pbank1->ref == 0) Safe_free (pbank1);
9106   } else {
9107     pbank0->size++;
9108   } // if
9109
9110   if (hitem)
9111     hitem->item = pbank0;
9112   else
9113     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9114   pbank0->ref++;
9115
9116   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9117
9118   return 0;
9119 }
9120
9121 /*----------------------------------------------------------------*/
9122 /* mergeGraphNodes - combines two nodes into one and modifies all */
9123 /*                   edges to and from the nodes accordingly      */
9124 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9125 /* then also (B,A) must be an edge (possibly with weight 0).      */
9126 /*----------------------------------------------------------------*/
9127 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9128 {
9129   GraphEdge *edge, *backedge, *nextedge;
9130   GraphNode *node;
9131   int backweight;
9132
9133   assert (node1 && node2);
9134   assert (node1 != node2);
9135
9136   // add all edges starting at node2 to node1
9137   edge = node2->edge;
9138   while (edge) {
9139     nextedge = edge->next;
9140     node = edge->node;
9141     backedge = getGEdge (node, node2);
9142     if (backedge)
9143       backweight = backedge->weight;
9144     else
9145       backweight = 0;
9146     // insert edges (node1,node) and (node,node1)
9147     addGEdge2 (node1, node, edge->weight, backweight);
9148     // remove edges (node, node2) and (node2, node)
9149     remGEdge (node2, node);
9150     remGEdge (node, node2);
9151     edge = nextedge;
9152   } // while
9153
9154   // now node2 should not be referenced by any other GraphNode...
9155   //remGNode (adj, node2->data, node2->hash);
9156 }
9157
9158 /*----------------------------------------------------------------*/
9159 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9160 /*----------------------------------------------------------------*/
9161 void showGraph (Graph *g)
9162 {
9163   GraphNode *node;
9164   GraphEdge *edge;
9165   pseudoBankNr bankNr;
9166   pseudoBank *pbank;
9167   unsigned int size;
9168
9169   node = g->node;
9170   while (node) {
9171     edge = node->edge;
9172     bankNr = getEffectiveBank (node->hash);
9173     assert (bankNr >= 0);
9174     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9175     if (pbank) {
9176       bankNr = pbank->bank;
9177       size = pbank->size;
9178     } else {
9179       size = 1;
9180     }
9181
9182     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9183
9184     while (edge) {
9185       if (edge->weight > 0)
9186         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9187       edge = edge->next;
9188     } // while (edge)
9189     node = node->next;
9190   } // while (node)
9191 }
9192
9193 /*---------------------------------------------------------------*/
9194 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9195 /*---------------------------------------------------------------*/
9196 void pic16_OptimizeBanksel ()
9197 {
9198   GraphNode *node, *node1, *node1next;
9199
9200 #if 0
9201   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9202   GraphEdge *edge, *backedge;
9203   GraphEdge *max;
9204   int maxWeight, weight, mergeMore, absMaxWeight;
9205   pseudoBankNr curr0, curr1;
9206 #endif
9207   pseudoBank *pbank;
9208   pseudoBankNr bankNr;
9209   char *base_symbol0, *base_symbol1;
9210   int len0, len1;
9211   pBlock *pb;
9212   set *set;
9213   regs *reg;
9214   unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9215
9216   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9217
9218   if (!the_pFile || !the_pFile->pbHead) return;
9219
9220   adj = newGraph (NULL);
9221   sym2bank = newHashTable ( 255 );
9222   bank2sym = newHashTable ( 255 );
9223   coerce = newHashTable ( 255 );
9224
9225   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9226   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9227     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9228   } // for pb
9229
9230 #if 1
9231   // assign symbols with absolute addresses to their respective bank nrs
9232   set = pic16_fix_udata;
9233   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9234     bankNr = reg->address >> 8;
9235     node = getOrAddGNode (adj, NULL, bankNr);
9236     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9237     assignToSameBank (node->hash, bankNr, 1);
9238
9239     assert (bankNr >= 0);
9240     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9241     if (!pbank) {
9242       pbank = Safe_calloc (1, sizeof (pseudoBank));
9243       pbank->bank = reg->address >> 8; //FIXED_BANK;
9244       pbank->size = 1;
9245       pbank->ref = 1;
9246       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9247     } else {
9248       assert (pbank->bank == (reg->address >> 8));
9249       pbank->bank = reg->address >> 8; //FIXED_BANK;
9250     }
9251     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9252   } // for reg
9253 #endif
9254
9255 #if 1
9256   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9257   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9258   node = adj->node;
9259   while (node) {
9260     if (node->hash < 0) { node = node->next; continue; }
9261     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9262     node1 = node->next;
9263     while (node1) {
9264       if (node1->hash < 0) { node1 = node1->next; continue; }
9265       node1next = node1->next;
9266       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9267       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9268         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9269         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9270         if (assignToSameBank (node->hash, node1->hash, 0)) {
9271           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9272           assert (0 && "Could not assign a symbol to a bank!");
9273         }
9274         mergeGraphNodes (node, node1);
9275         /*
9276         if (node->hash < node1->hash)
9277           mergeGraphNodes (node, node1);
9278         else
9279           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9280         */
9281       } // if
9282       node1 = node1next;
9283     } // while (node1)
9284     node = node->next;
9285   } // while (node)
9286 #endif
9287
9288 #if 0
9289   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9290   // assign tightly coupled operands to the same (pseudo) bank
9291   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9292   mergeMore = 1;
9293   absMaxWeight = 0;
9294   while (mergeMore) {
9295     node = adj->node;
9296     max = NULL;
9297     maxWeight = 0;
9298     while (node) {
9299       curr0 = getEffectiveBank (node->hash);
9300       if (curr0 < 0) { node = node->next; continue; }
9301       edge = node->edge;
9302       while (edge) {
9303         assert (edge->src == node);
9304         backedge = getGEdge (edge->node, edge->src);
9305         weight = edge->weight + (backedge ? backedge->weight : 0);
9306         curr1 = getEffectiveBank (edge->node->hash);
9307         if (curr1 < 0) { edge = edge->next; continue; }
9308
9309         // merging is only useful if the items are not assigned to the same bank already...
9310         if (curr0 != curr1 && weight > maxWeight) {
9311           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9312           maxWeight = weight;
9313           max = edge;
9314         } // if
9315         edge = edge->next;
9316       } // while
9317       node = node->next;
9318     } // while
9319
9320     if (maxWeight > 0) {
9321 #if 0
9322       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9323                max->src->hash, getSymFromBank (max->src->hash),
9324                max->node->hash, getSymFromBank (max->node->hash));
9325 #endif
9326
9327       node = getGNode (adj, max->src->data, max->src->hash);
9328       node1 = getGNode (adj, max->node->data, max->node->hash);
9329
9330       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9331         if (max->src->hash < max->node->hash)
9332           mergeGraphNodes (node, node1);
9333         else
9334           mergeGraphNodes (node1, node);
9335       } else {
9336         remGEdge (node, node1);
9337         remGEdge (node1, node);
9338         //mergeMore = 0;
9339       }
9340
9341     } else {
9342       mergeMore = 0;
9343     }
9344   } // while
9345 #endif
9346
9347 #if 1
9348   // remove redundant BANKSELs
9349   //fprintf (stderr, "removing redundant BANKSELs\n");
9350   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9351     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9352   } // for pb
9353 #endif
9354
9355 #if 0
9356   fprintf (stderr, "display graph\n");
9357   showGraph ();
9358 #endif
9359
9360   deleteGraph (adj);
9361   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9362 }
9363
9364 /*** END of stuff belonging to the BANKSEL optimization ***/
9365
9366
9367
9368 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9369
9370 typedef unsigned int symbol_t;
9371 typedef unsigned int valnum_t;
9372 //typedef unsigned int hash_t;
9373
9374 #ifndef INT_TO_PTR
9375 #define INT_TO_PTR(x) (((char *) 0) + (x))
9376 #endif
9377
9378 #ifndef PTR_TO_INT
9379 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9380 #endif
9381
9382 static int pic16_regIsLocal (regs *r);
9383 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9384
9385 /* statistics */
9386 static unsigned int pic16_df_removed_pcodes = 0;
9387 static unsigned int pic16_df_saved_bytes = 0;
9388 static unsigned int df_findall_sameflow = 0;
9389 static unsigned int df_findall_otherflow = 0;
9390 static unsigned int df_findall_in_vals = 0;
9391
9392 static void pic16_df_stats () {
9393   return;
9394   if (pic16_debug_verbose || pic16_pcode_verbose) {
9395     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9396     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9397     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9398   }
9399 }
9400
9401 /* Remove a pCode iff possible:
9402  * - previous pCode is no SKIP
9403  * - pc has no label
9404  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9405 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9406   pCode *pcprev, *pcnext;
9407   char buf[256], *total=NULL;
9408   int len;
9409
9410   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9411
9412   pcprev = pic16_findPrevInstruction (pc->prev);
9413   pcnext = pic16_findNextInstruction (pc->next);
9414
9415   /* move labels to next instruction (if possible) */
9416   if (PCI(pc)->label && !pcnext) return 0;
9417
9418   /* if this is a SKIP with side-effects -- do not remove */
9419   /* XXX: might try to replace this one with the side-effect only version */
9420   if (isPCI_SKIP(pc)
9421         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9422   {
9423     pCode *newpc;
9424     switch (PCI(pc)->op)
9425     {
9426     case POC_INCFSZ:
9427     case POC_INFSNZ:
9428       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9429       pic16_pCodeReplace( pc, newpc );
9430       return 1;
9431       break;
9432     case POC_INCFSZW:
9433       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9434       pic16_pCodeReplace( pc, newpc );
9435       return 1;
9436       break;
9437     case POC_DECFSZ:
9438     case POC_DCFSNZ:
9439       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9440       pic16_pCodeReplace( pc, newpc );
9441       return 1;
9442       break;
9443     case POC_DECFSZW:
9444       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9445       pic16_pCodeReplace( pc, newpc );
9446       return 1;
9447       break;
9448     default:
9449       return 0;
9450     }
9451     return 0;
9452   }
9453
9454   /* if previous instruction is a skip -- do not remove */
9455   if (pcprev && isPCI_SKIP(pcprev)) {
9456     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9457       /* preceeding SKIP could not be removed -- keep this instruction! */
9458       return 0;
9459     }
9460   }
9461
9462   if (PCI(pc)->label) {
9463     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9464     //pc->print (stderr, pc);
9465     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9466     PCI(pc)->label = NULL;
9467   }
9468
9469   /* update statistics */
9470   pic16_df_removed_pcodes++;
9471   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9472
9473   /* remove the pCode */
9474   pic16_pCode2str (buf, 256, pc);
9475   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9476   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9477     len = strlen (buf) + strlen (comment) + 10;
9478     total = (char *) Safe_malloc (len);
9479     SNPRINTF (total, len, "%s: %s", comment, buf);
9480     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9481     Safe_free (total);
9482   }
9483
9484   /* actually unlink it from the pBlock -- also remove from to/from lists */
9485   pic16_pCodeUnlink (pc);
9486
9487   /* remove the pCode -- release registers */
9488   pc->destruct (pc);
9489
9490   /* report success */
9491   return 1;
9492 }
9493
9494
9495 /* ======================================================================== */
9496 /* === SYMBOL HANDLING ==================================================== */
9497 /* ======================================================================== */
9498
9499 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9500 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9501 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9502
9503 /** Calculate a hash for a given string.
9504  * If len == 0 the string is assumed to be NUL terminated. */
9505 static hash_t symbolHash (const char *str, unsigned int len) {
9506   hash_t hash = 0;
9507   if (!len) {
9508     while (*str) {
9509       hash = (hash << 2) ^ *str;
9510       str++;
9511     } // while
9512   } else {
9513     while (len--) {
9514       hash = (hash << 2) ^ *str;
9515       str++;
9516     }
9517   }
9518   return hash;
9519 }
9520
9521 /** Return 1 iff strings v1 and v2 are identical. */
9522 static int symcmp (const void *v1, const void *v2) {
9523   return !strcmp ((const char *) v1, (const char *) v2);
9524 }
9525
9526 /** Return 1 iff pointers v1 and v2 are identical. */
9527 static int ptrcmp (const void *v1, const void *v2) {
9528   return (v1 == v2);
9529 }
9530
9531 enum {  SPO_WREG=0x1000,
9532         SPO_STATUS,
9533         SPO_PRODL,
9534         SPO_PRODH,
9535         SPO_INDF0,
9536         SPO_POSTDEC0,
9537         SPO_POSTINC0,
9538         SPO_PREINC0,
9539         SPO_PLUSW0,
9540         SPO_INDF1,
9541         SPO_POSTDEC1,
9542         SPO_POSTINC1,
9543         SPO_PREINC1,
9544         SPO_PLUSW1,
9545         SPO_INDF2,
9546         SPO_POSTDEC2,
9547         SPO_POSTINC2,
9548         SPO_PREINC2,
9549         SPO_PLUSW2,
9550         SPO_STKPTR,
9551         SPO_TOSL,
9552         SPO_TOSH,
9553         SPO_TOSU,
9554         SPO_BSR,
9555         SPO_FSR0L,
9556         SPO_FSR0H,
9557         SPO_FSR1L,
9558         SPO_FSR1H,
9559         SPO_FSR2L,
9560         SPO_FSR2H,
9561         SPO_PCL,
9562         SPO_PCLATH,
9563         SPO_PCLATU,
9564         SPO_TABLAT,
9565         SPO_TBLPTRL,
9566         SPO_TBLPTRH,
9567         SPO_TBLPTRU,
9568         SPO_LAST
9569 };
9570
9571 /* Return the unique symbol_t for the given string. */
9572 static symbol_t symFromStr (const char *str) {
9573   hash_t hash;
9574   char *res;
9575   symbol_t sym;
9576
9577   if (!map_symToStr) {
9578     int i;
9579     struct { char *name; symbol_t sym; } predefsyms[] = {
9580         {"WREG", SPO_WREG},
9581         {"STATUS", SPO_STATUS},
9582         {"PRODL", SPO_PRODL},
9583         {"PRODH", SPO_PRODH},
9584         {"INDF0", SPO_INDF0},
9585         {"POSTDEC0", SPO_POSTDEC0},
9586         {"POSTINC0", SPO_POSTINC0},
9587         {"PREINC0", SPO_PREINC0},
9588         {"PLUSW0", SPO_PLUSW0},
9589         {"INDF1", SPO_INDF1},
9590         {"POSTDEC1", SPO_POSTDEC1},
9591         {"POSTINC1", SPO_POSTINC1},
9592         {"PREINC1", SPO_PREINC1},
9593         {"PLUSW1", SPO_PLUSW1},
9594         {"INDF2", SPO_INDF2},
9595         {"POSTDEC2", SPO_POSTDEC2},
9596         {"POSTINC2", SPO_POSTINC2},
9597         {"PREINC2", SPO_PREINC2},
9598         {"PLUSW2", SPO_PLUSW2},
9599         {"STKPTR", SPO_STKPTR},
9600         {"TOSL", SPO_TOSL},
9601         {"TOSH", SPO_TOSH},
9602         {"TOSU", SPO_TOSU},
9603         {"BSR", SPO_BSR},
9604         {"FSR0L", SPO_FSR0L},
9605         {"FSR0H", SPO_FSR0H},
9606         {"FSR1L", SPO_FSR1L},
9607         {"FSR1H", SPO_FSR1H},
9608         {"FSR2L", SPO_FSR2L},
9609         {"FSR2H", SPO_FSR2H},
9610         {"PCL", SPO_PCL},
9611         {"PCLATH", SPO_PCLATH},
9612         {"PCLATU", SPO_PCLATU},
9613         {"TABLAT", SPO_TABLAT},
9614         {"TBLPTRL", SPO_TBLPTRL},
9615         {"TBLPTRH", SPO_TBLPTRH},
9616         {"TBLPTRU", SPO_TBLPTRU},
9617         {NULL, 0}
9618     };
9619
9620     map_strToSym = newHashTable (128);
9621     map_symToStr = newHashTable (128);
9622
9623     for (i=0; predefsyms[i].name; i++) {
9624       char *name;
9625
9626       /* enter new symbol */
9627       sym = predefsyms[i].sym;
9628       name = predefsyms[i].name;
9629       res = Safe_strdup (name);
9630       hash = symbolHash (name, 0);
9631
9632       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9633       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9634     } // for i
9635   }
9636
9637   hash = symbolHash (str, 0) % map_strToSym->size;
9638
9639   /* find symbol in table */
9640   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9641   if (sym) {
9642     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9643     return sym;
9644   }
9645
9646   /* enter new symbol */
9647   sym = nextSymbol++;
9648   res = Safe_strdup (str);
9649
9650   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9651   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9652
9653   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9654
9655   return sym;
9656 }
9657
9658 #if 1
9659 static const char *strFromSym (symbol_t sym) {
9660   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9661 }
9662 #endif
9663
9664 /* ======================================================================== */
9665 /* === DEFINITION MAP HANDLING ============================================ */
9666 /* ======================================================================== */
9667
9668 /* A defmap provides information about which symbol is defined by which pCode.
9669  * The most recent definitions are prepended to the list, so that the most
9670  * recent definition can be found by forward scanning the list.
9671  * pc2: MOVFF r0x00, r0x01
9672  * pc1: INCF r0x01
9673  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9674  *
9675  * We attach one defmap to each flow object, and each pCode will occur at
9676  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9677  * used to find definitions for a pCode in its own defmap that precede pCode.
9678  */
9679
9680 typedef struct defmap_s {
9681   symbol_t sym;                 /** symbol this item refers to */
9682   union {
9683     struct {
9684       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9685       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9686       int isRead:1;             /** sym/mask is read */
9687       int isWrite:1;            /** sym/mask is written */
9688     } access;
9689     int accessmethod;
9690   } acc;
9691   pCode *pc;                    /** pCode this symbol is refrenced at */
9692   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9693   valnum_t val;                 /** new unique number for this value (if isWrite) */
9694   struct defmap_s *prev, *next; /** link to previous an next definition */
9695 } defmap_t;
9696
9697 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9698 static int defmap_free_count = 0;               /** number of released defmap items */
9699
9700 /* Returns a defmap_t with the specified data; this will be the new list head.
9701  * next - pointer to the current list head */
9702 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9703   defmap_t *map;
9704
9705   if (defmap_free) {
9706     map = defmap_free;
9707     defmap_free = map->next;
9708     --defmap_free_count;
9709   } else {
9710     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9711   }
9712   map->sym = sym;
9713   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9714   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9715   map->acc.access.isRead = (isRead != 0);
9716   map->acc.access.isWrite = (isWrite != 0);
9717   map->pc = pc;
9718   map->in_val = 0;
9719   map->val = (isWrite ? val : 0);
9720   map->prev = NULL;
9721   map->next = next;
9722   if (next) next->prev = map;
9723
9724   return map;
9725 }
9726
9727 /* Returns a copy of the single defmap item. */
9728 static defmap_t *copyDefmap (defmap_t *map) {
9729   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9730   memcpy (res, map, sizeof (defmap_t));
9731   res->next = NULL;
9732   res->prev = NULL;
9733   return res;
9734 }
9735
9736 /* Insert a defmap item after the specified one. */
9737 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9738   if (!ref || !newItem) return 1;
9739
9740   newItem->next = ref->next;
9741   newItem->prev = ref;
9742   ref->next = newItem;
9743   if (newItem->next) newItem->next->prev = newItem;
9744
9745   return 0;
9746 }
9747
9748 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9749  * item is copied before insertion into chain and therefore left untouched.
9750  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9751 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9752   defmap_t *dummy;
9753   dummy = *head;
9754   while (dummy && (dummy->sym != item->sym
9755                           || dummy->pc != item->pc
9756                           || dummy->acc.accessmethod != item->acc.accessmethod
9757                           || dummy->val != item->val
9758                           || dummy->in_val != item->in_val)) {
9759     dummy = dummy->next;
9760   } // while
9761
9762   /* item already present? */
9763   if (dummy) return 0;
9764
9765   /* otherwise: insert copy of item */
9766   dummy = copyDefmap (item);
9767   dummy->next = *head;
9768   if (*head) (*head)->prev = dummy;
9769   *head = dummy;
9770
9771   return 1;
9772 }
9773
9774 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9775 static void deleteDefmap (defmap_t *map) {
9776   if (!map) return;
9777
9778   /* unlink from chain -- fails for the first item (head is not updated!) */
9779   if (map->next) map->next->prev = map->prev;
9780   if (map->prev) map->prev->next = map->next;
9781
9782   /* clear map */
9783   memset (map, 0, sizeof (defmap_t));
9784
9785   /* save for future use */
9786   map->next = defmap_free;
9787   defmap_free = map;
9788   ++defmap_free_count;
9789 }
9790
9791 /* Release all defmaps referenced from map. */
9792 static void deleteDefmapChain (defmap_t **_map) {
9793   defmap_t *map, *next;
9794
9795   if (!_map) return;
9796
9797   map = *_map;
9798
9799   /* find list head */
9800   while (map && map->prev) map = map->prev;
9801
9802   /* delete all items */
9803   while (map) {
9804     next = map->next;
9805     deleteDefmap (map);
9806     map = next;
9807   } // while
9808
9809   *_map = NULL;
9810 }
9811
9812 /* Free all defmap items. */
9813 static void freeDefmap (defmap_t **_map) {
9814   defmap_t *next;
9815   defmap_t *map;
9816
9817   if (!_map) return;
9818
9819   map = (*_map);
9820
9821   /* find list head */
9822   while (map->prev) map = map->prev;
9823
9824   /* release all items */
9825   while (map) {
9826     next = map->next;
9827     Safe_free (map);
9828     map = next;
9829   }
9830
9831   (*_map) = NULL;
9832 }
9833
9834 /* Returns the most recent definition for the given symbol preceeding pc.
9835  * If no definition is found, NULL is returned.
9836  * If pc == NULL the whole list is scanned. */
9837 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9838   defmap_t *curr = map;
9839
9840   if (pc) {
9841     /* skip all definitions up to pc */
9842     while (curr && (curr->pc != pc)) curr = curr->next;
9843
9844     /* pc not in the list -- scan the whole list for definitions */
9845     if (!curr) {
9846       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9847       curr = map;
9848     } else {
9849       /* skip all definitions performed by pc */
9850       while (curr && (curr->pc == pc)) curr = curr->next;
9851     }
9852   } // if (pc)
9853
9854   /* find definition for sym */
9855   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9856     curr = curr->next;
9857   }
9858
9859   return curr;
9860 }
9861
9862 #if 0
9863 /* Returns the first use (read) of the given symbol AFTER pc.
9864  * If no such use is found, NULL is returned.
9865  * If pc == NULL the whole list is scanned. */
9866 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9867   defmap_t *curr = map, *prev = NULL;
9868
9869   if (pc) {
9870     /* skip all definitions up to pc */
9871     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9872
9873     /* pc not in the list -- scan the whole list for definitions */
9874     if (!curr) {
9875       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9876       curr = prev;
9877     }
9878   } else {
9879     /* find end of list */
9880     while (curr && curr->next) curr = curr->next;
9881   } // if (pc)
9882
9883   /* find use of sym (scan list backwards) */
9884   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9885
9886   return curr;
9887 }
9888 #endif
9889
9890 /* Return the defmap entry for sym AT pc.
9891  * If none is found, NULL is returned.
9892  * If more than one entry is found an assertion is triggered. */
9893 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9894   defmap_t *res = NULL;
9895
9896   /* find entries for pc */
9897   while (map && map->pc != pc) map = map->next;
9898
9899   /* find first entry for sym @ pc */
9900   while (map && map->pc == pc && map->sym != sym) map = map->next;
9901
9902   /* no entry found */
9903   if (!map) return NULL;
9904
9905   /* check for more entries */
9906   res = map;
9907   map = map->next;
9908   while (map && map->pc == pc) {
9909     /* more than one entry for sym @ pc found? */
9910     assert (map->sym != sym);
9911     map = map->next;
9912   }
9913
9914   /* return single entry for sym @ pc */
9915   return res;
9916 }
9917
9918 /* Modifies the definition of sym at pCode to newval.
9919  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9920  */
9921 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9922   defmap_t *m  = map;
9923
9924   /* find definitions of pc */
9925   while (m && m->pc != pc) m = m->next;
9926
9927   /* find definition of sym at pc */
9928   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9929
9930   /* no definition found */
9931   if (!m) return 1;
9932
9933   /* redefine */
9934   m->val = newval;
9935
9936   /* update following uses of sym */
9937   while (m && m->pc == pc) m = m->prev;
9938   while (m) {
9939     if (m->sym == sym) {
9940       m->in_val = newval;
9941       if (m->acc.access.isWrite) m = NULL;
9942     } // if
9943     if (m) m = m->prev;
9944   } // while
9945
9946   return 0;
9947 }
9948
9949 /* ======================================================================== */
9950 /* === STACK ROUTINES ===================================================== */
9951 /* ======================================================================== */
9952
9953 typedef struct stack_s {
9954   void *data;
9955   struct stack_s *next;
9956 } stackitem_t;
9957
9958 typedef stackitem_t *dynstack_t;
9959 static stackitem_t *free_stackitems = NULL;
9960
9961 /* Create a stack with one item. */
9962 static dynstack_t *newStack () {
9963   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9964   *s = NULL;
9965   return s;
9966 }
9967
9968 /* Remove a stack -- its items are only marked free. */
9969 static void deleteStack (dynstack_t *s) {
9970   stackitem_t *i;
9971
9972   while (*s) {
9973     i = *s;
9974     *s = (*s)->next;
9975     i->next = free_stackitems;
9976     free_stackitems = i;
9977   } // while
9978   Safe_free (s);
9979 }
9980
9981 /* Release all stackitems. */
9982 static void releaseStack () {
9983   stackitem_t *i;
9984
9985   while (free_stackitems) {
9986     i = free_stackitems->next;
9987     Safe_free(free_stackitems);
9988     free_stackitems = i;
9989   } // while
9990 }
9991
9992 static void stackPush (dynstack_t *stack, void *data) {
9993   stackitem_t *i;
9994
9995   if (free_stackitems) {
9996     i = free_stackitems;
9997     free_stackitems = free_stackitems->next;
9998   } else {
9999     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10000   }
10001   i->data = data;
10002   i->next = *stack;
10003   *stack = i;
10004 }
10005
10006 static void *stackPop (dynstack_t *stack) {
10007   void *data;
10008   stackitem_t *i;
10009
10010   if (stack && *stack) {
10011     data = (*stack)->data;
10012     i = *stack;
10013     *stack = (*stack)->next;
10014     i->next = free_stackitems;
10015     free_stackitems = i;
10016     return data;
10017   } else {
10018     return NULL;
10019   }
10020 }
10021
10022 #if 0
10023 static int stackContains (dynstack_t *s, void *data) {
10024   stackitem_t *i;
10025   if (!s) return 0;
10026   i = *s;
10027   while (i) {
10028     if (i->data == data) return 1;
10029     i = i->next;
10030   } // while
10031
10032   /* not found */
10033   return 0;
10034 }
10035 #endif
10036
10037 static int stackIsEmpty (dynstack_t *s) {
10038   return (*s == NULL);
10039 }
10040
10041
10042 typedef struct {
10043   pCodeFlow *flow;
10044   defmap_t *lastdef;
10045 } state_t;
10046
10047 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10048   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10049   s->flow = flow;
10050   s->lastdef = lastdef;
10051   return s;
10052 }
10053
10054 static void deleteState (state_t *s) {
10055   Safe_free (s);
10056 }
10057
10058 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10059   stackitem_t *i;
10060
10061   /* scan working list for state */
10062   if (todo) {
10063     i = *todo;
10064     while (i) {
10065       /* is i == state? -- state not new */
10066       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10067       i = i->next;
10068     } // while
10069   }
10070
10071   if (done) {
10072     i = *done;
10073     while (i) {
10074       /* is i == state? -- state not new */
10075       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10076       i = i->next;
10077     } // while
10078   }
10079
10080   /* not found -- state is new */
10081   return 1;
10082 }
10083
10084 static inline valnum_t newValnum ();
10085
10086 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10087   pCode *pc;
10088
10089   if (!pb) return "<unknown function>";
10090
10091   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10092   if (pc && isPCF(pc)) return PCF(pc)->fname;
10093   else return "<unknown function>";
10094 }
10095
10096 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10097   defmap_t *map;
10098   pCodeFlow *pcfl;
10099
10100   assert(pb);
10101
10102   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10103
10104   /* find initial value (assigning pc == NULL) */
10105   map = PCFL(pcfl)->in_vals;
10106   while (map && map->sym != sym) map = map->next;
10107
10108   /* initial value already present? */
10109   if (map) {
10110     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10111     return map;
10112   }
10113
10114   /* create a new initial value */
10115   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10116   PCFL(pcfl)->in_vals = map;
10117   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10118   return map;
10119
10120 #if 0
10121   /* insert map as last item in pcfl's defmap */
10122   if (!prev) prev = PCFL(pcfl)->defmap;
10123   if (!prev) {
10124     PCFL(pcfl)->defmap = map;
10125   } else {
10126     while (prev->next) prev = prev->next;
10127     prev->next = map;
10128     map->prev = prev;
10129   }
10130
10131   return map;
10132 #endif
10133 }
10134
10135 /* Find all reaching definitions for sym at pc.
10136  * A new (!) list of definitions is returned.
10137  * Returns the number of reaching definitions found.
10138  * The defining defmap entries are returned in *chain.
10139  */
10140 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10141   defmap_t *map;
10142   defmap_t *res;
10143
10144   pCodeFlow *curr;
10145   pCodeFlowLink *succ;
10146   state_t *state;
10147   dynstack_t *todo;     /** stack of state_t */
10148   dynstack_t *done;     /** stack of state_t */
10149
10150   int firstState, n_defs;
10151
10152   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10153   assert (chain);
10154
10155   /* initialize return list */
10156   *chain = NULL;
10157
10158   /* wildcard symbol? */
10159   if (!sym) return 0;
10160
10161   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10162
10163   map = PCI(pc)->pcflow->defmap;
10164
10165   res = defmapFindDef (map, sym, pc);
10166   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10167
10168 #define USE_PRECALCED_INVALS 1
10169 #if USE_PRECALCED_INVALS
10170   if (!res && PCI(pc)->pcflow->in_vals) {
10171     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10172     if (res) {
10173       //fprintf  (stderr, "found def in init values\n");
10174       df_findall_in_vals++;
10175     }
10176   }
10177 #endif
10178
10179   if (res) {
10180     // found a single definition (in pc's flow)
10181     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10182     defmapAddCopyIfNew (chain, res);
10183     df_findall_sameflow++;
10184     return 1;
10185   }
10186
10187 #if USE_PRECALCED_INVALS
10188   else {
10189     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10190     return 1;
10191   }
10192
10193 #endif
10194
10195 #define FORWARD_FLOW_ANALYSIS 1
10196 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10197   /* no definition found in pc's flow preceeding pc */
10198   todo = newStack ();
10199   done = newStack ();
10200   n_defs = 0; firstState = 1;
10201   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10202
10203   while (!stackIsEmpty (todo)) {
10204     state = (state_t *) stackPop (todo);
10205     stackPush (done, state);
10206     curr = state->flow;
10207     res = state->lastdef;
10208     //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);
10209
10210     /* there are no definitions BEFORE pc in pc's flow (see above) */
10211     if (curr == PCI(pc)->pcflow) {
10212       if (!res) {
10213         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10214         res = pic16_pBlockAddInval (pc->pb, sym);
10215         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10216         res = NULL;
10217       } else {
10218         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10219         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10220       }
10221     }
10222
10223     /* save last definition of sym in this flow as initial def in successors */
10224     res = defmapFindDef (curr->defmap, sym, NULL);
10225     if (!res) res = state->lastdef;
10226
10227     /* add successors to working list */
10228     state = newState (NULL, NULL);
10229     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10230     while (succ) {
10231       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10232       state->flow = succ->pcflow;
10233       state->lastdef = res;
10234       if (stateIsNew (state, todo, done)) {
10235         stackPush (todo, state);
10236         state = newState (NULL, NULL);
10237       } // if
10238       succ = (pCodeFlowLink *) setNextItem (curr->to);
10239     } // while
10240     deleteState (state);
10241   } // while
10242
10243 #else // !FORWARD_FLOW_ANALYSIS
10244
10245   /* no definition found in pc's flow preceeding pc */
10246   todo = newStack ();
10247   done = newStack ();
10248   n_defs = 0; firstState = 1;
10249   stackPush (todo, newState (PCI(pc)->pcflow, res));
10250
10251   while (!stackIsEmpty (todo)) {
10252     state = (state_t *) stackPop (todo);
10253     curr = state->flow;
10254
10255     if (firstState) {
10256       firstState = 0;
10257       /* only check predecessor flows */
10258     } else {
10259       /* get (last) definition of sym in this flow */
10260       res = defmapFindDef (curr->defmap, sym, NULL);
10261     }
10262
10263     if (res) {
10264       /* definition found */
10265       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10266       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10267     } else {
10268       /* no definition found -- check predecessor flows */
10269       state = newState (NULL, NULL);
10270       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10271
10272       /* if no flow predecessor available -- sym might be uninitialized */
10273       if (!succ) {
10274         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10275         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10276         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10277         deleteDefmap (res); res = NULL;
10278       }
10279
10280       while (succ) {
10281         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10282         state->flow = succ->pcflow;
10283         state->lastdef = res;
10284         if (stateIsNew (state, todo, done)) {
10285           stackPush (todo, state);
10286           state = newState (NULL, NULL);
10287         } // if
10288         succ = (pCodeFlowLink *) setNextItem (curr->from);
10289       } // while
10290       deleteState (state);
10291     }
10292   } // while
10293
10294 #endif
10295
10296   /* clean up done stack */
10297   while (!stackIsEmpty(done)) {
10298     deleteState ((state_t *) stackPop (done));
10299   } // while
10300   deleteStack (done);
10301
10302   /* return number of items in result set */
10303   if (n_defs == 0) {
10304     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10305   } else if (n_defs == 1) {
10306     assert (*chain);
10307     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10308   } else if (n_defs > 0) {
10309     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10310 #if 0
10311     res = *chain;
10312     while (res) {
10313       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10314       res = res->next;
10315     } // while
10316 #endif
10317   }
10318   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10319   df_findall_otherflow++;
10320   return n_defs;
10321 }
10322
10323 /* ======================================================================== */
10324 /* === VALUE NUMBER HANDLING ============================================== */
10325 /* ======================================================================== */
10326
10327 static valnum_t nextValnum = 0x1000;
10328 static hTab *map_symToValnum = NULL;
10329
10330 /** Return a new value number. */
10331 static inline valnum_t newValnum () {
10332   return (nextValnum += 4);
10333 }
10334
10335 static valnum_t valnumFromStr (const char *str) {
10336   symbol_t sym;
10337   valnum_t val;
10338   void *res;
10339
10340   sym = symFromStr (str);
10341
10342   if (!map_symToValnum) {
10343     map_symToValnum = newHashTable (128);
10344   } // if
10345
10346   /* literal already known? */
10347   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10348
10349   /* return existing valnum */
10350   if (res) return (valnum_t) PTR_TO_INT(res);
10351
10352   /* create new valnum */
10353   val = newValnum();
10354   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10355   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10356   return val;
10357 }
10358
10359 /* Create a valnum for a literal. */
10360 static valnum_t valnumFromLit (unsigned int lit) {
10361   return ((valnum_t) 0x100 + (lit & 0x0FF));
10362 }
10363
10364 /* Return the (positive) literal value represented by val
10365  * or -1 iff val is no known literal's valnum. */
10366 static int litFromValnum (valnum_t val) {
10367   if (val >= 0x100 && val < 0x200) {
10368     /* valnum is a (known) literal */
10369     return val & 0x00FF;
10370   } else {
10371     /* valnum is not a known literal */
10372     return -1;
10373   }
10374 }
10375
10376 #if 0
10377 /* Sanity check - all flows in a block must be reachable from initial flow. */
10378 static int verifyAllFlowsReachable (pBlock *pb) {
10379   set *reached;
10380   set *flowInBlock;
10381   set *checked;
10382   pCode *pc;
10383   pCodeFlow *pcfl;
10384   pCodeFlowLink *succ;
10385   int res;
10386
10387   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10388
10389   reached = NULL;
10390   flowInBlock = NULL;
10391   checked = NULL;
10392   /* mark initial flow as reached (and "not needs to be reached") */
10393   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10394   assert (pc);
10395   addSetHead (&reached, pc);
10396   addSetHead (&checked, pc);
10397
10398   /* mark all further flows in block as "need to be reached" */
10399   pc = pb->pcHead;
10400   do {
10401     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10402     pc = pic16_findNextInstruction (pc->next);
10403   } while (pc);
10404
10405   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10406     /* mark as reached and "not need to be reached" */
10407     deleteSetItem (&reached, pcfl);
10408     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10409
10410     /* flow is no longer considered unreachable */
10411     deleteSetItem (&flowInBlock, pcfl);
10412
10413     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10414       if (!isinSet (checked, succ->pcflow)) {
10415         /* flow has never been reached before */
10416         addSetHead (&reached, succ->pcflow);
10417         addSetHead (&checked, succ->pcflow);
10418       } // if
10419     } // for succ
10420   } // while
10421
10422   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10423
10424   /* by now every flow should have been reached
10425    * --> flowInBlock should be empty */
10426   res = (flowInBlock == NULL);
10427
10428 #if 1
10429   if (flowInBlock) {
10430           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10431     while (flowInBlock) {
10432       pcfl = indexSet (flowInBlock, 0);
10433       fprintf (stderr, "not reached: flow %p\n", pcfl);
10434       deleteSetItem (&flowInBlock, pcfl);
10435     } // while
10436   }
10437 #endif
10438
10439   /* clean up */
10440   deleteSet (&reached);
10441   deleteSet (&flowInBlock);
10442   deleteSet (&checked);
10443
10444   /* if we reached every flow, succ is NULL by now... */
10445   //assert (res); // will fire on unreachable code...
10446   return (res);
10447 }
10448 #endif
10449
10450 /* Checks a flow for accesses to sym AFTER pc.
10451  *
10452  * Returns -1 if the symbol is read in this flow (before redefinition),
10453  * returns 0 if the symbol is redefined in this flow or
10454  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10455  */
10456 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10457   defmap_t *map, *mappc;
10458
10459   /* find pc or start of definitions */
10460   map = pcfl->defmap;
10461   while (map && (map->pc != pc) && map->next) map = map->next;
10462   /* if we found pc -- ignore it */
10463   while (map && map->pc == pc) map = map->prev;
10464
10465   /* scan list backwards (first definition first) */
10466   while (map && mask) {
10467 //    if (map->sym == sym) {
10468       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10469       mappc = map;
10470       /* scan list for reads at this pc first */
10471       while (map && map->pc == mappc->pc) {
10472         /* is the symbol (partially) read? */
10473         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10474           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10475           return -1;
10476         }
10477         map = map->prev;
10478       } // while
10479       map = mappc;
10480
10481       while (map && map->pc == mappc->pc) {
10482         /* honor (partial) redefinitions of sym */
10483         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10484           mask &= ~map->acc.access.mask;
10485           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10486         }
10487         map = map->prev;
10488       } // while
10489 //    } // if
10490     /* map already points to the first defmap for the next pCode */
10491     //map = mappc->prev;
10492   } // while
10493
10494   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10495    * is still alive; return the appropriate mask of alive bits */
10496   return mask;
10497 }
10498
10499 /* Check whether a symbol is alive (AFTER pc). */
10500 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10501   int mask, visit;
10502   defmap_t *map;
10503   dynstack_t *todo, *done;
10504   state_t *state;
10505   pCodeFlow *pcfl;
10506   pCodeFlowLink *succ;
10507
10508   mask = 0x00ff;
10509
10510   assert (isPCI(pc));
10511   pcfl = PCI(pc)->pcflow;
10512   map = pcfl->defmap;
10513
10514   todo = newStack ();
10515   done = newStack ();
10516
10517   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10518   stackPush (todo, state);
10519   visit = 0;
10520
10521   while (!stackIsEmpty (todo)) {
10522     state = (state_t *) stackPop (todo);
10523     pcfl = state->flow;
10524     mask = PTR_TO_INT(state->lastdef);
10525     if (visit) stackPush (done, state); else deleteState(state);
10526     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10527     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10528     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10529     visit++;
10530
10531     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10532     if (mask == 0) continue;
10533
10534     /* symbol is (partially) read before redefinition in flow */
10535     if (mask == -1) break;
10536
10537     /* symbol is neither read nor completely redefined -- check successor flows */
10538     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10539       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10540       if (stateIsNew (state, todo, done)) {
10541         stackPush (todo, state);
10542       } else {
10543         deleteState (state);
10544       }
10545     } // for
10546   } // while
10547
10548   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10549   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10550
10551   /* symbol is read in at least one flow -- is alive */
10552   if (mask == -1) return 1;
10553
10554   /* symbol is read in no flow */
10555   return 0;
10556 }
10557
10558 /* Returns whether access to the given symbol has side effects. */
10559 static int pic16_symIsSpecial (symbol_t sym) {
10560   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10561   switch (sym) {
10562   case SPO_INDF0:
10563   case SPO_PLUSW0:
10564   case SPO_POSTINC0:
10565   case SPO_POSTDEC0:
10566   case SPO_PREINC0:
10567   case SPO_INDF1:
10568   case SPO_PLUSW1:
10569   case SPO_POSTINC1:
10570   case SPO_POSTDEC1:
10571   case SPO_PREINC1:
10572   case SPO_INDF2:
10573   case SPO_PLUSW2:
10574   case SPO_POSTINC2:
10575   case SPO_POSTDEC2:
10576   case SPO_PREINC2:
10577   case SPO_PCL:
10578           return 1;
10579   default:
10580           /* no special effects known */
10581           return 0;
10582   } // switch
10583
10584   return 0;
10585 }
10586
10587 /* Check whether a register should be considered local (to the current function) or not. */
10588 static int pic16_regIsLocal (regs *r) {
10589   symbol_t sym;
10590   if (r) {
10591     if (r->type == REG_TMP) return 1;
10592
10593     sym = symFromStr (r->name);
10594     switch (sym) {
10595     case SPO_WREG:
10596     case SPO_FSR0L: // used in ptrget/ptrput
10597     case SPO_FSR0H: // ... as well
10598     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10599     case SPO_FSR1H: // ... as well
10600     case SPO_FSR2L: // used as frame pointer
10601     case SPO_FSR2H: // ... as well
10602     case SPO_PRODL: // used to return values from functions
10603     case SPO_PRODH: // ... as well
10604       /* these registers (and some more...) are considered local */
10605       return 1;
10606       break;
10607     default:
10608       /* for unknown regs: check is marked local, leave if not */
10609       if (r->isLocal) {
10610         return 1;
10611       } else {
10612         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10613         return 0;
10614       }
10615     } // switch
10616   } // if
10617
10618   /* if in doubt, assume non-local... */
10619   return 0;
10620 }
10621
10622 /* Check all symbols touched by pc whether their newly assigned values are read.
10623  * Returns 0 if no symbol is used later on, 1 otherwise. */
10624 static int pic16_pCodeIsAlive (pCode *pc) {
10625   pCodeInstruction *pci;
10626   defmap_t *map, *lastpc;
10627   regs *checkreg;
10628
10629   /* we can only handle PCIs */
10630   if (!isPCI(pc)) return 1;
10631
10632   //pc->print (stderr, pc);
10633
10634   pci = PCI(pc);
10635   assert (pci && pci->pcflow && pci->pcflow->defmap);
10636
10637   /* NEVER remove instructions with implicit side effects */
10638   switch (pci->op) {
10639   case POC_TBLRD:
10640   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10641   case POC_TBLRD_POSTDEC:
10642   case POC_TBLRD_PREINC:
10643   case POC_TBLWT:               /* modify program memory */
10644   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10645   case POC_TBLWT_POSTDEC:
10646   case POC_TBLWT_PREINC:
10647   case POC_CLRWDT:              /* clear watchdog timer */
10648   case POC_PUSH:                /* should be safe to remove though... */
10649   case POC_POP:                 /* should be safe to remove though... */
10650   case POC_CALL:
10651   case POC_RCALL:
10652   case POC_RETFIE:
10653   case POC_RETURN:
10654     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10655     return 1;
10656
10657   default:
10658     /* no special instruction */
10659     break;
10660   } // switch
10661
10662   /* prevent us from removing assignments to non-local variables */
10663   checkreg = NULL;
10664   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10665   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10666
10667   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10668     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10669     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10670     //pc->print (stderr, pc);
10671     return 1;
10672   }
10673   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10674     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10675     return 1;
10676   }
10677
10678 #if 1
10679   /* OVERKILL: prevent us from removing reads from non-local variables
10680    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10681    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10682   checkreg = NULL;
10683   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10684   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10685
10686   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10687     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10688     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10689     //pc->print (stderr, pc);
10690     return 1;
10691   }
10692   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10693     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10694     return 1;
10695   }
10696 #endif
10697
10698   /* now check that the defined symbols are not used */
10699   map = pci->pcflow->defmap;
10700
10701   /* find items for pc */
10702   while (map && map->pc != pc) map = map->next;
10703
10704   /* no entries found? something is fishy with DF analysis... -- play safe */
10705   if (!map) {
10706     if (pic16_pcode_verbose) {
10707       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10708     }
10709     return 1;
10710   }
10711
10712   /* remember first item assigned to pc for later use */
10713   lastpc = map;
10714
10715   /* check all symbols being modified by pc */
10716   while (map && map->pc == pc) {
10717     if (map->sym == 0) { map = map->next; continue; }
10718
10719     /* keep pc if it references special symbols (like POSTDEC0) */
10720 #if 0
10721     {
10722       char buf[256];
10723       pic16_pCode2str (buf, 256, pc);
10724       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10725     }
10726 #endif
10727     if (pic16_symIsSpecial (map->sym)) {
10728       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10729       return 1;
10730     }
10731     if (map->acc.access.isWrite) {
10732       if (pic16_isAlive (map->sym, pc)) {
10733         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10734         return 1;
10735       }
10736     }
10737     map = map->next;
10738   } // while
10739
10740   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10741 #if 0
10742   {
10743     char buf[256];
10744     pic16_pCode2str (buf, 256, pc);
10745     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10746   }
10747 #endif
10748   return 0;
10749 }
10750
10751 /* Adds implied operands to the list.
10752  * sym - operand being accessed in the pCode
10753  * list - list to append the operand
10754  * isRead - set to 1 iff sym is read in pCode
10755  * listRead - set to 1 iff all operands being read are to be listed
10756  *
10757  * Returns 0 for "normal" operands, 1 for special operands.
10758  */
10759 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10760   /* check whether accessing REG accesses other REGs as well */
10761   switch (sym) {
10762   case SPO_INDF0:
10763     /* reads FSR0x */
10764     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10765     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10766     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10767     break;
10768
10769   case SPO_PLUSW0:
10770     /* reads FSR0x and WREG */
10771     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10772     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10773     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10774     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10775     break;
10776
10777   case SPO_POSTDEC0:
10778   case SPO_POSTINC0:
10779   case SPO_PREINC0:
10780     /* reads/modifies FSR0x */
10781     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10782     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10783     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10784     break;
10785
10786   case SPO_INDF1:
10787     /* reads FSR1x */
10788     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10789     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10790     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10791     break;
10792
10793   case SPO_PLUSW1:
10794     /* reads FSR1x and WREG */
10795     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10796     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10797     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10798     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10799     break;
10800
10801   case SPO_POSTDEC1:
10802   case SPO_POSTINC1:
10803   case SPO_PREINC1:
10804     /* reads/modifies FSR1x */
10805     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10806     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10807     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10808     break;
10809
10810   case SPO_INDF2:
10811     /* reads FSR2x */
10812     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10813     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10814     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10815     break;
10816
10817   case SPO_PLUSW2:
10818     /* reads FSR2x and WREG */
10819     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10820     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10821     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10822     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10823     break;
10824
10825   case SPO_POSTDEC2:
10826   case SPO_POSTINC2:
10827   case SPO_PREINC2:
10828     /* reads/modifies FSR2x */
10829     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10830     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10831     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10832     break;
10833
10834   case SPO_PCL:
10835     /* modifies PCLATH and PCLATU */
10836     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10837     if (isRead) {
10838       /* reading PCL updates PCLATx */
10839       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10840       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10841     }
10842     if (isWrite) {
10843       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10844       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10845       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10846     }
10847     break;
10848
10849   default:
10850     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10851     /* nothing special */
10852     return 0;
10853     break;
10854   }
10855
10856   /* has been a special operand */
10857   return 1;
10858 }
10859
10860 static symbol_t pic16_fsrsym_idx[][2] = {
10861     {SPO_FSR0L, SPO_FSR0H},
10862     {SPO_FSR1L, SPO_FSR1H},
10863     {SPO_FSR2L, SPO_FSR2H}
10864 };
10865
10866 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10867 static void mergeDefmapSymbols (defmap_t *list) {
10868   defmap_t *ref, *curr, *temp;
10869
10870   /* now make sure that each symbol occurs at most once per pc */
10871   ref = list;
10872   while (ref && (ref->pc == list->pc)) {
10873     curr = ref->next;
10874     while (curr && (curr->pc == list->pc)) {
10875       if (curr->sym == ref->sym) {
10876         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10877         /* found a symbol occuring twice... merge the two */
10878         if (curr->acc.access.isRead) {
10879           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10880           ref->acc.access.isRead = 1;
10881           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10882         }
10883         if (curr->acc.access.isWrite) {
10884           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10885           ref->acc.access.isWrite = 1;
10886           ref->acc.access.mask |= curr->acc.access.mask;
10887         }
10888         temp = curr;
10889         curr = curr->next;
10890         deleteDefmap (temp);
10891         continue; // do not skip curr!
10892       } // if
10893       curr = curr->next;
10894     } // while
10895     ref = ref->next;
10896   } // while
10897 }
10898
10899 /** Prepend list with the reads and definitions performed by pc. */
10900 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10901   pCodeInstruction *pci;
10902   int cond, inCond, outCond;
10903   int mask = 0xff, smask;
10904   int isSpecial, isSpecial2;
10905   symbol_t sym, sym2;
10906   char *name;
10907
10908   if (isPCAD(pc)) {
10909     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10910     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10911     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10912     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10913     return list;
10914   }
10915   assert (isPCI(pc));
10916   pci = PCI(pc);
10917
10918   /* handle bit instructions */
10919   if (pci->isBitInst) {
10920     assert (pci->pcop->type == PO_GPR_BIT);
10921     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10922   }
10923
10924   /* handle (additional) implicit arguments */
10925   switch (pci->op) {
10926   case POC_LFSR:
10927     {
10928       int lit;
10929       valnum_t val;
10930       lit = PCOL(pci->pcop)->lit;
10931       assert (lit >= 0 && lit < 3);
10932       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10933       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10934       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10935       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10936       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...
10937     }
10938     break;
10939
10940   case POC_MOVLB: // BSR
10941   case POC_BANKSEL: // BSR
10942     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10943     break;
10944
10945   case POC_MULWF: // PRODx
10946   case POC_MULLW: // PRODx
10947     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10948     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10949     break;
10950
10951   case POC_POP: // TOS, STKPTR
10952     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10953     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10954     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10955     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10956     break;
10957
10958   case POC_PUSH: // STKPTR
10959     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10960     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10961     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10962     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10963     break;
10964
10965   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10966   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10967     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10968     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10969     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10970     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10971
10972     /* needs correctly set-up stack pointer */
10973     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10974     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10975     break;
10976
10977   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10978     /* pseudo read on (possible) return values */
10979     // WREG is handled below via outCond
10980     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10981     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10982     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10983
10984     /* caller's stack pointers must be restored */
10985     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10986     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10987     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10988     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10989     break;
10990
10991   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10992   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10993     /* pseudo read on (possible) return values */
10994     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10995     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10996     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10997     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10998
10999     /* caller's stack pointers must be restored */
11000     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11001     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11002     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11003     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11004     break;
11005
11006   case POC_TBLRD:
11007     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11008     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11009     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11010     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11011     break;
11012
11013   case POC_TBLRD_POSTINC:
11014   case POC_TBLRD_POSTDEC:
11015   case POC_TBLRD_PREINC:
11016     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11017     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11018     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11019     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11020     break;
11021
11022   case POC_TBLWT:
11023     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11024     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11025     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11026     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11027     break;
11028
11029   case POC_TBLWT_POSTINC:
11030   case POC_TBLWT_POSTDEC:
11031   case POC_TBLWT_PREINC:
11032     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11033     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11034     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11035     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11036     break;
11037
11038   default:
11039     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11040     break;
11041   } // switch
11042
11043   /* handle explicit arguments */
11044   inCond = pci->inCond;
11045   outCond = pci->outCond;
11046   cond = inCond | outCond;
11047   if (cond & PCC_W) {
11048     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11049   } // if
11050
11051   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11052   if (inCond & PCC_STATUS) {
11053     smask = 0;
11054     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11055     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11056     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11057     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11058     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11059
11060     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11061     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11062   } // if
11063
11064   if (outCond & PCC_STATUS) {
11065     smask = 0;
11066     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11067     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11068     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11069     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11070     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11071
11072     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11073     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11074   } // if
11075
11076   isSpecial = isSpecial2 = 0;
11077   sym = sym2 = 0;
11078   if (cond & PCC_REGISTER) {
11079     name = pic16_get_op (pci->pcop, NULL, 0);
11080     sym = symFromStr (name);
11081     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11082     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11083   }
11084
11085   if (cond & PCC_REGISTER2) {
11086     name = pic16_get_op2 (pci->pcop, NULL, 0);
11087     sym2 = symFromStr (name);
11088     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11089     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11090   }
11091
11092
11093   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11094   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11095
11096   mergeDefmapSymbols (list);
11097
11098   return list;
11099 }
11100
11101 #if 0
11102 static void printDefmap (defmap_t *map) {
11103   defmap_t *curr;
11104
11105   curr = map;
11106   fprintf (stderr, "defmap @ %p:\n", curr);
11107   while (curr) {
11108     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11109                     curr->acc.access.isRead ? "R" : " ",
11110                     curr->acc.access.isWrite ? "W": " ",
11111                     curr->in_val, curr->val,
11112                     curr->acc.access.in_mask, curr->acc.access.mask,
11113                     strFromSym(curr->sym), curr->sym,
11114                     curr->pc);
11115     curr = curr->next;
11116   } // while
11117   fprintf (stderr, "<EOL>\n");
11118 }
11119 #endif
11120
11121 /* Add "additional" definitions to uniq.
11122  * 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.
11123  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11124  *
11125  * If symbols defined in additional are not present in uniq, a definition is created.
11126  * Otherwise the present definition is altered to reflect the newer assignments.
11127  *
11128  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11129  *       before     `------- noted in additional --------'      after
11130  *
11131  * I assume that each symbol occurs AT MOST ONCE in uniq.
11132  *
11133  */
11134 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11135   defmap_t *curr;
11136   defmap_t *old;
11137   int change = 0;
11138
11139   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11140   /* find tail of additional list (holds the first assignment) */
11141   curr = additional;
11142   while (curr && curr->next) curr = curr->next;
11143
11144   /* update uniq */
11145   do {
11146     /* find next assignment in additionals */
11147     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11148
11149     if (!curr) break;
11150
11151     /* find item in uniq */
11152     old = *uniq;
11153     //printDefmap (*uniq);
11154     while (old && (old->sym != curr->sym)) old = old->next;
11155
11156     if (old) {
11157       /* definition found -- replace */
11158       if (old->val != curr->val) {
11159         old->val = curr->val;
11160         change++;
11161       } // if
11162     } else {
11163       /* new definition */
11164       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11165       change++;
11166     }
11167
11168     curr = curr->prev;
11169   } while (1);
11170
11171   /* return 0 iff uniq remained unchanged */
11172   return change;
11173 }
11174
11175 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11176  * lists of its predecessor flows.
11177  * Initially *combined should be NULL, alt_in will be copied to combined.
11178  * If *combined != NULL, combined will be altered:
11179  * - for symbols defined in *combined but not in alt_in,
11180  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11181  * - for symbols defined in alt_in but not in *combined,
11182  *   a 0 definition is created (value unknown, either INIT or alt).
11183  * - for symbols defined in both, *combined is:
11184  *   > left unchanged if *combined->val == alt_in->val or
11185  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11186  *
11187  * I assume that each symbol occurs AT MOST ONCE in each list!
11188  */
11189 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11190   defmap_t *curr;
11191   defmap_t *old;
11192   int change = 0;
11193   valnum_t val;
11194
11195   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11196
11197   if (!(*combined)) {
11198     return defmapUpdateUniqueSym (combined, alt_in);
11199   } // if
11200
11201   /* merge the two */
11202   curr = alt_in;
11203   while (curr) {
11204     /* find symbols definition in *combined */
11205     old = *combined;
11206     while (old && (old->sym != curr->sym)) old = old->next;
11207
11208     if (old) {
11209       /* definition found */
11210       if (old->val && (old->val != curr->val)) {
11211         old->val = 0; /* value unknown */
11212         change++;
11213       }
11214     } else {
11215       /* no definition found -- can be either INIT or alt_in's value */
11216       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11217       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11218       if (val != curr->val) change++;
11219     }
11220
11221     curr = curr->next;
11222   } // while (curr)
11223
11224   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11225   old = *combined;
11226   while (old) {
11227     if (old->val != 0) {
11228       /* find definition in alt_in */
11229       curr = alt_in;
11230       while (curr && curr->sym != old->sym) curr = curr->next;
11231       if (!curr) {
11232         /* symbol defined in *combined only -- can be either INIT or *combined */
11233         val = pic16_pBlockAddInval (pb, old->sym)->val;
11234         if (old->val != val) {
11235           old->val = 0;
11236           change++;
11237         }
11238       } // if
11239     } // if
11240
11241     old = old->next;
11242   } // while
11243
11244   return change;
11245 }
11246
11247 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11248   defmap_t *curr1, *curr2;
11249   symbol_t sym;
11250
11251   /* identical maps are equal */
11252   if (map1 == map2) return 0;
11253
11254   if (!map1) return -1;
11255   if (!map2) return 1;
11256
11257   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11258
11259   /* check length */
11260   curr1 = map1;
11261   curr2 = map2;
11262   while (curr1 && curr2) {
11263     curr1 = curr1->next;
11264     curr2 = curr2->next;
11265   } // while
11266
11267   /* one of them longer? */
11268   if (curr1) return 1;
11269   if (curr2) return -1;
11270
11271   /* both lists are of equal length -- compare (in O(n^2)) */
11272   curr1 = map1;
11273   while (curr1) {
11274     sym = curr1->sym;
11275     curr2 = map2;
11276     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11277     if (!curr2) return 1; // symbol not found in curr2
11278     if (curr2->val != curr1->val) return 1; // values differ
11279
11280     /* compare next symbol */
11281     curr1 = curr1->next;
11282   } // while
11283
11284   /* no difference found */
11285   return 0;
11286 }
11287
11288
11289 /* Prepare a list of all reaching definitions per flow.
11290  * This is done using a forward dataflow analysis.
11291  */
11292 static void createReachingDefinitions (pBlock *pb) {
11293   defmap_t *out_vals, *in_vals;
11294   pCode *pc;
11295   pCodeFlow *pcfl;
11296   pCodeFlowLink *link;
11297   set *todo;
11298   set *blacklist;
11299
11300   if (!pb) return;
11301
11302   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11303   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11304     if (isPCFL(pc)) {
11305       deleteDefmapChain (&PCFL(pc)->in_vals);
11306       deleteDefmapChain (&PCFL(pc)->out_vals);
11307       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11308     } // if
11309   } // for
11310
11311   pc = pic16_findNextInstruction (pb->pcHead);
11312   todo = NULL; blacklist = NULL;
11313   addSetHead (&todo, PCI(pc)->pcflow);
11314
11315   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11316   while (elementsInSet (todo)) {
11317     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11318     pcfl = PCFL(indexSet (todo, 0));
11319     deleteSetItem (&todo, pcfl);
11320     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11321     in_vals = NULL;
11322     out_vals = NULL;
11323
11324     if (isinSet (blacklist, pcfl)) {
11325             fprintf (stderr, "ignoring blacklisted flow\n");
11326       continue;
11327     }
11328
11329     /* create in_vals from predecessors out_vals */
11330     link = setFirstItem (pcfl->from);
11331     while (link) {
11332       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11333       link = setNextItem (pcfl->from);
11334     } // while
11335
11336     //printDefmap (in_vals);
11337     //printDefmap (pcfl->in_vals);
11338
11339     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11340       //fprintf (stderr, "in_vals changed\n");
11341       /* in_vals changed -- update out_vals */
11342       deleteDefmapChain (&pcfl->in_vals);
11343       pcfl->in_vals = in_vals;
11344
11345       /* create out_val from in_val and defmap */
11346       out_vals = NULL;
11347       defmapUpdateUniqueSym (&out_vals, in_vals);
11348       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11349
11350       /* is out_vals different from pcfl->out_vals */
11351       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11352         //fprintf (stderr, "out_vals changed\n");
11353         deleteDefmapChain (&pcfl->out_vals);
11354         pcfl->out_vals = out_vals;
11355
11356         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11357           addSet (&blacklist, pcfl);
11358         } // if
11359
11360         /* reschedule all successors */
11361         link = setFirstItem (pcfl->to);
11362         while (link) {
11363           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11364           addSetIfnotP (&todo, link->pcflow);
11365           link = setNextItem (pcfl->to);
11366         } // while
11367       } else {
11368         deleteDefmapChain (&out_vals);
11369       }// if
11370     } else {
11371       deleteDefmapChain (&in_vals);
11372     } // if
11373   } // while
11374 }
11375
11376 #if 0
11377 static void showAllDefs (symbol_t sym, pCode *pc) {
11378   defmap_t *map;
11379   int count;
11380
11381   assert (isPCI(pc));
11382   count = defmapFindAll (sym, pc, &map);
11383
11384   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11385   while (map) {
11386 #if 1
11387     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11388 #else
11389     { char buf[256];
11390     pic16_pCode2str (buf, 256, map->pc);
11391     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11392 #endif
11393     map = map->next;
11394   }
11395   deleteDefmapChain (&map);
11396 }
11397 #endif
11398
11399 /* safepCodeUnlink and remove pc from defmap. */
11400 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11401   defmap_t *map, *next, **head;
11402   int res, ispci;
11403
11404   ispci = isPCI(pc);
11405   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11406   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11407   res = pic16_safepCodeUnlink (pc, comment);
11408
11409   if (res && map) {
11410     /* remove pc from defmap */
11411     while (map) {
11412       next = map->next;
11413       if (map->pc == pc) {
11414         if (!map->prev && head) *head = map->next;
11415         deleteDefmap (map);
11416       } // if
11417       map = next;
11418     }
11419   }
11420
11421   return res;
11422 }
11423
11424 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11425   defmap_t *map;
11426   /* This breaks the defmap chain's references to pCodes... fix it! */
11427   map = PCI(pc)->pcflow->defmap;
11428
11429   while (map && map->pc != pc) map = map->next;
11430
11431   while (map && map->pc == pc) {
11432     map->pc = newpc;
11433     map = map->next;
11434   } // while
11435 }
11436
11437 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11438  * write accesses (isRead == 0). */
11439 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11440   defmap_t *map, *map_start;
11441   defmap_t *copy;
11442   if (!isPCI(pc)) return;
11443   if (sym == newsym) return;
11444
11445   map = PCI(pc)->pcflow->defmap;
11446
11447   while (map && map->pc != pc) map = map->next;
11448   map_start = map;
11449   while (map && map->pc == pc) {
11450     if (map->sym == sym) {
11451       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11452       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11453         /* only one kind of access handled... this is easy */
11454         map->sym = newsym;
11455       } else {
11456         /* must copy defmap entry before replacing symbol... */
11457         copy = copyDefmap (map);
11458         if (isRead) {
11459           map->acc.access.isRead = 0;
11460           copy->acc.access.isWrite = 0;
11461         } else {
11462           map->acc.access.isWrite = 0;
11463           copy->acc.access.isRead = 0;
11464         }
11465         copy->sym = newsym;
11466         /* insert copy into defmap chain */
11467         defmapInsertAfter (map, copy);
11468       }
11469     }
11470     map = map->next;
11471   } // while
11472
11473   /* as this might introduce multiple defmap entries for newsym... */
11474   mergeDefmapSymbols (map_start);
11475 }
11476
11477 /* Assign "better" valnums to results. */
11478 static void assignValnums (pCode *pc) {
11479   pCodeInstruction *pci;
11480   pCode *newpc;
11481   symbol_t sym1, sym2;
11482   int cond, isSpecial1, isSpecial2, count, mask, lit;
11483   defmap_t *list, *val, *oldval, *dummy;
11484   regs *reg1 = NULL, *reg2 = NULL;
11485   valnum_t litnum;
11486
11487   /* only works for pCodeInstructions... */
11488   if (!isPCI(pc)) return;
11489
11490   pci = PCI(pc);
11491   cond = pci->inCond | pci->outCond;
11492   list = pci->pcflow->defmap;
11493   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11494
11495   if (cond & PCC_REGISTER) {
11496     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11497     reg1 = pic16_getRegFromInstruction (pc);
11498     isSpecial1 = pic16_symIsSpecial (sym1);
11499   }
11500   if (cond & PCC_REGISTER2) {
11501     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11502     reg2 = pic16_getRegFromInstruction (pc);
11503     isSpecial2 = pic16_symIsSpecial (sym2);
11504   }
11505
11506   /* determine input values */
11507   val = list;
11508   while (val && val->pc != pc) val = val->next;
11509   //list = val; /* might save some time later... */
11510   while (val && val->pc == pc) {
11511     val->in_val = 0;
11512     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11513       /* get valnum for sym */
11514       count = defmapFindAll (val->sym, pc, &oldval);
11515       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11516       if (count == 1) {
11517         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11518           val->in_val = oldval->val;
11519         } else {
11520           val->in_val = 0;
11521         }
11522       } else if (count == 0) {
11523         /* no definition found */
11524         val->in_val = 0;
11525       } else {
11526         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11527         assert (oldval);
11528         dummy = oldval->next;
11529         mask = oldval->acc.access.mask;
11530         val->in_val = oldval->val;
11531         while (dummy && (dummy->val == val->in_val)) {
11532           mask &= dummy->acc.access.mask;
11533           dummy = dummy->next;
11534         } // while
11535
11536         /* found other values or to restictive mask */
11537         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11538           val->in_val = 0;
11539         }
11540       }
11541       if (count > 0) deleteDefmapChain (&oldval);
11542     } // if
11543     val = val->next;
11544   }
11545
11546   /* handle valnum assignment */
11547   switch (pci->op) {
11548   case POC_CLRF: /* modifies STATUS (Z) */
11549     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11550       oldval = defmapCurr (list, sym1, pc);
11551       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11552         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11553         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11554       }
11555       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11556     }
11557     break;
11558
11559   case POC_SETF: /* SETF does not touch STATUS */
11560     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11561       oldval = defmapCurr (list, sym1, pc);
11562       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11563         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11564         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11565       }
11566       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11567     }
11568     break;
11569
11570   case POC_MOVLW: /* does not touch STATUS */
11571     oldval = defmapCurr (list, SPO_WREG, pc);
11572     if (pci->pcop->type == PO_LITERAL) {
11573       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11574       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11575     } else {
11576       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11577       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11578     }
11579     if (oldval && oldval->in_val == litnum) {
11580       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11581       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11582     }
11583     defmapUpdate (list, SPO_WREG, pc, litnum);
11584     break;
11585
11586   case POC_ANDLW: /* modifies STATUS (Z,N) */
11587   case POC_IORLW: /* modifies STATUS (Z,N) */
11588   case POC_XORLW: /* modifies STATUS (Z,N) */
11589     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11590     if (pci->pcop->type == PO_LITERAL) {
11591       int vallit = -1;
11592       lit = (unsigned char) PCOL(pci->pcop)->lit;
11593       val = defmapCurr (list, SPO_WREG, pc);
11594       if (val) vallit = litFromValnum (val->in_val);
11595       if (vallit != -1) {
11596         /* xxxLW <literal>, WREG contains a known literal */
11597         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11598         if (pci->op == POC_ANDLW) {
11599           lit &= vallit;
11600         } else if (pci->op == POC_IORLW) {
11601           lit |= vallit;
11602         } else if (pci->op == POC_XORLW) {
11603           lit ^= vallit;
11604         } else {
11605           assert (0 && "invalid operation");
11606         }
11607         if (vallit == lit) {
11608           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11609           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11610         }
11611         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11612       } // if
11613     }
11614     break;
11615
11616   case POC_LFSR:
11617     {
11618       /* check if old value matches new value */
11619       int lit;
11620       int ok = 1;
11621       assert (pci->pcop->type == PO_LITERAL);
11622
11623       lit = PCOL(pci->pcop)->lit;
11624
11625       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11626
11627       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11628         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11629       } else {
11630         /* cannot remove this LFSR */
11631         ok = 0;
11632       } // if
11633
11634       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11635       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11636         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11637       } else {
11638         ok = 0;
11639       } // if
11640
11641       if (ok) {
11642         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11643       }
11644     }
11645     break;
11646
11647   case POC_MOVWF: /* does not touch flags */
11648     /* find value of WREG */
11649     val = defmapCurr (list, SPO_WREG, pc);
11650     oldval = defmapCurr (list, sym1, pc);
11651     if (val) lit = litFromValnum (val->in_val);
11652     else lit = -1;
11653     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11654
11655     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11656       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11657       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11658       if (lit == 0) {
11659         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11660       } else {
11661         assert (lit == 0x0ff);
11662         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11663       }
11664       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11665       pic16_pCodeReplace (pc, newpc);
11666       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11667       pic16_fixDefmap (pc, newpc);
11668       pc = newpc;
11669
11670       /* This breaks the defmap chain's references to pCodes... fix it! */
11671       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11672       if (!val->acc.access.isWrite) {
11673         deleteDefmap (val);     // delete reference to WREG as in value
11674         val = NULL;
11675       } else {
11676         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11677       }
11678       oldval = PCI(pc)->pcflow->defmap;
11679       while (oldval) {
11680         if (oldval->pc == pc) oldval->pc = newpc;
11681           oldval = oldval->next;
11682       } // while
11683     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11684       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11685       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11686     }
11687     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11688     break;
11689
11690   case POC_MOVFW: /* modifies STATUS (Z,N) */
11691     /* find value of REG */
11692     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11693       val = defmapCurr (list, sym1, pc);
11694       oldval = defmapCurr (list, SPO_WREG, pc);
11695       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11696         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11697         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11698       } else {
11699           defmap_t *pred, *predpred;
11700           /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11701            * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11702            * This might allow removal of the first two assignments. */
11703           pred = defmapFindDef (list, sym1, pc);
11704           predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11705           if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11706                 && !pic16_isAlive (SPO_STATUS, pc))
11707           {
11708               newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11709
11710               if (pic16_debug_verbose || pic16_pcode_verbose) {
11711                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11712               } // if
11713               pic16_pCodeReplace (pc, newpc);
11714               defmapReplaceSymRef (pc, sym1, 0, 1);
11715               pic16_fixDefmap (pc, newpc);
11716               pc = newpc;
11717
11718               /* This breaks the defmap chain's references to pCodes... fix it! */
11719               if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11720               if (!val->acc.access.isWrite) {
11721                   deleteDefmap (val);   // delete reference to reg1 as in value
11722                   val = NULL;
11723               } else {
11724                   val->acc.access.isRead = 0;   // delete reference to reg1 as in value
11725               }
11726               oldval = PCI(pc)->pcflow->defmap;
11727               while (oldval) {
11728                   if (oldval->pc == pc) oldval->pc = newpc;
11729                   oldval = oldval->next;
11730               } // while
11731           } // if
11732       }
11733       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11734     }
11735     break;
11736
11737   case POC_MOVFF: /* does not touch STATUS */
11738     /* find value of REG */
11739     val = defmapCurr (list, sym1, pc);
11740     oldval = defmapCurr (list, sym2, pc);
11741     if (val) lit = litFromValnum (val->in_val);
11742     else lit = -1;
11743     newpc = NULL;
11744     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11745       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11746       if (lit == 0) {
11747         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11748       } else if (lit == 0x00ff) {
11749         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11750       } else {
11751         newpc = NULL;
11752       }
11753       if (newpc) {
11754         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11755         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11756         pic16_pCodeReplace (pc, newpc);
11757         defmapReplaceSymRef (pc, sym1, 0, 1);
11758         pic16_fixDefmap (pc, newpc);
11759         pc = newpc;
11760         break; // do not process instruction as MOVFF...
11761       }
11762     } else if (!isSpecial1 && !isSpecial2
11763                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11764                 && val && oldval && (val->in_val != 0)) {
11765       if (val->in_val == oldval->in_val) {
11766         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11767         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11768       } else {
11769         if (!pic16_isAlive (sym1, pc)) {
11770           defmap_t *copy = NULL;
11771           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11772            * This should help eliminate
11773            *   MOVFF A,B
11774            *   <do something not changing A or using B>
11775            *   MOVFF B,C
11776            *   <B is not alive anymore>
11777            * and turn it into
11778            *   <do something not changing A or using B>
11779            *   MOVFF A,C
11780            */
11781
11782           /* scan defmap for symbols storing sym1's value */
11783           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11784           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11785             /* unique reaching definition for sym found */
11786             if (copy->val && copy->val == val->in_val) {
11787               //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);
11788               if (copy->sym == SPO_WREG) {
11789                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11790               } else {
11791                 pCodeOp *pcop = NULL;
11792                 /* the code below fails if we try to replace
11793                  *   MOVFF PRODL, r0x03
11794                  *   MOVFF r0x03, PCLATU
11795                  * with
11796                  *   MOVFF PRODL, PCLATU
11797                  * as copy(PRODL) contains has pc==NULL, by name fails...
11798                  */
11799                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11800
11801                 if (copy->pc && PCI(copy->pc)->pcop)
11802                   pcop = PCI(copy->pc)->pcop;
11803 #if 0
11804                 /* This code is broken--see above. */
11805                 else
11806                 {
11807                   const char *symname = strFromSym(copy->sym);
11808
11809                   assert( symname );
11810                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11811                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11812                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11813                 }
11814 #endif
11815                 assert( pcop );
11816                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11817                         pcop,
11818                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11819               }
11820               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11821               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11822               pic16_pCodeReplace (pc, newpc);
11823               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11824               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11825               pic16_fixDefmap (pc, newpc);
11826               pc = newpc;
11827             }
11828           }
11829           deleteDefmapChain (&copy);
11830         }
11831       }
11832       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11833     }
11834     break;
11835
11836   default:
11837     /* cannot optimize */
11838     break;
11839   } // switch
11840 }
11841
11842 static void pic16_destructDF (pBlock *pb) {
11843   pCode *pc, *next;
11844
11845   if (!pb) return;
11846
11847   /* remove old defmaps */
11848   pc = pic16_findNextInstruction (pb->pcHead);
11849   while (pc) {
11850     next = pic16_findNextInstruction (pc->next);
11851
11852     assert (isPCI(pc) || isPCAD(pc));
11853     assert (PCI(pc)->pcflow);
11854     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11855     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11856     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11857
11858     pc = next;
11859   } // while
11860
11861   if (defmap_free || defmap_free_count) {
11862     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11863     freeDefmap (&defmap_free);
11864     defmap_free_count = 0;
11865   }
11866 }
11867
11868 /* Checks whether a pBlock contains ASMDIRs. */
11869 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11870   pCode *pc;
11871
11872   if (!pb) return 0;
11873
11874   pc = pic16_findNextInstruction (pb->pcHead);
11875   while (pc) {
11876     if (isPCAD(pc)) return 1;
11877
11878     pc = pic16_findNextInstruction (pc->next);
11879   } // while
11880
11881   /* no PCADs found */
11882   return 0;
11883 }
11884
11885 #if 1
11886 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11887 static int pic16_removeUnusedRegistersDF () {
11888   pCode *pc, *pc2;
11889   pBlock *pb;
11890   regs *reg1, *reg2, *reg3;
11891   set *seenRegs = NULL;
11892   int cond, i;
11893   int islocal, change = 0;
11894
11895   /* no pBlocks? */
11896   if (!the_pFile || !the_pFile->pbHead) return 0;
11897
11898   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11899     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11900 #if 1
11901     /* find set of using pCodes per register */
11902     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11903                     pc = pic16_findNextInstruction(pc->next)) {
11904
11905       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11906       reg1 = reg2 = NULL;
11907       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11908       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11909
11910       if (reg1) {
11911         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11912         addSetIfnotP (&seenRegs, reg1);
11913         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11914       }
11915       if (reg2) {
11916         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11917         addSetIfnotP (&seenRegs, reg2);
11918         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11919       }
11920     } // for pc
11921 #endif
11922     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11923       /* may not use pic16_regIsLocal() here -- in interrupt routines
11924        * WREG, PRODx, FSR0x must be saved */
11925       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11926       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11927         pc = pc2 = NULL;
11928         for (i=0; i < 2; i++) {
11929           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11930           if (!pc2) pc2 = pc;
11931           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11932           reg2 = pic16_getRegFromInstruction (pc);
11933           reg3 = pic16_getRegFromInstruction2 (pc);
11934           if (!reg2 || !reg3
11935               || (reg2->rIdx != pic16_stack_preinc->rIdx
11936                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11937           if (i == 1) {
11938             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11939             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11940             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11941             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11942           }
11943         } // for
11944       } // if
11945       deleteSet (&reg1->reglives.usedpCodes);
11946     } // for reg1
11947
11948     deleteSet (&seenRegs);
11949   } // for pb
11950
11951   return change;
11952 }
11953 #endif
11954
11955 /* Set up pCodeFlow's defmap_ts.
11956  * Needs correctly set up to/from fields. */
11957 static void pic16_createDF (pBlock *pb) {
11958   pCode *pc, *next;
11959   int change=0;
11960
11961   if (!pb) return;
11962
11963   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11964
11965   pic16_destructDF (pb);
11966
11967   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11968   if (pic16_pBlockHasAsmdirs (pb)) {
11969     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11970     return;
11971   }
11972
11973   /* integrity check -- we need to reach all flows to guarantee
11974    * correct data flow analysis (reaching definitions, aliveness) */
11975 #if 0
11976   if (!verifyAllFlowsReachable (pb)) {
11977     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11978     return;
11979   }
11980 #endif
11981
11982   /* establish new defmaps */
11983   pc = pic16_findNextInstruction (pb->pcHead);
11984   while (pc) {
11985     next = pic16_findNextInstruction (pc->next);
11986
11987     assert (PCI(pc)->pcflow);
11988     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11989
11990     pc = next;
11991   } // while
11992
11993   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11994   createReachingDefinitions (pb);
11995
11996 #if 1
11997   /* assign better valnums */
11998   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11999   pc = pic16_findNextInstruction (pb->pcHead);
12000   while (pc) {
12001     next = pic16_findNextInstruction (pc->next);
12002
12003     assert (PCI(pc)->pcflow);
12004     assignValnums (pc);
12005
12006     pc = next;
12007   } // while
12008 #endif
12009
12010 #if 1
12011   /* remove dead pCodes */
12012   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
12013   do {
12014     change = 0;
12015     pc = pic16_findNextInstruction (pb->pcHead);
12016     while (pc) {
12017       next = pic16_findNextInstruction (pc->next);
12018
12019       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
12020         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
12021       }
12022
12023       pc = next;
12024     } // while
12025   } while (change);
12026 #endif
12027 }
12028
12029 /* ======================================================================== */
12030 /* === VCG DUMPER ROUTINES ================================================ */
12031 /* ======================================================================== */
12032 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12033 hTab *dumpedNodes = NULL;
12034
12035 /** Dump VCG header into of. */
12036 static void pic16_vcg_init (FILE *of) {
12037   /* graph defaults */
12038   fprintf (of, "graph:{\n");
12039   fprintf (of, "title:\"graph1\"\n");
12040   fprintf (of, "label:\"graph1\"\n");
12041   fprintf (of, "color:white\n");
12042   fprintf (of, "textcolor:black\n");
12043   fprintf (of, "bordercolor:black\n");
12044   fprintf (of, "borderwidth:1\n");
12045   fprintf (of, "textmode:center\n");
12046
12047   fprintf (of, "layoutalgorithm:dfs\n");
12048   fprintf (of, "late_edge_labels:yes\n");
12049   fprintf (of, "display_edge_labels:yes\n");
12050   fprintf (of, "dirty_edge_labels:yes\n");
12051   fprintf (of, "finetuning:yes\n");
12052   fprintf (of, "ignoresingles:no\n");
12053   fprintf (of, "straight_phase:yes\n");
12054   fprintf (of, "priority_phase:yes\n");
12055   fprintf (of, "manhattan_edges:yes\n");
12056   fprintf (of, "smanhattan_edges:no\n");
12057   fprintf (of, "nearedges:no\n");
12058   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12059   fprintf (of, "port_sharing:no\n");
12060   fprintf (of, "arrowmode:free\n"); // fixed|free
12061   fprintf (of, "crossingphase2:yes\n");
12062   fprintf (of, "crossingoptimization:yes\n");
12063   fprintf (of, "edges:yes\n");
12064   fprintf (of, "nodes:yes\n");
12065   fprintf (of, "splines:no\n");
12066
12067   /* node defaults */
12068   fprintf (of, "node.color:lightyellow\n");
12069   fprintf (of, "node.textcolor:black\n");
12070   fprintf (of, "node.textmode:center\n");
12071   fprintf (of, "node.shape:box\n");
12072   fprintf (of, "node.bordercolor:black\n");
12073   fprintf (of, "node.borderwidth:1\n");
12074
12075   /* edge defaults */
12076   fprintf (of, "edge.textcolor:black\n");
12077   fprintf (of, "edge.color:black\n");
12078   fprintf (of, "edge.thickness:1\n");
12079   fprintf (of, "edge.arrowcolor:black\n");
12080   fprintf (of, "edge.backarrowcolor:black\n");
12081   fprintf (of, "edge.arrowsize:15\n");
12082   fprintf (of, "edge.backarrowsize:15\n");
12083   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12084   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12085   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12086
12087   fprintf (of, "\n");
12088
12089   /* prepare data structures */
12090   if (dumpedNodes) {
12091     hTabDeleteAll (dumpedNodes);
12092     dumpedNodes = NULL;
12093   }
12094   dumpedNodes = newHashTable (128);
12095 }
12096
12097 /** Dump VCG footer into of. */
12098 static void pic16_vcg_close (FILE *of) {
12099   fprintf (of, "}\n");
12100 }
12101
12102 #define BUF_SIZE 128
12103 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12104
12105 #if 0
12106 static int ptrcmp (const void *p1, const void *p2) {
12107   return p1 == p2;
12108 }
12109 #endif
12110
12111 /** Dump a pCode node as VCG to of. */
12112 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12113   char buf[BUF_SIZE];
12114
12115   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12116     // dumped already
12117     return;
12118   }
12119   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12120   //fprintf (stderr, "dumping %p\n", pc);
12121
12122   /* only dump pCodeInstructions and Flow nodes */
12123   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12124
12125   /* emit node */
12126   fprintf (of, "node:{");
12127   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12128   fprintf (of, "label:\"%s\n", pcTitle(pc));
12129   if (isPCFL(pc)) {
12130     fprintf (of, "<PCFLOW>");
12131   } else if (isPCI(pc) || isPCAD(pc)) {
12132     pc->print (of, pc);
12133   } else {
12134     fprintf (of, "<!PCI>");
12135   }
12136   fprintf (of, "\" ");
12137   fprintf (of, "}\n");
12138
12139   if (1 && isPCFL(pc)) {
12140     defmap_t *map, *prev;
12141     unsigned int i;
12142     map = PCFL(pc)->defmap;
12143     i=0;
12144     while (map) {
12145       if (map->sym != 0) {
12146         i++;
12147
12148         /* emit definition node */
12149         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12150         fprintf (of, "label:\"");
12151
12152         prev = map;
12153         do {
12154           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));
12155           prev = map;
12156           map = map->next;
12157         } while (map && prev->pc == map->pc);
12158         map = prev;
12159
12160         fprintf (of, "\" ");
12161
12162         fprintf (of, "color:green ");
12163         fprintf (of, "}\n");
12164
12165         /* emit edge to previous definition */
12166         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12167         if (i == 1) {
12168           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12169         } else {
12170           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12171         }
12172         fprintf (of, "color:green ");
12173         fprintf (of, "}\n");
12174
12175         if (map->pc) {
12176           pic16_vcg_dumpnode (map->pc, of);
12177           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12178           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12179         }
12180       }
12181       map = map->next;
12182     } // while
12183   }
12184
12185   /* emit additional nodes (e.g. operands) */
12186 }
12187
12188 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12189 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12190   char buf[BUF_SIZE];
12191   pCodeInstruction *pci;
12192   pBranch *curr;
12193   int i;
12194
12195   if (1 && isPCFL(pc)) {
12196     /* emit edges to flow successors */
12197     void *pcfl;
12198     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12199     pcfl = setFirstItem (PCFL(pc)->to);
12200     while (pcfl) {
12201       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12202       pic16_vcg_dumpnode (pc, of);
12203       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12204       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12205       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12206       pcfl = setNextItem (PCFL(pc)->to);
12207     } // while
12208   } // if
12209
12210   if (!isPCI(pc) && !isPCAD(pc)) return;
12211
12212   pci = PCI(pc);
12213
12214   /* emit control flow edges (forward only) */
12215   curr = pci->to;
12216   i=0;
12217   while (curr) {
12218     pic16_vcg_dumpnode (curr->pc, of);
12219     fprintf (of, "edge:{");
12220     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12221     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12222     fprintf (of, "color:red ");
12223     fprintf (of, "}\n");
12224     curr = curr->next;
12225   } // while
12226
12227 #if 1
12228   /* dump "flow" edge (link pCode according to pBlock order) */
12229   {
12230     pCode *pcnext;
12231     pcnext = pic16_findNextInstruction (pc->next);
12232     if (pcnext) {
12233       pic16_vcg_dumpnode (pcnext, of);
12234       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12235       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12236     }
12237   }
12238 #endif
12239
12240 #if 0
12241   /* emit flow */
12242   if (pci->pcflow) {
12243     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12244     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12245     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12246   }
12247 #endif
12248
12249   /* emit data flow edges (backward only) */
12250   /* TODO: gather data flow information... */
12251 }
12252
12253 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12254   pCode *pc;
12255
12256   if (!pb) return;
12257
12258   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12259   if (pic16_pBlockHasAsmdirs (pb)) {
12260     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12261     return;
12262   }
12263
12264   for (pc=pb->pcHead; pc; pc = pc->next) {
12265     pic16_vcg_dumpnode (pc, of);
12266   } // for pc
12267
12268   for (pc=pb->pcHead; pc; pc = pc->next) {
12269     pic16_vcg_dumpedges (pc, of);
12270   } // for pc
12271 }
12272
12273 static void pic16_vcg_dump_default (pBlock *pb) {
12274   FILE *of;
12275   char buf[BUF_SIZE];
12276   pCode *pc;
12277
12278   if (!pb) return;
12279
12280   /* get function name */
12281   pc = pb->pcHead;
12282   while (pc && !isPCF(pc)) pc = pc->next;
12283   if (pc) {
12284     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12285   } else {
12286     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12287   }
12288
12289   //fprintf (stderr, "now dumping %s\n", buf);
12290   of = fopen (buf, "w");
12291   pic16_vcg_init (of);
12292   pic16_vcg_dump (of, pb);
12293   pic16_vcg_close (of);
12294   fclose (of);
12295 }
12296 #endif
12297
12298 /*** END of helpers for pCode dataflow optimizations ***/