b4fe226ae82d56b2df93b9e1044777e3f22b5360
[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 STRCASECMP stricmp
39 #define inline
40 #else
41 #define STRCASECMP strcasecmp
42 #endif
43
44 #define DUMP_DF_GRAPHS 0
45
46 /****************************************************************/
47 /****************************************************************/
48
49 static peepCommand peepCommands[] = {
50
51   {NOTBITSKIP, "_NOTBITSKIP_"},
52   {BITSKIP, "_BITSKIP_"},
53   {INVERTBITSKIP, "_INVERTBITSKIP_"},
54
55   {-1, NULL}
56 };
57
58
59
60 // Eventually this will go into device dependent files:
61 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
66 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
68
69 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
71 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
72
73 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
74 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
75 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
76 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
77
78 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
79
80 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
86
87 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
88 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
92
93 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
94 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
98
99 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
100 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
104
105 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
106 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
107
108 /* EEPROM registers */
109 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
113
114 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
115 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
117
118 pCodeOpReg *pic16_stackpnt_lo;
119 pCodeOpReg *pic16_stackpnt_hi;
120 pCodeOpReg *pic16_stack_postinc;
121 pCodeOpReg *pic16_stack_postdec;
122 pCodeOpReg *pic16_stack_preinc;
123 pCodeOpReg *pic16_stack_plusw;
124
125 pCodeOpReg *pic16_framepnt_lo;
126 pCodeOpReg *pic16_framepnt_hi;
127 pCodeOpReg *pic16_frame_postinc;
128 pCodeOpReg *pic16_frame_postdec;
129 pCodeOpReg *pic16_frame_preinc;
130 pCodeOpReg *pic16_frame_plusw;
131
132 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
133 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
134
135 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
136 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
137
138
139 static int mnemonics_initialized = 0;
140
141
142 static hTab *pic16MnemonicsHash = NULL;
143 static hTab *pic16pCodePeepCommandsHash = NULL;
144
145 static pFile *the_pFile = NULL;
146 static pBlock *pb_dead_pcodes = NULL;
147
148 /* Hardcoded flags to change the behavior of the PIC port */
149 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
150 static int functionInlining = 1;      /* inline functions if nonzero */
151 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
152
153 int pic16_pcode_verbose = 0;
154
155 //static int GpCodeSequenceNumber = 1;
156 static int GpcFlowSeq = 1;
157
158 extern void pic16_RemoveUnusedRegisters(void);
159 extern void pic16_RegsUnMapLiveRanges(void);
160 extern void pic16_BuildFlowTree(pBlock *pb);
161 extern void pic16_pCodeRegOptimizeRegUsage(int level);
162 extern int pic16_picIsInitialized(void);
163 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
164 extern int mnem2key(unsigned char const *mnem);
165
166 /****************************************************************/
167 /*                      Forward declarations                    */
168 /****************************************************************/
169
170 void pic16_unlinkpCode(pCode *pc);
171 #if 0
172 static void genericAnalyze(pCode *pc);
173 static void AnalyzeGOTO(pCode *pc);
174 static void AnalyzeSKIP(pCode *pc);
175 static void AnalyzeRETURN(pCode *pc);
176 #endif
177
178 static void genericDestruct(pCode *pc);
179 static void genericPrint(FILE *of,pCode *pc);
180
181 static void pCodePrintLabel(FILE *of, pCode *pc);
182 static void pCodePrintFunction(FILE *of, pCode *pc);
183 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
184 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
185 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
186 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
187 int pic16_pCodePeepMatchRule(pCode *pc);
188 static void pBlockStats(FILE *of, pBlock *pb);
189 static pBlock *newpBlock(void);
190 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
191 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
192 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
193 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
194 void OptimizeLocalRegs(void);
195 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
196
197 char *dumpPicOptype(PIC_OPTYPE type);
198
199 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
200 pCodeOp *pic16_popGetLit(int);
201 pCodeOp *pic16_popGetWithString(char *);
202 extern int inWparamList(char *s);
203
204 /** data flow optimization helpers **/
205 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
206 static void pic16_vcg_dump (FILE *of, pBlock *pb);
207 static void pic16_vcg_dump_default (pBlock *pb);
208 #endif
209 static int pic16_pCodeIsAlive (pCode *pc);
210 static void pic16_df_stats ();
211 static void pic16_createDF (pBlock *pb);
212 static int pic16_removeUnusedRegistersDF ();
213 static void pic16_destructDF (pBlock *pb);
214 static void releaseStack ();
215
216 /****************************************************************/
217 /*                    PIC Instructions                          */
218 /****************************************************************/
219
220 pCodeInstruction pic16_pciADDWF = {
221   {PC_OPCODE, NULL, NULL, 0, NULL, 
222    //   genericAnalyze,
223    genericDestruct,
224    genericPrint},
225   POC_ADDWF,
226   "ADDWF",
227   2,
228   NULL, // from branch
229   NULL, // to branch
230   NULL, // label
231   NULL, // operand
232   NULL, // flow block
233   NULL, // C source 
234   3,    // num ops
235   1,0,  // dest, bit instruction
236   0,0,  // branch, skip
237   0,    // literal operand
238   1,    // RAM access bit
239   0,    // fast call/return mode select bit
240   0,    // second memory operand
241   0,    // second literal operand
242   POC_NOP,
243   (PCC_W | PCC_REGISTER),   // inCond
244   (PCC_REGISTER | PCC_STATUS), // outCond
245   PCI_MAGIC
246 };
247
248 pCodeInstruction pic16_pciADDFW = {
249   {PC_OPCODE, NULL, NULL, 0, NULL, 
250    //   genericAnalyze,
251    genericDestruct,
252    genericPrint},
253   POC_ADDFW,
254   "ADDWF",
255   2,
256   NULL, // from branch
257   NULL, // to branch
258   NULL, // label
259   NULL, // operand
260   NULL, // flow block
261   NULL, // C source 
262   3,    // num ops
263   0,0,  // dest, bit instruction
264   0,0,  // branch, skip
265   0,    // literal operand
266   1,    // RAM access bit
267   0,    // fast call/return mode select bit
268   0,    // second memory operand
269   0,    // second literal operand
270   POC_NOP,
271   (PCC_W | PCC_REGISTER),   // inCond
272   (PCC_W | PCC_STATUS), // outCond
273   PCI_MAGIC
274 };
275
276 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
277   {PC_OPCODE, NULL, NULL, 0, NULL, 
278    //   genericAnalyze,
279    genericDestruct,
280    genericPrint},
281   POC_ADDWFC,
282   "ADDWFC",
283   2,
284   NULL, // from branch
285   NULL, // to branch
286   NULL, // label
287   NULL, // operand
288   NULL, // flow block
289   NULL, // C source 
290   3,    // num ops
291   1,0,  // dest, bit instruction
292   0,0,  // branch, skip
293   0,    // literal operand
294   1,    // RAM access bit
295   0,    // fast call/return mode select bit
296   0,    // second memory operand
297   0,    // second literal operand
298   POC_NOP,
299   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
300   (PCC_REGISTER | PCC_STATUS), // outCond
301   PCI_MAGIC
302 };
303
304 pCodeInstruction pic16_pciADDFWC = {
305   {PC_OPCODE, NULL, NULL, 0, NULL, 
306    //   genericAnalyze,
307    genericDestruct,
308    genericPrint},
309   POC_ADDFWC,
310   "ADDWFC",
311   2,
312   NULL, // from branch
313   NULL, // to branch
314   NULL, // label
315   NULL, // operand
316   NULL, // flow block
317   NULL, // C source 
318   3,    // num ops
319   0,0,  // dest, bit instruction
320   0,0,  // branch, skip
321   0,    // literal operand
322   1,    // RAM access bit
323   0,    // fast call/return mode select bit
324   0,    // second memory operand
325   0,    // second literal operand
326   POC_NOP,
327   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
328   (PCC_W | PCC_STATUS), // outCond
329   PCI_MAGIC
330 };
331
332 pCodeInstruction pic16_pciADDLW = {
333   {PC_OPCODE, NULL, NULL, 0, NULL, 
334    //   genericAnalyze,
335    genericDestruct,
336    genericPrint},
337   POC_ADDLW,
338   "ADDLW",
339   2,
340   NULL, // from branch
341   NULL, // to branch
342   NULL, // label
343   NULL, // operand
344   NULL, // flow block
345   NULL, // C source 
346   1,    // num ops
347   0,0,  // dest, bit instruction
348   0,0,  // branch, skip
349   1,    // literal operand
350   0,    // RAM access bit
351   0,    // fast call/return mode select bit
352   0,    // second memory operand
353   0,    // second literal operand
354   POC_NOP,
355   (PCC_W | PCC_LITERAL),   // inCond
356   (PCC_W | PCC_STATUS), // outCond
357   PCI_MAGIC
358 };
359
360 pCodeInstruction pic16_pciANDLW = {
361   {PC_OPCODE, NULL, NULL, 0, NULL, 
362    //   genericAnalyze,
363    genericDestruct,
364    genericPrint},
365   POC_ANDLW,
366   "ANDLW",
367   2,
368   NULL, // from branch
369   NULL, // to branch
370   NULL, // label
371   NULL, // operand
372   NULL, // flow block
373   NULL, // C source 
374   1,    // num ops
375   0,0,  // dest, bit instruction
376   0,0,  // branch, skip
377   1,    // literal operand
378   0,    // RAM access bit
379   0,    // fast call/return mode select bit
380   0,    // second memory operand
381   0,    // second literal operand
382   POC_NOP,
383   (PCC_W | PCC_LITERAL),   // inCond
384   (PCC_W | PCC_Z | PCC_N), // outCond
385   PCI_MAGIC
386 };
387
388 pCodeInstruction pic16_pciANDWF = {
389   {PC_OPCODE, NULL, NULL, 0, NULL, 
390    //   genericAnalyze,
391    genericDestruct,
392    genericPrint},
393   POC_ANDWF,
394   "ANDWF",
395   2,
396   NULL, // from branch
397   NULL, // to branch
398   NULL, // label
399   NULL, // operand
400   NULL, // flow block
401   NULL, // C source 
402   3,    // num ops
403   1,0,  // dest, bit instruction
404   0,0,  // branch, skip
405   0,    // literal operand
406   1,    // RAM access bit
407   0,    // fast call/return mode select bit
408   0,    // second memory operand
409   0,    // second literal operand
410   POC_NOP,
411   (PCC_W | PCC_REGISTER),   // inCond
412   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
413   PCI_MAGIC
414 };
415
416 pCodeInstruction pic16_pciANDFW = {
417   {PC_OPCODE, NULL, NULL, 0, NULL, 
418    //   genericAnalyze,
419    genericDestruct,
420    genericPrint},
421   POC_ANDFW,
422   "ANDWF",
423   2,
424   NULL, // from branch
425   NULL, // to branch
426   NULL, // label
427   NULL, // operand
428   NULL, // flow block
429   NULL, // C source 
430   3,    // num ops
431   0,0,  // dest, bit instruction
432   0,0,  // branch, skip
433   0,    // literal operand
434   1,    // RAM access bit
435   0,    // fast call/return mode select bit
436   0,    // second memory operand
437   0,    // second literal operand
438   POC_NOP,
439   (PCC_W | PCC_REGISTER),   // inCond
440   (PCC_W | PCC_Z | PCC_N) // outCond
441 };
442
443 pCodeInstruction pic16_pciBC = { // mdubuc - New
444   {PC_OPCODE, NULL, NULL, 0, NULL, 
445    //   genericAnalyze,
446    genericDestruct,
447    genericPrint},
448   POC_BC,
449   "BC",
450   2,
451   NULL, // from branch
452   NULL, // to branch
453   NULL, // label
454   NULL, // operand
455   NULL, // flow block
456   NULL, // C source 
457   1,    // num ops
458   0,0,  // dest, bit instruction
459   1,0,  // branch, skip
460   0,    // literal operand
461   0,    // RAM access bit
462   0,    // fast call/return mode select bit
463   0,    // second memory operand
464   0,    // second literal operand
465   POC_NOP,
466   (PCC_REL_ADDR | PCC_C),   // inCond
467   PCC_NONE,    // outCond
468   PCI_MAGIC
469 };
470
471 pCodeInstruction pic16_pciBCF = {
472   {PC_OPCODE, NULL, NULL, 0, NULL, 
473    //   genericAnalyze,
474    genericDestruct,
475    genericPrint},
476   POC_BCF,
477   "BCF",
478   2,
479   NULL, // from branch
480   NULL, // to branch
481   NULL, // label
482   NULL, // operand
483   NULL, // flow block
484   NULL, // C source 
485   3,    // num ops
486   1,1,  // dest, bit instruction
487   0,0,  // branch, skip
488   0,    // literal operand
489   1,    // RAM access bit
490   0,    // fast call/return mode select bit
491   0,    // second memory operand
492   0,    // second literal operand
493   POC_BSF,
494   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
495   PCC_REGISTER, // outCond
496   PCI_MAGIC
497 };
498
499 pCodeInstruction pic16_pciBN = { // mdubuc - New
500   {PC_OPCODE, NULL, NULL, 0, NULL, 
501    //   genericAnalyze,
502    genericDestruct,
503    genericPrint},
504   POC_BN,
505   "BN",
506   2,
507   NULL, // from branch
508   NULL, // to branch
509   NULL, // label
510   NULL, // operand
511   NULL, // flow block
512   NULL, // C source 
513   1,    // num ops
514   0,0,  // dest, bit instruction
515   1,0,  // branch, skip
516   0,    // literal operand
517   0,    // RAM access bit
518   0,    // fast call/return mode select bit
519   0,    // second memory operand
520   0,    // second literal operand
521   POC_NOP,
522   (PCC_REL_ADDR | PCC_N),   // inCond
523   PCC_NONE   , // outCond
524   PCI_MAGIC
525 };
526
527 pCodeInstruction pic16_pciBNC = { // mdubuc - New
528   {PC_OPCODE, NULL, NULL, 0, NULL, 
529    //   genericAnalyze,
530    genericDestruct,
531    genericPrint},
532   POC_BNC,
533   "BNC",
534   2,
535   NULL, // from branch
536   NULL, // to branch
537   NULL, // label
538   NULL, // operand
539   NULL, // flow block
540   NULL, // C source 
541   1,    // num ops
542   0,0,  // dest, bit instruction
543   1,0,  // branch, skip
544   0,    // literal operand
545   0,    // RAM access bit
546   0,    // fast call/return mode select bit
547   0,    // second memory operand
548   0,    // second literal operand
549   POC_NOP,
550   (PCC_REL_ADDR | PCC_C),   // inCond
551   PCC_NONE   , // outCond
552   PCI_MAGIC
553 };
554
555 pCodeInstruction pic16_pciBNN = { // mdubuc - New
556   {PC_OPCODE, NULL, NULL, 0, NULL, 
557    //   genericAnalyze,
558    genericDestruct,
559    genericPrint},
560   POC_BNN,
561   "BNN",
562   2,
563   NULL, // from branch
564   NULL, // to branch
565   NULL, // label
566   NULL, // operand
567   NULL, // flow block
568   NULL, // C source 
569   1,    // num ops
570   0,0,  // dest, bit instruction
571   1,0,  // branch, skip
572   0,    // literal operand
573   0,    // RAM access bit
574   0,    // fast call/return mode select bit
575   0,    // second memory operand
576   0,    // second literal operand
577   POC_NOP,
578   (PCC_REL_ADDR | PCC_N),   // inCond
579   PCC_NONE   , // outCond
580   PCI_MAGIC
581 };
582
583 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
584   {PC_OPCODE, NULL, NULL, 0, NULL, 
585    //   genericAnalyze,
586    genericDestruct,
587    genericPrint},
588   POC_BNOV,
589   "BNOV",
590   2,
591   NULL, // from branch
592   NULL, // to branch
593   NULL, // label
594   NULL, // operand
595   NULL, // flow block
596   NULL, // C source 
597   1,    // num ops
598   0,0,  // dest, bit instruction
599   1,0,  // branch, skip
600   0,    // literal operand
601   0,    // RAM access bit
602   0,    // fast call/return mode select bit
603   0,    // second memory operand
604   0,    // second literal operand
605   POC_NOP,
606   (PCC_REL_ADDR | PCC_OV),   // inCond
607   PCC_NONE   , // outCond
608   PCI_MAGIC
609 };
610
611 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
612   {PC_OPCODE, NULL, NULL, 0, NULL, 
613    //   genericAnalyze,
614    genericDestruct,
615    genericPrint},
616   POC_BNZ,
617   "BNZ",
618   2,
619   NULL, // from branch
620   NULL, // to branch
621   NULL, // label
622   NULL, // operand
623   NULL, // flow block
624   NULL, // C source 
625   1,    // num ops
626   0,0,  // dest, bit instruction
627   1,0,  // branch, skip
628   0,    // literal operand
629   0,    // RAM access bit
630   0,    // fast call/return mode select bit
631   0,    // second memory operand
632   0,    // second literal operand
633   POC_NOP,
634   (PCC_REL_ADDR | PCC_Z),   // inCond
635   PCC_NONE   , // outCond
636   PCI_MAGIC
637 };
638
639 pCodeInstruction pic16_pciBOV = { // mdubuc - New
640   {PC_OPCODE, NULL, NULL, 0, NULL, 
641    //   genericAnalyze,
642    genericDestruct,
643    genericPrint},
644   POC_BOV,
645   "BOV",
646   2,
647   NULL, // from branch
648   NULL, // to branch
649   NULL, // label
650   NULL, // operand
651   NULL, // flow block
652   NULL, // C source 
653   1,    // num ops
654   0,0,  // dest, bit instruction
655   1,0,  // branch, skip
656   0,    // literal operand
657   0,    // RAM access bit
658   0,    // fast call/return mode select bit
659   0,    // second memory operand
660   0,    // second literal operand
661   POC_NOP,
662   (PCC_REL_ADDR | PCC_OV),   // inCond
663   PCC_NONE , // outCond
664   PCI_MAGIC
665 };
666
667 pCodeInstruction pic16_pciBRA = { // mdubuc - New
668   {PC_OPCODE, NULL, NULL, 0, NULL, 
669    //   genericAnalyze,
670    genericDestruct,
671    genericPrint},
672   POC_BRA,
673   "BRA",
674   2,
675   NULL, // from branch
676   NULL, // to branch
677   NULL, // label
678   NULL, // operand
679   NULL, // flow block
680   NULL, // C source 
681   1,    // num ops
682   0,0,  // dest, bit instruction
683   1,0,  // branch, skip
684   0,    // literal operand
685   0,    // RAM access bit
686   0,    // fast call/return mode select bit
687   0,    // second memory operand
688   0,    // second literal operand
689   POC_NOP,
690   PCC_REL_ADDR,   // inCond
691   PCC_NONE   , // outCond
692   PCI_MAGIC
693 };
694
695 pCodeInstruction pic16_pciBSF = {
696   {PC_OPCODE, NULL, NULL, 0, NULL, 
697    //   genericAnalyze,
698    genericDestruct,
699    genericPrint},
700   POC_BSF,
701   "BSF",
702   2,
703   NULL, // from branch
704   NULL, // to branch
705   NULL, // label
706   NULL, // operand
707   NULL, // flow block
708   NULL, // C source 
709   3,    // num ops
710   1,1,  // dest, bit instruction
711   0,0,  // branch, skip
712   0,    // literal operand
713   1,    // RAM access bit
714   0,    // fast call/return mode select bit
715   0,    // second memory operand
716   0,    // second literal operand
717   POC_BCF,
718   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
719   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
720   PCI_MAGIC
721 };
722
723 pCodeInstruction pic16_pciBTFSC = {
724   {PC_OPCODE, NULL, NULL, 0, NULL, 
725    //   AnalyzeSKIP,
726    genericDestruct,
727    genericPrint},
728   POC_BTFSC,
729   "BTFSC",
730   2,
731   NULL, // from branch
732   NULL, // to branch
733   NULL, // label
734   NULL, // operand
735   NULL, // flow block
736   NULL, // C source 
737   3,    // num ops
738   0,1,  // dest, bit instruction
739   1,1,  // branch, skip
740   0,    // literal operand
741   1,    // RAM access bit
742   0,    // fast call/return mode select bit
743   0,    // second memory operand
744   0,    // second literal operand
745   POC_BTFSS,
746   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
747   PCC_EXAMINE_PCOP, // outCond
748   PCI_MAGIC
749 };
750
751 pCodeInstruction pic16_pciBTFSS = {
752   {PC_OPCODE, NULL, NULL, 0, NULL, 
753    //   AnalyzeSKIP,
754    genericDestruct,
755    genericPrint},
756   POC_BTFSS,
757   "BTFSS",
758   2,
759   NULL, // from branch
760   NULL, // to branch
761   NULL, // label
762   NULL, // operand
763   NULL, // flow block
764   NULL, // C source 
765   3,    // num ops
766   0,1,  // dest, bit instruction
767   1,1,  // branch, skip
768   0,    // literal operand
769   1,    // RAM access bit
770   0,    // fast call/return mode select bit
771   0,    // second memory operand
772   0,    // second literal operand
773   POC_BTFSC,
774   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
775   PCC_EXAMINE_PCOP, // outCond
776   PCI_MAGIC
777 };
778
779 pCodeInstruction pic16_pciBTG = { // mdubuc - New
780   {PC_OPCODE, NULL, NULL, 0, NULL, 
781    //   genericAnalyze,
782    genericDestruct,
783    genericPrint},
784   POC_BTG,
785   "BTG",
786   2,
787   NULL, // from branch
788   NULL, // to branch
789   NULL, // label
790   NULL, // operand
791   NULL, // flow block
792   NULL, // C source 
793   3,    // num ops
794   0,1,  // dest, bit instruction
795   0,0,  // branch, skip
796   0,    // literal operand
797   1,    // RAM access bit
798   0,    // fast call/return mode select bit
799   0,    // second memory operand
800   0,    // second literal operand
801   POC_NOP,
802   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
803   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
804   PCI_MAGIC
805 };
806
807 pCodeInstruction pic16_pciBZ = { // mdubuc - New
808   {PC_OPCODE, NULL, NULL, 0, NULL, 
809    //   genericAnalyze,
810    genericDestruct,
811    genericPrint},
812   POC_BZ,
813   "BZ",
814   2,
815   NULL, // from branch
816   NULL, // to branch
817   NULL, // label
818   NULL, // operand
819   NULL, // flow block
820   NULL, // C source 
821   1,    // num ops
822   0,0,  // dest, bit instruction
823   1,0,  // branch, skip
824   0,    // literal operand
825   0,    // RAM access bit
826   0,    // fast call/return mode select bit
827   0,    // second memory operand
828   0,    // second literal operand
829   POC_NOP,
830   (PCC_REL_ADDR | PCC_Z),   // inCond
831   PCC_NONE, // outCond
832   PCI_MAGIC
833 };
834
835 pCodeInstruction pic16_pciCALL = {
836   {PC_OPCODE, NULL, NULL, 0, NULL, 
837    //   genericAnalyze,
838    genericDestruct,
839    genericPrint},
840   POC_CALL,
841   "CALL",
842   4,
843   NULL, // from branch
844   NULL, // to branch
845   NULL, // label
846   NULL, // operand
847   NULL, // flow block
848   NULL, // C source 
849   2,    // num ops
850   0,0,  // dest, bit instruction
851   1,0,  // branch, skip
852   0,    // literal operand
853   0,    // RAM access bit
854   1,    // fast call/return mode select bit
855   0,    // second memory operand
856   0,    // second literal operand
857   POC_NOP,
858   PCC_NONE, // inCond
859   PCC_NONE, // outCond
860   PCI_MAGIC
861 };
862
863 pCodeInstruction pic16_pciCOMF = {
864   {PC_OPCODE, NULL, NULL, 0, NULL, 
865    //   genericAnalyze,
866    genericDestruct,
867    genericPrint},
868   POC_COMF,
869   "COMF",
870   2,
871   NULL, // from branch
872   NULL, // to branch
873   NULL, // label
874   NULL, // operand
875   NULL, // flow block
876   NULL, // C source 
877   3,    // num ops
878   1,0,  // dest, bit instruction
879   0,0,  // branch, skip
880   0,    // literal operand
881   1,    // RAM access bit
882   0,    // fast call/return mode select bit
883   0,    // second memory operand
884   0,    // second literal operand
885   POC_NOP,
886   PCC_REGISTER,  // inCond
887   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
888   PCI_MAGIC
889 };
890
891 pCodeInstruction pic16_pciCOMFW = {
892   {PC_OPCODE, NULL, NULL, 0, NULL, 
893    //   genericAnalyze,
894    genericDestruct,
895    genericPrint},
896   POC_COMFW,
897   "COMF",
898   2,
899   NULL, // from branch
900   NULL, // to branch
901   NULL, // label
902   NULL, // operand
903   NULL, // flow block
904   NULL, // C source 
905   3,    // num ops
906   0,0,  // dest, bit instruction
907   0,0,  // branch, skip
908   0,    // literal operand
909   1,    // RAM access bit
910   0,    // fast call/return mode select bit
911   0,    // second memory operand
912   0,    // second literal operand
913   POC_NOP,
914   PCC_REGISTER,  // inCond
915   (PCC_W | PCC_Z | PCC_N) , // outCond
916   PCI_MAGIC
917 };
918
919 pCodeInstruction pic16_pciCLRF = {
920   {PC_OPCODE, NULL, NULL, 0, NULL, 
921    //   genericAnalyze,
922    genericDestruct,
923    genericPrint},
924   POC_CLRF,
925   "CLRF",
926   2,
927   NULL, // from branch
928   NULL, // to branch
929   NULL, // label
930   NULL, // operand
931   NULL, // flow block
932   NULL, // C source 
933   2,    // num ops
934   0,0,  // dest, bit instruction
935   0,0,  // branch, skip
936   0,    // literal operand
937   1,    // RAM access bit
938   0,    // fast call/return mode select bit
939   0,    // second memory operand
940   0,    // second literal operand
941   POC_NOP,
942   PCC_NONE, // inCond
943   (PCC_REGISTER | PCC_Z), // outCond
944   PCI_MAGIC
945 };
946
947 pCodeInstruction pic16_pciCLRWDT = {
948   {PC_OPCODE, NULL, NULL, 0, NULL, 
949    //   genericAnalyze,
950    genericDestruct,
951    genericPrint},
952   POC_CLRWDT,
953   "CLRWDT",
954   2,
955   NULL, // from branch
956   NULL, // to branch
957   NULL, // label
958   NULL, // operand
959   NULL, // flow block
960   NULL, // C source 
961   0,    // num ops
962   0,0,  // dest, bit instruction
963   0,0,  // branch, skip
964   0,    // literal operand
965   0,    // RAM access bit
966   0,    // fast call/return mode select bit
967   0,    // second memory operand
968   0,    // second literal operand
969   POC_NOP,
970   PCC_NONE, // inCond
971   PCC_NONE , // outCond
972   PCI_MAGIC
973 };
974
975 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
976   {PC_OPCODE, NULL, NULL, 0, NULL, 
977    //   genericAnalyze,
978    genericDestruct,
979    genericPrint},
980   POC_CPFSEQ,
981   "CPFSEQ",
982   2,
983   NULL, // from branch
984   NULL, // to branch
985   NULL, // label
986   NULL, // operand
987   NULL, // flow block
988   NULL, // C source 
989   2,    // num ops
990   0,0,  // dest, bit instruction
991   1,1,  // branch, skip
992   0,    // literal operand
993   1,    // RAM access bit
994   0,    // fast call/return mode select bit
995   0,    // second memory operand
996   0,    // second literal operand
997   POC_NOP,
998   (PCC_W | PCC_REGISTER), // inCond
999   PCC_NONE , // outCond
1000   PCI_MAGIC
1001 };
1002
1003 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1004   {PC_OPCODE, NULL, NULL, 0, NULL, 
1005    //   genericAnalyze,
1006    genericDestruct,
1007    genericPrint},
1008   POC_CPFSGT,
1009   "CPFSGT",
1010   2,
1011   NULL, // from branch
1012   NULL, // to branch
1013   NULL, // label
1014   NULL, // operand
1015   NULL, // flow block
1016   NULL, // C source 
1017   2,    // num ops
1018   0,0,  // dest, bit instruction
1019   1,1,  // branch, skip
1020   0,    // literal operand
1021   1,    // RAM access bit
1022   0,    // fast call/return mode select bit
1023   0,    // second memory operand
1024   0,    // second literal operand
1025   POC_NOP,
1026   (PCC_W | PCC_REGISTER), // inCond
1027   PCC_NONE , // outCond
1028   PCI_MAGIC
1029 };
1030
1031 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1032   {PC_OPCODE, NULL, NULL, 0, NULL, 
1033    //   genericAnalyze,
1034    genericDestruct,
1035    genericPrint},
1036   POC_CPFSLT,
1037   "CPFSLT",
1038   2,
1039   NULL, // from branch
1040   NULL, // to branch
1041   NULL, // label
1042   NULL, // operand
1043   NULL, // flow block
1044   NULL, // C source 
1045   2,    // num ops
1046   1,0,  // dest, bit instruction
1047   1,1,  // branch, skip
1048   0,    // literal operand
1049   1,    // RAM access bit
1050   0,    // fast call/return mode select bit
1051   0,    // second memory operand
1052   0,    // second literal operand
1053   POC_NOP,
1054   (PCC_W | PCC_REGISTER), // inCond
1055   PCC_NONE , // outCond
1056   PCI_MAGIC
1057 };
1058
1059 pCodeInstruction pic16_pciDAW = {
1060   {PC_OPCODE, NULL, NULL, 0, NULL, 
1061    //   genericAnalyze,
1062    genericDestruct,
1063    genericPrint},
1064   POC_DAW,
1065   "DAW",
1066   2,
1067   NULL, // from branch
1068   NULL, // to branch
1069   NULL, // label
1070   NULL, // operand
1071   NULL, // flow block
1072   NULL, // C source 
1073   0,    // num ops
1074   0,0,  // dest, bit instruction
1075   0,0,  // branch, skip
1076   0,    // literal operand
1077   0,    // RAM access bit
1078   0,    // fast call/return mode select bit
1079   0,    // second memory operand
1080   0,    // second literal operand
1081   POC_NOP,
1082   PCC_W, // inCond
1083   (PCC_W | PCC_C), // outCond
1084   PCI_MAGIC
1085 };
1086
1087 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1088   {PC_OPCODE, NULL, NULL, 0, NULL, 
1089    //   genericAnalyze,
1090    genericDestruct,
1091    genericPrint},
1092   POC_DCFSNZ,
1093   "DCFSNZ",
1094   2,
1095   NULL, // from branch
1096   NULL, // to branch
1097   NULL, // label
1098   NULL, // operand
1099   NULL, // flow block
1100   NULL, // C source 
1101   3,    // num ops
1102   1,0,  // dest, bit instruction
1103   1,1,  // branch, skip
1104   0,    // literal operand
1105   1,    // RAM access bit
1106   0,    // fast call/return mode select bit
1107   0,    // second memory operand
1108   0,    // second literal operand
1109   POC_NOP,
1110   PCC_REGISTER, // inCond
1111   PCC_REGISTER , // outCond
1112   PCI_MAGIC
1113 };
1114
1115 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1116   {PC_OPCODE, NULL, NULL, 0, NULL, 
1117    //   genericAnalyze,
1118    genericDestruct,
1119    genericPrint},
1120   POC_DCFSNZW,
1121   "DCFSNZ",
1122   2,
1123   NULL, // from branch
1124   NULL, // to branch
1125   NULL, // label
1126   NULL, // operand
1127   NULL, // flow block
1128   NULL, // C source 
1129   3,    // num ops
1130   0,0,  // dest, bit instruction
1131   1,1,  // branch, skip
1132   0,    // literal operand
1133   1,    // RAM access bit
1134   0,    // fast call/return mode select bit
1135   0,    // second memory operand
1136   0,    // second literal operand
1137   POC_NOP,
1138   PCC_REGISTER, // inCond
1139   PCC_W , // outCond
1140   PCI_MAGIC
1141 };
1142
1143 pCodeInstruction pic16_pciDECF = {
1144   {PC_OPCODE, NULL, NULL, 0, NULL, 
1145    //   genericAnalyze,
1146    genericDestruct,
1147    genericPrint},
1148   POC_DECF,
1149   "DECF",
1150   2,
1151   NULL, // from branch
1152   NULL, // to branch
1153   NULL, // label
1154   NULL, // operand
1155   NULL, // flow block
1156   NULL, // C source 
1157   3,    // num ops
1158   1,0,  // dest, bit instruction
1159   0,0,  // branch, skip
1160   0,    // literal operand
1161   1,    // RAM access bit
1162   0,    // fast call/return mode select bit
1163   0,    // second memory operand
1164   0,    // second literal operand
1165   POC_NOP,
1166   PCC_REGISTER,   // inCond
1167   (PCC_REGISTER | PCC_STATUS)  , // outCond
1168   PCI_MAGIC
1169 };
1170
1171 pCodeInstruction pic16_pciDECFW = {
1172   {PC_OPCODE, NULL, NULL, 0, NULL, 
1173    //   genericAnalyze,
1174    genericDestruct,
1175    genericPrint},
1176   POC_DECFW,
1177   "DECF",
1178   2,
1179   NULL, // from branch
1180   NULL, // to branch
1181   NULL, // label
1182   NULL, // operand
1183   NULL, // flow block
1184   NULL, // C source 
1185   3,    // num ops
1186   0,0,  // dest, bit instruction
1187   0,0,  // branch, skip
1188   0,    // literal operand
1189   1,    // RAM access bit
1190   0,    // fast call/return mode select bit
1191   0,    // second memory operand
1192   0,    // second literal operand
1193   POC_NOP,
1194   PCC_REGISTER,   // inCond
1195   (PCC_W | PCC_STATUS)  , // outCond
1196   PCI_MAGIC
1197 };
1198
1199 pCodeInstruction pic16_pciDECFSZ = {
1200   {PC_OPCODE, NULL, NULL, 0, NULL, 
1201    //   AnalyzeSKIP,
1202    genericDestruct,
1203    genericPrint},
1204   POC_DECFSZ,
1205   "DECFSZ",
1206   2,
1207   NULL, // from branch
1208   NULL, // to branch
1209   NULL, // label
1210   NULL, // operand
1211   NULL, // flow block
1212   NULL, // C source 
1213   3,    // num ops
1214   1,0,  // dest, bit instruction
1215   1,1,  // branch, skip
1216   0,    // literal operand
1217   1,    // RAM access bit
1218   0,    // fast call/return mode select bit
1219   0,    // second memory operand
1220   0,    // second literal operand
1221   POC_NOP,
1222   PCC_REGISTER,   // inCond
1223   PCC_REGISTER   , // outCond
1224   PCI_MAGIC
1225 };
1226
1227 pCodeInstruction pic16_pciDECFSZW = {
1228   {PC_OPCODE, NULL, NULL, 0, NULL, 
1229    //   AnalyzeSKIP,
1230    genericDestruct,
1231    genericPrint},
1232   POC_DECFSZW,
1233   "DECFSZ",
1234   2,
1235   NULL, // from branch
1236   NULL, // to branch
1237   NULL, // label
1238   NULL, // operand
1239   NULL, // flow block
1240   NULL, // C source 
1241   3,    // num ops
1242   0,0,  // dest, bit instruction
1243   1,1,  // branch, skip
1244   0,    // literal operand
1245   1,    // RAM access bit
1246   0,    // fast call/return mode select bit
1247   0,    // second memory operand
1248   0,    // second literal operand
1249   POC_NOP,
1250   PCC_REGISTER,   // inCond
1251   PCC_W          , // outCond
1252   PCI_MAGIC
1253 };
1254
1255 pCodeInstruction pic16_pciGOTO = {
1256   {PC_OPCODE, NULL, NULL, 0, NULL, 
1257    //   AnalyzeGOTO,
1258    genericDestruct,
1259    genericPrint},
1260   POC_GOTO,
1261   "GOTO",
1262   4,
1263   NULL, // from branch
1264   NULL, // to branch
1265   NULL, // label
1266   NULL, // operand
1267   NULL, // flow block
1268   NULL, // C source 
1269   1,    // num ops
1270   0,0,  // dest, bit instruction
1271   1,0,  // branch, skip
1272   0,    // literal operand
1273   0,    // RAM access bit
1274   0,    // fast call/return mode select bit
1275   0,    // second memory operand
1276   0,    // second literal operand
1277   POC_NOP,
1278   PCC_REL_ADDR,   // inCond
1279   PCC_NONE   , // outCond
1280   PCI_MAGIC
1281 };
1282
1283 pCodeInstruction pic16_pciINCF = {
1284   {PC_OPCODE, NULL, NULL, 0, NULL, 
1285    //   genericAnalyze,
1286    genericDestruct,
1287    genericPrint},
1288   POC_INCF,
1289   "INCF",
1290   2,
1291   NULL, // from branch
1292   NULL, // to branch
1293   NULL, // label
1294   NULL, // operand
1295   NULL, // flow block
1296   NULL, // C source 
1297   3,    // num ops
1298   1,0,  // dest, bit instruction
1299   0,0,  // branch, skip
1300   0,    // literal operand
1301   1,    // RAM access bit
1302   0,    // fast call/return mode select bit
1303   0,    // second memory operand
1304   0,    // second literal operand
1305   POC_NOP,
1306   PCC_REGISTER,   // inCond
1307   (PCC_REGISTER | PCC_STATUS), // outCond
1308   PCI_MAGIC
1309 };
1310
1311 pCodeInstruction pic16_pciINCFW = {
1312   {PC_OPCODE, NULL, NULL, 0, NULL, 
1313    //   genericAnalyze,
1314    genericDestruct,
1315    genericPrint},
1316   POC_INCFW,
1317   "INCF",
1318   2,
1319   NULL, // from branch
1320   NULL, // to branch
1321   NULL, // label
1322   NULL, // operand
1323   NULL, // flow block
1324   NULL, // C source 
1325   3,    // num ops
1326   0,0,  // dest, bit instruction
1327   0,0,  // branch, skip
1328   0,    // literal operand
1329   1,    // RAM access bit
1330   0,    // fast call/return mode select bit
1331   0,    // second memory operand
1332   0,    // second literal operand
1333   POC_NOP,
1334   PCC_REGISTER,   // inCond
1335   (PCC_W | PCC_STATUS)  , // outCond
1336   PCI_MAGIC
1337 };
1338
1339 pCodeInstruction pic16_pciINCFSZ = {
1340   {PC_OPCODE, NULL, NULL, 0, NULL, 
1341    //   AnalyzeSKIP,
1342    genericDestruct,
1343    genericPrint},
1344   POC_INCFSZ,
1345   "INCFSZ",
1346   2,
1347   NULL, // from branch
1348   NULL, // to branch
1349   NULL, // label
1350   NULL, // operand
1351   NULL, // flow block
1352   NULL, // C source 
1353   3,    // num ops
1354   1,0,  // dest, bit instruction
1355   1,1,  // branch, skip
1356   0,    // literal operand
1357   1,    // RAM access bit
1358   0,    // fast call/return mode select bit
1359   0,    // second memory operand
1360   0,    // second literal operand
1361   POC_INFSNZ,
1362   PCC_REGISTER,   // inCond
1363   PCC_REGISTER   , // outCond
1364   PCI_MAGIC
1365 };
1366
1367 pCodeInstruction pic16_pciINCFSZW = {
1368   {PC_OPCODE, NULL, NULL, 0, NULL, 
1369    //   AnalyzeSKIP,
1370    genericDestruct,
1371    genericPrint},
1372   POC_INCFSZW,
1373   "INCFSZ",
1374   2,
1375   NULL, // from branch
1376   NULL, // to branch
1377   NULL, // label
1378   NULL, // operand
1379   NULL, // flow block
1380   NULL, // C source 
1381   3,    // num ops
1382   0,0,  // dest, bit instruction
1383   1,1,  // branch, skip
1384   0,    // literal operand
1385   1,    // RAM access bit
1386   0,    // fast call/return mode select bit
1387   0,    // second memory operand
1388   0,    // second literal operand
1389   POC_INFSNZW,
1390   PCC_REGISTER,   // inCond
1391   PCC_W          , // outCond
1392   PCI_MAGIC
1393 };
1394
1395 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1396   {PC_OPCODE, NULL, NULL, 0, NULL, 
1397    //   AnalyzeSKIP,
1398    genericDestruct,
1399    genericPrint},
1400   POC_INFSNZ,
1401   "INFSNZ",
1402   2,
1403   NULL, // from branch
1404   NULL, // to branch
1405   NULL, // label
1406   NULL, // operand
1407   NULL, // flow block
1408   NULL, // C source 
1409   3,    // num ops
1410   1,0,  // dest, bit instruction
1411   1,1,  // branch, skip
1412   0,    // literal operand
1413   1,    // RAM access bit
1414   0,    // fast call/return mode select bit
1415   0,    // second memory operand
1416   0,    // second literal operand
1417   POC_INCFSZ,
1418   PCC_REGISTER,   // inCond
1419   PCC_REGISTER   , // outCond
1420   PCI_MAGIC
1421 };
1422
1423 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1424   {PC_OPCODE, NULL, NULL, 0, NULL, 
1425    //   AnalyzeSKIP,
1426    genericDestruct,
1427    genericPrint},
1428   POC_INFSNZW,
1429   "INFSNZ",
1430   2,
1431   NULL, // from branch
1432   NULL, // to branch
1433   NULL, // label
1434   NULL, // operand
1435   NULL, // flow block
1436   NULL, // C source 
1437   3,    // num ops
1438   0,0,  // dest, bit instruction
1439   1,1,  // branch, skip
1440   0,    // literal operand
1441   1,    // RAM access bit
1442   0,    // fast call/return mode select bit
1443   0,    // second memory operand
1444   0,    // second literal operand
1445   POC_INCFSZW,
1446   PCC_REGISTER,   // inCond
1447   PCC_W          , // outCond
1448   PCI_MAGIC
1449 };
1450
1451 pCodeInstruction pic16_pciIORWF = {
1452   {PC_OPCODE, NULL, NULL, 0, NULL, 
1453    //   genericAnalyze,
1454    genericDestruct,
1455    genericPrint},
1456   POC_IORWF,
1457   "IORWF",
1458   2,
1459   NULL, // from branch
1460   NULL, // to branch
1461   NULL, // label
1462   NULL, // operand
1463   NULL, // flow block
1464   NULL, // C source 
1465   3,    // num ops
1466   1,0,  // dest, bit instruction
1467   0,0,  // branch, skip
1468   0,    // literal operand
1469   1,    // RAM access bit
1470   0,    // fast call/return mode select bit
1471   0,    // second memory operand
1472   0,    // second literal operand
1473   POC_NOP,
1474   (PCC_W | PCC_REGISTER),   // inCond
1475   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1476   PCI_MAGIC
1477 };
1478
1479 pCodeInstruction pic16_pciIORFW = {
1480   {PC_OPCODE, NULL, NULL, 0, NULL, 
1481    //   genericAnalyze,
1482    genericDestruct,
1483    genericPrint},
1484   POC_IORFW,
1485   "IORWF",
1486   2,
1487   NULL, // from branch
1488   NULL, // to branch
1489   NULL, // label
1490   NULL, // operand
1491   NULL, // flow block
1492   NULL, // C source 
1493   3,    // num ops
1494   0,0,  // dest, bit instruction
1495   0,0,  // branch, skip
1496   0,    // literal operand
1497   1,    // RAM access bit
1498   0,    // fast call/return mode select bit
1499   0,    // second memory operand
1500   0,    // second literal operand
1501   POC_NOP,
1502   (PCC_W | PCC_REGISTER),   // inCond
1503   (PCC_W | PCC_Z | PCC_N), // outCond
1504   PCI_MAGIC
1505 };
1506
1507 pCodeInstruction pic16_pciIORLW = {
1508   {PC_OPCODE, NULL, NULL, 0, NULL, 
1509    //   genericAnalyze,
1510    genericDestruct,
1511    genericPrint},
1512   POC_IORLW,
1513   "IORLW",
1514   2,
1515   NULL, // from branch
1516   NULL, // to branch
1517   NULL, // label
1518   NULL, // operand
1519   NULL, // flow block
1520   NULL, // C source 
1521   1,    // num ops
1522   0,0,  // dest, bit instruction
1523   0,0,  // branch, skip
1524   1,    // literal operand
1525   0,    // RAM access bit
1526   0,    // fast call/return mode select bit
1527   0,    // second memory operand
1528   0,    // second literal operand
1529   POC_NOP,
1530   (PCC_W | PCC_LITERAL),   // inCond
1531   (PCC_W | PCC_Z | PCC_N), // outCond
1532   PCI_MAGIC
1533 };
1534
1535 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1536   {PC_OPCODE, NULL, NULL, 0, NULL, 
1537    //   genericAnalyze,
1538    genericDestruct,
1539    genericPrint},
1540   POC_LFSR,
1541   "LFSR",
1542   4,
1543   NULL, // from branch
1544   NULL, // to branch
1545   NULL, // label
1546   NULL, // operand
1547   NULL, // flow block
1548   NULL, // C source 
1549   2,    // num ops
1550   0,0,  // dest, bit instruction
1551   0,0,  // branch, skip
1552   1,    // literal operand
1553   0,    // RAM access bit
1554   0,    // fast call/return mode select bit
1555   0,    // second memory operand
1556   1,    // second literal operand
1557   POC_NOP,
1558   PCC_LITERAL, // inCond
1559   PCC_NONE, // outCond
1560   PCI_MAGIC
1561 };
1562
1563 pCodeInstruction pic16_pciMOVF = {
1564   {PC_OPCODE, NULL, NULL, 0, NULL, 
1565    //   genericAnalyze,
1566    genericDestruct,
1567    genericPrint},
1568   POC_MOVF,
1569   "MOVF",
1570   2,
1571   NULL, // from branch
1572   NULL, // to branch
1573   NULL, // label
1574   NULL, // operand
1575   NULL, // flow block
1576   NULL, // C source 
1577   3,    // num ops
1578   1,0,  // dest, bit instruction
1579   0,0,  // branch, skip
1580   0,    // literal operand
1581   1,    // RAM access bit
1582   0,    // fast call/return mode select bit
1583   0,    // second memory operand
1584   0,    // second literal operand
1585   POC_NOP,
1586   PCC_REGISTER,   // inCond
1587   (PCC_Z | PCC_N), // outCond
1588   PCI_MAGIC
1589 };
1590
1591 pCodeInstruction pic16_pciMOVFW = {
1592   {PC_OPCODE, NULL, NULL, 0, NULL, 
1593    //   genericAnalyze,
1594    genericDestruct,
1595    genericPrint},
1596   POC_MOVFW,
1597   "MOVF",
1598   2,
1599   NULL, // from branch
1600   NULL, // to branch
1601   NULL, // label
1602   NULL, // operand
1603   NULL, // flow block
1604   NULL, // C source 
1605   3,    // num ops
1606   0,0,  // dest, bit instruction
1607   0,0,  // branch, skip
1608   0,    // literal operand
1609   1,    // RAM access bit
1610   0,    // fast call/return mode select bit
1611   0,    // second memory operand
1612   0,    // second literal operand
1613   POC_NOP,
1614   PCC_REGISTER,   // inCond
1615   (PCC_W | PCC_N | PCC_Z), // outCond
1616   PCI_MAGIC
1617 };
1618
1619 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1620   {PC_OPCODE, NULL, NULL, 0, NULL, 
1621    //   genericAnalyze,
1622    genericDestruct,
1623    genericPrint},
1624   POC_MOVFF,
1625   "MOVFF",
1626   4,
1627   NULL, // from branch
1628   NULL, // to branch
1629   NULL, // label
1630   NULL, // operand
1631   NULL, // flow block
1632   NULL, // C source 
1633   2,    // num ops
1634   0,0,  // dest, bit instruction
1635   0,0,  // branch, skip
1636   0,    // literal operand
1637   0,    // RAM access bit
1638   0,    // fast call/return mode select bit
1639   1,    // second memory operand
1640   0,    // second literal operand
1641   POC_NOP,
1642   PCC_REGISTER,   // inCond
1643   PCC_REGISTER2, // outCond
1644   PCI_MAGIC
1645 };
1646
1647 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1648   {PC_OPCODE, NULL, NULL, 0, NULL, 
1649    genericDestruct,
1650    genericPrint},
1651   POC_MOVLB,
1652   "MOVLB",
1653   2,
1654   NULL, // from branch
1655   NULL, // to branch
1656   NULL, // label
1657   NULL, // operand
1658   NULL, // flow block
1659   NULL, // C source 
1660   1,    // num ops
1661   0,0,  // dest, bit instruction
1662   0,0,  // branch, skip
1663   1,    // literal operand
1664   0,    // RAM access bit
1665   0,    // fast call/return mode select bit
1666   0,    // second memory operand
1667   0,    // second literal operand
1668   POC_NOP,
1669   (PCC_NONE | PCC_LITERAL),   // inCond
1670   PCC_REGISTER, // outCond - BSR
1671   PCI_MAGIC
1672 };
1673
1674 pCodeInstruction pic16_pciMOVLW = {
1675   {PC_OPCODE, NULL, NULL, 0, NULL, 
1676    genericDestruct,
1677    genericPrint},
1678   POC_MOVLW,
1679   "MOVLW",
1680   2,
1681   NULL, // from branch
1682   NULL, // to branch
1683   NULL, // label
1684   NULL, // operand
1685   NULL, // flow block
1686   NULL, // C source 
1687   1,    // num ops
1688   0,0,  // dest, bit instruction
1689   0,0,  // branch, skip
1690   1,    // literal operand
1691   0,    // RAM access bit
1692   0,    // fast call/return mode select bit
1693   0,    // second memory operand
1694   0,    // second literal operand
1695   POC_NOP,
1696   (PCC_NONE | PCC_LITERAL),   // inCond
1697   PCC_W, // outCond
1698   PCI_MAGIC
1699 };
1700
1701 pCodeInstruction pic16_pciMOVWF = {
1702   {PC_OPCODE, NULL, NULL, 0, NULL, 
1703    //   genericAnalyze,
1704    genericDestruct,
1705    genericPrint},
1706   POC_MOVWF,
1707   "MOVWF",
1708   2,
1709   NULL, // from branch
1710   NULL, // to branch
1711   NULL, // label
1712   NULL, // operand
1713   NULL, // flow block
1714   NULL, // C source 
1715   2,    // num ops
1716   0,0,  // dest, bit instruction
1717   0,0,  // branch, skip
1718   0,    // literal operand
1719   1,    // RAM access bit
1720   0,    // fast call/return mode select bit
1721   0,    // second memory operand
1722   0,    // second literal operand
1723   POC_NOP,
1724   PCC_W,   // inCond
1725   PCC_REGISTER, // outCond
1726   PCI_MAGIC
1727 };
1728
1729 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1730   {PC_OPCODE, NULL, NULL, 0, NULL, 
1731    genericDestruct,
1732    genericPrint},
1733   POC_MULLW,
1734   "MULLW",
1735   2,
1736   NULL, // from branch
1737   NULL, // to branch
1738   NULL, // label
1739   NULL, // operand
1740   NULL, // flow block
1741   NULL, // C source 
1742   1,    // num ops
1743   0,0,  // dest, bit instruction
1744   0,0,  // branch, skip
1745   1,    // literal operand
1746   0,    // RAM access bit
1747   0,    // fast call/return mode select bit
1748   0,    // second memory operand
1749   0,    // second literal operand
1750   POC_NOP,
1751   (PCC_W | PCC_LITERAL),   // inCond
1752   PCC_NONE, // outCond - PROD
1753   PCI_MAGIC
1754 };
1755
1756 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1757   {PC_OPCODE, NULL, NULL, 0, NULL, 
1758    genericDestruct,
1759    genericPrint},
1760   POC_MULWF,
1761   "MULWF",
1762   2,
1763   NULL, // from branch
1764   NULL, // to branch
1765   NULL, // label
1766   NULL, // operand
1767   NULL, // flow block
1768   NULL, // C source 
1769   2,    // num ops
1770   0,0,  // dest, bit instruction
1771   0,0,  // branch, skip
1772   0,    // literal operand
1773   1,    // RAM access bit
1774   0,    // fast call/return mode select bit
1775   0,    // second memory operand
1776   0,    // second literal operand
1777   POC_NOP,
1778   (PCC_W | PCC_REGISTER),   // inCond
1779   PCC_REGISTER, // outCond - PROD
1780   PCI_MAGIC
1781 };
1782
1783 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1784   {PC_OPCODE, NULL, NULL, 0, NULL, 
1785    genericDestruct,
1786    genericPrint},
1787   POC_NEGF,
1788   "NEGF",
1789   2,
1790   NULL, // from branch
1791   NULL, // to branch
1792   NULL, // label
1793   NULL, // operand
1794   NULL, // flow block
1795   NULL, // C source 
1796   2,    // num ops
1797   0,0,  // dest, bit instruction
1798   0,0,  // branch, skip
1799   0,    // literal operand
1800   1,    // RAM access bit
1801   0,    // fast call/return mode select bit
1802   0,    // second memory operand
1803   0,    // second literal operand
1804   POC_NOP,
1805   PCC_REGISTER, // inCond
1806   (PCC_REGISTER | PCC_STATUS), // outCond
1807   PCI_MAGIC
1808 };
1809
1810 pCodeInstruction pic16_pciNOP = {
1811   {PC_OPCODE, NULL, NULL, 0, NULL, 
1812    genericDestruct,
1813    genericPrint},
1814   POC_NOP,
1815   "NOP",
1816   2,
1817   NULL, // from branch
1818   NULL, // to branch
1819   NULL, // label
1820   NULL, // operand
1821   NULL, // flow block
1822   NULL, // C source 
1823   0,    // num ops
1824   0,0,  // dest, bit instruction
1825   0,0,  // branch, skip
1826   0,    // literal operand
1827   0,    // RAM access bit
1828   0,    // fast call/return mode select bit
1829   0,    // second memory operand
1830   0,    // second literal operand
1831   POC_NOP,
1832   PCC_NONE,   // inCond
1833   PCC_NONE, // outCond
1834   PCI_MAGIC
1835 };
1836
1837 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1838   {PC_OPCODE, NULL, NULL, 0, NULL, 
1839    genericDestruct,
1840    genericPrint},
1841   POC_POP,
1842   "POP",
1843   2,
1844   NULL, // from branch
1845   NULL, // to branch
1846   NULL, // label
1847   NULL, // operand
1848   NULL, // flow block
1849   NULL, // C source 
1850   0,    // num ops
1851   0,0,  // dest, bit instruction
1852   0,0,  // branch, skip
1853   0,    // literal operand
1854   0,    // RAM access bit
1855   0,    // fast call/return mode select bit
1856   0,    // second memory operand
1857   0,    // second literal operand
1858   POC_NOP,
1859   PCC_NONE,  // inCond
1860   PCC_NONE  , // outCond
1861   PCI_MAGIC
1862 };
1863
1864 pCodeInstruction pic16_pciPUSH = {
1865   {PC_OPCODE, NULL, NULL, 0, NULL, 
1866    genericDestruct,
1867    genericPrint},
1868   POC_PUSH,
1869   "PUSH",
1870   2,
1871   NULL, // from branch
1872   NULL, // to branch
1873   NULL, // label
1874   NULL, // operand
1875   NULL, // flow block
1876   NULL, // C source 
1877   0,    // num ops
1878   0,0,  // dest, bit instruction
1879   0,0,  // branch, skip
1880   0,    // literal operand
1881   0,    // RAM access bit
1882   0,    // fast call/return mode select bit
1883   0,    // second memory operand
1884   0,    // second literal operand
1885   POC_NOP,
1886   PCC_NONE,  // inCond
1887   PCC_NONE  , // outCond
1888   PCI_MAGIC
1889 };
1890
1891 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1892   {PC_OPCODE, NULL, NULL, 0, NULL, 
1893    genericDestruct,
1894    genericPrint},
1895   POC_RCALL,
1896   "RCALL",
1897   2,
1898   NULL, // from branch
1899   NULL, // to branch
1900   NULL, // label
1901   NULL, // operand
1902   NULL, // flow block
1903   NULL, // C source 
1904   1,    // num ops
1905   0,0,  // dest, bit instruction
1906   1,0,  // branch, skip
1907   0,    // literal operand
1908   0,    // RAM access bit
1909   0,    // fast call/return mode select bit
1910   0,    // second memory operand
1911   0,    // second literal operand
1912   POC_NOP,
1913   PCC_REL_ADDR,  // inCond
1914   PCC_NONE  , // outCond
1915   PCI_MAGIC
1916 };
1917
1918 pCodeInstruction pic16_pciRETFIE = {
1919   {PC_OPCODE, NULL, NULL, 0, NULL, 
1920    //   AnalyzeRETURN,
1921    genericDestruct,
1922    genericPrint},
1923   POC_RETFIE,
1924   "RETFIE",
1925   2,
1926   NULL, // from branch
1927   NULL, // to branch
1928   NULL, // label
1929   NULL, // operand
1930   NULL, // flow block
1931   NULL, // C source 
1932   1,    // num ops
1933   0,0,  // dest, bit instruction
1934   1,0,  // branch, skip
1935   0,    // literal operand
1936   0,    // RAM access bit
1937   1,    // fast call/return mode select bit
1938   0,    // second memory operand
1939   0,    // second literal operand
1940   POC_NOP,
1941   PCC_NONE,   // inCond
1942   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1943   PCI_MAGIC
1944 };
1945
1946 pCodeInstruction pic16_pciRETLW = {
1947   {PC_OPCODE, NULL, NULL, 0, NULL, 
1948    //   AnalyzeRETURN,
1949    genericDestruct,
1950    genericPrint},
1951   POC_RETLW,
1952   "RETLW",
1953   2,
1954   NULL, // from branch
1955   NULL, // to branch
1956   NULL, // label
1957   NULL, // operand
1958   NULL, // flow block
1959   NULL, // C source 
1960   1,    // num ops
1961   0,0,  // dest, bit instruction
1962   1,0,  // branch, skip
1963   1,    // literal operand
1964   0,    // RAM access bit
1965   0,    // fast call/return mode select bit
1966   0,    // second memory operand
1967   0,    // second literal operand
1968   POC_NOP,
1969   PCC_LITERAL,   // inCond
1970   PCC_W, // outCond
1971   PCI_MAGIC
1972 };
1973
1974 pCodeInstruction pic16_pciRETURN = {
1975   {PC_OPCODE, NULL, NULL, 0, NULL, 
1976    //   AnalyzeRETURN,
1977    genericDestruct,
1978    genericPrint},
1979   POC_RETURN,
1980   "RETURN",
1981   2,
1982   NULL, // from branch
1983   NULL, // to branch
1984   NULL, // label
1985   NULL, // operand
1986   NULL, // flow block
1987   NULL, // C source 
1988   1,    // num ops
1989   0,0,  // dest, bit instruction
1990   1,0,  // branch, skip
1991   0,    // literal operand
1992   0,    // RAM access bit
1993   1,    // fast call/return mode select bit
1994   0,    // second memory operand
1995   0,    // second literal operand
1996   POC_NOP,
1997   PCC_NONE,   // inCond
1998   PCC_NONE, // outCond
1999   PCI_MAGIC
2000 };
2001 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2002   {PC_OPCODE, NULL, NULL, 0, NULL, 
2003    //   genericAnalyze,
2004    genericDestruct,
2005    genericPrint},
2006   POC_RLCF,
2007   "RLCF",
2008   2,
2009   NULL, // from branch
2010   NULL, // to branch
2011   NULL, // label
2012   NULL, // operand
2013   NULL, // flow block
2014   NULL, // C source 
2015   3,    // num ops
2016   1,0,  // dest, bit instruction
2017   0,0,  // branch, skip
2018   0,    // literal operand
2019   1,    // RAM access bit
2020   0,    // fast call/return mode select bit
2021   0,    // second memory operand
2022   0,    // second literal operand
2023   POC_NOP,
2024   (PCC_C | PCC_REGISTER),   // inCond
2025   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2026   PCI_MAGIC
2027 };
2028
2029 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2030   {PC_OPCODE, NULL, NULL, 0, NULL, 
2031    //   genericAnalyze,
2032    genericDestruct,
2033    genericPrint},
2034   POC_RLCFW,
2035   "RLCF",
2036   2,
2037   NULL, // from branch
2038   NULL, // to branch
2039   NULL, // label
2040   NULL, // operand
2041   NULL, // flow block
2042   NULL, // C source 
2043   3,    // num ops
2044   0,0,  // dest, bit instruction
2045   0,0,  // branch, skip
2046   0,    // literal operand
2047   1,    // RAM access bit
2048   0,    // fast call/return mode select bit
2049   0,    // second memory operand
2050   0,    // second literal operand
2051   POC_NOP,
2052   (PCC_C | PCC_REGISTER),   // inCond
2053   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2054   PCI_MAGIC
2055 };
2056
2057 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2058   {PC_OPCODE, NULL, NULL, 0, NULL, 
2059    //   genericAnalyze,
2060    genericDestruct,
2061    genericPrint},
2062   POC_RLNCF,
2063   "RLNCF",
2064   2,
2065   NULL, // from branch
2066   NULL, // to branch
2067   NULL, // label
2068   NULL, // operand
2069   NULL, // flow block
2070   NULL, // C source 
2071   3,    // num ops
2072   1,0,  // dest, bit instruction
2073   0,0,  // branch, skip
2074   0,    // literal operand
2075   1,    // RAM access bit
2076   0,    // fast call/return mode select bit
2077   0,    // second memory operand
2078   0,    // second literal operand
2079   POC_NOP,
2080   PCC_REGISTER,   // inCond
2081   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2082   PCI_MAGIC
2083 };
2084 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2085   {PC_OPCODE, NULL, NULL, 0, NULL, 
2086    //   genericAnalyze,
2087    genericDestruct,
2088    genericPrint},
2089   POC_RLNCFW,
2090   "RLNCF",
2091   2,
2092   NULL, // from branch
2093   NULL, // to branch
2094   NULL, // label
2095   NULL, // operand
2096   NULL, // flow block
2097   NULL, // C source 
2098   3,    // num ops
2099   0,0,  // dest, bit instruction
2100   0,0,  // branch, skip
2101   0,    // literal operand
2102   1,    // RAM access bit
2103   0,    // fast call/return mode select bit
2104   0,    // second memory operand
2105   0,    // second literal operand
2106   POC_NOP,
2107   PCC_REGISTER,   // inCond
2108   (PCC_W | PCC_Z | PCC_N), // outCond
2109   PCI_MAGIC
2110 };
2111 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2112   {PC_OPCODE, NULL, NULL, 0, NULL, 
2113    //   genericAnalyze,
2114    genericDestruct,
2115    genericPrint},
2116   POC_RRCF,
2117   "RRCF",
2118   2,
2119   NULL, // from branch
2120   NULL, // to branch
2121   NULL, // label
2122   NULL, // operand
2123   NULL, // flow block
2124   NULL, // C source 
2125   3,    // num ops
2126   1,0,  // dest, bit instruction
2127   0,0,  // branch, skip
2128   0,    // literal operand
2129   1,    // RAM access bit
2130   0,    // fast call/return mode select bit
2131   0,    // second memory operand
2132   0,    // second literal operand
2133   POC_NOP,
2134   (PCC_C | PCC_REGISTER),   // inCond
2135   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2136   PCI_MAGIC
2137 };
2138 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2139   {PC_OPCODE, NULL, NULL, 0, NULL, 
2140    //   genericAnalyze,
2141    genericDestruct,
2142    genericPrint},
2143   POC_RRCFW,
2144   "RRCF",
2145   2,
2146   NULL, // from branch
2147   NULL, // to branch
2148   NULL, // label
2149   NULL, // operand
2150   NULL, // flow block
2151   NULL, // C source 
2152   3,    // num ops
2153   0,0,  // dest, bit instruction
2154   0,0,  // branch, skip
2155   0,    // literal operand
2156   1,    // RAM access bit
2157   0,    // fast call/return mode select bit
2158   0,    // second memory operand
2159   0,    // second literal operand
2160   POC_NOP,
2161   (PCC_C | PCC_REGISTER),   // inCond
2162   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2163   PCI_MAGIC
2164 };
2165 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2166   {PC_OPCODE, NULL, NULL, 0, NULL, 
2167    //   genericAnalyze,
2168    genericDestruct,
2169    genericPrint},
2170   POC_RRNCF,
2171   "RRNCF",
2172   2,
2173   NULL, // from branch
2174   NULL, // to branch
2175   NULL, // label
2176   NULL, // operand
2177   NULL, // flow block
2178   NULL, // C source 
2179   3,    // num ops
2180   1,0,  // dest, bit instruction
2181   0,0,  // branch, skip
2182   0,    // literal operand
2183   1,    // RAM access bit
2184   0,    // fast call/return mode select bit
2185   0,    // second memory operand
2186   0,    // second literal operand
2187   POC_NOP,
2188   PCC_REGISTER,   // inCond
2189   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2190   PCI_MAGIC
2191 };
2192
2193 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2194   {PC_OPCODE, NULL, NULL, 0, NULL, 
2195    //   genericAnalyze,
2196    genericDestruct,
2197    genericPrint},
2198   POC_RRNCFW,
2199   "RRNCF",
2200   2,
2201   NULL, // from branch
2202   NULL, // to branch
2203   NULL, // label
2204   NULL, // operand
2205   NULL, // flow block
2206   NULL, // C source 
2207   3,    // num ops
2208   0,0,  // dest, bit instruction
2209   0,0,  // branch, skip
2210   0,    // literal operand
2211   1,    // RAM access bit
2212   0,    // fast call/return mode select bit
2213   0,    // second memory operand
2214   0,    // second literal operand
2215   POC_NOP,
2216   PCC_REGISTER,   // inCond
2217   (PCC_W | PCC_Z | PCC_N), // outCond
2218   PCI_MAGIC
2219 };
2220
2221 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2222   {PC_OPCODE, NULL, NULL, 0, NULL, 
2223    //   genericAnalyze,
2224    genericDestruct,
2225    genericPrint},
2226   POC_SETF,
2227   "SETF",
2228   2,
2229   NULL, // from branch
2230   NULL, // to branch
2231   NULL, // label
2232   NULL, // operand
2233   NULL, // flow block
2234   NULL, // C source 
2235   2,    // num ops
2236   0,0,  // dest, bit instruction
2237   0,0,  // branch, skip
2238   0,    // literal operand
2239   1,    // RAM access bit
2240   0,    // fast call/return mode select bit
2241   0,    // second memory operand
2242   0,    // second literal operand
2243   POC_NOP,
2244   PCC_NONE,  // inCond
2245   PCC_REGISTER  , // outCond
2246   PCI_MAGIC
2247 };
2248
2249 pCodeInstruction pic16_pciSUBLW = {
2250   {PC_OPCODE, NULL, NULL, 0, NULL, 
2251    //   genericAnalyze,
2252    genericDestruct,
2253    genericPrint},
2254   POC_SUBLW,
2255   "SUBLW",
2256   2,
2257   NULL, // from branch
2258   NULL, // to branch
2259   NULL, // label
2260   NULL, // operand
2261   NULL, // flow block
2262   NULL, // C source 
2263   1,    // num ops
2264   0,0,  // dest, bit instruction
2265   0,0,  // branch, skip
2266   1,    // literal operand
2267   0,    // RAM access bit
2268   0,    // fast call/return mode select bit
2269   0,    // second memory operand
2270   0,    // second literal operand
2271   POC_NOP,
2272   (PCC_W | PCC_LITERAL),   // inCond
2273   (PCC_W | PCC_STATUS), // outCond
2274   PCI_MAGIC
2275 };
2276
2277 pCodeInstruction pic16_pciSUBFWB = {
2278   {PC_OPCODE, NULL, NULL, 0, NULL, 
2279    //   genericAnalyze,
2280    genericDestruct,
2281    genericPrint},
2282   POC_SUBFWB,
2283   "SUBFWB",
2284   2,
2285   NULL, // from branch
2286   NULL, // to branch
2287   NULL, // label
2288   NULL, // operand
2289   NULL, // flow block
2290   NULL, // C source 
2291   3,    // num ops
2292   1,0,  // dest, bit instruction
2293   0,0,  // branch, skip
2294   0,    // literal operand
2295   1,    // RAM access bit
2296   0,    // fast call/return mode select bit
2297   0,    // second memory operand
2298   0,    // second literal operand
2299   POC_NOP,
2300   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2301   (PCC_W | PCC_STATUS), // outCond
2302   PCI_MAGIC
2303 };
2304
2305 pCodeInstruction pic16_pciSUBWF = {
2306   {PC_OPCODE, NULL, NULL, 0, NULL, 
2307    //   genericAnalyze,
2308    genericDestruct,
2309    genericPrint},
2310   POC_SUBWF,
2311   "SUBWF",
2312   2,
2313   NULL, // from branch
2314   NULL, // to branch
2315   NULL, // label
2316   NULL, // operand
2317   NULL, // flow block
2318   NULL, // C source 
2319   3,    // num ops
2320   1,0,  // dest, bit instruction
2321   0,0,  // branch, skip
2322   0,    // literal operand
2323   1,    // RAM access bit
2324   0,    // fast call/return mode select bit
2325   0,    // second memory operand
2326   0,    // second literal operand
2327   POC_NOP,
2328   (PCC_W | PCC_REGISTER),   // inCond
2329   (PCC_REGISTER | PCC_STATUS), // outCond
2330   PCI_MAGIC
2331 };
2332
2333 pCodeInstruction pic16_pciSUBFW = {
2334   {PC_OPCODE, NULL, NULL, 0, NULL, 
2335    //   genericAnalyze,
2336    genericDestruct,
2337    genericPrint},
2338   POC_SUBFW,
2339   "SUBWF",
2340   2,
2341   NULL, // from branch
2342   NULL, // to branch
2343   NULL, // label
2344   NULL, // operand
2345   NULL, // flow block
2346   NULL, // C source 
2347   3,    // num ops
2348   0,0,  // dest, bit instruction
2349   0,0,  // branch, skip
2350   0,    // literal operand
2351   1,    // RAM access bit
2352   0,    // fast call/return mode select bit
2353   0,    // second memory operand
2354   0,    // second literal operand
2355   POC_NOP,
2356   (PCC_W | PCC_REGISTER),   // inCond
2357   (PCC_W | PCC_STATUS), // outCond
2358   PCI_MAGIC
2359 };
2360
2361 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2362   {PC_OPCODE, NULL, NULL, 0, NULL, 
2363    //   genericAnalyze,
2364    genericDestruct,
2365    genericPrint},
2366   POC_SUBFWB_D1,
2367   "SUBFWB",
2368   2,
2369   NULL, // from branch
2370   NULL, // to branch
2371   NULL, // label
2372   NULL, // operand
2373   NULL, // flow block
2374   NULL, // C source 
2375   3,    // num ops
2376   1,0,  // dest, bit instruction
2377   0,0,  // branch, skip
2378   0,    // literal operand
2379   1,    // RAM access bit
2380   0,    // fast call/return mode select bit
2381   0,    // second memory operand
2382   0,    // second literal operand
2383   POC_NOP,
2384   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2385   (PCC_REGISTER | PCC_STATUS), // outCond
2386   PCI_MAGIC
2387 };
2388
2389 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2390   {PC_OPCODE, NULL, NULL, 0, NULL, 
2391    //   genericAnalyze,
2392    genericDestruct,
2393    genericPrint},
2394   POC_SUBFWB_D0,
2395   "SUBFWB",
2396   2,
2397   NULL, // from branch
2398   NULL, // to branch
2399   NULL, // label
2400   NULL, // operand
2401   NULL, // flow block
2402   NULL, // C source 
2403   3,    // num ops
2404   0,0,  // dest, bit instruction
2405   0,0,  // branch, skip
2406   0,    // literal operand
2407   1,    // RAM access bit
2408   0,    // fast call/return mode select bit
2409   0,    // second memory operand
2410   0,    // second literal operand
2411   POC_NOP,
2412   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2413   (PCC_W | PCC_STATUS), // outCond
2414   PCI_MAGIC
2415 };
2416
2417 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2418   {PC_OPCODE, NULL, NULL, 0, NULL, 
2419    //   genericAnalyze,
2420    genericDestruct,
2421    genericPrint},
2422   POC_SUBWFB_D1,
2423   "SUBWFB",
2424   2,
2425   NULL, // from branch
2426   NULL, // to branch
2427   NULL, // label
2428   NULL, // operand
2429   NULL, // flow block
2430   NULL, // C source 
2431   3,    // num ops
2432   1,0,  // dest, bit instruction
2433   0,0,  // branch, skip
2434   0,    // literal operand
2435   1,    // RAM access bit
2436   0,    // fast call/return mode select bit
2437   0,    // second memory operand
2438   0,    // second literal operand
2439   POC_NOP,
2440   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2441   (PCC_REGISTER | PCC_STATUS), // outCond
2442   PCI_MAGIC
2443 };
2444
2445 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2446   {PC_OPCODE, NULL, NULL, 0, NULL, 
2447    //   genericAnalyze,
2448    genericDestruct,
2449    genericPrint},
2450   POC_SUBWFB_D0,
2451   "SUBWFB",
2452   2,
2453   NULL, // from branch
2454   NULL, // to branch
2455   NULL, // label
2456   NULL, // operand
2457   NULL, // flow block
2458   NULL, // C source 
2459   3,    // num ops
2460   0,0,  // dest, bit instruction
2461   0,0,  // branch, skip
2462   0,    // literal operand
2463   1,    // RAM access bit
2464   0,    // fast call/return mode select bit
2465   0,    // second memory operand
2466   0,    // second literal operand
2467   POC_NOP,
2468   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2469   (PCC_W | PCC_STATUS), // outCond
2470   PCI_MAGIC
2471 };
2472
2473 pCodeInstruction pic16_pciSWAPF = {
2474   {PC_OPCODE, NULL, NULL, 0, NULL, 
2475    //   genericAnalyze,
2476    genericDestruct,
2477    genericPrint},
2478   POC_SWAPF,
2479   "SWAPF",
2480   2,
2481   NULL, // from branch
2482   NULL, // to branch
2483   NULL, // label
2484   NULL, // operand
2485   NULL, // flow block
2486   NULL, // C source 
2487   3,    // num ops
2488   1,0,  // dest, bit instruction
2489   0,0,  // branch, skip
2490   0,    // literal operand
2491   1,    // RAM access bit
2492   0,    // fast call/return mode select bit
2493   0,    // second memory operand
2494   0,    // second literal operand
2495   POC_NOP,
2496   (PCC_REGISTER),   // inCond
2497   (PCC_REGISTER), // outCond
2498   PCI_MAGIC
2499 };
2500
2501 pCodeInstruction pic16_pciSWAPFW = {
2502   {PC_OPCODE, NULL, NULL, 0, NULL, 
2503    //   genericAnalyze,
2504    genericDestruct,
2505    genericPrint},
2506   POC_SWAPFW,
2507   "SWAPF",
2508   2,
2509   NULL, // from branch
2510   NULL, // to branch
2511   NULL, // label
2512   NULL, // operand
2513   NULL, // flow block
2514   NULL, // C source 
2515   3,    // num ops
2516   0,0,  // dest, bit instruction
2517   0,0,  // branch, skip
2518   0,    // literal operand
2519   1,    // RAM access bit
2520   0,    // fast call/return mode select bit
2521   0,    // second memory operand
2522   0,    // second literal operand
2523   POC_NOP,
2524   (PCC_REGISTER),   // inCond
2525   (PCC_W), // outCond
2526   PCI_MAGIC
2527 };
2528
2529 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2530   {PC_OPCODE, NULL, NULL, 0, NULL, 
2531    genericDestruct,
2532    genericPrint},
2533   POC_TBLRD,
2534   "TBLRD*",
2535   2,
2536   NULL, // from branch
2537   NULL, // to branch
2538   NULL, // label
2539   NULL, // operand
2540   NULL, // flow block
2541   NULL, // C source 
2542   0,    // num ops
2543   0,0,  // dest, bit instruction
2544   0,0,  // branch, skip
2545   0,    // literal operand
2546   0,    // RAM access bit
2547   0,    // fast call/return mode select bit
2548   0,    // second memory operand
2549   0,    // second literal operand
2550   POC_NOP,
2551   PCC_NONE,  // inCond
2552   PCC_NONE  , // outCond
2553   PCI_MAGIC
2554 };
2555
2556 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2557   {PC_OPCODE, NULL, NULL, 0, NULL, 
2558    genericDestruct,
2559    genericPrint},
2560   POC_TBLRD_POSTINC,
2561   "TBLRD*+",
2562   2,
2563   NULL, // from branch
2564   NULL, // to branch
2565   NULL, // label
2566   NULL, // operand
2567   NULL, // flow block
2568   NULL, // C source 
2569   0,    // num ops
2570   0,0,  // dest, bit instruction
2571   0,0,  // branch, skip
2572   0,    // literal operand
2573   0,    // RAM access bit
2574   0,    // fast call/return mode select bit
2575   0,    // second memory operand
2576   0,    // second literal operand
2577   POC_NOP,
2578   PCC_NONE,  // inCond
2579   PCC_NONE  , // outCond
2580   PCI_MAGIC
2581 };
2582
2583 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2584   {PC_OPCODE, NULL, NULL, 0, NULL, 
2585    genericDestruct,
2586    genericPrint},
2587   POC_TBLRD_POSTDEC,
2588   "TBLRD*-",
2589   2,
2590   NULL, // from branch
2591   NULL, // to branch
2592   NULL, // label
2593   NULL, // operand
2594   NULL, // flow block
2595   NULL, // C source 
2596   0,    // num ops
2597   0,0,  // dest, bit instruction
2598   0,0,  // branch, skip
2599   0,    // literal operand
2600   0,    // RAM access bit
2601   0,    // fast call/return mode select bit
2602   0,    // second memory operand
2603   0,    // second literal operand
2604   POC_NOP,
2605   PCC_NONE,  // inCond
2606   PCC_NONE  , // outCond
2607   PCI_MAGIC
2608 };
2609
2610 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2611   {PC_OPCODE, NULL, NULL, 0, NULL, 
2612    genericDestruct,
2613    genericPrint},
2614   POC_TBLRD_PREINC,
2615   "TBLRD+*",
2616   2,
2617   NULL, // from branch
2618   NULL, // to branch
2619   NULL, // label
2620   NULL, // operand
2621   NULL, // flow block
2622   NULL, // C source 
2623   0,    // num ops
2624   0,0,  // dest, bit instruction
2625   0,0,  // branch, skip
2626   0,    // literal operand
2627   0,    // RAM access bit
2628   0,    // fast call/return mode select bit
2629   0,    // second memory operand
2630   0,    // second literal operand
2631   POC_NOP,
2632   PCC_NONE,  // inCond
2633   PCC_NONE  , // outCond
2634   PCI_MAGIC
2635 };
2636
2637 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2638   {PC_OPCODE, NULL, NULL, 0, NULL, 
2639    genericDestruct,
2640    genericPrint},
2641   POC_TBLWT,
2642   "TBLWT*",
2643   2,
2644   NULL, // from branch
2645   NULL, // to branch
2646   NULL, // label
2647   NULL, // operand
2648   NULL, // flow block
2649   NULL, // C source 
2650   0,    // num ops
2651   0,0,  // dest, bit instruction
2652   0,0,  // branch, skip
2653   0,    // literal operand
2654   0,    // RAM access bit
2655   0,    // fast call/return mode select bit
2656   0,    // second memory operand
2657   0,    // second literal operand
2658   POC_NOP,
2659   PCC_NONE,  // inCond
2660   PCC_NONE  , // outCond
2661   PCI_MAGIC
2662 };
2663
2664 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2665   {PC_OPCODE, NULL, NULL, 0, NULL, 
2666    genericDestruct,
2667    genericPrint},
2668   POC_TBLWT_POSTINC,
2669   "TBLWT*+",
2670   2,
2671   NULL, // from branch
2672   NULL, // to branch
2673   NULL, // label
2674   NULL, // operand
2675   NULL, // flow block
2676   NULL, // C source 
2677   0,    // num ops
2678   0,0,  // dest, bit instruction
2679   0,0,  // branch, skip
2680   0,    // literal operand
2681   0,    // RAM access bit
2682   0,    // fast call/return mode select bit
2683   0,    // second memory operand
2684   0,    // second literal operand
2685   POC_NOP,
2686   PCC_NONE,  // inCond
2687   PCC_NONE  , // outCond
2688   PCI_MAGIC
2689 };
2690
2691 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2692   {PC_OPCODE, NULL, NULL, 0, NULL, 
2693    genericDestruct,
2694    genericPrint},
2695   POC_TBLWT_POSTDEC,
2696   "TBLWT*-",
2697   2,
2698   NULL, // from branch
2699   NULL, // to branch
2700   NULL, // label
2701   NULL, // operand
2702   NULL, // flow block
2703   NULL, // C source 
2704   0,    // num ops
2705   0,0,  // dest, bit instruction
2706   0,0,  // branch, skip
2707   0,    // literal operand
2708   0,    // RAM access bit
2709   0,    // fast call/return mode select bit
2710   0,    // second memory operand
2711   0,    // second literal operand
2712   POC_NOP,
2713   PCC_NONE,  // inCond
2714   PCC_NONE  , // outCond
2715   PCI_MAGIC
2716 };
2717
2718 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2719   {PC_OPCODE, NULL, NULL, 0, NULL, 
2720    genericDestruct,
2721    genericPrint},
2722   POC_TBLWT_PREINC,
2723   "TBLWT+*",
2724   2,
2725   NULL, // from branch
2726   NULL, // to branch
2727   NULL, // label
2728   NULL, // operand
2729   NULL, // flow block
2730   NULL, // C source 
2731   0,    // num ops
2732   0,0,  // dest, bit instruction
2733   0,0,  // branch, skip
2734   0,    // literal operand
2735   0,    // RAM access bit
2736   0,    // fast call/return mode select bit
2737   0,    // second memory operand
2738   0,    // second literal operand
2739   POC_NOP,
2740   PCC_NONE,  // inCond
2741   PCC_NONE  , // outCond
2742   PCI_MAGIC
2743 };
2744
2745 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2746   {PC_OPCODE, NULL, NULL, 0, NULL, 
2747    //   genericAnalyze,
2748    genericDestruct,
2749    genericPrint},
2750   POC_TSTFSZ,
2751   "TSTFSZ",
2752   2,
2753   NULL, // from branch
2754   NULL, // to branch
2755   NULL, // label
2756   NULL, // operand
2757   NULL, // flow block
2758   NULL, // C source 
2759   2,    // num ops
2760   0,0,  // dest, bit instruction
2761   1,1,  // branch, skip
2762   0,    // literal operand
2763   1,    // RAM access bit
2764   0,    // fast call/return mode select bit
2765   0,    // second memory operand
2766   0,    // second literal operand
2767   POC_NOP,
2768   PCC_REGISTER,   // inCond
2769   PCC_NONE, // outCond
2770   PCI_MAGIC
2771 };
2772
2773 pCodeInstruction pic16_pciXORWF = {
2774   {PC_OPCODE, NULL, NULL, 0, NULL, 
2775    //   genericAnalyze,
2776    genericDestruct,
2777    genericPrint},
2778   POC_XORWF,
2779   "XORWF",
2780   2,
2781   NULL, // from branch
2782   NULL, // to branch
2783   NULL, // label
2784   NULL, // operand
2785   NULL, // flow block
2786   NULL, // C source 
2787   3,    // num ops
2788   1,0,  // dest, bit instruction
2789   0,0,  // branch, skip
2790   0,    // literal operand
2791   1,    // RAM access bit
2792   0,    // fast call/return mode select bit
2793   0,    // second memory operand
2794   0,    // second literal operand
2795   POC_NOP,
2796   (PCC_W | PCC_REGISTER),   // inCond
2797   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2798   PCI_MAGIC
2799 };
2800
2801 pCodeInstruction pic16_pciXORFW = {
2802   {PC_OPCODE, NULL, NULL, 0, NULL, 
2803    //   genericAnalyze,
2804    genericDestruct,
2805    genericPrint},
2806   POC_XORFW,
2807   "XORWF",
2808   2,
2809   NULL, // from branch
2810   NULL, // to branch
2811   NULL, // label
2812   NULL, // operand
2813   NULL, // flow block
2814   NULL, // C source 
2815   3,    // num ops
2816   0,0,  // dest, bit instruction
2817   0,0,  // branch, skip
2818   0,    // literal operand
2819   1,    // RAM access bit
2820   0,    // fast call/return mode select bit
2821   0,    // second memory operand
2822   0,    // second literal operand
2823   POC_NOP,
2824   (PCC_W | PCC_REGISTER),   // inCond
2825   (PCC_W | PCC_Z | PCC_N), // outCond
2826   PCI_MAGIC
2827 };
2828
2829 pCodeInstruction pic16_pciXORLW = {
2830   {PC_OPCODE, NULL, NULL, 0, NULL, 
2831    //   genericAnalyze,
2832    genericDestruct,
2833    genericPrint},
2834   POC_XORLW,
2835   "XORLW",
2836   2,
2837   NULL, // from branch
2838   NULL, // to branch
2839   NULL, // label
2840   NULL, // operand
2841   NULL, // flow block
2842   NULL, // C source 
2843   1,    // num ops
2844   0,0,  // dest, bit instruction
2845   0,0,  // branch, skip
2846   1,    // literal operand
2847   1,    // RAM access bit
2848   0,    // fast call/return mode select bit
2849   0,    // second memory operand
2850   0,    // second literal operand
2851   POC_NOP,
2852   (PCC_W | PCC_LITERAL),   // inCond
2853   (PCC_W | PCC_Z | PCC_N), // outCond
2854   PCI_MAGIC
2855 };
2856
2857
2858 pCodeInstruction pic16_pciBANKSEL = {
2859   {PC_OPCODE, NULL, NULL, 0, NULL, 
2860    genericDestruct,
2861    genericPrint},
2862   POC_BANKSEL,
2863   "BANKSEL",
2864   2,
2865   NULL, // from branch
2866   NULL, // to branch
2867   NULL, // label
2868   NULL, // operand
2869   NULL, // flow block
2870   NULL, // C source 
2871   0,    // num ops
2872   0,0,  // dest, bit instruction
2873   0,0,  // branch, skip
2874   0,    // literal operand
2875   0,    // RAM access bit
2876   0,    // fast call/return mode select bit
2877   0,    // second memory operand
2878   0,    // second literal operand
2879   POC_NOP,
2880   PCC_NONE,   // inCond
2881   PCC_NONE, // outCond
2882   PCI_MAGIC
2883 };
2884
2885
2886 #define MAX_PIC16MNEMONICS 100
2887 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2888
2889 //#define USE_VSNPRINTF
2890 #if OPT_DISABLE_PIC
2891
2892 #ifdef USE_VSNPRINTF
2893   // Alas, vsnprintf is not ANSI standard, and does not exist
2894   // on Solaris (and probably other non-Gnu flavored Unixes).
2895
2896 /*-----------------------------------------------------------------*/
2897 /* SAFE_snprintf - like snprintf except the string pointer is      */
2898 /*                 after the string has been printed to. This is   */
2899 /*                 useful for printing to string as though if it   */
2900 /*                 were a stream.                                  */
2901 /*-----------------------------------------------------------------*/
2902 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2903 {
2904   va_list val;
2905   int len;
2906
2907   if(!str || !*str)
2908     return;
2909
2910   va_start(val, format);
2911
2912   vsnprintf(*str, *size, format, val);
2913
2914   va_end (val);
2915
2916   len = strlen(*str);
2917   if(len > *size) {
2918     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2919     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2920   }
2921
2922   *str += len;
2923   *size -= len;
2924
2925 }
2926
2927 #else
2928 // This version is *not* safe, despite the name.
2929
2930 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2931 {
2932   va_list val;
2933   int len;
2934   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2935
2936   if(!str || !*str)
2937     return;
2938
2939   va_start(val, format);
2940
2941   vsprintf(buffer, format, val);
2942   va_end (val);
2943
2944   len = strlen(buffer);
2945   if(len > *size) {
2946     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2947     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2948   }
2949
2950   strcpy(*str, buffer);
2951   *str += len;
2952   *size -= len;
2953
2954 }
2955
2956 #endif    //  USE_VSNPRINTF
2957 #endif
2958
2959 extern set *externs;
2960 extern  void pic16_initStack(int base_address, int size);
2961 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2962 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2963 extern void pic16_init_pic(char *);
2964
2965 void  pic16_pCodeInitRegisters(void)
2966 {
2967   static int initialized=0;
2968
2969         if(initialized)
2970                 return;
2971         
2972         initialized = 1;
2973
2974 //      pic16_initStack(0xfff, 8);
2975         pic16_init_pic(port->processor);
2976
2977         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2978         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2979         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2980         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2981         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2982         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2983         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2984
2985         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2986         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2987         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2988
2989         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2990         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2991         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2992         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2993
2994         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2995         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2996         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2997         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2998         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2999         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3000
3001         pic16_stackpnt_lo = &pic16_pc_fsr1l;
3002         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3003         pic16_stack_postdec = &pic16_pc_postdec1;
3004         pic16_stack_postinc = &pic16_pc_postinc1;
3005         pic16_stack_preinc = &pic16_pc_preinc1;
3006         pic16_stack_plusw = &pic16_pc_plusw1;
3007         
3008         pic16_framepnt_lo = &pic16_pc_fsr2l;
3009         pic16_framepnt_hi = &pic16_pc_fsr2h;
3010         pic16_frame_postdec = &pic16_pc_postdec2;
3011         pic16_frame_postinc = &pic16_pc_postinc2;
3012         pic16_frame_preinc = &pic16_pc_preinc2;
3013         pic16_frame_plusw = &pic16_pc_plusw2;
3014
3015         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3016         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3017         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3018         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3019         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3020         
3021         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3022         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3023         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3024         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3025         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3026
3027         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3028         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3029         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3030         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3031         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3032         
3033         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3034         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3035
3036
3037         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3038         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3039         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3040         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3041
3042         
3043         pic16_pc_status.rIdx = IDX_STATUS;
3044         pic16_pc_intcon.rIdx = IDX_INTCON;
3045         pic16_pc_pcl.rIdx = IDX_PCL;
3046         pic16_pc_pclath.rIdx = IDX_PCLATH;
3047         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3048         pic16_pc_wreg.rIdx = IDX_WREG;
3049         pic16_pc_bsr.rIdx = IDX_BSR;
3050
3051         pic16_pc_tosl.rIdx = IDX_TOSL;
3052         pic16_pc_tosh.rIdx = IDX_TOSH;
3053         pic16_pc_tosu.rIdx = IDX_TOSU;
3054
3055         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3056         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3057         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3058         pic16_pc_tablat.rIdx = IDX_TABLAT;
3059
3060         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3061         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3062         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3063         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3064         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3065         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3066         pic16_pc_indf0.rIdx = IDX_INDF0;
3067         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3068         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3069         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3070         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3071         pic16_pc_indf1.rIdx = IDX_INDF1;
3072         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3073         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3074         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3075         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3076         pic16_pc_indf2.rIdx = IDX_INDF2;
3077         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3078         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3079         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3080         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3081         pic16_pc_prodl.rIdx = IDX_PRODL;
3082         pic16_pc_prodh.rIdx = IDX_PRODH;
3083         
3084         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3085         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3086         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3087         
3088         pic16_pc_kzero.rIdx = IDX_KZ;
3089         pic16_pc_wsave.rIdx = IDX_WSAVE;
3090         pic16_pc_ssave.rIdx = IDX_SSAVE;
3091
3092         pic16_pc_eecon1.rIdx = IDX_EECON1;
3093         pic16_pc_eecon2.rIdx = IDX_EECON2;
3094         pic16_pc_eedata.rIdx = IDX_EEDATA;
3095         pic16_pc_eeadr.rIdx = IDX_EEADR;
3096         
3097         
3098         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3099         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3100
3101         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3102         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3103
3104         /* probably should put this in a separate initialization routine */
3105         pb_dead_pcodes = newpBlock();
3106
3107 }
3108
3109 #if OPT_DISABLE_PIC
3110 /*-----------------------------------------------------------------*/
3111 /*  mnem2key - convert a pic mnemonic into a hash key              */
3112 /*   (BTW - this spreads the mnemonics quite well)                 */
3113 /*                                                                 */
3114 /*-----------------------------------------------------------------*/
3115
3116 int mnem2key(unsigned char const *mnem)
3117 {
3118   int key = 0;
3119
3120   if(!mnem)
3121     return 0;
3122
3123   while(*mnem) {
3124
3125     key += toupper(*mnem++) +1;
3126
3127   }
3128
3129   return (key & 0x1f);
3130
3131 }
3132 #endif
3133
3134 void pic16initMnemonics(void)
3135 {
3136   int i = 0;
3137   int key;
3138   //  char *str;
3139   pCodeInstruction *pci;
3140
3141   if(mnemonics_initialized)
3142     return;
3143
3144   // NULL out the array before making the assignments
3145   // since we check the array contents below this initialization.
3146
3147   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3148     pic16Mnemonics[i] = NULL;
3149   }
3150
3151   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3152   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3153   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3154   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3155   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3156   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3157   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3158   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3159   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3160   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3161   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3162   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3163   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3164   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3165   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3166   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3167   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3168   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3169   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3170   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3171   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3172   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3173   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3174   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3175   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3176   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3177   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3178   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3179   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3180   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3181   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3182   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3183   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3184   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3185   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3186   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3187   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3188   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3189   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3190   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3191   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3192   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3193   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3194   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3195   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3196   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3197   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3198   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3199   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3200   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3201   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3202   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3203   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3204   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3205   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3206   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3207   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3208   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3209   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3210   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3211   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3212   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3213   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3214   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3215   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3216   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3217   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3218   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3219   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3220   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3221   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3222   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3223   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3224   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3225   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3226   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3227   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3228   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3229   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3230   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3231   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3232   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3233   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3234   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3235   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3236   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3237   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3238   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3239   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3240   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3241   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3242   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3243   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3244   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3245
3246   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3247     if(pic16Mnemonics[i])
3248       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3249   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3250
3251   while(pci) {
3252     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3253     pci = hTabNextItem(pic16MnemonicsHash, &key);
3254   }
3255
3256   mnemonics_initialized = 1;
3257 }
3258
3259 int pic16_getpCodePeepCommand(char *cmd);
3260
3261 int pic16_getpCode(char *mnem,unsigned dest)
3262 {
3263
3264   pCodeInstruction *pci;
3265   int key = mnem2key((unsigned char *)mnem);
3266
3267   if(!mnemonics_initialized)
3268     pic16initMnemonics();
3269
3270   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3271
3272   while(pci) {
3273
3274     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3275       if((pci->num_ops <= 1)
3276         || (pci->isModReg == dest)
3277         || (pci->isBitInst)
3278         || (pci->num_ops <= 2 && pci->isAccess)
3279         || (pci->num_ops <= 2 && pci->isFastCall)
3280         || (pci->num_ops <= 2 && pci->is2MemOp)
3281         || (pci->num_ops <= 2 && pci->is2LitOp) )
3282         return(pci->op);
3283     }
3284
3285     pci = hTabNextItemWK (pic16MnemonicsHash);
3286   
3287   }
3288
3289   return -1;
3290 }
3291
3292 /*-----------------------------------------------------------------*
3293  * pic16initpCodePeepCommands
3294  *
3295  *-----------------------------------------------------------------*/
3296 void pic16initpCodePeepCommands(void)
3297 {
3298
3299   int key, i;
3300   peepCommand *pcmd;
3301
3302   i = 0;
3303   do {
3304     hTabAddItem(&pic16pCodePeepCommandsHash, 
3305                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3306     i++;
3307   } while (peepCommands[i].cmd);
3308
3309   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3310
3311   while(pcmd) {
3312     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3313     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3314   }
3315
3316 }
3317
3318 /*-----------------------------------------------------------------
3319  *
3320  *
3321  *-----------------------------------------------------------------*/
3322
3323 int pic16_getpCodePeepCommand(char *cmd)
3324 {
3325
3326   peepCommand *pcmd;
3327   int key = mnem2key((unsigned char *)cmd);
3328
3329
3330   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3331
3332   while(pcmd) {
3333     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3334     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3335       return pcmd->id;
3336     }
3337
3338     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3339   
3340   }
3341
3342   return -1;
3343 }
3344
3345 static char getpBlock_dbName(pBlock *pb)
3346 {
3347   if(!pb)
3348     return 0;
3349
3350   if(pb->cmemmap)
3351     return pb->cmemmap->dbName;
3352
3353   return pb->dbName;
3354 }
3355 void pic16_pBlockConvert2ISR(pBlock *pb)
3356 {
3357         if(!pb)return;
3358
3359         if(pb->cmemmap)pb->cmemmap = NULL;
3360
3361         pb->dbName = 'I';
3362
3363         if(pic16_pcode_verbose)
3364                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3365 }
3366
3367 void pic16_pBlockConvert2Absolute(pBlock *pb)
3368 {
3369         if(!pb)return;
3370         if(pb->cmemmap)pb->cmemmap = NULL;
3371         
3372         pb->dbName = 'A';
3373         
3374         if(pic16_pcode_verbose)
3375                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3376 }
3377   
3378 /*-----------------------------------------------------------------*/
3379 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3380 /*                   instances to the front of the doubly linked   */
3381 /*                   list of pBlocks                               */
3382 /*-----------------------------------------------------------------*/
3383
3384 void pic16_movepBlock2Head(char dbName)
3385 {
3386   pBlock *pb;
3387
3388
3389   /* this can happen in sources without code,
3390    * only variable definitions */
3391   if(!the_pFile)return;
3392
3393   pb = the_pFile->pbHead;
3394
3395   while(pb) {
3396
3397     if(getpBlock_dbName(pb) == dbName) {
3398       pBlock *pbn = pb->next;
3399       pb->next = the_pFile->pbHead;
3400       the_pFile->pbHead->prev = pb;
3401       the_pFile->pbHead = pb;
3402
3403       if(pb->prev)
3404         pb->prev->next = pbn;
3405
3406       // If the pBlock that we just moved was the last
3407       // one in the link of all of the pBlocks, then we
3408       // need to point the tail to the block just before
3409       // the one we moved.
3410       // Note: if pb->next is NULL, then pb must have 
3411       // been the last pBlock in the chain.
3412
3413       if(pbn)
3414         pbn->prev = pb->prev;
3415       else
3416         the_pFile->pbTail = pb->prev;
3417
3418       pb = pbn;
3419
3420     } else
3421       pb = pb->next;
3422
3423   }
3424
3425 }
3426
3427 void pic16_copypCode(FILE *of, char dbName)
3428 {
3429   pBlock *pb;
3430
3431         if(!of || !the_pFile)
3432                 return;
3433
3434         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3435                 if(getpBlock_dbName(pb) == dbName) {
3436 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3437                         pBlockStats(of,pb);
3438                         pic16_printpBlock(of,pb);
3439                 }
3440         }
3441
3442 }
3443 void pic16_pcode_test(void)
3444 {
3445
3446   DFPRINTF((stderr,"pcode is alive!\n"));
3447
3448   //initMnemonics();
3449
3450   if(the_pFile) {
3451
3452     pBlock *pb;
3453     FILE *pFile;
3454     char buffer[100];
3455
3456     /* create the file name */
3457     strcpy(buffer,dstFileName);
3458     strcat(buffer,".p");
3459
3460     if( !(pFile = fopen(buffer, "w" ))) {
3461       werror(E_FILE_OPEN_ERR,buffer);
3462       exit(1);
3463     }
3464
3465     fprintf(pFile,"pcode dump\n\n");
3466
3467     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3468       fprintf(pFile,"\n\tNew pBlock\n\n");
3469       if(pb->cmemmap)
3470         fprintf(pFile,"%s",pb->cmemmap->sname);
3471       else
3472         fprintf(pFile,"internal pblock");
3473
3474       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3475       pic16_printpBlock(pFile,pb);
3476     }
3477   }
3478 }
3479
3480
3481 unsigned long pic16_countInstructions(void)
3482 {
3483   pBlock *pb;
3484   pCode *pc;
3485   unsigned long isize=0;
3486
3487     if(!the_pFile)return -1;
3488     
3489     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3490       for(pc = pb->pcHead; pc; pc = pc->next) {
3491         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3492       }
3493     }
3494   return (isize);
3495 }
3496
3497
3498 /*-----------------------------------------------------------------*/
3499 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3500 /*      ister, RegCond will return the bit being referenced.       */
3501 /*                                                                 */
3502 /* fixme - why not just OR in the pcop bit field                   */
3503 /*-----------------------------------------------------------------*/
3504
3505 static int RegCond(pCodeOp *pcop)
3506 {
3507
3508   if(!pcop)
3509     return 0;
3510
3511   if(!pcop->name)return 0;
3512
3513   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3514     switch(PCORB(pcop)->bit) {
3515     case PIC_C_BIT:
3516       return PCC_C;
3517     case PIC_DC_BIT:
3518         return PCC_DC;
3519     case PIC_Z_BIT:
3520       return PCC_Z;
3521     }
3522
3523   }
3524
3525   return 0;
3526 }
3527
3528
3529 /*-----------------------------------------------------------------*/
3530 /* pic16_newpCode - create and return a newly initialized pCode          */
3531 /*                                                                 */
3532 /*  fixme - rename this                                            */
3533 /*                                                                 */
3534 /* The purpose of this routine is to create a new Instruction      */
3535 /* pCode. This is called by gen.c while the assembly code is being */
3536 /* generated.                                                      */
3537 /*                                                                 */
3538 /* Inouts:                                                         */
3539 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3540 /*                  (note that the op is analogous to but not the  */
3541 /*                  same thing as the opcode of the instruction.)  */
3542 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3543 /*                                                                 */
3544 /* Outputs:                                                        */
3545 /*  a pointer to the new malloc'd pCode is returned.               */
3546 /*                                                                 */
3547 /*                                                                 */
3548 /*                                                                 */
3549 /*-----------------------------------------------------------------*/
3550 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3551 {
3552   pCodeInstruction *pci ;
3553
3554   if(!mnemonics_initialized)
3555     pic16initMnemonics();
3556     
3557   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3558
3559   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3560     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3561     pci->pcop = pcop;
3562
3563     if(pci->inCond & PCC_EXAMINE_PCOP)
3564       pci->inCond  |= RegCond(pcop);
3565
3566     if(pci->outCond & PCC_EXAMINE_PCOP)
3567       pci->outCond  |= RegCond(pcop);
3568
3569     pci->pc.prev = pci->pc.next = NULL;
3570     return (pCode *)pci;
3571   }
3572
3573   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3574   exit(1);
3575
3576   return NULL;
3577 }       
3578
3579 /*-----------------------------------------------------------------*/
3580 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3581 /*                                                                 */
3582 /* Wild pcodes are used during the peep hole optimizer to serve    */
3583 /* as place holders for any instruction. When a snippet of code is */
3584 /* compared to a peep hole rule, the wild card opcode will match   */
3585 /* any instruction. However, the optional operand and label are    */
3586 /* additional qualifiers that must also be matched before the      */
3587 /* line (of assembly code) is declared matched. Note that the      */
3588 /* operand may be wild too.                                        */
3589 /*                                                                 */
3590 /*   Note, a wild instruction is specified just like a wild var:   */
3591 /*      %4     ; A wild instruction,                               */
3592 /*  See the peeph.def file for additional examples                 */
3593 /*                                                                 */
3594 /*-----------------------------------------------------------------*/
3595
3596 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3597 {
3598
3599   pCodeWild *pcw;
3600     
3601   pcw = Safe_calloc(1,sizeof(pCodeWild));
3602
3603   pcw->pci.pc.type = PC_WILD;
3604   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3605   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3606   pcw->pci.pc.pb = NULL;
3607
3608   //  pcw->pci.pc.analyze = genericAnalyze;
3609   pcw->pci.pc.destruct = genericDestruct;
3610   pcw->pci.pc.print = genericPrint;
3611
3612   pcw->id = pCodeID;              // this is the 'n' in %n
3613   pcw->operand = optional_operand;
3614   pcw->label   = optional_label;
3615
3616   pcw->mustBeBitSkipInst = 0;
3617   pcw->mustNotBeBitSkipInst = 0;
3618   pcw->invertBitSkipInst = 0;
3619
3620   return ( (pCode *)pcw);
3621   
3622 }
3623
3624  /*-----------------------------------------------------------------*/
3625 /* newPcodeInlineP - create a new pCode from a char string           */
3626 /*-----------------------------------------------------------------*/
3627
3628
3629 pCode *pic16_newpCodeInlineP(char *cP)
3630 {
3631
3632   pCodeComment *pcc ;
3633     
3634   pcc = Safe_calloc(1,sizeof(pCodeComment));
3635
3636   pcc->pc.type = PC_INLINE;
3637   pcc->pc.prev = pcc->pc.next = NULL;
3638   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3639   pcc->pc.pb = NULL;
3640
3641   //  pcc->pc.analyze = genericAnalyze;
3642   pcc->pc.destruct = genericDestruct;
3643   pcc->pc.print = genericPrint;
3644
3645   if(cP)
3646     pcc->comment = Safe_strdup(cP);
3647   else
3648     pcc->comment = NULL;
3649
3650   return ( (pCode *)pcc);
3651
3652 }
3653
3654 /*-----------------------------------------------------------------*/
3655 /* newPcodeCharP - create a new pCode from a char string           */
3656 /*-----------------------------------------------------------------*/
3657
3658 pCode *pic16_newpCodeCharP(char *cP)
3659 {
3660
3661   pCodeComment *pcc ;
3662     
3663   pcc = Safe_calloc(1,sizeof(pCodeComment));
3664
3665   pcc->pc.type = PC_COMMENT;
3666   pcc->pc.prev = pcc->pc.next = NULL;
3667   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3668   pcc->pc.pb = NULL;
3669
3670   //  pcc->pc.analyze = genericAnalyze;
3671   pcc->pc.destruct = genericDestruct;
3672   pcc->pc.print = genericPrint;
3673
3674   if(cP)
3675     pcc->comment = Safe_strdup(cP);
3676   else
3677     pcc->comment = NULL;
3678
3679   return ( (pCode *)pcc);
3680
3681 }
3682
3683 /*-----------------------------------------------------------------*/
3684 /* pic16_newpCodeFunction -                                              */
3685 /*-----------------------------------------------------------------*/
3686
3687
3688 pCode *pic16_newpCodeFunction(char *mod,char *f)
3689 {
3690   pCodeFunction *pcf;
3691
3692   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3693
3694   pcf->pc.type = PC_FUNCTION;
3695   pcf->pc.prev = pcf->pc.next = NULL;
3696   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3697   pcf->pc.pb = NULL;
3698
3699   //  pcf->pc.analyze = genericAnalyze;
3700   pcf->pc.destruct = genericDestruct;
3701   pcf->pc.print = pCodePrintFunction;
3702
3703   pcf->ncalled = 0;
3704   pcf->absblock = 0;
3705   
3706   if(mod) {
3707     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3708     strcpy(pcf->modname,mod);
3709   } else
3710     pcf->modname = NULL;
3711
3712   if(f) {
3713     pcf->fname = Safe_calloc(1,strlen(f)+1);
3714     strcpy(pcf->fname,f);
3715   } else
3716     pcf->fname = NULL;
3717
3718   pcf->stackusage = 0;
3719
3720   return ( (pCode *)pcf);
3721 }
3722
3723 /*-----------------------------------------------------------------*/
3724 /* pic16_newpCodeFlow                                                    */
3725 /*-----------------------------------------------------------------*/
3726 static void destructpCodeFlow(pCode *pc)
3727 {
3728   if(!pc || !isPCFL(pc))
3729     return;
3730
3731 /*
3732   if(PCFL(pc)->from)
3733   if(PCFL(pc)->to)
3734 */
3735   pic16_unlinkpCode(pc);
3736
3737   deleteSet(&PCFL(pc)->registers);
3738   deleteSet(&PCFL(pc)->from);
3739   deleteSet(&PCFL(pc)->to);
3740
3741   /* Instead of deleting the memory used by this pCode, mark
3742    * the object as bad so that if there's a pointer to this pCode
3743    * dangling around somewhere then (hopefully) when the type is
3744    * checked we'll catch it.
3745    */
3746
3747   pc->type = PC_BAD;
3748   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3749
3750 //  Safe_free(pc);
3751
3752 }
3753
3754 pCode *pic16_newpCodeFlow(void )
3755 {
3756   pCodeFlow *pcflow;
3757
3758   //_ALLOC(pcflow,sizeof(pCodeFlow));
3759   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3760
3761   pcflow->pc.type = PC_FLOW;
3762   pcflow->pc.prev = pcflow->pc.next = NULL;
3763   pcflow->pc.pb = NULL;
3764
3765   //  pcflow->pc.analyze = genericAnalyze;
3766   pcflow->pc.destruct = destructpCodeFlow;
3767   pcflow->pc.print = genericPrint;
3768
3769   pcflow->pc.seq = GpcFlowSeq++;
3770
3771   pcflow->from = pcflow->to = NULL;
3772
3773   pcflow->inCond = PCC_NONE;
3774   pcflow->outCond = PCC_NONE;
3775
3776   pcflow->firstBank = -1;
3777   pcflow->lastBank = -1;
3778
3779   pcflow->FromConflicts = 0;
3780   pcflow->ToConflicts = 0;
3781
3782   pcflow->end = NULL;
3783
3784   pcflow->registers = newSet();
3785
3786   return ( (pCode *)pcflow);
3787
3788 }
3789
3790 /*-----------------------------------------------------------------*/
3791 /*-----------------------------------------------------------------*/
3792 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3793 {
3794   pCodeFlowLink *pcflowLink;
3795
3796   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3797
3798   pcflowLink->pcflow = pcflow;
3799   pcflowLink->bank_conflict = 0;
3800
3801   return pcflowLink;
3802 }
3803
3804 /*-----------------------------------------------------------------*/
3805 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3806 /*-----------------------------------------------------------------*/
3807
3808 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3809 {
3810
3811   pCodeCSource *pccs;
3812     
3813   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3814
3815   pccs->pc.type = PC_CSOURCE;
3816   pccs->pc.prev = pccs->pc.next = NULL;
3817   pccs->pc.pb = NULL;
3818
3819   pccs->pc.destruct = genericDestruct;
3820   pccs->pc.print = genericPrint;
3821
3822   pccs->line_number = ln;
3823   if(l)
3824     pccs->line = Safe_strdup(l);
3825   else
3826     pccs->line = NULL;
3827
3828   if(f)
3829     pccs->file_name = Safe_strdup(f);
3830   else
3831     pccs->file_name = NULL;
3832
3833   return ( (pCode *)pccs);
3834
3835 }
3836
3837
3838 /*******************************************************************/
3839 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3840 /*                      added by VR 6-Jun-2003                     */
3841 /*******************************************************************/
3842
3843 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3844 {
3845   pCodeAsmDir *pcad;
3846   va_list ap;
3847   char buffer[512];
3848   char *lbp=buffer;
3849   
3850         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3851         pcad->pci.pc.type = PC_ASMDIR;
3852         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3853         pcad->pci.pc.pb = NULL;
3854         pcad->pci.isize = 2;
3855         pcad->pci.pc.destruct = genericDestruct;
3856         pcad->pci.pc.print = genericPrint;
3857
3858         if(asdir && *asdir) {
3859                 
3860                 while(isspace((unsigned char)*asdir))asdir++;   // strip any white space from the beginning
3861                 
3862                 pcad->directive = Safe_strdup( asdir );
3863         }
3864         
3865         va_start(ap, argfmt);
3866         
3867         memset(buffer, 0, sizeof(buffer));
3868         if(argfmt && *argfmt)
3869                 vsprintf(buffer, argfmt, ap);
3870         
3871         va_end(ap);
3872         
3873         while(isspace((unsigned char)*lbp))lbp++;
3874         
3875         if(lbp && *lbp)
3876                 pcad->arg = Safe_strdup( lbp );
3877
3878   return ((pCode *)pcad);
3879 }
3880
3881 /*-----------------------------------------------------------------*/
3882 /* pCodeLabelDestruct - free memory used by a label.               */
3883 /*-----------------------------------------------------------------*/
3884 static void pCodeLabelDestruct(pCode *pc)
3885 {
3886
3887   if(!pc)
3888     return;
3889
3890 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3891 //    Safe_free(PCL(pc)->label);
3892
3893   /* Instead of deleting the memory used by this pCode, mark
3894    * the object as bad so that if there's a pointer to this pCode
3895    * dangling around somewhere then (hopefully) when the type is
3896    * checked we'll catch it.
3897    */
3898
3899   pc->type = PC_BAD;
3900   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3901
3902 //  Safe_free(pc);
3903
3904 }
3905
3906 pCode *pic16_newpCodeLabel(char *name, int key)
3907 {
3908
3909   char *s = buffer;
3910   pCodeLabel *pcl;
3911     
3912   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3913
3914   pcl->pc.type = PC_LABEL;
3915   pcl->pc.prev = pcl->pc.next = NULL;
3916   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3917   pcl->pc.pb = NULL;
3918
3919   //  pcl->pc.analyze = genericAnalyze;
3920   pcl->pc.destruct = pCodeLabelDestruct;
3921   pcl->pc.print = pCodePrintLabel;
3922
3923   pcl->key = key;
3924   pcl->force = 0;
3925   
3926   pcl->label = NULL;
3927   if(key>0) {
3928     sprintf(s,"_%05d_DS_",key);
3929   } else
3930     s = name;
3931
3932   if(s)
3933     pcl->label = Safe_strdup(s);
3934
3935 //  if(pic16_pcode_verbose)
3936 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3937
3938
3939   return ( (pCode *)pcl);
3940
3941 }
3942
3943 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3944 {
3945   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3946   
3947         pcl->force = 1;
3948   
3949   return ( (pCode *)pcl );
3950 }
3951
3952 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3953 {
3954   pCodeInfo *pci;
3955
3956     pci = Safe_calloc(1, sizeof(pCodeInfo));
3957     pci->pci.pc.type = PC_INFO;
3958     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3959     pci->pci.pc.pb = NULL;
3960     pci->pci.label = NULL;
3961         
3962     pci->pci.pc.destruct = genericDestruct;
3963     pci->pci.pc.print = genericPrint;
3964     
3965     pci->type = type;
3966     pci->oper1 = pcop;
3967   
3968   return ((pCode *)pci);
3969 }
3970
3971
3972 /*-----------------------------------------------------------------*/
3973 /* newpBlock - create and return a pointer to a new pBlock         */
3974 /*-----------------------------------------------------------------*/
3975 static pBlock *newpBlock(void)
3976 {
3977
3978   pBlock *PpB;
3979
3980   PpB = Safe_calloc(1,sizeof(pBlock) );
3981   PpB->next = PpB->prev = NULL;
3982
3983   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3984   PpB->tregisters = NULL;
3985   PpB->visited = 0;
3986   PpB->FlowTree = NULL;
3987
3988   return PpB;
3989
3990 }
3991
3992 /*-----------------------------------------------------------------*/
3993 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3994 /*-----------------------------------------------------------------*
3995  *
3996  *  This function will create a new pBlock and the pointer to the
3997  *  pCode that is passed in will be the first pCode in the block.
3998  *-----------------------------------------------------------------*/
3999
4000
4001 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4002 {
4003
4004   pBlock *pB  = newpBlock();
4005
4006   pB->pcHead  = pB->pcTail = pc;
4007   pB->cmemmap = cm;
4008   pB->dbName  = c;
4009
4010   return pB;
4011 }
4012
4013
4014
4015 /*-----------------------------------------------------------------*/
4016 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4017 /*  Note, a negative key means that the label is part of wild card */
4018 /*  (and hence a wild card label) used in the pCodePeep            */
4019 /*   optimizations).                                               */
4020 /*-----------------------------------------------------------------*/
4021
4022 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4023 {
4024   char *s=NULL;
4025   static int label_key=-1;
4026
4027   pCodeOp *pcop;
4028
4029   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4030   pcop->type = PO_LABEL;
4031
4032   pcop->name = NULL;
4033
4034   if(key>0)
4035     sprintf(s=buffer,"_%05d_DS_",key);
4036   else 
4037     s = name, key = label_key--;
4038
4039   if(s)
4040     pcop->name = Safe_strdup(s);
4041
4042   ((pCodeOpLabel *)pcop)->key = key;
4043
4044   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4045   return pcop;
4046 }
4047
4048 /*-----------------------------------------------------------------*/
4049 /*-----------------------------------------------------------------*/
4050 pCodeOp *pic16_newpCodeOpLit(int lit)
4051 {
4052   char *s = buffer;
4053   pCodeOp *pcop;
4054
4055
4056   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4057   pcop->type = PO_LITERAL;
4058
4059   pcop->name = NULL;
4060   //if(lit>=0)
4061     sprintf(s,"0x%02hhx", (unsigned char)lit);
4062   //else
4063   //  sprintf(s, "%i", lit);
4064   
4065   if(s)
4066     pcop->name = Safe_strdup(s);
4067
4068   ((pCodeOpLit *)pcop)->lit = lit;
4069
4070   return pcop;
4071 }
4072
4073 /* Allow for 12 bit literals, required for LFSR */
4074 pCodeOp *pic16_newpCodeOpLit12(int lit)
4075 {
4076   char *s = buffer;
4077   pCodeOp *pcop;
4078
4079
4080   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4081   pcop->type = PO_LITERAL;
4082
4083   pcop->name = NULL;
4084   //if(lit>=0)
4085     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4086   //else
4087   //  sprintf(s, "%i", lit);
4088   
4089   if(s)
4090     pcop->name = Safe_strdup(s);
4091
4092   ((pCodeOpLit *)pcop)->lit = lit;
4093
4094   return pcop;
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /*-----------------------------------------------------------------*/
4099 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4100 {
4101   char *s = buffer, tbuf[256], *tb=tbuf;
4102   pCodeOp *pcop;
4103
4104
4105   tb = pic16_get_op(arg2, NULL, 0);
4106   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4107   pcop->type = PO_LITERAL;
4108
4109   pcop->name = NULL;
4110   //if(lit>=0) {
4111     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4112     if(s)
4113       pcop->name = Safe_strdup(s);
4114   //}
4115
4116   ((pCodeOpLit2 *)pcop)->lit = lit;
4117   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4118
4119   return pcop;
4120 }
4121
4122 /*-----------------------------------------------------------------*/
4123 /*-----------------------------------------------------------------*/
4124 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4125 {
4126   pCodeOp *pcop;
4127
4128         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4129         pcop->type = PO_IMMEDIATE;
4130         if(name) {
4131                 regs *r = pic16_dirregWithName(name);
4132                 pcop->name = Safe_strdup(name);
4133                 PCOI(pcop)->r = r;
4134                 
4135                 if(r) {
4136 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4137                         PCOI(pcop)->rIdx = r->rIdx;
4138                 } else {
4139 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4140                         PCOI(pcop)->rIdx = -1;
4141                 }
4142 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4143         } else {
4144                 pcop->name = NULL;
4145                 PCOI(pcop)->rIdx = -1;
4146         }
4147
4148         PCOI(pcop)->index = index;
4149         PCOI(pcop)->offset = offset;
4150         PCOI(pcop)->_const = code_space;
4151
4152   return pcop;
4153 }
4154
4155 /*-----------------------------------------------------------------*/
4156 /*-----------------------------------------------------------------*/
4157 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4158 {
4159   char *s = buffer;
4160   pCodeOp *pcop;
4161
4162
4163   if(!pcwb || !subtype) {
4164     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4165     exit(1);
4166   }
4167
4168   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4169   pcop->type = PO_WILD;
4170   sprintf(s,"%%%d",id);
4171   pcop->name = Safe_strdup(s);
4172
4173   PCOW(pcop)->id = id;
4174   PCOW(pcop)->pcwb = pcwb;
4175   PCOW(pcop)->subtype = subtype;
4176   PCOW(pcop)->matched = NULL;
4177
4178   PCOW(pcop)->pcop2 = NULL;
4179   
4180   return pcop;
4181 }
4182
4183 /*-----------------------------------------------------------------*/
4184 /*-----------------------------------------------------------------*/
4185 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4186 {
4187   char *s = buffer;
4188   pCodeOp *pcop;
4189
4190
4191         if(!pcwb || !subtype || !subtype2) {
4192                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4193                 exit(1);
4194         }
4195
4196         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4197         pcop->type = PO_WILD;
4198         sprintf(s,"%%%d",id);
4199         pcop->name = Safe_strdup(s);
4200
4201         PCOW(pcop)->id = id;
4202         PCOW(pcop)->pcwb = pcwb;
4203         PCOW(pcop)->subtype = subtype;
4204         PCOW(pcop)->matched = NULL;
4205
4206         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4207
4208         if(!subtype2->name) {
4209                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4210                 PCOW2(pcop)->pcop.type = PO_WILD;
4211                 sprintf(s, "%%%d", id2);
4212                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4213                 PCOW2(pcop)->id = id2;
4214                 PCOW2(pcop)->subtype = subtype2;
4215
4216 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4217 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4218         } else {
4219                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4220
4221 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4222 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4223         }
4224   
4225
4226
4227   return pcop;
4228 }
4229
4230
4231 /*-----------------------------------------------------------------*/
4232 /*-----------------------------------------------------------------*/
4233 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4234 {
4235   pCodeOp *pcop;
4236   
4237   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4238   pcop->type = PO_GPR_BIT;
4239   if(s)
4240     pcop->name = Safe_strdup(s);   
4241   else
4242     pcop->name = NULL;
4243
4244   PCORB(pcop)->bit = bit;
4245   PCORB(pcop)->inBitSpace = inBitSpace;
4246   PCORB(pcop)->subtype = subt;
4247
4248   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4249   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4250 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4251 //  PCOR(pcop)->rIdx = 0;
4252   return pcop;
4253 }
4254
4255 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4256 {
4257   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4258                                 bit, 0, PO_GPR_REGISTER);
4259 }
4260
4261
4262 /*-----------------------------------------------------------------*
4263  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4264  *
4265  * If rIdx >=0 then a specific register from the set of registers
4266  * will be selected. If rIdx <0, then a new register will be searched
4267  * for.
4268  *-----------------------------------------------------------------*/
4269
4270 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4271 {
4272   pCodeOp *pcop;
4273   regs *r;
4274
4275   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4276
4277   pcop->name = NULL;
4278
4279   if(rIdx >= 0) {
4280         r = pic16_regWithIdx(rIdx);
4281         if(!r)
4282                 r = pic16_allocWithIdx(rIdx);
4283   } else {
4284     r = pic16_findFreeReg(REG_GPR);
4285
4286     if(!r) {
4287         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4288                 __FUNCTION__, __LINE__);
4289         exit(EXIT_FAILURE);
4290     }
4291   }
4292
4293   PCOR(pcop)->rIdx = rIdx;
4294   PCOR(pcop)->r = r;
4295   pcop->type = PCOR(pcop)->r->pc_type;
4296
4297   return pcop;
4298 }
4299
4300 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4301 {
4302   pCodeOp *pcop;
4303   regs *r;
4304   
4305     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4306     pcop->name = NULL;
4307     
4308     r = pic16_findFreeReg(REG_GPR);
4309
4310     while(r) {
4311       if(!bitVectBitValue(bv, r->rIdx)) {
4312         PCOR(pcop)->r = r;
4313         PCOR(pcop)->rIdx = r->rIdx;
4314         pcop->type = r->pc_type;
4315         return (pcop);
4316       }
4317       
4318       r = pic16_findFreeRegNext(REG_GPR, r);
4319     }
4320   
4321   return NULL;
4322 }
4323
4324       
4325
4326 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4327 {
4328   pCodeOp *pcop;
4329   regs *r;
4330
4331         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4332         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4333         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4334         pcop->type = PCOR(pcop)->r->pc_type;
4335         pcop->name = PCOR(pcop)->r->name;
4336
4337 //      if(pic16_pcode_verbose) {
4338 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4339 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4340 //      }
4341
4342   return pcop;
4343 }
4344
4345 /*-----------------------------------------------------------------*/
4346 /*-----------------------------------------------------------------*/
4347 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4348 {
4349   pCodeOpOpt *pcop;
4350
4351         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4352         
4353         pcop->type = type;
4354         pcop->key = Safe_strdup( key );
4355
4356   return (PCOP(pcop));
4357 }
4358
4359 /*-----------------------------------------------------------------*/
4360 /*-----------------------------------------------------------------*/
4361 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4362 {
4363   pCodeOpLocalReg *pcop;
4364
4365         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4366         
4367         pcop->type = type;
4368
4369   return (PCOP(pcop));
4370 }
4371
4372
4373 /*-----------------------------------------------------------------*/
4374 /*-----------------------------------------------------------------*/
4375
4376 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4377 {
4378   pCodeOp *pcop;
4379
4380   switch(type) {
4381   case PO_BIT:
4382   case PO_GPR_BIT:
4383     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4384     break;
4385
4386   case PO_LITERAL:
4387     pcop = pic16_newpCodeOpLit(-1);
4388     break;
4389
4390   case PO_LABEL:
4391     pcop = pic16_newpCodeOpLabel(NULL,-1);
4392     break;
4393   case PO_GPR_TEMP:
4394     pcop = pic16_newpCodeOpReg(-1);
4395     break;
4396
4397   case PO_GPR_REGISTER:
4398     if(name)
4399       pcop = pic16_newpCodeOpRegFromStr(name);
4400     else
4401       pcop = pic16_newpCodeOpReg(-1);
4402     break;
4403     
4404   case PO_TWO_OPS:
4405     assert( !"Cannot create PO_TWO_OPS from string!" );
4406     pcop = NULL;
4407     break;
4408
4409   default:
4410     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4411     pcop->type = type;
4412     if(name)
4413       pcop->name = Safe_strdup(name);   
4414     else
4415       pcop->name = NULL;
4416   }
4417
4418   return pcop;
4419 }
4420
4421 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4422 {
4423   pCodeOp2 *pcop2 = Safe_calloc(1, sizeof(pCodeOp2));
4424   pcop2->pcop.type = PO_TWO_OPS;
4425   pcop2->pcopL = src;
4426   pcop2->pcopR = dst;
4427   return PCOP(pcop2);
4428 }
4429
4430 /* This is a multiple of two as gpasm pads DB directives to even length,
4431  * thus the data would be interleaved with \0 bytes...
4432  * This is a multiple of three in order to have arrays of 3-byte pointers
4433  * continuously in memory (without 0-padding at the lines' end).
4434  * This is rather 12 than 6 in order not to split up 4-byte data types
4435  * in arrays right in the middle of a 4-byte word. */
4436 #define DB_ITEMS_PER_LINE       12
4437
4438 typedef struct DBdata
4439   {
4440     int count;
4441     char buffer[512];
4442   } DBdata;
4443
4444 struct DBdata DBd;
4445 static int DBd_init = -1;
4446
4447 /*-----------------------------------------------------------------*/
4448 /*    Initialiase "DB" data buffer                                 */
4449 /*-----------------------------------------------------------------*/
4450 void pic16_initDB(void)
4451 {
4452         DBd_init = -1;
4453 }
4454
4455
4456 /*-----------------------------------------------------------------*/
4457 /*    Flush pending "DB" data to a pBlock                          */
4458 /*                                                                 */
4459 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4460 /*-----------------------------------------------------------------*/
4461 void pic16_flushDB(char ptype, void *p)
4462 {
4463         if (DBd.count>0) {
4464                 if(ptype == 'p')
4465                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4466                 else
4467                 if(ptype == 'f')
4468                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4469                 else {
4470                         /* sanity check */
4471                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4472                 }
4473
4474                 DBd.count = 0;
4475                 DBd.buffer[0] = '\0';
4476         }
4477 }
4478
4479
4480 /*-----------------------------------------------------------------*/
4481 /*    Add "DB" directives to a pBlock                              */
4482 /*-----------------------------------------------------------------*/
4483 void pic16_emitDB(int c, char ptype, void *p)
4484 {
4485   int l;
4486
4487         if (DBd_init<0) {
4488          // we need to initialize
4489                 DBd_init = 0;
4490                 DBd.count = 0;
4491                 DBd.buffer[0] = '\0';
4492         }
4493
4494         l = strlen(DBd.buffer);
4495         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4496
4497 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4498         
4499         DBd.count++;
4500         if (DBd.count>= DB_ITEMS_PER_LINE)
4501                 pic16_flushDB(ptype, p);
4502 }
4503
4504 void pic16_emitDS(char *s, char ptype, void *p)
4505 {
4506   int l;
4507
4508         if (DBd_init<0) {
4509          // we need to initialize
4510                 DBd_init = 0;
4511                 DBd.count = 0;
4512                 DBd.buffer[0] = '\0';
4513         }
4514
4515         l = strlen(DBd.buffer);
4516         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4517
4518 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4519
4520         DBd.count++;    //=strlen(s);
4521         if (DBd.count>=DB_ITEMS_PER_LINE)
4522                 pic16_flushDB(ptype, p);
4523 }
4524
4525
4526 /*-----------------------------------------------------------------*/
4527 /*-----------------------------------------------------------------*/
4528 void pic16_pCodeConstString(char *name, char *value)
4529 {
4530   pBlock *pb;
4531   char *item;
4532   static set *emittedSymbols = NULL;
4533
4534   if(!name || !value)
4535     return;
4536
4537   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4538   if (emittedSymbols) {
4539     /* scan set for name */
4540     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4541     {
4542       if (!strcmp (item,name)) {
4543         //fprintf (stderr, "%s already emitted\n", name);
4544         return;
4545       } // if
4546     } // for
4547   } // if
4548   addSet (&emittedSymbols, Safe_strdup (name));
4549
4550   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4551
4552   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4553
4554   pic16_addpBlock(pb);
4555
4556 //  sprintf(buffer,"; %s = ", name);
4557 //  strcat(buffer, value);
4558 //  fputs(buffer, stderr);
4559
4560 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4561   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4562
4563   do {
4564         pic16_emitDB(*value, 'p', (void *)pb);
4565   }while (*value++);
4566   pic16_flushDB('p', (void *)pb);
4567 }
4568
4569 /*-----------------------------------------------------------------*/
4570 /*-----------------------------------------------------------------*/
4571 #if 0
4572 static void pCodeReadCodeTable(void)
4573 {
4574   pBlock *pb;
4575
4576   fprintf(stderr, " %s\n",__FUNCTION__);
4577
4578   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4579
4580   pic16_addpBlock(pb);
4581
4582   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4583   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4584   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4585   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4586
4587   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4588   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4589   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4590   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4591
4592
4593 }
4594 #endif
4595 /*-----------------------------------------------------------------*/
4596 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4597 /*-----------------------------------------------------------------*/
4598 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4599 {
4600
4601   if(!pc)
4602     return;
4603
4604   if(!pb->pcHead) {
4605     /* If this is the first pcode to be added to a block that
4606      * was initialized with a NULL pcode, then go ahead and
4607      * make this pcode the head and tail */
4608     pb->pcHead  = pb->pcTail = pc;
4609   } else {
4610     //    if(pb->pcTail)
4611     pb->pcTail->next = pc;
4612
4613     pc->prev = pb->pcTail;
4614     pc->pb = pb;
4615
4616     pb->pcTail = pc;
4617   }
4618 }
4619
4620 /*-----------------------------------------------------------------*/
4621 /* pic16_addpBlock - place a pBlock into the pFile                 */
4622 /*-----------------------------------------------------------------*/
4623 void pic16_addpBlock(pBlock *pb)
4624 {
4625   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4626
4627   if(!the_pFile) {
4628     /* First time called, we'll pass through here. */
4629     //_ALLOC(the_pFile,sizeof(pFile));
4630     the_pFile = Safe_calloc(1,sizeof(pFile));
4631     the_pFile->pbHead = the_pFile->pbTail = pb;
4632     the_pFile->functions = NULL;
4633     return;
4634   }
4635
4636   the_pFile->pbTail->next = pb;
4637   pb->prev = the_pFile->pbTail;
4638   pb->next = NULL;
4639   the_pFile->pbTail = pb;
4640 }
4641
4642 /*-----------------------------------------------------------------*/
4643 /* removepBlock - remove a pBlock from the pFile                   */
4644 /*-----------------------------------------------------------------*/
4645 static void removepBlock(pBlock *pb)
4646 {
4647   pBlock *pbs;
4648
4649   if(!the_pFile)
4650     return;
4651
4652
4653   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4654
4655   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4656     if(pbs == pb) {
4657
4658       if(pbs == the_pFile->pbHead)
4659         the_pFile->pbHead = pbs->next;
4660
4661       if (pbs == the_pFile->pbTail) 
4662         the_pFile->pbTail = pbs->prev;
4663
4664       if(pbs->next)
4665         pbs->next->prev = pbs->prev;
4666
4667       if(pbs->prev)
4668         pbs->prev->next = pbs->next;
4669
4670       return;
4671
4672     }
4673   }
4674
4675   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4676
4677 }
4678
4679 /*-----------------------------------------------------------------*/
4680 /* printpCode - write the contents of a pCode to a file            */
4681 /*-----------------------------------------------------------------*/
4682 static void printpCode(FILE *of, pCode *pc)
4683 {
4684
4685   if(!pc || !of)
4686     return;
4687
4688   if(pc->print) {
4689     pc->print(of,pc);
4690     return;
4691   }
4692
4693   fprintf(of,"warning - unable to print pCode\n");
4694 }
4695
4696 /*-----------------------------------------------------------------*/
4697 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4698 /*-----------------------------------------------------------------*/
4699 void pic16_printpBlock(FILE *of, pBlock *pb)
4700 {
4701   pCode *pc;
4702
4703         if(!pb)return;
4704
4705         if(!of)of=stderr;
4706
4707         for(pc = pb->pcHead; pc; pc = pc->next) {
4708                 if(isPCF(pc) && PCF(pc)->fname) {
4709                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4710                         if(pb->dbName == 'A') {
4711                           absSym *ab;
4712                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4713 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4714                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4715 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4716                                                 if(ab->address != -1)
4717                                                   fprintf(of, "\t0X%06X", ab->address);
4718                                                 break;
4719                                         }
4720                                 }
4721                         }
4722                         fprintf(of, "\n");
4723                 }
4724                 printpCode(of,pc);
4725         }
4726 }
4727
4728 /*-----------------------------------------------------------------*/
4729 /*                                                                 */
4730 /*       pCode processing                                          */
4731 /*                                                                 */
4732 /*                                                                 */
4733 /*                                                                 */
4734 /*-----------------------------------------------------------------*/
4735 pCode * pic16_findNextInstruction(pCode *pci);
4736 pCode * pic16_findPrevInstruction(pCode *pci);
4737
4738 void pic16_unlinkpCode(pCode *pc)
4739 {
4740   pCode *prev;
4741
4742   if(pc) {
4743 #ifdef PCODE_DEBUG
4744     fprintf(stderr,"Unlinking: ");
4745     printpCode(stderr, pc);
4746 #endif
4747     if(pc->prev) 
4748       pc->prev->next = pc->next;
4749     if(pc->next)
4750       pc->next->prev = pc->prev;
4751
4752     /* move C source line down (or up) */
4753     if (isPCI(pc) && PCI(pc)->cline) {
4754       prev = pic16_findNextInstruction (pc->next);
4755       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4756         PCI(prev)->cline = PCI(pc)->cline;
4757       } else {
4758         prev = pic16_findPrevInstruction (pc->prev);
4759         if (prev && isPCI(prev) && !PCI(prev)->cline)
4760           PCI(prev)->cline = PCI(pc)->cline;
4761       }
4762     }
4763     pc->prev = pc->next = NULL;
4764   }
4765 }
4766
4767 /*-----------------------------------------------------------------*/
4768 /*-----------------------------------------------------------------*/
4769
4770 static void genericDestruct(pCode *pc)
4771 {
4772
4773   pic16_unlinkpCode(pc);
4774
4775   if(isPCI(pc)) {
4776     /* For instructions, tell the register (if there's one used)
4777      * that it's no longer needed */
4778     regs *reg = pic16_getRegFromInstruction(pc);
4779     if(reg)
4780       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4781
4782         if(PCI(pc)->is2MemOp) {
4783                 reg = pic16_getRegFromInstruction2(pc);
4784                 if(reg)
4785                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4786         }
4787   }
4788
4789   /* Instead of deleting the memory used by this pCode, mark
4790    * the object as bad so that if there's a pointer to this pCode
4791    * dangling around somewhere then (hopefully) when the type is
4792    * checked we'll catch it.
4793    */
4794
4795   pc->type = PC_BAD;
4796   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4797
4798   //Safe_free(pc);
4799 }
4800
4801
4802 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4803 /*-----------------------------------------------------------------*/
4804 /*-----------------------------------------------------------------*/
4805 /* modifiers for constant immediate */
4806 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4807
4808 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4809 {
4810   regs *r;
4811   static char b[128];
4812   char *s;
4813   int use_buffer = 1;    // copy the string to the passed buffer pointer
4814
4815         if(!buffer) {
4816                 buffer = b;
4817                 size = sizeof(b);
4818                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4819         } 
4820
4821         if(pcop) {
4822
4823                 switch(pcop->type) {
4824                         case PO_W:
4825                         case PO_WREG:
4826                         case PO_PRODL:
4827                         case PO_PRODH:
4828                         case PO_INDF0:
4829                         case PO_FSR0:
4830                                 if(use_buffer) {
4831                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4832                                         return (buffer);
4833                                 }
4834                                 return (PCOR(pcop)->r->name);
4835                                 break;
4836                         case PO_GPR_TEMP:
4837                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4838                                 if(use_buffer) {
4839                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4840                                         return (buffer);
4841                                 }
4842                                 return (r->name);
4843
4844                         case PO_IMMEDIATE:
4845                                 s = buffer;
4846                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4847                                         if(PCOI(pcop)->index) {
4848                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4849                                                         immdmod[ PCOI(pcop)->offset ],
4850                                                         pcop->name,
4851                                                         PCOI(pcop)->index);
4852                                         } else {
4853                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4854                                                         immdmod[ PCOI(pcop)->offset ],
4855                                                         pcop->name);
4856                                         }
4857                                 } else {
4858                                         if(PCOI(pcop)->index) {
4859                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4860                                                         immdmod[ 0 ],
4861                                                         pcop->name,
4862                                                         PCOI(pcop)->index);
4863                                         } else {
4864                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4865                                                         immdmod[ 0 ],
4866                                                         pcop->name);
4867                                         }
4868                                 }
4869                                 return (buffer);
4870
4871                         case PO_GPR_REGISTER:
4872                         case PO_DIR:
4873                                 s = buffer;
4874 //                              size = sizeof(buffer);
4875                                 if( PCOR(pcop)->instance) {
4876                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4877                                                 pcop->name,
4878                                                 PCOR(pcop)->instance );
4879                                 } else {
4880                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4881                                 }
4882                                 return (buffer);
4883                         case PO_GPR_BIT:
4884                                 s = buffer;
4885                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4886                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4887                                 } else {
4888                                         if(PCORB(pcop)->pcor.instance)
4889                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4890                                         else
4891                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4892                                 }
4893
4894                                 return (buffer);
4895                         case PO_TWO_OPS:
4896                                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4897                                 
4898                         default:
4899                                 if(pcop->name) {
4900                                         if(use_buffer) {
4901                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4902                                                 return (buffer);
4903                                         }
4904                                 return (pcop->name);
4905                                 }
4906
4907                 }
4908                 return ("unhandled type for op1");
4909         }
4910
4911   return ("NO operand1");
4912 }
4913
4914 /*-----------------------------------------------------------------*/
4915 /* pic16_get_op2 - variant to support two memory operand commands  */
4916 /*-----------------------------------------------------------------*/
4917 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4918 {
4919
4920   if(pcop && pcop->type == PO_TWO_OPS) {
4921     return pic16_get_op( PCOP2(pcop)->pcopR, buffer, size );
4922   }
4923
4924   return "NO operand2";
4925 }
4926
4927 /*-----------------------------------------------------------------*/
4928 /*-----------------------------------------------------------------*/
4929 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4930 {
4931
4932   if(pcc )
4933     return pic16_get_op(pcc->pcop,NULL,0);
4934
4935   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
4936    *   return ("ERROR Null: "__FUNCTION__);
4937    */
4938   return ("ERROR Null: pic16_get_op_from_instruction");
4939
4940 }
4941
4942 /*-----------------------------------------------------------------*/
4943 /*-----------------------------------------------------------------*/
4944 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4945 {
4946
4947   fprintf(of,"pcodeopprint- not implemented\n");
4948 }
4949
4950 /*-----------------------------------------------------------------*/
4951 /* pic16_pCode2str - convert a pCode instruction to string               */
4952 /*-----------------------------------------------------------------*/
4953 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4954 {
4955   char *s = str;
4956   regs *r;
4957
4958 #if 0
4959         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4960                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4961                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4962 //              exit(EXIT_FAILURE);
4963         }
4964 #endif
4965
4966   switch(pc->type) {
4967
4968   case PC_OPCODE:
4969     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4970
4971     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4972
4973         //if(PCI(pc)->is2MemOp)
4974         if (PCI(pc)->pcop->type == PO_TWO_OPS)
4975         {
4976                 /* split into two phases due to static buffer in pic16_get_op() */
4977                 SAFE_snprintf(&s,&size, "%s", 
4978                         pic16_get_op((PCI(pc)->pcop), NULL, 0));
4979                 SAFE_snprintf(&s, &size, ", %s",
4980                         pic16_get_op2((PCI(pc)->pcop), NULL, 0));
4981                 break;
4982         }
4983
4984         if(PCI(pc)->is2LitOp) {
4985                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4986                 break;
4987         }
4988
4989       if(PCI(pc)->isBitInst) {
4990         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
4991           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
4992             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
4993                           PCI(pc)->pcop->name ,
4994                           PCI(pc)->pcop->name );
4995           else
4996             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
4997 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
4998                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
4999                           
5000         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5001           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5002         } else
5003           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5004         //PCI(pc)->pcop->t.bit );
5005       } else {
5006
5007         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5008           if( PCI(pc)->num_ops == 3)
5009             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5010           else
5011             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5012
5013         }
5014         else 
5015         {
5016           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5017         }
5018       }
5019         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5020           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5021             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5022
5023           r = pic16_getRegFromInstruction(pc);
5024 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5025 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?isACCESS_BANK(r):-1);
5026
5027           if(PCI(pc)->isAccess) {
5028             static char *bank_spec[2][2] = {
5029               { "", ", ACCESS" },  /* gpasm uses access bank by default */
5030               { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5031             };
5032              
5033             SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5034           }
5035         }
5036 //      
5037
5038     }
5039     break;
5040
5041   case PC_COMMENT:
5042     /* assuming that comment ends with a \n */
5043     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5044     break;
5045
5046   case PC_INFO:
5047     SAFE_snprintf(&s,&size,"; info ==>");
5048     switch( PCINF(pc)->type ) {
5049       case INF_OPTIMIZATION:
5050           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5051           break;
5052       case INF_LOCALREGS:
5053           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5054           break;
5055     }; break;
5056
5057   case PC_INLINE:
5058     /* assuming that inline code ends with a \n */
5059     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5060     break;
5061
5062   case PC_LABEL:
5063     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5064     break;
5065   case PC_FUNCTION:
5066     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5067     break;
5068   case PC_WILD:
5069     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5070     break;
5071   case PC_FLOW:
5072     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5073     break;
5074   case PC_CSOURCE:
5075 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5076       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5077         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5078     break;
5079   case PC_ASMDIR:
5080         if(PCAD(pc)->directive) {
5081                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5082         } else
5083         if(PCAD(pc)->arg) {
5084                 /* special case to handle inline labels without a tab */
5085                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5086         }
5087         break;
5088
5089   case PC_BAD:
5090     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5091     break;
5092   }
5093
5094   return str;
5095
5096 }
5097
5098 /*-----------------------------------------------------------------*/
5099 /* genericPrint - the contents of a pCode to a file                */
5100 /*-----------------------------------------------------------------*/
5101 static void genericPrint(FILE *of, pCode *pc)
5102 {
5103
5104   if(!pc || !of)
5105     return;
5106
5107   switch(pc->type) {
5108   case PC_COMMENT:
5109 //    fputs(((pCodeComment *)pc)->comment, of);
5110     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5111     break;
5112
5113   case PC_INFO:
5114     {
5115       pBranch *pbl = PCI(pc)->label;
5116       while(pbl && pbl->pc) {
5117         if(pbl->pc->type == PC_LABEL)
5118           pCodePrintLabel(of, pbl->pc);
5119         pbl = pbl->next;
5120       }
5121     }
5122           
5123     if(pic16_pcode_verbose) {
5124       fprintf(of, "; info ==>");
5125       switch(((pCodeInfo *)pc)->type) {
5126         case INF_OPTIMIZATION:
5127               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5128               break;
5129         case INF_LOCALREGS:
5130               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5131               break;
5132         }
5133     };
5134     
5135     break;
5136
5137   case PC_INLINE:
5138     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5139      break;
5140
5141   case PC_OPCODE:
5142     // If the opcode has a label, print that first
5143     {
5144       pBranch *pbl = PCI(pc)->label;
5145       while(pbl && pbl->pc) {
5146         if(pbl->pc->type == PC_LABEL)
5147           pCodePrintLabel(of, pbl->pc);
5148         pbl = pbl->next;
5149       }
5150     }
5151
5152     if(PCI(pc)->cline) 
5153       genericPrint(of,PCODE(PCI(pc)->cline));
5154
5155     {
5156       char str[256];
5157       
5158       pic16_pCode2str(str, 256, pc);
5159
5160       fprintf(of,"%s",str);
5161       /* Debug */
5162       if(pic16_debug_verbose) {
5163         fprintf(of, "\t;key=%03x",pc->seq);
5164         if(PCI(pc)->pcflow)
5165           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5166       }
5167     }
5168     fprintf(of, "\n");
5169     break;
5170       
5171   case PC_WILD:
5172     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5173     if(PCW(pc)->pci.label)
5174       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5175
5176     if(PCW(pc)->operand) {
5177       fprintf(of,";\toperand  ");
5178       pCodeOpPrint(of,PCW(pc)->operand );
5179     }
5180     break;
5181
5182   case PC_FLOW:
5183     if(pic16_debug_verbose) {
5184       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5185       if(PCFL(pc)->ancestor)
5186         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5187       fprintf(of,"\n");
5188
5189     }
5190     break;
5191
5192   case PC_CSOURCE:
5193 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5194     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5195         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5196          
5197     break;
5198
5199   case PC_ASMDIR:
5200         {
5201           pBranch *pbl = PCAD(pc)->pci.label;
5202                 while(pbl && pbl->pc) {
5203                         if(pbl->pc->type == PC_LABEL)
5204                                 pCodePrintLabel(of, pbl->pc);
5205                         pbl = pbl->next;
5206                 }
5207         }
5208         if(PCAD(pc)->directive) {
5209                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5210         } else
5211         if(PCAD(pc)->arg) {
5212                 /* special case to handle inline labels without tab */
5213                 fprintf(of, "%s\n", PCAD(pc)->arg);
5214         }
5215         break;
5216         
5217   case PC_LABEL:
5218   default:
5219     fprintf(of,"unknown pCode type %d\n",pc->type);
5220   }
5221
5222 }
5223
5224 /*-----------------------------------------------------------------*/
5225 /* pCodePrintFunction - prints function begin/end                  */
5226 /*-----------------------------------------------------------------*/
5227
5228 static void pCodePrintFunction(FILE *of, pCode *pc)
5229 {
5230
5231   if(!pc || !of)
5232     return;
5233
5234 #if 0
5235   if( ((pCodeFunction *)pc)->modname) 
5236     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5237 #endif
5238
5239   if(!PCF(pc)->absblock) {
5240       if(PCF(pc)->fname) {
5241       pBranch *exits = PCF(pc)->to;
5242       int i=0;
5243
5244       fprintf(of,"%s:", PCF(pc)->fname);
5245     
5246       if(pic16_pcode_verbose)
5247         fprintf(of, "\t;Function start");
5248     
5249       fprintf(of, "\n");
5250     
5251       while(exits) {
5252         i++;
5253         exits = exits->next;
5254       }
5255       //if(i) i--;
5256
5257       if(pic16_pcode_verbose)
5258         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5259     
5260     } else {
5261         if((PCF(pc)->from && 
5262                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5263                 PCF(PCF(pc)->from->pc)->fname) ) {
5264
5265                 if(pic16_pcode_verbose)
5266                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5267         } else {
5268                 if(pic16_pcode_verbose)
5269                         fprintf(of,"; exit point [can't find entry point]\n");
5270         }
5271         fprintf(of, "\n");
5272     }
5273   }
5274 }
5275 /*-----------------------------------------------------------------*/
5276 /* pCodePrintLabel - prints label                                  */
5277 /*-----------------------------------------------------------------*/
5278
5279 static void pCodePrintLabel(FILE *of, pCode *pc)
5280 {
5281
5282   if(!pc || !of)
5283     return;
5284
5285   if(PCL(pc)->label) 
5286     fprintf(of,"%s:\n",PCL(pc)->label);
5287   else if (PCL(pc)->key >=0) 
5288     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5289   else
5290     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5291
5292 }
5293 /*-----------------------------------------------------------------*/
5294 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5295 /*                         remove it if it is found.               */
5296 /*-----------------------------------------------------------------*/
5297 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5298 {
5299   pBranch *b, *bprev;
5300
5301
5302   bprev = NULL;
5303
5304   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5305     b = PCI(pcl)->label;
5306   else {
5307     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5308     exit(1);
5309
5310   }
5311
5312   //fprintf (stderr, "%s \n",__FUNCTION__);
5313   //pcl->print(stderr,pcl);
5314   //pc->print(stderr,pc);
5315   while(b) {
5316     if(b->pc == pc) {
5317       //fprintf (stderr, "found label\n");
5318       //pc->print(stderr, pc);
5319
5320       /* Found a label */
5321       if(bprev) {
5322         bprev->next = b->next;  /* Not first pCode in chain */
5323 //      Safe_free(b);
5324       } else {
5325         pc->destruct(pc);
5326         PCI(pcl)->label = b->next;   /* First pCode in chain */
5327 //      Safe_free(b);
5328       }
5329       return;  /* A label can't occur more than once */
5330     }
5331     bprev = b;
5332     b = b->next;
5333   }
5334
5335 }
5336
5337 /*-----------------------------------------------------------------*/
5338 /*-----------------------------------------------------------------*/
5339 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5340 {
5341   pBranch *b;
5342
5343   if(!h)
5344     return n;
5345
5346   if(h == n)
5347     return n;
5348
5349   b = h;
5350   while(b->next)
5351     b = b->next;
5352
5353   b->next = n;
5354
5355   return h;
5356   
5357 }  
5358 /*-----------------------------------------------------------------*/
5359 /* pBranchLink - given two pcodes, this function will link them    */
5360 /*               together through their pBranches                  */
5361 /*-----------------------------------------------------------------*/
5362 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5363 {
5364   pBranch *b;
5365
5366   // Declare a new branch object for the 'from' pCode.
5367
5368   //_ALLOC(b,sizeof(pBranch));
5369   b = Safe_calloc(1,sizeof(pBranch));
5370   b->pc = PCODE(t);             // The link to the 'to' pCode.
5371   b->next = NULL;
5372
5373   f->to = pic16_pBranchAppend(f->to,b);
5374
5375   // Now do the same for the 'to' pCode.
5376
5377   //_ALLOC(b,sizeof(pBranch));
5378   b = Safe_calloc(1,sizeof(pBranch));
5379   b->pc = PCODE(f);
5380   b->next = NULL;
5381
5382   t->from = pic16_pBranchAppend(t->from,b);
5383   
5384 }
5385
5386 #if 1
5387 /*-----------------------------------------------------------------*/
5388 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5389 /*               a pCode                                           */
5390 /*-----------------------------------------------------------------*/
5391 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5392 {
5393   while(pb) {
5394
5395     if(pb->pc == pc)
5396       return pb;
5397
5398     pb = pb->next;
5399   }
5400
5401   return NULL;
5402 }
5403
5404 /*-----------------------------------------------------------------*/
5405 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5406 /*-----------------------------------------------------------------*/
5407 void pic16_pCodeUnlink(pCode *pc)
5408 {
5409   pBranch *pb1,*pb2;
5410   pCode *pc1;
5411
5412   if(!pc->prev || !pc->next) {
5413     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5414     exit(1);
5415   }
5416   
5417   /* move C source line down (or up) */
5418   if (isPCI(pc) && PCI(pc)->cline) {
5419     pc1 = pic16_findNextInstruction (pc->next);
5420     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5421       PCI(pc1)->cline = PCI(pc)->cline;
5422     } else {
5423       pc1 = pic16_findPrevInstruction (pc->prev);
5424       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5425         PCI(pc1)->cline = PCI(pc)->cline;
5426     }
5427   }
5428
5429   /* first remove the pCode from the chain */
5430   pc->prev->next = pc->next;
5431   pc->next->prev = pc->prev;
5432
5433   pc->prev = pc->next = NULL;
5434
5435   /* Now for the hard part... */
5436
5437   /* Remove the branches */
5438
5439   pb1 = PCI(pc)->from;
5440   while(pb1) {
5441     pc1 = pb1->pc;    /* Get the pCode that branches to the
5442                        * one we're unlinking */
5443
5444     /* search for the link back to this pCode (the one we're
5445      * unlinking) */
5446     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5447       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5448
5449       /* if the pCode we're unlinking contains multiple 'to'
5450        * branches (e.g. this a skip instruction) then we need
5451        * to copy these extra branches to the chain. */
5452       if(PCI(pc)->to->next)
5453         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5454     }
5455     
5456     pb1 = pb1->next;
5457   }
5458
5459
5460 }
5461 #endif
5462 /*-----------------------------------------------------------------*/
5463 /*-----------------------------------------------------------------*/
5464 #if 0
5465 static void genericAnalyze(pCode *pc)
5466 {
5467   switch(pc->type) {
5468   case PC_WILD:
5469   case PC_COMMENT:
5470     return;
5471   case PC_LABEL:
5472   case PC_FUNCTION:
5473   case PC_OPCODE:
5474     {
5475       // Go through the pCodes that are in pCode chain and link
5476       // them together through the pBranches. Note, the pCodes
5477       // are linked together as a contiguous stream like the 
5478       // assembly source code lines. The linking here mimics this
5479       // except that comments are not linked in.
5480       // 
5481       pCode *npc = pc->next;
5482       while(npc) {
5483         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5484           pBranchLink(pc,npc);
5485           return;
5486         } else
5487           npc = npc->next;
5488       }
5489       /* reached the end of the pcode chain without finding
5490        * an instruction we could link to. */
5491     }
5492     break;
5493   case PC_FLOW:
5494     fprintf(stderr,"analyze PC_FLOW\n");
5495
5496     return;
5497   case PC_BAD:
5498     fprintf(stderr,,";A bad pCode is being used\n");
5499
5500   }
5501 }
5502 #endif
5503
5504 /*-----------------------------------------------------------------*/
5505 /*-----------------------------------------------------------------*/
5506 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5507 {
5508   pBranch *pbr;
5509
5510   if(pc->type == PC_LABEL) {
5511     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5512       return TRUE;
5513   }
5514   if((pc->type == PC_OPCODE)
5515         || (pc->type == PC_ASMDIR)
5516         ) {
5517     pbr = PCI(pc)->label;
5518     while(pbr) {
5519       if(pbr->pc->type == PC_LABEL) {
5520         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5521           return TRUE;
5522       }
5523       pbr = pbr->next;
5524     }
5525   }
5526
5527   return FALSE;
5528 }
5529
5530 /*-----------------------------------------------------------------*/
5531 /*-----------------------------------------------------------------*/
5532 static int checkLabel(pCode *pc)
5533 {
5534   pBranch *pbr;
5535
5536   if(pc && isPCI(pc)) {
5537     pbr = PCI(pc)->label;
5538     while(pbr) {
5539       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5540         return TRUE;
5541
5542       pbr = pbr->next;
5543     }
5544   }
5545
5546   return FALSE;
5547 }
5548
5549 /*-----------------------------------------------------------------*/
5550 /* findLabelinpBlock - Search the pCode for a particular label     */
5551 /*-----------------------------------------------------------------*/
5552 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5553 {
5554   pCode  *pc;
5555
5556   if(!pb)
5557     return NULL;
5558
5559   for(pc = pb->pcHead; pc; pc = pc->next) 
5560     if(compareLabel(pc,pcop_label))
5561       return pc;
5562     
5563   return NULL;
5564 }
5565 #if 0
5566 /*-----------------------------------------------------------------*/
5567 /* findLabel - Search the pCode for a particular label             */
5568 /*-----------------------------------------------------------------*/
5569 static pCode * findLabel(pCodeOpLabel *pcop_label)
5570 {
5571   pBlock *pb;
5572   pCode  *pc;
5573
5574   if(!the_pFile)
5575     return NULL;
5576
5577   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5578     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5579       return pc;
5580   }
5581
5582   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5583   return NULL;
5584 }
5585 #endif
5586 /*-----------------------------------------------------------------*/
5587 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5588 /*                 in the linked list                              */
5589 /*-----------------------------------------------------------------*/
5590 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5591 {
5592
5593   while(pc) {
5594     if(pc->type == pct)
5595       return pc;
5596
5597     pc = pc->next;
5598   }
5599
5600   return NULL;
5601 }
5602
5603 /*-----------------------------------------------------------------*/
5604 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5605 /*                 in the linked list                              */
5606 /*-----------------------------------------------------------------*/
5607 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5608 {
5609
5610   while(pc) {
5611     if(pc->type == pct)
5612       return pc;
5613
5614     pc = pc->prev;
5615   }
5616
5617   return NULL;
5618 }
5619
5620
5621 //#define PCODE_DEBUG
5622 /*-----------------------------------------------------------------*/
5623 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5624 /*                       in the linked list                        */
5625 /*-----------------------------------------------------------------*/
5626 pCode * pic16_findNextInstruction(pCode *pci)
5627 {
5628   pCode *pc = pci;
5629
5630   while(pc) {
5631     if((pc->type == PC_OPCODE)
5632         || (pc->type == PC_WILD)
5633         || (pc->type == PC_ASMDIR)
5634         )
5635       return pc;
5636
5637 #ifdef PCODE_DEBUG
5638     fprintf(stderr,"pic16_findNextInstruction:  ");
5639     printpCode(stderr, pc);
5640 #endif
5641     pc = pc->next;
5642   }
5643
5644   //fprintf(stderr,"Couldn't find instruction\n");
5645   return NULL;
5646 }
5647
5648 /*-----------------------------------------------------------------*/
5649 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5650 /*                       in the linked list                        */
5651 /*-----------------------------------------------------------------*/
5652 pCode * pic16_findPrevInstruction(pCode *pci)
5653 {
5654   pCode *pc = pci;
5655
5656   while(pc) {
5657
5658     if((pc->type == PC_OPCODE)
5659         || (pc->type == PC_WILD)
5660         || (pc->type == PC_ASMDIR)
5661         )
5662       return pc;
5663       
5664
5665 #ifdef PCODE_DEBUG
5666     fprintf(stderr,"pic16_findPrevInstruction:  ");
5667     printpCode(stderr, pc);
5668 #endif
5669     pc = pc->prev;
5670   }
5671
5672   //fprintf(stderr,"Couldn't find instruction\n");
5673   return NULL;
5674 }
5675
5676 #undef PCODE_DEBUG
5677
5678 #if 0
5679 /*-----------------------------------------------------------------*/
5680 /* findFunctionEnd - given a pCode find the end of the function    */
5681 /*                   that contains it                              */
5682 /*-----------------------------------------------------------------*/
5683 static pCode * findFunctionEnd(pCode *pc)
5684 {
5685
5686   while(pc) {
5687     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5688       return pc;
5689
5690     pc = pc->next;
5691   }
5692
5693   fprintf(stderr,"Couldn't find function end\n");
5694   return NULL;
5695 }
5696 #endif
5697 #if 0
5698 /*-----------------------------------------------------------------*/
5699 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5700 /*                instruction with which it is associated.         */
5701 /*-----------------------------------------------------------------*/
5702 static void AnalyzeLabel(pCode *pc)
5703 {
5704
5705   pic16_pCodeUnlink(pc);
5706
5707 }
5708 #endif
5709
5710 #if 0
5711 static void AnalyzeGOTO(pCode *pc)
5712 {
5713
5714   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5715
5716 }
5717
5718 static void AnalyzeSKIP(pCode *pc)
5719 {
5720
5721   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5722   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5723
5724 }
5725
5726 static void AnalyzeRETURN(pCode *pc)
5727 {
5728
5729   //  branch_link(pc,findFunctionEnd(pc->next));
5730
5731 }
5732
5733 #endif
5734
5735 /*-------------------------------------------------------------------*/
5736 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5737 /*                            if one is present. This is the common  */
5738 /*                            part of pic16_getRegFromInstruction(2) */
5739 /*-------------------------------------------------------------------*/
5740
5741 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5742   if (!pcop) return NULL;
5743   
5744   switch(pcop->type) {
5745   case PO_PRODL:
5746   case PO_PRODH:
5747   case PO_INDF0:
5748   case PO_FSR0:
5749   case PO_W:
5750   case PO_WREG:
5751   case PO_STATUS:
5752   case PO_INTCON:
5753   case PO_PCL:
5754   case PO_PCLATH:
5755   case PO_PCLATU:
5756   case PO_BSR:
5757     return PCOR(pcop)->r;
5758
5759   case PO_SFR_REGISTER:
5760     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5761     return PCOR(pcop)->r;
5762
5763   case PO_BIT:
5764   case PO_GPR_TEMP:
5765 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5766     return PCOR(pcop)->r;
5767
5768   case PO_IMMEDIATE:
5769 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5770
5771     if(PCOI(pcop)->r)
5772       return (PCOI(pcop)->r);
5773     else
5774       return NULL;
5775     
5776   case PO_GPR_BIT:
5777     return PCOR(pcop)->r;
5778
5779   case PO_GPR_REGISTER:
5780   case PO_DIR:
5781 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5782     return PCOR(pcop)->r;
5783
5784   case PO_LITERAL:
5785     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5786     break;
5787
5788   case PO_REL_ADDR:
5789   case PO_LABEL:
5790     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5791     break;
5792     
5793   case PO_CRY:
5794   case PO_STR:
5795     /* this should never turn up */
5796     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5797     break;
5798     
5799   case PO_WILD:
5800     break;
5801
5802   case PO_TWO_OPS:
5803     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5804     break;
5805     
5806   default:
5807         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5808 //      assert( 0 );
5809         break;
5810   }
5811
5812   return NULL;
5813 }
5814
5815 /*-----------------------------------------------------------------*/
5816 /*-----------------------------------------------------------------*/
5817 regs * pic16_getRegFromInstruction(pCode *pc)
5818 {
5819   if(!pc                   || 
5820      !isPCI(pc)            ||
5821      !PCI(pc)->pcop        ||
5822      PCI(pc)->num_ops == 0 ||
5823      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5824     return NULL;
5825
5826 #if 0
5827   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5828         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5829 #endif
5830
5831   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5832 }
5833
5834 /*-------------------------------------------------------------------------------*/
5835 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5836 /*-------------------------------------------------------------------------------*/
5837 regs * pic16_getRegFromInstruction2(pCode *pc)
5838 {
5839
5840   if(!pc                   || 
5841      !isPCI(pc)            ||
5842      !PCI(pc)->pcop        ||
5843      PCI(pc)->num_ops == 0 ||
5844      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5845     return NULL;
5846
5847   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5848     return NULL;
5849
5850 #if 0
5851   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5852         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5853 #endif
5854
5855   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5856 }
5857
5858 /*-----------------------------------------------------------------*/
5859 /*-----------------------------------------------------------------*/
5860
5861 static void AnalyzepBlock(pBlock *pb)
5862 {
5863   pCode *pc;
5864
5865   if(!pb)
5866     return;
5867
5868   /* Find all of the registers used in this pBlock 
5869    * by looking at each instruction and examining it's
5870    * operands
5871    */
5872   for(pc = pb->pcHead; pc; pc = pc->next) {
5873
5874     /* Is this an instruction with operands? */
5875     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5876
5877       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5878
5879         /* Loop through all of the registers declared so far in
5880            this block and see if we find this one there */
5881
5882         regs *r = setFirstItem(pb->tregisters);
5883
5884         while(r) {
5885           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5886             PCOR(PCI(pc)->pcop)->r = r;
5887             break;
5888           }
5889           r = setNextItem(pb->tregisters);
5890         }
5891
5892         if(!r) {
5893           /* register wasn't found */
5894           //r = Safe_calloc(1, sizeof(regs));
5895           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5896           //addSet(&pb->tregisters, r);
5897           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5898           //PCOR(PCI(pc)->pcop)->r = r;
5899           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5900         }/* else 
5901           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5902          */
5903       }
5904       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5905         if(PCOR(PCI(pc)->pcop)->r) {
5906           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5907           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5908         } else {
5909           if(PCI(pc)->pcop->name)
5910             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5911           else
5912             fprintf(stderr,"ERROR: NULL register\n");
5913         }
5914       }
5915     }
5916
5917
5918   }
5919 }
5920
5921 /*-----------------------------------------------------------------*/
5922 /* */
5923 /*-----------------------------------------------------------------*/
5924 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5925
5926 static void InsertpFlow(pCode *pc, pCode **pflow)
5927 {
5928   if(*pflow)
5929     PCFL(*pflow)->end = pc;
5930
5931   if(!pc || !pc->next)
5932     return;
5933
5934   *pflow = pic16_newpCodeFlow();
5935   pic16_pCodeInsertAfter(pc, *pflow);
5936 }
5937
5938 /*-----------------------------------------------------------------*/
5939 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5940 /*                         the flow blocks.                        */
5941 /*
5942  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5943  * point the instruction flow changes. 
5944  */
5945 /*-----------------------------------------------------------------*/
5946 void pic16_BuildFlow(pBlock *pb)
5947 {
5948   pCode *pc;
5949   pCode *last_pci=NULL;
5950   pCode *pflow=NULL;
5951   int seq = 0;
5952
5953   if(!pb)
5954     return;
5955
5956   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5957   /* Insert a pCodeFlow object at the beginning of a pBlock */
5958
5959   InsertpFlow(pb->pcHead, &pflow);
5960
5961   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5962   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5963   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5964   //pb->pcHead = pflow;        /* Make the Flow object the head */
5965   //pflow->pb = pb;
5966
5967   for( pc = pic16_findNextInstruction(pb->pcHead);
5968        pc != NULL;
5969        pc=pic16_findNextInstruction(pc)) { 
5970
5971     pc->seq = seq++;
5972     PCI(pc)->pcflow = PCFL(pflow);
5973
5974     //fprintf(stderr," build: ");
5975     //pflow->print(stderr,pflow);
5976
5977     if (checkLabel(pc)) { 
5978
5979       /* This instruction marks the beginning of a
5980        * new flow segment */
5981
5982       pc->seq = 0;
5983       seq = 1;
5984
5985       /* If the previous pCode is not a flow object, then 
5986        * insert a new flow object. (This check prevents 
5987        * two consecutive flow objects from being insert in
5988        * the case where a skip instruction preceeds an
5989        * instruction containing a label.) */
5990
5991       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
5992         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
5993
5994       PCI(pc)->pcflow = PCFL(pflow);
5995       
5996     }
5997
5998     if( PCI(pc)->isSkip) {
5999
6000       /* The two instructions immediately following this one 
6001        * mark the beginning of a new flow segment */
6002
6003       while(pc && PCI(pc)->isSkip) {
6004
6005         PCI(pc)->pcflow = PCFL(pflow);
6006         pc->seq = seq-1;
6007         seq = 1;
6008
6009         InsertpFlow(pc, &pflow);
6010         pc=pic16_findNextInstruction(pc->next);
6011       }
6012
6013       seq = 0;
6014
6015       if(!pc)
6016         break;
6017
6018       PCI(pc)->pcflow = PCFL(pflow);
6019       pc->seq = 0;
6020       InsertpFlow(pc, &pflow);
6021
6022     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6023
6024       InsertpFlow(pc, &pflow);
6025       seq = 0;
6026
6027     }
6028     last_pci = pc;
6029     pc = pc->next;
6030   }
6031
6032   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6033   if(pflow)
6034     PCFL(pflow)->end = pb->pcTail;
6035 }
6036
6037 /*-------------------------------------------------------------------*/
6038 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6039 /*                           the flow blocks.                        */
6040 /*
6041  * unBuildFlow removes pCodeFlow objects from a pCode chain
6042  */
6043 /*-----------------------------------------------------------------*/
6044 static void unBuildFlow(pBlock *pb)
6045 {
6046   pCode *pc,*pcnext;
6047
6048   if(!pb)
6049     return;
6050
6051   pc = pb->pcHead;
6052
6053   while(pc) {
6054     pcnext = pc->next;
6055
6056     if(isPCI(pc)) {
6057
6058       pc->seq = 0;
6059       if(PCI(pc)->pcflow) {
6060         //Safe_free(PCI(pc)->pcflow);
6061         PCI(pc)->pcflow = NULL;
6062       }
6063
6064     } else if(isPCFL(pc) )
6065       pc->destruct(pc);
6066
6067     pc = pcnext;
6068   }
6069
6070
6071 }
6072 #if 0
6073 /*-----------------------------------------------------------------*/
6074 /*-----------------------------------------------------------------*/
6075 static void dumpCond(int cond)
6076 {
6077
6078   static char *pcc_str[] = {
6079     //"PCC_NONE",
6080     "PCC_REGISTER",
6081     "PCC_C",
6082     "PCC_Z",
6083     "PCC_DC",
6084     "PCC_OV",
6085     "PCC_N",
6086     "PCC_W",
6087     "PCC_EXAMINE_PCOP",
6088     "PCC_LITERAL",
6089     "PCC_REL_ADDR"
6090   };
6091
6092   int ncond = sizeof(pcc_str) / sizeof(char *);
6093   int i,j;
6094
6095   fprintf(stderr, "0x%04X\n",cond);
6096
6097   for(i=0,j=1; i<ncond; i++, j<<=1)
6098     if(cond & j)
6099       fprintf(stderr, "  %s\n",pcc_str[i]);
6100
6101 }
6102 #endif
6103
6104 #if 0
6105 /*-----------------------------------------------------------------*/
6106 /*-----------------------------------------------------------------*/
6107 static void FlowStats(pCodeFlow *pcflow)
6108 {
6109
6110   pCode *pc;
6111
6112   if(!isPCFL(pcflow))
6113     return;
6114
6115   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6116
6117   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6118
6119   if(!pc) {
6120     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6121     return;
6122   }
6123
6124
6125   fprintf(stderr, "  FlowStats inCond: ");
6126   dumpCond(pcflow->inCond);
6127   fprintf(stderr, "  FlowStats outCond: ");
6128   dumpCond(pcflow->outCond);
6129
6130 }
6131 #endif
6132 /*-----------------------------------------------------------------*
6133  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6134  *    if it affects the banking bits. 
6135  * 
6136  * return: -1 == Banking bits are unaffected by this pCode.
6137  *
6138  * return: > 0 == Banking bits are affected.
6139  *
6140  *  If the banking bits are affected, then the returned value describes
6141  * which bits are affected and how they're affected. The lower half
6142  * of the integer maps to the bits that are affected, the upper half
6143  * to whether they're set or cleared.
6144  *
6145  *-----------------------------------------------------------------*/
6146
6147 static int isBankInstruction(pCode *pc)
6148 {
6149   regs *reg;
6150   int bank = -1;
6151
6152   if(!isPCI(pc))
6153     return 0;
6154
6155   if( PCI(pc)->op == POC_MOVLB ||
6156       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6157     bank = PCOL(pc)->lit;
6158   }
6159
6160   return 1;
6161 }
6162
6163
6164 /*-----------------------------------------------------------------*/
6165 /*-----------------------------------------------------------------*/
6166 static void FillFlow(pCodeFlow *pcflow)
6167 {
6168
6169   pCode *pc;
6170   int cur_bank;
6171
6172   if(!isPCFL(pcflow))
6173     return;
6174
6175   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6176
6177   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6178
6179   if(!pc) {
6180     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6181     return;
6182   }
6183
6184   cur_bank = -1;
6185
6186   do {
6187     isBankInstruction(pc);
6188     pc = pc->next;
6189   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6190
6191 /*
6192   if(!pc ) {
6193     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6194   } else {
6195     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6196     pc->print(stderr,pc);
6197   }
6198
6199   fprintf(stderr, "  FillFlow inCond: ");
6200   dumpCond(pcflow->inCond);
6201   fprintf(stderr, "  FillFlow outCond: ");
6202   dumpCond(pcflow->outCond);
6203 */
6204 }
6205
6206 /*-----------------------------------------------------------------*/
6207 /*-----------------------------------------------------------------*/
6208 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6209 {
6210   pCodeFlowLink *fromLink, *toLink;
6211
6212   if(!from || !to || !to->pcflow || !from->pcflow)
6213     return;
6214
6215   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6216   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6217
6218   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6219   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6220
6221 }
6222
6223 pCode *pic16_getJumptabpCode (pCode *pc) {
6224   pCode *pcinf;
6225
6226   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6227   //pc->print (stderr, pc);
6228   pcinf = pc;
6229   while (pcinf) {
6230     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6231     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6232       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6233       case OPT_JUMPTABLE_BEGIN:
6234         /* leading begin of jump table -- in one */
6235         pcinf = pic16_findPrevInstruction (pcinf);
6236         return pcinf;
6237         break;
6238         
6239       case OPT_JUMPTABLE_END:
6240         /* leading end of jumptable -- not in one */
6241         return NULL;
6242         break;
6243         
6244       default:
6245         /* ignore all other PCInfos */
6246         break;
6247       }
6248     }
6249     pcinf = pcinf->prev;
6250   }
6251
6252   /* no PCInfo found -- not in a jumptable */
6253   return NULL;
6254 }
6255
6256 /*-----------------------------------------------------------------*
6257  * void LinkFlow(pBlock *pb)
6258  *
6259  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6260  * non-branching segments. In LinkFlow, we determine the execution
6261  * order of these segments. For example, if one of the segments ends
6262  * with a skip, then we know that there are two possible flow segments
6263  * to which control may be passed.
6264  *-----------------------------------------------------------------*/
6265 static void LinkFlow(pBlock *pb)
6266 {
6267   pCode *pc=NULL;
6268   pCode *pcflow;
6269   pCode *pct;
6270   pCode *jumptab_pre = NULL;
6271
6272   //fprintf(stderr,"linkflow \n");
6273
6274   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6275        pcflow != NULL;
6276        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6277
6278     if(!isPCFL(pcflow))
6279       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6280
6281     //fprintf(stderr," link: ");
6282     //pcflow->print(stderr,pcflow);
6283
6284     //FillFlow(PCFL(pcflow));
6285
6286     pc = PCFL(pcflow)->end;
6287
6288     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6289     if(isPCI_SKIP(pc)) {
6290 //      fprintf(stderr, "ends with skip\n");
6291 //      pc->print(stderr,pc);
6292
6293       pct=pic16_findNextInstruction(pc->next);
6294       LinkFlow_pCode(PCI(pc),PCI(pct));
6295       pct=pic16_findNextInstruction(pct->next);
6296       LinkFlow_pCode(PCI(pc),PCI(pct));
6297       continue;
6298     }
6299
6300     if(isPCI_BRANCH(pc)) {
6301       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6302
6303       /* handle GOTOs in jumptables */
6304       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6305         /* link to previous flow */
6306         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6307         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6308       }
6309
6310       switch (PCI(pc)->op) {
6311       case POC_GOTO:
6312       case POC_BRA:
6313       case POC_RETURN:
6314       case POC_RETLW:
6315       case POC_RETFIE:
6316               /* unconditional branches -- do not link to next instruction */
6317               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6318               break;
6319               
6320       case POC_CALL:
6321       case POC_RCALL:
6322               /* unconditional calls -- link to next instruction */
6323               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6324               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6325               break;
6326               
6327       case POC_BC:
6328       case POC_BN:
6329       case POC_BNC:
6330       case POC_BNN:
6331       case POC_BNOV:
6332       case POC_BNZ:
6333       case POC_BOV:
6334       case POC_BZ:
6335               /* conditional branches -- also link to next instruction */
6336               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6337               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6338               break;
6339               
6340       default:
6341               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6342               assert (0 && "unhandled branching instruction");
6343               break;
6344       }
6345
6346       //fprintf(stderr, "ends with branch\n  ");
6347       //pc->print(stderr,pc);
6348
6349       if(!(pcol && isPCOLAB(pcol))) {
6350         if((PCI(pc)->op != POC_RETLW)
6351                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6352         
6353                 /* continue if label is '$' which assembler knows how to parse */
6354                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6355
6356                 if(pic16_pcode_verbose) {
6357                         pc->print(stderr,pc);
6358                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6359                 }
6360         }
6361         continue;
6362       }
6363
6364       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6365         LinkFlow_pCode(PCI(pc),PCI(pct));
6366       else
6367         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6368                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6369
6370 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6371
6372       continue;
6373     }
6374
6375     if(isPCI(pc)) {
6376       //fprintf(stderr, "ends with non-branching instruction:\n");
6377       //pc->print(stderr,pc);
6378
6379       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6380
6381       continue;
6382     }
6383
6384     if(pc) {
6385       //fprintf(stderr, "ends with unknown\n");
6386       //pc->print(stderr,pc);
6387       continue;
6388     }
6389
6390     //fprintf(stderr, "ends with nothing: ERROR\n");
6391     
6392   }
6393 }
6394 /*-----------------------------------------------------------------*/
6395 /*-----------------------------------------------------------------*/
6396
6397 /*-----------------------------------------------------------------*/
6398 /*-----------------------------------------------------------------*/
6399 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6400 {
6401
6402   if(!pc || !pcflow)
6403     return 0;
6404
6405   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6406     return 0;
6407
6408   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6409     return 1;
6410
6411   return 0;
6412 }
6413
6414
6415
6416
6417
6418 /*-----------------------------------------------------------------*/
6419 /* insertBankSwitch - inserts a bank switch statement in the       */
6420 /*                    assembly listing                             */
6421 /*                                                                 */
6422 /* position == 0: insert before                                    */
6423 /* position == 1: insert after pc                                  */
6424 /* position == 2: like 0 but previous was a skip instruction       */
6425 /*-----------------------------------------------------------------*/
6426 pCodeOp *pic16_popGetLabel(unsigned int key);
6427 extern int pic16_labelOffset;
6428
6429 static void insertBankSwitch(unsigned char position, pCode *pc)
6430 {
6431   pCode *new_pc;
6432
6433         if(!pc)
6434                 return;
6435
6436         /* emit BANKSEL [symbol] */
6437
6438
6439         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6440         
6441 //      position = 0;           // position is always before (sanity check!)
6442
6443 #if 0
6444         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6445         pc->print(stderr, pc);
6446 #endif
6447
6448         switch(position) {
6449                 case 1: {
6450                         /* insert the bank switch after this pc instruction */
6451                         pCode *pcnext = pic16_findNextInstruction(pc);
6452
6453                                 pic16_pCodeInsertAfter(pc, new_pc);
6454                                 if(pcnext)pc = pcnext;
6455                 }; break;
6456                 
6457                 case 0:
6458                         /* insert the bank switch BEFORE this pc instruction */
6459                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6460                         break;
6461
6462                 case 2: {
6463                           symbol *tlbl;
6464                           pCode *pcnext, *pcprev, *npci, *ppc;
6465                           PIC_OPCODE ipci;
6466                           int ofs1=0, ofs2=0, len=0;
6467                           
6468                         /* just like 0, but previous was a skip instruction,
6469                          * so some care should be taken */
6470                           
6471                                 pic16_labelOffset += 10000;
6472                                 tlbl = newiTempLabel(NULL);
6473                                 
6474                                 /* invert skip instruction */
6475                                 pcprev = pic16_findPrevInstruction(pc->prev);
6476                                 ipci = PCI(pcprev)->inverted_op;
6477                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6478
6479 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6480
6481                                 /* copy info from old pCode */
6482                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6483                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6484                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6485                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6486                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6487                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6488                                 
6489                                 /* unlink old pCode */
6490                                 ppc = pcprev->prev;
6491                                 ppc->next = pcprev->next;
6492                                 pcprev->next->prev = ppc;
6493                                 pic16_pCodeInsertAfter(ppc, npci);
6494                                 
6495                                 /* extra instructions to handle invertion */
6496                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6497                                 pic16_pCodeInsertAfter(npci, pcnext);
6498                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6499                                 
6500                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6501                                 pic16_pCodeInsertAfter(pc, pcnext);
6502                         }; break;
6503         }
6504         
6505
6506         /* Move the label, if there is one */
6507         if(PCI(pc)->label) {
6508 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6509 //                      __FILE__, __LINE__, pc, new_pc);
6510                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6511                 PCI(pc)->label = NULL;
6512         }
6513 }
6514
6515
6516 /*-----------------------------------------------------------------*/
6517 /*int compareBankFlow - compare the banking requirements between   */
6518 /*  flow objects. */
6519 /*-----------------------------------------------------------------*/
6520 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6521 {
6522
6523   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6524     return 0;
6525
6526   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6527     return 0;
6528
6529   if(pcflow->firstBank == -1)
6530     return 0;
6531
6532
6533   if(pcflowLink->pcflow->firstBank == -1) {
6534     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6535                                         pcflowLink->pcflow->to : 
6536                                         pcflowLink->pcflow->from);
6537     return compareBankFlow(pcflow, pctl, toORfrom);
6538   }
6539
6540   if(toORfrom) {
6541     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6542       return 0;
6543
6544     pcflowLink->bank_conflict++;
6545     pcflowLink->pcflow->FromConflicts++;
6546     pcflow->ToConflicts++;
6547   } else {
6548     
6549     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6550       return 0;
6551
6552     pcflowLink->bank_conflict++;
6553     pcflowLink->pcflow->ToConflicts++;
6554     pcflow->FromConflicts++;
6555
6556   }
6557   /*
6558   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6559           pcflowLink->pcflow->pc.seq,
6560           pcflowLink->pcflow->FromConflicts,
6561           pcflowLink->pcflow->ToConflicts);
6562   */
6563   return 1;
6564
6565 }
6566
6567 #if 0
6568 /*-----------------------------------------------------------------*/
6569 /*-----------------------------------------------------------------*/
6570 static void DumpFlow(pBlock *pb)
6571 {
6572   pCode *pc=NULL;
6573   pCode *pcflow;
6574   pCodeFlowLink *pcfl;
6575
6576
6577   fprintf(stderr,"Dump flow \n");
6578   pb->pcHead->print(stderr, pb->pcHead);
6579
6580   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6581   pcflow->print(stderr,pcflow);
6582
6583   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6584        pcflow != NULL;
6585        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6586
6587     if(!isPCFL(pcflow)) {
6588       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6589       continue;
6590     }
6591     fprintf(stderr,"dumping: ");
6592     pcflow->print(stderr,pcflow);
6593     FlowStats(PCFL(pcflow));
6594
6595     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6596
6597       pc = PCODE(pcfl->pcflow);
6598
6599       fprintf(stderr, "    from seq %d:\n",pc->seq);
6600       if(!isPCFL(pc)) {
6601         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6602         pc->print(stderr,pc);
6603       }
6604
6605     }
6606
6607     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6608
6609       pc = PCODE(pcfl->pcflow);
6610
6611       fprintf(stderr, "    to seq %d:\n",pc->seq);
6612       if(!isPCFL(pc)) {
6613         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6614         pc->print(stderr,pc);
6615       }
6616
6617     }
6618
6619   }
6620
6621 }
6622 #endif
6623 /*-----------------------------------------------------------------*/
6624 /*-----------------------------------------------------------------*/
6625 static int OptimizepBlock(pBlock *pb)
6626 {
6627   pCode *pc, *pcprev;
6628   int matches =0;
6629
6630   if(!pb || !peepOptimizing)
6631     return 0;
6632
6633   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6634 /*
6635   for(pc = pb->pcHead; pc; pc = pc->next)
6636     matches += pic16_pCodePeepMatchRule(pc);
6637 */
6638
6639   pc = pic16_findNextInstruction(pb->pcHead);
6640   if(!pc)
6641     return 0;
6642
6643   pcprev = pc->prev;
6644   do {
6645
6646
6647     if(pic16_pCodePeepMatchRule(pc)) {
6648
6649       matches++;
6650
6651       if(pcprev)
6652         pc = pic16_findNextInstruction(pcprev->next);
6653       else 
6654         pc = pic16_findNextInstruction(pb->pcHead);
6655     } else
6656       pc = pic16_findNextInstruction(pc->next);
6657   } while(pc);
6658
6659   if(matches)
6660     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6661   return matches;
6662
6663 }
6664
6665 /*-----------------------------------------------------------------*/
6666 /*-----------------------------------------------------------------*/
6667 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6668 {
6669   pCode *pc;
6670
6671   for(pc = pcs; pc; pc = pc->next) {
6672
6673     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6674        (PCI(pc)->pcop) && 
6675        (PCI(pc)->pcop->type == PO_LABEL) &&
6676        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6677       return pc;
6678   }
6679  
6680
6681   return NULL;
6682 }
6683
6684 /*-----------------------------------------------------------------*/
6685 /*-----------------------------------------------------------------*/
6686 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6687 {
6688
6689   char *s=NULL;
6690
6691   if(isPCI(pc) && 
6692      (PCI(pc)->pcop) && 
6693      (PCI(pc)->pcop->type == PO_LABEL)) {
6694
6695     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6696
6697 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6698 //    if(pcol->pcop.name)
6699 //      Safe_free(pcol->pcop.name);
6700
6701     /* If the key is negative, then we (probably) have a label to
6702      * a function and the name is already defined */
6703        
6704     if(pcl->key>0)
6705       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6706     else 
6707       s = pcl->label;
6708
6709     //sprintf(buffer,"_%05d_DS_",pcl->key);
6710     if(!s) {
6711       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6712     }
6713     pcol->pcop.name = Safe_strdup(s);
6714     pcol->key = pcl->key;
6715     //pc->print(stderr,pc);
6716
6717   }
6718
6719
6720 }
6721
6722 /*-----------------------------------------------------------------*/
6723 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6724 /*                            pCode chain if they're not used.     */
6725 /*-----------------------------------------------------------------*/
6726 static void pBlockRemoveUnusedLabels(pBlock *pb)
6727 {
6728   pCode *pc; pCodeLabel *pcl;
6729
6730   if(!pb)
6731     return;
6732
6733   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6734
6735     pBranch *pbr = PCI(pc)->label;
6736     if(pbr && pbr->next) {
6737       pCode *pcd = pb->pcHead;
6738
6739 //      fprintf(stderr, "multiple labels\n");
6740 //      pc->print(stderr,pc);
6741
6742       pbr = pbr->next;
6743       while(pbr) {
6744
6745         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6746           //fprintf(stderr,"Used by:\n");
6747           //pcd->print(stderr,pcd);
6748
6749           exchangeLabels(PCL(pbr->pc),pcd);
6750
6751           pcd = pcd->next;
6752         }
6753         pbr = pbr->next;
6754       }
6755     }
6756   }
6757
6758   for(pc = pb->pcHead; pc; pc = pc->next) {
6759
6760     if(isPCL(pc)) // pc->type == PC_LABEL)
6761       pcl = PCL(pc);
6762     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6763       pcl = PCL(PCI(pc)->label->pc);
6764     else continue;
6765
6766 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6767
6768     /* This pCode is a label, so search the pBlock to see if anyone
6769      * refers to it */
6770
6771     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6772         && (!pcl->force)) {
6773     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6774       /* Couldn't find an instruction that refers to this label
6775        * So, unlink the pCode label from it's pCode chain
6776        * and destroy the label */
6777 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6778
6779       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6780       if(pc->type == PC_LABEL) {
6781         pic16_unlinkpCode(pc);
6782         pCodeLabelDestruct(pc);
6783       } else {
6784         unlinkpCodeFromBranch(pc, PCODE(pcl));
6785         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6786           Safe_free(pc->label);
6787         }*/
6788       }
6789
6790     }
6791   }
6792
6793 }
6794
6795
6796 /*-----------------------------------------------------------------*/
6797 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6798 /*                     chain and put them into pBranches that are  */
6799 /*                     associated with the appropriate pCode       */
6800 /*                     instructions.                               */
6801 /*-----------------------------------------------------------------*/
6802 void pic16_pBlockMergeLabels(pBlock *pb)
6803 {
6804   pBranch *pbr;
6805   pCode *pc, *pcnext=NULL;
6806
6807   if(!pb)
6808     return;
6809
6810   /* First, Try to remove any unused labels */
6811   //pBlockRemoveUnusedLabels(pb);
6812
6813   /* Now loop through the pBlock and merge the labels with the opcodes */
6814
6815   pc = pb->pcHead;
6816   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6817
6818   while(pc) {
6819     pCode *pcn = pc->next;
6820
6821     if(pc->type == PC_LABEL) {
6822
6823 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6824 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6825
6826       if((pcnext = pic16_findNextInstruction(pc) )) {
6827
6828 //              pcnext->print(stderr, pcnext);
6829
6830         // Unlink the pCode label from it's pCode chain
6831         pic16_unlinkpCode(pc);
6832         
6833 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6834         // And link it into the instruction's pBranch labels. (Note, since
6835         // it's possible to have multiple labels associated with one instruction
6836         // we must provide a means to accomodate the additional labels. Thus
6837         // the labels are placed into the singly-linked list "label" as 
6838         // opposed to being a single member of the pCodeInstruction.)
6839
6840         //_ALLOC(pbr,sizeof(pBranch));
6841 #if 1
6842         pbr = Safe_calloc(1,sizeof(pBranch));
6843         pbr->pc = pc;
6844         pbr->next = NULL;
6845
6846         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6847 #endif
6848       } else {
6849         if(pic16_pcode_verbose)
6850         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6851       }
6852     } else if(pc->type == PC_CSOURCE) {
6853
6854       /* merge the source line symbolic info into the next instruction */
6855       if((pcnext = pic16_findNextInstruction(pc) )) {
6856
6857         // Unlink the pCode label from it's pCode chain
6858         pic16_unlinkpCode(pc);
6859         PCI(pcnext)->cline = PCCS(pc);
6860         //fprintf(stderr, "merging CSRC\n");
6861         //genericPrint(stderr,pcnext);
6862       }
6863
6864     }
6865     pc = pcn;
6866   }
6867   pBlockRemoveUnusedLabels(pb);
6868
6869 }
6870
6871 /*-----------------------------------------------------------------*/
6872 /*-----------------------------------------------------------------*/
6873 static int OptimizepCode(char dbName)
6874 {
6875 #define MAX_PASSES 4
6876
6877   int matches = 0;
6878   int passes = 0;
6879   pBlock *pb;
6880
6881   if(!the_pFile)
6882     return 0;
6883
6884   DFPRINTF((stderr," Optimizing pCode\n"));
6885
6886   do {
6887     matches = 0;
6888     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6889       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6890         matches += OptimizepBlock(pb);
6891     }
6892   }
6893   while(matches && ++passes < MAX_PASSES);
6894
6895   return matches;
6896 }
6897
6898
6899
6900 const char *pic16_pCodeOpType(pCodeOp *pcop);
6901 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6902
6903
6904 /*-----------------------------------------------------------------*/
6905 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6906 /*-----------------------------------------------------------------*/
6907
6908 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6909 {
6910   pCodeOp *pcop=NULL;
6911
6912 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6913
6914   if(pc->name) {
6915         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6916   } else {
6917     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6918   }
6919
6920   assert(pcop != NULL);
6921
6922   if( !( (pcop->type == PO_LABEL) ||
6923          (pcop->type == PO_LITERAL) ||
6924          (pcop->type == PO_STR) ))
6925     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6926     PCOR(pcop)->r->wasUsed = 1;
6927     PCOR(pcop)->instance = PCOR(pc)->instance;
6928
6929   return pcop;
6930 }
6931
6932
6933 /*----------------------------------------------------------------------*
6934  * pic16_areRegsSame - check to see if the names of two registers match *
6935  *----------------------------------------------------------------------*/
6936 int pic16_areRegsSame(regs *r1, regs *r2)
6937 {
6938         if(!strcmp(r1->name, r2->name))return 1;
6939
6940   return 0;
6941 }
6942
6943
6944 /*-----------------------------------------------------------------*/
6945 /*-----------------------------------------------------------------*/
6946 static void pic16_FixRegisterBanking(pBlock *pb)
6947 {
6948   pCode *pc=NULL;
6949   pCode *pcprev=NULL;
6950   regs *reg, *prevreg;
6951   unsigned char flag=0;
6952   
6953         if(!pb)
6954                 return;
6955
6956         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6957         if(!pc)return;
6958
6959         /* loop through all of the flow blocks with in one pblock */
6960
6961 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6962
6963         prevreg = NULL;
6964         do {
6965                 /* at this point, pc should point to a PC_FLOW object */
6966                 /* for each flow block, determine the register banking 
6967                  * requirements */
6968
6969                 
6970                 /* if label, then might come from other point, force banksel */
6971                 if(isPCL(pc))prevreg = NULL;
6972                 
6973                 if(!isPCI(pc))goto loop;
6974
6975                 if(PCI(pc)->label)prevreg = NULL;
6976
6977                 if(PCI(pc)->is2MemOp)goto loop;
6978
6979                 /* if goto, then force banksel */
6980 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6981        
6982                 reg = pic16_getRegFromInstruction(pc);
6983
6984 #if 0
6985                 pc->print(stderr, pc);
6986                 fprintf(stderr, "reg = %p\n", reg);
6987
6988                 if(reg) {
6989                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6990                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6991                                 reg->address,reg->isBitField, reg->isFixed);
6992                 }
6993 #endif
6994
6995                 /* now make some tests to make sure that instruction needs bank switch */
6996
6997                 /* if no register exists, and if not a bit opcode goto loop */
6998                 if(!reg) {
6999                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
7000                 }
7001                  
7002                 if(isPCI_SKIP(pc)) {
7003 //                      fprintf(stderr, "instruction is SKIP instruction\n");
7004 //                prevreg = NULL;
7005                 }
7006                 if(reg && isACCESS_BANK(reg))goto loop;
7007
7008                 if(!isBankInstruction(pc))goto loop;
7009
7010                 if(isPCI_LIT(pc))goto loop;
7011          
7012                 if(PCI(pc)->op == POC_CALL)goto loop;
7013
7014                 /* Examine the instruction before this one to make sure it is
7015                  * not a skip type instruction */
7016                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7017
7018                 flag = 0;               /* add before this instruction */
7019                 
7020                 /* if previous instruction is a skip one, then set flag
7021                  * to 2 and call insertBankSwitch */
7022                 if(pcprev && isPCI_SKIP(pcprev)) {
7023                   flag=2;       //goto loop
7024 //                prevreg = NULL;
7025                 }
7026                  
7027                 if(pic16_options.opt_banksel>0) {
7028                   char op1[128], op2[128];
7029                   
7030                     if(prevreg) {
7031                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7032                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7033                       if(!strcmp(op1, op2))goto loop;
7034                     }
7035                 }
7036                 prevreg = reg;
7037                 insertBankSwitch(flag, pc);
7038
7039 //              fprintf(stderr, "BANK SWITCH inserted\n");
7040                 
7041 loop:
7042                 pcprev = pc;
7043                 pc = pc->next;
7044         } while (pc);
7045 }
7046
7047 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7048
7049 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7050 int instrSize (pCode *pc)
7051 {
7052   if (!pc) return 0;
7053
7054   if (isPCAD(pc)) {
7055     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7056     return 4; // assumes only regular instructions using <= 4 bytes
7057   }
7058
7059   if (isPCI(pc)) return PCI(pc)->isize;
7060
7061   return 0;
7062 }
7063
7064 /* Returns 1 if pc is referenced by the given label (either
7065  * pc is the label itself or is an instruction with an attached
7066  * label).
7067  * Returns 0 if pc is not preceeded by the specified label.
7068  */
7069 int isLabel (pCode *pc, char *label)
7070 {
7071   if (!pc) return 0;
7072
7073   // label attached to the pCode?  
7074   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7075     pBranch *lab = NULL;
7076     lab = PCI(pc)->label;
7077
7078     while (lab) {
7079       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7080         return 1;
7081       }
7082       lab = lab->next;
7083     } // while
7084   } // if
7085
7086   // is inline assembly label?
7087   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7088     // do not compare trailing ':'
7089     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7090       return 1;
7091     }
7092   } // if
7093   
7094   // is pCodeLabel?
7095   if (isPCL(pc)) {
7096       if (strcmp(PCL(pc)->label,label) == 0) {
7097       return 1;
7098     }
7099   } // if
7100   
7101   // no label/no label attached/wrong label(s)
7102   return 0;
7103 }
7104
7105 /* Returns the distance to the given label in terms of words.
7106  * Labels are searched only within -max .. max words from pc.
7107  * Returns max if the label could not be found or
7108  * its distance from pc in (-max..+max).
7109  */
7110 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7111   int dist = instrSize(pc);
7112   pCode *curr = pc;
7113
7114   // search backwards
7115   while (dist < max && curr && !isLabel (curr, label)) {
7116     curr = curr->prev;
7117     dist += instrSize(curr); // sizeof (instruction)
7118   } // while
7119   if (curr && dist < max) {
7120     if (target != NULL) *target = curr;
7121     return -dist;
7122   }
7123
7124   dist = 0;
7125   curr = pic16_findNextInstruction (pc->next);
7126   //search forwards
7127   while (dist < max && curr && !isLabel (curr, label)) {
7128     dist += instrSize(curr); // sizeof (instruction)
7129     curr = curr->next;
7130   } // while
7131   if (curr && dist < max) {
7132     if (target != NULL) *target = curr;
7133     return dist;
7134   }
7135
7136   if (target != NULL) *target = NULL;
7137   return max;
7138 }
7139
7140 /* Returns -1 if pc does NOT denote an instruction like
7141  * BTFS[SC] STATUS,i
7142  * Otherwise we return 
7143  *   (a) 0x10 + i for BTFSS
7144  *   (b) 0x00 + i for BTFSC
7145  */
7146 int isSkipOnStatus (pCode *pc)
7147 {
7148   int res = -1;
7149   pCodeOp *pcop;
7150   if (!pc || !isPCI(pc)) return -1;
7151   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7152   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7153   else return -1;
7154
7155   pcop = PCI(pc)->pcop;
7156
7157   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7158     return res + ((pCodeOpRegBit *)pcop)->bit;
7159   }
7160
7161   return -1;
7162 }
7163
7164 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7165  * returns 0 otherwise. */
7166 int isConditionalBranch (pCode *pc)
7167 {
7168   if (!pc || !isPCI_BRANCH(pc)) return 0;
7169
7170   switch (PCI(pc)->op) {
7171   case POC_BC:
7172   case POC_BZ:
7173   case POC_BOV:
7174   case POC_BN:
7175   case POC_BNC:
7176   case POC_BNZ:
7177   case POC_BNOV:
7178   case POC_BNN:
7179     return 1;
7180
7181   default:
7182     break;
7183   } // switch
7184
7185   return 0;
7186 }
7187
7188 /* Returns 1 if pc has a label attached to it.
7189  * This can be either a label stored in the pCode itself (.label)
7190  * or a label making up its own pCode preceding this pc.
7191  * Returns 0 if pc cannot be reached directly via a label.
7192  */
7193 int hasNoLabel (pCode *pc)
7194 {
7195   pCode *prev;
7196   if (!pc) return 1;
7197
7198   // are there any label pCodes between pc and the previous instruction?
7199   prev = pic16_findPrevInstruction (pc->prev);
7200   while (pc && pc != prev) {
7201     // pCode with attached label?
7202     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7203         && PCI(pc)->label) {
7204       return 0;
7205     }
7206     // is inline assembly label?
7207     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7208     if (isPCW(pc) && PCW(pc)->label) return 0;
7209
7210     // pCodeLabel?
7211     if (isPCL(pc)) return 0;
7212
7213     pc = pc->prev;
7214   } // if
7215
7216   // no label found
7217   return 1;
7218 }
7219
7220 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7221   char buf[512];
7222   va_list va;
7223
7224   va_start (va, fmt);
7225   vsprintf (buf, fmt, va);
7226   va_end (va);
7227
7228   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7229 }
7230
7231 /* Replaces the old pCode with the new one, moving the labels,
7232  * C source line and probably flow information to the new pCode.
7233  */
7234 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7235   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7236     return;
7237
7238   /* first move all labels from old to new */
7239   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7240   PCI(oldPC)->label = NULL;
7241   
7242 #if 0
7243   /* move C source line (if possible) */
7244   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7245     PCI(newPC)->cline = PCI(oldPC)->cline;
7246 #endif
7247
7248   /* keep flow information intact */
7249   newPC->seq = oldPC->seq;
7250   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7251   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7252     PCI(newPC)->pcflow->end = newPC;
7253   }
7254
7255   /* insert a comment stating which pCode has been replaced */
7256 #if 1
7257   if (pic16_pcode_verbose || pic16_debug_verbose) {
7258     char pc_str[256];
7259     pic16_pCode2str (pc_str, 256, oldPC);
7260     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7261   }
7262 #endif
7263   
7264   /* insert new pCode into pBlock */
7265   pic16_pCodeInsertAfter (oldPC, newPC);
7266   pic16_unlinkpCode (oldPC);
7267   
7268   /* destruct replaced pCode */
7269   oldPC->destruct (oldPC);
7270 }
7271
7272 /* Returns the inverted conditional branch (if any) or NULL.
7273  * pcop must be set to the new jump target.
7274  */
7275 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7276 {
7277   pCode *newBcc;
7278
7279   if (!bcc || !isPCI(bcc)) return NULL;
7280
7281   switch (PCI(bcc)->op) {
7282   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7283   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7284   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7285   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7286   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7287   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7288   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7289   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7290   default:
7291     newBcc = NULL;
7292   }
7293   return newBcc;
7294 }
7295
7296 #define MAX_DIST_GOTO         0x7FFFFFFF
7297 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7298 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7299 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7300 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7301
7302 /* Follows GOTO/BRA instructions to their target instructions, stores the
7303  * final destination (not a GOTO or BRA instruction) in target and returns
7304  * the distance from the original pc to *target.
7305  */
7306 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7307         pCode *curr = pc;
7308         pCode *last = NULL;
7309         pCodeOp *lastPCOP = NULL;
7310         int dist = 0;
7311         int depth = 0;
7312
7313         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7314
7315         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7316         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7317                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7318                 last = curr;
7319                 lastPCOP = PCI(curr)->pcop;
7320                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7321                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7322         } // while
7323
7324         if (target) *target = last;
7325         if (pcop) *pcop = lastPCOP;
7326         return dist;
7327 }
7328
7329 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7330  * Otherwise the first pCode after the jumptable (after
7331  * the OPT_JUMPTABLE_END tag) is returned.
7332  */
7333 pCode *skipJumptables (pCode *pc, int *isJumptable)
7334 {
7335   *isJumptable = 0;
7336   if (!pc) return NULL;
7337   
7338   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7339     *isJumptable = 1;
7340     //fprintf (stderr, "SKIPPING jumptable\n");
7341     do {
7342       //pc->print(stderr, pc);
7343       pc = pc->next;
7344     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7345                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7346     //fprintf (stderr, "<<JUMPTAB:\n");
7347     // skip OPT_END as well
7348     if (pc) pc = pc->next;
7349   } // while
7350
7351   return pc;
7352 }
7353
7354 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7355 {
7356   int isJumptab;
7357   *isJumptable = 0;
7358   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7359     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7360     pc = skipJumptables (pc, &isJumptab);
7361     if (isJumptab) {
7362         // pc is the first pCode after the jumptable
7363         *isJumptable = 1;
7364     } else {
7365         // pc has not been changed by skipJumptables()
7366         pc = pc->next;
7367     }
7368   } // while
7369   
7370   return pc;
7371 }
7372
7373 /* Turn GOTOs into BRAs if distance between GOTO and label
7374  * is less than 1024 bytes.
7375  *
7376  * This method is especially useful if GOTOs after BTFS[SC]
7377  * can be turned into BRAs as GOTO would cost another NOP
7378  * if skipped.
7379  */
7380 void pic16_OptimizeJumps ()
7381 {
7382   pCode *pc;
7383   pCode *pc_prev = NULL;
7384   pCode *pc_next = NULL;
7385   pBlock *pb;
7386   pCode *target;
7387   int change, iteration, isJumptab;
7388   int isHandled = 0;
7389   char *label;
7390   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7391   
7392   if (!the_pFile) return;
7393   
7394   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7395   
7396   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7397     int matchedInvertRule = 1;
7398     iteration = 1;
7399     do {
7400       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7401       change = 0;
7402       pc = pic16_findNextInstruction (pb->pcHead);
7403     
7404       while (pc) {
7405         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7406         if (isJumptab) {
7407                 // skip jumptable, i.e. start over with no pc_prev!     
7408                 pc_prev = NULL;
7409                 pc = pc_next;
7410                 continue;
7411         } // if
7412
7413         /* (1) resolve chained jumps
7414          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7415          * (a) leave dead code in and
7416          * (b) skip over the dead code with an (unneccessary) jump.
7417          */
7418         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7419           pCodeOp *lastTargetOp = NULL;
7420           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7421           int maxDist = MAX_DIST_BCC;
7422           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7423           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7424           
7425           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7426           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7427               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7428             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7429             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7430             PCI(pc)->pcop->name = lastTargetOp->name;
7431             change++;
7432             opt_gotochain++;
7433           } // if
7434         } // if
7435
7436
7437         if (IS_GOTO(pc)) {
7438           int dist;
7439           int condBraType = isSkipOnStatus(pc_prev);
7440           label = PCI(pc)->pcop->name;
7441           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7442           if (dist < 0) dist = -dist;
7443           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7444           isHandled = 0;
7445           
7446           
7447           /* (2) remove "GOTO label; label:" */
7448           if (isLabel (pc_next, label)) {
7449             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7450             // first remove all preceeding SKIP instructions
7451             while (pc_prev && isPCI_SKIP(pc_prev)) {
7452               // attach labels on this instruction to pc_next
7453               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7454               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7455               PCI(pc_prev)->label = NULL;
7456               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7457               pic16_unlinkpCode (pc_prev);
7458               pc_prev = pic16_findPrevInstruction (pc);
7459             } // while
7460             // now remove the redundant goto itself
7461             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7462             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7463             pic16_unlinkpCode (pc);
7464             pc = pic16_findPrevInstruction(pc_next->prev);
7465             isHandled = 1; // do not perform further optimizations
7466             opt_gotonext++;
7467             change++;
7468           } // if
7469           
7470           
7471           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7472           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7473             if (dist < MAX_DIST_BCC) {
7474               pCode *bcc = NULL;
7475               switch (condBraType) {
7476               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7477                 // no BDC on DIGIT CARRY available
7478               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7479               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7480               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7481               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7482                 // no BNDC on DIGIT CARRY available
7483               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7484               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7485               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7486               default:
7487                 // no replacement possible
7488                 bcc = NULL;
7489                 break;
7490               } // switch
7491               if (bcc) {
7492                 // ATTENTION: keep labels attached to BTFSx!
7493                 // HINT: GOTO is label free (checked above)
7494                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7495                 isHandled = 1; // do not perform further optimizations
7496                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7497                 pic16_pCodeReplace (pc_prev, bcc);
7498                 pc->destruct(pc);
7499                 pc = bcc;
7500                 opt_cond++;
7501                 change++;
7502               } // if
7503             } else {
7504               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7505               cond_toofar++;
7506             } // if
7507           } // if
7508
7509           if (!isHandled) {
7510             // (4) eliminate the following (common) tripel:
7511             //           <pred.>;
7512             //  labels1: Bcc label2;
7513             //           GOTO somewhere;    ; <-- instruction referenced by pc
7514             //  label2:  <cont.>
7515             // and replace it by
7516             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7517             //  label2:  <cont.>
7518             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7519             //            to <cont.> instead
7520             // ATTENTION: This optimization is only valid if <pred.> is
7521             //            not a skip operation!
7522             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7523             // ATTENTION: no label may be attached to the GOTO instruction!
7524             if (isConditionalBranch(pc_prev)
7525                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7526                 && (dist < MAX_DIST_BCC)
7527                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7528                 && hasNoLabel(pc)) {
7529               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7530             
7531               if (newBcc) {
7532                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7533                 isHandled = 1; // do not perform further optimizations
7534                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7535                 pic16_pCodeReplace (pc_prev, newBcc);
7536                 pc->destruct(pc);
7537                 pc = newBcc;
7538                 opt_reorder++;
7539                 change++;
7540                 matchedInvertRule++;
7541               }
7542             }
7543           }
7544           
7545           /* (5) now just turn GOTO into BRA */ 
7546           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7547             if (dist < MAX_DIST_BRA) {
7548               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7549               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7550               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7551               pic16_pCodeReplace (pc, newBra);
7552               pc = newBra;
7553               opt++;
7554               change++;
7555             } else {
7556               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7557               toofar++;
7558             }
7559           } // if (!isHandled)
7560         } // if
7561
7562         pc_prev = pc;
7563         pc = pc_next;
7564       } // while (pc)
7565       
7566       pBlockRemoveUnusedLabels (pb);
7567       
7568       // This line enables goto chain resolution!
7569       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7570
7571       iteration++;
7572     } while (change); /* fixpoint iteration per pBlock */
7573   } // for (pb)
7574   
7575   // emit some statistics concerning goto-optimization
7576 #if 0
7577   if (pic16_debug_verbose || pic16_pcode_verbose) {
7578     fprintf (stderr, "optimize-goto:\n"
7579              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7580              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7581              "\t%5d conditional \"skipping\" jumps inverted\n"
7582              "\t%5d GOTOs to next instruction removed\n"
7583              "\t%5d chained GOTOs resolved\n",
7584              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7585   } // if
7586 #endif
7587   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7588 }
7589
7590 #undef IS_GOTO
7591 #undef MAX_JUMPCHAIN_DEPTH
7592 #undef MAX_DIST_GOTO
7593 #undef MAX_DIST_BRA
7594 #undef MAX_DIST_BCC
7595
7596 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7597
7598 static void pBlockDestruct(pBlock *pb)
7599 {
7600
7601   if(!pb)
7602     return;
7603
7604
7605 //  Safe_free(pb);
7606
7607 }
7608
7609 /*-----------------------------------------------------------------*/
7610 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7611 /*                                  name dbName and combine them   */
7612 /*                                  into one block                 */
7613 /*-----------------------------------------------------------------*/
7614 static void mergepBlocks(char dbName)
7615 {
7616
7617   pBlock *pb, *pbmerged = NULL,*pbn;
7618
7619   pb = the_pFile->pbHead;
7620
7621   //fprintf(stderr," merging blocks named %c\n",dbName);
7622   while(pb) {
7623
7624     pbn = pb->next;
7625     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7626     if( getpBlock_dbName(pb) == dbName) {
7627
7628       //fprintf(stderr," merged block %c\n",dbName);
7629
7630       if(!pbmerged) {
7631         pbmerged = pb;
7632       } else {
7633         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7634         /* pic16_addpCode2pBlock doesn't handle the tail: */
7635         pbmerged->pcTail = pb->pcTail;
7636
7637         pb->prev->next = pbn;
7638         if(pbn) 
7639           pbn->prev = pb->prev;
7640
7641
7642         pBlockDestruct(pb);
7643       }
7644       //pic16_printpBlock(stderr, pbmerged);
7645     } 
7646     pb = pbn;
7647   }
7648
7649 }
7650
7651 /*-----------------------------------------------------------------*/
7652 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7653 /*                                                                 */
7654 /* level 0 == minimal optimization                                 */
7655 /*   optimize registers that are used only by two instructions     */
7656 /* level 1 == maximal optimization                                 */
7657 /*   optimize by looking at pairs of instructions that use the     */
7658 /*   register.                                                     */
7659 /*-----------------------------------------------------------------*/
7660
7661 static void AnalyzeFlow(int level)
7662 {
7663   static int times_called=0;
7664   pBlock *pb;
7665
7666     if(!the_pFile) {
7667       /* remove unused allocated registers before exiting */
7668       pic16_RemoveUnusedRegisters();
7669       return;
7670     }
7671
7672
7673     /* if this is not the first time this function has been called,
7674      * then clean up old flow information */
7675     if(times_called++) {
7676       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7677         unBuildFlow(pb);
7678         pic16_RegsUnMapLiveRanges();
7679     }
7680     GpcFlowSeq = 1;
7681
7682     /* Phase 2 - Flow Analysis - Register Banking
7683      *
7684      * In this phase, the individual flow blocks are examined
7685      * and register banking is fixed.
7686      */
7687
7688 #if 0
7689     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7690       pic16_FixRegisterBanking(pb);
7691 #endif
7692
7693     /* Phase 2 - Flow Analysis
7694      *
7695      * In this phase, the pCode is partition into pCodeFlow 
7696      * blocks. The flow blocks mark the points where a continuous
7697      * stream of instructions changes flow (e.g. because of
7698      * a call or goto or whatever).
7699      */
7700
7701     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7702       pic16_BuildFlow(pb);
7703
7704
7705     /* Phase 2 - Flow Analysis - linking flow blocks
7706      *
7707      * In this phase, the individual flow blocks are examined
7708      * to determine their order of excution.
7709      */
7710
7711     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7712       LinkFlow(pb);
7713
7714 #if 1
7715         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7716                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7717                         pic16_createDF (pb);
7718 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7719                         pic16_vcg_dump_default (pb);
7720 #endif
7721                         //pic16_destructDF (pb);
7722                 }
7723
7724                 pic16_df_stats ();
7725                 if (0) releaseStack (); // releasing is costly...
7726         }
7727 #endif
7728
7729     /* Phase 3 - Flow Analysis - Flow Tree
7730      *
7731      * In this phase, the individual flow blocks are examined
7732      * to determine their order of execution.
7733      */
7734
7735     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7736       pic16_BuildFlowTree(pb);
7737
7738
7739     /* Phase x - Flow Analysis - Used Banks
7740      *
7741      * In this phase, the individual flow blocks are examined
7742      * to determine the Register Banks they use
7743      */
7744
7745 #if 0
7746     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7747       FixBankFlow(pb);
7748 #endif
7749
7750
7751     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7752       pic16_pCodeRegMapLiveRanges(pb);
7753
7754     pic16_RemoveUnusedRegisters();
7755     pic16_removeUnusedRegistersDF ();
7756
7757   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7758     pic16_pCodeRegOptimizeRegUsage(level);
7759
7760
7761 #if 0
7762     if(!options.nopeep)
7763       OptimizepCode('*');
7764 #endif
7765
7766 #if 0
7767     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7768       DumpFlow(pb);
7769 #endif
7770
7771     /* debug stuff */ 
7772     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7773       pCode *pcflow;
7774       
7775         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7776           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7777           pcflow = pcflow->next) {
7778             FillFlow(PCFL(pcflow));
7779         }
7780     }
7781
7782 #if 0
7783     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7784       pCode *pcflow;
7785
7786         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7787           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7788           pcflow = pcflow->next) {
7789             FlowStats(PCFL(pcflow));
7790         }
7791     }
7792 #endif
7793 }
7794
7795 /* VR -- no need to analyze banking in flow, but left here :
7796  *      1. because it may be used in the future for other purposes
7797  *      2. because if omitted we'll miss some optimization done here
7798  *
7799  * Perhaps I should rename it to something else
7800  */
7801
7802 /*-----------------------------------------------------------------*/
7803 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7804 /*                  assigned to the registers.                     */
7805 /*                                                                 */
7806 /*-----------------------------------------------------------------*/
7807
7808 void pic16_AnalyzeBanking(void)
7809 {
7810   pBlock  *pb;
7811
7812     /* Phase x - Flow Analysis - Used Banks
7813      *
7814      * In this phase, the individual flow blocks are examined
7815      * to determine the Register Banks they use
7816      */
7817
7818     AnalyzeFlow(0);
7819     AnalyzeFlow(1);
7820
7821     if(!options.nopeep)
7822       OptimizepCode('*');
7823
7824
7825     if(!the_pFile)return;
7826
7827     if(!pic16_options.no_banksel) {
7828       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7829 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7830         pic16_FixRegisterBanking(pb);
7831       }
7832     }
7833 }
7834
7835 /*-----------------------------------------------------------------*/
7836 /* buildCallTree - Look at the flow and extract all of the calls.  */
7837 /*-----------------------------------------------------------------*/
7838 static set *register_usage(pBlock *pb);
7839
7840 static void buildCallTree(void    )
7841 {
7842   pBranch *pbr;
7843   pBlock  *pb;
7844   pCode   *pc;
7845   regs *r;
7846   
7847   if(!the_pFile)
7848     return;
7849
7850
7851
7852   /* Now build the call tree.
7853      First we examine all of the pCodes for functions.
7854      Keep in mind that the function boundaries coincide
7855      with pBlock boundaries. 
7856
7857      The algorithm goes something like this:
7858      We have two nested loops. The outer loop iterates
7859      through all of the pBlocks/functions. The inner
7860      loop iterates through all of the pCodes for
7861      a given pBlock. When we begin iterating through
7862      a pBlock, the variable pc_fstart, pCode of the start
7863      of a function, is cleared. We then search for pCodes
7864      of type PC_FUNCTION. When one is encountered, we
7865      initialize pc_fstart to this and at the same time
7866      associate a new pBranch object that signifies a 
7867      branch entry. If a return is found, then this signifies
7868      a function exit point. We'll link the pCodes of these
7869      returns to the matching pc_fstart.
7870
7871      When we're done, a doubly linked list of pBranches
7872      will exist. The head of this list is stored in
7873      `the_pFile', which is the meta structure for all
7874      of the pCode. Look at the pic16_printCallTree function
7875      on how the pBranches are linked together.
7876
7877    */
7878   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7879     pCode *pc_fstart=NULL;
7880     for(pc = pb->pcHead; pc; pc = pc->next) {
7881
7882         if(isPCI(pc) && pc_fstart) {
7883                 if(PCI(pc)->is2MemOp) {
7884                         r = pic16_getRegFromInstruction2(pc);
7885                         if(r && !strcmp(r->name, "POSTDEC1"))
7886                                 PCF(pc_fstart)->stackusage++;
7887                 } else {
7888                         r = pic16_getRegFromInstruction(pc);
7889                         if(r && !strcmp(r->name, "PREINC1"))
7890                                 PCF(pc_fstart)->stackusage--;
7891                 }
7892         }
7893
7894       if(isPCF(pc)) {
7895         if (PCF(pc)->fname) {
7896         char buf[16];
7897
7898           sprintf(buf, "%smain", port->fun_prefix);
7899           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7900             //fprintf(stderr," found main \n");
7901             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7902             pb->dbName = 'M';
7903           }
7904
7905           pbr = Safe_calloc(1,sizeof(pBranch));
7906           pbr->pc = pc_fstart = pc;
7907           pbr->next = NULL;
7908
7909           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7910
7911           // Here's a better way of doing the same:
7912           addSet(&pb->function_entries, pc);
7913
7914         } else {
7915           // Found an exit point in a function, e.g. return
7916           // (Note, there may be more than one return per function)
7917           if(pc_fstart)
7918             pBranchLink(PCF(pc_fstart), PCF(pc));
7919
7920           addSet(&pb->function_exits, pc);
7921         }
7922       } else if(isCALL(pc)) {
7923         addSet(&pb->function_calls,pc);
7924       }
7925     }
7926   }
7927
7928
7929 #if 0
7930   /* This is not needed because currently all register used
7931    * by a function are stored in stack -- VR */
7932    
7933   /* Re-allocate the registers so that there are no collisions
7934    * between local variables when one function call another */
7935
7936   // this is weird...
7937   //  pic16_deallocateAllRegs();
7938
7939   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7940     if(!pb->visited)
7941       register_usage(pb);
7942   }
7943 #endif
7944
7945 }
7946
7947 /*-----------------------------------------------------------------*/
7948 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7949 /*                all of the logical connections.                  */
7950 /*                                                                 */
7951 /* Essentially what's done here is that the pCode flow is          */
7952 /* determined.                                                     */
7953 /*-----------------------------------------------------------------*/
7954
7955 void pic16_AnalyzepCode(char dbName)
7956 {
7957   pBlock *pb;
7958   int i,changes;
7959
7960   if(!the_pFile)
7961     return;
7962
7963   mergepBlocks('D');
7964
7965
7966   /* Phase 1 - Register allocation and peep hole optimization
7967    *
7968    * The first part of the analysis is to determine the registers
7969    * that are used in the pCode. Once that is done, the peep rules
7970    * are applied to the code. We continue to loop until no more
7971    * peep rule optimizations are found (or until we exceed the
7972    * MAX_PASSES threshold). 
7973    *
7974    * When done, the required registers will be determined.
7975    *
7976    */
7977   i = 0;
7978   do {
7979
7980     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7981     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7982
7983     /* First, merge the labels with the instructions */
7984     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7985       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7986
7987         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7988         //fprintf(stderr," analyze and merging block %c\n",dbName);
7989         pic16_pBlockMergeLabels(pb);
7990         AnalyzepBlock(pb);
7991       } else {
7992         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7993       }
7994     }
7995
7996         if(!options.nopeep)
7997                 changes = OptimizepCode(dbName);
7998         else changes = 0;
7999
8000   } while(changes && (i++ < MAX_PASSES));
8001
8002   
8003   buildCallTree();
8004 }
8005
8006
8007 /* convert a series of movff's of local regs to stack, with a single call to
8008  * a support functions which does the same thing via loop */
8009 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8010 {
8011   pBranch *pbr;
8012   pCode *pc, *pct;
8013   char *fname[]={"__lr_store", "__lr_restore"};
8014
8015 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8016
8017     pct = pic16_findNextInstruction(pcstart->next);
8018     do {
8019       pc = pct;
8020       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8021 //      pc->print(stderr, pc);
8022       if(isPCI(pc) && PCI(pc)->label) {
8023         pbr = PCI(pc)->label;
8024         while(pbr && pbr->pc) {
8025           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8026           pbr = pbr->next;
8027         }
8028
8029 //        pc->print(stderr, pc);
8030         /* unlink pCode */
8031         pc->prev->next = pct;
8032         pct->prev = pc->prev;
8033 //        pc->next = NULL;
8034 //        pc->prev = NULL;
8035       }
8036     } while ((pc) && (pc != pcend));
8037
8038     /* unlink movff instructions */
8039     pcstart->next = pcend;
8040     pcend->prev = pcstart;
8041
8042     pc = pcstart;
8043 //    if(!entry) {
8044 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8045 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8046 //    }
8047                 
8048     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8049     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8050     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8051
8052 //    if(!entry) {
8053 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8054 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8055 //    }
8056
8057     
8058     {
8059       symbol *sym;
8060
8061         sym = newSymbol( fname[ entry?0:1 ], 0 );
8062         strcpy(sym->rname, fname[ entry?0:1 ]);
8063         checkAddSym(&externs, sym);
8064         
8065 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8066     }
8067
8068 }
8069
8070 /*-----------------------------------------------------------------*/
8071 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8072 /*    local registers to a support function call                   */
8073 /*-----------------------------------------------------------------*/
8074 void pic16_OptimizeLocalRegs(void)
8075 {
8076   pBlock  *pb;
8077   pCode   *pc;
8078   pCodeInfo *pci;
8079   pCodeOpLocalReg *pclr;
8080   int regCount=0;
8081   int inRegCount=0;
8082   regs *r, *lastr=NULL, *firstr=NULL;
8083   pCode *pcstart=NULL, *pcend=NULL;
8084   int inEntry=0;
8085   char *curFunc=NULL;
8086
8087         /* Overview:
8088          *   local_regs begin mark
8089          *      MOVFF r0x01, POSTDEC1
8090          *      MOVFF r0x02, POSTDEC1
8091          *      ...
8092          *      ...
8093          *      MOVFF r0x0n, POSTDEC1
8094          *   local_regs end mark
8095          *
8096          * convert the above to the below:
8097          *      MOVLW   starting_register_index
8098          *      MOVWF   PRODL
8099          *      MOVLW   register_count
8100          *      call    __save_registers_in_stack
8101          */
8102
8103     if(!the_pFile)
8104       return;
8105
8106     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8107       inRegCount = regCount = 0;
8108       firstr = lastr = NULL;
8109       for(pc = pb->pcHead; pc; pc = pc->next) {
8110
8111         /* hold current function name */
8112         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8113         
8114         if(pc && (pc->type == PC_INFO)) {
8115           pci = PCINF(pc);
8116
8117           if(pci->type == INF_LOCALREGS) {
8118             pclr = PCOLR(pci->oper1);
8119             
8120             if((pclr->type == LR_ENTRY_BEGIN)
8121               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8122             else inEntry = 0;
8123             
8124             switch(pclr->type) {
8125               case LR_ENTRY_BEGIN:
8126               case LR_EXIT_BEGIN:
8127                         inRegCount = 1; regCount = 0;
8128                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8129                         firstr = lastr = NULL;
8130                         break;
8131               
8132               case LR_ENTRY_END:
8133               case LR_EXIT_END:
8134                         inRegCount = -1;
8135                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8136
8137 #if 1
8138                         if(curFunc && inWparamList(curFunc+1)) {
8139                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8140                                         filename, curFunc);
8141                         } else {
8142                           if(regCount>2) {
8143                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8144                               firstr, inEntry);
8145                           }
8146                         }
8147 #endif
8148                         firstr = lastr = NULL;
8149                         break;
8150             }
8151             
8152             if(inRegCount == -1) {
8153 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8154               regCount = 0;
8155               inRegCount = 0;
8156             }
8157           }
8158         } else {
8159           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8160             if(inEntry)
8161               r = pic16_getRegFromInstruction(pc);
8162             else
8163               r = pic16_getRegFromInstruction2(pc);
8164             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8165               if(!firstr)firstr = r;
8166               regCount++;
8167 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8168             }
8169           }
8170         }
8171       }
8172     }
8173 }
8174               
8175             
8176
8177
8178
8179 /*-----------------------------------------------------------------*/
8180 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8181 /*                   function                                      */
8182 /*-----------------------------------------------------------------*/
8183 static bool ispCodeFunction(pCode *pc)
8184 {
8185
8186   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8187     return 1;
8188
8189   return 0;
8190 }
8191
8192 /*-----------------------------------------------------------------*/
8193 /* findFunction - Search for a function by name (given the name)   */
8194 /*                in the set of all functions that are in a pBlock */
8195 /* (note - I expect this to change because I'm planning to limit   */
8196 /*  pBlock's to just one function declaration                      */
8197 /*-----------------------------------------------------------------*/
8198 static pCode *findFunction(char *fname)
8199 {
8200   pBlock *pb;
8201   pCode *pc;
8202   if(!fname)
8203     return NULL;
8204
8205   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8206
8207     pc = setFirstItem(pb->function_entries);
8208     while(pc) {
8209     
8210       if((pc->type == PC_FUNCTION) &&
8211          (PCF(pc)->fname) && 
8212          (strcmp(fname, PCF(pc)->fname)==0))
8213         return pc;
8214
8215       pc = setNextItem(pb->function_entries);
8216
8217     }
8218
8219   }
8220   return NULL;
8221 }
8222
8223 static void MarkUsedRegisters(set *regset)
8224 {
8225
8226   regs *r1,*r2;
8227
8228   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8229 //      fprintf(stderr, "marking register = %s\t", r1->name);
8230     r2 = pic16_regWithIdx(r1->rIdx);
8231 //      fprintf(stderr, "to register = %s\n", r2->name);
8232     r2->isFree = 0;
8233     r2->wasUsed = 1;
8234   }
8235 }
8236
8237 static void pBlockStats(FILE *of, pBlock *pb)
8238 {
8239
8240   pCode *pc;
8241   regs  *r;
8242
8243         if(!pic16_pcode_verbose)return;
8244         
8245   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8246
8247   // for now just print the first element of each set
8248   pc = setFirstItem(pb->function_entries);
8249   if(pc) {
8250     fprintf(of,";entry:  ");
8251     pc->print(of,pc);
8252   }
8253   pc = setFirstItem(pb->function_exits);
8254   if(pc) {
8255     fprintf(of,";has an exit\n");
8256     //pc->print(of,pc);
8257   }
8258
8259   pc = setFirstItem(pb->function_calls);
8260   if(pc) {
8261     fprintf(of,";functions called:\n");
8262
8263     while(pc) {
8264       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8265         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8266       }
8267       pc = setNextItem(pb->function_calls);
8268     }
8269   }
8270
8271   r = setFirstItem(pb->tregisters);
8272   if(r) {
8273     int n = elementsInSet(pb->tregisters);
8274
8275     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8276
8277     while (r) {
8278       fprintf(of,   ";   %s\n",r->name);
8279       r = setNextItem(pb->tregisters);
8280     }
8281   }
8282   
8283   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8284 }
8285
8286 /*-----------------------------------------------------------------*/
8287 /*-----------------------------------------------------------------*/
8288 #if 0
8289 static void sequencepCode(void)
8290 {
8291   pBlock *pb;
8292   pCode *pc;
8293
8294
8295   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8296
8297     pb->seq = GpCodeSequenceNumber+1;
8298
8299     for( pc = pb->pcHead; pc; pc = pc->next)
8300       pc->seq = ++GpCodeSequenceNumber;
8301   }
8302
8303 }
8304 #endif
8305
8306 /*-----------------------------------------------------------------*/
8307 /*-----------------------------------------------------------------*/
8308 static set *register_usage(pBlock *pb)
8309 {
8310   pCode *pc,*pcn;
8311   set *registers=NULL;
8312   set *registersInCallPath = NULL;
8313
8314   /* check recursion */
8315
8316   pc = setFirstItem(pb->function_entries);
8317
8318   if(!pc)
8319     return registers;
8320
8321   pb->visited = 1;
8322
8323   if(pc->type != PC_FUNCTION)
8324     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8325
8326   pc = setFirstItem(pb->function_calls);
8327   for( ; pc; pc = setNextItem(pb->function_calls)) {
8328
8329     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8330       char *dest = pic16_get_op_from_instruction(PCI(pc));
8331
8332       pcn = findFunction(dest);
8333       if(pcn) 
8334         registersInCallPath = register_usage(pcn->pb);
8335     } else
8336       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8337
8338   }
8339
8340 #ifdef PCODE_DEBUG
8341   pBlockStats(stderr,pb);  // debug
8342 #endif
8343
8344   // Mark the registers in this block as used.
8345
8346   MarkUsedRegisters(pb->tregisters);
8347   if(registersInCallPath) {
8348     /* registers were used in the functions this pBlock has called */
8349     /* so now, we need to see if these collide with the ones we are */
8350     /* using here */
8351
8352     regs *r1,*r2, *newreg;
8353
8354     DFPRINTF((stderr,"comparing registers\n"));
8355
8356     r1 = setFirstItem(registersInCallPath);
8357     while(r1) {
8358
8359       r2 = setFirstItem(pb->tregisters);
8360
8361       while(r2 && (r1->type != REG_STK)) {
8362
8363         if(r2->rIdx == r1->rIdx) {
8364           newreg = pic16_findFreeReg(REG_GPR);
8365
8366
8367           if(!newreg) {
8368             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8369             exit(1);
8370           }
8371
8372           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8373                   r1->rIdx, newreg->rIdx));
8374           r2->rIdx = newreg->rIdx;
8375           //if(r2->name) Safe_free(r2->name);
8376           if(newreg->name)
8377             r2->name = Safe_strdup(newreg->name);
8378           else
8379             r2->name = NULL;
8380           newreg->isFree = 0;
8381           newreg->wasUsed = 1;
8382         }
8383         r2 = setNextItem(pb->tregisters);
8384       }
8385
8386       r1 = setNextItem(registersInCallPath);
8387     }
8388
8389     /* Collisions have been resolved. Now free the registers in the call path */
8390     r1 = setFirstItem(registersInCallPath);
8391     while(r1) {
8392       if(r1->type != REG_STK) {
8393         newreg = pic16_regWithIdx(r1->rIdx);
8394         newreg->isFree = 1;
8395       }
8396       r1 = setNextItem(registersInCallPath);
8397     }
8398
8399   }// else
8400   //    MarkUsedRegisters(pb->registers);
8401
8402   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8403 #ifdef PCODE_DEBUG
8404   if(registers) 
8405     DFPRINTF((stderr,"returning regs\n"));
8406   else
8407     DFPRINTF((stderr,"not returning regs\n"));
8408
8409   DFPRINTF((stderr,"pBlock after register optim.\n"));
8410   pBlockStats(stderr,pb);  // debug
8411 #endif
8412
8413   return registers;
8414 }
8415
8416 /*-----------------------------------------------------------------*/
8417 /* pct2 - writes the call tree to a file                           */
8418 /*                                                                 */
8419 /*-----------------------------------------------------------------*/
8420 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8421 {
8422   pCode *pc,*pcn;
8423   int i;
8424   //  set *registersInCallPath = NULL;
8425
8426   if(!of)
8427     return;
8428
8429   if(indent > 10) {
8430         fprintf(of, "recursive function\n");
8431     return; //recursion ?
8432   }
8433
8434   pc = setFirstItem(pb->function_entries);
8435
8436   if(!pc)
8437     return;
8438
8439   pb->visited = 0;
8440
8441   for(i=0;i<indent;i++)   // Indentation
8442         fputs("+   ", of);
8443   fputs("+- ", of);
8444
8445   if(pc->type == PC_FUNCTION) {
8446     usedstack += PCF(pc)->stackusage;
8447     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8448   } else return;  // ???
8449
8450
8451   pc = setFirstItem(pb->function_calls);
8452   for( ; pc; pc = setNextItem(pb->function_calls)) {
8453
8454     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8455       char *dest = pic16_get_op_from_instruction(PCI(pc));
8456
8457       pcn = findFunction(dest);
8458       if(pcn) 
8459         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8460     } else
8461       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8462
8463   }
8464
8465
8466 }
8467
8468
8469 /*-----------------------------------------------------------------*/
8470 /* pic16_printCallTree - writes the call tree to a file                  */
8471 /*                                                                 */
8472 /*-----------------------------------------------------------------*/
8473
8474 void pic16_printCallTree(FILE *of)
8475 {
8476   pBranch *pbr;
8477   pBlock  *pb;
8478   pCode   *pc;
8479
8480   if(!the_pFile)
8481     return;
8482
8483   if(!of)
8484     of = stderr;
8485
8486   fprintf(of, "\npBlock statistics\n");
8487   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8488     pBlockStats(of,pb);
8489
8490
8491   fprintf(of,"Call Tree\n");
8492   pbr = the_pFile->functions;
8493   while(pbr) {
8494     if(pbr->pc) {
8495       pc = pbr->pc;
8496       if(!ispCodeFunction(pc))
8497         fprintf(of,"bug in call tree");
8498
8499
8500       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8501
8502       while(pc->next && !ispCodeFunction(pc->next)) {
8503         pc = pc->next;
8504         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8505           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8506       }
8507     }
8508
8509     pbr = pbr->next;
8510   }
8511
8512
8513   fprintf(of,"\n**************\n\na better call tree\n");
8514   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8515 //    if(pb->visited)
8516       pct2(of,pb,0,0);
8517   }
8518
8519   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8520     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8521   }
8522 }
8523
8524
8525
8526 /*-----------------------------------------------------------------*/
8527 /*                                                                 */
8528 /*-----------------------------------------------------------------*/
8529
8530 static void InlineFunction(pBlock *pb)
8531 {
8532   pCode *pc;
8533   pCode *pc_call;
8534
8535   if(!pb)
8536     return;
8537
8538   pc = setFirstItem(pb->function_calls);
8539
8540   for( ; pc; pc = setNextItem(pb->function_calls)) {
8541
8542     if(isCALL(pc)) {
8543       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8544       pCode *pct;
8545       pCode *pce;
8546
8547       pBranch *pbr;
8548
8549       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8550         
8551         //fprintf(stderr,"Cool can inline:\n");
8552         //pcn->print(stderr,pcn);
8553
8554         //fprintf(stderr,"recursive call Inline\n");
8555         InlineFunction(pcn->pb);
8556         //fprintf(stderr,"return from recursive call Inline\n");
8557
8558         /*
8559           At this point, *pc points to a CALL mnemonic, and
8560           *pcn points to the function that is being called.
8561
8562           To in-line this call, we need to remove the CALL
8563           and RETURN(s), and link the function pCode in with
8564           the CALLee pCode.
8565
8566         */
8567
8568
8569         /* Remove the CALL */
8570         pc_call = pc;
8571         pc = pc->prev;
8572
8573         /* remove callee pBlock from the pBlock linked list */
8574         removepBlock(pcn->pb);
8575
8576         pce = pcn;
8577         while(pce) {
8578           pce->pb = pb;
8579           pce = pce->next;
8580         }
8581
8582         /* Remove the Function pCode */
8583         pct = pic16_findNextInstruction(pcn->next);
8584
8585         /* Link the function with the callee */
8586         pc->next = pcn->next;
8587         pcn->next->prev = pc;
8588         
8589         /* Convert the function name into a label */
8590
8591         pbr = Safe_calloc(1,sizeof(pBranch));
8592         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8593         pbr->next = NULL;
8594         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8595         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8596
8597         /* turn all of the return's except the last into goto's */
8598         /* check case for 2 instruction pBlocks */
8599         pce = pic16_findNextInstruction(pcn->next);
8600         while(pce) {
8601           pCode *pce_next = pic16_findNextInstruction(pce->next);
8602
8603           if(pce_next == NULL) {
8604             /* found the last return */
8605             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8606
8607             //fprintf(stderr,"found last return\n");
8608             //pce->print(stderr,pce);
8609             pce->prev->next = pc_call->next;
8610             pc_call->next->prev = pce->prev;
8611             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8612                                                       PCI(pce)->label);
8613           }
8614
8615           pce = pce_next;
8616         }
8617
8618
8619       }
8620     } else
8621       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8622
8623   }
8624
8625 }
8626
8627 /*-----------------------------------------------------------------*/
8628 /*                                                                 */
8629 /*-----------------------------------------------------------------*/
8630
8631 void pic16_InlinepCode(void)
8632 {
8633
8634   pBlock  *pb;
8635   pCode   *pc;
8636
8637   if(!the_pFile)
8638     return;
8639
8640   if(!functionInlining)
8641     return;
8642
8643   /* Loop through all of the function definitions and count the
8644    * number of times each one is called */
8645   //fprintf(stderr,"inlining %d\n",__LINE__);
8646
8647   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8648
8649     pc = setFirstItem(pb->function_calls);
8650
8651     for( ; pc; pc = setNextItem(pb->function_calls)) {
8652
8653       if(isCALL(pc)) {
8654         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8655         if(pcn && isPCF(pcn)) {
8656           PCF(pcn)->ncalled++;
8657         }
8658       } else
8659         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8660
8661     }
8662   }
8663
8664   //fprintf(stderr,"inlining %d\n",__LINE__);
8665
8666   /* Now, Loop through the function definitions again, but this
8667    * time inline those functions that have only been called once. */
8668   
8669   InlineFunction(the_pFile->pbHead);
8670   //fprintf(stderr,"inlining %d\n",__LINE__);
8671
8672   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8673     unBuildFlow(pb);
8674
8675 }
8676
8677 char *pic_optype_names[]={
8678         "PO_NONE",         // No operand e.g. NOP
8679         "PO_W",              // The working register (as a destination)
8680         "PO_WREG",           // The working register (as a file register)
8681         "PO_STATUS",         // The 'STATUS' register
8682         "PO_BSR",            // The 'BSR' register
8683         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8684                              // of three)
8685         "PO_INDF0",          // The Indirect register
8686         "PO_INTCON",         // Interrupt Control register
8687         "PO_GPR_REGISTER",   // A general purpose register
8688         "PO_GPR_BIT",        // A bit of a general purpose register
8689         "PO_GPR_TEMP",       // A general purpose temporary register
8690         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8691         "PO_PCL",            // Program counter Low register
8692         "PO_PCLATH",         // Program counter Latch high register
8693         "PO_PCLATU",         // Program counter Latch upper register
8694         "PO_PRODL",          // Product Register Low
8695         "PO_PRODH",          // Product Register High
8696         "PO_LITERAL",        // A constant
8697         "PO_REL_ADDR",       // A relative address
8698         "PO_IMMEDIATE",      //  (8051 legacy)
8699         "PO_DIR",            // Direct memory (8051 legacy)
8700         "PO_CRY",            // bit memory (8051 legacy)
8701         "PO_BIT",            // bit operand.
8702         "PO_STR",            //  (8051 legacy)
8703         "PO_LABEL",
8704         "PO_WILD",           // Wild card operand in peep optimizer
8705         "PO_TWO_OPS"         // combine two operands
8706 };
8707
8708
8709 char *dumpPicOptype(PIC_OPTYPE type)
8710 {
8711         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8712         return (pic_optype_names[ type ]);
8713 }
8714
8715
8716 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8717 #include "graph.h"
8718
8719 #define MAX_COMMON_BANK_SIZE    32
8720 #define FIRST_PSEUDO_BANK_NR  1000
8721
8722 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8723 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8724 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8725 Graph *adj = NULL;
8726
8727 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8728
8729 typedef struct {
8730   pseudoBankNr bank;  // number assigned to this pseudoBank
8731   unsigned int size;  // number of operands assigned to this bank
8732   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8733 } pseudoBank;
8734
8735 /*----------------------------------------------------------------------*/
8736 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8737 /*----------------------------------------------------------------------*/
8738 unsigned int hashSymbol (const char *str)
8739 {
8740   unsigned int res = 0;
8741   if (!str) return 0;
8742
8743   while (*str) {
8744     res ^= (*str);
8745     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8746     str++;
8747   } // while
8748
8749   return res;
8750 }
8751
8752 /*-----------------------------------------------------------------------*/
8753 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8754 /*-----------------------------------------------------------------------*/
8755 int compareSymbol (const void *sym1, const void *sym2)
8756 {
8757   char *s1 = (char*) sym1;
8758   char *s2 = (char*) sym2;
8759   
8760   return (strcmp (s1,s2) == 0);
8761 }
8762
8763 /*-----------------------------------------------------------------------*/
8764 /* comparePre - return 1 iff p1 == p2                                    */
8765 /*-----------------------------------------------------------------------*/
8766 int comparePtr (const void *p1, const void *p2)
8767 {
8768   return (p1 == p2);
8769 }
8770
8771 /*----------------------------------------------------------*/
8772 /* getSymbolFromOperand - return a pointer to the symbol in */
8773 /*                        the given operand and its length  */
8774 /*----------------------------------------------------------*/
8775 char *getSymbolFromOperand (char *op, int *len)
8776 {
8777   char *sym, *curr;
8778   *len = 0;
8779
8780   if (!op) return NULL;
8781
8782   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8783   sym = op;
8784   if (*sym == '(') sym++;
8785
8786   curr = sym;
8787   while (((*curr >= 'A') && (*curr <= 'Z'))
8788          || ((*curr >= 'a') && (*curr <= 'z'))
8789          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8790          || (*curr == '_')) {
8791     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8792     curr++;
8793     (*len)++;
8794   } // while
8795
8796   return sym;
8797 }
8798
8799 /*--------------------------------------------------------------------------*/
8800 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8801 /*--------------------------------------------------------------------------*/
8802 char *getSymFromBank (pseudoBankNr bank)
8803 {
8804   assert (bank2sym);
8805
8806   if (bank < 0) return "<INVALID BANK NR>";
8807   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8808 }
8809
8810 /*-----------------------------------------------------------------------*/
8811 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8812 /*                           bank number (uses hTab sym2bank), if the    */
8813 /*                           symbol is not yet assigned a pseudo bank it */
8814 /*                           is assigned one here                        */
8815 /*-----------------------------------------------------------------------*/
8816 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8817 {
8818   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8819   pseudoBankNr bank;
8820   unsigned int hash;
8821
8822   assert (sym2bank);
8823
8824   hash = hashSymbol (op) % sym2bank->size;
8825   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8826   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8827
8828   if (bank == UNKNOWN_BANK) {
8829     // create a pseudo bank for the operand
8830     bank = next_bank++;
8831     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8832     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8833     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8834     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8835   } else {
8836     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8837   } // if
8838
8839   assert (bank >= 0);
8840
8841   return bank;
8842 }
8843
8844 /*--------------------------------------------------------------------*/
8845 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8846 /*--------------------------------------------------------------------*/
8847 int isBanksel (pCode *pc)
8848 {
8849   if (!pc) return 0;
8850
8851   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8852     // BANKSEL <variablename>  or  MOVLB <banknr>
8853     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8854     return 1;
8855   }
8856
8857   // check for inline assembler BANKSELs
8858   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8859                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8860     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8861     return 1;
8862   }
8863
8864   // assume pc is no BANKSEL instruction
8865   return 0;
8866 }
8867
8868 /*---------------------------------------------------------------------------------*/
8869 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8870 /*                  This method can not guarantee to find all modifications of the */
8871 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8872 /*                  generated plus some cases.                                     */
8873 /*---------------------------------------------------------------------------------*/
8874 int invalidatesBSR(pCode *pc)
8875 {
8876   // assembler directives invalidate BSR (well, they might, we don't know)
8877   if (isPCAD(pc)) return 1;
8878
8879   // only ASMDIRs and pCodeInstructions can invalidate BSR
8880   if (!isPCI(pc)) return 0;
8881
8882   // we have a pCodeInstruction
8883
8884   // check for BSR modifying instructions
8885   switch (PCI(pc)->op) {
8886   case POC_CALL:
8887   case POC_RCALL:
8888   case POC_MOVLB:
8889   case POC_RETFIE:  // might be used as CALL replacement
8890   case POC_RETLW:   // might be used as CALL replacement
8891   case POC_RETURN:  // might be used as CALL replacement
8892   case POC_BANKSEL:
8893     return 1;
8894     break;
8895
8896   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8897     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8898     break;
8899   } // switch
8900
8901   // no change of BSR possible/probable
8902   return 0;
8903 }
8904
8905 /*------------------------------------------------------------*/
8906 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8907 /*                      the symbol referenced in this BANKSEL */
8908 /*------------------------------------------------------------*/
8909 pseudoBankNr getBankFromBanksel (pCode *pc)
8910 {
8911   char *sym;
8912   int data = (int)NULL;
8913
8914   if (!pc) return INVALID_BANK;
8915   
8916   if (isPCAD(pc) && PCAD(pc)->directive) {
8917     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8918       // get symbolname from PCAD(pc)->arg
8919       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8920       sym = PCAD(pc)->arg;
8921       data = getPseudoBankNrFromOperand (sym);
8922       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8923     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8924       // get (literal) bank number from PCAD(pc)->arg
8925       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8926       assert (0 && "not yet implemented - turn off banksel optimization for now");
8927     }
8928   } else if (isPCI(pc)) {
8929     if (PCI(pc)->op == POC_BANKSEL) {
8930       // get symbolname from PCI(pc)->pcop->name (?)
8931       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8932       sym = PCI(pc)->pcop->name;
8933       data = getPseudoBankNrFromOperand (sym);
8934       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8935     } else if (PCI(pc)->op == POC_MOVLB) {
8936       // get (literal) bank number from PCI(pc)->pcop->name
8937       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8938       assert (0 && "not yet implemented - turn off banksel optimization for now");
8939     }
8940   }
8941   
8942   if (data == 0)
8943     // no assigned bank could be found
8944     return UNKNOWN_BANK;
8945   else
8946     return data;
8947 }
8948
8949 /*------------------------------------------------------------------------------*/
8950 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8951 /*------------------------------------------------------------------------------*/
8952 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8953 {
8954   pseudoBank *data;
8955
8956   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8957
8958   do {
8959     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8960     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8961     if (data) {
8962       if (data->bank != bank)
8963         bank = data->bank;
8964       else
8965         data = NULL;
8966     }
8967   } while (data);
8968   
8969   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8970   return bank;
8971 }
8972
8973 /*------------------------------------------------------------------*/
8974 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8975 /*                        bank is selected at a given pCode         */
8976 /*------------------------------------------------------------------*/
8977
8978 /* Create a graph with pseudo banks as its nodes and switches between
8979  * these as edges (with the edge weight representing the absolute
8980  * number of BANKSELs from one to the other).
8981  * Removes redundand BANKSELs instead iff mod == 1.
8982  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8983  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8984  * pseudo BSR.
8985  * TODO: check ALL instructions operands if they modify BSR directly...
8986  *
8987  * pb - the pBlock to annotate
8988  * mod  - select either graph creation (0) or BANKSEL removal (1)
8989  */
8990 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8991 {
8992   pCode *pc, *pc_next;
8993   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8994   int isBankselect = 0;
8995   unsigned int banksels=0;
8996   
8997   if (!pb) return 0;
8998
8999   pc = pic16_findNextInstruction(pb->pcHead);
9000   while (pc) {
9001     isBankselect = isBanksel (pc);
9002     pc_next = pic16_findNextInstruction (pc->next);
9003
9004     if (!hasNoLabel (pc)) {
9005       // we don't know our predecessors -- assume different BSRs
9006       prevBSR = UNKNOWN_BANK;
9007       pseudoBSR = UNKNOWN_BANK;
9008       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9009     } // if
9010
9011     // check if this is a BANKSEL instruction
9012     if (isBankselect) {
9013       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9014       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9015       if (mod) {
9016         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9017           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9018           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9019           pic16_unlinkpCode (pc);
9020           banksels++;
9021         }
9022       } else {
9023         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9024         banksels++;
9025       }
9026     } // if
9027
9028     if (!isBankselect && invalidatesBSR(pc)) {
9029       // check if this instruction invalidates the pseudoBSR
9030       pseudoBSR = UNKNOWN_BANK;
9031       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9032     } // if
9033
9034     prevBSR = pseudoBSR;
9035     pc = pc_next;
9036   } // while
9037
9038   return banksels;
9039 }
9040
9041 /*------------------------------------------------------------------------------------*/
9042 /* assignToSameBank - returns 0 on success or an error code                           */
9043 /*  1 - common bank would be too large                                                */
9044 /*  2 - assignment to fixed (absolute) bank not performed                             */
9045 /*                                                                                    */
9046 /* This functions assumes that unsplittable operands are already assigned to the same */
9047 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9048 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9049 /* TODO: Symbols with an abslute address must be handled specially!                   */
9050 /*------------------------------------------------------------------------------------*/
9051 int assignToSameBank (int bank0, int bank1, int doAbs)
9052 {
9053   int eff0, eff1, dummy;
9054   pseudoBank *pbank0, *pbank1;
9055   hashtItem *hitem;
9056
9057   eff0 = getEffectiveBank (bank0);
9058   eff1 = getEffectiveBank (bank1);
9059
9060   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9061
9062   // nothing to do if already same bank
9063   if (eff0 == eff1) return 0;
9064
9065   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9066     return 2;
9067
9068   // ensure eff0 < eff1
9069   if (eff0 > eff1) {
9070     // swap eff0 and eff1
9071     dummy = eff0;
9072     eff0 = eff1;
9073     eff1 = dummy;
9074     dummy = bank0;
9075     bank0 = bank1;
9076     bank1 = dummy;
9077   } // if
9078
9079   // now assign bank eff1 to bank eff0
9080   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9081   if (!pbank0) {
9082     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9083     pbank0->bank = eff0;
9084     pbank0->size = 1;
9085     pbank0->ref = 1;
9086     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9087   } // if
9088
9089   pbank1 = NULL;
9090   hitem = hTabSearch (coerce, eff1 % coerce->size);
9091   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9092     hitem = hitem->next;
9093
9094   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9095
9096 #if 0
9097   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9098            pbank0->bank, pbank0->size,
9099            getSymFromBank (eff0), getSymFromBank (eff1));
9100 #endif
9101
9102   if (pbank1) {
9103     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9104 #if 0
9105       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9106                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9107                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9108                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9109 #endif
9110       return 1;
9111     } // if
9112     pbank0->size += pbank1->size;
9113     pbank1->ref--;
9114     if (pbank1->ref == 0) Safe_free (pbank1);
9115   } else {
9116     pbank0->size++;
9117   } // if
9118
9119   if (hitem)
9120     hitem->item = pbank0;
9121   else  
9122     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9123   pbank0->ref++;
9124
9125   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9126
9127   return 0;
9128 }
9129
9130 /*----------------------------------------------------------------*/
9131 /* mergeGraphNodes - combines two nodes into one and modifies all */
9132 /*                   edges to and from the nodes accordingly      */
9133 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9134 /* then also (B,A) must be an edge (possibly with weight 0).      */
9135 /*----------------------------------------------------------------*/
9136 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9137 {
9138   GraphEdge *edge, *backedge, *nextedge;
9139   GraphNode *node;
9140   int backweight;
9141
9142   assert (node1 && node2);
9143   assert (node1 != node2);
9144   
9145   // add all edges starting at node2 to node1
9146   edge = node2->edge;
9147   while (edge) {
9148     nextedge = edge->next;
9149     node = edge->node;
9150     backedge = getGEdge (node, node2);
9151     if (backedge)
9152       backweight = backedge->weight;
9153     else
9154       backweight = 0;
9155     // insert edges (node1,node) and (node,node1)
9156     addGEdge2 (node1, node, edge->weight, backweight);
9157     // remove edges (node, node2) and (node2, node)
9158     remGEdge (node2, node);
9159     remGEdge (node, node2);
9160     edge = nextedge;
9161   } // while
9162   
9163   // now node2 should not be referenced by any other GraphNode...
9164   //remGNode (adj, node2->data, node2->hash);
9165 }
9166
9167 /*----------------------------------------------------------------*/
9168 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9169 /*----------------------------------------------------------------*/
9170 void showGraph (Graph *g)
9171 {
9172   GraphNode *node;
9173   GraphEdge *edge;
9174   pseudoBankNr bankNr;
9175   pseudoBank *pbank;
9176   unsigned int size;
9177
9178   node = g->node;
9179   while (node) {
9180     edge = node->edge;
9181     bankNr = getEffectiveBank (node->hash);
9182     assert (bankNr >= 0);
9183     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9184     if (pbank) {
9185       bankNr = pbank->bank;
9186       size = pbank->size;
9187     } else {
9188       size = 1;
9189     }
9190     
9191     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9192
9193     while (edge) {
9194       if (edge->weight > 0)
9195         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9196       edge = edge->next;
9197     } // while (edge)
9198     node = node->next;
9199   } // while (node)
9200 }
9201
9202 /*---------------------------------------------------------------*/
9203 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9204 /*---------------------------------------------------------------*/
9205 void pic16_OptimizeBanksel ()
9206 {
9207   GraphNode *node, *node1, *node1next;
9208
9209 #if 0
9210   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9211   GraphEdge *edge, *backedge;
9212   GraphEdge *max;
9213   int maxWeight, weight, mergeMore, absMaxWeight;
9214   pseudoBankNr curr0, curr1;
9215 #endif
9216   pseudoBank *pbank;
9217   pseudoBankNr bankNr;
9218   char *base_symbol0, *base_symbol1;
9219   int len0, len1;
9220   pBlock *pb;
9221   set *set;
9222   regs *reg;
9223   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9224
9225   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9226
9227   if (!the_pFile || !the_pFile->pbHead) return;
9228
9229   adj = newGraph (NULL);
9230   sym2bank = newHashTable ( 255 );
9231   bank2sym = newHashTable ( 255 );
9232   coerce = newHashTable ( 255 );
9233
9234   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9235   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9236     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9237   } // for pb
9238
9239 #if 1
9240   // assign symbols with absolute addresses to their respective bank nrs
9241   set = pic16_fix_udata;
9242   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9243     bankNr = reg->address >> 8;
9244     node = getOrAddGNode (adj, NULL, bankNr);
9245     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9246     assignToSameBank (node->hash, bankNr, 1);
9247     
9248     assert (bankNr >= 0);
9249     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9250     if (!pbank) {
9251       pbank = Safe_calloc (1, sizeof (pseudoBank));
9252       pbank->bank = reg->address >> 8; //FIXED_BANK;
9253       pbank->size = 1;
9254       pbank->ref = 1;
9255       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9256     } else {
9257       assert (pbank->bank == (reg->address >> 8));
9258       pbank->bank = reg->address >> 8; //FIXED_BANK;
9259     }
9260     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9261   } // for reg
9262 #endif
9263
9264 #if 1
9265   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9266   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9267   node = adj->node;
9268   while (node) {
9269     if (node->hash < 0) { node = node->next; continue; }
9270     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9271     node1 = node->next;
9272     while (node1) {
9273       if (node1->hash < 0) { node1 = node1->next; continue; }
9274       node1next = node1->next;
9275       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9276       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9277         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9278         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9279         if (assignToSameBank (node->hash, node1->hash, 0)) {
9280           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9281           assert (0 && "Could not assign a symbol to a bank!");
9282         }
9283         mergeGraphNodes (node, node1);
9284         /*
9285         if (node->hash < node1->hash)
9286           mergeGraphNodes (node, node1);
9287         else
9288           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9289         */
9290       } // if
9291       node1 = node1next;
9292     } // while (node1)
9293     node = node->next;
9294   } // while (node)
9295 #endif
9296
9297 #if 0
9298   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9299   // assign tightly coupled operands to the same (pseudo) bank
9300   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9301   mergeMore = 1;
9302   absMaxWeight = 0;
9303   while (mergeMore) {
9304     node = adj->node;
9305     max = NULL;
9306     maxWeight = 0;
9307     while (node) {
9308       curr0 = getEffectiveBank (node->hash);
9309       if (curr0 < 0) { node = node->next; continue; }
9310       edge = node->edge;
9311       while (edge) {
9312         assert (edge->src == node);
9313         backedge = getGEdge (edge->node, edge->src);
9314         weight = edge->weight + (backedge ? backedge->weight : 0);
9315         curr1 = getEffectiveBank (edge->node->hash);
9316         if (curr1 < 0) { edge = edge->next; continue; }
9317
9318         // merging is only useful if the items are not assigned to the same bank already...
9319         if (curr0 != curr1 && weight > maxWeight) {
9320           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9321           maxWeight = weight;
9322           max = edge;
9323         } // if
9324         edge = edge->next;
9325       } // while
9326       node = node->next;
9327     } // while
9328     
9329     if (maxWeight > 0) {
9330 #if 0
9331       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9332                max->src->hash, getSymFromBank (max->src->hash),
9333                max->node->hash, getSymFromBank (max->node->hash));
9334 #endif
9335
9336       node = getGNode (adj, max->src->data, max->src->hash);
9337       node1 = getGNode (adj, max->node->data, max->node->hash);
9338
9339       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9340         if (max->src->hash < max->node->hash)
9341           mergeGraphNodes (node, node1);
9342         else
9343           mergeGraphNodes (node1, node);
9344       } else {
9345         remGEdge (node, node1);
9346         remGEdge (node1, node);
9347         //mergeMore = 0;
9348       }
9349
9350     } else {
9351       mergeMore = 0;
9352     }
9353   } // while
9354 #endif
9355
9356 #if 1  
9357   // remove redundant BANKSELs
9358   //fprintf (stderr, "removing redundant BANKSELs\n");
9359   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9360     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9361   } // for pb
9362 #endif
9363
9364 #if 0
9365   fprintf (stderr, "display graph\n");
9366   showGraph ();
9367 #endif
9368
9369   deleteGraph (adj);
9370   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9371 }
9372
9373 /*** END of stuff belonging to the BANKSEL optimization ***/
9374
9375
9376
9377 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9378
9379 typedef unsigned int symbol_t;
9380 typedef unsigned int valnum_t;
9381 //typedef unsigned int hash_t;
9382
9383 #ifndef INT_TO_PTR
9384 #define INT_TO_PTR(x) (((char *) 0) + (x))
9385 #endif
9386
9387 #ifndef PTR_TO_INT
9388 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9389 #endif
9390
9391 static int pic16_regIsLocal (regs *r);
9392 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9393
9394 /* statistics */
9395 static unsigned int pic16_df_removed_pcodes = 0;
9396 static unsigned int pic16_df_saved_bytes = 0;
9397 static unsigned int df_findall_sameflow = 0;
9398 static unsigned int df_findall_otherflow = 0;
9399 static unsigned int df_findall_in_vals = 0;
9400
9401 static void pic16_df_stats () {
9402   return;
9403   if (pic16_debug_verbose || pic16_pcode_verbose) {
9404     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9405     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9406     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9407   }
9408 }
9409
9410 /* Remove a pCode iff possible:
9411  * - previous pCode is no SKIP
9412  * - pc has no label
9413  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9414 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9415   pCode *pcprev, *pcnext;
9416   char buf[256], *total=NULL;
9417   int len;
9418   
9419   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9420
9421   pcprev = pic16_findPrevInstruction (pc->prev);
9422   pcnext = pic16_findNextInstruction (pc->next);
9423   
9424   /* move labels to next instruction (if possible) */
9425   if (PCI(pc)->label && !pcnext) return 0;
9426
9427   /* if this is a SKIP with side-effects -- do not remove */
9428   /* XXX: might try to replace this one with the side-effect only version */
9429   if (isPCI_SKIP(pc)
9430         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9431   {
9432     pCode *newpc;
9433     switch (PCI(pc)->op)
9434     {
9435     case POC_INCFSZ:
9436     case POC_INFSNZ:
9437       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9438       pic16_pCodeReplace( pc, newpc );
9439       return 1;
9440       break;
9441     case POC_INCFSZW:
9442       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9443       pic16_pCodeReplace( pc, newpc );
9444       return 1;
9445       break;
9446     case POC_DECFSZ:
9447     case POC_DCFSNZ:
9448       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9449       pic16_pCodeReplace( pc, newpc );
9450       return 1;
9451       break;
9452     case POC_DECFSZW:
9453       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9454       pic16_pCodeReplace( pc, newpc );
9455       return 1;
9456       break;
9457     default:
9458       return 0;
9459     }
9460     return 0;
9461   }
9462
9463   /* if previous instruction is a skip -- do not remove */
9464   if (pcprev && isPCI_SKIP(pcprev)) {
9465     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9466       /* preceeding SKIP could not be removed -- keep this instruction! */
9467       return 0;
9468     }
9469   }
9470
9471   if (PCI(pc)->label) {
9472     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9473     //pc->print (stderr, pc);
9474     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9475     PCI(pc)->label = NULL;
9476   }
9477   
9478   /* update statistics */
9479   pic16_df_removed_pcodes++;
9480   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9481   
9482   /* remove the pCode */
9483   pic16_pCode2str (buf, 256, pc);
9484   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9485   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9486     len = strlen (buf) + strlen (comment) + 10;
9487     total = (char *) Safe_malloc (len);
9488     SNPRINTF (total, len, "%s: %s", comment, buf);
9489     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9490     Safe_free (total);
9491   }
9492
9493   /* actually unlink it from the pBlock -- also remove from to/from lists */
9494   pic16_pCodeUnlink (pc);
9495
9496   /* remove the pCode -- release registers */
9497   pc->destruct (pc);
9498
9499   /* report success */
9500   return 1;
9501 }
9502
9503
9504 /* ======================================================================== */
9505 /* === SYMBOL HANDLING ==================================================== */
9506 /* ======================================================================== */
9507
9508 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9509 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9510 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9511
9512 /** Calculate a hash for a given string.
9513  * If len == 0 the string is assumed to be NUL terminated. */
9514 static hash_t symbolHash (const char *str, unsigned int len) {
9515   hash_t hash = 0;
9516   if (!len) {
9517     while (*str) {
9518       hash = (hash << 2) ^ *str;
9519       str++;
9520     } // while
9521   } else {
9522     while (len--) {
9523       hash = (hash << 2) ^ *str;
9524       str++;
9525     }
9526   }
9527   return hash;
9528 }
9529
9530 /** Return 1 iff strings v1 and v2 are identical. */
9531 static int symcmp (const void *v1, const void *v2) {
9532   return !strcmp ((const char *) v1, (const char *) v2);
9533 }
9534
9535 /** Return 1 iff pointers v1 and v2 are identical. */
9536 static int ptrcmp (const void *v1, const void *v2) {
9537   return (v1 == v2);
9538 }
9539
9540 enum {  SPO_WREG=0x1000,
9541         SPO_STATUS,
9542         SPO_PRODL,
9543         SPO_PRODH,
9544         SPO_INDF0,
9545         SPO_POSTDEC0,
9546         SPO_POSTINC0,
9547         SPO_PREINC0,
9548         SPO_PLUSW0,
9549         SPO_INDF1,
9550         SPO_POSTDEC1,
9551         SPO_POSTINC1,
9552         SPO_PREINC1,
9553         SPO_PLUSW1,
9554         SPO_INDF2,
9555         SPO_POSTDEC2,
9556         SPO_POSTINC2,
9557         SPO_PREINC2,
9558         SPO_PLUSW2,
9559         SPO_STKPTR,
9560         SPO_TOSL,
9561         SPO_TOSH,
9562         SPO_TOSU,
9563         SPO_BSR,
9564         SPO_FSR0L,
9565         SPO_FSR0H,
9566         SPO_FSR1L,
9567         SPO_FSR1H,
9568         SPO_FSR2L,
9569         SPO_FSR2H,
9570         SPO_PCL,
9571         SPO_PCLATH,
9572         SPO_PCLATU,
9573         SPO_TABLAT,
9574         SPO_TBLPTRL,
9575         SPO_TBLPTRH,
9576         SPO_TBLPTRU,
9577         SPO_LAST
9578 };
9579
9580 /* Return the unique symbol_t for the given string. */
9581 static symbol_t symFromStr (const char *str) {
9582   hash_t hash;
9583   char *res;
9584   symbol_t sym;
9585
9586   if (!map_symToStr) {
9587     int i;
9588     struct { char *name; symbol_t sym; } predefsyms[] = {
9589         {"WREG", SPO_WREG},
9590         {"STATUS", SPO_STATUS},
9591         {"PRODL", SPO_PRODL},
9592         {"PRODH", SPO_PRODH},
9593         {"INDF0", SPO_INDF0},
9594         {"POSTDEC0", SPO_POSTDEC0},
9595         {"POSTINC0", SPO_POSTINC0},
9596         {"PREINC0", SPO_PREINC0},
9597         {"PLUSW0", SPO_PLUSW0},
9598         {"INDF1", SPO_INDF1},
9599         {"POSTDEC1", SPO_POSTDEC1},
9600         {"POSTINC1", SPO_POSTINC1},
9601         {"PREINC1", SPO_PREINC1},
9602         {"PLUSW1", SPO_PLUSW1},
9603         {"INDF2", SPO_INDF2},
9604         {"POSTDEC2", SPO_POSTDEC2},
9605         {"POSTINC2", SPO_POSTINC2},
9606         {"PREINC2", SPO_PREINC2},
9607         {"PLUSW2", SPO_PLUSW2},
9608         {"STKPTR", SPO_STKPTR},
9609         {"TOSL", SPO_TOSL},
9610         {"TOSH", SPO_TOSH},
9611         {"TOSU", SPO_TOSU},
9612         {"BSR", SPO_BSR},
9613         {"FSR0L", SPO_FSR0L},
9614         {"FSR0H", SPO_FSR0H},
9615         {"FSR1L", SPO_FSR1L},
9616         {"FSR1H", SPO_FSR1H},
9617         {"FSR2L", SPO_FSR2L},
9618         {"FSR2H", SPO_FSR2H},
9619         {"PCL", SPO_PCL},
9620         {"PCLATH", SPO_PCLATH},
9621         {"PCLATU", SPO_PCLATU},
9622         {"TABLAT", SPO_TABLAT},
9623         {"TBLPTRL", SPO_TBLPTRL},
9624         {"TBLPTRH", SPO_TBLPTRH},
9625         {"TBLPTRU", SPO_TBLPTRU},
9626         {NULL, 0}
9627     };
9628
9629     map_strToSym = newHashTable (128);
9630     map_symToStr = newHashTable (128);
9631
9632     for (i=0; predefsyms[i].name; i++) {
9633       char *name;
9634
9635       /* enter new symbol */
9636       sym = predefsyms[i].sym;
9637       name = predefsyms[i].name;
9638       res = Safe_strdup (name);
9639       hash = symbolHash (name, 0);
9640
9641       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9642       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9643     } // for i
9644   }
9645
9646   hash = symbolHash (str, 0) % map_strToSym->size;
9647   
9648   /* find symbol in table */
9649   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9650   if (sym) {
9651     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9652     return sym;
9653   }
9654
9655   /* enter new symbol */
9656   sym = nextSymbol++;
9657   res = Safe_strdup (str);
9658
9659   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9660   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9661
9662   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9663   
9664   return sym;
9665 }
9666
9667 #if 1
9668 static const char *strFromSym (symbol_t sym) {
9669   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9670 }
9671 #endif
9672
9673 /* ======================================================================== */
9674 /* === DEFINITION MAP HANDLING ============================================ */
9675 /* ======================================================================== */
9676
9677 /* A defmap provides information about which symbol is defined by which pCode.
9678  * The most recent definitions are prepended to the list, so that the most
9679  * recent definition can be found by forward scanning the list.
9680  * pc2: MOVFF r0x00, r0x01
9681  * pc1: INCF r0x01
9682  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9683  *
9684  * We attach one defmap to each flow object, and each pCode will occur at
9685  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9686  * used to find definitions for a pCode in its own defmap that precede pCode.
9687  */
9688
9689 typedef struct defmap_s {
9690   symbol_t sym;                 /** symbol this item refers to */
9691   union {
9692     struct {
9693       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9694       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9695       int isRead:1;             /** sym/mask is read */
9696       int isWrite:1;            /** sym/mask is written */
9697     } access;
9698     int accessmethod;
9699   } acc;
9700   pCode *pc;                    /** pCode this symbol is refrenced at */
9701   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9702   valnum_t val;                 /** new unique number for this value (if isWrite) */
9703   struct defmap_s *prev, *next; /** link to previous an next definition */
9704 } defmap_t;
9705
9706 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9707 static int defmap_free_count = 0;               /** number of released defmap items */
9708
9709 /* Returns a defmap_t with the specified data; this will be the new list head.
9710  * next - pointer to the current list head */
9711 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9712   defmap_t *map;
9713   
9714   if (defmap_free) {
9715     map = defmap_free;
9716     defmap_free = map->next;
9717     --defmap_free_count;
9718   } else {
9719     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9720   }
9721   map->sym = sym;
9722   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9723   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9724   map->acc.access.isRead = (isRead != 0);
9725   map->acc.access.isWrite = (isWrite != 0);
9726   map->pc = pc;
9727   map->in_val = 0;
9728   map->val = (isWrite ? val : 0);
9729   map->prev = NULL;
9730   map->next = next;
9731   if (next) next->prev = map;
9732   
9733   return map;
9734 }
9735
9736 /* Returns a copy of the single defmap item. */
9737 static defmap_t *copyDefmap (defmap_t *map) {
9738   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9739   memcpy (res, map, sizeof (defmap_t));
9740   res->next = NULL;
9741   res->prev = NULL;
9742   return res;
9743 }
9744
9745 /* Insert a defmap item after the specified one. */
9746 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9747   if (!ref || !newItem) return 1;
9748
9749   newItem->next = ref->next;
9750   newItem->prev = ref;
9751   ref->next = newItem;
9752   if (newItem->next) newItem->next->prev = newItem;
9753   
9754   return 0;
9755 }
9756
9757 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9758  * item is copied before insertion into chain and therefore left untouched.
9759  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9760 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9761   defmap_t *dummy;
9762   dummy = *head;
9763   while (dummy && (dummy->sym != item->sym
9764                           || dummy->pc != item->pc
9765                           || dummy->acc.accessmethod != item->acc.accessmethod
9766                           || dummy->val != item->val
9767                           || dummy->in_val != item->in_val)) {
9768     dummy = dummy->next;
9769   } // while
9770
9771   /* item already present? */
9772   if (dummy) return 0;
9773   
9774   /* otherwise: insert copy of item */
9775   dummy = copyDefmap (item);
9776   dummy->next = *head;
9777   if (*head) (*head)->prev = dummy;
9778   *head = dummy;
9779
9780   return 1;
9781 }
9782
9783 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9784 static void deleteDefmap (defmap_t *map) {
9785   if (!map) return;
9786   
9787   /* unlink from chain -- fails for the first item (head is not updated!) */
9788   if (map->next) map->next->prev = map->prev;
9789   if (map->prev) map->prev->next = map->next;
9790
9791   /* clear map */
9792   memset (map, 0, sizeof (defmap_t));
9793
9794   /* save for future use */
9795   map->next = defmap_free;
9796   defmap_free = map;
9797   ++defmap_free_count;
9798 }
9799
9800 /* Release all defmaps referenced from map. */
9801 static void deleteDefmapChain (defmap_t **_map) {
9802   defmap_t *map, *next;
9803
9804   if (!_map) return;
9805
9806   map = *_map;
9807   
9808   /* find list head */
9809   while (map && map->prev) map = map->prev;
9810
9811   /* delete all items */
9812   while (map) {
9813     next = map->next;
9814     deleteDefmap (map);
9815     map = next;
9816   } // while
9817
9818   *_map = NULL;
9819 }
9820
9821 /* Free all defmap items. */
9822 static void freeDefmap (defmap_t **_map) {
9823   defmap_t *next;
9824   defmap_t *map;
9825
9826   if (!_map) return;
9827
9828   map = (*_map);
9829   
9830   /* find list head */
9831   while (map->prev) map = map->prev;
9832
9833   /* release all items */
9834   while (map) {
9835     next = map->next;
9836     Safe_free (map);
9837     map = next;
9838   }
9839
9840   (*_map) = NULL;
9841 }
9842
9843 /* Returns the most recent definition for the given symbol preceeding pc.
9844  * If no definition is found, NULL is returned. 
9845  * If pc == NULL the whole list is scanned. */
9846 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9847   defmap_t *curr = map;
9848
9849   if (pc) {
9850     /* skip all definitions up to pc */
9851     while (curr && (curr->pc != pc)) curr = curr->next;
9852
9853     /* pc not in the list -- scan the whole list for definitions */
9854     if (!curr) {
9855       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9856       curr = map;
9857     } else {
9858       /* skip all definitions performed by pc */
9859       while (curr && (curr->pc == pc)) curr = curr->next;
9860     }
9861   } // if (pc)
9862
9863   /* find definition for sym */
9864   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9865     curr = curr->next;
9866   }
9867
9868   return curr;
9869 }
9870
9871 #if 0
9872 /* Returns the first use (read) of the given symbol AFTER pc.
9873  * If no such use is found, NULL is returned.
9874  * If pc == NULL the whole list is scanned. */
9875 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9876   defmap_t *curr = map, *prev = NULL;
9877   
9878   if (pc) {
9879     /* skip all definitions up to pc */
9880     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9881
9882     /* pc not in the list -- scan the whole list for definitions */
9883     if (!curr) {
9884       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9885       curr = prev;
9886     }
9887   } else {
9888     /* find end of list */
9889     while (curr && curr->next) curr = curr->next;
9890   } // if (pc)
9891
9892   /* find use of sym (scan list backwards) */
9893   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9894
9895   return curr;
9896 }
9897 #endif
9898
9899 /* Return the defmap entry for sym AT pc. 
9900  * If none is found, NULL is returned.
9901  * If more than one entry is found an assertion is triggered. */
9902 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9903   defmap_t *res = NULL;
9904
9905   /* find entries for pc */
9906   while (map && map->pc != pc) map = map->next;
9907
9908   /* find first entry for sym @ pc */
9909   while (map && map->pc == pc && map->sym != sym) map = map->next;
9910
9911   /* no entry found */
9912   if (!map) return NULL;
9913
9914   /* check for more entries */
9915   res = map;
9916   map = map->next;
9917   while (map && map->pc == pc) {
9918     /* more than one entry for sym @ pc found? */
9919     assert (map->sym != sym);
9920     map = map->next;
9921   }
9922
9923   /* return single entry for sym @ pc */
9924   return res;
9925 }
9926
9927 /* Modifies the definition of sym at pCode to newval.
9928  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9929  */
9930 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9931   defmap_t *m  = map;
9932
9933   /* find definitions of pc */
9934   while (m && m->pc != pc) m = m->next;
9935
9936   /* find definition of sym at pc */
9937   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9938   
9939   /* no definition found */
9940   if (!m) return 1;
9941
9942   /* redefine */
9943   m->val = newval;
9944
9945   /* update following uses of sym */
9946   while (m && m->pc == pc) m = m->prev;
9947   while (m) {
9948     if (m->sym == sym) {
9949       m->in_val = newval;
9950       if (m->acc.access.isWrite) m = NULL;
9951     } // if
9952     if (m) m = m->prev;
9953   } // while
9954   
9955   return 0;
9956 }
9957
9958 /* ======================================================================== */
9959 /* === STACK ROUTINES ===================================================== */
9960 /* ======================================================================== */
9961
9962 typedef struct stack_s {
9963   void *data;
9964   struct stack_s *next;
9965 } stackitem_t;
9966
9967 typedef stackitem_t *dynstack_t;
9968 static stackitem_t *free_stackitems = NULL;
9969
9970 /* Create a stack with one item. */
9971 static dynstack_t *newStack () {
9972   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9973   *s = NULL;
9974   return s;
9975 }
9976
9977 /* Remove a stack -- its items are only marked free. */
9978 static void deleteStack (dynstack_t *s) {
9979   stackitem_t *i;
9980
9981   while (*s) {
9982     i = *s;
9983     *s = (*s)->next;
9984     i->next = free_stackitems;
9985     free_stackitems = i;
9986   } // while
9987   Safe_free (s);
9988 }
9989
9990 /* Release all stackitems. */
9991 static void releaseStack () {
9992   stackitem_t *i;
9993   
9994   while (free_stackitems) {
9995     i = free_stackitems->next;
9996     Safe_free(free_stackitems);
9997     free_stackitems = i;
9998   } // while
9999 }
10000
10001 static void stackPush (dynstack_t *stack, void *data) {
10002   stackitem_t *i;
10003   
10004   if (free_stackitems) {
10005     i = free_stackitems;
10006     free_stackitems = free_stackitems->next;
10007   } else {
10008     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10009   }
10010   i->data = data;
10011   i->next = *stack;
10012   *stack = i;
10013 }
10014
10015 static void *stackPop (dynstack_t *stack) {
10016   void *data;
10017   stackitem_t *i;
10018   
10019   if (stack && *stack) {
10020     data = (*stack)->data;
10021     i = *stack;
10022     *stack = (*stack)->next;
10023     i->next = free_stackitems;
10024     free_stackitems = i;
10025     return data;
10026   } else {
10027     return NULL;
10028   }
10029 }
10030
10031 #if 0
10032 static int stackContains (dynstack_t *s, void *data) {
10033   stackitem_t *i;
10034   if (!s) return 0;
10035   i = *s;
10036   while (i) {
10037     if (i->data == data) return 1;
10038     i = i->next;
10039   } // while
10040
10041   /* not found */
10042   return 0;
10043 }
10044 #endif
10045
10046 static int stackIsEmpty (dynstack_t *s) {
10047   return (*s == NULL);
10048 }
10049
10050
10051 typedef struct {
10052   pCodeFlow *flow;
10053   defmap_t *lastdef;
10054 } state_t;
10055
10056 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10057   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10058   s->flow = flow;
10059   s->lastdef = lastdef;
10060   return s;
10061 }
10062
10063 static void deleteState (state_t *s) {
10064   Safe_free (s);
10065 }
10066
10067 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10068   stackitem_t *i;
10069
10070   /* scan working list for state */
10071   if (todo) {
10072     i = *todo;
10073     while (i) {
10074       /* is i == state? -- state not new */
10075       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10076       i = i->next;
10077     } // while
10078   }
10079
10080   if (done) {
10081     i = *done;
10082     while (i) {
10083       /* is i == state? -- state not new */
10084       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10085       i = i->next;
10086     } // while
10087   }
10088
10089   /* not found -- state is new */
10090   return 1;
10091 }
10092
10093 static inline valnum_t newValnum ();
10094
10095 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10096   pCode *pc;
10097
10098   if (!pb) return "<unknown function>";
10099
10100   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10101   if (pc && isPCF(pc)) return PCF(pc)->fname;
10102   else return "<unknown function>";
10103 }
10104
10105 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10106   defmap_t *map;
10107   pCodeFlow *pcfl;
10108
10109   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10110
10111   /* find initial value (assigning pc == NULL) */
10112   map = PCFL(pcfl)->in_vals;
10113   while (map && map->sym != sym) map = map->next;
10114
10115   /* initial value already present? */
10116   if (map) {
10117     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10118     return map;
10119   }
10120
10121   /* create a new initial value */
10122   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10123   PCFL(pcfl)->in_vals = map;
10124   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10125   return map;
10126
10127 #if 0
10128   /* insert map as last item in pcfl's defmap */
10129   if (!prev) prev = PCFL(pcfl)->defmap;
10130   if (!prev) {
10131     PCFL(pcfl)->defmap = map;
10132   } else {
10133     while (prev->next) prev = prev->next;
10134     prev->next = map;
10135     map->prev = prev;
10136   }
10137
10138   return map;
10139 #endif
10140 }
10141
10142 /* Find all reaching definitions for sym at pc. 
10143  * A new (!) list of definitions is returned.
10144  * Returns the number of reaching definitions found.
10145  * The defining defmap entries are returned in *chain.
10146  */
10147 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10148   defmap_t *map;
10149   defmap_t *res;
10150
10151   pCodeFlow *curr;
10152   pCodeFlowLink *succ;
10153   state_t *state;
10154   dynstack_t *todo;     /** stack of state_t */
10155   dynstack_t *done;     /** stack of state_t */
10156
10157   int firstState, n_defs;
10158   
10159   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10160   assert (chain);
10161
10162   /* initialize return list */
10163   *chain = NULL;
10164
10165   /* wildcard symbol? */
10166   if (!sym) return 0;
10167   
10168   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10169   
10170   map = PCI(pc)->pcflow->defmap;
10171
10172   res = defmapFindDef (map, sym, pc);
10173   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10174
10175 #define USE_PRECALCED_INVALS 1
10176 #if USE_PRECALCED_INVALS
10177   if (!res && PCI(pc)->pcflow->in_vals) {
10178     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10179     if (res) {
10180       //fprintf  (stderr, "found def in init values\n");
10181       df_findall_in_vals++;
10182     }
10183   }
10184 #endif
10185
10186   if (res) {
10187     // found a single definition (in pc's flow)
10188     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10189     defmapAddCopyIfNew (chain, res);
10190     df_findall_sameflow++;
10191     return 1;
10192   }
10193
10194 #if USE_PRECALCED_INVALS
10195   else {
10196     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10197     return 1;
10198   }
10199
10200 #endif
10201   
10202 #define FORWARD_FLOW_ANALYSIS 1
10203 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10204   /* no definition found in pc's flow preceeding pc */
10205   todo = newStack ();
10206   done = newStack ();
10207   n_defs = 0; firstState = 1;
10208   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10209
10210   while (!stackIsEmpty (todo)) {
10211     state = (state_t *) stackPop (todo);
10212     stackPush (done, state);
10213     curr = state->flow;
10214     res = state->lastdef;
10215     //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);
10216
10217     /* there are no definitions BEFORE pc in pc's flow (see above) */
10218     if (curr == PCI(pc)->pcflow) {
10219       if (!res) {
10220         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10221         res = pic16_pBlockAddInval (pc->pb, sym);
10222         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10223         res = NULL;
10224       } else {
10225         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10226         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10227       }
10228     }
10229
10230     /* save last definition of sym in this flow as initial def in successors */
10231     res = defmapFindDef (curr->defmap, sym, NULL);
10232     if (!res) res = state->lastdef;
10233     
10234     /* add successors to working list */
10235     state = newState (NULL, NULL);
10236     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10237     while (succ) {
10238       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10239       state->flow = succ->pcflow;
10240       state->lastdef = res;
10241       if (stateIsNew (state, todo, done)) {
10242         stackPush (todo, state);
10243         state = newState (NULL, NULL);
10244       } // if
10245       succ = (pCodeFlowLink *) setNextItem (curr->to);
10246     } // while
10247     deleteState (state);
10248   } // while
10249
10250 #else // !FORWARD_FLOW_ANALYSIS 
10251
10252   /* no definition found in pc's flow preceeding pc */
10253   todo = newStack ();
10254   done = newStack ();
10255   n_defs = 0; firstState = 1;
10256   stackPush (todo, newState (PCI(pc)->pcflow, res));
10257
10258   while (!stackIsEmpty (todo)) {
10259     state = (state_t *) stackPop (todo);
10260     curr = state->flow;
10261
10262     if (firstState) {
10263       firstState = 0;
10264       /* only check predecessor flows */
10265     } else {
10266       /* get (last) definition of sym in this flow */
10267       res = defmapFindDef (curr->defmap, sym, NULL);
10268     }
10269
10270     if (res) {
10271       /* definition found */
10272       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10273       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10274     } else {
10275       /* no definition found -- check predecessor flows */
10276       state = newState (NULL, NULL);
10277       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10278
10279       /* if no flow predecessor available -- sym might be uninitialized */
10280       if (!succ) {
10281         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10282         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10283         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10284         deleteDefmap (res); res = NULL;
10285       }
10286       
10287       while (succ) {
10288         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10289         state->flow = succ->pcflow;
10290         state->lastdef = res;
10291         if (stateIsNew (state, todo, done)) {
10292           stackPush (todo, state);
10293           state = newState (NULL, NULL);
10294         } // if
10295         succ = (pCodeFlowLink *) setNextItem (curr->from);
10296       } // while
10297       deleteState (state);
10298     }
10299   } // while
10300
10301 #endif
10302
10303   /* clean up done stack */
10304   while (!stackIsEmpty(done)) {
10305     deleteState ((state_t *) stackPop (done));
10306   } // while
10307   deleteStack (done);
10308
10309   /* return number of items in result set */
10310   if (n_defs == 0) {
10311     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10312   } else if (n_defs == 1) {
10313     assert (*chain);
10314     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10315   } else if (n_defs > 0) {
10316     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10317 #if 0
10318     res = *chain;
10319     while (res) {
10320       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10321       res = res->next;
10322     } // while
10323 #endif
10324   }
10325   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10326   df_findall_otherflow++;
10327   return n_defs;
10328 }
10329
10330 /* ======================================================================== */
10331 /* === VALUE NUMBER HANDLING ============================================== */
10332 /* ======================================================================== */
10333
10334 static valnum_t nextValnum = 0x1000;
10335 static hTab *map_symToValnum = NULL;
10336
10337 /** Return a new value number. */
10338 static inline valnum_t newValnum () {
10339   return (nextValnum += 4);
10340 }
10341
10342 static valnum_t valnumFromStr (const char *str) {
10343   symbol_t sym;
10344   valnum_t val;
10345   void *res;
10346   
10347   sym = symFromStr (str);
10348
10349   if (!map_symToValnum) {
10350     map_symToValnum = newHashTable (128);
10351   } // if
10352
10353   /* literal already known? */
10354   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10355
10356   /* return existing valnum */
10357   if (res) return (valnum_t) PTR_TO_INT(res);
10358   
10359   /* create new valnum */
10360   val = newValnum();
10361   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10362   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10363   return val;
10364 }
10365
10366 /* Create a valnum for a literal. */
10367 static valnum_t valnumFromLit (unsigned int lit) {
10368   return ((valnum_t) 0x100 + (lit & 0x0FF));
10369 }
10370
10371 /* Return the (positive) literal value represented by val
10372  * or -1 iff val is no known literal's valnum. */
10373 static int litFromValnum (valnum_t val) {
10374   if (val >= 0x100 && val < 0x200) {
10375     /* valnum is a (known) literal */
10376     return val & 0x00FF;
10377   } else {
10378     /* valnum is not a known literal */
10379     return -1;
10380   }
10381 }
10382
10383 #if 0
10384 /* Sanity check - all flows in a block must be reachable from initial flow. */
10385 static int verifyAllFlowsReachable (pBlock *pb) {
10386   set *reached;
10387   set *flowInBlock;
10388   set *checked;
10389   pCode *pc;
10390   pCodeFlow *pcfl;
10391   pCodeFlowLink *succ;
10392   int res;
10393
10394   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10395
10396   reached = NULL;
10397   flowInBlock = NULL;
10398   checked = NULL;
10399   /* mark initial flow as reached (and "not needs to be reached") */
10400   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10401   assert (pc);
10402   addSetHead (&reached, pc);
10403   addSetHead (&checked, pc);
10404   
10405   /* mark all further flows in block as "need to be reached" */
10406   pc = pb->pcHead;
10407   do {
10408     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10409     pc = pic16_findNextInstruction (pc->next);
10410   } while (pc);
10411
10412   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10413     /* mark as reached and "not need to be reached" */
10414     deleteSetItem (&reached, pcfl);
10415     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10416     
10417     /* flow is no longer considered unreachable */
10418     deleteSetItem (&flowInBlock, pcfl);
10419
10420     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10421       if (!isinSet (checked, succ->pcflow)) {
10422         /* flow has never been reached before */
10423         addSetHead (&reached, succ->pcflow);
10424         addSetHead (&checked, succ->pcflow);
10425       } // if
10426     } // for succ
10427   } // while
10428
10429   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10430
10431   /* by now every flow should have been reached
10432    * --> flowInBlock should be empty */
10433   res = (flowInBlock == NULL);
10434
10435 #if 1
10436   if (flowInBlock) {
10437           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10438     while (flowInBlock) {
10439       pcfl = indexSet (flowInBlock, 0);
10440       fprintf (stderr, "not reached: flow %p\n", pcfl);
10441       deleteSetItem (&flowInBlock, pcfl);
10442     } // while
10443   }
10444 #endif
10445   
10446   /* clean up */
10447   deleteSet (&reached);
10448   deleteSet (&flowInBlock);
10449   deleteSet (&checked);
10450   
10451   /* if we reached every flow, succ is NULL by now... */
10452   //assert (res); // will fire on unreachable code...
10453   return (res);
10454 }
10455 #endif
10456
10457 /* Checks a flow for accesses to sym AFTER pc.
10458  * 
10459  * Returns -1 if the symbol is read in this flow (before redefinition),
10460  * returns 0 if the symbol is redefined in this flow or
10461  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10462  */
10463 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10464   defmap_t *map, *mappc;
10465
10466   /* find pc or start of definitions */
10467   map = pcfl->defmap;
10468   while (map && (map->pc != pc) && map->next) map = map->next;
10469   /* if we found pc -- ignore it */
10470   while (map && map->pc == pc) map = map->prev;
10471
10472   /* scan list backwards (first definition first) */
10473   while (map && mask) {
10474 //    if (map->sym == sym) {
10475       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10476       mappc = map;
10477       /* scan list for reads at this pc first */
10478       while (map && map->pc == mappc->pc) {
10479         /* is the symbol (partially) read? */
10480         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10481           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10482           return -1;
10483         }
10484         map = map->prev;
10485       } // while
10486       map = mappc;
10487
10488       while (map && map->pc == mappc->pc) {
10489         /* honor (partial) redefinitions of sym */
10490         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10491           mask &= ~map->acc.access.mask;
10492           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10493         }
10494         map = map->prev;
10495       } // while
10496 //    } // if
10497     /* map already points to the first defmap for the next pCode */
10498     //map = mappc->prev;
10499   } // while
10500
10501   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10502    * is still alive; return the appropriate mask of alive bits */
10503   return mask;
10504 }
10505
10506 /* Check whether a symbol is alive (AFTER pc). */
10507 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10508   int mask, visit;
10509   defmap_t *map;
10510   dynstack_t *todo, *done;
10511   state_t *state;
10512   pCodeFlow *pcfl;
10513   pCodeFlowLink *succ;
10514
10515   mask = 0x00ff;
10516   
10517   assert (isPCI(pc));
10518   pcfl = PCI(pc)->pcflow;
10519   map = pcfl->defmap;
10520
10521   todo = newStack ();
10522   done = newStack ();
10523   
10524   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10525   stackPush (todo, state);
10526   visit = 0;
10527   
10528   while (!stackIsEmpty (todo)) {
10529     state = (state_t *) stackPop (todo);
10530     pcfl = state->flow;
10531     mask = PTR_TO_INT(state->lastdef);
10532     if (visit) stackPush (done, state); else deleteState(state);
10533     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10534     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10535     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10536     visit++;
10537
10538     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10539     if (mask == 0) continue;
10540
10541     /* symbol is (partially) read before redefinition in flow */
10542     if (mask == -1) break;
10543
10544     /* symbol is neither read nor completely redefined -- check successor flows */
10545     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10546       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10547       if (stateIsNew (state, todo, done)) {
10548         stackPush (todo, state);
10549       } else {
10550         deleteState (state);
10551       }
10552     } // for
10553   } // while
10554
10555   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10556   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10557
10558   /* symbol is read in at least one flow -- is alive */
10559   if (mask == -1) return 1;
10560
10561   /* symbol is read in no flow */
10562   return 0;
10563 }
10564
10565 /* Returns whether access to the given symbol has side effects. */
10566 static int pic16_symIsSpecial (symbol_t sym) {
10567   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10568   switch (sym) {
10569   case SPO_INDF0:
10570   case SPO_PLUSW0:
10571   case SPO_POSTINC0:
10572   case SPO_POSTDEC0:
10573   case SPO_PREINC0:
10574   case SPO_INDF1:
10575   case SPO_PLUSW1:
10576   case SPO_POSTINC1:
10577   case SPO_POSTDEC1:
10578   case SPO_PREINC1:
10579   case SPO_INDF2:
10580   case SPO_PLUSW2:
10581   case SPO_POSTINC2:
10582   case SPO_POSTDEC2:
10583   case SPO_PREINC2:
10584   case SPO_PCL:
10585           return 1;
10586   default:
10587           /* no special effects known */
10588           return 0;
10589   } // switch
10590
10591   return 0;
10592 }
10593
10594 /* Check whether a register should be considered local (to the current function) or not. */
10595 static int pic16_regIsLocal (regs *r) {
10596   symbol_t sym;
10597   if (r) {
10598     if (r->type == REG_TMP) return 1;
10599
10600     sym = symFromStr (r->name);
10601     switch (sym) {
10602     case SPO_WREG:
10603     case SPO_FSR0L: // used in ptrget/ptrput
10604     case SPO_FSR0H: // ... as well
10605     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10606     case SPO_FSR1H: // ... as well
10607     case SPO_FSR2L: // used as frame pointer
10608     case SPO_FSR2H: // ... as well
10609     case SPO_PRODL: // used to return values from functions
10610     case SPO_PRODH: // ... as well
10611       /* these registers (and some more...) are considered local */
10612       return 1;
10613       break;
10614     default:
10615       /* for unknown regs: check is marked local, leave if not */
10616       if (r->isLocal) {
10617         return 1;
10618       } else {
10619         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10620         return 0;
10621       }
10622     } // switch
10623   } // if
10624
10625   /* if in doubt, assume non-local... */
10626   return 0;
10627 }
10628
10629 /* Check all symbols touched by pc whether their newly assigned values are read.
10630  * Returns 0 if no symbol is used later on, 1 otherwise. */
10631 static int pic16_pCodeIsAlive (pCode *pc) {
10632   pCodeInstruction *pci;
10633   defmap_t *map, *lastpc;
10634   regs *checkreg;
10635   
10636   /* we can only handle PCIs */
10637   if (!isPCI(pc)) return 1;
10638
10639   //pc->print (stderr, pc);
10640
10641   pci = PCI(pc);
10642   assert (pci && pci->pcflow && pci->pcflow->defmap);
10643
10644   /* NEVER remove instructions with implicit side effects */
10645   switch (pci->op) {
10646   case POC_TBLRD:
10647   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10648   case POC_TBLRD_POSTDEC:
10649   case POC_TBLRD_PREINC:
10650   case POC_TBLWT:               /* modify program memory */
10651   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10652   case POC_TBLWT_POSTDEC:
10653   case POC_TBLWT_PREINC:
10654   case POC_CLRWDT:              /* clear watchdog timer */
10655   case POC_PUSH:                /* should be safe to remove though... */
10656   case POC_POP:                 /* should be safe to remove though... */
10657   case POC_CALL:
10658   case POC_RCALL:
10659   case POC_RETFIE:
10660   case POC_RETURN:
10661     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10662     return 1;
10663
10664   default:
10665     /* no special instruction */
10666     break;
10667   } // switch
10668
10669   /* prevent us from removing assignments to non-local variables */
10670   checkreg = NULL;
10671   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10672   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10673
10674   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10675     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10676     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10677     //pc->print (stderr, pc);
10678     return 1;
10679   }
10680   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10681     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10682     return 1;
10683   }
10684   
10685 #if 1
10686   /* OVERKILL: prevent us from removing reads from non-local variables 
10687    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10688    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10689   checkreg = NULL;
10690   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10691   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10692
10693   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10694     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10695     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10696     //pc->print (stderr, pc);
10697     return 1;
10698   }
10699   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10700     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10701     return 1;
10702   }
10703 #endif
10704   
10705   /* now check that the defined symbols are not used */
10706   map = pci->pcflow->defmap;
10707   
10708   /* find items for pc */
10709   while (map && map->pc != pc) map = map->next;
10710
10711   /* no entries found? something is fishy with DF analysis... -- play safe */
10712   if (!map) {
10713     if (pic16_pcode_verbose) {
10714       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10715     }
10716     return 1;
10717   }
10718
10719   /* remember first item assigned to pc for later use */
10720   lastpc = map;
10721   
10722   /* check all symbols being modified by pc */
10723   while (map && map->pc == pc) {
10724     if (map->sym == 0) { map = map->next; continue; }
10725
10726     /* keep pc if it references special symbols (like POSTDEC0) */
10727 #if 0
10728     {
10729       char buf[256];
10730       pic16_pCode2str (buf, 256, pc);
10731       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10732     }
10733 #endif
10734     if (pic16_symIsSpecial (map->sym)) {
10735       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10736       return 1;
10737     }
10738     if (map->acc.access.isWrite) {
10739       if (pic16_isAlive (map->sym, pc)) {
10740         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10741         return 1;
10742       }
10743     }
10744     map = map->next;
10745   } // while
10746
10747   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10748 #if 0
10749   {
10750     char buf[256];
10751     pic16_pCode2str (buf, 256, pc);
10752     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10753   }
10754 #endif
10755   return 0;
10756 }
10757
10758 /* Adds implied operands to the list.
10759  * sym - operand being accessed in the pCode
10760  * list - list to append the operand
10761  * isRead - set to 1 iff sym is read in pCode
10762  * listRead - set to 1 iff all operands being read are to be listed
10763  *
10764  * Returns 0 for "normal" operands, 1 for special operands.
10765  */
10766 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10767   /* check whether accessing REG accesses other REGs as well */
10768   switch (sym) {
10769   case SPO_INDF0:
10770     /* reads FSR0x */
10771     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10772     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10773     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10774     break;
10775     
10776   case SPO_PLUSW0:
10777     /* reads FSR0x and WREG */
10778     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10779     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10780     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10781     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10782     break;
10783     
10784   case SPO_POSTDEC0:
10785   case SPO_POSTINC0:
10786   case SPO_PREINC0:
10787     /* reads/modifies FSR0x */
10788     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10789     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10790     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10791     break;
10792
10793   case SPO_INDF1:
10794     /* reads FSR1x */
10795     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10796     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10797     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10798     break;
10799     
10800   case SPO_PLUSW1:
10801     /* reads FSR1x and WREG */
10802     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10803     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10804     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10805     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10806     break;
10807     
10808   case SPO_POSTDEC1:
10809   case SPO_POSTINC1:
10810   case SPO_PREINC1:
10811     /* reads/modifies FSR1x */
10812     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10813     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10814     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10815     break;
10816
10817   case SPO_INDF2:
10818     /* reads FSR2x */
10819     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10820     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10821     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10822     break;
10823     
10824   case SPO_PLUSW2:
10825     /* reads FSR2x and WREG */
10826     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10827     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10828     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10829     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10830     break;
10831     
10832   case SPO_POSTDEC2:
10833   case SPO_POSTINC2:
10834   case SPO_PREINC2:
10835     /* reads/modifies FSR2x */
10836     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10837     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10838     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10839     break;
10840
10841   case SPO_PCL:
10842     /* modifies PCLATH and PCLATU */
10843     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10844     if (isRead) {
10845       /* reading PCL updates PCLATx */
10846       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10847       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10848     }
10849     if (isWrite) {
10850       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10851       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10852       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10853     }
10854     break;
10855
10856   default:
10857     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10858     /* nothing special */
10859     return 0;
10860     break;
10861   }
10862
10863   /* has been a special operand */
10864   return 1;
10865 }
10866
10867 static symbol_t pic16_fsrsym_idx[][2] = {
10868     {SPO_FSR0L, SPO_FSR0H},
10869     {SPO_FSR1L, SPO_FSR1H},
10870     {SPO_FSR2L, SPO_FSR2H}
10871 };
10872
10873 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10874 static void mergeDefmapSymbols (defmap_t *list) { 
10875   defmap_t *ref, *curr, *temp;
10876
10877   /* now make sure that each symbol occurs at most once per pc */
10878   ref = list;
10879   while (ref && (ref->pc == list->pc)) {
10880     curr = ref->next;
10881     while (curr && (curr->pc == list->pc)) {
10882       if (curr->sym == ref->sym) {
10883         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10884         /* found a symbol occuring twice... merge the two */
10885         if (curr->acc.access.isRead) {
10886           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10887           ref->acc.access.isRead = 1;
10888           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10889         }
10890         if (curr->acc.access.isWrite) {
10891           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10892           ref->acc.access.isWrite = 1;
10893           ref->acc.access.mask |= curr->acc.access.mask;
10894         }
10895         temp = curr;
10896         curr = curr->next;
10897         deleteDefmap (temp);
10898         continue; // do not skip curr!
10899       } // if
10900       curr = curr->next;
10901     } // while
10902     ref = ref->next;
10903   } // while
10904 }
10905
10906 /** Prepend list with the reads and definitions performed by pc. */
10907 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10908   pCodeInstruction *pci;
10909   int cond, inCond, outCond;
10910   int mask = 0xff, smask;
10911   int isSpecial, isSpecial2;
10912   symbol_t sym, sym2;
10913   char *name;
10914
10915   if (isPCAD(pc)) {
10916     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10917     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10918     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10919     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10920     return list;
10921   }
10922   assert (isPCI(pc));
10923   pci = PCI(pc);
10924   
10925   /* handle bit instructions */
10926   if (pci->isBitInst) {
10927     assert (pci->pcop->type == PO_GPR_BIT);
10928     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10929   }
10930
10931   /* handle (additional) implicit arguments */
10932   switch (pci->op) {
10933   case POC_LFSR:
10934     {
10935       int lit;
10936       valnum_t val;
10937       lit = PCOL(pci->pcop)->lit;
10938       assert (lit >= 0 && lit < 3);
10939       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10940       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10941       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10942       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10943       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...
10944     }
10945     break;
10946
10947   case POC_MOVLB: // BSR
10948   case POC_BANKSEL: // BSR
10949     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10950     break;
10951
10952   case POC_MULWF: // PRODx
10953   case POC_MULLW: // PRODx
10954     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10955     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10956     break;
10957
10958   case POC_POP: // TOS, STKPTR
10959     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10960     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10961     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10962     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10963     break;
10964     
10965   case POC_PUSH: // STKPTR
10966     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10967     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10968     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10969     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10970     break;
10971     
10972   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10973   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10974     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10975     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10976     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10977     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10978
10979     /* needs correctly set-up stack pointer */
10980     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10981     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10982     break;
10983
10984   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10985     /* pseudo read on (possible) return values */
10986     // WREG is handled below via outCond
10987     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10988     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10989     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10990
10991     /* caller's stack pointers must be restored */
10992     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10993     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10994     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10995     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10996     break;
10997
10998   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10999   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
11000     /* pseudo read on (possible) return values */
11001     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
11002     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11003     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11004     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11005
11006     /* caller's stack pointers must be restored */
11007     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11008     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11009     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11010     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11011     break;
11012     
11013   case POC_TBLRD:
11014     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11015     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11016     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11017     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11018     break;
11019     
11020   case POC_TBLRD_POSTINC:
11021   case POC_TBLRD_POSTDEC:
11022   case POC_TBLRD_PREINC:
11023     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11024     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11025     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11026     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11027     break;
11028     
11029   case POC_TBLWT:
11030     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11031     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11032     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11033     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11034     break;
11035     
11036   case POC_TBLWT_POSTINC:
11037   case POC_TBLWT_POSTDEC:
11038   case POC_TBLWT_PREINC:
11039     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11040     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11041     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11042     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11043     break;
11044     
11045   default:
11046     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11047     break;
11048   } // switch
11049
11050   /* handle explicit arguments */
11051   inCond = pci->inCond;
11052   outCond = pci->outCond;
11053   cond = inCond | outCond;
11054   if (cond & PCC_W) {
11055     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11056   } // if
11057
11058   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11059   if (inCond & PCC_STATUS) {
11060     smask = 0;
11061     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11062     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11063     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11064     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11065     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11066
11067     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11068     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11069   } // if
11070   
11071   if (outCond & PCC_STATUS) {
11072     smask = 0;
11073     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11074     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11075     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11076     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11077     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11078
11079     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11080     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11081   } // if
11082   
11083   isSpecial = isSpecial2 = 0;
11084   sym = sym2 = 0;
11085   if (cond & PCC_REGISTER) {
11086     name = pic16_get_op (pci->pcop, NULL, 0);
11087     sym = symFromStr (name);
11088     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11089     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11090   }
11091
11092   if (cond & PCC_REGISTER2) {
11093     name = pic16_get_op2 (pci->pcop, NULL, 0);
11094     sym2 = symFromStr (name);
11095     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11096     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11097   }
11098
11099  
11100   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11101   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11102
11103   mergeDefmapSymbols (list);
11104   
11105   return list;
11106 }
11107
11108 #if 0
11109 static void printDefmap (defmap_t *map) {
11110   defmap_t *curr;
11111
11112   curr = map;
11113   fprintf (stderr, "defmap @ %p:\n", curr);
11114   while (curr) {
11115     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11116                     curr->acc.access.isRead ? "R" : " ",
11117                     curr->acc.access.isWrite ? "W": " ",
11118                     curr->in_val, curr->val,
11119                     curr->acc.access.in_mask, curr->acc.access.mask,
11120                     strFromSym(curr->sym), curr->sym,
11121                     curr->pc);
11122     curr = curr->next;
11123   } // while
11124   fprintf (stderr, "<EOL>\n");
11125 }
11126 #endif
11127
11128 /* Add "additional" definitions to uniq.
11129  * 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.
11130  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11131  *
11132  * If symbols defined in additional are not present in uniq, a definition is created.
11133  * Otherwise the present definition is altered to reflect the newer assignments.
11134  *
11135  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11136  *       before     `------- noted in additional --------'      after
11137  *
11138  * I assume that each symbol occurs AT MOST ONCE in uniq.
11139  *
11140  */
11141 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11142   defmap_t *curr;
11143   defmap_t *old;
11144   int change = 0;
11145
11146   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11147   /* find tail of additional list (holds the first assignment) */
11148   curr = additional;
11149   while (curr && curr->next) curr = curr->next;
11150
11151   /* update uniq */
11152   do {
11153     /* find next assignment in additionals */
11154     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11155
11156     if (!curr) break;
11157
11158     /* find item in uniq */
11159     old = *uniq;
11160     //printDefmap (*uniq);
11161     while (old && (old->sym != curr->sym)) old = old->next;
11162
11163     if (old) {
11164       /* definition found -- replace */
11165       if (old->val != curr->val) {
11166         old->val = curr->val;
11167         change++;
11168       } // if
11169     } else {
11170       /* new definition */
11171       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11172       change++;
11173     }
11174
11175     curr = curr->prev;
11176   } while (1);
11177
11178   /* return 0 iff uniq remained unchanged */
11179   return change;
11180 }
11181
11182 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11183  * lists of its predecessor flows. 
11184  * Initially *combined should be NULL, alt_in will be copied to combined.
11185  * If *combined != NULL, combined will be altered:
11186  * - for symbols defined in *combined but not in alt_in,
11187  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11188  * - for symbols defined in alt_in but not in *combined,
11189  *   a 0 definition is created (value unknown, either INIT or alt).
11190  * - for symbols defined in both, *combined is:
11191  *   > left unchanged if *combined->val == alt_in->val or
11192  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11193  * 
11194  * I assume that each symbol occurs AT MOST ONCE in each list!
11195  */
11196 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11197   defmap_t *curr;
11198   defmap_t *old;
11199   int change = 0;
11200   valnum_t val;
11201
11202   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11203   
11204   if (!(*combined)) {
11205     return defmapUpdateUniqueSym (combined, alt_in);
11206   } // if
11207   
11208   /* merge the two */
11209   curr = alt_in;
11210   while (curr) {
11211     /* find symbols definition in *combined */
11212     old = *combined;
11213     while (old && (old->sym != curr->sym)) old = old->next;
11214
11215     if (old) {
11216       /* definition found */
11217       if (old->val && (old->val != curr->val)) {
11218         old->val = 0; /* value unknown */
11219         change++;
11220       }
11221     } else {
11222       /* no definition found -- can be either INIT or alt_in's value */
11223       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11224       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11225       if (val != curr->val) change++;
11226     }
11227
11228     curr = curr->next;
11229   } // while (curr)
11230
11231   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11232   old = *combined;
11233   while (old) {
11234     if (old->val != 0) {
11235       /* find definition in alt_in */
11236       curr = alt_in;
11237       while (curr && curr->sym != old->sym) curr = curr->next;
11238       if (!curr) {
11239         /* symbol defined in *combined only -- can be either INIT or *combined */
11240         val = pic16_pBlockAddInval (pb, old->sym)->val;
11241         if (old->val != val) {
11242           old->val = 0;
11243           change++;
11244         }
11245       } // if
11246     } // if
11247
11248     old = old->next;
11249   } // while
11250
11251   return change;
11252 }
11253
11254 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11255   defmap_t *curr1, *curr2;
11256   symbol_t sym;
11257   
11258   /* identical maps are equal */
11259   if (map1 == map2) return 0;
11260
11261   if (!map1) return -1;
11262   if (!map2) return 1;
11263
11264   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11265   
11266   /* check length */
11267   curr1 = map1;
11268   curr2 = map2;
11269   while (curr1 && curr2) {
11270     curr1 = curr1->next;
11271     curr2 = curr2->next;
11272   } // while
11273
11274   /* one of them longer? */
11275   if (curr1) return 1;
11276   if (curr2) return -1;
11277
11278   /* both lists are of equal length -- compare (in O(n^2)) */
11279   curr1 = map1;
11280   while (curr1) {
11281     sym = curr1->sym;
11282     curr2 = map2;
11283     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11284     if (!curr2) return 1; // symbol not found in curr2
11285     if (curr2->val != curr1->val) return 1; // values differ
11286
11287     /* compare next symbol */
11288     curr1 = curr1->next;
11289   } // while
11290
11291   /* no difference found */
11292   return 0;
11293 }
11294
11295
11296 /* Prepare a list of all reaching definitions per flow.
11297  * This is done using a forward dataflow analysis.
11298  */
11299 static void createReachingDefinitions (pBlock *pb) {
11300   defmap_t *out_vals, *in_vals;
11301   pCode *pc;
11302   pCodeFlow *pcfl;
11303   pCodeFlowLink *link;
11304   set *todo;
11305   set *blacklist;
11306
11307   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11308   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11309     if (isPCFL(pc)) {
11310       deleteDefmapChain (&PCFL(pc)->in_vals);
11311       deleteDefmapChain (&PCFL(pc)->out_vals);
11312       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11313     } // if
11314   } // for
11315   
11316   pc = pic16_findNextInstruction (pb->pcHead);
11317   todo = NULL; blacklist = NULL;
11318   addSetHead (&todo, PCI(pc)->pcflow);
11319
11320   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11321   while (elementsInSet (todo)) {
11322     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11323     pcfl = PCFL(indexSet (todo, 0));
11324     deleteSetItem (&todo, pcfl);
11325     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11326     in_vals = NULL;
11327     out_vals = NULL;
11328
11329     if (isinSet (blacklist, pcfl)) {
11330             fprintf (stderr, "ignoring blacklisted flow\n");
11331       continue;
11332     }
11333     
11334     /* create in_vals from predecessors out_vals */
11335     link = setFirstItem (pcfl->from);
11336     while (link) {
11337       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11338       link = setNextItem (pcfl->from);
11339     } // while
11340
11341     //printDefmap (in_vals); 
11342     //printDefmap (pcfl->in_vals); 
11343
11344     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11345       //fprintf (stderr, "in_vals changed\n");
11346       /* in_vals changed -- update out_vals */
11347       deleteDefmapChain (&pcfl->in_vals);
11348       pcfl->in_vals = in_vals;
11349
11350       /* create out_val from in_val and defmap */
11351       out_vals = NULL;
11352       defmapUpdateUniqueSym (&out_vals, in_vals);
11353       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11354
11355       /* is out_vals different from pcfl->out_vals */
11356       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11357         //fprintf (stderr, "out_vals changed\n");
11358         deleteDefmapChain (&pcfl->out_vals);
11359         pcfl->out_vals = out_vals;
11360
11361         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11362           addSet (&blacklist, pcfl);
11363         } // if
11364         
11365         /* reschedule all successors */
11366         link = setFirstItem (pcfl->to);
11367         while (link) {
11368           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11369           addSetIfnotP (&todo, link->pcflow);
11370           link = setNextItem (pcfl->to);
11371         } // while
11372       } else {
11373         deleteDefmapChain (&out_vals);        
11374       }// if
11375     } else {
11376       deleteDefmapChain (&in_vals);         
11377     } // if
11378   } // while
11379 }
11380
11381 #if 0
11382 static void showAllDefs (symbol_t sym, pCode *pc) {
11383   defmap_t *map;
11384   int count;
11385
11386   assert (isPCI(pc));
11387   count = defmapFindAll (sym, pc, &map);
11388
11389   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11390   while (map) {
11391 #if 1
11392     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11393 #else
11394     { char buf[256];
11395     pic16_pCode2str (buf, 256, map->pc);
11396     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11397 #endif
11398     map = map->next;
11399   }
11400   deleteDefmapChain (&map);
11401 }
11402 #endif
11403
11404 /* safepCodeUnlink and remove pc from defmap. */
11405 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11406   defmap_t *map, *next, **head;
11407   int res, ispci;
11408   
11409   ispci = isPCI(pc);
11410   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11411   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11412   res = pic16_safepCodeUnlink (pc, comment);
11413
11414   if (res && map) {
11415     /* remove pc from defmap */
11416     while (map) {
11417       next = map->next;
11418       if (map->pc == pc) {
11419         if (!map->prev && head) *head = map->next;
11420         deleteDefmap (map);
11421       } // if
11422       map = next;
11423     }
11424   }
11425
11426   return res;
11427 }
11428       
11429 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11430   defmap_t *map;
11431   /* This breaks the defmap chain's references to pCodes... fix it! */
11432   map = PCI(pc)->pcflow->defmap;
11433
11434   while (map && map->pc != pc) map = map->next;
11435   
11436   while (map && map->pc == pc) {
11437     map->pc = newpc;
11438     map = map->next;
11439   } // while
11440 }
11441
11442 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11443  * write accesses (isRead == 0). */
11444 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11445   defmap_t *map, *map_start;
11446   defmap_t *copy;
11447   if (!isPCI(pc)) return;
11448   if (sym == newsym) return;
11449   
11450   map = PCI(pc)->pcflow->defmap;
11451
11452   while (map && map->pc != pc) map = map->next;
11453   map_start = map;
11454   while (map && map->pc == pc) {
11455     if (map->sym == sym) {
11456       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11457       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11458         /* only one kind of access handled... this is easy */
11459         map->sym = newsym;
11460       } else {
11461         /* must copy defmap entry before replacing symbol... */
11462         copy = copyDefmap (map);
11463         if (isRead) {
11464           map->acc.access.isRead = 0;
11465           copy->acc.access.isWrite = 0;
11466         } else {
11467           map->acc.access.isWrite = 0;
11468           copy->acc.access.isRead = 0;
11469         }
11470         copy->sym = newsym;
11471         /* insert copy into defmap chain */
11472         defmapInsertAfter (map, copy);
11473       }
11474     }
11475     map = map->next;
11476   } // while
11477
11478   /* as this might introduce multiple defmap entries for newsym... */
11479   mergeDefmapSymbols (map_start);
11480 }
11481
11482 /* Assign "better" valnums to results. */
11483 static void assignValnums (pCode *pc) {
11484   pCodeInstruction *pci;
11485   pCode *newpc;
11486   symbol_t sym1, sym2;
11487   int cond, isSpecial1, isSpecial2, count, mask, lit;
11488   defmap_t *list, *val, *oldval, *dummy;
11489   regs *reg1 = NULL, *reg2 = NULL;
11490   valnum_t litnum;
11491
11492   /* only works for pCodeInstructions... */
11493   if (!isPCI(pc)) return;
11494
11495   pci = PCI(pc);
11496   cond = pci->inCond | pci->outCond;
11497   list = pci->pcflow->defmap;
11498   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11499
11500   if (cond & PCC_REGISTER) {
11501     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11502     reg1 = pic16_getRegFromInstruction (pc);
11503     isSpecial1 = pic16_symIsSpecial (sym1);
11504   }
11505   if (cond & PCC_REGISTER2) {
11506     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11507     reg2 = pic16_getRegFromInstruction (pc);
11508     isSpecial2 = pic16_symIsSpecial (sym2);
11509   }
11510
11511   /* determine input values */
11512   val = list;
11513   while (val && val->pc != pc) val = val->next;
11514   //list = val; /* might save some time later... */
11515   while (val && val->pc == pc) {
11516     val->in_val = 0;
11517     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11518       /* get valnum for sym */
11519       count = defmapFindAll (val->sym, pc, &oldval);
11520       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11521       if (count == 1) {
11522         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11523           val->in_val = oldval->val;
11524         } else {
11525           val->in_val = 0;
11526         }
11527       } else if (count == 0) {
11528         /* no definition found */
11529         val->in_val = 0;
11530       } else {
11531         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11532         assert (oldval);
11533         dummy = oldval->next;
11534         mask = oldval->acc.access.mask;
11535         val->in_val = oldval->val;
11536         while (dummy && (dummy->val == val->in_val)) {
11537           mask &= dummy->acc.access.mask;
11538           dummy = dummy->next;
11539         } // while
11540
11541         /* found other values or to restictive mask */
11542         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11543           val->in_val = 0;
11544         }
11545       }
11546       if (count > 0) deleteDefmapChain (&oldval);
11547     } // if
11548     val = val->next;
11549   }
11550
11551   /* handle valnum assignment */
11552   switch (pci->op) {
11553   case POC_CLRF: /* modifies STATUS (Z) */
11554     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11555       oldval = defmapCurr (list, sym1, pc);
11556       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11557         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11558         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11559       }
11560       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11561     }
11562     break;
11563
11564   case POC_SETF: /* SETF does not touch STATUS */
11565     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11566       oldval = defmapCurr (list, sym1, pc);
11567       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11568         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11569         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11570       }
11571       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11572     }
11573     break;
11574     
11575   case POC_MOVLW: /* does not touch STATUS */
11576     oldval = defmapCurr (list, SPO_WREG, pc);
11577     if (pci->pcop->type == PO_LITERAL) {
11578       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11579       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11580     } else {
11581       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11582       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11583     }
11584     if (oldval && oldval->in_val == litnum) {
11585       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11586       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11587     }
11588     defmapUpdate (list, SPO_WREG, pc, litnum);
11589     break;
11590
11591   case POC_ANDLW: /* modifies STATUS (Z,N) */
11592   case POC_IORLW: /* modifies STATUS (Z,N) */
11593   case POC_XORLW: /* modifies STATUS (Z,N) */
11594     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11595     if (pci->pcop->type == PO_LITERAL) {
11596       int vallit = -1;
11597       lit = (unsigned char) PCOL(pci->pcop)->lit;
11598       val = defmapCurr (list, SPO_WREG, pc);
11599       if (val) vallit = litFromValnum (val->in_val);
11600       if (vallit != -1) {
11601         /* xxxLW <literal>, WREG contains a known literal */
11602         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11603         if (pci->op == POC_ANDLW) {
11604           lit &= vallit;
11605         } else if (pci->op == POC_IORLW) {
11606           lit |= vallit;
11607         } else if (pci->op == POC_XORLW) {
11608           lit ^= vallit;
11609         } else {
11610           assert (0 && "invalid operation");
11611         }
11612         if (vallit == lit) {
11613           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11614           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11615         }
11616         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11617       } // if
11618     }
11619     break;
11620
11621   case POC_LFSR:
11622     {
11623       /* check if old value matches new value */
11624       int lit;
11625       int ok = 1;
11626       assert (pci->pcop->type == PO_LITERAL);
11627       
11628       lit = PCOL(pci->pcop)->lit;
11629       
11630       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11631       
11632       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11633         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11634       } else {
11635         /* cannot remove this LFSR */
11636         ok = 0;      
11637       } // if
11638       
11639       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11640       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11641         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11642       } else {
11643         ok = 0;
11644       } // if
11645
11646       if (ok) {
11647         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11648       }
11649     }
11650     break;
11651     
11652   case POC_MOVWF: /* does not touch flags */
11653     /* find value of WREG */
11654     val = defmapCurr (list, SPO_WREG, pc);
11655     oldval = defmapCurr (list, sym1, pc);
11656     if (val) lit = litFromValnum (val->in_val);
11657     else lit = -1;
11658     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11659     
11660     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11661       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11662       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11663       if (lit == 0) {
11664         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11665       } else {
11666         assert (lit == 0x0ff);
11667         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11668       }
11669       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11670       pic16_pCodeReplace (pc, newpc);
11671       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11672       pic16_fixDefmap (pc, newpc);
11673       pc = newpc;
11674         
11675       /* This breaks the defmap chain's references to pCodes... fix it! */
11676       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11677       if (!val->acc.access.isWrite) {
11678         deleteDefmap (val);     // delete reference to WREG as in value
11679         val = NULL;
11680       } else {
11681         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11682       }
11683       oldval = PCI(pc)->pcflow->defmap;
11684       while (oldval) {
11685         if (oldval->pc == pc) oldval->pc = newpc;
11686           oldval = oldval->next;
11687       } // while
11688     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11689       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11690       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11691     }
11692     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11693     break;
11694     
11695   case POC_MOVFW: /* modifies STATUS (Z,N) */
11696     /* find value of REG */
11697     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11698       val = defmapCurr (list, sym1, pc);
11699       oldval = defmapCurr (list, SPO_WREG, pc);
11700       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11701         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11702         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11703       }
11704       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11705     }
11706     break;
11707
11708   case POC_MOVFF: /* does not touch STATUS */
11709     /* find value of REG */
11710     val = defmapCurr (list, sym1, pc);
11711     oldval = defmapCurr (list, sym2, pc);
11712     if (val) lit = litFromValnum (val->in_val);
11713     else lit = -1;
11714     newpc = NULL;
11715     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11716       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11717       if (lit == 0) {
11718         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11719       } else if (lit == 0x00ff) {
11720         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11721       } else {
11722         newpc = NULL;
11723       }
11724       if (newpc) {
11725         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11726         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11727         pic16_pCodeReplace (pc, newpc); 
11728         defmapReplaceSymRef (pc, sym1, 0, 1);
11729         pic16_fixDefmap (pc, newpc);
11730         pc = newpc;
11731         break; // do not process instruction as MOVFF...
11732       }
11733     } else if (!isSpecial1 && !isSpecial2
11734                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11735                 && val && oldval && (val->in_val != 0)) {
11736       if (val->in_val == oldval->in_val) {
11737         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11738         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11739       } else {
11740         if (!pic16_isAlive (sym1, pc)) {
11741           defmap_t *copy = NULL;
11742           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11743            * This should help eliminate
11744            *   MOVFF A,B
11745            *   <do something not changing A or using B>
11746            *   MOVFF B,C
11747            *   <B is not alive anymore>
11748            * and turn it into
11749            *   <do something not changing A or using B>
11750            *   MOVFF A,C
11751            */
11752
11753           /* scan defmap for symbols storing sym1's value */
11754           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11755           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11756             /* unique reaching definition for sym found */
11757             if (copy->val && copy->val == val->in_val) {
11758               //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);
11759               if (copy->sym == SPO_WREG) {
11760                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11761               } else {
11762                 pCodeOp *pcop = NULL;
11763                 /* the code below fails if we try to replace
11764                  *   MOVFF PRODL, r0x03
11765                  *   MOVFF r0x03, PCLATU
11766                  * with
11767                  *   MOVFF PRODL, PCLATU
11768                  * as copy(PRODL) contains has pc==NULL, by name fails...
11769                  */
11770                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11771                 
11772                 if (copy->pc && PCI(copy->pc)->pcop)
11773                   pcop = PCI(copy->pc)->pcop;
11774 #if 0
11775                 /* This code is broken--see above. */
11776                 else
11777                 {
11778                   const char *symname = strFromSym(copy->sym);
11779                   
11780                   assert( symname );
11781                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11782                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11783                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11784                 }
11785 #endif
11786                 assert( pcop );
11787                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11788                         pcop,
11789                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11790               }
11791               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11792               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11793               pic16_pCodeReplace (pc, newpc); 
11794               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11795               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11796               pic16_fixDefmap (pc, newpc);
11797               pc = newpc;
11798             }
11799           }
11800           deleteDefmapChain (&copy);
11801         }
11802       }
11803       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11804     }
11805     break;
11806
11807   default:
11808     /* cannot optimize */
11809     break;
11810   } // switch
11811 }
11812
11813 static void pic16_destructDF (pBlock *pb) {
11814   pCode *pc, *next;
11815
11816   /* remove old defmaps */
11817   pc = pic16_findNextInstruction (pb->pcHead);
11818   while (pc) {
11819     next = pic16_findNextInstruction (pc->next);
11820
11821     assert (isPCI(pc) || isPCAD(pc));
11822     assert (PCI(pc)->pcflow);
11823     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11824     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11825     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11826     
11827     pc = next;
11828   } // while
11829   
11830   if (defmap_free || defmap_free_count) {
11831     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11832     freeDefmap (&defmap_free);
11833     defmap_free_count = 0;
11834   }
11835 }
11836
11837 /* Checks whether a pBlock contains ASMDIRs. */
11838 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11839   pCode *pc;
11840
11841   pc = pic16_findNextInstruction (pb->pcHead);
11842   while (pc) {
11843     if (isPCAD(pc)) return 1;
11844
11845     pc = pic16_findNextInstruction (pc->next);
11846   } // while
11847
11848   /* no PCADs found */
11849   return 0;
11850 }
11851
11852 #if 1
11853 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11854 static int pic16_removeUnusedRegistersDF () {
11855   pCode *pc, *pc2;
11856   pBlock *pb;
11857   regs *reg1, *reg2, *reg3;
11858   set *seenRegs = NULL;
11859   int cond, i;
11860   int islocal, change = 0;
11861
11862   /* no pBlocks? */
11863   if (!the_pFile || !the_pFile->pbHead) return 0;
11864   
11865   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11866     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11867 #if 1
11868     /* find set of using pCodes per register */
11869     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11870                     pc = pic16_findNextInstruction(pc->next)) {
11871
11872       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11873       reg1 = reg2 = NULL;
11874       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11875       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11876
11877       if (reg1) {
11878         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11879         addSetIfnotP (&seenRegs, reg1);
11880         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11881       }
11882       if (reg2) {
11883         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11884         addSetIfnotP (&seenRegs, reg2);
11885         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11886       }
11887     } // for pc
11888 #endif
11889     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11890       /* may not use pic16_regIsLocal() here -- in interrupt routines
11891        * WREG, PRODx, FSR0x must be saved */
11892       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11893       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11894         pc = pc2 = NULL;
11895         for (i=0; i < 2; i++) {
11896           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11897           if (!pc2) pc2 = pc;
11898           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11899           reg2 = pic16_getRegFromInstruction (pc);
11900           reg3 = pic16_getRegFromInstruction2 (pc);
11901           if (!reg2 || !reg3
11902               || (reg2->rIdx != pic16_stack_preinc->rIdx
11903                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11904           if (i == 1) {
11905             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11906             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11907             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11908             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11909           }
11910         } // for
11911       } // if
11912       deleteSet (&reg1->reglives.usedpCodes);
11913     } // for reg1
11914
11915     deleteSet (&seenRegs);
11916   } // for pb
11917
11918   return change;
11919 }
11920 #endif
11921
11922 /* Set up pCodeFlow's defmap_ts. 
11923  * Needs correctly set up to/from fields. */
11924 static void pic16_createDF (pBlock *pb) {
11925   pCode *pc, *next;
11926   int change=0;
11927
11928   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11929
11930   pic16_destructDF (pb);
11931
11932   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11933   if (pic16_pBlockHasAsmdirs (pb)) {
11934     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11935     return;
11936   }
11937
11938   /* integrity check -- we need to reach all flows to guarantee
11939    * correct data flow analysis (reaching definitions, aliveness) */
11940 #if 0
11941   if (!verifyAllFlowsReachable (pb)) {
11942     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11943     return;
11944   }
11945 #endif
11946   
11947   /* establish new defmaps */
11948   pc = pic16_findNextInstruction (pb->pcHead);
11949   while (pc) {
11950     next = pic16_findNextInstruction (pc->next);
11951
11952     assert (PCI(pc)->pcflow);
11953     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11954
11955     pc = next;
11956   } // while
11957
11958   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11959   createReachingDefinitions (pb);
11960   
11961 #if 1
11962   /* assign better valnums */
11963   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11964   pc = pic16_findNextInstruction (pb->pcHead);
11965   while (pc) {
11966     next = pic16_findNextInstruction (pc->next);
11967
11968     assert (PCI(pc)->pcflow);
11969     assignValnums (pc);
11970
11971     pc = next;
11972   } // while
11973 #endif
11974
11975 #if 1
11976   /* remove dead pCodes */
11977   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11978   do {
11979     change = 0;
11980     pc = pic16_findNextInstruction (pb->pcHead);
11981     while (pc) {
11982       next = pic16_findNextInstruction (pc->next);
11983
11984       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11985         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11986       }
11987
11988       pc = next;
11989     } // while
11990   } while (change);
11991 #endif
11992 }
11993
11994 /* ======================================================================== */
11995 /* === VCG DUMPER ROUTINES ================================================ */
11996 /* ======================================================================== */
11997 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
11998 hTab *dumpedNodes = NULL;
11999
12000 /** Dump VCG header into of. */
12001 static void pic16_vcg_init (FILE *of) {
12002   /* graph defaults */
12003   fprintf (of, "graph:{\n");
12004   fprintf (of, "title:\"graph1\"\n");
12005   fprintf (of, "label:\"graph1\"\n");
12006   fprintf (of, "color:white\n");
12007   fprintf (of, "textcolor:black\n");
12008   fprintf (of, "bordercolor:black\n");
12009   fprintf (of, "borderwidth:1\n");
12010   fprintf (of, "textmode:center\n");
12011
12012   fprintf (of, "layoutalgorithm:dfs\n");
12013   fprintf (of, "late_edge_labels:yes\n");
12014   fprintf (of, "display_edge_labels:yes\n");
12015   fprintf (of, "dirty_edge_labels:yes\n");
12016   fprintf (of, "finetuning:yes\n");
12017   fprintf (of, "ignoresingles:no\n");
12018   fprintf (of, "straight_phase:yes\n");
12019   fprintf (of, "priority_phase:yes\n");
12020   fprintf (of, "manhattan_edges:yes\n");
12021   fprintf (of, "smanhattan_edges:no\n");
12022   fprintf (of, "nearedges:no\n");
12023   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12024   fprintf (of, "port_sharing:no\n");
12025   fprintf (of, "arrowmode:free\n"); // fixed|free
12026   fprintf (of, "crossingphase2:yes\n");
12027   fprintf (of, "crossingoptimization:yes\n");
12028   fprintf (of, "edges:yes\n");
12029   fprintf (of, "nodes:yes\n");
12030   fprintf (of, "splines:no\n");
12031   
12032   /* node defaults */
12033   fprintf (of, "node.color:lightyellow\n");
12034   fprintf (of, "node.textcolor:black\n");
12035   fprintf (of, "node.textmode:center\n");
12036   fprintf (of, "node.shape:box\n");
12037   fprintf (of, "node.bordercolor:black\n");
12038   fprintf (of, "node.borderwidth:1\n");
12039
12040   /* edge defaults */
12041   fprintf (of, "edge.textcolor:black\n");
12042   fprintf (of, "edge.color:black\n");
12043   fprintf (of, "edge.thickness:1\n");
12044   fprintf (of, "edge.arrowcolor:black\n");
12045   fprintf (of, "edge.backarrowcolor:black\n");
12046   fprintf (of, "edge.arrowsize:15\n");
12047   fprintf (of, "edge.backarrowsize:15\n");
12048   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12049   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12050   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12051   
12052   fprintf (of, "\n");
12053
12054   /* prepare data structures */
12055   if (dumpedNodes) {
12056     hTabDeleteAll (dumpedNodes);
12057     dumpedNodes = NULL;
12058   }
12059   dumpedNodes = newHashTable (128);
12060 }
12061
12062 /** Dump VCG footer into of. */
12063 static void pic16_vcg_close (FILE *of) {
12064   fprintf (of, "}\n");
12065 }
12066
12067 #define BUF_SIZE 128
12068 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12069
12070 #if 0
12071 static int ptrcmp (const void *p1, const void *p2) {
12072   return p1 == p2;
12073 }
12074 #endif
12075
12076 /** Dump a pCode node as VCG to of. */
12077 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12078   char buf[BUF_SIZE];
12079
12080   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12081     // dumped already
12082     return;
12083   }
12084   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12085   //fprintf (stderr, "dumping %p\n", pc);
12086  
12087   /* only dump pCodeInstructions and Flow nodes */
12088   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12089     
12090   /* emit node */
12091   fprintf (of, "node:{");
12092   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12093   fprintf (of, "label:\"%s\n", pcTitle(pc));
12094   if (isPCFL(pc)) {
12095     fprintf (of, "<PCFLOW>");
12096   } else if (isPCI(pc) || isPCAD(pc)) {
12097     pc->print (of, pc);
12098   } else {
12099     fprintf (of, "<!PCI>");
12100   }
12101   fprintf (of, "\" ");
12102   fprintf (of, "}\n");
12103   
12104   if (1 && isPCFL(pc)) {
12105     defmap_t *map, *prev;
12106     unsigned int i;
12107     map = PCFL(pc)->defmap;
12108     i=0;
12109     while (map) {
12110       if (map->sym != 0) {
12111         i++;
12112       
12113         /* emit definition node */
12114         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12115         fprintf (of, "label:\"");
12116
12117         prev = map;
12118         do {
12119           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));
12120           prev = map;
12121           map = map->next;
12122         } while (map && prev->pc == map->pc);
12123         map = prev;
12124         
12125         fprintf (of, "\" ");
12126       
12127         fprintf (of, "color:green ");
12128         fprintf (of, "}\n");
12129
12130         /* emit edge to previous definition */
12131         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12132         if (i == 1) {
12133           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12134         } else {
12135           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12136         }
12137         fprintf (of, "color:green ");
12138         fprintf (of, "}\n");
12139
12140         if (map->pc) {
12141           pic16_vcg_dumpnode (map->pc, of);
12142           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12143           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12144         }
12145       }
12146       map = map->next;
12147     } // while
12148   }
12149
12150   /* emit additional nodes (e.g. operands) */
12151 }
12152
12153 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12154 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12155   char buf[BUF_SIZE];
12156   pCodeInstruction *pci;
12157   pBranch *curr;
12158   int i;
12159   
12160   if (1 && isPCFL(pc)) {
12161     /* emit edges to flow successors */
12162     void *pcfl;
12163     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12164     pcfl = setFirstItem (PCFL(pc)->to);
12165     while (pcfl) {
12166       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12167       pic16_vcg_dumpnode (pc, of);
12168       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12169       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12170       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12171       pcfl = setNextItem (PCFL(pc)->to);
12172     } // while
12173   } // if
12174   
12175   if (!isPCI(pc) && !isPCAD(pc)) return;
12176
12177   pci = PCI(pc);
12178   
12179   /* emit control flow edges (forward only) */
12180   curr = pci->to;
12181   i=0;
12182   while (curr) {
12183     pic16_vcg_dumpnode (curr->pc, of);
12184     fprintf (of, "edge:{");
12185     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12186     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12187     fprintf (of, "color:red ");
12188     fprintf (of, "}\n");
12189     curr = curr->next;
12190   } // while
12191
12192 #if 1
12193   /* dump "flow" edge (link pCode according to pBlock order) */
12194   {
12195     pCode *pcnext;
12196     pcnext = pic16_findNextInstruction (pc->next);
12197     if (pcnext) {
12198       pic16_vcg_dumpnode (pcnext, of);
12199       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12200       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12201     }
12202   }
12203 #endif
12204   
12205 #if 0
12206   /* emit flow */
12207   if (pci->pcflow) {
12208     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12209     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12210     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12211   }
12212 #endif
12213   
12214   /* emit data flow edges (backward only) */
12215   /* TODO: gather data flow information... */
12216 }
12217
12218 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12219   pCode *pc;
12220
12221   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12222   if (pic16_pBlockHasAsmdirs (pb)) {
12223     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12224     return;
12225   }
12226
12227   for (pc=pb->pcHead; pc; pc = pc->next) {
12228     pic16_vcg_dumpnode (pc, of);
12229   } // for pc
12230   
12231   for (pc=pb->pcHead; pc; pc = pc->next) {
12232     pic16_vcg_dumpedges (pc, of);
12233   } // for pc
12234 }
12235
12236 static void pic16_vcg_dump_default (pBlock *pb) {
12237   FILE *of;
12238   char buf[BUF_SIZE];
12239   pCode *pc;
12240
12241   /* get function name */
12242   pc = pb->pcHead;
12243   while (pc && !isPCF(pc)) pc = pc->next;
12244   if (pc) {
12245     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12246   } else {
12247     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12248   }
12249
12250   //fprintf (stderr, "now dumping %s\n", buf);
12251   of = fopen (buf, "w");
12252   pic16_vcg_init (of);
12253   pic16_vcg_dump (of, pb);
12254   pic16_vcg_close (of);
12255   fclose (of);
12256 }
12257 #endif
12258
12259 /*** END of helpers for pCode dataflow optimizations ***/