* src/pic16/pcode.c (LinkFlow): fix invalid cast from pCodeLabel
[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
160 /****************************************************************/
161 /*                      Forward declarations                    */
162 /****************************************************************/
163
164 void pic16_unlinkpCode(pCode *pc);
165 #if 0
166 static void genericAnalyze(pCode *pc);
167 static void AnalyzeGOTO(pCode *pc);
168 static void AnalyzeSKIP(pCode *pc);
169 static void AnalyzeRETURN(pCode *pc);
170 #endif
171
172 static void genericDestruct(pCode *pc);
173 static void genericPrint(FILE *of,pCode *pc);
174
175 static void pCodePrintLabel(FILE *of, pCode *pc);
176 static void pCodePrintFunction(FILE *of, pCode *pc);
177 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
178 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
179 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
180 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
181 int pic16_pCodePeepMatchRule(pCode *pc);
182 static void pBlockStats(FILE *of, pBlock *pb);
183 static pBlock *newpBlock(void);
184 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
185 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
186 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
187 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
188 void OptimizeLocalRegs(void);
189 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
190
191 char *dumpPicOptype(PIC_OPTYPE type);
192
193 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
194 pCodeOp *pic16_popGetLit(int);
195 pCodeOp *pic16_popGetWithString(char *);
196 extern int inWparamList(char *s);
197
198 /** data flow optimization helpers **/
199 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
200 static void pic16_vcg_dump (FILE *of, pBlock *pb);
201 static void pic16_vcg_dump_default (pBlock *pb);
202 #endif
203 static int pic16_pCodeIsAlive (pCode *pc);
204 static void pic16_df_stats ();
205 static void pic16_createDF (pBlock *pb);
206 static int pic16_removeUnusedRegistersDF ();
207 static void pic16_destructDF (pBlock *pb);
208 static void releaseStack ();
209
210 /****************************************************************/
211 /*                    PIC Instructions                          */
212 /****************************************************************/
213
214 pCodeInstruction pic16_pciADDWF = {
215   {PC_OPCODE, NULL, NULL, 0, NULL,
216    //   genericAnalyze,
217    genericDestruct,
218    genericPrint},
219   POC_ADDWF,
220   "ADDWF",
221   2,
222   NULL, // from branch
223   NULL, // to branch
224   NULL, // label
225   NULL, // operand
226   NULL, // flow block
227   NULL, // C source
228   3,    // num ops
229   1,0,  // dest, bit instruction
230   0,0,  // branch, skip
231   0,    // literal operand
232   1,    // RAM access bit
233   0,    // fast call/return mode select bit
234   0,    // second memory operand
235   0,    // second literal operand
236   POC_NOP,
237   (PCC_W | PCC_REGISTER),   // inCond
238   (PCC_REGISTER | PCC_STATUS), // outCond
239   PCI_MAGIC
240 };
241
242 pCodeInstruction pic16_pciADDFW = {
243   {PC_OPCODE, NULL, NULL, 0, NULL,
244    //   genericAnalyze,
245    genericDestruct,
246    genericPrint},
247   POC_ADDFW,
248   "ADDWF",
249   2,
250   NULL, // from branch
251   NULL, // to branch
252   NULL, // label
253   NULL, // operand
254   NULL, // flow block
255   NULL, // C source
256   3,    // num ops
257   0,0,  // dest, bit instruction
258   0,0,  // branch, skip
259   0,    // literal operand
260   1,    // RAM access bit
261   0,    // fast call/return mode select bit
262   0,    // second memory operand
263   0,    // second literal operand
264   POC_NOP,
265   (PCC_W | PCC_REGISTER),   // inCond
266   (PCC_W | PCC_STATUS), // outCond
267   PCI_MAGIC
268 };
269
270 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
271   {PC_OPCODE, NULL, NULL, 0, NULL,
272    //   genericAnalyze,
273    genericDestruct,
274    genericPrint},
275   POC_ADDWFC,
276   "ADDWFC",
277   2,
278   NULL, // from branch
279   NULL, // to branch
280   NULL, // label
281   NULL, // operand
282   NULL, // flow block
283   NULL, // C source
284   3,    // num ops
285   1,0,  // dest, bit instruction
286   0,0,  // branch, skip
287   0,    // literal operand
288   1,    // RAM access bit
289   0,    // fast call/return mode select bit
290   0,    // second memory operand
291   0,    // second literal operand
292   POC_NOP,
293   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
294   (PCC_REGISTER | PCC_STATUS), // outCond
295   PCI_MAGIC
296 };
297
298 pCodeInstruction pic16_pciADDFWC = {
299   {PC_OPCODE, NULL, NULL, 0, NULL,
300    //   genericAnalyze,
301    genericDestruct,
302    genericPrint},
303   POC_ADDFWC,
304   "ADDWFC",
305   2,
306   NULL, // from branch
307   NULL, // to branch
308   NULL, // label
309   NULL, // operand
310   NULL, // flow block
311   NULL, // C source
312   3,    // num ops
313   0,0,  // dest, bit instruction
314   0,0,  // branch, skip
315   0,    // literal operand
316   1,    // RAM access bit
317   0,    // fast call/return mode select bit
318   0,    // second memory operand
319   0,    // second literal operand
320   POC_NOP,
321   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
322   (PCC_W | PCC_STATUS), // outCond
323   PCI_MAGIC
324 };
325
326 pCodeInstruction pic16_pciADDLW = {
327   {PC_OPCODE, NULL, NULL, 0, NULL,
328    //   genericAnalyze,
329    genericDestruct,
330    genericPrint},
331   POC_ADDLW,
332   "ADDLW",
333   2,
334   NULL, // from branch
335   NULL, // to branch
336   NULL, // label
337   NULL, // operand
338   NULL, // flow block
339   NULL, // C source
340   1,    // num ops
341   0,0,  // dest, bit instruction
342   0,0,  // branch, skip
343   1,    // literal operand
344   0,    // RAM access bit
345   0,    // fast call/return mode select bit
346   0,    // second memory operand
347   0,    // second literal operand
348   POC_NOP,
349   (PCC_W | PCC_LITERAL),   // inCond
350   (PCC_W | PCC_STATUS), // outCond
351   PCI_MAGIC
352 };
353
354 pCodeInstruction pic16_pciANDLW = {
355   {PC_OPCODE, NULL, NULL, 0, NULL,
356    //   genericAnalyze,
357    genericDestruct,
358    genericPrint},
359   POC_ANDLW,
360   "ANDLW",
361   2,
362   NULL, // from branch
363   NULL, // to branch
364   NULL, // label
365   NULL, // operand
366   NULL, // flow block
367   NULL, // C source
368   1,    // num ops
369   0,0,  // dest, bit instruction
370   0,0,  // branch, skip
371   1,    // literal operand
372   0,    // RAM access bit
373   0,    // fast call/return mode select bit
374   0,    // second memory operand
375   0,    // second literal operand
376   POC_NOP,
377   (PCC_W | PCC_LITERAL),   // inCond
378   (PCC_W | PCC_Z | PCC_N), // outCond
379   PCI_MAGIC
380 };
381
382 pCodeInstruction pic16_pciANDWF = {
383   {PC_OPCODE, NULL, NULL, 0, NULL,
384    //   genericAnalyze,
385    genericDestruct,
386    genericPrint},
387   POC_ANDWF,
388   "ANDWF",
389   2,
390   NULL, // from branch
391   NULL, // to branch
392   NULL, // label
393   NULL, // operand
394   NULL, // flow block
395   NULL, // C source
396   3,    // num ops
397   1,0,  // dest, bit instruction
398   0,0,  // branch, skip
399   0,    // literal operand
400   1,    // RAM access bit
401   0,    // fast call/return mode select bit
402   0,    // second memory operand
403   0,    // second literal operand
404   POC_NOP,
405   (PCC_W | PCC_REGISTER),   // inCond
406   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
407   PCI_MAGIC
408 };
409
410 pCodeInstruction pic16_pciANDFW = {
411   {PC_OPCODE, NULL, NULL, 0, NULL,
412    //   genericAnalyze,
413    genericDestruct,
414    genericPrint},
415   POC_ANDFW,
416   "ANDWF",
417   2,
418   NULL, // from branch
419   NULL, // to branch
420   NULL, // label
421   NULL, // operand
422   NULL, // flow block
423   NULL, // C source
424   3,    // num ops
425   0,0,  // dest, bit instruction
426   0,0,  // branch, skip
427   0,    // literal operand
428   1,    // RAM access bit
429   0,    // fast call/return mode select bit
430   0,    // second memory operand
431   0,    // second literal operand
432   POC_NOP,
433   (PCC_W | PCC_REGISTER),   // inCond
434   (PCC_W | PCC_Z | PCC_N) // outCond
435 };
436
437 pCodeInstruction pic16_pciBC = { // mdubuc - New
438   {PC_OPCODE, NULL, NULL, 0, NULL,
439    //   genericAnalyze,
440    genericDestruct,
441    genericPrint},
442   POC_BC,
443   "BC",
444   2,
445   NULL, // from branch
446   NULL, // to branch
447   NULL, // label
448   NULL, // operand
449   NULL, // flow block
450   NULL, // C source
451   1,    // num ops
452   0,0,  // dest, bit instruction
453   1,0,  // branch, skip
454   0,    // literal operand
455   0,    // RAM access bit
456   0,    // fast call/return mode select bit
457   0,    // second memory operand
458   0,    // second literal operand
459   POC_NOP,
460   (PCC_REL_ADDR | PCC_C),   // inCond
461   PCC_NONE,    // outCond
462   PCI_MAGIC
463 };
464
465 pCodeInstruction pic16_pciBCF = {
466   {PC_OPCODE, NULL, NULL, 0, NULL,
467    //   genericAnalyze,
468    genericDestruct,
469    genericPrint},
470   POC_BCF,
471   "BCF",
472   2,
473   NULL, // from branch
474   NULL, // to branch
475   NULL, // label
476   NULL, // operand
477   NULL, // flow block
478   NULL, // C source
479   3,    // num ops
480   1,1,  // dest, bit instruction
481   0,0,  // branch, skip
482   0,    // literal operand
483   1,    // RAM access bit
484   0,    // fast call/return mode select bit
485   0,    // second memory operand
486   0,    // second literal operand
487   POC_BSF,
488   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
489   PCC_REGISTER, // outCond
490   PCI_MAGIC
491 };
492
493 pCodeInstruction pic16_pciBN = { // mdubuc - New
494   {PC_OPCODE, NULL, NULL, 0, NULL,
495    //   genericAnalyze,
496    genericDestruct,
497    genericPrint},
498   POC_BN,
499   "BN",
500   2,
501   NULL, // from branch
502   NULL, // to branch
503   NULL, // label
504   NULL, // operand
505   NULL, // flow block
506   NULL, // C source
507   1,    // num ops
508   0,0,  // dest, bit instruction
509   1,0,  // branch, skip
510   0,    // literal operand
511   0,    // RAM access bit
512   0,    // fast call/return mode select bit
513   0,    // second memory operand
514   0,    // second literal operand
515   POC_NOP,
516   (PCC_REL_ADDR | PCC_N),   // inCond
517   PCC_NONE   , // outCond
518   PCI_MAGIC
519 };
520
521 pCodeInstruction pic16_pciBNC = { // mdubuc - New
522   {PC_OPCODE, NULL, NULL, 0, NULL,
523    //   genericAnalyze,
524    genericDestruct,
525    genericPrint},
526   POC_BNC,
527   "BNC",
528   2,
529   NULL, // from branch
530   NULL, // to branch
531   NULL, // label
532   NULL, // operand
533   NULL, // flow block
534   NULL, // C source
535   1,    // num ops
536   0,0,  // dest, bit instruction
537   1,0,  // branch, skip
538   0,    // literal operand
539   0,    // RAM access bit
540   0,    // fast call/return mode select bit
541   0,    // second memory operand
542   0,    // second literal operand
543   POC_NOP,
544   (PCC_REL_ADDR | PCC_C),   // inCond
545   PCC_NONE   , // outCond
546   PCI_MAGIC
547 };
548
549 pCodeInstruction pic16_pciBNN = { // mdubuc - New
550   {PC_OPCODE, NULL, NULL, 0, NULL,
551    //   genericAnalyze,
552    genericDestruct,
553    genericPrint},
554   POC_BNN,
555   "BNN",
556   2,
557   NULL, // from branch
558   NULL, // to branch
559   NULL, // label
560   NULL, // operand
561   NULL, // flow block
562   NULL, // C source
563   1,    // num ops
564   0,0,  // dest, bit instruction
565   1,0,  // branch, skip
566   0,    // literal operand
567   0,    // RAM access bit
568   0,    // fast call/return mode select bit
569   0,    // second memory operand
570   0,    // second literal operand
571   POC_NOP,
572   (PCC_REL_ADDR | PCC_N),   // inCond
573   PCC_NONE   , // outCond
574   PCI_MAGIC
575 };
576
577 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
578   {PC_OPCODE, NULL, NULL, 0, NULL,
579    //   genericAnalyze,
580    genericDestruct,
581    genericPrint},
582   POC_BNOV,
583   "BNOV",
584   2,
585   NULL, // from branch
586   NULL, // to branch
587   NULL, // label
588   NULL, // operand
589   NULL, // flow block
590   NULL, // C source
591   1,    // num ops
592   0,0,  // dest, bit instruction
593   1,0,  // branch, skip
594   0,    // literal operand
595   0,    // RAM access bit
596   0,    // fast call/return mode select bit
597   0,    // second memory operand
598   0,    // second literal operand
599   POC_NOP,
600   (PCC_REL_ADDR | PCC_OV),   // inCond
601   PCC_NONE   , // outCond
602   PCI_MAGIC
603 };
604
605 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
606   {PC_OPCODE, NULL, NULL, 0, NULL,
607    //   genericAnalyze,
608    genericDestruct,
609    genericPrint},
610   POC_BNZ,
611   "BNZ",
612   2,
613   NULL, // from branch
614   NULL, // to branch
615   NULL, // label
616   NULL, // operand
617   NULL, // flow block
618   NULL, // C source
619   1,    // num ops
620   0,0,  // dest, bit instruction
621   1,0,  // branch, skip
622   0,    // literal operand
623   0,    // RAM access bit
624   0,    // fast call/return mode select bit
625   0,    // second memory operand
626   0,    // second literal operand
627   POC_NOP,
628   (PCC_REL_ADDR | PCC_Z),   // inCond
629   PCC_NONE   , // outCond
630   PCI_MAGIC
631 };
632
633 pCodeInstruction pic16_pciBOV = { // mdubuc - New
634   {PC_OPCODE, NULL, NULL, 0, NULL,
635    //   genericAnalyze,
636    genericDestruct,
637    genericPrint},
638   POC_BOV,
639   "BOV",
640   2,
641   NULL, // from branch
642   NULL, // to branch
643   NULL, // label
644   NULL, // operand
645   NULL, // flow block
646   NULL, // C source
647   1,    // num ops
648   0,0,  // dest, bit instruction
649   1,0,  // branch, skip
650   0,    // literal operand
651   0,    // RAM access bit
652   0,    // fast call/return mode select bit
653   0,    // second memory operand
654   0,    // second literal operand
655   POC_NOP,
656   (PCC_REL_ADDR | PCC_OV),   // inCond
657   PCC_NONE , // outCond
658   PCI_MAGIC
659 };
660
661 pCodeInstruction pic16_pciBRA = { // mdubuc - New
662   {PC_OPCODE, NULL, NULL, 0, NULL,
663    //   genericAnalyze,
664    genericDestruct,
665    genericPrint},
666   POC_BRA,
667   "BRA",
668   2,
669   NULL, // from branch
670   NULL, // to branch
671   NULL, // label
672   NULL, // operand
673   NULL, // flow block
674   NULL, // C source
675   1,    // num ops
676   0,0,  // dest, bit instruction
677   1,0,  // branch, skip
678   0,    // literal operand
679   0,    // RAM access bit
680   0,    // fast call/return mode select bit
681   0,    // second memory operand
682   0,    // second literal operand
683   POC_NOP,
684   PCC_REL_ADDR,   // inCond
685   PCC_NONE   , // outCond
686   PCI_MAGIC
687 };
688
689 pCodeInstruction pic16_pciBSF = {
690   {PC_OPCODE, NULL, NULL, 0, NULL,
691    //   genericAnalyze,
692    genericDestruct,
693    genericPrint},
694   POC_BSF,
695   "BSF",
696   2,
697   NULL, // from branch
698   NULL, // to branch
699   NULL, // label
700   NULL, // operand
701   NULL, // flow block
702   NULL, // C source
703   3,    // num ops
704   1,1,  // dest, bit instruction
705   0,0,  // branch, skip
706   0,    // literal operand
707   1,    // RAM access bit
708   0,    // fast call/return mode select bit
709   0,    // second memory operand
710   0,    // second literal operand
711   POC_BCF,
712   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
713   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
714   PCI_MAGIC
715 };
716
717 pCodeInstruction pic16_pciBTFSC = {
718   {PC_OPCODE, NULL, NULL, 0, NULL,
719    //   AnalyzeSKIP,
720    genericDestruct,
721    genericPrint},
722   POC_BTFSC,
723   "BTFSC",
724   2,
725   NULL, // from branch
726   NULL, // to branch
727   NULL, // label
728   NULL, // operand
729   NULL, // flow block
730   NULL, // C source
731   3,    // num ops
732   0,1,  // dest, bit instruction
733   1,1,  // branch, skip
734   0,    // literal operand
735   1,    // RAM access bit
736   0,    // fast call/return mode select bit
737   0,    // second memory operand
738   0,    // second literal operand
739   POC_BTFSS,
740   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
741   PCC_EXAMINE_PCOP, // outCond
742   PCI_MAGIC
743 };
744
745 pCodeInstruction pic16_pciBTFSS = {
746   {PC_OPCODE, NULL, NULL, 0, NULL,
747    //   AnalyzeSKIP,
748    genericDestruct,
749    genericPrint},
750   POC_BTFSS,
751   "BTFSS",
752   2,
753   NULL, // from branch
754   NULL, // to branch
755   NULL, // label
756   NULL, // operand
757   NULL, // flow block
758   NULL, // C source
759   3,    // num ops
760   0,1,  // dest, bit instruction
761   1,1,  // branch, skip
762   0,    // literal operand
763   1,    // RAM access bit
764   0,    // fast call/return mode select bit
765   0,    // second memory operand
766   0,    // second literal operand
767   POC_BTFSC,
768   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
769   PCC_EXAMINE_PCOP, // outCond
770   PCI_MAGIC
771 };
772
773 pCodeInstruction pic16_pciBTG = { // mdubuc - New
774   {PC_OPCODE, NULL, NULL, 0, NULL,
775    //   genericAnalyze,
776    genericDestruct,
777    genericPrint},
778   POC_BTG,
779   "BTG",
780   2,
781   NULL, // from branch
782   NULL, // to branch
783   NULL, // label
784   NULL, // operand
785   NULL, // flow block
786   NULL, // C source
787   3,    // num ops
788   0,1,  // dest, bit instruction
789   0,0,  // branch, skip
790   0,    // literal operand
791   1,    // RAM access bit
792   0,    // fast call/return mode select bit
793   0,    // second memory operand
794   0,    // second literal operand
795   POC_NOP,
796   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
797   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
798   PCI_MAGIC
799 };
800
801 pCodeInstruction pic16_pciBZ = { // mdubuc - New
802   {PC_OPCODE, NULL, NULL, 0, NULL,
803    //   genericAnalyze,
804    genericDestruct,
805    genericPrint},
806   POC_BZ,
807   "BZ",
808   2,
809   NULL, // from branch
810   NULL, // to branch
811   NULL, // label
812   NULL, // operand
813   NULL, // flow block
814   NULL, // C source
815   1,    // num ops
816   0,0,  // dest, bit instruction
817   1,0,  // branch, skip
818   0,    // literal operand
819   0,    // RAM access bit
820   0,    // fast call/return mode select bit
821   0,    // second memory operand
822   0,    // second literal operand
823   POC_NOP,
824   (PCC_REL_ADDR | PCC_Z),   // inCond
825   PCC_NONE, // outCond
826   PCI_MAGIC
827 };
828
829 pCodeInstruction pic16_pciCALL = {
830   {PC_OPCODE, NULL, NULL, 0, NULL,
831    //   genericAnalyze,
832    genericDestruct,
833    genericPrint},
834   POC_CALL,
835   "CALL",
836   4,
837   NULL, // from branch
838   NULL, // to branch
839   NULL, // label
840   NULL, // operand
841   NULL, // flow block
842   NULL, // C source
843   2,    // num ops
844   0,0,  // dest, bit instruction
845   1,0,  // branch, skip
846   0,    // literal operand
847   0,    // RAM access bit
848   1,    // fast call/return mode select bit
849   0,    // second memory operand
850   0,    // second literal operand
851   POC_NOP,
852   PCC_NONE, // inCond
853   PCC_NONE, // outCond
854   PCI_MAGIC
855 };
856
857 pCodeInstruction pic16_pciCOMF = {
858   {PC_OPCODE, NULL, NULL, 0, NULL,
859    //   genericAnalyze,
860    genericDestruct,
861    genericPrint},
862   POC_COMF,
863   "COMF",
864   2,
865   NULL, // from branch
866   NULL, // to branch
867   NULL, // label
868   NULL, // operand
869   NULL, // flow block
870   NULL, // C source
871   3,    // num ops
872   1,0,  // dest, bit instruction
873   0,0,  // branch, skip
874   0,    // literal operand
875   1,    // RAM access bit
876   0,    // fast call/return mode select bit
877   0,    // second memory operand
878   0,    // second literal operand
879   POC_NOP,
880   PCC_REGISTER,  // inCond
881   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
882   PCI_MAGIC
883 };
884
885 pCodeInstruction pic16_pciCOMFW = {
886   {PC_OPCODE, NULL, NULL, 0, NULL,
887    //   genericAnalyze,
888    genericDestruct,
889    genericPrint},
890   POC_COMFW,
891   "COMF",
892   2,
893   NULL, // from branch
894   NULL, // to branch
895   NULL, // label
896   NULL, // operand
897   NULL, // flow block
898   NULL, // C source
899   3,    // num ops
900   0,0,  // dest, bit instruction
901   0,0,  // branch, skip
902   0,    // literal operand
903   1,    // RAM access bit
904   0,    // fast call/return mode select bit
905   0,    // second memory operand
906   0,    // second literal operand
907   POC_NOP,
908   PCC_REGISTER,  // inCond
909   (PCC_W | PCC_Z | PCC_N) , // outCond
910   PCI_MAGIC
911 };
912
913 pCodeInstruction pic16_pciCLRF = {
914   {PC_OPCODE, NULL, NULL, 0, NULL,
915    //   genericAnalyze,
916    genericDestruct,
917    genericPrint},
918   POC_CLRF,
919   "CLRF",
920   2,
921   NULL, // from branch
922   NULL, // to branch
923   NULL, // label
924   NULL, // operand
925   NULL, // flow block
926   NULL, // C source
927   2,    // num ops
928   0,0,  // dest, bit instruction
929   0,0,  // branch, skip
930   0,    // literal operand
931   1,    // RAM access bit
932   0,    // fast call/return mode select bit
933   0,    // second memory operand
934   0,    // second literal operand
935   POC_NOP,
936   PCC_NONE, // inCond
937   (PCC_REGISTER | PCC_Z), // outCond
938   PCI_MAGIC
939 };
940
941 pCodeInstruction pic16_pciCLRWDT = {
942   {PC_OPCODE, NULL, NULL, 0, NULL,
943    //   genericAnalyze,
944    genericDestruct,
945    genericPrint},
946   POC_CLRWDT,
947   "CLRWDT",
948   2,
949   NULL, // from branch
950   NULL, // to branch
951   NULL, // label
952   NULL, // operand
953   NULL, // flow block
954   NULL, // C source
955   0,    // num ops
956   0,0,  // dest, bit instruction
957   0,0,  // branch, skip
958   0,    // literal operand
959   0,    // RAM access bit
960   0,    // fast call/return mode select bit
961   0,    // second memory operand
962   0,    // second literal operand
963   POC_NOP,
964   PCC_NONE, // inCond
965   PCC_NONE , // outCond
966   PCI_MAGIC
967 };
968
969 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
970   {PC_OPCODE, NULL, NULL, 0, NULL,
971    //   genericAnalyze,
972    genericDestruct,
973    genericPrint},
974   POC_CPFSEQ,
975   "CPFSEQ",
976   2,
977   NULL, // from branch
978   NULL, // to branch
979   NULL, // label
980   NULL, // operand
981   NULL, // flow block
982   NULL, // C source
983   2,    // num ops
984   0,0,  // dest, bit instruction
985   1,1,  // branch, skip
986   0,    // literal operand
987   1,    // RAM access bit
988   0,    // fast call/return mode select bit
989   0,    // second memory operand
990   0,    // second literal operand
991   POC_NOP,
992   (PCC_W | PCC_REGISTER), // inCond
993   PCC_NONE , // outCond
994   PCI_MAGIC
995 };
996
997 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
998   {PC_OPCODE, NULL, NULL, 0, NULL,
999    //   genericAnalyze,
1000    genericDestruct,
1001    genericPrint},
1002   POC_CPFSGT,
1003   "CPFSGT",
1004   2,
1005   NULL, // from branch
1006   NULL, // to branch
1007   NULL, // label
1008   NULL, // operand
1009   NULL, // flow block
1010   NULL, // C source
1011   2,    // num ops
1012   0,0,  // dest, bit instruction
1013   1,1,  // branch, skip
1014   0,    // literal operand
1015   1,    // RAM access bit
1016   0,    // fast call/return mode select bit
1017   0,    // second memory operand
1018   0,    // second literal operand
1019   POC_NOP,
1020   (PCC_W | PCC_REGISTER), // inCond
1021   PCC_NONE , // outCond
1022   PCI_MAGIC
1023 };
1024
1025 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1026   {PC_OPCODE, NULL, NULL, 0, NULL,
1027    //   genericAnalyze,
1028    genericDestruct,
1029    genericPrint},
1030   POC_CPFSLT,
1031   "CPFSLT",
1032   2,
1033   NULL, // from branch
1034   NULL, // to branch
1035   NULL, // label
1036   NULL, // operand
1037   NULL, // flow block
1038   NULL, // C source
1039   2,    // num ops
1040   1,0,  // dest, bit instruction
1041   1,1,  // branch, skip
1042   0,    // literal operand
1043   1,    // RAM access bit
1044   0,    // fast call/return mode select bit
1045   0,    // second memory operand
1046   0,    // second literal operand
1047   POC_NOP,
1048   (PCC_W | PCC_REGISTER), // inCond
1049   PCC_NONE , // outCond
1050   PCI_MAGIC
1051 };
1052
1053 pCodeInstruction pic16_pciDAW = {
1054   {PC_OPCODE, NULL, NULL, 0, NULL,
1055    //   genericAnalyze,
1056    genericDestruct,
1057    genericPrint},
1058   POC_DAW,
1059   "DAW",
1060   2,
1061   NULL, // from branch
1062   NULL, // to branch
1063   NULL, // label
1064   NULL, // operand
1065   NULL, // flow block
1066   NULL, // C source
1067   0,    // num ops
1068   0,0,  // dest, bit instruction
1069   0,0,  // branch, skip
1070   0,    // literal operand
1071   0,    // RAM access bit
1072   0,    // fast call/return mode select bit
1073   0,    // second memory operand
1074   0,    // second literal operand
1075   POC_NOP,
1076   PCC_W, // inCond
1077   (PCC_W | PCC_C), // outCond
1078   PCI_MAGIC
1079 };
1080
1081 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1082   {PC_OPCODE, NULL, NULL, 0, NULL,
1083    //   genericAnalyze,
1084    genericDestruct,
1085    genericPrint},
1086   POC_DCFSNZ,
1087   "DCFSNZ",
1088   2,
1089   NULL, // from branch
1090   NULL, // to branch
1091   NULL, // label
1092   NULL, // operand
1093   NULL, // flow block
1094   NULL, // C source
1095   3,    // num ops
1096   1,0,  // dest, bit instruction
1097   1,1,  // branch, skip
1098   0,    // literal operand
1099   1,    // RAM access bit
1100   0,    // fast call/return mode select bit
1101   0,    // second memory operand
1102   0,    // second literal operand
1103   POC_NOP,
1104   PCC_REGISTER, // inCond
1105   PCC_REGISTER , // outCond
1106   PCI_MAGIC
1107 };
1108
1109 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1110   {PC_OPCODE, NULL, NULL, 0, NULL,
1111    //   genericAnalyze,
1112    genericDestruct,
1113    genericPrint},
1114   POC_DCFSNZW,
1115   "DCFSNZ",
1116   2,
1117   NULL, // from branch
1118   NULL, // to branch
1119   NULL, // label
1120   NULL, // operand
1121   NULL, // flow block
1122   NULL, // C source
1123   3,    // num ops
1124   0,0,  // dest, bit instruction
1125   1,1,  // branch, skip
1126   0,    // literal operand
1127   1,    // RAM access bit
1128   0,    // fast call/return mode select bit
1129   0,    // second memory operand
1130   0,    // second literal operand
1131   POC_NOP,
1132   PCC_REGISTER, // inCond
1133   PCC_W , // outCond
1134   PCI_MAGIC
1135 };
1136
1137 pCodeInstruction pic16_pciDECF = {
1138   {PC_OPCODE, NULL, NULL, 0, NULL,
1139    //   genericAnalyze,
1140    genericDestruct,
1141    genericPrint},
1142   POC_DECF,
1143   "DECF",
1144   2,
1145   NULL, // from branch
1146   NULL, // to branch
1147   NULL, // label
1148   NULL, // operand
1149   NULL, // flow block
1150   NULL, // C source
1151   3,    // num ops
1152   1,0,  // dest, bit instruction
1153   0,0,  // branch, skip
1154   0,    // literal operand
1155   1,    // RAM access bit
1156   0,    // fast call/return mode select bit
1157   0,    // second memory operand
1158   0,    // second literal operand
1159   POC_NOP,
1160   PCC_REGISTER,   // inCond
1161   (PCC_REGISTER | PCC_STATUS)  , // outCond
1162   PCI_MAGIC
1163 };
1164
1165 pCodeInstruction pic16_pciDECFW = {
1166   {PC_OPCODE, NULL, NULL, 0, NULL,
1167    //   genericAnalyze,
1168    genericDestruct,
1169    genericPrint},
1170   POC_DECFW,
1171   "DECF",
1172   2,
1173   NULL, // from branch
1174   NULL, // to branch
1175   NULL, // label
1176   NULL, // operand
1177   NULL, // flow block
1178   NULL, // C source
1179   3,    // num ops
1180   0,0,  // dest, bit instruction
1181   0,0,  // branch, skip
1182   0,    // literal operand
1183   1,    // RAM access bit
1184   0,    // fast call/return mode select bit
1185   0,    // second memory operand
1186   0,    // second literal operand
1187   POC_NOP,
1188   PCC_REGISTER,   // inCond
1189   (PCC_W | PCC_STATUS)  , // outCond
1190   PCI_MAGIC
1191 };
1192
1193 pCodeInstruction pic16_pciDECFSZ = {
1194   {PC_OPCODE, NULL, NULL, 0, NULL,
1195    //   AnalyzeSKIP,
1196    genericDestruct,
1197    genericPrint},
1198   POC_DECFSZ,
1199   "DECFSZ",
1200   2,
1201   NULL, // from branch
1202   NULL, // to branch
1203   NULL, // label
1204   NULL, // operand
1205   NULL, // flow block
1206   NULL, // C source
1207   3,    // num ops
1208   1,0,  // dest, bit instruction
1209   1,1,  // branch, skip
1210   0,    // literal operand
1211   1,    // RAM access bit
1212   0,    // fast call/return mode select bit
1213   0,    // second memory operand
1214   0,    // second literal operand
1215   POC_NOP,
1216   PCC_REGISTER,   // inCond
1217   PCC_REGISTER   , // outCond
1218   PCI_MAGIC
1219 };
1220
1221 pCodeInstruction pic16_pciDECFSZW = {
1222   {PC_OPCODE, NULL, NULL, 0, NULL,
1223    //   AnalyzeSKIP,
1224    genericDestruct,
1225    genericPrint},
1226   POC_DECFSZW,
1227   "DECFSZ",
1228   2,
1229   NULL, // from branch
1230   NULL, // to branch
1231   NULL, // label
1232   NULL, // operand
1233   NULL, // flow block
1234   NULL, // C source
1235   3,    // num ops
1236   0,0,  // dest, bit instruction
1237   1,1,  // branch, skip
1238   0,    // literal operand
1239   1,    // RAM access bit
1240   0,    // fast call/return mode select bit
1241   0,    // second memory operand
1242   0,    // second literal operand
1243   POC_NOP,
1244   PCC_REGISTER,   // inCond
1245   PCC_W          , // outCond
1246   PCI_MAGIC
1247 };
1248
1249 pCodeInstruction pic16_pciGOTO = {
1250   {PC_OPCODE, NULL, NULL, 0, NULL,
1251    //   AnalyzeGOTO,
1252    genericDestruct,
1253    genericPrint},
1254   POC_GOTO,
1255   "GOTO",
1256   4,
1257   NULL, // from branch
1258   NULL, // to branch
1259   NULL, // label
1260   NULL, // operand
1261   NULL, // flow block
1262   NULL, // C source
1263   1,    // num ops
1264   0,0,  // dest, bit instruction
1265   1,0,  // branch, skip
1266   0,    // literal operand
1267   0,    // RAM access bit
1268   0,    // fast call/return mode select bit
1269   0,    // second memory operand
1270   0,    // second literal operand
1271   POC_NOP,
1272   PCC_REL_ADDR,   // inCond
1273   PCC_NONE   , // outCond
1274   PCI_MAGIC
1275 };
1276
1277 pCodeInstruction pic16_pciINCF = {
1278   {PC_OPCODE, NULL, NULL, 0, NULL,
1279    //   genericAnalyze,
1280    genericDestruct,
1281    genericPrint},
1282   POC_INCF,
1283   "INCF",
1284   2,
1285   NULL, // from branch
1286   NULL, // to branch
1287   NULL, // label
1288   NULL, // operand
1289   NULL, // flow block
1290   NULL, // C source
1291   3,    // num ops
1292   1,0,  // dest, bit instruction
1293   0,0,  // branch, skip
1294   0,    // literal operand
1295   1,    // RAM access bit
1296   0,    // fast call/return mode select bit
1297   0,    // second memory operand
1298   0,    // second literal operand
1299   POC_NOP,
1300   PCC_REGISTER,   // inCond
1301   (PCC_REGISTER | PCC_STATUS), // outCond
1302   PCI_MAGIC
1303 };
1304
1305 pCodeInstruction pic16_pciINCFW = {
1306   {PC_OPCODE, NULL, NULL, 0, NULL,
1307    //   genericAnalyze,
1308    genericDestruct,
1309    genericPrint},
1310   POC_INCFW,
1311   "INCF",
1312   2,
1313   NULL, // from branch
1314   NULL, // to branch
1315   NULL, // label
1316   NULL, // operand
1317   NULL, // flow block
1318   NULL, // C source
1319   3,    // num ops
1320   0,0,  // dest, bit instruction
1321   0,0,  // branch, skip
1322   0,    // literal operand
1323   1,    // RAM access bit
1324   0,    // fast call/return mode select bit
1325   0,    // second memory operand
1326   0,    // second literal operand
1327   POC_NOP,
1328   PCC_REGISTER,   // inCond
1329   (PCC_W | PCC_STATUS)  , // outCond
1330   PCI_MAGIC
1331 };
1332
1333 pCodeInstruction pic16_pciINCFSZ = {
1334   {PC_OPCODE, NULL, NULL, 0, NULL,
1335    //   AnalyzeSKIP,
1336    genericDestruct,
1337    genericPrint},
1338   POC_INCFSZ,
1339   "INCFSZ",
1340   2,
1341   NULL, // from branch
1342   NULL, // to branch
1343   NULL, // label
1344   NULL, // operand
1345   NULL, // flow block
1346   NULL, // C source
1347   3,    // num ops
1348   1,0,  // dest, bit instruction
1349   1,1,  // branch, skip
1350   0,    // literal operand
1351   1,    // RAM access bit
1352   0,    // fast call/return mode select bit
1353   0,    // second memory operand
1354   0,    // second literal operand
1355   POC_INFSNZ,
1356   PCC_REGISTER,   // inCond
1357   PCC_REGISTER   , // outCond
1358   PCI_MAGIC
1359 };
1360
1361 pCodeInstruction pic16_pciINCFSZW = {
1362   {PC_OPCODE, NULL, NULL, 0, NULL,
1363    //   AnalyzeSKIP,
1364    genericDestruct,
1365    genericPrint},
1366   POC_INCFSZW,
1367   "INCFSZ",
1368   2,
1369   NULL, // from branch
1370   NULL, // to branch
1371   NULL, // label
1372   NULL, // operand
1373   NULL, // flow block
1374   NULL, // C source
1375   3,    // num ops
1376   0,0,  // dest, bit instruction
1377   1,1,  // branch, skip
1378   0,    // literal operand
1379   1,    // RAM access bit
1380   0,    // fast call/return mode select bit
1381   0,    // second memory operand
1382   0,    // second literal operand
1383   POC_INFSNZW,
1384   PCC_REGISTER,   // inCond
1385   PCC_W          , // outCond
1386   PCI_MAGIC
1387 };
1388
1389 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1390   {PC_OPCODE, NULL, NULL, 0, NULL,
1391    //   AnalyzeSKIP,
1392    genericDestruct,
1393    genericPrint},
1394   POC_INFSNZ,
1395   "INFSNZ",
1396   2,
1397   NULL, // from branch
1398   NULL, // to branch
1399   NULL, // label
1400   NULL, // operand
1401   NULL, // flow block
1402   NULL, // C source
1403   3,    // num ops
1404   1,0,  // dest, bit instruction
1405   1,1,  // branch, skip
1406   0,    // literal operand
1407   1,    // RAM access bit
1408   0,    // fast call/return mode select bit
1409   0,    // second memory operand
1410   0,    // second literal operand
1411   POC_INCFSZ,
1412   PCC_REGISTER,   // inCond
1413   PCC_REGISTER   , // outCond
1414   PCI_MAGIC
1415 };
1416
1417 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1418   {PC_OPCODE, NULL, NULL, 0, NULL,
1419    //   AnalyzeSKIP,
1420    genericDestruct,
1421    genericPrint},
1422   POC_INFSNZW,
1423   "INFSNZ",
1424   2,
1425   NULL, // from branch
1426   NULL, // to branch
1427   NULL, // label
1428   NULL, // operand
1429   NULL, // flow block
1430   NULL, // C source
1431   3,    // num ops
1432   0,0,  // dest, bit instruction
1433   1,1,  // branch, skip
1434   0,    // literal operand
1435   1,    // RAM access bit
1436   0,    // fast call/return mode select bit
1437   0,    // second memory operand
1438   0,    // second literal operand
1439   POC_INCFSZW,
1440   PCC_REGISTER,   // inCond
1441   PCC_W          , // outCond
1442   PCI_MAGIC
1443 };
1444
1445 pCodeInstruction pic16_pciIORWF = {
1446   {PC_OPCODE, NULL, NULL, 0, NULL,
1447    //   genericAnalyze,
1448    genericDestruct,
1449    genericPrint},
1450   POC_IORWF,
1451   "IORWF",
1452   2,
1453   NULL, // from branch
1454   NULL, // to branch
1455   NULL, // label
1456   NULL, // operand
1457   NULL, // flow block
1458   NULL, // C source
1459   3,    // num ops
1460   1,0,  // dest, bit instruction
1461   0,0,  // branch, skip
1462   0,    // literal operand
1463   1,    // RAM access bit
1464   0,    // fast call/return mode select bit
1465   0,    // second memory operand
1466   0,    // second literal operand
1467   POC_NOP,
1468   (PCC_W | PCC_REGISTER),   // inCond
1469   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1470   PCI_MAGIC
1471 };
1472
1473 pCodeInstruction pic16_pciIORFW = {
1474   {PC_OPCODE, NULL, NULL, 0, NULL,
1475    //   genericAnalyze,
1476    genericDestruct,
1477    genericPrint},
1478   POC_IORFW,
1479   "IORWF",
1480   2,
1481   NULL, // from branch
1482   NULL, // to branch
1483   NULL, // label
1484   NULL, // operand
1485   NULL, // flow block
1486   NULL, // C source
1487   3,    // num ops
1488   0,0,  // dest, bit instruction
1489   0,0,  // branch, skip
1490   0,    // literal operand
1491   1,    // RAM access bit
1492   0,    // fast call/return mode select bit
1493   0,    // second memory operand
1494   0,    // second literal operand
1495   POC_NOP,
1496   (PCC_W | PCC_REGISTER),   // inCond
1497   (PCC_W | PCC_Z | PCC_N), // outCond
1498   PCI_MAGIC
1499 };
1500
1501 pCodeInstruction pic16_pciIORLW = {
1502   {PC_OPCODE, NULL, NULL, 0, NULL,
1503    //   genericAnalyze,
1504    genericDestruct,
1505    genericPrint},
1506   POC_IORLW,
1507   "IORLW",
1508   2,
1509   NULL, // from branch
1510   NULL, // to branch
1511   NULL, // label
1512   NULL, // operand
1513   NULL, // flow block
1514   NULL, // C source
1515   1,    // num ops
1516   0,0,  // dest, bit instruction
1517   0,0,  // branch, skip
1518   1,    // literal operand
1519   0,    // RAM access bit
1520   0,    // fast call/return mode select bit
1521   0,    // second memory operand
1522   0,    // second literal operand
1523   POC_NOP,
1524   (PCC_W | PCC_LITERAL),   // inCond
1525   (PCC_W | PCC_Z | PCC_N), // outCond
1526   PCI_MAGIC
1527 };
1528
1529 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1530   {PC_OPCODE, NULL, NULL, 0, NULL,
1531    //   genericAnalyze,
1532    genericDestruct,
1533    genericPrint},
1534   POC_LFSR,
1535   "LFSR",
1536   4,
1537   NULL, // from branch
1538   NULL, // to branch
1539   NULL, // label
1540   NULL, // operand
1541   NULL, // flow block
1542   NULL, // C source
1543   2,    // num ops
1544   0,0,  // dest, bit instruction
1545   0,0,  // branch, skip
1546   1,    // literal operand
1547   0,    // RAM access bit
1548   0,    // fast call/return mode select bit
1549   0,    // second memory operand
1550   1,    // second literal operand
1551   POC_NOP,
1552   PCC_LITERAL, // inCond
1553   PCC_NONE, // outCond
1554   PCI_MAGIC
1555 };
1556
1557 pCodeInstruction pic16_pciMOVF = {
1558   {PC_OPCODE, NULL, NULL, 0, NULL,
1559    //   genericAnalyze,
1560    genericDestruct,
1561    genericPrint},
1562   POC_MOVF,
1563   "MOVF",
1564   2,
1565   NULL, // from branch
1566   NULL, // to branch
1567   NULL, // label
1568   NULL, // operand
1569   NULL, // flow block
1570   NULL, // C source
1571   3,    // num ops
1572   1,0,  // dest, bit instruction
1573   0,0,  // branch, skip
1574   0,    // literal operand
1575   1,    // RAM access bit
1576   0,    // fast call/return mode select bit
1577   0,    // second memory operand
1578   0,    // second literal operand
1579   POC_NOP,
1580   PCC_REGISTER,   // inCond
1581   (PCC_Z | PCC_N), // outCond
1582   PCI_MAGIC
1583 };
1584
1585 pCodeInstruction pic16_pciMOVFW = {
1586   {PC_OPCODE, NULL, NULL, 0, NULL,
1587    //   genericAnalyze,
1588    genericDestruct,
1589    genericPrint},
1590   POC_MOVFW,
1591   "MOVF",
1592   2,
1593   NULL, // from branch
1594   NULL, // to branch
1595   NULL, // label
1596   NULL, // operand
1597   NULL, // flow block
1598   NULL, // C source
1599   3,    // num ops
1600   0,0,  // dest, bit instruction
1601   0,0,  // branch, skip
1602   0,    // literal operand
1603   1,    // RAM access bit
1604   0,    // fast call/return mode select bit
1605   0,    // second memory operand
1606   0,    // second literal operand
1607   POC_NOP,
1608   PCC_REGISTER,   // inCond
1609   (PCC_W | PCC_N | PCC_Z), // outCond
1610   PCI_MAGIC
1611 };
1612
1613 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1614   {PC_OPCODE, NULL, NULL, 0, NULL,
1615    //   genericAnalyze,
1616    genericDestruct,
1617    genericPrint},
1618   POC_MOVFF,
1619   "MOVFF",
1620   4,
1621   NULL, // from branch
1622   NULL, // to branch
1623   NULL, // label
1624   NULL, // operand
1625   NULL, // flow block
1626   NULL, // C source
1627   2,    // num ops
1628   0,0,  // dest, bit instruction
1629   0,0,  // branch, skip
1630   0,    // literal operand
1631   0,    // RAM access bit
1632   0,    // fast call/return mode select bit
1633   1,    // second memory operand
1634   0,    // second literal operand
1635   POC_NOP,
1636   PCC_REGISTER,   // inCond
1637   PCC_REGISTER2, // outCond
1638   PCI_MAGIC
1639 };
1640
1641 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1642   {PC_OPCODE, NULL, NULL, 0, NULL,
1643    genericDestruct,
1644    genericPrint},
1645   POC_MOVLB,
1646   "MOVLB",
1647   2,
1648   NULL, // from branch
1649   NULL, // to branch
1650   NULL, // label
1651   NULL, // operand
1652   NULL, // flow block
1653   NULL, // C source
1654   1,    // num ops
1655   0,0,  // dest, bit instruction
1656   0,0,  // branch, skip
1657   1,    // literal operand
1658   0,    // RAM access bit
1659   0,    // fast call/return mode select bit
1660   0,    // second memory operand
1661   0,    // second literal operand
1662   POC_NOP,
1663   (PCC_NONE | PCC_LITERAL),   // inCond
1664   PCC_REGISTER, // outCond - BSR
1665   PCI_MAGIC
1666 };
1667
1668 pCodeInstruction pic16_pciMOVLW = {
1669   {PC_OPCODE, NULL, NULL, 0, NULL,
1670    genericDestruct,
1671    genericPrint},
1672   POC_MOVLW,
1673   "MOVLW",
1674   2,
1675   NULL, // from branch
1676   NULL, // to branch
1677   NULL, // label
1678   NULL, // operand
1679   NULL, // flow block
1680   NULL, // C source
1681   1,    // num ops
1682   0,0,  // dest, bit instruction
1683   0,0,  // branch, skip
1684   1,    // literal operand
1685   0,    // RAM access bit
1686   0,    // fast call/return mode select bit
1687   0,    // second memory operand
1688   0,    // second literal operand
1689   POC_NOP,
1690   (PCC_NONE | PCC_LITERAL),   // inCond
1691   PCC_W, // outCond
1692   PCI_MAGIC
1693 };
1694
1695 pCodeInstruction pic16_pciMOVWF = {
1696   {PC_OPCODE, NULL, NULL, 0, NULL,
1697    //   genericAnalyze,
1698    genericDestruct,
1699    genericPrint},
1700   POC_MOVWF,
1701   "MOVWF",
1702   2,
1703   NULL, // from branch
1704   NULL, // to branch
1705   NULL, // label
1706   NULL, // operand
1707   NULL, // flow block
1708   NULL, // C source
1709   2,    // num ops
1710   0,0,  // dest, bit instruction
1711   0,0,  // branch, skip
1712   0,    // literal operand
1713   1,    // RAM access bit
1714   0,    // fast call/return mode select bit
1715   0,    // second memory operand
1716   0,    // second literal operand
1717   POC_NOP,
1718   PCC_W,   // inCond
1719   PCC_REGISTER, // outCond
1720   PCI_MAGIC
1721 };
1722
1723 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1724   {PC_OPCODE, NULL, NULL, 0, NULL,
1725    genericDestruct,
1726    genericPrint},
1727   POC_MULLW,
1728   "MULLW",
1729   2,
1730   NULL, // from branch
1731   NULL, // to branch
1732   NULL, // label
1733   NULL, // operand
1734   NULL, // flow block
1735   NULL, // C source
1736   1,    // num ops
1737   0,0,  // dest, bit instruction
1738   0,0,  // branch, skip
1739   1,    // literal operand
1740   0,    // RAM access bit
1741   0,    // fast call/return mode select bit
1742   0,    // second memory operand
1743   0,    // second literal operand
1744   POC_NOP,
1745   (PCC_W | PCC_LITERAL),   // inCond
1746   PCC_NONE, // outCond - PROD
1747   PCI_MAGIC
1748 };
1749
1750 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1751   {PC_OPCODE, NULL, NULL, 0, NULL,
1752    genericDestruct,
1753    genericPrint},
1754   POC_MULWF,
1755   "MULWF",
1756   2,
1757   NULL, // from branch
1758   NULL, // to branch
1759   NULL, // label
1760   NULL, // operand
1761   NULL, // flow block
1762   NULL, // C source
1763   2,    // num ops
1764   0,0,  // dest, bit instruction
1765   0,0,  // branch, skip
1766   0,    // literal operand
1767   1,    // RAM access bit
1768   0,    // fast call/return mode select bit
1769   0,    // second memory operand
1770   0,    // second literal operand
1771   POC_NOP,
1772   (PCC_W | PCC_REGISTER),   // inCond
1773   PCC_REGISTER, // outCond - PROD
1774   PCI_MAGIC
1775 };
1776
1777 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1778   {PC_OPCODE, NULL, NULL, 0, NULL,
1779    genericDestruct,
1780    genericPrint},
1781   POC_NEGF,
1782   "NEGF",
1783   2,
1784   NULL, // from branch
1785   NULL, // to branch
1786   NULL, // label
1787   NULL, // operand
1788   NULL, // flow block
1789   NULL, // C source
1790   2,    // num ops
1791   0,0,  // dest, bit instruction
1792   0,0,  // branch, skip
1793   0,    // literal operand
1794   1,    // RAM access bit
1795   0,    // fast call/return mode select bit
1796   0,    // second memory operand
1797   0,    // second literal operand
1798   POC_NOP,
1799   PCC_REGISTER, // inCond
1800   (PCC_REGISTER | PCC_STATUS), // outCond
1801   PCI_MAGIC
1802 };
1803
1804 pCodeInstruction pic16_pciNOP = {
1805   {PC_OPCODE, NULL, NULL, 0, NULL,
1806    genericDestruct,
1807    genericPrint},
1808   POC_NOP,
1809   "NOP",
1810   2,
1811   NULL, // from branch
1812   NULL, // to branch
1813   NULL, // label
1814   NULL, // operand
1815   NULL, // flow block
1816   NULL, // C source
1817   0,    // num ops
1818   0,0,  // dest, bit instruction
1819   0,0,  // branch, skip
1820   0,    // literal operand
1821   0,    // RAM access bit
1822   0,    // fast call/return mode select bit
1823   0,    // second memory operand
1824   0,    // second literal operand
1825   POC_NOP,
1826   PCC_NONE,   // inCond
1827   PCC_NONE, // outCond
1828   PCI_MAGIC
1829 };
1830
1831 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1832   {PC_OPCODE, NULL, NULL, 0, NULL,
1833    genericDestruct,
1834    genericPrint},
1835   POC_POP,
1836   "POP",
1837   2,
1838   NULL, // from branch
1839   NULL, // to branch
1840   NULL, // label
1841   NULL, // operand
1842   NULL, // flow block
1843   NULL, // C source
1844   0,    // num ops
1845   0,0,  // dest, bit instruction
1846   0,0,  // branch, skip
1847   0,    // literal operand
1848   0,    // RAM access bit
1849   0,    // fast call/return mode select bit
1850   0,    // second memory operand
1851   0,    // second literal operand
1852   POC_NOP,
1853   PCC_NONE,  // inCond
1854   PCC_NONE  , // outCond
1855   PCI_MAGIC
1856 };
1857
1858 pCodeInstruction pic16_pciPUSH = {
1859   {PC_OPCODE, NULL, NULL, 0, NULL,
1860    genericDestruct,
1861    genericPrint},
1862   POC_PUSH,
1863   "PUSH",
1864   2,
1865   NULL, // from branch
1866   NULL, // to branch
1867   NULL, // label
1868   NULL, // operand
1869   NULL, // flow block
1870   NULL, // C source
1871   0,    // num ops
1872   0,0,  // dest, bit instruction
1873   0,0,  // branch, skip
1874   0,    // literal operand
1875   0,    // RAM access bit
1876   0,    // fast call/return mode select bit
1877   0,    // second memory operand
1878   0,    // second literal operand
1879   POC_NOP,
1880   PCC_NONE,  // inCond
1881   PCC_NONE  , // outCond
1882   PCI_MAGIC
1883 };
1884
1885 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1886   {PC_OPCODE, NULL, NULL, 0, NULL,
1887    genericDestruct,
1888    genericPrint},
1889   POC_RCALL,
1890   "RCALL",
1891   2,
1892   NULL, // from branch
1893   NULL, // to branch
1894   NULL, // label
1895   NULL, // operand
1896   NULL, // flow block
1897   NULL, // C source
1898   1,    // num ops
1899   0,0,  // dest, bit instruction
1900   1,0,  // branch, skip
1901   0,    // literal operand
1902   0,    // RAM access bit
1903   0,    // fast call/return mode select bit
1904   0,    // second memory operand
1905   0,    // second literal operand
1906   POC_NOP,
1907   PCC_REL_ADDR,  // inCond
1908   PCC_NONE  , // outCond
1909   PCI_MAGIC
1910 };
1911
1912 pCodeInstruction pic16_pciRETFIE = {
1913   {PC_OPCODE, NULL, NULL, 0, NULL,
1914    //   AnalyzeRETURN,
1915    genericDestruct,
1916    genericPrint},
1917   POC_RETFIE,
1918   "RETFIE",
1919   2,
1920   NULL, // from branch
1921   NULL, // to branch
1922   NULL, // label
1923   NULL, // operand
1924   NULL, // flow block
1925   NULL, // C source
1926   1,    // num ops
1927   0,0,  // dest, bit instruction
1928   1,0,  // branch, skip
1929   0,    // literal operand
1930   0,    // RAM access bit
1931   1,    // fast call/return mode select bit
1932   0,    // second memory operand
1933   0,    // second literal operand
1934   POC_NOP,
1935   PCC_NONE,   // inCond
1936   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1937   PCI_MAGIC
1938 };
1939
1940 pCodeInstruction pic16_pciRETLW = {
1941   {PC_OPCODE, NULL, NULL, 0, NULL,
1942    //   AnalyzeRETURN,
1943    genericDestruct,
1944    genericPrint},
1945   POC_RETLW,
1946   "RETLW",
1947   2,
1948   NULL, // from branch
1949   NULL, // to branch
1950   NULL, // label
1951   NULL, // operand
1952   NULL, // flow block
1953   NULL, // C source
1954   1,    // num ops
1955   0,0,  // dest, bit instruction
1956   1,0,  // branch, skip
1957   1,    // literal operand
1958   0,    // RAM access bit
1959   0,    // fast call/return mode select bit
1960   0,    // second memory operand
1961   0,    // second literal operand
1962   POC_NOP,
1963   PCC_LITERAL,   // inCond
1964   PCC_W, // outCond
1965   PCI_MAGIC
1966 };
1967
1968 pCodeInstruction pic16_pciRETURN = {
1969   {PC_OPCODE, NULL, NULL, 0, NULL,
1970    //   AnalyzeRETURN,
1971    genericDestruct,
1972    genericPrint},
1973   POC_RETURN,
1974   "RETURN",
1975   2,
1976   NULL, // from branch
1977   NULL, // to branch
1978   NULL, // label
1979   NULL, // operand
1980   NULL, // flow block
1981   NULL, // C source
1982   1,    // num ops
1983   0,0,  // dest, bit instruction
1984   1,0,  // branch, skip
1985   0,    // literal operand
1986   0,    // RAM access bit
1987   1,    // fast call/return mode select bit
1988   0,    // second memory operand
1989   0,    // second literal operand
1990   POC_NOP,
1991   PCC_NONE,   // inCond
1992   PCC_NONE, // outCond
1993   PCI_MAGIC
1994 };
1995 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1996   {PC_OPCODE, NULL, NULL, 0, NULL,
1997    //   genericAnalyze,
1998    genericDestruct,
1999    genericPrint},
2000   POC_RLCF,
2001   "RLCF",
2002   2,
2003   NULL, // from branch
2004   NULL, // to branch
2005   NULL, // label
2006   NULL, // operand
2007   NULL, // flow block
2008   NULL, // C source
2009   3,    // num ops
2010   1,0,  // dest, bit instruction
2011   0,0,  // branch, skip
2012   0,    // literal operand
2013   1,    // RAM access bit
2014   0,    // fast call/return mode select bit
2015   0,    // second memory operand
2016   0,    // second literal operand
2017   POC_NOP,
2018   (PCC_C | PCC_REGISTER),   // inCond
2019   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2020   PCI_MAGIC
2021 };
2022
2023 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2024   {PC_OPCODE, NULL, NULL, 0, NULL,
2025    //   genericAnalyze,
2026    genericDestruct,
2027    genericPrint},
2028   POC_RLCFW,
2029   "RLCF",
2030   2,
2031   NULL, // from branch
2032   NULL, // to branch
2033   NULL, // label
2034   NULL, // operand
2035   NULL, // flow block
2036   NULL, // C source
2037   3,    // num ops
2038   0,0,  // dest, bit instruction
2039   0,0,  // branch, skip
2040   0,    // literal operand
2041   1,    // RAM access bit
2042   0,    // fast call/return mode select bit
2043   0,    // second memory operand
2044   0,    // second literal operand
2045   POC_NOP,
2046   (PCC_C | PCC_REGISTER),   // inCond
2047   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2048   PCI_MAGIC
2049 };
2050
2051 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2052   {PC_OPCODE, NULL, NULL, 0, NULL,
2053    //   genericAnalyze,
2054    genericDestruct,
2055    genericPrint},
2056   POC_RLNCF,
2057   "RLNCF",
2058   2,
2059   NULL, // from branch
2060   NULL, // to branch
2061   NULL, // label
2062   NULL, // operand
2063   NULL, // flow block
2064   NULL, // C source
2065   3,    // num ops
2066   1,0,  // dest, bit instruction
2067   0,0,  // branch, skip
2068   0,    // literal operand
2069   1,    // RAM access bit
2070   0,    // fast call/return mode select bit
2071   0,    // second memory operand
2072   0,    // second literal operand
2073   POC_NOP,
2074   PCC_REGISTER,   // inCond
2075   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2076   PCI_MAGIC
2077 };
2078 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2079   {PC_OPCODE, NULL, NULL, 0, NULL,
2080    //   genericAnalyze,
2081    genericDestruct,
2082    genericPrint},
2083   POC_RLNCFW,
2084   "RLNCF",
2085   2,
2086   NULL, // from branch
2087   NULL, // to branch
2088   NULL, // label
2089   NULL, // operand
2090   NULL, // flow block
2091   NULL, // C source
2092   3,    // num ops
2093   0,0,  // dest, bit instruction
2094   0,0,  // branch, skip
2095   0,    // literal operand
2096   1,    // RAM access bit
2097   0,    // fast call/return mode select bit
2098   0,    // second memory operand
2099   0,    // second literal operand
2100   POC_NOP,
2101   PCC_REGISTER,   // inCond
2102   (PCC_W | PCC_Z | PCC_N), // outCond
2103   PCI_MAGIC
2104 };
2105 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2106   {PC_OPCODE, NULL, NULL, 0, NULL,
2107    //   genericAnalyze,
2108    genericDestruct,
2109    genericPrint},
2110   POC_RRCF,
2111   "RRCF",
2112   2,
2113   NULL, // from branch
2114   NULL, // to branch
2115   NULL, // label
2116   NULL, // operand
2117   NULL, // flow block
2118   NULL, // C source
2119   3,    // num ops
2120   1,0,  // dest, bit instruction
2121   0,0,  // branch, skip
2122   0,    // literal operand
2123   1,    // RAM access bit
2124   0,    // fast call/return mode select bit
2125   0,    // second memory operand
2126   0,    // second literal operand
2127   POC_NOP,
2128   (PCC_C | PCC_REGISTER),   // inCond
2129   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2130   PCI_MAGIC
2131 };
2132 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2133   {PC_OPCODE, NULL, NULL, 0, NULL,
2134    //   genericAnalyze,
2135    genericDestruct,
2136    genericPrint},
2137   POC_RRCFW,
2138   "RRCF",
2139   2,
2140   NULL, // from branch
2141   NULL, // to branch
2142   NULL, // label
2143   NULL, // operand
2144   NULL, // flow block
2145   NULL, // C source
2146   3,    // num ops
2147   0,0,  // dest, bit instruction
2148   0,0,  // branch, skip
2149   0,    // literal operand
2150   1,    // RAM access bit
2151   0,    // fast call/return mode select bit
2152   0,    // second memory operand
2153   0,    // second literal operand
2154   POC_NOP,
2155   (PCC_C | PCC_REGISTER),   // inCond
2156   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2157   PCI_MAGIC
2158 };
2159 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2160   {PC_OPCODE, NULL, NULL, 0, NULL,
2161    //   genericAnalyze,
2162    genericDestruct,
2163    genericPrint},
2164   POC_RRNCF,
2165   "RRNCF",
2166   2,
2167   NULL, // from branch
2168   NULL, // to branch
2169   NULL, // label
2170   NULL, // operand
2171   NULL, // flow block
2172   NULL, // C source
2173   3,    // num ops
2174   1,0,  // dest, bit instruction
2175   0,0,  // branch, skip
2176   0,    // literal operand
2177   1,    // RAM access bit
2178   0,    // fast call/return mode select bit
2179   0,    // second memory operand
2180   0,    // second literal operand
2181   POC_NOP,
2182   PCC_REGISTER,   // inCond
2183   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2184   PCI_MAGIC
2185 };
2186
2187 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2188   {PC_OPCODE, NULL, NULL, 0, NULL,
2189    //   genericAnalyze,
2190    genericDestruct,
2191    genericPrint},
2192   POC_RRNCFW,
2193   "RRNCF",
2194   2,
2195   NULL, // from branch
2196   NULL, // to branch
2197   NULL, // label
2198   NULL, // operand
2199   NULL, // flow block
2200   NULL, // C source
2201   3,    // num ops
2202   0,0,  // dest, bit instruction
2203   0,0,  // branch, skip
2204   0,    // literal operand
2205   1,    // RAM access bit
2206   0,    // fast call/return mode select bit
2207   0,    // second memory operand
2208   0,    // second literal operand
2209   POC_NOP,
2210   PCC_REGISTER,   // inCond
2211   (PCC_W | PCC_Z | PCC_N), // outCond
2212   PCI_MAGIC
2213 };
2214
2215 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2216   {PC_OPCODE, NULL, NULL, 0, NULL,
2217    //   genericAnalyze,
2218    genericDestruct,
2219    genericPrint},
2220   POC_SETF,
2221   "SETF",
2222   2,
2223   NULL, // from branch
2224   NULL, // to branch
2225   NULL, // label
2226   NULL, // operand
2227   NULL, // flow block
2228   NULL, // C source
2229   2,    // num ops
2230   0,0,  // dest, bit instruction
2231   0,0,  // branch, skip
2232   0,    // literal operand
2233   1,    // RAM access bit
2234   0,    // fast call/return mode select bit
2235   0,    // second memory operand
2236   0,    // second literal operand
2237   POC_NOP,
2238   PCC_NONE,  // inCond
2239   PCC_REGISTER  , // outCond
2240   PCI_MAGIC
2241 };
2242
2243 pCodeInstruction pic16_pciSUBLW = {
2244   {PC_OPCODE, NULL, NULL, 0, NULL,
2245    //   genericAnalyze,
2246    genericDestruct,
2247    genericPrint},
2248   POC_SUBLW,
2249   "SUBLW",
2250   2,
2251   NULL, // from branch
2252   NULL, // to branch
2253   NULL, // label
2254   NULL, // operand
2255   NULL, // flow block
2256   NULL, // C source
2257   1,    // num ops
2258   0,0,  // dest, bit instruction
2259   0,0,  // branch, skip
2260   1,    // literal operand
2261   0,    // RAM access bit
2262   0,    // fast call/return mode select bit
2263   0,    // second memory operand
2264   0,    // second literal operand
2265   POC_NOP,
2266   (PCC_W | PCC_LITERAL),   // inCond
2267   (PCC_W | PCC_STATUS), // outCond
2268   PCI_MAGIC
2269 };
2270
2271 pCodeInstruction pic16_pciSUBFWB = {
2272   {PC_OPCODE, NULL, NULL, 0, NULL,
2273    //   genericAnalyze,
2274    genericDestruct,
2275    genericPrint},
2276   POC_SUBFWB,
2277   "SUBFWB",
2278   2,
2279   NULL, // from branch
2280   NULL, // to branch
2281   NULL, // label
2282   NULL, // operand
2283   NULL, // flow block
2284   NULL, // C source
2285   3,    // num ops
2286   1,0,  // dest, bit instruction
2287   0,0,  // branch, skip
2288   0,    // literal operand
2289   1,    // RAM access bit
2290   0,    // fast call/return mode select bit
2291   0,    // second memory operand
2292   0,    // second literal operand
2293   POC_NOP,
2294   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2295   (PCC_W | PCC_STATUS), // outCond
2296   PCI_MAGIC
2297 };
2298
2299 pCodeInstruction pic16_pciSUBWF = {
2300   {PC_OPCODE, NULL, NULL, 0, NULL,
2301    //   genericAnalyze,
2302    genericDestruct,
2303    genericPrint},
2304   POC_SUBWF,
2305   "SUBWF",
2306   2,
2307   NULL, // from branch
2308   NULL, // to branch
2309   NULL, // label
2310   NULL, // operand
2311   NULL, // flow block
2312   NULL, // C source
2313   3,    // num ops
2314   1,0,  // dest, bit instruction
2315   0,0,  // branch, skip
2316   0,    // literal operand
2317   1,    // RAM access bit
2318   0,    // fast call/return mode select bit
2319   0,    // second memory operand
2320   0,    // second literal operand
2321   POC_NOP,
2322   (PCC_W | PCC_REGISTER),   // inCond
2323   (PCC_REGISTER | PCC_STATUS), // outCond
2324   PCI_MAGIC
2325 };
2326
2327 pCodeInstruction pic16_pciSUBFW = {
2328   {PC_OPCODE, NULL, NULL, 0, NULL,
2329    //   genericAnalyze,
2330    genericDestruct,
2331    genericPrint},
2332   POC_SUBFW,
2333   "SUBWF",
2334   2,
2335   NULL, // from branch
2336   NULL, // to branch
2337   NULL, // label
2338   NULL, // operand
2339   NULL, // flow block
2340   NULL, // C source
2341   3,    // num ops
2342   0,0,  // dest, bit instruction
2343   0,0,  // branch, skip
2344   0,    // literal operand
2345   1,    // RAM access bit
2346   0,    // fast call/return mode select bit
2347   0,    // second memory operand
2348   0,    // second literal operand
2349   POC_NOP,
2350   (PCC_W | PCC_REGISTER),   // inCond
2351   (PCC_W | PCC_STATUS), // outCond
2352   PCI_MAGIC
2353 };
2354
2355 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2356   {PC_OPCODE, NULL, NULL, 0, NULL,
2357    //   genericAnalyze,
2358    genericDestruct,
2359    genericPrint},
2360   POC_SUBFWB_D1,
2361   "SUBFWB",
2362   2,
2363   NULL, // from branch
2364   NULL, // to branch
2365   NULL, // label
2366   NULL, // operand
2367   NULL, // flow block
2368   NULL, // C source
2369   3,    // num ops
2370   1,0,  // dest, bit instruction
2371   0,0,  // branch, skip
2372   0,    // literal operand
2373   1,    // RAM access bit
2374   0,    // fast call/return mode select bit
2375   0,    // second memory operand
2376   0,    // second literal operand
2377   POC_NOP,
2378   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2379   (PCC_REGISTER | PCC_STATUS), // outCond
2380   PCI_MAGIC
2381 };
2382
2383 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2384   {PC_OPCODE, NULL, NULL, 0, NULL,
2385    //   genericAnalyze,
2386    genericDestruct,
2387    genericPrint},
2388   POC_SUBFWB_D0,
2389   "SUBFWB",
2390   2,
2391   NULL, // from branch
2392   NULL, // to branch
2393   NULL, // label
2394   NULL, // operand
2395   NULL, // flow block
2396   NULL, // C source
2397   3,    // num ops
2398   0,0,  // dest, bit instruction
2399   0,0,  // branch, skip
2400   0,    // literal operand
2401   1,    // RAM access bit
2402   0,    // fast call/return mode select bit
2403   0,    // second memory operand
2404   0,    // second literal operand
2405   POC_NOP,
2406   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2407   (PCC_W | PCC_STATUS), // outCond
2408   PCI_MAGIC
2409 };
2410
2411 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2412   {PC_OPCODE, NULL, NULL, 0, NULL,
2413    //   genericAnalyze,
2414    genericDestruct,
2415    genericPrint},
2416   POC_SUBWFB_D1,
2417   "SUBWFB",
2418   2,
2419   NULL, // from branch
2420   NULL, // to branch
2421   NULL, // label
2422   NULL, // operand
2423   NULL, // flow block
2424   NULL, // C source
2425   3,    // num ops
2426   1,0,  // dest, bit instruction
2427   0,0,  // branch, skip
2428   0,    // literal operand
2429   1,    // RAM access bit
2430   0,    // fast call/return mode select bit
2431   0,    // second memory operand
2432   0,    // second literal operand
2433   POC_NOP,
2434   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2435   (PCC_REGISTER | PCC_STATUS), // outCond
2436   PCI_MAGIC
2437 };
2438
2439 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2440   {PC_OPCODE, NULL, NULL, 0, NULL,
2441    //   genericAnalyze,
2442    genericDestruct,
2443    genericPrint},
2444   POC_SUBWFB_D0,
2445   "SUBWFB",
2446   2,
2447   NULL, // from branch
2448   NULL, // to branch
2449   NULL, // label
2450   NULL, // operand
2451   NULL, // flow block
2452   NULL, // C source
2453   3,    // num ops
2454   0,0,  // dest, bit instruction
2455   0,0,  // branch, skip
2456   0,    // literal operand
2457   1,    // RAM access bit
2458   0,    // fast call/return mode select bit
2459   0,    // second memory operand
2460   0,    // second literal operand
2461   POC_NOP,
2462   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2463   (PCC_W | PCC_STATUS), // outCond
2464   PCI_MAGIC
2465 };
2466
2467 pCodeInstruction pic16_pciSWAPF = {
2468   {PC_OPCODE, NULL, NULL, 0, NULL,
2469    //   genericAnalyze,
2470    genericDestruct,
2471    genericPrint},
2472   POC_SWAPF,
2473   "SWAPF",
2474   2,
2475   NULL, // from branch
2476   NULL, // to branch
2477   NULL, // label
2478   NULL, // operand
2479   NULL, // flow block
2480   NULL, // C source
2481   3,    // num ops
2482   1,0,  // dest, bit instruction
2483   0,0,  // branch, skip
2484   0,    // literal operand
2485   1,    // RAM access bit
2486   0,    // fast call/return mode select bit
2487   0,    // second memory operand
2488   0,    // second literal operand
2489   POC_NOP,
2490   (PCC_REGISTER),   // inCond
2491   (PCC_REGISTER), // outCond
2492   PCI_MAGIC
2493 };
2494
2495 pCodeInstruction pic16_pciSWAPFW = {
2496   {PC_OPCODE, NULL, NULL, 0, NULL,
2497    //   genericAnalyze,
2498    genericDestruct,
2499    genericPrint},
2500   POC_SWAPFW,
2501   "SWAPF",
2502   2,
2503   NULL, // from branch
2504   NULL, // to branch
2505   NULL, // label
2506   NULL, // operand
2507   NULL, // flow block
2508   NULL, // C source
2509   3,    // num ops
2510   0,0,  // dest, bit instruction
2511   0,0,  // branch, skip
2512   0,    // literal operand
2513   1,    // RAM access bit
2514   0,    // fast call/return mode select bit
2515   0,    // second memory operand
2516   0,    // second literal operand
2517   POC_NOP,
2518   (PCC_REGISTER),   // inCond
2519   (PCC_W), // outCond
2520   PCI_MAGIC
2521 };
2522
2523 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2524   {PC_OPCODE, NULL, NULL, 0, NULL,
2525    genericDestruct,
2526    genericPrint},
2527   POC_TBLRD,
2528   "TBLRD*",
2529   2,
2530   NULL, // from branch
2531   NULL, // to branch
2532   NULL, // label
2533   NULL, // operand
2534   NULL, // flow block
2535   NULL, // C source
2536   0,    // num ops
2537   0,0,  // dest, bit instruction
2538   0,0,  // branch, skip
2539   0,    // literal operand
2540   0,    // RAM access bit
2541   0,    // fast call/return mode select bit
2542   0,    // second memory operand
2543   0,    // second literal operand
2544   POC_NOP,
2545   PCC_NONE,  // inCond
2546   PCC_NONE  , // outCond
2547   PCI_MAGIC
2548 };
2549
2550 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2551   {PC_OPCODE, NULL, NULL, 0, NULL,
2552    genericDestruct,
2553    genericPrint},
2554   POC_TBLRD_POSTINC,
2555   "TBLRD*+",
2556   2,
2557   NULL, // from branch
2558   NULL, // to branch
2559   NULL, // label
2560   NULL, // operand
2561   NULL, // flow block
2562   NULL, // C source
2563   0,    // num ops
2564   0,0,  // dest, bit instruction
2565   0,0,  // branch, skip
2566   0,    // literal operand
2567   0,    // RAM access bit
2568   0,    // fast call/return mode select bit
2569   0,    // second memory operand
2570   0,    // second literal operand
2571   POC_NOP,
2572   PCC_NONE,  // inCond
2573   PCC_NONE  , // outCond
2574   PCI_MAGIC
2575 };
2576
2577 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2578   {PC_OPCODE, NULL, NULL, 0, NULL,
2579    genericDestruct,
2580    genericPrint},
2581   POC_TBLRD_POSTDEC,
2582   "TBLRD*-",
2583   2,
2584   NULL, // from branch
2585   NULL, // to branch
2586   NULL, // label
2587   NULL, // operand
2588   NULL, // flow block
2589   NULL, // C source
2590   0,    // num ops
2591   0,0,  // dest, bit instruction
2592   0,0,  // branch, skip
2593   0,    // literal operand
2594   0,    // RAM access bit
2595   0,    // fast call/return mode select bit
2596   0,    // second memory operand
2597   0,    // second literal operand
2598   POC_NOP,
2599   PCC_NONE,  // inCond
2600   PCC_NONE  , // outCond
2601   PCI_MAGIC
2602 };
2603
2604 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2605   {PC_OPCODE, NULL, NULL, 0, NULL,
2606    genericDestruct,
2607    genericPrint},
2608   POC_TBLRD_PREINC,
2609   "TBLRD+*",
2610   2,
2611   NULL, // from branch
2612   NULL, // to branch
2613   NULL, // label
2614   NULL, // operand
2615   NULL, // flow block
2616   NULL, // C source
2617   0,    // num ops
2618   0,0,  // dest, bit instruction
2619   0,0,  // branch, skip
2620   0,    // literal operand
2621   0,    // RAM access bit
2622   0,    // fast call/return mode select bit
2623   0,    // second memory operand
2624   0,    // second literal operand
2625   POC_NOP,
2626   PCC_NONE,  // inCond
2627   PCC_NONE  , // outCond
2628   PCI_MAGIC
2629 };
2630
2631 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2632   {PC_OPCODE, NULL, NULL, 0, NULL,
2633    genericDestruct,
2634    genericPrint},
2635   POC_TBLWT,
2636   "TBLWT*",
2637   2,
2638   NULL, // from branch
2639   NULL, // to branch
2640   NULL, // label
2641   NULL, // operand
2642   NULL, // flow block
2643   NULL, // C source
2644   0,    // num ops
2645   0,0,  // dest, bit instruction
2646   0,0,  // branch, skip
2647   0,    // literal operand
2648   0,    // RAM access bit
2649   0,    // fast call/return mode select bit
2650   0,    // second memory operand
2651   0,    // second literal operand
2652   POC_NOP,
2653   PCC_NONE,  // inCond
2654   PCC_NONE  , // outCond
2655   PCI_MAGIC
2656 };
2657
2658 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2659   {PC_OPCODE, NULL, NULL, 0, NULL,
2660    genericDestruct,
2661    genericPrint},
2662   POC_TBLWT_POSTINC,
2663   "TBLWT*+",
2664   2,
2665   NULL, // from branch
2666   NULL, // to branch
2667   NULL, // label
2668   NULL, // operand
2669   NULL, // flow block
2670   NULL, // C source
2671   0,    // num ops
2672   0,0,  // dest, bit instruction
2673   0,0,  // branch, skip
2674   0,    // literal operand
2675   0,    // RAM access bit
2676   0,    // fast call/return mode select bit
2677   0,    // second memory operand
2678   0,    // second literal operand
2679   POC_NOP,
2680   PCC_NONE,  // inCond
2681   PCC_NONE  , // outCond
2682   PCI_MAGIC
2683 };
2684
2685 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2686   {PC_OPCODE, NULL, NULL, 0, NULL,
2687    genericDestruct,
2688    genericPrint},
2689   POC_TBLWT_POSTDEC,
2690   "TBLWT*-",
2691   2,
2692   NULL, // from branch
2693   NULL, // to branch
2694   NULL, // label
2695   NULL, // operand
2696   NULL, // flow block
2697   NULL, // C source
2698   0,    // num ops
2699   0,0,  // dest, bit instruction
2700   0,0,  // branch, skip
2701   0,    // literal operand
2702   0,    // RAM access bit
2703   0,    // fast call/return mode select bit
2704   0,    // second memory operand
2705   0,    // second literal operand
2706   POC_NOP,
2707   PCC_NONE,  // inCond
2708   PCC_NONE  , // outCond
2709   PCI_MAGIC
2710 };
2711
2712 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2713   {PC_OPCODE, NULL, NULL, 0, NULL,
2714    genericDestruct,
2715    genericPrint},
2716   POC_TBLWT_PREINC,
2717   "TBLWT+*",
2718   2,
2719   NULL, // from branch
2720   NULL, // to branch
2721   NULL, // label
2722   NULL, // operand
2723   NULL, // flow block
2724   NULL, // C source
2725   0,    // num ops
2726   0,0,  // dest, bit instruction
2727   0,0,  // branch, skip
2728   0,    // literal operand
2729   0,    // RAM access bit
2730   0,    // fast call/return mode select bit
2731   0,    // second memory operand
2732   0,    // second literal operand
2733   POC_NOP,
2734   PCC_NONE,  // inCond
2735   PCC_NONE  , // outCond
2736   PCI_MAGIC
2737 };
2738
2739 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2740   {PC_OPCODE, NULL, NULL, 0, NULL,
2741    //   genericAnalyze,
2742    genericDestruct,
2743    genericPrint},
2744   POC_TSTFSZ,
2745   "TSTFSZ",
2746   2,
2747   NULL, // from branch
2748   NULL, // to branch
2749   NULL, // label
2750   NULL, // operand
2751   NULL, // flow block
2752   NULL, // C source
2753   2,    // num ops
2754   0,0,  // dest, bit instruction
2755   1,1,  // branch, skip
2756   0,    // literal operand
2757   1,    // RAM access bit
2758   0,    // fast call/return mode select bit
2759   0,    // second memory operand
2760   0,    // second literal operand
2761   POC_NOP,
2762   PCC_REGISTER,   // inCond
2763   PCC_NONE, // outCond
2764   PCI_MAGIC
2765 };
2766
2767 pCodeInstruction pic16_pciXORWF = {
2768   {PC_OPCODE, NULL, NULL, 0, NULL,
2769    //   genericAnalyze,
2770    genericDestruct,
2771    genericPrint},
2772   POC_XORWF,
2773   "XORWF",
2774   2,
2775   NULL, // from branch
2776   NULL, // to branch
2777   NULL, // label
2778   NULL, // operand
2779   NULL, // flow block
2780   NULL, // C source
2781   3,    // num ops
2782   1,0,  // dest, bit instruction
2783   0,0,  // branch, skip
2784   0,    // literal operand
2785   1,    // RAM access bit
2786   0,    // fast call/return mode select bit
2787   0,    // second memory operand
2788   0,    // second literal operand
2789   POC_NOP,
2790   (PCC_W | PCC_REGISTER),   // inCond
2791   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2792   PCI_MAGIC
2793 };
2794
2795 pCodeInstruction pic16_pciXORFW = {
2796   {PC_OPCODE, NULL, NULL, 0, NULL,
2797    //   genericAnalyze,
2798    genericDestruct,
2799    genericPrint},
2800   POC_XORFW,
2801   "XORWF",
2802   2,
2803   NULL, // from branch
2804   NULL, // to branch
2805   NULL, // label
2806   NULL, // operand
2807   NULL, // flow block
2808   NULL, // C source
2809   3,    // num ops
2810   0,0,  // dest, bit instruction
2811   0,0,  // branch, skip
2812   0,    // literal operand
2813   1,    // RAM access bit
2814   0,    // fast call/return mode select bit
2815   0,    // second memory operand
2816   0,    // second literal operand
2817   POC_NOP,
2818   (PCC_W | PCC_REGISTER),   // inCond
2819   (PCC_W | PCC_Z | PCC_N), // outCond
2820   PCI_MAGIC
2821 };
2822
2823 pCodeInstruction pic16_pciXORLW = {
2824   {PC_OPCODE, NULL, NULL, 0, NULL,
2825    //   genericAnalyze,
2826    genericDestruct,
2827    genericPrint},
2828   POC_XORLW,
2829   "XORLW",
2830   2,
2831   NULL, // from branch
2832   NULL, // to branch
2833   NULL, // label
2834   NULL, // operand
2835   NULL, // flow block
2836   NULL, // C source
2837   1,    // num ops
2838   0,0,  // dest, bit instruction
2839   0,0,  // branch, skip
2840   1,    // literal operand
2841   1,    // RAM access bit
2842   0,    // fast call/return mode select bit
2843   0,    // second memory operand
2844   0,    // second literal operand
2845   POC_NOP,
2846   (PCC_W | PCC_LITERAL),   // inCond
2847   (PCC_W | PCC_Z | PCC_N), // outCond
2848   PCI_MAGIC
2849 };
2850
2851
2852 pCodeInstruction pic16_pciBANKSEL = {
2853   {PC_OPCODE, NULL, NULL, 0, NULL,
2854    genericDestruct,
2855    genericPrint},
2856   POC_BANKSEL,
2857   "BANKSEL",
2858   2,
2859   NULL, // from branch
2860   NULL, // to branch
2861   NULL, // label
2862   NULL, // operand
2863   NULL, // flow block
2864   NULL, // C source
2865   0,    // num ops
2866   0,0,  // dest, bit instruction
2867   0,0,  // branch, skip
2868   0,    // literal operand
2869   0,    // RAM access bit
2870   0,    // fast call/return mode select bit
2871   0,    // second memory operand
2872   0,    // second literal operand
2873   POC_NOP,
2874   PCC_NONE,   // inCond
2875   PCC_NONE, // outCond
2876   PCI_MAGIC
2877 };
2878
2879
2880 #define MAX_PIC16MNEMONICS 100
2881 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2882
2883 extern set *externs;
2884 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2885 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2886
2887 void  pic16_pCodeInitRegisters(void)
2888 {
2889   static int initialized=0;
2890
2891         if(initialized)
2892                 return;
2893
2894         initialized = 1;
2895
2896         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2897         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2898         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2899         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2900         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2901         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2902         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2903
2904         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2905         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2906         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2907
2908         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2909         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2910         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2911         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2912
2913         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2914         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2915         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2916         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2917         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2918         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2919
2920         pic16_stackpnt_lo = &pic16_pc_fsr1l;
2921         pic16_stackpnt_hi = &pic16_pc_fsr1h;
2922         pic16_stack_postdec = &pic16_pc_postdec1;
2923         pic16_stack_postinc = &pic16_pc_postinc1;
2924         pic16_stack_preinc = &pic16_pc_preinc1;
2925         pic16_stack_plusw = &pic16_pc_plusw1;
2926
2927         pic16_framepnt_lo = &pic16_pc_fsr2l;
2928         pic16_framepnt_hi = &pic16_pc_fsr2h;
2929         pic16_frame_postdec = &pic16_pc_postdec2;
2930         pic16_frame_postinc = &pic16_pc_postinc2;
2931         pic16_frame_preinc = &pic16_pc_preinc2;
2932         pic16_frame_plusw = &pic16_pc_plusw2;
2933
2934         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
2935         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
2936         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
2937         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
2938         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
2939
2940         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
2941         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
2942         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
2943         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
2944         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
2945
2946         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
2947         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
2948         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
2949         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
2950         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
2951
2952         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
2953         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
2954
2955
2956         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
2957         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
2958         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
2959         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
2960
2961
2962         pic16_pc_status.rIdx = IDX_STATUS;
2963         pic16_pc_intcon.rIdx = IDX_INTCON;
2964         pic16_pc_pcl.rIdx = IDX_PCL;
2965         pic16_pc_pclath.rIdx = IDX_PCLATH;
2966         pic16_pc_pclatu.rIdx = IDX_PCLATU;
2967         pic16_pc_wreg.rIdx = IDX_WREG;
2968         pic16_pc_bsr.rIdx = IDX_BSR;
2969
2970         pic16_pc_tosl.rIdx = IDX_TOSL;
2971         pic16_pc_tosh.rIdx = IDX_TOSH;
2972         pic16_pc_tosu.rIdx = IDX_TOSU;
2973
2974         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
2975         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
2976         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
2977         pic16_pc_tablat.rIdx = IDX_TABLAT;
2978
2979         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
2980         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
2981         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
2982         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
2983         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
2984         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
2985         pic16_pc_indf0.rIdx = IDX_INDF0;
2986         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
2987         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
2988         pic16_pc_preinc0.rIdx = IDX_PREINC0;
2989         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
2990         pic16_pc_indf1.rIdx = IDX_INDF1;
2991         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
2992         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
2993         pic16_pc_preinc1.rIdx = IDX_PREINC1;
2994         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
2995         pic16_pc_indf2.rIdx = IDX_INDF2;
2996         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
2997         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
2998         pic16_pc_preinc2.rIdx = IDX_PREINC2;
2999         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3000         pic16_pc_prodl.rIdx = IDX_PRODL;
3001         pic16_pc_prodh.rIdx = IDX_PRODH;
3002
3003         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3004         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3005         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3006
3007         pic16_pc_kzero.rIdx = IDX_KZ;
3008         pic16_pc_wsave.rIdx = IDX_WSAVE;
3009         pic16_pc_ssave.rIdx = IDX_SSAVE;
3010
3011         pic16_pc_eecon1.rIdx = IDX_EECON1;
3012         pic16_pc_eecon2.rIdx = IDX_EECON2;
3013         pic16_pc_eedata.rIdx = IDX_EEDATA;
3014         pic16_pc_eeadr.rIdx = IDX_EEADR;
3015
3016
3017         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3018         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3019
3020         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3021         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3022
3023         /* probably should put this in a separate initialization routine */
3024         pb_dead_pcodes = newpBlock();
3025
3026 }
3027
3028 /*-----------------------------------------------------------------*/
3029 /*  mnem2key - convert a pic mnemonic into a hash key              */
3030 /*   (BTW - this spreads the mnemonics quite well)                 */
3031 /*                                                                 */
3032 /*-----------------------------------------------------------------*/
3033
3034 static int mnem2key(unsigned char const *mnem)
3035 {
3036   int key = 0;
3037
3038   if(!mnem)
3039     return 0;
3040
3041   while(*mnem) {
3042
3043     key += toupper(*mnem++) +1;
3044
3045   }
3046
3047   return (key & 0x1f);
3048
3049 }
3050
3051 void pic16initMnemonics(void)
3052 {
3053   int i = 0;
3054   int key;
3055   //  char *str;
3056   pCodeInstruction *pci;
3057
3058   if(mnemonics_initialized)
3059     return;
3060
3061   // NULL out the array before making the assignments
3062   // since we check the array contents below this initialization.
3063
3064   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3065     pic16Mnemonics[i] = NULL;
3066   }
3067
3068   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3069   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3070   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3071   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3072   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3073   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3074   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3075   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3076   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3077   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3078   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3079   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3080   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3081   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3082   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3083   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3084   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3085   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3086   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3087   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3088   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3089   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3090   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3091   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3092   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3093   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3094   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3095   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3096   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3097   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3098   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3099   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3100   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3101   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3102   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3103   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3104   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3105   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3106   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3107   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3108   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3109   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3110   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3111   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3112   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3113   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3114   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3115   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3116   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3117   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3118   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3119   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3120   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3121   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3122   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3123   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3124   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3125   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3126   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3127   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3128   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3129   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3130   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3131   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3132   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3133   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3134   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3135   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3136   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3137   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3138   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3139   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3140   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3141   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3142   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3143   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3144   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3145   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3146   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3147   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3148   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3149   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3150   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3151   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3152   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3153   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3154   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3155   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3156   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3157   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3158   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3159   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3160   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3161   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3162
3163   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3164     if(pic16Mnemonics[i])
3165       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3166   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3167
3168   while(pci) {
3169     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3170     pci = hTabNextItem(pic16MnemonicsHash, &key);
3171   }
3172
3173   mnemonics_initialized = 1;
3174 }
3175
3176 int pic16_getpCodePeepCommand(char *cmd);
3177
3178 int pic16_getpCode(char *mnem,unsigned dest)
3179 {
3180
3181   pCodeInstruction *pci;
3182   int key = mnem2key((unsigned char *)mnem);
3183
3184   if(!mnemonics_initialized)
3185     pic16initMnemonics();
3186
3187   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3188
3189   while(pci) {
3190
3191     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3192       if((pci->num_ops <= 1)
3193         || (pci->isModReg == dest)
3194         || (pci->isBitInst)
3195         || (pci->num_ops <= 2 && pci->isAccess)
3196         || (pci->num_ops <= 2 && pci->isFastCall)
3197         || (pci->num_ops <= 2 && pci->is2MemOp)
3198         || (pci->num_ops <= 2 && pci->is2LitOp) )
3199         return(pci->op);
3200     }
3201
3202     pci = hTabNextItemWK (pic16MnemonicsHash);
3203
3204   }
3205
3206   return -1;
3207 }
3208
3209 /*-----------------------------------------------------------------*
3210  * pic16initpCodePeepCommands
3211  *
3212  *-----------------------------------------------------------------*/
3213 void pic16initpCodePeepCommands(void)
3214 {
3215
3216   int key, i;
3217   peepCommand *pcmd;
3218
3219   i = 0;
3220   do {
3221     hTabAddItem(&pic16pCodePeepCommandsHash,
3222                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3223     i++;
3224   } while (peepCommands[i].cmd);
3225
3226   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3227
3228   while(pcmd) {
3229     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3230     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3231   }
3232
3233 }
3234
3235 /*-----------------------------------------------------------------
3236  *
3237  *
3238  *-----------------------------------------------------------------*/
3239
3240 int pic16_getpCodePeepCommand(char *cmd)
3241 {
3242
3243   peepCommand *pcmd;
3244   int key = mnem2key((unsigned char *)cmd);
3245
3246
3247   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3248
3249   while(pcmd) {
3250     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3251     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3252       return pcmd->id;
3253     }
3254
3255     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3256
3257   }
3258
3259   return -1;
3260 }
3261
3262 static char getpBlock_dbName(pBlock *pb)
3263 {
3264   if(!pb)
3265     return 0;
3266
3267   if(pb->cmemmap)
3268     return pb->cmemmap->dbName;
3269
3270   return pb->dbName;
3271 }
3272 void pic16_pBlockConvert2ISR(pBlock *pb)
3273 {
3274         if(!pb)return;
3275
3276         if(pb->cmemmap)pb->cmemmap = NULL;
3277
3278         pb->dbName = 'I';
3279
3280         if(pic16_pcode_verbose)
3281                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3282 }
3283
3284 void pic16_pBlockConvert2Absolute(pBlock *pb)
3285 {
3286         if(!pb)return;
3287         if(pb->cmemmap)pb->cmemmap = NULL;
3288
3289         pb->dbName = 'A';
3290
3291         if(pic16_pcode_verbose)
3292                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3293 }
3294
3295 /*-----------------------------------------------------------------*/
3296 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3297 /*                   instances to the front of the doubly linked   */
3298 /*                   list of pBlocks                               */
3299 /*-----------------------------------------------------------------*/
3300
3301 void pic16_movepBlock2Head(char dbName)
3302 {
3303   pBlock *pb;
3304
3305
3306   /* this can happen in sources without code,
3307    * only variable definitions */
3308   if(!the_pFile)return;
3309
3310   pb = the_pFile->pbHead;
3311
3312   while(pb) {
3313
3314     if(getpBlock_dbName(pb) == dbName) {
3315       pBlock *pbn = pb->next;
3316       pb->next = the_pFile->pbHead;
3317       the_pFile->pbHead->prev = pb;
3318       the_pFile->pbHead = pb;
3319
3320       if(pb->prev)
3321         pb->prev->next = pbn;
3322
3323       // If the pBlock that we just moved was the last
3324       // one in the link of all of the pBlocks, then we
3325       // need to point the tail to the block just before
3326       // the one we moved.
3327       // Note: if pb->next is NULL, then pb must have
3328       // been the last pBlock in the chain.
3329
3330       if(pbn)
3331         pbn->prev = pb->prev;
3332       else
3333         the_pFile->pbTail = pb->prev;
3334
3335       pb = pbn;
3336
3337     } else
3338       pb = pb->next;
3339
3340   }
3341
3342 }
3343
3344 void pic16_copypCode(FILE *of, char dbName)
3345 {
3346   pBlock *pb;
3347
3348         if(!of || !the_pFile)
3349                 return;
3350
3351         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3352                 if(getpBlock_dbName(pb) == dbName) {
3353 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3354                         pBlockStats(of,pb);
3355                         pic16_printpBlock(of,pb);
3356                 }
3357         }
3358
3359 }
3360 void pic16_pcode_test(void)
3361 {
3362
3363   DFPRINTF((stderr,"pcode is alive!\n"));
3364
3365   //initMnemonics();
3366
3367   if(the_pFile) {
3368
3369     pBlock *pb;
3370     FILE *pFile;
3371     char buffer[100];
3372
3373     /* create the file name */
3374     strcpy(buffer,dstFileName);
3375     strcat(buffer,".p");
3376
3377     if( !(pFile = fopen(buffer, "w" ))) {
3378       werror(E_FILE_OPEN_ERR,buffer);
3379       exit(1);
3380     }
3381
3382     fprintf(pFile,"pcode dump\n\n");
3383
3384     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3385       fprintf(pFile,"\n\tNew pBlock\n\n");
3386       if(pb->cmemmap)
3387         fprintf(pFile,"%s",pb->cmemmap->sname);
3388       else
3389         fprintf(pFile,"internal pblock");
3390
3391       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3392       pic16_printpBlock(pFile,pb);
3393     }
3394   }
3395 }
3396
3397
3398 unsigned long pic16_countInstructions(void)
3399 {
3400   pBlock *pb;
3401   pCode *pc;
3402   unsigned long isize=0;
3403
3404     if(!the_pFile)return -1;
3405
3406     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3407       for(pc = pb->pcHead; pc; pc = pc->next) {
3408         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3409       }
3410     }
3411   return (isize);
3412 }
3413
3414
3415 /*-----------------------------------------------------------------*/
3416 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3417 /*      ister, RegCond will return the bit being referenced.       */
3418 /*                                                                 */
3419 /* fixme - why not just OR in the pcop bit field                   */
3420 /*-----------------------------------------------------------------*/
3421
3422 static int RegCond(pCodeOp *pcop)
3423 {
3424
3425   if(!pcop)
3426     return 0;
3427
3428   if(!pcop->name)return 0;
3429
3430   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3431     switch(PCORB(pcop)->bit) {
3432     case PIC_C_BIT:
3433       return PCC_C;
3434     case PIC_DC_BIT:
3435         return PCC_DC;
3436     case PIC_Z_BIT:
3437       return PCC_Z;
3438     }
3439
3440   }
3441
3442   return 0;
3443 }
3444
3445
3446 /*-----------------------------------------------------------------*/
3447 /* pic16_newpCode - create and return a newly initialized pCode          */
3448 /*                                                                 */
3449 /*  fixme - rename this                                            */
3450 /*                                                                 */
3451 /* The purpose of this routine is to create a new Instruction      */
3452 /* pCode. This is called by gen.c while the assembly code is being */
3453 /* generated.                                                      */
3454 /*                                                                 */
3455 /* Inouts:                                                         */
3456 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3457 /*                  (note that the op is analogous to but not the  */
3458 /*                  same thing as the opcode of the instruction.)  */
3459 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3460 /*                                                                 */
3461 /* Outputs:                                                        */
3462 /*  a pointer to the new malloc'd pCode is returned.               */
3463 /*                                                                 */
3464 /*                                                                 */
3465 /*                                                                 */
3466 /*-----------------------------------------------------------------*/
3467 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3468 {
3469   pCodeInstruction *pci ;
3470
3471   if(!mnemonics_initialized)
3472     pic16initMnemonics();
3473
3474   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3475
3476   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3477     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3478     pci->pcop = pcop;
3479
3480     if(pci->inCond & PCC_EXAMINE_PCOP)
3481       pci->inCond  |= RegCond(pcop);
3482
3483     if(pci->outCond & PCC_EXAMINE_PCOP)
3484       pci->outCond  |= RegCond(pcop);
3485
3486     pci->pc.prev = pci->pc.next = NULL;
3487     return (pCode *)pci;
3488   }
3489
3490   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3491   exit(1);
3492
3493   return NULL;
3494 }
3495
3496 /*-----------------------------------------------------------------*/
3497 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3498 /*                                                                 */
3499 /* Wild pcodes are used during the peep hole optimizer to serve    */
3500 /* as place holders for any instruction. When a snippet of code is */
3501 /* compared to a peep hole rule, the wild card opcode will match   */
3502 /* any instruction. However, the optional operand and label are    */
3503 /* additional qualifiers that must also be matched before the      */
3504 /* line (of assembly code) is declared matched. Note that the      */
3505 /* operand may be wild too.                                        */
3506 /*                                                                 */
3507 /*   Note, a wild instruction is specified just like a wild var:   */
3508 /*      %4     ; A wild instruction,                               */
3509 /*  See the peeph.def file for additional examples                 */
3510 /*                                                                 */
3511 /*-----------------------------------------------------------------*/
3512
3513 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3514 {
3515
3516   pCodeWild *pcw;
3517
3518   pcw = Safe_calloc(1,sizeof(pCodeWild));
3519
3520   pcw->pci.pc.type = PC_WILD;
3521   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3522   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3523   pcw->pci.pc.pb = NULL;
3524
3525   //  pcw->pci.pc.analyze = genericAnalyze;
3526   pcw->pci.pc.destruct = genericDestruct;
3527   pcw->pci.pc.print = genericPrint;
3528
3529   pcw->id = pCodeID;              // this is the 'n' in %n
3530   pcw->operand = optional_operand;
3531   pcw->label   = optional_label;
3532
3533   pcw->mustBeBitSkipInst = 0;
3534   pcw->mustNotBeBitSkipInst = 0;
3535   pcw->invertBitSkipInst = 0;
3536
3537   return ( (pCode *)pcw);
3538
3539 }
3540
3541  /*-----------------------------------------------------------------*/
3542 /* newPcodeInlineP - create a new pCode from a char string           */
3543 /*-----------------------------------------------------------------*/
3544
3545
3546 pCode *pic16_newpCodeInlineP(char *cP)
3547 {
3548
3549   pCodeComment *pcc ;
3550
3551   pcc = Safe_calloc(1,sizeof(pCodeComment));
3552
3553   pcc->pc.type = PC_INLINE;
3554   pcc->pc.prev = pcc->pc.next = NULL;
3555   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3556   pcc->pc.pb = NULL;
3557
3558   //  pcc->pc.analyze = genericAnalyze;
3559   pcc->pc.destruct = genericDestruct;
3560   pcc->pc.print = genericPrint;
3561
3562   if(cP)
3563     pcc->comment = Safe_strdup(cP);
3564   else
3565     pcc->comment = NULL;
3566
3567   return ( (pCode *)pcc);
3568
3569 }
3570
3571 /*-----------------------------------------------------------------*/
3572 /* newPcodeCharP - create a new pCode from a char string           */
3573 /*-----------------------------------------------------------------*/
3574
3575 pCode *pic16_newpCodeCharP(char *cP)
3576 {
3577
3578   pCodeComment *pcc ;
3579
3580   pcc = Safe_calloc(1,sizeof(pCodeComment));
3581
3582   pcc->pc.type = PC_COMMENT;
3583   pcc->pc.prev = pcc->pc.next = NULL;
3584   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3585   pcc->pc.pb = NULL;
3586
3587   //  pcc->pc.analyze = genericAnalyze;
3588   pcc->pc.destruct = genericDestruct;
3589   pcc->pc.print = genericPrint;
3590
3591   if(cP)
3592     pcc->comment = Safe_strdup(cP);
3593   else
3594     pcc->comment = NULL;
3595
3596   return ( (pCode *)pcc);
3597
3598 }
3599
3600 /*-----------------------------------------------------------------*/
3601 /* pic16_newpCodeFunction -                                              */
3602 /*-----------------------------------------------------------------*/
3603
3604
3605 pCode *pic16_newpCodeFunction(char *mod,char *f)
3606 {
3607   pCodeFunction *pcf;
3608
3609   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3610
3611   pcf->pc.type = PC_FUNCTION;
3612   pcf->pc.prev = pcf->pc.next = NULL;
3613   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3614   pcf->pc.pb = NULL;
3615
3616   //  pcf->pc.analyze = genericAnalyze;
3617   pcf->pc.destruct = genericDestruct;
3618   pcf->pc.print = pCodePrintFunction;
3619
3620   pcf->ncalled = 0;
3621   pcf->absblock = 0;
3622
3623   if(mod) {
3624     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3625     strcpy(pcf->modname,mod);
3626   } else
3627     pcf->modname = NULL;
3628
3629   if(f) {
3630     pcf->fname = Safe_calloc(1,strlen(f)+1);
3631     strcpy(pcf->fname,f);
3632   } else
3633     pcf->fname = NULL;
3634
3635   pcf->stackusage = 0;
3636
3637   return ( (pCode *)pcf);
3638 }
3639
3640 /*-----------------------------------------------------------------*/
3641 /* pic16_newpCodeFlow                                                    */
3642 /*-----------------------------------------------------------------*/
3643 static void destructpCodeFlow(pCode *pc)
3644 {
3645   if(!pc || !isPCFL(pc))
3646     return;
3647
3648 /*
3649   if(PCFL(pc)->from)
3650   if(PCFL(pc)->to)
3651 */
3652   pic16_unlinkpCode(pc);
3653
3654   deleteSet(&PCFL(pc)->registers);
3655   deleteSet(&PCFL(pc)->from);
3656   deleteSet(&PCFL(pc)->to);
3657
3658   /* Instead of deleting the memory used by this pCode, mark
3659    * the object as bad so that if there's a pointer to this pCode
3660    * dangling around somewhere then (hopefully) when the type is
3661    * checked we'll catch it.
3662    */
3663
3664   pc->type = PC_BAD;
3665   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3666
3667 //  Safe_free(pc);
3668
3669 }
3670
3671 pCode *pic16_newpCodeFlow(void )
3672 {
3673   pCodeFlow *pcflow;
3674
3675   //_ALLOC(pcflow,sizeof(pCodeFlow));
3676   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3677
3678   pcflow->pc.type = PC_FLOW;
3679   pcflow->pc.prev = pcflow->pc.next = NULL;
3680   pcflow->pc.pb = NULL;
3681
3682   //  pcflow->pc.analyze = genericAnalyze;
3683   pcflow->pc.destruct = destructpCodeFlow;
3684   pcflow->pc.print = genericPrint;
3685
3686   pcflow->pc.seq = GpcFlowSeq++;
3687
3688   pcflow->from = pcflow->to = NULL;
3689
3690   pcflow->inCond = PCC_NONE;
3691   pcflow->outCond = PCC_NONE;
3692
3693   pcflow->firstBank = -1;
3694   pcflow->lastBank = -1;
3695
3696   pcflow->FromConflicts = 0;
3697   pcflow->ToConflicts = 0;
3698
3699   pcflow->end = NULL;
3700
3701   pcflow->registers = newSet();
3702
3703   return ( (pCode *)pcflow);
3704
3705 }
3706
3707 /*-----------------------------------------------------------------*/
3708 /*-----------------------------------------------------------------*/
3709 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3710 {
3711   pCodeFlowLink *pcflowLink;
3712
3713   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3714
3715   pcflowLink->pcflow = pcflow;
3716   pcflowLink->bank_conflict = 0;
3717
3718   return pcflowLink;
3719 }
3720
3721 /*-----------------------------------------------------------------*/
3722 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3723 /*-----------------------------------------------------------------*/
3724
3725 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3726 {
3727
3728   pCodeCSource *pccs;
3729
3730   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3731
3732   pccs->pc.type = PC_CSOURCE;
3733   pccs->pc.prev = pccs->pc.next = NULL;
3734   pccs->pc.pb = NULL;
3735
3736   pccs->pc.destruct = genericDestruct;
3737   pccs->pc.print = genericPrint;
3738
3739   pccs->line_number = ln;
3740   if(l)
3741     pccs->line = Safe_strdup(l);
3742   else
3743     pccs->line = NULL;
3744
3745   if(f)
3746     pccs->file_name = Safe_strdup(f);
3747   else
3748     pccs->file_name = NULL;
3749
3750   return ( (pCode *)pccs);
3751
3752 }
3753
3754
3755 /*******************************************************************/
3756 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3757 /*                      added by VR 6-Jun-2003                     */
3758 /*******************************************************************/
3759
3760 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3761 {
3762   pCodeAsmDir *pcad;
3763   va_list ap;
3764   char buffer[512];
3765   char *lbp=buffer;
3766
3767         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3768         pcad->pci.pc.type = PC_ASMDIR;
3769         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3770         pcad->pci.pc.pb = NULL;
3771         pcad->pci.isize = 2;
3772         pcad->pci.pc.destruct = genericDestruct;
3773         pcad->pci.pc.print = genericPrint;
3774
3775         if(asdir && *asdir) {
3776
3777                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3778
3779                 pcad->directive = Safe_strdup( asdir );
3780         }
3781
3782         va_start(ap, argfmt);
3783
3784         memset(buffer, 0, sizeof(buffer));
3785         if(argfmt && *argfmt)
3786                 vsprintf(buffer, argfmt, ap);
3787
3788         va_end(ap);
3789
3790         while(isspace((unsigned char)*lbp))lbp++;
3791
3792         if(lbp && *lbp)
3793                 pcad->arg = Safe_strdup( lbp );
3794
3795   return ((pCode *)pcad);
3796 }
3797
3798 /*-----------------------------------------------------------------*/
3799 /* pCodeLabelDestruct - free memory used by a label.               */
3800 /*-----------------------------------------------------------------*/
3801 static void pCodeLabelDestruct(pCode *pc)
3802 {
3803
3804   if(!pc)
3805     return;
3806
3807   pic16_unlinkpCode(pc);
3808
3809 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3810 //    Safe_free(PCL(pc)->label);
3811
3812   /* Instead of deleting the memory used by this pCode, mark
3813    * the object as bad so that if there's a pointer to this pCode
3814    * dangling around somewhere then (hopefully) when the type is
3815    * checked we'll catch it.
3816    */
3817
3818   pc->type = PC_BAD;
3819   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3820
3821 //  Safe_free(pc);
3822
3823 }
3824
3825 pCode *pic16_newpCodeLabel(char *name, int key)
3826 {
3827
3828   char *s = buffer;
3829   pCodeLabel *pcl;
3830
3831   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3832
3833   pcl->pc.type = PC_LABEL;
3834   pcl->pc.prev = pcl->pc.next = NULL;
3835   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3836   pcl->pc.pb = NULL;
3837
3838   //  pcl->pc.analyze = genericAnalyze;
3839   pcl->pc.destruct = pCodeLabelDestruct;
3840   pcl->pc.print = pCodePrintLabel;
3841
3842   pcl->key = key;
3843   pcl->force = 0;
3844
3845   pcl->label = NULL;
3846   if(key>0) {
3847     sprintf(s,"_%05d_DS_",key);
3848   } else
3849     s = name;
3850
3851   if(s)
3852     pcl->label = Safe_strdup(s);
3853
3854 //  if(pic16_pcode_verbose)
3855 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3856
3857
3858   return ( (pCode *)pcl);
3859
3860 }
3861
3862 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3863 {
3864   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3865
3866         pcl->force = 1;
3867
3868   return ( (pCode *)pcl );
3869 }
3870
3871 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3872 {
3873   pCodeInfo *pci;
3874
3875     pci = Safe_calloc(1, sizeof(pCodeInfo));
3876     pci->pci.pc.type = PC_INFO;
3877     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3878     pci->pci.pc.pb = NULL;
3879     pci->pci.label = NULL;
3880
3881     pci->pci.pc.destruct = genericDestruct;
3882     pci->pci.pc.print = genericPrint;
3883
3884     pci->type = type;
3885     pci->oper1 = pcop;
3886
3887   return ((pCode *)pci);
3888 }
3889
3890
3891 /*-----------------------------------------------------------------*/
3892 /* newpBlock - create and return a pointer to a new pBlock         */
3893 /*-----------------------------------------------------------------*/
3894 static pBlock *newpBlock(void)
3895 {
3896
3897   pBlock *PpB;
3898
3899   PpB = Safe_calloc(1,sizeof(pBlock) );
3900   PpB->next = PpB->prev = NULL;
3901
3902   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3903   PpB->tregisters = NULL;
3904   PpB->visited = 0;
3905   PpB->FlowTree = NULL;
3906
3907   return PpB;
3908
3909 }
3910
3911 /*-----------------------------------------------------------------*/
3912 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3913 /*-----------------------------------------------------------------*
3914  *
3915  *  This function will create a new pBlock and the pointer to the
3916  *  pCode that is passed in will be the first pCode in the block.
3917  *-----------------------------------------------------------------*/
3918
3919
3920 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3921 {
3922
3923   pBlock *pB  = newpBlock();
3924
3925   pB->pcHead  = pB->pcTail = pc;
3926   pB->cmemmap = cm;
3927   pB->dbName  = c;
3928
3929   return pB;
3930 }
3931
3932
3933
3934 /*-----------------------------------------------------------------*/
3935 /* pic16_newpCodeOpLabel - Create a new label given the key              */
3936 /*  Note, a negative key means that the label is part of wild card */
3937 /*  (and hence a wild card label) used in the pCodePeep            */
3938 /*   optimizations).                                               */
3939 /*-----------------------------------------------------------------*/
3940
3941 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3942 {
3943   char *s=NULL;
3944   static int label_key=-1;
3945
3946   pCodeOp *pcop;
3947
3948   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3949   pcop->type = PO_LABEL;
3950
3951   pcop->name = NULL;
3952
3953   if(key>0)
3954     sprintf(s=buffer,"_%05d_DS_",key);
3955   else
3956     s = name, key = label_key--;
3957
3958   if(s)
3959     pcop->name = Safe_strdup(s);
3960
3961   ((pCodeOpLabel *)pcop)->key = key;
3962
3963   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3964   return pcop;
3965 }
3966
3967 /*-----------------------------------------------------------------*/
3968 /*-----------------------------------------------------------------*/
3969 pCodeOp *pic16_newpCodeOpLit(int lit)
3970 {
3971   char *s = buffer;
3972   pCodeOp *pcop;
3973
3974
3975   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3976   pcop->type = PO_LITERAL;
3977
3978   pcop->name = NULL;
3979   //if(lit>=0)
3980     sprintf(s,"0x%02hhx", (unsigned char)lit);
3981   //else
3982   //  sprintf(s, "%i", lit);
3983
3984   if(s)
3985     pcop->name = Safe_strdup(s);
3986
3987   ((pCodeOpLit *)pcop)->lit = lit;
3988
3989   return pcop;
3990 }
3991
3992 /* Allow for 12 bit literals, required for LFSR */
3993 pCodeOp *pic16_newpCodeOpLit12(int lit)
3994 {
3995   char *s = buffer;
3996   pCodeOp *pcop;
3997
3998
3999   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4000   pcop->type = PO_LITERAL;
4001
4002   pcop->name = NULL;
4003   //if(lit>=0)
4004     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4005   //else
4006   //  sprintf(s, "%i", lit);
4007
4008   if(s)
4009     pcop->name = Safe_strdup(s);
4010
4011   ((pCodeOpLit *)pcop)->lit = lit;
4012
4013   return pcop;
4014 }
4015
4016 /*-----------------------------------------------------------------*/
4017 /*-----------------------------------------------------------------*/
4018 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4019 {
4020   char *s = buffer, tbuf[256], *tb=tbuf;
4021   pCodeOp *pcop;
4022
4023
4024   tb = pic16_get_op(arg2, NULL, 0);
4025   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4026   pcop->type = PO_LITERAL;
4027
4028   pcop->name = NULL;
4029   //if(lit>=0) {
4030     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4031     if(s)
4032       pcop->name = Safe_strdup(s);
4033   //}
4034
4035   ((pCodeOpLit2 *)pcop)->lit = lit;
4036   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4037
4038   return pcop;
4039 }
4040
4041 /*-----------------------------------------------------------------*/
4042 /*-----------------------------------------------------------------*/
4043 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4044 {
4045   pCodeOp *pcop;
4046
4047         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4048         pcop->type = PO_IMMEDIATE;
4049         if(name) {
4050                 regs *r = pic16_dirregWithName(name);
4051                 pcop->name = Safe_strdup(name);
4052                 PCOI(pcop)->r = r;
4053
4054                 if(r) {
4055 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4056                         PCOI(pcop)->rIdx = r->rIdx;
4057                 } else {
4058 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4059                         PCOI(pcop)->rIdx = -1;
4060                 }
4061 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4062         } else {
4063                 pcop->name = NULL;
4064                 PCOI(pcop)->rIdx = -1;
4065         }
4066
4067         PCOI(pcop)->index = index;
4068         PCOI(pcop)->offset = offset;
4069         PCOI(pcop)->_const = code_space;
4070
4071   return pcop;
4072 }
4073
4074 /*-----------------------------------------------------------------*/
4075 /*-----------------------------------------------------------------*/
4076 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4077 {
4078   char *s = buffer;
4079   pCodeOp *pcop;
4080
4081
4082   if(!pcwb || !subtype) {
4083     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4084     exit(1);
4085   }
4086
4087   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4088   pcop->type = PO_WILD;
4089   sprintf(s,"%%%d",id);
4090   pcop->name = Safe_strdup(s);
4091
4092   PCOW(pcop)->id = id;
4093   PCOW(pcop)->pcwb = pcwb;
4094   PCOW(pcop)->subtype = subtype;
4095   PCOW(pcop)->matched = NULL;
4096
4097   PCOW(pcop)->pcop2 = NULL;
4098
4099   return pcop;
4100 }
4101
4102 /*-----------------------------------------------------------------*/
4103 /*-----------------------------------------------------------------*/
4104 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4105 {
4106   char *s = buffer;
4107   pCodeOp *pcop;
4108
4109
4110         if(!pcwb || !subtype || !subtype2) {
4111                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4112                 exit(1);
4113         }
4114
4115         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4116         pcop->type = PO_WILD;
4117         sprintf(s,"%%%d",id);
4118         pcop->name = Safe_strdup(s);
4119
4120         PCOW(pcop)->id = id;
4121         PCOW(pcop)->pcwb = pcwb;
4122         PCOW(pcop)->subtype = subtype;
4123         PCOW(pcop)->matched = NULL;
4124
4125         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4126
4127         if(!subtype2->name) {
4128                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4129                 PCOW2(pcop)->pcop.type = PO_WILD;
4130                 sprintf(s, "%%%d", id2);
4131                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4132                 PCOW2(pcop)->id = id2;
4133                 PCOW2(pcop)->subtype = subtype2;
4134
4135 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4136 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4137         } else {
4138                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4139
4140 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4141 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4142         }
4143
4144
4145
4146   return pcop;
4147 }
4148
4149
4150 /*-----------------------------------------------------------------*/
4151 /*-----------------------------------------------------------------*/
4152 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4153 {
4154   pCodeOp *pcop;
4155
4156   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4157   pcop->type = PO_GPR_BIT;
4158   if(s)
4159     pcop->name = Safe_strdup(s);
4160   else
4161     pcop->name = NULL;
4162
4163   PCORB(pcop)->bit = bit;
4164   PCORB(pcop)->inBitSpace = inBitSpace;
4165   PCORB(pcop)->subtype = subt;
4166
4167   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4168   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4169 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4170 //  PCOR(pcop)->rIdx = 0;
4171   return pcop;
4172 }
4173
4174 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4175 {
4176   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4177                                 bit, 0, PO_GPR_REGISTER);
4178 }
4179
4180
4181 /*-----------------------------------------------------------------*
4182  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4183  *
4184  * If rIdx >=0 then a specific register from the set of registers
4185  * will be selected. If rIdx <0, then a new register will be searched
4186  * for.
4187  *-----------------------------------------------------------------*/
4188
4189 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4190 {
4191   pCodeOp *pcop;
4192   regs *r;
4193
4194   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4195
4196   pcop->name = NULL;
4197
4198   if(rIdx >= 0) {
4199         r = pic16_regWithIdx(rIdx);
4200         if(!r)
4201                 r = pic16_allocWithIdx(rIdx);
4202   } else {
4203     r = pic16_findFreeReg(REG_GPR);
4204
4205     if(!r) {
4206         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4207                 __FUNCTION__, __LINE__);
4208         exit(EXIT_FAILURE);
4209     }
4210   }
4211
4212   PCOR(pcop)->rIdx = rIdx;
4213   PCOR(pcop)->r = r;
4214   pcop->type = PCOR(pcop)->r->pc_type;
4215
4216   return pcop;
4217 }
4218
4219 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4220 {
4221   pCodeOp *pcop;
4222   regs *r;
4223
4224     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4225     pcop->name = NULL;
4226
4227     r = pic16_findFreeReg(REG_GPR);
4228
4229     while(r) {
4230       if(!bitVectBitValue(bv, r->rIdx)) {
4231         PCOR(pcop)->r = r;
4232         PCOR(pcop)->rIdx = r->rIdx;
4233         pcop->type = r->pc_type;
4234         return (pcop);
4235       }
4236
4237       r = pic16_findFreeRegNext(REG_GPR, r);
4238     }
4239
4240   return NULL;
4241 }
4242
4243
4244
4245 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4246 {
4247   pCodeOp *pcop;
4248   regs *r;
4249
4250         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4251         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4252         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4253         pcop->type = PCOR(pcop)->r->pc_type;
4254         pcop->name = PCOR(pcop)->r->name;
4255
4256 //      if(pic16_pcode_verbose) {
4257 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4258 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4259 //      }
4260
4261   return pcop;
4262 }
4263
4264 /*-----------------------------------------------------------------*/
4265 /*-----------------------------------------------------------------*/
4266 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4267 {
4268   pCodeOpOpt *pcop;
4269
4270         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4271
4272         pcop->type = type;
4273         pcop->key = Safe_strdup( key );
4274
4275   return (PCOP(pcop));
4276 }
4277
4278 /*-----------------------------------------------------------------*/
4279 /*-----------------------------------------------------------------*/
4280 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4281 {
4282   pCodeOpLocalReg *pcop;
4283
4284         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4285
4286         pcop->type = type;
4287
4288   return (PCOP(pcop));
4289 }
4290
4291
4292 /*-----------------------------------------------------------------*/
4293 /*-----------------------------------------------------------------*/
4294
4295 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4296 {
4297   pCodeOp *pcop;
4298
4299   switch(type) {
4300   case PO_BIT:
4301   case PO_GPR_BIT:
4302     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4303     break;
4304
4305   case PO_LITERAL:
4306     pcop = pic16_newpCodeOpLit(-1);
4307     break;
4308
4309   case PO_LABEL:
4310     pcop = pic16_newpCodeOpLabel(NULL,-1);
4311     break;
4312   case PO_GPR_TEMP:
4313     pcop = pic16_newpCodeOpReg(-1);
4314     break;
4315
4316   case PO_GPR_REGISTER:
4317     if(name)
4318       pcop = pic16_newpCodeOpRegFromStr(name);
4319     else
4320       pcop = pic16_newpCodeOpReg(-1);
4321     break;
4322
4323   case PO_TWO_OPS:
4324     assert( !"Cannot create PO_TWO_OPS from string!" );
4325     pcop = NULL;
4326     break;
4327
4328   default:
4329     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4330     pcop->type = type;
4331     if(name)
4332       pcop->name = Safe_strdup(name);
4333     else
4334       pcop->name = NULL;
4335   }
4336
4337   return pcop;
4338 }
4339
4340 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4341 {
4342   pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4343   pcop2->pcop.type = PO_TWO_OPS;
4344   pcop2->pcopL = src;
4345   pcop2->pcopR = dst;
4346   return PCOP(pcop2);
4347 }
4348
4349 /* This is a multiple of two as gpasm pads DB directives to even length,
4350  * thus the data would be interleaved with \0 bytes...
4351  * This is a multiple of three in order to have arrays of 3-byte pointers
4352  * continuously in memory (without 0-padding at the lines' end).
4353  * This is rather 12 than 6 in order not to split up 4-byte data types
4354  * in arrays right in the middle of a 4-byte word. */
4355 #define DB_ITEMS_PER_LINE       12
4356
4357 typedef struct DBdata
4358   {
4359     int count;
4360     char buffer[512];
4361   } DBdata;
4362
4363 struct DBdata DBd;
4364 static int DBd_init = -1;
4365
4366 /*-----------------------------------------------------------------*/
4367 /*    Initialiase "DB" data buffer                                 */
4368 /*-----------------------------------------------------------------*/
4369 void pic16_initDB(void)
4370 {
4371         DBd_init = -1;
4372 }
4373
4374
4375 /*-----------------------------------------------------------------*/
4376 /*    Flush pending "DB" data to a pBlock                          */
4377 /*                                                                 */
4378 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4379 /*-----------------------------------------------------------------*/
4380 void pic16_flushDB(char ptype, void *p)
4381 {
4382         if (DBd.count>0) {
4383                 if(ptype == 'p')
4384                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4385                 else
4386                 if(ptype == 'f')
4387                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4388                 else {
4389                         /* sanity check */
4390                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4391                 }
4392
4393                 DBd.count = 0;
4394                 DBd.buffer[0] = '\0';
4395         }
4396 }
4397
4398
4399 /*-----------------------------------------------------------------*/
4400 /*    Add "DB" directives to a pBlock                              */
4401 /*-----------------------------------------------------------------*/
4402 void pic16_emitDB(int c, char ptype, void *p)
4403 {
4404   int l;
4405
4406         if (DBd_init<0) {
4407          // we need to initialize
4408                 DBd_init = 0;
4409                 DBd.count = 0;
4410                 DBd.buffer[0] = '\0';
4411         }
4412
4413         l = strlen(DBd.buffer);
4414         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4415
4416 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4417
4418         DBd.count++;
4419         if (DBd.count>= DB_ITEMS_PER_LINE)
4420                 pic16_flushDB(ptype, p);
4421 }
4422
4423 void pic16_emitDS(char *s, char ptype, void *p)
4424 {
4425   int l;
4426
4427         if (DBd_init<0) {
4428          // we need to initialize
4429                 DBd_init = 0;
4430                 DBd.count = 0;
4431                 DBd.buffer[0] = '\0';
4432         }
4433
4434         l = strlen(DBd.buffer);
4435         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4436
4437 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4438
4439         DBd.count++;    //=strlen(s);
4440         if (DBd.count>=DB_ITEMS_PER_LINE)
4441                 pic16_flushDB(ptype, p);
4442 }
4443
4444
4445 /*-----------------------------------------------------------------*/
4446 /*-----------------------------------------------------------------*/
4447 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4448 {
4449   pBlock *pb;
4450   char *item;
4451   static set *emittedSymbols = NULL;
4452
4453   if(!name || !value)
4454     return;
4455
4456   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4457   if (emittedSymbols) {
4458     /* scan set for name */
4459     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4460     {
4461       if (!strcmp (item,name)) {
4462         //fprintf (stderr, "%s already emitted\n", name);
4463         return;
4464       } // if
4465     } // for
4466   } // if
4467   addSet (&emittedSymbols, Safe_strdup (name));
4468
4469   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4470
4471   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4472
4473   pic16_addpBlock(pb);
4474
4475 //  sprintf(buffer,"; %s = ", name);
4476 //  strcat(buffer, value);
4477 //  fputs(buffer, stderr);
4478
4479 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4480   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4481
4482   while (length--)
4483     pic16_emitDB(*value++, 'p', (void *)pb);
4484
4485   pic16_flushDB('p', (void *)pb);
4486 }
4487
4488 /*-----------------------------------------------------------------*/
4489 /*-----------------------------------------------------------------*/
4490 #if 0
4491 static void pCodeReadCodeTable(void)
4492 {
4493   pBlock *pb;
4494
4495   fprintf(stderr, " %s\n",__FUNCTION__);
4496
4497   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4498
4499   pic16_addpBlock(pb);
4500
4501   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4502   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4503   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4504   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4505
4506   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4507   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4508   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4509   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4510
4511
4512 }
4513 #endif
4514 /*-----------------------------------------------------------------*/
4515 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4516 /*-----------------------------------------------------------------*/
4517 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4518 {
4519
4520   if(!pc)
4521     return;
4522
4523   if(!pb->pcHead) {
4524     /* If this is the first pcode to be added to a block that
4525      * was initialized with a NULL pcode, then go ahead and
4526      * make this pcode the head and tail */
4527     pb->pcHead  = pb->pcTail = pc;
4528   } else {
4529     //    if(pb->pcTail)
4530     pb->pcTail->next = pc;
4531
4532     pc->prev = pb->pcTail;
4533     pc->pb = pb;
4534
4535     pb->pcTail = pc;
4536   }
4537 }
4538
4539 /*-----------------------------------------------------------------*/
4540 /* pic16_addpBlock - place a pBlock into the pFile                 */
4541 /*-----------------------------------------------------------------*/
4542 void pic16_addpBlock(pBlock *pb)
4543 {
4544   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4545
4546   if(!the_pFile) {
4547     /* First time called, we'll pass through here. */
4548     //_ALLOC(the_pFile,sizeof(pFile));
4549     the_pFile = Safe_calloc(1,sizeof(pFile));
4550     the_pFile->pbHead = the_pFile->pbTail = pb;
4551     the_pFile->functions = NULL;
4552     return;
4553   }
4554
4555   the_pFile->pbTail->next = pb;
4556   pb->prev = the_pFile->pbTail;
4557   pb->next = NULL;
4558   the_pFile->pbTail = pb;
4559 }
4560
4561 /*-----------------------------------------------------------------*/
4562 /* removepBlock - remove a pBlock from the pFile                   */
4563 /*-----------------------------------------------------------------*/
4564 static void removepBlock(pBlock *pb)
4565 {
4566   pBlock *pbs;
4567
4568   if(!the_pFile)
4569     return;
4570
4571
4572   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4573
4574   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4575     if(pbs == pb) {
4576
4577       if(pbs == the_pFile->pbHead)
4578         the_pFile->pbHead = pbs->next;
4579
4580       if (pbs == the_pFile->pbTail)
4581         the_pFile->pbTail = pbs->prev;
4582
4583       if(pbs->next)
4584         pbs->next->prev = pbs->prev;
4585
4586       if(pbs->prev)
4587         pbs->prev->next = pbs->next;
4588
4589       return;
4590
4591     }
4592   }
4593
4594   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4595
4596 }
4597
4598 /*-----------------------------------------------------------------*/
4599 /* printpCode - write the contents of a pCode to a file            */
4600 /*-----------------------------------------------------------------*/
4601 static void printpCode(FILE *of, pCode *pc)
4602 {
4603
4604   if(!pc || !of)
4605     return;
4606
4607   if(pc->print) {
4608     pc->print(of,pc);
4609     return;
4610   }
4611
4612   fprintf(of,"warning - unable to print pCode\n");
4613 }
4614
4615 /*-----------------------------------------------------------------*/
4616 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4617 /*-----------------------------------------------------------------*/
4618 void pic16_printpBlock(FILE *of, pBlock *pb)
4619 {
4620   pCode *pc;
4621
4622         if(!pb)return;
4623
4624         if(!of)of=stderr;
4625
4626         for(pc = pb->pcHead; pc; pc = pc->next) {
4627                 if(isPCF(pc) && PCF(pc)->fname) {
4628                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4629                         if(pb->dbName == 'A') {
4630                           absSym *ab;
4631                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4632 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4633                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4634 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4635                                                 if(ab->address != -1)
4636                                                   fprintf(of, "\t0X%06X", ab->address);
4637                                                 break;
4638                                         }
4639                                 }
4640                         }
4641                         fprintf(of, "\n");
4642                 }
4643                 printpCode(of,pc);
4644         }
4645 }
4646
4647 /*-----------------------------------------------------------------*/
4648 /*                                                                 */
4649 /*       pCode processing                                          */
4650 /*                                                                 */
4651 /*                                                                 */
4652 /*                                                                 */
4653 /*-----------------------------------------------------------------*/
4654 pCode * pic16_findNextInstruction(pCode *pci);
4655 pCode * pic16_findPrevInstruction(pCode *pci);
4656
4657 void pic16_unlinkpCode(pCode *pc)
4658 {
4659   pCode *prev;
4660
4661   if(pc) {
4662 #ifdef PCODE_DEBUG
4663     fprintf(stderr,"Unlinking: ");
4664     printpCode(stderr, pc);
4665 #endif
4666     if(pc->prev) {
4667       pc->prev->next = pc->next;
4668     } else if (pc->pb && (pc->pb->pcHead == pc)) {
4669         pc->pb->pcHead = pc->next;
4670     }
4671     if(pc->next) {
4672       pc->next->prev = pc->prev;
4673     } else if (pc->pb && (pc->pb->pcTail == pc)) {
4674         pc->pb->pcTail = pc->prev;
4675     }
4676
4677     /* move C source line down (or up) */
4678     if (isPCI(pc) && PCI(pc)->cline) {
4679       prev = pic16_findNextInstruction (pc->next);
4680       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4681         PCI(prev)->cline = PCI(pc)->cline;
4682       } else {
4683         prev = pic16_findPrevInstruction (pc->prev);
4684         if (prev && isPCI(prev) && !PCI(prev)->cline)
4685           PCI(prev)->cline = PCI(pc)->cline;
4686       }
4687     }
4688     pc->prev = pc->next = NULL;
4689   }
4690 }
4691
4692 /*-----------------------------------------------------------------*/
4693 /*-----------------------------------------------------------------*/
4694
4695 static void genericDestruct(pCode *pc)
4696 {
4697
4698   pic16_unlinkpCode(pc);
4699
4700   if(isPCI(pc)) {
4701     /* For instructions, tell the register (if there's one used)
4702      * that it's no longer needed */
4703     regs *reg = pic16_getRegFromInstruction(pc);
4704     if(reg)
4705       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4706
4707         if(PCI(pc)->is2MemOp) {
4708                 reg = pic16_getRegFromInstruction2(pc);
4709                 if(reg)
4710                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4711         }
4712   }
4713
4714   /* Instead of deleting the memory used by this pCode, mark
4715    * the object as bad so that if there's a pointer to this pCode
4716    * dangling around somewhere then (hopefully) when the type is
4717    * checked we'll catch it.
4718    */
4719
4720   pc->type = PC_BAD;
4721   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4722
4723   //Safe_free(pc);
4724 }
4725
4726
4727 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4728 /*-----------------------------------------------------------------*/
4729 /*-----------------------------------------------------------------*/
4730 /* modifiers for constant immediate */
4731 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4732
4733 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4734 {
4735     regs *r;
4736     static char b[128];
4737     char *s;
4738     int use_buffer = 1;    // copy the string to the passed buffer pointer
4739
4740     if(!buffer) {
4741         buffer = b;
4742         size = sizeof(b);
4743         use_buffer = 0;     // Don't bother copying the string to the buffer.
4744     }
4745
4746     if(pcop) {
4747
4748         switch(pcop->type) {
4749             case PO_W:
4750             case PO_WREG:
4751             case PO_PRODL:
4752             case PO_PRODH:
4753             case PO_INDF0:
4754             case PO_FSR0:
4755                 if(use_buffer) {
4756                     SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4757                     return (buffer);
4758                 }
4759                 return (PCOR(pcop)->r->name);
4760                 break;
4761             case PO_GPR_TEMP:
4762                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4763                 if(use_buffer) {
4764                     SNPRINTF(buffer,size,"%s",r->name);
4765                     return (buffer);
4766                 }
4767                 return (r->name);
4768                 break;
4769
4770             case PO_IMMEDIATE:
4771                 s = buffer;
4772                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4773                     if(PCOI(pcop)->index) {
4774                         SNPRINTF(s,size, "%s(%s + %d)",
4775                                 immdmod[ PCOI(pcop)->offset ],
4776                                 pcop->name,
4777                                 PCOI(pcop)->index);
4778                     } else {
4779                         SNPRINTF(s,size,"%s(%s)",
4780                                 immdmod[ PCOI(pcop)->offset ],
4781                                 pcop->name);
4782                     }
4783                 } else {
4784                     if(PCOI(pcop)->index) {
4785                         SNPRINTF(s,size, "%s(%s + %d)",
4786                                 immdmod[ 0 ],
4787                                 pcop->name,
4788                                 PCOI(pcop)->index);
4789                     } else {
4790                         SNPRINTF(s,size, "%s(%s)",
4791                                 immdmod[ 0 ],
4792                                 pcop->name);
4793                     }
4794                 }
4795                 return (buffer);
4796                 break;
4797
4798             case PO_GPR_REGISTER:
4799             case PO_DIR:
4800                 s = buffer;
4801                 //size = sizeof(buffer);
4802                 if( PCOR(pcop)->instance) {
4803                     SNPRINTF(s,size,"(%s + %d)",
4804                             pcop->name,
4805                             PCOR(pcop)->instance );
4806                 } else {
4807                     SNPRINTF(s,size,"%s",pcop->name);
4808                 }
4809                 return (buffer);
4810                 break;
4811
4812             case PO_GPR_BIT:
4813                 s = buffer;
4814                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4815                     SNPRINTF(s, size, "%s", pcop->name);
4816                 } else {
4817                     if(PCORB(pcop)->pcor.instance)
4818                         SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4819                     else
4820                         SNPRINTF(s, size, "%s", pcop->name);
4821                 }
4822                 return (buffer);
4823                 break;
4824
4825             case PO_TWO_OPS:
4826                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4827                 break;
4828
4829             default:
4830                 if(pcop->name) {
4831                     if(use_buffer) {
4832                         SNPRINTF(buffer,size,"%s",pcop->name);
4833                         return (buffer);
4834                     }
4835                     return (pcop->name);
4836                 }
4837
4838         }
4839         return ("unhandled type for op1");
4840     }
4841
4842     return ("NO operand1");
4843 }
4844
4845 /*-----------------------------------------------------------------*/
4846 /* pic16_get_op2 - variant to support two memory operand commands  */
4847 /*-----------------------------------------------------------------*/
4848 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4849 {
4850
4851   if(pcop && pcop->type == PO_TWO_OPS) {
4852     return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4853   }
4854
4855   return "NO operand2";
4856 }
4857
4858 /*-----------------------------------------------------------------*/
4859 /*-----------------------------------------------------------------*/
4860 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4861 {
4862
4863   if(pcc )
4864     return pic16_get_op(pcc->pcop,NULL,0);
4865
4866   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated
4867    *   return ("ERROR Null: "__FUNCTION__);
4868    */
4869   return ("ERROR Null: pic16_get_op_from_instruction");
4870
4871 }
4872
4873 /*-----------------------------------------------------------------*/
4874 /*-----------------------------------------------------------------*/
4875 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4876 {
4877
4878   fprintf(of,"pcodeopprint- not implemented\n");
4879 }
4880
4881 /*-----------------------------------------------------------------*/
4882 /* pic16_pCode2str - convert a pCode instruction to string               */
4883 /*-----------------------------------------------------------------*/
4884 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4885 {
4886     char *s = str;
4887     regs *r;
4888
4889 #if 0
4890     if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4891         fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4892                 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4893         //              exit(EXIT_FAILURE);
4894     }
4895 #endif
4896
4897     switch(pc->type) {
4898
4899         case PC_OPCODE:
4900             SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4901             size -= strlen(s);
4902             s += strlen(s);
4903
4904             if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4905
4906                 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4907                 {
4908                     /* split into two phases due to static buffer in pic16_get_op() */
4909                     SNPRINTF(s, size, "%s",
4910                             pic16_get_op((PCI(pc)->pcop), NULL, 0));
4911                     size -= strlen(s);
4912                     s += strlen(s);
4913                     SNPRINTF(s, size, ", %s",
4914                             pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4915                     break;
4916                 }
4917
4918                 if(PCI(pc)->is2LitOp) {
4919                     SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4920                     break;
4921                 }
4922
4923                 if(PCI(pc)->isBitInst) {
4924                     if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4925                         if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4926                             SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4927                                     PCI(pc)->pcop->name ,
4928                                     PCI(pc)->pcop->name );
4929                         else
4930                             SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4931                                     (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4932
4933                     } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4934                         SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4935                     } else
4936                         SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4937                 } else {
4938
4939                     if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4940                         if( PCI(pc)->num_ops == 3)
4941                             SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4942                         else
4943                             SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4944                     } else {
4945                         SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4946                     }
4947                 }
4948
4949                 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4950                     size -= strlen(s);
4951                     s += strlen(s);
4952                     if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4953                         SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4954                         size -= strlen(s);
4955                         s += strlen(s);
4956                     }
4957
4958                     r = pic16_getRegFromInstruction(pc);
4959
4960                     if(PCI(pc)->isAccess) {
4961                         static char *bank_spec[2][2] = {
4962                             { "", ", ACCESS" },  /* gpasm uses access bank by default */
4963                             { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4964                         };
4965
4966                         SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4967                     }
4968                 }
4969             }
4970             break;
4971
4972         case PC_COMMENT:
4973             /* assuming that comment ends with a \n */
4974             SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4975             break;
4976
4977         case PC_INFO:
4978             SNPRINTF(s,size,"; info ==>");
4979             size -= strlen(s);
4980             s += strlen(s);
4981             switch( PCINF(pc)->type ) {
4982                 case INF_OPTIMIZATION:
4983                     SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4984                     break;
4985                 case INF_LOCALREGS:
4986                     SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4987                     break;
4988             }; break;
4989
4990         case PC_INLINE:
4991             /* assuming that inline code ends with a \n */
4992             SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4993             break;
4994
4995         case PC_LABEL:
4996             SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4997             break;
4998         case PC_FUNCTION:
4999             SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5000             break;
5001         case PC_WILD:
5002             SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5003             break;
5004         case PC_FLOW:
5005             SNPRINTF(s,size,";\t--FLOW change\n");
5006             break;
5007         case PC_CSOURCE:
5008             SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5009                     PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5010             break;
5011         case PC_ASMDIR:
5012             if(PCAD(pc)->directive) {
5013                 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5014             } else
5015                 if(PCAD(pc)->arg) {
5016                     /* special case to handle inline labels without a tab */
5017                     SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5018                 }
5019             break;
5020
5021         case PC_BAD:
5022             SNPRINTF(s,size,";A bad pCode is being used\n");
5023             break;
5024     }
5025
5026     return str;
5027 }
5028
5029 /*-----------------------------------------------------------------*/
5030 /* genericPrint - the contents of a pCode to a file                */
5031 /*-----------------------------------------------------------------*/
5032 static void genericPrint(FILE *of, pCode *pc)
5033 {
5034
5035   if(!pc || !of)
5036     return;
5037
5038   switch(pc->type) {
5039   case PC_COMMENT:
5040 //    fputs(((pCodeComment *)pc)->comment, of);
5041     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5042     break;
5043
5044   case PC_INFO:
5045     {
5046       pBranch *pbl = PCI(pc)->label;
5047       while(pbl && pbl->pc) {
5048         if(pbl->pc->type == PC_LABEL)
5049           pCodePrintLabel(of, pbl->pc);
5050         pbl = pbl->next;
5051       }
5052     }
5053
5054     if(pic16_pcode_verbose) {
5055       fprintf(of, "; info ==>");
5056       switch(((pCodeInfo *)pc)->type) {
5057         case INF_OPTIMIZATION:
5058               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5059               break;
5060         case INF_LOCALREGS:
5061               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5062               break;
5063         }
5064     };
5065
5066     break;
5067
5068   case PC_INLINE:
5069     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5070      break;
5071
5072   case PC_OPCODE:
5073     // If the opcode has a label, print that first
5074     {
5075       pBranch *pbl = PCI(pc)->label;
5076       while(pbl && pbl->pc) {
5077         if(pbl->pc->type == PC_LABEL)
5078           pCodePrintLabel(of, pbl->pc);
5079         pbl = pbl->next;
5080       }
5081     }
5082
5083     if(PCI(pc)->cline)
5084       genericPrint(of,PCODE(PCI(pc)->cline));
5085
5086     {
5087       char str[256];
5088
5089       pic16_pCode2str(str, 256, pc);
5090
5091       fprintf(of,"%s",str);
5092       /* Debug */
5093       if(pic16_debug_verbose) {
5094         fprintf(of, "\t;key=%03x",pc->seq);
5095         if(PCI(pc)->pcflow)
5096           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5097       }
5098     }
5099     fprintf(of, "\n");
5100     break;
5101
5102   case PC_WILD:
5103     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5104     if(PCW(pc)->pci.label)
5105       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5106
5107     if(PCW(pc)->operand) {
5108       fprintf(of,";\toperand  ");
5109       pCodeOpPrint(of,PCW(pc)->operand );
5110     }
5111     break;
5112
5113   case PC_FLOW:
5114     if(pic16_debug_verbose) {
5115       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5116       if(PCFL(pc)->ancestor)
5117         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5118       fprintf(of,"\n");
5119
5120     }
5121     break;
5122
5123   case PC_CSOURCE:
5124 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5125     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5126         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5127
5128     break;
5129
5130   case PC_ASMDIR:
5131         {
5132           pBranch *pbl = PCAD(pc)->pci.label;
5133                 while(pbl && pbl->pc) {
5134                         if(pbl->pc->type == PC_LABEL)
5135                                 pCodePrintLabel(of, pbl->pc);
5136                         pbl = pbl->next;
5137                 }
5138         }
5139         if(PCAD(pc)->directive) {
5140                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5141         } else
5142         if(PCAD(pc)->arg) {
5143                 /* special case to handle inline labels without tab */
5144                 fprintf(of, "%s\n", PCAD(pc)->arg);
5145         }
5146         break;
5147
5148   case PC_LABEL:
5149   default:
5150     fprintf(of,"unknown pCode type %d\n",pc->type);
5151   }
5152
5153 }
5154
5155 /*-----------------------------------------------------------------*/
5156 /* pCodePrintFunction - prints function begin/end                  */
5157 /*-----------------------------------------------------------------*/
5158
5159 static void pCodePrintFunction(FILE *of, pCode *pc)
5160 {
5161
5162   if(!pc || !of)
5163     return;
5164
5165 #if 0
5166   if( ((pCodeFunction *)pc)->modname)
5167     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5168 #endif
5169
5170   if(!PCF(pc)->absblock) {
5171       if(PCF(pc)->fname) {
5172       pBranch *exits = PCF(pc)->to;
5173       int i=0;
5174
5175       fprintf(of,"%s:", PCF(pc)->fname);
5176
5177       if(pic16_pcode_verbose)
5178         fprintf(of, "\t;Function start");
5179
5180       fprintf(of, "\n");
5181
5182       while(exits) {
5183         i++;
5184         exits = exits->next;
5185       }
5186       //if(i) i--;
5187
5188       if(pic16_pcode_verbose)
5189         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5190
5191     } else {
5192         if((PCF(pc)->from &&
5193                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5194                 PCF(PCF(pc)->from->pc)->fname) ) {
5195
5196                 if(pic16_pcode_verbose)
5197                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5198         } else {
5199                 if(pic16_pcode_verbose)
5200                         fprintf(of,"; exit point [can't find entry point]\n");
5201         }
5202         fprintf(of, "\n");
5203     }
5204   }
5205 }
5206 /*-----------------------------------------------------------------*/
5207 /* pCodePrintLabel - prints label                                  */
5208 /*-----------------------------------------------------------------*/
5209
5210 static void pCodePrintLabel(FILE *of, pCode *pc)
5211 {
5212
5213   if(!pc || !of)
5214     return;
5215
5216   if(PCL(pc)->label)
5217     fprintf(of,"%s:\n",PCL(pc)->label);
5218   else if (PCL(pc)->key >=0)
5219     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5220   else
5221     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5222
5223 }
5224 /*-----------------------------------------------------------------*/
5225 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5226 /*                         remove it if it is found.               */
5227 /*-----------------------------------------------------------------*/
5228 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5229 {
5230   pBranch *b, *bprev;
5231
5232
5233   bprev = NULL;
5234
5235   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5236     b = PCI(pcl)->label;
5237   else {
5238     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5239     exit(1);
5240
5241   }
5242
5243   //fprintf (stderr, "%s \n",__FUNCTION__);
5244   //pcl->print(stderr,pcl);
5245   //pc->print(stderr,pc);
5246   while(b) {
5247     if(b->pc == pc) {
5248       //fprintf (stderr, "found label\n");
5249       //pc->print(stderr, pc);
5250
5251       /* Found a label */
5252       if(bprev) {
5253         bprev->next = b->next;  /* Not first pCode in chain */
5254 //      Safe_free(b);
5255       } else {
5256         pc->destruct(pc);
5257         PCI(pcl)->label = b->next;   /* First pCode in chain */
5258 //      Safe_free(b);
5259       }
5260       return;  /* A label can't occur more than once */
5261     }
5262     bprev = b;
5263     b = b->next;
5264   }
5265
5266 }
5267
5268 /*-----------------------------------------------------------------*/
5269 /*-----------------------------------------------------------------*/
5270 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5271 {
5272   pBranch *b;
5273
5274   if(!h)
5275     return n;
5276
5277   if(h == n)
5278     return n;
5279
5280   b = h;
5281   while(b->next)
5282     b = b->next;
5283
5284   b->next = n;
5285
5286   return h;
5287
5288 }
5289 /*-----------------------------------------------------------------*/
5290 /* pBranchLink - given two pcodes, this function will link them    */
5291 /*               together through their pBranches                  */
5292 /*-----------------------------------------------------------------*/
5293 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5294 {
5295   pBranch *b;
5296
5297   // Declare a new branch object for the 'from' pCode.
5298
5299   //_ALLOC(b,sizeof(pBranch));
5300   b = Safe_calloc(1,sizeof(pBranch));
5301   b->pc = PCODE(t);             // The link to the 'to' pCode.
5302   b->next = NULL;
5303
5304   f->to = pic16_pBranchAppend(f->to,b);
5305
5306   // Now do the same for the 'to' pCode.
5307
5308   //_ALLOC(b,sizeof(pBranch));
5309   b = Safe_calloc(1,sizeof(pBranch));
5310   b->pc = PCODE(f);
5311   b->next = NULL;
5312
5313   t->from = pic16_pBranchAppend(t->from,b);
5314
5315 }
5316
5317 #if 1
5318 /*-----------------------------------------------------------------*/
5319 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5320 /*               a pCode                                           */
5321 /*-----------------------------------------------------------------*/
5322 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5323 {
5324   while(pb) {
5325
5326     if(pb->pc == pc)
5327       return pb;
5328
5329     pb = pb->next;
5330   }
5331
5332   return NULL;
5333 }
5334
5335 /*-----------------------------------------------------------------*/
5336 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5337 /*-----------------------------------------------------------------*/
5338 void pic16_pCodeUnlink(pCode *pc)
5339 {
5340   pBranch *pb1,*pb2;
5341   pCode *pc1;
5342
5343   if (!pc) {
5344     return;
5345   }
5346
5347   /* Remove the branches */
5348
5349   pb1 = PCI(pc)->from;
5350   while(pb1) {
5351     pc1 = pb1->pc;    /* Get the pCode that branches to the
5352                        * one we're unlinking */
5353
5354     /* search for the link back to this pCode (the one we're
5355      * unlinking) */
5356     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5357       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5358
5359       /* if the pCode we're unlinking contains multiple 'to'
5360        * branches (e.g. this a skip instruction) then we need
5361        * to copy these extra branches to the chain. */
5362       if(PCI(pc)->to->next)
5363         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5364     }
5365
5366     pb1 = pb1->next;
5367   }
5368
5369   pic16_unlinkpCode (pc);
5370
5371 }
5372 #endif
5373 /*-----------------------------------------------------------------*/
5374 /*-----------------------------------------------------------------*/
5375 #if 0
5376 static void genericAnalyze(pCode *pc)
5377 {
5378   switch(pc->type) {
5379   case PC_WILD:
5380   case PC_COMMENT:
5381     return;
5382   case PC_LABEL:
5383   case PC_FUNCTION:
5384   case PC_OPCODE:
5385     {
5386       // Go through the pCodes that are in pCode chain and link
5387       // them together through the pBranches. Note, the pCodes
5388       // are linked together as a contiguous stream like the
5389       // assembly source code lines. The linking here mimics this
5390       // except that comments are not linked in.
5391       //
5392       pCode *npc = pc->next;
5393       while(npc) {
5394         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5395           pBranchLink(pc,npc);
5396           return;
5397         } else
5398           npc = npc->next;
5399       }
5400       /* reached the end of the pcode chain without finding
5401        * an instruction we could link to. */
5402     }
5403     break;
5404   case PC_FLOW:
5405     fprintf(stderr,"analyze PC_FLOW\n");
5406
5407     return;
5408   case PC_BAD:
5409     fprintf(stderr,,";A bad pCode is being used\n");
5410
5411   }
5412 }
5413 #endif
5414
5415 /*-----------------------------------------------------------------*/
5416 /*-----------------------------------------------------------------*/
5417 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5418 {
5419   pBranch *pbr;
5420
5421   if(pc->type == PC_LABEL) {
5422     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5423       return TRUE;
5424   }
5425   if((pc->type == PC_OPCODE)
5426         || (pc->type == PC_ASMDIR)
5427         ) {
5428     pbr = PCI(pc)->label;
5429     while(pbr) {
5430       if(pbr->pc->type == PC_LABEL) {
5431         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5432           return TRUE;
5433       }
5434       pbr = pbr->next;
5435     }
5436   }
5437
5438   return FALSE;
5439 }
5440
5441 /*-----------------------------------------------------------------*/
5442 /*-----------------------------------------------------------------*/
5443 static int checkLabel(pCode *pc)
5444 {
5445   pBranch *pbr;
5446
5447   if(pc && isPCI(pc)) {
5448     pbr = PCI(pc)->label;
5449     while(pbr) {
5450       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5451         return TRUE;
5452
5453       pbr = pbr->next;
5454     }
5455   }
5456
5457   return FALSE;
5458 }
5459
5460 /*-----------------------------------------------------------------*/
5461 /* findLabelinpBlock - Search the pCode for a particular label     */
5462 /*-----------------------------------------------------------------*/
5463 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5464 {
5465   pCode  *pc;
5466
5467   if(!pb)
5468     return NULL;
5469
5470   for(pc = pb->pcHead; pc; pc = pc->next)
5471     if(compareLabel(pc,pcop_label))
5472       return pc;
5473
5474   return NULL;
5475 }
5476 #if 0
5477 /*-----------------------------------------------------------------*/
5478 /* findLabel - Search the pCode for a particular label             */
5479 /*-----------------------------------------------------------------*/
5480 static pCode * findLabel(pCodeOpLabel *pcop_label)
5481 {
5482   pBlock *pb;
5483   pCode  *pc;
5484
5485   if(!the_pFile)
5486     return NULL;
5487
5488   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5489     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5490       return pc;
5491   }
5492
5493   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5494   return NULL;
5495 }
5496 #endif
5497 /*-----------------------------------------------------------------*/
5498 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5499 /*                 in the linked list                              */
5500 /*-----------------------------------------------------------------*/
5501 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5502 {
5503
5504   while(pc) {
5505     if(pc->type == pct)
5506       return pc;
5507
5508     pc = pc->next;
5509   }
5510
5511   return NULL;
5512 }
5513
5514 /*-----------------------------------------------------------------*/
5515 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5516 /*                 in the linked list                              */
5517 /*-----------------------------------------------------------------*/
5518 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5519 {
5520
5521   while(pc) {
5522     if(pc->type == pct)
5523       return pc;
5524
5525     pc = pc->prev;
5526   }
5527
5528   return NULL;
5529 }
5530
5531
5532 //#define PCODE_DEBUG
5533 /*-----------------------------------------------------------------*/
5534 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5535 /*                       in the linked list                        */
5536 /*-----------------------------------------------------------------*/
5537 pCode * pic16_findNextInstruction(pCode *pci)
5538 {
5539   pCode *pc = pci;
5540
5541   while(pc) {
5542     if((pc->type == PC_OPCODE)
5543         || (pc->type == PC_WILD)
5544         || (pc->type == PC_ASMDIR)
5545         )
5546       return pc;
5547
5548 #ifdef PCODE_DEBUG
5549     fprintf(stderr,"pic16_findNextInstruction:  ");
5550     printpCode(stderr, pc);
5551 #endif
5552     pc = pc->next;
5553   }
5554
5555   //fprintf(stderr,"Couldn't find instruction\n");
5556   return NULL;
5557 }
5558
5559 /*-----------------------------------------------------------------*/
5560 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5561 /*                       in the linked list                        */
5562 /*-----------------------------------------------------------------*/
5563 pCode * pic16_findPrevInstruction(pCode *pci)
5564 {
5565   pCode *pc = pci;
5566
5567   while(pc) {
5568
5569     if((pc->type == PC_OPCODE)
5570         || (pc->type == PC_WILD)
5571         || (pc->type == PC_ASMDIR)
5572         )
5573       return pc;
5574
5575
5576 #ifdef PCODE_DEBUG
5577     fprintf(stderr,"pic16_findPrevInstruction:  ");
5578     printpCode(stderr, pc);
5579 #endif
5580     pc = pc->prev;
5581   }
5582
5583   //fprintf(stderr,"Couldn't find instruction\n");
5584   return NULL;
5585 }
5586
5587 #undef PCODE_DEBUG
5588
5589 #if 0
5590 /*-----------------------------------------------------------------*/
5591 /* findFunctionEnd - given a pCode find the end of the function    */
5592 /*                   that contains it                              */
5593 /*-----------------------------------------------------------------*/
5594 static pCode * findFunctionEnd(pCode *pc)
5595 {
5596
5597   while(pc) {
5598     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5599       return pc;
5600
5601     pc = pc->next;
5602   }
5603
5604   fprintf(stderr,"Couldn't find function end\n");
5605   return NULL;
5606 }
5607 #endif
5608 #if 0
5609 /*-----------------------------------------------------------------*/
5610 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5611 /*                instruction with which it is associated.         */
5612 /*-----------------------------------------------------------------*/
5613 static void AnalyzeLabel(pCode *pc)
5614 {
5615
5616   pic16_pCodeUnlink(pc);
5617
5618 }
5619 #endif
5620
5621 #if 0
5622 static void AnalyzeGOTO(pCode *pc)
5623 {
5624
5625   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5626
5627 }
5628
5629 static void AnalyzeSKIP(pCode *pc)
5630 {
5631
5632   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5633   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5634
5635 }
5636
5637 static void AnalyzeRETURN(pCode *pc)
5638 {
5639
5640   //  branch_link(pc,findFunctionEnd(pc->next));
5641
5642 }
5643
5644 #endif
5645
5646 /*-------------------------------------------------------------------*/
5647 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5648 /*                            if one is present. This is the common  */
5649 /*                            part of pic16_getRegFromInstruction(2) */
5650 /*-------------------------------------------------------------------*/
5651
5652 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5653   if (!pcop) return NULL;
5654
5655   switch(pcop->type) {
5656   case PO_PRODL:
5657   case PO_PRODH:
5658   case PO_INDF0:
5659   case PO_FSR0:
5660   case PO_W:
5661   case PO_WREG:
5662   case PO_STATUS:
5663   case PO_INTCON:
5664   case PO_PCL:
5665   case PO_PCLATH:
5666   case PO_PCLATU:
5667   case PO_BSR:
5668     return PCOR(pcop)->r;
5669
5670   case PO_SFR_REGISTER:
5671     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5672     return PCOR(pcop)->r;
5673
5674   case PO_BIT:
5675   case PO_GPR_TEMP:
5676 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5677     return PCOR(pcop)->r;
5678
5679   case PO_IMMEDIATE:
5680 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5681
5682     if(PCOI(pcop)->r)
5683       return (PCOI(pcop)->r);
5684     else
5685       return NULL;
5686
5687   case PO_GPR_BIT:
5688     return PCOR(pcop)->r;
5689
5690   case PO_GPR_REGISTER:
5691   case PO_DIR:
5692 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5693     return PCOR(pcop)->r;
5694
5695   case PO_LITERAL:
5696     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5697     break;
5698
5699   case PO_REL_ADDR:
5700   case PO_LABEL:
5701     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5702     break;
5703
5704   case PO_CRY:
5705   case PO_STR:
5706     /* this should never turn up */
5707     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5708     break;
5709
5710   case PO_WILD:
5711     break;
5712
5713   case PO_TWO_OPS:
5714     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5715     break;
5716
5717   default:
5718         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5719 //      assert( 0 );
5720         break;
5721   }
5722
5723   return NULL;
5724 }
5725
5726 /*-----------------------------------------------------------------*/
5727 /*-----------------------------------------------------------------*/
5728 regs * pic16_getRegFromInstruction(pCode *pc)
5729 {
5730   if(!pc                   ||
5731      !isPCI(pc)            ||
5732      !PCI(pc)->pcop        ||
5733      PCI(pc)->num_ops == 0 ||
5734      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5735     return NULL;
5736
5737 #if 0
5738   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5739         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5740 #endif
5741
5742   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5743 }
5744
5745 /*-------------------------------------------------------------------------------*/
5746 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5747 /*-------------------------------------------------------------------------------*/
5748 regs * pic16_getRegFromInstruction2(pCode *pc)
5749 {
5750
5751   if(!pc                   ||
5752      !isPCI(pc)            ||
5753      !PCI(pc)->pcop        ||
5754      PCI(pc)->num_ops == 0 ||
5755      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5756     return NULL;
5757
5758   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5759     return NULL;
5760
5761 #if 0
5762   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5763         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5764 #endif
5765
5766   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5767 }
5768
5769 /*-----------------------------------------------------------------*/
5770 /*-----------------------------------------------------------------*/
5771
5772 static void AnalyzepBlock(pBlock *pb)
5773 {
5774   pCode *pc;
5775
5776   if(!pb)
5777     return;
5778
5779   /* Find all of the registers used in this pBlock
5780    * by looking at each instruction and examining it's
5781    * operands
5782    */
5783   for(pc = pb->pcHead; pc; pc = pc->next) {
5784
5785     /* Is this an instruction with operands? */
5786     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5787
5788       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5789
5790         /* Loop through all of the registers declared so far in
5791            this block and see if we find this one there */
5792
5793         regs *r = setFirstItem(pb->tregisters);
5794
5795         while(r) {
5796           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5797             PCOR(PCI(pc)->pcop)->r = r;
5798             break;
5799           }
5800           r = setNextItem(pb->tregisters);
5801         }
5802
5803         if(!r) {
5804           /* register wasn't found */
5805           //r = Safe_calloc(1, sizeof(regs));
5806           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5807           //addSet(&pb->tregisters, r);
5808           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5809           //PCOR(PCI(pc)->pcop)->r = r;
5810           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5811         }/* else
5812           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5813          */
5814       }
5815       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5816         if(PCOR(PCI(pc)->pcop)->r) {
5817           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5818           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5819         } else {
5820           if(PCI(pc)->pcop->name)
5821             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5822           else
5823             fprintf(stderr,"ERROR: NULL register\n");
5824         }
5825       }
5826     }
5827
5828
5829   }
5830 }
5831
5832 /*-----------------------------------------------------------------*/
5833 /* */
5834 /*-----------------------------------------------------------------*/
5835 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5836
5837 static void InsertpFlow(pCode *pc, pCode **pflow)
5838 {
5839   if(*pflow)
5840     PCFL(*pflow)->end = pc;
5841
5842   if(!pc || !pc->next)
5843     return;
5844
5845   *pflow = pic16_newpCodeFlow();
5846   pic16_pCodeInsertAfter(pc, *pflow);
5847 }
5848
5849 /*-----------------------------------------------------------------*/
5850 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5851 /*                         the flow blocks.                        */
5852 /*
5853  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5854  * point the instruction flow changes.
5855  */
5856 /*-----------------------------------------------------------------*/
5857 void pic16_BuildFlow(pBlock *pb)
5858 {
5859   pCode *pc;
5860   pCode *last_pci=NULL;
5861   pCode *pflow=NULL;
5862   int seq = 0;
5863
5864   if(!pb)
5865     return;
5866
5867   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5868   /* Insert a pCodeFlow object at the beginning of a pBlock */
5869
5870   InsertpFlow(pb->pcHead, &pflow);
5871
5872   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5873   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5874   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5875   //pb->pcHead = pflow;        /* Make the Flow object the head */
5876   //pflow->pb = pb;
5877
5878   for( pc = pic16_findNextInstruction(pb->pcHead);
5879        pc != NULL;
5880        pc=pic16_findNextInstruction(pc)) {
5881
5882     pc->seq = seq++;
5883     PCI(pc)->pcflow = PCFL(pflow);
5884
5885     //fprintf(stderr," build: ");
5886     //pflow->print(stderr,pflow);
5887
5888     if (checkLabel(pc)) {
5889
5890       /* This instruction marks the beginning of a
5891        * new flow segment */
5892
5893       pc->seq = 0;
5894       seq = 1;
5895
5896       /* If the previous pCode is not a flow object, then
5897        * insert a new flow object. (This check prevents
5898        * two consecutive flow objects from being insert in
5899        * the case where a skip instruction preceeds an
5900        * instruction containing a label.) */
5901
5902       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5903         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5904
5905       PCI(pc)->pcflow = PCFL(pflow);
5906
5907     }
5908
5909     if( PCI(pc)->isSkip) {
5910
5911       /* The two instructions immediately following this one
5912        * mark the beginning of a new flow segment */
5913
5914       while(pc && PCI(pc)->isSkip) {
5915
5916         PCI(pc)->pcflow = PCFL(pflow);
5917         pc->seq = seq-1;
5918         seq = 1;
5919
5920         InsertpFlow(pc, &pflow);
5921         pc=pic16_findNextInstruction(pc->next);
5922       }
5923
5924       seq = 0;
5925
5926       if(!pc)
5927         break;
5928
5929       PCI(pc)->pcflow = PCFL(pflow);
5930       pc->seq = 0;
5931       InsertpFlow(pc, &pflow);
5932
5933     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
5934
5935       InsertpFlow(pc, &pflow);
5936       seq = 0;
5937
5938     }
5939     last_pci = pc;
5940     pc = pc->next;
5941   }
5942
5943   //fprintf (stderr,",end seq %d",GpcFlowSeq);
5944   if(pflow)
5945     PCFL(pflow)->end = pb->pcTail;
5946 }
5947
5948 /*-------------------------------------------------------------------*/
5949 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5950 /*                           the flow blocks.                        */
5951 /*
5952  * unBuildFlow removes pCodeFlow objects from a pCode chain
5953  */
5954 /*-----------------------------------------------------------------*/
5955 static void unBuildFlow(pBlock *pb)
5956 {
5957   pCode *pc,*pcnext;
5958
5959   if(!pb)
5960     return;
5961
5962   pc = pb->pcHead;
5963
5964   while(pc) {
5965     pcnext = pc->next;
5966
5967     if(isPCI(pc)) {
5968
5969       pc->seq = 0;
5970       if(PCI(pc)->pcflow) {
5971         //Safe_free(PCI(pc)->pcflow);
5972         PCI(pc)->pcflow = NULL;
5973       }
5974
5975     } else if(isPCFL(pc) )
5976       pc->destruct(pc);
5977
5978     pc = pcnext;
5979   }
5980
5981
5982 }
5983 #if 0
5984 /*-----------------------------------------------------------------*/
5985 /*-----------------------------------------------------------------*/
5986 static void dumpCond(int cond)
5987 {
5988
5989   static char *pcc_str[] = {
5990     //"PCC_NONE",
5991     "PCC_REGISTER",
5992     "PCC_C",
5993     "PCC_Z",
5994     "PCC_DC",
5995     "PCC_OV",
5996     "PCC_N",
5997     "PCC_W",
5998     "PCC_EXAMINE_PCOP",
5999     "PCC_LITERAL",
6000     "PCC_REL_ADDR"
6001   };
6002
6003   int ncond = sizeof(pcc_str) / sizeof(char *);
6004   int i,j;
6005
6006   fprintf(stderr, "0x%04X\n",cond);
6007
6008   for(i=0,j=1; i<ncond; i++, j<<=1)
6009     if(cond & j)
6010       fprintf(stderr, "  %s\n",pcc_str[i]);
6011
6012 }
6013 #endif
6014
6015 #if 0
6016 /*-----------------------------------------------------------------*/
6017 /*-----------------------------------------------------------------*/
6018 static void FlowStats(pCodeFlow *pcflow)
6019 {
6020
6021   pCode *pc;
6022
6023   if(!isPCFL(pcflow))
6024     return;
6025
6026   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6027
6028   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6029
6030   if(!pc) {
6031     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6032     return;
6033   }
6034
6035
6036   fprintf(stderr, "  FlowStats inCond: ");
6037   dumpCond(pcflow->inCond);
6038   fprintf(stderr, "  FlowStats outCond: ");
6039   dumpCond(pcflow->outCond);
6040
6041 }
6042 #endif
6043 /*-----------------------------------------------------------------*
6044  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6045  *    if it affects the banking bits.
6046  *
6047  * return: -1 == Banking bits are unaffected by this pCode.
6048  *
6049  * return: > 0 == Banking bits are affected.
6050  *
6051  *  If the banking bits are affected, then the returned value describes
6052  * which bits are affected and how they're affected. The lower half
6053  * of the integer maps to the bits that are affected, the upper half
6054  * to whether they're set or cleared.
6055  *
6056  *-----------------------------------------------------------------*/
6057
6058 static int isBankInstruction(pCode *pc)
6059 {
6060   regs *reg;
6061   int bank = -1;
6062
6063   if(!isPCI(pc))
6064     return 0;
6065
6066   if( PCI(pc)->op == POC_MOVLB ||
6067       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6068     bank = PCOL(pc)->lit;
6069   }
6070
6071   return 1;
6072 }
6073
6074
6075 /*-----------------------------------------------------------------*/
6076 /*-----------------------------------------------------------------*/
6077 static void FillFlow(pCodeFlow *pcflow)
6078 {
6079
6080   pCode *pc;
6081   int cur_bank;
6082
6083   if(!isPCFL(pcflow))
6084     return;
6085
6086   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6087
6088   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6089
6090   if(!pc) {
6091     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6092     return;
6093   }
6094
6095   cur_bank = -1;
6096
6097   do {
6098     isBankInstruction(pc);
6099     pc = pc->next;
6100   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6101
6102 /*
6103   if(!pc ) {
6104     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6105   } else {
6106     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6107     pc->print(stderr,pc);
6108   }
6109
6110   fprintf(stderr, "  FillFlow inCond: ");
6111   dumpCond(pcflow->inCond);
6112   fprintf(stderr, "  FillFlow outCond: ");
6113   dumpCond(pcflow->outCond);
6114 */
6115 }
6116
6117 /*-----------------------------------------------------------------*/
6118 /*-----------------------------------------------------------------*/
6119 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6120 {
6121   pCodeFlowLink *fromLink, *toLink;
6122
6123   if(!from || !to || !to->pcflow || !from->pcflow)
6124     return;
6125
6126   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6127   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6128
6129   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6130   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6131
6132 }
6133
6134 pCode *pic16_getJumptabpCode (pCode *pc) {
6135   pCode *pcinf;
6136
6137   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6138   //pc->print (stderr, pc);
6139   pcinf = pc;
6140   while (pcinf) {
6141     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6142     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6143       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6144       case OPT_JUMPTABLE_BEGIN:
6145         /* leading begin of jump table -- in one */
6146         pcinf = pic16_findPrevInstruction (pcinf);
6147         return pcinf;
6148         break;
6149
6150       case OPT_JUMPTABLE_END:
6151         /* leading end of jumptable -- not in one */
6152         return NULL;
6153         break;
6154
6155       default:
6156         /* ignore all other PCInfos */
6157         break;
6158       }
6159     }
6160     pcinf = pcinf->prev;
6161   }
6162
6163   /* no PCInfo found -- not in a jumptable */
6164   return NULL;
6165 }
6166
6167 /*-----------------------------------------------------------------*
6168  * void LinkFlow(pBlock *pb)
6169  *
6170  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6171  * non-branching segments. In LinkFlow, we determine the execution
6172  * order of these segments. For example, if one of the segments ends
6173  * with a skip, then we know that there are two possible flow segments
6174  * to which control may be passed.
6175  *-----------------------------------------------------------------*/
6176 static void LinkFlow(pBlock *pb)
6177 {
6178   pCode *pc=NULL;
6179   pCode *pcflow;
6180   pCode *pct;
6181   pCode *jumptab_pre = NULL;
6182
6183   //fprintf(stderr,"linkflow \n");
6184
6185   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6186        pcflow != NULL;
6187        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6188
6189     if(!isPCFL(pcflow))
6190       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6191
6192     //fprintf(stderr," link: ");
6193     //pcflow->print(stderr,pcflow);
6194
6195     //FillFlow(PCFL(pcflow));
6196
6197     pc = PCFL(pcflow)->end;
6198
6199     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6200     if(isPCI_SKIP(pc)) {
6201 //      fprintf(stderr, "ends with skip\n");
6202 //      pc->print(stderr,pc);
6203
6204       pct=pic16_findNextInstruction(pc->next);
6205       LinkFlow_pCode(PCI(pc),PCI(pct));
6206       pct=pic16_findNextInstruction(pct->next);
6207       LinkFlow_pCode(PCI(pc),PCI(pct));
6208       continue;
6209     }
6210
6211     if(isPCI_BRANCH(pc)) {
6212       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6213
6214       /* handle GOTOs in jumptables */
6215       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6216         /* link to previous flow */
6217         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6218         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6219       }
6220
6221       switch (PCI(pc)->op) {
6222       case POC_GOTO:
6223       case POC_BRA:
6224       case POC_RETURN:
6225       case POC_RETLW:
6226       case POC_RETFIE:
6227               /* unconditional branches -- do not link to next instruction */
6228               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6229               break;
6230
6231       case POC_CALL:
6232       case POC_RCALL:
6233               /* unconditional calls -- link to next instruction */
6234               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6235               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6236               break;
6237
6238       case POC_BC:
6239       case POC_BN:
6240       case POC_BNC:
6241       case POC_BNN:
6242       case POC_BNOV:
6243       case POC_BNZ:
6244       case POC_BOV:
6245       case POC_BZ:
6246               /* conditional branches -- also link to next instruction */
6247               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6248               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6249               break;
6250
6251       default:
6252               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6253               assert (0 && "unhandled branching instruction");
6254               break;
6255       }
6256
6257       //fprintf(stderr, "ends with branch\n  ");
6258       //pc->print(stderr,pc);
6259
6260       if(!(pcol && isPCOLAB(pcol))) {
6261         if((PCI(pc)->op != POC_RETLW)
6262                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6263
6264                 /* continue if label is '$' which assembler knows how to parse */
6265                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6266
6267                 if(pic16_pcode_verbose) {
6268                         pc->print(stderr,pc);
6269                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6270                 }
6271         }
6272         continue;
6273       }
6274
6275       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6276         LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pct)));
6277       else
6278         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6279                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6280
6281 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6282
6283       continue;
6284     }
6285
6286     if(isPCI(pc)) {
6287       //fprintf(stderr, "ends with non-branching instruction:\n");
6288       //pc->print(stderr,pc);
6289
6290       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6291
6292       continue;
6293     }
6294
6295     if(pc) {
6296       //fprintf(stderr, "ends with unknown\n");
6297       //pc->print(stderr,pc);
6298       continue;
6299     }
6300
6301     //fprintf(stderr, "ends with nothing: ERROR\n");
6302
6303   }
6304 }
6305 /*-----------------------------------------------------------------*/
6306 /*-----------------------------------------------------------------*/
6307
6308 /*-----------------------------------------------------------------*/
6309 /*-----------------------------------------------------------------*/
6310 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6311 {
6312
6313   if(!pc || !pcflow)
6314     return 0;
6315
6316   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6317     return 0;
6318
6319   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6320     return 1;
6321
6322   return 0;
6323 }
6324
6325
6326
6327
6328
6329 /*-----------------------------------------------------------------*/
6330 /* insertBankSwitch - inserts a bank switch statement in the       */
6331 /*                    assembly listing                             */
6332 /*                                                                 */
6333 /* position == 0: insert before                                    */
6334 /* position == 1: insert after pc                                  */
6335 /* position == 2: like 0 but previous was a skip instruction       */
6336 /*-----------------------------------------------------------------*/
6337 pCodeOp *pic16_popGetLabel(unsigned int key);
6338 extern int pic16_labelOffset;
6339
6340 static void insertBankSwitch(unsigned char position, pCode *pc)
6341 {
6342   pCode *new_pc;
6343
6344         if(!pc)
6345                 return;
6346
6347         /* emit BANKSEL [symbol] */
6348
6349
6350         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6351
6352 //      position = 0;           // position is always before (sanity check!)
6353
6354 #if 0
6355         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6356         pc->print(stderr, pc);
6357 #endif
6358
6359         switch(position) {
6360                 case 1: {
6361                         /* insert the bank switch after this pc instruction */
6362                         pCode *pcnext = pic16_findNextInstruction(pc);
6363
6364                                 pic16_pCodeInsertAfter(pc, new_pc);
6365                                 if(pcnext)pc = pcnext;
6366                 }; break;
6367
6368                 case 0:
6369                         /* insert the bank switch BEFORE this pc instruction */
6370                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6371                         break;
6372
6373                 case 2: {
6374                           symbol *tlbl;
6375                           pCode *pcnext, *pcprev, *npci, *ppc;
6376                           PIC_OPCODE ipci;
6377                           int ofs1=0, ofs2=0, len=0;
6378
6379                         /* just like 0, but previous was a skip instruction,
6380                          * so some care should be taken */
6381
6382                                 pic16_labelOffset += 10000;
6383                                 tlbl = newiTempLabel(NULL);
6384
6385                                 /* invert skip instruction */
6386                                 pcprev = pic16_findPrevInstruction(pc->prev);
6387                                 ipci = PCI(pcprev)->inverted_op;
6388                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6389
6390 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6391
6392                                 /* copy info from old pCode */
6393                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6394                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6395                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6396                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6397                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6398                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6399
6400                                 /* unlink old pCode */
6401                                 ppc = pcprev->prev;
6402                                 ppc->next = pcprev->next;
6403                                 pcprev->next->prev = ppc;
6404                                 pic16_pCodeInsertAfter(ppc, npci);
6405
6406                                 /* extra instructions to handle invertion */
6407                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6408                                 pic16_pCodeInsertAfter(npci, pcnext);
6409                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6410
6411                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6412                                 pic16_pCodeInsertAfter(pc, pcnext);
6413                         }; break;
6414         }
6415
6416
6417         /* Move the label, if there is one */
6418         if(PCI(pc)->label) {
6419 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6420 //                      __FILE__, __LINE__, pc, new_pc);
6421                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6422                 PCI(pc)->label = NULL;
6423         }
6424 }
6425
6426
6427 #if 0
6428 /*-----------------------------------------------------------------*/
6429 /*int compareBankFlow - compare the banking requirements between   */
6430 /*  flow objects. */
6431 /*-----------------------------------------------------------------*/
6432 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6433 {
6434
6435   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6436     return 0;
6437
6438   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6439     return 0;
6440
6441   if(pcflow->firstBank == -1)
6442     return 0;
6443
6444
6445   if(pcflowLink->pcflow->firstBank == -1) {
6446     pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6447                                         pcflowLink->pcflow->to :
6448                                         pcflowLink->pcflow->from);
6449     return compareBankFlow(pcflow, pctl, toORfrom);
6450   }
6451
6452   if(toORfrom) {
6453     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6454       return 0;
6455
6456     pcflowLink->bank_conflict++;
6457     pcflowLink->pcflow->FromConflicts++;
6458     pcflow->ToConflicts++;
6459   } else {
6460
6461     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6462       return 0;
6463
6464     pcflowLink->bank_conflict++;
6465     pcflowLink->pcflow->ToConflicts++;
6466     pcflow->FromConflicts++;
6467
6468   }
6469   /*
6470   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6471           pcflowLink->pcflow->pc.seq,
6472           pcflowLink->pcflow->FromConflicts,
6473           pcflowLink->pcflow->ToConflicts);
6474   */
6475   return 1;
6476
6477 }
6478 #endif
6479
6480 #if 0
6481 /*-----------------------------------------------------------------*/
6482 /*-----------------------------------------------------------------*/
6483 static void DumpFlow(pBlock *pb)
6484 {
6485   pCode *pc=NULL;
6486   pCode *pcflow;
6487   pCodeFlowLink *pcfl;
6488
6489
6490   fprintf(stderr,"Dump flow \n");
6491   pb->pcHead->print(stderr, pb->pcHead);
6492
6493   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6494   pcflow->print(stderr,pcflow);
6495
6496   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6497        pcflow != NULL;
6498        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6499
6500     if(!isPCFL(pcflow)) {
6501       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6502       continue;
6503     }
6504     fprintf(stderr,"dumping: ");
6505     pcflow->print(stderr,pcflow);
6506     FlowStats(PCFL(pcflow));
6507
6508     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6509
6510       pc = PCODE(pcfl->pcflow);
6511
6512       fprintf(stderr, "    from seq %d:\n",pc->seq);
6513       if(!isPCFL(pc)) {
6514         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6515         pc->print(stderr,pc);
6516       }
6517
6518     }
6519
6520     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6521
6522       pc = PCODE(pcfl->pcflow);
6523
6524       fprintf(stderr, "    to seq %d:\n",pc->seq);
6525       if(!isPCFL(pc)) {
6526         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6527         pc->print(stderr,pc);
6528       }
6529
6530     }
6531
6532   }
6533
6534 }
6535 #endif
6536 /*-----------------------------------------------------------------*/
6537 /*-----------------------------------------------------------------*/
6538 static int OptimizepBlock(pBlock *pb)
6539 {
6540   pCode *pc, *pcprev;
6541   int matches =0;
6542
6543   if(!pb || !peepOptimizing)
6544     return 0;
6545
6546   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6547 /*
6548   for(pc = pb->pcHead; pc; pc = pc->next)
6549     matches += pic16_pCodePeepMatchRule(pc);
6550 */
6551
6552   pc = pic16_findNextInstruction(pb->pcHead);
6553   if(!pc)
6554     return 0;
6555
6556   pcprev = pc->prev;
6557   do {
6558
6559
6560     if(pic16_pCodePeepMatchRule(pc)) {
6561
6562       matches++;
6563
6564       if(pcprev)
6565         pc = pic16_findNextInstruction(pcprev->next);
6566       else
6567         pc = pic16_findNextInstruction(pb->pcHead);
6568     } else
6569       pc = pic16_findNextInstruction(pc->next);
6570   } while(pc);
6571
6572   if(matches)
6573     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6574   return matches;
6575
6576 }
6577
6578 /*-----------------------------------------------------------------*/
6579 /*-----------------------------------------------------------------*/
6580 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6581 {
6582   pCode *pc;
6583
6584   for(pc = pcs; pc; pc = pc->next) {
6585
6586     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6587        (PCI(pc)->pcop) &&
6588        (PCI(pc)->pcop->type == PO_LABEL) &&
6589        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6590       return pc;
6591   }
6592
6593
6594   return NULL;
6595 }
6596
6597 /*-----------------------------------------------------------------*/
6598 /*-----------------------------------------------------------------*/
6599 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6600 {
6601
6602   char *s=NULL;
6603
6604   if(isPCI(pc) &&
6605      (PCI(pc)->pcop) &&
6606      (PCI(pc)->pcop->type == PO_LABEL)) {
6607
6608     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6609
6610 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6611 //    if(pcol->pcop.name)
6612 //      Safe_free(pcol->pcop.name);
6613
6614     /* If the key is negative, then we (probably) have a label to
6615      * a function and the name is already defined */
6616
6617     if(pcl->key>0)
6618       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6619     else
6620       s = pcl->label;
6621
6622     //sprintf(buffer,"_%05d_DS_",pcl->key);
6623     if(!s) {
6624       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6625     }
6626     pcol->pcop.name = Safe_strdup(s);
6627     pcol->key = pcl->key;
6628     //pc->print(stderr,pc);
6629
6630   }
6631
6632
6633 }
6634
6635 /*-----------------------------------------------------------------*/
6636 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6637 /*                            pCode chain if they're not used.     */
6638 /*-----------------------------------------------------------------*/
6639 static void pBlockRemoveUnusedLabels(pBlock *pb)
6640 {
6641   pCode *pc; pCodeLabel *pcl;
6642
6643   if(!pb || !pb->pcHead)
6644     return;
6645
6646   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6647
6648     pBranch *pbr = PCI(pc)->label;
6649     if(pbr && pbr->next) {
6650       pCode *pcd = pb->pcHead;
6651
6652 //      fprintf(stderr, "multiple labels\n");
6653 //      pc->print(stderr,pc);
6654
6655       pbr = pbr->next;
6656       while(pbr) {
6657
6658         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6659           //fprintf(stderr,"Used by:\n");
6660           //pcd->print(stderr,pcd);
6661
6662           exchangeLabels(PCL(pbr->pc),pcd);
6663
6664           pcd = pcd->next;
6665         }
6666         pbr = pbr->next;
6667       }
6668     }
6669   }
6670
6671   for(pc = pb->pcHead; pc; pc = pc->next) {
6672
6673     if(isPCL(pc)) // pc->type == PC_LABEL)
6674       pcl = PCL(pc);
6675     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6676       pcl = PCL(PCI(pc)->label->pc);
6677     else continue;
6678
6679 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6680
6681     /* This pCode is a label, so search the pBlock to see if anyone
6682      * refers to it */
6683
6684     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6685         && (!pcl->force)) {
6686     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6687       /* Couldn't find an instruction that refers to this label
6688        * So, unlink the pCode label from it's pCode chain
6689        * and destroy the label */
6690 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6691
6692       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6693       if(pc->type == PC_LABEL) {
6694         pic16_unlinkpCode(pc);
6695         pCodeLabelDestruct(pc);
6696       } else {
6697         unlinkpCodeFromBranch(pc, PCODE(pcl));
6698         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6699           Safe_free(pc->label);
6700         }*/
6701       }
6702
6703     }
6704   }
6705
6706 }
6707
6708
6709 /*-----------------------------------------------------------------*/
6710 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6711 /*                     chain and put them into pBranches that are  */
6712 /*                     associated with the appropriate pCode       */
6713 /*                     instructions.                               */
6714 /*-----------------------------------------------------------------*/
6715 void pic16_pBlockMergeLabels(pBlock *pb)
6716 {
6717   pBranch *pbr;
6718   pCode *pc, *pcnext=NULL;
6719
6720   if(!pb)
6721     return;
6722
6723   /* First, Try to remove any unused labels */
6724   //pBlockRemoveUnusedLabels(pb);
6725
6726   /* Now loop through the pBlock and merge the labels with the opcodes */
6727
6728   pc = pb->pcHead;
6729   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6730
6731   while(pc) {
6732     pCode *pcn = pc->next;
6733
6734     if(pc->type == PC_LABEL) {
6735
6736 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6737 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6738
6739       if((pcnext = pic16_findNextInstruction(pc) )) {
6740
6741 //              pcnext->print(stderr, pcnext);
6742
6743         // Unlink the pCode label from it's pCode chain
6744         pic16_unlinkpCode(pc);
6745
6746 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6747         // And link it into the instruction's pBranch labels. (Note, since
6748         // it's possible to have multiple labels associated with one instruction
6749         // we must provide a means to accomodate the additional labels. Thus
6750         // the labels are placed into the singly-linked list "label" as
6751         // opposed to being a single member of the pCodeInstruction.)
6752
6753         //_ALLOC(pbr,sizeof(pBranch));
6754 #if 1
6755         pbr = Safe_calloc(1,sizeof(pBranch));
6756         pbr->pc = pc;
6757         pbr->next = NULL;
6758
6759         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6760 #endif
6761       } else {
6762         if(pic16_pcode_verbose)
6763         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6764       }
6765     } else if(pc->type == PC_CSOURCE) {
6766
6767       /* merge the source line symbolic info into the next instruction */
6768       if((pcnext = pic16_findNextInstruction(pc) )) {
6769
6770         // Unlink the pCode label from it's pCode chain
6771         pic16_unlinkpCode(pc);
6772         PCI(pcnext)->cline = PCCS(pc);
6773         //fprintf(stderr, "merging CSRC\n");
6774         //genericPrint(stderr,pcnext);
6775       }
6776
6777     }
6778     pc = pcn;
6779   }
6780   pBlockRemoveUnusedLabels(pb);
6781
6782 }
6783
6784 /*-----------------------------------------------------------------*/
6785 /*-----------------------------------------------------------------*/
6786 static int OptimizepCode(char dbName)
6787 {
6788 #define MAX_PASSES 4
6789
6790   int matches = 0;
6791   int passes = 0;
6792   pBlock *pb;
6793
6794   if(!the_pFile)
6795     return 0;
6796
6797   DFPRINTF((stderr," Optimizing pCode\n"));
6798
6799   do {
6800     matches = 0;
6801     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6802       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6803         matches += OptimizepBlock(pb);
6804     }
6805   }
6806   while(matches && ++passes < MAX_PASSES);
6807
6808   return matches;
6809 }
6810
6811
6812
6813 const char *pic16_pCodeOpType(pCodeOp *pcop);
6814 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6815
6816
6817 /*-----------------------------------------------------------------*/
6818 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6819 /*-----------------------------------------------------------------*/
6820
6821 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6822 {
6823   pCodeOp *pcop=NULL;
6824
6825 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6826
6827   if(pc->name) {
6828         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6829   } else {
6830     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6831   }
6832
6833   assert(pcop != NULL);
6834
6835   if( !( (pcop->type == PO_LABEL) ||
6836          (pcop->type == PO_LITERAL) ||
6837          (pcop->type == PO_STR) ))
6838     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6839     PCOR(pcop)->r->wasUsed = 1;
6840     PCOR(pcop)->instance = PCOR(pc)->instance;
6841
6842   return pcop;
6843 }
6844
6845
6846 /*----------------------------------------------------------------------*
6847  * pic16_areRegsSame - check to see if the names of two registers match *
6848  *----------------------------------------------------------------------*/
6849 int pic16_areRegsSame(regs *r1, regs *r2)
6850 {
6851         if(!strcmp(r1->name, r2->name))return 1;
6852
6853   return 0;
6854 }
6855
6856
6857 /*-----------------------------------------------------------------*/
6858 /*-----------------------------------------------------------------*/
6859 static void pic16_FixRegisterBanking(pBlock *pb)
6860 {
6861   pCode *pc=NULL;
6862   pCode *pcprev=NULL;
6863   regs *reg, *prevreg;
6864   unsigned char flag=0;
6865
6866         if(!pb)
6867                 return;
6868
6869         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6870         if(!pc)return;
6871
6872         /* loop through all of the flow blocks with in one pblock */
6873
6874 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6875
6876         prevreg = NULL;
6877         do {
6878                 /* at this point, pc should point to a PC_FLOW object */
6879                 /* for each flow block, determine the register banking
6880                  * requirements */
6881
6882
6883                 /* if label, then might come from other point, force banksel */
6884                 if(isPCL(pc))prevreg = NULL;
6885
6886                 if(!isPCI(pc))goto loop;
6887
6888                 if(PCI(pc)->label)prevreg = NULL;
6889
6890                 if(PCI(pc)->is2MemOp)goto loop;
6891
6892                 /* if goto, then force banksel */
6893 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6894
6895                 reg = pic16_getRegFromInstruction(pc);
6896
6897 #if 0
6898                 pc->print(stderr, pc);
6899                 fprintf(stderr, "reg = %p\n", reg);
6900
6901                 if(reg) {
6902                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6903                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6904                                 reg->address,reg->isBitField, reg->isFixed);
6905                 }
6906 #endif
6907
6908                 /* now make some tests to make sure that instruction needs bank switch */
6909
6910                 /* if no register exists, and if not a bit opcode goto loop */
6911                 if(!reg) {
6912                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6913                 }
6914
6915                 if(isPCI_SKIP(pc)) {
6916 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6917 //                prevreg = NULL;
6918                 }
6919                 if(reg && isACCESS_BANK(reg))goto loop;
6920
6921                 if(!isBankInstruction(pc))goto loop;
6922
6923                 if(isPCI_LIT(pc))goto loop;
6924
6925                 if(PCI(pc)->op == POC_CALL)goto loop;
6926
6927                 /* Examine the instruction before this one to make sure it is
6928                  * not a skip type instruction */
6929                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6930
6931                 flag = 0;               /* add before this instruction */
6932
6933                 /* if previous instruction is a skip one, then set flag
6934                  * to 2 and call insertBankSwitch */
6935                 if(pcprev && isPCI_SKIP(pcprev)) {
6936                   flag=2;       //goto loop
6937 //                prevreg = NULL;
6938                 }
6939
6940                 if(pic16_options.opt_banksel>0) {
6941                   char op1[128], op2[128];
6942
6943                     if(prevreg) {
6944                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6945                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6946                       if(!strcmp(op1, op2))goto loop;
6947                     }
6948                 }
6949                 prevreg = reg;
6950                 insertBankSwitch(flag, pc);
6951
6952 //              fprintf(stderr, "BANK SWITCH inserted\n");
6953
6954 loop:
6955                 pcprev = pc;
6956                 pc = pc->next;
6957         } while (pc);
6958 }
6959
6960 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6961
6962 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6963 int instrSize (pCode *pc)
6964 {
6965   if (!pc) return 0;
6966
6967   if (isPCAD(pc)) {
6968     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6969     return 4; // assumes only regular instructions using <= 4 bytes
6970   }
6971
6972   if (isPCI(pc)) return PCI(pc)->isize;
6973
6974   return 0;
6975 }
6976
6977 /* Returns 1 if pc is referenced by the given label (either
6978  * pc is the label itself or is an instruction with an attached
6979  * label).
6980  * Returns 0 if pc is not preceeded by the specified label.
6981  */
6982 int isLabel (pCode *pc, char *label)
6983 {
6984   if (!pc) return 0;
6985
6986   // label attached to the pCode?
6987   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
6988     pBranch *lab = NULL;
6989     lab = PCI(pc)->label;
6990
6991     while (lab) {
6992       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
6993         return 1;
6994       }
6995       lab = lab->next;
6996     } // while
6997   } // if
6998
6999   // is inline assembly label?
7000   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7001     // do not compare trailing ':'
7002     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7003       return 1;
7004     }
7005   } // if
7006
7007   // is pCodeLabel?
7008   if (isPCL(pc)) {
7009       if (strcmp(PCL(pc)->label,label) == 0) {
7010       return 1;
7011     }
7012   } // if
7013
7014   // no label/no label attached/wrong label(s)
7015   return 0;
7016 }
7017
7018 /* Returns the distance to the given label in terms of words.
7019  * Labels are searched only within -max .. max words from pc.
7020  * Returns max if the label could not be found or
7021  * its distance from pc in (-max..+max).
7022  */
7023 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7024   int dist = instrSize(pc);
7025   pCode *curr = pc;
7026
7027   // search backwards
7028   while (dist < max && curr && !isLabel (curr, label)) {
7029     curr = curr->prev;
7030     dist += instrSize(curr); // sizeof (instruction)
7031   } // while
7032   if (curr && dist < max) {
7033     if (target != NULL) *target = curr;
7034     return -dist;
7035   }
7036
7037   dist = 0;
7038   curr = pic16_findNextInstruction (pc->next);
7039   //search forwards
7040   while (dist < max && curr && !isLabel (curr, label)) {
7041     dist += instrSize(curr); // sizeof (instruction)
7042     curr = curr->next;
7043   } // while
7044   if (curr && dist < max) {
7045     if (target != NULL) *target = curr;
7046     return dist;
7047   }
7048
7049   if (target != NULL) *target = NULL;
7050   return max;
7051 }
7052
7053 /* Returns -1 if pc does NOT denote an instruction like
7054  * BTFS[SC] STATUS,i
7055  * Otherwise we return
7056  *   (a) 0x10 + i for BTFSS
7057  *   (b) 0x00 + i for BTFSC
7058  */
7059 int isSkipOnStatus (pCode *pc)
7060 {
7061   int res = -1;
7062   pCodeOp *pcop;
7063   if (!pc || !isPCI(pc)) return -1;
7064   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7065   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7066   else return -1;
7067
7068   pcop = PCI(pc)->pcop;
7069
7070   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7071     return res + ((pCodeOpRegBit *)pcop)->bit;
7072   }
7073
7074   return -1;
7075 }
7076
7077 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7078  * returns 0 otherwise. */
7079 int isConditionalBranch (pCode *pc)
7080 {
7081   if (!pc || !isPCI_BRANCH(pc)) return 0;
7082
7083   switch (PCI(pc)->op) {
7084   case POC_BC:
7085   case POC_BZ:
7086   case POC_BOV:
7087   case POC_BN:
7088   case POC_BNC:
7089   case POC_BNZ:
7090   case POC_BNOV:
7091   case POC_BNN:
7092     return 1;
7093
7094   default:
7095     break;
7096   } // switch
7097
7098   return 0;
7099 }
7100
7101 /* Returns 1 if pc has a label attached to it.
7102  * This can be either a label stored in the pCode itself (.label)
7103  * or a label making up its own pCode preceding this pc.
7104  * Returns 0 if pc cannot be reached directly via a label.
7105  */
7106 int hasNoLabel (pCode *pc)
7107 {
7108   pCode *prev;
7109   if (!pc) return 1;
7110
7111   // are there any label pCodes between pc and the previous instruction?
7112   prev = pic16_findPrevInstruction (pc->prev);
7113   while (pc && pc != prev) {
7114     // pCode with attached label?
7115     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7116         && PCI(pc)->label) {
7117       return 0;
7118     }
7119     // is inline assembly label?
7120     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7121     if (isPCW(pc) && PCW(pc)->label) return 0;
7122
7123     // pCodeLabel?
7124     if (isPCL(pc)) return 0;
7125
7126     pc = pc->prev;
7127   } // if
7128
7129   // no label found
7130   return 1;
7131 }
7132
7133 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7134   char buf[512];
7135   va_list va;
7136
7137   va_start (va, fmt);
7138   vsprintf (buf, fmt, va);
7139   va_end (va);
7140
7141   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7142 }
7143
7144 /* Replaces the old pCode with the new one, moving the labels,
7145  * C source line and probably flow information to the new pCode.
7146  */
7147 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7148   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7149     return;
7150
7151   /* first move all labels from old to new */
7152   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7153   PCI(oldPC)->label = NULL;
7154
7155 #if 0
7156   /* move C source line (if possible) */
7157   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7158     PCI(newPC)->cline = PCI(oldPC)->cline;
7159 #endif
7160
7161   /* keep flow information intact */
7162   newPC->seq = oldPC->seq;
7163   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7164   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7165     PCI(newPC)->pcflow->end = newPC;
7166   }
7167
7168   /* insert a comment stating which pCode has been replaced */
7169 #if 1
7170   if (pic16_pcode_verbose || pic16_debug_verbose) {
7171     char pc_str[256];
7172     pic16_pCode2str (pc_str, 256, oldPC);
7173     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7174   }
7175 #endif
7176
7177   /* insert new pCode into pBlock */
7178   pic16_pCodeInsertAfter (oldPC, newPC);
7179   pic16_unlinkpCode (oldPC);
7180
7181   /* destruct replaced pCode */
7182   oldPC->destruct (oldPC);
7183 }
7184
7185 /* Returns the inverted conditional branch (if any) or NULL.
7186  * pcop must be set to the new jump target.
7187  */
7188 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7189 {
7190   pCode *newBcc;
7191
7192   if (!bcc || !isPCI(bcc)) return NULL;
7193
7194   switch (PCI(bcc)->op) {
7195   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7196   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7197   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7198   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7199   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7200   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7201   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7202   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7203   default:
7204     newBcc = NULL;
7205   }
7206   return newBcc;
7207 }
7208
7209 #define MAX_DIST_GOTO         0x7FFFFFFF
7210 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7211 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7212 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7213 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7214
7215 /* Follows GOTO/BRA instructions to their target instructions, stores the
7216  * final destination (not a GOTO or BRA instruction) in target and returns
7217  * the distance from the original pc to *target.
7218  */
7219 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7220         pCode *curr = pc;
7221         pCode *last = NULL;
7222         pCodeOp *lastPCOP = NULL;
7223         int dist = 0;
7224         int depth = 0;
7225
7226         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7227
7228         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7229         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7230                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7231                 last = curr;
7232                 lastPCOP = PCI(curr)->pcop;
7233                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7234                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7235         } // while
7236
7237         if (target) *target = last;
7238         if (pcop) *pcop = lastPCOP;
7239         return dist;
7240 }
7241
7242 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7243  * Otherwise the first pCode after the jumptable (after
7244  * the OPT_JUMPTABLE_END tag) is returned.
7245  */
7246 pCode *skipJumptables (pCode *pc, int *isJumptable)
7247 {
7248   *isJumptable = 0;
7249   if (!pc) return NULL;
7250
7251   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7252     *isJumptable = 1;
7253     //fprintf (stderr, "SKIPPING jumptable\n");
7254     do {
7255       //pc->print(stderr, pc);
7256       pc = pc->next;
7257     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7258                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7259     //fprintf (stderr, "<<JUMPTAB:\n");
7260     // skip OPT_END as well
7261     if (pc) pc = pc->next;
7262   } // while
7263
7264   return pc;
7265 }
7266
7267 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7268 {
7269   int isJumptab;
7270   *isJumptable = 0;
7271   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7272     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7273     pc = skipJumptables (pc, &isJumptab);
7274     if (isJumptab) {
7275         // pc is the first pCode after the jumptable
7276         *isJumptable = 1;
7277     } else {
7278         // pc has not been changed by skipJumptables()
7279         pc = pc->next;
7280     }
7281   } // while
7282
7283   return pc;
7284 }
7285
7286 /* Turn GOTOs into BRAs if distance between GOTO and label
7287  * is less than 1024 bytes.
7288  *
7289  * This method is especially useful if GOTOs after BTFS[SC]
7290  * can be turned into BRAs as GOTO would cost another NOP
7291  * if skipped.
7292  */
7293 void pic16_OptimizeJumps ()
7294 {
7295   pCode *pc;
7296   pCode *pc_prev = NULL;
7297   pCode *pc_next = NULL;
7298   pBlock *pb;
7299   pCode *target;
7300   int change, iteration, isJumptab;
7301   int isHandled = 0;
7302   char *label;
7303   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7304
7305   if (!the_pFile) return;
7306
7307   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7308
7309   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7310     int matchedInvertRule = 1;
7311     iteration = 1;
7312     do {
7313       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7314       change = 0;
7315       pc = pic16_findNextInstruction (pb->pcHead);
7316
7317       while (pc) {
7318         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7319         if (isJumptab) {
7320                 // skip jumptable, i.e. start over with no pc_prev!
7321                 pc_prev = NULL;
7322                 pc = pc_next;
7323                 continue;
7324         } // if
7325
7326         /* (1) resolve chained jumps
7327          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7328          * (a) leave dead code in and
7329          * (b) skip over the dead code with an (unneccessary) jump.
7330          */
7331         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7332           pCodeOp *lastTargetOp = NULL;
7333           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7334           int maxDist = MAX_DIST_BCC;
7335           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7336           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7337
7338           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7339           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7340               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7341             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7342             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7343             PCI(pc)->pcop->name = lastTargetOp->name;
7344             change++;
7345             opt_gotochain++;
7346           } // if
7347         } // if
7348
7349
7350         if (IS_GOTO(pc)) {
7351           int dist;
7352           int condBraType = isSkipOnStatus(pc_prev);
7353           label = PCI(pc)->pcop->name;
7354           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7355           if (dist < 0) dist = -dist;
7356           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7357           isHandled = 0;
7358
7359
7360           /* (2) remove "GOTO label; label:" */
7361           if (isLabel (pc_next, label)) {
7362             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7363             // first remove all preceeding SKIP instructions
7364             while (pc_prev && isPCI_SKIP(pc_prev)) {
7365               // attach labels on this instruction to pc_next
7366               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7367               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7368               PCI(pc_prev)->label = NULL;
7369               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7370               pic16_unlinkpCode (pc_prev);
7371               pc_prev = pic16_findPrevInstruction (pc);
7372             } // while
7373             // now remove the redundant goto itself
7374             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7375             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7376             pic16_unlinkpCode (pc);
7377             pc = pic16_findPrevInstruction(pc_next->prev);
7378             isHandled = 1; // do not perform further optimizations
7379             opt_gotonext++;
7380             change++;
7381           } // if
7382
7383
7384           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7385           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7386             if (dist < MAX_DIST_BCC) {
7387               pCode *bcc = NULL;
7388               switch (condBraType) {
7389               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7390                 // no BDC on DIGIT CARRY available
7391               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7392               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7393               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7394               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7395                 // no BNDC on DIGIT CARRY available
7396               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7397               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7398               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7399               default:
7400                 // no replacement possible
7401                 bcc = NULL;
7402                 break;
7403               } // switch
7404               if (bcc) {
7405                 // ATTENTION: keep labels attached to BTFSx!
7406                 // HINT: GOTO is label free (checked above)
7407                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7408                 isHandled = 1; // do not perform further optimizations
7409                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7410                 pic16_pCodeReplace (pc_prev, bcc);
7411                 pc->destruct(pc);
7412                 pc = bcc;
7413                 opt_cond++;
7414                 change++;
7415               } // if
7416             } else {
7417               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7418               cond_toofar++;
7419             } // if
7420           } // if
7421
7422           if (!isHandled) {
7423             // (4) eliminate the following (common) tripel:
7424             //           <pred.>;
7425             //  labels1: Bcc label2;
7426             //           GOTO somewhere;    ; <-- instruction referenced by pc
7427             //  label2:  <cont.>
7428             // and replace it by
7429             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7430             //  label2:  <cont.>
7431             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7432             //            to <cont.> instead
7433             // ATTENTION: This optimization is only valid if <pred.> is
7434             //            not a skip operation!
7435             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7436             // ATTENTION: no label may be attached to the GOTO instruction!
7437             if (isConditionalBranch(pc_prev)
7438                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7439                 && (dist < MAX_DIST_BCC)
7440                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7441                 && hasNoLabel(pc)) {
7442               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7443
7444               if (newBcc) {
7445                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7446                 isHandled = 1; // do not perform further optimizations
7447                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7448                 pic16_pCodeReplace (pc_prev, newBcc);
7449                 pc->destruct(pc);
7450                 pc = newBcc;
7451                 opt_reorder++;
7452                 change++;
7453                 matchedInvertRule++;
7454               }
7455             }
7456           }
7457
7458           /* (5) now just turn GOTO into BRA */
7459           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7460             if (dist < MAX_DIST_BRA) {
7461               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7462               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7463               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7464               pic16_pCodeReplace (pc, newBra);
7465               pc = newBra;
7466               opt++;
7467               change++;
7468             } else {
7469               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7470               toofar++;
7471             }
7472           } // if (!isHandled)
7473         } // if
7474
7475         pc_prev = pc;
7476         pc = pc_next;
7477       } // while (pc)
7478
7479       pBlockRemoveUnusedLabels (pb);
7480
7481       // This line enables goto chain resolution!
7482       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7483
7484       iteration++;
7485     } while (change); /* fixpoint iteration per pBlock */
7486   } // for (pb)
7487
7488   // emit some statistics concerning goto-optimization
7489 #if 0
7490   if (pic16_debug_verbose || pic16_pcode_verbose) {
7491     fprintf (stderr, "optimize-goto:\n"
7492              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7493              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7494              "\t%5d conditional \"skipping\" jumps inverted\n"
7495              "\t%5d GOTOs to next instruction removed\n"
7496              "\t%5d chained GOTOs resolved\n",
7497              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7498   } // if
7499 #endif
7500   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7501 }
7502
7503 #undef IS_GOTO
7504 #undef MAX_JUMPCHAIN_DEPTH
7505 #undef MAX_DIST_GOTO
7506 #undef MAX_DIST_BRA
7507 #undef MAX_DIST_BCC
7508
7509 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7510
7511 static void pBlockDestruct(pBlock *pb)
7512 {
7513
7514   if(!pb)
7515     return;
7516
7517
7518 //  Safe_free(pb);
7519
7520 }
7521
7522 /*-----------------------------------------------------------------*/
7523 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7524 /*                                  name dbName and combine them   */
7525 /*                                  into one block                 */
7526 /*-----------------------------------------------------------------*/
7527 static void mergepBlocks(char dbName)
7528 {
7529
7530   pBlock *pb, *pbmerged = NULL,*pbn;
7531
7532   pb = the_pFile->pbHead;
7533
7534   //fprintf(stderr," merging blocks named %c\n",dbName);
7535   while(pb) {
7536
7537     pbn = pb->next;
7538     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7539     if( getpBlock_dbName(pb) == dbName) {
7540
7541       //fprintf(stderr," merged block %c\n",dbName);
7542
7543       if(!pbmerged) {
7544         pbmerged = pb;
7545       } else {
7546         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7547         /* pic16_addpCode2pBlock doesn't handle the tail: */
7548         pbmerged->pcTail = pb->pcTail;
7549
7550         pb->prev->next = pbn;
7551         if(pbn)
7552           pbn->prev = pb->prev;
7553
7554
7555         pBlockDestruct(pb);
7556       }
7557       //pic16_printpBlock(stderr, pbmerged);
7558     }
7559     pb = pbn;
7560   }
7561
7562 }
7563
7564 /*-----------------------------------------------------------------*/
7565 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7566 /*                                                                 */
7567 /* level 0 == minimal optimization                                 */
7568 /*   optimize registers that are used only by two instructions     */
7569 /* level 1 == maximal optimization                                 */
7570 /*   optimize by looking at pairs of instructions that use the     */
7571 /*   register.                                                     */
7572 /*-----------------------------------------------------------------*/
7573
7574 static void AnalyzeFlow(int level)
7575 {
7576   static int times_called=0;
7577   pBlock *pb;
7578
7579     if(!the_pFile) {
7580       /* remove unused allocated registers before exiting */
7581       pic16_RemoveUnusedRegisters();
7582       return;
7583     }
7584
7585
7586     /* if this is not the first time this function has been called,
7587      * then clean up old flow information */
7588     if(times_called++) {
7589       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7590         unBuildFlow(pb);
7591         pic16_RegsUnMapLiveRanges();
7592     }
7593     GpcFlowSeq = 1;
7594
7595     /* Phase 2 - Flow Analysis - Register Banking
7596      *
7597      * In this phase, the individual flow blocks are examined
7598      * and register banking is fixed.
7599      */
7600
7601 #if 0
7602     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7603       pic16_FixRegisterBanking(pb);
7604 #endif
7605
7606     /* Phase 2 - Flow Analysis
7607      *
7608      * In this phase, the pCode is partition into pCodeFlow
7609      * blocks. The flow blocks mark the points where a continuous
7610      * stream of instructions changes flow (e.g. because of
7611      * a call or goto or whatever).
7612      */
7613
7614     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7615       pic16_BuildFlow(pb);
7616
7617
7618     /* Phase 2 - Flow Analysis - linking flow blocks
7619      *
7620      * In this phase, the individual flow blocks are examined
7621      * to determine their order of excution.
7622      */
7623
7624     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7625       LinkFlow(pb);
7626
7627 #if 1
7628         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7629                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7630                         pic16_createDF (pb);
7631 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7632                         pic16_vcg_dump_default (pb);
7633 #endif
7634                         //pic16_destructDF (pb);
7635                 }
7636
7637                 pic16_df_stats ();
7638                 if (0) releaseStack (); // releasing is costly...
7639         }
7640 #endif
7641
7642     /* Phase 3 - Flow Analysis - Flow Tree
7643      *
7644      * In this phase, the individual flow blocks are examined
7645      * to determine their order of execution.
7646      */
7647
7648     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7649       pic16_BuildFlowTree(pb);
7650
7651
7652     /* Phase x - Flow Analysis - Used Banks
7653      *
7654      * In this phase, the individual flow blocks are examined
7655      * to determine the Register Banks they use
7656      */
7657
7658 #if 0
7659     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7660       FixBankFlow(pb);
7661 #endif
7662
7663
7664     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7665       pic16_pCodeRegMapLiveRanges(pb);
7666
7667     pic16_RemoveUnusedRegisters();
7668     pic16_removeUnusedRegistersDF ();
7669
7670   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7671     pic16_pCodeRegOptimizeRegUsage(level);
7672
7673
7674 #if 0
7675     if(!options.nopeep)
7676       OptimizepCode('*');
7677 #endif
7678
7679 #if 0
7680     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7681       DumpFlow(pb);
7682 #endif
7683
7684     /* debug stuff */
7685     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7686       pCode *pcflow;
7687
7688         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7689           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7690           pcflow = pcflow->next) {
7691             FillFlow(PCFL(pcflow));
7692         }
7693     }
7694
7695 #if 0
7696     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7697       pCode *pcflow;
7698
7699         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7700           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7701           pcflow = pcflow->next) {
7702             FlowStats(PCFL(pcflow));
7703         }
7704     }
7705 #endif
7706 }
7707
7708 /* VR -- no need to analyze banking in flow, but left here :
7709  *      1. because it may be used in the future for other purposes
7710  *      2. because if omitted we'll miss some optimization done here
7711  *
7712  * Perhaps I should rename it to something else
7713  */
7714
7715 /*-----------------------------------------------------------------*/
7716 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7717 /*                  assigned to the registers.                     */
7718 /*                                                                 */
7719 /*-----------------------------------------------------------------*/
7720
7721 void pic16_AnalyzeBanking(void)
7722 {
7723   pBlock  *pb;
7724
7725     /* Phase x - Flow Analysis - Used Banks
7726      *
7727      * In this phase, the individual flow blocks are examined
7728      * to determine the Register Banks they use
7729      */
7730
7731     AnalyzeFlow(0);
7732     AnalyzeFlow(1);
7733
7734     if(!options.nopeep)
7735       OptimizepCode('*');
7736
7737
7738     if(!the_pFile)return;
7739
7740     if(!pic16_options.no_banksel) {
7741       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7742 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7743         pic16_FixRegisterBanking(pb);
7744       }
7745     }
7746 }
7747
7748 /*-----------------------------------------------------------------*/
7749 /* buildCallTree - Look at the flow and extract all of the calls.  */
7750 /*-----------------------------------------------------------------*/
7751 #if 0
7752 static set *register_usage(pBlock *pb);
7753 #endif
7754
7755 static void buildCallTree(void    )
7756 {
7757   pBranch *pbr;
7758   pBlock  *pb;
7759   pCode   *pc;
7760   regs *r;
7761
7762   if(!the_pFile)
7763     return;
7764
7765
7766
7767   /* Now build the call tree.
7768      First we examine all of the pCodes for functions.
7769      Keep in mind that the function boundaries coincide
7770      with pBlock boundaries.
7771
7772      The algorithm goes something like this:
7773      We have two nested loops. The outer loop iterates
7774      through all of the pBlocks/functions. The inner
7775      loop iterates through all of the pCodes for
7776      a given pBlock. When we begin iterating through
7777      a pBlock, the variable pc_fstart, pCode of the start
7778      of a function, is cleared. We then search for pCodes
7779      of type PC_FUNCTION. When one is encountered, we
7780      initialize pc_fstart to this and at the same time
7781      associate a new pBranch object that signifies a
7782      branch entry. If a return is found, then this signifies
7783      a function exit point. We'll link the pCodes of these
7784      returns to the matching pc_fstart.
7785
7786      When we're done, a doubly linked list of pBranches
7787      will exist. The head of this list is stored in
7788      `the_pFile', which is the meta structure for all
7789      of the pCode. Look at the pic16_printCallTree function
7790      on how the pBranches are linked together.
7791
7792    */
7793   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7794     pCode *pc_fstart=NULL;
7795     for(pc = pb->pcHead; pc; pc = pc->next) {
7796
7797         if(isPCI(pc) && pc_fstart) {
7798                 if(PCI(pc)->is2MemOp) {
7799                         r = pic16_getRegFromInstruction2(pc);
7800                         if(r && !strcmp(r->name, "POSTDEC1"))
7801                                 PCF(pc_fstart)->stackusage++;
7802                 } else {
7803                         r = pic16_getRegFromInstruction(pc);
7804                         if(r && !strcmp(r->name, "PREINC1"))
7805                                 PCF(pc_fstart)->stackusage--;
7806                 }
7807         }
7808
7809       if(isPCF(pc)) {
7810         if (PCF(pc)->fname) {
7811         char buf[16];
7812
7813           sprintf(buf, "%smain", port->fun_prefix);
7814           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7815             //fprintf(stderr," found main \n");
7816             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7817             pb->dbName = 'M';
7818           }
7819
7820           pbr = Safe_calloc(1,sizeof(pBranch));
7821           pbr->pc = pc_fstart = pc;
7822           pbr->next = NULL;
7823
7824           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7825
7826           // Here's a better way of doing the same:
7827           addSet(&pb->function_entries, pc);
7828
7829         } else {
7830           // Found an exit point in a function, e.g. return
7831           // (Note, there may be more than one return per function)
7832           if(pc_fstart)
7833             pBranchLink(PCF(pc_fstart), PCF(pc));
7834
7835           addSet(&pb->function_exits, pc);
7836         }
7837       } else if(isCALL(pc)) {
7838         addSet(&pb->function_calls,pc);
7839       }
7840     }
7841   }
7842
7843
7844 #if 0
7845   /* This is not needed because currently all register used
7846    * by a function are stored in stack -- VR */
7847
7848   /* Re-allocate the registers so that there are no collisions
7849    * between local variables when one function call another */
7850
7851   // this is weird...
7852   //  pic16_deallocateAllRegs();
7853
7854   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7855     if(!pb->visited)
7856       register_usage(pb);
7857   }
7858 #endif
7859
7860 }
7861
7862 /*-----------------------------------------------------------------*/
7863 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7864 /*                all of the logical connections.                  */
7865 /*                                                                 */
7866 /* Essentially what's done here is that the pCode flow is          */
7867 /* determined.                                                     */
7868 /*-----------------------------------------------------------------*/
7869
7870 void pic16_AnalyzepCode(char dbName)
7871 {
7872   pBlock *pb;
7873   int i,changes;
7874
7875   if(!the_pFile)
7876     return;
7877
7878   mergepBlocks('D');
7879
7880
7881   /* Phase 1 - Register allocation and peep hole optimization
7882    *
7883    * The first part of the analysis is to determine the registers
7884    * that are used in the pCode. Once that is done, the peep rules
7885    * are applied to the code. We continue to loop until no more
7886    * peep rule optimizations are found (or until we exceed the
7887    * MAX_PASSES threshold).
7888    *
7889    * When done, the required registers will be determined.
7890    *
7891    */
7892   i = 0;
7893   do {
7894
7895     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7896     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7897
7898     /* First, merge the labels with the instructions */
7899     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7900       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7901
7902         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7903         //fprintf(stderr," analyze and merging block %c\n",dbName);
7904         pic16_pBlockMergeLabels(pb);
7905         AnalyzepBlock(pb);
7906       } else {
7907         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7908       }
7909     }
7910
7911         if(!options.nopeep)
7912                 changes = OptimizepCode(dbName);
7913         else changes = 0;
7914
7915   } while(changes && (i++ < MAX_PASSES));
7916
7917
7918   buildCallTree();
7919 }
7920
7921
7922 /* convert a series of movff's of local regs to stack, with a single call to
7923  * a support functions which does the same thing via loop */
7924 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7925 {
7926   pBranch *pbr;
7927   pCode *pc, *pct;
7928   char *fname[]={"__lr_store", "__lr_restore"};
7929
7930 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7931
7932     pct = pic16_findNextInstruction(pcstart->next);
7933     do {
7934       pc = pct;
7935       pct = pc->next;   //pic16_findNextInstruction(pc->next);
7936 //      pc->print(stderr, pc);
7937       if(isPCI(pc) && PCI(pc)->label) {
7938         pbr = PCI(pc)->label;
7939         while(pbr && pbr->pc) {
7940           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7941           pbr = pbr->next;
7942         }
7943
7944 //        pc->print(stderr, pc);
7945         /* unlink pCode */
7946         pc->prev->next = pct;
7947         pct->prev = pc->prev;
7948 //        pc->next = NULL;
7949 //        pc->prev = NULL;
7950       }
7951     } while ((pc) && (pc != pcend));
7952
7953     /* unlink movff instructions */
7954     pcstart->next = pcend;
7955     pcend->prev = pcstart;
7956
7957     pc = pcstart;
7958 //    if(!entry) {
7959 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7960 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7961 //    }
7962
7963     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7964     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7965     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7966
7967 //    if(!entry) {
7968 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7969 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7970 //    }
7971
7972
7973     {
7974       symbol *sym;
7975
7976         sym = newSymbol( fname[ entry?0:1 ], 0 );
7977         strcpy(sym->rname, fname[ entry?0:1 ]);
7978         checkAddSym(&externs, sym);
7979
7980 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7981     }
7982
7983 }
7984
7985 /*-----------------------------------------------------------------*/
7986 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
7987 /*    local registers to a support function call                   */
7988 /*-----------------------------------------------------------------*/
7989 void pic16_OptimizeLocalRegs(void)
7990 {
7991   pBlock  *pb;
7992   pCode   *pc;
7993   pCodeInfo *pci;
7994   pCodeOpLocalReg *pclr;
7995   int regCount=0;
7996   int inRegCount=0;
7997   regs *r, *lastr=NULL, *firstr=NULL;
7998   pCode *pcstart=NULL, *pcend=NULL;
7999   int inEntry=0;
8000   char *curFunc=NULL;
8001
8002         /* Overview:
8003          *   local_regs begin mark
8004          *      MOVFF r0x01, POSTDEC1
8005          *      MOVFF r0x02, POSTDEC1
8006          *      ...
8007          *      ...
8008          *      MOVFF r0x0n, POSTDEC1
8009          *   local_regs end mark
8010          *
8011          * convert the above to the below:
8012          *      MOVLW   starting_register_index
8013          *      MOVWF   PRODL
8014          *      MOVLW   register_count
8015          *      call    __save_registers_in_stack
8016          */
8017
8018     if(!the_pFile)
8019       return;
8020
8021     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8022       inRegCount = regCount = 0;
8023       firstr = lastr = NULL;
8024       for(pc = pb->pcHead; pc; pc = pc->next) {
8025
8026         /* hold current function name */
8027         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8028
8029         if(pc && (pc->type == PC_INFO)) {
8030           pci = PCINF(pc);
8031
8032           if(pci->type == INF_LOCALREGS) {
8033             pclr = PCOLR(pci->oper1);
8034
8035             if((pclr->type == LR_ENTRY_BEGIN)
8036               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8037             else inEntry = 0;
8038
8039             switch(pclr->type) {
8040               case LR_ENTRY_BEGIN:
8041               case LR_EXIT_BEGIN:
8042                         inRegCount = 1; regCount = 0;
8043                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8044                         firstr = lastr = NULL;
8045                         break;
8046
8047               case LR_ENTRY_END:
8048               case LR_EXIT_END:
8049                         inRegCount = -1;
8050                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8051
8052 #if 1
8053                         if(curFunc && inWparamList(curFunc+1)) {
8054                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8055                                         filename, curFunc);
8056                         } else {
8057                           if(regCount>2) {
8058                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8059                               firstr, inEntry);
8060                           }
8061                         }
8062 #endif
8063                         firstr = lastr = NULL;
8064                         break;
8065             }
8066
8067             if(inRegCount == -1) {
8068 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8069               regCount = 0;
8070               inRegCount = 0;
8071             }
8072           }
8073         } else {
8074           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8075             if(inEntry)
8076               r = pic16_getRegFromInstruction(pc);
8077             else
8078               r = pic16_getRegFromInstruction2(pc);
8079             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8080               if(!firstr)firstr = r;
8081               regCount++;
8082 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8083             }
8084           }
8085         }
8086       }
8087     }
8088 }
8089
8090
8091
8092
8093
8094 /*-----------------------------------------------------------------*/
8095 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8096 /*                   function                                      */
8097 /*-----------------------------------------------------------------*/
8098 static bool ispCodeFunction(pCode *pc)
8099 {
8100
8101   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8102     return 1;
8103
8104   return 0;
8105 }
8106
8107 /*-----------------------------------------------------------------*/
8108 /* findFunction - Search for a function by name (given the name)   */
8109 /*                in the set of all functions that are in a pBlock */
8110 /* (note - I expect this to change because I'm planning to limit   */
8111 /*  pBlock's to just one function declaration                      */
8112 /*-----------------------------------------------------------------*/
8113 static pCode *findFunction(char *fname)
8114 {
8115   pBlock *pb;
8116   pCode *pc;
8117   if(!fname)
8118     return NULL;
8119
8120   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8121
8122     pc = setFirstItem(pb->function_entries);
8123     while(pc) {
8124
8125       if((pc->type == PC_FUNCTION) &&
8126          (PCF(pc)->fname) &&
8127          (strcmp(fname, PCF(pc)->fname)==0))
8128         return pc;
8129
8130       pc = setNextItem(pb->function_entries);
8131
8132     }
8133
8134   }
8135   return NULL;
8136 }
8137
8138 #if 0
8139 static void MarkUsedRegisters(set *regset)
8140 {
8141
8142   regs *r1,*r2;
8143
8144   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8145 //      fprintf(stderr, "marking register = %s\t", r1->name);
8146     r2 = pic16_regWithIdx(r1->rIdx);
8147 //      fprintf(stderr, "to register = %s\n", r2->name);
8148     r2->isFree = 0;
8149     r2->wasUsed = 1;
8150   }
8151 }
8152 #endif
8153
8154 static void pBlockStats(FILE *of, pBlock *pb)
8155 {
8156
8157   pCode *pc;
8158   regs  *r;
8159
8160         if(!pic16_pcode_verbose)return;
8161
8162   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8163
8164   // for now just print the first element of each set
8165   pc = setFirstItem(pb->function_entries);
8166   if(pc) {
8167     fprintf(of,";entry:  ");
8168     pc->print(of,pc);
8169   }
8170   pc = setFirstItem(pb->function_exits);
8171   if(pc) {
8172     fprintf(of,";has an exit\n");
8173     //pc->print(of,pc);
8174   }
8175
8176   pc = setFirstItem(pb->function_calls);
8177   if(pc) {
8178     fprintf(of,";functions called:\n");
8179
8180     while(pc) {
8181       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8182         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8183       }
8184       pc = setNextItem(pb->function_calls);
8185     }
8186   }
8187
8188   r = setFirstItem(pb->tregisters);
8189   if(r) {
8190     int n = elementsInSet(pb->tregisters);
8191
8192     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8193
8194     while (r) {
8195       fprintf(of,   ";   %s\n",r->name);
8196       r = setNextItem(pb->tregisters);
8197     }
8198   }
8199
8200   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8201 }
8202
8203 /*-----------------------------------------------------------------*/
8204 /*-----------------------------------------------------------------*/
8205 #if 0
8206 static void sequencepCode(void)
8207 {
8208   pBlock *pb;
8209   pCode *pc;
8210
8211
8212   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8213
8214     pb->seq = GpCodeSequenceNumber+1;
8215
8216     for( pc = pb->pcHead; pc; pc = pc->next)
8217       pc->seq = ++GpCodeSequenceNumber;
8218   }
8219
8220 }
8221 #endif
8222
8223 #if 0
8224 /*-----------------------------------------------------------------*/
8225 /*-----------------------------------------------------------------*/
8226 static set *register_usage(pBlock *pb)
8227 {
8228   pCode *pc,*pcn;
8229   set *registers=NULL;
8230   set *registersInCallPath = NULL;
8231
8232   /* check recursion */
8233
8234   pc = setFirstItem(pb->function_entries);
8235
8236   if(!pc)
8237     return registers;
8238
8239   pb->visited = 1;
8240
8241   if(pc->type != PC_FUNCTION)
8242     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8243
8244   pc = setFirstItem(pb->function_calls);
8245   for( ; pc; pc = setNextItem(pb->function_calls)) {
8246
8247     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8248       char *dest = pic16_get_op_from_instruction(PCI(pc));
8249
8250       pcn = findFunction(dest);
8251       if(pcn)
8252         registersInCallPath = register_usage(pcn->pb);
8253     } else
8254       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8255
8256   }
8257
8258 #ifdef PCODE_DEBUG
8259   pBlockStats(stderr,pb);  // debug
8260 #endif
8261
8262   // Mark the registers in this block as used.
8263
8264   MarkUsedRegisters(pb->tregisters);
8265   if(registersInCallPath) {
8266     /* registers were used in the functions this pBlock has called */
8267     /* so now, we need to see if these collide with the ones we are */
8268     /* using here */
8269
8270     regs *r1,*r2, *newreg;
8271
8272     DFPRINTF((stderr,"comparing registers\n"));
8273
8274     r1 = setFirstItem(registersInCallPath);
8275     while(r1) {
8276
8277       r2 = setFirstItem(pb->tregisters);
8278
8279       while(r2 && (r1->type != REG_STK)) {
8280
8281         if(r2->rIdx == r1->rIdx) {
8282           newreg = pic16_findFreeReg(REG_GPR);
8283
8284
8285           if(!newreg) {
8286             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8287             exit(1);
8288           }
8289
8290           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8291                   r1->rIdx, newreg->rIdx));
8292           r2->rIdx = newreg->rIdx;
8293           //if(r2->name) Safe_free(r2->name);
8294           if(newreg->name)
8295             r2->name = Safe_strdup(newreg->name);
8296           else
8297             r2->name = NULL;
8298           newreg->isFree = 0;
8299           newreg->wasUsed = 1;
8300         }
8301         r2 = setNextItem(pb->tregisters);
8302       }
8303
8304       r1 = setNextItem(registersInCallPath);
8305     }
8306
8307     /* Collisions have been resolved. Now free the registers in the call path */
8308     r1 = setFirstItem(registersInCallPath);
8309     while(r1) {
8310       if(r1->type != REG_STK) {
8311         newreg = pic16_regWithIdx(r1->rIdx);
8312         newreg->isFree = 1;
8313       }
8314       r1 = setNextItem(registersInCallPath);
8315     }
8316
8317   }// else
8318   //    MarkUsedRegisters(pb->registers);
8319
8320   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8321 #ifdef PCODE_DEBUG
8322   if(registers)
8323     DFPRINTF((stderr,"returning regs\n"));
8324   else
8325     DFPRINTF((stderr,"not returning regs\n"));
8326
8327   DFPRINTF((stderr,"pBlock after register optim.\n"));
8328   pBlockStats(stderr,pb);  // debug
8329 #endif
8330
8331   return registers;
8332 }
8333 #endif
8334
8335 /*-----------------------------------------------------------------*/
8336 /* pct2 - writes the call tree to a file                           */
8337 /*                                                                 */
8338 /*-----------------------------------------------------------------*/
8339 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8340 {
8341   pCode *pc,*pcn;
8342   int i;
8343   //  set *registersInCallPath = NULL;
8344
8345   if(!of)
8346     return;
8347
8348   if(indent > 10) {
8349         fprintf(of, "recursive function\n");
8350     return; //recursion ?
8351   }
8352
8353   pc = setFirstItem(pb->function_entries);
8354
8355   if(!pc)
8356     return;
8357
8358   pb->visited = 0;
8359
8360   for(i=0;i<indent;i++)   // Indentation
8361         fputs("+   ", of);
8362   fputs("+- ", of);
8363
8364   if(pc->type == PC_FUNCTION) {
8365     usedstack += PCF(pc)->stackusage;
8366     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8367   } else return;  // ???
8368
8369
8370   pc = setFirstItem(pb->function_calls);
8371   for( ; pc; pc = setNextItem(pb->function_calls)) {
8372
8373     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8374       char *dest = pic16_get_op_from_instruction(PCI(pc));
8375
8376       pcn = findFunction(dest);
8377       if(pcn)
8378         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8379     } else
8380       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8381
8382   }
8383
8384
8385 }
8386
8387
8388 /*-----------------------------------------------------------------*/
8389 /* pic16_printCallTree - writes the call tree to a file                  */
8390 /*                                                                 */
8391 /*-----------------------------------------------------------------*/
8392
8393 void pic16_printCallTree(FILE *of)
8394 {
8395   pBranch *pbr;
8396   pBlock  *pb;
8397   pCode   *pc;
8398
8399   if(!the_pFile)
8400     return;
8401
8402   if(!of)
8403     of = stderr;
8404
8405   fprintf(of, "\npBlock statistics\n");
8406   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8407     pBlockStats(of,pb);
8408
8409
8410   fprintf(of,"Call Tree\n");
8411   pbr = the_pFile->functions;
8412   while(pbr) {
8413     if(pbr->pc) {
8414       pc = pbr->pc;
8415       if(!ispCodeFunction(pc))
8416         fprintf(of,"bug in call tree");
8417
8418
8419       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8420
8421       while(pc->next && !ispCodeFunction(pc->next)) {
8422         pc = pc->next;
8423         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8424           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8425       }
8426     }
8427
8428     pbr = pbr->next;
8429   }
8430
8431
8432   fprintf(of,"\n**************\n\na better call tree\n");
8433   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8434 //    if(pb->visited)
8435       pct2(of,pb,0,0);
8436   }
8437
8438   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8439     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8440   }
8441 }
8442
8443
8444
8445 /*-----------------------------------------------------------------*/
8446 /*                                                                 */
8447 /*-----------------------------------------------------------------*/
8448
8449 static void InlineFunction(pBlock *pb)
8450 {
8451   pCode *pc;
8452   pCode *pc_call;
8453
8454   if(!pb)
8455     return;
8456
8457   pc = setFirstItem(pb->function_calls);
8458
8459   for( ; pc; pc = setNextItem(pb->function_calls)) {
8460
8461     if(isCALL(pc)) {
8462       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8463       pCode *pct;
8464       pCode *pce;
8465
8466       pBranch *pbr;
8467
8468       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8469
8470         //fprintf(stderr,"Cool can inline:\n");
8471         //pcn->print(stderr,pcn);
8472
8473         //fprintf(stderr,"recursive call Inline\n");
8474         InlineFunction(pcn->pb);
8475         //fprintf(stderr,"return from recursive call Inline\n");
8476
8477         /*
8478           At this point, *pc points to a CALL mnemonic, and
8479           *pcn points to the function that is being called.
8480
8481           To in-line this call, we need to remove the CALL
8482           and RETURN(s), and link the function pCode in with
8483           the CALLee pCode.
8484
8485         */
8486
8487
8488         /* Remove the CALL */
8489         pc_call = pc;
8490         pc = pc->prev;
8491
8492         /* remove callee pBlock from the pBlock linked list */
8493         removepBlock(pcn->pb);
8494
8495         pce = pcn;
8496         while(pce) {
8497           pce->pb = pb;
8498           pce = pce->next;
8499         }
8500
8501         /* Remove the Function pCode */
8502         pct = pic16_findNextInstruction(pcn->next);
8503
8504         /* Link the function with the callee */
8505         pc->next = pcn->next;
8506         pcn->next->prev = pc;
8507
8508         /* Convert the function name into a label */
8509
8510         pbr = Safe_calloc(1,sizeof(pBranch));
8511         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8512         pbr->next = NULL;
8513         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8514         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8515
8516         /* turn all of the return's except the last into goto's */
8517         /* check case for 2 instruction pBlocks */
8518         pce = pic16_findNextInstruction(pcn->next);
8519         while(pce) {
8520           pCode *pce_next = pic16_findNextInstruction(pce->next);
8521
8522           if(pce_next == NULL) {
8523             /* found the last return */
8524             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8525
8526             //fprintf(stderr,"found last return\n");
8527             //pce->print(stderr,pce);
8528             pce->prev->next = pc_call->next;
8529             pc_call->next->prev = pce->prev;
8530             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8531                                                       PCI(pce)->label);
8532           }
8533
8534           pce = pce_next;
8535         }
8536
8537
8538       }
8539     } else
8540       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8541
8542   }
8543
8544 }
8545
8546 /*-----------------------------------------------------------------*/
8547 /*                                                                 */
8548 /*-----------------------------------------------------------------*/
8549
8550 void pic16_InlinepCode(void)
8551 {
8552
8553   pBlock  *pb;
8554   pCode   *pc;
8555
8556   if(!the_pFile)
8557     return;
8558
8559   if(!functionInlining)
8560     return;
8561
8562   /* Loop through all of the function definitions and count the
8563    * number of times each one is called */
8564   //fprintf(stderr,"inlining %d\n",__LINE__);
8565
8566   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8567
8568     pc = setFirstItem(pb->function_calls);
8569
8570     for( ; pc; pc = setNextItem(pb->function_calls)) {
8571
8572       if(isCALL(pc)) {
8573         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8574         if(pcn && isPCF(pcn)) {
8575           PCF(pcn)->ncalled++;
8576         }
8577       } else
8578         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8579
8580     }
8581   }
8582
8583   //fprintf(stderr,"inlining %d\n",__LINE__);
8584
8585   /* Now, Loop through the function definitions again, but this
8586    * time inline those functions that have only been called once. */
8587
8588   InlineFunction(the_pFile->pbHead);
8589   //fprintf(stderr,"inlining %d\n",__LINE__);
8590
8591   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8592     unBuildFlow(pb);
8593
8594 }
8595
8596 char *pic_optype_names[]={
8597         "PO_NONE",         // No operand e.g. NOP
8598         "PO_W",              // The working register (as a destination)
8599         "PO_WREG",           // The working register (as a file register)
8600         "PO_STATUS",         // The 'STATUS' register
8601         "PO_BSR",            // The 'BSR' register
8602         "PO_FSR0",           // The "file select register" (in PIC18 family it's one
8603                              // of three)
8604         "PO_INDF0",          // The Indirect register
8605         "PO_INTCON",         // Interrupt Control register
8606         "PO_GPR_REGISTER",   // A general purpose register
8607         "PO_GPR_BIT",        // A bit of a general purpose register
8608         "PO_GPR_TEMP",       // A general purpose temporary register
8609         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8610         "PO_PCL",            // Program counter Low register
8611         "PO_PCLATH",         // Program counter Latch high register
8612         "PO_PCLATU",         // Program counter Latch upper register
8613         "PO_PRODL",          // Product Register Low
8614         "PO_PRODH",          // Product Register High
8615         "PO_LITERAL",        // A constant
8616         "PO_REL_ADDR",       // A relative address
8617         "PO_IMMEDIATE",      //  (8051 legacy)
8618         "PO_DIR",            // Direct memory (8051 legacy)
8619         "PO_CRY",            // bit memory (8051 legacy)
8620         "PO_BIT",            // bit operand.
8621         "PO_STR",            //  (8051 legacy)
8622         "PO_LABEL",
8623         "PO_WILD",           // Wild card operand in peep optimizer
8624         "PO_TWO_OPS"         // combine two operands
8625 };
8626
8627
8628 char *dumpPicOptype(PIC_OPTYPE type)
8629 {
8630         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8631         return (pic_optype_names[ type ]);
8632 }
8633
8634
8635 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8636 #include "graph.h"
8637
8638 #define MAX_COMMON_BANK_SIZE    32
8639 #define FIRST_PSEUDO_BANK_NR  1000
8640
8641 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8642 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8643 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8644 Graph *adj = NULL;
8645
8646 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8647
8648 typedef struct {
8649   pseudoBankNr bank;  // number assigned to this pseudoBank
8650   unsigned int size;  // number of operands assigned to this bank
8651   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8652 } pseudoBank;
8653
8654 /*----------------------------------------------------------------------*/
8655 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8656 /*----------------------------------------------------------------------*/
8657 unsigned int hashSymbol (const char *str)
8658 {
8659   unsigned int res = 0;
8660   if (!str) return 0;
8661
8662   while (*str) {
8663     res ^= (*str);
8664     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8665     str++;
8666   } // while
8667
8668   return res;
8669 }
8670
8671 /*-----------------------------------------------------------------------*/
8672 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8673 /*-----------------------------------------------------------------------*/
8674 int compareSymbol (const void *sym1, const void *sym2)
8675 {
8676   char *s1 = (char*) sym1;
8677   char *s2 = (char*) sym2;
8678
8679   return (strcmp (s1,s2) == 0);
8680 }
8681
8682 /*-----------------------------------------------------------------------*/
8683 /* comparePre - return 1 iff p1 == p2                                    */
8684 /*-----------------------------------------------------------------------*/
8685 int comparePtr (const void *p1, const void *p2)
8686 {
8687   return (p1 == p2);
8688 }
8689
8690 /*----------------------------------------------------------*/
8691 /* getSymbolFromOperand - return a pointer to the symbol in */
8692 /*                        the given operand and its length  */
8693 /*----------------------------------------------------------*/
8694 char *getSymbolFromOperand (char *op, int *len)
8695 {
8696   char *sym, *curr;
8697   *len = 0;
8698
8699   if (!op) return NULL;
8700
8701   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8702   sym = op;
8703   if (*sym == '(') sym++;
8704
8705   curr = sym;
8706   while (((*curr >= 'A') && (*curr <= 'Z'))
8707          || ((*curr >= 'a') && (*curr <= 'z'))
8708          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8709          || (*curr == '_')) {
8710     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8711     curr++;
8712     (*len)++;
8713   } // while
8714
8715   return sym;
8716 }
8717
8718 /*--------------------------------------------------------------------------*/
8719 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8720 /*--------------------------------------------------------------------------*/
8721 char *getSymFromBank (pseudoBankNr bank)
8722 {
8723   assert (bank2sym);
8724
8725   if (bank < 0) return "<INVALID BANK NR>";
8726   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8727 }
8728
8729 /*-----------------------------------------------------------------------*/
8730 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8731 /*                           bank number (uses hTab sym2bank), if the    */
8732 /*                           symbol is not yet assigned a pseudo bank it */
8733 /*                           is assigned one here                        */
8734 /*-----------------------------------------------------------------------*/
8735 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8736 {
8737   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8738   pseudoBankNr bank;
8739   unsigned int hash;
8740
8741   assert (sym2bank);
8742
8743   hash = hashSymbol (op) % sym2bank->size;
8744   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8745   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8746
8747   if (bank == UNKNOWN_BANK) {
8748     // create a pseudo bank for the operand
8749     bank = next_bank++;
8750     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8751     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8752     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8753     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8754   } else {
8755     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8756   } // if
8757
8758   assert (bank >= 0);
8759
8760   return bank;
8761 }
8762
8763 /*--------------------------------------------------------------------*/
8764 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8765 /*--------------------------------------------------------------------*/
8766 int isBanksel (pCode *pc)
8767 {
8768   if (!pc) return 0;
8769
8770   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8771     // BANKSEL <variablename>  or  MOVLB <banknr>
8772     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8773     return 1;
8774   }
8775
8776   // check for inline assembler BANKSELs
8777   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8778                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8779     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8780     return 1;
8781   }
8782
8783   // assume pc is no BANKSEL instruction
8784   return 0;
8785 }
8786
8787 /*---------------------------------------------------------------------------------*/
8788 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8789 /*                  This method can not guarantee to find all modifications of the */
8790 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8791 /*                  generated plus some cases.                                     */
8792 /*---------------------------------------------------------------------------------*/
8793 int invalidatesBSR(pCode *pc)
8794 {
8795   // assembler directives invalidate BSR (well, they might, we don't know)
8796   if (isPCAD(pc)) return 1;
8797
8798   // only ASMDIRs and pCodeInstructions can invalidate BSR
8799   if (!isPCI(pc)) return 0;
8800
8801   // we have a pCodeInstruction
8802
8803   // check for BSR modifying instructions
8804   switch (PCI(pc)->op) {
8805   case POC_CALL:
8806   case POC_RCALL:
8807   case POC_MOVLB:
8808   case POC_RETFIE:  // might be used as CALL replacement
8809   case POC_RETLW:   // might be used as CALL replacement
8810   case POC_RETURN:  // might be used as CALL replacement
8811   case POC_BANKSEL:
8812     return 1;
8813     break;
8814
8815   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8816     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8817     break;
8818   } // switch
8819
8820   // no change of BSR possible/probable
8821   return 0;
8822 }
8823
8824 /*------------------------------------------------------------*/
8825 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8826 /*                      the symbol referenced in this BANKSEL */
8827 /*------------------------------------------------------------*/
8828 pseudoBankNr getBankFromBanksel (pCode *pc)
8829 {
8830   char *sym;
8831   int data = 0;
8832
8833   if (!pc) return INVALID_BANK;
8834
8835   if (isPCAD(pc) && PCAD(pc)->directive) {
8836     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8837       // get symbolname from PCAD(pc)->arg
8838       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8839       sym = PCAD(pc)->arg;
8840       data = getPseudoBankNrFromOperand (sym);
8841       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8842     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8843       // get (literal) bank number from PCAD(pc)->arg
8844       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8845       assert (0 && "not yet implemented - turn off banksel optimization for now");
8846     }
8847   } else if (isPCI(pc)) {
8848     if (PCI(pc)->op == POC_BANKSEL) {
8849       // get symbolname from PCI(pc)->pcop->name (?)
8850       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8851       sym = PCI(pc)->pcop->name;
8852       data = getPseudoBankNrFromOperand (sym);
8853       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8854     } else if (PCI(pc)->op == POC_MOVLB) {
8855       // get (literal) bank number from PCI(pc)->pcop->name
8856       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8857       assert (0 && "not yet implemented - turn off banksel optimization for now");
8858     }
8859   }
8860
8861   if (data == 0)
8862     // no assigned bank could be found
8863     return UNKNOWN_BANK;
8864   else
8865     return data;
8866 }
8867
8868 /*------------------------------------------------------------------------------*/
8869 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8870 /*------------------------------------------------------------------------------*/
8871 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8872 {
8873   pseudoBank *data;
8874
8875   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8876
8877   do {
8878     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8879     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8880     if (data) {
8881       if (data->bank != bank)
8882         bank = data->bank;
8883       else
8884         data = NULL;
8885     }
8886   } while (data);
8887
8888   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8889   return bank;
8890 }
8891
8892 /*------------------------------------------------------------------*/
8893 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8894 /*                        bank is selected at a given pCode         */
8895 /*------------------------------------------------------------------*/
8896
8897 /* Create a graph with pseudo banks as its nodes and switches between
8898  * these as edges (with the edge weight representing the absolute
8899  * number of BANKSELs from one to the other).
8900  * Removes redundand BANKSELs instead iff mod == 1.
8901  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8902  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8903  * pseudo BSR.
8904  * TODO: check ALL instructions operands if they modify BSR directly...
8905  *
8906  * pb - the pBlock to annotate
8907  * mod  - select either graph creation (0) or BANKSEL removal (1)
8908  */
8909 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8910 {
8911   pCode *pc, *pc_next;
8912   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8913   int isBankselect = 0;
8914   unsigned int banksels=0;
8915
8916   if (!pb) return 0;
8917
8918   pc = pic16_findNextInstruction(pb->pcHead);
8919   while (pc) {
8920     isBankselect = isBanksel (pc);
8921     pc_next = pic16_findNextInstruction (pc->next);
8922
8923     if (!hasNoLabel (pc)) {
8924       // we don't know our predecessors -- assume different BSRs
8925       prevBSR = UNKNOWN_BANK;
8926       pseudoBSR = UNKNOWN_BANK;
8927       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8928     } // if
8929
8930     // check if this is a BANKSEL instruction
8931     if (isBankselect) {
8932       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8933       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8934       if (mod) {
8935         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8936           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8937           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8938           pic16_unlinkpCode (pc);
8939           banksels++;
8940         }
8941       } else {
8942         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8943         banksels++;
8944       }
8945     } // if
8946
8947     if (!isBankselect && invalidatesBSR(pc)) {
8948       // check if this instruction invalidates the pseudoBSR
8949       pseudoBSR = UNKNOWN_BANK;
8950       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8951     } // if
8952
8953     prevBSR = pseudoBSR;
8954     pc = pc_next;
8955   } // while
8956
8957   return banksels;
8958 }
8959
8960 /*------------------------------------------------------------------------------------*/
8961 /* assignToSameBank - returns 0 on success or an error code                           */
8962 /*  1 - common bank would be too large                                                */
8963 /*  2 - assignment to fixed (absolute) bank not performed                             */
8964 /*                                                                                    */
8965 /* This functions assumes that unsplittable operands are already assigned to the same */
8966 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
8967 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
8968 /* TODO: Symbols with an abslute address must be handled specially!                   */
8969 /*------------------------------------------------------------------------------------*/
8970 int assignToSameBank (int bank0, int bank1, int doAbs, int force)
8971 {
8972   int eff0, eff1, dummy;
8973   pseudoBank *pbank0, *pbank1;
8974   hashtItem *hitem;
8975
8976   eff0 = getEffectiveBank (bank0);
8977   eff1 = getEffectiveBank (bank1);
8978
8979   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8980
8981   // nothing to do if already same bank
8982   if (eff0 == eff1) return 0;
8983
8984   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8985     return 2;
8986
8987   // ensure eff0 < eff1
8988   if (eff0 > eff1) {
8989     // swap eff0 and eff1
8990     dummy = eff0;
8991     eff0 = eff1;
8992     eff1 = dummy;
8993     dummy = bank0;
8994     bank0 = bank1;
8995     bank1 = dummy;
8996   } // if
8997
8998   // now assign bank eff1 to bank eff0
8999   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9000   if (!pbank0) {
9001     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9002     pbank0->bank = eff0;
9003     pbank0->size = 1;
9004     pbank0->ref = 1;
9005     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9006   } // if
9007
9008   pbank1 = NULL;
9009   hitem = hTabSearch (coerce, eff1 % coerce->size);
9010   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9011     hitem = hitem->next;
9012
9013   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9014
9015 #if 0
9016   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9017            pbank0->bank, pbank0->size,
9018            getSymFromBank (eff0), getSymFromBank (eff1));
9019 #endif
9020
9021   if (pbank1) {
9022     if (!force && (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE)) {
9023 #if 0
9024       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9025                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9026                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9027                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9028 #endif
9029       return 1;
9030     } // if
9031     pbank0->size += pbank1->size;
9032     pbank1->ref--;
9033     if (pbank1->ref == 0) Safe_free (pbank1);
9034   } else {
9035     pbank0->size++;
9036   } // if
9037
9038   if (hitem)
9039     hitem->item = pbank0;
9040   else
9041     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9042   pbank0->ref++;
9043
9044   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9045
9046   return 0;
9047 }
9048
9049 /*----------------------------------------------------------------*/
9050 /* mergeGraphNodes - combines two nodes into one and modifies all */
9051 /*                   edges to and from the nodes accordingly      */
9052 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9053 /* then also (B,A) must be an edge (possibly with weight 0).      */
9054 /*----------------------------------------------------------------*/
9055 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9056 {
9057   GraphEdge *edge, *backedge, *nextedge;
9058   GraphNode *node;
9059   int backweight;
9060
9061   assert (node1 && node2);
9062   assert (node1 != node2);
9063
9064   // add all edges starting at node2 to node1
9065   edge = node2->edge;
9066   while (edge) {
9067     nextedge = edge->next;
9068     node = edge->node;
9069     backedge = getGEdge (node, node2);
9070     if (backedge)
9071       backweight = backedge->weight;
9072     else
9073       backweight = 0;
9074     // insert edges (node1,node) and (node,node1)
9075     addGEdge2 (node1, node, edge->weight, backweight);
9076     // remove edges (node, node2) and (node2, node)
9077     remGEdge (node2, node);
9078     remGEdge (node, node2);
9079     edge = nextedge;
9080   } // while
9081
9082   // now node2 should not be referenced by any other GraphNode...
9083   //remGNode (adj, node2->data, node2->hash);
9084 }
9085
9086 /*----------------------------------------------------------------*/
9087 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9088 /*----------------------------------------------------------------*/
9089 void showGraph (Graph *g)
9090 {
9091   GraphNode *node;
9092   GraphEdge *edge;
9093   pseudoBankNr bankNr;
9094   pseudoBank *pbank;
9095   unsigned int size;
9096
9097   node = g->node;
9098   while (node) {
9099     edge = node->edge;
9100     bankNr = getEffectiveBank (node->hash);
9101     assert (bankNr >= 0);
9102     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9103     if (pbank) {
9104       bankNr = pbank->bank;
9105       size = pbank->size;
9106     } else {
9107       size = 1;
9108     }
9109
9110     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9111
9112     while (edge) {
9113       if (edge->weight > 0)
9114         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9115       edge = edge->next;
9116     } // while (edge)
9117     node = node->next;
9118   } // while (node)
9119 }
9120
9121 /*---------------------------------------------------------------*/
9122 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9123 /*---------------------------------------------------------------*/
9124 void pic16_OptimizeBanksel ()
9125 {
9126   GraphNode *node, *node1, *node1next;
9127
9128 #if 0
9129   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9130   GraphEdge *edge, *backedge;
9131   GraphEdge *max;
9132   int maxWeight, weight, mergeMore, absMaxWeight;
9133   pseudoBankNr curr0, curr1;
9134 #endif
9135   pseudoBank *pbank;
9136   pseudoBankNr bankNr;
9137   char *base_symbol0, *base_symbol1;
9138   int len0, len1;
9139   pBlock *pb;
9140   set *set;
9141   regs *reg;
9142   unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9143
9144   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9145
9146   if (!the_pFile || !the_pFile->pbHead) return;
9147
9148   adj = newGraph (NULL);
9149   sym2bank = newHashTable ( 255 );
9150   bank2sym = newHashTable ( 255 );
9151   coerce = newHashTable ( 255 );
9152
9153   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9154   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9155     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9156   } // for pb
9157
9158 #if 1
9159   // assign symbols with absolute addresses to their respective bank nrs
9160   set = pic16_fix_udata;
9161   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9162     bankNr = reg->address >> 8;
9163     node = getOrAddGNode (adj, NULL, bankNr);
9164     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9165     assignToSameBank (node->hash, bankNr, 1, 1);
9166
9167     assert (bankNr >= 0);
9168     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9169     if (!pbank) {
9170       pbank = Safe_calloc (1, sizeof (pseudoBank));
9171       pbank->bank = reg->address >> 8; //FIXED_BANK;
9172       pbank->size = 1;
9173       pbank->ref = 1;
9174       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9175     } else {
9176       assert (pbank->bank == (reg->address >> 8));
9177       pbank->bank = reg->address >> 8; //FIXED_BANK;
9178       pbank->size++;
9179     }
9180     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9181   } // for reg
9182 #endif
9183
9184 #if 1
9185   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9186   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9187   node = adj->node;
9188   while (node) {
9189     if (node->hash < 0) { node = node->next; continue; }
9190     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9191     node1 = node->next;
9192     while (node1) {
9193       if (node1->hash < 0) { node1 = node1->next; continue; }
9194       node1next = node1->next;
9195       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9196       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9197         int res;
9198         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9199         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9200         if (0 != (res = assignToSameBank (node->hash, node1->hash, 0, 1))) {
9201           fprintf (stderr, "%s(%d) == %s(%d), res=%d\n", base_symbol0, len0, base_symbol1, len1, res);
9202           assert (0 && "Could not assign a symbol to a bank!");
9203         }
9204         mergeGraphNodes (node, node1);
9205         /*
9206         if (node->hash < node1->hash)
9207           mergeGraphNodes (node, node1);
9208         else
9209           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9210         */
9211       } // if
9212       node1 = node1next;
9213     } // while (node1)
9214     node = node->next;
9215   } // while (node)
9216 #endif
9217
9218 #if 0
9219   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9220   // assign tightly coupled operands to the same (pseudo) bank
9221   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9222   mergeMore = 1;
9223   absMaxWeight = 0;
9224   while (mergeMore) {
9225     node = adj->node;
9226     max = NULL;
9227     maxWeight = 0;
9228     while (node) {
9229       curr0 = getEffectiveBank (node->hash);
9230       if (curr0 < 0) { node = node->next; continue; }
9231       edge = node->edge;
9232       while (edge) {
9233         assert (edge->src == node);
9234         backedge = getGEdge (edge->node, edge->src);
9235         weight = edge->weight + (backedge ? backedge->weight : 0);
9236         curr1 = getEffectiveBank (edge->node->hash);
9237         if (curr1 < 0) { edge = edge->next; continue; }
9238
9239         // merging is only useful if the items are not assigned to the same bank already...
9240         if (curr0 != curr1 && weight > maxWeight) {
9241           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9242           maxWeight = weight;
9243           max = edge;
9244         } // if
9245         edge = edge->next;
9246       } // while
9247       node = node->next;
9248     } // while
9249
9250     if (maxWeight > 0) {
9251 #if 0
9252       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9253                max->src->hash, getSymFromBank (max->src->hash),
9254                max->node->hash, getSymFromBank (max->node->hash));
9255 #endif
9256
9257       node = getGNode (adj, max->src->data, max->src->hash);
9258       node1 = getGNode (adj, max->node->data, max->node->hash);
9259
9260       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0, 0)) {
9261         if (max->src->hash < max->node->hash)
9262           mergeGraphNodes (node, node1);
9263         else
9264           mergeGraphNodes (node1, node);
9265       } else {
9266         remGEdge (node, node1);
9267         remGEdge (node1, node);
9268         //mergeMore = 0;
9269       }
9270
9271     } else {
9272       mergeMore = 0;
9273     }
9274   } // while
9275 #endif
9276
9277 #if 1
9278   // remove redundant BANKSELs
9279   //fprintf (stderr, "removing redundant BANKSELs\n");
9280   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9281     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9282   } // for pb
9283 #endif
9284
9285 #if 0
9286   fprintf (stderr, "display graph\n");
9287   showGraph ();
9288 #endif
9289
9290   deleteGraph (adj);
9291   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9292 }
9293
9294 /*** END of stuff belonging to the BANKSEL optimization ***/
9295
9296
9297
9298 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9299
9300 typedef unsigned int symbol_t;
9301 typedef unsigned int valnum_t;
9302 //typedef unsigned int hash_t;
9303
9304 #ifndef INT_TO_PTR
9305 #define INT_TO_PTR(x) (((char *) 0) + (x))
9306 #endif
9307
9308 #ifndef PTR_TO_INT
9309 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9310 #endif
9311
9312 static int pic16_regIsLocal (regs *r);
9313 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9314
9315 /* statistics */
9316 static unsigned int pic16_df_removed_pcodes = 0;
9317 static unsigned int pic16_df_saved_bytes = 0;
9318 static unsigned int df_findall_sameflow = 0;
9319 static unsigned int df_findall_otherflow = 0;
9320 static unsigned int df_findall_in_vals = 0;
9321
9322 static void pic16_df_stats () {
9323   return;
9324   if (pic16_debug_verbose || pic16_pcode_verbose) {
9325     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9326     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9327     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9328   }
9329 }
9330
9331 /* Remove a pCode iff possible:
9332  * - previous pCode is no SKIP
9333  * - pc has no label
9334  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9335 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9336   pCode *pcprev, *pcnext;
9337   char buf[256], *total=NULL;
9338   int len;
9339
9340   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9341
9342   pcprev = pic16_findPrevInstruction (pc->prev);
9343   pcnext = pic16_findNextInstruction (pc->next);
9344
9345   /* move labels to next instruction (if possible) */
9346   if (PCI(pc)->label && !pcnext) return 0;
9347
9348   /* if this is a SKIP with side-effects -- do not remove */
9349   /* XXX: might try to replace this one with the side-effect only version */
9350   if (isPCI_SKIP(pc)
9351         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9352   {
9353     pCode *newpc;
9354     switch (PCI(pc)->op)
9355     {
9356     case POC_INCFSZ:
9357     case POC_INFSNZ:
9358       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9359       pic16_pCodeReplace( pc, newpc );
9360       return 1;
9361       break;
9362     case POC_INCFSZW:
9363       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9364       pic16_pCodeReplace( pc, newpc );
9365       return 1;
9366       break;
9367     case POC_DECFSZ:
9368     case POC_DCFSNZ:
9369       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9370       pic16_pCodeReplace( pc, newpc );
9371       return 1;
9372       break;
9373     case POC_DECFSZW:
9374       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9375       pic16_pCodeReplace( pc, newpc );
9376       return 1;
9377       break;
9378     default:
9379       return 0;
9380     }
9381     return 0;
9382   }
9383
9384   /* if previous instruction is a skip -- do not remove */
9385   if (pcprev && isPCI_SKIP(pcprev)) {
9386     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9387       /* preceeding SKIP could not be removed -- keep this instruction! */
9388       return 0;
9389     }
9390   }
9391
9392   if (PCI(pc)->label) {
9393     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9394     //pc->print (stderr, pc);
9395     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9396     PCI(pc)->label = NULL;
9397   }
9398
9399   /* update statistics */
9400   pic16_df_removed_pcodes++;
9401   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9402
9403   /* remove the pCode */
9404   pic16_pCode2str (buf, 256, pc);
9405   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9406   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9407     len = strlen (buf) + strlen (comment) + 10;
9408     total = (char *) Safe_malloc (len);
9409     SNPRINTF (total, len, "%s: %s", comment, buf);
9410     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9411     Safe_free (total);
9412   }
9413
9414   /* actually unlink it from the pBlock -- also remove from to/from lists */
9415   pic16_pCodeUnlink (pc);
9416
9417   /* remove the pCode -- release registers */
9418   pc->destruct (pc);
9419
9420   /* report success */
9421   return 1;
9422 }
9423
9424
9425 /* ======================================================================== */
9426 /* === SYMBOL HANDLING ==================================================== */
9427 /* ======================================================================== */
9428
9429 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9430 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9431 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9432
9433 /** Calculate a hash for a given string.
9434  * If len == 0 the string is assumed to be NUL terminated. */
9435 static hash_t symbolHash (const char *str, unsigned int len) {
9436   hash_t hash = 0;
9437   if (!len) {
9438     while (*str) {
9439       hash = (hash << 2) ^ *str;
9440       str++;
9441     } // while
9442   } else {
9443     while (len--) {
9444       hash = (hash << 2) ^ *str;
9445       str++;
9446     }
9447   }
9448   return hash;
9449 }
9450
9451 /** Return 1 iff strings v1 and v2 are identical. */
9452 static int symcmp (const void *v1, const void *v2) {
9453   return !strcmp ((const char *) v1, (const char *) v2);
9454 }
9455
9456 /** Return 1 iff pointers v1 and v2 are identical. */
9457 static int ptrcmp (const void *v1, const void *v2) {
9458   return (v1 == v2);
9459 }
9460
9461 enum {  SPO_WREG=0x1000,
9462         SPO_STATUS,
9463         SPO_PRODL,
9464         SPO_PRODH,
9465         SPO_INDF0,
9466         SPO_POSTDEC0,
9467         SPO_POSTINC0,
9468         SPO_PREINC0,
9469         SPO_PLUSW0,
9470         SPO_INDF1,
9471         SPO_POSTDEC1,
9472         SPO_POSTINC1,
9473         SPO_PREINC1,
9474         SPO_PLUSW1,
9475         SPO_INDF2,
9476         SPO_POSTDEC2,
9477         SPO_POSTINC2,
9478         SPO_PREINC2,
9479         SPO_PLUSW2,
9480         SPO_STKPTR,
9481         SPO_TOSL,
9482         SPO_TOSH,
9483         SPO_TOSU,
9484         SPO_BSR,
9485         SPO_FSR0L,
9486         SPO_FSR0H,
9487         SPO_FSR1L,
9488         SPO_FSR1H,
9489         SPO_FSR2L,
9490         SPO_FSR2H,
9491         SPO_PCL,
9492         SPO_PCLATH,
9493         SPO_PCLATU,
9494         SPO_TABLAT,
9495         SPO_TBLPTRL,
9496         SPO_TBLPTRH,
9497         SPO_TBLPTRU,
9498         SPO_LAST
9499 };
9500
9501 /* Return the unique symbol_t for the given string. */
9502 static symbol_t symFromStr (const char *str) {
9503   hash_t hash;
9504   char *res;
9505   symbol_t sym;
9506
9507   if (!map_symToStr) {
9508     int i;
9509     struct { char *name; symbol_t sym; } predefsyms[] = {
9510         {"WREG", SPO_WREG},
9511         {"STATUS", SPO_STATUS},
9512         {"PRODL", SPO_PRODL},
9513         {"PRODH", SPO_PRODH},
9514         {"INDF0", SPO_INDF0},
9515         {"POSTDEC0", SPO_POSTDEC0},
9516         {"POSTINC0", SPO_POSTINC0},
9517         {"PREINC0", SPO_PREINC0},
9518         {"PLUSW0", SPO_PLUSW0},
9519         {"INDF1", SPO_INDF1},
9520         {"POSTDEC1", SPO_POSTDEC1},
9521         {"POSTINC1", SPO_POSTINC1},
9522         {"PREINC1", SPO_PREINC1},
9523         {"PLUSW1", SPO_PLUSW1},
9524         {"INDF2", SPO_INDF2},
9525         {"POSTDEC2", SPO_POSTDEC2},
9526         {"POSTINC2", SPO_POSTINC2},
9527         {"PREINC2", SPO_PREINC2},
9528         {"PLUSW2", SPO_PLUSW2},
9529         {"STKPTR", SPO_STKPTR},
9530         {"TOSL", SPO_TOSL},
9531         {"TOSH", SPO_TOSH},
9532         {"TOSU", SPO_TOSU},
9533         {"BSR", SPO_BSR},
9534         {"FSR0L", SPO_FSR0L},
9535         {"FSR0H", SPO_FSR0H},
9536         {"FSR1L", SPO_FSR1L},
9537         {"FSR1H", SPO_FSR1H},
9538         {"FSR2L", SPO_FSR2L},
9539         {"FSR2H", SPO_FSR2H},
9540         {"PCL", SPO_PCL},
9541         {"PCLATH", SPO_PCLATH},
9542         {"PCLATU", SPO_PCLATU},
9543         {"TABLAT", SPO_TABLAT},
9544         {"TBLPTRL", SPO_TBLPTRL},
9545         {"TBLPTRH", SPO_TBLPTRH},
9546         {"TBLPTRU", SPO_TBLPTRU},
9547         {NULL, 0}
9548     };
9549
9550     map_strToSym = newHashTable (128);
9551     map_symToStr = newHashTable (128);
9552
9553     for (i=0; predefsyms[i].name; i++) {
9554       char *name;
9555
9556       /* enter new symbol */
9557       sym = predefsyms[i].sym;
9558       name = predefsyms[i].name;
9559       res = Safe_strdup (name);
9560       hash = symbolHash (name, 0);
9561
9562       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9563       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9564     } // for i
9565   }
9566
9567   hash = symbolHash (str, 0) % map_strToSym->size;
9568
9569   /* find symbol in table */
9570   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9571   if (sym) {
9572     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9573     return sym;
9574   }
9575
9576   /* enter new symbol */
9577   sym = nextSymbol++;
9578   res = Safe_strdup (str);
9579
9580   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9581   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9582
9583   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9584
9585   return sym;
9586 }
9587
9588 #if 1
9589 static const char *strFromSym (symbol_t sym) {
9590   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9591 }
9592 #endif
9593
9594 /* ======================================================================== */
9595 /* === DEFINITION MAP HANDLING ============================================ */
9596 /* ======================================================================== */
9597
9598 /* A defmap provides information about which symbol is defined by which pCode.
9599  * The most recent definitions are prepended to the list, so that the most
9600  * recent definition can be found by forward scanning the list.
9601  * pc2: MOVFF r0x00, r0x01
9602  * pc1: INCF r0x01
9603  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9604  *
9605  * We attach one defmap to each flow object, and each pCode will occur at
9606  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9607  * used to find definitions for a pCode in its own defmap that precede pCode.
9608  */
9609
9610 typedef struct defmap_s {
9611   symbol_t sym;                 /** symbol this item refers to */
9612   union {
9613     struct {
9614       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9615       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9616       int isRead:1;             /** sym/mask is read */
9617       int isWrite:1;            /** sym/mask is written */
9618     } access;
9619     int accessmethod;
9620   } acc;
9621   pCode *pc;                    /** pCode this symbol is refrenced at */
9622   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9623   valnum_t val;                 /** new unique number for this value (if isWrite) */
9624   struct defmap_s *prev, *next; /** link to previous an next definition */
9625 } defmap_t;
9626
9627 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9628 static int defmap_free_count = 0;               /** number of released defmap items */
9629
9630 /* Returns a defmap_t with the specified data; this will be the new list head.
9631  * next - pointer to the current list head */
9632 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9633   defmap_t *map;
9634
9635   if (defmap_free) {
9636     map = defmap_free;
9637     defmap_free = map->next;
9638     --defmap_free_count;
9639   } else {
9640     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9641   }
9642   map->sym = sym;
9643   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9644   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9645   map->acc.access.isRead = (isRead != 0);
9646   map->acc.access.isWrite = (isWrite != 0);
9647   map->pc = pc;
9648   map->in_val = 0;
9649   map->val = (isWrite ? val : 0);
9650   map->prev = NULL;
9651   map->next = next;
9652   if (next) next->prev = map;
9653
9654   return map;
9655 }
9656
9657 /* Returns a copy of the single defmap item. */
9658 static defmap_t *copyDefmap (defmap_t *map) {
9659   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9660   memcpy (res, map, sizeof (defmap_t));
9661   res->next = NULL;
9662   res->prev = NULL;
9663   return res;
9664 }
9665
9666 /* Insert a defmap item after the specified one. */
9667 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9668   if (!ref || !newItem) return 1;
9669
9670   newItem->next = ref->next;
9671   newItem->prev = ref;
9672   ref->next = newItem;
9673   if (newItem->next) newItem->next->prev = newItem;
9674
9675   return 0;
9676 }
9677
9678 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9679  * item is copied before insertion into chain and therefore left untouched.
9680  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9681 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9682   defmap_t *dummy;
9683   dummy = *head;
9684   while (dummy && (dummy->sym != item->sym
9685                           || dummy->pc != item->pc
9686                           || dummy->acc.accessmethod != item->acc.accessmethod
9687                           || dummy->val != item->val
9688                           || dummy->in_val != item->in_val)) {
9689     dummy = dummy->next;
9690   } // while
9691
9692   /* item already present? */
9693   if (dummy) return 0;
9694
9695   /* otherwise: insert copy of item */
9696   dummy = copyDefmap (item);
9697   dummy->next = *head;
9698   if (*head) (*head)->prev = dummy;
9699   *head = dummy;
9700
9701   return 1;
9702 }
9703
9704 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9705 static void deleteDefmap (defmap_t *map) {
9706   if (!map) return;
9707
9708   /* unlink from chain -- fails for the first item (head is not updated!) */
9709   if (map->next) map->next->prev = map->prev;
9710   if (map->prev) map->prev->next = map->next;
9711
9712   /* clear map */
9713   memset (map, 0, sizeof (defmap_t));
9714
9715   /* save for future use */
9716   map->next = defmap_free;
9717   defmap_free = map;
9718   ++defmap_free_count;
9719 }
9720
9721 /* Release all defmaps referenced from map. */
9722 static void deleteDefmapChain (defmap_t **_map) {
9723   defmap_t *map, *next;
9724
9725   if (!_map) return;
9726
9727   map = *_map;
9728
9729   /* find list head */
9730   while (map && map->prev) map = map->prev;
9731
9732   /* delete all items */
9733   while (map) {
9734     next = map->next;
9735     deleteDefmap (map);
9736     map = next;
9737   } // while
9738
9739   *_map = NULL;
9740 }
9741
9742 /* Free all defmap items. */
9743 static void freeDefmap (defmap_t **_map) {
9744   defmap_t *next;
9745   defmap_t *map;
9746
9747   if (!_map) return;
9748
9749   map = (*_map);
9750
9751   /* find list head */
9752   while (map->prev) map = map->prev;
9753
9754   /* release all items */
9755   while (map) {
9756     next = map->next;
9757     Safe_free (map);
9758     map = next;
9759   }
9760
9761   (*_map) = NULL;
9762 }
9763
9764 /* Returns the most recent definition for the given symbol preceeding pc.
9765  * If no definition is found, NULL is returned.
9766  * If pc == NULL the whole list is scanned. */
9767 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9768   defmap_t *curr = map;
9769
9770   if (pc) {
9771     /* skip all definitions up to pc */
9772     while (curr && (curr->pc != pc)) curr = curr->next;
9773
9774     /* pc not in the list -- scan the whole list for definitions */
9775     if (!curr) {
9776       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9777       curr = map;
9778     } else {
9779       /* skip all definitions performed by pc */
9780       while (curr && (curr->pc == pc)) curr = curr->next;
9781     }
9782   } // if (pc)
9783
9784   /* find definition for sym */
9785   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9786     curr = curr->next;
9787   }
9788
9789   return curr;
9790 }
9791
9792 #if 0
9793 /* Returns the first use (read) of the given symbol AFTER pc.
9794  * If no such use is found, NULL is returned.
9795  * If pc == NULL the whole list is scanned. */
9796 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9797   defmap_t *curr = map, *prev = NULL;
9798
9799   if (pc) {
9800     /* skip all definitions up to pc */
9801     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9802
9803     /* pc not in the list -- scan the whole list for definitions */
9804     if (!curr) {
9805       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9806       curr = prev;
9807     }
9808   } else {
9809     /* find end of list */
9810     while (curr && curr->next) curr = curr->next;
9811   } // if (pc)
9812
9813   /* find use of sym (scan list backwards) */
9814   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9815
9816   return curr;
9817 }
9818 #endif
9819
9820 /* Return the defmap entry for sym AT pc.
9821  * If none is found, NULL is returned.
9822  * If more than one entry is found an assertion is triggered. */
9823 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9824   defmap_t *res = NULL;
9825
9826   /* find entries for pc */
9827   while (map && map->pc != pc) map = map->next;
9828
9829   /* find first entry for sym @ pc */
9830   while (map && map->pc == pc && map->sym != sym) map = map->next;
9831
9832   /* no entry found */
9833   if (!map) return NULL;
9834
9835   /* check for more entries */
9836   res = map;
9837   map = map->next;
9838   while (map && map->pc == pc) {
9839     /* more than one entry for sym @ pc found? */
9840     assert (map->sym != sym);
9841     map = map->next;
9842   }
9843
9844   /* return single entry for sym @ pc */
9845   return res;
9846 }
9847
9848 /* Modifies the definition of sym at pCode to newval.
9849  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9850  */
9851 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9852   defmap_t *m  = map;
9853
9854   /* find definitions of pc */
9855   while (m && m->pc != pc) m = m->next;
9856
9857   /* find definition of sym at pc */
9858   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9859
9860   /* no definition found */
9861   if (!m) return 1;
9862
9863   /* redefine */
9864   m->val = newval;
9865
9866   /* update following uses of sym */
9867   while (m && m->pc == pc) m = m->prev;
9868   while (m) {
9869     if (m->sym == sym) {
9870       m->in_val = newval;
9871       if (m->acc.access.isWrite) m = NULL;
9872     } // if
9873     if (m) m = m->prev;
9874   } // while
9875
9876   return 0;
9877 }
9878
9879 /* ======================================================================== */
9880 /* === STACK ROUTINES ===================================================== */
9881 /* ======================================================================== */
9882
9883 typedef struct stack_s {
9884   void *data;
9885   struct stack_s *next;
9886 } stackitem_t;
9887
9888 typedef stackitem_t *dynstack_t;
9889 static stackitem_t *free_stackitems = NULL;
9890
9891 /* Create a stack with one item. */
9892 static dynstack_t *newStack () {
9893   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9894   *s = NULL;
9895   return s;
9896 }
9897
9898 /* Remove a stack -- its items are only marked free. */
9899 static void deleteStack (dynstack_t *s) {
9900   stackitem_t *i;
9901
9902   while (*s) {
9903     i = *s;
9904     *s = (*s)->next;
9905     i->next = free_stackitems;
9906     free_stackitems = i;
9907   } // while
9908   Safe_free (s);
9909 }
9910
9911 /* Release all stackitems. */
9912 static void releaseStack () {
9913   stackitem_t *i;
9914
9915   while (free_stackitems) {
9916     i = free_stackitems->next;
9917     Safe_free(free_stackitems);
9918     free_stackitems = i;
9919   } // while
9920 }
9921
9922 static void stackPush (dynstack_t *stack, void *data) {
9923   stackitem_t *i;
9924
9925   if (free_stackitems) {
9926     i = free_stackitems;
9927     free_stackitems = free_stackitems->next;
9928   } else {
9929     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9930   }
9931   i->data = data;
9932   i->next = *stack;
9933   *stack = i;
9934 }
9935
9936 static void *stackPop (dynstack_t *stack) {
9937   void *data;
9938   stackitem_t *i;
9939
9940   if (stack && *stack) {
9941     data = (*stack)->data;
9942     i = *stack;
9943     *stack = (*stack)->next;
9944     i->next = free_stackitems;
9945     free_stackitems = i;
9946     return data;
9947   } else {
9948     return NULL;
9949   }
9950 }
9951
9952 #if 0
9953 static int stackContains (dynstack_t *s, void *data) {
9954   stackitem_t *i;
9955   if (!s) return 0;
9956   i = *s;
9957   while (i) {
9958     if (i->data == data) return 1;
9959     i = i->next;
9960   } // while
9961
9962   /* not found */
9963   return 0;
9964 }
9965 #endif
9966
9967 static int stackIsEmpty (dynstack_t *s) {
9968   return (*s == NULL);
9969 }
9970
9971
9972 typedef struct {
9973   pCodeFlow *flow;
9974   defmap_t *lastdef;
9975 } state_t;
9976
9977 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9978   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9979   s->flow = flow;
9980   s->lastdef = lastdef;
9981   return s;
9982 }
9983
9984 static void deleteState (state_t *s) {
9985   Safe_free (s);
9986 }
9987
9988 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9989   stackitem_t *i;
9990
9991   /* scan working list for state */
9992   if (todo) {
9993     i = *todo;
9994     while (i) {
9995       /* is i == state? -- state not new */
9996       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
9997       i = i->next;
9998     } // while
9999   }
10000
10001   if (done) {
10002     i = *done;
10003     while (i) {
10004       /* is i == state? -- state not new */
10005       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10006       i = i->next;
10007     } // while
10008   }
10009
10010   /* not found -- state is new */
10011   return 1;
10012 }
10013
10014 static inline valnum_t newValnum ();
10015
10016 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10017   pCode *pc;
10018
10019   if (!pb) return "<unknown function>";
10020
10021   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10022   if (pc && isPCF(pc)) return PCF(pc)->fname;
10023   else return "<unknown function>";
10024 }
10025
10026 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10027   defmap_t *map;
10028   pCodeFlow *pcfl;
10029
10030   assert(pb);
10031
10032   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10033
10034   /* find initial value (assigning pc == NULL) */
10035   map = PCFL(pcfl)->in_vals;
10036   while (map && map->sym != sym) map = map->next;
10037
10038   /* initial value already present? */
10039   if (map) {
10040     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10041     return map;
10042   }
10043
10044   /* create a new initial value */
10045   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10046   PCFL(pcfl)->in_vals = map;
10047   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10048   return map;
10049
10050 #if 0
10051   /* insert map as last item in pcfl's defmap */
10052   if (!prev) prev = PCFL(pcfl)->defmap;
10053   if (!prev) {
10054     PCFL(pcfl)->defmap = map;
10055   } else {
10056     while (prev->next) prev = prev->next;
10057     prev->next = map;
10058     map->prev = prev;
10059   }
10060
10061   return map;
10062 #endif
10063 }
10064
10065 /* Find all reaching definitions for sym at pc.
10066  * A new (!) list of definitions is returned.
10067  * Returns the number of reaching definitions found.
10068  * The defining defmap entries are returned in *chain.
10069  */
10070 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10071   defmap_t *map;
10072   defmap_t *res;
10073
10074   pCodeFlow *curr;
10075   pCodeFlowLink *succ;
10076   state_t *state;
10077   dynstack_t *todo;     /** stack of state_t */
10078   dynstack_t *done;     /** stack of state_t */
10079
10080   int firstState, n_defs;
10081
10082   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10083   assert (chain);
10084
10085   /* initialize return list */
10086   *chain = NULL;
10087
10088   /* wildcard symbol? */
10089   if (!sym) return 0;
10090
10091   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10092
10093   map = PCI(pc)->pcflow->defmap;
10094
10095   res = defmapFindDef (map, sym, pc);
10096   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10097
10098 #define USE_PRECALCED_INVALS 1
10099 #if USE_PRECALCED_INVALS
10100   if (!res && PCI(pc)->pcflow->in_vals) {
10101     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10102     if (res) {
10103       //fprintf  (stderr, "found def in init values\n");
10104       df_findall_in_vals++;
10105     }
10106   }
10107 #endif
10108
10109   if (res) {
10110     // found a single definition (in pc's flow)
10111     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10112     defmapAddCopyIfNew (chain, res);
10113     df_findall_sameflow++;
10114     return 1;
10115   }
10116
10117 #if USE_PRECALCED_INVALS
10118   else {
10119     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10120     return 1;
10121   }
10122
10123 #endif
10124
10125 #define FORWARD_FLOW_ANALYSIS 1
10126 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10127   /* no definition found in pc's flow preceeding pc */
10128   todo = newStack ();
10129   done = newStack ();
10130   n_defs = 0; firstState = 1;
10131   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10132
10133   while (!stackIsEmpty (todo)) {
10134     state = (state_t *) stackPop (todo);
10135     stackPush (done, state);
10136     curr = state->flow;
10137     res = state->lastdef;
10138     //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);
10139
10140     /* there are no definitions BEFORE pc in pc's flow (see above) */
10141     if (curr == PCI(pc)->pcflow) {
10142       if (!res) {
10143         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10144         res = pic16_pBlockAddInval (pc->pb, sym);
10145         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10146         res = NULL;
10147       } else {
10148         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10149         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10150       }
10151     }
10152
10153     /* save last definition of sym in this flow as initial def in successors */
10154     res = defmapFindDef (curr->defmap, sym, NULL);
10155     if (!res) res = state->lastdef;
10156
10157     /* add successors to working list */
10158     state = newState (NULL, NULL);
10159     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10160     while (succ) {
10161       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10162       state->flow = succ->pcflow;
10163       state->lastdef = res;
10164       if (stateIsNew (state, todo, done)) {
10165         stackPush (todo, state);
10166         state = newState (NULL, NULL);
10167       } // if
10168       succ = (pCodeFlowLink *) setNextItem (curr->to);
10169     } // while
10170     deleteState (state);
10171   } // while
10172
10173 #else // !FORWARD_FLOW_ANALYSIS
10174
10175   /* no definition found in pc's flow preceeding pc */
10176   todo = newStack ();
10177   done = newStack ();
10178   n_defs = 0; firstState = 1;
10179   stackPush (todo, newState (PCI(pc)->pcflow, res));
10180
10181   while (!stackIsEmpty (todo)) {
10182     state = (state_t *) stackPop (todo);
10183     curr = state->flow;
10184
10185     if (firstState) {
10186       firstState = 0;
10187       /* only check predecessor flows */
10188     } else {
10189       /* get (last) definition of sym in this flow */
10190       res = defmapFindDef (curr->defmap, sym, NULL);
10191     }
10192
10193     if (res) {
10194       /* definition found */
10195       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10196       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10197     } else {
10198       /* no definition found -- check predecessor flows */
10199       state = newState (NULL, NULL);
10200       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10201
10202       /* if no flow predecessor available -- sym might be uninitialized */
10203       if (!succ) {
10204         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10205         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10206         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10207         deleteDefmap (res); res = NULL;
10208       }
10209
10210       while (succ) {
10211         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10212         state->flow = succ->pcflow;
10213         state->lastdef = res;
10214         if (stateIsNew (state, todo, done)) {
10215           stackPush (todo, state);
10216           state = newState (NULL, NULL);
10217         } // if
10218         succ = (pCodeFlowLink *) setNextItem (curr->from);
10219       } // while
10220       deleteState (state);
10221     }
10222   } // while
10223
10224 #endif
10225
10226   /* clean up done stack */
10227   while (!stackIsEmpty(done)) {
10228     deleteState ((state_t *) stackPop (done));
10229   } // while
10230   deleteStack (done);
10231
10232   /* return number of items in result set */
10233   if (n_defs == 0) {
10234     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10235   } else if (n_defs == 1) {
10236     assert (*chain);
10237     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10238   } else if (n_defs > 0) {
10239     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10240 #if 0
10241     res = *chain;
10242     while (res) {
10243       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10244       res = res->next;
10245     } // while
10246 #endif
10247   }
10248   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10249   df_findall_otherflow++;
10250   return n_defs;
10251 }
10252
10253 /* ======================================================================== */
10254 /* === VALUE NUMBER HANDLING ============================================== */
10255 /* ======================================================================== */
10256
10257 static valnum_t nextValnum = 0x1000;
10258 static hTab *map_symToValnum = NULL;
10259
10260 /** Return a new value number. */
10261 static inline valnum_t newValnum () {
10262   return (nextValnum += 4);
10263 }
10264
10265 static valnum_t valnumFromStr (const char *str) {
10266   symbol_t sym;
10267   valnum_t val;
10268   void *res;
10269
10270   sym = symFromStr (str);
10271
10272   if (!map_symToValnum) {
10273     map_symToValnum = newHashTable (128);
10274   } // if
10275
10276   /* literal already known? */
10277   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10278
10279   /* return existing valnum */
10280   if (res) return (valnum_t) PTR_TO_INT(res);
10281
10282   /* create new valnum */
10283   val = newValnum();
10284   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10285   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10286   return val;
10287 }
10288
10289 /* Create a valnum for a literal. */
10290 static valnum_t valnumFromLit (unsigned int lit) {
10291   return ((valnum_t) 0x100 + (lit & 0x0FF));
10292 }
10293
10294 /* Return the (positive) literal value represented by val
10295  * or -1 iff val is no known literal's valnum. */
10296 static int litFromValnum (valnum_t val) {
10297   if (val >= 0x100 && val < 0x200) {
10298     /* valnum is a (known) literal */
10299     return val & 0x00FF;
10300   } else {
10301     /* valnum is not a known literal */
10302     return -1;
10303   }
10304 }
10305
10306 #if 0
10307 /* Sanity check - all flows in a block must be reachable from initial flow. */
10308 static int verifyAllFlowsReachable (pBlock *pb) {
10309   set *reached;
10310   set *flowInBlock;
10311   set *checked;
10312   pCode *pc;
10313   pCodeFlow *pcfl;
10314   pCodeFlowLink *succ;
10315   int res;
10316
10317   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10318
10319   reached = NULL;
10320   flowInBlock = NULL;
10321   checked = NULL;
10322   /* mark initial flow as reached (and "not needs to be reached") */
10323   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10324   assert (pc);
10325   addSetHead (&reached, pc);
10326   addSetHead (&checked, pc);
10327
10328   /* mark all further flows in block as "need to be reached" */
10329   pc = pb->pcHead;
10330   do {
10331     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10332     pc = pic16_findNextInstruction (pc->next);
10333   } while (pc);
10334
10335   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10336     /* mark as reached and "not need to be reached" */
10337     deleteSetItem (&reached, pcfl);
10338     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10339
10340     /* flow is no longer considered unreachable */
10341     deleteSetItem (&flowInBlock, pcfl);
10342
10343     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10344       if (!isinSet (checked, succ->pcflow)) {
10345         /* flow has never been reached before */
10346         addSetHead (&reached, succ->pcflow);
10347         addSetHead (&checked, succ->pcflow);
10348       } // if
10349     } // for succ
10350   } // while
10351
10352   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10353
10354   /* by now every flow should have been reached
10355    * --> flowInBlock should be empty */
10356   res = (flowInBlock == NULL);
10357
10358 #if 1
10359   if (flowInBlock) {
10360           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10361     while (flowInBlock) {
10362       pcfl = indexSet (flowInBlock, 0);
10363       fprintf (stderr, "not reached: flow %p\n", pcfl);
10364       deleteSetItem (&flowInBlock, pcfl);
10365     } // while
10366   }
10367 #endif
10368
10369   /* clean up */
10370   deleteSet (&reached);
10371   deleteSet (&flowInBlock);
10372   deleteSet (&checked);
10373
10374   /* if we reached every flow, succ is NULL by now... */
10375   //assert (res); // will fire on unreachable code...
10376   return (res);
10377 }
10378 #endif
10379
10380 /* Checks a flow for accesses to sym AFTER pc.
10381  *
10382  * Returns -1 if the symbol is read in this flow (before redefinition),
10383  * returns 0 if the symbol is redefined in this flow or
10384  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10385  */
10386 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10387   defmap_t *map, *mappc;
10388
10389   /* find pc or start of definitions */
10390   map = pcfl->defmap;
10391   while (map && (map->pc != pc) && map->next) map = map->next;
10392   /* if we found pc -- ignore it */
10393   while (map && map->pc == pc) map = map->prev;
10394
10395   /* scan list backwards (first definition first) */
10396   while (map && mask) {
10397 //    if (map->sym == sym) {
10398       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10399       mappc = map;
10400       /* scan list for reads at this pc first */
10401       while (map && map->pc == mappc->pc) {
10402         /* is the symbol (partially) read? */
10403         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10404           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10405           return -1;
10406         }
10407         map = map->prev;
10408       } // while
10409       map = mappc;
10410
10411       while (map && map->pc == mappc->pc) {
10412         /* honor (partial) redefinitions of sym */
10413         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10414           mask &= ~map->acc.access.mask;
10415           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10416         }
10417         map = map->prev;
10418       } // while
10419 //    } // if
10420     /* map already points to the first defmap for the next pCode */
10421     //map = mappc->prev;
10422   } // while
10423
10424   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10425    * is still alive; return the appropriate mask of alive bits */
10426   return mask;
10427 }
10428
10429 /* Check whether a symbol is alive (AFTER pc). */
10430 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10431   int mask, visit;
10432   defmap_t *map;
10433   dynstack_t *todo, *done;
10434   state_t *state;
10435   pCodeFlow *pcfl;
10436   pCodeFlowLink *succ;
10437
10438   mask = 0x00ff;
10439
10440   assert (isPCI(pc));
10441   pcfl = PCI(pc)->pcflow;
10442   map = pcfl->defmap;
10443
10444   todo = newStack ();
10445   done = newStack ();
10446
10447   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10448   stackPush (todo, state);
10449   visit = 0;
10450
10451   while (!stackIsEmpty (todo)) {
10452     state = (state_t *) stackPop (todo);
10453     pcfl = state->flow;
10454     mask = PTR_TO_INT(state->lastdef);
10455     if (visit) stackPush (done, state); else deleteState(state);
10456     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10457     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10458     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10459     visit++;
10460
10461     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10462     if (mask == 0) continue;
10463
10464     /* symbol is (partially) read before redefinition in flow */
10465     if (mask == -1) break;
10466
10467     /* symbol is neither read nor completely redefined -- check successor flows */
10468     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10469       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10470       if (stateIsNew (state, todo, done)) {
10471         stackPush (todo, state);
10472       } else {
10473         deleteState (state);
10474       }
10475     } // for
10476   } // while
10477
10478   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10479   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10480
10481   /* symbol is read in at least one flow -- is alive */
10482   if (mask == -1) return 1;
10483
10484   /* symbol is read in no flow */
10485   return 0;
10486 }
10487
10488 /* Returns whether access to the given symbol has side effects. */
10489 static int pic16_symIsSpecial (symbol_t sym) {
10490   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10491   switch (sym) {
10492   case SPO_INDF0:
10493   case SPO_PLUSW0:
10494   case SPO_POSTINC0:
10495   case SPO_POSTDEC0:
10496   case SPO_PREINC0:
10497   case SPO_INDF1:
10498   case SPO_PLUSW1:
10499   case SPO_POSTINC1:
10500   case SPO_POSTDEC1:
10501   case SPO_PREINC1:
10502   case SPO_INDF2:
10503   case SPO_PLUSW2:
10504   case SPO_POSTINC2:
10505   case SPO_POSTDEC2:
10506   case SPO_PREINC2:
10507   case SPO_PCL:
10508           return 1;
10509   default:
10510           /* no special effects known */
10511           return 0;
10512   } // switch
10513
10514   return 0;
10515 }
10516
10517 /* Check whether a register should be considered local (to the current function) or not. */
10518 static int pic16_regIsLocal (regs *r) {
10519   symbol_t sym;
10520   if (r) {
10521     if (r->type == REG_TMP) return 1;
10522
10523     sym = symFromStr (r->name);
10524     switch (sym) {
10525     case SPO_WREG:
10526     case SPO_FSR0L: // used in ptrget/ptrput
10527     case SPO_FSR0H: // ... as well
10528     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10529     case SPO_FSR1H: // ... as well
10530     case SPO_FSR2L: // used as frame pointer
10531     case SPO_FSR2H: // ... as well
10532     case SPO_PRODL: // used to return values from functions
10533     case SPO_PRODH: // ... as well
10534       /* these registers (and some more...) are considered local */
10535       return 1;
10536       break;
10537     default:
10538       /* for unknown regs: check is marked local, leave if not */
10539       if (r->isLocal) {
10540         return 1;
10541       } else {
10542         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10543         return 0;
10544       }
10545     } // switch
10546   } // if
10547
10548   /* if in doubt, assume non-local... */
10549   return 0;
10550 }
10551
10552 /* Check all symbols touched by pc whether their newly assigned values are read.
10553  * Returns 0 if no symbol is used later on, 1 otherwise. */
10554 static int pic16_pCodeIsAlive (pCode *pc) {
10555   pCodeInstruction *pci;
10556   defmap_t *map, *lastpc;
10557   regs *checkreg;
10558
10559   /* we can only handle PCIs */
10560   if (!isPCI(pc)) return 1;
10561
10562   //pc->print (stderr, pc);
10563
10564   pci = PCI(pc);
10565   assert (pci && pci->pcflow && pci->pcflow->defmap);
10566
10567   /* NEVER remove instructions with implicit side effects */
10568   switch (pci->op) {
10569   case POC_TBLRD:
10570   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10571   case POC_TBLRD_POSTDEC:
10572   case POC_TBLRD_PREINC:
10573   case POC_TBLWT:               /* modify program memory */
10574   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10575   case POC_TBLWT_POSTDEC:
10576   case POC_TBLWT_PREINC:
10577   case POC_CLRWDT:              /* clear watchdog timer */
10578   case POC_PUSH:                /* should be safe to remove though... */
10579   case POC_POP:                 /* should be safe to remove though... */
10580   case POC_CALL:
10581   case POC_RCALL:
10582   case POC_RETFIE:
10583   case POC_RETURN:
10584     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10585     return 1;
10586
10587   default:
10588     /* no special instruction */
10589     break;
10590   } // switch
10591
10592   /* prevent us from removing assignments to non-local variables */
10593   checkreg = NULL;
10594   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10595   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10596
10597   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10598     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10599     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10600     //pc->print (stderr, pc);
10601     return 1;
10602   }
10603   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10604     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10605     return 1;
10606   }
10607
10608 #if 1
10609   /* OVERKILL: prevent us from removing reads from non-local variables
10610    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10611    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10612   checkreg = NULL;
10613   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10614   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10615
10616   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10617     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10618     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10619     //pc->print (stderr, pc);
10620     return 1;
10621   }
10622   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10623     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10624     return 1;
10625   }
10626 #endif
10627
10628   /* now check that the defined symbols are not used */
10629   map = pci->pcflow->defmap;
10630
10631   /* find items for pc */
10632   while (map && map->pc != pc) map = map->next;
10633
10634   /* no entries found? something is fishy with DF analysis... -- play safe */
10635   if (!map) {
10636     if (pic16_pcode_verbose) {
10637       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10638     }
10639     return 1;
10640   }
10641
10642   /* remember first item assigned to pc for later use */
10643   lastpc = map;
10644
10645   /* check all symbols being modified by pc */
10646   while (map && map->pc == pc) {
10647     if (map->sym == 0) { map = map->next; continue; }
10648
10649     /* keep pc if it references special symbols (like POSTDEC0) */
10650 #if 0
10651     {
10652       char buf[256];
10653       pic16_pCode2str (buf, 256, pc);
10654       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10655     }
10656 #endif
10657     if (pic16_symIsSpecial (map->sym)) {
10658       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10659       return 1;
10660     }
10661     if (map->acc.access.isWrite) {
10662       if (pic16_isAlive (map->sym, pc)) {
10663         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10664         return 1;
10665       }
10666     }
10667     map = map->next;
10668   } // while
10669
10670   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10671 #if 0
10672   {
10673     char buf[256];
10674     pic16_pCode2str (buf, 256, pc);
10675     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10676   }
10677 #endif
10678   return 0;
10679 }
10680
10681 /* Adds implied operands to the list.
10682  * sym - operand being accessed in the pCode
10683  * list - list to append the operand
10684  * isRead - set to 1 iff sym is read in pCode
10685  * listRead - set to 1 iff all operands being read are to be listed
10686  *
10687  * Returns 0 for "normal" operands, 1 for special operands.
10688  */
10689 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10690   /* check whether accessing REG accesses other REGs as well */
10691   switch (sym) {
10692   case SPO_INDF0:
10693     /* reads FSR0x */
10694     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10695     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10696     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10697     break;
10698
10699   case SPO_PLUSW0:
10700     /* reads FSR0x and WREG */
10701     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10702     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10703     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10704     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10705     break;
10706
10707   case SPO_POSTDEC0:
10708   case SPO_POSTINC0:
10709   case SPO_PREINC0:
10710     /* reads/modifies FSR0x */
10711     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10712     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10713     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10714     break;
10715
10716   case SPO_INDF1:
10717     /* reads FSR1x */
10718     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10719     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10720     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10721     break;
10722
10723   case SPO_PLUSW1:
10724     /* reads FSR1x and WREG */
10725     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10726     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10727     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10728     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10729     break;
10730
10731   case SPO_POSTDEC1:
10732   case SPO_POSTINC1:
10733   case SPO_PREINC1:
10734     /* reads/modifies FSR1x */
10735     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10736     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10737     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10738     break;
10739
10740   case SPO_INDF2:
10741     /* reads FSR2x */
10742     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10743     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10744     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10745     break;
10746
10747   case SPO_PLUSW2:
10748     /* reads FSR2x and WREG */
10749     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10750     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10751     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10752     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10753     break;
10754
10755   case SPO_POSTDEC2:
10756   case SPO_POSTINC2:
10757   case SPO_PREINC2:
10758     /* reads/modifies FSR2x */
10759     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10760     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10761     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10762     break;
10763
10764   case SPO_PCL:
10765     /* modifies PCLATH and PCLATU */
10766     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10767     if (isRead) {
10768       /* reading PCL updates PCLATx */
10769       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10770       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10771     }
10772     if (isWrite) {
10773       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10774       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10775       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10776     }
10777     break;
10778
10779   default:
10780     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10781     /* nothing special */
10782     return 0;
10783     break;
10784   }
10785
10786   /* has been a special operand */
10787   return 1;
10788 }
10789
10790 static symbol_t pic16_fsrsym_idx[][2] = {
10791     {SPO_FSR0L, SPO_FSR0H},
10792     {SPO_FSR1L, SPO_FSR1H},
10793     {SPO_FSR2L, SPO_FSR2H}
10794 };
10795
10796 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10797 static void mergeDefmapSymbols (defmap_t *list) {
10798   defmap_t *ref, *curr, *temp;
10799
10800   /* now make sure that each symbol occurs at most once per pc */
10801   ref = list;
10802   while (ref && (ref->pc == list->pc)) {
10803     curr = ref->next;
10804     while (curr && (curr->pc == list->pc)) {
10805       if (curr->sym == ref->sym) {
10806         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10807         /* found a symbol occuring twice... merge the two */
10808         if (curr->acc.access.isRead) {
10809           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10810           ref->acc.access.isRead = 1;
10811           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10812         }
10813         if (curr->acc.access.isWrite) {
10814           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10815           ref->acc.access.isWrite = 1;
10816           ref->acc.access.mask |= curr->acc.access.mask;
10817         }
10818         temp = curr;
10819         curr = curr->next;
10820         deleteDefmap (temp);
10821         continue; // do not skip curr!
10822       } // if
10823       curr = curr->next;
10824     } // while
10825     ref = ref->next;
10826   } // while
10827 }
10828
10829 /** Prepend list with the reads and definitions performed by pc. */
10830 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10831   pCodeInstruction *pci;
10832   int cond, inCond, outCond;
10833   int mask = 0xff, smask;
10834   int isSpecial, isSpecial2;
10835   symbol_t sym, sym2;
10836   char *name;
10837
10838   if (isPCAD(pc)) {
10839     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10840     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10841     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10842     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10843     return list;
10844   }
10845   assert (isPCI(pc));
10846   pci = PCI(pc);
10847
10848   /* handle bit instructions */
10849   if (pci->isBitInst) {
10850     assert (pci->pcop->type == PO_GPR_BIT);
10851     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10852   }
10853
10854   /* handle (additional) implicit arguments */
10855   switch (pci->op) {
10856   case POC_LFSR:
10857     {
10858       int lit;
10859       valnum_t val;
10860       lit = PCOL(pci->pcop)->lit;
10861       assert (lit >= 0 && lit < 3);
10862       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10863       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10864       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10865       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10866       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...
10867     }
10868     break;
10869
10870   case POC_MOVLB: // BSR
10871   case POC_BANKSEL: // BSR
10872     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10873     break;
10874
10875   case POC_MULWF: // PRODx
10876   case POC_MULLW: // PRODx
10877     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10878     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10879     break;
10880
10881   case POC_POP: // TOS, STKPTR
10882     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10883     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10884     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10885     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10886     break;
10887
10888   case POC_PUSH: // STKPTR
10889     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10890     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10891     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10892     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10893     break;
10894
10895   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10896   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10897     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10898     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10899     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10900     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10901
10902     /* needs correctly set-up stack pointer */
10903     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10904     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10905     break;
10906
10907   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10908     /* pseudo read on (possible) return values */
10909     // WREG is handled below via outCond
10910     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10911     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10912     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10913
10914     /* caller's stack pointers must be restored */
10915     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10916     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10917     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10918     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10919     break;
10920
10921   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10922   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10923     /* pseudo read on (possible) return values */
10924     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10925     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10926     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10927     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10928
10929     /* caller's stack pointers must be restored */
10930     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10931     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10932     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10933     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10934     break;
10935
10936   case POC_TBLRD:
10937     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10938     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10939     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10940     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10941     break;
10942
10943   case POC_TBLRD_POSTINC:
10944   case POC_TBLRD_POSTDEC:
10945   case POC_TBLRD_PREINC:
10946     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10947     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10948     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10949     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10950     break;
10951
10952   case POC_TBLWT:
10953     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10954     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10955     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10956     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10957     break;
10958
10959   case POC_TBLWT_POSTINC:
10960   case POC_TBLWT_POSTDEC:
10961   case POC_TBLWT_PREINC:
10962     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10963     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10964     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10965     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10966     break;
10967
10968   default:
10969     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10970     break;
10971   } // switch
10972
10973   /* handle explicit arguments */
10974   inCond = pci->inCond;
10975   outCond = pci->outCond;
10976   cond = inCond | outCond;
10977   if (cond & PCC_W) {
10978     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10979   } // if
10980
10981   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10982   if (inCond & PCC_STATUS) {
10983     smask = 0;
10984     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10985     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10986     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10987     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10988     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10989
10990     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10991     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10992   } // if
10993
10994   if (outCond & PCC_STATUS) {
10995     smask = 0;
10996     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10997     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10998     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10999     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11000     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11001
11002     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11003     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11004   } // if
11005
11006   isSpecial = isSpecial2 = 0;
11007   sym = sym2 = 0;
11008   if (cond & PCC_REGISTER) {
11009     name = pic16_get_op (pci->pcop, NULL, 0);
11010     sym = symFromStr (name);
11011     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11012     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11013   }
11014
11015   if (cond & PCC_REGISTER2) {
11016     name = pic16_get_op2 (pci->pcop, NULL, 0);
11017     sym2 = symFromStr (name);
11018     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11019     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11020   }
11021
11022
11023   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11024   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11025
11026   mergeDefmapSymbols (list);
11027
11028   return list;
11029 }
11030
11031 #if 0
11032 static void printDefmap (defmap_t *map) {
11033   defmap_t *curr;
11034
11035   curr = map;
11036   fprintf (stderr, "defmap @ %p:\n", curr);
11037   while (curr) {
11038     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11039                     curr->acc.access.isRead ? "R" : " ",
11040                     curr->acc.access.isWrite ? "W": " ",
11041                     curr->in_val, curr->val,
11042                     curr->acc.access.in_mask, curr->acc.access.mask,
11043                     strFromSym(curr->sym), curr->sym,
11044                     curr->pc);
11045     curr = curr->next;
11046   } // while
11047   fprintf (stderr, "<EOL>\n");
11048 }
11049 #endif
11050
11051 /* Add "additional" definitions to uniq.
11052  * 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.
11053  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11054  *
11055  * If symbols defined in additional are not present in uniq, a definition is created.
11056  * Otherwise the present definition is altered to reflect the newer assignments.
11057  *
11058  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11059  *       before     `------- noted in additional --------'      after
11060  *
11061  * I assume that each symbol occurs AT MOST ONCE in uniq.
11062  *
11063  */
11064 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11065   defmap_t *curr;
11066   defmap_t *old;
11067   int change = 0;
11068
11069   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11070   /* find tail of additional list (holds the first assignment) */
11071   curr = additional;
11072   while (curr && curr->next) curr = curr->next;
11073
11074   /* update uniq */
11075   do {
11076     /* find next assignment in additionals */
11077     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11078
11079     if (!curr) break;
11080
11081     /* find item in uniq */
11082     old = *uniq;
11083     //printDefmap (*uniq);
11084     while (old && (old->sym != curr->sym)) old = old->next;
11085
11086     if (old) {
11087       /* definition found -- replace */
11088       if (old->val != curr->val) {
11089         old->val = curr->val;
11090         change++;
11091       } // if
11092     } else {
11093       /* new definition */
11094       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11095       change++;
11096     }
11097
11098     curr = curr->prev;
11099   } while (1);
11100
11101   /* return 0 iff uniq remained unchanged */
11102   return change;
11103 }
11104
11105 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11106  * lists of its predecessor flows.
11107  * Initially *combined should be NULL, alt_in will be copied to combined.
11108  * If *combined != NULL, combined will be altered:
11109  * - for symbols defined in *combined but not in alt_in,
11110  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11111  * - for symbols defined in alt_in but not in *combined,
11112  *   a 0 definition is created (value unknown, either INIT or alt).
11113  * - for symbols defined in both, *combined is:
11114  *   > left unchanged if *combined->val == alt_in->val or
11115  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11116  *
11117  * I assume that each symbol occurs AT MOST ONCE in each list!
11118  */
11119 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11120   defmap_t *curr;
11121   defmap_t *old;
11122   int change = 0;
11123   valnum_t val;
11124
11125   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11126
11127   if (!(*combined)) {
11128     return defmapUpdateUniqueSym (combined, alt_in);
11129   } // if
11130
11131   /* merge the two */
11132   curr = alt_in;
11133   while (curr) {
11134     /* find symbols definition in *combined */
11135     old = *combined;
11136     while (old && (old->sym != curr->sym)) old = old->next;
11137
11138     if (old) {
11139       /* definition found */
11140       if (old->val && (old->val != curr->val)) {
11141         old->val = 0; /* value unknown */
11142         change++;
11143       }
11144     } else {
11145       /* no definition found -- can be either INIT or alt_in's value */
11146       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11147       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11148       if (val != curr->val) change++;
11149     }
11150
11151     curr = curr->next;
11152   } // while (curr)
11153
11154   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11155   old = *combined;
11156   while (old) {
11157     if (old->val != 0) {
11158       /* find definition in alt_in */
11159       curr = alt_in;
11160       while (curr && curr->sym != old->sym) curr = curr->next;
11161       if (!curr) {
11162         /* symbol defined in *combined only -- can be either INIT or *combined */
11163         val = pic16_pBlockAddInval (pb, old->sym)->val;
11164         if (old->val != val) {
11165           old->val = 0;
11166           change++;
11167         }
11168       } // if
11169     } // if
11170
11171     old = old->next;
11172   } // while
11173
11174   return change;
11175 }
11176
11177 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11178   defmap_t *curr1, *curr2;
11179   symbol_t sym;
11180
11181   /* identical maps are equal */
11182   if (map1 == map2) return 0;
11183
11184   if (!map1) return -1;
11185   if (!map2) return 1;
11186
11187   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11188
11189   /* check length */
11190   curr1 = map1;
11191   curr2 = map2;
11192   while (curr1 && curr2) {
11193     curr1 = curr1->next;
11194     curr2 = curr2->next;
11195   } // while
11196
11197   /* one of them longer? */
11198   if (curr1) return 1;
11199   if (curr2) return -1;
11200
11201   /* both lists are of equal length -- compare (in O(n^2)) */
11202   curr1 = map1;
11203   while (curr1) {
11204     sym = curr1->sym;
11205     curr2 = map2;
11206     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11207     if (!curr2) return 1; // symbol not found in curr2
11208     if (curr2->val != curr1->val) return 1; // values differ
11209
11210     /* compare next symbol */
11211     curr1 = curr1->next;
11212   } // while
11213
11214   /* no difference found */
11215   return 0;
11216 }
11217
11218
11219 /* Prepare a list of all reaching definitions per flow.
11220  * This is done using a forward dataflow analysis.
11221  */
11222 static void createReachingDefinitions (pBlock *pb) {
11223   defmap_t *out_vals, *in_vals;
11224   pCode *pc;
11225   pCodeFlow *pcfl;
11226   pCodeFlowLink *link;
11227   set *todo;
11228   set *blacklist;
11229
11230   if (!pb) return;
11231
11232   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11233   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11234     if (isPCFL(pc)) {
11235       deleteDefmapChain (&PCFL(pc)->in_vals);
11236       deleteDefmapChain (&PCFL(pc)->out_vals);
11237       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11238     } // if
11239   } // for
11240
11241   pc = pic16_findNextInstruction (pb->pcHead);
11242   if (!pc) {
11243       // empty function, avoid NULL pointer dereference
11244       return;
11245   } // if
11246   todo = NULL; blacklist = NULL;
11247   addSetHead (&todo, PCI(pc)->pcflow);
11248
11249   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11250   while (elementsInSet (todo)) {
11251     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11252     pcfl = PCFL(indexSet (todo, 0));
11253     deleteSetItem (&todo, pcfl);
11254     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11255     in_vals = NULL;
11256     out_vals = NULL;
11257
11258     if (isinSet (blacklist, pcfl)) {
11259             fprintf (stderr, "ignoring blacklisted flow\n");
11260       continue;
11261     }
11262
11263     /* create in_vals from predecessors out_vals */
11264     link = setFirstItem (pcfl->from);
11265     while (link) {
11266       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11267       link = setNextItem (pcfl->from);
11268     } // while
11269
11270     //printDefmap (in_vals);
11271     //printDefmap (pcfl->in_vals);
11272
11273     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11274       //fprintf (stderr, "in_vals changed\n");
11275       /* in_vals changed -- update out_vals */
11276       deleteDefmapChain (&pcfl->in_vals);
11277       pcfl->in_vals = in_vals;
11278
11279       /* create out_val from in_val and defmap */
11280       out_vals = NULL;
11281       defmapUpdateUniqueSym (&out_vals, in_vals);
11282       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11283
11284       /* is out_vals different from pcfl->out_vals */
11285       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11286         //fprintf (stderr, "out_vals changed\n");
11287         deleteDefmapChain (&pcfl->out_vals);
11288         pcfl->out_vals = out_vals;
11289
11290         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11291           addSet (&blacklist, pcfl);
11292         } // if
11293
11294         /* reschedule all successors */
11295         link = setFirstItem (pcfl->to);
11296         while (link) {
11297           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11298           addSetIfnotP (&todo, link->pcflow);
11299           link = setNextItem (pcfl->to);
11300         } // while
11301       } else {
11302         deleteDefmapChain (&out_vals);
11303       }// if
11304     } else {
11305       deleteDefmapChain (&in_vals);
11306     } // if
11307   } // while
11308 }
11309
11310 #if 0
11311 static void showAllDefs (symbol_t sym, pCode *pc) {
11312   defmap_t *map;
11313   int count;
11314
11315   assert (isPCI(pc));
11316   count = defmapFindAll (sym, pc, &map);
11317
11318   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11319   while (map) {
11320 #if 1
11321     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11322 #else
11323     { char buf[256];
11324     pic16_pCode2str (buf, 256, map->pc);
11325     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11326 #endif
11327     map = map->next;
11328   }
11329   deleteDefmapChain (&map);
11330 }
11331 #endif
11332
11333 /* safepCodeUnlink and remove pc from defmap. */
11334 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11335   defmap_t *map, *next, **head;
11336   int res, ispci;
11337
11338   ispci = isPCI(pc);
11339   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11340   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11341   res = pic16_safepCodeUnlink (pc, comment);
11342
11343   if (res && map) {
11344     /* remove pc from defmap */
11345     while (map) {
11346       next = map->next;
11347       if (map->pc == pc) {
11348         if (!map->prev && head) *head = map->next;
11349         deleteDefmap (map);
11350       } // if
11351       map = next;
11352     }
11353   }
11354
11355   return res;
11356 }
11357
11358 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11359   defmap_t *map;
11360   /* This breaks the defmap chain's references to pCodes... fix it! */
11361   map = PCI(pc)->pcflow->defmap;
11362
11363   while (map && map->pc != pc) map = map->next;
11364
11365   while (map && map->pc == pc) {
11366     map->pc = newpc;
11367     map = map->next;
11368   } // while
11369 }
11370
11371 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11372  * write accesses (isRead == 0). */
11373 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11374   defmap_t *map, *map_start;
11375   defmap_t *copy;
11376   if (!isPCI(pc)) return;
11377   if (sym == newsym) return;
11378
11379   map = PCI(pc)->pcflow->defmap;
11380
11381   while (map && map->pc != pc) map = map->next;
11382   map_start = map;
11383   while (map && map->pc == pc) {
11384     if (map->sym == sym) {
11385       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11386       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11387         /* only one kind of access handled... this is easy */
11388         map->sym = newsym;
11389       } else {
11390         /* must copy defmap entry before replacing symbol... */
11391         copy = copyDefmap (map);
11392         if (isRead) {
11393           map->acc.access.isRead = 0;
11394           copy->acc.access.isWrite = 0;
11395         } else {
11396           map->acc.access.isWrite = 0;
11397           copy->acc.access.isRead = 0;
11398         }
11399         copy->sym = newsym;
11400         /* insert copy into defmap chain */
11401         defmapInsertAfter (map, copy);
11402       }
11403     }
11404     map = map->next;
11405   } // while
11406
11407   /* as this might introduce multiple defmap entries for newsym... */
11408   mergeDefmapSymbols (map_start);
11409 }
11410
11411 /* Assign "better" valnums to results. */
11412 static void assignValnums (pCode *pc) {
11413   pCodeInstruction *pci;
11414   pCode *newpc;
11415   symbol_t sym1, sym2;
11416   int cond, isSpecial1, isSpecial2, count, mask, lit;
11417   defmap_t *list, *val, *oldval, *dummy;
11418   regs *reg1 = NULL, *reg2 = NULL;
11419   valnum_t litnum;
11420
11421   /* only works for pCodeInstructions... */
11422   if (!isPCI(pc)) return;
11423
11424   pci = PCI(pc);
11425   cond = pci->inCond | pci->outCond;
11426   list = pci->pcflow->defmap;
11427   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11428
11429   if (cond & PCC_REGISTER) {
11430     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11431     reg1 = pic16_getRegFromInstruction (pc);
11432     isSpecial1 = pic16_symIsSpecial (sym1);
11433   }
11434   if (cond & PCC_REGISTER2) {
11435     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11436     reg2 = pic16_getRegFromInstruction (pc);
11437     isSpecial2 = pic16_symIsSpecial (sym2);
11438   }
11439
11440   /* determine input values */
11441   val = list;
11442   while (val && val->pc != pc) val = val->next;
11443   //list = val; /* might save some time later... */
11444   while (val && val->pc == pc) {
11445     val->in_val = 0;
11446     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11447       /* get valnum for sym */
11448       count = defmapFindAll (val->sym, pc, &oldval);
11449       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11450       if (count == 1) {
11451         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11452           val->in_val = oldval->val;
11453         } else {
11454           val->in_val = 0;
11455         }
11456       } else if (count == 0) {
11457         /* no definition found */
11458         val->in_val = 0;
11459       } else {
11460         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11461         assert (oldval);
11462         dummy = oldval->next;
11463         mask = oldval->acc.access.mask;
11464         val->in_val = oldval->val;
11465         while (dummy && (dummy->val == val->in_val)) {
11466           mask &= dummy->acc.access.mask;
11467           dummy = dummy->next;
11468         } // while
11469
11470         /* found other values or to restictive mask */
11471         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11472           val->in_val = 0;
11473         }
11474       }
11475       if (count > 0) deleteDefmapChain (&oldval);
11476     } // if
11477     val = val->next;
11478   }
11479
11480   /* handle valnum assignment */
11481   switch (pci->op) {
11482   case POC_CLRF: /* modifies STATUS (Z) */
11483     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11484       oldval = defmapCurr (list, sym1, pc);
11485       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11486         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11487         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11488       }
11489       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11490     }
11491     break;
11492
11493   case POC_SETF: /* SETF does not touch STATUS */
11494     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11495       oldval = defmapCurr (list, sym1, pc);
11496       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11497         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11498         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11499       }
11500       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11501     }
11502     break;
11503
11504   case POC_MOVLW: /* does not touch STATUS */
11505     oldval = defmapCurr (list, SPO_WREG, pc);
11506     if (pci->pcop->type == PO_LITERAL) {
11507       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11508       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11509     } else {
11510       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11511       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11512     }
11513     if (oldval && oldval->in_val == litnum) {
11514       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11515       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11516     }
11517     defmapUpdate (list, SPO_WREG, pc, litnum);
11518     break;
11519
11520   case POC_ANDLW: /* modifies STATUS (Z,N) */
11521   case POC_IORLW: /* modifies STATUS (Z,N) */
11522   case POC_XORLW: /* modifies STATUS (Z,N) */
11523     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11524     if (pci->pcop->type == PO_LITERAL) {
11525       int vallit = -1;
11526       lit = (unsigned char) PCOL(pci->pcop)->lit;
11527       val = defmapCurr (list, SPO_WREG, pc);
11528       if (val) vallit = litFromValnum (val->in_val);
11529       if (vallit != -1) {
11530         /* xxxLW <literal>, WREG contains a known literal */
11531         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11532         if (pci->op == POC_ANDLW) {
11533           lit &= vallit;
11534         } else if (pci->op == POC_IORLW) {
11535           lit |= vallit;
11536         } else if (pci->op == POC_XORLW) {
11537           lit ^= vallit;
11538         } else {
11539           assert (0 && "invalid operation");
11540         }
11541         if (vallit == lit) {
11542           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11543           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11544         }
11545         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11546       } // if
11547     }
11548     break;
11549
11550   case POC_LFSR:
11551     {
11552       /* check if old value matches new value */
11553       int lit;
11554       int ok = 1;
11555       assert (pci->pcop->type == PO_LITERAL);
11556
11557       lit = PCOL(pci->pcop)->lit;
11558
11559       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11560
11561       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11562         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11563       } else {
11564         /* cannot remove this LFSR */
11565         ok = 0;
11566       } // if
11567
11568       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11569       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11570         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11571       } else {
11572         ok = 0;
11573       } // if
11574
11575       if (ok) {
11576         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11577       }
11578     }
11579     break;
11580
11581   case POC_MOVWF: /* does not touch flags */
11582     /* find value of WREG */
11583     val = defmapCurr (list, SPO_WREG, pc);
11584     oldval = defmapCurr (list, sym1, pc);
11585     if (val) lit = litFromValnum (val->in_val);
11586     else lit = -1;
11587     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11588
11589     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11590       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11591       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11592       if (lit == 0) {
11593         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11594       } else {
11595         assert (lit == 0x0ff);
11596         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11597       }
11598       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11599       pic16_pCodeReplace (pc, newpc);
11600       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11601       pic16_fixDefmap (pc, newpc);
11602       pc = newpc;
11603
11604       /* This breaks the defmap chain's references to pCodes... fix it! */
11605       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11606       if (!val->acc.access.isWrite) {
11607         deleteDefmap (val);     // delete reference to WREG as in value
11608         val = NULL;
11609       } else {
11610         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11611       }
11612       oldval = PCI(pc)->pcflow->defmap;
11613       while (oldval) {
11614         if (oldval->pc == pc) oldval->pc = newpc;
11615           oldval = oldval->next;
11616       } // while
11617     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11618       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11619       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11620     }
11621     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11622     break;
11623
11624   case POC_MOVFW: /* modifies STATUS (Z,N) */
11625     /* find value of REG */
11626     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11627       val = defmapCurr (list, sym1, pc);
11628       oldval = defmapCurr (list, SPO_WREG, pc);
11629       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11630         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11631         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11632       } else {
11633           defmap_t *pred, *predpred;
11634           /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11635            * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11636            * This might allow removal of the first two assignments. */
11637           pred = defmapFindDef (list, sym1, pc);
11638           predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11639           if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11640                 && !pic16_isAlive (SPO_STATUS, pc))
11641           {
11642               newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11643
11644               if (pic16_debug_verbose || pic16_pcode_verbose) {
11645                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11646               } // if
11647               pic16_pCodeReplace (pc, newpc);
11648               defmapReplaceSymRef (pc, sym1, 0, 1);
11649               pic16_fixDefmap (pc, newpc);
11650               pc = newpc;
11651
11652               /* This breaks the defmap chain's references to pCodes... fix it! */
11653               if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11654               if (!val->acc.access.isWrite) {
11655                   deleteDefmap (val);   // delete reference to reg1 as in value
11656                   val = NULL;
11657               } else {
11658                   val->acc.access.isRead = 0;   // delete reference to reg1 as in value
11659               }
11660               oldval = PCI(pc)->pcflow->defmap;
11661               while (oldval) {
11662                   if (oldval->pc == pc) oldval->pc = newpc;
11663                   oldval = oldval->next;
11664               } // while
11665           } // if
11666       }
11667       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11668     }
11669     break;
11670
11671   case POC_MOVFF: /* does not touch STATUS */
11672     /* find value of REG */
11673     val = defmapCurr (list, sym1, pc);
11674     oldval = defmapCurr (list, sym2, pc);
11675     if (val) lit = litFromValnum (val->in_val);
11676     else lit = -1;
11677     newpc = NULL;
11678     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11679       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11680       if (lit == 0) {
11681         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11682       } else if (lit == 0x00ff) {
11683         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11684       } else {
11685         newpc = NULL;
11686       }
11687       if (newpc) {
11688         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11689         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11690         pic16_pCodeReplace (pc, newpc);
11691         defmapReplaceSymRef (pc, sym1, 0, 1);
11692         pic16_fixDefmap (pc, newpc);
11693         pc = newpc;
11694         break; // do not process instruction as MOVFF...
11695       }
11696     } else if (!isSpecial1 && !isSpecial2
11697                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11698                 && val && oldval && (val->in_val != 0)) {
11699       if (val->in_val == oldval->in_val) {
11700         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11701         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11702       } else {
11703         if (!pic16_isAlive (sym1, pc)) {
11704           defmap_t *copy = NULL;
11705           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11706            * This should help eliminate
11707            *   MOVFF A,B
11708            *   <do something not changing A or using B>
11709            *   MOVFF B,C
11710            *   <B is not alive anymore>
11711            * and turn it into
11712            *   <do something not changing A or using B>
11713            *   MOVFF A,C
11714            */
11715
11716           /* scan defmap for symbols storing sym1's value */
11717           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11718           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11719             /* unique reaching definition for sym found */
11720             if (copy->val && copy->val == val->in_val) {
11721               //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);
11722               if (copy->sym == SPO_WREG) {
11723                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11724               } else {
11725                 pCodeOp *pcop = NULL;
11726                 /* the code below fails if we try to replace
11727                  *   MOVFF PRODL, r0x03
11728                  *   MOVFF r0x03, PCLATU
11729                  * with
11730                  *   MOVFF PRODL, PCLATU
11731                  * as copy(PRODL) contains has pc==NULL, by name fails...
11732                  */
11733                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11734
11735                 if (copy->pc && PCI(copy->pc)->pcop)
11736                   pcop = PCI(copy->pc)->pcop;
11737 #if 0
11738                 /* This code is broken--see above. */
11739                 else
11740                 {
11741                   const char *symname = strFromSym(copy->sym);
11742
11743                   assert( symname );
11744                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11745                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11746                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11747                 }
11748 #endif
11749                 assert( pcop );
11750                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11751                         pcop,
11752                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11753               }
11754               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11755               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11756               pic16_pCodeReplace (pc, newpc);
11757               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11758               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11759               pic16_fixDefmap (pc, newpc);
11760               pc = newpc;
11761             }
11762           }
11763           deleteDefmapChain (&copy);
11764         }
11765       }
11766       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11767     }
11768     break;
11769
11770   default:
11771     /* cannot optimize */
11772     break;
11773   } // switch
11774 }
11775
11776 static void pic16_destructDF (pBlock *pb) {
11777   pCode *pc, *next;
11778
11779   if (!pb) return;
11780
11781   /* remove old defmaps */
11782   pc = pic16_findNextInstruction (pb->pcHead);
11783   while (pc) {
11784     next = pic16_findNextInstruction (pc->next);
11785
11786     assert (isPCI(pc) || isPCAD(pc));
11787     assert (PCI(pc)->pcflow);
11788     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11789     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11790     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11791
11792     pc = next;
11793   } // while
11794
11795   if (defmap_free || defmap_free_count) {
11796     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11797     freeDefmap (&defmap_free);
11798     defmap_free_count = 0;
11799   }
11800 }
11801
11802 /* Checks whether a pBlock contains ASMDIRs. */
11803 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11804   pCode *pc;
11805
11806   if (!pb) return 0;
11807
11808   pc = pic16_findNextInstruction (pb->pcHead);
11809   while (pc) {
11810     if (isPCAD(pc)) return 1;
11811
11812     pc = pic16_findNextInstruction (pc->next);
11813   } // while
11814
11815   /* no PCADs found */
11816   return 0;
11817 }
11818
11819 #if 1
11820 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11821 static int pic16_removeUnusedRegistersDF () {
11822   pCode *pc, *pc2;
11823   pBlock *pb;
11824   regs *reg1, *reg2, *reg3;
11825   set *seenRegs = NULL;
11826   int cond, i;
11827   int islocal, change = 0;
11828
11829   /* no pBlocks? */
11830   if (!the_pFile || !the_pFile->pbHead) return 0;
11831
11832   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11833     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11834 #if 1
11835     /* find set of using pCodes per register */
11836     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11837                     pc = pic16_findNextInstruction(pc->next)) {
11838
11839       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11840       reg1 = reg2 = NULL;
11841       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11842       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11843
11844       if (reg1) {
11845         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11846         addSetIfnotP (&seenRegs, reg1);
11847         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11848       }
11849       if (reg2) {
11850         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11851         addSetIfnotP (&seenRegs, reg2);
11852         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11853       }
11854     } // for pc
11855 #endif
11856     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11857       /* may not use pic16_regIsLocal() here -- in interrupt routines
11858        * WREG, PRODx, FSR0x must be saved */
11859       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11860       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11861         pc = pc2 = NULL;
11862         for (i=0; i < 2; i++) {
11863           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11864           if (!pc2) pc2 = pc;
11865           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11866           reg2 = pic16_getRegFromInstruction (pc);
11867           reg3 = pic16_getRegFromInstruction2 (pc);
11868           if (!reg2 || !reg3
11869               || (reg2->rIdx != pic16_stack_preinc->rIdx
11870                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11871           if (i == 1) {
11872             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11873             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11874             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11875             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11876           }
11877         } // for
11878       } // if
11879       deleteSet (&reg1->reglives.usedpCodes);
11880     } // for reg1
11881
11882     deleteSet (&seenRegs);
11883   } // for pb
11884
11885   return change;
11886 }
11887 #endif
11888
11889 /* Set up pCodeFlow's defmap_ts.
11890  * Needs correctly set up to/from fields. */
11891 static void pic16_createDF (pBlock *pb) {
11892   pCode *pc, *next;
11893   int change=0;
11894
11895   if (!pb) return;
11896
11897   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11898
11899   pic16_destructDF (pb);
11900
11901   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11902   if (pic16_pBlockHasAsmdirs (pb)) {
11903     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11904     return;
11905   }
11906
11907   /* integrity check -- we need to reach all flows to guarantee
11908    * correct data flow analysis (reaching definitions, aliveness) */
11909 #if 0
11910   if (!verifyAllFlowsReachable (pb)) {
11911     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11912     return;
11913   }
11914 #endif
11915
11916   /* establish new defmaps */
11917   pc = pic16_findNextInstruction (pb->pcHead);
11918   while (pc) {
11919     next = pic16_findNextInstruction (pc->next);
11920
11921     assert (PCI(pc)->pcflow);
11922     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11923
11924     pc = next;
11925   } // while
11926
11927   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11928   createReachingDefinitions (pb);
11929
11930 #if 1
11931   /* assign better valnums */
11932   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11933   pc = pic16_findNextInstruction (pb->pcHead);
11934   while (pc) {
11935     next = pic16_findNextInstruction (pc->next);
11936
11937     assert (PCI(pc)->pcflow);
11938     assignValnums (pc);
11939
11940     pc = next;
11941   } // while
11942 #endif
11943
11944 #if 1
11945   /* remove dead pCodes */
11946   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11947   do {
11948     change = 0;
11949     pc = pic16_findNextInstruction (pb->pcHead);
11950     while (pc) {
11951       next = pic16_findNextInstruction (pc->next);
11952
11953       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11954         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11955       }
11956
11957       pc = next;
11958     } // while
11959   } while (change);
11960 #endif
11961 }
11962
11963 /* ======================================================================== */
11964 /* === VCG DUMPER ROUTINES ================================================ */
11965 /* ======================================================================== */
11966 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11967 hTab *dumpedNodes = NULL;
11968
11969 /** Dump VCG header into of. */
11970 static void pic16_vcg_init (FILE *of) {
11971   /* graph defaults */
11972   fprintf (of, "graph:{\n");
11973   fprintf (of, "title:\"graph1\"\n");
11974   fprintf (of, "label:\"graph1\"\n");
11975   fprintf (of, "color:white\n");
11976   fprintf (of, "textcolor:black\n");
11977   fprintf (of, "bordercolor:black\n");
11978   fprintf (of, "borderwidth:1\n");
11979   fprintf (of, "textmode:center\n");
11980
11981   fprintf (of, "layoutalgorithm:dfs\n");
11982   fprintf (of, "late_edge_labels:yes\n");
11983   fprintf (of, "display_edge_labels:yes\n");
11984   fprintf (of, "dirty_edge_labels:yes\n");
11985   fprintf (of, "finetuning:yes\n");
11986   fprintf (of, "ignoresingles:no\n");
11987   fprintf (of, "straight_phase:yes\n");
11988   fprintf (of, "priority_phase:yes\n");
11989   fprintf (of, "manhattan_edges:yes\n");
11990   fprintf (of, "smanhattan_edges:no\n");
11991   fprintf (of, "nearedges:no\n");
11992   fprintf (of, "node_alignment:center\n"); // bottom|top|center
11993   fprintf (of, "port_sharing:no\n");
11994   fprintf (of, "arrowmode:free\n"); // fixed|free
11995   fprintf (of, "crossingphase2:yes\n");
11996   fprintf (of, "crossingoptimization:yes\n");
11997   fprintf (of, "edges:yes\n");
11998   fprintf (of, "nodes:yes\n");
11999   fprintf (of, "splines:no\n");
12000
12001   /* node defaults */
12002   fprintf (of, "node.color:lightyellow\n");
12003   fprintf (of, "node.textcolor:black\n");
12004   fprintf (of, "node.textmode:center\n");
12005   fprintf (of, "node.shape:box\n");
12006   fprintf (of, "node.bordercolor:black\n");
12007   fprintf (of, "node.borderwidth:1\n");
12008
12009   /* edge defaults */
12010   fprintf (of, "edge.textcolor:black\n");
12011   fprintf (of, "edge.color:black\n");
12012   fprintf (of, "edge.thickness:1\n");
12013   fprintf (of, "edge.arrowcolor:black\n");
12014   fprintf (of, "edge.backarrowcolor:black\n");
12015   fprintf (of, "edge.arrowsize:15\n");
12016   fprintf (of, "edge.backarrowsize:15\n");
12017   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12018   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12019   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12020
12021   fprintf (of, "\n");
12022
12023   /* prepare data structures */
12024   if (dumpedNodes) {
12025     hTabDeleteAll (dumpedNodes);
12026     dumpedNodes = NULL;
12027   }
12028   dumpedNodes = newHashTable (128);
12029 }
12030
12031 /** Dump VCG footer into of. */
12032 static void pic16_vcg_close (FILE *of) {
12033   fprintf (of, "}\n");
12034 }
12035
12036 #define BUF_SIZE 128
12037 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12038
12039 #if 0
12040 static int ptrcmp (const void *p1, const void *p2) {
12041   return p1 == p2;
12042 }
12043 #endif
12044
12045 /** Dump a pCode node as VCG to of. */
12046 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12047   char buf[BUF_SIZE];
12048
12049   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12050     // dumped already
12051     return;
12052   }
12053   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12054   //fprintf (stderr, "dumping %p\n", pc);
12055
12056   /* only dump pCodeInstructions and Flow nodes */
12057   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12058
12059   /* emit node */
12060   fprintf (of, "node:{");
12061   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12062   fprintf (of, "label:\"%s\n", pcTitle(pc));
12063   if (isPCFL(pc)) {
12064     fprintf (of, "<PCFLOW>");
12065   } else if (isPCI(pc) || isPCAD(pc)) {
12066     pc->print (of, pc);
12067   } else {
12068     fprintf (of, "<!PCI>");
12069   }
12070   fprintf (of, "\" ");
12071   fprintf (of, "}\n");
12072
12073   if (1 && isPCFL(pc)) {
12074     defmap_t *map, *prev;
12075     unsigned int i;
12076     map = PCFL(pc)->defmap;
12077     i=0;
12078     while (map) {
12079       if (map->sym != 0) {
12080         i++;
12081
12082         /* emit definition node */
12083         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12084         fprintf (of, "label:\"");
12085
12086         prev = map;
12087         do {
12088           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));
12089           prev = map;
12090           map = map->next;
12091         } while (map && prev->pc == map->pc);
12092         map = prev;
12093
12094         fprintf (of, "\" ");
12095
12096         fprintf (of, "color:green ");
12097         fprintf (of, "}\n");
12098
12099         /* emit edge to previous definition */
12100         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12101         if (i == 1) {
12102           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12103         } else {
12104           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12105         }
12106         fprintf (of, "color:green ");
12107         fprintf (of, "}\n");
12108
12109         if (map->pc) {
12110           pic16_vcg_dumpnode (map->pc, of);
12111           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12112           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12113         }
12114       }
12115       map = map->next;
12116     } // while
12117   }
12118
12119   /* emit additional nodes (e.g. operands) */
12120 }
12121
12122 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12123 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12124   char buf[BUF_SIZE];
12125   pCodeInstruction *pci;
12126   pBranch *curr;
12127   int i;
12128
12129   if (1 && isPCFL(pc)) {
12130     /* emit edges to flow successors */
12131     void *pcfl;
12132     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12133     pcfl = setFirstItem (PCFL(pc)->to);
12134     while (pcfl) {
12135       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12136       pic16_vcg_dumpnode (pc, of);
12137       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12138       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12139       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12140       pcfl = setNextItem (PCFL(pc)->to);
12141     } // while
12142   } // if
12143
12144   if (!isPCI(pc) && !isPCAD(pc)) return;
12145
12146   pci = PCI(pc);
12147
12148   /* emit control flow edges (forward only) */
12149   curr = pci->to;
12150   i=0;
12151   while (curr) {
12152     pic16_vcg_dumpnode (curr->pc, of);
12153     fprintf (of, "edge:{");
12154     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12155     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12156     fprintf (of, "color:red ");
12157     fprintf (of, "}\n");
12158     curr = curr->next;
12159   } // while
12160
12161 #if 1
12162   /* dump "flow" edge (link pCode according to pBlock order) */
12163   {
12164     pCode *pcnext;
12165     pcnext = pic16_findNextInstruction (pc->next);
12166     if (pcnext) {
12167       pic16_vcg_dumpnode (pcnext, of);
12168       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12169       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12170     }
12171   }
12172 #endif
12173
12174 #if 0
12175   /* emit flow */
12176   if (pci->pcflow) {
12177     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12178     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12179     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12180   }
12181 #endif
12182
12183   /* emit data flow edges (backward only) */
12184   /* TODO: gather data flow information... */
12185 }
12186
12187 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12188   pCode *pc;
12189
12190   if (!pb) return;
12191
12192   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12193   if (pic16_pBlockHasAsmdirs (pb)) {
12194     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12195     return;
12196   }
12197
12198   for (pc=pb->pcHead; pc; pc = pc->next) {
12199     pic16_vcg_dumpnode (pc, of);
12200   } // for pc
12201
12202   for (pc=pb->pcHead; pc; pc = pc->next) {
12203     pic16_vcg_dumpedges (pc, of);
12204   } // for pc
12205 }
12206
12207 static void pic16_vcg_dump_default (pBlock *pb) {
12208   FILE *of;
12209   char buf[BUF_SIZE];
12210   pCode *pc;
12211
12212   if (!pb) return;
12213
12214   /* get function name */
12215   pc = pb->pcHead;
12216   while (pc && !isPCF(pc)) pc = pc->next;
12217   if (pc) {
12218     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12219   } else {
12220     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12221   }
12222
12223   //fprintf (stderr, "now dumping %s\n", buf);
12224   of = fopen (buf, "w");
12225   pic16_vcg_init (of);
12226   pic16_vcg_dump (of, pb);
12227   pic16_vcg_close (of);
12228   fclose (of);
12229 }
12230 #endif
12231
12232 /*** END of helpers for pCode dataflow optimizations ***/