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