* as/link/lkar.h: changed type of ar_size to size_t to make it work on
[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 #if 0
6428 /*-----------------------------------------------------------------*/
6429 /*int compareBankFlow - compare the banking requirements between   */
6430 /*  flow objects. */
6431 /*-----------------------------------------------------------------*/
6432 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6433 {
6434
6435   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6436     return 0;
6437
6438   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6439     return 0;
6440
6441   if(pcflow->firstBank == -1)
6442     return 0;
6443
6444
6445   if(pcflowLink->pcflow->firstBank == -1) {
6446     pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6447                                         pcflowLink->pcflow->to :
6448                                         pcflowLink->pcflow->from);
6449     return compareBankFlow(pcflow, pctl, toORfrom);
6450   }
6451
6452   if(toORfrom) {
6453     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6454       return 0;
6455
6456     pcflowLink->bank_conflict++;
6457     pcflowLink->pcflow->FromConflicts++;
6458     pcflow->ToConflicts++;
6459   } else {
6460
6461     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6462       return 0;
6463
6464     pcflowLink->bank_conflict++;
6465     pcflowLink->pcflow->ToConflicts++;
6466     pcflow->FromConflicts++;
6467
6468   }
6469   /*
6470   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6471           pcflowLink->pcflow->pc.seq,
6472           pcflowLink->pcflow->FromConflicts,
6473           pcflowLink->pcflow->ToConflicts);
6474   */
6475   return 1;
6476
6477 }
6478 #endif
6479
6480 #if 0
6481 /*-----------------------------------------------------------------*/
6482 /*-----------------------------------------------------------------*/
6483 static void DumpFlow(pBlock *pb)
6484 {
6485   pCode *pc=NULL;
6486   pCode *pcflow;
6487   pCodeFlowLink *pcfl;
6488
6489
6490   fprintf(stderr,"Dump flow \n");
6491   pb->pcHead->print(stderr, pb->pcHead);
6492
6493   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6494   pcflow->print(stderr,pcflow);
6495
6496   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6497        pcflow != NULL;
6498        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6499
6500     if(!isPCFL(pcflow)) {
6501       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6502       continue;
6503     }
6504     fprintf(stderr,"dumping: ");
6505     pcflow->print(stderr,pcflow);
6506     FlowStats(PCFL(pcflow));
6507
6508     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6509
6510       pc = PCODE(pcfl->pcflow);
6511
6512       fprintf(stderr, "    from seq %d:\n",pc->seq);
6513       if(!isPCFL(pc)) {
6514         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6515         pc->print(stderr,pc);
6516       }
6517
6518     }
6519
6520     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6521
6522       pc = PCODE(pcfl->pcflow);
6523
6524       fprintf(stderr, "    to seq %d:\n",pc->seq);
6525       if(!isPCFL(pc)) {
6526         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6527         pc->print(stderr,pc);
6528       }
6529
6530     }
6531
6532   }
6533
6534 }
6535 #endif
6536 /*-----------------------------------------------------------------*/
6537 /*-----------------------------------------------------------------*/
6538 static int OptimizepBlock(pBlock *pb)
6539 {
6540   pCode *pc, *pcprev;
6541   int matches =0;
6542
6543   if(!pb || !peepOptimizing)
6544     return 0;
6545
6546   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6547 /*
6548   for(pc = pb->pcHead; pc; pc = pc->next)
6549     matches += pic16_pCodePeepMatchRule(pc);
6550 */
6551
6552   pc = pic16_findNextInstruction(pb->pcHead);
6553   if(!pc)
6554     return 0;
6555
6556   pcprev = pc->prev;
6557   do {
6558
6559
6560     if(pic16_pCodePeepMatchRule(pc)) {
6561
6562       matches++;
6563
6564       if(pcprev)
6565         pc = pic16_findNextInstruction(pcprev->next);
6566       else
6567         pc = pic16_findNextInstruction(pb->pcHead);
6568     } else
6569       pc = pic16_findNextInstruction(pc->next);
6570   } while(pc);
6571
6572   if(matches)
6573     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6574   return matches;
6575
6576 }
6577
6578 /*-----------------------------------------------------------------*/
6579 /*-----------------------------------------------------------------*/
6580 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6581 {
6582   pCode *pc;
6583
6584   for(pc = pcs; pc; pc = pc->next) {
6585
6586     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6587        (PCI(pc)->pcop) &&
6588        (PCI(pc)->pcop->type == PO_LABEL) &&
6589        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6590       return pc;
6591   }
6592
6593
6594   return NULL;
6595 }
6596
6597 /*-----------------------------------------------------------------*/
6598 /*-----------------------------------------------------------------*/
6599 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6600 {
6601
6602   char *s=NULL;
6603
6604   if(isPCI(pc) &&
6605      (PCI(pc)->pcop) &&
6606      (PCI(pc)->pcop->type == PO_LABEL)) {
6607
6608     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6609
6610 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6611 //    if(pcol->pcop.name)
6612 //      Safe_free(pcol->pcop.name);
6613
6614     /* If the key is negative, then we (probably) have a label to
6615      * a function and the name is already defined */
6616
6617     if(pcl->key>0)
6618       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6619     else
6620       s = pcl->label;
6621
6622     //sprintf(buffer,"_%05d_DS_",pcl->key);
6623     if(!s) {
6624       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6625     }
6626     pcol->pcop.name = Safe_strdup(s);
6627     pcol->key = pcl->key;
6628     //pc->print(stderr,pc);
6629
6630   }
6631
6632
6633 }
6634
6635 /*-----------------------------------------------------------------*/
6636 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6637 /*                            pCode chain if they're not used.     */
6638 /*-----------------------------------------------------------------*/
6639 static void pBlockRemoveUnusedLabels(pBlock *pb)
6640 {
6641   pCode *pc; pCodeLabel *pcl;
6642
6643   if(!pb || !pb->pcHead)
6644     return;
6645
6646   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6647
6648     pBranch *pbr = PCI(pc)->label;
6649     if(pbr && pbr->next) {
6650       pCode *pcd = pb->pcHead;
6651
6652 //      fprintf(stderr, "multiple labels\n");
6653 //      pc->print(stderr,pc);
6654
6655       pbr = pbr->next;
6656       while(pbr) {
6657
6658         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6659           //fprintf(stderr,"Used by:\n");
6660           //pcd->print(stderr,pcd);
6661
6662           exchangeLabels(PCL(pbr->pc),pcd);
6663
6664           pcd = pcd->next;
6665         }
6666         pbr = pbr->next;
6667       }
6668     }
6669   }
6670
6671   for(pc = pb->pcHead; pc; pc = pc->next) {
6672
6673     if(isPCL(pc)) // pc->type == PC_LABEL)
6674       pcl = PCL(pc);
6675     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6676       pcl = PCL(PCI(pc)->label->pc);
6677     else continue;
6678
6679 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6680
6681     /* This pCode is a label, so search the pBlock to see if anyone
6682      * refers to it */
6683
6684     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6685         && (!pcl->force)) {
6686     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6687       /* Couldn't find an instruction that refers to this label
6688        * So, unlink the pCode label from it's pCode chain
6689        * and destroy the label */
6690 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6691
6692       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6693       if(pc->type == PC_LABEL) {
6694         pic16_unlinkpCode(pc);
6695         pCodeLabelDestruct(pc);
6696       } else {
6697         unlinkpCodeFromBranch(pc, PCODE(pcl));
6698         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6699           Safe_free(pc->label);
6700         }*/
6701       }
6702
6703     }
6704   }
6705
6706 }
6707
6708
6709 /*-----------------------------------------------------------------*/
6710 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6711 /*                     chain and put them into pBranches that are  */
6712 /*                     associated with the appropriate pCode       */
6713 /*                     instructions.                               */
6714 /*-----------------------------------------------------------------*/
6715 void pic16_pBlockMergeLabels(pBlock *pb)
6716 {
6717   pBranch *pbr;
6718   pCode *pc, *pcnext=NULL;
6719
6720   if(!pb)
6721     return;
6722
6723   /* First, Try to remove any unused labels */
6724   //pBlockRemoveUnusedLabels(pb);
6725
6726   /* Now loop through the pBlock and merge the labels with the opcodes */
6727
6728   pc = pb->pcHead;
6729   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6730
6731   while(pc) {
6732     pCode *pcn = pc->next;
6733
6734     if(pc->type == PC_LABEL) {
6735
6736 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6737 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6738
6739       if((pcnext = pic16_findNextInstruction(pc) )) {
6740
6741 //              pcnext->print(stderr, pcnext);
6742
6743         // Unlink the pCode label from it's pCode chain
6744         pic16_unlinkpCode(pc);
6745
6746 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6747         // And link it into the instruction's pBranch labels. (Note, since
6748         // it's possible to have multiple labels associated with one instruction
6749         // we must provide a means to accomodate the additional labels. Thus
6750         // the labels are placed into the singly-linked list "label" as
6751         // opposed to being a single member of the pCodeInstruction.)
6752
6753         //_ALLOC(pbr,sizeof(pBranch));
6754 #if 1
6755         pbr = Safe_calloc(1,sizeof(pBranch));
6756         pbr->pc = pc;
6757         pbr->next = NULL;
6758
6759         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6760 #endif
6761       } else {
6762         if(pic16_pcode_verbose)
6763         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6764       }
6765     } else if(pc->type == PC_CSOURCE) {
6766
6767       /* merge the source line symbolic info into the next instruction */
6768       if((pcnext = pic16_findNextInstruction(pc) )) {
6769
6770         // Unlink the pCode label from it's pCode chain
6771         pic16_unlinkpCode(pc);
6772         PCI(pcnext)->cline = PCCS(pc);
6773         //fprintf(stderr, "merging CSRC\n");
6774         //genericPrint(stderr,pcnext);
6775       }
6776
6777     }
6778     pc = pcn;
6779   }
6780   pBlockRemoveUnusedLabels(pb);
6781
6782 }
6783
6784 /*-----------------------------------------------------------------*/
6785 /*-----------------------------------------------------------------*/
6786 static int OptimizepCode(char dbName)
6787 {
6788 #define MAX_PASSES 4
6789
6790   int matches = 0;
6791   int passes = 0;
6792   pBlock *pb;
6793
6794   if(!the_pFile)
6795     return 0;
6796
6797   DFPRINTF((stderr," Optimizing pCode\n"));
6798
6799   do {
6800     matches = 0;
6801     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6802       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6803         matches += OptimizepBlock(pb);
6804     }
6805   }
6806   while(matches && ++passes < MAX_PASSES);
6807
6808   return matches;
6809 }
6810
6811
6812
6813 const char *pic16_pCodeOpType(pCodeOp *pcop);
6814 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6815
6816
6817 /*-----------------------------------------------------------------*/
6818 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6819 /*-----------------------------------------------------------------*/
6820
6821 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6822 {
6823   pCodeOp *pcop=NULL;
6824
6825 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6826
6827   if(pc->name) {
6828         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6829   } else {
6830     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6831   }
6832
6833   assert(pcop != NULL);
6834
6835   if( !( (pcop->type == PO_LABEL) ||
6836          (pcop->type == PO_LITERAL) ||
6837          (pcop->type == PO_STR) ))
6838     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6839     PCOR(pcop)->r->wasUsed = 1;
6840     PCOR(pcop)->instance = PCOR(pc)->instance;
6841
6842   return pcop;
6843 }
6844
6845
6846 /*----------------------------------------------------------------------*
6847  * pic16_areRegsSame - check to see if the names of two registers match *
6848  *----------------------------------------------------------------------*/
6849 int pic16_areRegsSame(regs *r1, regs *r2)
6850 {
6851         if(!strcmp(r1->name, r2->name))return 1;
6852
6853   return 0;
6854 }
6855
6856
6857 /*-----------------------------------------------------------------*/
6858 /*-----------------------------------------------------------------*/
6859 static void pic16_FixRegisterBanking(pBlock *pb)
6860 {
6861   pCode *pc=NULL;
6862   pCode *pcprev=NULL;
6863   regs *reg, *prevreg;
6864   unsigned char flag=0;
6865
6866         if(!pb)
6867                 return;
6868
6869         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6870         if(!pc)return;
6871
6872         /* loop through all of the flow blocks with in one pblock */
6873
6874 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6875
6876         prevreg = NULL;
6877         do {
6878                 /* at this point, pc should point to a PC_FLOW object */
6879                 /* for each flow block, determine the register banking
6880                  * requirements */
6881
6882
6883                 /* if label, then might come from other point, force banksel */
6884                 if(isPCL(pc))prevreg = NULL;
6885
6886                 if(!isPCI(pc))goto loop;
6887
6888                 if(PCI(pc)->label)prevreg = NULL;
6889
6890                 if(PCI(pc)->is2MemOp)goto loop;
6891
6892                 /* if goto, then force banksel */
6893 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6894
6895                 reg = pic16_getRegFromInstruction(pc);
6896
6897 #if 0
6898                 pc->print(stderr, pc);
6899                 fprintf(stderr, "reg = %p\n", reg);
6900
6901                 if(reg) {
6902                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6903                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6904                                 reg->address,reg->isBitField, reg->isFixed);
6905                 }
6906 #endif
6907
6908                 /* now make some tests to make sure that instruction needs bank switch */
6909
6910                 /* if no register exists, and if not a bit opcode goto loop */
6911                 if(!reg) {
6912                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6913                 }
6914
6915                 if(isPCI_SKIP(pc)) {
6916 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6917 //                prevreg = NULL;
6918                 }
6919                 if(reg && isACCESS_BANK(reg))goto loop;
6920
6921                 if(!isBankInstruction(pc))goto loop;
6922
6923                 if(isPCI_LIT(pc))goto loop;
6924
6925                 if(PCI(pc)->op == POC_CALL)goto loop;
6926
6927                 /* Examine the instruction before this one to make sure it is
6928                  * not a skip type instruction */
6929                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6930
6931                 flag = 0;               /* add before this instruction */
6932
6933                 /* if previous instruction is a skip one, then set flag
6934                  * to 2 and call insertBankSwitch */
6935                 if(pcprev && isPCI_SKIP(pcprev)) {
6936                   flag=2;       //goto loop
6937 //                prevreg = NULL;
6938                 }
6939
6940                 if(pic16_options.opt_banksel>0) {
6941                   char op1[128], op2[128];
6942
6943                     if(prevreg) {
6944                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
6945                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
6946                       if(!strcmp(op1, op2))goto loop;
6947                     }
6948                 }
6949                 prevreg = reg;
6950                 insertBankSwitch(flag, pc);
6951
6952 //              fprintf(stderr, "BANK SWITCH inserted\n");
6953
6954 loop:
6955                 pcprev = pc;
6956                 pc = pc->next;
6957         } while (pc);
6958 }
6959
6960 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
6961
6962 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
6963 int instrSize (pCode *pc)
6964 {
6965   if (!pc) return 0;
6966
6967   if (isPCAD(pc)) {
6968     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
6969     return 4; // assumes only regular instructions using <= 4 bytes
6970   }
6971
6972   if (isPCI(pc)) return PCI(pc)->isize;
6973
6974   return 0;
6975 }
6976
6977 /* Returns 1 if pc is referenced by the given label (either
6978  * pc is the label itself or is an instruction with an attached
6979  * label).
6980  * Returns 0 if pc is not preceeded by the specified label.
6981  */
6982 int isLabel (pCode *pc, char *label)
6983 {
6984   if (!pc) return 0;
6985
6986   // label attached to the pCode?
6987   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
6988     pBranch *lab = NULL;
6989     lab = PCI(pc)->label;
6990
6991     while (lab) {
6992       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
6993         return 1;
6994       }
6995       lab = lab->next;
6996     } // while
6997   } // if
6998
6999   // is inline assembly label?
7000   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7001     // do not compare trailing ':'
7002     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7003       return 1;
7004     }
7005   } // if
7006
7007   // is pCodeLabel?
7008   if (isPCL(pc)) {
7009       if (strcmp(PCL(pc)->label,label) == 0) {
7010       return 1;
7011     }
7012   } // if
7013
7014   // no label/no label attached/wrong label(s)
7015   return 0;
7016 }
7017
7018 /* Returns the distance to the given label in terms of words.
7019  * Labels are searched only within -max .. max words from pc.
7020  * Returns max if the label could not be found or
7021  * its distance from pc in (-max..+max).
7022  */
7023 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7024   int dist = instrSize(pc);
7025   pCode *curr = pc;
7026
7027   // search backwards
7028   while (dist < max && curr && !isLabel (curr, label)) {
7029     curr = curr->prev;
7030     dist += instrSize(curr); // sizeof (instruction)
7031   } // while
7032   if (curr && dist < max) {
7033     if (target != NULL) *target = curr;
7034     return -dist;
7035   }
7036
7037   dist = 0;
7038   curr = pic16_findNextInstruction (pc->next);
7039   //search forwards
7040   while (dist < max && curr && !isLabel (curr, label)) {
7041     dist += instrSize(curr); // sizeof (instruction)
7042     curr = curr->next;
7043   } // while
7044   if (curr && dist < max) {
7045     if (target != NULL) *target = curr;
7046     return dist;
7047   }
7048
7049   if (target != NULL) *target = NULL;
7050   return max;
7051 }
7052
7053 /* Returns -1 if pc does NOT denote an instruction like
7054  * BTFS[SC] STATUS,i
7055  * Otherwise we return
7056  *   (a) 0x10 + i for BTFSS
7057  *   (b) 0x00 + i for BTFSC
7058  */
7059 int isSkipOnStatus (pCode *pc)
7060 {
7061   int res = -1;
7062   pCodeOp *pcop;
7063   if (!pc || !isPCI(pc)) return -1;
7064   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7065   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7066   else return -1;
7067
7068   pcop = PCI(pc)->pcop;
7069
7070   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7071     return res + ((pCodeOpRegBit *)pcop)->bit;
7072   }
7073
7074   return -1;
7075 }
7076
7077 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7078  * returns 0 otherwise. */
7079 int isConditionalBranch (pCode *pc)
7080 {
7081   if (!pc || !isPCI_BRANCH(pc)) return 0;
7082
7083   switch (PCI(pc)->op) {
7084   case POC_BC:
7085   case POC_BZ:
7086   case POC_BOV:
7087   case POC_BN:
7088   case POC_BNC:
7089   case POC_BNZ:
7090   case POC_BNOV:
7091   case POC_BNN:
7092     return 1;
7093
7094   default:
7095     break;
7096   } // switch
7097
7098   return 0;
7099 }
7100
7101 /* Returns 1 if pc has a label attached to it.
7102  * This can be either a label stored in the pCode itself (.label)
7103  * or a label making up its own pCode preceding this pc.
7104  * Returns 0 if pc cannot be reached directly via a label.
7105  */
7106 int hasNoLabel (pCode *pc)
7107 {
7108   pCode *prev;
7109   if (!pc) return 1;
7110
7111   // are there any label pCodes between pc and the previous instruction?
7112   prev = pic16_findPrevInstruction (pc->prev);
7113   while (pc && pc != prev) {
7114     // pCode with attached label?
7115     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7116         && PCI(pc)->label) {
7117       return 0;
7118     }
7119     // is inline assembly label?
7120     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7121     if (isPCW(pc) && PCW(pc)->label) return 0;
7122
7123     // pCodeLabel?
7124     if (isPCL(pc)) return 0;
7125
7126     pc = pc->prev;
7127   } // if
7128
7129   // no label found
7130   return 1;
7131 }
7132
7133 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7134   char buf[512];
7135   va_list va;
7136
7137   va_start (va, fmt);
7138   vsprintf (buf, fmt, va);
7139   va_end (va);
7140
7141   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7142 }
7143
7144 /* Replaces the old pCode with the new one, moving the labels,
7145  * C source line and probably flow information to the new pCode.
7146  */
7147 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7148   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7149     return;
7150
7151   /* first move all labels from old to new */
7152   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7153   PCI(oldPC)->label = NULL;
7154
7155 #if 0
7156   /* move C source line (if possible) */
7157   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7158     PCI(newPC)->cline = PCI(oldPC)->cline;
7159 #endif
7160
7161   /* keep flow information intact */
7162   newPC->seq = oldPC->seq;
7163   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7164   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7165     PCI(newPC)->pcflow->end = newPC;
7166   }
7167
7168   /* insert a comment stating which pCode has been replaced */
7169 #if 1
7170   if (pic16_pcode_verbose || pic16_debug_verbose) {
7171     char pc_str[256];
7172     pic16_pCode2str (pc_str, 256, oldPC);
7173     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7174   }
7175 #endif
7176
7177   /* insert new pCode into pBlock */
7178   pic16_pCodeInsertAfter (oldPC, newPC);
7179   pic16_unlinkpCode (oldPC);
7180
7181   /* destruct replaced pCode */
7182   oldPC->destruct (oldPC);
7183 }
7184
7185 /* Returns the inverted conditional branch (if any) or NULL.
7186  * pcop must be set to the new jump target.
7187  */
7188 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7189 {
7190   pCode *newBcc;
7191
7192   if (!bcc || !isPCI(bcc)) return NULL;
7193
7194   switch (PCI(bcc)->op) {
7195   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7196   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7197   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7198   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7199   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7200   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7201   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7202   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7203   default:
7204     newBcc = NULL;
7205   }
7206   return newBcc;
7207 }
7208
7209 #define MAX_DIST_GOTO         0x7FFFFFFF
7210 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7211 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7212 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7213 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7214
7215 /* Follows GOTO/BRA instructions to their target instructions, stores the
7216  * final destination (not a GOTO or BRA instruction) in target and returns
7217  * the distance from the original pc to *target.
7218  */
7219 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7220         pCode *curr = pc;
7221         pCode *last = NULL;
7222         pCodeOp *lastPCOP = NULL;
7223         int dist = 0;
7224         int depth = 0;
7225
7226         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7227
7228         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7229         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7230                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7231                 last = curr;
7232                 lastPCOP = PCI(curr)->pcop;
7233                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7234                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7235         } // while
7236
7237         if (target) *target = last;
7238         if (pcop) *pcop = lastPCOP;
7239         return dist;
7240 }
7241
7242 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7243  * Otherwise the first pCode after the jumptable (after
7244  * the OPT_JUMPTABLE_END tag) is returned.
7245  */
7246 pCode *skipJumptables (pCode *pc, int *isJumptable)
7247 {
7248   *isJumptable = 0;
7249   if (!pc) return NULL;
7250
7251   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7252     *isJumptable = 1;
7253     //fprintf (stderr, "SKIPPING jumptable\n");
7254     do {
7255       //pc->print(stderr, pc);
7256       pc = pc->next;
7257     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7258                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7259     //fprintf (stderr, "<<JUMPTAB:\n");
7260     // skip OPT_END as well
7261     if (pc) pc = pc->next;
7262   } // while
7263
7264   return pc;
7265 }
7266
7267 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7268 {
7269   int isJumptab;
7270   *isJumptable = 0;
7271   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7272     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7273     pc = skipJumptables (pc, &isJumptab);
7274     if (isJumptab) {
7275         // pc is the first pCode after the jumptable
7276         *isJumptable = 1;
7277     } else {
7278         // pc has not been changed by skipJumptables()
7279         pc = pc->next;
7280     }
7281   } // while
7282
7283   return pc;
7284 }
7285
7286 /* Turn GOTOs into BRAs if distance between GOTO and label
7287  * is less than 1024 bytes.
7288  *
7289  * This method is especially useful if GOTOs after BTFS[SC]
7290  * can be turned into BRAs as GOTO would cost another NOP
7291  * if skipped.
7292  */
7293 void pic16_OptimizeJumps ()
7294 {
7295   pCode *pc;
7296   pCode *pc_prev = NULL;
7297   pCode *pc_next = NULL;
7298   pBlock *pb;
7299   pCode *target;
7300   int change, iteration, isJumptab;
7301   int isHandled = 0;
7302   char *label;
7303   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7304
7305   if (!the_pFile) return;
7306
7307   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7308
7309   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7310     int matchedInvertRule = 1;
7311     iteration = 1;
7312     do {
7313       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7314       change = 0;
7315       pc = pic16_findNextInstruction (pb->pcHead);
7316
7317       while (pc) {
7318         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7319         if (isJumptab) {
7320                 // skip jumptable, i.e. start over with no pc_prev!
7321                 pc_prev = NULL;
7322                 pc = pc_next;
7323                 continue;
7324         } // if
7325
7326         /* (1) resolve chained jumps
7327          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7328          * (a) leave dead code in and
7329          * (b) skip over the dead code with an (unneccessary) jump.
7330          */
7331         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7332           pCodeOp *lastTargetOp = NULL;
7333           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7334           int maxDist = MAX_DIST_BCC;
7335           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7336           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7337
7338           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7339           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7340               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7341             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7342             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7343             PCI(pc)->pcop->name = lastTargetOp->name;
7344             change++;
7345             opt_gotochain++;
7346           } // if
7347         } // if
7348
7349
7350         if (IS_GOTO(pc)) {
7351           int dist;
7352           int condBraType = isSkipOnStatus(pc_prev);
7353           label = PCI(pc)->pcop->name;
7354           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7355           if (dist < 0) dist = -dist;
7356           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7357           isHandled = 0;
7358
7359
7360           /* (2) remove "GOTO label; label:" */
7361           if (isLabel (pc_next, label)) {
7362             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7363             // first remove all preceeding SKIP instructions
7364             while (pc_prev && isPCI_SKIP(pc_prev)) {
7365               // attach labels on this instruction to pc_next
7366               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7367               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7368               PCI(pc_prev)->label = NULL;
7369               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7370               pic16_unlinkpCode (pc_prev);
7371               pc_prev = pic16_findPrevInstruction (pc);
7372             } // while
7373             // now remove the redundant goto itself
7374             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7375             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7376             pic16_unlinkpCode (pc);
7377             pc = pic16_findPrevInstruction(pc_next->prev);
7378             isHandled = 1; // do not perform further optimizations
7379             opt_gotonext++;
7380             change++;
7381           } // if
7382
7383
7384           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7385           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7386             if (dist < MAX_DIST_BCC) {
7387               pCode *bcc = NULL;
7388               switch (condBraType) {
7389               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7390                 // no BDC on DIGIT CARRY available
7391               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7392               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7393               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7394               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7395                 // no BNDC on DIGIT CARRY available
7396               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7397               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7398               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7399               default:
7400                 // no replacement possible
7401                 bcc = NULL;
7402                 break;
7403               } // switch
7404               if (bcc) {
7405                 // ATTENTION: keep labels attached to BTFSx!
7406                 // HINT: GOTO is label free (checked above)
7407                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7408                 isHandled = 1; // do not perform further optimizations
7409                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7410                 pic16_pCodeReplace (pc_prev, bcc);
7411                 pc->destruct(pc);
7412                 pc = bcc;
7413                 opt_cond++;
7414                 change++;
7415               } // if
7416             } else {
7417               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7418               cond_toofar++;
7419             } // if
7420           } // if
7421
7422           if (!isHandled) {
7423             // (4) eliminate the following (common) tripel:
7424             //           <pred.>;
7425             //  labels1: Bcc label2;
7426             //           GOTO somewhere;    ; <-- instruction referenced by pc
7427             //  label2:  <cont.>
7428             // and replace it by
7429             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7430             //  label2:  <cont.>
7431             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7432             //            to <cont.> instead
7433             // ATTENTION: This optimization is only valid if <pred.> is
7434             //            not a skip operation!
7435             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7436             // ATTENTION: no label may be attached to the GOTO instruction!
7437             if (isConditionalBranch(pc_prev)
7438                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7439                 && (dist < MAX_DIST_BCC)
7440                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7441                 && hasNoLabel(pc)) {
7442               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7443
7444               if (newBcc) {
7445                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7446                 isHandled = 1; // do not perform further optimizations
7447                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7448                 pic16_pCodeReplace (pc_prev, newBcc);
7449                 pc->destruct(pc);
7450                 pc = newBcc;
7451                 opt_reorder++;
7452                 change++;
7453                 matchedInvertRule++;
7454               }
7455             }
7456           }
7457
7458           /* (5) now just turn GOTO into BRA */
7459           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7460             if (dist < MAX_DIST_BRA) {
7461               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7462               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7463               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7464               pic16_pCodeReplace (pc, newBra);
7465               pc = newBra;
7466               opt++;
7467               change++;
7468             } else {
7469               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7470               toofar++;
7471             }
7472           } // if (!isHandled)
7473         } // if
7474
7475         pc_prev = pc;
7476         pc = pc_next;
7477       } // while (pc)
7478
7479       pBlockRemoveUnusedLabels (pb);
7480
7481       // This line enables goto chain resolution!
7482       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7483
7484       iteration++;
7485     } while (change); /* fixpoint iteration per pBlock */
7486   } // for (pb)
7487
7488   // emit some statistics concerning goto-optimization
7489 #if 0
7490   if (pic16_debug_verbose || pic16_pcode_verbose) {
7491     fprintf (stderr, "optimize-goto:\n"
7492              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7493              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7494              "\t%5d conditional \"skipping\" jumps inverted\n"
7495              "\t%5d GOTOs to next instruction removed\n"
7496              "\t%5d chained GOTOs resolved\n",
7497              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7498   } // if
7499 #endif
7500   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7501 }
7502
7503 #undef IS_GOTO
7504 #undef MAX_JUMPCHAIN_DEPTH
7505 #undef MAX_DIST_GOTO
7506 #undef MAX_DIST_BRA
7507 #undef MAX_DIST_BCC
7508
7509 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7510
7511 static void pBlockDestruct(pBlock *pb)
7512 {
7513
7514   if(!pb)
7515     return;
7516
7517
7518 //  Safe_free(pb);
7519
7520 }
7521
7522 /*-----------------------------------------------------------------*/
7523 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7524 /*                                  name dbName and combine them   */
7525 /*                                  into one block                 */
7526 /*-----------------------------------------------------------------*/
7527 static void mergepBlocks(char dbName)
7528 {
7529
7530   pBlock *pb, *pbmerged = NULL,*pbn;
7531
7532   pb = the_pFile->pbHead;
7533
7534   //fprintf(stderr," merging blocks named %c\n",dbName);
7535   while(pb) {
7536
7537     pbn = pb->next;
7538     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7539     if( getpBlock_dbName(pb) == dbName) {
7540
7541       //fprintf(stderr," merged block %c\n",dbName);
7542
7543       if(!pbmerged) {
7544         pbmerged = pb;
7545       } else {
7546         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7547         /* pic16_addpCode2pBlock doesn't handle the tail: */
7548         pbmerged->pcTail = pb->pcTail;
7549
7550         pb->prev->next = pbn;
7551         if(pbn)
7552           pbn->prev = pb->prev;
7553
7554
7555         pBlockDestruct(pb);
7556       }
7557       //pic16_printpBlock(stderr, pbmerged);
7558     }
7559     pb = pbn;
7560   }
7561
7562 }
7563
7564 /*-----------------------------------------------------------------*/
7565 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7566 /*                                                                 */
7567 /* level 0 == minimal optimization                                 */
7568 /*   optimize registers that are used only by two instructions     */
7569 /* level 1 == maximal optimization                                 */
7570 /*   optimize by looking at pairs of instructions that use the     */
7571 /*   register.                                                     */
7572 /*-----------------------------------------------------------------*/
7573
7574 static void AnalyzeFlow(int level)
7575 {
7576   static int times_called=0;
7577   pBlock *pb;
7578
7579     if(!the_pFile) {
7580       /* remove unused allocated registers before exiting */
7581       pic16_RemoveUnusedRegisters();
7582       return;
7583     }
7584
7585
7586     /* if this is not the first time this function has been called,
7587      * then clean up old flow information */
7588     if(times_called++) {
7589       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7590         unBuildFlow(pb);
7591         pic16_RegsUnMapLiveRanges();
7592     }
7593     GpcFlowSeq = 1;
7594
7595     /* Phase 2 - Flow Analysis - Register Banking
7596      *
7597      * In this phase, the individual flow blocks are examined
7598      * and register banking is fixed.
7599      */
7600
7601 #if 0
7602     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7603       pic16_FixRegisterBanking(pb);
7604 #endif
7605
7606     /* Phase 2 - Flow Analysis
7607      *
7608      * In this phase, the pCode is partition into pCodeFlow
7609      * blocks. The flow blocks mark the points where a continuous
7610      * stream of instructions changes flow (e.g. because of
7611      * a call or goto or whatever).
7612      */
7613
7614     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7615       pic16_BuildFlow(pb);
7616
7617
7618     /* Phase 2 - Flow Analysis - linking flow blocks
7619      *
7620      * In this phase, the individual flow blocks are examined
7621      * to determine their order of excution.
7622      */
7623
7624     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7625       LinkFlow(pb);
7626
7627 #if 1
7628         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7629                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7630                         pic16_createDF (pb);
7631 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7632                         pic16_vcg_dump_default (pb);
7633 #endif
7634                         //pic16_destructDF (pb);
7635                 }
7636
7637                 pic16_df_stats ();
7638                 if (0) releaseStack (); // releasing is costly...
7639         }
7640 #endif
7641
7642     /* Phase 3 - Flow Analysis - Flow Tree
7643      *
7644      * In this phase, the individual flow blocks are examined
7645      * to determine their order of execution.
7646      */
7647
7648     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7649       pic16_BuildFlowTree(pb);
7650
7651
7652     /* Phase x - Flow Analysis - Used Banks
7653      *
7654      * In this phase, the individual flow blocks are examined
7655      * to determine the Register Banks they use
7656      */
7657
7658 #if 0
7659     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7660       FixBankFlow(pb);
7661 #endif
7662
7663
7664     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7665       pic16_pCodeRegMapLiveRanges(pb);
7666
7667     pic16_RemoveUnusedRegisters();
7668     pic16_removeUnusedRegistersDF ();
7669
7670   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7671     pic16_pCodeRegOptimizeRegUsage(level);
7672
7673
7674 #if 0
7675     if(!options.nopeep)
7676       OptimizepCode('*');
7677 #endif
7678
7679 #if 0
7680     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7681       DumpFlow(pb);
7682 #endif
7683
7684     /* debug stuff */
7685     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7686       pCode *pcflow;
7687
7688         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7689           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7690           pcflow = pcflow->next) {
7691             FillFlow(PCFL(pcflow));
7692         }
7693     }
7694
7695 #if 0
7696     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7697       pCode *pcflow;
7698
7699         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7700           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7701           pcflow = pcflow->next) {
7702             FlowStats(PCFL(pcflow));
7703         }
7704     }
7705 #endif
7706 }
7707
7708 /* VR -- no need to analyze banking in flow, but left here :
7709  *      1. because it may be used in the future for other purposes
7710  *      2. because if omitted we'll miss some optimization done here
7711  *
7712  * Perhaps I should rename it to something else
7713  */
7714
7715 /*-----------------------------------------------------------------*/
7716 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7717 /*                  assigned to the registers.                     */
7718 /*                                                                 */
7719 /*-----------------------------------------------------------------*/
7720
7721 void pic16_AnalyzeBanking(void)
7722 {
7723   pBlock  *pb;
7724
7725     /* Phase x - Flow Analysis - Used Banks
7726      *
7727      * In this phase, the individual flow blocks are examined
7728      * to determine the Register Banks they use
7729      */
7730
7731     AnalyzeFlow(0);
7732     AnalyzeFlow(1);
7733
7734     if(!options.nopeep)
7735       OptimizepCode('*');
7736
7737
7738     if(!the_pFile)return;
7739
7740     if(!pic16_options.no_banksel) {
7741       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7742 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7743         pic16_FixRegisterBanking(pb);
7744       }
7745     }
7746 }
7747
7748 /*-----------------------------------------------------------------*/
7749 /* buildCallTree - Look at the flow and extract all of the calls.  */
7750 /*-----------------------------------------------------------------*/
7751 #if 0
7752 static set *register_usage(pBlock *pb);
7753 #endif
7754
7755 static void buildCallTree(void    )
7756 {
7757   pBranch *pbr;
7758   pBlock  *pb;
7759   pCode   *pc;
7760   regs *r;
7761
7762   if(!the_pFile)
7763     return;
7764
7765
7766
7767   /* Now build the call tree.
7768      First we examine all of the pCodes for functions.
7769      Keep in mind that the function boundaries coincide
7770      with pBlock boundaries.
7771
7772      The algorithm goes something like this:
7773      We have two nested loops. The outer loop iterates
7774      through all of the pBlocks/functions. The inner
7775      loop iterates through all of the pCodes for
7776      a given pBlock. When we begin iterating through
7777      a pBlock, the variable pc_fstart, pCode of the start
7778      of a function, is cleared. We then search for pCodes
7779      of type PC_FUNCTION. When one is encountered, we
7780      initialize pc_fstart to this and at the same time
7781      associate a new pBranch object that signifies a
7782      branch entry. If a return is found, then this signifies
7783      a function exit point. We'll link the pCodes of these
7784      returns to the matching pc_fstart.
7785
7786      When we're done, a doubly linked list of pBranches
7787      will exist. The head of this list is stored in
7788      `the_pFile', which is the meta structure for all
7789      of the pCode. Look at the pic16_printCallTree function
7790      on how the pBranches are linked together.
7791
7792    */
7793   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7794     pCode *pc_fstart=NULL;
7795     for(pc = pb->pcHead; pc; pc = pc->next) {
7796
7797         if(isPCI(pc) && pc_fstart) {
7798                 if(PCI(pc)->is2MemOp) {
7799                         r = pic16_getRegFromInstruction2(pc);
7800                         if(r && !strcmp(r->name, "POSTDEC1"))
7801                                 PCF(pc_fstart)->stackusage++;
7802                 } else {
7803                         r = pic16_getRegFromInstruction(pc);
7804                         if(r && !strcmp(r->name, "PREINC1"))
7805                                 PCF(pc_fstart)->stackusage--;
7806                 }
7807         }
7808
7809       if(isPCF(pc)) {
7810         if (PCF(pc)->fname) {
7811         char buf[16];
7812
7813           sprintf(buf, "%smain", port->fun_prefix);
7814           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7815             //fprintf(stderr," found main \n");
7816             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7817             pb->dbName = 'M';
7818           }
7819
7820           pbr = Safe_calloc(1,sizeof(pBranch));
7821           pbr->pc = pc_fstart = pc;
7822           pbr->next = NULL;
7823
7824           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7825
7826           // Here's a better way of doing the same:
7827           addSet(&pb->function_entries, pc);
7828
7829         } else {
7830           // Found an exit point in a function, e.g. return
7831           // (Note, there may be more than one return per function)
7832           if(pc_fstart)
7833             pBranchLink(PCF(pc_fstart), PCF(pc));
7834
7835           addSet(&pb->function_exits, pc);
7836         }
7837       } else if(isCALL(pc)) {
7838         addSet(&pb->function_calls,pc);
7839       }
7840     }
7841   }
7842
7843
7844 #if 0
7845   /* This is not needed because currently all register used
7846    * by a function are stored in stack -- VR */
7847
7848   /* Re-allocate the registers so that there are no collisions
7849    * between local variables when one function call another */
7850
7851   // this is weird...
7852   //  pic16_deallocateAllRegs();
7853
7854   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7855     if(!pb->visited)
7856       register_usage(pb);
7857   }
7858 #endif
7859
7860 }
7861
7862 /*-----------------------------------------------------------------*/
7863 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7864 /*                all of the logical connections.                  */
7865 /*                                                                 */
7866 /* Essentially what's done here is that the pCode flow is          */
7867 /* determined.                                                     */
7868 /*-----------------------------------------------------------------*/
7869
7870 void pic16_AnalyzepCode(char dbName)
7871 {
7872   pBlock *pb;
7873   int i,changes;
7874
7875   if(!the_pFile)
7876     return;
7877
7878   mergepBlocks('D');
7879
7880
7881   /* Phase 1 - Register allocation and peep hole optimization
7882    *
7883    * The first part of the analysis is to determine the registers
7884    * that are used in the pCode. Once that is done, the peep rules
7885    * are applied to the code. We continue to loop until no more
7886    * peep rule optimizations are found (or until we exceed the
7887    * MAX_PASSES threshold).
7888    *
7889    * When done, the required registers will be determined.
7890    *
7891    */
7892   i = 0;
7893   do {
7894
7895     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7896     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7897
7898     /* First, merge the labels with the instructions */
7899     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7900       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7901
7902         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7903         //fprintf(stderr," analyze and merging block %c\n",dbName);
7904         pic16_pBlockMergeLabels(pb);
7905         AnalyzepBlock(pb);
7906       } else {
7907         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7908       }
7909     }
7910
7911         if(!options.nopeep)
7912                 changes = OptimizepCode(dbName);
7913         else changes = 0;
7914
7915   } while(changes && (i++ < MAX_PASSES));
7916
7917
7918   buildCallTree();
7919 }
7920
7921
7922 /* convert a series of movff's of local regs to stack, with a single call to
7923  * a support functions which does the same thing via loop */
7924 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
7925 {
7926   pBranch *pbr;
7927   pCode *pc, *pct;
7928   char *fname[]={"__lr_store", "__lr_restore"};
7929
7930 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7931
7932     pct = pic16_findNextInstruction(pcstart->next);
7933     do {
7934       pc = pct;
7935       pct = pc->next;   //pic16_findNextInstruction(pc->next);
7936 //      pc->print(stderr, pc);
7937       if(isPCI(pc) && PCI(pc)->label) {
7938         pbr = PCI(pc)->label;
7939         while(pbr && pbr->pc) {
7940           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
7941           pbr = pbr->next;
7942         }
7943
7944 //        pc->print(stderr, pc);
7945         /* unlink pCode */
7946         pc->prev->next = pct;
7947         pct->prev = pc->prev;
7948 //        pc->next = NULL;
7949 //        pc->prev = NULL;
7950       }
7951     } while ((pc) && (pc != pcend));
7952
7953     /* unlink movff instructions */
7954     pcstart->next = pcend;
7955     pcend->prev = pcstart;
7956
7957     pc = pcstart;
7958 //    if(!entry) {
7959 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7960 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
7961 //    }
7962
7963     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
7964     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
7965     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
7966
7967 //    if(!entry) {
7968 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
7969 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
7970 //    }
7971
7972
7973     {
7974       symbol *sym;
7975
7976         sym = newSymbol( fname[ entry?0:1 ], 0 );
7977         strcpy(sym->rname, fname[ entry?0:1 ]);
7978         checkAddSym(&externs, sym);
7979
7980 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
7981     }
7982
7983 }
7984
7985 /*-----------------------------------------------------------------*/
7986 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
7987 /*    local registers to a support function call                   */
7988 /*-----------------------------------------------------------------*/
7989 void pic16_OptimizeLocalRegs(void)
7990 {
7991   pBlock  *pb;
7992   pCode   *pc;
7993   pCodeInfo *pci;
7994   pCodeOpLocalReg *pclr;
7995   int regCount=0;
7996   int inRegCount=0;
7997   regs *r, *lastr=NULL, *firstr=NULL;
7998   pCode *pcstart=NULL, *pcend=NULL;
7999   int inEntry=0;
8000   char *curFunc=NULL;
8001
8002         /* Overview:
8003          *   local_regs begin mark
8004          *      MOVFF r0x01, POSTDEC1
8005          *      MOVFF r0x02, POSTDEC1
8006          *      ...
8007          *      ...
8008          *      MOVFF r0x0n, POSTDEC1
8009          *   local_regs end mark
8010          *
8011          * convert the above to the below:
8012          *      MOVLW   starting_register_index
8013          *      MOVWF   PRODL
8014          *      MOVLW   register_count
8015          *      call    __save_registers_in_stack
8016          */
8017
8018     if(!the_pFile)
8019       return;
8020
8021     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8022       inRegCount = regCount = 0;
8023       firstr = lastr = NULL;
8024       for(pc = pb->pcHead; pc; pc = pc->next) {
8025
8026         /* hold current function name */
8027         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8028
8029         if(pc && (pc->type == PC_INFO)) {
8030           pci = PCINF(pc);
8031
8032           if(pci->type == INF_LOCALREGS) {
8033             pclr = PCOLR(pci->oper1);
8034
8035             if((pclr->type == LR_ENTRY_BEGIN)
8036               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8037             else inEntry = 0;
8038
8039             switch(pclr->type) {
8040               case LR_ENTRY_BEGIN:
8041               case LR_EXIT_BEGIN:
8042                         inRegCount = 1; regCount = 0;
8043                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8044                         firstr = lastr = NULL;
8045                         break;
8046
8047               case LR_ENTRY_END:
8048               case LR_EXIT_END:
8049                         inRegCount = -1;
8050                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8051
8052 #if 1
8053                         if(curFunc && inWparamList(curFunc+1)) {
8054                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8055                                         filename, curFunc);
8056                         } else {
8057                           if(regCount>2) {
8058                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8059                               firstr, inEntry);
8060                           }
8061                         }
8062 #endif
8063                         firstr = lastr = NULL;
8064                         break;
8065             }
8066
8067             if(inRegCount == -1) {
8068 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8069               regCount = 0;
8070               inRegCount = 0;
8071             }
8072           }
8073         } else {
8074           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8075             if(inEntry)
8076               r = pic16_getRegFromInstruction(pc);
8077             else
8078               r = pic16_getRegFromInstruction2(pc);
8079             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8080               if(!firstr)firstr = r;
8081               regCount++;
8082 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8083             }
8084           }
8085         }
8086       }
8087     }
8088 }
8089
8090
8091
8092
8093
8094 /*-----------------------------------------------------------------*/
8095 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8096 /*                   function                                      */
8097 /*-----------------------------------------------------------------*/
8098 static bool ispCodeFunction(pCode *pc)
8099 {
8100
8101   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8102     return 1;
8103
8104   return 0;
8105 }
8106
8107 /*-----------------------------------------------------------------*/
8108 /* findFunction - Search for a function by name (given the name)   */
8109 /*                in the set of all functions that are in a pBlock */
8110 /* (note - I expect this to change because I'm planning to limit   */
8111 /*  pBlock's to just one function declaration                      */
8112 /*-----------------------------------------------------------------*/
8113 static pCode *findFunction(char *fname)
8114 {
8115   pBlock *pb;
8116   pCode *pc;
8117   if(!fname)
8118     return NULL;
8119
8120   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8121
8122     pc = setFirstItem(pb->function_entries);
8123     while(pc) {
8124
8125       if((pc->type == PC_FUNCTION) &&
8126          (PCF(pc)->fname) &&
8127          (strcmp(fname, PCF(pc)->fname)==0))
8128         return pc;
8129
8130       pc = setNextItem(pb->function_entries);
8131
8132     }
8133
8134   }
8135   return NULL;
8136 }
8137
8138 #if 0
8139 static void MarkUsedRegisters(set *regset)
8140 {
8141
8142   regs *r1,*r2;
8143
8144   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8145 //      fprintf(stderr, "marking register = %s\t", r1->name);
8146     r2 = pic16_regWithIdx(r1->rIdx);
8147 //      fprintf(stderr, "to register = %s\n", r2->name);
8148     r2->isFree = 0;
8149     r2->wasUsed = 1;
8150   }
8151 }
8152 #endif
8153
8154 static void pBlockStats(FILE *of, pBlock *pb)
8155 {
8156
8157   pCode *pc;
8158   regs  *r;
8159
8160         if(!pic16_pcode_verbose)return;
8161
8162   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8163
8164   // for now just print the first element of each set
8165   pc = setFirstItem(pb->function_entries);
8166   if(pc) {
8167     fprintf(of,";entry:  ");
8168     pc->print(of,pc);
8169   }
8170   pc = setFirstItem(pb->function_exits);
8171   if(pc) {
8172     fprintf(of,";has an exit\n");
8173     //pc->print(of,pc);
8174   }
8175
8176   pc = setFirstItem(pb->function_calls);
8177   if(pc) {
8178     fprintf(of,";functions called:\n");
8179
8180     while(pc) {
8181       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8182         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8183       }
8184       pc = setNextItem(pb->function_calls);
8185     }
8186   }
8187
8188   r = setFirstItem(pb->tregisters);
8189   if(r) {
8190     int n = elementsInSet(pb->tregisters);
8191
8192     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8193
8194     while (r) {
8195       fprintf(of,   ";   %s\n",r->name);
8196       r = setNextItem(pb->tregisters);
8197     }
8198   }
8199
8200   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8201 }
8202
8203 /*-----------------------------------------------------------------*/
8204 /*-----------------------------------------------------------------*/
8205 #if 0
8206 static void sequencepCode(void)
8207 {
8208   pBlock *pb;
8209   pCode *pc;
8210
8211
8212   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8213
8214     pb->seq = GpCodeSequenceNumber+1;
8215
8216     for( pc = pb->pcHead; pc; pc = pc->next)
8217       pc->seq = ++GpCodeSequenceNumber;
8218   }
8219
8220 }
8221 #endif
8222
8223 #if 0
8224 /*-----------------------------------------------------------------*/
8225 /*-----------------------------------------------------------------*/
8226 static set *register_usage(pBlock *pb)
8227 {
8228   pCode *pc,*pcn;
8229   set *registers=NULL;
8230   set *registersInCallPath = NULL;
8231
8232   /* check recursion */
8233
8234   pc = setFirstItem(pb->function_entries);
8235
8236   if(!pc)
8237     return registers;
8238
8239   pb->visited = 1;
8240
8241   if(pc->type != PC_FUNCTION)
8242     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8243
8244   pc = setFirstItem(pb->function_calls);
8245   for( ; pc; pc = setNextItem(pb->function_calls)) {
8246
8247     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8248       char *dest = pic16_get_op_from_instruction(PCI(pc));
8249
8250       pcn = findFunction(dest);
8251       if(pcn)
8252         registersInCallPath = register_usage(pcn->pb);
8253     } else
8254       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8255
8256   }
8257
8258 #ifdef PCODE_DEBUG
8259   pBlockStats(stderr,pb);  // debug
8260 #endif
8261
8262   // Mark the registers in this block as used.
8263
8264   MarkUsedRegisters(pb->tregisters);
8265   if(registersInCallPath) {
8266     /* registers were used in the functions this pBlock has called */
8267     /* so now, we need to see if these collide with the ones we are */
8268     /* using here */
8269
8270     regs *r1,*r2, *newreg;
8271
8272     DFPRINTF((stderr,"comparing registers\n"));
8273
8274     r1 = setFirstItem(registersInCallPath);
8275     while(r1) {
8276
8277       r2 = setFirstItem(pb->tregisters);
8278
8279       while(r2 && (r1->type != REG_STK)) {
8280
8281         if(r2->rIdx == r1->rIdx) {
8282           newreg = pic16_findFreeReg(REG_GPR);
8283
8284
8285           if(!newreg) {
8286             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8287             exit(1);
8288           }
8289
8290           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8291                   r1->rIdx, newreg->rIdx));
8292           r2->rIdx = newreg->rIdx;
8293           //if(r2->name) Safe_free(r2->name);
8294           if(newreg->name)
8295             r2->name = Safe_strdup(newreg->name);
8296           else
8297             r2->name = NULL;
8298           newreg->isFree = 0;
8299           newreg->wasUsed = 1;
8300         }
8301         r2 = setNextItem(pb->tregisters);
8302       }
8303
8304       r1 = setNextItem(registersInCallPath);
8305     }
8306
8307     /* Collisions have been resolved. Now free the registers in the call path */
8308     r1 = setFirstItem(registersInCallPath);
8309     while(r1) {
8310       if(r1->type != REG_STK) {
8311         newreg = pic16_regWithIdx(r1->rIdx);
8312         newreg->isFree = 1;
8313       }
8314       r1 = setNextItem(registersInCallPath);
8315     }
8316
8317   }// else
8318   //    MarkUsedRegisters(pb->registers);
8319
8320   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8321 #ifdef PCODE_DEBUG
8322   if(registers)
8323     DFPRINTF((stderr,"returning regs\n"));
8324   else
8325     DFPRINTF((stderr,"not returning regs\n"));
8326
8327   DFPRINTF((stderr,"pBlock after register optim.\n"));
8328   pBlockStats(stderr,pb);  // debug
8329 #endif
8330
8331   return registers;
8332 }
8333 #endif
8334
8335 /*-----------------------------------------------------------------*/
8336 /* pct2 - writes the call tree to a file                           */
8337 /*                                                                 */
8338 /*-----------------------------------------------------------------*/
8339 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8340 {
8341   pCode *pc,*pcn;
8342   int i;
8343   //  set *registersInCallPath = NULL;
8344
8345   if(!of)
8346     return;
8347
8348   if(indent > 10) {
8349         fprintf(of, "recursive function\n");
8350     return; //recursion ?
8351   }
8352
8353   pc = setFirstItem(pb->function_entries);
8354
8355   if(!pc)
8356     return;
8357
8358   pb->visited = 0;
8359
8360   for(i=0;i<indent;i++)   // Indentation
8361         fputs("+   ", of);
8362   fputs("+- ", of);
8363
8364   if(pc->type == PC_FUNCTION) {
8365     usedstack += PCF(pc)->stackusage;
8366     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8367   } else return;  // ???
8368
8369
8370   pc = setFirstItem(pb->function_calls);
8371   for( ; pc; pc = setNextItem(pb->function_calls)) {
8372
8373     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8374       char *dest = pic16_get_op_from_instruction(PCI(pc));
8375
8376       pcn = findFunction(dest);
8377       if(pcn)
8378         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8379     } else
8380       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8381
8382   }
8383
8384
8385 }
8386
8387
8388 /*-----------------------------------------------------------------*/
8389 /* pic16_printCallTree - writes the call tree to a file                  */
8390 /*                                                                 */
8391 /*-----------------------------------------------------------------*/
8392
8393 void pic16_printCallTree(FILE *of)
8394 {
8395   pBranch *pbr;
8396   pBlock  *pb;
8397   pCode   *pc;
8398
8399   if(!the_pFile)
8400     return;
8401
8402   if(!of)
8403     of = stderr;
8404
8405   fprintf(of, "\npBlock statistics\n");
8406   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8407     pBlockStats(of,pb);
8408
8409
8410   fprintf(of,"Call Tree\n");
8411   pbr = the_pFile->functions;
8412   while(pbr) {
8413     if(pbr->pc) {
8414       pc = pbr->pc;
8415       if(!ispCodeFunction(pc))
8416         fprintf(of,"bug in call tree");
8417
8418
8419       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8420
8421       while(pc->next && !ispCodeFunction(pc->next)) {
8422         pc = pc->next;
8423         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8424           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8425       }
8426     }
8427
8428     pbr = pbr->next;
8429   }
8430
8431
8432   fprintf(of,"\n**************\n\na better call tree\n");
8433   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8434 //    if(pb->visited)
8435       pct2(of,pb,0,0);
8436   }
8437
8438   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8439     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8440   }
8441 }
8442
8443
8444
8445 /*-----------------------------------------------------------------*/
8446 /*                                                                 */
8447 /*-----------------------------------------------------------------*/
8448
8449 static void InlineFunction(pBlock *pb)
8450 {
8451   pCode *pc;
8452   pCode *pc_call;
8453
8454   if(!pb)
8455     return;
8456
8457   pc = setFirstItem(pb->function_calls);
8458
8459   for( ; pc; pc = setNextItem(pb->function_calls)) {
8460
8461     if(isCALL(pc)) {
8462       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8463       pCode *pct;
8464       pCode *pce;
8465
8466       pBranch *pbr;
8467
8468       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8469
8470         //fprintf(stderr,"Cool can inline:\n");
8471         //pcn->print(stderr,pcn);
8472
8473         //fprintf(stderr,"recursive call Inline\n");
8474         InlineFunction(pcn->pb);
8475         //fprintf(stderr,"return from recursive call Inline\n");
8476
8477         /*
8478           At this point, *pc points to a CALL mnemonic, and
8479           *pcn points to the function that is being called.
8480
8481           To in-line this call, we need to remove the CALL
8482           and RETURN(s), and link the function pCode in with
8483           the CALLee pCode.
8484
8485         */
8486
8487
8488         /* Remove the CALL */
8489         pc_call = pc;
8490         pc = pc->prev;
8491
8492         /* remove callee pBlock from the pBlock linked list */
8493         removepBlock(pcn->pb);
8494
8495         pce = pcn;
8496         while(pce) {
8497           pce->pb = pb;
8498           pce = pce->next;
8499         }
8500
8501         /* Remove the Function pCode */
8502         pct = pic16_findNextInstruction(pcn->next);
8503
8504         /* Link the function with the callee */
8505         pc->next = pcn->next;
8506         pcn->next->prev = pc;
8507
8508         /* Convert the function name into a label */
8509
8510         pbr = Safe_calloc(1,sizeof(pBranch));
8511         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8512         pbr->next = NULL;
8513         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8514         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8515
8516         /* turn all of the return's except the last into goto's */
8517         /* check case for 2 instruction pBlocks */
8518         pce = pic16_findNextInstruction(pcn->next);
8519         while(pce) {
8520           pCode *pce_next = pic16_findNextInstruction(pce->next);
8521
8522           if(pce_next == NULL) {
8523             /* found the last return */
8524             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8525
8526             //fprintf(stderr,"found last return\n");
8527             //pce->print(stderr,pce);
8528             pce->prev->next = pc_call->next;
8529             pc_call->next->prev = pce->prev;
8530             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8531                                                       PCI(pce)->label);
8532           }
8533
8534           pce = pce_next;
8535         }
8536
8537
8538       }
8539     } else
8540       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8541
8542   }
8543
8544 }
8545
8546 /*-----------------------------------------------------------------*/
8547 /*                                                                 */
8548 /*-----------------------------------------------------------------*/
8549
8550 void pic16_InlinepCode(void)
8551 {
8552
8553   pBlock  *pb;
8554   pCode   *pc;
8555
8556   if(!the_pFile)
8557     return;
8558
8559   if(!functionInlining)
8560     return;
8561
8562   /* Loop through all of the function definitions and count the
8563    * number of times each one is called */
8564   //fprintf(stderr,"inlining %d\n",__LINE__);
8565
8566   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8567
8568     pc = setFirstItem(pb->function_calls);
8569
8570     for( ; pc; pc = setNextItem(pb->function_calls)) {
8571
8572       if(isCALL(pc)) {
8573         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8574         if(pcn && isPCF(pcn)) {
8575           PCF(pcn)->ncalled++;
8576         }
8577       } else
8578         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8579
8580     }
8581   }
8582
8583   //fprintf(stderr,"inlining %d\n",__LINE__);
8584
8585   /* Now, Loop through the function definitions again, but this
8586    * time inline those functions that have only been called once. */
8587
8588   InlineFunction(the_pFile->pbHead);
8589   //fprintf(stderr,"inlining %d\n",__LINE__);
8590
8591   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8592     unBuildFlow(pb);
8593
8594 }
8595
8596 char *pic_optype_names[]={
8597         "PO_NONE",         // No operand e.g. NOP
8598         "PO_W",              // The working register (as a destination)
8599         "PO_WREG",           // The working register (as a file register)
8600         "PO_STATUS",         // The 'STATUS' register
8601         "PO_BSR",            // The 'BSR' register
8602         "PO_FSR0",           // The "file select register" (in PIC18 family it's one
8603                              // of three)
8604         "PO_INDF0",          // The Indirect register
8605         "PO_INTCON",         // Interrupt Control register
8606         "PO_GPR_REGISTER",   // A general purpose register
8607         "PO_GPR_BIT",        // A bit of a general purpose register
8608         "PO_GPR_TEMP",       // A general purpose temporary register
8609         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8610         "PO_PCL",            // Program counter Low register
8611         "PO_PCLATH",         // Program counter Latch high register
8612         "PO_PCLATU",         // Program counter Latch upper register
8613         "PO_PRODL",          // Product Register Low
8614         "PO_PRODH",          // Product Register High
8615         "PO_LITERAL",        // A constant
8616         "PO_REL_ADDR",       // A relative address
8617         "PO_IMMEDIATE",      //  (8051 legacy)
8618         "PO_DIR",            // Direct memory (8051 legacy)
8619         "PO_CRY",            // bit memory (8051 legacy)
8620         "PO_BIT",            // bit operand.
8621         "PO_STR",            //  (8051 legacy)
8622         "PO_LABEL",
8623         "PO_WILD",           // Wild card operand in peep optimizer
8624         "PO_TWO_OPS"         // combine two operands
8625 };
8626
8627
8628 char *dumpPicOptype(PIC_OPTYPE type)
8629 {
8630         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8631         return (pic_optype_names[ type ]);
8632 }
8633
8634
8635 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8636 #include "graph.h"
8637
8638 #define MAX_COMMON_BANK_SIZE    32
8639 #define FIRST_PSEUDO_BANK_NR  1000
8640
8641 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8642 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8643 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8644 Graph *adj = NULL;
8645
8646 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8647
8648 typedef struct {
8649   pseudoBankNr bank;  // number assigned to this pseudoBank
8650   unsigned int size;  // number of operands assigned to this bank
8651   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8652 } pseudoBank;
8653
8654 /*----------------------------------------------------------------------*/
8655 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8656 /*----------------------------------------------------------------------*/
8657 unsigned int hashSymbol (const char *str)
8658 {
8659   unsigned int res = 0;
8660   if (!str) return 0;
8661
8662   while (*str) {
8663     res ^= (*str);
8664     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8665     str++;
8666   } // while
8667
8668   return res;
8669 }
8670
8671 /*-----------------------------------------------------------------------*/
8672 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8673 /*-----------------------------------------------------------------------*/
8674 int compareSymbol (const void *sym1, const void *sym2)
8675 {
8676   char *s1 = (char*) sym1;
8677   char *s2 = (char*) sym2;
8678
8679   return (strcmp (s1,s2) == 0);
8680 }
8681
8682 /*-----------------------------------------------------------------------*/
8683 /* comparePre - return 1 iff p1 == p2                                    */
8684 /*-----------------------------------------------------------------------*/
8685 int comparePtr (const void *p1, const void *p2)
8686 {
8687   return (p1 == p2);
8688 }
8689
8690 /*----------------------------------------------------------*/
8691 /* getSymbolFromOperand - return a pointer to the symbol in */
8692 /*                        the given operand and its length  */
8693 /*----------------------------------------------------------*/
8694 char *getSymbolFromOperand (char *op, int *len)
8695 {
8696   char *sym, *curr;
8697   *len = 0;
8698
8699   if (!op) return NULL;
8700
8701   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8702   sym = op;
8703   if (*sym == '(') sym++;
8704
8705   curr = sym;
8706   while (((*curr >= 'A') && (*curr <= 'Z'))
8707          || ((*curr >= 'a') && (*curr <= 'z'))
8708          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8709          || (*curr == '_')) {
8710     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8711     curr++;
8712     (*len)++;
8713   } // while
8714
8715   return sym;
8716 }
8717
8718 /*--------------------------------------------------------------------------*/
8719 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8720 /*--------------------------------------------------------------------------*/
8721 char *getSymFromBank (pseudoBankNr bank)
8722 {
8723   assert (bank2sym);
8724
8725   if (bank < 0) return "<INVALID BANK NR>";
8726   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8727 }
8728
8729 /*-----------------------------------------------------------------------*/
8730 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8731 /*                           bank number (uses hTab sym2bank), if the    */
8732 /*                           symbol is not yet assigned a pseudo bank it */
8733 /*                           is assigned one here                        */
8734 /*-----------------------------------------------------------------------*/
8735 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8736 {
8737   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8738   pseudoBankNr bank;
8739   unsigned int hash;
8740
8741   assert (sym2bank);
8742
8743   hash = hashSymbol (op) % sym2bank->size;
8744   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8745   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8746
8747   if (bank == UNKNOWN_BANK) {
8748     // create a pseudo bank for the operand
8749     bank = next_bank++;
8750     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8751     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8752     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8753     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8754   } else {
8755     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8756   } // if
8757
8758   assert (bank >= 0);
8759
8760   return bank;
8761 }
8762
8763 /*--------------------------------------------------------------------*/
8764 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8765 /*--------------------------------------------------------------------*/
8766 int isBanksel (pCode *pc)
8767 {
8768   if (!pc) return 0;
8769
8770   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8771     // BANKSEL <variablename>  or  MOVLB <banknr>
8772     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8773     return 1;
8774   }
8775
8776   // check for inline assembler BANKSELs
8777   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8778                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8779     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8780     return 1;
8781   }
8782
8783   // assume pc is no BANKSEL instruction
8784   return 0;
8785 }
8786
8787 /*---------------------------------------------------------------------------------*/
8788 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8789 /*                  This method can not guarantee to find all modifications of the */
8790 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8791 /*                  generated plus some cases.                                     */
8792 /*---------------------------------------------------------------------------------*/
8793 int invalidatesBSR(pCode *pc)
8794 {
8795   // assembler directives invalidate BSR (well, they might, we don't know)
8796   if (isPCAD(pc)) return 1;
8797
8798   // only ASMDIRs and pCodeInstructions can invalidate BSR
8799   if (!isPCI(pc)) return 0;
8800
8801   // we have a pCodeInstruction
8802
8803   // check for BSR modifying instructions
8804   switch (PCI(pc)->op) {
8805   case POC_CALL:
8806   case POC_RCALL:
8807   case POC_MOVLB:
8808   case POC_RETFIE:  // might be used as CALL replacement
8809   case POC_RETLW:   // might be used as CALL replacement
8810   case POC_RETURN:  // might be used as CALL replacement
8811   case POC_BANKSEL:
8812     return 1;
8813     break;
8814
8815   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8816     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8817     break;
8818   } // switch
8819
8820   // no change of BSR possible/probable
8821   return 0;
8822 }
8823
8824 /*------------------------------------------------------------*/
8825 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8826 /*                      the symbol referenced in this BANKSEL */
8827 /*------------------------------------------------------------*/
8828 pseudoBankNr getBankFromBanksel (pCode *pc)
8829 {
8830   char *sym;
8831   int data = 0;
8832
8833   if (!pc) return INVALID_BANK;
8834
8835   if (isPCAD(pc) && PCAD(pc)->directive) {
8836     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8837       // get symbolname from PCAD(pc)->arg
8838       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8839       sym = PCAD(pc)->arg;
8840       data = getPseudoBankNrFromOperand (sym);
8841       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8842     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8843       // get (literal) bank number from PCAD(pc)->arg
8844       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8845       assert (0 && "not yet implemented - turn off banksel optimization for now");
8846     }
8847   } else if (isPCI(pc)) {
8848     if (PCI(pc)->op == POC_BANKSEL) {
8849       // get symbolname from PCI(pc)->pcop->name (?)
8850       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8851       sym = PCI(pc)->pcop->name;
8852       data = getPseudoBankNrFromOperand (sym);
8853       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8854     } else if (PCI(pc)->op == POC_MOVLB) {
8855       // get (literal) bank number from PCI(pc)->pcop->name
8856       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8857       assert (0 && "not yet implemented - turn off banksel optimization for now");
8858     }
8859   }
8860
8861   if (data == 0)
8862     // no assigned bank could be found
8863     return UNKNOWN_BANK;
8864   else
8865     return data;
8866 }
8867
8868 /*------------------------------------------------------------------------------*/
8869 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8870 /*------------------------------------------------------------------------------*/
8871 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8872 {
8873   pseudoBank *data;
8874
8875   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8876
8877   do {
8878     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8879     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8880     if (data) {
8881       if (data->bank != bank)
8882         bank = data->bank;
8883       else
8884         data = NULL;
8885     }
8886   } while (data);
8887
8888   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8889   return bank;
8890 }
8891
8892 /*------------------------------------------------------------------*/
8893 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8894 /*                        bank is selected at a given pCode         */
8895 /*------------------------------------------------------------------*/
8896
8897 /* Create a graph with pseudo banks as its nodes and switches between
8898  * these as edges (with the edge weight representing the absolute
8899  * number of BANKSELs from one to the other).
8900  * Removes redundand BANKSELs instead iff mod == 1.
8901  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8902  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8903  * pseudo BSR.
8904  * TODO: check ALL instructions operands if they modify BSR directly...
8905  *
8906  * pb - the pBlock to annotate
8907  * mod  - select either graph creation (0) or BANKSEL removal (1)
8908  */
8909 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8910 {
8911   pCode *pc, *pc_next;
8912   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8913   int isBankselect = 0;
8914   unsigned int banksels=0;
8915
8916   if (!pb) return 0;
8917
8918   pc = pic16_findNextInstruction(pb->pcHead);
8919   while (pc) {
8920     isBankselect = isBanksel (pc);
8921     pc_next = pic16_findNextInstruction (pc->next);
8922
8923     if (!hasNoLabel (pc)) {
8924       // we don't know our predecessors -- assume different BSRs
8925       prevBSR = UNKNOWN_BANK;
8926       pseudoBSR = UNKNOWN_BANK;
8927       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8928     } // if
8929
8930     // check if this is a BANKSEL instruction
8931     if (isBankselect) {
8932       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8933       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8934       if (mod) {
8935         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8936           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8937           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8938           pic16_unlinkpCode (pc);
8939           banksels++;
8940         }
8941       } else {
8942         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8943         banksels++;
8944       }
8945     } // if
8946
8947     if (!isBankselect && invalidatesBSR(pc)) {
8948       // check if this instruction invalidates the pseudoBSR
8949       pseudoBSR = UNKNOWN_BANK;
8950       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8951     } // if
8952
8953     prevBSR = pseudoBSR;
8954     pc = pc_next;
8955   } // while
8956
8957   return banksels;
8958 }
8959
8960 /*------------------------------------------------------------------------------------*/
8961 /* assignToSameBank - returns 0 on success or an error code                           */
8962 /*  1 - common bank would be too large                                                */
8963 /*  2 - assignment to fixed (absolute) bank not performed                             */
8964 /*                                                                                    */
8965 /* This functions assumes that unsplittable operands are already assigned to the same */
8966 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
8967 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
8968 /* TODO: Symbols with an abslute address must be handled specially!                   */
8969 /*------------------------------------------------------------------------------------*/
8970 int assignToSameBank (int bank0, int bank1, int doAbs)
8971 {
8972   int eff0, eff1, dummy;
8973   pseudoBank *pbank0, *pbank1;
8974   hashtItem *hitem;
8975
8976   eff0 = getEffectiveBank (bank0);
8977   eff1 = getEffectiveBank (bank1);
8978
8979   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
8980
8981   // nothing to do if already same bank
8982   if (eff0 == eff1) return 0;
8983
8984   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
8985     return 2;
8986
8987   // ensure eff0 < eff1
8988   if (eff0 > eff1) {
8989     // swap eff0 and eff1
8990     dummy = eff0;
8991     eff0 = eff1;
8992     eff1 = dummy;
8993     dummy = bank0;
8994     bank0 = bank1;
8995     bank1 = dummy;
8996   } // if
8997
8998   // now assign bank eff1 to bank eff0
8999   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9000   if (!pbank0) {
9001     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9002     pbank0->bank = eff0;
9003     pbank0->size = 1;
9004     pbank0->ref = 1;
9005     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9006   } // if
9007
9008   pbank1 = NULL;
9009   hitem = hTabSearch (coerce, eff1 % coerce->size);
9010   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9011     hitem = hitem->next;
9012
9013   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9014
9015 #if 0
9016   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9017            pbank0->bank, pbank0->size,
9018            getSymFromBank (eff0), getSymFromBank (eff1));
9019 #endif
9020
9021   if (pbank1) {
9022     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9023 #if 0
9024       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9025                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9026                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9027                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9028 #endif
9029       return 1;
9030     } // if
9031     pbank0->size += pbank1->size;
9032     pbank1->ref--;
9033     if (pbank1->ref == 0) Safe_free (pbank1);
9034   } else {
9035     pbank0->size++;
9036   } // if
9037
9038   if (hitem)
9039     hitem->item = pbank0;
9040   else
9041     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9042   pbank0->ref++;
9043
9044   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9045
9046   return 0;
9047 }
9048
9049 /*----------------------------------------------------------------*/
9050 /* mergeGraphNodes - combines two nodes into one and modifies all */
9051 /*                   edges to and from the nodes accordingly      */
9052 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9053 /* then also (B,A) must be an edge (possibly with weight 0).      */
9054 /*----------------------------------------------------------------*/
9055 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9056 {
9057   GraphEdge *edge, *backedge, *nextedge;
9058   GraphNode *node;
9059   int backweight;
9060
9061   assert (node1 && node2);
9062   assert (node1 != node2);
9063
9064   // add all edges starting at node2 to node1
9065   edge = node2->edge;
9066   while (edge) {
9067     nextedge = edge->next;
9068     node = edge->node;
9069     backedge = getGEdge (node, node2);
9070     if (backedge)
9071       backweight = backedge->weight;
9072     else
9073       backweight = 0;
9074     // insert edges (node1,node) and (node,node1)
9075     addGEdge2 (node1, node, edge->weight, backweight);
9076     // remove edges (node, node2) and (node2, node)
9077     remGEdge (node2, node);
9078     remGEdge (node, node2);
9079     edge = nextedge;
9080   } // while
9081
9082   // now node2 should not be referenced by any other GraphNode...
9083   //remGNode (adj, node2->data, node2->hash);
9084 }
9085
9086 /*----------------------------------------------------------------*/
9087 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9088 /*----------------------------------------------------------------*/
9089 void showGraph (Graph *g)
9090 {
9091   GraphNode *node;
9092   GraphEdge *edge;
9093   pseudoBankNr bankNr;
9094   pseudoBank *pbank;
9095   unsigned int size;
9096
9097   node = g->node;
9098   while (node) {
9099     edge = node->edge;
9100     bankNr = getEffectiveBank (node->hash);
9101     assert (bankNr >= 0);
9102     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9103     if (pbank) {
9104       bankNr = pbank->bank;
9105       size = pbank->size;
9106     } else {
9107       size = 1;
9108     }
9109
9110     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9111
9112     while (edge) {
9113       if (edge->weight > 0)
9114         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9115       edge = edge->next;
9116     } // while (edge)
9117     node = node->next;
9118   } // while (node)
9119 }
9120
9121 /*---------------------------------------------------------------*/
9122 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9123 /*---------------------------------------------------------------*/
9124 void pic16_OptimizeBanksel ()
9125 {
9126   GraphNode *node, *node1, *node1next;
9127
9128 #if 0
9129   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9130   GraphEdge *edge, *backedge;
9131   GraphEdge *max;
9132   int maxWeight, weight, mergeMore, absMaxWeight;
9133   pseudoBankNr curr0, curr1;
9134 #endif
9135   pseudoBank *pbank;
9136   pseudoBankNr bankNr;
9137   char *base_symbol0, *base_symbol1;
9138   int len0, len1;
9139   pBlock *pb;
9140   set *set;
9141   regs *reg;
9142   unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9143
9144   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9145
9146   if (!the_pFile || !the_pFile->pbHead) return;
9147
9148   adj = newGraph (NULL);
9149   sym2bank = newHashTable ( 255 );
9150   bank2sym = newHashTable ( 255 );
9151   coerce = newHashTable ( 255 );
9152
9153   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9154   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9155     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9156   } // for pb
9157
9158 #if 1
9159   // assign symbols with absolute addresses to their respective bank nrs
9160   set = pic16_fix_udata;
9161   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9162     bankNr = reg->address >> 8;
9163     node = getOrAddGNode (adj, NULL, bankNr);
9164     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9165     assignToSameBank (node->hash, bankNr, 1);
9166
9167     assert (bankNr >= 0);
9168     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9169     if (!pbank) {
9170       pbank = Safe_calloc (1, sizeof (pseudoBank));
9171       pbank->bank = reg->address >> 8; //FIXED_BANK;
9172       pbank->size = 1;
9173       pbank->ref = 1;
9174       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9175     } else {
9176       assert (pbank->bank == (reg->address >> 8));
9177       pbank->bank = reg->address >> 8; //FIXED_BANK;
9178     }
9179     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9180   } // for reg
9181 #endif
9182
9183 #if 1
9184   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9185   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9186   node = adj->node;
9187   while (node) {
9188     if (node->hash < 0) { node = node->next; continue; }
9189     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9190     node1 = node->next;
9191     while (node1) {
9192       if (node1->hash < 0) { node1 = node1->next; continue; }
9193       node1next = node1->next;
9194       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9195       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9196         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9197         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9198         if (assignToSameBank (node->hash, node1->hash, 0)) {
9199           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9200           assert (0 && "Could not assign a symbol to a bank!");
9201         }
9202         mergeGraphNodes (node, node1);
9203         /*
9204         if (node->hash < node1->hash)
9205           mergeGraphNodes (node, node1);
9206         else
9207           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9208         */
9209       } // if
9210       node1 = node1next;
9211     } // while (node1)
9212     node = node->next;
9213   } // while (node)
9214 #endif
9215
9216 #if 0
9217   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9218   // assign tightly coupled operands to the same (pseudo) bank
9219   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9220   mergeMore = 1;
9221   absMaxWeight = 0;
9222   while (mergeMore) {
9223     node = adj->node;
9224     max = NULL;
9225     maxWeight = 0;
9226     while (node) {
9227       curr0 = getEffectiveBank (node->hash);
9228       if (curr0 < 0) { node = node->next; continue; }
9229       edge = node->edge;
9230       while (edge) {
9231         assert (edge->src == node);
9232         backedge = getGEdge (edge->node, edge->src);
9233         weight = edge->weight + (backedge ? backedge->weight : 0);
9234         curr1 = getEffectiveBank (edge->node->hash);
9235         if (curr1 < 0) { edge = edge->next; continue; }
9236
9237         // merging is only useful if the items are not assigned to the same bank already...
9238         if (curr0 != curr1 && weight > maxWeight) {
9239           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9240           maxWeight = weight;
9241           max = edge;
9242         } // if
9243         edge = edge->next;
9244       } // while
9245       node = node->next;
9246     } // while
9247
9248     if (maxWeight > 0) {
9249 #if 0
9250       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9251                max->src->hash, getSymFromBank (max->src->hash),
9252                max->node->hash, getSymFromBank (max->node->hash));
9253 #endif
9254
9255       node = getGNode (adj, max->src->data, max->src->hash);
9256       node1 = getGNode (adj, max->node->data, max->node->hash);
9257
9258       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9259         if (max->src->hash < max->node->hash)
9260           mergeGraphNodes (node, node1);
9261         else
9262           mergeGraphNodes (node1, node);
9263       } else {
9264         remGEdge (node, node1);
9265         remGEdge (node1, node);
9266         //mergeMore = 0;
9267       }
9268
9269     } else {
9270       mergeMore = 0;
9271     }
9272   } // while
9273 #endif
9274
9275 #if 1
9276   // remove redundant BANKSELs
9277   //fprintf (stderr, "removing redundant BANKSELs\n");
9278   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9279     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9280   } // for pb
9281 #endif
9282
9283 #if 0
9284   fprintf (stderr, "display graph\n");
9285   showGraph ();
9286 #endif
9287
9288   deleteGraph (adj);
9289   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9290 }
9291
9292 /*** END of stuff belonging to the BANKSEL optimization ***/
9293
9294
9295
9296 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9297
9298 typedef unsigned int symbol_t;
9299 typedef unsigned int valnum_t;
9300 //typedef unsigned int hash_t;
9301
9302 #ifndef INT_TO_PTR
9303 #define INT_TO_PTR(x) (((char *) 0) + (x))
9304 #endif
9305
9306 #ifndef PTR_TO_INT
9307 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9308 #endif
9309
9310 static int pic16_regIsLocal (regs *r);
9311 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9312
9313 /* statistics */
9314 static unsigned int pic16_df_removed_pcodes = 0;
9315 static unsigned int pic16_df_saved_bytes = 0;
9316 static unsigned int df_findall_sameflow = 0;
9317 static unsigned int df_findall_otherflow = 0;
9318 static unsigned int df_findall_in_vals = 0;
9319
9320 static void pic16_df_stats () {
9321   return;
9322   if (pic16_debug_verbose || pic16_pcode_verbose) {
9323     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9324     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9325     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9326   }
9327 }
9328
9329 /* Remove a pCode iff possible:
9330  * - previous pCode is no SKIP
9331  * - pc has no label
9332  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9333 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9334   pCode *pcprev, *pcnext;
9335   char buf[256], *total=NULL;
9336   int len;
9337
9338   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9339
9340   pcprev = pic16_findPrevInstruction (pc->prev);
9341   pcnext = pic16_findNextInstruction (pc->next);
9342
9343   /* move labels to next instruction (if possible) */
9344   if (PCI(pc)->label && !pcnext) return 0;
9345
9346   /* if this is a SKIP with side-effects -- do not remove */
9347   /* XXX: might try to replace this one with the side-effect only version */
9348   if (isPCI_SKIP(pc)
9349         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9350   {
9351     pCode *newpc;
9352     switch (PCI(pc)->op)
9353     {
9354     case POC_INCFSZ:
9355     case POC_INFSNZ:
9356       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9357       pic16_pCodeReplace( pc, newpc );
9358       return 1;
9359       break;
9360     case POC_INCFSZW:
9361       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9362       pic16_pCodeReplace( pc, newpc );
9363       return 1;
9364       break;
9365     case POC_DECFSZ:
9366     case POC_DCFSNZ:
9367       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9368       pic16_pCodeReplace( pc, newpc );
9369       return 1;
9370       break;
9371     case POC_DECFSZW:
9372       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9373       pic16_pCodeReplace( pc, newpc );
9374       return 1;
9375       break;
9376     default:
9377       return 0;
9378     }
9379     return 0;
9380   }
9381
9382   /* if previous instruction is a skip -- do not remove */
9383   if (pcprev && isPCI_SKIP(pcprev)) {
9384     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9385       /* preceeding SKIP could not be removed -- keep this instruction! */
9386       return 0;
9387     }
9388   }
9389
9390   if (PCI(pc)->label) {
9391     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9392     //pc->print (stderr, pc);
9393     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9394     PCI(pc)->label = NULL;
9395   }
9396
9397   /* update statistics */
9398   pic16_df_removed_pcodes++;
9399   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9400
9401   /* remove the pCode */
9402   pic16_pCode2str (buf, 256, pc);
9403   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9404   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9405     len = strlen (buf) + strlen (comment) + 10;
9406     total = (char *) Safe_malloc (len);
9407     SNPRINTF (total, len, "%s: %s", comment, buf);
9408     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9409     Safe_free (total);
9410   }
9411
9412   /* actually unlink it from the pBlock -- also remove from to/from lists */
9413   pic16_pCodeUnlink (pc);
9414
9415   /* remove the pCode -- release registers */
9416   pc->destruct (pc);
9417
9418   /* report success */
9419   return 1;
9420 }
9421
9422
9423 /* ======================================================================== */
9424 /* === SYMBOL HANDLING ==================================================== */
9425 /* ======================================================================== */
9426
9427 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9428 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9429 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9430
9431 /** Calculate a hash for a given string.
9432  * If len == 0 the string is assumed to be NUL terminated. */
9433 static hash_t symbolHash (const char *str, unsigned int len) {
9434   hash_t hash = 0;
9435   if (!len) {
9436     while (*str) {
9437       hash = (hash << 2) ^ *str;
9438       str++;
9439     } // while
9440   } else {
9441     while (len--) {
9442       hash = (hash << 2) ^ *str;
9443       str++;
9444     }
9445   }
9446   return hash;
9447 }
9448
9449 /** Return 1 iff strings v1 and v2 are identical. */
9450 static int symcmp (const void *v1, const void *v2) {
9451   return !strcmp ((const char *) v1, (const char *) v2);
9452 }
9453
9454 /** Return 1 iff pointers v1 and v2 are identical. */
9455 static int ptrcmp (const void *v1, const void *v2) {
9456   return (v1 == v2);
9457 }
9458
9459 enum {  SPO_WREG=0x1000,
9460         SPO_STATUS,
9461         SPO_PRODL,
9462         SPO_PRODH,
9463         SPO_INDF0,
9464         SPO_POSTDEC0,
9465         SPO_POSTINC0,
9466         SPO_PREINC0,
9467         SPO_PLUSW0,
9468         SPO_INDF1,
9469         SPO_POSTDEC1,
9470         SPO_POSTINC1,
9471         SPO_PREINC1,
9472         SPO_PLUSW1,
9473         SPO_INDF2,
9474         SPO_POSTDEC2,
9475         SPO_POSTINC2,
9476         SPO_PREINC2,
9477         SPO_PLUSW2,
9478         SPO_STKPTR,
9479         SPO_TOSL,
9480         SPO_TOSH,
9481         SPO_TOSU,
9482         SPO_BSR,
9483         SPO_FSR0L,
9484         SPO_FSR0H,
9485         SPO_FSR1L,
9486         SPO_FSR1H,
9487         SPO_FSR2L,
9488         SPO_FSR2H,
9489         SPO_PCL,
9490         SPO_PCLATH,
9491         SPO_PCLATU,
9492         SPO_TABLAT,
9493         SPO_TBLPTRL,
9494         SPO_TBLPTRH,
9495         SPO_TBLPTRU,
9496         SPO_LAST
9497 };
9498
9499 /* Return the unique symbol_t for the given string. */
9500 static symbol_t symFromStr (const char *str) {
9501   hash_t hash;
9502   char *res;
9503   symbol_t sym;
9504
9505   if (!map_symToStr) {
9506     int i;
9507     struct { char *name; symbol_t sym; } predefsyms[] = {
9508         {"WREG", SPO_WREG},
9509         {"STATUS", SPO_STATUS},
9510         {"PRODL", SPO_PRODL},
9511         {"PRODH", SPO_PRODH},
9512         {"INDF0", SPO_INDF0},
9513         {"POSTDEC0", SPO_POSTDEC0},
9514         {"POSTINC0", SPO_POSTINC0},
9515         {"PREINC0", SPO_PREINC0},
9516         {"PLUSW0", SPO_PLUSW0},
9517         {"INDF1", SPO_INDF1},
9518         {"POSTDEC1", SPO_POSTDEC1},
9519         {"POSTINC1", SPO_POSTINC1},
9520         {"PREINC1", SPO_PREINC1},
9521         {"PLUSW1", SPO_PLUSW1},
9522         {"INDF2", SPO_INDF2},
9523         {"POSTDEC2", SPO_POSTDEC2},
9524         {"POSTINC2", SPO_POSTINC2},
9525         {"PREINC2", SPO_PREINC2},
9526         {"PLUSW2", SPO_PLUSW2},
9527         {"STKPTR", SPO_STKPTR},
9528         {"TOSL", SPO_TOSL},
9529         {"TOSH", SPO_TOSH},
9530         {"TOSU", SPO_TOSU},
9531         {"BSR", SPO_BSR},
9532         {"FSR0L", SPO_FSR0L},
9533         {"FSR0H", SPO_FSR0H},
9534         {"FSR1L", SPO_FSR1L},
9535         {"FSR1H", SPO_FSR1H},
9536         {"FSR2L", SPO_FSR2L},
9537         {"FSR2H", SPO_FSR2H},
9538         {"PCL", SPO_PCL},
9539         {"PCLATH", SPO_PCLATH},
9540         {"PCLATU", SPO_PCLATU},
9541         {"TABLAT", SPO_TABLAT},
9542         {"TBLPTRL", SPO_TBLPTRL},
9543         {"TBLPTRH", SPO_TBLPTRH},
9544         {"TBLPTRU", SPO_TBLPTRU},
9545         {NULL, 0}
9546     };
9547
9548     map_strToSym = newHashTable (128);
9549     map_symToStr = newHashTable (128);
9550
9551     for (i=0; predefsyms[i].name; i++) {
9552       char *name;
9553
9554       /* enter new symbol */
9555       sym = predefsyms[i].sym;
9556       name = predefsyms[i].name;
9557       res = Safe_strdup (name);
9558       hash = symbolHash (name, 0);
9559
9560       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9561       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9562     } // for i
9563   }
9564
9565   hash = symbolHash (str, 0) % map_strToSym->size;
9566
9567   /* find symbol in table */
9568   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9569   if (sym) {
9570     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9571     return sym;
9572   }
9573
9574   /* enter new symbol */
9575   sym = nextSymbol++;
9576   res = Safe_strdup (str);
9577
9578   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9579   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9580
9581   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9582
9583   return sym;
9584 }
9585
9586 #if 1
9587 static const char *strFromSym (symbol_t sym) {
9588   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9589 }
9590 #endif
9591
9592 /* ======================================================================== */
9593 /* === DEFINITION MAP HANDLING ============================================ */
9594 /* ======================================================================== */
9595
9596 /* A defmap provides information about which symbol is defined by which pCode.
9597  * The most recent definitions are prepended to the list, so that the most
9598  * recent definition can be found by forward scanning the list.
9599  * pc2: MOVFF r0x00, r0x01
9600  * pc1: INCF r0x01
9601  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9602  *
9603  * We attach one defmap to each flow object, and each pCode will occur at
9604  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9605  * used to find definitions for a pCode in its own defmap that precede pCode.
9606  */
9607
9608 typedef struct defmap_s {
9609   symbol_t sym;                 /** symbol this item refers to */
9610   union {
9611     struct {
9612       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9613       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9614       int isRead:1;             /** sym/mask is read */
9615       int isWrite:1;            /** sym/mask is written */
9616     } access;
9617     int accessmethod;
9618   } acc;
9619   pCode *pc;                    /** pCode this symbol is refrenced at */
9620   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9621   valnum_t val;                 /** new unique number for this value (if isWrite) */
9622   struct defmap_s *prev, *next; /** link to previous an next definition */
9623 } defmap_t;
9624
9625 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9626 static int defmap_free_count = 0;               /** number of released defmap items */
9627
9628 /* Returns a defmap_t with the specified data; this will be the new list head.
9629  * next - pointer to the current list head */
9630 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9631   defmap_t *map;
9632
9633   if (defmap_free) {
9634     map = defmap_free;
9635     defmap_free = map->next;
9636     --defmap_free_count;
9637   } else {
9638     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9639   }
9640   map->sym = sym;
9641   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9642   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9643   map->acc.access.isRead = (isRead != 0);
9644   map->acc.access.isWrite = (isWrite != 0);
9645   map->pc = pc;
9646   map->in_val = 0;
9647   map->val = (isWrite ? val : 0);
9648   map->prev = NULL;
9649   map->next = next;
9650   if (next) next->prev = map;
9651
9652   return map;
9653 }
9654
9655 /* Returns a copy of the single defmap item. */
9656 static defmap_t *copyDefmap (defmap_t *map) {
9657   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9658   memcpy (res, map, sizeof (defmap_t));
9659   res->next = NULL;
9660   res->prev = NULL;
9661   return res;
9662 }
9663
9664 /* Insert a defmap item after the specified one. */
9665 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9666   if (!ref || !newItem) return 1;
9667
9668   newItem->next = ref->next;
9669   newItem->prev = ref;
9670   ref->next = newItem;
9671   if (newItem->next) newItem->next->prev = newItem;
9672
9673   return 0;
9674 }
9675
9676 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9677  * item is copied before insertion into chain and therefore left untouched.
9678  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9679 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9680   defmap_t *dummy;
9681   dummy = *head;
9682   while (dummy && (dummy->sym != item->sym
9683                           || dummy->pc != item->pc
9684                           || dummy->acc.accessmethod != item->acc.accessmethod
9685                           || dummy->val != item->val
9686                           || dummy->in_val != item->in_val)) {
9687     dummy = dummy->next;
9688   } // while
9689
9690   /* item already present? */
9691   if (dummy) return 0;
9692
9693   /* otherwise: insert copy of item */
9694   dummy = copyDefmap (item);
9695   dummy->next = *head;
9696   if (*head) (*head)->prev = dummy;
9697   *head = dummy;
9698
9699   return 1;
9700 }
9701
9702 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9703 static void deleteDefmap (defmap_t *map) {
9704   if (!map) return;
9705
9706   /* unlink from chain -- fails for the first item (head is not updated!) */
9707   if (map->next) map->next->prev = map->prev;
9708   if (map->prev) map->prev->next = map->next;
9709
9710   /* clear map */
9711   memset (map, 0, sizeof (defmap_t));
9712
9713   /* save for future use */
9714   map->next = defmap_free;
9715   defmap_free = map;
9716   ++defmap_free_count;
9717 }
9718
9719 /* Release all defmaps referenced from map. */
9720 static void deleteDefmapChain (defmap_t **_map) {
9721   defmap_t *map, *next;
9722
9723   if (!_map) return;
9724
9725   map = *_map;
9726
9727   /* find list head */
9728   while (map && map->prev) map = map->prev;
9729
9730   /* delete all items */
9731   while (map) {
9732     next = map->next;
9733     deleteDefmap (map);
9734     map = next;
9735   } // while
9736
9737   *_map = NULL;
9738 }
9739
9740 /* Free all defmap items. */
9741 static void freeDefmap (defmap_t **_map) {
9742   defmap_t *next;
9743   defmap_t *map;
9744
9745   if (!_map) return;
9746
9747   map = (*_map);
9748
9749   /* find list head */
9750   while (map->prev) map = map->prev;
9751
9752   /* release all items */
9753   while (map) {
9754     next = map->next;
9755     Safe_free (map);
9756     map = next;
9757   }
9758
9759   (*_map) = NULL;
9760 }
9761
9762 /* Returns the most recent definition for the given symbol preceeding pc.
9763  * If no definition is found, NULL is returned.
9764  * If pc == NULL the whole list is scanned. */
9765 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9766   defmap_t *curr = map;
9767
9768   if (pc) {
9769     /* skip all definitions up to pc */
9770     while (curr && (curr->pc != pc)) curr = curr->next;
9771
9772     /* pc not in the list -- scan the whole list for definitions */
9773     if (!curr) {
9774       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9775       curr = map;
9776     } else {
9777       /* skip all definitions performed by pc */
9778       while (curr && (curr->pc == pc)) curr = curr->next;
9779     }
9780   } // if (pc)
9781
9782   /* find definition for sym */
9783   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9784     curr = curr->next;
9785   }
9786
9787   return curr;
9788 }
9789
9790 #if 0
9791 /* Returns the first use (read) of the given symbol AFTER pc.
9792  * If no such use is found, NULL is returned.
9793  * If pc == NULL the whole list is scanned. */
9794 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9795   defmap_t *curr = map, *prev = NULL;
9796
9797   if (pc) {
9798     /* skip all definitions up to pc */
9799     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9800
9801     /* pc not in the list -- scan the whole list for definitions */
9802     if (!curr) {
9803       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9804       curr = prev;
9805     }
9806   } else {
9807     /* find end of list */
9808     while (curr && curr->next) curr = curr->next;
9809   } // if (pc)
9810
9811   /* find use of sym (scan list backwards) */
9812   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9813
9814   return curr;
9815 }
9816 #endif
9817
9818 /* Return the defmap entry for sym AT pc.
9819  * If none is found, NULL is returned.
9820  * If more than one entry is found an assertion is triggered. */
9821 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9822   defmap_t *res = NULL;
9823
9824   /* find entries for pc */
9825   while (map && map->pc != pc) map = map->next;
9826
9827   /* find first entry for sym @ pc */
9828   while (map && map->pc == pc && map->sym != sym) map = map->next;
9829
9830   /* no entry found */
9831   if (!map) return NULL;
9832
9833   /* check for more entries */
9834   res = map;
9835   map = map->next;
9836   while (map && map->pc == pc) {
9837     /* more than one entry for sym @ pc found? */
9838     assert (map->sym != sym);
9839     map = map->next;
9840   }
9841
9842   /* return single entry for sym @ pc */
9843   return res;
9844 }
9845
9846 /* Modifies the definition of sym at pCode to newval.
9847  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9848  */
9849 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9850   defmap_t *m  = map;
9851
9852   /* find definitions of pc */
9853   while (m && m->pc != pc) m = m->next;
9854
9855   /* find definition of sym at pc */
9856   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9857
9858   /* no definition found */
9859   if (!m) return 1;
9860
9861   /* redefine */
9862   m->val = newval;
9863
9864   /* update following uses of sym */
9865   while (m && m->pc == pc) m = m->prev;
9866   while (m) {
9867     if (m->sym == sym) {
9868       m->in_val = newval;
9869       if (m->acc.access.isWrite) m = NULL;
9870     } // if
9871     if (m) m = m->prev;
9872   } // while
9873
9874   return 0;
9875 }
9876
9877 /* ======================================================================== */
9878 /* === STACK ROUTINES ===================================================== */
9879 /* ======================================================================== */
9880
9881 typedef struct stack_s {
9882   void *data;
9883   struct stack_s *next;
9884 } stackitem_t;
9885
9886 typedef stackitem_t *dynstack_t;
9887 static stackitem_t *free_stackitems = NULL;
9888
9889 /* Create a stack with one item. */
9890 static dynstack_t *newStack () {
9891   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9892   *s = NULL;
9893   return s;
9894 }
9895
9896 /* Remove a stack -- its items are only marked free. */
9897 static void deleteStack (dynstack_t *s) {
9898   stackitem_t *i;
9899
9900   while (*s) {
9901     i = *s;
9902     *s = (*s)->next;
9903     i->next = free_stackitems;
9904     free_stackitems = i;
9905   } // while
9906   Safe_free (s);
9907 }
9908
9909 /* Release all stackitems. */
9910 static void releaseStack () {
9911   stackitem_t *i;
9912
9913   while (free_stackitems) {
9914     i = free_stackitems->next;
9915     Safe_free(free_stackitems);
9916     free_stackitems = i;
9917   } // while
9918 }
9919
9920 static void stackPush (dynstack_t *stack, void *data) {
9921   stackitem_t *i;
9922
9923   if (free_stackitems) {
9924     i = free_stackitems;
9925     free_stackitems = free_stackitems->next;
9926   } else {
9927     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9928   }
9929   i->data = data;
9930   i->next = *stack;
9931   *stack = i;
9932 }
9933
9934 static void *stackPop (dynstack_t *stack) {
9935   void *data;
9936   stackitem_t *i;
9937
9938   if (stack && *stack) {
9939     data = (*stack)->data;
9940     i = *stack;
9941     *stack = (*stack)->next;
9942     i->next = free_stackitems;
9943     free_stackitems = i;
9944     return data;
9945   } else {
9946     return NULL;
9947   }
9948 }
9949
9950 #if 0
9951 static int stackContains (dynstack_t *s, void *data) {
9952   stackitem_t *i;
9953   if (!s) return 0;
9954   i = *s;
9955   while (i) {
9956     if (i->data == data) return 1;
9957     i = i->next;
9958   } // while
9959
9960   /* not found */
9961   return 0;
9962 }
9963 #endif
9964
9965 static int stackIsEmpty (dynstack_t *s) {
9966   return (*s == NULL);
9967 }
9968
9969
9970 typedef struct {
9971   pCodeFlow *flow;
9972   defmap_t *lastdef;
9973 } state_t;
9974
9975 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
9976   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
9977   s->flow = flow;
9978   s->lastdef = lastdef;
9979   return s;
9980 }
9981
9982 static void deleteState (state_t *s) {
9983   Safe_free (s);
9984 }
9985
9986 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
9987   stackitem_t *i;
9988
9989   /* scan working list for state */
9990   if (todo) {
9991     i = *todo;
9992     while (i) {
9993       /* is i == state? -- state not new */
9994       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
9995       i = i->next;
9996     } // while
9997   }
9998
9999   if (done) {
10000     i = *done;
10001     while (i) {
10002       /* is i == state? -- state not new */
10003       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10004       i = i->next;
10005     } // while
10006   }
10007
10008   /* not found -- state is new */
10009   return 1;
10010 }
10011
10012 static inline valnum_t newValnum ();
10013
10014 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10015   pCode *pc;
10016
10017   if (!pb) return "<unknown function>";
10018
10019   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10020   if (pc && isPCF(pc)) return PCF(pc)->fname;
10021   else return "<unknown function>";
10022 }
10023
10024 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10025   defmap_t *map;
10026   pCodeFlow *pcfl;
10027
10028   assert(pb);
10029
10030   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10031
10032   /* find initial value (assigning pc == NULL) */
10033   map = PCFL(pcfl)->in_vals;
10034   while (map && map->sym != sym) map = map->next;
10035
10036   /* initial value already present? */
10037   if (map) {
10038     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10039     return map;
10040   }
10041
10042   /* create a new initial value */
10043   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10044   PCFL(pcfl)->in_vals = map;
10045   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10046   return map;
10047
10048 #if 0
10049   /* insert map as last item in pcfl's defmap */
10050   if (!prev) prev = PCFL(pcfl)->defmap;
10051   if (!prev) {
10052     PCFL(pcfl)->defmap = map;
10053   } else {
10054     while (prev->next) prev = prev->next;
10055     prev->next = map;
10056     map->prev = prev;
10057   }
10058
10059   return map;
10060 #endif
10061 }
10062
10063 /* Find all reaching definitions for sym at pc.
10064  * A new (!) list of definitions is returned.
10065  * Returns the number of reaching definitions found.
10066  * The defining defmap entries are returned in *chain.
10067  */
10068 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10069   defmap_t *map;
10070   defmap_t *res;
10071
10072   pCodeFlow *curr;
10073   pCodeFlowLink *succ;
10074   state_t *state;
10075   dynstack_t *todo;     /** stack of state_t */
10076   dynstack_t *done;     /** stack of state_t */
10077
10078   int firstState, n_defs;
10079
10080   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10081   assert (chain);
10082
10083   /* initialize return list */
10084   *chain = NULL;
10085
10086   /* wildcard symbol? */
10087   if (!sym) return 0;
10088
10089   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10090
10091   map = PCI(pc)->pcflow->defmap;
10092
10093   res = defmapFindDef (map, sym, pc);
10094   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10095
10096 #define USE_PRECALCED_INVALS 1
10097 #if USE_PRECALCED_INVALS
10098   if (!res && PCI(pc)->pcflow->in_vals) {
10099     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10100     if (res) {
10101       //fprintf  (stderr, "found def in init values\n");
10102       df_findall_in_vals++;
10103     }
10104   }
10105 #endif
10106
10107   if (res) {
10108     // found a single definition (in pc's flow)
10109     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10110     defmapAddCopyIfNew (chain, res);
10111     df_findall_sameflow++;
10112     return 1;
10113   }
10114
10115 #if USE_PRECALCED_INVALS
10116   else {
10117     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10118     return 1;
10119   }
10120
10121 #endif
10122
10123 #define FORWARD_FLOW_ANALYSIS 1
10124 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10125   /* no definition found in pc's flow preceeding pc */
10126   todo = newStack ();
10127   done = newStack ();
10128   n_defs = 0; firstState = 1;
10129   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10130
10131   while (!stackIsEmpty (todo)) {
10132     state = (state_t *) stackPop (todo);
10133     stackPush (done, state);
10134     curr = state->flow;
10135     res = state->lastdef;
10136     //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);
10137
10138     /* there are no definitions BEFORE pc in pc's flow (see above) */
10139     if (curr == PCI(pc)->pcflow) {
10140       if (!res) {
10141         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10142         res = pic16_pBlockAddInval (pc->pb, sym);
10143         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10144         res = NULL;
10145       } else {
10146         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10147         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10148       }
10149     }
10150
10151     /* save last definition of sym in this flow as initial def in successors */
10152     res = defmapFindDef (curr->defmap, sym, NULL);
10153     if (!res) res = state->lastdef;
10154
10155     /* add successors to working list */
10156     state = newState (NULL, NULL);
10157     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10158     while (succ) {
10159       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10160       state->flow = succ->pcflow;
10161       state->lastdef = res;
10162       if (stateIsNew (state, todo, done)) {
10163         stackPush (todo, state);
10164         state = newState (NULL, NULL);
10165       } // if
10166       succ = (pCodeFlowLink *) setNextItem (curr->to);
10167     } // while
10168     deleteState (state);
10169   } // while
10170
10171 #else // !FORWARD_FLOW_ANALYSIS
10172
10173   /* no definition found in pc's flow preceeding pc */
10174   todo = newStack ();
10175   done = newStack ();
10176   n_defs = 0; firstState = 1;
10177   stackPush (todo, newState (PCI(pc)->pcflow, res));
10178
10179   while (!stackIsEmpty (todo)) {
10180     state = (state_t *) stackPop (todo);
10181     curr = state->flow;
10182
10183     if (firstState) {
10184       firstState = 0;
10185       /* only check predecessor flows */
10186     } else {
10187       /* get (last) definition of sym in this flow */
10188       res = defmapFindDef (curr->defmap, sym, NULL);
10189     }
10190
10191     if (res) {
10192       /* definition found */
10193       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10194       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10195     } else {
10196       /* no definition found -- check predecessor flows */
10197       state = newState (NULL, NULL);
10198       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10199
10200       /* if no flow predecessor available -- sym might be uninitialized */
10201       if (!succ) {
10202         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10203         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10204         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10205         deleteDefmap (res); res = NULL;
10206       }
10207
10208       while (succ) {
10209         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10210         state->flow = succ->pcflow;
10211         state->lastdef = res;
10212         if (stateIsNew (state, todo, done)) {
10213           stackPush (todo, state);
10214           state = newState (NULL, NULL);
10215         } // if
10216         succ = (pCodeFlowLink *) setNextItem (curr->from);
10217       } // while
10218       deleteState (state);
10219     }
10220   } // while
10221
10222 #endif
10223
10224   /* clean up done stack */
10225   while (!stackIsEmpty(done)) {
10226     deleteState ((state_t *) stackPop (done));
10227   } // while
10228   deleteStack (done);
10229
10230   /* return number of items in result set */
10231   if (n_defs == 0) {
10232     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10233   } else if (n_defs == 1) {
10234     assert (*chain);
10235     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10236   } else if (n_defs > 0) {
10237     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10238 #if 0
10239     res = *chain;
10240     while (res) {
10241       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10242       res = res->next;
10243     } // while
10244 #endif
10245   }
10246   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10247   df_findall_otherflow++;
10248   return n_defs;
10249 }
10250
10251 /* ======================================================================== */
10252 /* === VALUE NUMBER HANDLING ============================================== */
10253 /* ======================================================================== */
10254
10255 static valnum_t nextValnum = 0x1000;
10256 static hTab *map_symToValnum = NULL;
10257
10258 /** Return a new value number. */
10259 static inline valnum_t newValnum () {
10260   return (nextValnum += 4);
10261 }
10262
10263 static valnum_t valnumFromStr (const char *str) {
10264   symbol_t sym;
10265   valnum_t val;
10266   void *res;
10267
10268   sym = symFromStr (str);
10269
10270   if (!map_symToValnum) {
10271     map_symToValnum = newHashTable (128);
10272   } // if
10273
10274   /* literal already known? */
10275   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10276
10277   /* return existing valnum */
10278   if (res) return (valnum_t) PTR_TO_INT(res);
10279
10280   /* create new valnum */
10281   val = newValnum();
10282   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10283   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10284   return val;
10285 }
10286
10287 /* Create a valnum for a literal. */
10288 static valnum_t valnumFromLit (unsigned int lit) {
10289   return ((valnum_t) 0x100 + (lit & 0x0FF));
10290 }
10291
10292 /* Return the (positive) literal value represented by val
10293  * or -1 iff val is no known literal's valnum. */
10294 static int litFromValnum (valnum_t val) {
10295   if (val >= 0x100 && val < 0x200) {
10296     /* valnum is a (known) literal */
10297     return val & 0x00FF;
10298   } else {
10299     /* valnum is not a known literal */
10300     return -1;
10301   }
10302 }
10303
10304 #if 0
10305 /* Sanity check - all flows in a block must be reachable from initial flow. */
10306 static int verifyAllFlowsReachable (pBlock *pb) {
10307   set *reached;
10308   set *flowInBlock;
10309   set *checked;
10310   pCode *pc;
10311   pCodeFlow *pcfl;
10312   pCodeFlowLink *succ;
10313   int res;
10314
10315   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10316
10317   reached = NULL;
10318   flowInBlock = NULL;
10319   checked = NULL;
10320   /* mark initial flow as reached (and "not needs to be reached") */
10321   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10322   assert (pc);
10323   addSetHead (&reached, pc);
10324   addSetHead (&checked, pc);
10325
10326   /* mark all further flows in block as "need to be reached" */
10327   pc = pb->pcHead;
10328   do {
10329     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10330     pc = pic16_findNextInstruction (pc->next);
10331   } while (pc);
10332
10333   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10334     /* mark as reached and "not need to be reached" */
10335     deleteSetItem (&reached, pcfl);
10336     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10337
10338     /* flow is no longer considered unreachable */
10339     deleteSetItem (&flowInBlock, pcfl);
10340
10341     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10342       if (!isinSet (checked, succ->pcflow)) {
10343         /* flow has never been reached before */
10344         addSetHead (&reached, succ->pcflow);
10345         addSetHead (&checked, succ->pcflow);
10346       } // if
10347     } // for succ
10348   } // while
10349
10350   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10351
10352   /* by now every flow should have been reached
10353    * --> flowInBlock should be empty */
10354   res = (flowInBlock == NULL);
10355
10356 #if 1
10357   if (flowInBlock) {
10358           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10359     while (flowInBlock) {
10360       pcfl = indexSet (flowInBlock, 0);
10361       fprintf (stderr, "not reached: flow %p\n", pcfl);
10362       deleteSetItem (&flowInBlock, pcfl);
10363     } // while
10364   }
10365 #endif
10366
10367   /* clean up */
10368   deleteSet (&reached);
10369   deleteSet (&flowInBlock);
10370   deleteSet (&checked);
10371
10372   /* if we reached every flow, succ is NULL by now... */
10373   //assert (res); // will fire on unreachable code...
10374   return (res);
10375 }
10376 #endif
10377
10378 /* Checks a flow for accesses to sym AFTER pc.
10379  *
10380  * Returns -1 if the symbol is read in this flow (before redefinition),
10381  * returns 0 if the symbol is redefined in this flow or
10382  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10383  */
10384 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10385   defmap_t *map, *mappc;
10386
10387   /* find pc or start of definitions */
10388   map = pcfl->defmap;
10389   while (map && (map->pc != pc) && map->next) map = map->next;
10390   /* if we found pc -- ignore it */
10391   while (map && map->pc == pc) map = map->prev;
10392
10393   /* scan list backwards (first definition first) */
10394   while (map && mask) {
10395 //    if (map->sym == sym) {
10396       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10397       mappc = map;
10398       /* scan list for reads at this pc first */
10399       while (map && map->pc == mappc->pc) {
10400         /* is the symbol (partially) read? */
10401         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10402           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10403           return -1;
10404         }
10405         map = map->prev;
10406       } // while
10407       map = mappc;
10408
10409       while (map && map->pc == mappc->pc) {
10410         /* honor (partial) redefinitions of sym */
10411         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10412           mask &= ~map->acc.access.mask;
10413           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10414         }
10415         map = map->prev;
10416       } // while
10417 //    } // if
10418     /* map already points to the first defmap for the next pCode */
10419     //map = mappc->prev;
10420   } // while
10421
10422   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10423    * is still alive; return the appropriate mask of alive bits */
10424   return mask;
10425 }
10426
10427 /* Check whether a symbol is alive (AFTER pc). */
10428 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10429   int mask, visit;
10430   defmap_t *map;
10431   dynstack_t *todo, *done;
10432   state_t *state;
10433   pCodeFlow *pcfl;
10434   pCodeFlowLink *succ;
10435
10436   mask = 0x00ff;
10437
10438   assert (isPCI(pc));
10439   pcfl = PCI(pc)->pcflow;
10440   map = pcfl->defmap;
10441
10442   todo = newStack ();
10443   done = newStack ();
10444
10445   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10446   stackPush (todo, state);
10447   visit = 0;
10448
10449   while (!stackIsEmpty (todo)) {
10450     state = (state_t *) stackPop (todo);
10451     pcfl = state->flow;
10452     mask = PTR_TO_INT(state->lastdef);
10453     if (visit) stackPush (done, state); else deleteState(state);
10454     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10455     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10456     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10457     visit++;
10458
10459     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10460     if (mask == 0) continue;
10461
10462     /* symbol is (partially) read before redefinition in flow */
10463     if (mask == -1) break;
10464
10465     /* symbol is neither read nor completely redefined -- check successor flows */
10466     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10467       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10468       if (stateIsNew (state, todo, done)) {
10469         stackPush (todo, state);
10470       } else {
10471         deleteState (state);
10472       }
10473     } // for
10474   } // while
10475
10476   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10477   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10478
10479   /* symbol is read in at least one flow -- is alive */
10480   if (mask == -1) return 1;
10481
10482   /* symbol is read in no flow */
10483   return 0;
10484 }
10485
10486 /* Returns whether access to the given symbol has side effects. */
10487 static int pic16_symIsSpecial (symbol_t sym) {
10488   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10489   switch (sym) {
10490   case SPO_INDF0:
10491   case SPO_PLUSW0:
10492   case SPO_POSTINC0:
10493   case SPO_POSTDEC0:
10494   case SPO_PREINC0:
10495   case SPO_INDF1:
10496   case SPO_PLUSW1:
10497   case SPO_POSTINC1:
10498   case SPO_POSTDEC1:
10499   case SPO_PREINC1:
10500   case SPO_INDF2:
10501   case SPO_PLUSW2:
10502   case SPO_POSTINC2:
10503   case SPO_POSTDEC2:
10504   case SPO_PREINC2:
10505   case SPO_PCL:
10506           return 1;
10507   default:
10508           /* no special effects known */
10509           return 0;
10510   } // switch
10511
10512   return 0;
10513 }
10514
10515 /* Check whether a register should be considered local (to the current function) or not. */
10516 static int pic16_regIsLocal (regs *r) {
10517   symbol_t sym;
10518   if (r) {
10519     if (r->type == REG_TMP) return 1;
10520
10521     sym = symFromStr (r->name);
10522     switch (sym) {
10523     case SPO_WREG:
10524     case SPO_FSR0L: // used in ptrget/ptrput
10525     case SPO_FSR0H: // ... as well
10526     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10527     case SPO_FSR1H: // ... as well
10528     case SPO_FSR2L: // used as frame pointer
10529     case SPO_FSR2H: // ... as well
10530     case SPO_PRODL: // used to return values from functions
10531     case SPO_PRODH: // ... as well
10532       /* these registers (and some more...) are considered local */
10533       return 1;
10534       break;
10535     default:
10536       /* for unknown regs: check is marked local, leave if not */
10537       if (r->isLocal) {
10538         return 1;
10539       } else {
10540         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10541         return 0;
10542       }
10543     } // switch
10544   } // if
10545
10546   /* if in doubt, assume non-local... */
10547   return 0;
10548 }
10549
10550 /* Check all symbols touched by pc whether their newly assigned values are read.
10551  * Returns 0 if no symbol is used later on, 1 otherwise. */
10552 static int pic16_pCodeIsAlive (pCode *pc) {
10553   pCodeInstruction *pci;
10554   defmap_t *map, *lastpc;
10555   regs *checkreg;
10556
10557   /* we can only handle PCIs */
10558   if (!isPCI(pc)) return 1;
10559
10560   //pc->print (stderr, pc);
10561
10562   pci = PCI(pc);
10563   assert (pci && pci->pcflow && pci->pcflow->defmap);
10564
10565   /* NEVER remove instructions with implicit side effects */
10566   switch (pci->op) {
10567   case POC_TBLRD:
10568   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10569   case POC_TBLRD_POSTDEC:
10570   case POC_TBLRD_PREINC:
10571   case POC_TBLWT:               /* modify program memory */
10572   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10573   case POC_TBLWT_POSTDEC:
10574   case POC_TBLWT_PREINC:
10575   case POC_CLRWDT:              /* clear watchdog timer */
10576   case POC_PUSH:                /* should be safe to remove though... */
10577   case POC_POP:                 /* should be safe to remove though... */
10578   case POC_CALL:
10579   case POC_RCALL:
10580   case POC_RETFIE:
10581   case POC_RETURN:
10582     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10583     return 1;
10584
10585   default:
10586     /* no special instruction */
10587     break;
10588   } // switch
10589
10590   /* prevent us from removing assignments to non-local variables */
10591   checkreg = NULL;
10592   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10593   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10594
10595   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10596     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10597     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10598     //pc->print (stderr, pc);
10599     return 1;
10600   }
10601   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10602     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10603     return 1;
10604   }
10605
10606 #if 1
10607   /* OVERKILL: prevent us from removing reads from non-local variables
10608    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10609    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10610   checkreg = NULL;
10611   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10612   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10613
10614   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10615     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10616     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10617     //pc->print (stderr, pc);
10618     return 1;
10619   }
10620   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10621     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10622     return 1;
10623   }
10624 #endif
10625
10626   /* now check that the defined symbols are not used */
10627   map = pci->pcflow->defmap;
10628
10629   /* find items for pc */
10630   while (map && map->pc != pc) map = map->next;
10631
10632   /* no entries found? something is fishy with DF analysis... -- play safe */
10633   if (!map) {
10634     if (pic16_pcode_verbose) {
10635       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10636     }
10637     return 1;
10638   }
10639
10640   /* remember first item assigned to pc for later use */
10641   lastpc = map;
10642
10643   /* check all symbols being modified by pc */
10644   while (map && map->pc == pc) {
10645     if (map->sym == 0) { map = map->next; continue; }
10646
10647     /* keep pc if it references special symbols (like POSTDEC0) */
10648 #if 0
10649     {
10650       char buf[256];
10651       pic16_pCode2str (buf, 256, pc);
10652       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10653     }
10654 #endif
10655     if (pic16_symIsSpecial (map->sym)) {
10656       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10657       return 1;
10658     }
10659     if (map->acc.access.isWrite) {
10660       if (pic16_isAlive (map->sym, pc)) {
10661         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10662         return 1;
10663       }
10664     }
10665     map = map->next;
10666   } // while
10667
10668   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10669 #if 0
10670   {
10671     char buf[256];
10672     pic16_pCode2str (buf, 256, pc);
10673     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10674   }
10675 #endif
10676   return 0;
10677 }
10678
10679 /* Adds implied operands to the list.
10680  * sym - operand being accessed in the pCode
10681  * list - list to append the operand
10682  * isRead - set to 1 iff sym is read in pCode
10683  * listRead - set to 1 iff all operands being read are to be listed
10684  *
10685  * Returns 0 for "normal" operands, 1 for special operands.
10686  */
10687 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10688   /* check whether accessing REG accesses other REGs as well */
10689   switch (sym) {
10690   case SPO_INDF0:
10691     /* reads FSR0x */
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_PLUSW0:
10698     /* reads FSR0x and WREG */
10699     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10700     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10701     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10702     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10703     break;
10704
10705   case SPO_POSTDEC0:
10706   case SPO_POSTINC0:
10707   case SPO_PREINC0:
10708     /* reads/modifies FSR0x */
10709     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10710     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10711     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10712     break;
10713
10714   case SPO_INDF1:
10715     /* reads FSR1x */
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_PLUSW1:
10722     /* reads FSR1x and WREG */
10723     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10724     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10725     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10726     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10727     break;
10728
10729   case SPO_POSTDEC1:
10730   case SPO_POSTINC1:
10731   case SPO_PREINC1:
10732     /* reads/modifies FSR1x */
10733     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10734     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10735     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10736     break;
10737
10738   case SPO_INDF2:
10739     /* reads FSR2x */
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_PLUSW2:
10746     /* reads FSR2x and WREG */
10747     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10748     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10749     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10750     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10751     break;
10752
10753   case SPO_POSTDEC2:
10754   case SPO_POSTINC2:
10755   case SPO_PREINC2:
10756     /* reads/modifies FSR2x */
10757     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10758     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10759     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10760     break;
10761
10762   case SPO_PCL:
10763     /* modifies PCLATH and PCLATU */
10764     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10765     if (isRead) {
10766       /* reading PCL updates PCLATx */
10767       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10768       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10769     }
10770     if (isWrite) {
10771       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10772       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10773       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10774     }
10775     break;
10776
10777   default:
10778     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10779     /* nothing special */
10780     return 0;
10781     break;
10782   }
10783
10784   /* has been a special operand */
10785   return 1;
10786 }
10787
10788 static symbol_t pic16_fsrsym_idx[][2] = {
10789     {SPO_FSR0L, SPO_FSR0H},
10790     {SPO_FSR1L, SPO_FSR1H},
10791     {SPO_FSR2L, SPO_FSR2H}
10792 };
10793
10794 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10795 static void mergeDefmapSymbols (defmap_t *list) {
10796   defmap_t *ref, *curr, *temp;
10797
10798   /* now make sure that each symbol occurs at most once per pc */
10799   ref = list;
10800   while (ref && (ref->pc == list->pc)) {
10801     curr = ref->next;
10802     while (curr && (curr->pc == list->pc)) {
10803       if (curr->sym == ref->sym) {
10804         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10805         /* found a symbol occuring twice... merge the two */
10806         if (curr->acc.access.isRead) {
10807           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10808           ref->acc.access.isRead = 1;
10809           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10810         }
10811         if (curr->acc.access.isWrite) {
10812           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10813           ref->acc.access.isWrite = 1;
10814           ref->acc.access.mask |= curr->acc.access.mask;
10815         }
10816         temp = curr;
10817         curr = curr->next;
10818         deleteDefmap (temp);
10819         continue; // do not skip curr!
10820       } // if
10821       curr = curr->next;
10822     } // while
10823     ref = ref->next;
10824   } // while
10825 }
10826
10827 /** Prepend list with the reads and definitions performed by pc. */
10828 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10829   pCodeInstruction *pci;
10830   int cond, inCond, outCond;
10831   int mask = 0xff, smask;
10832   int isSpecial, isSpecial2;
10833   symbol_t sym, sym2;
10834   char *name;
10835
10836   if (isPCAD(pc)) {
10837     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10838     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10839     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10840     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10841     return list;
10842   }
10843   assert (isPCI(pc));
10844   pci = PCI(pc);
10845
10846   /* handle bit instructions */
10847   if (pci->isBitInst) {
10848     assert (pci->pcop->type == PO_GPR_BIT);
10849     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10850   }
10851
10852   /* handle (additional) implicit arguments */
10853   switch (pci->op) {
10854   case POC_LFSR:
10855     {
10856       int lit;
10857       valnum_t val;
10858       lit = PCOL(pci->pcop)->lit;
10859       assert (lit >= 0 && lit < 3);
10860       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10861       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10862       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10863       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10864       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...
10865     }
10866     break;
10867
10868   case POC_MOVLB: // BSR
10869   case POC_BANKSEL: // BSR
10870     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10871     break;
10872
10873   case POC_MULWF: // PRODx
10874   case POC_MULLW: // PRODx
10875     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10876     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10877     break;
10878
10879   case POC_POP: // TOS, STKPTR
10880     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10881     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10882     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10883     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10884     break;
10885
10886   case POC_PUSH: // STKPTR
10887     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10888     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10889     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10890     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10891     break;
10892
10893   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10894   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10895     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10896     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10897     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10898     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10899
10900     /* needs correctly set-up stack pointer */
10901     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10902     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10903     break;
10904
10905   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10906     /* pseudo read on (possible) return values */
10907     // WREG is handled below via outCond
10908     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10909     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10910     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10911
10912     /* caller's stack pointers must be restored */
10913     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10914     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10915     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10916     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10917     break;
10918
10919   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10920   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10921     /* pseudo read on (possible) return values */
10922     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10923     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10924     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10925     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10926
10927     /* caller's stack pointers must be restored */
10928     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10929     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10930     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10931     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10932     break;
10933
10934   case POC_TBLRD:
10935     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10936     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10937     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10938     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10939     break;
10940
10941   case POC_TBLRD_POSTINC:
10942   case POC_TBLRD_POSTDEC:
10943   case POC_TBLRD_PREINC:
10944     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10945     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10946     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10947     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10948     break;
10949
10950   case POC_TBLWT:
10951     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10952     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10953     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10954     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10955     break;
10956
10957   case POC_TBLWT_POSTINC:
10958   case POC_TBLWT_POSTDEC:
10959   case POC_TBLWT_PREINC:
10960     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10961     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10962     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10963     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10964     break;
10965
10966   default:
10967     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
10968     break;
10969   } // switch
10970
10971   /* handle explicit arguments */
10972   inCond = pci->inCond;
10973   outCond = pci->outCond;
10974   cond = inCond | outCond;
10975   if (cond & PCC_W) {
10976     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
10977   } // if
10978
10979   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
10980   if (inCond & PCC_STATUS) {
10981     smask = 0;
10982     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
10983     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10984     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10985     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10986     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
10987
10988     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
10989     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
10990   } // if
10991
10992   if (outCond & PCC_STATUS) {
10993     smask = 0;
10994     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
10995     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
10996     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
10997     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
10998     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
10999
11000     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11001     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11002   } // if
11003
11004   isSpecial = isSpecial2 = 0;
11005   sym = sym2 = 0;
11006   if (cond & PCC_REGISTER) {
11007     name = pic16_get_op (pci->pcop, NULL, 0);
11008     sym = symFromStr (name);
11009     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11010     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11011   }
11012
11013   if (cond & PCC_REGISTER2) {
11014     name = pic16_get_op2 (pci->pcop, NULL, 0);
11015     sym2 = symFromStr (name);
11016     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11017     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11018   }
11019
11020
11021   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11022   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11023
11024   mergeDefmapSymbols (list);
11025
11026   return list;
11027 }
11028
11029 #if 0
11030 static void printDefmap (defmap_t *map) {
11031   defmap_t *curr;
11032
11033   curr = map;
11034   fprintf (stderr, "defmap @ %p:\n", curr);
11035   while (curr) {
11036     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11037                     curr->acc.access.isRead ? "R" : " ",
11038                     curr->acc.access.isWrite ? "W": " ",
11039                     curr->in_val, curr->val,
11040                     curr->acc.access.in_mask, curr->acc.access.mask,
11041                     strFromSym(curr->sym), curr->sym,
11042                     curr->pc);
11043     curr = curr->next;
11044   } // while
11045   fprintf (stderr, "<EOL>\n");
11046 }
11047 #endif
11048
11049 /* Add "additional" definitions to uniq.
11050  * 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.
11051  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11052  *
11053  * If symbols defined in additional are not present in uniq, a definition is created.
11054  * Otherwise the present definition is altered to reflect the newer assignments.
11055  *
11056  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11057  *       before     `------- noted in additional --------'      after
11058  *
11059  * I assume that each symbol occurs AT MOST ONCE in uniq.
11060  *
11061  */
11062 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11063   defmap_t *curr;
11064   defmap_t *old;
11065   int change = 0;
11066
11067   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11068   /* find tail of additional list (holds the first assignment) */
11069   curr = additional;
11070   while (curr && curr->next) curr = curr->next;
11071
11072   /* update uniq */
11073   do {
11074     /* find next assignment in additionals */
11075     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11076
11077     if (!curr) break;
11078
11079     /* find item in uniq */
11080     old = *uniq;
11081     //printDefmap (*uniq);
11082     while (old && (old->sym != curr->sym)) old = old->next;
11083
11084     if (old) {
11085       /* definition found -- replace */
11086       if (old->val != curr->val) {
11087         old->val = curr->val;
11088         change++;
11089       } // if
11090     } else {
11091       /* new definition */
11092       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11093       change++;
11094     }
11095
11096     curr = curr->prev;
11097   } while (1);
11098
11099   /* return 0 iff uniq remained unchanged */
11100   return change;
11101 }
11102
11103 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11104  * lists of its predecessor flows.
11105  * Initially *combined should be NULL, alt_in will be copied to combined.
11106  * If *combined != NULL, combined will be altered:
11107  * - for symbols defined in *combined but not in alt_in,
11108  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11109  * - for symbols defined in alt_in but not in *combined,
11110  *   a 0 definition is created (value unknown, either INIT or alt).
11111  * - for symbols defined in both, *combined is:
11112  *   > left unchanged if *combined->val == alt_in->val or
11113  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11114  *
11115  * I assume that each symbol occurs AT MOST ONCE in each list!
11116  */
11117 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11118   defmap_t *curr;
11119   defmap_t *old;
11120   int change = 0;
11121   valnum_t val;
11122
11123   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11124
11125   if (!(*combined)) {
11126     return defmapUpdateUniqueSym (combined, alt_in);
11127   } // if
11128
11129   /* merge the two */
11130   curr = alt_in;
11131   while (curr) {
11132     /* find symbols definition in *combined */
11133     old = *combined;
11134     while (old && (old->sym != curr->sym)) old = old->next;
11135
11136     if (old) {
11137       /* definition found */
11138       if (old->val && (old->val != curr->val)) {
11139         old->val = 0; /* value unknown */
11140         change++;
11141       }
11142     } else {
11143       /* no definition found -- can be either INIT or alt_in's value */
11144       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11145       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11146       if (val != curr->val) change++;
11147     }
11148
11149     curr = curr->next;
11150   } // while (curr)
11151
11152   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11153   old = *combined;
11154   while (old) {
11155     if (old->val != 0) {
11156       /* find definition in alt_in */
11157       curr = alt_in;
11158       while (curr && curr->sym != old->sym) curr = curr->next;
11159       if (!curr) {
11160         /* symbol defined in *combined only -- can be either INIT or *combined */
11161         val = pic16_pBlockAddInval (pb, old->sym)->val;
11162         if (old->val != val) {
11163           old->val = 0;
11164           change++;
11165         }
11166       } // if
11167     } // if
11168
11169     old = old->next;
11170   } // while
11171
11172   return change;
11173 }
11174
11175 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11176   defmap_t *curr1, *curr2;
11177   symbol_t sym;
11178
11179   /* identical maps are equal */
11180   if (map1 == map2) return 0;
11181
11182   if (!map1) return -1;
11183   if (!map2) return 1;
11184
11185   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11186
11187   /* check length */
11188   curr1 = map1;
11189   curr2 = map2;
11190   while (curr1 && curr2) {
11191     curr1 = curr1->next;
11192     curr2 = curr2->next;
11193   } // while
11194
11195   /* one of them longer? */
11196   if (curr1) return 1;
11197   if (curr2) return -1;
11198
11199   /* both lists are of equal length -- compare (in O(n^2)) */
11200   curr1 = map1;
11201   while (curr1) {
11202     sym = curr1->sym;
11203     curr2 = map2;
11204     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11205     if (!curr2) return 1; // symbol not found in curr2
11206     if (curr2->val != curr1->val) return 1; // values differ
11207
11208     /* compare next symbol */
11209     curr1 = curr1->next;
11210   } // while
11211
11212   /* no difference found */
11213   return 0;
11214 }
11215
11216
11217 /* Prepare a list of all reaching definitions per flow.
11218  * This is done using a forward dataflow analysis.
11219  */
11220 static void createReachingDefinitions (pBlock *pb) {
11221   defmap_t *out_vals, *in_vals;
11222   pCode *pc;
11223   pCodeFlow *pcfl;
11224   pCodeFlowLink *link;
11225   set *todo;
11226   set *blacklist;
11227
11228   if (!pb) return;
11229
11230   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11231   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11232     if (isPCFL(pc)) {
11233       deleteDefmapChain (&PCFL(pc)->in_vals);
11234       deleteDefmapChain (&PCFL(pc)->out_vals);
11235       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11236     } // if
11237   } // for
11238
11239   pc = pic16_findNextInstruction (pb->pcHead);
11240   if (!pc) {
11241       // empty function, avoid NULL pointer dereference
11242       return;
11243   } // if
11244   todo = NULL; blacklist = NULL;
11245   addSetHead (&todo, PCI(pc)->pcflow);
11246
11247   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11248   while (elementsInSet (todo)) {
11249     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11250     pcfl = PCFL(indexSet (todo, 0));
11251     deleteSetItem (&todo, pcfl);
11252     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11253     in_vals = NULL;
11254     out_vals = NULL;
11255
11256     if (isinSet (blacklist, pcfl)) {
11257             fprintf (stderr, "ignoring blacklisted flow\n");
11258       continue;
11259     }
11260
11261     /* create in_vals from predecessors out_vals */
11262     link = setFirstItem (pcfl->from);
11263     while (link) {
11264       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11265       link = setNextItem (pcfl->from);
11266     } // while
11267
11268     //printDefmap (in_vals);
11269     //printDefmap (pcfl->in_vals);
11270
11271     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11272       //fprintf (stderr, "in_vals changed\n");
11273       /* in_vals changed -- update out_vals */
11274       deleteDefmapChain (&pcfl->in_vals);
11275       pcfl->in_vals = in_vals;
11276
11277       /* create out_val from in_val and defmap */
11278       out_vals = NULL;
11279       defmapUpdateUniqueSym (&out_vals, in_vals);
11280       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11281
11282       /* is out_vals different from pcfl->out_vals */
11283       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11284         //fprintf (stderr, "out_vals changed\n");
11285         deleteDefmapChain (&pcfl->out_vals);
11286         pcfl->out_vals = out_vals;
11287
11288         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11289           addSet (&blacklist, pcfl);
11290         } // if
11291
11292         /* reschedule all successors */
11293         link = setFirstItem (pcfl->to);
11294         while (link) {
11295           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11296           addSetIfnotP (&todo, link->pcflow);
11297           link = setNextItem (pcfl->to);
11298         } // while
11299       } else {
11300         deleteDefmapChain (&out_vals);
11301       }// if
11302     } else {
11303       deleteDefmapChain (&in_vals);
11304     } // if
11305   } // while
11306 }
11307
11308 #if 0
11309 static void showAllDefs (symbol_t sym, pCode *pc) {
11310   defmap_t *map;
11311   int count;
11312
11313   assert (isPCI(pc));
11314   count = defmapFindAll (sym, pc, &map);
11315
11316   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11317   while (map) {
11318 #if 1
11319     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11320 #else
11321     { char buf[256];
11322     pic16_pCode2str (buf, 256, map->pc);
11323     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11324 #endif
11325     map = map->next;
11326   }
11327   deleteDefmapChain (&map);
11328 }
11329 #endif
11330
11331 /* safepCodeUnlink and remove pc from defmap. */
11332 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11333   defmap_t *map, *next, **head;
11334   int res, ispci;
11335
11336   ispci = isPCI(pc);
11337   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11338   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11339   res = pic16_safepCodeUnlink (pc, comment);
11340
11341   if (res && map) {
11342     /* remove pc from defmap */
11343     while (map) {
11344       next = map->next;
11345       if (map->pc == pc) {
11346         if (!map->prev && head) *head = map->next;
11347         deleteDefmap (map);
11348       } // if
11349       map = next;
11350     }
11351   }
11352
11353   return res;
11354 }
11355
11356 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11357   defmap_t *map;
11358   /* This breaks the defmap chain's references to pCodes... fix it! */
11359   map = PCI(pc)->pcflow->defmap;
11360
11361   while (map && map->pc != pc) map = map->next;
11362
11363   while (map && map->pc == pc) {
11364     map->pc = newpc;
11365     map = map->next;
11366   } // while
11367 }
11368
11369 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11370  * write accesses (isRead == 0). */
11371 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11372   defmap_t *map, *map_start;
11373   defmap_t *copy;
11374   if (!isPCI(pc)) return;
11375   if (sym == newsym) return;
11376
11377   map = PCI(pc)->pcflow->defmap;
11378
11379   while (map && map->pc != pc) map = map->next;
11380   map_start = map;
11381   while (map && map->pc == pc) {
11382     if (map->sym == sym) {
11383       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11384       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11385         /* only one kind of access handled... this is easy */
11386         map->sym = newsym;
11387       } else {
11388         /* must copy defmap entry before replacing symbol... */
11389         copy = copyDefmap (map);
11390         if (isRead) {
11391           map->acc.access.isRead = 0;
11392           copy->acc.access.isWrite = 0;
11393         } else {
11394           map->acc.access.isWrite = 0;
11395           copy->acc.access.isRead = 0;
11396         }
11397         copy->sym = newsym;
11398         /* insert copy into defmap chain */
11399         defmapInsertAfter (map, copy);
11400       }
11401     }
11402     map = map->next;
11403   } // while
11404
11405   /* as this might introduce multiple defmap entries for newsym... */
11406   mergeDefmapSymbols (map_start);
11407 }
11408
11409 /* Assign "better" valnums to results. */
11410 static void assignValnums (pCode *pc) {
11411   pCodeInstruction *pci;
11412   pCode *newpc;
11413   symbol_t sym1, sym2;
11414   int cond, isSpecial1, isSpecial2, count, mask, lit;
11415   defmap_t *list, *val, *oldval, *dummy;
11416   regs *reg1 = NULL, *reg2 = NULL;
11417   valnum_t litnum;
11418
11419   /* only works for pCodeInstructions... */
11420   if (!isPCI(pc)) return;
11421
11422   pci = PCI(pc);
11423   cond = pci->inCond | pci->outCond;
11424   list = pci->pcflow->defmap;
11425   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11426
11427   if (cond & PCC_REGISTER) {
11428     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11429     reg1 = pic16_getRegFromInstruction (pc);
11430     isSpecial1 = pic16_symIsSpecial (sym1);
11431   }
11432   if (cond & PCC_REGISTER2) {
11433     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11434     reg2 = pic16_getRegFromInstruction (pc);
11435     isSpecial2 = pic16_symIsSpecial (sym2);
11436   }
11437
11438   /* determine input values */
11439   val = list;
11440   while (val && val->pc != pc) val = val->next;
11441   //list = val; /* might save some time later... */
11442   while (val && val->pc == pc) {
11443     val->in_val = 0;
11444     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11445       /* get valnum for sym */
11446       count = defmapFindAll (val->sym, pc, &oldval);
11447       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11448       if (count == 1) {
11449         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11450           val->in_val = oldval->val;
11451         } else {
11452           val->in_val = 0;
11453         }
11454       } else if (count == 0) {
11455         /* no definition found */
11456         val->in_val = 0;
11457       } else {
11458         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11459         assert (oldval);
11460         dummy = oldval->next;
11461         mask = oldval->acc.access.mask;
11462         val->in_val = oldval->val;
11463         while (dummy && (dummy->val == val->in_val)) {
11464           mask &= dummy->acc.access.mask;
11465           dummy = dummy->next;
11466         } // while
11467
11468         /* found other values or to restictive mask */
11469         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11470           val->in_val = 0;
11471         }
11472       }
11473       if (count > 0) deleteDefmapChain (&oldval);
11474     } // if
11475     val = val->next;
11476   }
11477
11478   /* handle valnum assignment */
11479   switch (pci->op) {
11480   case POC_CLRF: /* modifies STATUS (Z) */
11481     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11482       oldval = defmapCurr (list, sym1, pc);
11483       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11484         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11485         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11486       }
11487       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11488     }
11489     break;
11490
11491   case POC_SETF: /* SETF does not touch STATUS */
11492     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11493       oldval = defmapCurr (list, sym1, pc);
11494       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11495         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11496         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11497       }
11498       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11499     }
11500     break;
11501
11502   case POC_MOVLW: /* does not touch STATUS */
11503     oldval = defmapCurr (list, SPO_WREG, pc);
11504     if (pci->pcop->type == PO_LITERAL) {
11505       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11506       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11507     } else {
11508       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11509       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11510     }
11511     if (oldval && oldval->in_val == litnum) {
11512       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11513       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11514     }
11515     defmapUpdate (list, SPO_WREG, pc, litnum);
11516     break;
11517
11518   case POC_ANDLW: /* modifies STATUS (Z,N) */
11519   case POC_IORLW: /* modifies STATUS (Z,N) */
11520   case POC_XORLW: /* modifies STATUS (Z,N) */
11521     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11522     if (pci->pcop->type == PO_LITERAL) {
11523       int vallit = -1;
11524       lit = (unsigned char) PCOL(pci->pcop)->lit;
11525       val = defmapCurr (list, SPO_WREG, pc);
11526       if (val) vallit = litFromValnum (val->in_val);
11527       if (vallit != -1) {
11528         /* xxxLW <literal>, WREG contains a known literal */
11529         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11530         if (pci->op == POC_ANDLW) {
11531           lit &= vallit;
11532         } else if (pci->op == POC_IORLW) {
11533           lit |= vallit;
11534         } else if (pci->op == POC_XORLW) {
11535           lit ^= vallit;
11536         } else {
11537           assert (0 && "invalid operation");
11538         }
11539         if (vallit == lit) {
11540           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11541           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11542         }
11543         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11544       } // if
11545     }
11546     break;
11547
11548   case POC_LFSR:
11549     {
11550       /* check if old value matches new value */
11551       int lit;
11552       int ok = 1;
11553       assert (pci->pcop->type == PO_LITERAL);
11554
11555       lit = PCOL(pci->pcop)->lit;
11556
11557       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11558
11559       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11560         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11561       } else {
11562         /* cannot remove this LFSR */
11563         ok = 0;
11564       } // if
11565
11566       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11567       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11568         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11569       } else {
11570         ok = 0;
11571       } // if
11572
11573       if (ok) {
11574         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11575       }
11576     }
11577     break;
11578
11579   case POC_MOVWF: /* does not touch flags */
11580     /* find value of WREG */
11581     val = defmapCurr (list, SPO_WREG, pc);
11582     oldval = defmapCurr (list, sym1, pc);
11583     if (val) lit = litFromValnum (val->in_val);
11584     else lit = -1;
11585     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11586
11587     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11588       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11589       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11590       if (lit == 0) {
11591         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11592       } else {
11593         assert (lit == 0x0ff);
11594         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11595       }
11596       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11597       pic16_pCodeReplace (pc, newpc);
11598       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11599       pic16_fixDefmap (pc, newpc);
11600       pc = newpc;
11601
11602       /* This breaks the defmap chain's references to pCodes... fix it! */
11603       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11604       if (!val->acc.access.isWrite) {
11605         deleteDefmap (val);     // delete reference to WREG as in value
11606         val = NULL;
11607       } else {
11608         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11609       }
11610       oldval = PCI(pc)->pcflow->defmap;
11611       while (oldval) {
11612         if (oldval->pc == pc) oldval->pc = newpc;
11613           oldval = oldval->next;
11614       } // while
11615     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11616       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11617       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11618     }
11619     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11620     break;
11621
11622   case POC_MOVFW: /* modifies STATUS (Z,N) */
11623     /* find value of REG */
11624     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11625       val = defmapCurr (list, sym1, pc);
11626       oldval = defmapCurr (list, SPO_WREG, pc);
11627       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11628         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11629         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11630       } else {
11631           defmap_t *pred, *predpred;
11632           /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11633            * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11634            * This might allow removal of the first two assignments. */
11635           pred = defmapFindDef (list, sym1, pc);
11636           predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11637           if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11638                 && !pic16_isAlive (SPO_STATUS, pc))
11639           {
11640               newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11641
11642               if (pic16_debug_verbose || pic16_pcode_verbose) {
11643                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11644               } // if
11645               pic16_pCodeReplace (pc, newpc);
11646               defmapReplaceSymRef (pc, sym1, 0, 1);
11647               pic16_fixDefmap (pc, newpc);
11648               pc = newpc;
11649
11650               /* This breaks the defmap chain's references to pCodes... fix it! */
11651               if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11652               if (!val->acc.access.isWrite) {
11653                   deleteDefmap (val);   // delete reference to reg1 as in value
11654                   val = NULL;
11655               } else {
11656                   val->acc.access.isRead = 0;   // delete reference to reg1 as in value
11657               }
11658               oldval = PCI(pc)->pcflow->defmap;
11659               while (oldval) {
11660                   if (oldval->pc == pc) oldval->pc = newpc;
11661                   oldval = oldval->next;
11662               } // while
11663           } // if
11664       }
11665       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11666     }
11667     break;
11668
11669   case POC_MOVFF: /* does not touch STATUS */
11670     /* find value of REG */
11671     val = defmapCurr (list, sym1, pc);
11672     oldval = defmapCurr (list, sym2, pc);
11673     if (val) lit = litFromValnum (val->in_val);
11674     else lit = -1;
11675     newpc = NULL;
11676     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11677       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11678       if (lit == 0) {
11679         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11680       } else if (lit == 0x00ff) {
11681         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11682       } else {
11683         newpc = NULL;
11684       }
11685       if (newpc) {
11686         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11687         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11688         pic16_pCodeReplace (pc, newpc);
11689         defmapReplaceSymRef (pc, sym1, 0, 1);
11690         pic16_fixDefmap (pc, newpc);
11691         pc = newpc;
11692         break; // do not process instruction as MOVFF...
11693       }
11694     } else if (!isSpecial1 && !isSpecial2
11695                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11696                 && val && oldval && (val->in_val != 0)) {
11697       if (val->in_val == oldval->in_val) {
11698         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11699         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11700       } else {
11701         if (!pic16_isAlive (sym1, pc)) {
11702           defmap_t *copy = NULL;
11703           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11704            * This should help eliminate
11705            *   MOVFF A,B
11706            *   <do something not changing A or using B>
11707            *   MOVFF B,C
11708            *   <B is not alive anymore>
11709            * and turn it into
11710            *   <do something not changing A or using B>
11711            *   MOVFF A,C
11712            */
11713
11714           /* scan defmap for symbols storing sym1's value */
11715           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11716           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11717             /* unique reaching definition for sym found */
11718             if (copy->val && copy->val == val->in_val) {
11719               //fprintf (stderr, "found replacement symbol for %s (val %x) <-- %s (assigned %x @ %p)\n", strFromSym(sym1), val->in_val, strFromSym(copy->sym), copy->val, copy->pc);
11720               if (copy->sym == SPO_WREG) {
11721                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11722               } else {
11723                 pCodeOp *pcop = NULL;
11724                 /* the code below fails if we try to replace
11725                  *   MOVFF PRODL, r0x03
11726                  *   MOVFF r0x03, PCLATU
11727                  * with
11728                  *   MOVFF PRODL, PCLATU
11729                  * as copy(PRODL) contains has pc==NULL, by name fails...
11730                  */
11731                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11732
11733                 if (copy->pc && PCI(copy->pc)->pcop)
11734                   pcop = PCI(copy->pc)->pcop;
11735 #if 0
11736                 /* This code is broken--see above. */
11737                 else
11738                 {
11739                   const char *symname = strFromSym(copy->sym);
11740
11741                   assert( symname );
11742                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11743                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11744                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11745                 }
11746 #endif
11747                 assert( pcop );
11748                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11749                         pcop,
11750                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11751               }
11752               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11753               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11754               pic16_pCodeReplace (pc, newpc);
11755               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11756               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11757               pic16_fixDefmap (pc, newpc);
11758               pc = newpc;
11759             }
11760           }
11761           deleteDefmapChain (&copy);
11762         }
11763       }
11764       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11765     }
11766     break;
11767
11768   default:
11769     /* cannot optimize */
11770     break;
11771   } // switch
11772 }
11773
11774 static void pic16_destructDF (pBlock *pb) {
11775   pCode *pc, *next;
11776
11777   if (!pb) return;
11778
11779   /* remove old defmaps */
11780   pc = pic16_findNextInstruction (pb->pcHead);
11781   while (pc) {
11782     next = pic16_findNextInstruction (pc->next);
11783
11784     assert (isPCI(pc) || isPCAD(pc));
11785     assert (PCI(pc)->pcflow);
11786     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11787     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11788     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11789
11790     pc = next;
11791   } // while
11792
11793   if (defmap_free || defmap_free_count) {
11794     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11795     freeDefmap (&defmap_free);
11796     defmap_free_count = 0;
11797   }
11798 }
11799
11800 /* Checks whether a pBlock contains ASMDIRs. */
11801 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11802   pCode *pc;
11803
11804   if (!pb) return 0;
11805
11806   pc = pic16_findNextInstruction (pb->pcHead);
11807   while (pc) {
11808     if (isPCAD(pc)) return 1;
11809
11810     pc = pic16_findNextInstruction (pc->next);
11811   } // while
11812
11813   /* no PCADs found */
11814   return 0;
11815 }
11816
11817 #if 1
11818 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11819 static int pic16_removeUnusedRegistersDF () {
11820   pCode *pc, *pc2;
11821   pBlock *pb;
11822   regs *reg1, *reg2, *reg3;
11823   set *seenRegs = NULL;
11824   int cond, i;
11825   int islocal, change = 0;
11826
11827   /* no pBlocks? */
11828   if (!the_pFile || !the_pFile->pbHead) return 0;
11829
11830   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11831     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11832 #if 1
11833     /* find set of using pCodes per register */
11834     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11835                     pc = pic16_findNextInstruction(pc->next)) {
11836
11837       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11838       reg1 = reg2 = NULL;
11839       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11840       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11841
11842       if (reg1) {
11843         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11844         addSetIfnotP (&seenRegs, reg1);
11845         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11846       }
11847       if (reg2) {
11848         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11849         addSetIfnotP (&seenRegs, reg2);
11850         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11851       }
11852     } // for pc
11853 #endif
11854     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11855       /* may not use pic16_regIsLocal() here -- in interrupt routines
11856        * WREG, PRODx, FSR0x must be saved */
11857       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11858       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11859         pc = pc2 = NULL;
11860         for (i=0; i < 2; i++) {
11861           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11862           if (!pc2) pc2 = pc;
11863           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11864           reg2 = pic16_getRegFromInstruction (pc);
11865           reg3 = pic16_getRegFromInstruction2 (pc);
11866           if (!reg2 || !reg3
11867               || (reg2->rIdx != pic16_stack_preinc->rIdx
11868                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11869           if (i == 1) {
11870             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11871             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11872             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11873             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11874           }
11875         } // for
11876       } // if
11877       deleteSet (&reg1->reglives.usedpCodes);
11878     } // for reg1
11879
11880     deleteSet (&seenRegs);
11881   } // for pb
11882
11883   return change;
11884 }
11885 #endif
11886
11887 /* Set up pCodeFlow's defmap_ts.
11888  * Needs correctly set up to/from fields. */
11889 static void pic16_createDF (pBlock *pb) {
11890   pCode *pc, *next;
11891   int change=0;
11892
11893   if (!pb) return;
11894
11895   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11896
11897   pic16_destructDF (pb);
11898
11899   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11900   if (pic16_pBlockHasAsmdirs (pb)) {
11901     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11902     return;
11903   }
11904
11905   /* integrity check -- we need to reach all flows to guarantee
11906    * correct data flow analysis (reaching definitions, aliveness) */
11907 #if 0
11908   if (!verifyAllFlowsReachable (pb)) {
11909     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11910     return;
11911   }
11912 #endif
11913
11914   /* establish new defmaps */
11915   pc = pic16_findNextInstruction (pb->pcHead);
11916   while (pc) {
11917     next = pic16_findNextInstruction (pc->next);
11918
11919     assert (PCI(pc)->pcflow);
11920     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11921
11922     pc = next;
11923   } // while
11924
11925   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11926   createReachingDefinitions (pb);
11927
11928 #if 1
11929   /* assign better valnums */
11930   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11931   pc = pic16_findNextInstruction (pb->pcHead);
11932   while (pc) {
11933     next = pic16_findNextInstruction (pc->next);
11934
11935     assert (PCI(pc)->pcflow);
11936     assignValnums (pc);
11937
11938     pc = next;
11939   } // while
11940 #endif
11941
11942 #if 1
11943   /* remove dead pCodes */
11944   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11945   do {
11946     change = 0;
11947     pc = pic16_findNextInstruction (pb->pcHead);
11948     while (pc) {
11949       next = pic16_findNextInstruction (pc->next);
11950
11951       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11952         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11953       }
11954
11955       pc = next;
11956     } // while
11957   } while (change);
11958 #endif
11959 }
11960
11961 /* ======================================================================== */
11962 /* === VCG DUMPER ROUTINES ================================================ */
11963 /* ======================================================================== */
11964 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11965 hTab *dumpedNodes = NULL;
11966
11967 /** Dump VCG header into of. */
11968 static void pic16_vcg_init (FILE *of) {
11969   /* graph defaults */
11970   fprintf (of, "graph:{\n");
11971   fprintf (of, "title:\"graph1\"\n");
11972   fprintf (of, "label:\"graph1\"\n");
11973   fprintf (of, "color:white\n");
11974   fprintf (of, "textcolor:black\n");
11975   fprintf (of, "bordercolor:black\n");
11976   fprintf (of, "borderwidth:1\n");
11977   fprintf (of, "textmode:center\n");
11978
11979   fprintf (of, "layoutalgorithm:dfs\n");
11980   fprintf (of, "late_edge_labels:yes\n");
11981   fprintf (of, "display_edge_labels:yes\n");
11982   fprintf (of, "dirty_edge_labels:yes\n");
11983   fprintf (of, "finetuning:yes\n");
11984   fprintf (of, "ignoresingles:no\n");
11985   fprintf (of, "straight_phase:yes\n");
11986   fprintf (of, "priority_phase:yes\n");
11987   fprintf (of, "manhattan_edges:yes\n");
11988   fprintf (of, "smanhattan_edges:no\n");
11989   fprintf (of, "nearedges:no\n");
11990   fprintf (of, "node_alignment:center\n"); // bottom|top|center
11991   fprintf (of, "port_sharing:no\n");
11992   fprintf (of, "arrowmode:free\n"); // fixed|free
11993   fprintf (of, "crossingphase2:yes\n");
11994   fprintf (of, "crossingoptimization:yes\n");
11995   fprintf (of, "edges:yes\n");
11996   fprintf (of, "nodes:yes\n");
11997   fprintf (of, "splines:no\n");
11998
11999   /* node defaults */
12000   fprintf (of, "node.color:lightyellow\n");
12001   fprintf (of, "node.textcolor:black\n");
12002   fprintf (of, "node.textmode:center\n");
12003   fprintf (of, "node.shape:box\n");
12004   fprintf (of, "node.bordercolor:black\n");
12005   fprintf (of, "node.borderwidth:1\n");
12006
12007   /* edge defaults */
12008   fprintf (of, "edge.textcolor:black\n");
12009   fprintf (of, "edge.color:black\n");
12010   fprintf (of, "edge.thickness:1\n");
12011   fprintf (of, "edge.arrowcolor:black\n");
12012   fprintf (of, "edge.backarrowcolor:black\n");
12013   fprintf (of, "edge.arrowsize:15\n");
12014   fprintf (of, "edge.backarrowsize:15\n");
12015   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12016   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12017   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12018
12019   fprintf (of, "\n");
12020
12021   /* prepare data structures */
12022   if (dumpedNodes) {
12023     hTabDeleteAll (dumpedNodes);
12024     dumpedNodes = NULL;
12025   }
12026   dumpedNodes = newHashTable (128);
12027 }
12028
12029 /** Dump VCG footer into of. */
12030 static void pic16_vcg_close (FILE *of) {
12031   fprintf (of, "}\n");
12032 }
12033
12034 #define BUF_SIZE 128
12035 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12036
12037 #if 0
12038 static int ptrcmp (const void *p1, const void *p2) {
12039   return p1 == p2;
12040 }
12041 #endif
12042
12043 /** Dump a pCode node as VCG to of. */
12044 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12045   char buf[BUF_SIZE];
12046
12047   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12048     // dumped already
12049     return;
12050   }
12051   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12052   //fprintf (stderr, "dumping %p\n", pc);
12053
12054   /* only dump pCodeInstructions and Flow nodes */
12055   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12056
12057   /* emit node */
12058   fprintf (of, "node:{");
12059   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12060   fprintf (of, "label:\"%s\n", pcTitle(pc));
12061   if (isPCFL(pc)) {
12062     fprintf (of, "<PCFLOW>");
12063   } else if (isPCI(pc) || isPCAD(pc)) {
12064     pc->print (of, pc);
12065   } else {
12066     fprintf (of, "<!PCI>");
12067   }
12068   fprintf (of, "\" ");
12069   fprintf (of, "}\n");
12070
12071   if (1 && isPCFL(pc)) {
12072     defmap_t *map, *prev;
12073     unsigned int i;
12074     map = PCFL(pc)->defmap;
12075     i=0;
12076     while (map) {
12077       if (map->sym != 0) {
12078         i++;
12079
12080         /* emit definition node */
12081         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12082         fprintf (of, "label:\"");
12083
12084         prev = map;
12085         do {
12086           fprintf (of, "%s%c%c: val %4x|%4x & %02x|%02x, sym %s", (prev == map) ? "" : "\n", map->acc.access.isRead ? 'R' : ' ', map->acc.access.isWrite ? 'W' : ' ', map->in_val, map->val, map->acc.access.in_mask, map->acc.access.mask, strFromSym (map->sym));
12087           prev = map;
12088           map = map->next;
12089         } while (map && prev->pc == map->pc);
12090         map = prev;
12091
12092         fprintf (of, "\" ");
12093
12094         fprintf (of, "color:green ");
12095         fprintf (of, "}\n");
12096
12097         /* emit edge to previous definition */
12098         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12099         if (i == 1) {
12100           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12101         } else {
12102           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12103         }
12104         fprintf (of, "color:green ");
12105         fprintf (of, "}\n");
12106
12107         if (map->pc) {
12108           pic16_vcg_dumpnode (map->pc, of);
12109           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12110           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12111         }
12112       }
12113       map = map->next;
12114     } // while
12115   }
12116
12117   /* emit additional nodes (e.g. operands) */
12118 }
12119
12120 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12121 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12122   char buf[BUF_SIZE];
12123   pCodeInstruction *pci;
12124   pBranch *curr;
12125   int i;
12126
12127   if (1 && isPCFL(pc)) {
12128     /* emit edges to flow successors */
12129     void *pcfl;
12130     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12131     pcfl = setFirstItem (PCFL(pc)->to);
12132     while (pcfl) {
12133       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12134       pic16_vcg_dumpnode (pc, of);
12135       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12136       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12137       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12138       pcfl = setNextItem (PCFL(pc)->to);
12139     } // while
12140   } // if
12141
12142   if (!isPCI(pc) && !isPCAD(pc)) return;
12143
12144   pci = PCI(pc);
12145
12146   /* emit control flow edges (forward only) */
12147   curr = pci->to;
12148   i=0;
12149   while (curr) {
12150     pic16_vcg_dumpnode (curr->pc, of);
12151     fprintf (of, "edge:{");
12152     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12153     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12154     fprintf (of, "color:red ");
12155     fprintf (of, "}\n");
12156     curr = curr->next;
12157   } // while
12158
12159 #if 1
12160   /* dump "flow" edge (link pCode according to pBlock order) */
12161   {
12162     pCode *pcnext;
12163     pcnext = pic16_findNextInstruction (pc->next);
12164     if (pcnext) {
12165       pic16_vcg_dumpnode (pcnext, of);
12166       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12167       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12168     }
12169   }
12170 #endif
12171
12172 #if 0
12173   /* emit flow */
12174   if (pci->pcflow) {
12175     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12176     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12177     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12178   }
12179 #endif
12180
12181   /* emit data flow edges (backward only) */
12182   /* TODO: gather data flow information... */
12183 }
12184
12185 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12186   pCode *pc;
12187
12188   if (!pb) return;
12189
12190   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12191   if (pic16_pBlockHasAsmdirs (pb)) {
12192     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12193     return;
12194   }
12195
12196   for (pc=pb->pcHead; pc; pc = pc->next) {
12197     pic16_vcg_dumpnode (pc, of);
12198   } // for pc
12199
12200   for (pc=pb->pcHead; pc; pc = pc->next) {
12201     pic16_vcg_dumpedges (pc, of);
12202   } // for pc
12203 }
12204
12205 static void pic16_vcg_dump_default (pBlock *pb) {
12206   FILE *of;
12207   char buf[BUF_SIZE];
12208   pCode *pc;
12209
12210   if (!pb) return;
12211
12212   /* get function name */
12213   pc = pb->pcHead;
12214   while (pc && !isPCF(pc)) pc = pc->next;
12215   if (pc) {
12216     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12217   } else {
12218     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12219   }
12220
12221   //fprintf (stderr, "now dumping %s\n", buf);
12222   of = fopen (buf, "w");
12223   pic16_vcg_init (of);
12224   pic16_vcg_dump (of, pb);
12225   pic16_vcg_close (of);
12226   fclose (of);
12227 }
12228 #endif
12229
12230 /*** END of helpers for pCode dataflow optimizations ***/