* src/pic/pcoderegs.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 int mnem2key(unsigned char const *mnem);
160
161 /****************************************************************/
162 /*                      Forward declarations                    */
163 /****************************************************************/
164
165 void pic16_unlinkpCode(pCode *pc);
166 #if 0
167 static void genericAnalyze(pCode *pc);
168 static void AnalyzeGOTO(pCode *pc);
169 static void AnalyzeSKIP(pCode *pc);
170 static void AnalyzeRETURN(pCode *pc);
171 #endif
172
173 static void genericDestruct(pCode *pc);
174 static void genericPrint(FILE *of,pCode *pc);
175
176 static void pCodePrintLabel(FILE *of, pCode *pc);
177 static void pCodePrintFunction(FILE *of, pCode *pc);
178 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
179 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
180 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
181 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
182 int pic16_pCodePeepMatchRule(pCode *pc);
183 static void pBlockStats(FILE *of, pBlock *pb);
184 static pBlock *newpBlock(void);
185 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
186 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
187 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
188 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
189 void OptimizeLocalRegs(void);
190 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
191
192 char *dumpPicOptype(PIC_OPTYPE type);
193
194 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
195 pCodeOp *pic16_popGetLit(int);
196 pCodeOp *pic16_popGetWithString(char *);
197 extern int inWparamList(char *s);
198
199 /** data flow optimization helpers **/
200 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
201 static void pic16_vcg_dump (FILE *of, pBlock *pb);
202 static void pic16_vcg_dump_default (pBlock *pb);
203 #endif
204 static int pic16_pCodeIsAlive (pCode *pc);
205 static void pic16_df_stats ();
206 static void pic16_createDF (pBlock *pb);
207 static int pic16_removeUnusedRegistersDF ();
208 static void pic16_destructDF (pBlock *pb);
209 static void releaseStack ();
210
211 /****************************************************************/
212 /*                    PIC Instructions                          */
213 /****************************************************************/
214
215 pCodeInstruction pic16_pciADDWF = {
216   {PC_OPCODE, NULL, NULL, 0, NULL,
217    //   genericAnalyze,
218    genericDestruct,
219    genericPrint},
220   POC_ADDWF,
221   "ADDWF",
222   2,
223   NULL, // from branch
224   NULL, // to branch
225   NULL, // label
226   NULL, // operand
227   NULL, // flow block
228   NULL, // C source
229   3,    // num ops
230   1,0,  // dest, bit instruction
231   0,0,  // branch, skip
232   0,    // literal operand
233   1,    // RAM access bit
234   0,    // fast call/return mode select bit
235   0,    // second memory operand
236   0,    // second literal operand
237   POC_NOP,
238   (PCC_W | PCC_REGISTER),   // inCond
239   (PCC_REGISTER | PCC_STATUS), // outCond
240   PCI_MAGIC
241 };
242
243 pCodeInstruction pic16_pciADDFW = {
244   {PC_OPCODE, NULL, NULL, 0, NULL,
245    //   genericAnalyze,
246    genericDestruct,
247    genericPrint},
248   POC_ADDFW,
249   "ADDWF",
250   2,
251   NULL, // from branch
252   NULL, // to branch
253   NULL, // label
254   NULL, // operand
255   NULL, // flow block
256   NULL, // C source
257   3,    // num ops
258   0,0,  // dest, bit instruction
259   0,0,  // branch, skip
260   0,    // literal operand
261   1,    // RAM access bit
262   0,    // fast call/return mode select bit
263   0,    // second memory operand
264   0,    // second literal operand
265   POC_NOP,
266   (PCC_W | PCC_REGISTER),   // inCond
267   (PCC_W | PCC_STATUS), // outCond
268   PCI_MAGIC
269 };
270
271 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
272   {PC_OPCODE, NULL, NULL, 0, NULL,
273    //   genericAnalyze,
274    genericDestruct,
275    genericPrint},
276   POC_ADDWFC,
277   "ADDWFC",
278   2,
279   NULL, // from branch
280   NULL, // to branch
281   NULL, // label
282   NULL, // operand
283   NULL, // flow block
284   NULL, // C source
285   3,    // num ops
286   1,0,  // dest, bit instruction
287   0,0,  // branch, skip
288   0,    // literal operand
289   1,    // RAM access bit
290   0,    // fast call/return mode select bit
291   0,    // second memory operand
292   0,    // second literal operand
293   POC_NOP,
294   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
295   (PCC_REGISTER | PCC_STATUS), // outCond
296   PCI_MAGIC
297 };
298
299 pCodeInstruction pic16_pciADDFWC = {
300   {PC_OPCODE, NULL, NULL, 0, NULL,
301    //   genericAnalyze,
302    genericDestruct,
303    genericPrint},
304   POC_ADDFWC,
305   "ADDWFC",
306   2,
307   NULL, // from branch
308   NULL, // to branch
309   NULL, // label
310   NULL, // operand
311   NULL, // flow block
312   NULL, // C source
313   3,    // num ops
314   0,0,  // dest, bit instruction
315   0,0,  // branch, skip
316   0,    // literal operand
317   1,    // RAM access bit
318   0,    // fast call/return mode select bit
319   0,    // second memory operand
320   0,    // second literal operand
321   POC_NOP,
322   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
323   (PCC_W | PCC_STATUS), // outCond
324   PCI_MAGIC
325 };
326
327 pCodeInstruction pic16_pciADDLW = {
328   {PC_OPCODE, NULL, NULL, 0, NULL,
329    //   genericAnalyze,
330    genericDestruct,
331    genericPrint},
332   POC_ADDLW,
333   "ADDLW",
334   2,
335   NULL, // from branch
336   NULL, // to branch
337   NULL, // label
338   NULL, // operand
339   NULL, // flow block
340   NULL, // C source
341   1,    // num ops
342   0,0,  // dest, bit instruction
343   0,0,  // branch, skip
344   1,    // literal operand
345   0,    // RAM access bit
346   0,    // fast call/return mode select bit
347   0,    // second memory operand
348   0,    // second literal operand
349   POC_NOP,
350   (PCC_W | PCC_LITERAL),   // inCond
351   (PCC_W | PCC_STATUS), // outCond
352   PCI_MAGIC
353 };
354
355 pCodeInstruction pic16_pciANDLW = {
356   {PC_OPCODE, NULL, NULL, 0, NULL,
357    //   genericAnalyze,
358    genericDestruct,
359    genericPrint},
360   POC_ANDLW,
361   "ANDLW",
362   2,
363   NULL, // from branch
364   NULL, // to branch
365   NULL, // label
366   NULL, // operand
367   NULL, // flow block
368   NULL, // C source
369   1,    // num ops
370   0,0,  // dest, bit instruction
371   0,0,  // branch, skip
372   1,    // literal operand
373   0,    // RAM access bit
374   0,    // fast call/return mode select bit
375   0,    // second memory operand
376   0,    // second literal operand
377   POC_NOP,
378   (PCC_W | PCC_LITERAL),   // inCond
379   (PCC_W | PCC_Z | PCC_N), // outCond
380   PCI_MAGIC
381 };
382
383 pCodeInstruction pic16_pciANDWF = {
384   {PC_OPCODE, NULL, NULL, 0, NULL,
385    //   genericAnalyze,
386    genericDestruct,
387    genericPrint},
388   POC_ANDWF,
389   "ANDWF",
390   2,
391   NULL, // from branch
392   NULL, // to branch
393   NULL, // label
394   NULL, // operand
395   NULL, // flow block
396   NULL, // C source
397   3,    // num ops
398   1,0,  // dest, bit instruction
399   0,0,  // branch, skip
400   0,    // literal operand
401   1,    // RAM access bit
402   0,    // fast call/return mode select bit
403   0,    // second memory operand
404   0,    // second literal operand
405   POC_NOP,
406   (PCC_W | PCC_REGISTER),   // inCond
407   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
408   PCI_MAGIC
409 };
410
411 pCodeInstruction pic16_pciANDFW = {
412   {PC_OPCODE, NULL, NULL, 0, NULL,
413    //   genericAnalyze,
414    genericDestruct,
415    genericPrint},
416   POC_ANDFW,
417   "ANDWF",
418   2,
419   NULL, // from branch
420   NULL, // to branch
421   NULL, // label
422   NULL, // operand
423   NULL, // flow block
424   NULL, // C source
425   3,    // num ops
426   0,0,  // dest, bit instruction
427   0,0,  // branch, skip
428   0,    // literal operand
429   1,    // RAM access bit
430   0,    // fast call/return mode select bit
431   0,    // second memory operand
432   0,    // second literal operand
433   POC_NOP,
434   (PCC_W | PCC_REGISTER),   // inCond
435   (PCC_W | PCC_Z | PCC_N) // outCond
436 };
437
438 pCodeInstruction pic16_pciBC = { // mdubuc - New
439   {PC_OPCODE, NULL, NULL, 0, NULL,
440    //   genericAnalyze,
441    genericDestruct,
442    genericPrint},
443   POC_BC,
444   "BC",
445   2,
446   NULL, // from branch
447   NULL, // to branch
448   NULL, // label
449   NULL, // operand
450   NULL, // flow block
451   NULL, // C source
452   1,    // num ops
453   0,0,  // dest, bit instruction
454   1,0,  // branch, skip
455   0,    // literal operand
456   0,    // RAM access bit
457   0,    // fast call/return mode select bit
458   0,    // second memory operand
459   0,    // second literal operand
460   POC_NOP,
461   (PCC_REL_ADDR | PCC_C),   // inCond
462   PCC_NONE,    // outCond
463   PCI_MAGIC
464 };
465
466 pCodeInstruction pic16_pciBCF = {
467   {PC_OPCODE, NULL, NULL, 0, NULL,
468    //   genericAnalyze,
469    genericDestruct,
470    genericPrint},
471   POC_BCF,
472   "BCF",
473   2,
474   NULL, // from branch
475   NULL, // to branch
476   NULL, // label
477   NULL, // operand
478   NULL, // flow block
479   NULL, // C source
480   3,    // num ops
481   1,1,  // dest, bit instruction
482   0,0,  // branch, skip
483   0,    // literal operand
484   1,    // RAM access bit
485   0,    // fast call/return mode select bit
486   0,    // second memory operand
487   0,    // second literal operand
488   POC_BSF,
489   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
490   PCC_REGISTER, // outCond
491   PCI_MAGIC
492 };
493
494 pCodeInstruction pic16_pciBN = { // mdubuc - New
495   {PC_OPCODE, NULL, NULL, 0, NULL,
496    //   genericAnalyze,
497    genericDestruct,
498    genericPrint},
499   POC_BN,
500   "BN",
501   2,
502   NULL, // from branch
503   NULL, // to branch
504   NULL, // label
505   NULL, // operand
506   NULL, // flow block
507   NULL, // C source
508   1,    // num ops
509   0,0,  // dest, bit instruction
510   1,0,  // branch, skip
511   0,    // literal operand
512   0,    // RAM access bit
513   0,    // fast call/return mode select bit
514   0,    // second memory operand
515   0,    // second literal operand
516   POC_NOP,
517   (PCC_REL_ADDR | PCC_N),   // inCond
518   PCC_NONE   , // outCond
519   PCI_MAGIC
520 };
521
522 pCodeInstruction pic16_pciBNC = { // mdubuc - New
523   {PC_OPCODE, NULL, NULL, 0, NULL,
524    //   genericAnalyze,
525    genericDestruct,
526    genericPrint},
527   POC_BNC,
528   "BNC",
529   2,
530   NULL, // from branch
531   NULL, // to branch
532   NULL, // label
533   NULL, // operand
534   NULL, // flow block
535   NULL, // C source
536   1,    // num ops
537   0,0,  // dest, bit instruction
538   1,0,  // branch, skip
539   0,    // literal operand
540   0,    // RAM access bit
541   0,    // fast call/return mode select bit
542   0,    // second memory operand
543   0,    // second literal operand
544   POC_NOP,
545   (PCC_REL_ADDR | PCC_C),   // inCond
546   PCC_NONE   , // outCond
547   PCI_MAGIC
548 };
549
550 pCodeInstruction pic16_pciBNN = { // mdubuc - New
551   {PC_OPCODE, NULL, NULL, 0, NULL,
552    //   genericAnalyze,
553    genericDestruct,
554    genericPrint},
555   POC_BNN,
556   "BNN",
557   2,
558   NULL, // from branch
559   NULL, // to branch
560   NULL, // label
561   NULL, // operand
562   NULL, // flow block
563   NULL, // C source
564   1,    // num ops
565   0,0,  // dest, bit instruction
566   1,0,  // branch, skip
567   0,    // literal operand
568   0,    // RAM access bit
569   0,    // fast call/return mode select bit
570   0,    // second memory operand
571   0,    // second literal operand
572   POC_NOP,
573   (PCC_REL_ADDR | PCC_N),   // inCond
574   PCC_NONE   , // outCond
575   PCI_MAGIC
576 };
577
578 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
579   {PC_OPCODE, NULL, NULL, 0, NULL,
580    //   genericAnalyze,
581    genericDestruct,
582    genericPrint},
583   POC_BNOV,
584   "BNOV",
585   2,
586   NULL, // from branch
587   NULL, // to branch
588   NULL, // label
589   NULL, // operand
590   NULL, // flow block
591   NULL, // C source
592   1,    // num ops
593   0,0,  // dest, bit instruction
594   1,0,  // branch, skip
595   0,    // literal operand
596   0,    // RAM access bit
597   0,    // fast call/return mode select bit
598   0,    // second memory operand
599   0,    // second literal operand
600   POC_NOP,
601   (PCC_REL_ADDR | PCC_OV),   // inCond
602   PCC_NONE   , // outCond
603   PCI_MAGIC
604 };
605
606 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
607   {PC_OPCODE, NULL, NULL, 0, NULL,
608    //   genericAnalyze,
609    genericDestruct,
610    genericPrint},
611   POC_BNZ,
612   "BNZ",
613   2,
614   NULL, // from branch
615   NULL, // to branch
616   NULL, // label
617   NULL, // operand
618   NULL, // flow block
619   NULL, // C source
620   1,    // num ops
621   0,0,  // dest, bit instruction
622   1,0,  // branch, skip
623   0,    // literal operand
624   0,    // RAM access bit
625   0,    // fast call/return mode select bit
626   0,    // second memory operand
627   0,    // second literal operand
628   POC_NOP,
629   (PCC_REL_ADDR | PCC_Z),   // inCond
630   PCC_NONE   , // outCond
631   PCI_MAGIC
632 };
633
634 pCodeInstruction pic16_pciBOV = { // mdubuc - New
635   {PC_OPCODE, NULL, NULL, 0, NULL,
636    //   genericAnalyze,
637    genericDestruct,
638    genericPrint},
639   POC_BOV,
640   "BOV",
641   2,
642   NULL, // from branch
643   NULL, // to branch
644   NULL, // label
645   NULL, // operand
646   NULL, // flow block
647   NULL, // C source
648   1,    // num ops
649   0,0,  // dest, bit instruction
650   1,0,  // branch, skip
651   0,    // literal operand
652   0,    // RAM access bit
653   0,    // fast call/return mode select bit
654   0,    // second memory operand
655   0,    // second literal operand
656   POC_NOP,
657   (PCC_REL_ADDR | PCC_OV),   // inCond
658   PCC_NONE , // outCond
659   PCI_MAGIC
660 };
661
662 pCodeInstruction pic16_pciBRA = { // mdubuc - New
663   {PC_OPCODE, NULL, NULL, 0, NULL,
664    //   genericAnalyze,
665    genericDestruct,
666    genericPrint},
667   POC_BRA,
668   "BRA",
669   2,
670   NULL, // from branch
671   NULL, // to branch
672   NULL, // label
673   NULL, // operand
674   NULL, // flow block
675   NULL, // C source
676   1,    // num ops
677   0,0,  // dest, bit instruction
678   1,0,  // branch, skip
679   0,    // literal operand
680   0,    // RAM access bit
681   0,    // fast call/return mode select bit
682   0,    // second memory operand
683   0,    // second literal operand
684   POC_NOP,
685   PCC_REL_ADDR,   // inCond
686   PCC_NONE   , // outCond
687   PCI_MAGIC
688 };
689
690 pCodeInstruction pic16_pciBSF = {
691   {PC_OPCODE, NULL, NULL, 0, NULL,
692    //   genericAnalyze,
693    genericDestruct,
694    genericPrint},
695   POC_BSF,
696   "BSF",
697   2,
698   NULL, // from branch
699   NULL, // to branch
700   NULL, // label
701   NULL, // operand
702   NULL, // flow block
703   NULL, // C source
704   3,    // num ops
705   1,1,  // dest, bit instruction
706   0,0,  // branch, skip
707   0,    // literal operand
708   1,    // RAM access bit
709   0,    // fast call/return mode select bit
710   0,    // second memory operand
711   0,    // second literal operand
712   POC_BCF,
713   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
714   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
715   PCI_MAGIC
716 };
717
718 pCodeInstruction pic16_pciBTFSC = {
719   {PC_OPCODE, NULL, NULL, 0, NULL,
720    //   AnalyzeSKIP,
721    genericDestruct,
722    genericPrint},
723   POC_BTFSC,
724   "BTFSC",
725   2,
726   NULL, // from branch
727   NULL, // to branch
728   NULL, // label
729   NULL, // operand
730   NULL, // flow block
731   NULL, // C source
732   3,    // num ops
733   0,1,  // dest, bit instruction
734   1,1,  // branch, skip
735   0,    // literal operand
736   1,    // RAM access bit
737   0,    // fast call/return mode select bit
738   0,    // second memory operand
739   0,    // second literal operand
740   POC_BTFSS,
741   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
742   PCC_EXAMINE_PCOP, // outCond
743   PCI_MAGIC
744 };
745
746 pCodeInstruction pic16_pciBTFSS = {
747   {PC_OPCODE, NULL, NULL, 0, NULL,
748    //   AnalyzeSKIP,
749    genericDestruct,
750    genericPrint},
751   POC_BTFSS,
752   "BTFSS",
753   2,
754   NULL, // from branch
755   NULL, // to branch
756   NULL, // label
757   NULL, // operand
758   NULL, // flow block
759   NULL, // C source
760   3,    // num ops
761   0,1,  // dest, bit instruction
762   1,1,  // branch, skip
763   0,    // literal operand
764   1,    // RAM access bit
765   0,    // fast call/return mode select bit
766   0,    // second memory operand
767   0,    // second literal operand
768   POC_BTFSC,
769   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
770   PCC_EXAMINE_PCOP, // outCond
771   PCI_MAGIC
772 };
773
774 pCodeInstruction pic16_pciBTG = { // mdubuc - New
775   {PC_OPCODE, NULL, NULL, 0, NULL,
776    //   genericAnalyze,
777    genericDestruct,
778    genericPrint},
779   POC_BTG,
780   "BTG",
781   2,
782   NULL, // from branch
783   NULL, // to branch
784   NULL, // label
785   NULL, // operand
786   NULL, // flow block
787   NULL, // C source
788   3,    // num ops
789   0,1,  // dest, bit instruction
790   0,0,  // branch, skip
791   0,    // literal operand
792   1,    // RAM access bit
793   0,    // fast call/return mode select bit
794   0,    // second memory operand
795   0,    // second literal operand
796   POC_NOP,
797   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
798   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
799   PCI_MAGIC
800 };
801
802 pCodeInstruction pic16_pciBZ = { // mdubuc - New
803   {PC_OPCODE, NULL, NULL, 0, NULL,
804    //   genericAnalyze,
805    genericDestruct,
806    genericPrint},
807   POC_BZ,
808   "BZ",
809   2,
810   NULL, // from branch
811   NULL, // to branch
812   NULL, // label
813   NULL, // operand
814   NULL, // flow block
815   NULL, // C source
816   1,    // num ops
817   0,0,  // dest, bit instruction
818   1,0,  // branch, skip
819   0,    // literal operand
820   0,    // RAM access bit
821   0,    // fast call/return mode select bit
822   0,    // second memory operand
823   0,    // second literal operand
824   POC_NOP,
825   (PCC_REL_ADDR | PCC_Z),   // inCond
826   PCC_NONE, // outCond
827   PCI_MAGIC
828 };
829
830 pCodeInstruction pic16_pciCALL = {
831   {PC_OPCODE, NULL, NULL, 0, NULL,
832    //   genericAnalyze,
833    genericDestruct,
834    genericPrint},
835   POC_CALL,
836   "CALL",
837   4,
838   NULL, // from branch
839   NULL, // to branch
840   NULL, // label
841   NULL, // operand
842   NULL, // flow block
843   NULL, // C source
844   2,    // num ops
845   0,0,  // dest, bit instruction
846   1,0,  // branch, skip
847   0,    // literal operand
848   0,    // RAM access bit
849   1,    // fast call/return mode select bit
850   0,    // second memory operand
851   0,    // second literal operand
852   POC_NOP,
853   PCC_NONE, // inCond
854   PCC_NONE, // outCond
855   PCI_MAGIC
856 };
857
858 pCodeInstruction pic16_pciCOMF = {
859   {PC_OPCODE, NULL, NULL, 0, NULL,
860    //   genericAnalyze,
861    genericDestruct,
862    genericPrint},
863   POC_COMF,
864   "COMF",
865   2,
866   NULL, // from branch
867   NULL, // to branch
868   NULL, // label
869   NULL, // operand
870   NULL, // flow block
871   NULL, // C source
872   3,    // num ops
873   1,0,  // dest, bit instruction
874   0,0,  // branch, skip
875   0,    // literal operand
876   1,    // RAM access bit
877   0,    // fast call/return mode select bit
878   0,    // second memory operand
879   0,    // second literal operand
880   POC_NOP,
881   PCC_REGISTER,  // inCond
882   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
883   PCI_MAGIC
884 };
885
886 pCodeInstruction pic16_pciCOMFW = {
887   {PC_OPCODE, NULL, NULL, 0, NULL,
888    //   genericAnalyze,
889    genericDestruct,
890    genericPrint},
891   POC_COMFW,
892   "COMF",
893   2,
894   NULL, // from branch
895   NULL, // to branch
896   NULL, // label
897   NULL, // operand
898   NULL, // flow block
899   NULL, // C source
900   3,    // num ops
901   0,0,  // dest, bit instruction
902   0,0,  // branch, skip
903   0,    // literal operand
904   1,    // RAM access bit
905   0,    // fast call/return mode select bit
906   0,    // second memory operand
907   0,    // second literal operand
908   POC_NOP,
909   PCC_REGISTER,  // inCond
910   (PCC_W | PCC_Z | PCC_N) , // outCond
911   PCI_MAGIC
912 };
913
914 pCodeInstruction pic16_pciCLRF = {
915   {PC_OPCODE, NULL, NULL, 0, NULL,
916    //   genericAnalyze,
917    genericDestruct,
918    genericPrint},
919   POC_CLRF,
920   "CLRF",
921   2,
922   NULL, // from branch
923   NULL, // to branch
924   NULL, // label
925   NULL, // operand
926   NULL, // flow block
927   NULL, // C source
928   2,    // num ops
929   0,0,  // dest, bit instruction
930   0,0,  // branch, skip
931   0,    // literal operand
932   1,    // RAM access bit
933   0,    // fast call/return mode select bit
934   0,    // second memory operand
935   0,    // second literal operand
936   POC_NOP,
937   PCC_NONE, // inCond
938   (PCC_REGISTER | PCC_Z), // outCond
939   PCI_MAGIC
940 };
941
942 pCodeInstruction pic16_pciCLRWDT = {
943   {PC_OPCODE, NULL, NULL, 0, NULL,
944    //   genericAnalyze,
945    genericDestruct,
946    genericPrint},
947   POC_CLRWDT,
948   "CLRWDT",
949   2,
950   NULL, // from branch
951   NULL, // to branch
952   NULL, // label
953   NULL, // operand
954   NULL, // flow block
955   NULL, // C source
956   0,    // num ops
957   0,0,  // dest, bit instruction
958   0,0,  // branch, skip
959   0,    // literal operand
960   0,    // RAM access bit
961   0,    // fast call/return mode select bit
962   0,    // second memory operand
963   0,    // second literal operand
964   POC_NOP,
965   PCC_NONE, // inCond
966   PCC_NONE , // outCond
967   PCI_MAGIC
968 };
969
970 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
971   {PC_OPCODE, NULL, NULL, 0, NULL,
972    //   genericAnalyze,
973    genericDestruct,
974    genericPrint},
975   POC_CPFSEQ,
976   "CPFSEQ",
977   2,
978   NULL, // from branch
979   NULL, // to branch
980   NULL, // label
981   NULL, // operand
982   NULL, // flow block
983   NULL, // C source
984   2,    // num ops
985   0,0,  // dest, bit instruction
986   1,1,  // branch, skip
987   0,    // literal operand
988   1,    // RAM access bit
989   0,    // fast call/return mode select bit
990   0,    // second memory operand
991   0,    // second literal operand
992   POC_NOP,
993   (PCC_W | PCC_REGISTER), // inCond
994   PCC_NONE , // outCond
995   PCI_MAGIC
996 };
997
998 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
999   {PC_OPCODE, NULL, NULL, 0, NULL,
1000    //   genericAnalyze,
1001    genericDestruct,
1002    genericPrint},
1003   POC_CPFSGT,
1004   "CPFSGT",
1005   2,
1006   NULL, // from branch
1007   NULL, // to branch
1008   NULL, // label
1009   NULL, // operand
1010   NULL, // flow block
1011   NULL, // C source
1012   2,    // num ops
1013   0,0,  // dest, bit instruction
1014   1,1,  // branch, skip
1015   0,    // literal operand
1016   1,    // RAM access bit
1017   0,    // fast call/return mode select bit
1018   0,    // second memory operand
1019   0,    // second literal operand
1020   POC_NOP,
1021   (PCC_W | PCC_REGISTER), // inCond
1022   PCC_NONE , // outCond
1023   PCI_MAGIC
1024 };
1025
1026 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1027   {PC_OPCODE, NULL, NULL, 0, NULL,
1028    //   genericAnalyze,
1029    genericDestruct,
1030    genericPrint},
1031   POC_CPFSLT,
1032   "CPFSLT",
1033   2,
1034   NULL, // from branch
1035   NULL, // to branch
1036   NULL, // label
1037   NULL, // operand
1038   NULL, // flow block
1039   NULL, // C source
1040   2,    // num ops
1041   1,0,  // dest, bit instruction
1042   1,1,  // branch, skip
1043   0,    // literal operand
1044   1,    // RAM access bit
1045   0,    // fast call/return mode select bit
1046   0,    // second memory operand
1047   0,    // second literal operand
1048   POC_NOP,
1049   (PCC_W | PCC_REGISTER), // inCond
1050   PCC_NONE , // outCond
1051   PCI_MAGIC
1052 };
1053
1054 pCodeInstruction pic16_pciDAW = {
1055   {PC_OPCODE, NULL, NULL, 0, NULL,
1056    //   genericAnalyze,
1057    genericDestruct,
1058    genericPrint},
1059   POC_DAW,
1060   "DAW",
1061   2,
1062   NULL, // from branch
1063   NULL, // to branch
1064   NULL, // label
1065   NULL, // operand
1066   NULL, // flow block
1067   NULL, // C source
1068   0,    // num ops
1069   0,0,  // dest, bit instruction
1070   0,0,  // branch, skip
1071   0,    // literal operand
1072   0,    // RAM access bit
1073   0,    // fast call/return mode select bit
1074   0,    // second memory operand
1075   0,    // second literal operand
1076   POC_NOP,
1077   PCC_W, // inCond
1078   (PCC_W | PCC_C), // outCond
1079   PCI_MAGIC
1080 };
1081
1082 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1083   {PC_OPCODE, NULL, NULL, 0, NULL,
1084    //   genericAnalyze,
1085    genericDestruct,
1086    genericPrint},
1087   POC_DCFSNZ,
1088   "DCFSNZ",
1089   2,
1090   NULL, // from branch
1091   NULL, // to branch
1092   NULL, // label
1093   NULL, // operand
1094   NULL, // flow block
1095   NULL, // C source
1096   3,    // num ops
1097   1,0,  // dest, bit instruction
1098   1,1,  // branch, skip
1099   0,    // literal operand
1100   1,    // RAM access bit
1101   0,    // fast call/return mode select bit
1102   0,    // second memory operand
1103   0,    // second literal operand
1104   POC_NOP,
1105   PCC_REGISTER, // inCond
1106   PCC_REGISTER , // outCond
1107   PCI_MAGIC
1108 };
1109
1110 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1111   {PC_OPCODE, NULL, NULL, 0, NULL,
1112    //   genericAnalyze,
1113    genericDestruct,
1114    genericPrint},
1115   POC_DCFSNZW,
1116   "DCFSNZ",
1117   2,
1118   NULL, // from branch
1119   NULL, // to branch
1120   NULL, // label
1121   NULL, // operand
1122   NULL, // flow block
1123   NULL, // C source
1124   3,    // num ops
1125   0,0,  // dest, bit instruction
1126   1,1,  // branch, skip
1127   0,    // literal operand
1128   1,    // RAM access bit
1129   0,    // fast call/return mode select bit
1130   0,    // second memory operand
1131   0,    // second literal operand
1132   POC_NOP,
1133   PCC_REGISTER, // inCond
1134   PCC_W , // outCond
1135   PCI_MAGIC
1136 };
1137
1138 pCodeInstruction pic16_pciDECF = {
1139   {PC_OPCODE, NULL, NULL, 0, NULL,
1140    //   genericAnalyze,
1141    genericDestruct,
1142    genericPrint},
1143   POC_DECF,
1144   "DECF",
1145   2,
1146   NULL, // from branch
1147   NULL, // to branch
1148   NULL, // label
1149   NULL, // operand
1150   NULL, // flow block
1151   NULL, // C source
1152   3,    // num ops
1153   1,0,  // dest, bit instruction
1154   0,0,  // branch, skip
1155   0,    // literal operand
1156   1,    // RAM access bit
1157   0,    // fast call/return mode select bit
1158   0,    // second memory operand
1159   0,    // second literal operand
1160   POC_NOP,
1161   PCC_REGISTER,   // inCond
1162   (PCC_REGISTER | PCC_STATUS)  , // outCond
1163   PCI_MAGIC
1164 };
1165
1166 pCodeInstruction pic16_pciDECFW = {
1167   {PC_OPCODE, NULL, NULL, 0, NULL,
1168    //   genericAnalyze,
1169    genericDestruct,
1170    genericPrint},
1171   POC_DECFW,
1172   "DECF",
1173   2,
1174   NULL, // from branch
1175   NULL, // to branch
1176   NULL, // label
1177   NULL, // operand
1178   NULL, // flow block
1179   NULL, // C source
1180   3,    // num ops
1181   0,0,  // dest, bit instruction
1182   0,0,  // branch, skip
1183   0,    // literal operand
1184   1,    // RAM access bit
1185   0,    // fast call/return mode select bit
1186   0,    // second memory operand
1187   0,    // second literal operand
1188   POC_NOP,
1189   PCC_REGISTER,   // inCond
1190   (PCC_W | PCC_STATUS)  , // outCond
1191   PCI_MAGIC
1192 };
1193
1194 pCodeInstruction pic16_pciDECFSZ = {
1195   {PC_OPCODE, NULL, NULL, 0, NULL,
1196    //   AnalyzeSKIP,
1197    genericDestruct,
1198    genericPrint},
1199   POC_DECFSZ,
1200   "DECFSZ",
1201   2,
1202   NULL, // from branch
1203   NULL, // to branch
1204   NULL, // label
1205   NULL, // operand
1206   NULL, // flow block
1207   NULL, // C source
1208   3,    // num ops
1209   1,0,  // dest, bit instruction
1210   1,1,  // branch, skip
1211   0,    // literal operand
1212   1,    // RAM access bit
1213   0,    // fast call/return mode select bit
1214   0,    // second memory operand
1215   0,    // second literal operand
1216   POC_NOP,
1217   PCC_REGISTER,   // inCond
1218   PCC_REGISTER   , // outCond
1219   PCI_MAGIC
1220 };
1221
1222 pCodeInstruction pic16_pciDECFSZW = {
1223   {PC_OPCODE, NULL, NULL, 0, NULL,
1224    //   AnalyzeSKIP,
1225    genericDestruct,
1226    genericPrint},
1227   POC_DECFSZW,
1228   "DECFSZ",
1229   2,
1230   NULL, // from branch
1231   NULL, // to branch
1232   NULL, // label
1233   NULL, // operand
1234   NULL, // flow block
1235   NULL, // C source
1236   3,    // num ops
1237   0,0,  // dest, bit instruction
1238   1,1,  // branch, skip
1239   0,    // literal operand
1240   1,    // RAM access bit
1241   0,    // fast call/return mode select bit
1242   0,    // second memory operand
1243   0,    // second literal operand
1244   POC_NOP,
1245   PCC_REGISTER,   // inCond
1246   PCC_W          , // outCond
1247   PCI_MAGIC
1248 };
1249
1250 pCodeInstruction pic16_pciGOTO = {
1251   {PC_OPCODE, NULL, NULL, 0, NULL,
1252    //   AnalyzeGOTO,
1253    genericDestruct,
1254    genericPrint},
1255   POC_GOTO,
1256   "GOTO",
1257   4,
1258   NULL, // from branch
1259   NULL, // to branch
1260   NULL, // label
1261   NULL, // operand
1262   NULL, // flow block
1263   NULL, // C source
1264   1,    // num ops
1265   0,0,  // dest, bit instruction
1266   1,0,  // branch, skip
1267   0,    // literal operand
1268   0,    // RAM access bit
1269   0,    // fast call/return mode select bit
1270   0,    // second memory operand
1271   0,    // second literal operand
1272   POC_NOP,
1273   PCC_REL_ADDR,   // inCond
1274   PCC_NONE   , // outCond
1275   PCI_MAGIC
1276 };
1277
1278 pCodeInstruction pic16_pciINCF = {
1279   {PC_OPCODE, NULL, NULL, 0, NULL,
1280    //   genericAnalyze,
1281    genericDestruct,
1282    genericPrint},
1283   POC_INCF,
1284   "INCF",
1285   2,
1286   NULL, // from branch
1287   NULL, // to branch
1288   NULL, // label
1289   NULL, // operand
1290   NULL, // flow block
1291   NULL, // C source
1292   3,    // num ops
1293   1,0,  // dest, bit instruction
1294   0,0,  // branch, skip
1295   0,    // literal operand
1296   1,    // RAM access bit
1297   0,    // fast call/return mode select bit
1298   0,    // second memory operand
1299   0,    // second literal operand
1300   POC_NOP,
1301   PCC_REGISTER,   // inCond
1302   (PCC_REGISTER | PCC_STATUS), // outCond
1303   PCI_MAGIC
1304 };
1305
1306 pCodeInstruction pic16_pciINCFW = {
1307   {PC_OPCODE, NULL, NULL, 0, NULL,
1308    //   genericAnalyze,
1309    genericDestruct,
1310    genericPrint},
1311   POC_INCFW,
1312   "INCF",
1313   2,
1314   NULL, // from branch
1315   NULL, // to branch
1316   NULL, // label
1317   NULL, // operand
1318   NULL, // flow block
1319   NULL, // C source
1320   3,    // num ops
1321   0,0,  // dest, bit instruction
1322   0,0,  // branch, skip
1323   0,    // literal operand
1324   1,    // RAM access bit
1325   0,    // fast call/return mode select bit
1326   0,    // second memory operand
1327   0,    // second literal operand
1328   POC_NOP,
1329   PCC_REGISTER,   // inCond
1330   (PCC_W | PCC_STATUS)  , // outCond
1331   PCI_MAGIC
1332 };
1333
1334 pCodeInstruction pic16_pciINCFSZ = {
1335   {PC_OPCODE, NULL, NULL, 0, NULL,
1336    //   AnalyzeSKIP,
1337    genericDestruct,
1338    genericPrint},
1339   POC_INCFSZ,
1340   "INCFSZ",
1341   2,
1342   NULL, // from branch
1343   NULL, // to branch
1344   NULL, // label
1345   NULL, // operand
1346   NULL, // flow block
1347   NULL, // C source
1348   3,    // num ops
1349   1,0,  // dest, bit instruction
1350   1,1,  // branch, skip
1351   0,    // literal operand
1352   1,    // RAM access bit
1353   0,    // fast call/return mode select bit
1354   0,    // second memory operand
1355   0,    // second literal operand
1356   POC_INFSNZ,
1357   PCC_REGISTER,   // inCond
1358   PCC_REGISTER   , // outCond
1359   PCI_MAGIC
1360 };
1361
1362 pCodeInstruction pic16_pciINCFSZW = {
1363   {PC_OPCODE, NULL, NULL, 0, NULL,
1364    //   AnalyzeSKIP,
1365    genericDestruct,
1366    genericPrint},
1367   POC_INCFSZW,
1368   "INCFSZ",
1369   2,
1370   NULL, // from branch
1371   NULL, // to branch
1372   NULL, // label
1373   NULL, // operand
1374   NULL, // flow block
1375   NULL, // C source
1376   3,    // num ops
1377   0,0,  // dest, bit instruction
1378   1,1,  // branch, skip
1379   0,    // literal operand
1380   1,    // RAM access bit
1381   0,    // fast call/return mode select bit
1382   0,    // second memory operand
1383   0,    // second literal operand
1384   POC_INFSNZW,
1385   PCC_REGISTER,   // inCond
1386   PCC_W          , // outCond
1387   PCI_MAGIC
1388 };
1389
1390 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1391   {PC_OPCODE, NULL, NULL, 0, NULL,
1392    //   AnalyzeSKIP,
1393    genericDestruct,
1394    genericPrint},
1395   POC_INFSNZ,
1396   "INFSNZ",
1397   2,
1398   NULL, // from branch
1399   NULL, // to branch
1400   NULL, // label
1401   NULL, // operand
1402   NULL, // flow block
1403   NULL, // C source
1404   3,    // num ops
1405   1,0,  // dest, bit instruction
1406   1,1,  // branch, skip
1407   0,    // literal operand
1408   1,    // RAM access bit
1409   0,    // fast call/return mode select bit
1410   0,    // second memory operand
1411   0,    // second literal operand
1412   POC_INCFSZ,
1413   PCC_REGISTER,   // inCond
1414   PCC_REGISTER   , // outCond
1415   PCI_MAGIC
1416 };
1417
1418 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1419   {PC_OPCODE, NULL, NULL, 0, NULL,
1420    //   AnalyzeSKIP,
1421    genericDestruct,
1422    genericPrint},
1423   POC_INFSNZW,
1424   "INFSNZ",
1425   2,
1426   NULL, // from branch
1427   NULL, // to branch
1428   NULL, // label
1429   NULL, // operand
1430   NULL, // flow block
1431   NULL, // C source
1432   3,    // num ops
1433   0,0,  // dest, bit instruction
1434   1,1,  // branch, skip
1435   0,    // literal operand
1436   1,    // RAM access bit
1437   0,    // fast call/return mode select bit
1438   0,    // second memory operand
1439   0,    // second literal operand
1440   POC_INCFSZW,
1441   PCC_REGISTER,   // inCond
1442   PCC_W          , // outCond
1443   PCI_MAGIC
1444 };
1445
1446 pCodeInstruction pic16_pciIORWF = {
1447   {PC_OPCODE, NULL, NULL, 0, NULL,
1448    //   genericAnalyze,
1449    genericDestruct,
1450    genericPrint},
1451   POC_IORWF,
1452   "IORWF",
1453   2,
1454   NULL, // from branch
1455   NULL, // to branch
1456   NULL, // label
1457   NULL, // operand
1458   NULL, // flow block
1459   NULL, // C source
1460   3,    // num ops
1461   1,0,  // dest, bit instruction
1462   0,0,  // branch, skip
1463   0,    // literal operand
1464   1,    // RAM access bit
1465   0,    // fast call/return mode select bit
1466   0,    // second memory operand
1467   0,    // second literal operand
1468   POC_NOP,
1469   (PCC_W | PCC_REGISTER),   // inCond
1470   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1471   PCI_MAGIC
1472 };
1473
1474 pCodeInstruction pic16_pciIORFW = {
1475   {PC_OPCODE, NULL, NULL, 0, NULL,
1476    //   genericAnalyze,
1477    genericDestruct,
1478    genericPrint},
1479   POC_IORFW,
1480   "IORWF",
1481   2,
1482   NULL, // from branch
1483   NULL, // to branch
1484   NULL, // label
1485   NULL, // operand
1486   NULL, // flow block
1487   NULL, // C source
1488   3,    // num ops
1489   0,0,  // dest, bit instruction
1490   0,0,  // branch, skip
1491   0,    // literal operand
1492   1,    // RAM access bit
1493   0,    // fast call/return mode select bit
1494   0,    // second memory operand
1495   0,    // second literal operand
1496   POC_NOP,
1497   (PCC_W | PCC_REGISTER),   // inCond
1498   (PCC_W | PCC_Z | PCC_N), // outCond
1499   PCI_MAGIC
1500 };
1501
1502 pCodeInstruction pic16_pciIORLW = {
1503   {PC_OPCODE, NULL, NULL, 0, NULL,
1504    //   genericAnalyze,
1505    genericDestruct,
1506    genericPrint},
1507   POC_IORLW,
1508   "IORLW",
1509   2,
1510   NULL, // from branch
1511   NULL, // to branch
1512   NULL, // label
1513   NULL, // operand
1514   NULL, // flow block
1515   NULL, // C source
1516   1,    // num ops
1517   0,0,  // dest, bit instruction
1518   0,0,  // branch, skip
1519   1,    // literal operand
1520   0,    // RAM access bit
1521   0,    // fast call/return mode select bit
1522   0,    // second memory operand
1523   0,    // second literal operand
1524   POC_NOP,
1525   (PCC_W | PCC_LITERAL),   // inCond
1526   (PCC_W | PCC_Z | PCC_N), // outCond
1527   PCI_MAGIC
1528 };
1529
1530 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1531   {PC_OPCODE, NULL, NULL, 0, NULL,
1532    //   genericAnalyze,
1533    genericDestruct,
1534    genericPrint},
1535   POC_LFSR,
1536   "LFSR",
1537   4,
1538   NULL, // from branch
1539   NULL, // to branch
1540   NULL, // label
1541   NULL, // operand
1542   NULL, // flow block
1543   NULL, // C source
1544   2,    // num ops
1545   0,0,  // dest, bit instruction
1546   0,0,  // branch, skip
1547   1,    // literal operand
1548   0,    // RAM access bit
1549   0,    // fast call/return mode select bit
1550   0,    // second memory operand
1551   1,    // second literal operand
1552   POC_NOP,
1553   PCC_LITERAL, // inCond
1554   PCC_NONE, // outCond
1555   PCI_MAGIC
1556 };
1557
1558 pCodeInstruction pic16_pciMOVF = {
1559   {PC_OPCODE, NULL, NULL, 0, NULL,
1560    //   genericAnalyze,
1561    genericDestruct,
1562    genericPrint},
1563   POC_MOVF,
1564   "MOVF",
1565   2,
1566   NULL, // from branch
1567   NULL, // to branch
1568   NULL, // label
1569   NULL, // operand
1570   NULL, // flow block
1571   NULL, // C source
1572   3,    // num ops
1573   1,0,  // dest, bit instruction
1574   0,0,  // branch, skip
1575   0,    // literal operand
1576   1,    // RAM access bit
1577   0,    // fast call/return mode select bit
1578   0,    // second memory operand
1579   0,    // second literal operand
1580   POC_NOP,
1581   PCC_REGISTER,   // inCond
1582   (PCC_Z | PCC_N), // outCond
1583   PCI_MAGIC
1584 };
1585
1586 pCodeInstruction pic16_pciMOVFW = {
1587   {PC_OPCODE, NULL, NULL, 0, NULL,
1588    //   genericAnalyze,
1589    genericDestruct,
1590    genericPrint},
1591   POC_MOVFW,
1592   "MOVF",
1593   2,
1594   NULL, // from branch
1595   NULL, // to branch
1596   NULL, // label
1597   NULL, // operand
1598   NULL, // flow block
1599   NULL, // C source
1600   3,    // num ops
1601   0,0,  // dest, bit instruction
1602   0,0,  // branch, skip
1603   0,    // literal operand
1604   1,    // RAM access bit
1605   0,    // fast call/return mode select bit
1606   0,    // second memory operand
1607   0,    // second literal operand
1608   POC_NOP,
1609   PCC_REGISTER,   // inCond
1610   (PCC_W | PCC_N | PCC_Z), // outCond
1611   PCI_MAGIC
1612 };
1613
1614 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1615   {PC_OPCODE, NULL, NULL, 0, NULL,
1616    //   genericAnalyze,
1617    genericDestruct,
1618    genericPrint},
1619   POC_MOVFF,
1620   "MOVFF",
1621   4,
1622   NULL, // from branch
1623   NULL, // to branch
1624   NULL, // label
1625   NULL, // operand
1626   NULL, // flow block
1627   NULL, // C source
1628   2,    // num ops
1629   0,0,  // dest, bit instruction
1630   0,0,  // branch, skip
1631   0,    // literal operand
1632   0,    // RAM access bit
1633   0,    // fast call/return mode select bit
1634   1,    // second memory operand
1635   0,    // second literal operand
1636   POC_NOP,
1637   PCC_REGISTER,   // inCond
1638   PCC_REGISTER2, // outCond
1639   PCI_MAGIC
1640 };
1641
1642 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1643   {PC_OPCODE, NULL, NULL, 0, NULL,
1644    genericDestruct,
1645    genericPrint},
1646   POC_MOVLB,
1647   "MOVLB",
1648   2,
1649   NULL, // from branch
1650   NULL, // to branch
1651   NULL, // label
1652   NULL, // operand
1653   NULL, // flow block
1654   NULL, // C source
1655   1,    // num ops
1656   0,0,  // dest, bit instruction
1657   0,0,  // branch, skip
1658   1,    // literal operand
1659   0,    // RAM access bit
1660   0,    // fast call/return mode select bit
1661   0,    // second memory operand
1662   0,    // second literal operand
1663   POC_NOP,
1664   (PCC_NONE | PCC_LITERAL),   // inCond
1665   PCC_REGISTER, // outCond - BSR
1666   PCI_MAGIC
1667 };
1668
1669 pCodeInstruction pic16_pciMOVLW = {
1670   {PC_OPCODE, NULL, NULL, 0, NULL,
1671    genericDestruct,
1672    genericPrint},
1673   POC_MOVLW,
1674   "MOVLW",
1675   2,
1676   NULL, // from branch
1677   NULL, // to branch
1678   NULL, // label
1679   NULL, // operand
1680   NULL, // flow block
1681   NULL, // C source
1682   1,    // num ops
1683   0,0,  // dest, bit instruction
1684   0,0,  // branch, skip
1685   1,    // literal operand
1686   0,    // RAM access bit
1687   0,    // fast call/return mode select bit
1688   0,    // second memory operand
1689   0,    // second literal operand
1690   POC_NOP,
1691   (PCC_NONE | PCC_LITERAL),   // inCond
1692   PCC_W, // outCond
1693   PCI_MAGIC
1694 };
1695
1696 pCodeInstruction pic16_pciMOVWF = {
1697   {PC_OPCODE, NULL, NULL, 0, NULL,
1698    //   genericAnalyze,
1699    genericDestruct,
1700    genericPrint},
1701   POC_MOVWF,
1702   "MOVWF",
1703   2,
1704   NULL, // from branch
1705   NULL, // to branch
1706   NULL, // label
1707   NULL, // operand
1708   NULL, // flow block
1709   NULL, // C source
1710   2,    // num ops
1711   0,0,  // dest, bit instruction
1712   0,0,  // branch, skip
1713   0,    // literal operand
1714   1,    // RAM access bit
1715   0,    // fast call/return mode select bit
1716   0,    // second memory operand
1717   0,    // second literal operand
1718   POC_NOP,
1719   PCC_W,   // inCond
1720   PCC_REGISTER, // outCond
1721   PCI_MAGIC
1722 };
1723
1724 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1725   {PC_OPCODE, NULL, NULL, 0, NULL,
1726    genericDestruct,
1727    genericPrint},
1728   POC_MULLW,
1729   "MULLW",
1730   2,
1731   NULL, // from branch
1732   NULL, // to branch
1733   NULL, // label
1734   NULL, // operand
1735   NULL, // flow block
1736   NULL, // C source
1737   1,    // num ops
1738   0,0,  // dest, bit instruction
1739   0,0,  // branch, skip
1740   1,    // literal operand
1741   0,    // RAM access bit
1742   0,    // fast call/return mode select bit
1743   0,    // second memory operand
1744   0,    // second literal operand
1745   POC_NOP,
1746   (PCC_W | PCC_LITERAL),   // inCond
1747   PCC_NONE, // outCond - PROD
1748   PCI_MAGIC
1749 };
1750
1751 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1752   {PC_OPCODE, NULL, NULL, 0, NULL,
1753    genericDestruct,
1754    genericPrint},
1755   POC_MULWF,
1756   "MULWF",
1757   2,
1758   NULL, // from branch
1759   NULL, // to branch
1760   NULL, // label
1761   NULL, // operand
1762   NULL, // flow block
1763   NULL, // C source
1764   2,    // num ops
1765   0,0,  // dest, bit instruction
1766   0,0,  // branch, skip
1767   0,    // literal operand
1768   1,    // RAM access bit
1769   0,    // fast call/return mode select bit
1770   0,    // second memory operand
1771   0,    // second literal operand
1772   POC_NOP,
1773   (PCC_W | PCC_REGISTER),   // inCond
1774   PCC_REGISTER, // outCond - PROD
1775   PCI_MAGIC
1776 };
1777
1778 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1779   {PC_OPCODE, NULL, NULL, 0, NULL,
1780    genericDestruct,
1781    genericPrint},
1782   POC_NEGF,
1783   "NEGF",
1784   2,
1785   NULL, // from branch
1786   NULL, // to branch
1787   NULL, // label
1788   NULL, // operand
1789   NULL, // flow block
1790   NULL, // C source
1791   2,    // num ops
1792   0,0,  // dest, bit instruction
1793   0,0,  // branch, skip
1794   0,    // literal operand
1795   1,    // RAM access bit
1796   0,    // fast call/return mode select bit
1797   0,    // second memory operand
1798   0,    // second literal operand
1799   POC_NOP,
1800   PCC_REGISTER, // inCond
1801   (PCC_REGISTER | PCC_STATUS), // outCond
1802   PCI_MAGIC
1803 };
1804
1805 pCodeInstruction pic16_pciNOP = {
1806   {PC_OPCODE, NULL, NULL, 0, NULL,
1807    genericDestruct,
1808    genericPrint},
1809   POC_NOP,
1810   "NOP",
1811   2,
1812   NULL, // from branch
1813   NULL, // to branch
1814   NULL, // label
1815   NULL, // operand
1816   NULL, // flow block
1817   NULL, // C source
1818   0,    // num ops
1819   0,0,  // dest, bit instruction
1820   0,0,  // branch, skip
1821   0,    // literal operand
1822   0,    // RAM access bit
1823   0,    // fast call/return mode select bit
1824   0,    // second memory operand
1825   0,    // second literal operand
1826   POC_NOP,
1827   PCC_NONE,   // inCond
1828   PCC_NONE, // outCond
1829   PCI_MAGIC
1830 };
1831
1832 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1833   {PC_OPCODE, NULL, NULL, 0, NULL,
1834    genericDestruct,
1835    genericPrint},
1836   POC_POP,
1837   "POP",
1838   2,
1839   NULL, // from branch
1840   NULL, // to branch
1841   NULL, // label
1842   NULL, // operand
1843   NULL, // flow block
1844   NULL, // C source
1845   0,    // num ops
1846   0,0,  // dest, bit instruction
1847   0,0,  // branch, skip
1848   0,    // literal operand
1849   0,    // RAM access bit
1850   0,    // fast call/return mode select bit
1851   0,    // second memory operand
1852   0,    // second literal operand
1853   POC_NOP,
1854   PCC_NONE,  // inCond
1855   PCC_NONE  , // outCond
1856   PCI_MAGIC
1857 };
1858
1859 pCodeInstruction pic16_pciPUSH = {
1860   {PC_OPCODE, NULL, NULL, 0, NULL,
1861    genericDestruct,
1862    genericPrint},
1863   POC_PUSH,
1864   "PUSH",
1865   2,
1866   NULL, // from branch
1867   NULL, // to branch
1868   NULL, // label
1869   NULL, // operand
1870   NULL, // flow block
1871   NULL, // C source
1872   0,    // num ops
1873   0,0,  // dest, bit instruction
1874   0,0,  // branch, skip
1875   0,    // literal operand
1876   0,    // RAM access bit
1877   0,    // fast call/return mode select bit
1878   0,    // second memory operand
1879   0,    // second literal operand
1880   POC_NOP,
1881   PCC_NONE,  // inCond
1882   PCC_NONE  , // outCond
1883   PCI_MAGIC
1884 };
1885
1886 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1887   {PC_OPCODE, NULL, NULL, 0, NULL,
1888    genericDestruct,
1889    genericPrint},
1890   POC_RCALL,
1891   "RCALL",
1892   2,
1893   NULL, // from branch
1894   NULL, // to branch
1895   NULL, // label
1896   NULL, // operand
1897   NULL, // flow block
1898   NULL, // C source
1899   1,    // num ops
1900   0,0,  // dest, bit instruction
1901   1,0,  // branch, skip
1902   0,    // literal operand
1903   0,    // RAM access bit
1904   0,    // fast call/return mode select bit
1905   0,    // second memory operand
1906   0,    // second literal operand
1907   POC_NOP,
1908   PCC_REL_ADDR,  // inCond
1909   PCC_NONE  , // outCond
1910   PCI_MAGIC
1911 };
1912
1913 pCodeInstruction pic16_pciRETFIE = {
1914   {PC_OPCODE, NULL, NULL, 0, NULL,
1915    //   AnalyzeRETURN,
1916    genericDestruct,
1917    genericPrint},
1918   POC_RETFIE,
1919   "RETFIE",
1920   2,
1921   NULL, // from branch
1922   NULL, // to branch
1923   NULL, // label
1924   NULL, // operand
1925   NULL, // flow block
1926   NULL, // C source
1927   1,    // num ops
1928   0,0,  // dest, bit instruction
1929   1,0,  // branch, skip
1930   0,    // literal operand
1931   0,    // RAM access bit
1932   1,    // fast call/return mode select bit
1933   0,    // second memory operand
1934   0,    // second literal operand
1935   POC_NOP,
1936   PCC_NONE,   // inCond
1937   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1938   PCI_MAGIC
1939 };
1940
1941 pCodeInstruction pic16_pciRETLW = {
1942   {PC_OPCODE, NULL, NULL, 0, NULL,
1943    //   AnalyzeRETURN,
1944    genericDestruct,
1945    genericPrint},
1946   POC_RETLW,
1947   "RETLW",
1948   2,
1949   NULL, // from branch
1950   NULL, // to branch
1951   NULL, // label
1952   NULL, // operand
1953   NULL, // flow block
1954   NULL, // C source
1955   1,    // num ops
1956   0,0,  // dest, bit instruction
1957   1,0,  // branch, skip
1958   1,    // literal operand
1959   0,    // RAM access bit
1960   0,    // fast call/return mode select bit
1961   0,    // second memory operand
1962   0,    // second literal operand
1963   POC_NOP,
1964   PCC_LITERAL,   // inCond
1965   PCC_W, // outCond
1966   PCI_MAGIC
1967 };
1968
1969 pCodeInstruction pic16_pciRETURN = {
1970   {PC_OPCODE, NULL, NULL, 0, NULL,
1971    //   AnalyzeRETURN,
1972    genericDestruct,
1973    genericPrint},
1974   POC_RETURN,
1975   "RETURN",
1976   2,
1977   NULL, // from branch
1978   NULL, // to branch
1979   NULL, // label
1980   NULL, // operand
1981   NULL, // flow block
1982   NULL, // C source
1983   1,    // num ops
1984   0,0,  // dest, bit instruction
1985   1,0,  // branch, skip
1986   0,    // literal operand
1987   0,    // RAM access bit
1988   1,    // fast call/return mode select bit
1989   0,    // second memory operand
1990   0,    // second literal operand
1991   POC_NOP,
1992   PCC_NONE,   // inCond
1993   PCC_NONE, // outCond
1994   PCI_MAGIC
1995 };
1996 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1997   {PC_OPCODE, NULL, NULL, 0, NULL,
1998    //   genericAnalyze,
1999    genericDestruct,
2000    genericPrint},
2001   POC_RLCF,
2002   "RLCF",
2003   2,
2004   NULL, // from branch
2005   NULL, // to branch
2006   NULL, // label
2007   NULL, // operand
2008   NULL, // flow block
2009   NULL, // C source
2010   3,    // num ops
2011   1,0,  // dest, bit instruction
2012   0,0,  // branch, skip
2013   0,    // literal operand
2014   1,    // RAM access bit
2015   0,    // fast call/return mode select bit
2016   0,    // second memory operand
2017   0,    // second literal operand
2018   POC_NOP,
2019   (PCC_C | PCC_REGISTER),   // inCond
2020   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2021   PCI_MAGIC
2022 };
2023
2024 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2025   {PC_OPCODE, NULL, NULL, 0, NULL,
2026    //   genericAnalyze,
2027    genericDestruct,
2028    genericPrint},
2029   POC_RLCFW,
2030   "RLCF",
2031   2,
2032   NULL, // from branch
2033   NULL, // to branch
2034   NULL, // label
2035   NULL, // operand
2036   NULL, // flow block
2037   NULL, // C source
2038   3,    // num ops
2039   0,0,  // dest, bit instruction
2040   0,0,  // branch, skip
2041   0,    // literal operand
2042   1,    // RAM access bit
2043   0,    // fast call/return mode select bit
2044   0,    // second memory operand
2045   0,    // second literal operand
2046   POC_NOP,
2047   (PCC_C | PCC_REGISTER),   // inCond
2048   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2049   PCI_MAGIC
2050 };
2051
2052 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2053   {PC_OPCODE, NULL, NULL, 0, NULL,
2054    //   genericAnalyze,
2055    genericDestruct,
2056    genericPrint},
2057   POC_RLNCF,
2058   "RLNCF",
2059   2,
2060   NULL, // from branch
2061   NULL, // to branch
2062   NULL, // label
2063   NULL, // operand
2064   NULL, // flow block
2065   NULL, // C source
2066   3,    // num ops
2067   1,0,  // dest, bit instruction
2068   0,0,  // branch, skip
2069   0,    // literal operand
2070   1,    // RAM access bit
2071   0,    // fast call/return mode select bit
2072   0,    // second memory operand
2073   0,    // second literal operand
2074   POC_NOP,
2075   PCC_REGISTER,   // inCond
2076   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2077   PCI_MAGIC
2078 };
2079 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2080   {PC_OPCODE, NULL, NULL, 0, NULL,
2081    //   genericAnalyze,
2082    genericDestruct,
2083    genericPrint},
2084   POC_RLNCFW,
2085   "RLNCF",
2086   2,
2087   NULL, // from branch
2088   NULL, // to branch
2089   NULL, // label
2090   NULL, // operand
2091   NULL, // flow block
2092   NULL, // C source
2093   3,    // num ops
2094   0,0,  // dest, bit instruction
2095   0,0,  // branch, skip
2096   0,    // literal operand
2097   1,    // RAM access bit
2098   0,    // fast call/return mode select bit
2099   0,    // second memory operand
2100   0,    // second literal operand
2101   POC_NOP,
2102   PCC_REGISTER,   // inCond
2103   (PCC_W | PCC_Z | PCC_N), // outCond
2104   PCI_MAGIC
2105 };
2106 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2107   {PC_OPCODE, NULL, NULL, 0, NULL,
2108    //   genericAnalyze,
2109    genericDestruct,
2110    genericPrint},
2111   POC_RRCF,
2112   "RRCF",
2113   2,
2114   NULL, // from branch
2115   NULL, // to branch
2116   NULL, // label
2117   NULL, // operand
2118   NULL, // flow block
2119   NULL, // C source
2120   3,    // num ops
2121   1,0,  // dest, bit instruction
2122   0,0,  // branch, skip
2123   0,    // literal operand
2124   1,    // RAM access bit
2125   0,    // fast call/return mode select bit
2126   0,    // second memory operand
2127   0,    // second literal operand
2128   POC_NOP,
2129   (PCC_C | PCC_REGISTER),   // inCond
2130   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2131   PCI_MAGIC
2132 };
2133 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2134   {PC_OPCODE, NULL, NULL, 0, NULL,
2135    //   genericAnalyze,
2136    genericDestruct,
2137    genericPrint},
2138   POC_RRCFW,
2139   "RRCF",
2140   2,
2141   NULL, // from branch
2142   NULL, // to branch
2143   NULL, // label
2144   NULL, // operand
2145   NULL, // flow block
2146   NULL, // C source
2147   3,    // num ops
2148   0,0,  // dest, bit instruction
2149   0,0,  // branch, skip
2150   0,    // literal operand
2151   1,    // RAM access bit
2152   0,    // fast call/return mode select bit
2153   0,    // second memory operand
2154   0,    // second literal operand
2155   POC_NOP,
2156   (PCC_C | PCC_REGISTER),   // inCond
2157   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2158   PCI_MAGIC
2159 };
2160 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2161   {PC_OPCODE, NULL, NULL, 0, NULL,
2162    //   genericAnalyze,
2163    genericDestruct,
2164    genericPrint},
2165   POC_RRNCF,
2166   "RRNCF",
2167   2,
2168   NULL, // from branch
2169   NULL, // to branch
2170   NULL, // label
2171   NULL, // operand
2172   NULL, // flow block
2173   NULL, // C source
2174   3,    // num ops
2175   1,0,  // dest, bit instruction
2176   0,0,  // branch, skip
2177   0,    // literal operand
2178   1,    // RAM access bit
2179   0,    // fast call/return mode select bit
2180   0,    // second memory operand
2181   0,    // second literal operand
2182   POC_NOP,
2183   PCC_REGISTER,   // inCond
2184   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2185   PCI_MAGIC
2186 };
2187
2188 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2189   {PC_OPCODE, NULL, NULL, 0, NULL,
2190    //   genericAnalyze,
2191    genericDestruct,
2192    genericPrint},
2193   POC_RRNCFW,
2194   "RRNCF",
2195   2,
2196   NULL, // from branch
2197   NULL, // to branch
2198   NULL, // label
2199   NULL, // operand
2200   NULL, // flow block
2201   NULL, // C source
2202   3,    // num ops
2203   0,0,  // dest, bit instruction
2204   0,0,  // branch, skip
2205   0,    // literal operand
2206   1,    // RAM access bit
2207   0,    // fast call/return mode select bit
2208   0,    // second memory operand
2209   0,    // second literal operand
2210   POC_NOP,
2211   PCC_REGISTER,   // inCond
2212   (PCC_W | PCC_Z | PCC_N), // outCond
2213   PCI_MAGIC
2214 };
2215
2216 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2217   {PC_OPCODE, NULL, NULL, 0, NULL,
2218    //   genericAnalyze,
2219    genericDestruct,
2220    genericPrint},
2221   POC_SETF,
2222   "SETF",
2223   2,
2224   NULL, // from branch
2225   NULL, // to branch
2226   NULL, // label
2227   NULL, // operand
2228   NULL, // flow block
2229   NULL, // C source
2230   2,    // num ops
2231   0,0,  // dest, bit instruction
2232   0,0,  // branch, skip
2233   0,    // literal operand
2234   1,    // RAM access bit
2235   0,    // fast call/return mode select bit
2236   0,    // second memory operand
2237   0,    // second literal operand
2238   POC_NOP,
2239   PCC_NONE,  // inCond
2240   PCC_REGISTER  , // outCond
2241   PCI_MAGIC
2242 };
2243
2244 pCodeInstruction pic16_pciSUBLW = {
2245   {PC_OPCODE, NULL, NULL, 0, NULL,
2246    //   genericAnalyze,
2247    genericDestruct,
2248    genericPrint},
2249   POC_SUBLW,
2250   "SUBLW",
2251   2,
2252   NULL, // from branch
2253   NULL, // to branch
2254   NULL, // label
2255   NULL, // operand
2256   NULL, // flow block
2257   NULL, // C source
2258   1,    // num ops
2259   0,0,  // dest, bit instruction
2260   0,0,  // branch, skip
2261   1,    // literal operand
2262   0,    // RAM access bit
2263   0,    // fast call/return mode select bit
2264   0,    // second memory operand
2265   0,    // second literal operand
2266   POC_NOP,
2267   (PCC_W | PCC_LITERAL),   // inCond
2268   (PCC_W | PCC_STATUS), // outCond
2269   PCI_MAGIC
2270 };
2271
2272 pCodeInstruction pic16_pciSUBFWB = {
2273   {PC_OPCODE, NULL, NULL, 0, NULL,
2274    //   genericAnalyze,
2275    genericDestruct,
2276    genericPrint},
2277   POC_SUBFWB,
2278   "SUBFWB",
2279   2,
2280   NULL, // from branch
2281   NULL, // to branch
2282   NULL, // label
2283   NULL, // operand
2284   NULL, // flow block
2285   NULL, // C source
2286   3,    // num ops
2287   1,0,  // dest, bit instruction
2288   0,0,  // branch, skip
2289   0,    // literal operand
2290   1,    // RAM access bit
2291   0,    // fast call/return mode select bit
2292   0,    // second memory operand
2293   0,    // second literal operand
2294   POC_NOP,
2295   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2296   (PCC_W | PCC_STATUS), // outCond
2297   PCI_MAGIC
2298 };
2299
2300 pCodeInstruction pic16_pciSUBWF = {
2301   {PC_OPCODE, NULL, NULL, 0, NULL,
2302    //   genericAnalyze,
2303    genericDestruct,
2304    genericPrint},
2305   POC_SUBWF,
2306   "SUBWF",
2307   2,
2308   NULL, // from branch
2309   NULL, // to branch
2310   NULL, // label
2311   NULL, // operand
2312   NULL, // flow block
2313   NULL, // C source
2314   3,    // num ops
2315   1,0,  // dest, bit instruction
2316   0,0,  // branch, skip
2317   0,    // literal operand
2318   1,    // RAM access bit
2319   0,    // fast call/return mode select bit
2320   0,    // second memory operand
2321   0,    // second literal operand
2322   POC_NOP,
2323   (PCC_W | PCC_REGISTER),   // inCond
2324   (PCC_REGISTER | PCC_STATUS), // outCond
2325   PCI_MAGIC
2326 };
2327
2328 pCodeInstruction pic16_pciSUBFW = {
2329   {PC_OPCODE, NULL, NULL, 0, NULL,
2330    //   genericAnalyze,
2331    genericDestruct,
2332    genericPrint},
2333   POC_SUBFW,
2334   "SUBWF",
2335   2,
2336   NULL, // from branch
2337   NULL, // to branch
2338   NULL, // label
2339   NULL, // operand
2340   NULL, // flow block
2341   NULL, // C source
2342   3,    // num ops
2343   0,0,  // dest, bit instruction
2344   0,0,  // branch, skip
2345   0,    // literal operand
2346   1,    // RAM access bit
2347   0,    // fast call/return mode select bit
2348   0,    // second memory operand
2349   0,    // second literal operand
2350   POC_NOP,
2351   (PCC_W | PCC_REGISTER),   // inCond
2352   (PCC_W | PCC_STATUS), // outCond
2353   PCI_MAGIC
2354 };
2355
2356 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2357   {PC_OPCODE, NULL, NULL, 0, NULL,
2358    //   genericAnalyze,
2359    genericDestruct,
2360    genericPrint},
2361   POC_SUBFWB_D1,
2362   "SUBFWB",
2363   2,
2364   NULL, // from branch
2365   NULL, // to branch
2366   NULL, // label
2367   NULL, // operand
2368   NULL, // flow block
2369   NULL, // C source
2370   3,    // num ops
2371   1,0,  // dest, bit instruction
2372   0,0,  // branch, skip
2373   0,    // literal operand
2374   1,    // RAM access bit
2375   0,    // fast call/return mode select bit
2376   0,    // second memory operand
2377   0,    // second literal operand
2378   POC_NOP,
2379   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2380   (PCC_REGISTER | PCC_STATUS), // outCond
2381   PCI_MAGIC
2382 };
2383
2384 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2385   {PC_OPCODE, NULL, NULL, 0, NULL,
2386    //   genericAnalyze,
2387    genericDestruct,
2388    genericPrint},
2389   POC_SUBFWB_D0,
2390   "SUBFWB",
2391   2,
2392   NULL, // from branch
2393   NULL, // to branch
2394   NULL, // label
2395   NULL, // operand
2396   NULL, // flow block
2397   NULL, // C source
2398   3,    // num ops
2399   0,0,  // dest, bit instruction
2400   0,0,  // branch, skip
2401   0,    // literal operand
2402   1,    // RAM access bit
2403   0,    // fast call/return mode select bit
2404   0,    // second memory operand
2405   0,    // second literal operand
2406   POC_NOP,
2407   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2408   (PCC_W | PCC_STATUS), // outCond
2409   PCI_MAGIC
2410 };
2411
2412 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2413   {PC_OPCODE, NULL, NULL, 0, NULL,
2414    //   genericAnalyze,
2415    genericDestruct,
2416    genericPrint},
2417   POC_SUBWFB_D1,
2418   "SUBWFB",
2419   2,
2420   NULL, // from branch
2421   NULL, // to branch
2422   NULL, // label
2423   NULL, // operand
2424   NULL, // flow block
2425   NULL, // C source
2426   3,    // num ops
2427   1,0,  // dest, bit instruction
2428   0,0,  // branch, skip
2429   0,    // literal operand
2430   1,    // RAM access bit
2431   0,    // fast call/return mode select bit
2432   0,    // second memory operand
2433   0,    // second literal operand
2434   POC_NOP,
2435   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2436   (PCC_REGISTER | PCC_STATUS), // outCond
2437   PCI_MAGIC
2438 };
2439
2440 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2441   {PC_OPCODE, NULL, NULL, 0, NULL,
2442    //   genericAnalyze,
2443    genericDestruct,
2444    genericPrint},
2445   POC_SUBWFB_D0,
2446   "SUBWFB",
2447   2,
2448   NULL, // from branch
2449   NULL, // to branch
2450   NULL, // label
2451   NULL, // operand
2452   NULL, // flow block
2453   NULL, // C source
2454   3,    // num ops
2455   0,0,  // dest, bit instruction
2456   0,0,  // branch, skip
2457   0,    // literal operand
2458   1,    // RAM access bit
2459   0,    // fast call/return mode select bit
2460   0,    // second memory operand
2461   0,    // second literal operand
2462   POC_NOP,
2463   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2464   (PCC_W | PCC_STATUS), // outCond
2465   PCI_MAGIC
2466 };
2467
2468 pCodeInstruction pic16_pciSWAPF = {
2469   {PC_OPCODE, NULL, NULL, 0, NULL,
2470    //   genericAnalyze,
2471    genericDestruct,
2472    genericPrint},
2473   POC_SWAPF,
2474   "SWAPF",
2475   2,
2476   NULL, // from branch
2477   NULL, // to branch
2478   NULL, // label
2479   NULL, // operand
2480   NULL, // flow block
2481   NULL, // C source
2482   3,    // num ops
2483   1,0,  // dest, bit instruction
2484   0,0,  // branch, skip
2485   0,    // literal operand
2486   1,    // RAM access bit
2487   0,    // fast call/return mode select bit
2488   0,    // second memory operand
2489   0,    // second literal operand
2490   POC_NOP,
2491   (PCC_REGISTER),   // inCond
2492   (PCC_REGISTER), // outCond
2493   PCI_MAGIC
2494 };
2495
2496 pCodeInstruction pic16_pciSWAPFW = {
2497   {PC_OPCODE, NULL, NULL, 0, NULL,
2498    //   genericAnalyze,
2499    genericDestruct,
2500    genericPrint},
2501   POC_SWAPFW,
2502   "SWAPF",
2503   2,
2504   NULL, // from branch
2505   NULL, // to branch
2506   NULL, // label
2507   NULL, // operand
2508   NULL, // flow block
2509   NULL, // C source
2510   3,    // num ops
2511   0,0,  // dest, bit instruction
2512   0,0,  // branch, skip
2513   0,    // literal operand
2514   1,    // RAM access bit
2515   0,    // fast call/return mode select bit
2516   0,    // second memory operand
2517   0,    // second literal operand
2518   POC_NOP,
2519   (PCC_REGISTER),   // inCond
2520   (PCC_W), // outCond
2521   PCI_MAGIC
2522 };
2523
2524 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2525   {PC_OPCODE, NULL, NULL, 0, NULL,
2526    genericDestruct,
2527    genericPrint},
2528   POC_TBLRD,
2529   "TBLRD*",
2530   2,
2531   NULL, // from branch
2532   NULL, // to branch
2533   NULL, // label
2534   NULL, // operand
2535   NULL, // flow block
2536   NULL, // C source
2537   0,    // num ops
2538   0,0,  // dest, bit instruction
2539   0,0,  // branch, skip
2540   0,    // literal operand
2541   0,    // RAM access bit
2542   0,    // fast call/return mode select bit
2543   0,    // second memory operand
2544   0,    // second literal operand
2545   POC_NOP,
2546   PCC_NONE,  // inCond
2547   PCC_NONE  , // outCond
2548   PCI_MAGIC
2549 };
2550
2551 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2552   {PC_OPCODE, NULL, NULL, 0, NULL,
2553    genericDestruct,
2554    genericPrint},
2555   POC_TBLRD_POSTINC,
2556   "TBLRD*+",
2557   2,
2558   NULL, // from branch
2559   NULL, // to branch
2560   NULL, // label
2561   NULL, // operand
2562   NULL, // flow block
2563   NULL, // C source
2564   0,    // num ops
2565   0,0,  // dest, bit instruction
2566   0,0,  // branch, skip
2567   0,    // literal operand
2568   0,    // RAM access bit
2569   0,    // fast call/return mode select bit
2570   0,    // second memory operand
2571   0,    // second literal operand
2572   POC_NOP,
2573   PCC_NONE,  // inCond
2574   PCC_NONE  , // outCond
2575   PCI_MAGIC
2576 };
2577
2578 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2579   {PC_OPCODE, NULL, NULL, 0, NULL,
2580    genericDestruct,
2581    genericPrint},
2582   POC_TBLRD_POSTDEC,
2583   "TBLRD*-",
2584   2,
2585   NULL, // from branch
2586   NULL, // to branch
2587   NULL, // label
2588   NULL, // operand
2589   NULL, // flow block
2590   NULL, // C source
2591   0,    // num ops
2592   0,0,  // dest, bit instruction
2593   0,0,  // branch, skip
2594   0,    // literal operand
2595   0,    // RAM access bit
2596   0,    // fast call/return mode select bit
2597   0,    // second memory operand
2598   0,    // second literal operand
2599   POC_NOP,
2600   PCC_NONE,  // inCond
2601   PCC_NONE  , // outCond
2602   PCI_MAGIC
2603 };
2604
2605 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2606   {PC_OPCODE, NULL, NULL, 0, NULL,
2607    genericDestruct,
2608    genericPrint},
2609   POC_TBLRD_PREINC,
2610   "TBLRD+*",
2611   2,
2612   NULL, // from branch
2613   NULL, // to branch
2614   NULL, // label
2615   NULL, // operand
2616   NULL, // flow block
2617   NULL, // C source
2618   0,    // num ops
2619   0,0,  // dest, bit instruction
2620   0,0,  // branch, skip
2621   0,    // literal operand
2622   0,    // RAM access bit
2623   0,    // fast call/return mode select bit
2624   0,    // second memory operand
2625   0,    // second literal operand
2626   POC_NOP,
2627   PCC_NONE,  // inCond
2628   PCC_NONE  , // outCond
2629   PCI_MAGIC
2630 };
2631
2632 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2633   {PC_OPCODE, NULL, NULL, 0, NULL,
2634    genericDestruct,
2635    genericPrint},
2636   POC_TBLWT,
2637   "TBLWT*",
2638   2,
2639   NULL, // from branch
2640   NULL, // to branch
2641   NULL, // label
2642   NULL, // operand
2643   NULL, // flow block
2644   NULL, // C source
2645   0,    // num ops
2646   0,0,  // dest, bit instruction
2647   0,0,  // branch, skip
2648   0,    // literal operand
2649   0,    // RAM access bit
2650   0,    // fast call/return mode select bit
2651   0,    // second memory operand
2652   0,    // second literal operand
2653   POC_NOP,
2654   PCC_NONE,  // inCond
2655   PCC_NONE  , // outCond
2656   PCI_MAGIC
2657 };
2658
2659 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2660   {PC_OPCODE, NULL, NULL, 0, NULL,
2661    genericDestruct,
2662    genericPrint},
2663   POC_TBLWT_POSTINC,
2664   "TBLWT*+",
2665   2,
2666   NULL, // from branch
2667   NULL, // to branch
2668   NULL, // label
2669   NULL, // operand
2670   NULL, // flow block
2671   NULL, // C source
2672   0,    // num ops
2673   0,0,  // dest, bit instruction
2674   0,0,  // branch, skip
2675   0,    // literal operand
2676   0,    // RAM access bit
2677   0,    // fast call/return mode select bit
2678   0,    // second memory operand
2679   0,    // second literal operand
2680   POC_NOP,
2681   PCC_NONE,  // inCond
2682   PCC_NONE  , // outCond
2683   PCI_MAGIC
2684 };
2685
2686 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2687   {PC_OPCODE, NULL, NULL, 0, NULL,
2688    genericDestruct,
2689    genericPrint},
2690   POC_TBLWT_POSTDEC,
2691   "TBLWT*-",
2692   2,
2693   NULL, // from branch
2694   NULL, // to branch
2695   NULL, // label
2696   NULL, // operand
2697   NULL, // flow block
2698   NULL, // C source
2699   0,    // num ops
2700   0,0,  // dest, bit instruction
2701   0,0,  // branch, skip
2702   0,    // literal operand
2703   0,    // RAM access bit
2704   0,    // fast call/return mode select bit
2705   0,    // second memory operand
2706   0,    // second literal operand
2707   POC_NOP,
2708   PCC_NONE,  // inCond
2709   PCC_NONE  , // outCond
2710   PCI_MAGIC
2711 };
2712
2713 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2714   {PC_OPCODE, NULL, NULL, 0, NULL,
2715    genericDestruct,
2716    genericPrint},
2717   POC_TBLWT_PREINC,
2718   "TBLWT+*",
2719   2,
2720   NULL, // from branch
2721   NULL, // to branch
2722   NULL, // label
2723   NULL, // operand
2724   NULL, // flow block
2725   NULL, // C source
2726   0,    // num ops
2727   0,0,  // dest, bit instruction
2728   0,0,  // branch, skip
2729   0,    // literal operand
2730   0,    // RAM access bit
2731   0,    // fast call/return mode select bit
2732   0,    // second memory operand
2733   0,    // second literal operand
2734   POC_NOP,
2735   PCC_NONE,  // inCond
2736   PCC_NONE  , // outCond
2737   PCI_MAGIC
2738 };
2739
2740 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2741   {PC_OPCODE, NULL, NULL, 0, NULL,
2742    //   genericAnalyze,
2743    genericDestruct,
2744    genericPrint},
2745   POC_TSTFSZ,
2746   "TSTFSZ",
2747   2,
2748   NULL, // from branch
2749   NULL, // to branch
2750   NULL, // label
2751   NULL, // operand
2752   NULL, // flow block
2753   NULL, // C source
2754   2,    // num ops
2755   0,0,  // dest, bit instruction
2756   1,1,  // branch, skip
2757   0,    // literal operand
2758   1,    // RAM access bit
2759   0,    // fast call/return mode select bit
2760   0,    // second memory operand
2761   0,    // second literal operand
2762   POC_NOP,
2763   PCC_REGISTER,   // inCond
2764   PCC_NONE, // outCond
2765   PCI_MAGIC
2766 };
2767
2768 pCodeInstruction pic16_pciXORWF = {
2769   {PC_OPCODE, NULL, NULL, 0, NULL,
2770    //   genericAnalyze,
2771    genericDestruct,
2772    genericPrint},
2773   POC_XORWF,
2774   "XORWF",
2775   2,
2776   NULL, // from branch
2777   NULL, // to branch
2778   NULL, // label
2779   NULL, // operand
2780   NULL, // flow block
2781   NULL, // C source
2782   3,    // num ops
2783   1,0,  // dest, bit instruction
2784   0,0,  // branch, skip
2785   0,    // literal operand
2786   1,    // RAM access bit
2787   0,    // fast call/return mode select bit
2788   0,    // second memory operand
2789   0,    // second literal operand
2790   POC_NOP,
2791   (PCC_W | PCC_REGISTER),   // inCond
2792   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2793   PCI_MAGIC
2794 };
2795
2796 pCodeInstruction pic16_pciXORFW = {
2797   {PC_OPCODE, NULL, NULL, 0, NULL,
2798    //   genericAnalyze,
2799    genericDestruct,
2800    genericPrint},
2801   POC_XORFW,
2802   "XORWF",
2803   2,
2804   NULL, // from branch
2805   NULL, // to branch
2806   NULL, // label
2807   NULL, // operand
2808   NULL, // flow block
2809   NULL, // C source
2810   3,    // num ops
2811   0,0,  // dest, bit instruction
2812   0,0,  // branch, skip
2813   0,    // literal operand
2814   1,    // RAM access bit
2815   0,    // fast call/return mode select bit
2816   0,    // second memory operand
2817   0,    // second literal operand
2818   POC_NOP,
2819   (PCC_W | PCC_REGISTER),   // inCond
2820   (PCC_W | PCC_Z | PCC_N), // outCond
2821   PCI_MAGIC
2822 };
2823
2824 pCodeInstruction pic16_pciXORLW = {
2825   {PC_OPCODE, NULL, NULL, 0, NULL,
2826    //   genericAnalyze,
2827    genericDestruct,
2828    genericPrint},
2829   POC_XORLW,
2830   "XORLW",
2831   2,
2832   NULL, // from branch
2833   NULL, // to branch
2834   NULL, // label
2835   NULL, // operand
2836   NULL, // flow block
2837   NULL, // C source
2838   1,    // num ops
2839   0,0,  // dest, bit instruction
2840   0,0,  // branch, skip
2841   1,    // literal operand
2842   1,    // RAM access bit
2843   0,    // fast call/return mode select bit
2844   0,    // second memory operand
2845   0,    // second literal operand
2846   POC_NOP,
2847   (PCC_W | PCC_LITERAL),   // inCond
2848   (PCC_W | PCC_Z | PCC_N), // outCond
2849   PCI_MAGIC
2850 };
2851
2852
2853 pCodeInstruction pic16_pciBANKSEL = {
2854   {PC_OPCODE, NULL, NULL, 0, NULL,
2855    genericDestruct,
2856    genericPrint},
2857   POC_BANKSEL,
2858   "BANKSEL",
2859   2,
2860   NULL, // from branch
2861   NULL, // to branch
2862   NULL, // label
2863   NULL, // operand
2864   NULL, // flow block
2865   NULL, // C source
2866   0,    // num ops
2867   0,0,  // dest, bit instruction
2868   0,0,  // branch, skip
2869   0,    // literal operand
2870   0,    // RAM access bit
2871   0,    // fast call/return mode select bit
2872   0,    // second memory operand
2873   0,    // second literal operand
2874   POC_NOP,
2875   PCC_NONE,   // inCond
2876   PCC_NONE, // outCond
2877   PCI_MAGIC
2878 };
2879
2880
2881 #define MAX_PIC16MNEMONICS 100
2882 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2883
2884 extern set *externs;
2885 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2886 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2887
2888 void  pic16_pCodeInitRegisters(void)
2889 {
2890   static int initialized=0;
2891
2892         if(initialized)
2893                 return;
2894
2895         initialized = 1;
2896
2897         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2898         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2899         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2900         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2901         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2902         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2903         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2904
2905         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2906         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2907         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2908
2909         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2910         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2911         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2912         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2913
2914         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2915         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2916         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2917         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2918         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2919         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2920
2921         pic16_stackpnt_lo = &pic16_pc_fsr1l;
2922         pic16_stackpnt_hi = &pic16_pc_fsr1h;
2923         pic16_stack_postdec = &pic16_pc_postdec1;
2924         pic16_stack_postinc = &pic16_pc_postinc1;
2925         pic16_stack_preinc = &pic16_pc_preinc1;
2926         pic16_stack_plusw = &pic16_pc_plusw1;
2927
2928         pic16_framepnt_lo = &pic16_pc_fsr2l;
2929         pic16_framepnt_hi = &pic16_pc_fsr2h;
2930         pic16_frame_postdec = &pic16_pc_postdec2;
2931         pic16_frame_postinc = &pic16_pc_postinc2;
2932         pic16_frame_preinc = &pic16_pc_preinc2;
2933         pic16_frame_plusw = &pic16_pc_plusw2;
2934
2935         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
2936         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
2937         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
2938         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
2939         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
2940
2941         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
2942         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
2943         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
2944         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
2945         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
2946
2947         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
2948         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
2949         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
2950         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
2951         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
2952
2953         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
2954         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
2955
2956
2957         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
2958         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
2959         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
2960         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
2961
2962
2963         pic16_pc_status.rIdx = IDX_STATUS;
2964         pic16_pc_intcon.rIdx = IDX_INTCON;
2965         pic16_pc_pcl.rIdx = IDX_PCL;
2966         pic16_pc_pclath.rIdx = IDX_PCLATH;
2967         pic16_pc_pclatu.rIdx = IDX_PCLATU;
2968         pic16_pc_wreg.rIdx = IDX_WREG;
2969         pic16_pc_bsr.rIdx = IDX_BSR;
2970
2971         pic16_pc_tosl.rIdx = IDX_TOSL;
2972         pic16_pc_tosh.rIdx = IDX_TOSH;
2973         pic16_pc_tosu.rIdx = IDX_TOSU;
2974
2975         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
2976         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
2977         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
2978         pic16_pc_tablat.rIdx = IDX_TABLAT;
2979
2980         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
2981         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
2982         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
2983         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
2984         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
2985         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
2986         pic16_pc_indf0.rIdx = IDX_INDF0;
2987         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
2988         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
2989         pic16_pc_preinc0.rIdx = IDX_PREINC0;
2990         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
2991         pic16_pc_indf1.rIdx = IDX_INDF1;
2992         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
2993         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
2994         pic16_pc_preinc1.rIdx = IDX_PREINC1;
2995         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
2996         pic16_pc_indf2.rIdx = IDX_INDF2;
2997         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
2998         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
2999         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3000         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3001         pic16_pc_prodl.rIdx = IDX_PRODL;
3002         pic16_pc_prodh.rIdx = IDX_PRODH;
3003
3004         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3005         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3006         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3007
3008         pic16_pc_kzero.rIdx = IDX_KZ;
3009         pic16_pc_wsave.rIdx = IDX_WSAVE;
3010         pic16_pc_ssave.rIdx = IDX_SSAVE;
3011
3012         pic16_pc_eecon1.rIdx = IDX_EECON1;
3013         pic16_pc_eecon2.rIdx = IDX_EECON2;
3014         pic16_pc_eedata.rIdx = IDX_EEDATA;
3015         pic16_pc_eeadr.rIdx = IDX_EEADR;
3016
3017
3018         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3019         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3020
3021         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3022         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3023
3024         /* probably should put this in a separate initialization routine */
3025         pb_dead_pcodes = newpBlock();
3026
3027 }
3028
3029 #if OPT_DISABLE_PIC
3030 /*-----------------------------------------------------------------*/
3031 /*  mnem2key - convert a pic mnemonic into a hash key              */
3032 /*   (BTW - this spreads the mnemonics quite well)                 */
3033 /*                                                                 */
3034 /*-----------------------------------------------------------------*/
3035
3036 int mnem2key(unsigned char const *mnem)
3037 {
3038   int key = 0;
3039
3040   if(!mnem)
3041     return 0;
3042
3043   while(*mnem) {
3044
3045     key += toupper(*mnem++) +1;
3046
3047   }
3048
3049   return (key & 0x1f);
3050
3051 }
3052 #endif
3053
3054 void pic16initMnemonics(void)
3055 {
3056   int i = 0;
3057   int key;
3058   //  char *str;
3059   pCodeInstruction *pci;
3060
3061   if(mnemonics_initialized)
3062     return;
3063
3064   // NULL out the array before making the assignments
3065   // since we check the array contents below this initialization.
3066
3067   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3068     pic16Mnemonics[i] = NULL;
3069   }
3070
3071   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3072   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3073   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3074   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3075   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3076   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3077   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3078   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3079   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3080   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3081   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3082   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3083   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3084   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3085   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3086   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3087   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3088   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3089   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3090   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3091   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3092   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3093   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3094   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3095   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3096   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3097   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3098   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3099   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3100   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3101   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3102   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3103   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3104   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3105   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3106   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3107   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3108   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3109   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3110   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3111   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3112   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3113   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3114   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3115   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3116   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3117   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3118   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3119   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3120   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3121   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3122   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3123   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3124   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3125   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3126   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3127   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3128   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3129   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3130   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3131   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3132   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3133   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3134   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3135   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3136   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3137   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3138   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3139   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3140   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3141   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3142   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3143   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3144   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3145   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3146   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3147   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3148   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3149   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3150   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3151   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3152   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3153   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3154   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3155   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3156   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3157   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3158   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3159   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3160   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3161   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3162   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3163   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3164   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3165
3166   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3167     if(pic16Mnemonics[i])
3168       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3169   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3170
3171   while(pci) {
3172     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3173     pci = hTabNextItem(pic16MnemonicsHash, &key);
3174   }
3175
3176   mnemonics_initialized = 1;
3177 }
3178
3179 int pic16_getpCodePeepCommand(char *cmd);
3180
3181 int pic16_getpCode(char *mnem,unsigned dest)
3182 {
3183
3184   pCodeInstruction *pci;
3185   int key = mnem2key((unsigned char *)mnem);
3186
3187   if(!mnemonics_initialized)
3188     pic16initMnemonics();
3189
3190   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3191
3192   while(pci) {
3193
3194     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3195       if((pci->num_ops <= 1)
3196         || (pci->isModReg == dest)
3197         || (pci->isBitInst)
3198         || (pci->num_ops <= 2 && pci->isAccess)
3199         || (pci->num_ops <= 2 && pci->isFastCall)
3200         || (pci->num_ops <= 2 && pci->is2MemOp)
3201         || (pci->num_ops <= 2 && pci->is2LitOp) )
3202         return(pci->op);
3203     }
3204
3205     pci = hTabNextItemWK (pic16MnemonicsHash);
3206
3207   }
3208
3209   return -1;
3210 }
3211
3212 /*-----------------------------------------------------------------*
3213  * pic16initpCodePeepCommands
3214  *
3215  *-----------------------------------------------------------------*/
3216 void pic16initpCodePeepCommands(void)
3217 {
3218
3219   int key, i;
3220   peepCommand *pcmd;
3221
3222   i = 0;
3223   do {
3224     hTabAddItem(&pic16pCodePeepCommandsHash,
3225                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3226     i++;
3227   } while (peepCommands[i].cmd);
3228
3229   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3230
3231   while(pcmd) {
3232     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3233     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3234   }
3235
3236 }
3237
3238 /*-----------------------------------------------------------------
3239  *
3240  *
3241  *-----------------------------------------------------------------*/
3242
3243 int pic16_getpCodePeepCommand(char *cmd)
3244 {
3245
3246   peepCommand *pcmd;
3247   int key = mnem2key((unsigned char *)cmd);
3248
3249
3250   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3251
3252   while(pcmd) {
3253     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3254     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3255       return pcmd->id;
3256     }
3257
3258     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3259
3260   }
3261
3262   return -1;
3263 }
3264
3265 static char getpBlock_dbName(pBlock *pb)
3266 {
3267   if(!pb)
3268     return 0;
3269
3270   if(pb->cmemmap)
3271     return pb->cmemmap->dbName;
3272
3273   return pb->dbName;
3274 }
3275 void pic16_pBlockConvert2ISR(pBlock *pb)
3276 {
3277         if(!pb)return;
3278
3279         if(pb->cmemmap)pb->cmemmap = NULL;
3280
3281         pb->dbName = 'I';
3282
3283         if(pic16_pcode_verbose)
3284                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3285 }
3286
3287 void pic16_pBlockConvert2Absolute(pBlock *pb)
3288 {
3289         if(!pb)return;
3290         if(pb->cmemmap)pb->cmemmap = NULL;
3291
3292         pb->dbName = 'A';
3293
3294         if(pic16_pcode_verbose)
3295                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3296 }
3297
3298 /*-----------------------------------------------------------------*/
3299 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3300 /*                   instances to the front of the doubly linked   */
3301 /*                   list of pBlocks                               */
3302 /*-----------------------------------------------------------------*/
3303
3304 void pic16_movepBlock2Head(char dbName)
3305 {
3306   pBlock *pb;
3307
3308
3309   /* this can happen in sources without code,
3310    * only variable definitions */
3311   if(!the_pFile)return;
3312
3313   pb = the_pFile->pbHead;
3314
3315   while(pb) {
3316
3317     if(getpBlock_dbName(pb) == dbName) {
3318       pBlock *pbn = pb->next;
3319       pb->next = the_pFile->pbHead;
3320       the_pFile->pbHead->prev = pb;
3321       the_pFile->pbHead = pb;
3322
3323       if(pb->prev)
3324         pb->prev->next = pbn;
3325
3326       // If the pBlock that we just moved was the last
3327       // one in the link of all of the pBlocks, then we
3328       // need to point the tail to the block just before
3329       // the one we moved.
3330       // Note: if pb->next is NULL, then pb must have
3331       // been the last pBlock in the chain.
3332
3333       if(pbn)
3334         pbn->prev = pb->prev;
3335       else
3336         the_pFile->pbTail = pb->prev;
3337
3338       pb = pbn;
3339
3340     } else
3341       pb = pb->next;
3342
3343   }
3344
3345 }
3346
3347 void pic16_copypCode(FILE *of, char dbName)
3348 {
3349   pBlock *pb;
3350
3351         if(!of || !the_pFile)
3352                 return;
3353
3354         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3355                 if(getpBlock_dbName(pb) == dbName) {
3356 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3357                         pBlockStats(of,pb);
3358                         pic16_printpBlock(of,pb);
3359                 }
3360         }
3361
3362 }
3363 void pic16_pcode_test(void)
3364 {
3365
3366   DFPRINTF((stderr,"pcode is alive!\n"));
3367
3368   //initMnemonics();
3369
3370   if(the_pFile) {
3371
3372     pBlock *pb;
3373     FILE *pFile;
3374     char buffer[100];
3375
3376     /* create the file name */
3377     strcpy(buffer,dstFileName);
3378     strcat(buffer,".p");
3379
3380     if( !(pFile = fopen(buffer, "w" ))) {
3381       werror(E_FILE_OPEN_ERR,buffer);
3382       exit(1);
3383     }
3384
3385     fprintf(pFile,"pcode dump\n\n");
3386
3387     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3388       fprintf(pFile,"\n\tNew pBlock\n\n");
3389       if(pb->cmemmap)
3390         fprintf(pFile,"%s",pb->cmemmap->sname);
3391       else
3392         fprintf(pFile,"internal pblock");
3393
3394       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3395       pic16_printpBlock(pFile,pb);
3396     }
3397   }
3398 }
3399
3400
3401 unsigned long pic16_countInstructions(void)
3402 {
3403   pBlock *pb;
3404   pCode *pc;
3405   unsigned long isize=0;
3406
3407     if(!the_pFile)return -1;
3408
3409     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3410       for(pc = pb->pcHead; pc; pc = pc->next) {
3411         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3412       }
3413     }
3414   return (isize);
3415 }
3416
3417
3418 /*-----------------------------------------------------------------*/
3419 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3420 /*      ister, RegCond will return the bit being referenced.       */
3421 /*                                                                 */
3422 /* fixme - why not just OR in the pcop bit field                   */
3423 /*-----------------------------------------------------------------*/
3424
3425 static int RegCond(pCodeOp *pcop)
3426 {
3427
3428   if(!pcop)
3429     return 0;
3430
3431   if(!pcop->name)return 0;
3432
3433   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3434     switch(PCORB(pcop)->bit) {
3435     case PIC_C_BIT:
3436       return PCC_C;
3437     case PIC_DC_BIT:
3438         return PCC_DC;
3439     case PIC_Z_BIT:
3440       return PCC_Z;
3441     }
3442
3443   }
3444
3445   return 0;
3446 }
3447
3448
3449 /*-----------------------------------------------------------------*/
3450 /* pic16_newpCode - create and return a newly initialized pCode          */
3451 /*                                                                 */
3452 /*  fixme - rename this                                            */
3453 /*                                                                 */
3454 /* The purpose of this routine is to create a new Instruction      */
3455 /* pCode. This is called by gen.c while the assembly code is being */
3456 /* generated.                                                      */
3457 /*                                                                 */
3458 /* Inouts:                                                         */
3459 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3460 /*                  (note that the op is analogous to but not the  */
3461 /*                  same thing as the opcode of the instruction.)  */
3462 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3463 /*                                                                 */
3464 /* Outputs:                                                        */
3465 /*  a pointer to the new malloc'd pCode is returned.               */
3466 /*                                                                 */
3467 /*                                                                 */
3468 /*                                                                 */
3469 /*-----------------------------------------------------------------*/
3470 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3471 {
3472   pCodeInstruction *pci ;
3473
3474   if(!mnemonics_initialized)
3475     pic16initMnemonics();
3476
3477   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3478
3479   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3480     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3481     pci->pcop = pcop;
3482
3483     if(pci->inCond & PCC_EXAMINE_PCOP)
3484       pci->inCond  |= RegCond(pcop);
3485
3486     if(pci->outCond & PCC_EXAMINE_PCOP)
3487       pci->outCond  |= RegCond(pcop);
3488
3489     pci->pc.prev = pci->pc.next = NULL;
3490     return (pCode *)pci;
3491   }
3492
3493   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3494   exit(1);
3495
3496   return NULL;
3497 }
3498
3499 /*-----------------------------------------------------------------*/
3500 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3501 /*                                                                 */
3502 /* Wild pcodes are used during the peep hole optimizer to serve    */
3503 /* as place holders for any instruction. When a snippet of code is */
3504 /* compared to a peep hole rule, the wild card opcode will match   */
3505 /* any instruction. However, the optional operand and label are    */
3506 /* additional qualifiers that must also be matched before the      */
3507 /* line (of assembly code) is declared matched. Note that the      */
3508 /* operand may be wild too.                                        */
3509 /*                                                                 */
3510 /*   Note, a wild instruction is specified just like a wild var:   */
3511 /*      %4     ; A wild instruction,                               */
3512 /*  See the peeph.def file for additional examples                 */
3513 /*                                                                 */
3514 /*-----------------------------------------------------------------*/
3515
3516 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3517 {
3518
3519   pCodeWild *pcw;
3520
3521   pcw = Safe_calloc(1,sizeof(pCodeWild));
3522
3523   pcw->pci.pc.type = PC_WILD;
3524   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3525   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3526   pcw->pci.pc.pb = NULL;
3527
3528   //  pcw->pci.pc.analyze = genericAnalyze;
3529   pcw->pci.pc.destruct = genericDestruct;
3530   pcw->pci.pc.print = genericPrint;
3531
3532   pcw->id = pCodeID;              // this is the 'n' in %n
3533   pcw->operand = optional_operand;
3534   pcw->label   = optional_label;
3535
3536   pcw->mustBeBitSkipInst = 0;
3537   pcw->mustNotBeBitSkipInst = 0;
3538   pcw->invertBitSkipInst = 0;
3539
3540   return ( (pCode *)pcw);
3541
3542 }
3543
3544  /*-----------------------------------------------------------------*/
3545 /* newPcodeInlineP - create a new pCode from a char string           */
3546 /*-----------------------------------------------------------------*/
3547
3548
3549 pCode *pic16_newpCodeInlineP(char *cP)
3550 {
3551
3552   pCodeComment *pcc ;
3553
3554   pcc = Safe_calloc(1,sizeof(pCodeComment));
3555
3556   pcc->pc.type = PC_INLINE;
3557   pcc->pc.prev = pcc->pc.next = NULL;
3558   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3559   pcc->pc.pb = NULL;
3560
3561   //  pcc->pc.analyze = genericAnalyze;
3562   pcc->pc.destruct = genericDestruct;
3563   pcc->pc.print = genericPrint;
3564
3565   if(cP)
3566     pcc->comment = Safe_strdup(cP);
3567   else
3568     pcc->comment = NULL;
3569
3570   return ( (pCode *)pcc);
3571
3572 }
3573
3574 /*-----------------------------------------------------------------*/
3575 /* newPcodeCharP - create a new pCode from a char string           */
3576 /*-----------------------------------------------------------------*/
3577
3578 pCode *pic16_newpCodeCharP(char *cP)
3579 {
3580
3581   pCodeComment *pcc ;
3582
3583   pcc = Safe_calloc(1,sizeof(pCodeComment));
3584
3585   pcc->pc.type = PC_COMMENT;
3586   pcc->pc.prev = pcc->pc.next = NULL;
3587   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3588   pcc->pc.pb = NULL;
3589
3590   //  pcc->pc.analyze = genericAnalyze;
3591   pcc->pc.destruct = genericDestruct;
3592   pcc->pc.print = genericPrint;
3593
3594   if(cP)
3595     pcc->comment = Safe_strdup(cP);
3596   else
3597     pcc->comment = NULL;
3598
3599   return ( (pCode *)pcc);
3600
3601 }
3602
3603 /*-----------------------------------------------------------------*/
3604 /* pic16_newpCodeFunction -                                              */
3605 /*-----------------------------------------------------------------*/
3606
3607
3608 pCode *pic16_newpCodeFunction(char *mod,char *f)
3609 {
3610   pCodeFunction *pcf;
3611
3612   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3613
3614   pcf->pc.type = PC_FUNCTION;
3615   pcf->pc.prev = pcf->pc.next = NULL;
3616   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3617   pcf->pc.pb = NULL;
3618
3619   //  pcf->pc.analyze = genericAnalyze;
3620   pcf->pc.destruct = genericDestruct;
3621   pcf->pc.print = pCodePrintFunction;
3622
3623   pcf->ncalled = 0;
3624   pcf->absblock = 0;
3625
3626   if(mod) {
3627     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3628     strcpy(pcf->modname,mod);
3629   } else
3630     pcf->modname = NULL;
3631
3632   if(f) {
3633     pcf->fname = Safe_calloc(1,strlen(f)+1);
3634     strcpy(pcf->fname,f);
3635   } else
3636     pcf->fname = NULL;
3637
3638   pcf->stackusage = 0;
3639
3640   return ( (pCode *)pcf);
3641 }
3642
3643 /*-----------------------------------------------------------------*/
3644 /* pic16_newpCodeFlow                                                    */
3645 /*-----------------------------------------------------------------*/
3646 static void destructpCodeFlow(pCode *pc)
3647 {
3648   if(!pc || !isPCFL(pc))
3649     return;
3650
3651 /*
3652   if(PCFL(pc)->from)
3653   if(PCFL(pc)->to)
3654 */
3655   pic16_unlinkpCode(pc);
3656
3657   deleteSet(&PCFL(pc)->registers);
3658   deleteSet(&PCFL(pc)->from);
3659   deleteSet(&PCFL(pc)->to);
3660
3661   /* Instead of deleting the memory used by this pCode, mark
3662    * the object as bad so that if there's a pointer to this pCode
3663    * dangling around somewhere then (hopefully) when the type is
3664    * checked we'll catch it.
3665    */
3666
3667   pc->type = PC_BAD;
3668   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3669
3670 //  Safe_free(pc);
3671
3672 }
3673
3674 pCode *pic16_newpCodeFlow(void )
3675 {
3676   pCodeFlow *pcflow;
3677
3678   //_ALLOC(pcflow,sizeof(pCodeFlow));
3679   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3680
3681   pcflow->pc.type = PC_FLOW;
3682   pcflow->pc.prev = pcflow->pc.next = NULL;
3683   pcflow->pc.pb = NULL;
3684
3685   //  pcflow->pc.analyze = genericAnalyze;
3686   pcflow->pc.destruct = destructpCodeFlow;
3687   pcflow->pc.print = genericPrint;
3688
3689   pcflow->pc.seq = GpcFlowSeq++;
3690
3691   pcflow->from = pcflow->to = NULL;
3692
3693   pcflow->inCond = PCC_NONE;
3694   pcflow->outCond = PCC_NONE;
3695
3696   pcflow->firstBank = -1;
3697   pcflow->lastBank = -1;
3698
3699   pcflow->FromConflicts = 0;
3700   pcflow->ToConflicts = 0;
3701
3702   pcflow->end = NULL;
3703
3704   pcflow->registers = newSet();
3705
3706   return ( (pCode *)pcflow);
3707
3708 }
3709
3710 /*-----------------------------------------------------------------*/
3711 /*-----------------------------------------------------------------*/
3712 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3713 {
3714   pCodeFlowLink *pcflowLink;
3715
3716   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3717
3718   pcflowLink->pcflow = pcflow;
3719   pcflowLink->bank_conflict = 0;
3720
3721   return pcflowLink;
3722 }
3723
3724 /*-----------------------------------------------------------------*/
3725 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3726 /*-----------------------------------------------------------------*/
3727
3728 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3729 {
3730
3731   pCodeCSource *pccs;
3732
3733   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3734
3735   pccs->pc.type = PC_CSOURCE;
3736   pccs->pc.prev = pccs->pc.next = NULL;
3737   pccs->pc.pb = NULL;
3738
3739   pccs->pc.destruct = genericDestruct;
3740   pccs->pc.print = genericPrint;
3741
3742   pccs->line_number = ln;
3743   if(l)
3744     pccs->line = Safe_strdup(l);
3745   else
3746     pccs->line = NULL;
3747
3748   if(f)
3749     pccs->file_name = Safe_strdup(f);
3750   else
3751     pccs->file_name = NULL;
3752
3753   return ( (pCode *)pccs);
3754
3755 }
3756
3757
3758 /*******************************************************************/
3759 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3760 /*                      added by VR 6-Jun-2003                     */
3761 /*******************************************************************/
3762
3763 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3764 {
3765   pCodeAsmDir *pcad;
3766   va_list ap;
3767   char buffer[512];
3768   char *lbp=buffer;
3769
3770         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3771         pcad->pci.pc.type = PC_ASMDIR;
3772         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3773         pcad->pci.pc.pb = NULL;
3774         pcad->pci.isize = 2;
3775         pcad->pci.pc.destruct = genericDestruct;
3776         pcad->pci.pc.print = genericPrint;
3777
3778         if(asdir && *asdir) {
3779
3780                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3781
3782                 pcad->directive = Safe_strdup( asdir );
3783         }
3784
3785         va_start(ap, argfmt);
3786
3787         memset(buffer, 0, sizeof(buffer));
3788         if(argfmt && *argfmt)
3789                 vsprintf(buffer, argfmt, ap);
3790
3791         va_end(ap);
3792
3793         while(isspace((unsigned char)*lbp))lbp++;
3794
3795         if(lbp && *lbp)
3796                 pcad->arg = Safe_strdup( lbp );
3797
3798   return ((pCode *)pcad);
3799 }
3800
3801 /*-----------------------------------------------------------------*/
3802 /* pCodeLabelDestruct - free memory used by a label.               */
3803 /*-----------------------------------------------------------------*/
3804 static void pCodeLabelDestruct(pCode *pc)
3805 {
3806
3807   if(!pc)
3808     return;
3809
3810 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3811 //    Safe_free(PCL(pc)->label);
3812
3813   /* Instead of deleting the memory used by this pCode, mark
3814    * the object as bad so that if there's a pointer to this pCode
3815    * dangling around somewhere then (hopefully) when the type is
3816    * checked we'll catch it.
3817    */
3818
3819   pc->type = PC_BAD;
3820   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3821
3822 //  Safe_free(pc);
3823
3824 }
3825
3826 pCode *pic16_newpCodeLabel(char *name, int key)
3827 {
3828
3829   char *s = buffer;
3830   pCodeLabel *pcl;
3831
3832   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3833
3834   pcl->pc.type = PC_LABEL;
3835   pcl->pc.prev = pcl->pc.next = NULL;
3836   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3837   pcl->pc.pb = NULL;
3838
3839   //  pcl->pc.analyze = genericAnalyze;
3840   pcl->pc.destruct = pCodeLabelDestruct;
3841   pcl->pc.print = pCodePrintLabel;
3842
3843   pcl->key = key;
3844   pcl->force = 0;
3845
3846   pcl->label = NULL;
3847   if(key>0) {
3848     sprintf(s,"_%05d_DS_",key);
3849   } else
3850     s = name;
3851
3852   if(s)
3853     pcl->label = Safe_strdup(s);
3854
3855 //  if(pic16_pcode_verbose)
3856 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3857
3858
3859   return ( (pCode *)pcl);
3860
3861 }
3862
3863 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3864 {
3865   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3866
3867         pcl->force = 1;
3868
3869   return ( (pCode *)pcl );
3870 }
3871
3872 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3873 {
3874   pCodeInfo *pci;
3875
3876     pci = Safe_calloc(1, sizeof(pCodeInfo));
3877     pci->pci.pc.type = PC_INFO;
3878     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3879     pci->pci.pc.pb = NULL;
3880     pci->pci.label = NULL;
3881
3882     pci->pci.pc.destruct = genericDestruct;
3883     pci->pci.pc.print = genericPrint;
3884
3885     pci->type = type;
3886     pci->oper1 = pcop;
3887
3888   return ((pCode *)pci);
3889 }
3890
3891
3892 /*-----------------------------------------------------------------*/
3893 /* newpBlock - create and return a pointer to a new pBlock         */
3894 /*-----------------------------------------------------------------*/
3895 static pBlock *newpBlock(void)
3896 {
3897
3898   pBlock *PpB;
3899
3900   PpB = Safe_calloc(1,sizeof(pBlock) );
3901   PpB->next = PpB->prev = NULL;
3902
3903   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3904   PpB->tregisters = NULL;
3905   PpB->visited = 0;
3906   PpB->FlowTree = NULL;
3907
3908   return PpB;
3909
3910 }
3911
3912 /*-----------------------------------------------------------------*/
3913 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3914 /*-----------------------------------------------------------------*
3915  *
3916  *  This function will create a new pBlock and the pointer to the
3917  *  pCode that is passed in will be the first pCode in the block.
3918  *-----------------------------------------------------------------*/
3919
3920
3921 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3922 {
3923
3924   pBlock *pB  = newpBlock();
3925
3926   pB->pcHead  = pB->pcTail = pc;
3927   pB->cmemmap = cm;
3928   pB->dbName  = c;
3929
3930   return pB;
3931 }
3932
3933
3934
3935 /*-----------------------------------------------------------------*/
3936 /* pic16_newpCodeOpLabel - Create a new label given the key              */
3937 /*  Note, a negative key means that the label is part of wild card */
3938 /*  (and hence a wild card label) used in the pCodePeep            */
3939 /*   optimizations).                                               */
3940 /*-----------------------------------------------------------------*/
3941
3942 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3943 {
3944   char *s=NULL;
3945   static int label_key=-1;
3946
3947   pCodeOp *pcop;
3948
3949   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3950   pcop->type = PO_LABEL;
3951
3952   pcop->name = NULL;
3953
3954   if(key>0)
3955     sprintf(s=buffer,"_%05d_DS_",key);
3956   else
3957     s = name, key = label_key--;
3958
3959   if(s)
3960     pcop->name = Safe_strdup(s);
3961
3962   ((pCodeOpLabel *)pcop)->key = key;
3963
3964   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3965   return pcop;
3966 }
3967
3968 /*-----------------------------------------------------------------*/
3969 /*-----------------------------------------------------------------*/
3970 pCodeOp *pic16_newpCodeOpLit(int lit)
3971 {
3972   char *s = buffer;
3973   pCodeOp *pcop;
3974
3975
3976   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3977   pcop->type = PO_LITERAL;
3978
3979   pcop->name = NULL;
3980   //if(lit>=0)
3981     sprintf(s,"0x%02hhx", (unsigned char)lit);
3982   //else
3983   //  sprintf(s, "%i", lit);
3984
3985   if(s)
3986     pcop->name = Safe_strdup(s);
3987
3988   ((pCodeOpLit *)pcop)->lit = lit;
3989
3990   return pcop;
3991 }
3992
3993 /* Allow for 12 bit literals, required for LFSR */
3994 pCodeOp *pic16_newpCodeOpLit12(int lit)
3995 {
3996   char *s = buffer;
3997   pCodeOp *pcop;
3998
3999
4000   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4001   pcop->type = PO_LITERAL;
4002
4003   pcop->name = NULL;
4004   //if(lit>=0)
4005     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4006   //else
4007   //  sprintf(s, "%i", lit);
4008
4009   if(s)
4010     pcop->name = Safe_strdup(s);
4011
4012   ((pCodeOpLit *)pcop)->lit = lit;
4013
4014   return pcop;
4015 }
4016
4017 /*-----------------------------------------------------------------*/
4018 /*-----------------------------------------------------------------*/
4019 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4020 {
4021   char *s = buffer, tbuf[256], *tb=tbuf;
4022   pCodeOp *pcop;
4023
4024
4025   tb = pic16_get_op(arg2, NULL, 0);
4026   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4027   pcop->type = PO_LITERAL;
4028
4029   pcop->name = NULL;
4030   //if(lit>=0) {
4031     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4032     if(s)
4033       pcop->name = Safe_strdup(s);
4034   //}
4035
4036   ((pCodeOpLit2 *)pcop)->lit = lit;
4037   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4038
4039   return pcop;
4040 }
4041
4042 /*-----------------------------------------------------------------*/
4043 /*-----------------------------------------------------------------*/
4044 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4045 {
4046   pCodeOp *pcop;
4047
4048         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4049         pcop->type = PO_IMMEDIATE;
4050         if(name) {
4051                 regs *r = pic16_dirregWithName(name);
4052                 pcop->name = Safe_strdup(name);
4053                 PCOI(pcop)->r = r;
4054
4055                 if(r) {
4056 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4057                         PCOI(pcop)->rIdx = r->rIdx;
4058                 } else {
4059 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4060                         PCOI(pcop)->rIdx = -1;
4061                 }
4062 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4063         } else {
4064                 pcop->name = NULL;
4065                 PCOI(pcop)->rIdx = -1;
4066         }
4067
4068         PCOI(pcop)->index = index;
4069         PCOI(pcop)->offset = offset;
4070         PCOI(pcop)->_const = code_space;
4071
4072   return pcop;
4073 }
4074
4075 /*-----------------------------------------------------------------*/
4076 /*-----------------------------------------------------------------*/
4077 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4078 {
4079   char *s = buffer;
4080   pCodeOp *pcop;
4081
4082
4083   if(!pcwb || !subtype) {
4084     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4085     exit(1);
4086   }
4087
4088   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4089   pcop->type = PO_WILD;
4090   sprintf(s,"%%%d",id);
4091   pcop->name = Safe_strdup(s);
4092
4093   PCOW(pcop)->id = id;
4094   PCOW(pcop)->pcwb = pcwb;
4095   PCOW(pcop)->subtype = subtype;
4096   PCOW(pcop)->matched = NULL;
4097
4098   PCOW(pcop)->pcop2 = NULL;
4099
4100   return pcop;
4101 }
4102
4103 /*-----------------------------------------------------------------*/
4104 /*-----------------------------------------------------------------*/
4105 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4106 {
4107   char *s = buffer;
4108   pCodeOp *pcop;
4109
4110
4111         if(!pcwb || !subtype || !subtype2) {
4112                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4113                 exit(1);
4114         }
4115
4116         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4117         pcop->type = PO_WILD;
4118         sprintf(s,"%%%d",id);
4119         pcop->name = Safe_strdup(s);
4120
4121         PCOW(pcop)->id = id;
4122         PCOW(pcop)->pcwb = pcwb;
4123         PCOW(pcop)->subtype = subtype;
4124         PCOW(pcop)->matched = NULL;
4125
4126         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4127
4128         if(!subtype2->name) {
4129                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4130                 PCOW2(pcop)->pcop.type = PO_WILD;
4131                 sprintf(s, "%%%d", id2);
4132                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4133                 PCOW2(pcop)->id = id2;
4134                 PCOW2(pcop)->subtype = subtype2;
4135
4136 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4137 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4138         } else {
4139                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4140
4141 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4142 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4143         }
4144
4145
4146
4147   return pcop;
4148 }
4149
4150
4151 /*-----------------------------------------------------------------*/
4152 /*-----------------------------------------------------------------*/
4153 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4154 {
4155   pCodeOp *pcop;
4156
4157   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4158   pcop->type = PO_GPR_BIT;
4159   if(s)
4160     pcop->name = Safe_strdup(s);
4161   else
4162     pcop->name = NULL;
4163
4164   PCORB(pcop)->bit = bit;
4165   PCORB(pcop)->inBitSpace = inBitSpace;
4166   PCORB(pcop)->subtype = subt;
4167
4168   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4169   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4170 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4171 //  PCOR(pcop)->rIdx = 0;
4172   return pcop;
4173 }
4174
4175 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4176 {
4177   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4178                                 bit, 0, PO_GPR_REGISTER);
4179 }
4180
4181
4182 /*-----------------------------------------------------------------*
4183  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4184  *
4185  * If rIdx >=0 then a specific register from the set of registers
4186  * will be selected. If rIdx <0, then a new register will be searched
4187  * for.
4188  *-----------------------------------------------------------------*/
4189
4190 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4191 {
4192   pCodeOp *pcop;
4193   regs *r;
4194
4195   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4196
4197   pcop->name = NULL;
4198
4199   if(rIdx >= 0) {
4200         r = pic16_regWithIdx(rIdx);
4201         if(!r)
4202                 r = pic16_allocWithIdx(rIdx);
4203   } else {
4204     r = pic16_findFreeReg(REG_GPR);
4205
4206     if(!r) {
4207         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4208                 __FUNCTION__, __LINE__);
4209         exit(EXIT_FAILURE);
4210     }
4211   }
4212
4213   PCOR(pcop)->rIdx = rIdx;
4214   PCOR(pcop)->r = r;
4215   pcop->type = PCOR(pcop)->r->pc_type;
4216
4217   return pcop;
4218 }
4219
4220 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4221 {
4222   pCodeOp *pcop;
4223   regs *r;
4224
4225     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4226     pcop->name = NULL;
4227
4228     r = pic16_findFreeReg(REG_GPR);
4229
4230     while(r) {
4231       if(!bitVectBitValue(bv, r->rIdx)) {
4232         PCOR(pcop)->r = r;
4233         PCOR(pcop)->rIdx = r->rIdx;
4234         pcop->type = r->pc_type;
4235         return (pcop);
4236       }
4237
4238       r = pic16_findFreeRegNext(REG_GPR, r);
4239     }
4240
4241   return NULL;
4242 }
4243
4244
4245
4246 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4247 {
4248   pCodeOp *pcop;
4249   regs *r;
4250
4251         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4252         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4253         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4254         pcop->type = PCOR(pcop)->r->pc_type;
4255         pcop->name = PCOR(pcop)->r->name;
4256
4257 //      if(pic16_pcode_verbose) {
4258 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4259 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4260 //      }
4261
4262   return pcop;
4263 }
4264
4265 /*-----------------------------------------------------------------*/
4266 /*-----------------------------------------------------------------*/
4267 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4268 {
4269   pCodeOpOpt *pcop;
4270
4271         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4272
4273         pcop->type = type;
4274         pcop->key = Safe_strdup( key );
4275
4276   return (PCOP(pcop));
4277 }
4278
4279 /*-----------------------------------------------------------------*/
4280 /*-----------------------------------------------------------------*/
4281 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4282 {
4283   pCodeOpLocalReg *pcop;
4284
4285         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4286
4287         pcop->type = type;
4288
4289   return (PCOP(pcop));
4290 }
4291
4292
4293 /*-----------------------------------------------------------------*/
4294 /*-----------------------------------------------------------------*/
4295
4296 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4297 {
4298   pCodeOp *pcop;
4299
4300   switch(type) {
4301   case PO_BIT:
4302   case PO_GPR_BIT:
4303     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4304     break;
4305
4306   case PO_LITERAL:
4307     pcop = pic16_newpCodeOpLit(-1);
4308     break;
4309
4310   case PO_LABEL:
4311     pcop = pic16_newpCodeOpLabel(NULL,-1);
4312     break;
4313   case PO_GPR_TEMP:
4314     pcop = pic16_newpCodeOpReg(-1);
4315     break;
4316
4317   case PO_GPR_REGISTER:
4318     if(name)
4319       pcop = pic16_newpCodeOpRegFromStr(name);
4320     else
4321       pcop = pic16_newpCodeOpReg(-1);
4322     break;
4323
4324   case PO_TWO_OPS:
4325     assert( !"Cannot create PO_TWO_OPS from string!" );
4326     pcop = NULL;
4327     break;
4328
4329   default:
4330     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4331     pcop->type = type;
4332     if(name)
4333       pcop->name = Safe_strdup(name);
4334     else
4335       pcop->name = NULL;
4336   }
4337
4338   return pcop;
4339 }
4340
4341 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4342 {
4343   pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4344   pcop2->pcop.type = PO_TWO_OPS;
4345   pcop2->pcopL = src;
4346   pcop2->pcopR = dst;
4347   return PCOP(pcop2);
4348 }
4349
4350 /* This is a multiple of two as gpasm pads DB directives to even length,
4351  * thus the data would be interleaved with \0 bytes...
4352  * This is a multiple of three in order to have arrays of 3-byte pointers
4353  * continuously in memory (without 0-padding at the lines' end).
4354  * This is rather 12 than 6 in order not to split up 4-byte data types
4355  * in arrays right in the middle of a 4-byte word. */
4356 #define DB_ITEMS_PER_LINE       12
4357
4358 typedef struct DBdata
4359   {
4360     int count;
4361     char buffer[512];
4362   } DBdata;
4363
4364 struct DBdata DBd;
4365 static int DBd_init = -1;
4366
4367 /*-----------------------------------------------------------------*/
4368 /*    Initialiase "DB" data buffer                                 */
4369 /*-----------------------------------------------------------------*/
4370 void pic16_initDB(void)
4371 {
4372         DBd_init = -1;
4373 }
4374
4375
4376 /*-----------------------------------------------------------------*/
4377 /*    Flush pending "DB" data to a pBlock                          */
4378 /*                                                                 */
4379 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4380 /*-----------------------------------------------------------------*/
4381 void pic16_flushDB(char ptype, void *p)
4382 {
4383         if (DBd.count>0) {
4384                 if(ptype == 'p')
4385                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4386                 else
4387                 if(ptype == 'f')
4388                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4389                 else {
4390                         /* sanity check */
4391                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4392                 }
4393
4394                 DBd.count = 0;
4395                 DBd.buffer[0] = '\0';
4396         }
4397 }
4398
4399
4400 /*-----------------------------------------------------------------*/
4401 /*    Add "DB" directives to a pBlock                              */
4402 /*-----------------------------------------------------------------*/
4403 void pic16_emitDB(int c, char ptype, void *p)
4404 {
4405   int l;
4406
4407         if (DBd_init<0) {
4408          // we need to initialize
4409                 DBd_init = 0;
4410                 DBd.count = 0;
4411                 DBd.buffer[0] = '\0';
4412         }
4413
4414         l = strlen(DBd.buffer);
4415         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4416
4417 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4418
4419         DBd.count++;
4420         if (DBd.count>= DB_ITEMS_PER_LINE)
4421                 pic16_flushDB(ptype, p);
4422 }
4423
4424 void pic16_emitDS(char *s, char ptype, void *p)
4425 {
4426   int l;
4427
4428         if (DBd_init<0) {
4429          // we need to initialize
4430                 DBd_init = 0;
4431                 DBd.count = 0;
4432                 DBd.buffer[0] = '\0';
4433         }
4434
4435         l = strlen(DBd.buffer);
4436         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4437
4438 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4439
4440         DBd.count++;    //=strlen(s);
4441         if (DBd.count>=DB_ITEMS_PER_LINE)
4442                 pic16_flushDB(ptype, p);
4443 }
4444
4445
4446 /*-----------------------------------------------------------------*/
4447 /*-----------------------------------------------------------------*/
4448 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4449 {
4450   pBlock *pb;
4451   char *item;
4452   static set *emittedSymbols = NULL;
4453
4454   if(!name || !value)
4455     return;
4456
4457   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4458   if (emittedSymbols) {
4459     /* scan set for name */
4460     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4461     {
4462       if (!strcmp (item,name)) {
4463         //fprintf (stderr, "%s already emitted\n", name);
4464         return;
4465       } // if
4466     } // for
4467   } // if
4468   addSet (&emittedSymbols, Safe_strdup (name));
4469
4470   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4471
4472   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4473
4474   pic16_addpBlock(pb);
4475
4476 //  sprintf(buffer,"; %s = ", name);
4477 //  strcat(buffer, value);
4478 //  fputs(buffer, stderr);
4479
4480 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4481   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4482
4483   while (length--)
4484     pic16_emitDB(*value++, 'p', (void *)pb);
4485
4486   pic16_flushDB('p', (void *)pb);
4487 }
4488
4489 /*-----------------------------------------------------------------*/
4490 /*-----------------------------------------------------------------*/
4491 #if 0
4492 static void pCodeReadCodeTable(void)
4493 {
4494   pBlock *pb;
4495
4496   fprintf(stderr, " %s\n",__FUNCTION__);
4497
4498   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4499
4500   pic16_addpBlock(pb);
4501
4502   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4503   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4504   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4505   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4506
4507   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4508   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4509   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4510   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4511
4512
4513 }
4514 #endif
4515 /*-----------------------------------------------------------------*/
4516 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4517 /*-----------------------------------------------------------------*/
4518 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4519 {
4520
4521   if(!pc)
4522     return;
4523
4524   if(!pb->pcHead) {
4525     /* If this is the first pcode to be added to a block that
4526      * was initialized with a NULL pcode, then go ahead and
4527      * make this pcode the head and tail */
4528     pb->pcHead  = pb->pcTail = pc;
4529   } else {
4530     //    if(pb->pcTail)
4531     pb->pcTail->next = pc;
4532
4533     pc->prev = pb->pcTail;
4534     pc->pb = pb;
4535
4536     pb->pcTail = pc;
4537   }
4538 }
4539
4540 /*-----------------------------------------------------------------*/
4541 /* pic16_addpBlock - place a pBlock into the pFile                 */
4542 /*-----------------------------------------------------------------*/
4543 void pic16_addpBlock(pBlock *pb)
4544 {
4545   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4546
4547   if(!the_pFile) {
4548     /* First time called, we'll pass through here. */
4549     //_ALLOC(the_pFile,sizeof(pFile));
4550     the_pFile = Safe_calloc(1,sizeof(pFile));
4551     the_pFile->pbHead = the_pFile->pbTail = pb;
4552     the_pFile->functions = NULL;
4553     return;
4554   }
4555
4556   the_pFile->pbTail->next = pb;
4557   pb->prev = the_pFile->pbTail;
4558   pb->next = NULL;
4559   the_pFile->pbTail = pb;
4560 }
4561
4562 /*-----------------------------------------------------------------*/
4563 /* removepBlock - remove a pBlock from the pFile                   */
4564 /*-----------------------------------------------------------------*/
4565 static void removepBlock(pBlock *pb)
4566 {
4567   pBlock *pbs;
4568
4569   if(!the_pFile)
4570     return;
4571
4572
4573   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4574
4575   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4576     if(pbs == pb) {
4577
4578       if(pbs == the_pFile->pbHead)
4579         the_pFile->pbHead = pbs->next;
4580
4581       if (pbs == the_pFile->pbTail)
4582         the_pFile->pbTail = pbs->prev;
4583
4584       if(pbs->next)
4585         pbs->next->prev = pbs->prev;
4586
4587       if(pbs->prev)
4588         pbs->prev->next = pbs->next;
4589
4590       return;
4591
4592     }
4593   }
4594
4595   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4596
4597 }
4598
4599 /*-----------------------------------------------------------------*/
4600 /* printpCode - write the contents of a pCode to a file            */
4601 /*-----------------------------------------------------------------*/
4602 static void printpCode(FILE *of, pCode *pc)
4603 {
4604
4605   if(!pc || !of)
4606     return;
4607
4608   if(pc->print) {
4609     pc->print(of,pc);
4610     return;
4611   }
4612
4613   fprintf(of,"warning - unable to print pCode\n");
4614 }
4615
4616 /*-----------------------------------------------------------------*/
4617 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4618 /*-----------------------------------------------------------------*/
4619 void pic16_printpBlock(FILE *of, pBlock *pb)
4620 {
4621   pCode *pc;
4622
4623         if(!pb)return;
4624
4625         if(!of)of=stderr;
4626
4627         for(pc = pb->pcHead; pc; pc = pc->next) {
4628                 if(isPCF(pc) && PCF(pc)->fname) {
4629                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4630                         if(pb->dbName == 'A') {
4631                           absSym *ab;
4632                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4633 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4634                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4635 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4636                                                 if(ab->address != -1)
4637                                                   fprintf(of, "\t0X%06X", ab->address);
4638                                                 break;
4639                                         }
4640                                 }
4641                         }
4642                         fprintf(of, "\n");
4643                 }
4644                 printpCode(of,pc);
4645         }
4646 }
4647
4648 /*-----------------------------------------------------------------*/
4649 /*                                                                 */
4650 /*       pCode processing                                          */
4651 /*                                                                 */
4652 /*                                                                 */
4653 /*                                                                 */
4654 /*-----------------------------------------------------------------*/
4655 pCode * pic16_findNextInstruction(pCode *pci);
4656 pCode * pic16_findPrevInstruction(pCode *pci);
4657
4658 void pic16_unlinkpCode(pCode *pc)
4659 {
4660   pCode *prev;
4661
4662   if(pc) {
4663 #ifdef PCODE_DEBUG
4664     fprintf(stderr,"Unlinking: ");
4665     printpCode(stderr, pc);
4666 #endif
4667     if(pc->prev)
4668       pc->prev->next = pc->next;
4669     if(pc->next)
4670       pc->next->prev = pc->prev;
4671
4672     /* move C source line down (or up) */
4673     if (isPCI(pc) && PCI(pc)->cline) {
4674       prev = pic16_findNextInstruction (pc->next);
4675       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4676         PCI(prev)->cline = PCI(pc)->cline;
4677       } else {
4678         prev = pic16_findPrevInstruction (pc->prev);
4679         if (prev && isPCI(prev) && !PCI(prev)->cline)
4680           PCI(prev)->cline = PCI(pc)->cline;
4681       }
4682     }
4683     pc->prev = pc->next = NULL;
4684   }
4685 }
4686
4687 /*-----------------------------------------------------------------*/
4688 /*-----------------------------------------------------------------*/
4689
4690 static void genericDestruct(pCode *pc)
4691 {
4692
4693   pic16_unlinkpCode(pc);
4694
4695   if(isPCI(pc)) {
4696     /* For instructions, tell the register (if there's one used)
4697      * that it's no longer needed */
4698     regs *reg = pic16_getRegFromInstruction(pc);
4699     if(reg)
4700       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4701
4702         if(PCI(pc)->is2MemOp) {
4703                 reg = pic16_getRegFromInstruction2(pc);
4704                 if(reg)
4705                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4706         }
4707   }
4708
4709   /* Instead of deleting the memory used by this pCode, mark
4710    * the object as bad so that if there's a pointer to this pCode
4711    * dangling around somewhere then (hopefully) when the type is
4712    * checked we'll catch it.
4713    */
4714
4715   pc->type = PC_BAD;
4716   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4717
4718   //Safe_free(pc);
4719 }
4720
4721
4722 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4723 /*-----------------------------------------------------------------*/
4724 /*-----------------------------------------------------------------*/
4725 /* modifiers for constant immediate */
4726 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4727
4728 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4729 {
4730     regs *r;
4731     static char b[128];
4732     char *s;
4733     int use_buffer = 1;    // copy the string to the passed buffer pointer
4734
4735     if(!buffer) {
4736         buffer = b;
4737         size = sizeof(b);
4738         use_buffer = 0;     // Don't bother copying the string to the buffer.
4739     }
4740
4741     if(pcop) {
4742
4743         switch(pcop->type) {
4744             case PO_W:
4745             case PO_WREG:
4746             case PO_PRODL:
4747             case PO_PRODH:
4748             case PO_INDF0:
4749             case PO_FSR0:
4750                 if(use_buffer) {
4751                     SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4752                     return (buffer);
4753                 }
4754                 return (PCOR(pcop)->r->name);
4755                 break;
4756             case PO_GPR_TEMP:
4757                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4758                 if(use_buffer) {
4759                     SNPRINTF(buffer,size,"%s",r->name);
4760                     return (buffer);
4761                 }
4762                 return (r->name);
4763                 break;
4764
4765             case PO_IMMEDIATE:
4766                 s = buffer;
4767                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4768                     if(PCOI(pcop)->index) {
4769                         SNPRINTF(s,size, "%s(%s + %d)",
4770                                 immdmod[ PCOI(pcop)->offset ],
4771                                 pcop->name,
4772                                 PCOI(pcop)->index);
4773                     } else {
4774                         SNPRINTF(s,size,"%s(%s)",
4775                                 immdmod[ PCOI(pcop)->offset ],
4776                                 pcop->name);
4777                     }
4778                 } else {
4779                     if(PCOI(pcop)->index) {
4780                         SNPRINTF(s,size, "%s(%s + %d)",
4781                                 immdmod[ 0 ],
4782                                 pcop->name,
4783                                 PCOI(pcop)->index);
4784                     } else {
4785                         SNPRINTF(s,size, "%s(%s)",
4786                                 immdmod[ 0 ],
4787                                 pcop->name);
4788                     }
4789                 }
4790                 return (buffer);
4791                 break;
4792
4793             case PO_GPR_REGISTER:
4794             case PO_DIR:
4795                 s = buffer;
4796                 //size = sizeof(buffer);
4797                 if( PCOR(pcop)->instance) {
4798                     SNPRINTF(s,size,"(%s + %d)",
4799                             pcop->name,
4800                             PCOR(pcop)->instance );
4801                 } else {
4802                     SNPRINTF(s,size,"%s",pcop->name);
4803                 }
4804                 return (buffer);
4805                 break;
4806
4807             case PO_GPR_BIT:
4808                 s = buffer;
4809                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4810                     SNPRINTF(s, size, "%s", pcop->name);
4811                 } else {
4812                     if(PCORB(pcop)->pcor.instance)
4813                         SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4814                     else
4815                         SNPRINTF(s, size, "%s", pcop->name);
4816                 }
4817                 return (buffer);
4818                 break;
4819
4820             case PO_TWO_OPS:
4821                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4822                 break;
4823
4824             default:
4825                 if(pcop->name) {
4826                     if(use_buffer) {
4827                         SNPRINTF(buffer,size,"%s",pcop->name);
4828                         return (buffer);
4829                     }
4830                     return (pcop->name);
4831                 }
4832
4833         }
4834         return ("unhandled type for op1");
4835     }
4836
4837     return ("NO operand1");
4838 }
4839
4840 /*-----------------------------------------------------------------*/
4841 /* pic16_get_op2 - variant to support two memory operand commands  */
4842 /*-----------------------------------------------------------------*/
4843 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4844 {
4845
4846   if(pcop && pcop->type == PO_TWO_OPS) {
4847     return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4848   }
4849
4850   return "NO operand2";
4851 }
4852
4853 /*-----------------------------------------------------------------*/
4854 /*-----------------------------------------------------------------*/
4855 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4856 {
4857
4858   if(pcc )
4859     return pic16_get_op(pcc->pcop,NULL,0);
4860
4861   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated
4862    *   return ("ERROR Null: "__FUNCTION__);
4863    */
4864   return ("ERROR Null: pic16_get_op_from_instruction");
4865
4866 }
4867
4868 /*-----------------------------------------------------------------*/
4869 /*-----------------------------------------------------------------*/
4870 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4871 {
4872
4873   fprintf(of,"pcodeopprint- not implemented\n");
4874 }
4875
4876 /*-----------------------------------------------------------------*/
4877 /* pic16_pCode2str - convert a pCode instruction to string               */
4878 /*-----------------------------------------------------------------*/
4879 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4880 {
4881     char *s = str;
4882     regs *r;
4883
4884 #if 0
4885     if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4886         fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4887                 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4888         //              exit(EXIT_FAILURE);
4889     }
4890 #endif
4891
4892     switch(pc->type) {
4893
4894         case PC_OPCODE:
4895             SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4896             size -= strlen(s);
4897             s += strlen(s);
4898
4899             if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4900
4901                 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4902                 {
4903                     /* split into two phases due to static buffer in pic16_get_op() */
4904                     SNPRINTF(s, size, "%s",
4905                             pic16_get_op((PCI(pc)->pcop), NULL, 0));
4906                     size -= strlen(s);
4907                     s += strlen(s);
4908                     SNPRINTF(s, size, ", %s",
4909                             pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4910                     break;
4911                 }
4912
4913                 if(PCI(pc)->is2LitOp) {
4914                     SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4915                     break;
4916                 }
4917
4918                 if(PCI(pc)->isBitInst) {
4919                     if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4920                         if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4921                             SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4922                                     PCI(pc)->pcop->name ,
4923                                     PCI(pc)->pcop->name );
4924                         else
4925                             SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4926                                     (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4927
4928                     } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4929                         SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4930                     } else
4931                         SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4932                 } else {
4933
4934                     if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4935                         if( PCI(pc)->num_ops == 3)
4936                             SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4937                         else
4938                             SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4939                     } else {
4940                         SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4941                     }
4942                 }
4943
4944                 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4945                     size -= strlen(s);
4946                     s += strlen(s);
4947                     if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4948                         SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4949                         size -= strlen(s);
4950                         s += strlen(s);
4951                     }
4952
4953                     r = pic16_getRegFromInstruction(pc);
4954
4955                     if(PCI(pc)->isAccess) {
4956                         static char *bank_spec[2][2] = {
4957                             { "", ", ACCESS" },  /* gpasm uses access bank by default */
4958                             { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4959                         };
4960
4961                         SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4962                     }
4963                 }
4964             }
4965             break;
4966
4967         case PC_COMMENT:
4968             /* assuming that comment ends with a \n */
4969             SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4970             break;
4971
4972         case PC_INFO:
4973             SNPRINTF(s,size,"; info ==>");
4974             size -= strlen(s);
4975             s += strlen(s);
4976             switch( PCINF(pc)->type ) {
4977                 case INF_OPTIMIZATION:
4978                     SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4979                     break;
4980                 case INF_LOCALREGS:
4981                     SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4982                     break;
4983             }; break;
4984
4985         case PC_INLINE:
4986             /* assuming that inline code ends with a \n */
4987             SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4988             break;
4989
4990         case PC_LABEL:
4991             SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4992             break;
4993         case PC_FUNCTION:
4994             SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
4995             break;
4996         case PC_WILD:
4997             SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
4998             break;
4999         case PC_FLOW:
5000             SNPRINTF(s,size,";\t--FLOW change\n");
5001             break;
5002         case PC_CSOURCE:
5003             SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5004                     PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5005             break;
5006         case PC_ASMDIR:
5007             if(PCAD(pc)->directive) {
5008                 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5009             } else
5010                 if(PCAD(pc)->arg) {
5011                     /* special case to handle inline labels without a tab */
5012                     SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5013                 }
5014             break;
5015
5016         case PC_BAD:
5017             SNPRINTF(s,size,";A bad pCode is being used\n");
5018             break;
5019     }
5020
5021     return str;
5022 }
5023
5024 /*-----------------------------------------------------------------*/
5025 /* genericPrint - the contents of a pCode to a file                */
5026 /*-----------------------------------------------------------------*/
5027 static void genericPrint(FILE *of, pCode *pc)
5028 {
5029
5030   if(!pc || !of)
5031     return;
5032
5033   switch(pc->type) {
5034   case PC_COMMENT:
5035 //    fputs(((pCodeComment *)pc)->comment, of);
5036     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5037     break;
5038
5039   case PC_INFO:
5040     {
5041       pBranch *pbl = PCI(pc)->label;
5042       while(pbl && pbl->pc) {
5043         if(pbl->pc->type == PC_LABEL)
5044           pCodePrintLabel(of, pbl->pc);
5045         pbl = pbl->next;
5046       }
5047     }
5048
5049     if(pic16_pcode_verbose) {
5050       fprintf(of, "; info ==>");
5051       switch(((pCodeInfo *)pc)->type) {
5052         case INF_OPTIMIZATION:
5053               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5054               break;
5055         case INF_LOCALREGS:
5056               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5057               break;
5058         }
5059     };
5060
5061     break;
5062
5063   case PC_INLINE:
5064     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5065      break;
5066
5067   case PC_OPCODE:
5068     // If the opcode has a label, print that first
5069     {
5070       pBranch *pbl = PCI(pc)->label;
5071       while(pbl && pbl->pc) {
5072         if(pbl->pc->type == PC_LABEL)
5073           pCodePrintLabel(of, pbl->pc);
5074         pbl = pbl->next;
5075       }
5076     }
5077
5078     if(PCI(pc)->cline)
5079       genericPrint(of,PCODE(PCI(pc)->cline));
5080
5081     {
5082       char str[256];
5083
5084       pic16_pCode2str(str, 256, pc);
5085
5086       fprintf(of,"%s",str);
5087       /* Debug */
5088       if(pic16_debug_verbose) {
5089         fprintf(of, "\t;key=%03x",pc->seq);
5090         if(PCI(pc)->pcflow)
5091           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5092       }
5093     }
5094     fprintf(of, "\n");
5095     break;
5096
5097   case PC_WILD:
5098     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5099     if(PCW(pc)->pci.label)
5100       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5101
5102     if(PCW(pc)->operand) {
5103       fprintf(of,";\toperand  ");
5104       pCodeOpPrint(of,PCW(pc)->operand );
5105     }
5106     break;
5107
5108   case PC_FLOW:
5109     if(pic16_debug_verbose) {
5110       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5111       if(PCFL(pc)->ancestor)
5112         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5113       fprintf(of,"\n");
5114
5115     }
5116     break;
5117
5118   case PC_CSOURCE:
5119 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5120     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5121         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5122
5123     break;
5124
5125   case PC_ASMDIR:
5126         {
5127           pBranch *pbl = PCAD(pc)->pci.label;
5128                 while(pbl && pbl->pc) {
5129                         if(pbl->pc->type == PC_LABEL)
5130                                 pCodePrintLabel(of, pbl->pc);
5131                         pbl = pbl->next;
5132                 }
5133         }
5134         if(PCAD(pc)->directive) {
5135                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5136         } else
5137         if(PCAD(pc)->arg) {
5138                 /* special case to handle inline labels without tab */
5139                 fprintf(of, "%s\n", PCAD(pc)->arg);
5140         }
5141         break;
5142
5143   case PC_LABEL:
5144   default:
5145     fprintf(of,"unknown pCode type %d\n",pc->type);
5146   }
5147
5148 }
5149
5150 /*-----------------------------------------------------------------*/
5151 /* pCodePrintFunction - prints function begin/end                  */
5152 /*-----------------------------------------------------------------*/
5153
5154 static void pCodePrintFunction(FILE *of, pCode *pc)
5155 {
5156
5157   if(!pc || !of)
5158     return;
5159
5160 #if 0
5161   if( ((pCodeFunction *)pc)->modname)
5162     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5163 #endif
5164
5165   if(!PCF(pc)->absblock) {
5166       if(PCF(pc)->fname) {
5167       pBranch *exits = PCF(pc)->to;
5168       int i=0;
5169
5170       fprintf(of,"%s:", PCF(pc)->fname);
5171
5172       if(pic16_pcode_verbose)
5173         fprintf(of, "\t;Function start");
5174
5175       fprintf(of, "\n");
5176
5177       while(exits) {
5178         i++;
5179         exits = exits->next;
5180       }
5181       //if(i) i--;
5182
5183       if(pic16_pcode_verbose)
5184         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5185
5186     } else {
5187         if((PCF(pc)->from &&
5188                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5189                 PCF(PCF(pc)->from->pc)->fname) ) {
5190
5191                 if(pic16_pcode_verbose)
5192                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5193         } else {
5194                 if(pic16_pcode_verbose)
5195                         fprintf(of,"; exit point [can't find entry point]\n");
5196         }
5197         fprintf(of, "\n");
5198     }
5199   }
5200 }
5201 /*-----------------------------------------------------------------*/
5202 /* pCodePrintLabel - prints label                                  */
5203 /*-----------------------------------------------------------------*/
5204
5205 static void pCodePrintLabel(FILE *of, pCode *pc)
5206 {
5207
5208   if(!pc || !of)
5209     return;
5210
5211   if(PCL(pc)->label)
5212     fprintf(of,"%s:\n",PCL(pc)->label);
5213   else if (PCL(pc)->key >=0)
5214     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5215   else
5216     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5217
5218 }
5219 /*-----------------------------------------------------------------*/
5220 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5221 /*                         remove it if it is found.               */
5222 /*-----------------------------------------------------------------*/
5223 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5224 {
5225   pBranch *b, *bprev;
5226
5227
5228   bprev = NULL;
5229
5230   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5231     b = PCI(pcl)->label;
5232   else {
5233     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5234     exit(1);
5235
5236   }
5237
5238   //fprintf (stderr, "%s \n",__FUNCTION__);
5239   //pcl->print(stderr,pcl);
5240   //pc->print(stderr,pc);
5241   while(b) {
5242     if(b->pc == pc) {
5243       //fprintf (stderr, "found label\n");
5244       //pc->print(stderr, pc);
5245
5246       /* Found a label */
5247       if(bprev) {
5248         bprev->next = b->next;  /* Not first pCode in chain */
5249 //      Safe_free(b);
5250       } else {
5251         pc->destruct(pc);
5252         PCI(pcl)->label = b->next;   /* First pCode in chain */
5253 //      Safe_free(b);
5254       }
5255       return;  /* A label can't occur more than once */
5256     }
5257     bprev = b;
5258     b = b->next;
5259   }
5260
5261 }
5262
5263 /*-----------------------------------------------------------------*/
5264 /*-----------------------------------------------------------------*/
5265 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5266 {
5267   pBranch *b;
5268
5269   if(!h)
5270     return n;
5271
5272   if(h == n)
5273     return n;
5274
5275   b = h;
5276   while(b->next)
5277     b = b->next;
5278
5279   b->next = n;
5280
5281   return h;
5282
5283 }
5284 /*-----------------------------------------------------------------*/
5285 /* pBranchLink - given two pcodes, this function will link them    */
5286 /*               together through their pBranches                  */
5287 /*-----------------------------------------------------------------*/
5288 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5289 {
5290   pBranch *b;
5291
5292   // Declare a new branch object for the 'from' pCode.
5293
5294   //_ALLOC(b,sizeof(pBranch));
5295   b = Safe_calloc(1,sizeof(pBranch));
5296   b->pc = PCODE(t);             // The link to the 'to' pCode.
5297   b->next = NULL;
5298
5299   f->to = pic16_pBranchAppend(f->to,b);
5300
5301   // Now do the same for the 'to' pCode.
5302
5303   //_ALLOC(b,sizeof(pBranch));
5304   b = Safe_calloc(1,sizeof(pBranch));
5305   b->pc = PCODE(f);
5306   b->next = NULL;
5307
5308   t->from = pic16_pBranchAppend(t->from,b);
5309
5310 }
5311
5312 #if 1
5313 /*-----------------------------------------------------------------*/
5314 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5315 /*               a pCode                                           */
5316 /*-----------------------------------------------------------------*/
5317 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5318 {
5319   while(pb) {
5320
5321     if(pb->pc == pc)
5322       return pb;
5323
5324     pb = pb->next;
5325   }
5326
5327   return NULL;
5328 }
5329
5330 /*-----------------------------------------------------------------*/
5331 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5332 /*-----------------------------------------------------------------*/
5333 void pic16_pCodeUnlink(pCode *pc)
5334 {
5335   pBranch *pb1,*pb2;
5336   pCode *pc1;
5337
5338   if(!pc->prev || !pc->next) {
5339     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5340     exit(1);
5341   }
5342
5343   /* move C source line down (or up) */
5344   if (isPCI(pc) && PCI(pc)->cline) {
5345     pc1 = pic16_findNextInstruction (pc->next);
5346     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5347       PCI(pc1)->cline = PCI(pc)->cline;
5348     } else {
5349       pc1 = pic16_findPrevInstruction (pc->prev);
5350       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5351         PCI(pc1)->cline = PCI(pc)->cline;
5352     }
5353   }
5354
5355   /* first remove the pCode from the chain */
5356   pc->prev->next = pc->next;
5357   pc->next->prev = pc->prev;
5358
5359   pc->prev = pc->next = NULL;
5360
5361   /* Now for the hard part... */
5362
5363   /* Remove the branches */
5364
5365   pb1 = PCI(pc)->from;
5366   while(pb1) {
5367     pc1 = pb1->pc;    /* Get the pCode that branches to the
5368                        * one we're unlinking */
5369
5370     /* search for the link back to this pCode (the one we're
5371      * unlinking) */
5372     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5373       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5374
5375       /* if the pCode we're unlinking contains multiple 'to'
5376        * branches (e.g. this a skip instruction) then we need
5377        * to copy these extra branches to the chain. */
5378       if(PCI(pc)->to->next)
5379         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5380     }
5381
5382     pb1 = pb1->next;
5383   }
5384
5385
5386 }
5387 #endif
5388 /*-----------------------------------------------------------------*/
5389 /*-----------------------------------------------------------------*/
5390 #if 0
5391 static void genericAnalyze(pCode *pc)
5392 {
5393   switch(pc->type) {
5394   case PC_WILD:
5395   case PC_COMMENT:
5396     return;
5397   case PC_LABEL:
5398   case PC_FUNCTION:
5399   case PC_OPCODE:
5400     {
5401       // Go through the pCodes that are in pCode chain and link
5402       // them together through the pBranches. Note, the pCodes
5403       // are linked together as a contiguous stream like the
5404       // assembly source code lines. The linking here mimics this
5405       // except that comments are not linked in.
5406       //
5407       pCode *npc = pc->next;
5408       while(npc) {
5409         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5410           pBranchLink(pc,npc);
5411           return;
5412         } else
5413           npc = npc->next;
5414       }
5415       /* reached the end of the pcode chain without finding
5416        * an instruction we could link to. */
5417     }
5418     break;
5419   case PC_FLOW:
5420     fprintf(stderr,"analyze PC_FLOW\n");
5421
5422     return;
5423   case PC_BAD:
5424     fprintf(stderr,,";A bad pCode is being used\n");
5425
5426   }
5427 }
5428 #endif
5429
5430 /*-----------------------------------------------------------------*/
5431 /*-----------------------------------------------------------------*/
5432 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5433 {
5434   pBranch *pbr;
5435
5436   if(pc->type == PC_LABEL) {
5437     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5438       return TRUE;
5439   }
5440   if((pc->type == PC_OPCODE)
5441         || (pc->type == PC_ASMDIR)
5442         ) {
5443     pbr = PCI(pc)->label;
5444     while(pbr) {
5445       if(pbr->pc->type == PC_LABEL) {
5446         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5447           return TRUE;
5448       }
5449       pbr = pbr->next;
5450     }
5451   }
5452
5453   return FALSE;
5454 }
5455
5456 /*-----------------------------------------------------------------*/
5457 /*-----------------------------------------------------------------*/
5458 static int checkLabel(pCode *pc)
5459 {
5460   pBranch *pbr;
5461
5462   if(pc && isPCI(pc)) {
5463     pbr = PCI(pc)->label;
5464     while(pbr) {
5465       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5466         return TRUE;
5467
5468       pbr = pbr->next;
5469     }
5470   }
5471
5472   return FALSE;
5473 }
5474
5475 /*-----------------------------------------------------------------*/
5476 /* findLabelinpBlock - Search the pCode for a particular label     */
5477 /*-----------------------------------------------------------------*/
5478 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5479 {
5480   pCode  *pc;
5481
5482   if(!pb)
5483     return NULL;
5484
5485   for(pc = pb->pcHead; pc; pc = pc->next)
5486     if(compareLabel(pc,pcop_label))
5487       return pc;
5488
5489   return NULL;
5490 }
5491 #if 0
5492 /*-----------------------------------------------------------------*/
5493 /* findLabel - Search the pCode for a particular label             */
5494 /*-----------------------------------------------------------------*/
5495 static pCode * findLabel(pCodeOpLabel *pcop_label)
5496 {
5497   pBlock *pb;
5498   pCode  *pc;
5499
5500   if(!the_pFile)
5501     return NULL;
5502
5503   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5504     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5505       return pc;
5506   }
5507
5508   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5509   return NULL;
5510 }
5511 #endif
5512 /*-----------------------------------------------------------------*/
5513 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5514 /*                 in the linked list                              */
5515 /*-----------------------------------------------------------------*/
5516 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5517 {
5518
5519   while(pc) {
5520     if(pc->type == pct)
5521       return pc;
5522
5523     pc = pc->next;
5524   }
5525
5526   return NULL;
5527 }
5528
5529 /*-----------------------------------------------------------------*/
5530 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5531 /*                 in the linked list                              */
5532 /*-----------------------------------------------------------------*/
5533 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5534 {
5535
5536   while(pc) {
5537     if(pc->type == pct)
5538       return pc;
5539
5540     pc = pc->prev;
5541   }
5542
5543   return NULL;
5544 }
5545
5546
5547 //#define PCODE_DEBUG
5548 /*-----------------------------------------------------------------*/
5549 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5550 /*                       in the linked list                        */
5551 /*-----------------------------------------------------------------*/
5552 pCode * pic16_findNextInstruction(pCode *pci)
5553 {
5554   pCode *pc = pci;
5555
5556   while(pc) {
5557     if((pc->type == PC_OPCODE)
5558         || (pc->type == PC_WILD)
5559         || (pc->type == PC_ASMDIR)
5560         )
5561       return pc;
5562
5563 #ifdef PCODE_DEBUG
5564     fprintf(stderr,"pic16_findNextInstruction:  ");
5565     printpCode(stderr, pc);
5566 #endif
5567     pc = pc->next;
5568   }
5569
5570   //fprintf(stderr,"Couldn't find instruction\n");
5571   return NULL;
5572 }
5573
5574 /*-----------------------------------------------------------------*/
5575 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5576 /*                       in the linked list                        */
5577 /*-----------------------------------------------------------------*/
5578 pCode * pic16_findPrevInstruction(pCode *pci)
5579 {
5580   pCode *pc = pci;
5581
5582   while(pc) {
5583
5584     if((pc->type == PC_OPCODE)
5585         || (pc->type == PC_WILD)
5586         || (pc->type == PC_ASMDIR)
5587         )
5588       return pc;
5589
5590
5591 #ifdef PCODE_DEBUG
5592     fprintf(stderr,"pic16_findPrevInstruction:  ");
5593     printpCode(stderr, pc);
5594 #endif
5595     pc = pc->prev;
5596   }
5597
5598   //fprintf(stderr,"Couldn't find instruction\n");
5599   return NULL;
5600 }
5601
5602 #undef PCODE_DEBUG
5603
5604 #if 0
5605 /*-----------------------------------------------------------------*/
5606 /* findFunctionEnd - given a pCode find the end of the function    */
5607 /*                   that contains it                              */
5608 /*-----------------------------------------------------------------*/
5609 static pCode * findFunctionEnd(pCode *pc)
5610 {
5611
5612   while(pc) {
5613     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5614       return pc;
5615
5616     pc = pc->next;
5617   }
5618
5619   fprintf(stderr,"Couldn't find function end\n");
5620   return NULL;
5621 }
5622 #endif
5623 #if 0
5624 /*-----------------------------------------------------------------*/
5625 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5626 /*                instruction with which it is associated.         */
5627 /*-----------------------------------------------------------------*/
5628 static void AnalyzeLabel(pCode *pc)
5629 {
5630
5631   pic16_pCodeUnlink(pc);
5632
5633 }
5634 #endif
5635
5636 #if 0
5637 static void AnalyzeGOTO(pCode *pc)
5638 {
5639
5640   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5641
5642 }
5643
5644 static void AnalyzeSKIP(pCode *pc)
5645 {
5646
5647   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5648   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5649
5650 }
5651
5652 static void AnalyzeRETURN(pCode *pc)
5653 {
5654
5655   //  branch_link(pc,findFunctionEnd(pc->next));
5656
5657 }
5658
5659 #endif
5660
5661 /*-------------------------------------------------------------------*/
5662 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5663 /*                            if one is present. This is the common  */
5664 /*                            part of pic16_getRegFromInstruction(2) */
5665 /*-------------------------------------------------------------------*/
5666
5667 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5668   if (!pcop) return NULL;
5669
5670   switch(pcop->type) {
5671   case PO_PRODL:
5672   case PO_PRODH:
5673   case PO_INDF0:
5674   case PO_FSR0:
5675   case PO_W:
5676   case PO_WREG:
5677   case PO_STATUS:
5678   case PO_INTCON:
5679   case PO_PCL:
5680   case PO_PCLATH:
5681   case PO_PCLATU:
5682   case PO_BSR:
5683     return PCOR(pcop)->r;
5684
5685   case PO_SFR_REGISTER:
5686     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5687     return PCOR(pcop)->r;
5688
5689   case PO_BIT:
5690   case PO_GPR_TEMP:
5691 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5692     return PCOR(pcop)->r;
5693
5694   case PO_IMMEDIATE:
5695 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5696
5697     if(PCOI(pcop)->r)
5698       return (PCOI(pcop)->r);
5699     else
5700       return NULL;
5701
5702   case PO_GPR_BIT:
5703     return PCOR(pcop)->r;
5704
5705   case PO_GPR_REGISTER:
5706   case PO_DIR:
5707 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5708     return PCOR(pcop)->r;
5709
5710   case PO_LITERAL:
5711     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5712     break;
5713
5714   case PO_REL_ADDR:
5715   case PO_LABEL:
5716     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5717     break;
5718
5719   case PO_CRY:
5720   case PO_STR:
5721     /* this should never turn up */
5722     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5723     break;
5724
5725   case PO_WILD:
5726     break;
5727
5728   case PO_TWO_OPS:
5729     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5730     break;
5731
5732   default:
5733         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5734 //      assert( 0 );
5735         break;
5736   }
5737
5738   return NULL;
5739 }
5740
5741 /*-----------------------------------------------------------------*/
5742 /*-----------------------------------------------------------------*/
5743 regs * pic16_getRegFromInstruction(pCode *pc)
5744 {
5745   if(!pc                   ||
5746      !isPCI(pc)            ||
5747      !PCI(pc)->pcop        ||
5748      PCI(pc)->num_ops == 0 ||
5749      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5750     return NULL;
5751
5752 #if 0
5753   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5754         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5755 #endif
5756
5757   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5758 }
5759
5760 /*-------------------------------------------------------------------------------*/
5761 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5762 /*-------------------------------------------------------------------------------*/
5763 regs * pic16_getRegFromInstruction2(pCode *pc)
5764 {
5765
5766   if(!pc                   ||
5767      !isPCI(pc)            ||
5768      !PCI(pc)->pcop        ||
5769      PCI(pc)->num_ops == 0 ||
5770      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5771     return NULL;
5772
5773   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5774     return NULL;
5775
5776 #if 0
5777   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5778         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5779 #endif
5780
5781   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5782 }
5783
5784 /*-----------------------------------------------------------------*/
5785 /*-----------------------------------------------------------------*/
5786
5787 static void AnalyzepBlock(pBlock *pb)
5788 {
5789   pCode *pc;
5790
5791   if(!pb)
5792     return;
5793
5794   /* Find all of the registers used in this pBlock
5795    * by looking at each instruction and examining it's
5796    * operands
5797    */
5798   for(pc = pb->pcHead; pc; pc = pc->next) {
5799
5800     /* Is this an instruction with operands? */
5801     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5802
5803       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5804
5805         /* Loop through all of the registers declared so far in
5806            this block and see if we find this one there */
5807
5808         regs *r = setFirstItem(pb->tregisters);
5809
5810         while(r) {
5811           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5812             PCOR(PCI(pc)->pcop)->r = r;
5813             break;
5814           }
5815           r = setNextItem(pb->tregisters);
5816         }
5817
5818         if(!r) {
5819           /* register wasn't found */
5820           //r = Safe_calloc(1, sizeof(regs));
5821           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5822           //addSet(&pb->tregisters, r);
5823           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5824           //PCOR(PCI(pc)->pcop)->r = r;
5825           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5826         }/* else
5827           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5828          */
5829       }
5830       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5831         if(PCOR(PCI(pc)->pcop)->r) {
5832           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5833           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5834         } else {
5835           if(PCI(pc)->pcop->name)
5836             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5837           else
5838             fprintf(stderr,"ERROR: NULL register\n");
5839         }
5840       }
5841     }
5842
5843
5844   }
5845 }
5846
5847 /*-----------------------------------------------------------------*/
5848 /* */
5849 /*-----------------------------------------------------------------*/
5850 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5851
5852 static void InsertpFlow(pCode *pc, pCode **pflow)
5853 {
5854   if(*pflow)
5855     PCFL(*pflow)->end = pc;
5856
5857   if(!pc || !pc->next)
5858     return;
5859
5860   *pflow = pic16_newpCodeFlow();
5861   pic16_pCodeInsertAfter(pc, *pflow);
5862 }
5863
5864 /*-----------------------------------------------------------------*/
5865 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5866 /*                         the flow blocks.                        */
5867 /*
5868  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5869  * point the instruction flow changes.
5870  */
5871 /*-----------------------------------------------------------------*/
5872 void pic16_BuildFlow(pBlock *pb)
5873 {
5874   pCode *pc;
5875   pCode *last_pci=NULL;
5876   pCode *pflow=NULL;
5877   int seq = 0;
5878
5879   if(!pb)
5880     return;
5881
5882   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5883   /* Insert a pCodeFlow object at the beginning of a pBlock */
5884
5885   InsertpFlow(pb->pcHead, &pflow);
5886
5887   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5888   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5889   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5890   //pb->pcHead = pflow;        /* Make the Flow object the head */
5891   //pflow->pb = pb;
5892
5893   for( pc = pic16_findNextInstruction(pb->pcHead);
5894        pc != NULL;
5895        pc=pic16_findNextInstruction(pc)) {
5896
5897     pc->seq = seq++;
5898     PCI(pc)->pcflow = PCFL(pflow);
5899
5900     //fprintf(stderr," build: ");
5901     //pflow->print(stderr,pflow);
5902
5903     if (checkLabel(pc)) {
5904
5905       /* This instruction marks the beginning of a
5906        * new flow segment */
5907
5908       pc->seq = 0;
5909       seq = 1;
5910
5911       /* If the previous pCode is not a flow object, then
5912        * insert a new flow object. (This check prevents
5913        * two consecutive flow objects from being insert in
5914        * the case where a skip instruction preceeds an
5915        * instruction containing a label.) */
5916
5917       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5918         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5919
5920       PCI(pc)->pcflow = PCFL(pflow);
5921
5922     }
5923
5924     if( PCI(pc)->isSkip) {
5925
5926       /* The two instructions immediately following this one
5927        * mark the beginning of a new flow segment */
5928
5929       while(pc && PCI(pc)->isSkip) {
5930
5931         PCI(pc)->pcflow = PCFL(pflow);
5932         pc->seq = seq-1;
5933         seq = 1;
5934
5935         InsertpFlow(pc, &pflow);
5936         pc=pic16_findNextInstruction(pc->next);
5937       }
5938
5939       seq = 0;
5940
5941       if(!pc)
5942         break;
5943
5944       PCI(pc)->pcflow = PCFL(pflow);
5945       pc->seq = 0;
5946       InsertpFlow(pc, &pflow);
5947
5948     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
5949
5950       InsertpFlow(pc, &pflow);
5951       seq = 0;
5952
5953     }
5954     last_pci = pc;
5955     pc = pc->next;
5956   }
5957
5958   //fprintf (stderr,",end seq %d",GpcFlowSeq);
5959   if(pflow)
5960     PCFL(pflow)->end = pb->pcTail;
5961 }
5962
5963 /*-------------------------------------------------------------------*/
5964 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5965 /*                           the flow blocks.                        */
5966 /*
5967  * unBuildFlow removes pCodeFlow objects from a pCode chain
5968  */
5969 /*-----------------------------------------------------------------*/
5970 static void unBuildFlow(pBlock *pb)
5971 {
5972   pCode *pc,*pcnext;
5973
5974   if(!pb)
5975     return;
5976
5977   pc = pb->pcHead;
5978
5979   while(pc) {
5980     pcnext = pc->next;
5981
5982     if(isPCI(pc)) {
5983
5984       pc->seq = 0;
5985       if(PCI(pc)->pcflow) {
5986         //Safe_free(PCI(pc)->pcflow);
5987         PCI(pc)->pcflow = NULL;
5988       }
5989
5990     } else if(isPCFL(pc) )
5991       pc->destruct(pc);
5992
5993     pc = pcnext;
5994   }
5995
5996
5997 }
5998 #if 0
5999 /*-----------------------------------------------------------------*/
6000 /*-----------------------------------------------------------------*/
6001 static void dumpCond(int cond)
6002 {
6003
6004   static char *pcc_str[] = {
6005     //"PCC_NONE",
6006     "PCC_REGISTER",
6007     "PCC_C",
6008     "PCC_Z",
6009     "PCC_DC",
6010     "PCC_OV",
6011     "PCC_N",
6012     "PCC_W",
6013     "PCC_EXAMINE_PCOP",
6014     "PCC_LITERAL",
6015     "PCC_REL_ADDR"
6016   };
6017
6018   int ncond = sizeof(pcc_str) / sizeof(char *);
6019   int i,j;
6020
6021   fprintf(stderr, "0x%04X\n",cond);
6022
6023   for(i=0,j=1; i<ncond; i++, j<<=1)
6024     if(cond & j)
6025       fprintf(stderr, "  %s\n",pcc_str[i]);
6026
6027 }
6028 #endif
6029
6030 #if 0
6031 /*-----------------------------------------------------------------*/
6032 /*-----------------------------------------------------------------*/
6033 static void FlowStats(pCodeFlow *pcflow)
6034 {
6035
6036   pCode *pc;
6037
6038   if(!isPCFL(pcflow))
6039     return;
6040
6041   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6042
6043   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6044
6045   if(!pc) {
6046     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6047     return;
6048   }
6049
6050
6051   fprintf(stderr, "  FlowStats inCond: ");
6052   dumpCond(pcflow->inCond);
6053   fprintf(stderr, "  FlowStats outCond: ");
6054   dumpCond(pcflow->outCond);
6055
6056 }
6057 #endif
6058 /*-----------------------------------------------------------------*
6059  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6060  *    if it affects the banking bits.
6061  *
6062  * return: -1 == Banking bits are unaffected by this pCode.
6063  *
6064  * return: > 0 == Banking bits are affected.
6065  *
6066  *  If the banking bits are affected, then the returned value describes
6067  * which bits are affected and how they're affected. The lower half
6068  * of the integer maps to the bits that are affected, the upper half
6069  * to whether they're set or cleared.
6070  *
6071  *-----------------------------------------------------------------*/
6072
6073 static int isBankInstruction(pCode *pc)
6074 {
6075   regs *reg;
6076   int bank = -1;
6077
6078   if(!isPCI(pc))
6079     return 0;
6080
6081   if( PCI(pc)->op == POC_MOVLB ||
6082       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6083     bank = PCOL(pc)->lit;
6084   }
6085
6086   return 1;
6087 }
6088
6089
6090 /*-----------------------------------------------------------------*/
6091 /*-----------------------------------------------------------------*/
6092 static void FillFlow(pCodeFlow *pcflow)
6093 {
6094
6095   pCode *pc;
6096   int cur_bank;
6097
6098   if(!isPCFL(pcflow))
6099     return;
6100
6101   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6102
6103   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6104
6105   if(!pc) {
6106     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6107     return;
6108   }
6109
6110   cur_bank = -1;
6111
6112   do {
6113     isBankInstruction(pc);
6114     pc = pc->next;
6115   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6116
6117 /*
6118   if(!pc ) {
6119     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6120   } else {
6121     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6122     pc->print(stderr,pc);
6123   }
6124
6125   fprintf(stderr, "  FillFlow inCond: ");
6126   dumpCond(pcflow->inCond);
6127   fprintf(stderr, "  FillFlow outCond: ");
6128   dumpCond(pcflow->outCond);
6129 */
6130 }
6131
6132 /*-----------------------------------------------------------------*/
6133 /*-----------------------------------------------------------------*/
6134 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6135 {
6136   pCodeFlowLink *fromLink, *toLink;
6137
6138   if(!from || !to || !to->pcflow || !from->pcflow)
6139     return;
6140
6141   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6142   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6143
6144   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6145   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6146
6147 }
6148
6149 pCode *pic16_getJumptabpCode (pCode *pc) {
6150   pCode *pcinf;
6151
6152   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6153   //pc->print (stderr, pc);
6154   pcinf = pc;
6155   while (pcinf) {
6156     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6157     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6158       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6159       case OPT_JUMPTABLE_BEGIN:
6160         /* leading begin of jump table -- in one */
6161         pcinf = pic16_findPrevInstruction (pcinf);
6162         return pcinf;
6163         break;
6164
6165       case OPT_JUMPTABLE_END:
6166         /* leading end of jumptable -- not in one */
6167         return NULL;
6168         break;
6169
6170       default:
6171         /* ignore all other PCInfos */
6172         break;
6173       }
6174     }
6175     pcinf = pcinf->prev;
6176   }
6177
6178   /* no PCInfo found -- not in a jumptable */
6179   return NULL;
6180 }
6181
6182 /*-----------------------------------------------------------------*
6183  * void LinkFlow(pBlock *pb)
6184  *
6185  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6186  * non-branching segments. In LinkFlow, we determine the execution
6187  * order of these segments. For example, if one of the segments ends
6188  * with a skip, then we know that there are two possible flow segments
6189  * to which control may be passed.
6190  *-----------------------------------------------------------------*/
6191 static void LinkFlow(pBlock *pb)
6192 {
6193   pCode *pc=NULL;
6194   pCode *pcflow;
6195   pCode *pct;
6196   pCode *jumptab_pre = NULL;
6197
6198   //fprintf(stderr,"linkflow \n");
6199
6200   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6201        pcflow != NULL;
6202        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6203
6204     if(!isPCFL(pcflow))
6205       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6206
6207     //fprintf(stderr," link: ");
6208     //pcflow->print(stderr,pcflow);
6209
6210     //FillFlow(PCFL(pcflow));
6211
6212     pc = PCFL(pcflow)->end;
6213
6214     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6215     if(isPCI_SKIP(pc)) {
6216 //      fprintf(stderr, "ends with skip\n");
6217 //      pc->print(stderr,pc);
6218
6219       pct=pic16_findNextInstruction(pc->next);
6220       LinkFlow_pCode(PCI(pc),PCI(pct));
6221       pct=pic16_findNextInstruction(pct->next);
6222       LinkFlow_pCode(PCI(pc),PCI(pct));
6223       continue;
6224     }
6225
6226     if(isPCI_BRANCH(pc)) {
6227       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6228
6229       /* handle GOTOs in jumptables */
6230       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6231         /* link to previous flow */
6232         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6233         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6234       }
6235
6236       switch (PCI(pc)->op) {
6237       case POC_GOTO:
6238       case POC_BRA:
6239       case POC_RETURN:
6240       case POC_RETLW:
6241       case POC_RETFIE:
6242               /* unconditional branches -- do not link to next instruction */
6243               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6244               break;
6245
6246       case POC_CALL:
6247       case POC_RCALL:
6248               /* unconditional calls -- link to next instruction */
6249               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6250               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6251               break;
6252
6253       case POC_BC:
6254       case POC_BN:
6255       case POC_BNC:
6256       case POC_BNN:
6257       case POC_BNOV:
6258       case POC_BNZ:
6259       case POC_BOV:
6260       case POC_BZ:
6261               /* conditional branches -- also link to next instruction */
6262               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6263               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6264               break;
6265
6266       default:
6267               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6268               assert (0 && "unhandled branching instruction");
6269               break;
6270       }
6271
6272       //fprintf(stderr, "ends with branch\n  ");
6273       //pc->print(stderr,pc);
6274
6275       if(!(pcol && isPCOLAB(pcol))) {
6276         if((PCI(pc)->op != POC_RETLW)
6277                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6278
6279                 /* continue if label is '$' which assembler knows how to parse */
6280                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6281
6282                 if(pic16_pcode_verbose) {
6283                         pc->print(stderr,pc);
6284                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6285                 }
6286         }
6287         continue;
6288       }
6289
6290       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6291         LinkFlow_pCode(PCI(pc),PCI(pct));
6292       else
6293         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6294                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6295
6296 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6297
6298       continue;
6299     }
6300
6301     if(isPCI(pc)) {
6302       //fprintf(stderr, "ends with non-branching instruction:\n");
6303       //pc->print(stderr,pc);
6304
6305       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6306
6307       continue;
6308     }
6309
6310     if(pc) {
6311       //fprintf(stderr, "ends with unknown\n");
6312       //pc->print(stderr,pc);
6313       continue;
6314     }
6315
6316     //fprintf(stderr, "ends with nothing: ERROR\n");
6317
6318   }
6319 }
6320 /*-----------------------------------------------------------------*/
6321 /*-----------------------------------------------------------------*/
6322
6323 /*-----------------------------------------------------------------*/
6324 /*-----------------------------------------------------------------*/
6325 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6326 {
6327
6328   if(!pc || !pcflow)
6329     return 0;
6330
6331   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6332     return 0;
6333
6334   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6335     return 1;
6336
6337   return 0;
6338 }
6339
6340
6341
6342
6343
6344 /*-----------------------------------------------------------------*/
6345 /* insertBankSwitch - inserts a bank switch statement in the       */
6346 /*                    assembly listing                             */
6347 /*                                                                 */
6348 /* position == 0: insert before                                    */
6349 /* position == 1: insert after pc                                  */
6350 /* position == 2: like 0 but previous was a skip instruction       */
6351 /*-----------------------------------------------------------------*/
6352 pCodeOp *pic16_popGetLabel(unsigned int key);
6353 extern int pic16_labelOffset;
6354
6355 static void insertBankSwitch(unsigned char position, pCode *pc)
6356 {
6357   pCode *new_pc;
6358
6359         if(!pc)
6360                 return;
6361
6362         /* emit BANKSEL [symbol] */
6363
6364
6365         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6366
6367 //      position = 0;           // position is always before (sanity check!)
6368
6369 #if 0
6370         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6371         pc->print(stderr, pc);
6372 #endif
6373
6374         switch(position) {
6375                 case 1: {
6376                         /* insert the bank switch after this pc instruction */
6377                         pCode *pcnext = pic16_findNextInstruction(pc);
6378
6379                                 pic16_pCodeInsertAfter(pc, new_pc);
6380                                 if(pcnext)pc = pcnext;
6381                 }; break;
6382
6383                 case 0:
6384                         /* insert the bank switch BEFORE this pc instruction */
6385                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6386                         break;
6387
6388                 case 2: {
6389                           symbol *tlbl;
6390                           pCode *pcnext, *pcprev, *npci, *ppc;
6391                           PIC_OPCODE ipci;
6392                           int ofs1=0, ofs2=0, len=0;
6393
6394                         /* just like 0, but previous was a skip instruction,
6395                          * so some care should be taken */
6396
6397                                 pic16_labelOffset += 10000;
6398                                 tlbl = newiTempLabel(NULL);
6399
6400                                 /* invert skip instruction */
6401                                 pcprev = pic16_findPrevInstruction(pc->prev);
6402                                 ipci = PCI(pcprev)->inverted_op;
6403                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6404
6405 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6406
6407                                 /* copy info from old pCode */
6408                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6409                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6410                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6411                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6412                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6413                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6414
6415                                 /* unlink old pCode */
6416                                 ppc = pcprev->prev;
6417                                 ppc->next = pcprev->next;
6418                                 pcprev->next->prev = ppc;
6419                                 pic16_pCodeInsertAfter(ppc, npci);
6420
6421                                 /* extra instructions to handle invertion */
6422                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6423                                 pic16_pCodeInsertAfter(npci, pcnext);
6424                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6425
6426                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6427                                 pic16_pCodeInsertAfter(pc, pcnext);
6428                         }; break;
6429         }
6430
6431
6432         /* Move the label, if there is one */
6433         if(PCI(pc)->label) {
6434 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6435 //                      __FILE__, __LINE__, pc, new_pc);
6436                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6437                 PCI(pc)->label = NULL;
6438         }
6439 }
6440
6441
6442 /*-----------------------------------------------------------------*/
6443 /*int compareBankFlow - compare the banking requirements between   */
6444 /*  flow objects. */
6445 /*-----------------------------------------------------------------*/
6446 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6447 {
6448
6449   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6450     return 0;
6451
6452   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6453     return 0;
6454
6455   if(pcflow->firstBank == -1)
6456     return 0;
6457
6458
6459   if(pcflowLink->pcflow->firstBank == -1) {
6460     pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6461                                         pcflowLink->pcflow->to :
6462                                         pcflowLink->pcflow->from);
6463     return compareBankFlow(pcflow, pctl, toORfrom);
6464   }
6465
6466   if(toORfrom) {
6467     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6468       return 0;
6469
6470     pcflowLink->bank_conflict++;
6471     pcflowLink->pcflow->FromConflicts++;
6472     pcflow->ToConflicts++;
6473   } else {
6474
6475     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6476       return 0;
6477
6478     pcflowLink->bank_conflict++;
6479     pcflowLink->pcflow->ToConflicts++;
6480     pcflow->FromConflicts++;
6481
6482   }
6483   /*
6484   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6485           pcflowLink->pcflow->pc.seq,
6486           pcflowLink->pcflow->FromConflicts,
6487           pcflowLink->pcflow->ToConflicts);
6488   */
6489   return 1;
6490
6491 }
6492
6493 #if 0
6494 /*-----------------------------------------------------------------*/
6495 /*-----------------------------------------------------------------*/
6496 static void DumpFlow(pBlock *pb)
6497 {
6498   pCode *pc=NULL;
6499   pCode *pcflow;
6500   pCodeFlowLink *pcfl;
6501
6502
6503   fprintf(stderr,"Dump flow \n");
6504   pb->pcHead->print(stderr, pb->pcHead);
6505
6506   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6507   pcflow->print(stderr,pcflow);
6508
6509   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6510        pcflow != NULL;
6511        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6512
6513     if(!isPCFL(pcflow)) {
6514       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6515       continue;
6516     }
6517     fprintf(stderr,"dumping: ");
6518     pcflow->print(stderr,pcflow);
6519     FlowStats(PCFL(pcflow));
6520
6521     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6522
6523       pc = PCODE(pcfl->pcflow);
6524
6525       fprintf(stderr, "    from seq %d:\n",pc->seq);
6526       if(!isPCFL(pc)) {
6527         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6528         pc->print(stderr,pc);
6529       }
6530
6531     }
6532
6533     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6534
6535       pc = PCODE(pcfl->pcflow);
6536
6537       fprintf(stderr, "    to seq %d:\n",pc->seq);
6538       if(!isPCFL(pc)) {
6539         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6540         pc->print(stderr,pc);
6541       }
6542
6543     }
6544
6545   }
6546
6547 }
6548 #endif
6549 /*-----------------------------------------------------------------*/
6550 /*-----------------------------------------------------------------*/
6551 static int OptimizepBlock(pBlock *pb)
6552 {
6553   pCode *pc, *pcprev;
6554   int matches =0;
6555
6556   if(!pb || !peepOptimizing)
6557     return 0;
6558
6559   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6560 /*
6561   for(pc = pb->pcHead; pc; pc = pc->next)
6562     matches += pic16_pCodePeepMatchRule(pc);
6563 */
6564
6565   pc = pic16_findNextInstruction(pb->pcHead);
6566   if(!pc)
6567     return 0;
6568
6569   pcprev = pc->prev;
6570   do {
6571
6572
6573     if(pic16_pCodePeepMatchRule(pc)) {
6574
6575       matches++;
6576
6577       if(pcprev)
6578         pc = pic16_findNextInstruction(pcprev->next);
6579       else
6580         pc = pic16_findNextInstruction(pb->pcHead);
6581     } else
6582       pc = pic16_findNextInstruction(pc->next);
6583   } while(pc);
6584
6585   if(matches)
6586     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6587   return matches;
6588
6589 }
6590
6591 /*-----------------------------------------------------------------*/
6592 /*-----------------------------------------------------------------*/
6593 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6594 {
6595   pCode *pc;
6596
6597   for(pc = pcs; pc; pc = pc->next) {
6598
6599     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6600        (PCI(pc)->pcop) &&
6601        (PCI(pc)->pcop->type == PO_LABEL) &&
6602        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6603       return pc;
6604   }
6605
6606
6607   return NULL;
6608 }
6609
6610 /*-----------------------------------------------------------------*/
6611 /*-----------------------------------------------------------------*/
6612 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6613 {
6614
6615   char *s=NULL;
6616
6617   if(isPCI(pc) &&
6618      (PCI(pc)->pcop) &&
6619      (PCI(pc)->pcop->type == PO_LABEL)) {
6620
6621     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6622
6623 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6624 //    if(pcol->pcop.name)
6625 //      Safe_free(pcol->pcop.name);
6626
6627     /* If the key is negative, then we (probably) have a label to
6628      * a function and the name is already defined */
6629
6630     if(pcl->key>0)
6631       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6632     else
6633       s = pcl->label;
6634
6635     //sprintf(buffer,"_%05d_DS_",pcl->key);
6636     if(!s) {
6637       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6638     }
6639     pcol->pcop.name = Safe_strdup(s);
6640     pcol->key = pcl->key;
6641     //pc->print(stderr,pc);
6642
6643   }
6644
6645
6646 }
6647
6648 /*-----------------------------------------------------------------*/
6649 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6650 /*                            pCode chain if they're not used.     */
6651 /*-----------------------------------------------------------------*/
6652 static void pBlockRemoveUnusedLabels(pBlock *pb)
6653 {
6654   pCode *pc; pCodeLabel *pcl;
6655
6656   if(!pb || !pb->pcHead)
6657     return;
6658
6659   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6660
6661     pBranch *pbr = PCI(pc)->label;
6662     if(pbr && pbr->next) {
6663       pCode *pcd = pb->pcHead;
6664
6665 //      fprintf(stderr, "multiple labels\n");
6666 //      pc->print(stderr,pc);
6667
6668       pbr = pbr->next;
6669       while(pbr) {
6670
6671         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6672           //fprintf(stderr,"Used by:\n");
6673           //pcd->print(stderr,pcd);
6674
6675           exchangeLabels(PCL(pbr->pc),pcd);
6676
6677           pcd = pcd->next;
6678         }
6679         pbr = pbr->next;
6680       }
6681     }
6682   }
6683
6684   for(pc = pb->pcHead; pc; pc = pc->next) {
6685
6686     if(isPCL(pc)) // pc->type == PC_LABEL)
6687       pcl = PCL(pc);
6688     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6689       pcl = PCL(PCI(pc)->label->pc);
6690     else continue;
6691
6692 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6693
6694     /* This pCode is a label, so search the pBlock to see if anyone
6695      * refers to it */
6696
6697     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6698         && (!pcl->force)) {
6699     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6700       /* Couldn't find an instruction that refers to this label
6701        * So, unlink the pCode label from it's pCode chain
6702        * and destroy the label */
6703 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6704
6705       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6706       if(pc->type == PC_LABEL) {
6707         pic16_unlinkpCode(pc);
6708         pCodeLabelDestruct(pc);
6709       } else {
6710         unlinkpCodeFromBranch(pc, PCODE(pcl));
6711         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6712           Safe_free(pc->label);
6713         }*/
6714       }
6715
6716     }
6717   }
6718
6719 }
6720
6721
6722 /*-----------------------------------------------------------------*/
6723 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6724 /*                     chain and put them into pBranches that are  */
6725 /*                     associated with the appropriate pCode       */
6726 /*                     instructions.                               */
6727 /*-----------------------------------------------------------------*/
6728 void pic16_pBlockMergeLabels(pBlock *pb)
6729 {
6730   pBranch *pbr;
6731   pCode *pc, *pcnext=NULL;
6732
6733   if(!pb)
6734     return;
6735
6736   /* First, Try to remove any unused labels */
6737   //pBlockRemoveUnusedLabels(pb);
6738
6739   /* Now loop through the pBlock and merge the labels with the opcodes */
6740
6741   pc = pb->pcHead;
6742   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6743
6744   while(pc) {
6745     pCode *pcn = pc->next;
6746
6747     if(pc->type == PC_LABEL) {
6748
6749 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6750 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6751
6752       if((pcnext = pic16_findNextInstruction(pc) )) {
6753
6754 //              pcnext->print(stderr, pcnext);
6755
6756         // Unlink the pCode label from it's pCode chain
6757         pic16_unlinkpCode(pc);
6758
6759 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6760         // And link it into the instruction's pBranch labels. (Note, since
6761         // it's possible to have multiple labels associated with one instruction
6762         // we must provide a means to accomodate the additional labels. Thus
6763         // the labels are placed into the singly-linked list "label" as
6764         // opposed to being a single member of the pCodeInstruction.)
6765
6766         //_ALLOC(pbr,sizeof(pBranch));
6767 #if 1
6768         pbr = Safe_calloc(1,sizeof(pBranch));
6769         pbr->pc = pc;
6770         pbr->next = NULL;
6771
6772         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6773 #endif
6774       } else {
6775         if(pic16_pcode_verbose)
6776         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6777       }
6778     } else if(pc->type == PC_CSOURCE) {
6779
6780       /* merge the source line symbolic info into the next instruction */
6781       if((pcnext = pic16_findNextInstruction(pc) )) {
6782
6783         // Unlink the pCode label from it's pCode chain
6784         pic16_unlinkpCode(pc);
6785         PCI(pcnext)->cline = PCCS(pc);
6786         //fprintf(stderr, "merging CSRC\n");
6787         //genericPrint(stderr,pcnext);
6788       }
6789
6790     }
6791     pc = pcn;
6792   }
6793   pBlockRemoveUnusedLabels(pb);
6794
6795 }
6796
6797 /*-----------------------------------------------------------------*/
6798 /*-----------------------------------------------------------------*/
6799 static int OptimizepCode(char dbName)
6800 {
6801 #define MAX_PASSES 4
6802
6803   int matches = 0;
6804   int passes = 0;
6805   pBlock *pb;
6806
6807   if(!the_pFile)
6808     return 0;
6809
6810   DFPRINTF((stderr," Optimizing pCode\n"));
6811
6812   do {
6813     matches = 0;
6814     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6815       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6816         matches += OptimizepBlock(pb);
6817     }
6818   }
6819   while(matches && ++passes < MAX_PASSES);
6820
6821   return matches;
6822 }
6823
6824
6825
6826 const char *pic16_pCodeOpType(pCodeOp *pcop);
6827 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6828
6829
6830 /*-----------------------------------------------------------------*/
6831 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6832 /*-----------------------------------------------------------------*/
6833
6834 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6835 {
6836   pCodeOp *pcop=NULL;
6837
6838 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6839
6840   if(pc->name) {
6841         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6842   } else {
6843     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6844   }
6845
6846   assert(pcop != NULL);
6847
6848   if( !( (pcop->type == PO_LABEL) ||
6849          (pcop->type == PO_LITERAL) ||
6850          (pcop->type == PO_STR) ))
6851     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6852     PCOR(pcop)->r->wasUsed = 1;
6853     PCOR(pcop)->instance = PCOR(pc)->instance;
6854
6855   return pcop;
6856 }
6857
6858
6859 /*----------------------------------------------------------------------*
6860  * pic16_areRegsSame - check to see if the names of two registers match *
6861  *----------------------------------------------------------------------*/
6862 int pic16_areRegsSame(regs *r1, regs *r2)
6863 {
6864         if(!strcmp(r1->name, r2->name))return 1;
6865
6866   return 0;
6867 }
6868
6869
6870 /*-----------------------------------------------------------------*/
6871 /*-----------------------------------------------------------------*/
6872 static void pic16_FixRegisterBanking(pBlock *pb)
6873 {
6874   pCode *pc=NULL;
6875   pCode *pcprev=NULL;
6876   regs *reg, *prevreg;
6877   unsigned char flag=0;
6878
6879         if(!pb)
6880                 return;
6881
6882         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6883         if(!pc)return;
6884
6885         /* loop through all of the flow blocks with in one pblock */
6886
6887 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6888
6889         prevreg = NULL;
6890         do {
6891                 /* at this point, pc should point to a PC_FLOW object */
6892                 /* for each flow block, determine the register banking
6893                  * requirements */
6894
6895
6896                 /* if label, then might come from other point, force banksel */
6897                 if(isPCL(pc))prevreg = NULL;
6898
6899                 if(!isPCI(pc))goto loop;
6900
6901                 if(PCI(pc)->label)prevreg = NULL;
6902
6903                 if(PCI(pc)->is2MemOp)goto loop;
6904
6905                 /* if goto, then force banksel */
6906 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6907
6908                 reg = pic16_getRegFromInstruction(pc);
6909
6910 #if 0
6911                 pc->print(stderr, pc);
6912                 fprintf(stderr, "reg = %p\n", reg);
6913
6914                 if(reg) {
6915                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6916                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6917                                 reg->address,reg->isBitField, reg->isFixed);
6918                 }
6919 #endif
6920
6921                 /* now make some tests to make sure that instruction needs bank switch */
6922
6923                 /* if no register exists, and if not a bit opcode goto loop */
6924                 if(!reg) {
6925                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6926                 }
6927
6928                 if(isPCI_SKIP(pc)) {
6929 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6930 //                prevreg = NULL;
6931                 }
6932                 if(reg && isACCESS_BANK(reg))goto loop;
6933
6934                 if(!isBankInstruction(pc))goto loop;
6935
6936                 if(isPCI_LIT(pc))goto loop;
6937
6938                 if(PCI(pc)->op == POC_CALL)goto loop;
6939
6940                 /* Examine the instruction before this one to make sure it is
6941                  * not a skip type instruction */
6942                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6943
6944                 flag = 0;               /* add before this instruction */
6945
6946                 /* if previous instruction is a skip one, then set flag
6947                  * to 2 and call insertBankSwitch */
6948                 if(pcprev && isPCI_SKIP(pcprev)) {
6949                   flag=2;       //goto loop
6950 //                prevreg = NULL;
6951                 }
6952
6953                 if(pic16_options.opt_banksel>0) {
6954                   char op1[128], op2[128];
6955
6956                     if(prevreg) {
6957                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6958                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6959                       if(!strcmp(op1, op2))goto loop;
6960                     }
6961                 }
6962                 prevreg = reg;
6963                 insertBankSwitch(flag, pc);
6964
6965 //              fprintf(stderr, "BANK SWITCH inserted\n");
6966
6967 loop:
6968                 pcprev = pc;
6969                 pc = pc->next;
6970         } while (pc);
6971 }
6972
6973 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6974
6975 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6976 int instrSize (pCode *pc)
6977 {
6978   if (!pc) return 0;
6979
6980   if (isPCAD(pc)) {
6981     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6982     return 4; // assumes only regular instructions using <= 4 bytes
6983   }
6984
6985   if (isPCI(pc)) return PCI(pc)->isize;
6986
6987   return 0;
6988 }
6989
6990 /* Returns 1 if pc is referenced by the given label (either
6991  * pc is the label itself or is an instruction with an attached
6992  * label).
6993  * Returns 0 if pc is not preceeded by the specified label.
6994  */
6995 int isLabel (pCode *pc, char *label)
6996 {
6997   if (!pc) return 0;
6998
6999   // label attached to the pCode?
7000   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7001     pBranch *lab = NULL;
7002     lab = PCI(pc)->label;
7003
7004     while (lab) {
7005       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7006         return 1;
7007       }
7008       lab = lab->next;
7009     } // while
7010   } // if
7011
7012   // is inline assembly label?
7013   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7014     // do not compare trailing ':'
7015     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7016       return 1;
7017     }
7018   } // if
7019
7020   // is pCodeLabel?
7021   if (isPCL(pc)) {
7022       if (strcmp(PCL(pc)->label,label) == 0) {
7023       return 1;
7024     }
7025   } // if
7026
7027   // no label/no label attached/wrong label(s)
7028   return 0;
7029 }
7030
7031 /* Returns the distance to the given label in terms of words.
7032  * Labels are searched only within -max .. max words from pc.
7033  * Returns max if the label could not be found or
7034  * its distance from pc in (-max..+max).
7035  */
7036 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7037   int dist = instrSize(pc);
7038   pCode *curr = pc;
7039
7040   // search backwards
7041   while (dist < max && curr && !isLabel (curr, label)) {
7042     curr = curr->prev;
7043     dist += instrSize(curr); // sizeof (instruction)
7044   } // while
7045   if (curr && dist < max) {
7046     if (target != NULL) *target = curr;
7047     return -dist;
7048   }
7049
7050   dist = 0;
7051   curr = pic16_findNextInstruction (pc->next);
7052   //search forwards
7053   while (dist < max && curr && !isLabel (curr, label)) {
7054     dist += instrSize(curr); // sizeof (instruction)
7055     curr = curr->next;
7056   } // while
7057   if (curr && dist < max) {
7058     if (target != NULL) *target = curr;
7059     return dist;
7060   }
7061
7062   if (target != NULL) *target = NULL;
7063   return max;
7064 }
7065
7066 /* Returns -1 if pc does NOT denote an instruction like
7067  * BTFS[SC] STATUS,i
7068  * Otherwise we return
7069  *   (a) 0x10 + i for BTFSS
7070  *   (b) 0x00 + i for BTFSC
7071  */
7072 int isSkipOnStatus (pCode *pc)
7073 {
7074   int res = -1;
7075   pCodeOp *pcop;
7076   if (!pc || !isPCI(pc)) return -1;
7077   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7078   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7079   else return -1;
7080
7081   pcop = PCI(pc)->pcop;
7082
7083   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7084     return res + ((pCodeOpRegBit *)pcop)->bit;
7085   }
7086
7087   return -1;
7088 }
7089
7090 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7091  * returns 0 otherwise. */
7092 int isConditionalBranch (pCode *pc)
7093 {
7094   if (!pc || !isPCI_BRANCH(pc)) return 0;
7095
7096   switch (PCI(pc)->op) {
7097   case POC_BC:
7098   case POC_BZ:
7099   case POC_BOV:
7100   case POC_BN:
7101   case POC_BNC:
7102   case POC_BNZ:
7103   case POC_BNOV:
7104   case POC_BNN:
7105     return 1;
7106
7107   default:
7108     break;
7109   } // switch
7110
7111   return 0;
7112 }
7113
7114 /* Returns 1 if pc has a label attached to it.
7115  * This can be either a label stored in the pCode itself (.label)
7116  * or a label making up its own pCode preceding this pc.
7117  * Returns 0 if pc cannot be reached directly via a label.
7118  */
7119 int hasNoLabel (pCode *pc)
7120 {
7121   pCode *prev;
7122   if (!pc) return 1;
7123
7124   // are there any label pCodes between pc and the previous instruction?
7125   prev = pic16_findPrevInstruction (pc->prev);
7126   while (pc && pc != prev) {
7127     // pCode with attached label?
7128     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7129         && PCI(pc)->label) {
7130       return 0;
7131     }
7132     // is inline assembly label?
7133     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7134     if (isPCW(pc) && PCW(pc)->label) return 0;
7135
7136     // pCodeLabel?
7137     if (isPCL(pc)) return 0;
7138
7139     pc = pc->prev;
7140   } // if
7141
7142   // no label found
7143   return 1;
7144 }
7145
7146 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7147   char buf[512];
7148   va_list va;
7149
7150   va_start (va, fmt);
7151   vsprintf (buf, fmt, va);
7152   va_end (va);
7153
7154   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7155 }
7156
7157 /* Replaces the old pCode with the new one, moving the labels,
7158  * C source line and probably flow information to the new pCode.
7159  */
7160 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7161   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7162     return;
7163
7164   /* first move all labels from old to new */
7165   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7166   PCI(oldPC)->label = NULL;
7167
7168 #if 0
7169   /* move C source line (if possible) */
7170   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7171     PCI(newPC)->cline = PCI(oldPC)->cline;
7172 #endif
7173
7174   /* keep flow information intact */
7175   newPC->seq = oldPC->seq;
7176   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7177   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7178     PCI(newPC)->pcflow->end = newPC;
7179   }
7180
7181   /* insert a comment stating which pCode has been replaced */
7182 #if 1
7183   if (pic16_pcode_verbose || pic16_debug_verbose) {
7184     char pc_str[256];
7185     pic16_pCode2str (pc_str, 256, oldPC);
7186     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7187   }
7188 #endif
7189
7190   /* insert new pCode into pBlock */
7191   pic16_pCodeInsertAfter (oldPC, newPC);
7192   pic16_unlinkpCode (oldPC);
7193
7194   /* destruct replaced pCode */
7195   oldPC->destruct (oldPC);
7196 }
7197
7198 /* Returns the inverted conditional branch (if any) or NULL.
7199  * pcop must be set to the new jump target.
7200  */
7201 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7202 {
7203   pCode *newBcc;
7204
7205   if (!bcc || !isPCI(bcc)) return NULL;
7206
7207   switch (PCI(bcc)->op) {
7208   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7209   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7210   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7211   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7212   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7213   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7214   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7215   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7216   default:
7217     newBcc = NULL;
7218   }
7219   return newBcc;
7220 }
7221
7222 #define MAX_DIST_GOTO         0x7FFFFFFF
7223 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7224 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7225 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7226 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7227
7228 /* Follows GOTO/BRA instructions to their target instructions, stores the
7229  * final destination (not a GOTO or BRA instruction) in target and returns
7230  * the distance from the original pc to *target.
7231  */
7232 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7233         pCode *curr = pc;
7234         pCode *last = NULL;
7235         pCodeOp *lastPCOP = NULL;
7236         int dist = 0;
7237         int depth = 0;
7238
7239         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7240
7241         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7242         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7243                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7244                 last = curr;
7245                 lastPCOP = PCI(curr)->pcop;
7246                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7247                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7248         } // while
7249
7250         if (target) *target = last;
7251         if (pcop) *pcop = lastPCOP;
7252         return dist;
7253 }
7254
7255 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7256  * Otherwise the first pCode after the jumptable (after
7257  * the OPT_JUMPTABLE_END tag) is returned.
7258  */
7259 pCode *skipJumptables (pCode *pc, int *isJumptable)
7260 {
7261   *isJumptable = 0;
7262   if (!pc) return NULL;
7263
7264   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7265     *isJumptable = 1;
7266     //fprintf (stderr, "SKIPPING jumptable\n");
7267     do {
7268       //pc->print(stderr, pc);
7269       pc = pc->next;
7270     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7271                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7272     //fprintf (stderr, "<<JUMPTAB:\n");
7273     // skip OPT_END as well
7274     if (pc) pc = pc->next;
7275   } // while
7276
7277   return pc;
7278 }
7279
7280 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7281 {
7282   int isJumptab;
7283   *isJumptable = 0;
7284   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7285     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7286     pc = skipJumptables (pc, &isJumptab);
7287     if (isJumptab) {
7288         // pc is the first pCode after the jumptable
7289         *isJumptable = 1;
7290     } else {
7291         // pc has not been changed by skipJumptables()
7292         pc = pc->next;
7293     }
7294   } // while
7295
7296   return pc;
7297 }
7298
7299 /* Turn GOTOs into BRAs if distance between GOTO and label
7300  * is less than 1024 bytes.
7301  *
7302  * This method is especially useful if GOTOs after BTFS[SC]
7303  * can be turned into BRAs as GOTO would cost another NOP
7304  * if skipped.
7305  */
7306 void pic16_OptimizeJumps ()
7307 {
7308   pCode *pc;
7309   pCode *pc_prev = NULL;
7310   pCode *pc_next = NULL;
7311   pBlock *pb;
7312   pCode *target;
7313   int change, iteration, isJumptab;
7314   int isHandled = 0;
7315   char *label;
7316   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7317
7318   if (!the_pFile) return;
7319
7320   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7321
7322   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7323     int matchedInvertRule = 1;
7324     iteration = 1;
7325     do {
7326       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7327       change = 0;
7328       pc = pic16_findNextInstruction (pb->pcHead);
7329
7330       while (pc) {
7331         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7332         if (isJumptab) {
7333                 // skip jumptable, i.e. start over with no pc_prev!
7334                 pc_prev = NULL;
7335                 pc = pc_next;
7336                 continue;
7337         } // if
7338
7339         /* (1) resolve chained jumps
7340          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7341          * (a) leave dead code in and
7342          * (b) skip over the dead code with an (unneccessary) jump.
7343          */
7344         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7345           pCodeOp *lastTargetOp = NULL;
7346           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7347           int maxDist = MAX_DIST_BCC;
7348           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7349           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7350
7351           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7352           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7353               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7354             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7355             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7356             PCI(pc)->pcop->name = lastTargetOp->name;
7357             change++;
7358             opt_gotochain++;
7359           } // if
7360         } // if
7361
7362
7363         if (IS_GOTO(pc)) {
7364           int dist;
7365           int condBraType = isSkipOnStatus(pc_prev);
7366           label = PCI(pc)->pcop->name;
7367           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7368           if (dist < 0) dist = -dist;
7369           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7370           isHandled = 0;
7371
7372
7373           /* (2) remove "GOTO label; label:" */
7374           if (isLabel (pc_next, label)) {
7375             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7376             // first remove all preceeding SKIP instructions
7377             while (pc_prev && isPCI_SKIP(pc_prev)) {
7378               // attach labels on this instruction to pc_next
7379               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7380               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7381               PCI(pc_prev)->label = NULL;
7382               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7383               pic16_unlinkpCode (pc_prev);
7384               pc_prev = pic16_findPrevInstruction (pc);
7385             } // while
7386             // now remove the redundant goto itself
7387             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7388             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7389             pic16_unlinkpCode (pc);
7390             pc = pic16_findPrevInstruction(pc_next->prev);
7391             isHandled = 1; // do not perform further optimizations
7392             opt_gotonext++;
7393             change++;
7394           } // if
7395
7396
7397           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7398           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7399             if (dist < MAX_DIST_BCC) {
7400               pCode *bcc = NULL;
7401               switch (condBraType) {
7402               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7403                 // no BDC on DIGIT CARRY available
7404               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7405               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7406               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7407               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7408                 // no BNDC on DIGIT CARRY available
7409               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7410               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7411               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7412               default:
7413                 // no replacement possible
7414                 bcc = NULL;
7415                 break;
7416               } // switch
7417               if (bcc) {
7418                 // ATTENTION: keep labels attached to BTFSx!
7419                 // HINT: GOTO is label free (checked above)
7420                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7421                 isHandled = 1; // do not perform further optimizations
7422                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7423                 pic16_pCodeReplace (pc_prev, bcc);
7424                 pc->destruct(pc);
7425                 pc = bcc;
7426                 opt_cond++;
7427                 change++;
7428               } // if
7429             } else {
7430               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7431               cond_toofar++;
7432             } // if
7433           } // if
7434
7435           if (!isHandled) {
7436             // (4) eliminate the following (common) tripel:
7437             //           <pred.>;
7438             //  labels1: Bcc label2;
7439             //           GOTO somewhere;    ; <-- instruction referenced by pc
7440             //  label2:  <cont.>
7441             // and replace it by
7442             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7443             //  label2:  <cont.>
7444             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7445             //            to <cont.> instead
7446             // ATTENTION: This optimization is only valid if <pred.> is
7447             //            not a skip operation!
7448             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7449             // ATTENTION: no label may be attached to the GOTO instruction!
7450             if (isConditionalBranch(pc_prev)
7451                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7452                 && (dist < MAX_DIST_BCC)
7453                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7454                 && hasNoLabel(pc)) {
7455               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7456
7457               if (newBcc) {
7458                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7459                 isHandled = 1; // do not perform further optimizations
7460                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7461                 pic16_pCodeReplace (pc_prev, newBcc);
7462                 pc->destruct(pc);
7463                 pc = newBcc;
7464                 opt_reorder++;
7465                 change++;
7466                 matchedInvertRule++;
7467               }
7468             }
7469           }
7470
7471           /* (5) now just turn GOTO into BRA */
7472           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7473             if (dist < MAX_DIST_BRA) {
7474               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7475               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7476               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7477               pic16_pCodeReplace (pc, newBra);
7478               pc = newBra;
7479               opt++;
7480               change++;
7481             } else {
7482               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7483               toofar++;
7484             }
7485           } // if (!isHandled)
7486         } // if
7487
7488         pc_prev = pc;
7489         pc = pc_next;
7490       } // while (pc)
7491
7492       pBlockRemoveUnusedLabels (pb);
7493
7494       // This line enables goto chain resolution!
7495       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7496
7497       iteration++;
7498     } while (change); /* fixpoint iteration per pBlock */
7499   } // for (pb)
7500
7501   // emit some statistics concerning goto-optimization
7502 #if 0
7503   if (pic16_debug_verbose || pic16_pcode_verbose) {
7504     fprintf (stderr, "optimize-goto:\n"
7505              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7506              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7507              "\t%5d conditional \"skipping\" jumps inverted\n"
7508              "\t%5d GOTOs to next instruction removed\n"
7509              "\t%5d chained GOTOs resolved\n",
7510              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7511   } // if
7512 #endif
7513   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7514 }
7515
7516 #undef IS_GOTO
7517 #undef MAX_JUMPCHAIN_DEPTH
7518 #undef MAX_DIST_GOTO
7519 #undef MAX_DIST_BRA
7520 #undef MAX_DIST_BCC
7521
7522 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7523
7524 static void pBlockDestruct(pBlock *pb)
7525 {
7526
7527   if(!pb)
7528     return;
7529
7530
7531 //  Safe_free(pb);
7532
7533 }
7534
7535 /*-----------------------------------------------------------------*/
7536 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7537 /*                                  name dbName and combine them   */
7538 /*                                  into one block                 */
7539 /*-----------------------------------------------------------------*/
7540 static void mergepBlocks(char dbName)
7541 {
7542
7543   pBlock *pb, *pbmerged = NULL,*pbn;
7544
7545   pb = the_pFile->pbHead;
7546
7547   //fprintf(stderr," merging blocks named %c\n",dbName);
7548   while(pb) {
7549
7550     pbn = pb->next;
7551     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7552     if( getpBlock_dbName(pb) == dbName) {
7553
7554       //fprintf(stderr," merged block %c\n",dbName);
7555
7556       if(!pbmerged) {
7557         pbmerged = pb;
7558       } else {
7559         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7560         /* pic16_addpCode2pBlock doesn't handle the tail: */
7561         pbmerged->pcTail = pb->pcTail;
7562
7563         pb->prev->next = pbn;
7564         if(pbn)
7565           pbn->prev = pb->prev;
7566
7567
7568         pBlockDestruct(pb);
7569       }
7570       //pic16_printpBlock(stderr, pbmerged);
7571     }
7572     pb = pbn;
7573   }
7574
7575 }
7576
7577 /*-----------------------------------------------------------------*/
7578 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7579 /*                                                                 */
7580 /* level 0 == minimal optimization                                 */
7581 /*   optimize registers that are used only by two instructions     */
7582 /* level 1 == maximal optimization                                 */
7583 /*   optimize by looking at pairs of instructions that use the     */
7584 /*   register.                                                     */
7585 /*-----------------------------------------------------------------*/
7586
7587 static void AnalyzeFlow(int level)
7588 {
7589   static int times_called=0;
7590   pBlock *pb;
7591
7592     if(!the_pFile) {
7593       /* remove unused allocated registers before exiting */
7594       pic16_RemoveUnusedRegisters();
7595       return;
7596     }
7597
7598
7599     /* if this is not the first time this function has been called,
7600      * then clean up old flow information */
7601     if(times_called++) {
7602       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7603         unBuildFlow(pb);
7604         pic16_RegsUnMapLiveRanges();
7605     }
7606     GpcFlowSeq = 1;
7607
7608     /* Phase 2 - Flow Analysis - Register Banking
7609      *
7610      * In this phase, the individual flow blocks are examined
7611      * and register banking is fixed.
7612      */
7613
7614 #if 0
7615     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7616       pic16_FixRegisterBanking(pb);
7617 #endif
7618
7619     /* Phase 2 - Flow Analysis
7620      *
7621      * In this phase, the pCode is partition into pCodeFlow
7622      * blocks. The flow blocks mark the points where a continuous
7623      * stream of instructions changes flow (e.g. because of
7624      * a call or goto or whatever).
7625      */
7626
7627     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7628       pic16_BuildFlow(pb);
7629
7630
7631     /* Phase 2 - Flow Analysis - linking flow blocks
7632      *
7633      * In this phase, the individual flow blocks are examined
7634      * to determine their order of excution.
7635      */
7636
7637     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7638       LinkFlow(pb);
7639
7640 #if 1
7641         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7642                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7643                         pic16_createDF (pb);
7644 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7645                         pic16_vcg_dump_default (pb);
7646 #endif
7647                         //pic16_destructDF (pb);
7648                 }
7649
7650                 pic16_df_stats ();
7651                 if (0) releaseStack (); // releasing is costly...
7652         }
7653 #endif
7654
7655     /* Phase 3 - Flow Analysis - Flow Tree
7656      *
7657      * In this phase, the individual flow blocks are examined
7658      * to determine their order of execution.
7659      */
7660
7661     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7662       pic16_BuildFlowTree(pb);
7663
7664
7665     /* Phase x - Flow Analysis - Used Banks
7666      *
7667      * In this phase, the individual flow blocks are examined
7668      * to determine the Register Banks they use
7669      */
7670
7671 #if 0
7672     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7673       FixBankFlow(pb);
7674 #endif
7675
7676
7677     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7678       pic16_pCodeRegMapLiveRanges(pb);
7679
7680     pic16_RemoveUnusedRegisters();
7681     pic16_removeUnusedRegistersDF ();
7682
7683   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7684     pic16_pCodeRegOptimizeRegUsage(level);
7685
7686
7687 #if 0
7688     if(!options.nopeep)
7689       OptimizepCode('*');
7690 #endif
7691
7692 #if 0
7693     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7694       DumpFlow(pb);
7695 #endif
7696
7697     /* debug stuff */
7698     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7699       pCode *pcflow;
7700
7701         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7702           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7703           pcflow = pcflow->next) {
7704             FillFlow(PCFL(pcflow));
7705         }
7706     }
7707
7708 #if 0
7709     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7710       pCode *pcflow;
7711
7712         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7713           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7714           pcflow = pcflow->next) {
7715             FlowStats(PCFL(pcflow));
7716         }
7717     }
7718 #endif
7719 }
7720
7721 /* VR -- no need to analyze banking in flow, but left here :
7722  *      1. because it may be used in the future for other purposes
7723  *      2. because if omitted we'll miss some optimization done here
7724  *
7725  * Perhaps I should rename it to something else
7726  */
7727
7728 /*-----------------------------------------------------------------*/
7729 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7730 /*                  assigned to the registers.                     */
7731 /*                                                                 */
7732 /*-----------------------------------------------------------------*/
7733
7734 void pic16_AnalyzeBanking(void)
7735 {
7736   pBlock  *pb;
7737
7738     /* Phase x - Flow Analysis - Used Banks
7739      *
7740      * In this phase, the individual flow blocks are examined
7741      * to determine the Register Banks they use
7742      */
7743
7744     AnalyzeFlow(0);
7745     AnalyzeFlow(1);
7746
7747     if(!options.nopeep)
7748       OptimizepCode('*');
7749
7750
7751     if(!the_pFile)return;
7752
7753     if(!pic16_options.no_banksel) {
7754       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7755 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7756         pic16_FixRegisterBanking(pb);
7757       }
7758     }
7759 }
7760
7761 /*-----------------------------------------------------------------*/
7762 /* buildCallTree - Look at the flow and extract all of the calls.  */
7763 /*-----------------------------------------------------------------*/
7764 static set *register_usage(pBlock *pb);
7765
7766 static void buildCallTree(void    )
7767 {
7768   pBranch *pbr;
7769   pBlock  *pb;
7770   pCode   *pc;
7771   regs *r;
7772
7773   if(!the_pFile)
7774     return;
7775
7776
7777
7778   /* Now build the call tree.
7779      First we examine all of the pCodes for functions.
7780      Keep in mind that the function boundaries coincide
7781      with pBlock boundaries.
7782
7783      The algorithm goes something like this:
7784      We have two nested loops. The outer loop iterates
7785      through all of the pBlocks/functions. The inner
7786      loop iterates through all of the pCodes for
7787      a given pBlock. When we begin iterating through
7788      a pBlock, the variable pc_fstart, pCode of the start
7789      of a function, is cleared. We then search for pCodes
7790      of type PC_FUNCTION. When one is encountered, we
7791      initialize pc_fstart to this and at the same time
7792      associate a new pBranch object that signifies a
7793      branch entry. If a return is found, then this signifies
7794      a function exit point. We'll link the pCodes of these
7795      returns to the matching pc_fstart.
7796
7797      When we're done, a doubly linked list of pBranches
7798      will exist. The head of this list is stored in
7799      `the_pFile', which is the meta structure for all
7800      of the pCode. Look at the pic16_printCallTree function
7801      on how the pBranches are linked together.
7802
7803    */
7804   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7805     pCode *pc_fstart=NULL;
7806     for(pc = pb->pcHead; pc; pc = pc->next) {
7807
7808         if(isPCI(pc) && pc_fstart) {
7809                 if(PCI(pc)->is2MemOp) {
7810                         r = pic16_getRegFromInstruction2(pc);
7811                         if(r && !strcmp(r->name, "POSTDEC1"))
7812                                 PCF(pc_fstart)->stackusage++;
7813                 } else {
7814                         r = pic16_getRegFromInstruction(pc);
7815                         if(r && !strcmp(r->name, "PREINC1"))
7816                                 PCF(pc_fstart)->stackusage--;
7817                 }
7818         }
7819
7820       if(isPCF(pc)) {
7821         if (PCF(pc)->fname) {
7822         char buf[16];
7823
7824           sprintf(buf, "%smain", port->fun_prefix);
7825           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7826             //fprintf(stderr," found main \n");
7827             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7828             pb->dbName = 'M';
7829           }
7830
7831           pbr = Safe_calloc(1,sizeof(pBranch));
7832           pbr->pc = pc_fstart = pc;
7833           pbr->next = NULL;
7834
7835           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7836
7837           // Here's a better way of doing the same:
7838           addSet(&pb->function_entries, pc);
7839
7840         } else {
7841           // Found an exit point in a function, e.g. return
7842           // (Note, there may be more than one return per function)
7843           if(pc_fstart)
7844             pBranchLink(PCF(pc_fstart), PCF(pc));
7845
7846           addSet(&pb->function_exits, pc);
7847         }
7848       } else if(isCALL(pc)) {
7849         addSet(&pb->function_calls,pc);
7850       }
7851     }
7852   }
7853
7854
7855 #if 0
7856   /* This is not needed because currently all register used
7857    * by a function are stored in stack -- VR */
7858
7859   /* Re-allocate the registers so that there are no collisions
7860    * between local variables when one function call another */
7861
7862   // this is weird...
7863   //  pic16_deallocateAllRegs();
7864
7865   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7866     if(!pb->visited)
7867       register_usage(pb);
7868   }
7869 #endif
7870
7871 }
7872
7873 /*-----------------------------------------------------------------*/
7874 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7875 /*                all of the logical connections.                  */
7876 /*                                                                 */
7877 /* Essentially what's done here is that the pCode flow is          */
7878 /* determined.                                                     */
7879 /*-----------------------------------------------------------------*/
7880
7881 void pic16_AnalyzepCode(char dbName)
7882 {
7883   pBlock *pb;
7884   int i,changes;
7885
7886   if(!the_pFile)
7887     return;
7888
7889   mergepBlocks('D');
7890
7891
7892   /* Phase 1 - Register allocation and peep hole optimization
7893    *
7894    * The first part of the analysis is to determine the registers
7895    * that are used in the pCode. Once that is done, the peep rules
7896    * are applied to the code. We continue to loop until no more
7897    * peep rule optimizations are found (or until we exceed the
7898    * MAX_PASSES threshold).
7899    *
7900    * When done, the required registers will be determined.
7901    *
7902    */
7903   i = 0;
7904   do {
7905
7906     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7907     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7908
7909     /* First, merge the labels with the instructions */
7910     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7911       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7912
7913         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7914         //fprintf(stderr," analyze and merging block %c\n",dbName);
7915         pic16_pBlockMergeLabels(pb);
7916         AnalyzepBlock(pb);
7917       } else {
7918         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7919       }
7920     }
7921
7922         if(!options.nopeep)
7923                 changes = OptimizepCode(dbName);
7924         else changes = 0;
7925
7926   } while(changes && (i++ < MAX_PASSES));
7927
7928
7929   buildCallTree();
7930 }
7931
7932
7933 /* convert a series of movff's of local regs to stack, with a single call to
7934  * a support functions which does the same thing via loop */
7935 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7936 {
7937   pBranch *pbr;
7938   pCode *pc, *pct;
7939   char *fname[]={"__lr_store", "__lr_restore"};
7940
7941 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7942
7943     pct = pic16_findNextInstruction(pcstart->next);
7944     do {
7945       pc = pct;
7946       pct = pc->next;   //pic16_findNextInstruction(pc->next);
7947 //      pc->print(stderr, pc);
7948       if(isPCI(pc) && PCI(pc)->label) {
7949         pbr = PCI(pc)->label;
7950         while(pbr && pbr->pc) {
7951           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7952           pbr = pbr->next;
7953         }
7954
7955 //        pc->print(stderr, pc);
7956         /* unlink pCode */
7957         pc->prev->next = pct;
7958         pct->prev = pc->prev;
7959 //        pc->next = NULL;
7960 //        pc->prev = NULL;
7961       }
7962     } while ((pc) && (pc != pcend));
7963
7964     /* unlink movff instructions */
7965     pcstart->next = pcend;
7966     pcend->prev = pcstart;
7967
7968     pc = pcstart;
7969 //    if(!entry) {
7970 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7971 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7972 //    }
7973
7974     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7975     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7976     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7977
7978 //    if(!entry) {
7979 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7980 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7981 //    }
7982
7983
7984     {
7985       symbol *sym;
7986
7987         sym = newSymbol( fname[ entry?0:1 ], 0 );
7988         strcpy(sym->rname, fname[ entry?0:1 ]);
7989         checkAddSym(&externs, sym);
7990
7991 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7992     }
7993
7994 }
7995
7996 /*-----------------------------------------------------------------*/
7997 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
7998 /*    local registers to a support function call                   */
7999 /*-----------------------------------------------------------------*/
8000 void pic16_OptimizeLocalRegs(void)
8001 {
8002   pBlock  *pb;
8003   pCode   *pc;
8004   pCodeInfo *pci;
8005   pCodeOpLocalReg *pclr;
8006   int regCount=0;
8007   int inRegCount=0;
8008   regs *r, *lastr=NULL, *firstr=NULL;
8009   pCode *pcstart=NULL, *pcend=NULL;
8010   int inEntry=0;
8011   char *curFunc=NULL;
8012
8013         /* Overview:
8014          *   local_regs begin mark
8015          *      MOVFF r0x01, POSTDEC1
8016          *      MOVFF r0x02, POSTDEC1
8017          *      ...
8018          *      ...
8019          *      MOVFF r0x0n, POSTDEC1
8020          *   local_regs end mark
8021          *
8022          * convert the above to the below:
8023          *      MOVLW   starting_register_index
8024          *      MOVWF   PRODL
8025          *      MOVLW   register_count
8026          *      call    __save_registers_in_stack
8027          */
8028
8029     if(!the_pFile)
8030       return;
8031
8032     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8033       inRegCount = regCount = 0;
8034       firstr = lastr = NULL;
8035       for(pc = pb->pcHead; pc; pc = pc->next) {
8036
8037         /* hold current function name */
8038         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8039
8040         if(pc && (pc->type == PC_INFO)) {
8041           pci = PCINF(pc);
8042
8043           if(pci->type == INF_LOCALREGS) {
8044             pclr = PCOLR(pci->oper1);
8045
8046             if((pclr->type == LR_ENTRY_BEGIN)
8047               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8048             else inEntry = 0;
8049
8050             switch(pclr->type) {
8051               case LR_ENTRY_BEGIN:
8052               case LR_EXIT_BEGIN:
8053                         inRegCount = 1; regCount = 0;
8054                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8055                         firstr = lastr = NULL;
8056                         break;
8057
8058               case LR_ENTRY_END:
8059               case LR_EXIT_END:
8060                         inRegCount = -1;
8061                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8062
8063 #if 1
8064                         if(curFunc && inWparamList(curFunc+1)) {
8065                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8066                                         filename, curFunc);
8067                         } else {
8068                           if(regCount>2) {
8069                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8070                               firstr, inEntry);
8071                           }
8072                         }
8073 #endif
8074                         firstr = lastr = NULL;
8075                         break;
8076             }
8077
8078             if(inRegCount == -1) {
8079 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8080               regCount = 0;
8081               inRegCount = 0;
8082             }
8083           }
8084         } else {
8085           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8086             if(inEntry)
8087               r = pic16_getRegFromInstruction(pc);
8088             else
8089               r = pic16_getRegFromInstruction2(pc);
8090             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8091               if(!firstr)firstr = r;
8092               regCount++;
8093 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8094             }
8095           }
8096         }
8097       }
8098     }
8099 }
8100
8101
8102
8103
8104
8105 /*-----------------------------------------------------------------*/
8106 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8107 /*                   function                                      */
8108 /*-----------------------------------------------------------------*/
8109 static bool ispCodeFunction(pCode *pc)
8110 {
8111
8112   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8113     return 1;
8114
8115   return 0;
8116 }
8117
8118 /*-----------------------------------------------------------------*/
8119 /* findFunction - Search for a function by name (given the name)   */
8120 /*                in the set of all functions that are in a pBlock */
8121 /* (note - I expect this to change because I'm planning to limit   */
8122 /*  pBlock's to just one function declaration                      */
8123 /*-----------------------------------------------------------------*/
8124 static pCode *findFunction(char *fname)
8125 {
8126   pBlock *pb;
8127   pCode *pc;
8128   if(!fname)
8129     return NULL;
8130
8131   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8132
8133     pc = setFirstItem(pb->function_entries);
8134     while(pc) {
8135
8136       if((pc->type == PC_FUNCTION) &&
8137          (PCF(pc)->fname) &&
8138          (strcmp(fname, PCF(pc)->fname)==0))
8139         return pc;
8140
8141       pc = setNextItem(pb->function_entries);
8142
8143     }
8144
8145   }
8146   return NULL;
8147 }
8148
8149 static void MarkUsedRegisters(set *regset)
8150 {
8151
8152   regs *r1,*r2;
8153
8154   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8155 //      fprintf(stderr, "marking register = %s\t", r1->name);
8156     r2 = pic16_regWithIdx(r1->rIdx);
8157 //      fprintf(stderr, "to register = %s\n", r2->name);
8158     r2->isFree = 0;
8159     r2->wasUsed = 1;
8160   }
8161 }
8162
8163 static void pBlockStats(FILE *of, pBlock *pb)
8164 {
8165
8166   pCode *pc;
8167   regs  *r;
8168
8169         if(!pic16_pcode_verbose)return;
8170
8171   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8172
8173   // for now just print the first element of each set
8174   pc = setFirstItem(pb->function_entries);
8175   if(pc) {
8176     fprintf(of,";entry:  ");
8177     pc->print(of,pc);
8178   }
8179   pc = setFirstItem(pb->function_exits);
8180   if(pc) {
8181     fprintf(of,";has an exit\n");
8182     //pc->print(of,pc);
8183   }
8184
8185   pc = setFirstItem(pb->function_calls);
8186   if(pc) {
8187     fprintf(of,";functions called:\n");
8188
8189     while(pc) {
8190       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8191         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8192       }
8193       pc = setNextItem(pb->function_calls);
8194     }
8195   }
8196
8197   r = setFirstItem(pb->tregisters);
8198   if(r) {
8199     int n = elementsInSet(pb->tregisters);
8200
8201     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8202
8203     while (r) {
8204       fprintf(of,   ";   %s\n",r->name);
8205       r = setNextItem(pb->tregisters);
8206     }
8207   }
8208
8209   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8210 }
8211
8212 /*-----------------------------------------------------------------*/
8213 /*-----------------------------------------------------------------*/
8214 #if 0
8215 static void sequencepCode(void)
8216 {
8217   pBlock *pb;
8218   pCode *pc;
8219
8220
8221   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8222
8223     pb->seq = GpCodeSequenceNumber+1;
8224
8225     for( pc = pb->pcHead; pc; pc = pc->next)
8226       pc->seq = ++GpCodeSequenceNumber;
8227   }
8228
8229 }
8230 #endif
8231
8232 /*-----------------------------------------------------------------*/
8233 /*-----------------------------------------------------------------*/
8234 static set *register_usage(pBlock *pb)
8235 {
8236   pCode *pc,*pcn;
8237   set *registers=NULL;
8238   set *registersInCallPath = NULL;
8239
8240   /* check recursion */
8241
8242   pc = setFirstItem(pb->function_entries);
8243
8244   if(!pc)
8245     return registers;
8246
8247   pb->visited = 1;
8248
8249   if(pc->type != PC_FUNCTION)
8250     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8251
8252   pc = setFirstItem(pb->function_calls);
8253   for( ; pc; pc = setNextItem(pb->function_calls)) {
8254
8255     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8256       char *dest = pic16_get_op_from_instruction(PCI(pc));
8257
8258       pcn = findFunction(dest);
8259       if(pcn)
8260         registersInCallPath = register_usage(pcn->pb);
8261     } else
8262       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8263
8264   }
8265
8266 #ifdef PCODE_DEBUG
8267   pBlockStats(stderr,pb);  // debug
8268 #endif
8269
8270   // Mark the registers in this block as used.
8271
8272   MarkUsedRegisters(pb->tregisters);
8273   if(registersInCallPath) {
8274     /* registers were used in the functions this pBlock has called */
8275     /* so now, we need to see if these collide with the ones we are */
8276     /* using here */
8277
8278     regs *r1,*r2, *newreg;
8279
8280     DFPRINTF((stderr,"comparing registers\n"));
8281
8282     r1 = setFirstItem(registersInCallPath);
8283     while(r1) {
8284
8285       r2 = setFirstItem(pb->tregisters);
8286
8287       while(r2 && (r1->type != REG_STK)) {
8288
8289         if(r2->rIdx == r1->rIdx) {
8290           newreg = pic16_findFreeReg(REG_GPR);
8291
8292
8293           if(!newreg) {
8294             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8295             exit(1);
8296           }
8297
8298           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8299                   r1->rIdx, newreg->rIdx));
8300           r2->rIdx = newreg->rIdx;
8301           //if(r2->name) Safe_free(r2->name);
8302           if(newreg->name)
8303             r2->name = Safe_strdup(newreg->name);
8304           else
8305             r2->name = NULL;
8306           newreg->isFree = 0;
8307           newreg->wasUsed = 1;
8308         }
8309         r2 = setNextItem(pb->tregisters);
8310       }
8311
8312       r1 = setNextItem(registersInCallPath);
8313     }
8314
8315     /* Collisions have been resolved. Now free the registers in the call path */
8316     r1 = setFirstItem(registersInCallPath);
8317     while(r1) {
8318       if(r1->type != REG_STK) {
8319         newreg = pic16_regWithIdx(r1->rIdx);
8320         newreg->isFree = 1;
8321       }
8322       r1 = setNextItem(registersInCallPath);
8323     }
8324
8325   }// else
8326   //    MarkUsedRegisters(pb->registers);
8327
8328   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8329 #ifdef PCODE_DEBUG
8330   if(registers)
8331     DFPRINTF((stderr,"returning regs\n"));
8332   else
8333     DFPRINTF((stderr,"not returning regs\n"));
8334
8335   DFPRINTF((stderr,"pBlock after register optim.\n"));
8336   pBlockStats(stderr,pb);  // debug
8337 #endif
8338
8339   return registers;
8340 }
8341
8342 /*-----------------------------------------------------------------*/
8343 /* pct2 - writes the call tree to a file                           */
8344 /*                                                                 */
8345 /*-----------------------------------------------------------------*/
8346 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8347 {
8348   pCode *pc,*pcn;
8349   int i;
8350   //  set *registersInCallPath = NULL;
8351
8352   if(!of)
8353     return;
8354
8355   if(indent > 10) {
8356         fprintf(of, "recursive function\n");
8357     return; //recursion ?
8358   }
8359
8360   pc = setFirstItem(pb->function_entries);
8361
8362   if(!pc)
8363     return;
8364
8365   pb->visited = 0;
8366
8367   for(i=0;i<indent;i++)   // Indentation
8368         fputs("+   ", of);
8369   fputs("+- ", of);
8370
8371   if(pc->type == PC_FUNCTION) {
8372     usedstack += PCF(pc)->stackusage;
8373     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8374   } else return;  // ???
8375
8376
8377   pc = setFirstItem(pb->function_calls);
8378   for( ; pc; pc = setNextItem(pb->function_calls)) {
8379
8380     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8381       char *dest = pic16_get_op_from_instruction(PCI(pc));
8382
8383       pcn = findFunction(dest);
8384       if(pcn)
8385         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8386     } else
8387       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8388
8389   }
8390
8391
8392 }
8393
8394
8395 /*-----------------------------------------------------------------*/
8396 /* pic16_printCallTree - writes the call tree to a file                  */
8397 /*                                                                 */
8398 /*-----------------------------------------------------------------*/
8399
8400 void pic16_printCallTree(FILE *of)
8401 {
8402   pBranch *pbr;
8403   pBlock  *pb;
8404   pCode   *pc;
8405
8406   if(!the_pFile)
8407     return;
8408
8409   if(!of)
8410     of = stderr;
8411
8412   fprintf(of, "\npBlock statistics\n");
8413   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8414     pBlockStats(of,pb);
8415
8416
8417   fprintf(of,"Call Tree\n");
8418   pbr = the_pFile->functions;
8419   while(pbr) {
8420     if(pbr->pc) {
8421       pc = pbr->pc;
8422       if(!ispCodeFunction(pc))
8423         fprintf(of,"bug in call tree");
8424
8425
8426       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8427
8428       while(pc->next && !ispCodeFunction(pc->next)) {
8429         pc = pc->next;
8430         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8431           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8432       }
8433     }
8434
8435     pbr = pbr->next;
8436   }
8437
8438
8439   fprintf(of,"\n**************\n\na better call tree\n");
8440   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8441 //    if(pb->visited)
8442       pct2(of,pb,0,0);
8443   }
8444
8445   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8446     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8447   }
8448 }
8449
8450
8451
8452 /*-----------------------------------------------------------------*/
8453 /*                                                                 */
8454 /*-----------------------------------------------------------------*/
8455
8456 static void InlineFunction(pBlock *pb)
8457 {
8458   pCode *pc;
8459   pCode *pc_call;
8460
8461   if(!pb)
8462     return;
8463
8464   pc = setFirstItem(pb->function_calls);
8465
8466   for( ; pc; pc = setNextItem(pb->function_calls)) {
8467
8468     if(isCALL(pc)) {
8469       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8470       pCode *pct;
8471       pCode *pce;
8472
8473       pBranch *pbr;
8474
8475       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8476
8477         //fprintf(stderr,"Cool can inline:\n");
8478         //pcn->print(stderr,pcn);
8479
8480         //fprintf(stderr,"recursive call Inline\n");
8481         InlineFunction(pcn->pb);
8482         //fprintf(stderr,"return from recursive call Inline\n");
8483
8484         /*
8485           At this point, *pc points to a CALL mnemonic, and
8486           *pcn points to the function that is being called.
8487
8488           To in-line this call, we need to remove the CALL
8489           and RETURN(s), and link the function pCode in with
8490           the CALLee pCode.
8491
8492         */
8493
8494
8495         /* Remove the CALL */
8496         pc_call = pc;
8497         pc = pc->prev;
8498
8499         /* remove callee pBlock from the pBlock linked list */
8500         removepBlock(pcn->pb);
8501
8502         pce = pcn;
8503         while(pce) {
8504           pce->pb = pb;
8505           pce = pce->next;
8506         }
8507
8508         /* Remove the Function pCode */
8509         pct = pic16_findNextInstruction(pcn->next);
8510
8511         /* Link the function with the callee */
8512         pc->next = pcn->next;
8513         pcn->next->prev = pc;
8514
8515         /* Convert the function name into a label */
8516
8517         pbr = Safe_calloc(1,sizeof(pBranch));
8518         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8519         pbr->next = NULL;
8520         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8521         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8522
8523         /* turn all of the return's except the last into goto's */
8524         /* check case for 2 instruction pBlocks */
8525         pce = pic16_findNextInstruction(pcn->next);
8526         while(pce) {
8527           pCode *pce_next = pic16_findNextInstruction(pce->next);
8528
8529           if(pce_next == NULL) {
8530             /* found the last return */
8531             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8532
8533             //fprintf(stderr,"found last return\n");
8534             //pce->print(stderr,pce);
8535             pce->prev->next = pc_call->next;
8536             pc_call->next->prev = pce->prev;
8537             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8538                                                       PCI(pce)->label);
8539           }
8540
8541           pce = pce_next;
8542         }
8543
8544
8545       }
8546     } else
8547       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8548
8549   }
8550
8551 }
8552
8553 /*-----------------------------------------------------------------*/
8554 /*                                                                 */
8555 /*-----------------------------------------------------------------*/
8556
8557 void pic16_InlinepCode(void)
8558 {
8559
8560   pBlock  *pb;
8561   pCode   *pc;
8562
8563   if(!the_pFile)
8564     return;
8565
8566   if(!functionInlining)
8567     return;
8568
8569   /* Loop through all of the function definitions and count the
8570    * number of times each one is called */
8571   //fprintf(stderr,"inlining %d\n",__LINE__);
8572
8573   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8574
8575     pc = setFirstItem(pb->function_calls);
8576
8577     for( ; pc; pc = setNextItem(pb->function_calls)) {
8578
8579       if(isCALL(pc)) {
8580         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8581         if(pcn && isPCF(pcn)) {
8582           PCF(pcn)->ncalled++;
8583         }
8584       } else
8585         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8586
8587     }
8588   }
8589
8590   //fprintf(stderr,"inlining %d\n",__LINE__);
8591
8592   /* Now, Loop through the function definitions again, but this
8593    * time inline those functions that have only been called once. */
8594
8595   InlineFunction(the_pFile->pbHead);
8596   //fprintf(stderr,"inlining %d\n",__LINE__);
8597
8598   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8599     unBuildFlow(pb);
8600
8601 }
8602
8603 char *pic_optype_names[]={
8604         "PO_NONE",         // No operand e.g. NOP
8605         "PO_W",              // The working register (as a destination)
8606         "PO_WREG",           // The working register (as a file register)
8607         "PO_STATUS",         // The 'STATUS' register
8608         "PO_BSR",            // The 'BSR' register
8609         "PO_FSR0",           // The "file select register" (in PIC18 family it's one
8610                              // of three)
8611         "PO_INDF0",          // The Indirect register
8612         "PO_INTCON",         // Interrupt Control register
8613         "PO_GPR_REGISTER",   // A general purpose register
8614         "PO_GPR_BIT",        // A bit of a general purpose register
8615         "PO_GPR_TEMP",       // A general purpose temporary register
8616         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8617         "PO_PCL",            // Program counter Low register
8618         "PO_PCLATH",         // Program counter Latch high register
8619         "PO_PCLATU",         // Program counter Latch upper register
8620         "PO_PRODL",          // Product Register Low
8621         "PO_PRODH",          // Product Register High
8622         "PO_LITERAL",        // A constant
8623         "PO_REL_ADDR",       // A relative address
8624         "PO_IMMEDIATE",      //  (8051 legacy)
8625         "PO_DIR",            // Direct memory (8051 legacy)
8626         "PO_CRY",            // bit memory (8051 legacy)
8627         "PO_BIT",            // bit operand.
8628         "PO_STR",            //  (8051 legacy)
8629         "PO_LABEL",
8630         "PO_WILD",           // Wild card operand in peep optimizer
8631         "PO_TWO_OPS"         // combine two operands
8632 };
8633
8634
8635 char *dumpPicOptype(PIC_OPTYPE type)
8636 {
8637         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8638         return (pic_optype_names[ type ]);
8639 }
8640
8641
8642 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8643 #include "graph.h"
8644
8645 #define MAX_COMMON_BANK_SIZE    32
8646 #define FIRST_PSEUDO_BANK_NR  1000
8647
8648 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8649 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8650 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8651 Graph *adj = NULL;
8652
8653 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8654
8655 typedef struct {
8656   pseudoBankNr bank;  // number assigned to this pseudoBank
8657   unsigned int size;  // number of operands assigned to this bank
8658   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8659 } pseudoBank;
8660
8661 /*----------------------------------------------------------------------*/
8662 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8663 /*----------------------------------------------------------------------*/
8664 unsigned int hashSymbol (const char *str)
8665 {
8666   unsigned int res = 0;
8667   if (!str) return 0;
8668
8669   while (*str) {
8670     res ^= (*str);
8671     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8672     str++;
8673   } // while
8674
8675   return res;
8676 }
8677
8678 /*-----------------------------------------------------------------------*/
8679 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8680 /*-----------------------------------------------------------------------*/
8681 int compareSymbol (const void *sym1, const void *sym2)
8682 {
8683   char *s1 = (char*) sym1;
8684   char *s2 = (char*) sym2;
8685
8686   return (strcmp (s1,s2) == 0);
8687 }
8688
8689 /*-----------------------------------------------------------------------*/
8690 /* comparePre - return 1 iff p1 == p2                                    */
8691 /*-----------------------------------------------------------------------*/
8692 int comparePtr (const void *p1, const void *p2)
8693 {
8694   return (p1 == p2);
8695 }
8696
8697 /*----------------------------------------------------------*/
8698 /* getSymbolFromOperand - return a pointer to the symbol in */
8699 /*                        the given operand and its length  */
8700 /*----------------------------------------------------------*/
8701 char *getSymbolFromOperand (char *op, int *len)
8702 {
8703   char *sym, *curr;
8704   *len = 0;
8705
8706   if (!op) return NULL;
8707
8708   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8709   sym = op;
8710   if (*sym == '(') sym++;
8711
8712   curr = sym;
8713   while (((*curr >= 'A') && (*curr <= 'Z'))
8714          || ((*curr >= 'a') && (*curr <= 'z'))
8715          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8716          || (*curr == '_')) {
8717     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8718     curr++;
8719     (*len)++;
8720   } // while
8721
8722   return sym;
8723 }
8724
8725 /*--------------------------------------------------------------------------*/
8726 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8727 /*--------------------------------------------------------------------------*/
8728 char *getSymFromBank (pseudoBankNr bank)
8729 {
8730   assert (bank2sym);
8731
8732   if (bank < 0) return "<INVALID BANK NR>";
8733   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8734 }
8735
8736 /*-----------------------------------------------------------------------*/
8737 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8738 /*                           bank number (uses hTab sym2bank), if the    */
8739 /*                           symbol is not yet assigned a pseudo bank it */
8740 /*                           is assigned one here                        */
8741 /*-----------------------------------------------------------------------*/
8742 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8743 {
8744   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8745   pseudoBankNr bank;
8746   unsigned int hash;
8747
8748   assert (sym2bank);
8749
8750   hash = hashSymbol (op) % sym2bank->size;
8751   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8752   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8753
8754   if (bank == UNKNOWN_BANK) {
8755     // create a pseudo bank for the operand
8756     bank = next_bank++;
8757     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8758     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8759     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8760     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8761   } else {
8762     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8763   } // if
8764
8765   assert (bank >= 0);
8766
8767   return bank;
8768 }
8769
8770 /*--------------------------------------------------------------------*/
8771 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8772 /*--------------------------------------------------------------------*/
8773 int isBanksel (pCode *pc)
8774 {
8775   if (!pc) return 0;
8776
8777   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8778     // BANKSEL <variablename>  or  MOVLB <banknr>
8779     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8780     return 1;
8781   }
8782
8783   // check for inline assembler BANKSELs
8784   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8785                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8786     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8787     return 1;
8788   }
8789
8790   // assume pc is no BANKSEL instruction
8791   return 0;
8792 }
8793
8794 /*---------------------------------------------------------------------------------*/
8795 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8796 /*                  This method can not guarantee to find all modifications of the */
8797 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8798 /*                  generated plus some cases.                                     */
8799 /*---------------------------------------------------------------------------------*/
8800 int invalidatesBSR(pCode *pc)
8801 {
8802   // assembler directives invalidate BSR (well, they might, we don't know)
8803   if (isPCAD(pc)) return 1;
8804
8805   // only ASMDIRs and pCodeInstructions can invalidate BSR
8806   if (!isPCI(pc)) return 0;
8807
8808   // we have a pCodeInstruction
8809
8810   // check for BSR modifying instructions
8811   switch (PCI(pc)->op) {
8812   case POC_CALL:
8813   case POC_RCALL:
8814   case POC_MOVLB:
8815   case POC_RETFIE:  // might be used as CALL replacement
8816   case POC_RETLW:   // might be used as CALL replacement
8817   case POC_RETURN:  // might be used as CALL replacement
8818   case POC_BANKSEL:
8819     return 1;
8820     break;
8821
8822   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8823     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8824     break;
8825   } // switch
8826
8827   // no change of BSR possible/probable
8828   return 0;
8829 }
8830
8831 /*------------------------------------------------------------*/
8832 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8833 /*                      the symbol referenced in this BANKSEL */
8834 /*------------------------------------------------------------*/
8835 pseudoBankNr getBankFromBanksel (pCode *pc)
8836 {
8837   char *sym;
8838   int data = 0;
8839
8840   if (!pc) return INVALID_BANK;
8841
8842   if (isPCAD(pc) && PCAD(pc)->directive) {
8843     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8844       // get symbolname from PCAD(pc)->arg
8845       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8846       sym = PCAD(pc)->arg;
8847       data = getPseudoBankNrFromOperand (sym);
8848       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8849     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8850       // get (literal) bank number from PCAD(pc)->arg
8851       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8852       assert (0 && "not yet implemented - turn off banksel optimization for now");
8853     }
8854   } else if (isPCI(pc)) {
8855     if (PCI(pc)->op == POC_BANKSEL) {
8856       // get symbolname from PCI(pc)->pcop->name (?)
8857       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8858       sym = PCI(pc)->pcop->name;
8859       data = getPseudoBankNrFromOperand (sym);
8860       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8861     } else if (PCI(pc)->op == POC_MOVLB) {
8862       // get (literal) bank number from PCI(pc)->pcop->name
8863       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8864       assert (0 && "not yet implemented - turn off banksel optimization for now");
8865     }
8866   }
8867
8868   if (data == 0)
8869     // no assigned bank could be found
8870     return UNKNOWN_BANK;
8871   else
8872     return data;
8873 }
8874
8875 /*------------------------------------------------------------------------------*/
8876 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8877 /*------------------------------------------------------------------------------*/
8878 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8879 {
8880   pseudoBank *data;
8881
8882   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8883
8884   do {
8885     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8886     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8887     if (data) {
8888       if (data->bank != bank)
8889         bank = data->bank;
8890       else
8891         data = NULL;
8892     }
8893   } while (data);
8894
8895   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8896   return bank;
8897 }
8898
8899 /*------------------------------------------------------------------*/
8900 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8901 /*                        bank is selected at a given pCode         */
8902 /*------------------------------------------------------------------*/
8903
8904 /* Create a graph with pseudo banks as its nodes and switches between
8905  * these as edges (with the edge weight representing the absolute
8906  * number of BANKSELs from one to the other).
8907  * Removes redundand BANKSELs instead iff mod == 1.
8908  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8909  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8910  * pseudo BSR.
8911  * TODO: check ALL instructions operands if they modify BSR directly...
8912  *
8913  * pb - the pBlock to annotate
8914  * mod  - select either graph creation (0) or BANKSEL removal (1)
8915  */
8916 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8917 {
8918   pCode *pc, *pc_next;
8919   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8920   int isBankselect = 0;
8921   unsigned int banksels=0;
8922
8923   if (!pb) return 0;
8924
8925   pc = pic16_findNextInstruction(pb->pcHead);
8926   while (pc) {
8927     isBankselect = isBanksel (pc);
8928     pc_next = pic16_findNextInstruction (pc->next);
8929
8930     if (!hasNoLabel (pc)) {
8931       // we don't know our predecessors -- assume different BSRs
8932       prevBSR = UNKNOWN_BANK;
8933       pseudoBSR = UNKNOWN_BANK;
8934       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8935     } // if
8936
8937     // check if this is a BANKSEL instruction
8938     if (isBankselect) {
8939       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8940       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8941       if (mod) {
8942         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8943           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8944           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8945           pic16_unlinkpCode (pc);
8946           banksels++;
8947         }
8948       } else {
8949         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8950         banksels++;
8951       }
8952     } // if
8953
8954     if (!isBankselect && invalidatesBSR(pc)) {
8955       // check if this instruction invalidates the pseudoBSR
8956       pseudoBSR = UNKNOWN_BANK;
8957       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8958     } // if
8959
8960     prevBSR = pseudoBSR;
8961     pc = pc_next;
8962   } // while
8963
8964   return banksels;
8965 }
8966
8967 /*------------------------------------------------------------------------------------*/
8968 /* assignToSameBank - returns 0 on success or an error code                           */
8969 /*  1 - common bank would be too large                                                */
8970 /*  2 - assignment to fixed (absolute) bank not performed                             */
8971 /*                                                                                    */
8972 /* This functions assumes that unsplittable operands are already assigned to the same */
8973 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
8974 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
8975 /* TODO: Symbols with an abslute address must be handled specially!                   */
8976 /*------------------------------------------------------------------------------------*/
8977 int assignToSameBank (int bank0, int bank1, int doAbs)
8978 {
8979   int eff0, eff1, dummy;
8980   pseudoBank *pbank0, *pbank1;
8981   hashtItem *hitem;
8982
8983   eff0 = getEffectiveBank (bank0);
8984   eff1 = getEffectiveBank (bank1);
8985
8986   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8987
8988   // nothing to do if already same bank
8989   if (eff0 == eff1) return 0;
8990
8991   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8992     return 2;
8993
8994   // ensure eff0 < eff1
8995   if (eff0 > eff1) {
8996     // swap eff0 and eff1
8997     dummy = eff0;
8998     eff0 = eff1;
8999     eff1 = dummy;
9000     dummy = bank0;
9001     bank0 = bank1;
9002     bank1 = dummy;
9003   } // if
9004
9005   // now assign bank eff1 to bank eff0
9006   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9007   if (!pbank0) {
9008     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9009     pbank0->bank = eff0;
9010     pbank0->size = 1;
9011     pbank0->ref = 1;
9012     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9013   } // if
9014
9015   pbank1 = NULL;
9016   hitem = hTabSearch (coerce, eff1 % coerce->size);
9017   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9018     hitem = hitem->next;
9019
9020   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9021
9022 #if 0
9023   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9024            pbank0->bank, pbank0->size,
9025            getSymFromBank (eff0), getSymFromBank (eff1));
9026 #endif
9027
9028   if (pbank1) {
9029     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9030 #if 0
9031       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9032                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9033                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9034                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9035 #endif
9036       return 1;
9037     } // if
9038     pbank0->size += pbank1->size;
9039     pbank1->ref--;
9040     if (pbank1->ref == 0) Safe_free (pbank1);
9041   } else {
9042     pbank0->size++;
9043   } // if
9044
9045   if (hitem)
9046     hitem->item = pbank0;
9047   else
9048     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9049   pbank0->ref++;
9050
9051   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9052
9053   return 0;
9054 }
9055
9056 /*----------------------------------------------------------------*/
9057 /* mergeGraphNodes - combines two nodes into one and modifies all */
9058 /*                   edges to and from the nodes accordingly      */
9059 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9060 /* then also (B,A) must be an edge (possibly with weight 0).      */
9061 /*----------------------------------------------------------------*/
9062 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9063 {
9064   GraphEdge *edge, *backedge, *nextedge;
9065   GraphNode *node;
9066   int backweight;
9067
9068   assert (node1 && node2);
9069   assert (node1 != node2);
9070
9071   // add all edges starting at node2 to node1
9072   edge = node2->edge;
9073   while (edge) {
9074     nextedge = edge->next;
9075     node = edge->node;
9076     backedge = getGEdge (node, node2);
9077     if (backedge)
9078       backweight = backedge->weight;
9079     else
9080       backweight = 0;
9081     // insert edges (node1,node) and (node,node1)
9082     addGEdge2 (node1, node, edge->weight, backweight);
9083     // remove edges (node, node2) and (node2, node)
9084     remGEdge (node2, node);
9085     remGEdge (node, node2);
9086     edge = nextedge;
9087   } // while
9088
9089   // now node2 should not be referenced by any other GraphNode...
9090   //remGNode (adj, node2->data, node2->hash);
9091 }
9092
9093 /*----------------------------------------------------------------*/
9094 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9095 /*----------------------------------------------------------------*/
9096 void showGraph (Graph *g)
9097 {
9098   GraphNode *node;
9099   GraphEdge *edge;
9100   pseudoBankNr bankNr;
9101   pseudoBank *pbank;
9102   unsigned int size;
9103
9104   node = g->node;
9105   while (node) {
9106     edge = node->edge;
9107     bankNr = getEffectiveBank (node->hash);
9108     assert (bankNr >= 0);
9109     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9110     if (pbank) {
9111       bankNr = pbank->bank;
9112       size = pbank->size;
9113     } else {
9114       size = 1;
9115     }
9116
9117     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9118
9119     while (edge) {
9120       if (edge->weight > 0)
9121         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9122       edge = edge->next;
9123     } // while (edge)
9124     node = node->next;
9125   } // while (node)
9126 }
9127
9128 /*---------------------------------------------------------------*/
9129 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9130 /*---------------------------------------------------------------*/
9131 void pic16_OptimizeBanksel ()
9132 {
9133   GraphNode *node, *node1, *node1next;
9134
9135 #if 0
9136   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9137   GraphEdge *edge, *backedge;
9138   GraphEdge *max;
9139   int maxWeight, weight, mergeMore, absMaxWeight;
9140   pseudoBankNr curr0, curr1;
9141 #endif
9142   pseudoBank *pbank;
9143   pseudoBankNr bankNr;
9144   char *base_symbol0, *base_symbol1;
9145   int len0, len1;
9146   pBlock *pb;
9147   set *set;
9148   regs *reg;
9149   unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9150
9151   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9152
9153   if (!the_pFile || !the_pFile->pbHead) return;
9154
9155   adj = newGraph (NULL);
9156   sym2bank = newHashTable ( 255 );
9157   bank2sym = newHashTable ( 255 );
9158   coerce = newHashTable ( 255 );
9159
9160   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9161   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9162     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9163   } // for pb
9164
9165 #if 1
9166   // assign symbols with absolute addresses to their respective bank nrs
9167   set = pic16_fix_udata;
9168   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9169     bankNr = reg->address >> 8;
9170     node = getOrAddGNode (adj, NULL, bankNr);
9171     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9172     assignToSameBank (node->hash, bankNr, 1);
9173
9174     assert (bankNr >= 0);
9175     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9176     if (!pbank) {
9177       pbank = Safe_calloc (1, sizeof (pseudoBank));
9178       pbank->bank = reg->address >> 8; //FIXED_BANK;
9179       pbank->size = 1;
9180       pbank->ref = 1;
9181       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9182     } else {
9183       assert (pbank->bank == (reg->address >> 8));
9184       pbank->bank = reg->address >> 8; //FIXED_BANK;
9185     }
9186     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9187   } // for reg
9188 #endif
9189
9190 #if 1
9191   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9192   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9193   node = adj->node;
9194   while (node) {
9195     if (node->hash < 0) { node = node->next; continue; }
9196     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9197     node1 = node->next;
9198     while (node1) {
9199       if (node1->hash < 0) { node1 = node1->next; continue; }
9200       node1next = node1->next;
9201       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9202       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9203         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9204         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9205         if (assignToSameBank (node->hash, node1->hash, 0)) {
9206           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9207           assert (0 && "Could not assign a symbol to a bank!");
9208         }
9209         mergeGraphNodes (node, node1);
9210         /*
9211         if (node->hash < node1->hash)
9212           mergeGraphNodes (node, node1);
9213         else
9214           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9215         */
9216       } // if
9217       node1 = node1next;
9218     } // while (node1)
9219     node = node->next;
9220   } // while (node)
9221 #endif
9222
9223 #if 0
9224   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9225   // assign tightly coupled operands to the same (pseudo) bank
9226   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9227   mergeMore = 1;
9228   absMaxWeight = 0;
9229   while (mergeMore) {
9230     node = adj->node;
9231     max = NULL;
9232     maxWeight = 0;
9233     while (node) {
9234       curr0 = getEffectiveBank (node->hash);
9235       if (curr0 < 0) { node = node->next; continue; }
9236       edge = node->edge;
9237       while (edge) {
9238         assert (edge->src == node);
9239         backedge = getGEdge (edge->node, edge->src);
9240         weight = edge->weight + (backedge ? backedge->weight : 0);
9241         curr1 = getEffectiveBank (edge->node->hash);
9242         if (curr1 < 0) { edge = edge->next; continue; }
9243
9244         // merging is only useful if the items are not assigned to the same bank already...
9245         if (curr0 != curr1 && weight > maxWeight) {
9246           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9247           maxWeight = weight;
9248           max = edge;
9249         } // if
9250         edge = edge->next;
9251       } // while
9252       node = node->next;
9253     } // while
9254
9255     if (maxWeight > 0) {
9256 #if 0
9257       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9258                max->src->hash, getSymFromBank (max->src->hash),
9259                max->node->hash, getSymFromBank (max->node->hash));
9260 #endif
9261
9262       node = getGNode (adj, max->src->data, max->src->hash);
9263       node1 = getGNode (adj, max->node->data, max->node->hash);
9264
9265       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9266         if (max->src->hash < max->node->hash)
9267           mergeGraphNodes (node, node1);
9268         else
9269           mergeGraphNodes (node1, node);
9270       } else {
9271         remGEdge (node, node1);
9272         remGEdge (node1, node);
9273         //mergeMore = 0;
9274       }
9275
9276     } else {
9277       mergeMore = 0;
9278     }
9279   } // while
9280 #endif
9281
9282 #if 1
9283   // remove redundant BANKSELs
9284   //fprintf (stderr, "removing redundant BANKSELs\n");
9285   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9286     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9287   } // for pb
9288 #endif
9289
9290 #if 0
9291   fprintf (stderr, "display graph\n");
9292   showGraph ();
9293 #endif
9294
9295   deleteGraph (adj);
9296   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9297 }
9298
9299 /*** END of stuff belonging to the BANKSEL optimization ***/
9300
9301
9302
9303 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9304
9305 typedef unsigned int symbol_t;
9306 typedef unsigned int valnum_t;
9307 //typedef unsigned int hash_t;
9308
9309 #ifndef INT_TO_PTR
9310 #define INT_TO_PTR(x) (((char *) 0) + (x))
9311 #endif
9312
9313 #ifndef PTR_TO_INT
9314 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9315 #endif
9316
9317 static int pic16_regIsLocal (regs *r);
9318 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9319
9320 /* statistics */
9321 static unsigned int pic16_df_removed_pcodes = 0;
9322 static unsigned int pic16_df_saved_bytes = 0;
9323 static unsigned int df_findall_sameflow = 0;
9324 static unsigned int df_findall_otherflow = 0;
9325 static unsigned int df_findall_in_vals = 0;
9326
9327 static void pic16_df_stats () {
9328   return;
9329   if (pic16_debug_verbose || pic16_pcode_verbose) {
9330     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9331     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9332     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9333   }
9334 }
9335
9336 /* Remove a pCode iff possible:
9337  * - previous pCode is no SKIP
9338  * - pc has no label
9339  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9340 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9341   pCode *pcprev, *pcnext;
9342   char buf[256], *total=NULL;
9343   int len;
9344
9345   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9346
9347   pcprev = pic16_findPrevInstruction (pc->prev);
9348   pcnext = pic16_findNextInstruction (pc->next);
9349
9350   /* move labels to next instruction (if possible) */
9351   if (PCI(pc)->label && !pcnext) return 0;
9352
9353   /* if this is a SKIP with side-effects -- do not remove */
9354   /* XXX: might try to replace this one with the side-effect only version */
9355   if (isPCI_SKIP(pc)
9356         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9357   {
9358     pCode *newpc;
9359     switch (PCI(pc)->op)
9360     {
9361     case POC_INCFSZ:
9362     case POC_INFSNZ:
9363       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9364       pic16_pCodeReplace( pc, newpc );
9365       return 1;
9366       break;
9367     case POC_INCFSZW:
9368       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9369       pic16_pCodeReplace( pc, newpc );
9370       return 1;
9371       break;
9372     case POC_DECFSZ:
9373     case POC_DCFSNZ:
9374       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9375       pic16_pCodeReplace( pc, newpc );
9376       return 1;
9377       break;
9378     case POC_DECFSZW:
9379       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9380       pic16_pCodeReplace( pc, newpc );
9381       return 1;
9382       break;
9383     default:
9384       return 0;
9385     }
9386     return 0;
9387   }
9388
9389   /* if previous instruction is a skip -- do not remove */
9390   if (pcprev && isPCI_SKIP(pcprev)) {
9391     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9392       /* preceeding SKIP could not be removed -- keep this instruction! */
9393       return 0;
9394     }
9395   }
9396
9397   if (PCI(pc)->label) {
9398     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9399     //pc->print (stderr, pc);
9400     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9401     PCI(pc)->label = NULL;
9402   }
9403
9404   /* update statistics */
9405   pic16_df_removed_pcodes++;
9406   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9407
9408   /* remove the pCode */
9409   pic16_pCode2str (buf, 256, pc);
9410   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9411   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9412     len = strlen (buf) + strlen (comment) + 10;
9413     total = (char *) Safe_malloc (len);
9414     SNPRINTF (total, len, "%s: %s", comment, buf);
9415     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9416     Safe_free (total);
9417   }
9418
9419   /* actually unlink it from the pBlock -- also remove from to/from lists */
9420   pic16_pCodeUnlink (pc);
9421
9422   /* remove the pCode -- release registers */
9423   pc->destruct (pc);
9424
9425   /* report success */
9426   return 1;
9427 }
9428
9429
9430 /* ======================================================================== */
9431 /* === SYMBOL HANDLING ==================================================== */
9432 /* ======================================================================== */
9433
9434 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9435 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9436 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9437
9438 /** Calculate a hash for a given string.
9439  * If len == 0 the string is assumed to be NUL terminated. */
9440 static hash_t symbolHash (const char *str, unsigned int len) {
9441   hash_t hash = 0;
9442   if (!len) {
9443     while (*str) {
9444       hash = (hash << 2) ^ *str;
9445       str++;
9446     } // while
9447   } else {
9448     while (len--) {
9449       hash = (hash << 2) ^ *str;
9450       str++;
9451     }
9452   }
9453   return hash;
9454 }
9455
9456 /** Return 1 iff strings v1 and v2 are identical. */
9457 static int symcmp (const void *v1, const void *v2) {
9458   return !strcmp ((const char *) v1, (const char *) v2);
9459 }
9460
9461 /** Return 1 iff pointers v1 and v2 are identical. */
9462 static int ptrcmp (const void *v1, const void *v2) {
9463   return (v1 == v2);
9464 }
9465
9466 enum {  SPO_WREG=0x1000,
9467         SPO_STATUS,
9468         SPO_PRODL,
9469         SPO_PRODH,
9470         SPO_INDF0,
9471         SPO_POSTDEC0,
9472         SPO_POSTINC0,
9473         SPO_PREINC0,
9474         SPO_PLUSW0,
9475         SPO_INDF1,
9476         SPO_POSTDEC1,
9477         SPO_POSTINC1,
9478         SPO_PREINC1,
9479         SPO_PLUSW1,
9480         SPO_INDF2,
9481         SPO_POSTDEC2,
9482         SPO_POSTINC2,
9483         SPO_PREINC2,
9484         SPO_PLUSW2,
9485         SPO_STKPTR,
9486         SPO_TOSL,
9487         SPO_TOSH,
9488         SPO_TOSU,
9489         SPO_BSR,
9490         SPO_FSR0L,
9491         SPO_FSR0H,
9492         SPO_FSR1L,
9493         SPO_FSR1H,
9494         SPO_FSR2L,
9495         SPO_FSR2H,
9496         SPO_PCL,
9497         SPO_PCLATH,
9498         SPO_PCLATU,
9499         SPO_TABLAT,
9500         SPO_TBLPTRL,
9501         SPO_TBLPTRH,
9502         SPO_TBLPTRU,
9503         SPO_LAST
9504 };
9505
9506 /* Return the unique symbol_t for the given string. */
9507 static symbol_t symFromStr (const char *str) {
9508   hash_t hash;
9509   char *res;
9510   symbol_t sym;
9511
9512   if (!map_symToStr) {
9513     int i;
9514     struct { char *name; symbol_t sym; } predefsyms[] = {
9515         {"WREG", SPO_WREG},
9516         {"STATUS", SPO_STATUS},
9517         {"PRODL", SPO_PRODL},
9518         {"PRODH", SPO_PRODH},
9519         {"INDF0", SPO_INDF0},
9520         {"POSTDEC0", SPO_POSTDEC0},
9521         {"POSTINC0", SPO_POSTINC0},
9522         {"PREINC0", SPO_PREINC0},
9523         {"PLUSW0", SPO_PLUSW0},
9524         {"INDF1", SPO_INDF1},
9525         {"POSTDEC1", SPO_POSTDEC1},
9526         {"POSTINC1", SPO_POSTINC1},
9527         {"PREINC1", SPO_PREINC1},
9528         {"PLUSW1", SPO_PLUSW1},
9529         {"INDF2", SPO_INDF2},
9530         {"POSTDEC2", SPO_POSTDEC2},
9531         {"POSTINC2", SPO_POSTINC2},
9532         {"PREINC2", SPO_PREINC2},
9533         {"PLUSW2", SPO_PLUSW2},
9534         {"STKPTR", SPO_STKPTR},
9535         {"TOSL", SPO_TOSL},
9536         {"TOSH", SPO_TOSH},
9537         {"TOSU", SPO_TOSU},
9538         {"BSR", SPO_BSR},
9539         {"FSR0L", SPO_FSR0L},
9540         {"FSR0H", SPO_FSR0H},
9541         {"FSR1L", SPO_FSR1L},
9542         {"FSR1H", SPO_FSR1H},
9543         {"FSR2L", SPO_FSR2L},
9544         {"FSR2H", SPO_FSR2H},
9545         {"PCL", SPO_PCL},
9546         {"PCLATH", SPO_PCLATH},
9547         {"PCLATU", SPO_PCLATU},
9548         {"TABLAT", SPO_TABLAT},
9549         {"TBLPTRL", SPO_TBLPTRL},
9550         {"TBLPTRH", SPO_TBLPTRH},
9551         {"TBLPTRU", SPO_TBLPTRU},
9552         {NULL, 0}
9553     };
9554
9555     map_strToSym = newHashTable (128);
9556     map_symToStr = newHashTable (128);
9557
9558     for (i=0; predefsyms[i].name; i++) {
9559       char *name;
9560
9561       /* enter new symbol */
9562       sym = predefsyms[i].sym;
9563       name = predefsyms[i].name;
9564       res = Safe_strdup (name);
9565       hash = symbolHash (name, 0);
9566
9567       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9568       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9569     } // for i
9570   }
9571
9572   hash = symbolHash (str, 0) % map_strToSym->size;
9573
9574   /* find symbol in table */
9575   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9576   if (sym) {
9577     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9578     return sym;
9579   }
9580
9581   /* enter new symbol */
9582   sym = nextSymbol++;
9583   res = Safe_strdup (str);
9584
9585   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9586   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9587
9588   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9589
9590   return sym;
9591 }
9592
9593 #if 1
9594 static const char *strFromSym (symbol_t sym) {
9595   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9596 }
9597 #endif
9598
9599 /* ======================================================================== */
9600 /* === DEFINITION MAP HANDLING ============================================ */
9601 /* ======================================================================== */
9602
9603 /* A defmap provides information about which symbol is defined by which pCode.
9604  * The most recent definitions are prepended to the list, so that the most
9605  * recent definition can be found by forward scanning the list.
9606  * pc2: MOVFF r0x00, r0x01
9607  * pc1: INCF r0x01
9608  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9609  *
9610  * We attach one defmap to each flow object, and each pCode will occur at
9611  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9612  * used to find definitions for a pCode in its own defmap that precede pCode.
9613  */
9614
9615 typedef struct defmap_s {
9616   symbol_t sym;                 /** symbol this item refers to */
9617   union {
9618     struct {
9619       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9620       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9621       int isRead:1;             /** sym/mask is read */
9622       int isWrite:1;            /** sym/mask is written */
9623     } access;
9624     int accessmethod;
9625   } acc;
9626   pCode *pc;                    /** pCode this symbol is refrenced at */
9627   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9628   valnum_t val;                 /** new unique number for this value (if isWrite) */
9629   struct defmap_s *prev, *next; /** link to previous an next definition */
9630 } defmap_t;
9631
9632 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9633 static int defmap_free_count = 0;               /** number of released defmap items */
9634
9635 /* Returns a defmap_t with the specified data; this will be the new list head.
9636  * next - pointer to the current list head */
9637 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9638   defmap_t *map;
9639
9640   if (defmap_free) {
9641     map = defmap_free;
9642     defmap_free = map->next;
9643     --defmap_free_count;
9644   } else {
9645     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9646   }
9647   map->sym = sym;
9648   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9649   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9650   map->acc.access.isRead = (isRead != 0);
9651   map->acc.access.isWrite = (isWrite != 0);
9652   map->pc = pc;
9653   map->in_val = 0;
9654   map->val = (isWrite ? val : 0);
9655   map->prev = NULL;
9656   map->next = next;
9657   if (next) next->prev = map;
9658
9659   return map;
9660 }
9661
9662 /* Returns a copy of the single defmap item. */
9663 static defmap_t *copyDefmap (defmap_t *map) {
9664   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9665   memcpy (res, map, sizeof (defmap_t));
9666   res->next = NULL;
9667   res->prev = NULL;
9668   return res;
9669 }
9670
9671 /* Insert a defmap item after the specified one. */
9672 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9673   if (!ref || !newItem) return 1;
9674
9675   newItem->next = ref->next;
9676   newItem->prev = ref;
9677   ref->next = newItem;
9678   if (newItem->next) newItem->next->prev = newItem;
9679
9680   return 0;
9681 }
9682
9683 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9684  * item is copied before insertion into chain and therefore left untouched.
9685  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9686 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9687   defmap_t *dummy;
9688   dummy = *head;
9689   while (dummy && (dummy->sym != item->sym
9690                           || dummy->pc != item->pc
9691                           || dummy->acc.accessmethod != item->acc.accessmethod
9692                           || dummy->val != item->val
9693                           || dummy->in_val != item->in_val)) {
9694     dummy = dummy->next;
9695   } // while
9696
9697   /* item already present? */
9698   if (dummy) return 0;
9699
9700   /* otherwise: insert copy of item */
9701   dummy = copyDefmap (item);
9702   dummy->next = *head;
9703   if (*head) (*head)->prev = dummy;
9704   *head = dummy;
9705
9706   return 1;
9707 }
9708
9709 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9710 static void deleteDefmap (defmap_t *map) {
9711   if (!map) return;
9712
9713   /* unlink from chain -- fails for the first item (head is not updated!) */
9714   if (map->next) map->next->prev = map->prev;
9715   if (map->prev) map->prev->next = map->next;
9716
9717   /* clear map */
9718   memset (map, 0, sizeof (defmap_t));
9719
9720   /* save for future use */
9721   map->next = defmap_free;
9722   defmap_free = map;
9723   ++defmap_free_count;
9724 }
9725
9726 /* Release all defmaps referenced from map. */
9727 static void deleteDefmapChain (defmap_t **_map) {
9728   defmap_t *map, *next;
9729
9730   if (!_map) return;
9731
9732   map = *_map;
9733
9734   /* find list head */
9735   while (map && map->prev) map = map->prev;
9736
9737   /* delete all items */
9738   while (map) {
9739     next = map->next;
9740     deleteDefmap (map);
9741     map = next;
9742   } // while
9743
9744   *_map = NULL;
9745 }
9746
9747 /* Free all defmap items. */
9748 static void freeDefmap (defmap_t **_map) {
9749   defmap_t *next;
9750   defmap_t *map;
9751
9752   if (!_map) return;
9753
9754   map = (*_map);
9755
9756   /* find list head */
9757   while (map->prev) map = map->prev;
9758
9759   /* release all items */
9760   while (map) {
9761     next = map->next;
9762     Safe_free (map);
9763     map = next;
9764   }
9765
9766   (*_map) = NULL;
9767 }
9768
9769 /* Returns the most recent definition for the given symbol preceeding pc.
9770  * If no definition is found, NULL is returned.
9771  * If pc == NULL the whole list is scanned. */
9772 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9773   defmap_t *curr = map;
9774
9775   if (pc) {
9776     /* skip all definitions up to pc */
9777     while (curr && (curr->pc != pc)) curr = curr->next;
9778
9779     /* pc not in the list -- scan the whole list for definitions */
9780     if (!curr) {
9781       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9782       curr = map;
9783     } else {
9784       /* skip all definitions performed by pc */
9785       while (curr && (curr->pc == pc)) curr = curr->next;
9786     }
9787   } // if (pc)
9788
9789   /* find definition for sym */
9790   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9791     curr = curr->next;
9792   }
9793
9794   return curr;
9795 }
9796
9797 #if 0
9798 /* Returns the first use (read) of the given symbol AFTER pc.
9799  * If no such use is found, NULL is returned.
9800  * If pc == NULL the whole list is scanned. */
9801 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9802   defmap_t *curr = map, *prev = NULL;
9803
9804   if (pc) {
9805     /* skip all definitions up to pc */
9806     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9807
9808     /* pc not in the list -- scan the whole list for definitions */
9809     if (!curr) {
9810       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9811       curr = prev;
9812     }
9813   } else {
9814     /* find end of list */
9815     while (curr && curr->next) curr = curr->next;
9816   } // if (pc)
9817
9818   /* find use of sym (scan list backwards) */
9819   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9820
9821   return curr;
9822 }
9823 #endif
9824
9825 /* Return the defmap entry for sym AT pc.
9826  * If none is found, NULL is returned.
9827  * If more than one entry is found an assertion is triggered. */
9828 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9829   defmap_t *res = NULL;
9830
9831   /* find entries for pc */
9832   while (map && map->pc != pc) map = map->next;
9833
9834   /* find first entry for sym @ pc */
9835   while (map && map->pc == pc && map->sym != sym) map = map->next;
9836
9837   /* no entry found */
9838   if (!map) return NULL;
9839
9840   /* check for more entries */
9841   res = map;
9842   map = map->next;
9843   while (map && map->pc == pc) {
9844     /* more than one entry for sym @ pc found? */
9845     assert (map->sym != sym);
9846     map = map->next;
9847   }
9848
9849   /* return single entry for sym @ pc */
9850   return res;
9851 }
9852
9853 /* Modifies the definition of sym at pCode to newval.
9854  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9855  */
9856 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9857   defmap_t *m  = map;
9858
9859   /* find definitions of pc */
9860   while (m && m->pc != pc) m = m->next;
9861
9862   /* find definition of sym at pc */
9863   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9864
9865   /* no definition found */
9866   if (!m) return 1;
9867
9868   /* redefine */
9869   m->val = newval;
9870
9871   /* update following uses of sym */
9872   while (m && m->pc == pc) m = m->prev;
9873   while (m) {
9874     if (m->sym == sym) {
9875       m->in_val = newval;
9876       if (m->acc.access.isWrite) m = NULL;
9877     } // if
9878     if (m) m = m->prev;
9879   } // while
9880
9881   return 0;
9882 }
9883
9884 /* ======================================================================== */
9885 /* === STACK ROUTINES ===================================================== */
9886 /* ======================================================================== */
9887
9888 typedef struct stack_s {
9889   void *data;
9890   struct stack_s *next;
9891 } stackitem_t;
9892
9893 typedef stackitem_t *dynstack_t;
9894 static stackitem_t *free_stackitems = NULL;
9895
9896 /* Create a stack with one item. */
9897 static dynstack_t *newStack () {
9898   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9899   *s = NULL;
9900   return s;
9901 }
9902
9903 /* Remove a stack -- its items are only marked free. */
9904 static void deleteStack (dynstack_t *s) {
9905   stackitem_t *i;
9906
9907   while (*s) {
9908     i = *s;
9909     *s = (*s)->next;
9910     i->next = free_stackitems;
9911     free_stackitems = i;
9912   } // while
9913   Safe_free (s);
9914 }
9915
9916 /* Release all stackitems. */
9917 static void releaseStack () {
9918   stackitem_t *i;
9919
9920   while (free_stackitems) {
9921     i = free_stackitems->next;
9922     Safe_free(free_stackitems);
9923     free_stackitems = i;
9924   } // while
9925 }
9926
9927 static void stackPush (dynstack_t *stack, void *data) {
9928   stackitem_t *i;
9929
9930   if (free_stackitems) {
9931     i = free_stackitems;
9932     free_stackitems = free_stackitems->next;
9933   } else {
9934     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9935   }
9936   i->data = data;
9937   i->next = *stack;
9938   *stack = i;
9939 }
9940
9941 static void *stackPop (dynstack_t *stack) {
9942   void *data;
9943   stackitem_t *i;
9944
9945   if (stack && *stack) {
9946     data = (*stack)->data;
9947     i = *stack;
9948     *stack = (*stack)->next;
9949     i->next = free_stackitems;
9950     free_stackitems = i;
9951     return data;
9952   } else {
9953     return NULL;
9954   }
9955 }
9956
9957 #if 0
9958 static int stackContains (dynstack_t *s, void *data) {
9959   stackitem_t *i;
9960   if (!s) return 0;
9961   i = *s;
9962   while (i) {
9963     if (i->data == data) return 1;
9964     i = i->next;
9965   } // while
9966
9967   /* not found */
9968   return 0;
9969 }
9970 #endif
9971
9972 static int stackIsEmpty (dynstack_t *s) {
9973   return (*s == NULL);
9974 }
9975
9976
9977 typedef struct {
9978   pCodeFlow *flow;
9979   defmap_t *lastdef;
9980 } state_t;
9981
9982 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9983   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9984   s->flow = flow;
9985   s->lastdef = lastdef;
9986   return s;
9987 }
9988
9989 static void deleteState (state_t *s) {
9990   Safe_free (s);
9991 }
9992
9993 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9994   stackitem_t *i;
9995
9996   /* scan working list for state */
9997   if (todo) {
9998     i = *todo;
9999     while (i) {
10000       /* is i == state? -- state not new */
10001       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10002       i = i->next;
10003     } // while
10004   }
10005
10006   if (done) {
10007     i = *done;
10008     while (i) {
10009       /* is i == state? -- state not new */
10010       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10011       i = i->next;
10012     } // while
10013   }
10014
10015   /* not found -- state is new */
10016   return 1;
10017 }
10018
10019 static inline valnum_t newValnum ();
10020
10021 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10022   pCode *pc;
10023
10024   if (!pb) return "<unknown function>";
10025
10026   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10027   if (pc && isPCF(pc)) return PCF(pc)->fname;
10028   else return "<unknown function>";
10029 }
10030
10031 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10032   defmap_t *map;
10033   pCodeFlow *pcfl;
10034
10035   assert(pb);
10036
10037   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10038
10039   /* find initial value (assigning pc == NULL) */
10040   map = PCFL(pcfl)->in_vals;
10041   while (map && map->sym != sym) map = map->next;
10042
10043   /* initial value already present? */
10044   if (map) {
10045     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10046     return map;
10047   }
10048
10049   /* create a new initial value */
10050   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10051   PCFL(pcfl)->in_vals = map;
10052   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10053   return map;
10054
10055 #if 0
10056   /* insert map as last item in pcfl's defmap */
10057   if (!prev) prev = PCFL(pcfl)->defmap;
10058   if (!prev) {
10059     PCFL(pcfl)->defmap = map;
10060   } else {
10061     while (prev->next) prev = prev->next;
10062     prev->next = map;
10063     map->prev = prev;
10064   }
10065
10066   return map;
10067 #endif
10068 }
10069
10070 /* Find all reaching definitions for sym at pc.
10071  * A new (!) list of definitions is returned.
10072  * Returns the number of reaching definitions found.
10073  * The defining defmap entries are returned in *chain.
10074  */
10075 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10076   defmap_t *map;
10077   defmap_t *res;
10078
10079   pCodeFlow *curr;
10080   pCodeFlowLink *succ;
10081   state_t *state;
10082   dynstack_t *todo;     /** stack of state_t */
10083   dynstack_t *done;     /** stack of state_t */
10084
10085   int firstState, n_defs;
10086
10087   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10088   assert (chain);
10089
10090   /* initialize return list */
10091   *chain = NULL;
10092
10093   /* wildcard symbol? */
10094   if (!sym) return 0;
10095
10096   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10097
10098   map = PCI(pc)->pcflow->defmap;
10099
10100   res = defmapFindDef (map, sym, pc);
10101   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10102
10103 #define USE_PRECALCED_INVALS 1
10104 #if USE_PRECALCED_INVALS
10105   if (!res && PCI(pc)->pcflow->in_vals) {
10106     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10107     if (res) {
10108       //fprintf  (stderr, "found def in init values\n");
10109       df_findall_in_vals++;
10110     }
10111   }
10112 #endif
10113
10114   if (res) {
10115     // found a single definition (in pc's flow)
10116     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10117     defmapAddCopyIfNew (chain, res);
10118     df_findall_sameflow++;
10119     return 1;
10120   }
10121
10122 #if USE_PRECALCED_INVALS
10123   else {
10124     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10125     return 1;
10126   }
10127
10128 #endif
10129
10130 #define FORWARD_FLOW_ANALYSIS 1
10131 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10132   /* no definition found in pc's flow preceeding pc */
10133   todo = newStack ();
10134   done = newStack ();
10135   n_defs = 0; firstState = 1;
10136   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10137
10138   while (!stackIsEmpty (todo)) {
10139     state = (state_t *) stackPop (todo);
10140     stackPush (done, state);
10141     curr = state->flow;
10142     res = state->lastdef;
10143     //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);
10144
10145     /* there are no definitions BEFORE pc in pc's flow (see above) */
10146     if (curr == PCI(pc)->pcflow) {
10147       if (!res) {
10148         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10149         res = pic16_pBlockAddInval (pc->pb, sym);
10150         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10151         res = NULL;
10152       } else {
10153         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10154         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10155       }
10156     }
10157
10158     /* save last definition of sym in this flow as initial def in successors */
10159     res = defmapFindDef (curr->defmap, sym, NULL);
10160     if (!res) res = state->lastdef;
10161
10162     /* add successors to working list */
10163     state = newState (NULL, NULL);
10164     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10165     while (succ) {
10166       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10167       state->flow = succ->pcflow;
10168       state->lastdef = res;
10169       if (stateIsNew (state, todo, done)) {
10170         stackPush (todo, state);
10171         state = newState (NULL, NULL);
10172       } // if
10173       succ = (pCodeFlowLink *) setNextItem (curr->to);
10174     } // while
10175     deleteState (state);
10176   } // while
10177
10178 #else // !FORWARD_FLOW_ANALYSIS
10179
10180   /* no definition found in pc's flow preceeding pc */
10181   todo = newStack ();
10182   done = newStack ();
10183   n_defs = 0; firstState = 1;
10184   stackPush (todo, newState (PCI(pc)->pcflow, res));
10185
10186   while (!stackIsEmpty (todo)) {
10187     state = (state_t *) stackPop (todo);
10188     curr = state->flow;
10189
10190     if (firstState) {
10191       firstState = 0;
10192       /* only check predecessor flows */
10193     } else {
10194       /* get (last) definition of sym in this flow */
10195       res = defmapFindDef (curr->defmap, sym, NULL);
10196     }
10197
10198     if (res) {
10199       /* definition found */
10200       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10201       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10202     } else {
10203       /* no definition found -- check predecessor flows */
10204       state = newState (NULL, NULL);
10205       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10206
10207       /* if no flow predecessor available -- sym might be uninitialized */
10208       if (!succ) {
10209         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10210         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10211         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10212         deleteDefmap (res); res = NULL;
10213       }
10214
10215       while (succ) {
10216         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10217         state->flow = succ->pcflow;
10218         state->lastdef = res;
10219         if (stateIsNew (state, todo, done)) {
10220           stackPush (todo, state);
10221           state = newState (NULL, NULL);
10222         } // if
10223         succ = (pCodeFlowLink *) setNextItem (curr->from);
10224       } // while
10225       deleteState (state);
10226     }
10227   } // while
10228
10229 #endif
10230
10231   /* clean up done stack */
10232   while (!stackIsEmpty(done)) {
10233     deleteState ((state_t *) stackPop (done));
10234   } // while
10235   deleteStack (done);
10236
10237   /* return number of items in result set */
10238   if (n_defs == 0) {
10239     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10240   } else if (n_defs == 1) {
10241     assert (*chain);
10242     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10243   } else if (n_defs > 0) {
10244     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10245 #if 0
10246     res = *chain;
10247     while (res) {
10248       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10249       res = res->next;
10250     } // while
10251 #endif
10252   }
10253   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10254   df_findall_otherflow++;
10255   return n_defs;
10256 }
10257
10258 /* ======================================================================== */
10259 /* === VALUE NUMBER HANDLING ============================================== */
10260 /* ======================================================================== */
10261
10262 static valnum_t nextValnum = 0x1000;
10263 static hTab *map_symToValnum = NULL;
10264
10265 /** Return a new value number. */
10266 static inline valnum_t newValnum () {
10267   return (nextValnum += 4);
10268 }
10269
10270 static valnum_t valnumFromStr (const char *str) {
10271   symbol_t sym;
10272   valnum_t val;
10273   void *res;
10274
10275   sym = symFromStr (str);
10276
10277   if (!map_symToValnum) {
10278     map_symToValnum = newHashTable (128);
10279   } // if
10280
10281   /* literal already known? */
10282   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10283
10284   /* return existing valnum */
10285   if (res) return (valnum_t) PTR_TO_INT(res);
10286
10287   /* create new valnum */
10288   val = newValnum();
10289   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10290   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10291   return val;
10292 }
10293
10294 /* Create a valnum for a literal. */
10295 static valnum_t valnumFromLit (unsigned int lit) {
10296   return ((valnum_t) 0x100 + (lit & 0x0FF));
10297 }
10298
10299 /* Return the (positive) literal value represented by val
10300  * or -1 iff val is no known literal's valnum. */
10301 static int litFromValnum (valnum_t val) {
10302   if (val >= 0x100 && val < 0x200) {
10303     /* valnum is a (known) literal */
10304     return val & 0x00FF;
10305   } else {
10306     /* valnum is not a known literal */
10307     return -1;
10308   }
10309 }
10310
10311 #if 0
10312 /* Sanity check - all flows in a block must be reachable from initial flow. */
10313 static int verifyAllFlowsReachable (pBlock *pb) {
10314   set *reached;
10315   set *flowInBlock;
10316   set *checked;
10317   pCode *pc;
10318   pCodeFlow *pcfl;
10319   pCodeFlowLink *succ;
10320   int res;
10321
10322   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10323
10324   reached = NULL;
10325   flowInBlock = NULL;
10326   checked = NULL;
10327   /* mark initial flow as reached (and "not needs to be reached") */
10328   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10329   assert (pc);
10330   addSetHead (&reached, pc);
10331   addSetHead (&checked, pc);
10332
10333   /* mark all further flows in block as "need to be reached" */
10334   pc = pb->pcHead;
10335   do {
10336     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10337     pc = pic16_findNextInstruction (pc->next);
10338   } while (pc);
10339
10340   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10341     /* mark as reached and "not need to be reached" */
10342     deleteSetItem (&reached, pcfl);
10343     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10344
10345     /* flow is no longer considered unreachable */
10346     deleteSetItem (&flowInBlock, pcfl);
10347
10348     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10349       if (!isinSet (checked, succ->pcflow)) {
10350         /* flow has never been reached before */
10351         addSetHead (&reached, succ->pcflow);
10352         addSetHead (&checked, succ->pcflow);
10353       } // if
10354     } // for succ
10355   } // while
10356
10357   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10358
10359   /* by now every flow should have been reached
10360    * --> flowInBlock should be empty */
10361   res = (flowInBlock == NULL);
10362
10363 #if 1
10364   if (flowInBlock) {
10365           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10366     while (flowInBlock) {
10367       pcfl = indexSet (flowInBlock, 0);
10368       fprintf (stderr, "not reached: flow %p\n", pcfl);
10369       deleteSetItem (&flowInBlock, pcfl);
10370     } // while
10371   }
10372 #endif
10373
10374   /* clean up */
10375   deleteSet (&reached);
10376   deleteSet (&flowInBlock);
10377   deleteSet (&checked);
10378
10379   /* if we reached every flow, succ is NULL by now... */
10380   //assert (res); // will fire on unreachable code...
10381   return (res);
10382 }
10383 #endif
10384
10385 /* Checks a flow for accesses to sym AFTER pc.
10386  *
10387  * Returns -1 if the symbol is read in this flow (before redefinition),
10388  * returns 0 if the symbol is redefined in this flow or
10389  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10390  */
10391 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10392   defmap_t *map, *mappc;
10393
10394   /* find pc or start of definitions */
10395   map = pcfl->defmap;
10396   while (map && (map->pc != pc) && map->next) map = map->next;
10397   /* if we found pc -- ignore it */
10398   while (map && map->pc == pc) map = map->prev;
10399
10400   /* scan list backwards (first definition first) */
10401   while (map && mask) {
10402 //    if (map->sym == sym) {
10403       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10404       mappc = map;
10405       /* scan list for reads at this pc first */
10406       while (map && map->pc == mappc->pc) {
10407         /* is the symbol (partially) read? */
10408         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10409           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10410           return -1;
10411         }
10412         map = map->prev;
10413       } // while
10414       map = mappc;
10415
10416       while (map && map->pc == mappc->pc) {
10417         /* honor (partial) redefinitions of sym */
10418         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10419           mask &= ~map->acc.access.mask;
10420           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10421         }
10422         map = map->prev;
10423       } // while
10424 //    } // if
10425     /* map already points to the first defmap for the next pCode */
10426     //map = mappc->prev;
10427   } // while
10428
10429   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10430    * is still alive; return the appropriate mask of alive bits */
10431   return mask;
10432 }
10433
10434 /* Check whether a symbol is alive (AFTER pc). */
10435 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10436   int mask, visit;
10437   defmap_t *map;
10438   dynstack_t *todo, *done;
10439   state_t *state;
10440   pCodeFlow *pcfl;
10441   pCodeFlowLink *succ;
10442
10443   mask = 0x00ff;
10444
10445   assert (isPCI(pc));
10446   pcfl = PCI(pc)->pcflow;
10447   map = pcfl->defmap;
10448
10449   todo = newStack ();
10450   done = newStack ();
10451
10452   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10453   stackPush (todo, state);
10454   visit = 0;
10455
10456   while (!stackIsEmpty (todo)) {
10457     state = (state_t *) stackPop (todo);
10458     pcfl = state->flow;
10459     mask = PTR_TO_INT(state->lastdef);
10460     if (visit) stackPush (done, state); else deleteState(state);
10461     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10462     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10463     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10464     visit++;
10465
10466     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10467     if (mask == 0) continue;
10468
10469     /* symbol is (partially) read before redefinition in flow */
10470     if (mask == -1) break;
10471
10472     /* symbol is neither read nor completely redefined -- check successor flows */
10473     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10474       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10475       if (stateIsNew (state, todo, done)) {
10476         stackPush (todo, state);
10477       } else {
10478         deleteState (state);
10479       }
10480     } // for
10481   } // while
10482
10483   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10484   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10485
10486   /* symbol is read in at least one flow -- is alive */
10487   if (mask == -1) return 1;
10488
10489   /* symbol is read in no flow */
10490   return 0;
10491 }
10492
10493 /* Returns whether access to the given symbol has side effects. */
10494 static int pic16_symIsSpecial (symbol_t sym) {
10495   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10496   switch (sym) {
10497   case SPO_INDF0:
10498   case SPO_PLUSW0:
10499   case SPO_POSTINC0:
10500   case SPO_POSTDEC0:
10501   case SPO_PREINC0:
10502   case SPO_INDF1:
10503   case SPO_PLUSW1:
10504   case SPO_POSTINC1:
10505   case SPO_POSTDEC1:
10506   case SPO_PREINC1:
10507   case SPO_INDF2:
10508   case SPO_PLUSW2:
10509   case SPO_POSTINC2:
10510   case SPO_POSTDEC2:
10511   case SPO_PREINC2:
10512   case SPO_PCL:
10513           return 1;
10514   default:
10515           /* no special effects known */
10516           return 0;
10517   } // switch
10518
10519   return 0;
10520 }
10521
10522 /* Check whether a register should be considered local (to the current function) or not. */
10523 static int pic16_regIsLocal (regs *r) {
10524   symbol_t sym;
10525   if (r) {
10526     if (r->type == REG_TMP) return 1;
10527
10528     sym = symFromStr (r->name);
10529     switch (sym) {
10530     case SPO_WREG:
10531     case SPO_FSR0L: // used in ptrget/ptrput
10532     case SPO_FSR0H: // ... as well
10533     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10534     case SPO_FSR1H: // ... as well
10535     case SPO_FSR2L: // used as frame pointer
10536     case SPO_FSR2H: // ... as well
10537     case SPO_PRODL: // used to return values from functions
10538     case SPO_PRODH: // ... as well
10539       /* these registers (and some more...) are considered local */
10540       return 1;
10541       break;
10542     default:
10543       /* for unknown regs: check is marked local, leave if not */
10544       if (r->isLocal) {
10545         return 1;
10546       } else {
10547         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10548         return 0;
10549       }
10550     } // switch
10551   } // if
10552
10553   /* if in doubt, assume non-local... */
10554   return 0;
10555 }
10556
10557 /* Check all symbols touched by pc whether their newly assigned values are read.
10558  * Returns 0 if no symbol is used later on, 1 otherwise. */
10559 static int pic16_pCodeIsAlive (pCode *pc) {
10560   pCodeInstruction *pci;
10561   defmap_t *map, *lastpc;
10562   regs *checkreg;
10563
10564   /* we can only handle PCIs */
10565   if (!isPCI(pc)) return 1;
10566
10567   //pc->print (stderr, pc);
10568
10569   pci = PCI(pc);
10570   assert (pci && pci->pcflow && pci->pcflow->defmap);
10571
10572   /* NEVER remove instructions with implicit side effects */
10573   switch (pci->op) {
10574   case POC_TBLRD:
10575   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10576   case POC_TBLRD_POSTDEC:
10577   case POC_TBLRD_PREINC:
10578   case POC_TBLWT:               /* modify program memory */
10579   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10580   case POC_TBLWT_POSTDEC:
10581   case POC_TBLWT_PREINC:
10582   case POC_CLRWDT:              /* clear watchdog timer */
10583   case POC_PUSH:                /* should be safe to remove though... */
10584   case POC_POP:                 /* should be safe to remove though... */
10585   case POC_CALL:
10586   case POC_RCALL:
10587   case POC_RETFIE:
10588   case POC_RETURN:
10589     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10590     return 1;
10591
10592   default:
10593     /* no special instruction */
10594     break;
10595   } // switch
10596
10597   /* prevent us from removing assignments to non-local variables */
10598   checkreg = NULL;
10599   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10600   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10601
10602   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10603     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10604     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10605     //pc->print (stderr, pc);
10606     return 1;
10607   }
10608   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10609     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10610     return 1;
10611   }
10612
10613 #if 1
10614   /* OVERKILL: prevent us from removing reads from non-local variables
10615    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10616    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10617   checkreg = NULL;
10618   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10619   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10620
10621   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10622     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10623     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10624     //pc->print (stderr, pc);
10625     return 1;
10626   }
10627   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10628     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10629     return 1;
10630   }
10631 #endif
10632
10633   /* now check that the defined symbols are not used */
10634   map = pci->pcflow->defmap;
10635
10636   /* find items for pc */
10637   while (map && map->pc != pc) map = map->next;
10638
10639   /* no entries found? something is fishy with DF analysis... -- play safe */
10640   if (!map) {
10641     if (pic16_pcode_verbose) {
10642       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10643     }
10644     return 1;
10645   }
10646
10647   /* remember first item assigned to pc for later use */
10648   lastpc = map;
10649
10650   /* check all symbols being modified by pc */
10651   while (map && map->pc == pc) {
10652     if (map->sym == 0) { map = map->next; continue; }
10653
10654     /* keep pc if it references special symbols (like POSTDEC0) */
10655 #if 0
10656     {
10657       char buf[256];
10658       pic16_pCode2str (buf, 256, pc);
10659       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10660     }
10661 #endif
10662     if (pic16_symIsSpecial (map->sym)) {
10663       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10664       return 1;
10665     }
10666     if (map->acc.access.isWrite) {
10667       if (pic16_isAlive (map->sym, pc)) {
10668         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10669         return 1;
10670       }
10671     }
10672     map = map->next;
10673   } // while
10674
10675   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10676 #if 0
10677   {
10678     char buf[256];
10679     pic16_pCode2str (buf, 256, pc);
10680     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10681   }
10682 #endif
10683   return 0;
10684 }
10685
10686 /* Adds implied operands to the list.
10687  * sym - operand being accessed in the pCode
10688  * list - list to append the operand
10689  * isRead - set to 1 iff sym is read in pCode
10690  * listRead - set to 1 iff all operands being read are to be listed
10691  *
10692  * Returns 0 for "normal" operands, 1 for special operands.
10693  */
10694 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10695   /* check whether accessing REG accesses other REGs as well */
10696   switch (sym) {
10697   case SPO_INDF0:
10698     /* reads FSR0x */
10699     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10700     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10701     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10702     break;
10703
10704   case SPO_PLUSW0:
10705     /* reads FSR0x and WREG */
10706     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10707     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10708     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10709     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10710     break;
10711
10712   case SPO_POSTDEC0:
10713   case SPO_POSTINC0:
10714   case SPO_PREINC0:
10715     /* reads/modifies FSR0x */
10716     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10717     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10718     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10719     break;
10720
10721   case SPO_INDF1:
10722     /* reads FSR1x */
10723     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10724     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10725     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10726     break;
10727
10728   case SPO_PLUSW1:
10729     /* reads FSR1x and WREG */
10730     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10731     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10732     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10733     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10734     break;
10735
10736   case SPO_POSTDEC1:
10737   case SPO_POSTINC1:
10738   case SPO_PREINC1:
10739     /* reads/modifies FSR1x */
10740     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10741     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10742     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10743     break;
10744
10745   case SPO_INDF2:
10746     /* reads FSR2x */
10747     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10748     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10749     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10750     break;
10751
10752   case SPO_PLUSW2:
10753     /* reads FSR2x and WREG */
10754     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10755     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10756     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10757     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10758     break;
10759
10760   case SPO_POSTDEC2:
10761   case SPO_POSTINC2:
10762   case SPO_PREINC2:
10763     /* reads/modifies FSR2x */
10764     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10765     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10766     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10767     break;
10768
10769   case SPO_PCL:
10770     /* modifies PCLATH and PCLATU */
10771     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10772     if (isRead) {
10773       /* reading PCL updates PCLATx */
10774       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10775       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10776     }
10777     if (isWrite) {
10778       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10779       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10780       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10781     }
10782     break;
10783
10784   default:
10785     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10786     /* nothing special */
10787     return 0;
10788     break;
10789   }
10790
10791   /* has been a special operand */
10792   return 1;
10793 }
10794
10795 static symbol_t pic16_fsrsym_idx[][2] = {
10796     {SPO_FSR0L, SPO_FSR0H},
10797     {SPO_FSR1L, SPO_FSR1H},
10798     {SPO_FSR2L, SPO_FSR2H}
10799 };
10800
10801 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10802 static void mergeDefmapSymbols (defmap_t *list) {
10803   defmap_t *ref, *curr, *temp;
10804
10805   /* now make sure that each symbol occurs at most once per pc */
10806   ref = list;
10807   while (ref && (ref->pc == list->pc)) {
10808     curr = ref->next;
10809     while (curr && (curr->pc == list->pc)) {
10810       if (curr->sym == ref->sym) {
10811         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10812         /* found a symbol occuring twice... merge the two */
10813         if (curr->acc.access.isRead) {
10814           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10815           ref->acc.access.isRead = 1;
10816           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10817         }
10818         if (curr->acc.access.isWrite) {
10819           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10820           ref->acc.access.isWrite = 1;
10821           ref->acc.access.mask |= curr->acc.access.mask;
10822         }
10823         temp = curr;
10824         curr = curr->next;
10825         deleteDefmap (temp);
10826         continue; // do not skip curr!
10827       } // if
10828       curr = curr->next;
10829     } // while
10830     ref = ref->next;
10831   } // while
10832 }
10833
10834 /** Prepend list with the reads and definitions performed by pc. */
10835 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10836   pCodeInstruction *pci;
10837   int cond, inCond, outCond;
10838   int mask = 0xff, smask;
10839   int isSpecial, isSpecial2;
10840   symbol_t sym, sym2;
10841   char *name;
10842
10843   if (isPCAD(pc)) {
10844     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10845     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10846     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10847     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10848     return list;
10849   }
10850   assert (isPCI(pc));
10851   pci = PCI(pc);
10852
10853   /* handle bit instructions */
10854   if (pci->isBitInst) {
10855     assert (pci->pcop->type == PO_GPR_BIT);
10856     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10857   }
10858
10859   /* handle (additional) implicit arguments */
10860   switch (pci->op) {
10861   case POC_LFSR:
10862     {
10863       int lit;
10864       valnum_t val;
10865       lit = PCOL(pci->pcop)->lit;
10866       assert (lit >= 0 && lit < 3);
10867       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10868       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10869       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10870       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10871       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...
10872     }
10873     break;
10874
10875   case POC_MOVLB: // BSR
10876   case POC_BANKSEL: // BSR
10877     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10878     break;
10879
10880   case POC_MULWF: // PRODx
10881   case POC_MULLW: // PRODx
10882     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10883     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10884     break;
10885
10886   case POC_POP: // TOS, STKPTR
10887     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10888     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10889     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10890     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10891     break;
10892
10893   case POC_PUSH: // STKPTR
10894     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10895     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10896     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10897     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10898     break;
10899
10900   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10901   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10902     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10903     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10904     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10905     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10906
10907     /* needs correctly set-up stack pointer */
10908     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10909     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10910     break;
10911
10912   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10913     /* pseudo read on (possible) return values */
10914     // WREG is handled below via outCond
10915     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10916     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10917     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10918
10919     /* caller's stack pointers must be restored */
10920     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10921     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10922     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10923     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10924     break;
10925
10926   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10927   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10928     /* pseudo read on (possible) return values */
10929     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10930     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10931     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10932     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10933
10934     /* caller's stack pointers must be restored */
10935     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10936     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10937     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10938     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10939     break;
10940
10941   case POC_TBLRD:
10942     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10943     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10944     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10945     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10946     break;
10947
10948   case POC_TBLRD_POSTINC:
10949   case POC_TBLRD_POSTDEC:
10950   case POC_TBLRD_PREINC:
10951     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10952     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10953     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10954     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10955     break;
10956
10957   case POC_TBLWT:
10958     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10959     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10960     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10961     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10962     break;
10963
10964   case POC_TBLWT_POSTINC:
10965   case POC_TBLWT_POSTDEC:
10966   case POC_TBLWT_PREINC:
10967     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10968     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10969     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10970     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10971     break;
10972
10973   default:
10974     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10975     break;
10976   } // switch
10977
10978   /* handle explicit arguments */
10979   inCond = pci->inCond;
10980   outCond = pci->outCond;
10981   cond = inCond | outCond;
10982   if (cond & PCC_W) {
10983     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10984   } // if
10985
10986   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10987   if (inCond & PCC_STATUS) {
10988     smask = 0;
10989     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10990     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10991     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10992     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10993     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10994
10995     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10996     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10997   } // if
10998
10999   if (outCond & PCC_STATUS) {
11000     smask = 0;
11001     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11002     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11003     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11004     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11005     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11006
11007     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11008     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11009   } // if
11010
11011   isSpecial = isSpecial2 = 0;
11012   sym = sym2 = 0;
11013   if (cond & PCC_REGISTER) {
11014     name = pic16_get_op (pci->pcop, NULL, 0);
11015     sym = symFromStr (name);
11016     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11017     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11018   }
11019
11020   if (cond & PCC_REGISTER2) {
11021     name = pic16_get_op2 (pci->pcop, NULL, 0);
11022     sym2 = symFromStr (name);
11023     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11024     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11025   }
11026
11027
11028   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11029   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11030
11031   mergeDefmapSymbols (list);
11032
11033   return list;
11034 }
11035
11036 #if 0
11037 static void printDefmap (defmap_t *map) {
11038   defmap_t *curr;
11039
11040   curr = map;
11041   fprintf (stderr, "defmap @ %p:\n", curr);
11042   while (curr) {
11043     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11044                     curr->acc.access.isRead ? "R" : " ",
11045                     curr->acc.access.isWrite ? "W": " ",
11046                     curr->in_val, curr->val,
11047                     curr->acc.access.in_mask, curr->acc.access.mask,
11048                     strFromSym(curr->sym), curr->sym,
11049                     curr->pc);
11050     curr = curr->next;
11051   } // while
11052   fprintf (stderr, "<EOL>\n");
11053 }
11054 #endif
11055
11056 /* Add "additional" definitions to uniq.
11057  * 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.
11058  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11059  *
11060  * If symbols defined in additional are not present in uniq, a definition is created.
11061  * Otherwise the present definition is altered to reflect the newer assignments.
11062  *
11063  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11064  *       before     `------- noted in additional --------'      after
11065  *
11066  * I assume that each symbol occurs AT MOST ONCE in uniq.
11067  *
11068  */
11069 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11070   defmap_t *curr;
11071   defmap_t *old;
11072   int change = 0;
11073
11074   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11075   /* find tail of additional list (holds the first assignment) */
11076   curr = additional;
11077   while (curr && curr->next) curr = curr->next;
11078
11079   /* update uniq */
11080   do {
11081     /* find next assignment in additionals */
11082     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11083
11084     if (!curr) break;
11085
11086     /* find item in uniq */
11087     old = *uniq;
11088     //printDefmap (*uniq);
11089     while (old && (old->sym != curr->sym)) old = old->next;
11090
11091     if (old) {
11092       /* definition found -- replace */
11093       if (old->val != curr->val) {
11094         old->val = curr->val;
11095         change++;
11096       } // if
11097     } else {
11098       /* new definition */
11099       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11100       change++;
11101     }
11102
11103     curr = curr->prev;
11104   } while (1);
11105
11106   /* return 0 iff uniq remained unchanged */
11107   return change;
11108 }
11109
11110 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11111  * lists of its predecessor flows.
11112  * Initially *combined should be NULL, alt_in will be copied to combined.
11113  * If *combined != NULL, combined will be altered:
11114  * - for symbols defined in *combined but not in alt_in,
11115  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11116  * - for symbols defined in alt_in but not in *combined,
11117  *   a 0 definition is created (value unknown, either INIT or alt).
11118  * - for symbols defined in both, *combined is:
11119  *   > left unchanged if *combined->val == alt_in->val or
11120  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11121  *
11122  * I assume that each symbol occurs AT MOST ONCE in each list!
11123  */
11124 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11125   defmap_t *curr;
11126   defmap_t *old;
11127   int change = 0;
11128   valnum_t val;
11129
11130   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11131
11132   if (!(*combined)) {
11133     return defmapUpdateUniqueSym (combined, alt_in);
11134   } // if
11135
11136   /* merge the two */
11137   curr = alt_in;
11138   while (curr) {
11139     /* find symbols definition in *combined */
11140     old = *combined;
11141     while (old && (old->sym != curr->sym)) old = old->next;
11142
11143     if (old) {
11144       /* definition found */
11145       if (old->val && (old->val != curr->val)) {
11146         old->val = 0; /* value unknown */
11147         change++;
11148       }
11149     } else {
11150       /* no definition found -- can be either INIT or alt_in's value */
11151       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11152       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11153       if (val != curr->val) change++;
11154     }
11155
11156     curr = curr->next;
11157   } // while (curr)
11158
11159   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11160   old = *combined;
11161   while (old) {
11162     if (old->val != 0) {
11163       /* find definition in alt_in */
11164       curr = alt_in;
11165       while (curr && curr->sym != old->sym) curr = curr->next;
11166       if (!curr) {
11167         /* symbol defined in *combined only -- can be either INIT or *combined */
11168         val = pic16_pBlockAddInval (pb, old->sym)->val;
11169         if (old->val != val) {
11170           old->val = 0;
11171           change++;
11172         }
11173       } // if
11174     } // if
11175
11176     old = old->next;
11177   } // while
11178
11179   return change;
11180 }
11181
11182 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11183   defmap_t *curr1, *curr2;
11184   symbol_t sym;
11185
11186   /* identical maps are equal */
11187   if (map1 == map2) return 0;
11188
11189   if (!map1) return -1;
11190   if (!map2) return 1;
11191
11192   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11193
11194   /* check length */
11195   curr1 = map1;
11196   curr2 = map2;
11197   while (curr1 && curr2) {
11198     curr1 = curr1->next;
11199     curr2 = curr2->next;
11200   } // while
11201
11202   /* one of them longer? */
11203   if (curr1) return 1;
11204   if (curr2) return -1;
11205
11206   /* both lists are of equal length -- compare (in O(n^2)) */
11207   curr1 = map1;
11208   while (curr1) {
11209     sym = curr1->sym;
11210     curr2 = map2;
11211     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11212     if (!curr2) return 1; // symbol not found in curr2
11213     if (curr2->val != curr1->val) return 1; // values differ
11214
11215     /* compare next symbol */
11216     curr1 = curr1->next;
11217   } // while
11218
11219   /* no difference found */
11220   return 0;
11221 }
11222
11223
11224 /* Prepare a list of all reaching definitions per flow.
11225  * This is done using a forward dataflow analysis.
11226  */
11227 static void createReachingDefinitions (pBlock *pb) {
11228   defmap_t *out_vals, *in_vals;
11229   pCode *pc;
11230   pCodeFlow *pcfl;
11231   pCodeFlowLink *link;
11232   set *todo;
11233   set *blacklist;
11234
11235   if (!pb) return;
11236
11237   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11238   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11239     if (isPCFL(pc)) {
11240       deleteDefmapChain (&PCFL(pc)->in_vals);
11241       deleteDefmapChain (&PCFL(pc)->out_vals);
11242       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11243     } // if
11244   } // for
11245
11246   pc = pic16_findNextInstruction (pb->pcHead);
11247   todo = NULL; blacklist = NULL;
11248   addSetHead (&todo, PCI(pc)->pcflow);
11249
11250   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11251   while (elementsInSet (todo)) {
11252     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11253     pcfl = PCFL(indexSet (todo, 0));
11254     deleteSetItem (&todo, pcfl);
11255     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11256     in_vals = NULL;
11257     out_vals = NULL;
11258
11259     if (isinSet (blacklist, pcfl)) {
11260             fprintf (stderr, "ignoring blacklisted flow\n");
11261       continue;
11262     }
11263
11264     /* create in_vals from predecessors out_vals */
11265     link = setFirstItem (pcfl->from);
11266     while (link) {
11267       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11268       link = setNextItem (pcfl->from);
11269     } // while
11270
11271     //printDefmap (in_vals);
11272     //printDefmap (pcfl->in_vals);
11273
11274     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11275       //fprintf (stderr, "in_vals changed\n");
11276       /* in_vals changed -- update out_vals */
11277       deleteDefmapChain (&pcfl->in_vals);
11278       pcfl->in_vals = in_vals;
11279
11280       /* create out_val from in_val and defmap */
11281       out_vals = NULL;
11282       defmapUpdateUniqueSym (&out_vals, in_vals);
11283       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11284
11285       /* is out_vals different from pcfl->out_vals */
11286       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11287         //fprintf (stderr, "out_vals changed\n");
11288         deleteDefmapChain (&pcfl->out_vals);
11289         pcfl->out_vals = out_vals;
11290
11291         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11292           addSet (&blacklist, pcfl);
11293         } // if
11294
11295         /* reschedule all successors */
11296         link = setFirstItem (pcfl->to);
11297         while (link) {
11298           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11299           addSetIfnotP (&todo, link->pcflow);
11300           link = setNextItem (pcfl->to);
11301         } // while
11302       } else {
11303         deleteDefmapChain (&out_vals);
11304       }// if
11305     } else {
11306       deleteDefmapChain (&in_vals);
11307     } // if
11308   } // while
11309 }
11310
11311 #if 0
11312 static void showAllDefs (symbol_t sym, pCode *pc) {
11313   defmap_t *map;
11314   int count;
11315
11316   assert (isPCI(pc));
11317   count = defmapFindAll (sym, pc, &map);
11318
11319   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11320   while (map) {
11321 #if 1
11322     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11323 #else
11324     { char buf[256];
11325     pic16_pCode2str (buf, 256, map->pc);
11326     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11327 #endif
11328     map = map->next;
11329   }
11330   deleteDefmapChain (&map);
11331 }
11332 #endif
11333
11334 /* safepCodeUnlink and remove pc from defmap. */
11335 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11336   defmap_t *map, *next, **head;
11337   int res, ispci;
11338
11339   ispci = isPCI(pc);
11340   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11341   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11342   res = pic16_safepCodeUnlink (pc, comment);
11343
11344   if (res && map) {
11345     /* remove pc from defmap */
11346     while (map) {
11347       next = map->next;
11348       if (map->pc == pc) {
11349         if (!map->prev && head) *head = map->next;
11350         deleteDefmap (map);
11351       } // if
11352       map = next;
11353     }
11354   }
11355
11356   return res;
11357 }
11358
11359 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11360   defmap_t *map;
11361   /* This breaks the defmap chain's references to pCodes... fix it! */
11362   map = PCI(pc)->pcflow->defmap;
11363
11364   while (map && map->pc != pc) map = map->next;
11365
11366   while (map && map->pc == pc) {
11367     map->pc = newpc;
11368     map = map->next;
11369   } // while
11370 }
11371
11372 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11373  * write accesses (isRead == 0). */
11374 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11375   defmap_t *map, *map_start;
11376   defmap_t *copy;
11377   if (!isPCI(pc)) return;
11378   if (sym == newsym) return;
11379
11380   map = PCI(pc)->pcflow->defmap;
11381
11382   while (map && map->pc != pc) map = map->next;
11383   map_start = map;
11384   while (map && map->pc == pc) {
11385     if (map->sym == sym) {
11386       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11387       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11388         /* only one kind of access handled... this is easy */
11389         map->sym = newsym;
11390       } else {
11391         /* must copy defmap entry before replacing symbol... */
11392         copy = copyDefmap (map);
11393         if (isRead) {
11394           map->acc.access.isRead = 0;
11395           copy->acc.access.isWrite = 0;
11396         } else {
11397           map->acc.access.isWrite = 0;
11398           copy->acc.access.isRead = 0;
11399         }
11400         copy->sym = newsym;
11401         /* insert copy into defmap chain */
11402         defmapInsertAfter (map, copy);
11403       }
11404     }
11405     map = map->next;
11406   } // while
11407
11408   /* as this might introduce multiple defmap entries for newsym... */
11409   mergeDefmapSymbols (map_start);
11410 }
11411
11412 /* Assign "better" valnums to results. */
11413 static void assignValnums (pCode *pc) {
11414   pCodeInstruction *pci;
11415   pCode *newpc;
11416   symbol_t sym1, sym2;
11417   int cond, isSpecial1, isSpecial2, count, mask, lit;
11418   defmap_t *list, *val, *oldval, *dummy;
11419   regs *reg1 = NULL, *reg2 = NULL;
11420   valnum_t litnum;
11421
11422   /* only works for pCodeInstructions... */
11423   if (!isPCI(pc)) return;
11424
11425   pci = PCI(pc);
11426   cond = pci->inCond | pci->outCond;
11427   list = pci->pcflow->defmap;
11428   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11429
11430   if (cond & PCC_REGISTER) {
11431     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11432     reg1 = pic16_getRegFromInstruction (pc);
11433     isSpecial1 = pic16_symIsSpecial (sym1);
11434   }
11435   if (cond & PCC_REGISTER2) {
11436     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11437     reg2 = pic16_getRegFromInstruction (pc);
11438     isSpecial2 = pic16_symIsSpecial (sym2);
11439   }
11440
11441   /* determine input values */
11442   val = list;
11443   while (val && val->pc != pc) val = val->next;
11444   //list = val; /* might save some time later... */
11445   while (val && val->pc == pc) {
11446     val->in_val = 0;
11447     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11448       /* get valnum for sym */
11449       count = defmapFindAll (val->sym, pc, &oldval);
11450       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11451       if (count == 1) {
11452         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11453           val->in_val = oldval->val;
11454         } else {
11455           val->in_val = 0;
11456         }
11457       } else if (count == 0) {
11458         /* no definition found */
11459         val->in_val = 0;
11460       } else {
11461         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11462         assert (oldval);
11463         dummy = oldval->next;
11464         mask = oldval->acc.access.mask;
11465         val->in_val = oldval->val;
11466         while (dummy && (dummy->val == val->in_val)) {
11467           mask &= dummy->acc.access.mask;
11468           dummy = dummy->next;
11469         } // while
11470
11471         /* found other values or to restictive mask */
11472         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11473           val->in_val = 0;
11474         }
11475       }
11476       if (count > 0) deleteDefmapChain (&oldval);
11477     } // if
11478     val = val->next;
11479   }
11480
11481   /* handle valnum assignment */
11482   switch (pci->op) {
11483   case POC_CLRF: /* modifies STATUS (Z) */
11484     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11485       oldval = defmapCurr (list, sym1, pc);
11486       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11487         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11488         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11489       }
11490       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11491     }
11492     break;
11493
11494   case POC_SETF: /* SETF does not touch STATUS */
11495     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11496       oldval = defmapCurr (list, sym1, pc);
11497       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11498         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11499         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11500       }
11501       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11502     }
11503     break;
11504
11505   case POC_MOVLW: /* does not touch STATUS */
11506     oldval = defmapCurr (list, SPO_WREG, pc);
11507     if (pci->pcop->type == PO_LITERAL) {
11508       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11509       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11510     } else {
11511       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11512       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11513     }
11514     if (oldval && oldval->in_val == litnum) {
11515       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11516       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11517     }
11518     defmapUpdate (list, SPO_WREG, pc, litnum);
11519     break;
11520
11521   case POC_ANDLW: /* modifies STATUS (Z,N) */
11522   case POC_IORLW: /* modifies STATUS (Z,N) */
11523   case POC_XORLW: /* modifies STATUS (Z,N) */
11524     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11525     if (pci->pcop->type == PO_LITERAL) {
11526       int vallit = -1;
11527       lit = (unsigned char) PCOL(pci->pcop)->lit;
11528       val = defmapCurr (list, SPO_WREG, pc);
11529       if (val) vallit = litFromValnum (val->in_val);
11530       if (vallit != -1) {
11531         /* xxxLW <literal>, WREG contains a known literal */
11532         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11533         if (pci->op == POC_ANDLW) {
11534           lit &= vallit;
11535         } else if (pci->op == POC_IORLW) {
11536           lit |= vallit;
11537         } else if (pci->op == POC_XORLW) {
11538           lit ^= vallit;
11539         } else {
11540           assert (0 && "invalid operation");
11541         }
11542         if (vallit == lit) {
11543           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11544           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11545         }
11546         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11547       } // if
11548     }
11549     break;
11550
11551   case POC_LFSR:
11552     {
11553       /* check if old value matches new value */
11554       int lit;
11555       int ok = 1;
11556       assert (pci->pcop->type == PO_LITERAL);
11557
11558       lit = PCOL(pci->pcop)->lit;
11559
11560       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11561
11562       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11563         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11564       } else {
11565         /* cannot remove this LFSR */
11566         ok = 0;
11567       } // if
11568
11569       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11570       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11571         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11572       } else {
11573         ok = 0;
11574       } // if
11575
11576       if (ok) {
11577         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11578       }
11579     }
11580     break;
11581
11582   case POC_MOVWF: /* does not touch flags */
11583     /* find value of WREG */
11584     val = defmapCurr (list, SPO_WREG, pc);
11585     oldval = defmapCurr (list, sym1, pc);
11586     if (val) lit = litFromValnum (val->in_val);
11587     else lit = -1;
11588     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11589
11590     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11591       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11592       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11593       if (lit == 0) {
11594         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11595       } else {
11596         assert (lit == 0x0ff);
11597         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11598       }
11599       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11600       pic16_pCodeReplace (pc, newpc);
11601       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11602       pic16_fixDefmap (pc, newpc);
11603       pc = newpc;
11604
11605       /* This breaks the defmap chain's references to pCodes... fix it! */
11606       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11607       if (!val->acc.access.isWrite) {
11608         deleteDefmap (val);     // delete reference to WREG as in value
11609         val = NULL;
11610       } else {
11611         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11612       }
11613       oldval = PCI(pc)->pcflow->defmap;
11614       while (oldval) {
11615         if (oldval->pc == pc) oldval->pc = newpc;
11616           oldval = oldval->next;
11617       } // while
11618     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11619       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11620       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11621     }
11622     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11623     break;
11624
11625   case POC_MOVFW: /* modifies STATUS (Z,N) */
11626     /* find value of REG */
11627     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11628       val = defmapCurr (list, sym1, pc);
11629       oldval = defmapCurr (list, SPO_WREG, pc);
11630       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11631         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11632         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11633       } else {
11634           defmap_t *pred, *predpred;
11635           /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11636            * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11637            * This might allow removal of the first two assignments. */
11638           pred = defmapFindDef (list, sym1, pc);
11639           predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11640           if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11641                 && !pic16_isAlive (SPO_STATUS, pc))
11642           {
11643               newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11644
11645               if (pic16_debug_verbose || pic16_pcode_verbose) {
11646                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11647               } // if
11648               pic16_pCodeReplace (pc, newpc);
11649               defmapReplaceSymRef (pc, sym1, 0, 1);
11650               pic16_fixDefmap (pc, newpc);
11651               pc = newpc;
11652
11653               /* This breaks the defmap chain's references to pCodes... fix it! */
11654               if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11655               if (!val->acc.access.isWrite) {
11656                   deleteDefmap (val);   // delete reference to reg1 as in value
11657                   val = NULL;
11658               } else {
11659                   val->acc.access.isRead = 0;   // delete reference to reg1 as in value
11660               }
11661               oldval = PCI(pc)->pcflow->defmap;
11662               while (oldval) {
11663                   if (oldval->pc == pc) oldval->pc = newpc;
11664                   oldval = oldval->next;
11665               } // while
11666           } // if
11667       }
11668       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11669     }
11670     break;
11671
11672   case POC_MOVFF: /* does not touch STATUS */
11673     /* find value of REG */
11674     val = defmapCurr (list, sym1, pc);
11675     oldval = defmapCurr (list, sym2, pc);
11676     if (val) lit = litFromValnum (val->in_val);
11677     else lit = -1;
11678     newpc = NULL;
11679     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11680       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11681       if (lit == 0) {
11682         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11683       } else if (lit == 0x00ff) {
11684         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11685       } else {
11686         newpc = NULL;
11687       }
11688       if (newpc) {
11689         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11690         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11691         pic16_pCodeReplace (pc, newpc);
11692         defmapReplaceSymRef (pc, sym1, 0, 1);
11693         pic16_fixDefmap (pc, newpc);
11694         pc = newpc;
11695         break; // do not process instruction as MOVFF...
11696       }
11697     } else if (!isSpecial1 && !isSpecial2
11698                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11699                 && val && oldval && (val->in_val != 0)) {
11700       if (val->in_val == oldval->in_val) {
11701         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11702         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11703       } else {
11704         if (!pic16_isAlive (sym1, pc)) {
11705           defmap_t *copy = NULL;
11706           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11707            * This should help eliminate
11708            *   MOVFF A,B
11709            *   <do something not changing A or using B>
11710            *   MOVFF B,C
11711            *   <B is not alive anymore>
11712            * and turn it into
11713            *   <do something not changing A or using B>
11714            *   MOVFF A,C
11715            */
11716
11717           /* scan defmap for symbols storing sym1's value */
11718           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11719           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11720             /* unique reaching definition for sym found */
11721             if (copy->val && copy->val == val->in_val) {
11722               //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);
11723               if (copy->sym == SPO_WREG) {
11724                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11725               } else {
11726                 pCodeOp *pcop = NULL;
11727                 /* the code below fails if we try to replace
11728                  *   MOVFF PRODL, r0x03
11729                  *   MOVFF r0x03, PCLATU
11730                  * with
11731                  *   MOVFF PRODL, PCLATU
11732                  * as copy(PRODL) contains has pc==NULL, by name fails...
11733                  */
11734                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11735
11736                 if (copy->pc && PCI(copy->pc)->pcop)
11737                   pcop = PCI(copy->pc)->pcop;
11738 #if 0
11739                 /* This code is broken--see above. */
11740                 else
11741                 {
11742                   const char *symname = strFromSym(copy->sym);
11743
11744                   assert( symname );
11745                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11746                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11747                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11748                 }
11749 #endif
11750                 assert( pcop );
11751                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11752                         pcop,
11753                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11754               }
11755               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11756               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11757               pic16_pCodeReplace (pc, newpc);
11758               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11759               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11760               pic16_fixDefmap (pc, newpc);
11761               pc = newpc;
11762             }
11763           }
11764           deleteDefmapChain (&copy);
11765         }
11766       }
11767       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11768     }
11769     break;
11770
11771   default:
11772     /* cannot optimize */
11773     break;
11774   } // switch
11775 }
11776
11777 static void pic16_destructDF (pBlock *pb) {
11778   pCode *pc, *next;
11779
11780   if (!pb) return;
11781
11782   /* remove old defmaps */
11783   pc = pic16_findNextInstruction (pb->pcHead);
11784   while (pc) {
11785     next = pic16_findNextInstruction (pc->next);
11786
11787     assert (isPCI(pc) || isPCAD(pc));
11788     assert (PCI(pc)->pcflow);
11789     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11790     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11791     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11792
11793     pc = next;
11794   } // while
11795
11796   if (defmap_free || defmap_free_count) {
11797     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11798     freeDefmap (&defmap_free);
11799     defmap_free_count = 0;
11800   }
11801 }
11802
11803 /* Checks whether a pBlock contains ASMDIRs. */
11804 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11805   pCode *pc;
11806
11807   if (!pb) return 0;
11808
11809   pc = pic16_findNextInstruction (pb->pcHead);
11810   while (pc) {
11811     if (isPCAD(pc)) return 1;
11812
11813     pc = pic16_findNextInstruction (pc->next);
11814   } // while
11815
11816   /* no PCADs found */
11817   return 0;
11818 }
11819
11820 #if 1
11821 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11822 static int pic16_removeUnusedRegistersDF () {
11823   pCode *pc, *pc2;
11824   pBlock *pb;
11825   regs *reg1, *reg2, *reg3;
11826   set *seenRegs = NULL;
11827   int cond, i;
11828   int islocal, change = 0;
11829
11830   /* no pBlocks? */
11831   if (!the_pFile || !the_pFile->pbHead) return 0;
11832
11833   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11834     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11835 #if 1
11836     /* find set of using pCodes per register */
11837     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11838                     pc = pic16_findNextInstruction(pc->next)) {
11839
11840       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11841       reg1 = reg2 = NULL;
11842       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11843       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11844
11845       if (reg1) {
11846         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11847         addSetIfnotP (&seenRegs, reg1);
11848         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11849       }
11850       if (reg2) {
11851         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11852         addSetIfnotP (&seenRegs, reg2);
11853         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11854       }
11855     } // for pc
11856 #endif
11857     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11858       /* may not use pic16_regIsLocal() here -- in interrupt routines
11859        * WREG, PRODx, FSR0x must be saved */
11860       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11861       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11862         pc = pc2 = NULL;
11863         for (i=0; i < 2; i++) {
11864           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11865           if (!pc2) pc2 = pc;
11866           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11867           reg2 = pic16_getRegFromInstruction (pc);
11868           reg3 = pic16_getRegFromInstruction2 (pc);
11869           if (!reg2 || !reg3
11870               || (reg2->rIdx != pic16_stack_preinc->rIdx
11871                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11872           if (i == 1) {
11873             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11874             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11875             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11876             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11877           }
11878         } // for
11879       } // if
11880       deleteSet (&reg1->reglives.usedpCodes);
11881     } // for reg1
11882
11883     deleteSet (&seenRegs);
11884   } // for pb
11885
11886   return change;
11887 }
11888 #endif
11889
11890 /* Set up pCodeFlow's defmap_ts.
11891  * Needs correctly set up to/from fields. */
11892 static void pic16_createDF (pBlock *pb) {
11893   pCode *pc, *next;
11894   int change=0;
11895
11896   if (!pb) return;
11897
11898   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11899
11900   pic16_destructDF (pb);
11901
11902   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11903   if (pic16_pBlockHasAsmdirs (pb)) {
11904     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11905     return;
11906   }
11907
11908   /* integrity check -- we need to reach all flows to guarantee
11909    * correct data flow analysis (reaching definitions, aliveness) */
11910 #if 0
11911   if (!verifyAllFlowsReachable (pb)) {
11912     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11913     return;
11914   }
11915 #endif
11916
11917   /* establish new defmaps */
11918   pc = pic16_findNextInstruction (pb->pcHead);
11919   while (pc) {
11920     next = pic16_findNextInstruction (pc->next);
11921
11922     assert (PCI(pc)->pcflow);
11923     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11924
11925     pc = next;
11926   } // while
11927
11928   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11929   createReachingDefinitions (pb);
11930
11931 #if 1
11932   /* assign better valnums */
11933   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11934   pc = pic16_findNextInstruction (pb->pcHead);
11935   while (pc) {
11936     next = pic16_findNextInstruction (pc->next);
11937
11938     assert (PCI(pc)->pcflow);
11939     assignValnums (pc);
11940
11941     pc = next;
11942   } // while
11943 #endif
11944
11945 #if 1
11946   /* remove dead pCodes */
11947   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11948   do {
11949     change = 0;
11950     pc = pic16_findNextInstruction (pb->pcHead);
11951     while (pc) {
11952       next = pic16_findNextInstruction (pc->next);
11953
11954       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11955         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11956       }
11957
11958       pc = next;
11959     } // while
11960   } while (change);
11961 #endif
11962 }
11963
11964 /* ======================================================================== */
11965 /* === VCG DUMPER ROUTINES ================================================ */
11966 /* ======================================================================== */
11967 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11968 hTab *dumpedNodes = NULL;
11969
11970 /** Dump VCG header into of. */
11971 static void pic16_vcg_init (FILE *of) {
11972   /* graph defaults */
11973   fprintf (of, "graph:{\n");
11974   fprintf (of, "title:\"graph1\"\n");
11975   fprintf (of, "label:\"graph1\"\n");
11976   fprintf (of, "color:white\n");
11977   fprintf (of, "textcolor:black\n");
11978   fprintf (of, "bordercolor:black\n");
11979   fprintf (of, "borderwidth:1\n");
11980   fprintf (of, "textmode:center\n");
11981
11982   fprintf (of, "layoutalgorithm:dfs\n");
11983   fprintf (of, "late_edge_labels:yes\n");
11984   fprintf (of, "display_edge_labels:yes\n");
11985   fprintf (of, "dirty_edge_labels:yes\n");
11986   fprintf (of, "finetuning:yes\n");
11987   fprintf (of, "ignoresingles:no\n");
11988   fprintf (of, "straight_phase:yes\n");
11989   fprintf (of, "priority_phase:yes\n");
11990   fprintf (of, "manhattan_edges:yes\n");
11991   fprintf (of, "smanhattan_edges:no\n");
11992   fprintf (of, "nearedges:no\n");
11993   fprintf (of, "node_alignment:center\n"); // bottom|top|center
11994   fprintf (of, "port_sharing:no\n");
11995   fprintf (of, "arrowmode:free\n"); // fixed|free
11996   fprintf (of, "crossingphase2:yes\n");
11997   fprintf (of, "crossingoptimization:yes\n");
11998   fprintf (of, "edges:yes\n");
11999   fprintf (of, "nodes:yes\n");
12000   fprintf (of, "splines:no\n");
12001
12002   /* node defaults */
12003   fprintf (of, "node.color:lightyellow\n");
12004   fprintf (of, "node.textcolor:black\n");
12005   fprintf (of, "node.textmode:center\n");
12006   fprintf (of, "node.shape:box\n");
12007   fprintf (of, "node.bordercolor:black\n");
12008   fprintf (of, "node.borderwidth:1\n");
12009
12010   /* edge defaults */
12011   fprintf (of, "edge.textcolor:black\n");
12012   fprintf (of, "edge.color:black\n");
12013   fprintf (of, "edge.thickness:1\n");
12014   fprintf (of, "edge.arrowcolor:black\n");
12015   fprintf (of, "edge.backarrowcolor:black\n");
12016   fprintf (of, "edge.arrowsize:15\n");
12017   fprintf (of, "edge.backarrowsize:15\n");
12018   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12019   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12020   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12021
12022   fprintf (of, "\n");
12023
12024   /* prepare data structures */
12025   if (dumpedNodes) {
12026     hTabDeleteAll (dumpedNodes);
12027     dumpedNodes = NULL;
12028   }
12029   dumpedNodes = newHashTable (128);
12030 }
12031
12032 /** Dump VCG footer into of. */
12033 static void pic16_vcg_close (FILE *of) {
12034   fprintf (of, "}\n");
12035 }
12036
12037 #define BUF_SIZE 128
12038 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12039
12040 #if 0
12041 static int ptrcmp (const void *p1, const void *p2) {
12042   return p1 == p2;
12043 }
12044 #endif
12045
12046 /** Dump a pCode node as VCG to of. */
12047 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12048   char buf[BUF_SIZE];
12049
12050   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12051     // dumped already
12052     return;
12053   }
12054   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12055   //fprintf (stderr, "dumping %p\n", pc);
12056
12057   /* only dump pCodeInstructions and Flow nodes */
12058   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12059
12060   /* emit node */
12061   fprintf (of, "node:{");
12062   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12063   fprintf (of, "label:\"%s\n", pcTitle(pc));
12064   if (isPCFL(pc)) {
12065     fprintf (of, "<PCFLOW>");
12066   } else if (isPCI(pc) || isPCAD(pc)) {
12067     pc->print (of, pc);
12068   } else {
12069     fprintf (of, "<!PCI>");
12070   }
12071   fprintf (of, "\" ");
12072   fprintf (of, "}\n");
12073
12074   if (1 && isPCFL(pc)) {
12075     defmap_t *map, *prev;
12076     unsigned int i;
12077     map = PCFL(pc)->defmap;
12078     i=0;
12079     while (map) {
12080       if (map->sym != 0) {
12081         i++;
12082
12083         /* emit definition node */
12084         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12085         fprintf (of, "label:\"");
12086
12087         prev = map;
12088         do {
12089           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));
12090           prev = map;
12091           map = map->next;
12092         } while (map && prev->pc == map->pc);
12093         map = prev;
12094
12095         fprintf (of, "\" ");
12096
12097         fprintf (of, "color:green ");
12098         fprintf (of, "}\n");
12099
12100         /* emit edge to previous definition */
12101         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12102         if (i == 1) {
12103           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12104         } else {
12105           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12106         }
12107         fprintf (of, "color:green ");
12108         fprintf (of, "}\n");
12109
12110         if (map->pc) {
12111           pic16_vcg_dumpnode (map->pc, of);
12112           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12113           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12114         }
12115       }
12116       map = map->next;
12117     } // while
12118   }
12119
12120   /* emit additional nodes (e.g. operands) */
12121 }
12122
12123 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12124 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12125   char buf[BUF_SIZE];
12126   pCodeInstruction *pci;
12127   pBranch *curr;
12128   int i;
12129
12130   if (1 && isPCFL(pc)) {
12131     /* emit edges to flow successors */
12132     void *pcfl;
12133     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12134     pcfl = setFirstItem (PCFL(pc)->to);
12135     while (pcfl) {
12136       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12137       pic16_vcg_dumpnode (pc, of);
12138       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12139       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12140       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12141       pcfl = setNextItem (PCFL(pc)->to);
12142     } // while
12143   } // if
12144
12145   if (!isPCI(pc) && !isPCAD(pc)) return;
12146
12147   pci = PCI(pc);
12148
12149   /* emit control flow edges (forward only) */
12150   curr = pci->to;
12151   i=0;
12152   while (curr) {
12153     pic16_vcg_dumpnode (curr->pc, of);
12154     fprintf (of, "edge:{");
12155     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12156     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12157     fprintf (of, "color:red ");
12158     fprintf (of, "}\n");
12159     curr = curr->next;
12160   } // while
12161
12162 #if 1
12163   /* dump "flow" edge (link pCode according to pBlock order) */
12164   {
12165     pCode *pcnext;
12166     pcnext = pic16_findNextInstruction (pc->next);
12167     if (pcnext) {
12168       pic16_vcg_dumpnode (pcnext, of);
12169       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12170       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12171     }
12172   }
12173 #endif
12174
12175 #if 0
12176   /* emit flow */
12177   if (pci->pcflow) {
12178     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12179     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12180     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12181   }
12182 #endif
12183
12184   /* emit data flow edges (backward only) */
12185   /* TODO: gather data flow information... */
12186 }
12187
12188 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12189   pCode *pc;
12190
12191   if (!pb) return;
12192
12193   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12194   if (pic16_pBlockHasAsmdirs (pb)) {
12195     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12196     return;
12197   }
12198
12199   for (pc=pb->pcHead; pc; pc = pc->next) {
12200     pic16_vcg_dumpnode (pc, of);
12201   } // for pc
12202
12203   for (pc=pb->pcHead; pc; pc = pc->next) {
12204     pic16_vcg_dumpedges (pc, of);
12205   } // for pc
12206 }
12207
12208 static void pic16_vcg_dump_default (pBlock *pb) {
12209   FILE *of;
12210   char buf[BUF_SIZE];
12211   pCode *pc;
12212
12213   if (!pb) return;
12214
12215   /* get function name */
12216   pc = pb->pcHead;
12217   while (pc && !isPCF(pc)) pc = pc->next;
12218   if (pc) {
12219     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12220   } else {
12221     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12222   }
12223
12224   //fprintf (stderr, "now dumping %s\n", buf);
12225   of = fopen (buf, "w");
12226   pic16_vcg_init (of);
12227   pic16_vcg_dump (of, pb);
12228   pic16_vcg_close (of);
12229   fclose (of);
12230 }
12231 #endif
12232
12233 /*** END of helpers for pCode dataflow optimizations ***/