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