* device/include/pic16/stdio.h,
[fw/sdcc] / src / pic16 / pcode.c
1 /*-------------------------------------------------------------------------
2
3   pcode.c - post code generation
4
5    Written By -  Scott Dattalo scott@dattalo.com
6    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
7
8    This program is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23 #include <stdio.h>
24
25 #include "common.h"   // Include everything in the SDCC src directory
26 #include "newalloc.h"
27
28
29 #include "main.h"
30 #include "pcode.h"
31 #include "pcodeflow.h"
32 #include "ralloc.h"
33 #include "device.h"
34
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
36
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
38 #define inline
39 #endif
40
41 #define DUMP_DF_GRAPHS 0
42
43 /****************************************************************/
44 /****************************************************************/
45
46 static peepCommand peepCommands[] = {
47
48   {NOTBITSKIP, "_NOTBITSKIP_"},
49   {BITSKIP, "_BITSKIP_"},
50   {INVERTBITSKIP, "_INVERTBITSKIP_"},
51
52   {-1, NULL}
53 };
54
55
56
57 // Eventually this will go into device dependent files:
58 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
59 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
63 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
65
66 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
67 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
68 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
69
70 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
71 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
72 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
74
75 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
76
77 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
78 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
83
84 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
85 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
86 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
89
90 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
91 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
92 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
95
96 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
97 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
98 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
101
102 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
104
105 /* EEPROM registers */
106 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
107 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
110
111 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
112 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
114
115 pCodeOpReg *pic16_stackpnt_lo;
116 pCodeOpReg *pic16_stackpnt_hi;
117 pCodeOpReg *pic16_stack_postinc;
118 pCodeOpReg *pic16_stack_postdec;
119 pCodeOpReg *pic16_stack_preinc;
120 pCodeOpReg *pic16_stack_plusw;
121
122 pCodeOpReg *pic16_framepnt_lo;
123 pCodeOpReg *pic16_framepnt_hi;
124 pCodeOpReg *pic16_frame_postinc;
125 pCodeOpReg *pic16_frame_postdec;
126 pCodeOpReg *pic16_frame_preinc;
127 pCodeOpReg *pic16_frame_plusw;
128
129 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
130 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
131
132 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
133 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
134
135
136 static int mnemonics_initialized = 0;
137
138
139 static hTab *pic16MnemonicsHash = NULL;
140 static hTab *pic16pCodePeepCommandsHash = NULL;
141
142 static pFile *the_pFile = NULL;
143 static pBlock *pb_dead_pcodes = NULL;
144
145 /* Hardcoded flags to change the behavior of the PIC port */
146 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
147 static int functionInlining = 1;      /* inline functions if nonzero */
148 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
149
150 int pic16_pcode_verbose = 0;
151
152 //static int GpCodeSequenceNumber = 1;
153 static int GpcFlowSeq = 1;
154
155 extern void pic16_RemoveUnusedRegisters(void);
156 extern void pic16_RegsUnMapLiveRanges(void);
157 extern void pic16_BuildFlowTree(pBlock *pb);
158 extern void pic16_pCodeRegOptimizeRegUsage(int level);
159
160 /****************************************************************/
161 /*                      Forward declarations                    */
162 /****************************************************************/
163
164 void pic16_unlinkpCode(pCode *pc);
165 #if 0
166 static void genericAnalyze(pCode *pc);
167 static void AnalyzeGOTO(pCode *pc);
168 static void AnalyzeSKIP(pCode *pc);
169 static void AnalyzeRETURN(pCode *pc);
170 #endif
171
172 static void genericDestruct(pCode *pc);
173 static void genericPrint(FILE *of,pCode *pc);
174
175 static void pCodePrintLabel(FILE *of, pCode *pc);
176 static void pCodePrintFunction(FILE *of, pCode *pc);
177 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
178 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
179 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
180 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
181 int pic16_pCodePeepMatchRule(pCode *pc);
182 static void pBlockStats(FILE *of, pBlock *pb);
183 static pBlock *newpBlock(void);
184 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
185 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
186 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
187 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
188 void OptimizeLocalRegs(void);
189 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
190
191 char *dumpPicOptype(PIC_OPTYPE type);
192
193 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
194 pCodeOp *pic16_popGetLit(int);
195 pCodeOp *pic16_popGetWithString(char *);
196 extern int inWparamList(char *s);
197
198 /** data flow optimization helpers **/
199 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
200 static void pic16_vcg_dump (FILE *of, pBlock *pb);
201 static void pic16_vcg_dump_default (pBlock *pb);
202 #endif
203 static int pic16_pCodeIsAlive (pCode *pc);
204 static void pic16_df_stats ();
205 static void pic16_createDF (pBlock *pb);
206 static int pic16_removeUnusedRegistersDF ();
207 static void pic16_destructDF (pBlock *pb);
208 static void releaseStack ();
209
210 /****************************************************************/
211 /*                    PIC Instructions                          */
212 /****************************************************************/
213
214 pCodeInstruction pic16_pciADDWF = {
215   {PC_OPCODE, NULL, NULL, 0, NULL,
216    //   genericAnalyze,
217    genericDestruct,
218    genericPrint},
219   POC_ADDWF,
220   "ADDWF",
221   2,
222   NULL, // from branch
223   NULL, // to branch
224   NULL, // label
225   NULL, // operand
226   NULL, // flow block
227   NULL, // C source
228   3,    // num ops
229   1,0,  // dest, bit instruction
230   0,0,  // branch, skip
231   0,    // literal operand
232   1,    // RAM access bit
233   0,    // fast call/return mode select bit
234   0,    // second memory operand
235   0,    // second literal operand
236   POC_NOP,
237   (PCC_W | PCC_REGISTER),   // inCond
238   (PCC_REGISTER | PCC_STATUS), // outCond
239   PCI_MAGIC
240 };
241
242 pCodeInstruction pic16_pciADDFW = {
243   {PC_OPCODE, NULL, NULL, 0, NULL,
244    //   genericAnalyze,
245    genericDestruct,
246    genericPrint},
247   POC_ADDFW,
248   "ADDWF",
249   2,
250   NULL, // from branch
251   NULL, // to branch
252   NULL, // label
253   NULL, // operand
254   NULL, // flow block
255   NULL, // C source
256   3,    // num ops
257   0,0,  // dest, bit instruction
258   0,0,  // branch, skip
259   0,    // literal operand
260   1,    // RAM access bit
261   0,    // fast call/return mode select bit
262   0,    // second memory operand
263   0,    // second literal operand
264   POC_NOP,
265   (PCC_W | PCC_REGISTER),   // inCond
266   (PCC_W | PCC_STATUS), // outCond
267   PCI_MAGIC
268 };
269
270 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
271   {PC_OPCODE, NULL, NULL, 0, NULL,
272    //   genericAnalyze,
273    genericDestruct,
274    genericPrint},
275   POC_ADDWFC,
276   "ADDWFC",
277   2,
278   NULL, // from branch
279   NULL, // to branch
280   NULL, // label
281   NULL, // operand
282   NULL, // flow block
283   NULL, // C source
284   3,    // num ops
285   1,0,  // dest, bit instruction
286   0,0,  // branch, skip
287   0,    // literal operand
288   1,    // RAM access bit
289   0,    // fast call/return mode select bit
290   0,    // second memory operand
291   0,    // second literal operand
292   POC_NOP,
293   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
294   (PCC_REGISTER | PCC_STATUS), // outCond
295   PCI_MAGIC
296 };
297
298 pCodeInstruction pic16_pciADDFWC = {
299   {PC_OPCODE, NULL, NULL, 0, NULL,
300    //   genericAnalyze,
301    genericDestruct,
302    genericPrint},
303   POC_ADDFWC,
304   "ADDWFC",
305   2,
306   NULL, // from branch
307   NULL, // to branch
308   NULL, // label
309   NULL, // operand
310   NULL, // flow block
311   NULL, // C source
312   3,    // num ops
313   0,0,  // dest, bit instruction
314   0,0,  // branch, skip
315   0,    // literal operand
316   1,    // RAM access bit
317   0,    // fast call/return mode select bit
318   0,    // second memory operand
319   0,    // second literal operand
320   POC_NOP,
321   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
322   (PCC_W | PCC_STATUS), // outCond
323   PCI_MAGIC
324 };
325
326 pCodeInstruction pic16_pciADDLW = {
327   {PC_OPCODE, NULL, NULL, 0, NULL,
328    //   genericAnalyze,
329    genericDestruct,
330    genericPrint},
331   POC_ADDLW,
332   "ADDLW",
333   2,
334   NULL, // from branch
335   NULL, // to branch
336   NULL, // label
337   NULL, // operand
338   NULL, // flow block
339   NULL, // C source
340   1,    // num ops
341   0,0,  // dest, bit instruction
342   0,0,  // branch, skip
343   1,    // literal operand
344   0,    // RAM access bit
345   0,    // fast call/return mode select bit
346   0,    // second memory operand
347   0,    // second literal operand
348   POC_NOP,
349   (PCC_W | PCC_LITERAL),   // inCond
350   (PCC_W | PCC_STATUS), // outCond
351   PCI_MAGIC
352 };
353
354 pCodeInstruction pic16_pciANDLW = {
355   {PC_OPCODE, NULL, NULL, 0, NULL,
356    //   genericAnalyze,
357    genericDestruct,
358    genericPrint},
359   POC_ANDLW,
360   "ANDLW",
361   2,
362   NULL, // from branch
363   NULL, // to branch
364   NULL, // label
365   NULL, // operand
366   NULL, // flow block
367   NULL, // C source
368   1,    // num ops
369   0,0,  // dest, bit instruction
370   0,0,  // branch, skip
371   1,    // literal operand
372   0,    // RAM access bit
373   0,    // fast call/return mode select bit
374   0,    // second memory operand
375   0,    // second literal operand
376   POC_NOP,
377   (PCC_W | PCC_LITERAL),   // inCond
378   (PCC_W | PCC_Z | PCC_N), // outCond
379   PCI_MAGIC
380 };
381
382 pCodeInstruction pic16_pciANDWF = {
383   {PC_OPCODE, NULL, NULL, 0, NULL,
384    //   genericAnalyze,
385    genericDestruct,
386    genericPrint},
387   POC_ANDWF,
388   "ANDWF",
389   2,
390   NULL, // from branch
391   NULL, // to branch
392   NULL, // label
393   NULL, // operand
394   NULL, // flow block
395   NULL, // C source
396   3,    // num ops
397   1,0,  // dest, bit instruction
398   0,0,  // branch, skip
399   0,    // literal operand
400   1,    // RAM access bit
401   0,    // fast call/return mode select bit
402   0,    // second memory operand
403   0,    // second literal operand
404   POC_NOP,
405   (PCC_W | PCC_REGISTER),   // inCond
406   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
407   PCI_MAGIC
408 };
409
410 pCodeInstruction pic16_pciANDFW = {
411   {PC_OPCODE, NULL, NULL, 0, NULL,
412    //   genericAnalyze,
413    genericDestruct,
414    genericPrint},
415   POC_ANDFW,
416   "ANDWF",
417   2,
418   NULL, // from branch
419   NULL, // to branch
420   NULL, // label
421   NULL, // operand
422   NULL, // flow block
423   NULL, // C source
424   3,    // num ops
425   0,0,  // dest, bit instruction
426   0,0,  // branch, skip
427   0,    // literal operand
428   1,    // RAM access bit
429   0,    // fast call/return mode select bit
430   0,    // second memory operand
431   0,    // second literal operand
432   POC_NOP,
433   (PCC_W | PCC_REGISTER),   // inCond
434   (PCC_W | PCC_Z | PCC_N) // outCond
435 };
436
437 pCodeInstruction pic16_pciBC = { // mdubuc - New
438   {PC_OPCODE, NULL, NULL, 0, NULL,
439    //   genericAnalyze,
440    genericDestruct,
441    genericPrint},
442   POC_BC,
443   "BC",
444   2,
445   NULL, // from branch
446   NULL, // to branch
447   NULL, // label
448   NULL, // operand
449   NULL, // flow block
450   NULL, // C source
451   1,    // num ops
452   0,0,  // dest, bit instruction
453   1,0,  // branch, skip
454   0,    // literal operand
455   0,    // RAM access bit
456   0,    // fast call/return mode select bit
457   0,    // second memory operand
458   0,    // second literal operand
459   POC_NOP,
460   (PCC_REL_ADDR | PCC_C),   // inCond
461   PCC_NONE,    // outCond
462   PCI_MAGIC
463 };
464
465 pCodeInstruction pic16_pciBCF = {
466   {PC_OPCODE, NULL, NULL, 0, NULL,
467    //   genericAnalyze,
468    genericDestruct,
469    genericPrint},
470   POC_BCF,
471   "BCF",
472   2,
473   NULL, // from branch
474   NULL, // to branch
475   NULL, // label
476   NULL, // operand
477   NULL, // flow block
478   NULL, // C source
479   3,    // num ops
480   1,1,  // dest, bit instruction
481   0,0,  // branch, skip
482   0,    // literal operand
483   1,    // RAM access bit
484   0,    // fast call/return mode select bit
485   0,    // second memory operand
486   0,    // second literal operand
487   POC_BSF,
488   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
489   PCC_REGISTER, // outCond
490   PCI_MAGIC
491 };
492
493 pCodeInstruction pic16_pciBN = { // mdubuc - New
494   {PC_OPCODE, NULL, NULL, 0, NULL,
495    //   genericAnalyze,
496    genericDestruct,
497    genericPrint},
498   POC_BN,
499   "BN",
500   2,
501   NULL, // from branch
502   NULL, // to branch
503   NULL, // label
504   NULL, // operand
505   NULL, // flow block
506   NULL, // C source
507   1,    // num ops
508   0,0,  // dest, bit instruction
509   1,0,  // branch, skip
510   0,    // literal operand
511   0,    // RAM access bit
512   0,    // fast call/return mode select bit
513   0,    // second memory operand
514   0,    // second literal operand
515   POC_NOP,
516   (PCC_REL_ADDR | PCC_N),   // inCond
517   PCC_NONE   , // outCond
518   PCI_MAGIC
519 };
520
521 pCodeInstruction pic16_pciBNC = { // mdubuc - New
522   {PC_OPCODE, NULL, NULL, 0, NULL,
523    //   genericAnalyze,
524    genericDestruct,
525    genericPrint},
526   POC_BNC,
527   "BNC",
528   2,
529   NULL, // from branch
530   NULL, // to branch
531   NULL, // label
532   NULL, // operand
533   NULL, // flow block
534   NULL, // C source
535   1,    // num ops
536   0,0,  // dest, bit instruction
537   1,0,  // branch, skip
538   0,    // literal operand
539   0,    // RAM access bit
540   0,    // fast call/return mode select bit
541   0,    // second memory operand
542   0,    // second literal operand
543   POC_NOP,
544   (PCC_REL_ADDR | PCC_C),   // inCond
545   PCC_NONE   , // outCond
546   PCI_MAGIC
547 };
548
549 pCodeInstruction pic16_pciBNN = { // mdubuc - New
550   {PC_OPCODE, NULL, NULL, 0, NULL,
551    //   genericAnalyze,
552    genericDestruct,
553    genericPrint},
554   POC_BNN,
555   "BNN",
556   2,
557   NULL, // from branch
558   NULL, // to branch
559   NULL, // label
560   NULL, // operand
561   NULL, // flow block
562   NULL, // C source
563   1,    // num ops
564   0,0,  // dest, bit instruction
565   1,0,  // branch, skip
566   0,    // literal operand
567   0,    // RAM access bit
568   0,    // fast call/return mode select bit
569   0,    // second memory operand
570   0,    // second literal operand
571   POC_NOP,
572   (PCC_REL_ADDR | PCC_N),   // inCond
573   PCC_NONE   , // outCond
574   PCI_MAGIC
575 };
576
577 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
578   {PC_OPCODE, NULL, NULL, 0, NULL,
579    //   genericAnalyze,
580    genericDestruct,
581    genericPrint},
582   POC_BNOV,
583   "BNOV",
584   2,
585   NULL, // from branch
586   NULL, // to branch
587   NULL, // label
588   NULL, // operand
589   NULL, // flow block
590   NULL, // C source
591   1,    // num ops
592   0,0,  // dest, bit instruction
593   1,0,  // branch, skip
594   0,    // literal operand
595   0,    // RAM access bit
596   0,    // fast call/return mode select bit
597   0,    // second memory operand
598   0,    // second literal operand
599   POC_NOP,
600   (PCC_REL_ADDR | PCC_OV),   // inCond
601   PCC_NONE   , // outCond
602   PCI_MAGIC
603 };
604
605 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
606   {PC_OPCODE, NULL, NULL, 0, NULL,
607    //   genericAnalyze,
608    genericDestruct,
609    genericPrint},
610   POC_BNZ,
611   "BNZ",
612   2,
613   NULL, // from branch
614   NULL, // to branch
615   NULL, // label
616   NULL, // operand
617   NULL, // flow block
618   NULL, // C source
619   1,    // num ops
620   0,0,  // dest, bit instruction
621   1,0,  // branch, skip
622   0,    // literal operand
623   0,    // RAM access bit
624   0,    // fast call/return mode select bit
625   0,    // second memory operand
626   0,    // second literal operand
627   POC_NOP,
628   (PCC_REL_ADDR | PCC_Z),   // inCond
629   PCC_NONE   , // outCond
630   PCI_MAGIC
631 };
632
633 pCodeInstruction pic16_pciBOV = { // mdubuc - New
634   {PC_OPCODE, NULL, NULL, 0, NULL,
635    //   genericAnalyze,
636    genericDestruct,
637    genericPrint},
638   POC_BOV,
639   "BOV",
640   2,
641   NULL, // from branch
642   NULL, // to branch
643   NULL, // label
644   NULL, // operand
645   NULL, // flow block
646   NULL, // C source
647   1,    // num ops
648   0,0,  // dest, bit instruction
649   1,0,  // branch, skip
650   0,    // literal operand
651   0,    // RAM access bit
652   0,    // fast call/return mode select bit
653   0,    // second memory operand
654   0,    // second literal operand
655   POC_NOP,
656   (PCC_REL_ADDR | PCC_OV),   // inCond
657   PCC_NONE , // outCond
658   PCI_MAGIC
659 };
660
661 pCodeInstruction pic16_pciBRA = { // mdubuc - New
662   {PC_OPCODE, NULL, NULL, 0, NULL,
663    //   genericAnalyze,
664    genericDestruct,
665    genericPrint},
666   POC_BRA,
667   "BRA",
668   2,
669   NULL, // from branch
670   NULL, // to branch
671   NULL, // label
672   NULL, // operand
673   NULL, // flow block
674   NULL, // C source
675   1,    // num ops
676   0,0,  // dest, bit instruction
677   1,0,  // branch, skip
678   0,    // literal operand
679   0,    // RAM access bit
680   0,    // fast call/return mode select bit
681   0,    // second memory operand
682   0,    // second literal operand
683   POC_NOP,
684   PCC_REL_ADDR,   // inCond
685   PCC_NONE   , // outCond
686   PCI_MAGIC
687 };
688
689 pCodeInstruction pic16_pciBSF = {
690   {PC_OPCODE, NULL, NULL, 0, NULL,
691    //   genericAnalyze,
692    genericDestruct,
693    genericPrint},
694   POC_BSF,
695   "BSF",
696   2,
697   NULL, // from branch
698   NULL, // to branch
699   NULL, // label
700   NULL, // operand
701   NULL, // flow block
702   NULL, // C source
703   3,    // num ops
704   1,1,  // dest, bit instruction
705   0,0,  // branch, skip
706   0,    // literal operand
707   1,    // RAM access bit
708   0,    // fast call/return mode select bit
709   0,    // second memory operand
710   0,    // second literal operand
711   POC_BCF,
712   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
713   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
714   PCI_MAGIC
715 };
716
717 pCodeInstruction pic16_pciBTFSC = {
718   {PC_OPCODE, NULL, NULL, 0, NULL,
719    //   AnalyzeSKIP,
720    genericDestruct,
721    genericPrint},
722   POC_BTFSC,
723   "BTFSC",
724   2,
725   NULL, // from branch
726   NULL, // to branch
727   NULL, // label
728   NULL, // operand
729   NULL, // flow block
730   NULL, // C source
731   3,    // num ops
732   0,1,  // dest, bit instruction
733   1,1,  // branch, skip
734   0,    // literal operand
735   1,    // RAM access bit
736   0,    // fast call/return mode select bit
737   0,    // second memory operand
738   0,    // second literal operand
739   POC_BTFSS,
740   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
741   PCC_EXAMINE_PCOP, // outCond
742   PCI_MAGIC
743 };
744
745 pCodeInstruction pic16_pciBTFSS = {
746   {PC_OPCODE, NULL, NULL, 0, NULL,
747    //   AnalyzeSKIP,
748    genericDestruct,
749    genericPrint},
750   POC_BTFSS,
751   "BTFSS",
752   2,
753   NULL, // from branch
754   NULL, // to branch
755   NULL, // label
756   NULL, // operand
757   NULL, // flow block
758   NULL, // C source
759   3,    // num ops
760   0,1,  // dest, bit instruction
761   1,1,  // branch, skip
762   0,    // literal operand
763   1,    // RAM access bit
764   0,    // fast call/return mode select bit
765   0,    // second memory operand
766   0,    // second literal operand
767   POC_BTFSC,
768   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
769   PCC_EXAMINE_PCOP, // outCond
770   PCI_MAGIC
771 };
772
773 pCodeInstruction pic16_pciBTG = { // mdubuc - New
774   {PC_OPCODE, NULL, NULL, 0, NULL,
775    //   genericAnalyze,
776    genericDestruct,
777    genericPrint},
778   POC_BTG,
779   "BTG",
780   2,
781   NULL, // from branch
782   NULL, // to branch
783   NULL, // label
784   NULL, // operand
785   NULL, // flow block
786   NULL, // C source
787   3,    // num ops
788   0,1,  // dest, bit instruction
789   0,0,  // branch, skip
790   0,    // literal operand
791   1,    // RAM access bit
792   0,    // fast call/return mode select bit
793   0,    // second memory operand
794   0,    // second literal operand
795   POC_NOP,
796   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
797   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
798   PCI_MAGIC
799 };
800
801 pCodeInstruction pic16_pciBZ = { // mdubuc - New
802   {PC_OPCODE, NULL, NULL, 0, NULL,
803    //   genericAnalyze,
804    genericDestruct,
805    genericPrint},
806   POC_BZ,
807   "BZ",
808   2,
809   NULL, // from branch
810   NULL, // to branch
811   NULL, // label
812   NULL, // operand
813   NULL, // flow block
814   NULL, // C source
815   1,    // num ops
816   0,0,  // dest, bit instruction
817   1,0,  // branch, skip
818   0,    // literal operand
819   0,    // RAM access bit
820   0,    // fast call/return mode select bit
821   0,    // second memory operand
822   0,    // second literal operand
823   POC_NOP,
824   (PCC_REL_ADDR | PCC_Z),   // inCond
825   PCC_NONE, // outCond
826   PCI_MAGIC
827 };
828
829 pCodeInstruction pic16_pciCALL = {
830   {PC_OPCODE, NULL, NULL, 0, NULL,
831    //   genericAnalyze,
832    genericDestruct,
833    genericPrint},
834   POC_CALL,
835   "CALL",
836   4,
837   NULL, // from branch
838   NULL, // to branch
839   NULL, // label
840   NULL, // operand
841   NULL, // flow block
842   NULL, // C source
843   2,    // num ops
844   0,0,  // dest, bit instruction
845   1,0,  // branch, skip
846   0,    // literal operand
847   0,    // RAM access bit
848   1,    // fast call/return mode select bit
849   0,    // second memory operand
850   0,    // second literal operand
851   POC_NOP,
852   PCC_NONE, // inCond
853   PCC_NONE, // outCond
854   PCI_MAGIC
855 };
856
857 pCodeInstruction pic16_pciCOMF = {
858   {PC_OPCODE, NULL, NULL, 0, NULL,
859    //   genericAnalyze,
860    genericDestruct,
861    genericPrint},
862   POC_COMF,
863   "COMF",
864   2,
865   NULL, // from branch
866   NULL, // to branch
867   NULL, // label
868   NULL, // operand
869   NULL, // flow block
870   NULL, // C source
871   3,    // num ops
872   1,0,  // dest, bit instruction
873   0,0,  // branch, skip
874   0,    // literal operand
875   1,    // RAM access bit
876   0,    // fast call/return mode select bit
877   0,    // second memory operand
878   0,    // second literal operand
879   POC_NOP,
880   PCC_REGISTER,  // inCond
881   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
882   PCI_MAGIC
883 };
884
885 pCodeInstruction pic16_pciCOMFW = {
886   {PC_OPCODE, NULL, NULL, 0, NULL,
887    //   genericAnalyze,
888    genericDestruct,
889    genericPrint},
890   POC_COMFW,
891   "COMF",
892   2,
893   NULL, // from branch
894   NULL, // to branch
895   NULL, // label
896   NULL, // operand
897   NULL, // flow block
898   NULL, // C source
899   3,    // num ops
900   0,0,  // dest, bit instruction
901   0,0,  // branch, skip
902   0,    // literal operand
903   1,    // RAM access bit
904   0,    // fast call/return mode select bit
905   0,    // second memory operand
906   0,    // second literal operand
907   POC_NOP,
908   PCC_REGISTER,  // inCond
909   (PCC_W | PCC_Z | PCC_N) , // outCond
910   PCI_MAGIC
911 };
912
913 pCodeInstruction pic16_pciCLRF = {
914   {PC_OPCODE, NULL, NULL, 0, NULL,
915    //   genericAnalyze,
916    genericDestruct,
917    genericPrint},
918   POC_CLRF,
919   "CLRF",
920   2,
921   NULL, // from branch
922   NULL, // to branch
923   NULL, // label
924   NULL, // operand
925   NULL, // flow block
926   NULL, // C source
927   2,    // num ops
928   0,0,  // dest, bit instruction
929   0,0,  // branch, skip
930   0,    // literal operand
931   1,    // RAM access bit
932   0,    // fast call/return mode select bit
933   0,    // second memory operand
934   0,    // second literal operand
935   POC_NOP,
936   PCC_NONE, // inCond
937   (PCC_REGISTER | PCC_Z), // outCond
938   PCI_MAGIC
939 };
940
941 pCodeInstruction pic16_pciCLRWDT = {
942   {PC_OPCODE, NULL, NULL, 0, NULL,
943    //   genericAnalyze,
944    genericDestruct,
945    genericPrint},
946   POC_CLRWDT,
947   "CLRWDT",
948   2,
949   NULL, // from branch
950   NULL, // to branch
951   NULL, // label
952   NULL, // operand
953   NULL, // flow block
954   NULL, // C source
955   0,    // num ops
956   0,0,  // dest, bit instruction
957   0,0,  // branch, skip
958   0,    // literal operand
959   0,    // RAM access bit
960   0,    // fast call/return mode select bit
961   0,    // second memory operand
962   0,    // second literal operand
963   POC_NOP,
964   PCC_NONE, // inCond
965   PCC_NONE , // outCond
966   PCI_MAGIC
967 };
968
969 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
970   {PC_OPCODE, NULL, NULL, 0, NULL,
971    //   genericAnalyze,
972    genericDestruct,
973    genericPrint},
974   POC_CPFSEQ,
975   "CPFSEQ",
976   2,
977   NULL, // from branch
978   NULL, // to branch
979   NULL, // label
980   NULL, // operand
981   NULL, // flow block
982   NULL, // C source
983   2,    // num ops
984   0,0,  // dest, bit instruction
985   1,1,  // branch, skip
986   0,    // literal operand
987   1,    // RAM access bit
988   0,    // fast call/return mode select bit
989   0,    // second memory operand
990   0,    // second literal operand
991   POC_NOP,
992   (PCC_W | PCC_REGISTER), // inCond
993   PCC_NONE , // outCond
994   PCI_MAGIC
995 };
996
997 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
998   {PC_OPCODE, NULL, NULL, 0, NULL,
999    //   genericAnalyze,
1000    genericDestruct,
1001    genericPrint},
1002   POC_CPFSGT,
1003   "CPFSGT",
1004   2,
1005   NULL, // from branch
1006   NULL, // to branch
1007   NULL, // label
1008   NULL, // operand
1009   NULL, // flow block
1010   NULL, // C source
1011   2,    // num ops
1012   0,0,  // dest, bit instruction
1013   1,1,  // branch, skip
1014   0,    // literal operand
1015   1,    // RAM access bit
1016   0,    // fast call/return mode select bit
1017   0,    // second memory operand
1018   0,    // second literal operand
1019   POC_NOP,
1020   (PCC_W | PCC_REGISTER), // inCond
1021   PCC_NONE , // outCond
1022   PCI_MAGIC
1023 };
1024
1025 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1026   {PC_OPCODE, NULL, NULL, 0, NULL,
1027    //   genericAnalyze,
1028    genericDestruct,
1029    genericPrint},
1030   POC_CPFSLT,
1031   "CPFSLT",
1032   2,
1033   NULL, // from branch
1034   NULL, // to branch
1035   NULL, // label
1036   NULL, // operand
1037   NULL, // flow block
1038   NULL, // C source
1039   2,    // num ops
1040   1,0,  // dest, bit instruction
1041   1,1,  // branch, skip
1042   0,    // literal operand
1043   1,    // RAM access bit
1044   0,    // fast call/return mode select bit
1045   0,    // second memory operand
1046   0,    // second literal operand
1047   POC_NOP,
1048   (PCC_W | PCC_REGISTER), // inCond
1049   PCC_NONE , // outCond
1050   PCI_MAGIC
1051 };
1052
1053 pCodeInstruction pic16_pciDAW = {
1054   {PC_OPCODE, NULL, NULL, 0, NULL,
1055    //   genericAnalyze,
1056    genericDestruct,
1057    genericPrint},
1058   POC_DAW,
1059   "DAW",
1060   2,
1061   NULL, // from branch
1062   NULL, // to branch
1063   NULL, // label
1064   NULL, // operand
1065   NULL, // flow block
1066   NULL, // C source
1067   0,    // num ops
1068   0,0,  // dest, bit instruction
1069   0,0,  // branch, skip
1070   0,    // literal operand
1071   0,    // RAM access bit
1072   0,    // fast call/return mode select bit
1073   0,    // second memory operand
1074   0,    // second literal operand
1075   POC_NOP,
1076   PCC_W, // inCond
1077   (PCC_W | PCC_C), // outCond
1078   PCI_MAGIC
1079 };
1080
1081 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1082   {PC_OPCODE, NULL, NULL, 0, NULL,
1083    //   genericAnalyze,
1084    genericDestruct,
1085    genericPrint},
1086   POC_DCFSNZ,
1087   "DCFSNZ",
1088   2,
1089   NULL, // from branch
1090   NULL, // to branch
1091   NULL, // label
1092   NULL, // operand
1093   NULL, // flow block
1094   NULL, // C source
1095   3,    // num ops
1096   1,0,  // dest, bit instruction
1097   1,1,  // branch, skip
1098   0,    // literal operand
1099   1,    // RAM access bit
1100   0,    // fast call/return mode select bit
1101   0,    // second memory operand
1102   0,    // second literal operand
1103   POC_NOP,
1104   PCC_REGISTER, // inCond
1105   PCC_REGISTER , // outCond
1106   PCI_MAGIC
1107 };
1108
1109 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1110   {PC_OPCODE, NULL, NULL, 0, NULL,
1111    //   genericAnalyze,
1112    genericDestruct,
1113    genericPrint},
1114   POC_DCFSNZW,
1115   "DCFSNZ",
1116   2,
1117   NULL, // from branch
1118   NULL, // to branch
1119   NULL, // label
1120   NULL, // operand
1121   NULL, // flow block
1122   NULL, // C source
1123   3,    // num ops
1124   0,0,  // dest, bit instruction
1125   1,1,  // branch, skip
1126   0,    // literal operand
1127   1,    // RAM access bit
1128   0,    // fast call/return mode select bit
1129   0,    // second memory operand
1130   0,    // second literal operand
1131   POC_NOP,
1132   PCC_REGISTER, // inCond
1133   PCC_W , // outCond
1134   PCI_MAGIC
1135 };
1136
1137 pCodeInstruction pic16_pciDECF = {
1138   {PC_OPCODE, NULL, NULL, 0, NULL,
1139    //   genericAnalyze,
1140    genericDestruct,
1141    genericPrint},
1142   POC_DECF,
1143   "DECF",
1144   2,
1145   NULL, // from branch
1146   NULL, // to branch
1147   NULL, // label
1148   NULL, // operand
1149   NULL, // flow block
1150   NULL, // C source
1151   3,    // num ops
1152   1,0,  // dest, bit instruction
1153   0,0,  // branch, skip
1154   0,    // literal operand
1155   1,    // RAM access bit
1156   0,    // fast call/return mode select bit
1157   0,    // second memory operand
1158   0,    // second literal operand
1159   POC_NOP,
1160   PCC_REGISTER,   // inCond
1161   (PCC_REGISTER | PCC_STATUS)  , // outCond
1162   PCI_MAGIC
1163 };
1164
1165 pCodeInstruction pic16_pciDECFW = {
1166   {PC_OPCODE, NULL, NULL, 0, NULL,
1167    //   genericAnalyze,
1168    genericDestruct,
1169    genericPrint},
1170   POC_DECFW,
1171   "DECF",
1172   2,
1173   NULL, // from branch
1174   NULL, // to branch
1175   NULL, // label
1176   NULL, // operand
1177   NULL, // flow block
1178   NULL, // C source
1179   3,    // num ops
1180   0,0,  // dest, bit instruction
1181   0,0,  // branch, skip
1182   0,    // literal operand
1183   1,    // RAM access bit
1184   0,    // fast call/return mode select bit
1185   0,    // second memory operand
1186   0,    // second literal operand
1187   POC_NOP,
1188   PCC_REGISTER,   // inCond
1189   (PCC_W | PCC_STATUS)  , // outCond
1190   PCI_MAGIC
1191 };
1192
1193 pCodeInstruction pic16_pciDECFSZ = {
1194   {PC_OPCODE, NULL, NULL, 0, NULL,
1195    //   AnalyzeSKIP,
1196    genericDestruct,
1197    genericPrint},
1198   POC_DECFSZ,
1199   "DECFSZ",
1200   2,
1201   NULL, // from branch
1202   NULL, // to branch
1203   NULL, // label
1204   NULL, // operand
1205   NULL, // flow block
1206   NULL, // C source
1207   3,    // num ops
1208   1,0,  // dest, bit instruction
1209   1,1,  // branch, skip
1210   0,    // literal operand
1211   1,    // RAM access bit
1212   0,    // fast call/return mode select bit
1213   0,    // second memory operand
1214   0,    // second literal operand
1215   POC_NOP,
1216   PCC_REGISTER,   // inCond
1217   PCC_REGISTER   , // outCond
1218   PCI_MAGIC
1219 };
1220
1221 pCodeInstruction pic16_pciDECFSZW = {
1222   {PC_OPCODE, NULL, NULL, 0, NULL,
1223    //   AnalyzeSKIP,
1224    genericDestruct,
1225    genericPrint},
1226   POC_DECFSZW,
1227   "DECFSZ",
1228   2,
1229   NULL, // from branch
1230   NULL, // to branch
1231   NULL, // label
1232   NULL, // operand
1233   NULL, // flow block
1234   NULL, // C source
1235   3,    // num ops
1236   0,0,  // dest, bit instruction
1237   1,1,  // branch, skip
1238   0,    // literal operand
1239   1,    // RAM access bit
1240   0,    // fast call/return mode select bit
1241   0,    // second memory operand
1242   0,    // second literal operand
1243   POC_NOP,
1244   PCC_REGISTER,   // inCond
1245   PCC_W          , // outCond
1246   PCI_MAGIC
1247 };
1248
1249 pCodeInstruction pic16_pciGOTO = {
1250   {PC_OPCODE, NULL, NULL, 0, NULL,
1251    //   AnalyzeGOTO,
1252    genericDestruct,
1253    genericPrint},
1254   POC_GOTO,
1255   "GOTO",
1256   4,
1257   NULL, // from branch
1258   NULL, // to branch
1259   NULL, // label
1260   NULL, // operand
1261   NULL, // flow block
1262   NULL, // C source
1263   1,    // num ops
1264   0,0,  // dest, bit instruction
1265   1,0,  // branch, skip
1266   0,    // literal operand
1267   0,    // RAM access bit
1268   0,    // fast call/return mode select bit
1269   0,    // second memory operand
1270   0,    // second literal operand
1271   POC_NOP,
1272   PCC_REL_ADDR,   // inCond
1273   PCC_NONE   , // outCond
1274   PCI_MAGIC
1275 };
1276
1277 pCodeInstruction pic16_pciINCF = {
1278   {PC_OPCODE, NULL, NULL, 0, NULL,
1279    //   genericAnalyze,
1280    genericDestruct,
1281    genericPrint},
1282   POC_INCF,
1283   "INCF",
1284   2,
1285   NULL, // from branch
1286   NULL, // to branch
1287   NULL, // label
1288   NULL, // operand
1289   NULL, // flow block
1290   NULL, // C source
1291   3,    // num ops
1292   1,0,  // dest, bit instruction
1293   0,0,  // branch, skip
1294   0,    // literal operand
1295   1,    // RAM access bit
1296   0,    // fast call/return mode select bit
1297   0,    // second memory operand
1298   0,    // second literal operand
1299   POC_NOP,
1300   PCC_REGISTER,   // inCond
1301   (PCC_REGISTER | PCC_STATUS), // outCond
1302   PCI_MAGIC
1303 };
1304
1305 pCodeInstruction pic16_pciINCFW = {
1306   {PC_OPCODE, NULL, NULL, 0, NULL,
1307    //   genericAnalyze,
1308    genericDestruct,
1309    genericPrint},
1310   POC_INCFW,
1311   "INCF",
1312   2,
1313   NULL, // from branch
1314   NULL, // to branch
1315   NULL, // label
1316   NULL, // operand
1317   NULL, // flow block
1318   NULL, // C source
1319   3,    // num ops
1320   0,0,  // dest, bit instruction
1321   0,0,  // branch, skip
1322   0,    // literal operand
1323   1,    // RAM access bit
1324   0,    // fast call/return mode select bit
1325   0,    // second memory operand
1326   0,    // second literal operand
1327   POC_NOP,
1328   PCC_REGISTER,   // inCond
1329   (PCC_W | PCC_STATUS)  , // outCond
1330   PCI_MAGIC
1331 };
1332
1333 pCodeInstruction pic16_pciINCFSZ = {
1334   {PC_OPCODE, NULL, NULL, 0, NULL,
1335    //   AnalyzeSKIP,
1336    genericDestruct,
1337    genericPrint},
1338   POC_INCFSZ,
1339   "INCFSZ",
1340   2,
1341   NULL, // from branch
1342   NULL, // to branch
1343   NULL, // label
1344   NULL, // operand
1345   NULL, // flow block
1346   NULL, // C source
1347   3,    // num ops
1348   1,0,  // dest, bit instruction
1349   1,1,  // branch, skip
1350   0,    // literal operand
1351   1,    // RAM access bit
1352   0,    // fast call/return mode select bit
1353   0,    // second memory operand
1354   0,    // second literal operand
1355   POC_INFSNZ,
1356   PCC_REGISTER,   // inCond
1357   PCC_REGISTER   , // outCond
1358   PCI_MAGIC
1359 };
1360
1361 pCodeInstruction pic16_pciINCFSZW = {
1362   {PC_OPCODE, NULL, NULL, 0, NULL,
1363    //   AnalyzeSKIP,
1364    genericDestruct,
1365    genericPrint},
1366   POC_INCFSZW,
1367   "INCFSZ",
1368   2,
1369   NULL, // from branch
1370   NULL, // to branch
1371   NULL, // label
1372   NULL, // operand
1373   NULL, // flow block
1374   NULL, // C source
1375   3,    // num ops
1376   0,0,  // dest, bit instruction
1377   1,1,  // branch, skip
1378   0,    // literal operand
1379   1,    // RAM access bit
1380   0,    // fast call/return mode select bit
1381   0,    // second memory operand
1382   0,    // second literal operand
1383   POC_INFSNZW,
1384   PCC_REGISTER,   // inCond
1385   PCC_W          , // outCond
1386   PCI_MAGIC
1387 };
1388
1389 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1390   {PC_OPCODE, NULL, NULL, 0, NULL,
1391    //   AnalyzeSKIP,
1392    genericDestruct,
1393    genericPrint},
1394   POC_INFSNZ,
1395   "INFSNZ",
1396   2,
1397   NULL, // from branch
1398   NULL, // to branch
1399   NULL, // label
1400   NULL, // operand
1401   NULL, // flow block
1402   NULL, // C source
1403   3,    // num ops
1404   1,0,  // dest, bit instruction
1405   1,1,  // branch, skip
1406   0,    // literal operand
1407   1,    // RAM access bit
1408   0,    // fast call/return mode select bit
1409   0,    // second memory operand
1410   0,    // second literal operand
1411   POC_INCFSZ,
1412   PCC_REGISTER,   // inCond
1413   PCC_REGISTER   , // outCond
1414   PCI_MAGIC
1415 };
1416
1417 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1418   {PC_OPCODE, NULL, NULL, 0, NULL,
1419    //   AnalyzeSKIP,
1420    genericDestruct,
1421    genericPrint},
1422   POC_INFSNZW,
1423   "INFSNZ",
1424   2,
1425   NULL, // from branch
1426   NULL, // to branch
1427   NULL, // label
1428   NULL, // operand
1429   NULL, // flow block
1430   NULL, // C source
1431   3,    // num ops
1432   0,0,  // dest, bit instruction
1433   1,1,  // branch, skip
1434   0,    // literal operand
1435   1,    // RAM access bit
1436   0,    // fast call/return mode select bit
1437   0,    // second memory operand
1438   0,    // second literal operand
1439   POC_INCFSZW,
1440   PCC_REGISTER,   // inCond
1441   PCC_W          , // outCond
1442   PCI_MAGIC
1443 };
1444
1445 pCodeInstruction pic16_pciIORWF = {
1446   {PC_OPCODE, NULL, NULL, 0, NULL,
1447    //   genericAnalyze,
1448    genericDestruct,
1449    genericPrint},
1450   POC_IORWF,
1451   "IORWF",
1452   2,
1453   NULL, // from branch
1454   NULL, // to branch
1455   NULL, // label
1456   NULL, // operand
1457   NULL, // flow block
1458   NULL, // C source
1459   3,    // num ops
1460   1,0,  // dest, bit instruction
1461   0,0,  // branch, skip
1462   0,    // literal operand
1463   1,    // RAM access bit
1464   0,    // fast call/return mode select bit
1465   0,    // second memory operand
1466   0,    // second literal operand
1467   POC_NOP,
1468   (PCC_W | PCC_REGISTER),   // inCond
1469   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1470   PCI_MAGIC
1471 };
1472
1473 pCodeInstruction pic16_pciIORFW = {
1474   {PC_OPCODE, NULL, NULL, 0, NULL,
1475    //   genericAnalyze,
1476    genericDestruct,
1477    genericPrint},
1478   POC_IORFW,
1479   "IORWF",
1480   2,
1481   NULL, // from branch
1482   NULL, // to branch
1483   NULL, // label
1484   NULL, // operand
1485   NULL, // flow block
1486   NULL, // C source
1487   3,    // num ops
1488   0,0,  // dest, bit instruction
1489   0,0,  // branch, skip
1490   0,    // literal operand
1491   1,    // RAM access bit
1492   0,    // fast call/return mode select bit
1493   0,    // second memory operand
1494   0,    // second literal operand
1495   POC_NOP,
1496   (PCC_W | PCC_REGISTER),   // inCond
1497   (PCC_W | PCC_Z | PCC_N), // outCond
1498   PCI_MAGIC
1499 };
1500
1501 pCodeInstruction pic16_pciIORLW = {
1502   {PC_OPCODE, NULL, NULL, 0, NULL,
1503    //   genericAnalyze,
1504    genericDestruct,
1505    genericPrint},
1506   POC_IORLW,
1507   "IORLW",
1508   2,
1509   NULL, // from branch
1510   NULL, // to branch
1511   NULL, // label
1512   NULL, // operand
1513   NULL, // flow block
1514   NULL, // C source
1515   1,    // num ops
1516   0,0,  // dest, bit instruction
1517   0,0,  // branch, skip
1518   1,    // literal operand
1519   0,    // RAM access bit
1520   0,    // fast call/return mode select bit
1521   0,    // second memory operand
1522   0,    // second literal operand
1523   POC_NOP,
1524   (PCC_W | PCC_LITERAL),   // inCond
1525   (PCC_W | PCC_Z | PCC_N), // outCond
1526   PCI_MAGIC
1527 };
1528
1529 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1530   {PC_OPCODE, NULL, NULL, 0, NULL,
1531    //   genericAnalyze,
1532    genericDestruct,
1533    genericPrint},
1534   POC_LFSR,
1535   "LFSR",
1536   4,
1537   NULL, // from branch
1538   NULL, // to branch
1539   NULL, // label
1540   NULL, // operand
1541   NULL, // flow block
1542   NULL, // C source
1543   2,    // num ops
1544   0,0,  // dest, bit instruction
1545   0,0,  // branch, skip
1546   1,    // literal operand
1547   0,    // RAM access bit
1548   0,    // fast call/return mode select bit
1549   0,    // second memory operand
1550   1,    // second literal operand
1551   POC_NOP,
1552   PCC_LITERAL, // inCond
1553   PCC_NONE, // outCond
1554   PCI_MAGIC
1555 };
1556
1557 pCodeInstruction pic16_pciMOVF = {
1558   {PC_OPCODE, NULL, NULL, 0, NULL,
1559    //   genericAnalyze,
1560    genericDestruct,
1561    genericPrint},
1562   POC_MOVF,
1563   "MOVF",
1564   2,
1565   NULL, // from branch
1566   NULL, // to branch
1567   NULL, // label
1568   NULL, // operand
1569   NULL, // flow block
1570   NULL, // C source
1571   3,    // num ops
1572   1,0,  // dest, bit instruction
1573   0,0,  // branch, skip
1574   0,    // literal operand
1575   1,    // RAM access bit
1576   0,    // fast call/return mode select bit
1577   0,    // second memory operand
1578   0,    // second literal operand
1579   POC_NOP,
1580   PCC_REGISTER,   // inCond
1581   (PCC_Z | PCC_N), // outCond
1582   PCI_MAGIC
1583 };
1584
1585 pCodeInstruction pic16_pciMOVFW = {
1586   {PC_OPCODE, NULL, NULL, 0, NULL,
1587    //   genericAnalyze,
1588    genericDestruct,
1589    genericPrint},
1590   POC_MOVFW,
1591   "MOVF",
1592   2,
1593   NULL, // from branch
1594   NULL, // to branch
1595   NULL, // label
1596   NULL, // operand
1597   NULL, // flow block
1598   NULL, // C source
1599   3,    // num ops
1600   0,0,  // dest, bit instruction
1601   0,0,  // branch, skip
1602   0,    // literal operand
1603   1,    // RAM access bit
1604   0,    // fast call/return mode select bit
1605   0,    // second memory operand
1606   0,    // second literal operand
1607   POC_NOP,
1608   PCC_REGISTER,   // inCond
1609   (PCC_W | PCC_N | PCC_Z), // outCond
1610   PCI_MAGIC
1611 };
1612
1613 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1614   {PC_OPCODE, NULL, NULL, 0, NULL,
1615    //   genericAnalyze,
1616    genericDestruct,
1617    genericPrint},
1618   POC_MOVFF,
1619   "MOVFF",
1620   4,
1621   NULL, // from branch
1622   NULL, // to branch
1623   NULL, // label
1624   NULL, // operand
1625   NULL, // flow block
1626   NULL, // C source
1627   2,    // num ops
1628   0,0,  // dest, bit instruction
1629   0,0,  // branch, skip
1630   0,    // literal operand
1631   0,    // RAM access bit
1632   0,    // fast call/return mode select bit
1633   1,    // second memory operand
1634   0,    // second literal operand
1635   POC_NOP,
1636   PCC_REGISTER,   // inCond
1637   PCC_REGISTER2, // outCond
1638   PCI_MAGIC
1639 };
1640
1641 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1642   {PC_OPCODE, NULL, NULL, 0, NULL,
1643    genericDestruct,
1644    genericPrint},
1645   POC_MOVLB,
1646   "MOVLB",
1647   2,
1648   NULL, // from branch
1649   NULL, // to branch
1650   NULL, // label
1651   NULL, // operand
1652   NULL, // flow block
1653   NULL, // C source
1654   1,    // num ops
1655   0,0,  // dest, bit instruction
1656   0,0,  // branch, skip
1657   1,    // literal operand
1658   0,    // RAM access bit
1659   0,    // fast call/return mode select bit
1660   0,    // second memory operand
1661   0,    // second literal operand
1662   POC_NOP,
1663   (PCC_NONE | PCC_LITERAL),   // inCond
1664   PCC_REGISTER, // outCond - BSR
1665   PCI_MAGIC
1666 };
1667
1668 pCodeInstruction pic16_pciMOVLW = {
1669   {PC_OPCODE, NULL, NULL, 0, NULL,
1670    genericDestruct,
1671    genericPrint},
1672   POC_MOVLW,
1673   "MOVLW",
1674   2,
1675   NULL, // from branch
1676   NULL, // to branch
1677   NULL, // label
1678   NULL, // operand
1679   NULL, // flow block
1680   NULL, // C source
1681   1,    // num ops
1682   0,0,  // dest, bit instruction
1683   0,0,  // branch, skip
1684   1,    // literal operand
1685   0,    // RAM access bit
1686   0,    // fast call/return mode select bit
1687   0,    // second memory operand
1688   0,    // second literal operand
1689   POC_NOP,
1690   (PCC_NONE | PCC_LITERAL),   // inCond
1691   PCC_W, // outCond
1692   PCI_MAGIC
1693 };
1694
1695 pCodeInstruction pic16_pciMOVWF = {
1696   {PC_OPCODE, NULL, NULL, 0, NULL,
1697    //   genericAnalyze,
1698    genericDestruct,
1699    genericPrint},
1700   POC_MOVWF,
1701   "MOVWF",
1702   2,
1703   NULL, // from branch
1704   NULL, // to branch
1705   NULL, // label
1706   NULL, // operand
1707   NULL, // flow block
1708   NULL, // C source
1709   2,    // num ops
1710   0,0,  // dest, bit instruction
1711   0,0,  // branch, skip
1712   0,    // literal operand
1713   1,    // RAM access bit
1714   0,    // fast call/return mode select bit
1715   0,    // second memory operand
1716   0,    // second literal operand
1717   POC_NOP,
1718   PCC_W,   // inCond
1719   PCC_REGISTER, // outCond
1720   PCI_MAGIC
1721 };
1722
1723 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1724   {PC_OPCODE, NULL, NULL, 0, NULL,
1725    genericDestruct,
1726    genericPrint},
1727   POC_MULLW,
1728   "MULLW",
1729   2,
1730   NULL, // from branch
1731   NULL, // to branch
1732   NULL, // label
1733   NULL, // operand
1734   NULL, // flow block
1735   NULL, // C source
1736   1,    // num ops
1737   0,0,  // dest, bit instruction
1738   0,0,  // branch, skip
1739   1,    // literal operand
1740   0,    // RAM access bit
1741   0,    // fast call/return mode select bit
1742   0,    // second memory operand
1743   0,    // second literal operand
1744   POC_NOP,
1745   (PCC_W | PCC_LITERAL),   // inCond
1746   PCC_NONE, // outCond - PROD
1747   PCI_MAGIC
1748 };
1749
1750 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1751   {PC_OPCODE, NULL, NULL, 0, NULL,
1752    genericDestruct,
1753    genericPrint},
1754   POC_MULWF,
1755   "MULWF",
1756   2,
1757   NULL, // from branch
1758   NULL, // to branch
1759   NULL, // label
1760   NULL, // operand
1761   NULL, // flow block
1762   NULL, // C source
1763   2,    // num ops
1764   0,0,  // dest, bit instruction
1765   0,0,  // branch, skip
1766   0,    // literal operand
1767   1,    // RAM access bit
1768   0,    // fast call/return mode select bit
1769   0,    // second memory operand
1770   0,    // second literal operand
1771   POC_NOP,
1772   (PCC_W | PCC_REGISTER),   // inCond
1773   PCC_REGISTER, // outCond - PROD
1774   PCI_MAGIC
1775 };
1776
1777 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1778   {PC_OPCODE, NULL, NULL, 0, NULL,
1779    genericDestruct,
1780    genericPrint},
1781   POC_NEGF,
1782   "NEGF",
1783   2,
1784   NULL, // from branch
1785   NULL, // to branch
1786   NULL, // label
1787   NULL, // operand
1788   NULL, // flow block
1789   NULL, // C source
1790   2,    // num ops
1791   0,0,  // dest, bit instruction
1792   0,0,  // branch, skip
1793   0,    // literal operand
1794   1,    // RAM access bit
1795   0,    // fast call/return mode select bit
1796   0,    // second memory operand
1797   0,    // second literal operand
1798   POC_NOP,
1799   PCC_REGISTER, // inCond
1800   (PCC_REGISTER | PCC_STATUS), // outCond
1801   PCI_MAGIC
1802 };
1803
1804 pCodeInstruction pic16_pciNOP = {
1805   {PC_OPCODE, NULL, NULL, 0, NULL,
1806    genericDestruct,
1807    genericPrint},
1808   POC_NOP,
1809   "NOP",
1810   2,
1811   NULL, // from branch
1812   NULL, // to branch
1813   NULL, // label
1814   NULL, // operand
1815   NULL, // flow block
1816   NULL, // C source
1817   0,    // num ops
1818   0,0,  // dest, bit instruction
1819   0,0,  // branch, skip
1820   0,    // literal operand
1821   0,    // RAM access bit
1822   0,    // fast call/return mode select bit
1823   0,    // second memory operand
1824   0,    // second literal operand
1825   POC_NOP,
1826   PCC_NONE,   // inCond
1827   PCC_NONE, // outCond
1828   PCI_MAGIC
1829 };
1830
1831 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1832   {PC_OPCODE, NULL, NULL, 0, NULL,
1833    genericDestruct,
1834    genericPrint},
1835   POC_POP,
1836   "POP",
1837   2,
1838   NULL, // from branch
1839   NULL, // to branch
1840   NULL, // label
1841   NULL, // operand
1842   NULL, // flow block
1843   NULL, // C source
1844   0,    // num ops
1845   0,0,  // dest, bit instruction
1846   0,0,  // branch, skip
1847   0,    // literal operand
1848   0,    // RAM access bit
1849   0,    // fast call/return mode select bit
1850   0,    // second memory operand
1851   0,    // second literal operand
1852   POC_NOP,
1853   PCC_NONE,  // inCond
1854   PCC_NONE  , // outCond
1855   PCI_MAGIC
1856 };
1857
1858 pCodeInstruction pic16_pciPUSH = {
1859   {PC_OPCODE, NULL, NULL, 0, NULL,
1860    genericDestruct,
1861    genericPrint},
1862   POC_PUSH,
1863   "PUSH",
1864   2,
1865   NULL, // from branch
1866   NULL, // to branch
1867   NULL, // label
1868   NULL, // operand
1869   NULL, // flow block
1870   NULL, // C source
1871   0,    // num ops
1872   0,0,  // dest, bit instruction
1873   0,0,  // branch, skip
1874   0,    // literal operand
1875   0,    // RAM access bit
1876   0,    // fast call/return mode select bit
1877   0,    // second memory operand
1878   0,    // second literal operand
1879   POC_NOP,
1880   PCC_NONE,  // inCond
1881   PCC_NONE  , // outCond
1882   PCI_MAGIC
1883 };
1884
1885 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1886   {PC_OPCODE, NULL, NULL, 0, NULL,
1887    genericDestruct,
1888    genericPrint},
1889   POC_RCALL,
1890   "RCALL",
1891   2,
1892   NULL, // from branch
1893   NULL, // to branch
1894   NULL, // label
1895   NULL, // operand
1896   NULL, // flow block
1897   NULL, // C source
1898   1,    // num ops
1899   0,0,  // dest, bit instruction
1900   1,0,  // branch, skip
1901   0,    // literal operand
1902   0,    // RAM access bit
1903   0,    // fast call/return mode select bit
1904   0,    // second memory operand
1905   0,    // second literal operand
1906   POC_NOP,
1907   PCC_REL_ADDR,  // inCond
1908   PCC_NONE  , // outCond
1909   PCI_MAGIC
1910 };
1911
1912 pCodeInstruction pic16_pciRETFIE = {
1913   {PC_OPCODE, NULL, NULL, 0, NULL,
1914    //   AnalyzeRETURN,
1915    genericDestruct,
1916    genericPrint},
1917   POC_RETFIE,
1918   "RETFIE",
1919   2,
1920   NULL, // from branch
1921   NULL, // to branch
1922   NULL, // label
1923   NULL, // operand
1924   NULL, // flow block
1925   NULL, // C source
1926   1,    // num ops
1927   0,0,  // dest, bit instruction
1928   1,0,  // branch, skip
1929   0,    // literal operand
1930   0,    // RAM access bit
1931   1,    // fast call/return mode select bit
1932   0,    // second memory operand
1933   0,    // second literal operand
1934   POC_NOP,
1935   PCC_NONE,   // inCond
1936   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1937   PCI_MAGIC
1938 };
1939
1940 pCodeInstruction pic16_pciRETLW = {
1941   {PC_OPCODE, NULL, NULL, 0, NULL,
1942    //   AnalyzeRETURN,
1943    genericDestruct,
1944    genericPrint},
1945   POC_RETLW,
1946   "RETLW",
1947   2,
1948   NULL, // from branch
1949   NULL, // to branch
1950   NULL, // label
1951   NULL, // operand
1952   NULL, // flow block
1953   NULL, // C source
1954   1,    // num ops
1955   0,0,  // dest, bit instruction
1956   1,0,  // branch, skip
1957   1,    // literal operand
1958   0,    // RAM access bit
1959   0,    // fast call/return mode select bit
1960   0,    // second memory operand
1961   0,    // second literal operand
1962   POC_NOP,
1963   PCC_LITERAL,   // inCond
1964   PCC_W, // outCond
1965   PCI_MAGIC
1966 };
1967
1968 pCodeInstruction pic16_pciRETURN = {
1969   {PC_OPCODE, NULL, NULL, 0, NULL,
1970    //   AnalyzeRETURN,
1971    genericDestruct,
1972    genericPrint},
1973   POC_RETURN,
1974   "RETURN",
1975   2,
1976   NULL, // from branch
1977   NULL, // to branch
1978   NULL, // label
1979   NULL, // operand
1980   NULL, // flow block
1981   NULL, // C source
1982   1,    // num ops
1983   0,0,  // dest, bit instruction
1984   1,0,  // branch, skip
1985   0,    // literal operand
1986   0,    // RAM access bit
1987   1,    // fast call/return mode select bit
1988   0,    // second memory operand
1989   0,    // second literal operand
1990   POC_NOP,
1991   PCC_NONE,   // inCond
1992   PCC_NONE, // outCond
1993   PCI_MAGIC
1994 };
1995 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
1996   {PC_OPCODE, NULL, NULL, 0, NULL,
1997    //   genericAnalyze,
1998    genericDestruct,
1999    genericPrint},
2000   POC_RLCF,
2001   "RLCF",
2002   2,
2003   NULL, // from branch
2004   NULL, // to branch
2005   NULL, // label
2006   NULL, // operand
2007   NULL, // flow block
2008   NULL, // C source
2009   3,    // num ops
2010   1,0,  // dest, bit instruction
2011   0,0,  // branch, skip
2012   0,    // literal operand
2013   1,    // RAM access bit
2014   0,    // fast call/return mode select bit
2015   0,    // second memory operand
2016   0,    // second literal operand
2017   POC_NOP,
2018   (PCC_C | PCC_REGISTER),   // inCond
2019   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2020   PCI_MAGIC
2021 };
2022
2023 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2024   {PC_OPCODE, NULL, NULL, 0, NULL,
2025    //   genericAnalyze,
2026    genericDestruct,
2027    genericPrint},
2028   POC_RLCFW,
2029   "RLCF",
2030   2,
2031   NULL, // from branch
2032   NULL, // to branch
2033   NULL, // label
2034   NULL, // operand
2035   NULL, // flow block
2036   NULL, // C source
2037   3,    // num ops
2038   0,0,  // dest, bit instruction
2039   0,0,  // branch, skip
2040   0,    // literal operand
2041   1,    // RAM access bit
2042   0,    // fast call/return mode select bit
2043   0,    // second memory operand
2044   0,    // second literal operand
2045   POC_NOP,
2046   (PCC_C | PCC_REGISTER),   // inCond
2047   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2048   PCI_MAGIC
2049 };
2050
2051 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2052   {PC_OPCODE, NULL, NULL, 0, NULL,
2053    //   genericAnalyze,
2054    genericDestruct,
2055    genericPrint},
2056   POC_RLNCF,
2057   "RLNCF",
2058   2,
2059   NULL, // from branch
2060   NULL, // to branch
2061   NULL, // label
2062   NULL, // operand
2063   NULL, // flow block
2064   NULL, // C source
2065   3,    // num ops
2066   1,0,  // dest, bit instruction
2067   0,0,  // branch, skip
2068   0,    // literal operand
2069   1,    // RAM access bit
2070   0,    // fast call/return mode select bit
2071   0,    // second memory operand
2072   0,    // second literal operand
2073   POC_NOP,
2074   PCC_REGISTER,   // inCond
2075   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2076   PCI_MAGIC
2077 };
2078 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2079   {PC_OPCODE, NULL, NULL, 0, NULL,
2080    //   genericAnalyze,
2081    genericDestruct,
2082    genericPrint},
2083   POC_RLNCFW,
2084   "RLNCF",
2085   2,
2086   NULL, // from branch
2087   NULL, // to branch
2088   NULL, // label
2089   NULL, // operand
2090   NULL, // flow block
2091   NULL, // C source
2092   3,    // num ops
2093   0,0,  // dest, bit instruction
2094   0,0,  // branch, skip
2095   0,    // literal operand
2096   1,    // RAM access bit
2097   0,    // fast call/return mode select bit
2098   0,    // second memory operand
2099   0,    // second literal operand
2100   POC_NOP,
2101   PCC_REGISTER,   // inCond
2102   (PCC_W | PCC_Z | PCC_N), // outCond
2103   PCI_MAGIC
2104 };
2105 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2106   {PC_OPCODE, NULL, NULL, 0, NULL,
2107    //   genericAnalyze,
2108    genericDestruct,
2109    genericPrint},
2110   POC_RRCF,
2111   "RRCF",
2112   2,
2113   NULL, // from branch
2114   NULL, // to branch
2115   NULL, // label
2116   NULL, // operand
2117   NULL, // flow block
2118   NULL, // C source
2119   3,    // num ops
2120   1,0,  // dest, bit instruction
2121   0,0,  // branch, skip
2122   0,    // literal operand
2123   1,    // RAM access bit
2124   0,    // fast call/return mode select bit
2125   0,    // second memory operand
2126   0,    // second literal operand
2127   POC_NOP,
2128   (PCC_C | PCC_REGISTER),   // inCond
2129   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2130   PCI_MAGIC
2131 };
2132 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2133   {PC_OPCODE, NULL, NULL, 0, NULL,
2134    //   genericAnalyze,
2135    genericDestruct,
2136    genericPrint},
2137   POC_RRCFW,
2138   "RRCF",
2139   2,
2140   NULL, // from branch
2141   NULL, // to branch
2142   NULL, // label
2143   NULL, // operand
2144   NULL, // flow block
2145   NULL, // C source
2146   3,    // num ops
2147   0,0,  // dest, bit instruction
2148   0,0,  // branch, skip
2149   0,    // literal operand
2150   1,    // RAM access bit
2151   0,    // fast call/return mode select bit
2152   0,    // second memory operand
2153   0,    // second literal operand
2154   POC_NOP,
2155   (PCC_C | PCC_REGISTER),   // inCond
2156   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2157   PCI_MAGIC
2158 };
2159 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2160   {PC_OPCODE, NULL, NULL, 0, NULL,
2161    //   genericAnalyze,
2162    genericDestruct,
2163    genericPrint},
2164   POC_RRNCF,
2165   "RRNCF",
2166   2,
2167   NULL, // from branch
2168   NULL, // to branch
2169   NULL, // label
2170   NULL, // operand
2171   NULL, // flow block
2172   NULL, // C source
2173   3,    // num ops
2174   1,0,  // dest, bit instruction
2175   0,0,  // branch, skip
2176   0,    // literal operand
2177   1,    // RAM access bit
2178   0,    // fast call/return mode select bit
2179   0,    // second memory operand
2180   0,    // second literal operand
2181   POC_NOP,
2182   PCC_REGISTER,   // inCond
2183   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2184   PCI_MAGIC
2185 };
2186
2187 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2188   {PC_OPCODE, NULL, NULL, 0, NULL,
2189    //   genericAnalyze,
2190    genericDestruct,
2191    genericPrint},
2192   POC_RRNCFW,
2193   "RRNCF",
2194   2,
2195   NULL, // from branch
2196   NULL, // to branch
2197   NULL, // label
2198   NULL, // operand
2199   NULL, // flow block
2200   NULL, // C source
2201   3,    // num ops
2202   0,0,  // dest, bit instruction
2203   0,0,  // branch, skip
2204   0,    // literal operand
2205   1,    // RAM access bit
2206   0,    // fast call/return mode select bit
2207   0,    // second memory operand
2208   0,    // second literal operand
2209   POC_NOP,
2210   PCC_REGISTER,   // inCond
2211   (PCC_W | PCC_Z | PCC_N), // outCond
2212   PCI_MAGIC
2213 };
2214
2215 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2216   {PC_OPCODE, NULL, NULL, 0, NULL,
2217    //   genericAnalyze,
2218    genericDestruct,
2219    genericPrint},
2220   POC_SETF,
2221   "SETF",
2222   2,
2223   NULL, // from branch
2224   NULL, // to branch
2225   NULL, // label
2226   NULL, // operand
2227   NULL, // flow block
2228   NULL, // C source
2229   2,    // num ops
2230   0,0,  // dest, bit instruction
2231   0,0,  // branch, skip
2232   0,    // literal operand
2233   1,    // RAM access bit
2234   0,    // fast call/return mode select bit
2235   0,    // second memory operand
2236   0,    // second literal operand
2237   POC_NOP,
2238   PCC_NONE,  // inCond
2239   PCC_REGISTER  , // outCond
2240   PCI_MAGIC
2241 };
2242
2243 pCodeInstruction pic16_pciSUBLW = {
2244   {PC_OPCODE, NULL, NULL, 0, NULL,
2245    //   genericAnalyze,
2246    genericDestruct,
2247    genericPrint},
2248   POC_SUBLW,
2249   "SUBLW",
2250   2,
2251   NULL, // from branch
2252   NULL, // to branch
2253   NULL, // label
2254   NULL, // operand
2255   NULL, // flow block
2256   NULL, // C source
2257   1,    // num ops
2258   0,0,  // dest, bit instruction
2259   0,0,  // branch, skip
2260   1,    // literal operand
2261   0,    // RAM access bit
2262   0,    // fast call/return mode select bit
2263   0,    // second memory operand
2264   0,    // second literal operand
2265   POC_NOP,
2266   (PCC_W | PCC_LITERAL),   // inCond
2267   (PCC_W | PCC_STATUS), // outCond
2268   PCI_MAGIC
2269 };
2270
2271 pCodeInstruction pic16_pciSUBFWB = {
2272   {PC_OPCODE, NULL, NULL, 0, NULL,
2273    //   genericAnalyze,
2274    genericDestruct,
2275    genericPrint},
2276   POC_SUBFWB,
2277   "SUBFWB",
2278   2,
2279   NULL, // from branch
2280   NULL, // to branch
2281   NULL, // label
2282   NULL, // operand
2283   NULL, // flow block
2284   NULL, // C source
2285   3,    // num ops
2286   1,0,  // dest, bit instruction
2287   0,0,  // branch, skip
2288   0,    // literal operand
2289   1,    // RAM access bit
2290   0,    // fast call/return mode select bit
2291   0,    // second memory operand
2292   0,    // second literal operand
2293   POC_NOP,
2294   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2295   (PCC_W | PCC_STATUS), // outCond
2296   PCI_MAGIC
2297 };
2298
2299 pCodeInstruction pic16_pciSUBWF = {
2300   {PC_OPCODE, NULL, NULL, 0, NULL,
2301    //   genericAnalyze,
2302    genericDestruct,
2303    genericPrint},
2304   POC_SUBWF,
2305   "SUBWF",
2306   2,
2307   NULL, // from branch
2308   NULL, // to branch
2309   NULL, // label
2310   NULL, // operand
2311   NULL, // flow block
2312   NULL, // C source
2313   3,    // num ops
2314   1,0,  // dest, bit instruction
2315   0,0,  // branch, skip
2316   0,    // literal operand
2317   1,    // RAM access bit
2318   0,    // fast call/return mode select bit
2319   0,    // second memory operand
2320   0,    // second literal operand
2321   POC_NOP,
2322   (PCC_W | PCC_REGISTER),   // inCond
2323   (PCC_REGISTER | PCC_STATUS), // outCond
2324   PCI_MAGIC
2325 };
2326
2327 pCodeInstruction pic16_pciSUBFW = {
2328   {PC_OPCODE, NULL, NULL, 0, NULL,
2329    //   genericAnalyze,
2330    genericDestruct,
2331    genericPrint},
2332   POC_SUBFW,
2333   "SUBWF",
2334   2,
2335   NULL, // from branch
2336   NULL, // to branch
2337   NULL, // label
2338   NULL, // operand
2339   NULL, // flow block
2340   NULL, // C source
2341   3,    // num ops
2342   0,0,  // dest, bit instruction
2343   0,0,  // branch, skip
2344   0,    // literal operand
2345   1,    // RAM access bit
2346   0,    // fast call/return mode select bit
2347   0,    // second memory operand
2348   0,    // second literal operand
2349   POC_NOP,
2350   (PCC_W | PCC_REGISTER),   // inCond
2351   (PCC_W | PCC_STATUS), // outCond
2352   PCI_MAGIC
2353 };
2354
2355 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2356   {PC_OPCODE, NULL, NULL, 0, NULL,
2357    //   genericAnalyze,
2358    genericDestruct,
2359    genericPrint},
2360   POC_SUBFWB_D1,
2361   "SUBFWB",
2362   2,
2363   NULL, // from branch
2364   NULL, // to branch
2365   NULL, // label
2366   NULL, // operand
2367   NULL, // flow block
2368   NULL, // C source
2369   3,    // num ops
2370   1,0,  // dest, bit instruction
2371   0,0,  // branch, skip
2372   0,    // literal operand
2373   1,    // RAM access bit
2374   0,    // fast call/return mode select bit
2375   0,    // second memory operand
2376   0,    // second literal operand
2377   POC_NOP,
2378   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2379   (PCC_REGISTER | PCC_STATUS), // outCond
2380   PCI_MAGIC
2381 };
2382
2383 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2384   {PC_OPCODE, NULL, NULL, 0, NULL,
2385    //   genericAnalyze,
2386    genericDestruct,
2387    genericPrint},
2388   POC_SUBFWB_D0,
2389   "SUBFWB",
2390   2,
2391   NULL, // from branch
2392   NULL, // to branch
2393   NULL, // label
2394   NULL, // operand
2395   NULL, // flow block
2396   NULL, // C source
2397   3,    // num ops
2398   0,0,  // dest, bit instruction
2399   0,0,  // branch, skip
2400   0,    // literal operand
2401   1,    // RAM access bit
2402   0,    // fast call/return mode select bit
2403   0,    // second memory operand
2404   0,    // second literal operand
2405   POC_NOP,
2406   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2407   (PCC_W | PCC_STATUS), // outCond
2408   PCI_MAGIC
2409 };
2410
2411 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2412   {PC_OPCODE, NULL, NULL, 0, NULL,
2413    //   genericAnalyze,
2414    genericDestruct,
2415    genericPrint},
2416   POC_SUBWFB_D1,
2417   "SUBWFB",
2418   2,
2419   NULL, // from branch
2420   NULL, // to branch
2421   NULL, // label
2422   NULL, // operand
2423   NULL, // flow block
2424   NULL, // C source
2425   3,    // num ops
2426   1,0,  // dest, bit instruction
2427   0,0,  // branch, skip
2428   0,    // literal operand
2429   1,    // RAM access bit
2430   0,    // fast call/return mode select bit
2431   0,    // second memory operand
2432   0,    // second literal operand
2433   POC_NOP,
2434   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2435   (PCC_REGISTER | PCC_STATUS), // outCond
2436   PCI_MAGIC
2437 };
2438
2439 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2440   {PC_OPCODE, NULL, NULL, 0, NULL,
2441    //   genericAnalyze,
2442    genericDestruct,
2443    genericPrint},
2444   POC_SUBWFB_D0,
2445   "SUBWFB",
2446   2,
2447   NULL, // from branch
2448   NULL, // to branch
2449   NULL, // label
2450   NULL, // operand
2451   NULL, // flow block
2452   NULL, // C source
2453   3,    // num ops
2454   0,0,  // dest, bit instruction
2455   0,0,  // branch, skip
2456   0,    // literal operand
2457   1,    // RAM access bit
2458   0,    // fast call/return mode select bit
2459   0,    // second memory operand
2460   0,    // second literal operand
2461   POC_NOP,
2462   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2463   (PCC_W | PCC_STATUS), // outCond
2464   PCI_MAGIC
2465 };
2466
2467 pCodeInstruction pic16_pciSWAPF = {
2468   {PC_OPCODE, NULL, NULL, 0, NULL,
2469    //   genericAnalyze,
2470    genericDestruct,
2471    genericPrint},
2472   POC_SWAPF,
2473   "SWAPF",
2474   2,
2475   NULL, // from branch
2476   NULL, // to branch
2477   NULL, // label
2478   NULL, // operand
2479   NULL, // flow block
2480   NULL, // C source
2481   3,    // num ops
2482   1,0,  // dest, bit instruction
2483   0,0,  // branch, skip
2484   0,    // literal operand
2485   1,    // RAM access bit
2486   0,    // fast call/return mode select bit
2487   0,    // second memory operand
2488   0,    // second literal operand
2489   POC_NOP,
2490   (PCC_REGISTER),   // inCond
2491   (PCC_REGISTER), // outCond
2492   PCI_MAGIC
2493 };
2494
2495 pCodeInstruction pic16_pciSWAPFW = {
2496   {PC_OPCODE, NULL, NULL, 0, NULL,
2497    //   genericAnalyze,
2498    genericDestruct,
2499    genericPrint},
2500   POC_SWAPFW,
2501   "SWAPF",
2502   2,
2503   NULL, // from branch
2504   NULL, // to branch
2505   NULL, // label
2506   NULL, // operand
2507   NULL, // flow block
2508   NULL, // C source
2509   3,    // num ops
2510   0,0,  // dest, bit instruction
2511   0,0,  // branch, skip
2512   0,    // literal operand
2513   1,    // RAM access bit
2514   0,    // fast call/return mode select bit
2515   0,    // second memory operand
2516   0,    // second literal operand
2517   POC_NOP,
2518   (PCC_REGISTER),   // inCond
2519   (PCC_W), // outCond
2520   PCI_MAGIC
2521 };
2522
2523 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2524   {PC_OPCODE, NULL, NULL, 0, NULL,
2525    genericDestruct,
2526    genericPrint},
2527   POC_TBLRD,
2528   "TBLRD*",
2529   2,
2530   NULL, // from branch
2531   NULL, // to branch
2532   NULL, // label
2533   NULL, // operand
2534   NULL, // flow block
2535   NULL, // C source
2536   0,    // num ops
2537   0,0,  // dest, bit instruction
2538   0,0,  // branch, skip
2539   0,    // literal operand
2540   0,    // RAM access bit
2541   0,    // fast call/return mode select bit
2542   0,    // second memory operand
2543   0,    // second literal operand
2544   POC_NOP,
2545   PCC_NONE,  // inCond
2546   PCC_NONE  , // outCond
2547   PCI_MAGIC
2548 };
2549
2550 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2551   {PC_OPCODE, NULL, NULL, 0, NULL,
2552    genericDestruct,
2553    genericPrint},
2554   POC_TBLRD_POSTINC,
2555   "TBLRD*+",
2556   2,
2557   NULL, // from branch
2558   NULL, // to branch
2559   NULL, // label
2560   NULL, // operand
2561   NULL, // flow block
2562   NULL, // C source
2563   0,    // num ops
2564   0,0,  // dest, bit instruction
2565   0,0,  // branch, skip
2566   0,    // literal operand
2567   0,    // RAM access bit
2568   0,    // fast call/return mode select bit
2569   0,    // second memory operand
2570   0,    // second literal operand
2571   POC_NOP,
2572   PCC_NONE,  // inCond
2573   PCC_NONE  , // outCond
2574   PCI_MAGIC
2575 };
2576
2577 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2578   {PC_OPCODE, NULL, NULL, 0, NULL,
2579    genericDestruct,
2580    genericPrint},
2581   POC_TBLRD_POSTDEC,
2582   "TBLRD*-",
2583   2,
2584   NULL, // from branch
2585   NULL, // to branch
2586   NULL, // label
2587   NULL, // operand
2588   NULL, // flow block
2589   NULL, // C source
2590   0,    // num ops
2591   0,0,  // dest, bit instruction
2592   0,0,  // branch, skip
2593   0,    // literal operand
2594   0,    // RAM access bit
2595   0,    // fast call/return mode select bit
2596   0,    // second memory operand
2597   0,    // second literal operand
2598   POC_NOP,
2599   PCC_NONE,  // inCond
2600   PCC_NONE  , // outCond
2601   PCI_MAGIC
2602 };
2603
2604 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2605   {PC_OPCODE, NULL, NULL, 0, NULL,
2606    genericDestruct,
2607    genericPrint},
2608   POC_TBLRD_PREINC,
2609   "TBLRD+*",
2610   2,
2611   NULL, // from branch
2612   NULL, // to branch
2613   NULL, // label
2614   NULL, // operand
2615   NULL, // flow block
2616   NULL, // C source
2617   0,    // num ops
2618   0,0,  // dest, bit instruction
2619   0,0,  // branch, skip
2620   0,    // literal operand
2621   0,    // RAM access bit
2622   0,    // fast call/return mode select bit
2623   0,    // second memory operand
2624   0,    // second literal operand
2625   POC_NOP,
2626   PCC_NONE,  // inCond
2627   PCC_NONE  , // outCond
2628   PCI_MAGIC
2629 };
2630
2631 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2632   {PC_OPCODE, NULL, NULL, 0, NULL,
2633    genericDestruct,
2634    genericPrint},
2635   POC_TBLWT,
2636   "TBLWT*",
2637   2,
2638   NULL, // from branch
2639   NULL, // to branch
2640   NULL, // label
2641   NULL, // operand
2642   NULL, // flow block
2643   NULL, // C source
2644   0,    // num ops
2645   0,0,  // dest, bit instruction
2646   0,0,  // branch, skip
2647   0,    // literal operand
2648   0,    // RAM access bit
2649   0,    // fast call/return mode select bit
2650   0,    // second memory operand
2651   0,    // second literal operand
2652   POC_NOP,
2653   PCC_NONE,  // inCond
2654   PCC_NONE  , // outCond
2655   PCI_MAGIC
2656 };
2657
2658 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2659   {PC_OPCODE, NULL, NULL, 0, NULL,
2660    genericDestruct,
2661    genericPrint},
2662   POC_TBLWT_POSTINC,
2663   "TBLWT*+",
2664   2,
2665   NULL, // from branch
2666   NULL, // to branch
2667   NULL, // label
2668   NULL, // operand
2669   NULL, // flow block
2670   NULL, // C source
2671   0,    // num ops
2672   0,0,  // dest, bit instruction
2673   0,0,  // branch, skip
2674   0,    // literal operand
2675   0,    // RAM access bit
2676   0,    // fast call/return mode select bit
2677   0,    // second memory operand
2678   0,    // second literal operand
2679   POC_NOP,
2680   PCC_NONE,  // inCond
2681   PCC_NONE  , // outCond
2682   PCI_MAGIC
2683 };
2684
2685 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2686   {PC_OPCODE, NULL, NULL, 0, NULL,
2687    genericDestruct,
2688    genericPrint},
2689   POC_TBLWT_POSTDEC,
2690   "TBLWT*-",
2691   2,
2692   NULL, // from branch
2693   NULL, // to branch
2694   NULL, // label
2695   NULL, // operand
2696   NULL, // flow block
2697   NULL, // C source
2698   0,    // num ops
2699   0,0,  // dest, bit instruction
2700   0,0,  // branch, skip
2701   0,    // literal operand
2702   0,    // RAM access bit
2703   0,    // fast call/return mode select bit
2704   0,    // second memory operand
2705   0,    // second literal operand
2706   POC_NOP,
2707   PCC_NONE,  // inCond
2708   PCC_NONE  , // outCond
2709   PCI_MAGIC
2710 };
2711
2712 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2713   {PC_OPCODE, NULL, NULL, 0, NULL,
2714    genericDestruct,
2715    genericPrint},
2716   POC_TBLWT_PREINC,
2717   "TBLWT+*",
2718   2,
2719   NULL, // from branch
2720   NULL, // to branch
2721   NULL, // label
2722   NULL, // operand
2723   NULL, // flow block
2724   NULL, // C source
2725   0,    // num ops
2726   0,0,  // dest, bit instruction
2727   0,0,  // branch, skip
2728   0,    // literal operand
2729   0,    // RAM access bit
2730   0,    // fast call/return mode select bit
2731   0,    // second memory operand
2732   0,    // second literal operand
2733   POC_NOP,
2734   PCC_NONE,  // inCond
2735   PCC_NONE  , // outCond
2736   PCI_MAGIC
2737 };
2738
2739 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2740   {PC_OPCODE, NULL, NULL, 0, NULL,
2741    //   genericAnalyze,
2742    genericDestruct,
2743    genericPrint},
2744   POC_TSTFSZ,
2745   "TSTFSZ",
2746   2,
2747   NULL, // from branch
2748   NULL, // to branch
2749   NULL, // label
2750   NULL, // operand
2751   NULL, // flow block
2752   NULL, // C source
2753   2,    // num ops
2754   0,0,  // dest, bit instruction
2755   1,1,  // branch, skip
2756   0,    // literal operand
2757   1,    // RAM access bit
2758   0,    // fast call/return mode select bit
2759   0,    // second memory operand
2760   0,    // second literal operand
2761   POC_NOP,
2762   PCC_REGISTER,   // inCond
2763   PCC_NONE, // outCond
2764   PCI_MAGIC
2765 };
2766
2767 pCodeInstruction pic16_pciXORWF = {
2768   {PC_OPCODE, NULL, NULL, 0, NULL,
2769    //   genericAnalyze,
2770    genericDestruct,
2771    genericPrint},
2772   POC_XORWF,
2773   "XORWF",
2774   2,
2775   NULL, // from branch
2776   NULL, // to branch
2777   NULL, // label
2778   NULL, // operand
2779   NULL, // flow block
2780   NULL, // C source
2781   3,    // num ops
2782   1,0,  // dest, bit instruction
2783   0,0,  // branch, skip
2784   0,    // literal operand
2785   1,    // RAM access bit
2786   0,    // fast call/return mode select bit
2787   0,    // second memory operand
2788   0,    // second literal operand
2789   POC_NOP,
2790   (PCC_W | PCC_REGISTER),   // inCond
2791   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2792   PCI_MAGIC
2793 };
2794
2795 pCodeInstruction pic16_pciXORFW = {
2796   {PC_OPCODE, NULL, NULL, 0, NULL,
2797    //   genericAnalyze,
2798    genericDestruct,
2799    genericPrint},
2800   POC_XORFW,
2801   "XORWF",
2802   2,
2803   NULL, // from branch
2804   NULL, // to branch
2805   NULL, // label
2806   NULL, // operand
2807   NULL, // flow block
2808   NULL, // C source
2809   3,    // num ops
2810   0,0,  // dest, bit instruction
2811   0,0,  // branch, skip
2812   0,    // literal operand
2813   1,    // RAM access bit
2814   0,    // fast call/return mode select bit
2815   0,    // second memory operand
2816   0,    // second literal operand
2817   POC_NOP,
2818   (PCC_W | PCC_REGISTER),   // inCond
2819   (PCC_W | PCC_Z | PCC_N), // outCond
2820   PCI_MAGIC
2821 };
2822
2823 pCodeInstruction pic16_pciXORLW = {
2824   {PC_OPCODE, NULL, NULL, 0, NULL,
2825    //   genericAnalyze,
2826    genericDestruct,
2827    genericPrint},
2828   POC_XORLW,
2829   "XORLW",
2830   2,
2831   NULL, // from branch
2832   NULL, // to branch
2833   NULL, // label
2834   NULL, // operand
2835   NULL, // flow block
2836   NULL, // C source
2837   1,    // num ops
2838   0,0,  // dest, bit instruction
2839   0,0,  // branch, skip
2840   1,    // literal operand
2841   1,    // RAM access bit
2842   0,    // fast call/return mode select bit
2843   0,    // second memory operand
2844   0,    // second literal operand
2845   POC_NOP,
2846   (PCC_W | PCC_LITERAL),   // inCond
2847   (PCC_W | PCC_Z | PCC_N), // outCond
2848   PCI_MAGIC
2849 };
2850
2851
2852 pCodeInstruction pic16_pciBANKSEL = {
2853   {PC_OPCODE, NULL, NULL, 0, NULL,
2854    genericDestruct,
2855    genericPrint},
2856   POC_BANKSEL,
2857   "BANKSEL",
2858   2,
2859   NULL, // from branch
2860   NULL, // to branch
2861   NULL, // label
2862   NULL, // operand
2863   NULL, // flow block
2864   NULL, // C source
2865   0,    // num ops
2866   0,0,  // dest, bit instruction
2867   0,0,  // branch, skip
2868   0,    // literal operand
2869   0,    // RAM access bit
2870   0,    // fast call/return mode select bit
2871   0,    // second memory operand
2872   0,    // second literal operand
2873   POC_NOP,
2874   PCC_NONE,   // inCond
2875   PCC_NONE, // outCond
2876   PCI_MAGIC
2877 };
2878
2879
2880 #define MAX_PIC16MNEMONICS 100
2881 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2882
2883 extern set *externs;
2884 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2885 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2886
2887 void  pic16_pCodeInitRegisters(void)
2888 {
2889   static int initialized=0;
2890
2891         if(initialized)
2892                 return;
2893
2894         initialized = 1;
2895
2896         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2897         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2898         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2899         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2900         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2901         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2902         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2903
2904         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2905         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2906         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2907
2908         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2909         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2910         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2911         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2912
2913         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2914         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2915         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2916         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2917         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2918         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
2919
2920         pic16_stackpnt_lo = &pic16_pc_fsr1l;
2921         pic16_stackpnt_hi = &pic16_pc_fsr1h;
2922         pic16_stack_postdec = &pic16_pc_postdec1;
2923         pic16_stack_postinc = &pic16_pc_postinc1;
2924         pic16_stack_preinc = &pic16_pc_preinc1;
2925         pic16_stack_plusw = &pic16_pc_plusw1;
2926
2927         pic16_framepnt_lo = &pic16_pc_fsr2l;
2928         pic16_framepnt_hi = &pic16_pc_fsr2h;
2929         pic16_frame_postdec = &pic16_pc_postdec2;
2930         pic16_frame_postinc = &pic16_pc_postinc2;
2931         pic16_frame_preinc = &pic16_pc_preinc2;
2932         pic16_frame_plusw = &pic16_pc_plusw2;
2933
2934         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
2935         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
2936         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
2937         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
2938         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
2939
2940         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
2941         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
2942         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
2943         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
2944         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
2945
2946         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
2947         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
2948         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
2949         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
2950         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
2951
2952         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
2953         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
2954
2955
2956         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
2957         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
2958         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
2959         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
2960
2961
2962         pic16_pc_status.rIdx = IDX_STATUS;
2963         pic16_pc_intcon.rIdx = IDX_INTCON;
2964         pic16_pc_pcl.rIdx = IDX_PCL;
2965         pic16_pc_pclath.rIdx = IDX_PCLATH;
2966         pic16_pc_pclatu.rIdx = IDX_PCLATU;
2967         pic16_pc_wreg.rIdx = IDX_WREG;
2968         pic16_pc_bsr.rIdx = IDX_BSR;
2969
2970         pic16_pc_tosl.rIdx = IDX_TOSL;
2971         pic16_pc_tosh.rIdx = IDX_TOSH;
2972         pic16_pc_tosu.rIdx = IDX_TOSU;
2973
2974         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
2975         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
2976         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
2977         pic16_pc_tablat.rIdx = IDX_TABLAT;
2978
2979         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
2980         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
2981         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
2982         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
2983         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
2984         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
2985         pic16_pc_indf0.rIdx = IDX_INDF0;
2986         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
2987         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
2988         pic16_pc_preinc0.rIdx = IDX_PREINC0;
2989         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
2990         pic16_pc_indf1.rIdx = IDX_INDF1;
2991         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
2992         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
2993         pic16_pc_preinc1.rIdx = IDX_PREINC1;
2994         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
2995         pic16_pc_indf2.rIdx = IDX_INDF2;
2996         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
2997         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
2998         pic16_pc_preinc2.rIdx = IDX_PREINC2;
2999         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3000         pic16_pc_prodl.rIdx = IDX_PRODL;
3001         pic16_pc_prodh.rIdx = IDX_PRODH;
3002
3003         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3004         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3005         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3006
3007         pic16_pc_kzero.rIdx = IDX_KZ;
3008         pic16_pc_wsave.rIdx = IDX_WSAVE;
3009         pic16_pc_ssave.rIdx = IDX_SSAVE;
3010
3011         pic16_pc_eecon1.rIdx = IDX_EECON1;
3012         pic16_pc_eecon2.rIdx = IDX_EECON2;
3013         pic16_pc_eedata.rIdx = IDX_EEDATA;
3014         pic16_pc_eeadr.rIdx = IDX_EEADR;
3015
3016
3017         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3018         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3019
3020         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3021         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3022
3023         /* probably should put this in a separate initialization routine */
3024         pb_dead_pcodes = newpBlock();
3025
3026 }
3027
3028 /*-----------------------------------------------------------------*/
3029 /*  mnem2key - convert a pic mnemonic into a hash key              */
3030 /*   (BTW - this spreads the mnemonics quite well)                 */
3031 /*                                                                 */
3032 /*-----------------------------------------------------------------*/
3033
3034 static int mnem2key(unsigned char const *mnem)
3035 {
3036   int key = 0;
3037
3038   if(!mnem)
3039     return 0;
3040
3041   while(*mnem) {
3042
3043     key += toupper(*mnem++) +1;
3044
3045   }
3046
3047   return (key & 0x1f);
3048
3049 }
3050
3051 void pic16initMnemonics(void)
3052 {
3053   int i = 0;
3054   int key;
3055   //  char *str;
3056   pCodeInstruction *pci;
3057
3058   if(mnemonics_initialized)
3059     return;
3060
3061   // NULL out the array before making the assignments
3062   // since we check the array contents below this initialization.
3063
3064   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3065     pic16Mnemonics[i] = NULL;
3066   }
3067
3068   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3069   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3070   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3071   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3072   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3073   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3074   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3075   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3076   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3077   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3078   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3079   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3080   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3081   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3082   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3083   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3084   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3085   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3086   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3087   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3088   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3089   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3090   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3091   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3092   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3093   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3094   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3095   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3096   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3097   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3098   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3099   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3100   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3101   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3102   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3103   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3104   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3105   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3106   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3107   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3108   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3109   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3110   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3111   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3112   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3113   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3114   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3115   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3116   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3117   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3118   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3119   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3120   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3121   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3122   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3123   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3124   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3125   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3126   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3127   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3128   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3129   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3130   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3131   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3132   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3133   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3134   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3135   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3136   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3137   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3138   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3139   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3140   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3141   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3142   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3143   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3144   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3145   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3146   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3147   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3148   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3149   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3150   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3151   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3152   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3153   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3154   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3155   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3156   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3157   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3158   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3159   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3160   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3161   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3162
3163   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3164     if(pic16Mnemonics[i])
3165       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3166   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3167
3168   while(pci) {
3169     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3170     pci = hTabNextItem(pic16MnemonicsHash, &key);
3171   }
3172
3173   mnemonics_initialized = 1;
3174 }
3175
3176 int pic16_getpCodePeepCommand(char *cmd);
3177
3178 int pic16_getpCode(char *mnem,unsigned dest)
3179 {
3180
3181   pCodeInstruction *pci;
3182   int key = mnem2key((unsigned char *)mnem);
3183
3184   if(!mnemonics_initialized)
3185     pic16initMnemonics();
3186
3187   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3188
3189   while(pci) {
3190
3191     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3192       if((pci->num_ops <= 1)
3193         || (pci->isModReg == dest)
3194         || (pci->isBitInst)
3195         || (pci->num_ops <= 2 && pci->isAccess)
3196         || (pci->num_ops <= 2 && pci->isFastCall)
3197         || (pci->num_ops <= 2 && pci->is2MemOp)
3198         || (pci->num_ops <= 2 && pci->is2LitOp) )
3199         return(pci->op);
3200     }
3201
3202     pci = hTabNextItemWK (pic16MnemonicsHash);
3203
3204   }
3205
3206   return -1;
3207 }
3208
3209 /*-----------------------------------------------------------------*
3210  * pic16initpCodePeepCommands
3211  *
3212  *-----------------------------------------------------------------*/
3213 void pic16initpCodePeepCommands(void)
3214 {
3215
3216   int key, i;
3217   peepCommand *pcmd;
3218
3219   i = 0;
3220   do {
3221     hTabAddItem(&pic16pCodePeepCommandsHash,
3222                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3223     i++;
3224   } while (peepCommands[i].cmd);
3225
3226   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3227
3228   while(pcmd) {
3229     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3230     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3231   }
3232
3233 }
3234
3235 /*-----------------------------------------------------------------
3236  *
3237  *
3238  *-----------------------------------------------------------------*/
3239
3240 int pic16_getpCodePeepCommand(char *cmd)
3241 {
3242
3243   peepCommand *pcmd;
3244   int key = mnem2key((unsigned char *)cmd);
3245
3246
3247   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3248
3249   while(pcmd) {
3250     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3251     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3252       return pcmd->id;
3253     }
3254
3255     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3256
3257   }
3258
3259   return -1;
3260 }
3261
3262 static char getpBlock_dbName(pBlock *pb)
3263 {
3264   if(!pb)
3265     return 0;
3266
3267   if(pb->cmemmap)
3268     return pb->cmemmap->dbName;
3269
3270   return pb->dbName;
3271 }
3272 void pic16_pBlockConvert2ISR(pBlock *pb)
3273 {
3274         if(!pb)return;
3275
3276         if(pb->cmemmap)pb->cmemmap = NULL;
3277
3278         pb->dbName = 'I';
3279
3280         if(pic16_pcode_verbose)
3281                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3282 }
3283
3284 void pic16_pBlockConvert2Absolute(pBlock *pb)
3285 {
3286         if(!pb)return;
3287         if(pb->cmemmap)pb->cmemmap = NULL;
3288
3289         pb->dbName = 'A';
3290
3291         if(pic16_pcode_verbose)
3292                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3293 }
3294
3295 /*-----------------------------------------------------------------*/
3296 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3297 /*                   instances to the front of the doubly linked   */
3298 /*                   list of pBlocks                               */
3299 /*-----------------------------------------------------------------*/
3300
3301 void pic16_movepBlock2Head(char dbName)
3302 {
3303   pBlock *pb;
3304
3305
3306   /* this can happen in sources without code,
3307    * only variable definitions */
3308   if(!the_pFile)return;
3309
3310   pb = the_pFile->pbHead;
3311
3312   while(pb) {
3313
3314     if(getpBlock_dbName(pb) == dbName) {
3315       pBlock *pbn = pb->next;
3316       pb->next = the_pFile->pbHead;
3317       the_pFile->pbHead->prev = pb;
3318       the_pFile->pbHead = pb;
3319
3320       if(pb->prev)
3321         pb->prev->next = pbn;
3322
3323       // If the pBlock that we just moved was the last
3324       // one in the link of all of the pBlocks, then we
3325       // need to point the tail to the block just before
3326       // the one we moved.
3327       // Note: if pb->next is NULL, then pb must have
3328       // been the last pBlock in the chain.
3329
3330       if(pbn)
3331         pbn->prev = pb->prev;
3332       else
3333         the_pFile->pbTail = pb->prev;
3334
3335       pb = pbn;
3336
3337     } else
3338       pb = pb->next;
3339
3340   }
3341
3342 }
3343
3344 void pic16_copypCode(FILE *of, char dbName)
3345 {
3346   pBlock *pb;
3347
3348         if(!of || !the_pFile)
3349                 return;
3350
3351         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3352                 if(getpBlock_dbName(pb) == dbName) {
3353 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3354                         pBlockStats(of,pb);
3355                         pic16_printpBlock(of,pb);
3356                 }
3357         }
3358
3359 }
3360 void pic16_pcode_test(void)
3361 {
3362
3363   DFPRINTF((stderr,"pcode is alive!\n"));
3364
3365   //initMnemonics();
3366
3367   if(the_pFile) {
3368
3369     pBlock *pb;
3370     FILE *pFile;
3371     char buffer[100];
3372
3373     /* create the file name */
3374     strcpy(buffer,dstFileName);
3375     strcat(buffer,".p");
3376
3377     if( !(pFile = fopen(buffer, "w" ))) {
3378       werror(E_FILE_OPEN_ERR,buffer);
3379       exit(1);
3380     }
3381
3382     fprintf(pFile,"pcode dump\n\n");
3383
3384     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3385       fprintf(pFile,"\n\tNew pBlock\n\n");
3386       if(pb->cmemmap)
3387         fprintf(pFile,"%s",pb->cmemmap->sname);
3388       else
3389         fprintf(pFile,"internal pblock");
3390
3391       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3392       pic16_printpBlock(pFile,pb);
3393     }
3394   }
3395 }
3396
3397
3398 unsigned long pic16_countInstructions(void)
3399 {
3400   pBlock *pb;
3401   pCode *pc;
3402   unsigned long isize=0;
3403
3404     if(!the_pFile)return -1;
3405
3406     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3407       for(pc = pb->pcHead; pc; pc = pc->next) {
3408         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3409       }
3410     }
3411   return (isize);
3412 }
3413
3414
3415 /*-----------------------------------------------------------------*/
3416 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3417 /*      ister, RegCond will return the bit being referenced.       */
3418 /*                                                                 */
3419 /* fixme - why not just OR in the pcop bit field                   */
3420 /*-----------------------------------------------------------------*/
3421
3422 static int RegCond(pCodeOp *pcop)
3423 {
3424
3425   if(!pcop)
3426     return 0;
3427
3428   if(!pcop->name)return 0;
3429
3430   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3431     switch(PCORB(pcop)->bit) {
3432     case PIC_C_BIT:
3433       return PCC_C;
3434     case PIC_DC_BIT:
3435         return PCC_DC;
3436     case PIC_Z_BIT:
3437       return PCC_Z;
3438     }
3439
3440   }
3441
3442   return 0;
3443 }
3444
3445
3446 /*-----------------------------------------------------------------*/
3447 /* pic16_newpCode - create and return a newly initialized pCode          */
3448 /*                                                                 */
3449 /*  fixme - rename this                                            */
3450 /*                                                                 */
3451 /* The purpose of this routine is to create a new Instruction      */
3452 /* pCode. This is called by gen.c while the assembly code is being */
3453 /* generated.                                                      */
3454 /*                                                                 */
3455 /* Inouts:                                                         */
3456 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3457 /*                  (note that the op is analogous to but not the  */
3458 /*                  same thing as the opcode of the instruction.)  */
3459 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3460 /*                                                                 */
3461 /* Outputs:                                                        */
3462 /*  a pointer to the new malloc'd pCode is returned.               */
3463 /*                                                                 */
3464 /*                                                                 */
3465 /*                                                                 */
3466 /*-----------------------------------------------------------------*/
3467 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3468 {
3469   pCodeInstruction *pci ;
3470
3471   if(!mnemonics_initialized)
3472     pic16initMnemonics();
3473
3474   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3475
3476   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3477     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3478     pci->pcop = pcop;
3479
3480     if(pci->inCond & PCC_EXAMINE_PCOP)
3481       pci->inCond  |= RegCond(pcop);
3482
3483     if(pci->outCond & PCC_EXAMINE_PCOP)
3484       pci->outCond  |= RegCond(pcop);
3485
3486     pci->pc.prev = pci->pc.next = NULL;
3487     return (pCode *)pci;
3488   }
3489
3490   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3491   exit(1);
3492
3493   return NULL;
3494 }
3495
3496 /*-----------------------------------------------------------------*/
3497 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3498 /*                                                                 */
3499 /* Wild pcodes are used during the peep hole optimizer to serve    */
3500 /* as place holders for any instruction. When a snippet of code is */
3501 /* compared to a peep hole rule, the wild card opcode will match   */
3502 /* any instruction. However, the optional operand and label are    */
3503 /* additional qualifiers that must also be matched before the      */
3504 /* line (of assembly code) is declared matched. Note that the      */
3505 /* operand may be wild too.                                        */
3506 /*                                                                 */
3507 /*   Note, a wild instruction is specified just like a wild var:   */
3508 /*      %4     ; A wild instruction,                               */
3509 /*  See the peeph.def file for additional examples                 */
3510 /*                                                                 */
3511 /*-----------------------------------------------------------------*/
3512
3513 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3514 {
3515
3516   pCodeWild *pcw;
3517
3518   pcw = Safe_calloc(1,sizeof(pCodeWild));
3519
3520   pcw->pci.pc.type = PC_WILD;
3521   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3522   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3523   pcw->pci.pc.pb = NULL;
3524
3525   //  pcw->pci.pc.analyze = genericAnalyze;
3526   pcw->pci.pc.destruct = genericDestruct;
3527   pcw->pci.pc.print = genericPrint;
3528
3529   pcw->id = pCodeID;              // this is the 'n' in %n
3530   pcw->operand = optional_operand;
3531   pcw->label   = optional_label;
3532
3533   pcw->mustBeBitSkipInst = 0;
3534   pcw->mustNotBeBitSkipInst = 0;
3535   pcw->invertBitSkipInst = 0;
3536
3537   return ( (pCode *)pcw);
3538
3539 }
3540
3541  /*-----------------------------------------------------------------*/
3542 /* newPcodeInlineP - create a new pCode from a char string           */
3543 /*-----------------------------------------------------------------*/
3544
3545
3546 pCode *pic16_newpCodeInlineP(char *cP)
3547 {
3548
3549   pCodeComment *pcc ;
3550
3551   pcc = Safe_calloc(1,sizeof(pCodeComment));
3552
3553   pcc->pc.type = PC_INLINE;
3554   pcc->pc.prev = pcc->pc.next = NULL;
3555   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3556   pcc->pc.pb = NULL;
3557
3558   //  pcc->pc.analyze = genericAnalyze;
3559   pcc->pc.destruct = genericDestruct;
3560   pcc->pc.print = genericPrint;
3561
3562   if(cP)
3563     pcc->comment = Safe_strdup(cP);
3564   else
3565     pcc->comment = NULL;
3566
3567   return ( (pCode *)pcc);
3568
3569 }
3570
3571 /*-----------------------------------------------------------------*/
3572 /* newPcodeCharP - create a new pCode from a char string           */
3573 /*-----------------------------------------------------------------*/
3574
3575 pCode *pic16_newpCodeCharP(char *cP)
3576 {
3577
3578   pCodeComment *pcc ;
3579
3580   pcc = Safe_calloc(1,sizeof(pCodeComment));
3581
3582   pcc->pc.type = PC_COMMENT;
3583   pcc->pc.prev = pcc->pc.next = NULL;
3584   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3585   pcc->pc.pb = NULL;
3586
3587   //  pcc->pc.analyze = genericAnalyze;
3588   pcc->pc.destruct = genericDestruct;
3589   pcc->pc.print = genericPrint;
3590
3591   if(cP)
3592     pcc->comment = Safe_strdup(cP);
3593   else
3594     pcc->comment = NULL;
3595
3596   return ( (pCode *)pcc);
3597
3598 }
3599
3600 /*-----------------------------------------------------------------*/
3601 /* pic16_newpCodeFunction -                                              */
3602 /*-----------------------------------------------------------------*/
3603
3604
3605 pCode *pic16_newpCodeFunction(char *mod,char *f)
3606 {
3607   pCodeFunction *pcf;
3608
3609   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3610
3611   pcf->pc.type = PC_FUNCTION;
3612   pcf->pc.prev = pcf->pc.next = NULL;
3613   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3614   pcf->pc.pb = NULL;
3615
3616   //  pcf->pc.analyze = genericAnalyze;
3617   pcf->pc.destruct = genericDestruct;
3618   pcf->pc.print = pCodePrintFunction;
3619
3620   pcf->ncalled = 0;
3621   pcf->absblock = 0;
3622
3623   if(mod) {
3624     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3625     strcpy(pcf->modname,mod);
3626   } else
3627     pcf->modname = NULL;
3628
3629   if(f) {
3630     pcf->fname = Safe_calloc(1,strlen(f)+1);
3631     strcpy(pcf->fname,f);
3632   } else
3633     pcf->fname = NULL;
3634
3635   pcf->stackusage = 0;
3636
3637   return ( (pCode *)pcf);
3638 }
3639
3640 /*-----------------------------------------------------------------*/
3641 /* pic16_newpCodeFlow                                                    */
3642 /*-----------------------------------------------------------------*/
3643 static void destructpCodeFlow(pCode *pc)
3644 {
3645   if(!pc || !isPCFL(pc))
3646     return;
3647
3648 /*
3649   if(PCFL(pc)->from)
3650   if(PCFL(pc)->to)
3651 */
3652   pic16_unlinkpCode(pc);
3653
3654   deleteSet(&PCFL(pc)->registers);
3655   deleteSet(&PCFL(pc)->from);
3656   deleteSet(&PCFL(pc)->to);
3657
3658   /* Instead of deleting the memory used by this pCode, mark
3659    * the object as bad so that if there's a pointer to this pCode
3660    * dangling around somewhere then (hopefully) when the type is
3661    * checked we'll catch it.
3662    */
3663
3664   pc->type = PC_BAD;
3665   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3666
3667 //  Safe_free(pc);
3668
3669 }
3670
3671 pCode *pic16_newpCodeFlow(void )
3672 {
3673   pCodeFlow *pcflow;
3674
3675   //_ALLOC(pcflow,sizeof(pCodeFlow));
3676   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3677
3678   pcflow->pc.type = PC_FLOW;
3679   pcflow->pc.prev = pcflow->pc.next = NULL;
3680   pcflow->pc.pb = NULL;
3681
3682   //  pcflow->pc.analyze = genericAnalyze;
3683   pcflow->pc.destruct = destructpCodeFlow;
3684   pcflow->pc.print = genericPrint;
3685
3686   pcflow->pc.seq = GpcFlowSeq++;
3687
3688   pcflow->from = pcflow->to = NULL;
3689
3690   pcflow->inCond = PCC_NONE;
3691   pcflow->outCond = PCC_NONE;
3692
3693   pcflow->firstBank = -1;
3694   pcflow->lastBank = -1;
3695
3696   pcflow->FromConflicts = 0;
3697   pcflow->ToConflicts = 0;
3698
3699   pcflow->end = NULL;
3700
3701   pcflow->registers = newSet();
3702
3703   return ( (pCode *)pcflow);
3704
3705 }
3706
3707 /*-----------------------------------------------------------------*/
3708 /*-----------------------------------------------------------------*/
3709 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3710 {
3711   pCodeFlowLink *pcflowLink;
3712
3713   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3714
3715   pcflowLink->pcflow = pcflow;
3716   pcflowLink->bank_conflict = 0;
3717
3718   return pcflowLink;
3719 }
3720
3721 /*-----------------------------------------------------------------*/
3722 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3723 /*-----------------------------------------------------------------*/
3724
3725 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3726 {
3727
3728   pCodeCSource *pccs;
3729
3730   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3731
3732   pccs->pc.type = PC_CSOURCE;
3733   pccs->pc.prev = pccs->pc.next = NULL;
3734   pccs->pc.pb = NULL;
3735
3736   pccs->pc.destruct = genericDestruct;
3737   pccs->pc.print = genericPrint;
3738
3739   pccs->line_number = ln;
3740   if(l)
3741     pccs->line = Safe_strdup(l);
3742   else
3743     pccs->line = NULL;
3744
3745   if(f)
3746     pccs->file_name = Safe_strdup(f);
3747   else
3748     pccs->file_name = NULL;
3749
3750   return ( (pCode *)pccs);
3751
3752 }
3753
3754
3755 /*******************************************************************/
3756 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3757 /*                      added by VR 6-Jun-2003                     */
3758 /*******************************************************************/
3759
3760 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3761 {
3762   pCodeAsmDir *pcad;
3763   va_list ap;
3764   char buffer[512];
3765   char *lbp=buffer;
3766
3767         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3768         pcad->pci.pc.type = PC_ASMDIR;
3769         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3770         pcad->pci.pc.pb = NULL;
3771         pcad->pci.isize = 2;
3772         pcad->pci.pc.destruct = genericDestruct;
3773         pcad->pci.pc.print = genericPrint;
3774
3775         if(asdir && *asdir) {
3776
3777                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3778
3779                 pcad->directive = Safe_strdup( asdir );
3780         }
3781
3782         va_start(ap, argfmt);
3783
3784         memset(buffer, 0, sizeof(buffer));
3785         if(argfmt && *argfmt)
3786                 vsprintf(buffer, argfmt, ap);
3787
3788         va_end(ap);
3789
3790         while(isspace((unsigned char)*lbp))lbp++;
3791
3792         if(lbp && *lbp)
3793                 pcad->arg = Safe_strdup( lbp );
3794
3795   return ((pCode *)pcad);
3796 }
3797
3798 /*-----------------------------------------------------------------*/
3799 /* pCodeLabelDestruct - free memory used by a label.               */
3800 /*-----------------------------------------------------------------*/
3801 static void pCodeLabelDestruct(pCode *pc)
3802 {
3803
3804   if(!pc)
3805     return;
3806
3807   pic16_unlinkpCode(pc);
3808
3809 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3810 //    Safe_free(PCL(pc)->label);
3811
3812   /* Instead of deleting the memory used by this pCode, mark
3813    * the object as bad so that if there's a pointer to this pCode
3814    * dangling around somewhere then (hopefully) when the type is
3815    * checked we'll catch it.
3816    */
3817
3818   pc->type = PC_BAD;
3819   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3820
3821 //  Safe_free(pc);
3822
3823 }
3824
3825 pCode *pic16_newpCodeLabel(char *name, int key)
3826 {
3827
3828   char *s = buffer;
3829   pCodeLabel *pcl;
3830
3831   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3832
3833   pcl->pc.type = PC_LABEL;
3834   pcl->pc.prev = pcl->pc.next = NULL;
3835   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3836   pcl->pc.pb = NULL;
3837
3838   //  pcl->pc.analyze = genericAnalyze;
3839   pcl->pc.destruct = pCodeLabelDestruct;
3840   pcl->pc.print = pCodePrintLabel;
3841
3842   pcl->key = key;
3843   pcl->force = 0;
3844
3845   pcl->label = NULL;
3846   if(key>0) {
3847     sprintf(s,"_%05d_DS_",key);
3848   } else
3849     s = name;
3850
3851   if(s)
3852     pcl->label = Safe_strdup(s);
3853
3854 //  if(pic16_pcode_verbose)
3855 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3856
3857
3858   return ( (pCode *)pcl);
3859
3860 }
3861
3862 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3863 {
3864   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3865
3866         pcl->force = 1;
3867
3868   return ( (pCode *)pcl );
3869 }
3870
3871 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3872 {
3873   pCodeInfo *pci;
3874
3875     pci = Safe_calloc(1, sizeof(pCodeInfo));
3876     pci->pci.pc.type = PC_INFO;
3877     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3878     pci->pci.pc.pb = NULL;
3879     pci->pci.label = NULL;
3880
3881     pci->pci.pc.destruct = genericDestruct;
3882     pci->pci.pc.print = genericPrint;
3883
3884     pci->type = type;
3885     pci->oper1 = pcop;
3886
3887   return ((pCode *)pci);
3888 }
3889
3890
3891 /*-----------------------------------------------------------------*/
3892 /* newpBlock - create and return a pointer to a new pBlock         */
3893 /*-----------------------------------------------------------------*/
3894 static pBlock *newpBlock(void)
3895 {
3896
3897   pBlock *PpB;
3898
3899   PpB = Safe_calloc(1,sizeof(pBlock) );
3900   PpB->next = PpB->prev = NULL;
3901
3902   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3903   PpB->tregisters = NULL;
3904   PpB->visited = 0;
3905   PpB->FlowTree = NULL;
3906
3907   return PpB;
3908
3909 }
3910
3911 /*-----------------------------------------------------------------*/
3912 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3913 /*-----------------------------------------------------------------*
3914  *
3915  *  This function will create a new pBlock and the pointer to the
3916  *  pCode that is passed in will be the first pCode in the block.
3917  *-----------------------------------------------------------------*/
3918
3919
3920 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
3921 {
3922
3923   pBlock *pB  = newpBlock();
3924
3925   pB->pcHead  = pB->pcTail = pc;
3926   pB->cmemmap = cm;
3927   pB->dbName  = c;
3928
3929   return pB;
3930 }
3931
3932
3933
3934 /*-----------------------------------------------------------------*/
3935 /* pic16_newpCodeOpLabel - Create a new label given the key              */
3936 /*  Note, a negative key means that the label is part of wild card */
3937 /*  (and hence a wild card label) used in the pCodePeep            */
3938 /*   optimizations).                                               */
3939 /*-----------------------------------------------------------------*/
3940
3941 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
3942 {
3943   char *s=NULL;
3944   static int label_key=-1;
3945
3946   pCodeOp *pcop;
3947
3948   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
3949   pcop->type = PO_LABEL;
3950
3951   pcop->name = NULL;
3952
3953   if(key>0)
3954     sprintf(s=buffer,"_%05d_DS_",key);
3955   else
3956     s = name, key = label_key--;
3957
3958   if(s)
3959     pcop->name = Safe_strdup(s);
3960
3961   ((pCodeOpLabel *)pcop)->key = key;
3962
3963   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
3964   return pcop;
3965 }
3966
3967 /*-----------------------------------------------------------------*/
3968 /*-----------------------------------------------------------------*/
3969 pCodeOp *pic16_newpCodeOpLit(int lit)
3970 {
3971   char *s = buffer;
3972   pCodeOp *pcop;
3973
3974
3975   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
3976   pcop->type = PO_LITERAL;
3977
3978   pcop->name = NULL;
3979   //if(lit>=0)
3980     sprintf(s,"0x%02hhx", (unsigned char)lit);
3981   //else
3982   //  sprintf(s, "%i", lit);
3983
3984   if(s)
3985     pcop->name = Safe_strdup(s);
3986
3987   ((pCodeOpLit *)pcop)->lit = lit;
3988
3989   return pcop;
3990 }
3991
3992 /* Allow for 12 bit literals, required for LFSR */
3993 pCodeOp *pic16_newpCodeOpLit12(int lit)
3994 {
3995   char *s = buffer;
3996   pCodeOp *pcop;
3997
3998
3999   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4000   pcop->type = PO_LITERAL;
4001
4002   pcop->name = NULL;
4003   //if(lit>=0)
4004     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4005   //else
4006   //  sprintf(s, "%i", lit);
4007
4008   if(s)
4009     pcop->name = Safe_strdup(s);
4010
4011   ((pCodeOpLit *)pcop)->lit = lit;
4012
4013   return pcop;
4014 }
4015
4016 /*-----------------------------------------------------------------*/
4017 /*-----------------------------------------------------------------*/
4018 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4019 {
4020   char *s = buffer, tbuf[256], *tb=tbuf;
4021   pCodeOp *pcop;
4022
4023
4024   tb = pic16_get_op(arg2, NULL, 0);
4025   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4026   pcop->type = PO_LITERAL;
4027
4028   pcop->name = NULL;
4029   //if(lit>=0) {
4030     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4031     if(s)
4032       pcop->name = Safe_strdup(s);
4033   //}
4034
4035   ((pCodeOpLit2 *)pcop)->lit = lit;
4036   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4037
4038   return pcop;
4039 }
4040
4041 /*-----------------------------------------------------------------*/
4042 /*-----------------------------------------------------------------*/
4043 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4044 {
4045   pCodeOp *pcop;
4046
4047         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4048         pcop->type = PO_IMMEDIATE;
4049         if(name) {
4050                 regs *r = pic16_dirregWithName(name);
4051                 pcop->name = Safe_strdup(name);
4052                 PCOI(pcop)->r = r;
4053
4054                 if(r) {
4055 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4056                         PCOI(pcop)->rIdx = r->rIdx;
4057                 } else {
4058 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4059                         PCOI(pcop)->rIdx = -1;
4060                 }
4061 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4062         } else {
4063                 pcop->name = NULL;
4064                 PCOI(pcop)->rIdx = -1;
4065         }
4066
4067         PCOI(pcop)->index = index;
4068         PCOI(pcop)->offset = offset;
4069         PCOI(pcop)->_const = code_space;
4070
4071   return pcop;
4072 }
4073
4074 /*-----------------------------------------------------------------*/
4075 /*-----------------------------------------------------------------*/
4076 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4077 {
4078   char *s = buffer;
4079   pCodeOp *pcop;
4080
4081
4082   if(!pcwb || !subtype) {
4083     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4084     exit(1);
4085   }
4086
4087   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4088   pcop->type = PO_WILD;
4089   sprintf(s,"%%%d",id);
4090   pcop->name = Safe_strdup(s);
4091
4092   PCOW(pcop)->id = id;
4093   PCOW(pcop)->pcwb = pcwb;
4094   PCOW(pcop)->subtype = subtype;
4095   PCOW(pcop)->matched = NULL;
4096
4097   PCOW(pcop)->pcop2 = NULL;
4098
4099   return pcop;
4100 }
4101
4102 /*-----------------------------------------------------------------*/
4103 /*-----------------------------------------------------------------*/
4104 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4105 {
4106   char *s = buffer;
4107   pCodeOp *pcop;
4108
4109
4110         if(!pcwb || !subtype || !subtype2) {
4111                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4112                 exit(1);
4113         }
4114
4115         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4116         pcop->type = PO_WILD;
4117         sprintf(s,"%%%d",id);
4118         pcop->name = Safe_strdup(s);
4119
4120         PCOW(pcop)->id = id;
4121         PCOW(pcop)->pcwb = pcwb;
4122         PCOW(pcop)->subtype = subtype;
4123         PCOW(pcop)->matched = NULL;
4124
4125         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4126
4127         if(!subtype2->name) {
4128                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4129                 PCOW2(pcop)->pcop.type = PO_WILD;
4130                 sprintf(s, "%%%d", id2);
4131                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4132                 PCOW2(pcop)->id = id2;
4133                 PCOW2(pcop)->subtype = subtype2;
4134
4135 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4136 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4137         } else {
4138                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4139
4140 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4141 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4142         }
4143
4144
4145
4146   return pcop;
4147 }
4148
4149
4150 /*-----------------------------------------------------------------*/
4151 /*-----------------------------------------------------------------*/
4152 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4153 {
4154   pCodeOp *pcop;
4155
4156   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4157   pcop->type = PO_GPR_BIT;
4158   if(s)
4159     pcop->name = Safe_strdup(s);
4160   else
4161     pcop->name = NULL;
4162
4163   PCORB(pcop)->bit = bit;
4164   PCORB(pcop)->inBitSpace = inBitSpace;
4165   PCORB(pcop)->subtype = subt;
4166
4167   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4168   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4169 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4170 //  PCOR(pcop)->rIdx = 0;
4171   return pcop;
4172 }
4173
4174 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4175 {
4176   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4177                                 bit, 0, PO_GPR_REGISTER);
4178 }
4179
4180
4181 /*-----------------------------------------------------------------*
4182  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4183  *
4184  * If rIdx >=0 then a specific register from the set of registers
4185  * will be selected. If rIdx <0, then a new register will be searched
4186  * for.
4187  *-----------------------------------------------------------------*/
4188
4189 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4190 {
4191   pCodeOp *pcop;
4192   regs *r;
4193
4194   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4195
4196   pcop->name = NULL;
4197
4198   if(rIdx >= 0) {
4199         r = pic16_regWithIdx(rIdx);
4200         if(!r)
4201                 r = pic16_allocWithIdx(rIdx);
4202   } else {
4203     r = pic16_findFreeReg(REG_GPR);
4204
4205     if(!r) {
4206         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4207                 __FUNCTION__, __LINE__);
4208         exit(EXIT_FAILURE);
4209     }
4210   }
4211
4212   PCOR(pcop)->rIdx = rIdx;
4213   PCOR(pcop)->r = r;
4214   pcop->type = PCOR(pcop)->r->pc_type;
4215
4216   return pcop;
4217 }
4218
4219 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4220 {
4221   pCodeOp *pcop;
4222   regs *r;
4223
4224     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4225     pcop->name = NULL;
4226
4227     r = pic16_findFreeReg(REG_GPR);
4228
4229     while(r) {
4230       if(!bitVectBitValue(bv, r->rIdx)) {
4231         PCOR(pcop)->r = r;
4232         PCOR(pcop)->rIdx = r->rIdx;
4233         pcop->type = r->pc_type;
4234         return (pcop);
4235       }
4236
4237       r = pic16_findFreeRegNext(REG_GPR, r);
4238     }
4239
4240   return NULL;
4241 }
4242
4243
4244
4245 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4246 {
4247   pCodeOp *pcop;
4248   regs *r;
4249
4250         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4251         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4252         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4253         pcop->type = PCOR(pcop)->r->pc_type;
4254         pcop->name = PCOR(pcop)->r->name;
4255
4256 //      if(pic16_pcode_verbose) {
4257 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4258 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4259 //      }
4260
4261   return pcop;
4262 }
4263
4264 /*-----------------------------------------------------------------*/
4265 /*-----------------------------------------------------------------*/
4266 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4267 {
4268   pCodeOpOpt *pcop;
4269
4270         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4271
4272         pcop->type = type;
4273         pcop->key = Safe_strdup( key );
4274
4275   return (PCOP(pcop));
4276 }
4277
4278 /*-----------------------------------------------------------------*/
4279 /*-----------------------------------------------------------------*/
4280 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4281 {
4282   pCodeOpLocalReg *pcop;
4283
4284         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4285
4286         pcop->type = type;
4287
4288   return (PCOP(pcop));
4289 }
4290
4291
4292 /*-----------------------------------------------------------------*/
4293 /*-----------------------------------------------------------------*/
4294
4295 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4296 {
4297   pCodeOp *pcop;
4298
4299   switch(type) {
4300   case PO_BIT:
4301   case PO_GPR_BIT:
4302     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4303     break;
4304
4305   case PO_LITERAL:
4306     pcop = pic16_newpCodeOpLit(-1);
4307     break;
4308
4309   case PO_LABEL:
4310     pcop = pic16_newpCodeOpLabel(NULL,-1);
4311     break;
4312   case PO_GPR_TEMP:
4313     pcop = pic16_newpCodeOpReg(-1);
4314     break;
4315
4316   case PO_GPR_REGISTER:
4317     if(name)
4318       pcop = pic16_newpCodeOpRegFromStr(name);
4319     else
4320       pcop = pic16_newpCodeOpReg(-1);
4321     break;
4322
4323   case PO_TWO_OPS:
4324     assert( !"Cannot create PO_TWO_OPS from string!" );
4325     pcop = NULL;
4326     break;
4327
4328   default:
4329     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4330     pcop->type = type;
4331     if(name)
4332       pcop->name = Safe_strdup(name);
4333     else
4334       pcop->name = NULL;
4335   }
4336
4337   return pcop;
4338 }
4339
4340 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4341 {
4342   pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4343   pcop2->pcop.type = PO_TWO_OPS;
4344   pcop2->pcopL = src;
4345   pcop2->pcopR = dst;
4346   return PCOP(pcop2);
4347 }
4348
4349 /* This is a multiple of two as gpasm pads DB directives to even length,
4350  * thus the data would be interleaved with \0 bytes...
4351  * This is a multiple of three in order to have arrays of 3-byte pointers
4352  * continuously in memory (without 0-padding at the lines' end).
4353  * This is rather 12 than 6 in order not to split up 4-byte data types
4354  * in arrays right in the middle of a 4-byte word. */
4355 #define DB_ITEMS_PER_LINE       12
4356
4357 typedef struct DBdata
4358   {
4359     int count;
4360     char buffer[512];
4361   } DBdata;
4362
4363 struct DBdata DBd;
4364 static int DBd_init = -1;
4365
4366 /*-----------------------------------------------------------------*/
4367 /*    Initialiase "DB" data buffer                                 */
4368 /*-----------------------------------------------------------------*/
4369 void pic16_initDB(void)
4370 {
4371         DBd_init = -1;
4372 }
4373
4374
4375 /*-----------------------------------------------------------------*/
4376 /*    Flush pending "DB" data to a pBlock                          */
4377 /*                                                                 */
4378 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4379 /*-----------------------------------------------------------------*/
4380 void pic16_flushDB(char ptype, void *p)
4381 {
4382         if (DBd.count>0) {
4383                 if(ptype == 'p')
4384                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4385                 else
4386                 if(ptype == 'f')
4387                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4388                 else {
4389                         /* sanity check */
4390                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4391                 }
4392
4393                 DBd.count = 0;
4394                 DBd.buffer[0] = '\0';
4395         }
4396 }
4397
4398
4399 /*-----------------------------------------------------------------*/
4400 /*    Add "DB" directives to a pBlock                              */
4401 /*-----------------------------------------------------------------*/
4402 void pic16_emitDB(int c, char ptype, void *p)
4403 {
4404   int l;
4405
4406         if (DBd_init<0) {
4407          // we need to initialize
4408                 DBd_init = 0;
4409                 DBd.count = 0;
4410                 DBd.buffer[0] = '\0';
4411         }
4412
4413         l = strlen(DBd.buffer);
4414         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4415
4416 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4417
4418         DBd.count++;
4419         if (DBd.count>= DB_ITEMS_PER_LINE)
4420                 pic16_flushDB(ptype, p);
4421 }
4422
4423 void pic16_emitDS(char *s, char ptype, void *p)
4424 {
4425   int l;
4426
4427         if (DBd_init<0) {
4428          // we need to initialize
4429                 DBd_init = 0;
4430                 DBd.count = 0;
4431                 DBd.buffer[0] = '\0';
4432         }
4433
4434         l = strlen(DBd.buffer);
4435         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4436
4437 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4438
4439         DBd.count++;    //=strlen(s);
4440         if (DBd.count>=DB_ITEMS_PER_LINE)
4441                 pic16_flushDB(ptype, p);
4442 }
4443
4444
4445 /*-----------------------------------------------------------------*/
4446 /*-----------------------------------------------------------------*/
4447 void pic16_pCodeConstString(char *name, char *value, unsigned length)
4448 {
4449   pBlock *pb;
4450   char *item;
4451   static set *emittedSymbols = NULL;
4452
4453   if(!name || !value)
4454     return;
4455
4456   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4457   if (emittedSymbols) {
4458     /* scan set for name */
4459     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4460     {
4461       if (!strcmp (item,name)) {
4462         //fprintf (stderr, "%s already emitted\n", name);
4463         return;
4464       } // if
4465     } // for
4466   } // if
4467   addSet (&emittedSymbols, Safe_strdup (name));
4468
4469   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4470
4471   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4472
4473   pic16_addpBlock(pb);
4474
4475 //  sprintf(buffer,"; %s = ", name);
4476 //  strcat(buffer, value);
4477 //  fputs(buffer, stderr);
4478
4479 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4480   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4481
4482   while (length--)
4483     pic16_emitDB(*value++, 'p', (void *)pb);
4484
4485   pic16_flushDB('p', (void *)pb);
4486 }
4487
4488 /*-----------------------------------------------------------------*/
4489 /*-----------------------------------------------------------------*/
4490 #if 0
4491 static void pCodeReadCodeTable(void)
4492 {
4493   pBlock *pb;
4494
4495   fprintf(stderr, " %s\n",__FUNCTION__);
4496
4497   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4498
4499   pic16_addpBlock(pb);
4500
4501   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4502   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4503   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4504   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4505
4506   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4507   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4508   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4509   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4510
4511
4512 }
4513 #endif
4514 /*-----------------------------------------------------------------*/
4515 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4516 /*-----------------------------------------------------------------*/
4517 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4518 {
4519
4520   if(!pc)
4521     return;
4522
4523   if(!pb->pcHead) {
4524     /* If this is the first pcode to be added to a block that
4525      * was initialized with a NULL pcode, then go ahead and
4526      * make this pcode the head and tail */
4527     pb->pcHead  = pb->pcTail = pc;
4528   } else {
4529     //    if(pb->pcTail)
4530     pb->pcTail->next = pc;
4531
4532     pc->prev = pb->pcTail;
4533     pc->pb = pb;
4534
4535     pb->pcTail = pc;
4536   }
4537 }
4538
4539 /*-----------------------------------------------------------------*/
4540 /* pic16_addpBlock - place a pBlock into the pFile                 */
4541 /*-----------------------------------------------------------------*/
4542 void pic16_addpBlock(pBlock *pb)
4543 {
4544   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4545
4546   if(!the_pFile) {
4547     /* First time called, we'll pass through here. */
4548     //_ALLOC(the_pFile,sizeof(pFile));
4549     the_pFile = Safe_calloc(1,sizeof(pFile));
4550     the_pFile->pbHead = the_pFile->pbTail = pb;
4551     the_pFile->functions = NULL;
4552     return;
4553   }
4554
4555   the_pFile->pbTail->next = pb;
4556   pb->prev = the_pFile->pbTail;
4557   pb->next = NULL;
4558   the_pFile->pbTail = pb;
4559 }
4560
4561 /*-----------------------------------------------------------------*/
4562 /* removepBlock - remove a pBlock from the pFile                   */
4563 /*-----------------------------------------------------------------*/
4564 static void removepBlock(pBlock *pb)
4565 {
4566   pBlock *pbs;
4567
4568   if(!the_pFile)
4569     return;
4570
4571
4572   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4573
4574   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4575     if(pbs == pb) {
4576
4577       if(pbs == the_pFile->pbHead)
4578         the_pFile->pbHead = pbs->next;
4579
4580       if (pbs == the_pFile->pbTail)
4581         the_pFile->pbTail = pbs->prev;
4582
4583       if(pbs->next)
4584         pbs->next->prev = pbs->prev;
4585
4586       if(pbs->prev)
4587         pbs->prev->next = pbs->next;
4588
4589       return;
4590
4591     }
4592   }
4593
4594   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4595
4596 }
4597
4598 /*-----------------------------------------------------------------*/
4599 /* printpCode - write the contents of a pCode to a file            */
4600 /*-----------------------------------------------------------------*/
4601 static void printpCode(FILE *of, pCode *pc)
4602 {
4603
4604   if(!pc || !of)
4605     return;
4606
4607   if(pc->print) {
4608     pc->print(of,pc);
4609     return;
4610   }
4611
4612   fprintf(of,"warning - unable to print pCode\n");
4613 }
4614
4615 /*-----------------------------------------------------------------*/
4616 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4617 /*-----------------------------------------------------------------*/
4618 void pic16_printpBlock(FILE *of, pBlock *pb)
4619 {
4620   pCode *pc;
4621
4622         if(!pb)return;
4623
4624         if(!of)of=stderr;
4625
4626         for(pc = pb->pcHead; pc; pc = pc->next) {
4627                 if(isPCF(pc) && PCF(pc)->fname) {
4628                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4629                         if(pb->dbName == 'A') {
4630                           absSym *ab;
4631                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4632 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4633                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4634 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4635                                                 if(ab->address != -1)
4636                                                   fprintf(of, "\t0X%06X", ab->address);
4637                                                 break;
4638                                         }
4639                                 }
4640                         }
4641                         fprintf(of, "\n");
4642                 }
4643                 printpCode(of,pc);
4644         }
4645 }
4646
4647 /*-----------------------------------------------------------------*/
4648 /*                                                                 */
4649 /*       pCode processing                                          */
4650 /*                                                                 */
4651 /*                                                                 */
4652 /*                                                                 */
4653 /*-----------------------------------------------------------------*/
4654 pCode * pic16_findNextInstruction(pCode *pci);
4655 pCode * pic16_findPrevInstruction(pCode *pci);
4656
4657 void pic16_unlinkpCode(pCode *pc)
4658 {
4659   pCode *prev;
4660
4661   if(pc) {
4662 #ifdef PCODE_DEBUG
4663     fprintf(stderr,"Unlinking: ");
4664     printpCode(stderr, pc);
4665 #endif
4666     if(pc->prev) {
4667       pc->prev->next = pc->next;
4668     } else if (pc->pb && (pc->pb->pcHead == pc)) {
4669         pc->pb->pcHead = pc->next;
4670     }
4671     if(pc->next) {
4672       pc->next->prev = pc->prev;
4673     } else if (pc->pb && (pc->pb->pcTail == pc)) {
4674         pc->pb->pcTail = pc->prev;
4675     }
4676
4677     /* move C source line down (or up) */
4678     if (isPCI(pc) && PCI(pc)->cline) {
4679       prev = pic16_findNextInstruction (pc->next);
4680       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4681         PCI(prev)->cline = PCI(pc)->cline;
4682       } else {
4683         prev = pic16_findPrevInstruction (pc->prev);
4684         if (prev && isPCI(prev) && !PCI(prev)->cline)
4685           PCI(prev)->cline = PCI(pc)->cline;
4686       }
4687     }
4688     pc->prev = pc->next = NULL;
4689   }
4690 }
4691
4692 /*-----------------------------------------------------------------*/
4693 /*-----------------------------------------------------------------*/
4694
4695 static void genericDestruct(pCode *pc)
4696 {
4697
4698   pic16_unlinkpCode(pc);
4699
4700   if(isPCI(pc)) {
4701     /* For instructions, tell the register (if there's one used)
4702      * that it's no longer needed */
4703     regs *reg = pic16_getRegFromInstruction(pc);
4704     if(reg)
4705       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4706
4707         if(PCI(pc)->is2MemOp) {
4708                 reg = pic16_getRegFromInstruction2(pc);
4709                 if(reg)
4710                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4711         }
4712   }
4713
4714   /* Instead of deleting the memory used by this pCode, mark
4715    * the object as bad so that if there's a pointer to this pCode
4716    * dangling around somewhere then (hopefully) when the type is
4717    * checked we'll catch it.
4718    */
4719
4720   pc->type = PC_BAD;
4721   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4722
4723   //Safe_free(pc);
4724 }
4725
4726
4727 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4728 /*-----------------------------------------------------------------*/
4729 /*-----------------------------------------------------------------*/
4730 /* modifiers for constant immediate */
4731 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4732
4733 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4734 {
4735     regs *r;
4736     static char b[128];
4737     char *s;
4738     int use_buffer = 1;    // copy the string to the passed buffer pointer
4739
4740     if(!buffer) {
4741         buffer = b;
4742         size = sizeof(b);
4743         use_buffer = 0;     // Don't bother copying the string to the buffer.
4744     }
4745
4746     if(pcop) {
4747
4748         switch(pcop->type) {
4749             case PO_W:
4750             case PO_WREG:
4751             case PO_PRODL:
4752             case PO_PRODH:
4753             case PO_INDF0:
4754             case PO_FSR0:
4755                 if(use_buffer) {
4756                     SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4757                     return (buffer);
4758                 }
4759                 return (PCOR(pcop)->r->name);
4760                 break;
4761             case PO_GPR_TEMP:
4762                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4763                 if(use_buffer) {
4764                     SNPRINTF(buffer,size,"%s",r->name);
4765                     return (buffer);
4766                 }
4767                 return (r->name);
4768                 break;
4769
4770             case PO_IMMEDIATE:
4771                 s = buffer;
4772                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4773                     if(PCOI(pcop)->index) {
4774                         SNPRINTF(s,size, "%s(%s + %d)",
4775                                 immdmod[ PCOI(pcop)->offset ],
4776                                 pcop->name,
4777                                 PCOI(pcop)->index);
4778                     } else {
4779                         SNPRINTF(s,size,"%s(%s)",
4780                                 immdmod[ PCOI(pcop)->offset ],
4781                                 pcop->name);
4782                     }
4783                 } else {
4784                     if(PCOI(pcop)->index) {
4785                         SNPRINTF(s,size, "%s(%s + %d)",
4786                                 immdmod[ 0 ],
4787                                 pcop->name,
4788                                 PCOI(pcop)->index);
4789                     } else {
4790                         SNPRINTF(s,size, "%s(%s)",
4791                                 immdmod[ 0 ],
4792                                 pcop->name);
4793                     }
4794                 }
4795                 return (buffer);
4796                 break;
4797
4798             case PO_GPR_REGISTER:
4799             case PO_DIR:
4800                 s = buffer;
4801                 //size = sizeof(buffer);
4802                 if( PCOR(pcop)->instance) {
4803                     SNPRINTF(s,size,"(%s + %d)",
4804                             pcop->name,
4805                             PCOR(pcop)->instance );
4806                 } else {
4807                     SNPRINTF(s,size,"%s",pcop->name);
4808                 }
4809                 return (buffer);
4810                 break;
4811
4812             case PO_GPR_BIT:
4813                 s = buffer;
4814                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4815                     SNPRINTF(s, size, "%s", pcop->name);
4816                 } else {
4817                     if(PCORB(pcop)->pcor.instance)
4818                         SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4819                     else
4820                         SNPRINTF(s, size, "%s", pcop->name);
4821                 }
4822                 return (buffer);
4823                 break;
4824
4825             case PO_TWO_OPS:
4826                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4827                 break;
4828
4829             default:
4830                 if(pcop->name) {
4831                     if(use_buffer) {
4832                         SNPRINTF(buffer,size,"%s",pcop->name);
4833                         return (buffer);
4834                     }
4835                     return (pcop->name);
4836                 }
4837
4838         }
4839         return ("unhandled type for op1");
4840     }
4841
4842     return ("NO operand1");
4843 }
4844
4845 /*-----------------------------------------------------------------*/
4846 /* pic16_get_op2 - variant to support two memory operand commands  */
4847 /*-----------------------------------------------------------------*/
4848 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4849 {
4850
4851   if(pcop && pcop->type == PO_TWO_OPS) {
4852     return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4853   }
4854
4855   return "NO operand2";
4856 }
4857
4858 /*-----------------------------------------------------------------*/
4859 /*-----------------------------------------------------------------*/
4860 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4861 {
4862
4863   if(pcc )
4864     return pic16_get_op(pcc->pcop,NULL,0);
4865
4866   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated
4867    *   return ("ERROR Null: "__FUNCTION__);
4868    */
4869   return ("ERROR Null: pic16_get_op_from_instruction");
4870
4871 }
4872
4873 /*-----------------------------------------------------------------*/
4874 /*-----------------------------------------------------------------*/
4875 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4876 {
4877
4878   fprintf(of,"pcodeopprint- not implemented\n");
4879 }
4880
4881 /*-----------------------------------------------------------------*/
4882 /* pic16_pCode2str - convert a pCode instruction to string               */
4883 /*-----------------------------------------------------------------*/
4884 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4885 {
4886     char *s = str;
4887     regs *r;
4888
4889 #if 0
4890     if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4891         fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4892                 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4893         //              exit(EXIT_FAILURE);
4894     }
4895 #endif
4896
4897     switch(pc->type) {
4898
4899         case PC_OPCODE:
4900             SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
4901             size -= strlen(s);
4902             s += strlen(s);
4903
4904             if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4905
4906                 if (PCI(pc)->pcop->type == PO_TWO_OPS)
4907                 {
4908                     /* split into two phases due to static buffer in pic16_get_op() */
4909                     SNPRINTF(s, size, "%s",
4910                             pic16_get_op((PCI(pc)->pcop), NULL, 0));
4911                     size -= strlen(s);
4912                     s += strlen(s);
4913                     SNPRINTF(s, size, ", %s",
4914                             pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4915                     break;
4916                 }
4917
4918                 if(PCI(pc)->is2LitOp) {
4919                     SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
4920                     break;
4921                 }
4922
4923                 if(PCI(pc)->isBitInst) {
4924                     if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4925                         if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4926                             SNPRINTF(s,size,"(%s >> 3), (%s & 7)",
4927                                     PCI(pc)->pcop->name ,
4928                                     PCI(pc)->pcop->name );
4929                         else
4930                             SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4931                                     (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4932
4933                     } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4934                         SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
4935                     } else
4936                         SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
4937                 } else {
4938
4939                     if(PCI(pc)->pcop->type == PO_GPR_BIT) {
4940                         if( PCI(pc)->num_ops == 3)
4941                             SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
4942                         else
4943                             SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
4944                     } else {
4945                         SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
4946                     }
4947                 }
4948
4949                 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
4950                     size -= strlen(s);
4951                     s += strlen(s);
4952                     if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
4953                         SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
4954                         size -= strlen(s);
4955                         s += strlen(s);
4956                     }
4957
4958                     r = pic16_getRegFromInstruction(pc);
4959
4960                     if(PCI(pc)->isAccess) {
4961                         static char *bank_spec[2][2] = {
4962                             { "", ", ACCESS" },  /* gpasm uses access bank by default */
4963                             { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
4964                         };
4965
4966                         SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
4967                     }
4968                 }
4969             }
4970             break;
4971
4972         case PC_COMMENT:
4973             /* assuming that comment ends with a \n */
4974             SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
4975             break;
4976
4977         case PC_INFO:
4978             SNPRINTF(s,size,"; info ==>");
4979             size -= strlen(s);
4980             s += strlen(s);
4981             switch( PCINF(pc)->type ) {
4982                 case INF_OPTIMIZATION:
4983                     SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
4984                     break;
4985                 case INF_LOCALREGS:
4986                     SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
4987                     break;
4988             }; break;
4989
4990         case PC_INLINE:
4991             /* assuming that inline code ends with a \n */
4992             SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
4993             break;
4994
4995         case PC_LABEL:
4996             SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
4997             break;
4998         case PC_FUNCTION:
4999             SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5000             break;
5001         case PC_WILD:
5002             SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5003             break;
5004         case PC_FLOW:
5005             SNPRINTF(s,size,";\t--FLOW change\n");
5006             break;
5007         case PC_CSOURCE:
5008             SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5009                     PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5010             break;
5011         case PC_ASMDIR:
5012             if(PCAD(pc)->directive) {
5013                 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5014             } else
5015                 if(PCAD(pc)->arg) {
5016                     /* special case to handle inline labels without a tab */
5017                     SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5018                 }
5019             break;
5020
5021         case PC_BAD:
5022             SNPRINTF(s,size,";A bad pCode is being used\n");
5023             break;
5024     }
5025
5026     return str;
5027 }
5028
5029 /*-----------------------------------------------------------------*/
5030 /* genericPrint - the contents of a pCode to a file                */
5031 /*-----------------------------------------------------------------*/
5032 static void genericPrint(FILE *of, pCode *pc)
5033 {
5034
5035   if(!pc || !of)
5036     return;
5037
5038   switch(pc->type) {
5039   case PC_COMMENT:
5040 //    fputs(((pCodeComment *)pc)->comment, of);
5041     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5042     break;
5043
5044   case PC_INFO:
5045     {
5046       pBranch *pbl = PCI(pc)->label;
5047       while(pbl && pbl->pc) {
5048         if(pbl->pc->type == PC_LABEL)
5049           pCodePrintLabel(of, pbl->pc);
5050         pbl = pbl->next;
5051       }
5052     }
5053
5054     if(pic16_pcode_verbose) {
5055       fprintf(of, "; info ==>");
5056       switch(((pCodeInfo *)pc)->type) {
5057         case INF_OPTIMIZATION:
5058               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5059               break;
5060         case INF_LOCALREGS:
5061               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5062               break;
5063         }
5064     };
5065
5066     break;
5067
5068   case PC_INLINE:
5069     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5070      break;
5071
5072   case PC_OPCODE:
5073     // If the opcode has a label, print that first
5074     {
5075       pBranch *pbl = PCI(pc)->label;
5076       while(pbl && pbl->pc) {
5077         if(pbl->pc->type == PC_LABEL)
5078           pCodePrintLabel(of, pbl->pc);
5079         pbl = pbl->next;
5080       }
5081     }
5082
5083     if(PCI(pc)->cline)
5084       genericPrint(of,PCODE(PCI(pc)->cline));
5085
5086     {
5087       char str[256];
5088
5089       pic16_pCode2str(str, 256, pc);
5090
5091       fprintf(of,"%s",str);
5092       /* Debug */
5093       if(pic16_debug_verbose) {
5094         fprintf(of, "\t;key=%03x",pc->seq);
5095         if(PCI(pc)->pcflow)
5096           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5097       }
5098     }
5099     fprintf(of, "\n");
5100     break;
5101
5102   case PC_WILD:
5103     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5104     if(PCW(pc)->pci.label)
5105       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5106
5107     if(PCW(pc)->operand) {
5108       fprintf(of,";\toperand  ");
5109       pCodeOpPrint(of,PCW(pc)->operand );
5110     }
5111     break;
5112
5113   case PC_FLOW:
5114     if(pic16_debug_verbose) {
5115       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5116       if(PCFL(pc)->ancestor)
5117         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5118       fprintf(of,"\n");
5119
5120     }
5121     break;
5122
5123   case PC_CSOURCE:
5124 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5125     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5126         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5127
5128     break;
5129
5130   case PC_ASMDIR:
5131         {
5132           pBranch *pbl = PCAD(pc)->pci.label;
5133                 while(pbl && pbl->pc) {
5134                         if(pbl->pc->type == PC_LABEL)
5135                                 pCodePrintLabel(of, pbl->pc);
5136                         pbl = pbl->next;
5137                 }
5138         }
5139         if(PCAD(pc)->directive) {
5140                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5141         } else
5142         if(PCAD(pc)->arg) {
5143                 /* special case to handle inline labels without tab */
5144                 fprintf(of, "%s\n", PCAD(pc)->arg);
5145         }
5146         break;
5147
5148   case PC_LABEL:
5149   default:
5150     fprintf(of,"unknown pCode type %d\n",pc->type);
5151   }
5152
5153 }
5154
5155 /*-----------------------------------------------------------------*/
5156 /* pCodePrintFunction - prints function begin/end                  */
5157 /*-----------------------------------------------------------------*/
5158
5159 static void pCodePrintFunction(FILE *of, pCode *pc)
5160 {
5161
5162   if(!pc || !of)
5163     return;
5164
5165 #if 0
5166   if( ((pCodeFunction *)pc)->modname)
5167     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5168 #endif
5169
5170   if(!PCF(pc)->absblock) {
5171       if(PCF(pc)->fname) {
5172       pBranch *exits = PCF(pc)->to;
5173       int i=0;
5174
5175       fprintf(of,"%s:", PCF(pc)->fname);
5176
5177       if(pic16_pcode_verbose)
5178         fprintf(of, "\t;Function start");
5179
5180       fprintf(of, "\n");
5181
5182       while(exits) {
5183         i++;
5184         exits = exits->next;
5185       }
5186       //if(i) i--;
5187
5188       if(pic16_pcode_verbose)
5189         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5190
5191     } else {
5192         if((PCF(pc)->from &&
5193                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5194                 PCF(PCF(pc)->from->pc)->fname) ) {
5195
5196                 if(pic16_pcode_verbose)
5197                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5198         } else {
5199                 if(pic16_pcode_verbose)
5200                         fprintf(of,"; exit point [can't find entry point]\n");
5201         }
5202         fprintf(of, "\n");
5203     }
5204   }
5205 }
5206 /*-----------------------------------------------------------------*/
5207 /* pCodePrintLabel - prints label                                  */
5208 /*-----------------------------------------------------------------*/
5209
5210 static void pCodePrintLabel(FILE *of, pCode *pc)
5211 {
5212
5213   if(!pc || !of)
5214     return;
5215
5216   if(PCL(pc)->label)
5217     fprintf(of,"%s:\n",PCL(pc)->label);
5218   else if (PCL(pc)->key >=0)
5219     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5220   else
5221     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5222
5223 }
5224 /*-----------------------------------------------------------------*/
5225 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5226 /*                         remove it if it is found.               */
5227 /*-----------------------------------------------------------------*/
5228 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5229 {
5230   pBranch *b, *bprev;
5231
5232
5233   bprev = NULL;
5234
5235   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5236     b = PCI(pcl)->label;
5237   else {
5238     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5239     exit(1);
5240
5241   }
5242
5243   //fprintf (stderr, "%s \n",__FUNCTION__);
5244   //pcl->print(stderr,pcl);
5245   //pc->print(stderr,pc);
5246   while(b) {
5247     if(b->pc == pc) {
5248       //fprintf (stderr, "found label\n");
5249       //pc->print(stderr, pc);
5250
5251       /* Found a label */
5252       if(bprev) {
5253         bprev->next = b->next;  /* Not first pCode in chain */
5254 //      Safe_free(b);
5255       } else {
5256         pc->destruct(pc);
5257         PCI(pcl)->label = b->next;   /* First pCode in chain */
5258 //      Safe_free(b);
5259       }
5260       return;  /* A label can't occur more than once */
5261     }
5262     bprev = b;
5263     b = b->next;
5264   }
5265
5266 }
5267
5268 /*-----------------------------------------------------------------*/
5269 /*-----------------------------------------------------------------*/
5270 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5271 {
5272   pBranch *b;
5273
5274   if(!h)
5275     return n;
5276
5277   if(h == n)
5278     return n;
5279
5280   b = h;
5281   while(b->next)
5282     b = b->next;
5283
5284   b->next = n;
5285
5286   return h;
5287
5288 }
5289 /*-----------------------------------------------------------------*/
5290 /* pBranchLink - given two pcodes, this function will link them    */
5291 /*               together through their pBranches                  */
5292 /*-----------------------------------------------------------------*/
5293 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5294 {
5295   pBranch *b;
5296
5297   // Declare a new branch object for the 'from' pCode.
5298
5299   //_ALLOC(b,sizeof(pBranch));
5300   b = Safe_calloc(1,sizeof(pBranch));
5301   b->pc = PCODE(t);             // The link to the 'to' pCode.
5302   b->next = NULL;
5303
5304   f->to = pic16_pBranchAppend(f->to,b);
5305
5306   // Now do the same for the 'to' pCode.
5307
5308   //_ALLOC(b,sizeof(pBranch));
5309   b = Safe_calloc(1,sizeof(pBranch));
5310   b->pc = PCODE(f);
5311   b->next = NULL;
5312
5313   t->from = pic16_pBranchAppend(t->from,b);
5314
5315 }
5316
5317 #if 1
5318 /*-----------------------------------------------------------------*/
5319 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5320 /*               a pCode                                           */
5321 /*-----------------------------------------------------------------*/
5322 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5323 {
5324   while(pb) {
5325
5326     if(pb->pc == pc)
5327       return pb;
5328
5329     pb = pb->next;
5330   }
5331
5332   return NULL;
5333 }
5334
5335 /*-----------------------------------------------------------------*/
5336 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5337 /*-----------------------------------------------------------------*/
5338 void pic16_pCodeUnlink(pCode *pc)
5339 {
5340   pBranch *pb1,*pb2;
5341   pCode *pc1;
5342
5343   if (!pc) {
5344     return;
5345   }
5346
5347   /* Remove the branches */
5348
5349   pb1 = PCI(pc)->from;
5350   while(pb1) {
5351     pc1 = pb1->pc;    /* Get the pCode that branches to the
5352                        * one we're unlinking */
5353
5354     /* search for the link back to this pCode (the one we're
5355      * unlinking) */
5356     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5357       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5358
5359       /* if the pCode we're unlinking contains multiple 'to'
5360        * branches (e.g. this a skip instruction) then we need
5361        * to copy these extra branches to the chain. */
5362       if(PCI(pc)->to->next)
5363         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5364     }
5365
5366     pb1 = pb1->next;
5367   }
5368
5369   pic16_unlinkpCode (pc);
5370
5371 }
5372 #endif
5373 /*-----------------------------------------------------------------*/
5374 /*-----------------------------------------------------------------*/
5375 #if 0
5376 static void genericAnalyze(pCode *pc)
5377 {
5378   switch(pc->type) {
5379   case PC_WILD:
5380   case PC_COMMENT:
5381     return;
5382   case PC_LABEL:
5383   case PC_FUNCTION:
5384   case PC_OPCODE:
5385     {
5386       // Go through the pCodes that are in pCode chain and link
5387       // them together through the pBranches. Note, the pCodes
5388       // are linked together as a contiguous stream like the
5389       // assembly source code lines. The linking here mimics this
5390       // except that comments are not linked in.
5391       //
5392       pCode *npc = pc->next;
5393       while(npc) {
5394         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5395           pBranchLink(pc,npc);
5396           return;
5397         } else
5398           npc = npc->next;
5399       }
5400       /* reached the end of the pcode chain without finding
5401        * an instruction we could link to. */
5402     }
5403     break;
5404   case PC_FLOW:
5405     fprintf(stderr,"analyze PC_FLOW\n");
5406
5407     return;
5408   case PC_BAD:
5409     fprintf(stderr,,";A bad pCode is being used\n");
5410
5411   }
5412 }
5413 #endif
5414
5415 /*-----------------------------------------------------------------*/
5416 /*-----------------------------------------------------------------*/
5417 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5418 {
5419   pBranch *pbr;
5420
5421   if(pc->type == PC_LABEL) {
5422     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5423       return TRUE;
5424   }
5425   if((pc->type == PC_OPCODE)
5426         || (pc->type == PC_ASMDIR)
5427         ) {
5428     pbr = PCI(pc)->label;
5429     while(pbr) {
5430       if(pbr->pc->type == PC_LABEL) {
5431         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5432           return TRUE;
5433       }
5434       pbr = pbr->next;
5435     }
5436   }
5437
5438   return FALSE;
5439 }
5440
5441 /*-----------------------------------------------------------------*/
5442 /*-----------------------------------------------------------------*/
5443 static int checkLabel(pCode *pc)
5444 {
5445   pBranch *pbr;
5446
5447   if(pc && isPCI(pc)) {
5448     pbr = PCI(pc)->label;
5449     while(pbr) {
5450       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5451         return TRUE;
5452
5453       pbr = pbr->next;
5454     }
5455   }
5456
5457   return FALSE;
5458 }
5459
5460 /*-----------------------------------------------------------------*/
5461 /* findLabelinpBlock - Search the pCode for a particular label     */
5462 /*-----------------------------------------------------------------*/
5463 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5464 {
5465   pCode  *pc;
5466
5467   if(!pb)
5468     return NULL;
5469
5470   for(pc = pb->pcHead; pc; pc = pc->next)
5471     if(compareLabel(pc,pcop_label))
5472       return pc;
5473
5474   return NULL;
5475 }
5476 #if 0
5477 /*-----------------------------------------------------------------*/
5478 /* findLabel - Search the pCode for a particular label             */
5479 /*-----------------------------------------------------------------*/
5480 static pCode * findLabel(pCodeOpLabel *pcop_label)
5481 {
5482   pBlock *pb;
5483   pCode  *pc;
5484
5485   if(!the_pFile)
5486     return NULL;
5487
5488   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5489     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5490       return pc;
5491   }
5492
5493   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5494   return NULL;
5495 }
5496 #endif
5497 /*-----------------------------------------------------------------*/
5498 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5499 /*                 in the linked list                              */
5500 /*-----------------------------------------------------------------*/
5501 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5502 {
5503
5504   while(pc) {
5505     if(pc->type == pct)
5506       return pc;
5507
5508     pc = pc->next;
5509   }
5510
5511   return NULL;
5512 }
5513
5514 /*-----------------------------------------------------------------*/
5515 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5516 /*                 in the linked list                              */
5517 /*-----------------------------------------------------------------*/
5518 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5519 {
5520
5521   while(pc) {
5522     if(pc->type == pct)
5523       return pc;
5524
5525     pc = pc->prev;
5526   }
5527
5528   return NULL;
5529 }
5530
5531
5532 //#define PCODE_DEBUG
5533 /*-----------------------------------------------------------------*/
5534 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5535 /*                       in the linked list                        */
5536 /*-----------------------------------------------------------------*/
5537 pCode * pic16_findNextInstruction(pCode *pci)
5538 {
5539   pCode *pc = pci;
5540
5541   while(pc) {
5542     if((pc->type == PC_OPCODE)
5543         || (pc->type == PC_WILD)
5544         || (pc->type == PC_ASMDIR)
5545         )
5546       return pc;
5547
5548 #ifdef PCODE_DEBUG
5549     fprintf(stderr,"pic16_findNextInstruction:  ");
5550     printpCode(stderr, pc);
5551 #endif
5552     pc = pc->next;
5553   }
5554
5555   //fprintf(stderr,"Couldn't find instruction\n");
5556   return NULL;
5557 }
5558
5559 /*-----------------------------------------------------------------*/
5560 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5561 /*                       in the linked list                        */
5562 /*-----------------------------------------------------------------*/
5563 pCode * pic16_findPrevInstruction(pCode *pci)
5564 {
5565   pCode *pc = pci;
5566
5567   while(pc) {
5568
5569     if((pc->type == PC_OPCODE)
5570         || (pc->type == PC_WILD)
5571         || (pc->type == PC_ASMDIR)
5572         )
5573       return pc;
5574
5575
5576 #ifdef PCODE_DEBUG
5577     fprintf(stderr,"pic16_findPrevInstruction:  ");
5578     printpCode(stderr, pc);
5579 #endif
5580     pc = pc->prev;
5581   }
5582
5583   //fprintf(stderr,"Couldn't find instruction\n");
5584   return NULL;
5585 }
5586
5587 #undef PCODE_DEBUG
5588
5589 #if 0
5590 /*-----------------------------------------------------------------*/
5591 /* findFunctionEnd - given a pCode find the end of the function    */
5592 /*                   that contains it                              */
5593 /*-----------------------------------------------------------------*/
5594 static pCode * findFunctionEnd(pCode *pc)
5595 {
5596
5597   while(pc) {
5598     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5599       return pc;
5600
5601     pc = pc->next;
5602   }
5603
5604   fprintf(stderr,"Couldn't find function end\n");
5605   return NULL;
5606 }
5607 #endif
5608 #if 0
5609 /*-----------------------------------------------------------------*/
5610 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5611 /*                instruction with which it is associated.         */
5612 /*-----------------------------------------------------------------*/
5613 static void AnalyzeLabel(pCode *pc)
5614 {
5615
5616   pic16_pCodeUnlink(pc);
5617
5618 }
5619 #endif
5620
5621 #if 0
5622 static void AnalyzeGOTO(pCode *pc)
5623 {
5624
5625   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5626
5627 }
5628
5629 static void AnalyzeSKIP(pCode *pc)
5630 {
5631
5632   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5633   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5634
5635 }
5636
5637 static void AnalyzeRETURN(pCode *pc)
5638 {
5639
5640   //  branch_link(pc,findFunctionEnd(pc->next));
5641
5642 }
5643
5644 #endif
5645
5646 /*-------------------------------------------------------------------*/
5647 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5648 /*                            if one is present. This is the common  */
5649 /*                            part of pic16_getRegFromInstruction(2) */
5650 /*-------------------------------------------------------------------*/
5651
5652 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5653   if (!pcop) return NULL;
5654
5655   switch(pcop->type) {
5656   case PO_PRODL:
5657   case PO_PRODH:
5658   case PO_INDF0:
5659   case PO_FSR0:
5660   case PO_W:
5661   case PO_WREG:
5662   case PO_STATUS:
5663   case PO_INTCON:
5664   case PO_PCL:
5665   case PO_PCLATH:
5666   case PO_PCLATU:
5667   case PO_BSR:
5668     return PCOR(pcop)->r;
5669
5670   case PO_SFR_REGISTER:
5671     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5672     return PCOR(pcop)->r;
5673
5674   case PO_BIT:
5675   case PO_GPR_TEMP:
5676 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5677     return PCOR(pcop)->r;
5678
5679   case PO_IMMEDIATE:
5680 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5681
5682     if(PCOI(pcop)->r)
5683       return (PCOI(pcop)->r);
5684     else
5685       return NULL;
5686
5687   case PO_GPR_BIT:
5688     return PCOR(pcop)->r;
5689
5690   case PO_GPR_REGISTER:
5691   case PO_DIR:
5692 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5693     return PCOR(pcop)->r;
5694
5695   case PO_LITERAL:
5696     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5697     break;
5698
5699   case PO_REL_ADDR:
5700   case PO_LABEL:
5701     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5702     break;
5703
5704   case PO_CRY:
5705   case PO_STR:
5706     /* this should never turn up */
5707     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5708     break;
5709
5710   case PO_WILD:
5711     break;
5712
5713   case PO_TWO_OPS:
5714     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5715     break;
5716
5717   default:
5718         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5719 //      assert( 0 );
5720         break;
5721   }
5722
5723   return NULL;
5724 }
5725
5726 /*-----------------------------------------------------------------*/
5727 /*-----------------------------------------------------------------*/
5728 regs * pic16_getRegFromInstruction(pCode *pc)
5729 {
5730   if(!pc                   ||
5731      !isPCI(pc)            ||
5732      !PCI(pc)->pcop        ||
5733      PCI(pc)->num_ops == 0 ||
5734      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5735     return NULL;
5736
5737 #if 0
5738   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5739         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5740 #endif
5741
5742   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5743 }
5744
5745 /*-------------------------------------------------------------------------------*/
5746 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5747 /*-------------------------------------------------------------------------------*/
5748 regs * pic16_getRegFromInstruction2(pCode *pc)
5749 {
5750
5751   if(!pc                   ||
5752      !isPCI(pc)            ||
5753      !PCI(pc)->pcop        ||
5754      PCI(pc)->num_ops == 0 ||
5755      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5756     return NULL;
5757
5758   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5759     return NULL;
5760
5761 #if 0
5762   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5763         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5764 #endif
5765
5766   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5767 }
5768
5769 /*-----------------------------------------------------------------*/
5770 /*-----------------------------------------------------------------*/
5771
5772 static void AnalyzepBlock(pBlock *pb)
5773 {
5774   pCode *pc;
5775
5776   if(!pb)
5777     return;
5778
5779   /* Find all of the registers used in this pBlock
5780    * by looking at each instruction and examining it's
5781    * operands
5782    */
5783   for(pc = pb->pcHead; pc; pc = pc->next) {
5784
5785     /* Is this an instruction with operands? */
5786     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5787
5788       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5789
5790         /* Loop through all of the registers declared so far in
5791            this block and see if we find this one there */
5792
5793         regs *r = setFirstItem(pb->tregisters);
5794
5795         while(r) {
5796           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5797             PCOR(PCI(pc)->pcop)->r = r;
5798             break;
5799           }
5800           r = setNextItem(pb->tregisters);
5801         }
5802
5803         if(!r) {
5804           /* register wasn't found */
5805           //r = Safe_calloc(1, sizeof(regs));
5806           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5807           //addSet(&pb->tregisters, r);
5808           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5809           //PCOR(PCI(pc)->pcop)->r = r;
5810           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5811         }/* else
5812           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5813          */
5814       }
5815       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5816         if(PCOR(PCI(pc)->pcop)->r) {
5817           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5818           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5819         } else {
5820           if(PCI(pc)->pcop->name)
5821             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5822           else
5823             fprintf(stderr,"ERROR: NULL register\n");
5824         }
5825       }
5826     }
5827
5828
5829   }
5830 }
5831
5832 /*-----------------------------------------------------------------*/
5833 /* */
5834 /*-----------------------------------------------------------------*/
5835 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5836
5837 static void InsertpFlow(pCode *pc, pCode **pflow)
5838 {
5839   if(*pflow)
5840     PCFL(*pflow)->end = pc;
5841
5842   if(!pc || !pc->next)
5843     return;
5844
5845   *pflow = pic16_newpCodeFlow();
5846   pic16_pCodeInsertAfter(pc, *pflow);
5847 }
5848
5849 /*-----------------------------------------------------------------*/
5850 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5851 /*                         the flow blocks.                        */
5852 /*
5853  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5854  * point the instruction flow changes.
5855  */
5856 /*-----------------------------------------------------------------*/
5857 void pic16_BuildFlow(pBlock *pb)
5858 {
5859   pCode *pc;
5860   pCode *last_pci=NULL;
5861   pCode *pflow=NULL;
5862   int seq = 0;
5863
5864   if(!pb)
5865     return;
5866
5867   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5868   /* Insert a pCodeFlow object at the beginning of a pBlock */
5869
5870   InsertpFlow(pb->pcHead, &pflow);
5871
5872   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5873   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5874   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5875   //pb->pcHead = pflow;        /* Make the Flow object the head */
5876   //pflow->pb = pb;
5877
5878   for( pc = pic16_findNextInstruction(pb->pcHead);
5879        pc != NULL;
5880        pc=pic16_findNextInstruction(pc)) {
5881
5882     pc->seq = seq++;
5883     PCI(pc)->pcflow = PCFL(pflow);
5884
5885     //fprintf(stderr," build: ");
5886     //pflow->print(stderr,pflow);
5887
5888     if (checkLabel(pc)) {
5889
5890       /* This instruction marks the beginning of a
5891        * new flow segment */
5892
5893       pc->seq = 0;
5894       seq = 1;
5895
5896       /* If the previous pCode is not a flow object, then
5897        * insert a new flow object. (This check prevents
5898        * two consecutive flow objects from being insert in
5899        * the case where a skip instruction preceeds an
5900        * instruction containing a label.) */
5901
5902       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5903         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5904
5905       PCI(pc)->pcflow = PCFL(pflow);
5906
5907     }
5908
5909     if( PCI(pc)->isSkip) {
5910
5911       /* The two instructions immediately following this one
5912        * mark the beginning of a new flow segment */
5913
5914       while(pc && PCI(pc)->isSkip) {
5915
5916         PCI(pc)->pcflow = PCFL(pflow);
5917         pc->seq = seq-1;
5918         seq = 1;
5919
5920         InsertpFlow(pc, &pflow);
5921         pc=pic16_findNextInstruction(pc->next);
5922       }
5923
5924       seq = 0;
5925
5926       if(!pc)
5927         break;
5928
5929       PCI(pc)->pcflow = PCFL(pflow);
5930       pc->seq = 0;
5931       InsertpFlow(pc, &pflow);
5932
5933     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
5934
5935       InsertpFlow(pc, &pflow);
5936       seq = 0;
5937
5938     }
5939     last_pci = pc;
5940     pc = pc->next;
5941   }
5942
5943   //fprintf (stderr,",end seq %d",GpcFlowSeq);
5944   if(pflow)
5945     PCFL(pflow)->end = pb->pcTail;
5946 }
5947
5948 /*-------------------------------------------------------------------*/
5949 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5950 /*                           the flow blocks.                        */
5951 /*
5952  * unBuildFlow removes pCodeFlow objects from a pCode chain
5953  */
5954 /*-----------------------------------------------------------------*/
5955 static void unBuildFlow(pBlock *pb)
5956 {
5957   pCode *pc,*pcnext;
5958
5959   if(!pb)
5960     return;
5961
5962   pc = pb->pcHead;
5963
5964   while(pc) {
5965     pcnext = pc->next;
5966
5967     if(isPCI(pc)) {
5968
5969       pc->seq = 0;
5970       if(PCI(pc)->pcflow) {
5971         //Safe_free(PCI(pc)->pcflow);
5972         PCI(pc)->pcflow = NULL;
5973       }
5974
5975     } else if(isPCFL(pc) )
5976       pc->destruct(pc);
5977
5978     pc = pcnext;
5979   }
5980
5981
5982 }
5983 #if 0
5984 /*-----------------------------------------------------------------*/
5985 /*-----------------------------------------------------------------*/
5986 static void dumpCond(int cond)
5987 {
5988
5989   static char *pcc_str[] = {
5990     //"PCC_NONE",
5991     "PCC_REGISTER",
5992     "PCC_C",
5993     "PCC_Z",
5994     "PCC_DC",
5995     "PCC_OV",
5996     "PCC_N",
5997     "PCC_W",
5998     "PCC_EXAMINE_PCOP",
5999     "PCC_LITERAL",
6000     "PCC_REL_ADDR"
6001   };
6002
6003   int ncond = sizeof(pcc_str) / sizeof(char *);
6004   int i,j;
6005
6006   fprintf(stderr, "0x%04X\n",cond);
6007
6008   for(i=0,j=1; i<ncond; i++, j<<=1)
6009     if(cond & j)
6010       fprintf(stderr, "  %s\n",pcc_str[i]);
6011
6012 }
6013 #endif
6014
6015 #if 0
6016 /*-----------------------------------------------------------------*/
6017 /*-----------------------------------------------------------------*/
6018 static void FlowStats(pCodeFlow *pcflow)
6019 {
6020
6021   pCode *pc;
6022
6023   if(!isPCFL(pcflow))
6024     return;
6025
6026   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6027
6028   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6029
6030   if(!pc) {
6031     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6032     return;
6033   }
6034
6035
6036   fprintf(stderr, "  FlowStats inCond: ");
6037   dumpCond(pcflow->inCond);
6038   fprintf(stderr, "  FlowStats outCond: ");
6039   dumpCond(pcflow->outCond);
6040
6041 }
6042 #endif
6043 /*-----------------------------------------------------------------*
6044  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6045  *    if it affects the banking bits.
6046  *
6047  * return: -1 == Banking bits are unaffected by this pCode.
6048  *
6049  * return: > 0 == Banking bits are affected.
6050  *
6051  *  If the banking bits are affected, then the returned value describes
6052  * which bits are affected and how they're affected. The lower half
6053  * of the integer maps to the bits that are affected, the upper half
6054  * to whether they're set or cleared.
6055  *
6056  *-----------------------------------------------------------------*/
6057
6058 static int isBankInstruction(pCode *pc)
6059 {
6060   regs *reg;
6061   int bank = -1;
6062
6063   if(!isPCI(pc))
6064     return 0;
6065
6066   if( PCI(pc)->op == POC_MOVLB ||
6067       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6068     bank = PCOL(pc)->lit;
6069   }
6070
6071   return 1;
6072 }
6073
6074
6075 /*-----------------------------------------------------------------*/
6076 /*-----------------------------------------------------------------*/
6077 static void FillFlow(pCodeFlow *pcflow)
6078 {
6079
6080   pCode *pc;
6081   int cur_bank;
6082
6083   if(!isPCFL(pcflow))
6084     return;
6085
6086   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6087
6088   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6089
6090   if(!pc) {
6091     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6092     return;
6093   }
6094
6095   cur_bank = -1;
6096
6097   do {
6098     isBankInstruction(pc);
6099     pc = pc->next;
6100   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6101
6102 /*
6103   if(!pc ) {
6104     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6105   } else {
6106     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6107     pc->print(stderr,pc);
6108   }
6109
6110   fprintf(stderr, "  FillFlow inCond: ");
6111   dumpCond(pcflow->inCond);
6112   fprintf(stderr, "  FillFlow outCond: ");
6113   dumpCond(pcflow->outCond);
6114 */
6115 }
6116
6117 /*-----------------------------------------------------------------*/
6118 /*-----------------------------------------------------------------*/
6119 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6120 {
6121   pCodeFlowLink *fromLink, *toLink;
6122
6123   if(!from || !to || !to->pcflow || !from->pcflow)
6124     return;
6125
6126   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6127   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6128
6129   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6130   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6131
6132 }
6133
6134 pCode *pic16_getJumptabpCode (pCode *pc) {
6135   pCode *pcinf;
6136
6137   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6138   //pc->print (stderr, pc);
6139   pcinf = pc;
6140   while (pcinf) {
6141     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6142     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6143       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6144       case OPT_JUMPTABLE_BEGIN:
6145         /* leading begin of jump table -- in one */
6146         pcinf = pic16_findPrevInstruction (pcinf);
6147         return pcinf;
6148         break;
6149
6150       case OPT_JUMPTABLE_END:
6151         /* leading end of jumptable -- not in one */
6152         return NULL;
6153         break;
6154
6155       default:
6156         /* ignore all other PCInfos */
6157         break;
6158       }
6159     }
6160     pcinf = pcinf->prev;
6161   }
6162
6163   /* no PCInfo found -- not in a jumptable */
6164   return NULL;
6165 }
6166
6167 /*-----------------------------------------------------------------*
6168  * void LinkFlow(pBlock *pb)
6169  *
6170  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6171  * non-branching segments. In LinkFlow, we determine the execution
6172  * order of these segments. For example, if one of the segments ends
6173  * with a skip, then we know that there are two possible flow segments
6174  * to which control may be passed.
6175  *-----------------------------------------------------------------*/
6176 static void LinkFlow(pBlock *pb)
6177 {
6178   pCode *pc=NULL;
6179   pCode *pcflow;
6180   pCode *pct;
6181   pCode *jumptab_pre = NULL;
6182
6183   //fprintf(stderr,"linkflow \n");
6184
6185   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6186        pcflow != NULL;
6187        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6188
6189     if(!isPCFL(pcflow))
6190       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6191
6192     //fprintf(stderr," link: ");
6193     //pcflow->print(stderr,pcflow);
6194
6195     //FillFlow(PCFL(pcflow));
6196
6197     pc = PCFL(pcflow)->end;
6198
6199     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6200     if(isPCI_SKIP(pc)) {
6201 //      fprintf(stderr, "ends with skip\n");
6202 //      pc->print(stderr,pc);
6203
6204       pct=pic16_findNextInstruction(pc->next);
6205       LinkFlow_pCode(PCI(pc),PCI(pct));
6206       pct=pic16_findNextInstruction(pct->next);
6207       LinkFlow_pCode(PCI(pc),PCI(pct));
6208       continue;
6209     }
6210
6211     if(isPCI_BRANCH(pc)) {
6212       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6213
6214       /* handle GOTOs in jumptables */
6215       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6216         /* link to previous flow */
6217         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6218         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6219       }
6220
6221       switch (PCI(pc)->op) {
6222       case POC_GOTO:
6223       case POC_BRA:
6224       case POC_RETURN:
6225       case POC_RETLW:
6226       case POC_RETFIE:
6227               /* unconditional branches -- do not link to next instruction */
6228               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6229               break;
6230
6231       case POC_CALL:
6232       case POC_RCALL:
6233               /* unconditional calls -- link to next instruction */
6234               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6235               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6236               break;
6237
6238       case POC_BC:
6239       case POC_BN:
6240       case POC_BNC:
6241       case POC_BNN:
6242       case POC_BNOV:
6243       case POC_BNZ:
6244       case POC_BOV:
6245       case POC_BZ:
6246               /* conditional branches -- also link to next instruction */
6247               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6248               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6249               break;
6250
6251       default:
6252               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6253               assert (0 && "unhandled branching instruction");
6254               break;
6255       }
6256
6257       //fprintf(stderr, "ends with branch\n  ");
6258       //pc->print(stderr,pc);
6259
6260       if(!(pcol && isPCOLAB(pcol))) {
6261         if((PCI(pc)->op != POC_RETLW)
6262                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6263
6264                 /* continue if label is '$' which assembler knows how to parse */
6265                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6266
6267                 if(pic16_pcode_verbose) {
6268                         pc->print(stderr,pc);
6269                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6270                 }
6271         }
6272         continue;
6273       }
6274
6275       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6276         LinkFlow_pCode(PCI(pc),PCI(pct));
6277       else
6278         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6279                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6280
6281 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6282
6283       continue;
6284     }
6285
6286     if(isPCI(pc)) {
6287       //fprintf(stderr, "ends with non-branching instruction:\n");
6288       //pc->print(stderr,pc);
6289
6290       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6291
6292       continue;
6293     }
6294
6295     if(pc) {
6296       //fprintf(stderr, "ends with unknown\n");
6297       //pc->print(stderr,pc);
6298       continue;
6299     }
6300
6301     //fprintf(stderr, "ends with nothing: ERROR\n");
6302
6303   }
6304 }
6305 /*-----------------------------------------------------------------*/
6306 /*-----------------------------------------------------------------*/
6307
6308 /*-----------------------------------------------------------------*/
6309 /*-----------------------------------------------------------------*/
6310 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6311 {
6312
6313   if(!pc || !pcflow)
6314     return 0;
6315
6316   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6317     return 0;
6318
6319   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6320     return 1;
6321
6322   return 0;
6323 }
6324
6325
6326
6327
6328
6329 /*-----------------------------------------------------------------*/
6330 /* insertBankSwitch - inserts a bank switch statement in the       */
6331 /*                    assembly listing                             */
6332 /*                                                                 */
6333 /* position == 0: insert before                                    */
6334 /* position == 1: insert after pc                                  */
6335 /* position == 2: like 0 but previous was a skip instruction       */
6336 /*-----------------------------------------------------------------*/
6337 pCodeOp *pic16_popGetLabel(unsigned int key);
6338 extern int pic16_labelOffset;
6339
6340 static void insertBankSwitch(unsigned char position, pCode *pc)
6341 {
6342   pCode *new_pc;
6343
6344         if(!pc)
6345                 return;
6346
6347         /* emit BANKSEL [symbol] */
6348
6349
6350         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6351
6352 //      position = 0;           // position is always before (sanity check!)
6353
6354 #if 0
6355         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6356         pc->print(stderr, pc);
6357 #endif
6358
6359         switch(position) {
6360                 case 1: {
6361                         /* insert the bank switch after this pc instruction */
6362                         pCode *pcnext = pic16_findNextInstruction(pc);
6363
6364                                 pic16_pCodeInsertAfter(pc, new_pc);
6365                                 if(pcnext)pc = pcnext;
6366                 }; break;
6367
6368                 case 0:
6369                         /* insert the bank switch BEFORE this pc instruction */
6370                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6371                         break;
6372
6373                 case 2: {
6374                           symbol *tlbl;
6375                           pCode *pcnext, *pcprev, *npci, *ppc;
6376                           PIC_OPCODE ipci;
6377                           int ofs1=0, ofs2=0, len=0;
6378
6379                         /* just like 0, but previous was a skip instruction,
6380                          * so some care should be taken */
6381
6382                                 pic16_labelOffset += 10000;
6383                                 tlbl = newiTempLabel(NULL);
6384
6385                                 /* invert skip instruction */
6386                                 pcprev = pic16_findPrevInstruction(pc->prev);
6387                                 ipci = PCI(pcprev)->inverted_op;
6388                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6389
6390 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6391
6392                                 /* copy info from old pCode */
6393                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6394                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6395                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6396                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6397                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6398                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6399
6400                                 /* unlink old pCode */
6401                                 ppc = pcprev->prev;
6402                                 ppc->next = pcprev->next;
6403                                 pcprev->next->prev = ppc;
6404                                 pic16_pCodeInsertAfter(ppc, npci);
6405
6406                                 /* extra instructions to handle invertion */
6407                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6408                                 pic16_pCodeInsertAfter(npci, pcnext);
6409                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6410
6411                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6412                                 pic16_pCodeInsertAfter(pc, pcnext);
6413                         }; break;
6414         }
6415
6416
6417         /* Move the label, if there is one */
6418         if(PCI(pc)->label) {
6419 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6420 //                      __FILE__, __LINE__, pc, new_pc);
6421                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6422                 PCI(pc)->label = NULL;
6423         }
6424 }
6425
6426
6427 /*-----------------------------------------------------------------*/
6428 /*int compareBankFlow - compare the banking requirements between   */
6429 /*  flow objects. */
6430 /*-----------------------------------------------------------------*/
6431 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6432 {
6433
6434   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6435     return 0;
6436
6437   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6438     return 0;
6439
6440   if(pcflow->firstBank == -1)
6441     return 0;
6442
6443
6444   if(pcflowLink->pcflow->firstBank == -1) {
6445     pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6446                                         pcflowLink->pcflow->to :
6447                                         pcflowLink->pcflow->from);
6448     return compareBankFlow(pcflow, pctl, toORfrom);
6449   }
6450
6451   if(toORfrom) {
6452     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6453       return 0;
6454
6455     pcflowLink->bank_conflict++;
6456     pcflowLink->pcflow->FromConflicts++;
6457     pcflow->ToConflicts++;
6458   } else {
6459
6460     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6461       return 0;
6462
6463     pcflowLink->bank_conflict++;
6464     pcflowLink->pcflow->ToConflicts++;
6465     pcflow->FromConflicts++;
6466
6467   }
6468   /*
6469   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6470           pcflowLink->pcflow->pc.seq,
6471           pcflowLink->pcflow->FromConflicts,
6472           pcflowLink->pcflow->ToConflicts);
6473   */
6474   return 1;
6475
6476 }
6477
6478 #if 0
6479 /*-----------------------------------------------------------------*/
6480 /*-----------------------------------------------------------------*/
6481 static void DumpFlow(pBlock *pb)
6482 {
6483   pCode *pc=NULL;
6484   pCode *pcflow;
6485   pCodeFlowLink *pcfl;
6486
6487
6488   fprintf(stderr,"Dump flow \n");
6489   pb->pcHead->print(stderr, pb->pcHead);
6490
6491   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6492   pcflow->print(stderr,pcflow);
6493
6494   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6495        pcflow != NULL;
6496        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6497
6498     if(!isPCFL(pcflow)) {
6499       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6500       continue;
6501     }
6502     fprintf(stderr,"dumping: ");
6503     pcflow->print(stderr,pcflow);
6504     FlowStats(PCFL(pcflow));
6505
6506     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6507
6508       pc = PCODE(pcfl->pcflow);
6509
6510       fprintf(stderr, "    from seq %d:\n",pc->seq);
6511       if(!isPCFL(pc)) {
6512         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6513         pc->print(stderr,pc);
6514       }
6515
6516     }
6517
6518     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6519
6520       pc = PCODE(pcfl->pcflow);
6521
6522       fprintf(stderr, "    to seq %d:\n",pc->seq);
6523       if(!isPCFL(pc)) {
6524         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6525         pc->print(stderr,pc);
6526       }
6527
6528     }
6529
6530   }
6531
6532 }
6533 #endif
6534 /*-----------------------------------------------------------------*/
6535 /*-----------------------------------------------------------------*/
6536 static int OptimizepBlock(pBlock *pb)
6537 {
6538   pCode *pc, *pcprev;
6539   int matches =0;
6540
6541   if(!pb || !peepOptimizing)
6542     return 0;
6543
6544   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6545 /*
6546   for(pc = pb->pcHead; pc; pc = pc->next)
6547     matches += pic16_pCodePeepMatchRule(pc);
6548 */
6549
6550   pc = pic16_findNextInstruction(pb->pcHead);
6551   if(!pc)
6552     return 0;
6553
6554   pcprev = pc->prev;
6555   do {
6556
6557
6558     if(pic16_pCodePeepMatchRule(pc)) {
6559
6560       matches++;
6561
6562       if(pcprev)
6563         pc = pic16_findNextInstruction(pcprev->next);
6564       else
6565         pc = pic16_findNextInstruction(pb->pcHead);
6566     } else
6567       pc = pic16_findNextInstruction(pc->next);
6568   } while(pc);
6569
6570   if(matches)
6571     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6572   return matches;
6573
6574 }
6575
6576 /*-----------------------------------------------------------------*/
6577 /*-----------------------------------------------------------------*/
6578 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6579 {
6580   pCode *pc;
6581
6582   for(pc = pcs; pc; pc = pc->next) {
6583
6584     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6585        (PCI(pc)->pcop) &&
6586        (PCI(pc)->pcop->type == PO_LABEL) &&
6587        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6588       return pc;
6589   }
6590
6591
6592   return NULL;
6593 }
6594
6595 /*-----------------------------------------------------------------*/
6596 /*-----------------------------------------------------------------*/
6597 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6598 {
6599
6600   char *s=NULL;
6601
6602   if(isPCI(pc) &&
6603      (PCI(pc)->pcop) &&
6604      (PCI(pc)->pcop->type == PO_LABEL)) {
6605
6606     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6607
6608 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6609 //    if(pcol->pcop.name)
6610 //      Safe_free(pcol->pcop.name);
6611
6612     /* If the key is negative, then we (probably) have a label to
6613      * a function and the name is already defined */
6614
6615     if(pcl->key>0)
6616       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6617     else
6618       s = pcl->label;
6619
6620     //sprintf(buffer,"_%05d_DS_",pcl->key);
6621     if(!s) {
6622       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6623     }
6624     pcol->pcop.name = Safe_strdup(s);
6625     pcol->key = pcl->key;
6626     //pc->print(stderr,pc);
6627
6628   }
6629
6630
6631 }
6632
6633 /*-----------------------------------------------------------------*/
6634 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6635 /*                            pCode chain if they're not used.     */
6636 /*-----------------------------------------------------------------*/
6637 static void pBlockRemoveUnusedLabels(pBlock *pb)
6638 {
6639   pCode *pc; pCodeLabel *pcl;
6640
6641   if(!pb || !pb->pcHead)
6642     return;
6643
6644   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6645
6646     pBranch *pbr = PCI(pc)->label;
6647     if(pbr && pbr->next) {
6648       pCode *pcd = pb->pcHead;
6649
6650 //      fprintf(stderr, "multiple labels\n");
6651 //      pc->print(stderr,pc);
6652
6653       pbr = pbr->next;
6654       while(pbr) {
6655
6656         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6657           //fprintf(stderr,"Used by:\n");
6658           //pcd->print(stderr,pcd);
6659
6660           exchangeLabels(PCL(pbr->pc),pcd);
6661
6662           pcd = pcd->next;
6663         }
6664         pbr = pbr->next;
6665       }
6666     }
6667   }
6668
6669   for(pc = pb->pcHead; pc; pc = pc->next) {
6670
6671     if(isPCL(pc)) // pc->type == PC_LABEL)
6672       pcl = PCL(pc);
6673     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6674       pcl = PCL(PCI(pc)->label->pc);
6675     else continue;
6676
6677 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6678
6679     /* This pCode is a label, so search the pBlock to see if anyone
6680      * refers to it */
6681
6682     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6683         && (!pcl->force)) {
6684     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6685       /* Couldn't find an instruction that refers to this label
6686        * So, unlink the pCode label from it's pCode chain
6687        * and destroy the label */
6688 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6689
6690       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6691       if(pc->type == PC_LABEL) {
6692         pic16_unlinkpCode(pc);
6693         pCodeLabelDestruct(pc);
6694       } else {
6695         unlinkpCodeFromBranch(pc, PCODE(pcl));
6696         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6697           Safe_free(pc->label);
6698         }*/
6699       }
6700
6701     }
6702   }
6703
6704 }
6705
6706
6707 /*-----------------------------------------------------------------*/
6708 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6709 /*                     chain and put them into pBranches that are  */
6710 /*                     associated with the appropriate pCode       */
6711 /*                     instructions.                               */
6712 /*-----------------------------------------------------------------*/
6713 void pic16_pBlockMergeLabels(pBlock *pb)
6714 {
6715   pBranch *pbr;
6716   pCode *pc, *pcnext=NULL;
6717
6718   if(!pb)
6719     return;
6720
6721   /* First, Try to remove any unused labels */
6722   //pBlockRemoveUnusedLabels(pb);
6723
6724   /* Now loop through the pBlock and merge the labels with the opcodes */
6725
6726   pc = pb->pcHead;
6727   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6728
6729   while(pc) {
6730     pCode *pcn = pc->next;
6731
6732     if(pc->type == PC_LABEL) {
6733
6734 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6735 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6736
6737       if((pcnext = pic16_findNextInstruction(pc) )) {
6738
6739 //              pcnext->print(stderr, pcnext);
6740
6741         // Unlink the pCode label from it's pCode chain
6742         pic16_unlinkpCode(pc);
6743
6744 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6745         // And link it into the instruction's pBranch labels. (Note, since
6746         // it's possible to have multiple labels associated with one instruction
6747         // we must provide a means to accomodate the additional labels. Thus
6748         // the labels are placed into the singly-linked list "label" as
6749         // opposed to being a single member of the pCodeInstruction.)
6750
6751         //_ALLOC(pbr,sizeof(pBranch));
6752 #if 1
6753         pbr = Safe_calloc(1,sizeof(pBranch));
6754         pbr->pc = pc;
6755         pbr->next = NULL;
6756
6757         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6758 #endif
6759       } else {
6760         if(pic16_pcode_verbose)
6761         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6762       }
6763     } else if(pc->type == PC_CSOURCE) {
6764
6765       /* merge the source line symbolic info into the next instruction */
6766       if((pcnext = pic16_findNextInstruction(pc) )) {
6767
6768         // Unlink the pCode label from it's pCode chain
6769         pic16_unlinkpCode(pc);
6770         PCI(pcnext)->cline = PCCS(pc);
6771         //fprintf(stderr, "merging CSRC\n");
6772         //genericPrint(stderr,pcnext);
6773       }
6774
6775     }
6776     pc = pcn;
6777   }
6778   pBlockRemoveUnusedLabels(pb);
6779
6780 }
6781
6782 /*-----------------------------------------------------------------*/
6783 /*-----------------------------------------------------------------*/
6784 static int OptimizepCode(char dbName)
6785 {
6786 #define MAX_PASSES 4
6787
6788   int matches = 0;
6789   int passes = 0;
6790   pBlock *pb;
6791
6792   if(!the_pFile)
6793     return 0;
6794
6795   DFPRINTF((stderr," Optimizing pCode\n"));
6796
6797   do {
6798     matches = 0;
6799     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6800       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6801         matches += OptimizepBlock(pb);
6802     }
6803   }
6804   while(matches && ++passes < MAX_PASSES);
6805
6806   return matches;
6807 }
6808
6809
6810
6811 const char *pic16_pCodeOpType(pCodeOp *pcop);
6812 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6813
6814
6815 /*-----------------------------------------------------------------*/
6816 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6817 /*-----------------------------------------------------------------*/
6818
6819 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6820 {
6821   pCodeOp *pcop=NULL;
6822
6823 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6824
6825   if(pc->name) {
6826         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6827   } else {
6828     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6829   }
6830
6831   assert(pcop != NULL);
6832
6833   if( !( (pcop->type == PO_LABEL) ||
6834          (pcop->type == PO_LITERAL) ||
6835          (pcop->type == PO_STR) ))
6836     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6837     PCOR(pcop)->r->wasUsed = 1;
6838     PCOR(pcop)->instance = PCOR(pc)->instance;
6839
6840   return pcop;
6841 }
6842
6843
6844 /*----------------------------------------------------------------------*
6845  * pic16_areRegsSame - check to see if the names of two registers match *
6846  *----------------------------------------------------------------------*/
6847 int pic16_areRegsSame(regs *r1, regs *r2)
6848 {
6849         if(!strcmp(r1->name, r2->name))return 1;
6850
6851   return 0;
6852 }
6853
6854
6855 /*-----------------------------------------------------------------*/
6856 /*-----------------------------------------------------------------*/
6857 static void pic16_FixRegisterBanking(pBlock *pb)
6858 {
6859   pCode *pc=NULL;
6860   pCode *pcprev=NULL;
6861   regs *reg, *prevreg;
6862   unsigned char flag=0;
6863
6864         if(!pb)
6865                 return;
6866
6867         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6868         if(!pc)return;
6869
6870         /* loop through all of the flow blocks with in one pblock */
6871
6872 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6873
6874         prevreg = NULL;
6875         do {
6876                 /* at this point, pc should point to a PC_FLOW object */
6877                 /* for each flow block, determine the register banking
6878                  * requirements */
6879
6880
6881                 /* if label, then might come from other point, force banksel */
6882                 if(isPCL(pc))prevreg = NULL;
6883
6884                 if(!isPCI(pc))goto loop;
6885
6886                 if(PCI(pc)->label)prevreg = NULL;
6887
6888                 if(PCI(pc)->is2MemOp)goto loop;
6889
6890                 /* if goto, then force banksel */
6891 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6892
6893                 reg = pic16_getRegFromInstruction(pc);
6894
6895 #if 0
6896                 pc->print(stderr, pc);
6897                 fprintf(stderr, "reg = %p\n", reg);
6898
6899                 if(reg) {
6900                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6901                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6902                                 reg->address,reg->isBitField, reg->isFixed);
6903                 }
6904 #endif
6905
6906                 /* now make some tests to make sure that instruction needs bank switch */
6907
6908                 /* if no register exists, and if not a bit opcode goto loop */
6909                 if(!reg) {
6910                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6911                 }
6912
6913                 if(isPCI_SKIP(pc)) {
6914 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6915 //                prevreg = NULL;
6916                 }
6917                 if(reg && isACCESS_BANK(reg))goto loop;
6918
6919                 if(!isBankInstruction(pc))goto loop;
6920
6921                 if(isPCI_LIT(pc))goto loop;
6922
6923                 if(PCI(pc)->op == POC_CALL)goto loop;
6924
6925                 /* Examine the instruction before this one to make sure it is
6926                  * not a skip type instruction */
6927                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6928
6929                 flag = 0;               /* add before this instruction */
6930
6931                 /* if previous instruction is a skip one, then set flag
6932                  * to 2 and call insertBankSwitch */
6933                 if(pcprev && isPCI_SKIP(pcprev)) {
6934                   flag=2;       //goto loop
6935 //                prevreg = NULL;
6936                 }
6937
6938                 if(pic16_options.opt_banksel>0) {
6939                   char op1[128], op2[128];
6940
6941                     if(prevreg) {
6942                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6943                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6944                       if(!strcmp(op1, op2))goto loop;
6945                     }
6946                 }
6947                 prevreg = reg;
6948                 insertBankSwitch(flag, pc);
6949
6950 //              fprintf(stderr, "BANK SWITCH inserted\n");
6951
6952 loop:
6953                 pcprev = pc;
6954                 pc = pc->next;
6955         } while (pc);
6956 }
6957
6958 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6959
6960 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6961 int instrSize (pCode *pc)
6962 {
6963   if (!pc) return 0;
6964
6965   if (isPCAD(pc)) {
6966     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6967     return 4; // assumes only regular instructions using <= 4 bytes
6968   }
6969
6970   if (isPCI(pc)) return PCI(pc)->isize;
6971
6972   return 0;
6973 }
6974
6975 /* Returns 1 if pc is referenced by the given label (either
6976  * pc is the label itself or is an instruction with an attached
6977  * label).
6978  * Returns 0 if pc is not preceeded by the specified label.
6979  */
6980 int isLabel (pCode *pc, char *label)
6981 {
6982   if (!pc) return 0;
6983
6984   // label attached to the pCode?
6985   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
6986     pBranch *lab = NULL;
6987     lab = PCI(pc)->label;
6988
6989     while (lab) {
6990       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
6991         return 1;
6992       }
6993       lab = lab->next;
6994     } // while
6995   } // if
6996
6997   // is inline assembly label?
6998   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
6999     // do not compare trailing ':'
7000     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7001       return 1;
7002     }
7003   } // if
7004
7005   // is pCodeLabel?
7006   if (isPCL(pc)) {
7007       if (strcmp(PCL(pc)->label,label) == 0) {
7008       return 1;
7009     }
7010   } // if
7011
7012   // no label/no label attached/wrong label(s)
7013   return 0;
7014 }
7015
7016 /* Returns the distance to the given label in terms of words.
7017  * Labels are searched only within -max .. max words from pc.
7018  * Returns max if the label could not be found or
7019  * its distance from pc in (-max..+max).
7020  */
7021 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7022   int dist = instrSize(pc);
7023   pCode *curr = pc;
7024
7025   // search backwards
7026   while (dist < max && curr && !isLabel (curr, label)) {
7027     curr = curr->prev;
7028     dist += instrSize(curr); // sizeof (instruction)
7029   } // while
7030   if (curr && dist < max) {
7031     if (target != NULL) *target = curr;
7032     return -dist;
7033   }
7034
7035   dist = 0;
7036   curr = pic16_findNextInstruction (pc->next);
7037   //search forwards
7038   while (dist < max && curr && !isLabel (curr, label)) {
7039     dist += instrSize(curr); // sizeof (instruction)
7040     curr = curr->next;
7041   } // while
7042   if (curr && dist < max) {
7043     if (target != NULL) *target = curr;
7044     return dist;
7045   }
7046
7047   if (target != NULL) *target = NULL;
7048   return max;
7049 }
7050
7051 /* Returns -1 if pc does NOT denote an instruction like
7052  * BTFS[SC] STATUS,i
7053  * Otherwise we return
7054  *   (a) 0x10 + i for BTFSS
7055  *   (b) 0x00 + i for BTFSC
7056  */
7057 int isSkipOnStatus (pCode *pc)
7058 {
7059   int res = -1;
7060   pCodeOp *pcop;
7061   if (!pc || !isPCI(pc)) return -1;
7062   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7063   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7064   else return -1;
7065
7066   pcop = PCI(pc)->pcop;
7067
7068   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7069     return res + ((pCodeOpRegBit *)pcop)->bit;
7070   }
7071
7072   return -1;
7073 }
7074
7075 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7076  * returns 0 otherwise. */
7077 int isConditionalBranch (pCode *pc)
7078 {
7079   if (!pc || !isPCI_BRANCH(pc)) return 0;
7080
7081   switch (PCI(pc)->op) {
7082   case POC_BC:
7083   case POC_BZ:
7084   case POC_BOV:
7085   case POC_BN:
7086   case POC_BNC:
7087   case POC_BNZ:
7088   case POC_BNOV:
7089   case POC_BNN:
7090     return 1;
7091
7092   default:
7093     break;
7094   } // switch
7095
7096   return 0;
7097 }
7098
7099 /* Returns 1 if pc has a label attached to it.
7100  * This can be either a label stored in the pCode itself (.label)
7101  * or a label making up its own pCode preceding this pc.
7102  * Returns 0 if pc cannot be reached directly via a label.
7103  */
7104 int hasNoLabel (pCode *pc)
7105 {
7106   pCode *prev;
7107   if (!pc) return 1;
7108
7109   // are there any label pCodes between pc and the previous instruction?
7110   prev = pic16_findPrevInstruction (pc->prev);
7111   while (pc && pc != prev) {
7112     // pCode with attached label?
7113     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7114         && PCI(pc)->label) {
7115       return 0;
7116     }
7117     // is inline assembly label?
7118     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7119     if (isPCW(pc) && PCW(pc)->label) return 0;
7120
7121     // pCodeLabel?
7122     if (isPCL(pc)) return 0;
7123
7124     pc = pc->prev;
7125   } // if
7126
7127   // no label found
7128   return 1;
7129 }
7130
7131 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7132   char buf[512];
7133   va_list va;
7134
7135   va_start (va, fmt);
7136   vsprintf (buf, fmt, va);
7137   va_end (va);
7138
7139   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7140 }
7141
7142 /* Replaces the old pCode with the new one, moving the labels,
7143  * C source line and probably flow information to the new pCode.
7144  */
7145 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7146   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7147     return;
7148
7149   /* first move all labels from old to new */
7150   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7151   PCI(oldPC)->label = NULL;
7152
7153 #if 0
7154   /* move C source line (if possible) */
7155   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7156     PCI(newPC)->cline = PCI(oldPC)->cline;
7157 #endif
7158
7159   /* keep flow information intact */
7160   newPC->seq = oldPC->seq;
7161   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7162   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7163     PCI(newPC)->pcflow->end = newPC;
7164   }
7165
7166   /* insert a comment stating which pCode has been replaced */
7167 #if 1
7168   if (pic16_pcode_verbose || pic16_debug_verbose) {
7169     char pc_str[256];
7170     pic16_pCode2str (pc_str, 256, oldPC);
7171     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7172   }
7173 #endif
7174
7175   /* insert new pCode into pBlock */
7176   pic16_pCodeInsertAfter (oldPC, newPC);
7177   pic16_unlinkpCode (oldPC);
7178
7179   /* destruct replaced pCode */
7180   oldPC->destruct (oldPC);
7181 }
7182
7183 /* Returns the inverted conditional branch (if any) or NULL.
7184  * pcop must be set to the new jump target.
7185  */
7186 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7187 {
7188   pCode *newBcc;
7189
7190   if (!bcc || !isPCI(bcc)) return NULL;
7191
7192   switch (PCI(bcc)->op) {
7193   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7194   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7195   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7196   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7197   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7198   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7199   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7200   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7201   default:
7202     newBcc = NULL;
7203   }
7204   return newBcc;
7205 }
7206
7207 #define MAX_DIST_GOTO         0x7FFFFFFF
7208 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7209 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7210 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7211 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7212
7213 /* Follows GOTO/BRA instructions to their target instructions, stores the
7214  * final destination (not a GOTO or BRA instruction) in target and returns
7215  * the distance from the original pc to *target.
7216  */
7217 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7218         pCode *curr = pc;
7219         pCode *last = NULL;
7220         pCodeOp *lastPCOP = NULL;
7221         int dist = 0;
7222         int depth = 0;
7223
7224         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7225
7226         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7227         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7228                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7229                 last = curr;
7230                 lastPCOP = PCI(curr)->pcop;
7231                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7232                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7233         } // while
7234
7235         if (target) *target = last;
7236         if (pcop) *pcop = lastPCOP;
7237         return dist;
7238 }
7239
7240 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7241  * Otherwise the first pCode after the jumptable (after
7242  * the OPT_JUMPTABLE_END tag) is returned.
7243  */
7244 pCode *skipJumptables (pCode *pc, int *isJumptable)
7245 {
7246   *isJumptable = 0;
7247   if (!pc) return NULL;
7248
7249   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7250     *isJumptable = 1;
7251     //fprintf (stderr, "SKIPPING jumptable\n");
7252     do {
7253       //pc->print(stderr, pc);
7254       pc = pc->next;
7255     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7256                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7257     //fprintf (stderr, "<<JUMPTAB:\n");
7258     // skip OPT_END as well
7259     if (pc) pc = pc->next;
7260   } // while
7261
7262   return pc;
7263 }
7264
7265 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7266 {
7267   int isJumptab;
7268   *isJumptable = 0;
7269   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7270     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7271     pc = skipJumptables (pc, &isJumptab);
7272     if (isJumptab) {
7273         // pc is the first pCode after the jumptable
7274         *isJumptable = 1;
7275     } else {
7276         // pc has not been changed by skipJumptables()
7277         pc = pc->next;
7278     }
7279   } // while
7280
7281   return pc;
7282 }
7283
7284 /* Turn GOTOs into BRAs if distance between GOTO and label
7285  * is less than 1024 bytes.
7286  *
7287  * This method is especially useful if GOTOs after BTFS[SC]
7288  * can be turned into BRAs as GOTO would cost another NOP
7289  * if skipped.
7290  */
7291 void pic16_OptimizeJumps ()
7292 {
7293   pCode *pc;
7294   pCode *pc_prev = NULL;
7295   pCode *pc_next = NULL;
7296   pBlock *pb;
7297   pCode *target;
7298   int change, iteration, isJumptab;
7299   int isHandled = 0;
7300   char *label;
7301   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7302
7303   if (!the_pFile) return;
7304
7305   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7306
7307   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7308     int matchedInvertRule = 1;
7309     iteration = 1;
7310     do {
7311       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7312       change = 0;
7313       pc = pic16_findNextInstruction (pb->pcHead);
7314
7315       while (pc) {
7316         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7317         if (isJumptab) {
7318                 // skip jumptable, i.e. start over with no pc_prev!
7319                 pc_prev = NULL;
7320                 pc = pc_next;
7321                 continue;
7322         } // if
7323
7324         /* (1) resolve chained jumps
7325          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7326          * (a) leave dead code in and
7327          * (b) skip over the dead code with an (unneccessary) jump.
7328          */
7329         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7330           pCodeOp *lastTargetOp = NULL;
7331           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7332           int maxDist = MAX_DIST_BCC;
7333           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7334           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7335
7336           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7337           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7338               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7339             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7340             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7341             PCI(pc)->pcop->name = lastTargetOp->name;
7342             change++;
7343             opt_gotochain++;
7344           } // if
7345         } // if
7346
7347
7348         if (IS_GOTO(pc)) {
7349           int dist;
7350           int condBraType = isSkipOnStatus(pc_prev);
7351           label = PCI(pc)->pcop->name;
7352           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7353           if (dist < 0) dist = -dist;
7354           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7355           isHandled = 0;
7356
7357
7358           /* (2) remove "GOTO label; label:" */
7359           if (isLabel (pc_next, label)) {
7360             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7361             // first remove all preceeding SKIP instructions
7362             while (pc_prev && isPCI_SKIP(pc_prev)) {
7363               // attach labels on this instruction to pc_next
7364               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7365               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7366               PCI(pc_prev)->label = NULL;
7367               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7368               pic16_unlinkpCode (pc_prev);
7369               pc_prev = pic16_findPrevInstruction (pc);
7370             } // while
7371             // now remove the redundant goto itself
7372             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7373             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7374             pic16_unlinkpCode (pc);
7375             pc = pic16_findPrevInstruction(pc_next->prev);
7376             isHandled = 1; // do not perform further optimizations
7377             opt_gotonext++;
7378             change++;
7379           } // if
7380
7381
7382           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7383           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7384             if (dist < MAX_DIST_BCC) {
7385               pCode *bcc = NULL;
7386               switch (condBraType) {
7387               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7388                 // no BDC on DIGIT CARRY available
7389               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7390               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7391               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7392               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7393                 // no BNDC on DIGIT CARRY available
7394               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7395               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7396               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7397               default:
7398                 // no replacement possible
7399                 bcc = NULL;
7400                 break;
7401               } // switch
7402               if (bcc) {
7403                 // ATTENTION: keep labels attached to BTFSx!
7404                 // HINT: GOTO is label free (checked above)
7405                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7406                 isHandled = 1; // do not perform further optimizations
7407                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7408                 pic16_pCodeReplace (pc_prev, bcc);
7409                 pc->destruct(pc);
7410                 pc = bcc;
7411                 opt_cond++;
7412                 change++;
7413               } // if
7414             } else {
7415               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7416               cond_toofar++;
7417             } // if
7418           } // if
7419
7420           if (!isHandled) {
7421             // (4) eliminate the following (common) tripel:
7422             //           <pred.>;
7423             //  labels1: Bcc label2;
7424             //           GOTO somewhere;    ; <-- instruction referenced by pc
7425             //  label2:  <cont.>
7426             // and replace it by
7427             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7428             //  label2:  <cont.>
7429             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7430             //            to <cont.> instead
7431             // ATTENTION: This optimization is only valid if <pred.> is
7432             //            not a skip operation!
7433             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7434             // ATTENTION: no label may be attached to the GOTO instruction!
7435             if (isConditionalBranch(pc_prev)
7436                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7437                 && (dist < MAX_DIST_BCC)
7438                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7439                 && hasNoLabel(pc)) {
7440               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7441
7442               if (newBcc) {
7443                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7444                 isHandled = 1; // do not perform further optimizations
7445                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7446                 pic16_pCodeReplace (pc_prev, newBcc);
7447                 pc->destruct(pc);
7448                 pc = newBcc;
7449                 opt_reorder++;
7450                 change++;
7451                 matchedInvertRule++;
7452               }
7453             }
7454           }
7455
7456           /* (5) now just turn GOTO into BRA */
7457           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7458             if (dist < MAX_DIST_BRA) {
7459               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7460               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7461               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7462               pic16_pCodeReplace (pc, newBra);
7463               pc = newBra;
7464               opt++;
7465               change++;
7466             } else {
7467               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7468               toofar++;
7469             }
7470           } // if (!isHandled)
7471         } // if
7472
7473         pc_prev = pc;
7474         pc = pc_next;
7475       } // while (pc)
7476
7477       pBlockRemoveUnusedLabels (pb);
7478
7479       // This line enables goto chain resolution!
7480       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7481
7482       iteration++;
7483     } while (change); /* fixpoint iteration per pBlock */
7484   } // for (pb)
7485
7486   // emit some statistics concerning goto-optimization
7487 #if 0
7488   if (pic16_debug_verbose || pic16_pcode_verbose) {
7489     fprintf (stderr, "optimize-goto:\n"
7490              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7491              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7492              "\t%5d conditional \"skipping\" jumps inverted\n"
7493              "\t%5d GOTOs to next instruction removed\n"
7494              "\t%5d chained GOTOs resolved\n",
7495              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7496   } // if
7497 #endif
7498   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7499 }
7500
7501 #undef IS_GOTO
7502 #undef MAX_JUMPCHAIN_DEPTH
7503 #undef MAX_DIST_GOTO
7504 #undef MAX_DIST_BRA
7505 #undef MAX_DIST_BCC
7506
7507 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7508
7509 static void pBlockDestruct(pBlock *pb)
7510 {
7511
7512   if(!pb)
7513     return;
7514
7515
7516 //  Safe_free(pb);
7517
7518 }
7519
7520 /*-----------------------------------------------------------------*/
7521 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7522 /*                                  name dbName and combine them   */
7523 /*                                  into one block                 */
7524 /*-----------------------------------------------------------------*/
7525 static void mergepBlocks(char dbName)
7526 {
7527
7528   pBlock *pb, *pbmerged = NULL,*pbn;
7529
7530   pb = the_pFile->pbHead;
7531
7532   //fprintf(stderr," merging blocks named %c\n",dbName);
7533   while(pb) {
7534
7535     pbn = pb->next;
7536     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7537     if( getpBlock_dbName(pb) == dbName) {
7538
7539       //fprintf(stderr," merged block %c\n",dbName);
7540
7541       if(!pbmerged) {
7542         pbmerged = pb;
7543       } else {
7544         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7545         /* pic16_addpCode2pBlock doesn't handle the tail: */
7546         pbmerged->pcTail = pb->pcTail;
7547
7548         pb->prev->next = pbn;
7549         if(pbn)
7550           pbn->prev = pb->prev;
7551
7552
7553         pBlockDestruct(pb);
7554       }
7555       //pic16_printpBlock(stderr, pbmerged);
7556     }
7557     pb = pbn;
7558   }
7559
7560 }
7561
7562 /*-----------------------------------------------------------------*/
7563 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7564 /*                                                                 */
7565 /* level 0 == minimal optimization                                 */
7566 /*   optimize registers that are used only by two instructions     */
7567 /* level 1 == maximal optimization                                 */
7568 /*   optimize by looking at pairs of instructions that use the     */
7569 /*   register.                                                     */
7570 /*-----------------------------------------------------------------*/
7571
7572 static void AnalyzeFlow(int level)
7573 {
7574   static int times_called=0;
7575   pBlock *pb;
7576
7577     if(!the_pFile) {
7578       /* remove unused allocated registers before exiting */
7579       pic16_RemoveUnusedRegisters();
7580       return;
7581     }
7582
7583
7584     /* if this is not the first time this function has been called,
7585      * then clean up old flow information */
7586     if(times_called++) {
7587       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7588         unBuildFlow(pb);
7589         pic16_RegsUnMapLiveRanges();
7590     }
7591     GpcFlowSeq = 1;
7592
7593     /* Phase 2 - Flow Analysis - Register Banking
7594      *
7595      * In this phase, the individual flow blocks are examined
7596      * and register banking is fixed.
7597      */
7598
7599 #if 0
7600     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7601       pic16_FixRegisterBanking(pb);
7602 #endif
7603
7604     /* Phase 2 - Flow Analysis
7605      *
7606      * In this phase, the pCode is partition into pCodeFlow
7607      * blocks. The flow blocks mark the points where a continuous
7608      * stream of instructions changes flow (e.g. because of
7609      * a call or goto or whatever).
7610      */
7611
7612     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7613       pic16_BuildFlow(pb);
7614
7615
7616     /* Phase 2 - Flow Analysis - linking flow blocks
7617      *
7618      * In this phase, the individual flow blocks are examined
7619      * to determine their order of excution.
7620      */
7621
7622     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7623       LinkFlow(pb);
7624
7625 #if 1
7626         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7627                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7628                         pic16_createDF (pb);
7629 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7630                         pic16_vcg_dump_default (pb);
7631 #endif
7632                         //pic16_destructDF (pb);
7633                 }
7634
7635                 pic16_df_stats ();
7636                 if (0) releaseStack (); // releasing is costly...
7637         }
7638 #endif
7639
7640     /* Phase 3 - Flow Analysis - Flow Tree
7641      *
7642      * In this phase, the individual flow blocks are examined
7643      * to determine their order of execution.
7644      */
7645
7646     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7647       pic16_BuildFlowTree(pb);
7648
7649
7650     /* Phase x - Flow Analysis - Used Banks
7651      *
7652      * In this phase, the individual flow blocks are examined
7653      * to determine the Register Banks they use
7654      */
7655
7656 #if 0
7657     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7658       FixBankFlow(pb);
7659 #endif
7660
7661
7662     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7663       pic16_pCodeRegMapLiveRanges(pb);
7664
7665     pic16_RemoveUnusedRegisters();
7666     pic16_removeUnusedRegistersDF ();
7667
7668   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7669     pic16_pCodeRegOptimizeRegUsage(level);
7670
7671
7672 #if 0
7673     if(!options.nopeep)
7674       OptimizepCode('*');
7675 #endif
7676
7677 #if 0
7678     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7679       DumpFlow(pb);
7680 #endif
7681
7682     /* debug stuff */
7683     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7684       pCode *pcflow;
7685
7686         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7687           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7688           pcflow = pcflow->next) {
7689             FillFlow(PCFL(pcflow));
7690         }
7691     }
7692
7693 #if 0
7694     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7695       pCode *pcflow;
7696
7697         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7698           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7699           pcflow = pcflow->next) {
7700             FlowStats(PCFL(pcflow));
7701         }
7702     }
7703 #endif
7704 }
7705
7706 /* VR -- no need to analyze banking in flow, but left here :
7707  *      1. because it may be used in the future for other purposes
7708  *      2. because if omitted we'll miss some optimization done here
7709  *
7710  * Perhaps I should rename it to something else
7711  */
7712
7713 /*-----------------------------------------------------------------*/
7714 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7715 /*                  assigned to the registers.                     */
7716 /*                                                                 */
7717 /*-----------------------------------------------------------------*/
7718
7719 void pic16_AnalyzeBanking(void)
7720 {
7721   pBlock  *pb;
7722
7723     /* Phase x - Flow Analysis - Used Banks
7724      *
7725      * In this phase, the individual flow blocks are examined
7726      * to determine the Register Banks they use
7727      */
7728
7729     AnalyzeFlow(0);
7730     AnalyzeFlow(1);
7731
7732     if(!options.nopeep)
7733       OptimizepCode('*');
7734
7735
7736     if(!the_pFile)return;
7737
7738     if(!pic16_options.no_banksel) {
7739       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7740 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7741         pic16_FixRegisterBanking(pb);
7742       }
7743     }
7744 }
7745
7746 /*-----------------------------------------------------------------*/
7747 /* buildCallTree - Look at the flow and extract all of the calls.  */
7748 /*-----------------------------------------------------------------*/
7749 static set *register_usage(pBlock *pb);
7750
7751 static void buildCallTree(void    )
7752 {
7753   pBranch *pbr;
7754   pBlock  *pb;
7755   pCode   *pc;
7756   regs *r;
7757
7758   if(!the_pFile)
7759     return;
7760
7761
7762
7763   /* Now build the call tree.
7764      First we examine all of the pCodes for functions.
7765      Keep in mind that the function boundaries coincide
7766      with pBlock boundaries.
7767
7768      The algorithm goes something like this:
7769      We have two nested loops. The outer loop iterates
7770      through all of the pBlocks/functions. The inner
7771      loop iterates through all of the pCodes for
7772      a given pBlock. When we begin iterating through
7773      a pBlock, the variable pc_fstart, pCode of the start
7774      of a function, is cleared. We then search for pCodes
7775      of type PC_FUNCTION. When one is encountered, we
7776      initialize pc_fstart to this and at the same time
7777      associate a new pBranch object that signifies a
7778      branch entry. If a return is found, then this signifies
7779      a function exit point. We'll link the pCodes of these
7780      returns to the matching pc_fstart.
7781
7782      When we're done, a doubly linked list of pBranches
7783      will exist. The head of this list is stored in
7784      `the_pFile', which is the meta structure for all
7785      of the pCode. Look at the pic16_printCallTree function
7786      on how the pBranches are linked together.
7787
7788    */
7789   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7790     pCode *pc_fstart=NULL;
7791     for(pc = pb->pcHead; pc; pc = pc->next) {
7792
7793         if(isPCI(pc) && pc_fstart) {
7794                 if(PCI(pc)->is2MemOp) {
7795                         r = pic16_getRegFromInstruction2(pc);
7796                         if(r && !strcmp(r->name, "POSTDEC1"))
7797                                 PCF(pc_fstart)->stackusage++;
7798                 } else {
7799                         r = pic16_getRegFromInstruction(pc);
7800                         if(r && !strcmp(r->name, "PREINC1"))
7801                                 PCF(pc_fstart)->stackusage--;
7802                 }
7803         }
7804
7805       if(isPCF(pc)) {
7806         if (PCF(pc)->fname) {
7807         char buf[16];
7808
7809           sprintf(buf, "%smain", port->fun_prefix);
7810           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7811             //fprintf(stderr," found main \n");
7812             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7813             pb->dbName = 'M';
7814           }
7815
7816           pbr = Safe_calloc(1,sizeof(pBranch));
7817           pbr->pc = pc_fstart = pc;
7818           pbr->next = NULL;
7819
7820           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7821
7822           // Here's a better way of doing the same:
7823           addSet(&pb->function_entries, pc);
7824
7825         } else {
7826           // Found an exit point in a function, e.g. return
7827           // (Note, there may be more than one return per function)
7828           if(pc_fstart)
7829             pBranchLink(PCF(pc_fstart), PCF(pc));
7830
7831           addSet(&pb->function_exits, pc);
7832         }
7833       } else if(isCALL(pc)) {
7834         addSet(&pb->function_calls,pc);
7835       }
7836     }
7837   }
7838
7839
7840 #if 0
7841   /* This is not needed because currently all register used
7842    * by a function are stored in stack -- VR */
7843
7844   /* Re-allocate the registers so that there are no collisions
7845    * between local variables when one function call another */
7846
7847   // this is weird...
7848   //  pic16_deallocateAllRegs();
7849
7850   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7851     if(!pb->visited)
7852       register_usage(pb);
7853   }
7854 #endif
7855
7856 }
7857
7858 /*-----------------------------------------------------------------*/
7859 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7860 /*                all of the logical connections.                  */
7861 /*                                                                 */
7862 /* Essentially what's done here is that the pCode flow is          */
7863 /* determined.                                                     */
7864 /*-----------------------------------------------------------------*/
7865
7866 void pic16_AnalyzepCode(char dbName)
7867 {
7868   pBlock *pb;
7869   int i,changes;
7870
7871   if(!the_pFile)
7872     return;
7873
7874   mergepBlocks('D');
7875
7876
7877   /* Phase 1 - Register allocation and peep hole optimization
7878    *
7879    * The first part of the analysis is to determine the registers
7880    * that are used in the pCode. Once that is done, the peep rules
7881    * are applied to the code. We continue to loop until no more
7882    * peep rule optimizations are found (or until we exceed the
7883    * MAX_PASSES threshold).
7884    *
7885    * When done, the required registers will be determined.
7886    *
7887    */
7888   i = 0;
7889   do {
7890
7891     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7892     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7893
7894     /* First, merge the labels with the instructions */
7895     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7896       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7897
7898         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7899         //fprintf(stderr," analyze and merging block %c\n",dbName);
7900         pic16_pBlockMergeLabels(pb);
7901         AnalyzepBlock(pb);
7902       } else {
7903         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7904       }
7905     }
7906
7907         if(!options.nopeep)
7908                 changes = OptimizepCode(dbName);
7909         else changes = 0;
7910
7911   } while(changes && (i++ < MAX_PASSES));
7912
7913
7914   buildCallTree();
7915 }
7916
7917
7918 /* convert a series of movff's of local regs to stack, with a single call to
7919  * a support functions which does the same thing via loop */
7920 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7921 {
7922   pBranch *pbr;
7923   pCode *pc, *pct;
7924   char *fname[]={"__lr_store", "__lr_restore"};
7925
7926 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7927
7928     pct = pic16_findNextInstruction(pcstart->next);
7929     do {
7930       pc = pct;
7931       pct = pc->next;   //pic16_findNextInstruction(pc->next);
7932 //      pc->print(stderr, pc);
7933       if(isPCI(pc) && PCI(pc)->label) {
7934         pbr = PCI(pc)->label;
7935         while(pbr && pbr->pc) {
7936           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7937           pbr = pbr->next;
7938         }
7939
7940 //        pc->print(stderr, pc);
7941         /* unlink pCode */
7942         pc->prev->next = pct;
7943         pct->prev = pc->prev;
7944 //        pc->next = NULL;
7945 //        pc->prev = NULL;
7946       }
7947     } while ((pc) && (pc != pcend));
7948
7949     /* unlink movff instructions */
7950     pcstart->next = pcend;
7951     pcend->prev = pcstart;
7952
7953     pc = pcstart;
7954 //    if(!entry) {
7955 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7956 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7957 //    }
7958
7959     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7960     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7961     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7962
7963 //    if(!entry) {
7964 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7965 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7966 //    }
7967
7968
7969     {
7970       symbol *sym;
7971
7972         sym = newSymbol( fname[ entry?0:1 ], 0 );
7973         strcpy(sym->rname, fname[ entry?0:1 ]);
7974         checkAddSym(&externs, sym);
7975
7976 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7977     }
7978
7979 }
7980
7981 /*-----------------------------------------------------------------*/
7982 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
7983 /*    local registers to a support function call                   */
7984 /*-----------------------------------------------------------------*/
7985 void pic16_OptimizeLocalRegs(void)
7986 {
7987   pBlock  *pb;
7988   pCode   *pc;
7989   pCodeInfo *pci;
7990   pCodeOpLocalReg *pclr;
7991   int regCount=0;
7992   int inRegCount=0;
7993   regs *r, *lastr=NULL, *firstr=NULL;
7994   pCode *pcstart=NULL, *pcend=NULL;
7995   int inEntry=0;
7996   char *curFunc=NULL;
7997
7998         /* Overview:
7999          *   local_regs begin mark
8000          *      MOVFF r0x01, POSTDEC1
8001          *      MOVFF r0x02, POSTDEC1
8002          *      ...
8003          *      ...
8004          *      MOVFF r0x0n, POSTDEC1
8005          *   local_regs end mark
8006          *
8007          * convert the above to the below:
8008          *      MOVLW   starting_register_index
8009          *      MOVWF   PRODL
8010          *      MOVLW   register_count
8011          *      call    __save_registers_in_stack
8012          */
8013
8014     if(!the_pFile)
8015       return;
8016
8017     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8018       inRegCount = regCount = 0;
8019       firstr = lastr = NULL;
8020       for(pc = pb->pcHead; pc; pc = pc->next) {
8021
8022         /* hold current function name */
8023         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8024
8025         if(pc && (pc->type == PC_INFO)) {
8026           pci = PCINF(pc);
8027
8028           if(pci->type == INF_LOCALREGS) {
8029             pclr = PCOLR(pci->oper1);
8030
8031             if((pclr->type == LR_ENTRY_BEGIN)
8032               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8033             else inEntry = 0;
8034
8035             switch(pclr->type) {
8036               case LR_ENTRY_BEGIN:
8037               case LR_EXIT_BEGIN:
8038                         inRegCount = 1; regCount = 0;
8039                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8040                         firstr = lastr = NULL;
8041                         break;
8042
8043               case LR_ENTRY_END:
8044               case LR_EXIT_END:
8045                         inRegCount = -1;
8046                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8047
8048 #if 1
8049                         if(curFunc && inWparamList(curFunc+1)) {
8050                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8051                                         filename, curFunc);
8052                         } else {
8053                           if(regCount>2) {
8054                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8055                               firstr, inEntry);
8056                           }
8057                         }
8058 #endif
8059                         firstr = lastr = NULL;
8060                         break;
8061             }
8062
8063             if(inRegCount == -1) {
8064 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8065               regCount = 0;
8066               inRegCount = 0;
8067             }
8068           }
8069         } else {
8070           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8071             if(inEntry)
8072               r = pic16_getRegFromInstruction(pc);
8073             else
8074               r = pic16_getRegFromInstruction2(pc);
8075             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8076               if(!firstr)firstr = r;
8077               regCount++;
8078 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8079             }
8080           }
8081         }
8082       }
8083     }
8084 }
8085
8086
8087
8088
8089
8090 /*-----------------------------------------------------------------*/
8091 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8092 /*                   function                                      */
8093 /*-----------------------------------------------------------------*/
8094 static bool ispCodeFunction(pCode *pc)
8095 {
8096
8097   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8098     return 1;
8099
8100   return 0;
8101 }
8102
8103 /*-----------------------------------------------------------------*/
8104 /* findFunction - Search for a function by name (given the name)   */
8105 /*                in the set of all functions that are in a pBlock */
8106 /* (note - I expect this to change because I'm planning to limit   */
8107 /*  pBlock's to just one function declaration                      */
8108 /*-----------------------------------------------------------------*/
8109 static pCode *findFunction(char *fname)
8110 {
8111   pBlock *pb;
8112   pCode *pc;
8113   if(!fname)
8114     return NULL;
8115
8116   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8117
8118     pc = setFirstItem(pb->function_entries);
8119     while(pc) {
8120
8121       if((pc->type == PC_FUNCTION) &&
8122          (PCF(pc)->fname) &&
8123          (strcmp(fname, PCF(pc)->fname)==0))
8124         return pc;
8125
8126       pc = setNextItem(pb->function_entries);
8127
8128     }
8129
8130   }
8131   return NULL;
8132 }
8133
8134 static void MarkUsedRegisters(set *regset)
8135 {
8136
8137   regs *r1,*r2;
8138
8139   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8140 //      fprintf(stderr, "marking register = %s\t", r1->name);
8141     r2 = pic16_regWithIdx(r1->rIdx);
8142 //      fprintf(stderr, "to register = %s\n", r2->name);
8143     r2->isFree = 0;
8144     r2->wasUsed = 1;
8145   }
8146 }
8147
8148 static void pBlockStats(FILE *of, pBlock *pb)
8149 {
8150
8151   pCode *pc;
8152   regs  *r;
8153
8154         if(!pic16_pcode_verbose)return;
8155
8156   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8157
8158   // for now just print the first element of each set
8159   pc = setFirstItem(pb->function_entries);
8160   if(pc) {
8161     fprintf(of,";entry:  ");
8162     pc->print(of,pc);
8163   }
8164   pc = setFirstItem(pb->function_exits);
8165   if(pc) {
8166     fprintf(of,";has an exit\n");
8167     //pc->print(of,pc);
8168   }
8169
8170   pc = setFirstItem(pb->function_calls);
8171   if(pc) {
8172     fprintf(of,";functions called:\n");
8173
8174     while(pc) {
8175       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8176         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8177       }
8178       pc = setNextItem(pb->function_calls);
8179     }
8180   }
8181
8182   r = setFirstItem(pb->tregisters);
8183   if(r) {
8184     int n = elementsInSet(pb->tregisters);
8185
8186     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8187
8188     while (r) {
8189       fprintf(of,   ";   %s\n",r->name);
8190       r = setNextItem(pb->tregisters);
8191     }
8192   }
8193
8194   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8195 }
8196
8197 /*-----------------------------------------------------------------*/
8198 /*-----------------------------------------------------------------*/
8199 #if 0
8200 static void sequencepCode(void)
8201 {
8202   pBlock *pb;
8203   pCode *pc;
8204
8205
8206   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8207
8208     pb->seq = GpCodeSequenceNumber+1;
8209
8210     for( pc = pb->pcHead; pc; pc = pc->next)
8211       pc->seq = ++GpCodeSequenceNumber;
8212   }
8213
8214 }
8215 #endif
8216
8217 /*-----------------------------------------------------------------*/
8218 /*-----------------------------------------------------------------*/
8219 static set *register_usage(pBlock *pb)
8220 {
8221   pCode *pc,*pcn;
8222   set *registers=NULL;
8223   set *registersInCallPath = NULL;
8224
8225   /* check recursion */
8226
8227   pc = setFirstItem(pb->function_entries);
8228
8229   if(!pc)
8230     return registers;
8231
8232   pb->visited = 1;
8233
8234   if(pc->type != PC_FUNCTION)
8235     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8236
8237   pc = setFirstItem(pb->function_calls);
8238   for( ; pc; pc = setNextItem(pb->function_calls)) {
8239
8240     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8241       char *dest = pic16_get_op_from_instruction(PCI(pc));
8242
8243       pcn = findFunction(dest);
8244       if(pcn)
8245         registersInCallPath = register_usage(pcn->pb);
8246     } else
8247       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8248
8249   }
8250
8251 #ifdef PCODE_DEBUG
8252   pBlockStats(stderr,pb);  // debug
8253 #endif
8254
8255   // Mark the registers in this block as used.
8256
8257   MarkUsedRegisters(pb->tregisters);
8258   if(registersInCallPath) {
8259     /* registers were used in the functions this pBlock has called */
8260     /* so now, we need to see if these collide with the ones we are */
8261     /* using here */
8262
8263     regs *r1,*r2, *newreg;
8264
8265     DFPRINTF((stderr,"comparing registers\n"));
8266
8267     r1 = setFirstItem(registersInCallPath);
8268     while(r1) {
8269
8270       r2 = setFirstItem(pb->tregisters);
8271
8272       while(r2 && (r1->type != REG_STK)) {
8273
8274         if(r2->rIdx == r1->rIdx) {
8275           newreg = pic16_findFreeReg(REG_GPR);
8276
8277
8278           if(!newreg) {
8279             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8280             exit(1);
8281           }
8282
8283           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8284                   r1->rIdx, newreg->rIdx));
8285           r2->rIdx = newreg->rIdx;
8286           //if(r2->name) Safe_free(r2->name);
8287           if(newreg->name)
8288             r2->name = Safe_strdup(newreg->name);
8289           else
8290             r2->name = NULL;
8291           newreg->isFree = 0;
8292           newreg->wasUsed = 1;
8293         }
8294         r2 = setNextItem(pb->tregisters);
8295       }
8296
8297       r1 = setNextItem(registersInCallPath);
8298     }
8299
8300     /* Collisions have been resolved. Now free the registers in the call path */
8301     r1 = setFirstItem(registersInCallPath);
8302     while(r1) {
8303       if(r1->type != REG_STK) {
8304         newreg = pic16_regWithIdx(r1->rIdx);
8305         newreg->isFree = 1;
8306       }
8307       r1 = setNextItem(registersInCallPath);
8308     }
8309
8310   }// else
8311   //    MarkUsedRegisters(pb->registers);
8312
8313   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8314 #ifdef PCODE_DEBUG
8315   if(registers)
8316     DFPRINTF((stderr,"returning regs\n"));
8317   else
8318     DFPRINTF((stderr,"not returning regs\n"));
8319
8320   DFPRINTF((stderr,"pBlock after register optim.\n"));
8321   pBlockStats(stderr,pb);  // debug
8322 #endif
8323
8324   return registers;
8325 }
8326
8327 /*-----------------------------------------------------------------*/
8328 /* pct2 - writes the call tree to a file                           */
8329 /*                                                                 */
8330 /*-----------------------------------------------------------------*/
8331 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8332 {
8333   pCode *pc,*pcn;
8334   int i;
8335   //  set *registersInCallPath = NULL;
8336
8337   if(!of)
8338     return;
8339
8340   if(indent > 10) {
8341         fprintf(of, "recursive function\n");
8342     return; //recursion ?
8343   }
8344
8345   pc = setFirstItem(pb->function_entries);
8346
8347   if(!pc)
8348     return;
8349
8350   pb->visited = 0;
8351
8352   for(i=0;i<indent;i++)   // Indentation
8353         fputs("+   ", of);
8354   fputs("+- ", of);
8355
8356   if(pc->type == PC_FUNCTION) {
8357     usedstack += PCF(pc)->stackusage;
8358     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8359   } else return;  // ???
8360
8361
8362   pc = setFirstItem(pb->function_calls);
8363   for( ; pc; pc = setNextItem(pb->function_calls)) {
8364
8365     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8366       char *dest = pic16_get_op_from_instruction(PCI(pc));
8367
8368       pcn = findFunction(dest);
8369       if(pcn)
8370         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8371     } else
8372       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8373
8374   }
8375
8376
8377 }
8378
8379
8380 /*-----------------------------------------------------------------*/
8381 /* pic16_printCallTree - writes the call tree to a file                  */
8382 /*                                                                 */
8383 /*-----------------------------------------------------------------*/
8384
8385 void pic16_printCallTree(FILE *of)
8386 {
8387   pBranch *pbr;
8388   pBlock  *pb;
8389   pCode   *pc;
8390
8391   if(!the_pFile)
8392     return;
8393
8394   if(!of)
8395     of = stderr;
8396
8397   fprintf(of, "\npBlock statistics\n");
8398   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8399     pBlockStats(of,pb);
8400
8401
8402   fprintf(of,"Call Tree\n");
8403   pbr = the_pFile->functions;
8404   while(pbr) {
8405     if(pbr->pc) {
8406       pc = pbr->pc;
8407       if(!ispCodeFunction(pc))
8408         fprintf(of,"bug in call tree");
8409
8410
8411       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8412
8413       while(pc->next && !ispCodeFunction(pc->next)) {
8414         pc = pc->next;
8415         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8416           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8417       }
8418     }
8419
8420     pbr = pbr->next;
8421   }
8422
8423
8424   fprintf(of,"\n**************\n\na better call tree\n");
8425   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8426 //    if(pb->visited)
8427       pct2(of,pb,0,0);
8428   }
8429
8430   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8431     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8432   }
8433 }
8434
8435
8436
8437 /*-----------------------------------------------------------------*/
8438 /*                                                                 */
8439 /*-----------------------------------------------------------------*/
8440
8441 static void InlineFunction(pBlock *pb)
8442 {
8443   pCode *pc;
8444   pCode *pc_call;
8445
8446   if(!pb)
8447     return;
8448
8449   pc = setFirstItem(pb->function_calls);
8450
8451   for( ; pc; pc = setNextItem(pb->function_calls)) {
8452
8453     if(isCALL(pc)) {
8454       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8455       pCode *pct;
8456       pCode *pce;
8457
8458       pBranch *pbr;
8459
8460       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8461
8462         //fprintf(stderr,"Cool can inline:\n");
8463         //pcn->print(stderr,pcn);
8464
8465         //fprintf(stderr,"recursive call Inline\n");
8466         InlineFunction(pcn->pb);
8467         //fprintf(stderr,"return from recursive call Inline\n");
8468
8469         /*
8470           At this point, *pc points to a CALL mnemonic, and
8471           *pcn points to the function that is being called.
8472
8473           To in-line this call, we need to remove the CALL
8474           and RETURN(s), and link the function pCode in with
8475           the CALLee pCode.
8476
8477         */
8478
8479
8480         /* Remove the CALL */
8481         pc_call = pc;
8482         pc = pc->prev;
8483
8484         /* remove callee pBlock from the pBlock linked list */
8485         removepBlock(pcn->pb);
8486
8487         pce = pcn;
8488         while(pce) {
8489           pce->pb = pb;
8490           pce = pce->next;
8491         }
8492
8493         /* Remove the Function pCode */
8494         pct = pic16_findNextInstruction(pcn->next);
8495
8496         /* Link the function with the callee */
8497         pc->next = pcn->next;
8498         pcn->next->prev = pc;
8499
8500         /* Convert the function name into a label */
8501
8502         pbr = Safe_calloc(1,sizeof(pBranch));
8503         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8504         pbr->next = NULL;
8505         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8506         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8507
8508         /* turn all of the return's except the last into goto's */
8509         /* check case for 2 instruction pBlocks */
8510         pce = pic16_findNextInstruction(pcn->next);
8511         while(pce) {
8512           pCode *pce_next = pic16_findNextInstruction(pce->next);
8513
8514           if(pce_next == NULL) {
8515             /* found the last return */
8516             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8517
8518             //fprintf(stderr,"found last return\n");
8519             //pce->print(stderr,pce);
8520             pce->prev->next = pc_call->next;
8521             pc_call->next->prev = pce->prev;
8522             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8523                                                       PCI(pce)->label);
8524           }
8525
8526           pce = pce_next;
8527         }
8528
8529
8530       }
8531     } else
8532       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8533
8534   }
8535
8536 }
8537
8538 /*-----------------------------------------------------------------*/
8539 /*                                                                 */
8540 /*-----------------------------------------------------------------*/
8541
8542 void pic16_InlinepCode(void)
8543 {
8544
8545   pBlock  *pb;
8546   pCode   *pc;
8547
8548   if(!the_pFile)
8549     return;
8550
8551   if(!functionInlining)
8552     return;
8553
8554   /* Loop through all of the function definitions and count the
8555    * number of times each one is called */
8556   //fprintf(stderr,"inlining %d\n",__LINE__);
8557
8558   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8559
8560     pc = setFirstItem(pb->function_calls);
8561
8562     for( ; pc; pc = setNextItem(pb->function_calls)) {
8563
8564       if(isCALL(pc)) {
8565         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8566         if(pcn && isPCF(pcn)) {
8567           PCF(pcn)->ncalled++;
8568         }
8569       } else
8570         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8571
8572     }
8573   }
8574
8575   //fprintf(stderr,"inlining %d\n",__LINE__);
8576
8577   /* Now, Loop through the function definitions again, but this
8578    * time inline those functions that have only been called once. */
8579
8580   InlineFunction(the_pFile->pbHead);
8581   //fprintf(stderr,"inlining %d\n",__LINE__);
8582
8583   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8584     unBuildFlow(pb);
8585
8586 }
8587
8588 char *pic_optype_names[]={
8589         "PO_NONE",         // No operand e.g. NOP
8590         "PO_W",              // The working register (as a destination)
8591         "PO_WREG",           // The working register (as a file register)
8592         "PO_STATUS",         // The 'STATUS' register
8593         "PO_BSR",            // The 'BSR' register
8594         "PO_FSR0",           // The "file select register" (in PIC18 family it's one
8595                              // of three)
8596         "PO_INDF0",          // The Indirect register
8597         "PO_INTCON",         // Interrupt Control register
8598         "PO_GPR_REGISTER",   // A general purpose register
8599         "PO_GPR_BIT",        // A bit of a general purpose register
8600         "PO_GPR_TEMP",       // A general purpose temporary register
8601         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8602         "PO_PCL",            // Program counter Low register
8603         "PO_PCLATH",         // Program counter Latch high register
8604         "PO_PCLATU",         // Program counter Latch upper register
8605         "PO_PRODL",          // Product Register Low
8606         "PO_PRODH",          // Product Register High
8607         "PO_LITERAL",        // A constant
8608         "PO_REL_ADDR",       // A relative address
8609         "PO_IMMEDIATE",      //  (8051 legacy)
8610         "PO_DIR",            // Direct memory (8051 legacy)
8611         "PO_CRY",            // bit memory (8051 legacy)
8612         "PO_BIT",            // bit operand.
8613         "PO_STR",            //  (8051 legacy)
8614         "PO_LABEL",
8615         "PO_WILD",           // Wild card operand in peep optimizer
8616         "PO_TWO_OPS"         // combine two operands
8617 };
8618
8619
8620 char *dumpPicOptype(PIC_OPTYPE type)
8621 {
8622         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8623         return (pic_optype_names[ type ]);
8624 }
8625
8626
8627 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8628 #include "graph.h"
8629
8630 #define MAX_COMMON_BANK_SIZE    32
8631 #define FIRST_PSEUDO_BANK_NR  1000
8632
8633 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8634 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8635 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8636 Graph *adj = NULL;
8637
8638 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8639
8640 typedef struct {
8641   pseudoBankNr bank;  // number assigned to this pseudoBank
8642   unsigned int size;  // number of operands assigned to this bank
8643   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8644 } pseudoBank;
8645
8646 /*----------------------------------------------------------------------*/
8647 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8648 /*----------------------------------------------------------------------*/
8649 unsigned int hashSymbol (const char *str)
8650 {
8651   unsigned int res = 0;
8652   if (!str) return 0;
8653
8654   while (*str) {
8655     res ^= (*str);
8656     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8657     str++;
8658   } // while
8659
8660   return res;
8661 }
8662
8663 /*-----------------------------------------------------------------------*/
8664 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8665 /*-----------------------------------------------------------------------*/
8666 int compareSymbol (const void *sym1, const void *sym2)
8667 {
8668   char *s1 = (char*) sym1;
8669   char *s2 = (char*) sym2;
8670
8671   return (strcmp (s1,s2) == 0);
8672 }
8673
8674 /*-----------------------------------------------------------------------*/
8675 /* comparePre - return 1 iff p1 == p2                                    */
8676 /*-----------------------------------------------------------------------*/
8677 int comparePtr (const void *p1, const void *p2)
8678 {
8679   return (p1 == p2);
8680 }
8681
8682 /*----------------------------------------------------------*/
8683 /* getSymbolFromOperand - return a pointer to the symbol in */
8684 /*                        the given operand and its length  */
8685 /*----------------------------------------------------------*/
8686 char *getSymbolFromOperand (char *op, int *len)
8687 {
8688   char *sym, *curr;
8689   *len = 0;
8690
8691   if (!op) return NULL;
8692
8693   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8694   sym = op;
8695   if (*sym == '(') sym++;
8696
8697   curr = sym;
8698   while (((*curr >= 'A') && (*curr <= 'Z'))
8699          || ((*curr >= 'a') && (*curr <= 'z'))
8700          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8701          || (*curr == '_')) {
8702     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8703     curr++;
8704     (*len)++;
8705   } // while
8706
8707   return sym;
8708 }
8709
8710 /*--------------------------------------------------------------------------*/
8711 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8712 /*--------------------------------------------------------------------------*/
8713 char *getSymFromBank (pseudoBankNr bank)
8714 {
8715   assert (bank2sym);
8716
8717   if (bank < 0) return "<INVALID BANK NR>";
8718   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8719 }
8720
8721 /*-----------------------------------------------------------------------*/
8722 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8723 /*                           bank number (uses hTab sym2bank), if the    */
8724 /*                           symbol is not yet assigned a pseudo bank it */
8725 /*                           is assigned one here                        */
8726 /*-----------------------------------------------------------------------*/
8727 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8728 {
8729   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8730   pseudoBankNr bank;
8731   unsigned int hash;
8732
8733   assert (sym2bank);
8734
8735   hash = hashSymbol (op) % sym2bank->size;
8736   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8737   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8738
8739   if (bank == UNKNOWN_BANK) {
8740     // create a pseudo bank for the operand
8741     bank = next_bank++;
8742     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8743     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8744     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8745     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8746   } else {
8747     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8748   } // if
8749
8750   assert (bank >= 0);
8751
8752   return bank;
8753 }
8754
8755 /*--------------------------------------------------------------------*/
8756 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8757 /*--------------------------------------------------------------------*/
8758 int isBanksel (pCode *pc)
8759 {
8760   if (!pc) return 0;
8761
8762   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8763     // BANKSEL <variablename>  or  MOVLB <banknr>
8764     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8765     return 1;
8766   }
8767
8768   // check for inline assembler BANKSELs
8769   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8770                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8771     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8772     return 1;
8773   }
8774
8775   // assume pc is no BANKSEL instruction
8776   return 0;
8777 }
8778
8779 /*---------------------------------------------------------------------------------*/
8780 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8781 /*                  This method can not guarantee to find all modifications of the */
8782 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8783 /*                  generated plus some cases.                                     */
8784 /*---------------------------------------------------------------------------------*/
8785 int invalidatesBSR(pCode *pc)
8786 {
8787   // assembler directives invalidate BSR (well, they might, we don't know)
8788   if (isPCAD(pc)) return 1;
8789
8790   // only ASMDIRs and pCodeInstructions can invalidate BSR
8791   if (!isPCI(pc)) return 0;
8792
8793   // we have a pCodeInstruction
8794
8795   // check for BSR modifying instructions
8796   switch (PCI(pc)->op) {
8797   case POC_CALL:
8798   case POC_RCALL:
8799   case POC_MOVLB:
8800   case POC_RETFIE:  // might be used as CALL replacement
8801   case POC_RETLW:   // might be used as CALL replacement
8802   case POC_RETURN:  // might be used as CALL replacement
8803   case POC_BANKSEL:
8804     return 1;
8805     break;
8806
8807   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8808     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8809     break;
8810   } // switch
8811
8812   // no change of BSR possible/probable
8813   return 0;
8814 }
8815
8816 /*------------------------------------------------------------*/
8817 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8818 /*                      the symbol referenced in this BANKSEL */
8819 /*------------------------------------------------------------*/
8820 pseudoBankNr getBankFromBanksel (pCode *pc)
8821 {
8822   char *sym;
8823   int data = 0;
8824
8825   if (!pc) return INVALID_BANK;
8826
8827   if (isPCAD(pc) && PCAD(pc)->directive) {
8828     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8829       // get symbolname from PCAD(pc)->arg
8830       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8831       sym = PCAD(pc)->arg;
8832       data = getPseudoBankNrFromOperand (sym);
8833       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8834     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8835       // get (literal) bank number from PCAD(pc)->arg
8836       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8837       assert (0 && "not yet implemented - turn off banksel optimization for now");
8838     }
8839   } else if (isPCI(pc)) {
8840     if (PCI(pc)->op == POC_BANKSEL) {
8841       // get symbolname from PCI(pc)->pcop->name (?)
8842       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8843       sym = PCI(pc)->pcop->name;
8844       data = getPseudoBankNrFromOperand (sym);
8845       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8846     } else if (PCI(pc)->op == POC_MOVLB) {
8847       // get (literal) bank number from PCI(pc)->pcop->name
8848       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8849       assert (0 && "not yet implemented - turn off banksel optimization for now");
8850     }
8851   }
8852
8853   if (data == 0)
8854     // no assigned bank could be found
8855     return UNKNOWN_BANK;
8856   else
8857     return data;
8858 }
8859
8860 /*------------------------------------------------------------------------------*/
8861 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8862 /*------------------------------------------------------------------------------*/
8863 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8864 {
8865   pseudoBank *data;
8866
8867   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8868
8869   do {
8870     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8871     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8872     if (data) {
8873       if (data->bank != bank)
8874         bank = data->bank;
8875       else
8876         data = NULL;
8877     }
8878   } while (data);
8879
8880   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8881   return bank;
8882 }
8883
8884 /*------------------------------------------------------------------*/
8885 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8886 /*                        bank is selected at a given pCode         */
8887 /*------------------------------------------------------------------*/
8888
8889 /* Create a graph with pseudo banks as its nodes and switches between
8890  * these as edges (with the edge weight representing the absolute
8891  * number of BANKSELs from one to the other).
8892  * Removes redundand BANKSELs instead iff mod == 1.
8893  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8894  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8895  * pseudo BSR.
8896  * TODO: check ALL instructions operands if they modify BSR directly...
8897  *
8898  * pb - the pBlock to annotate
8899  * mod  - select either graph creation (0) or BANKSEL removal (1)
8900  */
8901 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8902 {
8903   pCode *pc, *pc_next;
8904   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8905   int isBankselect = 0;
8906   unsigned int banksels=0;
8907
8908   if (!pb) return 0;
8909
8910   pc = pic16_findNextInstruction(pb->pcHead);
8911   while (pc) {
8912     isBankselect = isBanksel (pc);
8913     pc_next = pic16_findNextInstruction (pc->next);
8914
8915     if (!hasNoLabel (pc)) {
8916       // we don't know our predecessors -- assume different BSRs
8917       prevBSR = UNKNOWN_BANK;
8918       pseudoBSR = UNKNOWN_BANK;
8919       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8920     } // if
8921
8922     // check if this is a BANKSEL instruction
8923     if (isBankselect) {
8924       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8925       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8926       if (mod) {
8927         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8928           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8929           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8930           pic16_unlinkpCode (pc);
8931           banksels++;
8932         }
8933       } else {
8934         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8935         banksels++;
8936       }
8937     } // if
8938
8939     if (!isBankselect && invalidatesBSR(pc)) {
8940       // check if this instruction invalidates the pseudoBSR
8941       pseudoBSR = UNKNOWN_BANK;
8942       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8943     } // if
8944
8945     prevBSR = pseudoBSR;
8946     pc = pc_next;
8947   } // while
8948
8949   return banksels;
8950 }
8951
8952 /*------------------------------------------------------------------------------------*/
8953 /* assignToSameBank - returns 0 on success or an error code                           */
8954 /*  1 - common bank would be too large                                                */
8955 /*  2 - assignment to fixed (absolute) bank not performed                             */
8956 /*                                                                                    */
8957 /* This functions assumes that unsplittable operands are already assigned to the same */
8958 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
8959 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
8960 /* TODO: Symbols with an abslute address must be handled specially!                   */
8961 /*------------------------------------------------------------------------------------*/
8962 int assignToSameBank (int bank0, int bank1, int doAbs)
8963 {
8964   int eff0, eff1, dummy;
8965   pseudoBank *pbank0, *pbank1;
8966   hashtItem *hitem;
8967
8968   eff0 = getEffectiveBank (bank0);
8969   eff1 = getEffectiveBank (bank1);
8970
8971   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8972
8973   // nothing to do if already same bank
8974   if (eff0 == eff1) return 0;
8975
8976   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8977     return 2;
8978
8979   // ensure eff0 < eff1
8980   if (eff0 > eff1) {
8981     // swap eff0 and eff1
8982     dummy = eff0;
8983     eff0 = eff1;
8984     eff1 = dummy;
8985     dummy = bank0;
8986     bank0 = bank1;
8987     bank1 = dummy;
8988   } // if
8989
8990   // now assign bank eff1 to bank eff0
8991   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
8992   if (!pbank0) {
8993     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
8994     pbank0->bank = eff0;
8995     pbank0->size = 1;
8996     pbank0->ref = 1;
8997     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
8998   } // if
8999
9000   pbank1 = NULL;
9001   hitem = hTabSearch (coerce, eff1 % coerce->size);
9002   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9003     hitem = hitem->next;
9004
9005   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9006
9007 #if 0
9008   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9009            pbank0->bank, pbank0->size,
9010            getSymFromBank (eff0), getSymFromBank (eff1));
9011 #endif
9012
9013   if (pbank1) {
9014     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9015 #if 0
9016       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9017                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9018                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9019                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9020 #endif
9021       return 1;
9022     } // if
9023     pbank0->size += pbank1->size;
9024     pbank1->ref--;
9025     if (pbank1->ref == 0) Safe_free (pbank1);
9026   } else {
9027     pbank0->size++;
9028   } // if
9029
9030   if (hitem)
9031     hitem->item = pbank0;
9032   else
9033     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9034   pbank0->ref++;
9035
9036   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9037
9038   return 0;
9039 }
9040
9041 /*----------------------------------------------------------------*/
9042 /* mergeGraphNodes - combines two nodes into one and modifies all */
9043 /*                   edges to and from the nodes accordingly      */
9044 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9045 /* then also (B,A) must be an edge (possibly with weight 0).      */
9046 /*----------------------------------------------------------------*/
9047 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9048 {
9049   GraphEdge *edge, *backedge, *nextedge;
9050   GraphNode *node;
9051   int backweight;
9052
9053   assert (node1 && node2);
9054   assert (node1 != node2);
9055
9056   // add all edges starting at node2 to node1
9057   edge = node2->edge;
9058   while (edge) {
9059     nextedge = edge->next;
9060     node = edge->node;
9061     backedge = getGEdge (node, node2);
9062     if (backedge)
9063       backweight = backedge->weight;
9064     else
9065       backweight = 0;
9066     // insert edges (node1,node) and (node,node1)
9067     addGEdge2 (node1, node, edge->weight, backweight);
9068     // remove edges (node, node2) and (node2, node)
9069     remGEdge (node2, node);
9070     remGEdge (node, node2);
9071     edge = nextedge;
9072   } // while
9073
9074   // now node2 should not be referenced by any other GraphNode...
9075   //remGNode (adj, node2->data, node2->hash);
9076 }
9077
9078 /*----------------------------------------------------------------*/
9079 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9080 /*----------------------------------------------------------------*/
9081 void showGraph (Graph *g)
9082 {
9083   GraphNode *node;
9084   GraphEdge *edge;
9085   pseudoBankNr bankNr;
9086   pseudoBank *pbank;
9087   unsigned int size;
9088
9089   node = g->node;
9090   while (node) {
9091     edge = node->edge;
9092     bankNr = getEffectiveBank (node->hash);
9093     assert (bankNr >= 0);
9094     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9095     if (pbank) {
9096       bankNr = pbank->bank;
9097       size = pbank->size;
9098     } else {
9099       size = 1;
9100     }
9101
9102     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9103
9104     while (edge) {
9105       if (edge->weight > 0)
9106         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9107       edge = edge->next;
9108     } // while (edge)
9109     node = node->next;
9110   } // while (node)
9111 }
9112
9113 /*---------------------------------------------------------------*/
9114 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9115 /*---------------------------------------------------------------*/
9116 void pic16_OptimizeBanksel ()
9117 {
9118   GraphNode *node, *node1, *node1next;
9119
9120 #if 0
9121   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9122   GraphEdge *edge, *backedge;
9123   GraphEdge *max;
9124   int maxWeight, weight, mergeMore, absMaxWeight;
9125   pseudoBankNr curr0, curr1;
9126 #endif
9127   pseudoBank *pbank;
9128   pseudoBankNr bankNr;
9129   char *base_symbol0, *base_symbol1;
9130   int len0, len1;
9131   pBlock *pb;
9132   set *set;
9133   regs *reg;
9134   unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9135
9136   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9137
9138   if (!the_pFile || !the_pFile->pbHead) return;
9139
9140   adj = newGraph (NULL);
9141   sym2bank = newHashTable ( 255 );
9142   bank2sym = newHashTable ( 255 );
9143   coerce = newHashTable ( 255 );
9144
9145   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9146   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9147     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9148   } // for pb
9149
9150 #if 1
9151   // assign symbols with absolute addresses to their respective bank nrs
9152   set = pic16_fix_udata;
9153   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9154     bankNr = reg->address >> 8;
9155     node = getOrAddGNode (adj, NULL, bankNr);
9156     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9157     assignToSameBank (node->hash, bankNr, 1);
9158
9159     assert (bankNr >= 0);
9160     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9161     if (!pbank) {
9162       pbank = Safe_calloc (1, sizeof (pseudoBank));
9163       pbank->bank = reg->address >> 8; //FIXED_BANK;
9164       pbank->size = 1;
9165       pbank->ref = 1;
9166       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9167     } else {
9168       assert (pbank->bank == (reg->address >> 8));
9169       pbank->bank = reg->address >> 8; //FIXED_BANK;
9170     }
9171     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9172   } // for reg
9173 #endif
9174
9175 #if 1
9176   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9177   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9178   node = adj->node;
9179   while (node) {
9180     if (node->hash < 0) { node = node->next; continue; }
9181     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9182     node1 = node->next;
9183     while (node1) {
9184       if (node1->hash < 0) { node1 = node1->next; continue; }
9185       node1next = node1->next;
9186       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9187       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9188         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9189         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9190         if (assignToSameBank (node->hash, node1->hash, 0)) {
9191           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9192           assert (0 && "Could not assign a symbol to a bank!");
9193         }
9194         mergeGraphNodes (node, node1);
9195         /*
9196         if (node->hash < node1->hash)
9197           mergeGraphNodes (node, node1);
9198         else
9199           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9200         */
9201       } // if
9202       node1 = node1next;
9203     } // while (node1)
9204     node = node->next;
9205   } // while (node)
9206 #endif
9207
9208 #if 0
9209   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9210   // assign tightly coupled operands to the same (pseudo) bank
9211   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9212   mergeMore = 1;
9213   absMaxWeight = 0;
9214   while (mergeMore) {
9215     node = adj->node;
9216     max = NULL;
9217     maxWeight = 0;
9218     while (node) {
9219       curr0 = getEffectiveBank (node->hash);
9220       if (curr0 < 0) { node = node->next; continue; }
9221       edge = node->edge;
9222       while (edge) {
9223         assert (edge->src == node);
9224         backedge = getGEdge (edge->node, edge->src);
9225         weight = edge->weight + (backedge ? backedge->weight : 0);
9226         curr1 = getEffectiveBank (edge->node->hash);
9227         if (curr1 < 0) { edge = edge->next; continue; }
9228
9229         // merging is only useful if the items are not assigned to the same bank already...
9230         if (curr0 != curr1 && weight > maxWeight) {
9231           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9232           maxWeight = weight;
9233           max = edge;
9234         } // if
9235         edge = edge->next;
9236       } // while
9237       node = node->next;
9238     } // while
9239
9240     if (maxWeight > 0) {
9241 #if 0
9242       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9243                max->src->hash, getSymFromBank (max->src->hash),
9244                max->node->hash, getSymFromBank (max->node->hash));
9245 #endif
9246
9247       node = getGNode (adj, max->src->data, max->src->hash);
9248       node1 = getGNode (adj, max->node->data, max->node->hash);
9249
9250       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9251         if (max->src->hash < max->node->hash)
9252           mergeGraphNodes (node, node1);
9253         else
9254           mergeGraphNodes (node1, node);
9255       } else {
9256         remGEdge (node, node1);
9257         remGEdge (node1, node);
9258         //mergeMore = 0;
9259       }
9260
9261     } else {
9262       mergeMore = 0;
9263     }
9264   } // while
9265 #endif
9266
9267 #if 1
9268   // remove redundant BANKSELs
9269   //fprintf (stderr, "removing redundant BANKSELs\n");
9270   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9271     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9272   } // for pb
9273 #endif
9274
9275 #if 0
9276   fprintf (stderr, "display graph\n");
9277   showGraph ();
9278 #endif
9279
9280   deleteGraph (adj);
9281   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9282 }
9283
9284 /*** END of stuff belonging to the BANKSEL optimization ***/
9285
9286
9287
9288 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9289
9290 typedef unsigned int symbol_t;
9291 typedef unsigned int valnum_t;
9292 //typedef unsigned int hash_t;
9293
9294 #ifndef INT_TO_PTR
9295 #define INT_TO_PTR(x) (((char *) 0) + (x))
9296 #endif
9297
9298 #ifndef PTR_TO_INT
9299 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9300 #endif
9301
9302 static int pic16_regIsLocal (regs *r);
9303 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9304
9305 /* statistics */
9306 static unsigned int pic16_df_removed_pcodes = 0;
9307 static unsigned int pic16_df_saved_bytes = 0;
9308 static unsigned int df_findall_sameflow = 0;
9309 static unsigned int df_findall_otherflow = 0;
9310 static unsigned int df_findall_in_vals = 0;
9311
9312 static void pic16_df_stats () {
9313   return;
9314   if (pic16_debug_verbose || pic16_pcode_verbose) {
9315     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9316     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9317     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9318   }
9319 }
9320
9321 /* Remove a pCode iff possible:
9322  * - previous pCode is no SKIP
9323  * - pc has no label
9324  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9325 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9326   pCode *pcprev, *pcnext;
9327   char buf[256], *total=NULL;
9328   int len;
9329
9330   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9331
9332   pcprev = pic16_findPrevInstruction (pc->prev);
9333   pcnext = pic16_findNextInstruction (pc->next);
9334
9335   /* move labels to next instruction (if possible) */
9336   if (PCI(pc)->label && !pcnext) return 0;
9337
9338   /* if this is a SKIP with side-effects -- do not remove */
9339   /* XXX: might try to replace this one with the side-effect only version */
9340   if (isPCI_SKIP(pc)
9341         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9342   {
9343     pCode *newpc;
9344     switch (PCI(pc)->op)
9345     {
9346     case POC_INCFSZ:
9347     case POC_INFSNZ:
9348       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9349       pic16_pCodeReplace( pc, newpc );
9350       return 1;
9351       break;
9352     case POC_INCFSZW:
9353       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9354       pic16_pCodeReplace( pc, newpc );
9355       return 1;
9356       break;
9357     case POC_DECFSZ:
9358     case POC_DCFSNZ:
9359       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9360       pic16_pCodeReplace( pc, newpc );
9361       return 1;
9362       break;
9363     case POC_DECFSZW:
9364       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9365       pic16_pCodeReplace( pc, newpc );
9366       return 1;
9367       break;
9368     default:
9369       return 0;
9370     }
9371     return 0;
9372   }
9373
9374   /* if previous instruction is a skip -- do not remove */
9375   if (pcprev && isPCI_SKIP(pcprev)) {
9376     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9377       /* preceeding SKIP could not be removed -- keep this instruction! */
9378       return 0;
9379     }
9380   }
9381
9382   if (PCI(pc)->label) {
9383     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9384     //pc->print (stderr, pc);
9385     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9386     PCI(pc)->label = NULL;
9387   }
9388
9389   /* update statistics */
9390   pic16_df_removed_pcodes++;
9391   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9392
9393   /* remove the pCode */
9394   pic16_pCode2str (buf, 256, pc);
9395   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9396   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9397     len = strlen (buf) + strlen (comment) + 10;
9398     total = (char *) Safe_malloc (len);
9399     SNPRINTF (total, len, "%s: %s", comment, buf);
9400     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9401     Safe_free (total);
9402   }
9403
9404   /* actually unlink it from the pBlock -- also remove from to/from lists */
9405   pic16_pCodeUnlink (pc);
9406
9407   /* remove the pCode -- release registers */
9408   pc->destruct (pc);
9409
9410   /* report success */
9411   return 1;
9412 }
9413
9414
9415 /* ======================================================================== */
9416 /* === SYMBOL HANDLING ==================================================== */
9417 /* ======================================================================== */
9418
9419 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9420 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9421 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9422
9423 /** Calculate a hash for a given string.
9424  * If len == 0 the string is assumed to be NUL terminated. */
9425 static hash_t symbolHash (const char *str, unsigned int len) {
9426   hash_t hash = 0;
9427   if (!len) {
9428     while (*str) {
9429       hash = (hash << 2) ^ *str;
9430       str++;
9431     } // while
9432   } else {
9433     while (len--) {
9434       hash = (hash << 2) ^ *str;
9435       str++;
9436     }
9437   }
9438   return hash;
9439 }
9440
9441 /** Return 1 iff strings v1 and v2 are identical. */
9442 static int symcmp (const void *v1, const void *v2) {
9443   return !strcmp ((const char *) v1, (const char *) v2);
9444 }
9445
9446 /** Return 1 iff pointers v1 and v2 are identical. */
9447 static int ptrcmp (const void *v1, const void *v2) {
9448   return (v1 == v2);
9449 }
9450
9451 enum {  SPO_WREG=0x1000,
9452         SPO_STATUS,
9453         SPO_PRODL,
9454         SPO_PRODH,
9455         SPO_INDF0,
9456         SPO_POSTDEC0,
9457         SPO_POSTINC0,
9458         SPO_PREINC0,
9459         SPO_PLUSW0,
9460         SPO_INDF1,
9461         SPO_POSTDEC1,
9462         SPO_POSTINC1,
9463         SPO_PREINC1,
9464         SPO_PLUSW1,
9465         SPO_INDF2,
9466         SPO_POSTDEC2,
9467         SPO_POSTINC2,
9468         SPO_PREINC2,
9469         SPO_PLUSW2,
9470         SPO_STKPTR,
9471         SPO_TOSL,
9472         SPO_TOSH,
9473         SPO_TOSU,
9474         SPO_BSR,
9475         SPO_FSR0L,
9476         SPO_FSR0H,
9477         SPO_FSR1L,
9478         SPO_FSR1H,
9479         SPO_FSR2L,
9480         SPO_FSR2H,
9481         SPO_PCL,
9482         SPO_PCLATH,
9483         SPO_PCLATU,
9484         SPO_TABLAT,
9485         SPO_TBLPTRL,
9486         SPO_TBLPTRH,
9487         SPO_TBLPTRU,
9488         SPO_LAST
9489 };
9490
9491 /* Return the unique symbol_t for the given string. */
9492 static symbol_t symFromStr (const char *str) {
9493   hash_t hash;
9494   char *res;
9495   symbol_t sym;
9496
9497   if (!map_symToStr) {
9498     int i;
9499     struct { char *name; symbol_t sym; } predefsyms[] = {
9500         {"WREG", SPO_WREG},
9501         {"STATUS", SPO_STATUS},
9502         {"PRODL", SPO_PRODL},
9503         {"PRODH", SPO_PRODH},
9504         {"INDF0", SPO_INDF0},
9505         {"POSTDEC0", SPO_POSTDEC0},
9506         {"POSTINC0", SPO_POSTINC0},
9507         {"PREINC0", SPO_PREINC0},
9508         {"PLUSW0", SPO_PLUSW0},
9509         {"INDF1", SPO_INDF1},
9510         {"POSTDEC1", SPO_POSTDEC1},
9511         {"POSTINC1", SPO_POSTINC1},
9512         {"PREINC1", SPO_PREINC1},
9513         {"PLUSW1", SPO_PLUSW1},
9514         {"INDF2", SPO_INDF2},
9515         {"POSTDEC2", SPO_POSTDEC2},
9516         {"POSTINC2", SPO_POSTINC2},
9517         {"PREINC2", SPO_PREINC2},
9518         {"PLUSW2", SPO_PLUSW2},
9519         {"STKPTR", SPO_STKPTR},
9520         {"TOSL", SPO_TOSL},
9521         {"TOSH", SPO_TOSH},
9522         {"TOSU", SPO_TOSU},
9523         {"BSR", SPO_BSR},
9524         {"FSR0L", SPO_FSR0L},
9525         {"FSR0H", SPO_FSR0H},
9526         {"FSR1L", SPO_FSR1L},
9527         {"FSR1H", SPO_FSR1H},
9528         {"FSR2L", SPO_FSR2L},
9529         {"FSR2H", SPO_FSR2H},
9530         {"PCL", SPO_PCL},
9531         {"PCLATH", SPO_PCLATH},
9532         {"PCLATU", SPO_PCLATU},
9533         {"TABLAT", SPO_TABLAT},
9534         {"TBLPTRL", SPO_TBLPTRL},
9535         {"TBLPTRH", SPO_TBLPTRH},
9536         {"TBLPTRU", SPO_TBLPTRU},
9537         {NULL, 0}
9538     };
9539
9540     map_strToSym = newHashTable (128);
9541     map_symToStr = newHashTable (128);
9542
9543     for (i=0; predefsyms[i].name; i++) {
9544       char *name;
9545
9546       /* enter new symbol */
9547       sym = predefsyms[i].sym;
9548       name = predefsyms[i].name;
9549       res = Safe_strdup (name);
9550       hash = symbolHash (name, 0);
9551
9552       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9553       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9554     } // for i
9555   }
9556
9557   hash = symbolHash (str, 0) % map_strToSym->size;
9558
9559   /* find symbol in table */
9560   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9561   if (sym) {
9562     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9563     return sym;
9564   }
9565
9566   /* enter new symbol */
9567   sym = nextSymbol++;
9568   res = Safe_strdup (str);
9569
9570   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9571   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9572
9573   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9574
9575   return sym;
9576 }
9577
9578 #if 1
9579 static const char *strFromSym (symbol_t sym) {
9580   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9581 }
9582 #endif
9583
9584 /* ======================================================================== */
9585 /* === DEFINITION MAP HANDLING ============================================ */
9586 /* ======================================================================== */
9587
9588 /* A defmap provides information about which symbol is defined by which pCode.
9589  * The most recent definitions are prepended to the list, so that the most
9590  * recent definition can be found by forward scanning the list.
9591  * pc2: MOVFF r0x00, r0x01
9592  * pc1: INCF r0x01
9593  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9594  *
9595  * We attach one defmap to each flow object, and each pCode will occur at
9596  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9597  * used to find definitions for a pCode in its own defmap that precede pCode.
9598  */
9599
9600 typedef struct defmap_s {
9601   symbol_t sym;                 /** symbol this item refers to */
9602   union {
9603     struct {
9604       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9605       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9606       int isRead:1;             /** sym/mask is read */
9607       int isWrite:1;            /** sym/mask is written */
9608     } access;
9609     int accessmethod;
9610   } acc;
9611   pCode *pc;                    /** pCode this symbol is refrenced at */
9612   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9613   valnum_t val;                 /** new unique number for this value (if isWrite) */
9614   struct defmap_s *prev, *next; /** link to previous an next definition */
9615 } defmap_t;
9616
9617 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9618 static int defmap_free_count = 0;               /** number of released defmap items */
9619
9620 /* Returns a defmap_t with the specified data; this will be the new list head.
9621  * next - pointer to the current list head */
9622 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9623   defmap_t *map;
9624
9625   if (defmap_free) {
9626     map = defmap_free;
9627     defmap_free = map->next;
9628     --defmap_free_count;
9629   } else {
9630     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9631   }
9632   map->sym = sym;
9633   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9634   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9635   map->acc.access.isRead = (isRead != 0);
9636   map->acc.access.isWrite = (isWrite != 0);
9637   map->pc = pc;
9638   map->in_val = 0;
9639   map->val = (isWrite ? val : 0);
9640   map->prev = NULL;
9641   map->next = next;
9642   if (next) next->prev = map;
9643
9644   return map;
9645 }
9646
9647 /* Returns a copy of the single defmap item. */
9648 static defmap_t *copyDefmap (defmap_t *map) {
9649   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9650   memcpy (res, map, sizeof (defmap_t));
9651   res->next = NULL;
9652   res->prev = NULL;
9653   return res;
9654 }
9655
9656 /* Insert a defmap item after the specified one. */
9657 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9658   if (!ref || !newItem) return 1;
9659
9660   newItem->next = ref->next;
9661   newItem->prev = ref;
9662   ref->next = newItem;
9663   if (newItem->next) newItem->next->prev = newItem;
9664
9665   return 0;
9666 }
9667
9668 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9669  * item is copied before insertion into chain and therefore left untouched.
9670  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9671 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9672   defmap_t *dummy;
9673   dummy = *head;
9674   while (dummy && (dummy->sym != item->sym
9675                           || dummy->pc != item->pc
9676                           || dummy->acc.accessmethod != item->acc.accessmethod
9677                           || dummy->val != item->val
9678                           || dummy->in_val != item->in_val)) {
9679     dummy = dummy->next;
9680   } // while
9681
9682   /* item already present? */
9683   if (dummy) return 0;
9684
9685   /* otherwise: insert copy of item */
9686   dummy = copyDefmap (item);
9687   dummy->next = *head;
9688   if (*head) (*head)->prev = dummy;
9689   *head = dummy;
9690
9691   return 1;
9692 }
9693
9694 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9695 static void deleteDefmap (defmap_t *map) {
9696   if (!map) return;
9697
9698   /* unlink from chain -- fails for the first item (head is not updated!) */
9699   if (map->next) map->next->prev = map->prev;
9700   if (map->prev) map->prev->next = map->next;
9701
9702   /* clear map */
9703   memset (map, 0, sizeof (defmap_t));
9704
9705   /* save for future use */
9706   map->next = defmap_free;
9707   defmap_free = map;
9708   ++defmap_free_count;
9709 }
9710
9711 /* Release all defmaps referenced from map. */
9712 static void deleteDefmapChain (defmap_t **_map) {
9713   defmap_t *map, *next;
9714
9715   if (!_map) return;
9716
9717   map = *_map;
9718
9719   /* find list head */
9720   while (map && map->prev) map = map->prev;
9721
9722   /* delete all items */
9723   while (map) {
9724     next = map->next;
9725     deleteDefmap (map);
9726     map = next;
9727   } // while
9728
9729   *_map = NULL;
9730 }
9731
9732 /* Free all defmap items. */
9733 static void freeDefmap (defmap_t **_map) {
9734   defmap_t *next;
9735   defmap_t *map;
9736
9737   if (!_map) return;
9738
9739   map = (*_map);
9740
9741   /* find list head */
9742   while (map->prev) map = map->prev;
9743
9744   /* release all items */
9745   while (map) {
9746     next = map->next;
9747     Safe_free (map);
9748     map = next;
9749   }
9750
9751   (*_map) = NULL;
9752 }
9753
9754 /* Returns the most recent definition for the given symbol preceeding pc.
9755  * If no definition is found, NULL is returned.
9756  * If pc == NULL the whole list is scanned. */
9757 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9758   defmap_t *curr = map;
9759
9760   if (pc) {
9761     /* skip all definitions up to pc */
9762     while (curr && (curr->pc != pc)) curr = curr->next;
9763
9764     /* pc not in the list -- scan the whole list for definitions */
9765     if (!curr) {
9766       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9767       curr = map;
9768     } else {
9769       /* skip all definitions performed by pc */
9770       while (curr && (curr->pc == pc)) curr = curr->next;
9771     }
9772   } // if (pc)
9773
9774   /* find definition for sym */
9775   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9776     curr = curr->next;
9777   }
9778
9779   return curr;
9780 }
9781
9782 #if 0
9783 /* Returns the first use (read) of the given symbol AFTER pc.
9784  * If no such use is found, NULL is returned.
9785  * If pc == NULL the whole list is scanned. */
9786 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9787   defmap_t *curr = map, *prev = NULL;
9788
9789   if (pc) {
9790     /* skip all definitions up to pc */
9791     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9792
9793     /* pc not in the list -- scan the whole list for definitions */
9794     if (!curr) {
9795       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9796       curr = prev;
9797     }
9798   } else {
9799     /* find end of list */
9800     while (curr && curr->next) curr = curr->next;
9801   } // if (pc)
9802
9803   /* find use of sym (scan list backwards) */
9804   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9805
9806   return curr;
9807 }
9808 #endif
9809
9810 /* Return the defmap entry for sym AT pc.
9811  * If none is found, NULL is returned.
9812  * If more than one entry is found an assertion is triggered. */
9813 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9814   defmap_t *res = NULL;
9815
9816   /* find entries for pc */
9817   while (map && map->pc != pc) map = map->next;
9818
9819   /* find first entry for sym @ pc */
9820   while (map && map->pc == pc && map->sym != sym) map = map->next;
9821
9822   /* no entry found */
9823   if (!map) return NULL;
9824
9825   /* check for more entries */
9826   res = map;
9827   map = map->next;
9828   while (map && map->pc == pc) {
9829     /* more than one entry for sym @ pc found? */
9830     assert (map->sym != sym);
9831     map = map->next;
9832   }
9833
9834   /* return single entry for sym @ pc */
9835   return res;
9836 }
9837
9838 /* Modifies the definition of sym at pCode to newval.
9839  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9840  */
9841 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9842   defmap_t *m  = map;
9843
9844   /* find definitions of pc */
9845   while (m && m->pc != pc) m = m->next;
9846
9847   /* find definition of sym at pc */
9848   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9849
9850   /* no definition found */
9851   if (!m) return 1;
9852
9853   /* redefine */
9854   m->val = newval;
9855
9856   /* update following uses of sym */
9857   while (m && m->pc == pc) m = m->prev;
9858   while (m) {
9859     if (m->sym == sym) {
9860       m->in_val = newval;
9861       if (m->acc.access.isWrite) m = NULL;
9862     } // if
9863     if (m) m = m->prev;
9864   } // while
9865
9866   return 0;
9867 }
9868
9869 /* ======================================================================== */
9870 /* === STACK ROUTINES ===================================================== */
9871 /* ======================================================================== */
9872
9873 typedef struct stack_s {
9874   void *data;
9875   struct stack_s *next;
9876 } stackitem_t;
9877
9878 typedef stackitem_t *dynstack_t;
9879 static stackitem_t *free_stackitems = NULL;
9880
9881 /* Create a stack with one item. */
9882 static dynstack_t *newStack () {
9883   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9884   *s = NULL;
9885   return s;
9886 }
9887
9888 /* Remove a stack -- its items are only marked free. */
9889 static void deleteStack (dynstack_t *s) {
9890   stackitem_t *i;
9891
9892   while (*s) {
9893     i = *s;
9894     *s = (*s)->next;
9895     i->next = free_stackitems;
9896     free_stackitems = i;
9897   } // while
9898   Safe_free (s);
9899 }
9900
9901 /* Release all stackitems. */
9902 static void releaseStack () {
9903   stackitem_t *i;
9904
9905   while (free_stackitems) {
9906     i = free_stackitems->next;
9907     Safe_free(free_stackitems);
9908     free_stackitems = i;
9909   } // while
9910 }
9911
9912 static void stackPush (dynstack_t *stack, void *data) {
9913   stackitem_t *i;
9914
9915   if (free_stackitems) {
9916     i = free_stackitems;
9917     free_stackitems = free_stackitems->next;
9918   } else {
9919     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9920   }
9921   i->data = data;
9922   i->next = *stack;
9923   *stack = i;
9924 }
9925
9926 static void *stackPop (dynstack_t *stack) {
9927   void *data;
9928   stackitem_t *i;
9929
9930   if (stack && *stack) {
9931     data = (*stack)->data;
9932     i = *stack;
9933     *stack = (*stack)->next;
9934     i->next = free_stackitems;
9935     free_stackitems = i;
9936     return data;
9937   } else {
9938     return NULL;
9939   }
9940 }
9941
9942 #if 0
9943 static int stackContains (dynstack_t *s, void *data) {
9944   stackitem_t *i;
9945   if (!s) return 0;
9946   i = *s;
9947   while (i) {
9948     if (i->data == data) return 1;
9949     i = i->next;
9950   } // while
9951
9952   /* not found */
9953   return 0;
9954 }
9955 #endif
9956
9957 static int stackIsEmpty (dynstack_t *s) {
9958   return (*s == NULL);
9959 }
9960
9961
9962 typedef struct {
9963   pCodeFlow *flow;
9964   defmap_t *lastdef;
9965 } state_t;
9966
9967 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9968   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9969   s->flow = flow;
9970   s->lastdef = lastdef;
9971   return s;
9972 }
9973
9974 static void deleteState (state_t *s) {
9975   Safe_free (s);
9976 }
9977
9978 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9979   stackitem_t *i;
9980
9981   /* scan working list for state */
9982   if (todo) {
9983     i = *todo;
9984     while (i) {
9985       /* is i == state? -- state not new */
9986       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
9987       i = i->next;
9988     } // while
9989   }
9990
9991   if (done) {
9992     i = *done;
9993     while (i) {
9994       /* is i == state? -- state not new */
9995       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
9996       i = i->next;
9997     } // while
9998   }
9999
10000   /* not found -- state is new */
10001   return 1;
10002 }
10003
10004 static inline valnum_t newValnum ();
10005
10006 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10007   pCode *pc;
10008
10009   if (!pb) return "<unknown function>";
10010
10011   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10012   if (pc && isPCF(pc)) return PCF(pc)->fname;
10013   else return "<unknown function>";
10014 }
10015
10016 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10017   defmap_t *map;
10018   pCodeFlow *pcfl;
10019
10020   assert(pb);
10021
10022   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10023
10024   /* find initial value (assigning pc == NULL) */
10025   map = PCFL(pcfl)->in_vals;
10026   while (map && map->sym != sym) map = map->next;
10027
10028   /* initial value already present? */
10029   if (map) {
10030     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10031     return map;
10032   }
10033
10034   /* create a new initial value */
10035   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10036   PCFL(pcfl)->in_vals = map;
10037   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10038   return map;
10039
10040 #if 0
10041   /* insert map as last item in pcfl's defmap */
10042   if (!prev) prev = PCFL(pcfl)->defmap;
10043   if (!prev) {
10044     PCFL(pcfl)->defmap = map;
10045   } else {
10046     while (prev->next) prev = prev->next;
10047     prev->next = map;
10048     map->prev = prev;
10049   }
10050
10051   return map;
10052 #endif
10053 }
10054
10055 /* Find all reaching definitions for sym at pc.
10056  * A new (!) list of definitions is returned.
10057  * Returns the number of reaching definitions found.
10058  * The defining defmap entries are returned in *chain.
10059  */
10060 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10061   defmap_t *map;
10062   defmap_t *res;
10063
10064   pCodeFlow *curr;
10065   pCodeFlowLink *succ;
10066   state_t *state;
10067   dynstack_t *todo;     /** stack of state_t */
10068   dynstack_t *done;     /** stack of state_t */
10069
10070   int firstState, n_defs;
10071
10072   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10073   assert (chain);
10074
10075   /* initialize return list */
10076   *chain = NULL;
10077
10078   /* wildcard symbol? */
10079   if (!sym) return 0;
10080
10081   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10082
10083   map = PCI(pc)->pcflow->defmap;
10084
10085   res = defmapFindDef (map, sym, pc);
10086   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10087
10088 #define USE_PRECALCED_INVALS 1
10089 #if USE_PRECALCED_INVALS
10090   if (!res && PCI(pc)->pcflow->in_vals) {
10091     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10092     if (res) {
10093       //fprintf  (stderr, "found def in init values\n");
10094       df_findall_in_vals++;
10095     }
10096   }
10097 #endif
10098
10099   if (res) {
10100     // found a single definition (in pc's flow)
10101     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10102     defmapAddCopyIfNew (chain, res);
10103     df_findall_sameflow++;
10104     return 1;
10105   }
10106
10107 #if USE_PRECALCED_INVALS
10108   else {
10109     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10110     return 1;
10111   }
10112
10113 #endif
10114
10115 #define FORWARD_FLOW_ANALYSIS 1
10116 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10117   /* no definition found in pc's flow preceeding pc */
10118   todo = newStack ();
10119   done = newStack ();
10120   n_defs = 0; firstState = 1;
10121   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10122
10123   while (!stackIsEmpty (todo)) {
10124     state = (state_t *) stackPop (todo);
10125     stackPush (done, state);
10126     curr = state->flow;
10127     res = state->lastdef;
10128     //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);
10129
10130     /* there are no definitions BEFORE pc in pc's flow (see above) */
10131     if (curr == PCI(pc)->pcflow) {
10132       if (!res) {
10133         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10134         res = pic16_pBlockAddInval (pc->pb, sym);
10135         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10136         res = NULL;
10137       } else {
10138         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10139         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10140       }
10141     }
10142
10143     /* save last definition of sym in this flow as initial def in successors */
10144     res = defmapFindDef (curr->defmap, sym, NULL);
10145     if (!res) res = state->lastdef;
10146
10147     /* add successors to working list */
10148     state = newState (NULL, NULL);
10149     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10150     while (succ) {
10151       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10152       state->flow = succ->pcflow;
10153       state->lastdef = res;
10154       if (stateIsNew (state, todo, done)) {
10155         stackPush (todo, state);
10156         state = newState (NULL, NULL);
10157       } // if
10158       succ = (pCodeFlowLink *) setNextItem (curr->to);
10159     } // while
10160     deleteState (state);
10161   } // while
10162
10163 #else // !FORWARD_FLOW_ANALYSIS
10164
10165   /* no definition found in pc's flow preceeding pc */
10166   todo = newStack ();
10167   done = newStack ();
10168   n_defs = 0; firstState = 1;
10169   stackPush (todo, newState (PCI(pc)->pcflow, res));
10170
10171   while (!stackIsEmpty (todo)) {
10172     state = (state_t *) stackPop (todo);
10173     curr = state->flow;
10174
10175     if (firstState) {
10176       firstState = 0;
10177       /* only check predecessor flows */
10178     } else {
10179       /* get (last) definition of sym in this flow */
10180       res = defmapFindDef (curr->defmap, sym, NULL);
10181     }
10182
10183     if (res) {
10184       /* definition found */
10185       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10186       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10187     } else {
10188       /* no definition found -- check predecessor flows */
10189       state = newState (NULL, NULL);
10190       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10191
10192       /* if no flow predecessor available -- sym might be uninitialized */
10193       if (!succ) {
10194         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10195         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10196         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10197         deleteDefmap (res); res = NULL;
10198       }
10199
10200       while (succ) {
10201         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10202         state->flow = succ->pcflow;
10203         state->lastdef = res;
10204         if (stateIsNew (state, todo, done)) {
10205           stackPush (todo, state);
10206           state = newState (NULL, NULL);
10207         } // if
10208         succ = (pCodeFlowLink *) setNextItem (curr->from);
10209       } // while
10210       deleteState (state);
10211     }
10212   } // while
10213
10214 #endif
10215
10216   /* clean up done stack */
10217   while (!stackIsEmpty(done)) {
10218     deleteState ((state_t *) stackPop (done));
10219   } // while
10220   deleteStack (done);
10221
10222   /* return number of items in result set */
10223   if (n_defs == 0) {
10224     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10225   } else if (n_defs == 1) {
10226     assert (*chain);
10227     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10228   } else if (n_defs > 0) {
10229     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10230 #if 0
10231     res = *chain;
10232     while (res) {
10233       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10234       res = res->next;
10235     } // while
10236 #endif
10237   }
10238   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10239   df_findall_otherflow++;
10240   return n_defs;
10241 }
10242
10243 /* ======================================================================== */
10244 /* === VALUE NUMBER HANDLING ============================================== */
10245 /* ======================================================================== */
10246
10247 static valnum_t nextValnum = 0x1000;
10248 static hTab *map_symToValnum = NULL;
10249
10250 /** Return a new value number. */
10251 static inline valnum_t newValnum () {
10252   return (nextValnum += 4);
10253 }
10254
10255 static valnum_t valnumFromStr (const char *str) {
10256   symbol_t sym;
10257   valnum_t val;
10258   void *res;
10259
10260   sym = symFromStr (str);
10261
10262   if (!map_symToValnum) {
10263     map_symToValnum = newHashTable (128);
10264   } // if
10265
10266   /* literal already known? */
10267   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10268
10269   /* return existing valnum */
10270   if (res) return (valnum_t) PTR_TO_INT(res);
10271
10272   /* create new valnum */
10273   val = newValnum();
10274   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10275   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10276   return val;
10277 }
10278
10279 /* Create a valnum for a literal. */
10280 static valnum_t valnumFromLit (unsigned int lit) {
10281   return ((valnum_t) 0x100 + (lit & 0x0FF));
10282 }
10283
10284 /* Return the (positive) literal value represented by val
10285  * or -1 iff val is no known literal's valnum. */
10286 static int litFromValnum (valnum_t val) {
10287   if (val >= 0x100 && val < 0x200) {
10288     /* valnum is a (known) literal */
10289     return val & 0x00FF;
10290   } else {
10291     /* valnum is not a known literal */
10292     return -1;
10293   }
10294 }
10295
10296 #if 0
10297 /* Sanity check - all flows in a block must be reachable from initial flow. */
10298 static int verifyAllFlowsReachable (pBlock *pb) {
10299   set *reached;
10300   set *flowInBlock;
10301   set *checked;
10302   pCode *pc;
10303   pCodeFlow *pcfl;
10304   pCodeFlowLink *succ;
10305   int res;
10306
10307   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10308
10309   reached = NULL;
10310   flowInBlock = NULL;
10311   checked = NULL;
10312   /* mark initial flow as reached (and "not needs to be reached") */
10313   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10314   assert (pc);
10315   addSetHead (&reached, pc);
10316   addSetHead (&checked, pc);
10317
10318   /* mark all further flows in block as "need to be reached" */
10319   pc = pb->pcHead;
10320   do {
10321     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10322     pc = pic16_findNextInstruction (pc->next);
10323   } while (pc);
10324
10325   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10326     /* mark as reached and "not need to be reached" */
10327     deleteSetItem (&reached, pcfl);
10328     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10329
10330     /* flow is no longer considered unreachable */
10331     deleteSetItem (&flowInBlock, pcfl);
10332
10333     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10334       if (!isinSet (checked, succ->pcflow)) {
10335         /* flow has never been reached before */
10336         addSetHead (&reached, succ->pcflow);
10337         addSetHead (&checked, succ->pcflow);
10338       } // if
10339     } // for succ
10340   } // while
10341
10342   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10343
10344   /* by now every flow should have been reached
10345    * --> flowInBlock should be empty */
10346   res = (flowInBlock == NULL);
10347
10348 #if 1
10349   if (flowInBlock) {
10350           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10351     while (flowInBlock) {
10352       pcfl = indexSet (flowInBlock, 0);
10353       fprintf (stderr, "not reached: flow %p\n", pcfl);
10354       deleteSetItem (&flowInBlock, pcfl);
10355     } // while
10356   }
10357 #endif
10358
10359   /* clean up */
10360   deleteSet (&reached);
10361   deleteSet (&flowInBlock);
10362   deleteSet (&checked);
10363
10364   /* if we reached every flow, succ is NULL by now... */
10365   //assert (res); // will fire on unreachable code...
10366   return (res);
10367 }
10368 #endif
10369
10370 /* Checks a flow for accesses to sym AFTER pc.
10371  *
10372  * Returns -1 if the symbol is read in this flow (before redefinition),
10373  * returns 0 if the symbol is redefined in this flow or
10374  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10375  */
10376 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10377   defmap_t *map, *mappc;
10378
10379   /* find pc or start of definitions */
10380   map = pcfl->defmap;
10381   while (map && (map->pc != pc) && map->next) map = map->next;
10382   /* if we found pc -- ignore it */
10383   while (map && map->pc == pc) map = map->prev;
10384
10385   /* scan list backwards (first definition first) */
10386   while (map && mask) {
10387 //    if (map->sym == sym) {
10388       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10389       mappc = map;
10390       /* scan list for reads at this pc first */
10391       while (map && map->pc == mappc->pc) {
10392         /* is the symbol (partially) read? */
10393         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10394           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10395           return -1;
10396         }
10397         map = map->prev;
10398       } // while
10399       map = mappc;
10400
10401       while (map && map->pc == mappc->pc) {
10402         /* honor (partial) redefinitions of sym */
10403         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10404           mask &= ~map->acc.access.mask;
10405           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10406         }
10407         map = map->prev;
10408       } // while
10409 //    } // if
10410     /* map already points to the first defmap for the next pCode */
10411     //map = mappc->prev;
10412   } // while
10413
10414   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10415    * is still alive; return the appropriate mask of alive bits */
10416   return mask;
10417 }
10418
10419 /* Check whether a symbol is alive (AFTER pc). */
10420 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10421   int mask, visit;
10422   defmap_t *map;
10423   dynstack_t *todo, *done;
10424   state_t *state;
10425   pCodeFlow *pcfl;
10426   pCodeFlowLink *succ;
10427
10428   mask = 0x00ff;
10429
10430   assert (isPCI(pc));
10431   pcfl = PCI(pc)->pcflow;
10432   map = pcfl->defmap;
10433
10434   todo = newStack ();
10435   done = newStack ();
10436
10437   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10438   stackPush (todo, state);
10439   visit = 0;
10440
10441   while (!stackIsEmpty (todo)) {
10442     state = (state_t *) stackPop (todo);
10443     pcfl = state->flow;
10444     mask = PTR_TO_INT(state->lastdef);
10445     if (visit) stackPush (done, state); else deleteState(state);
10446     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10447     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10448     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10449     visit++;
10450
10451     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10452     if (mask == 0) continue;
10453
10454     /* symbol is (partially) read before redefinition in flow */
10455     if (mask == -1) break;
10456
10457     /* symbol is neither read nor completely redefined -- check successor flows */
10458     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10459       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10460       if (stateIsNew (state, todo, done)) {
10461         stackPush (todo, state);
10462       } else {
10463         deleteState (state);
10464       }
10465     } // for
10466   } // while
10467
10468   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10469   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10470
10471   /* symbol is read in at least one flow -- is alive */
10472   if (mask == -1) return 1;
10473
10474   /* symbol is read in no flow */
10475   return 0;
10476 }
10477
10478 /* Returns whether access to the given symbol has side effects. */
10479 static int pic16_symIsSpecial (symbol_t sym) {
10480   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10481   switch (sym) {
10482   case SPO_INDF0:
10483   case SPO_PLUSW0:
10484   case SPO_POSTINC0:
10485   case SPO_POSTDEC0:
10486   case SPO_PREINC0:
10487   case SPO_INDF1:
10488   case SPO_PLUSW1:
10489   case SPO_POSTINC1:
10490   case SPO_POSTDEC1:
10491   case SPO_PREINC1:
10492   case SPO_INDF2:
10493   case SPO_PLUSW2:
10494   case SPO_POSTINC2:
10495   case SPO_POSTDEC2:
10496   case SPO_PREINC2:
10497   case SPO_PCL:
10498           return 1;
10499   default:
10500           /* no special effects known */
10501           return 0;
10502   } // switch
10503
10504   return 0;
10505 }
10506
10507 /* Check whether a register should be considered local (to the current function) or not. */
10508 static int pic16_regIsLocal (regs *r) {
10509   symbol_t sym;
10510   if (r) {
10511     if (r->type == REG_TMP) return 1;
10512
10513     sym = symFromStr (r->name);
10514     switch (sym) {
10515     case SPO_WREG:
10516     case SPO_FSR0L: // used in ptrget/ptrput
10517     case SPO_FSR0H: // ... as well
10518     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10519     case SPO_FSR1H: // ... as well
10520     case SPO_FSR2L: // used as frame pointer
10521     case SPO_FSR2H: // ... as well
10522     case SPO_PRODL: // used to return values from functions
10523     case SPO_PRODH: // ... as well
10524       /* these registers (and some more...) are considered local */
10525       return 1;
10526       break;
10527     default:
10528       /* for unknown regs: check is marked local, leave if not */
10529       if (r->isLocal) {
10530         return 1;
10531       } else {
10532         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10533         return 0;
10534       }
10535     } // switch
10536   } // if
10537
10538   /* if in doubt, assume non-local... */
10539   return 0;
10540 }
10541
10542 /* Check all symbols touched by pc whether their newly assigned values are read.
10543  * Returns 0 if no symbol is used later on, 1 otherwise. */
10544 static int pic16_pCodeIsAlive (pCode *pc) {
10545   pCodeInstruction *pci;
10546   defmap_t *map, *lastpc;
10547   regs *checkreg;
10548
10549   /* we can only handle PCIs */
10550   if (!isPCI(pc)) return 1;
10551
10552   //pc->print (stderr, pc);
10553
10554   pci = PCI(pc);
10555   assert (pci && pci->pcflow && pci->pcflow->defmap);
10556
10557   /* NEVER remove instructions with implicit side effects */
10558   switch (pci->op) {
10559   case POC_TBLRD:
10560   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10561   case POC_TBLRD_POSTDEC:
10562   case POC_TBLRD_PREINC:
10563   case POC_TBLWT:               /* modify program memory */
10564   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10565   case POC_TBLWT_POSTDEC:
10566   case POC_TBLWT_PREINC:
10567   case POC_CLRWDT:              /* clear watchdog timer */
10568   case POC_PUSH:                /* should be safe to remove though... */
10569   case POC_POP:                 /* should be safe to remove though... */
10570   case POC_CALL:
10571   case POC_RCALL:
10572   case POC_RETFIE:
10573   case POC_RETURN:
10574     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10575     return 1;
10576
10577   default:
10578     /* no special instruction */
10579     break;
10580   } // switch
10581
10582   /* prevent us from removing assignments to non-local variables */
10583   checkreg = NULL;
10584   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10585   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10586
10587   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10588     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10589     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10590     //pc->print (stderr, pc);
10591     return 1;
10592   }
10593   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10594     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10595     return 1;
10596   }
10597
10598 #if 1
10599   /* OVERKILL: prevent us from removing reads from non-local variables
10600    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10601    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10602   checkreg = NULL;
10603   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10604   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10605
10606   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10607     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10608     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10609     //pc->print (stderr, pc);
10610     return 1;
10611   }
10612   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10613     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10614     return 1;
10615   }
10616 #endif
10617
10618   /* now check that the defined symbols are not used */
10619   map = pci->pcflow->defmap;
10620
10621   /* find items for pc */
10622   while (map && map->pc != pc) map = map->next;
10623
10624   /* no entries found? something is fishy with DF analysis... -- play safe */
10625   if (!map) {
10626     if (pic16_pcode_verbose) {
10627       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10628     }
10629     return 1;
10630   }
10631
10632   /* remember first item assigned to pc for later use */
10633   lastpc = map;
10634
10635   /* check all symbols being modified by pc */
10636   while (map && map->pc == pc) {
10637     if (map->sym == 0) { map = map->next; continue; }
10638
10639     /* keep pc if it references special symbols (like POSTDEC0) */
10640 #if 0
10641     {
10642       char buf[256];
10643       pic16_pCode2str (buf, 256, pc);
10644       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10645     }
10646 #endif
10647     if (pic16_symIsSpecial (map->sym)) {
10648       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10649       return 1;
10650     }
10651     if (map->acc.access.isWrite) {
10652       if (pic16_isAlive (map->sym, pc)) {
10653         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10654         return 1;
10655       }
10656     }
10657     map = map->next;
10658   } // while
10659
10660   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10661 #if 0
10662   {
10663     char buf[256];
10664     pic16_pCode2str (buf, 256, pc);
10665     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10666   }
10667 #endif
10668   return 0;
10669 }
10670
10671 /* Adds implied operands to the list.
10672  * sym - operand being accessed in the pCode
10673  * list - list to append the operand
10674  * isRead - set to 1 iff sym is read in pCode
10675  * listRead - set to 1 iff all operands being read are to be listed
10676  *
10677  * Returns 0 for "normal" operands, 1 for special operands.
10678  */
10679 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10680   /* check whether accessing REG accesses other REGs as well */
10681   switch (sym) {
10682   case SPO_INDF0:
10683     /* reads FSR0x */
10684     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10685     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10686     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10687     break;
10688
10689   case SPO_PLUSW0:
10690     /* reads FSR0x and WREG */
10691     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10692     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10693     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10694     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10695     break;
10696
10697   case SPO_POSTDEC0:
10698   case SPO_POSTINC0:
10699   case SPO_PREINC0:
10700     /* reads/modifies FSR0x */
10701     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10702     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10703     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10704     break;
10705
10706   case SPO_INDF1:
10707     /* reads FSR1x */
10708     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10709     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10710     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10711     break;
10712
10713   case SPO_PLUSW1:
10714     /* reads FSR1x and WREG */
10715     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10716     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10717     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10718     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10719     break;
10720
10721   case SPO_POSTDEC1:
10722   case SPO_POSTINC1:
10723   case SPO_PREINC1:
10724     /* reads/modifies FSR1x */
10725     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10726     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10727     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10728     break;
10729
10730   case SPO_INDF2:
10731     /* reads FSR2x */
10732     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10733     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10734     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10735     break;
10736
10737   case SPO_PLUSW2:
10738     /* reads FSR2x and WREG */
10739     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10740     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10741     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10742     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10743     break;
10744
10745   case SPO_POSTDEC2:
10746   case SPO_POSTINC2:
10747   case SPO_PREINC2:
10748     /* reads/modifies FSR2x */
10749     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10750     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10751     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10752     break;
10753
10754   case SPO_PCL:
10755     /* modifies PCLATH and PCLATU */
10756     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10757     if (isRead) {
10758       /* reading PCL updates PCLATx */
10759       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10760       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10761     }
10762     if (isWrite) {
10763       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10764       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10765       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10766     }
10767     break;
10768
10769   default:
10770     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10771     /* nothing special */
10772     return 0;
10773     break;
10774   }
10775
10776   /* has been a special operand */
10777   return 1;
10778 }
10779
10780 static symbol_t pic16_fsrsym_idx[][2] = {
10781     {SPO_FSR0L, SPO_FSR0H},
10782     {SPO_FSR1L, SPO_FSR1H},
10783     {SPO_FSR2L, SPO_FSR2H}
10784 };
10785
10786 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10787 static void mergeDefmapSymbols (defmap_t *list) {
10788   defmap_t *ref, *curr, *temp;
10789
10790   /* now make sure that each symbol occurs at most once per pc */
10791   ref = list;
10792   while (ref && (ref->pc == list->pc)) {
10793     curr = ref->next;
10794     while (curr && (curr->pc == list->pc)) {
10795       if (curr->sym == ref->sym) {
10796         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10797         /* found a symbol occuring twice... merge the two */
10798         if (curr->acc.access.isRead) {
10799           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10800           ref->acc.access.isRead = 1;
10801           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10802         }
10803         if (curr->acc.access.isWrite) {
10804           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10805           ref->acc.access.isWrite = 1;
10806           ref->acc.access.mask |= curr->acc.access.mask;
10807         }
10808         temp = curr;
10809         curr = curr->next;
10810         deleteDefmap (temp);
10811         continue; // do not skip curr!
10812       } // if
10813       curr = curr->next;
10814     } // while
10815     ref = ref->next;
10816   } // while
10817 }
10818
10819 /** Prepend list with the reads and definitions performed by pc. */
10820 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10821   pCodeInstruction *pci;
10822   int cond, inCond, outCond;
10823   int mask = 0xff, smask;
10824   int isSpecial, isSpecial2;
10825   symbol_t sym, sym2;
10826   char *name;
10827
10828   if (isPCAD(pc)) {
10829     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10830     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10831     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10832     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10833     return list;
10834   }
10835   assert (isPCI(pc));
10836   pci = PCI(pc);
10837
10838   /* handle bit instructions */
10839   if (pci->isBitInst) {
10840     assert (pci->pcop->type == PO_GPR_BIT);
10841     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10842   }
10843
10844   /* handle (additional) implicit arguments */
10845   switch (pci->op) {
10846   case POC_LFSR:
10847     {
10848       int lit;
10849       valnum_t val;
10850       lit = PCOL(pci->pcop)->lit;
10851       assert (lit >= 0 && lit < 3);
10852       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10853       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10854       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10855       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10856       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...
10857     }
10858     break;
10859
10860   case POC_MOVLB: // BSR
10861   case POC_BANKSEL: // BSR
10862     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10863     break;
10864
10865   case POC_MULWF: // PRODx
10866   case POC_MULLW: // PRODx
10867     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10868     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10869     break;
10870
10871   case POC_POP: // TOS, STKPTR
10872     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10873     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10874     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10875     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10876     break;
10877
10878   case POC_PUSH: // STKPTR
10879     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10880     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10881     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10882     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10883     break;
10884
10885   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10886   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10887     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10888     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10889     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10890     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10891
10892     /* needs correctly set-up stack pointer */
10893     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10894     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10895     break;
10896
10897   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10898     /* pseudo read on (possible) return values */
10899     // WREG is handled below via outCond
10900     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10901     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10902     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10903
10904     /* caller's stack pointers must be restored */
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     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10908     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10909     break;
10910
10911   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10912   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10913     /* pseudo read on (possible) return values */
10914     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10915     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10916     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10917     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10918
10919     /* caller's stack pointers must be restored */
10920     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10921     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10922     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10923     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10924     break;
10925
10926   case POC_TBLRD:
10927     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10928     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10929     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10930     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10931     break;
10932
10933   case POC_TBLRD_POSTINC:
10934   case POC_TBLRD_POSTDEC:
10935   case POC_TBLRD_PREINC:
10936     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10937     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10938     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10939     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10940     break;
10941
10942   case POC_TBLWT:
10943     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10944     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10945     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10946     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10947     break;
10948
10949   case POC_TBLWT_POSTINC:
10950   case POC_TBLWT_POSTDEC:
10951   case POC_TBLWT_PREINC:
10952     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10953     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10954     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10955     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10956     break;
10957
10958   default:
10959     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10960     break;
10961   } // switch
10962
10963   /* handle explicit arguments */
10964   inCond = pci->inCond;
10965   outCond = pci->outCond;
10966   cond = inCond | outCond;
10967   if (cond & PCC_W) {
10968     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10969   } // if
10970
10971   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10972   if (inCond & PCC_STATUS) {
10973     smask = 0;
10974     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10975     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10976     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10977     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10978     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10979
10980     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10981     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10982   } // if
10983
10984   if (outCond & PCC_STATUS) {
10985     smask = 0;
10986     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10987     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10988     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10989     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10990     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10991
10992     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
10993     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10994   } // if
10995
10996   isSpecial = isSpecial2 = 0;
10997   sym = sym2 = 0;
10998   if (cond & PCC_REGISTER) {
10999     name = pic16_get_op (pci->pcop, NULL, 0);
11000     sym = symFromStr (name);
11001     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11002     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11003   }
11004
11005   if (cond & PCC_REGISTER2) {
11006     name = pic16_get_op2 (pci->pcop, NULL, 0);
11007     sym2 = symFromStr (name);
11008     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11009     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11010   }
11011
11012
11013   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11014   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11015
11016   mergeDefmapSymbols (list);
11017
11018   return list;
11019 }
11020
11021 #if 0
11022 static void printDefmap (defmap_t *map) {
11023   defmap_t *curr;
11024
11025   curr = map;
11026   fprintf (stderr, "defmap @ %p:\n", curr);
11027   while (curr) {
11028     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11029                     curr->acc.access.isRead ? "R" : " ",
11030                     curr->acc.access.isWrite ? "W": " ",
11031                     curr->in_val, curr->val,
11032                     curr->acc.access.in_mask, curr->acc.access.mask,
11033                     strFromSym(curr->sym), curr->sym,
11034                     curr->pc);
11035     curr = curr->next;
11036   } // while
11037   fprintf (stderr, "<EOL>\n");
11038 }
11039 #endif
11040
11041 /* Add "additional" definitions to uniq.
11042  * 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.
11043  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11044  *
11045  * If symbols defined in additional are not present in uniq, a definition is created.
11046  * Otherwise the present definition is altered to reflect the newer assignments.
11047  *
11048  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11049  *       before     `------- noted in additional --------'      after
11050  *
11051  * I assume that each symbol occurs AT MOST ONCE in uniq.
11052  *
11053  */
11054 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11055   defmap_t *curr;
11056   defmap_t *old;
11057   int change = 0;
11058
11059   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11060   /* find tail of additional list (holds the first assignment) */
11061   curr = additional;
11062   while (curr && curr->next) curr = curr->next;
11063
11064   /* update uniq */
11065   do {
11066     /* find next assignment in additionals */
11067     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11068
11069     if (!curr) break;
11070
11071     /* find item in uniq */
11072     old = *uniq;
11073     //printDefmap (*uniq);
11074     while (old && (old->sym != curr->sym)) old = old->next;
11075
11076     if (old) {
11077       /* definition found -- replace */
11078       if (old->val != curr->val) {
11079         old->val = curr->val;
11080         change++;
11081       } // if
11082     } else {
11083       /* new definition */
11084       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11085       change++;
11086     }
11087
11088     curr = curr->prev;
11089   } while (1);
11090
11091   /* return 0 iff uniq remained unchanged */
11092   return change;
11093 }
11094
11095 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11096  * lists of its predecessor flows.
11097  * Initially *combined should be NULL, alt_in will be copied to combined.
11098  * If *combined != NULL, combined will be altered:
11099  * - for symbols defined in *combined but not in alt_in,
11100  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11101  * - for symbols defined in alt_in but not in *combined,
11102  *   a 0 definition is created (value unknown, either INIT or alt).
11103  * - for symbols defined in both, *combined is:
11104  *   > left unchanged if *combined->val == alt_in->val or
11105  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11106  *
11107  * I assume that each symbol occurs AT MOST ONCE in each list!
11108  */
11109 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11110   defmap_t *curr;
11111   defmap_t *old;
11112   int change = 0;
11113   valnum_t val;
11114
11115   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11116
11117   if (!(*combined)) {
11118     return defmapUpdateUniqueSym (combined, alt_in);
11119   } // if
11120
11121   /* merge the two */
11122   curr = alt_in;
11123   while (curr) {
11124     /* find symbols definition in *combined */
11125     old = *combined;
11126     while (old && (old->sym != curr->sym)) old = old->next;
11127
11128     if (old) {
11129       /* definition found */
11130       if (old->val && (old->val != curr->val)) {
11131         old->val = 0; /* value unknown */
11132         change++;
11133       }
11134     } else {
11135       /* no definition found -- can be either INIT or alt_in's value */
11136       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11137       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11138       if (val != curr->val) change++;
11139     }
11140
11141     curr = curr->next;
11142   } // while (curr)
11143
11144   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11145   old = *combined;
11146   while (old) {
11147     if (old->val != 0) {
11148       /* find definition in alt_in */
11149       curr = alt_in;
11150       while (curr && curr->sym != old->sym) curr = curr->next;
11151       if (!curr) {
11152         /* symbol defined in *combined only -- can be either INIT or *combined */
11153         val = pic16_pBlockAddInval (pb, old->sym)->val;
11154         if (old->val != val) {
11155           old->val = 0;
11156           change++;
11157         }
11158       } // if
11159     } // if
11160
11161     old = old->next;
11162   } // while
11163
11164   return change;
11165 }
11166
11167 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11168   defmap_t *curr1, *curr2;
11169   symbol_t sym;
11170
11171   /* identical maps are equal */
11172   if (map1 == map2) return 0;
11173
11174   if (!map1) return -1;
11175   if (!map2) return 1;
11176
11177   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11178
11179   /* check length */
11180   curr1 = map1;
11181   curr2 = map2;
11182   while (curr1 && curr2) {
11183     curr1 = curr1->next;
11184     curr2 = curr2->next;
11185   } // while
11186
11187   /* one of them longer? */
11188   if (curr1) return 1;
11189   if (curr2) return -1;
11190
11191   /* both lists are of equal length -- compare (in O(n^2)) */
11192   curr1 = map1;
11193   while (curr1) {
11194     sym = curr1->sym;
11195     curr2 = map2;
11196     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11197     if (!curr2) return 1; // symbol not found in curr2
11198     if (curr2->val != curr1->val) return 1; // values differ
11199
11200     /* compare next symbol */
11201     curr1 = curr1->next;
11202   } // while
11203
11204   /* no difference found */
11205   return 0;
11206 }
11207
11208
11209 /* Prepare a list of all reaching definitions per flow.
11210  * This is done using a forward dataflow analysis.
11211  */
11212 static void createReachingDefinitions (pBlock *pb) {
11213   defmap_t *out_vals, *in_vals;
11214   pCode *pc;
11215   pCodeFlow *pcfl;
11216   pCodeFlowLink *link;
11217   set *todo;
11218   set *blacklist;
11219
11220   if (!pb) return;
11221
11222   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11223   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11224     if (isPCFL(pc)) {
11225       deleteDefmapChain (&PCFL(pc)->in_vals);
11226       deleteDefmapChain (&PCFL(pc)->out_vals);
11227       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11228     } // if
11229   } // for
11230
11231   pc = pic16_findNextInstruction (pb->pcHead);
11232   if (!pc) {
11233       // empty function, avoid NULL pointer dereference
11234       return;
11235   } // if
11236   todo = NULL; blacklist = NULL;
11237   addSetHead (&todo, PCI(pc)->pcflow);
11238
11239   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11240   while (elementsInSet (todo)) {
11241     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11242     pcfl = PCFL(indexSet (todo, 0));
11243     deleteSetItem (&todo, pcfl);
11244     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11245     in_vals = NULL;
11246     out_vals = NULL;
11247
11248     if (isinSet (blacklist, pcfl)) {
11249             fprintf (stderr, "ignoring blacklisted flow\n");
11250       continue;
11251     }
11252
11253     /* create in_vals from predecessors out_vals */
11254     link = setFirstItem (pcfl->from);
11255     while (link) {
11256       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11257       link = setNextItem (pcfl->from);
11258     } // while
11259
11260     //printDefmap (in_vals);
11261     //printDefmap (pcfl->in_vals);
11262
11263     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11264       //fprintf (stderr, "in_vals changed\n");
11265       /* in_vals changed -- update out_vals */
11266       deleteDefmapChain (&pcfl->in_vals);
11267       pcfl->in_vals = in_vals;
11268
11269       /* create out_val from in_val and defmap */
11270       out_vals = NULL;
11271       defmapUpdateUniqueSym (&out_vals, in_vals);
11272       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11273
11274       /* is out_vals different from pcfl->out_vals */
11275       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11276         //fprintf (stderr, "out_vals changed\n");
11277         deleteDefmapChain (&pcfl->out_vals);
11278         pcfl->out_vals = out_vals;
11279
11280         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11281           addSet (&blacklist, pcfl);
11282         } // if
11283
11284         /* reschedule all successors */
11285         link = setFirstItem (pcfl->to);
11286         while (link) {
11287           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11288           addSetIfnotP (&todo, link->pcflow);
11289           link = setNextItem (pcfl->to);
11290         } // while
11291       } else {
11292         deleteDefmapChain (&out_vals);
11293       }// if
11294     } else {
11295       deleteDefmapChain (&in_vals);
11296     } // if
11297   } // while
11298 }
11299
11300 #if 0
11301 static void showAllDefs (symbol_t sym, pCode *pc) {
11302   defmap_t *map;
11303   int count;
11304
11305   assert (isPCI(pc));
11306   count = defmapFindAll (sym, pc, &map);
11307
11308   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11309   while (map) {
11310 #if 1
11311     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11312 #else
11313     { char buf[256];
11314     pic16_pCode2str (buf, 256, map->pc);
11315     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11316 #endif
11317     map = map->next;
11318   }
11319   deleteDefmapChain (&map);
11320 }
11321 #endif
11322
11323 /* safepCodeUnlink and remove pc from defmap. */
11324 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11325   defmap_t *map, *next, **head;
11326   int res, ispci;
11327
11328   ispci = isPCI(pc);
11329   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11330   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11331   res = pic16_safepCodeUnlink (pc, comment);
11332
11333   if (res && map) {
11334     /* remove pc from defmap */
11335     while (map) {
11336       next = map->next;
11337       if (map->pc == pc) {
11338         if (!map->prev && head) *head = map->next;
11339         deleteDefmap (map);
11340       } // if
11341       map = next;
11342     }
11343   }
11344
11345   return res;
11346 }
11347
11348 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11349   defmap_t *map;
11350   /* This breaks the defmap chain's references to pCodes... fix it! */
11351   map = PCI(pc)->pcflow->defmap;
11352
11353   while (map && map->pc != pc) map = map->next;
11354
11355   while (map && map->pc == pc) {
11356     map->pc = newpc;
11357     map = map->next;
11358   } // while
11359 }
11360
11361 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11362  * write accesses (isRead == 0). */
11363 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11364   defmap_t *map, *map_start;
11365   defmap_t *copy;
11366   if (!isPCI(pc)) return;
11367   if (sym == newsym) return;
11368
11369   map = PCI(pc)->pcflow->defmap;
11370
11371   while (map && map->pc != pc) map = map->next;
11372   map_start = map;
11373   while (map && map->pc == pc) {
11374     if (map->sym == sym) {
11375       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11376       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11377         /* only one kind of access handled... this is easy */
11378         map->sym = newsym;
11379       } else {
11380         /* must copy defmap entry before replacing symbol... */
11381         copy = copyDefmap (map);
11382         if (isRead) {
11383           map->acc.access.isRead = 0;
11384           copy->acc.access.isWrite = 0;
11385         } else {
11386           map->acc.access.isWrite = 0;
11387           copy->acc.access.isRead = 0;
11388         }
11389         copy->sym = newsym;
11390         /* insert copy into defmap chain */
11391         defmapInsertAfter (map, copy);
11392       }
11393     }
11394     map = map->next;
11395   } // while
11396
11397   /* as this might introduce multiple defmap entries for newsym... */
11398   mergeDefmapSymbols (map_start);
11399 }
11400
11401 /* Assign "better" valnums to results. */
11402 static void assignValnums (pCode *pc) {
11403   pCodeInstruction *pci;
11404   pCode *newpc;
11405   symbol_t sym1, sym2;
11406   int cond, isSpecial1, isSpecial2, count, mask, lit;
11407   defmap_t *list, *val, *oldval, *dummy;
11408   regs *reg1 = NULL, *reg2 = NULL;
11409   valnum_t litnum;
11410
11411   /* only works for pCodeInstructions... */
11412   if (!isPCI(pc)) return;
11413
11414   pci = PCI(pc);
11415   cond = pci->inCond | pci->outCond;
11416   list = pci->pcflow->defmap;
11417   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11418
11419   if (cond & PCC_REGISTER) {
11420     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11421     reg1 = pic16_getRegFromInstruction (pc);
11422     isSpecial1 = pic16_symIsSpecial (sym1);
11423   }
11424   if (cond & PCC_REGISTER2) {
11425     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11426     reg2 = pic16_getRegFromInstruction (pc);
11427     isSpecial2 = pic16_symIsSpecial (sym2);
11428   }
11429
11430   /* determine input values */
11431   val = list;
11432   while (val && val->pc != pc) val = val->next;
11433   //list = val; /* might save some time later... */
11434   while (val && val->pc == pc) {
11435     val->in_val = 0;
11436     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11437       /* get valnum for sym */
11438       count = defmapFindAll (val->sym, pc, &oldval);
11439       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11440       if (count == 1) {
11441         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11442           val->in_val = oldval->val;
11443         } else {
11444           val->in_val = 0;
11445         }
11446       } else if (count == 0) {
11447         /* no definition found */
11448         val->in_val = 0;
11449       } else {
11450         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11451         assert (oldval);
11452         dummy = oldval->next;
11453         mask = oldval->acc.access.mask;
11454         val->in_val = oldval->val;
11455         while (dummy && (dummy->val == val->in_val)) {
11456           mask &= dummy->acc.access.mask;
11457           dummy = dummy->next;
11458         } // while
11459
11460         /* found other values or to restictive mask */
11461         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11462           val->in_val = 0;
11463         }
11464       }
11465       if (count > 0) deleteDefmapChain (&oldval);
11466     } // if
11467     val = val->next;
11468   }
11469
11470   /* handle valnum assignment */
11471   switch (pci->op) {
11472   case POC_CLRF: /* modifies STATUS (Z) */
11473     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11474       oldval = defmapCurr (list, sym1, pc);
11475       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11476         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11477         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11478       }
11479       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11480     }
11481     break;
11482
11483   case POC_SETF: /* SETF does not touch STATUS */
11484     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11485       oldval = defmapCurr (list, sym1, pc);
11486       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11487         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11488         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11489       }
11490       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11491     }
11492     break;
11493
11494   case POC_MOVLW: /* does not touch STATUS */
11495     oldval = defmapCurr (list, SPO_WREG, pc);
11496     if (pci->pcop->type == PO_LITERAL) {
11497       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11498       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11499     } else {
11500       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11501       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11502     }
11503     if (oldval && oldval->in_val == litnum) {
11504       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11505       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11506     }
11507     defmapUpdate (list, SPO_WREG, pc, litnum);
11508     break;
11509
11510   case POC_ANDLW: /* modifies STATUS (Z,N) */
11511   case POC_IORLW: /* modifies STATUS (Z,N) */
11512   case POC_XORLW: /* modifies STATUS (Z,N) */
11513     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11514     if (pci->pcop->type == PO_LITERAL) {
11515       int vallit = -1;
11516       lit = (unsigned char) PCOL(pci->pcop)->lit;
11517       val = defmapCurr (list, SPO_WREG, pc);
11518       if (val) vallit = litFromValnum (val->in_val);
11519       if (vallit != -1) {
11520         /* xxxLW <literal>, WREG contains a known literal */
11521         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11522         if (pci->op == POC_ANDLW) {
11523           lit &= vallit;
11524         } else if (pci->op == POC_IORLW) {
11525           lit |= vallit;
11526         } else if (pci->op == POC_XORLW) {
11527           lit ^= vallit;
11528         } else {
11529           assert (0 && "invalid operation");
11530         }
11531         if (vallit == lit) {
11532           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11533           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11534         }
11535         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11536       } // if
11537     }
11538     break;
11539
11540   case POC_LFSR:
11541     {
11542       /* check if old value matches new value */
11543       int lit;
11544       int ok = 1;
11545       assert (pci->pcop->type == PO_LITERAL);
11546
11547       lit = PCOL(pci->pcop)->lit;
11548
11549       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11550
11551       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11552         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11553       } else {
11554         /* cannot remove this LFSR */
11555         ok = 0;
11556       } // if
11557
11558       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11559       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11560         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11561       } else {
11562         ok = 0;
11563       } // if
11564
11565       if (ok) {
11566         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11567       }
11568     }
11569     break;
11570
11571   case POC_MOVWF: /* does not touch flags */
11572     /* find value of WREG */
11573     val = defmapCurr (list, SPO_WREG, pc);
11574     oldval = defmapCurr (list, sym1, pc);
11575     if (val) lit = litFromValnum (val->in_val);
11576     else lit = -1;
11577     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11578
11579     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11580       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11581       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11582       if (lit == 0) {
11583         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11584       } else {
11585         assert (lit == 0x0ff);
11586         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11587       }
11588       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11589       pic16_pCodeReplace (pc, newpc);
11590       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11591       pic16_fixDefmap (pc, newpc);
11592       pc = newpc;
11593
11594       /* This breaks the defmap chain's references to pCodes... fix it! */
11595       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11596       if (!val->acc.access.isWrite) {
11597         deleteDefmap (val);     // delete reference to WREG as in value
11598         val = NULL;
11599       } else {
11600         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11601       }
11602       oldval = PCI(pc)->pcflow->defmap;
11603       while (oldval) {
11604         if (oldval->pc == pc) oldval->pc = newpc;
11605           oldval = oldval->next;
11606       } // while
11607     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11608       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11609       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11610     }
11611     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11612     break;
11613
11614   case POC_MOVFW: /* modifies STATUS (Z,N) */
11615     /* find value of REG */
11616     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11617       val = defmapCurr (list, sym1, pc);
11618       oldval = defmapCurr (list, SPO_WREG, pc);
11619       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11620         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11621         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11622       } else {
11623           defmap_t *pred, *predpred;
11624           /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11625            * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11626            * This might allow removal of the first two assignments. */
11627           pred = defmapFindDef (list, sym1, pc);
11628           predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11629           if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11630                 && !pic16_isAlive (SPO_STATUS, pc))
11631           {
11632               newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11633
11634               if (pic16_debug_verbose || pic16_pcode_verbose) {
11635                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11636               } // if
11637               pic16_pCodeReplace (pc, newpc);
11638               defmapReplaceSymRef (pc, sym1, 0, 1);
11639               pic16_fixDefmap (pc, newpc);
11640               pc = newpc;
11641
11642               /* This breaks the defmap chain's references to pCodes... fix it! */
11643               if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11644               if (!val->acc.access.isWrite) {
11645                   deleteDefmap (val);   // delete reference to reg1 as in value
11646                   val = NULL;
11647               } else {
11648                   val->acc.access.isRead = 0;   // delete reference to reg1 as in value
11649               }
11650               oldval = PCI(pc)->pcflow->defmap;
11651               while (oldval) {
11652                   if (oldval->pc == pc) oldval->pc = newpc;
11653                   oldval = oldval->next;
11654               } // while
11655           } // if
11656       }
11657       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11658     }
11659     break;
11660
11661   case POC_MOVFF: /* does not touch STATUS */
11662     /* find value of REG */
11663     val = defmapCurr (list, sym1, pc);
11664     oldval = defmapCurr (list, sym2, pc);
11665     if (val) lit = litFromValnum (val->in_val);
11666     else lit = -1;
11667     newpc = NULL;
11668     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11669       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11670       if (lit == 0) {
11671         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11672       } else if (lit == 0x00ff) {
11673         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11674       } else {
11675         newpc = NULL;
11676       }
11677       if (newpc) {
11678         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11679         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11680         pic16_pCodeReplace (pc, newpc);
11681         defmapReplaceSymRef (pc, sym1, 0, 1);
11682         pic16_fixDefmap (pc, newpc);
11683         pc = newpc;
11684         break; // do not process instruction as MOVFF...
11685       }
11686     } else if (!isSpecial1 && !isSpecial2
11687                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11688                 && val && oldval && (val->in_val != 0)) {
11689       if (val->in_val == oldval->in_val) {
11690         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11691         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11692       } else {
11693         if (!pic16_isAlive (sym1, pc)) {
11694           defmap_t *copy = NULL;
11695           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11696            * This should help eliminate
11697            *   MOVFF A,B
11698            *   <do something not changing A or using B>
11699            *   MOVFF B,C
11700            *   <B is not alive anymore>
11701            * and turn it into
11702            *   <do something not changing A or using B>
11703            *   MOVFF A,C
11704            */
11705
11706           /* scan defmap for symbols storing sym1's value */
11707           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11708           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11709             /* unique reaching definition for sym found */
11710             if (copy->val && copy->val == val->in_val) {
11711               //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);
11712               if (copy->sym == SPO_WREG) {
11713                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11714               } else {
11715                 pCodeOp *pcop = NULL;
11716                 /* the code below fails if we try to replace
11717                  *   MOVFF PRODL, r0x03
11718                  *   MOVFF r0x03, PCLATU
11719                  * with
11720                  *   MOVFF PRODL, PCLATU
11721                  * as copy(PRODL) contains has pc==NULL, by name fails...
11722                  */
11723                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11724
11725                 if (copy->pc && PCI(copy->pc)->pcop)
11726                   pcop = PCI(copy->pc)->pcop;
11727 #if 0
11728                 /* This code is broken--see above. */
11729                 else
11730                 {
11731                   const char *symname = strFromSym(copy->sym);
11732
11733                   assert( symname );
11734                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11735                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11736                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11737                 }
11738 #endif
11739                 assert( pcop );
11740                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11741                         pcop,
11742                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11743               }
11744               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11745               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11746               pic16_pCodeReplace (pc, newpc);
11747               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11748               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11749               pic16_fixDefmap (pc, newpc);
11750               pc = newpc;
11751             }
11752           }
11753           deleteDefmapChain (&copy);
11754         }
11755       }
11756       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11757     }
11758     break;
11759
11760   default:
11761     /* cannot optimize */
11762     break;
11763   } // switch
11764 }
11765
11766 static void pic16_destructDF (pBlock *pb) {
11767   pCode *pc, *next;
11768
11769   if (!pb) return;
11770
11771   /* remove old defmaps */
11772   pc = pic16_findNextInstruction (pb->pcHead);
11773   while (pc) {
11774     next = pic16_findNextInstruction (pc->next);
11775
11776     assert (isPCI(pc) || isPCAD(pc));
11777     assert (PCI(pc)->pcflow);
11778     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11779     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11780     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11781
11782     pc = next;
11783   } // while
11784
11785   if (defmap_free || defmap_free_count) {
11786     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11787     freeDefmap (&defmap_free);
11788     defmap_free_count = 0;
11789   }
11790 }
11791
11792 /* Checks whether a pBlock contains ASMDIRs. */
11793 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11794   pCode *pc;
11795
11796   if (!pb) return 0;
11797
11798   pc = pic16_findNextInstruction (pb->pcHead);
11799   while (pc) {
11800     if (isPCAD(pc)) return 1;
11801
11802     pc = pic16_findNextInstruction (pc->next);
11803   } // while
11804
11805   /* no PCADs found */
11806   return 0;
11807 }
11808
11809 #if 1
11810 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11811 static int pic16_removeUnusedRegistersDF () {
11812   pCode *pc, *pc2;
11813   pBlock *pb;
11814   regs *reg1, *reg2, *reg3;
11815   set *seenRegs = NULL;
11816   int cond, i;
11817   int islocal, change = 0;
11818
11819   /* no pBlocks? */
11820   if (!the_pFile || !the_pFile->pbHead) return 0;
11821
11822   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11823     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11824 #if 1
11825     /* find set of using pCodes per register */
11826     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11827                     pc = pic16_findNextInstruction(pc->next)) {
11828
11829       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11830       reg1 = reg2 = NULL;
11831       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11832       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11833
11834       if (reg1) {
11835         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11836         addSetIfnotP (&seenRegs, reg1);
11837         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11838       }
11839       if (reg2) {
11840         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11841         addSetIfnotP (&seenRegs, reg2);
11842         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11843       }
11844     } // for pc
11845 #endif
11846     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11847       /* may not use pic16_regIsLocal() here -- in interrupt routines
11848        * WREG, PRODx, FSR0x must be saved */
11849       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11850       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11851         pc = pc2 = NULL;
11852         for (i=0; i < 2; i++) {
11853           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11854           if (!pc2) pc2 = pc;
11855           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11856           reg2 = pic16_getRegFromInstruction (pc);
11857           reg3 = pic16_getRegFromInstruction2 (pc);
11858           if (!reg2 || !reg3
11859               || (reg2->rIdx != pic16_stack_preinc->rIdx
11860                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11861           if (i == 1) {
11862             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11863             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11864             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11865             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11866           }
11867         } // for
11868       } // if
11869       deleteSet (&reg1->reglives.usedpCodes);
11870     } // for reg1
11871
11872     deleteSet (&seenRegs);
11873   } // for pb
11874
11875   return change;
11876 }
11877 #endif
11878
11879 /* Set up pCodeFlow's defmap_ts.
11880  * Needs correctly set up to/from fields. */
11881 static void pic16_createDF (pBlock *pb) {
11882   pCode *pc, *next;
11883   int change=0;
11884
11885   if (!pb) return;
11886
11887   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11888
11889   pic16_destructDF (pb);
11890
11891   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11892   if (pic16_pBlockHasAsmdirs (pb)) {
11893     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11894     return;
11895   }
11896
11897   /* integrity check -- we need to reach all flows to guarantee
11898    * correct data flow analysis (reaching definitions, aliveness) */
11899 #if 0
11900   if (!verifyAllFlowsReachable (pb)) {
11901     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11902     return;
11903   }
11904 #endif
11905
11906   /* establish new defmaps */
11907   pc = pic16_findNextInstruction (pb->pcHead);
11908   while (pc) {
11909     next = pic16_findNextInstruction (pc->next);
11910
11911     assert (PCI(pc)->pcflow);
11912     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11913
11914     pc = next;
11915   } // while
11916
11917   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11918   createReachingDefinitions (pb);
11919
11920 #if 1
11921   /* assign better valnums */
11922   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11923   pc = pic16_findNextInstruction (pb->pcHead);
11924   while (pc) {
11925     next = pic16_findNextInstruction (pc->next);
11926
11927     assert (PCI(pc)->pcflow);
11928     assignValnums (pc);
11929
11930     pc = next;
11931   } // while
11932 #endif
11933
11934 #if 1
11935   /* remove dead pCodes */
11936   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11937   do {
11938     change = 0;
11939     pc = pic16_findNextInstruction (pb->pcHead);
11940     while (pc) {
11941       next = pic16_findNextInstruction (pc->next);
11942
11943       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11944         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11945       }
11946
11947       pc = next;
11948     } // while
11949   } while (change);
11950 #endif
11951 }
11952
11953 /* ======================================================================== */
11954 /* === VCG DUMPER ROUTINES ================================================ */
11955 /* ======================================================================== */
11956 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11957 hTab *dumpedNodes = NULL;
11958
11959 /** Dump VCG header into of. */
11960 static void pic16_vcg_init (FILE *of) {
11961   /* graph defaults */
11962   fprintf (of, "graph:{\n");
11963   fprintf (of, "title:\"graph1\"\n");
11964   fprintf (of, "label:\"graph1\"\n");
11965   fprintf (of, "color:white\n");
11966   fprintf (of, "textcolor:black\n");
11967   fprintf (of, "bordercolor:black\n");
11968   fprintf (of, "borderwidth:1\n");
11969   fprintf (of, "textmode:center\n");
11970
11971   fprintf (of, "layoutalgorithm:dfs\n");
11972   fprintf (of, "late_edge_labels:yes\n");
11973   fprintf (of, "display_edge_labels:yes\n");
11974   fprintf (of, "dirty_edge_labels:yes\n");
11975   fprintf (of, "finetuning:yes\n");
11976   fprintf (of, "ignoresingles:no\n");
11977   fprintf (of, "straight_phase:yes\n");
11978   fprintf (of, "priority_phase:yes\n");
11979   fprintf (of, "manhattan_edges:yes\n");
11980   fprintf (of, "smanhattan_edges:no\n");
11981   fprintf (of, "nearedges:no\n");
11982   fprintf (of, "node_alignment:center\n"); // bottom|top|center
11983   fprintf (of, "port_sharing:no\n");
11984   fprintf (of, "arrowmode:free\n"); // fixed|free
11985   fprintf (of, "crossingphase2:yes\n");
11986   fprintf (of, "crossingoptimization:yes\n");
11987   fprintf (of, "edges:yes\n");
11988   fprintf (of, "nodes:yes\n");
11989   fprintf (of, "splines:no\n");
11990
11991   /* node defaults */
11992   fprintf (of, "node.color:lightyellow\n");
11993   fprintf (of, "node.textcolor:black\n");
11994   fprintf (of, "node.textmode:center\n");
11995   fprintf (of, "node.shape:box\n");
11996   fprintf (of, "node.bordercolor:black\n");
11997   fprintf (of, "node.borderwidth:1\n");
11998
11999   /* edge defaults */
12000   fprintf (of, "edge.textcolor:black\n");
12001   fprintf (of, "edge.color:black\n");
12002   fprintf (of, "edge.thickness:1\n");
12003   fprintf (of, "edge.arrowcolor:black\n");
12004   fprintf (of, "edge.backarrowcolor:black\n");
12005   fprintf (of, "edge.arrowsize:15\n");
12006   fprintf (of, "edge.backarrowsize:15\n");
12007   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12008   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12009   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12010
12011   fprintf (of, "\n");
12012
12013   /* prepare data structures */
12014   if (dumpedNodes) {
12015     hTabDeleteAll (dumpedNodes);
12016     dumpedNodes = NULL;
12017   }
12018   dumpedNodes = newHashTable (128);
12019 }
12020
12021 /** Dump VCG footer into of. */
12022 static void pic16_vcg_close (FILE *of) {
12023   fprintf (of, "}\n");
12024 }
12025
12026 #define BUF_SIZE 128
12027 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12028
12029 #if 0
12030 static int ptrcmp (const void *p1, const void *p2) {
12031   return p1 == p2;
12032 }
12033 #endif
12034
12035 /** Dump a pCode node as VCG to of. */
12036 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12037   char buf[BUF_SIZE];
12038
12039   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12040     // dumped already
12041     return;
12042   }
12043   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12044   //fprintf (stderr, "dumping %p\n", pc);
12045
12046   /* only dump pCodeInstructions and Flow nodes */
12047   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12048
12049   /* emit node */
12050   fprintf (of, "node:{");
12051   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12052   fprintf (of, "label:\"%s\n", pcTitle(pc));
12053   if (isPCFL(pc)) {
12054     fprintf (of, "<PCFLOW>");
12055   } else if (isPCI(pc) || isPCAD(pc)) {
12056     pc->print (of, pc);
12057   } else {
12058     fprintf (of, "<!PCI>");
12059   }
12060   fprintf (of, "\" ");
12061   fprintf (of, "}\n");
12062
12063   if (1 && isPCFL(pc)) {
12064     defmap_t *map, *prev;
12065     unsigned int i;
12066     map = PCFL(pc)->defmap;
12067     i=0;
12068     while (map) {
12069       if (map->sym != 0) {
12070         i++;
12071
12072         /* emit definition node */
12073         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12074         fprintf (of, "label:\"");
12075
12076         prev = map;
12077         do {
12078           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));
12079           prev = map;
12080           map = map->next;
12081         } while (map && prev->pc == map->pc);
12082         map = prev;
12083
12084         fprintf (of, "\" ");
12085
12086         fprintf (of, "color:green ");
12087         fprintf (of, "}\n");
12088
12089         /* emit edge to previous definition */
12090         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12091         if (i == 1) {
12092           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12093         } else {
12094           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12095         }
12096         fprintf (of, "color:green ");
12097         fprintf (of, "}\n");
12098
12099         if (map->pc) {
12100           pic16_vcg_dumpnode (map->pc, of);
12101           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12102           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12103         }
12104       }
12105       map = map->next;
12106     } // while
12107   }
12108
12109   /* emit additional nodes (e.g. operands) */
12110 }
12111
12112 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12113 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12114   char buf[BUF_SIZE];
12115   pCodeInstruction *pci;
12116   pBranch *curr;
12117   int i;
12118
12119   if (1 && isPCFL(pc)) {
12120     /* emit edges to flow successors */
12121     void *pcfl;
12122     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12123     pcfl = setFirstItem (PCFL(pc)->to);
12124     while (pcfl) {
12125       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12126       pic16_vcg_dumpnode (pc, of);
12127       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12128       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12129       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12130       pcfl = setNextItem (PCFL(pc)->to);
12131     } // while
12132   } // if
12133
12134   if (!isPCI(pc) && !isPCAD(pc)) return;
12135
12136   pci = PCI(pc);
12137
12138   /* emit control flow edges (forward only) */
12139   curr = pci->to;
12140   i=0;
12141   while (curr) {
12142     pic16_vcg_dumpnode (curr->pc, of);
12143     fprintf (of, "edge:{");
12144     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12145     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12146     fprintf (of, "color:red ");
12147     fprintf (of, "}\n");
12148     curr = curr->next;
12149   } // while
12150
12151 #if 1
12152   /* dump "flow" edge (link pCode according to pBlock order) */
12153   {
12154     pCode *pcnext;
12155     pcnext = pic16_findNextInstruction (pc->next);
12156     if (pcnext) {
12157       pic16_vcg_dumpnode (pcnext, of);
12158       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12159       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12160     }
12161   }
12162 #endif
12163
12164 #if 0
12165   /* emit flow */
12166   if (pci->pcflow) {
12167     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12168     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12169     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12170   }
12171 #endif
12172
12173   /* emit data flow edges (backward only) */
12174   /* TODO: gather data flow information... */
12175 }
12176
12177 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12178   pCode *pc;
12179
12180   if (!pb) return;
12181
12182   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12183   if (pic16_pBlockHasAsmdirs (pb)) {
12184     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12185     return;
12186   }
12187
12188   for (pc=pb->pcHead; pc; pc = pc->next) {
12189     pic16_vcg_dumpnode (pc, of);
12190   } // for pc
12191
12192   for (pc=pb->pcHead; pc; pc = pc->next) {
12193     pic16_vcg_dumpedges (pc, of);
12194   } // for pc
12195 }
12196
12197 static void pic16_vcg_dump_default (pBlock *pb) {
12198   FILE *of;
12199   char buf[BUF_SIZE];
12200   pCode *pc;
12201
12202   if (!pb) return;
12203
12204   /* get function name */
12205   pc = pb->pcHead;
12206   while (pc && !isPCF(pc)) pc = pc->next;
12207   if (pc) {
12208     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12209   } else {
12210     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12211   }
12212
12213   //fprintf (stderr, "now dumping %s\n", buf);
12214   of = fopen (buf, "w");
12215   pic16_vcg_init (of);
12216   pic16_vcg_dump (of, pb);
12217   pic16_vcg_close (of);
12218   fclose (of);
12219 }
12220 #endif
12221
12222 /*** END of helpers for pCode dataflow optimizations ***/