* src/avr/gen.c (aopop),
[fw/sdcc] / src / pic16 / pcode.c
1 /*-------------------------------------------------------------------------
2
3   pcode.c - post code generation
4
5    Written By -  Scott Dattalo scott@dattalo.com
6    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
7
8    This program is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23 #include <stdio.h>
24
25 #include "common.h"   // Include everything in the SDCC src directory
26 #include "newalloc.h"
27
28
29 #include "main.h"
30 #include "pcode.h"
31 #include "pcodeflow.h"
32 #include "ralloc.h"
33 #include "device.h"
34
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
36
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
38 #define STRCASECMP stricmp
39 #define inline
40 #else
41 #define STRCASECMP strcasecmp
42 #endif
43
44 #define DUMP_DF_GRAPHS 0
45
46 /****************************************************************/
47 /****************************************************************/
48
49 static peepCommand peepCommands[] = {
50
51   {NOTBITSKIP, "_NOTBITSKIP_"},
52   {BITSKIP, "_BITSKIP_"},
53   {INVERTBITSKIP, "_INVERTBITSKIP_"},
54
55   {-1, NULL}
56 };
57
58
59
60 // Eventually this will go into device dependent files:
61 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
66 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
68
69 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
71 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
72
73 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
74 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
75 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
76 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
77
78 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
79
80 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
86
87 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
88 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
92
93 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
94 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
98
99 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
100 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
104
105 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
106 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
107
108 /* EEPROM registers */
109 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
113
114 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
115 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
117
118 pCodeOpReg *pic16_stackpnt_lo;
119 pCodeOpReg *pic16_stackpnt_hi;
120 pCodeOpReg *pic16_stack_postinc;
121 pCodeOpReg *pic16_stack_postdec;
122 pCodeOpReg *pic16_stack_preinc;
123 pCodeOpReg *pic16_stack_plusw;
124
125 pCodeOpReg *pic16_framepnt_lo;
126 pCodeOpReg *pic16_framepnt_hi;
127 pCodeOpReg *pic16_frame_postinc;
128 pCodeOpReg *pic16_frame_postdec;
129 pCodeOpReg *pic16_frame_preinc;
130 pCodeOpReg *pic16_frame_plusw;
131
132 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
133 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
134
135 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
136 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
137
138
139 static int mnemonics_initialized = 0;
140
141
142 static hTab *pic16MnemonicsHash = NULL;
143 static hTab *pic16pCodePeepCommandsHash = NULL;
144
145 static pFile *the_pFile = NULL;
146 static pBlock *pb_dead_pcodes = NULL;
147
148 /* Hardcoded flags to change the behavior of the PIC port */
149 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
150 static int functionInlining = 1;      /* inline functions if nonzero */
151 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
152
153 int pic16_pcode_verbose = 0;
154
155 //static int GpCodeSequenceNumber = 1;
156 static int GpcFlowSeq = 1;
157
158 extern void pic16_RemoveUnusedRegisters(void);
159 extern void pic16_RegsUnMapLiveRanges(void);
160 extern void pic16_BuildFlowTree(pBlock *pb);
161 extern void pic16_pCodeRegOptimizeRegUsage(int level);
162 extern int pic16_picIsInitialized(void);
163 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
164 extern int mnem2key(unsigned char const *mnem);
165
166 /****************************************************************/
167 /*                      Forward declarations                    */
168 /****************************************************************/
169
170 void pic16_unlinkpCode(pCode *pc);
171 #if 0
172 static void genericAnalyze(pCode *pc);
173 static void AnalyzeGOTO(pCode *pc);
174 static void AnalyzeSKIP(pCode *pc);
175 static void AnalyzeRETURN(pCode *pc);
176 #endif
177
178 static void genericDestruct(pCode *pc);
179 static void genericPrint(FILE *of,pCode *pc);
180
181 static void pCodePrintLabel(FILE *of, pCode *pc);
182 static void pCodePrintFunction(FILE *of, pCode *pc);
183 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
184 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
185 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
186 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
187 int pic16_pCodePeepMatchRule(pCode *pc);
188 static void pBlockStats(FILE *of, pBlock *pb);
189 static pBlock *newpBlock(void);
190 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
191 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
192 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
193 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
194 void OptimizeLocalRegs(void);
195 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
196
197 char *dumpPicOptype(PIC_OPTYPE type);
198
199 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
200 pCodeOp *pic16_popGetLit(int);
201 pCodeOp *pic16_popGetWithString(char *);
202 extern int inWparamList(char *s);
203
204 /** data flow optimization helpers **/
205 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
206 static void pic16_vcg_dump (FILE *of, pBlock *pb);
207 static void pic16_vcg_dump_default (pBlock *pb);
208 #endif
209 static int pic16_pCodeIsAlive (pCode *pc);
210 static void pic16_df_stats ();
211 static void pic16_createDF (pBlock *pb);
212 static int pic16_removeUnusedRegistersDF ();
213 static void pic16_destructDF (pBlock *pb);
214 static void releaseStack ();
215
216 /****************************************************************/
217 /*                    PIC Instructions                          */
218 /****************************************************************/
219
220 pCodeInstruction pic16_pciADDWF = {
221   {PC_OPCODE, NULL, NULL, 0, NULL, 
222    //   genericAnalyze,
223    genericDestruct,
224    genericPrint},
225   POC_ADDWF,
226   "ADDWF",
227   2,
228   NULL, // from branch
229   NULL, // to branch
230   NULL, // label
231   NULL, // operand
232   NULL, // flow block
233   NULL, // C source 
234   3,    // num ops
235   1,0,  // dest, bit instruction
236   0,0,  // branch, skip
237   0,    // literal operand
238   1,    // RAM access bit
239   0,    // fast call/return mode select bit
240   0,    // second memory operand
241   0,    // second literal operand
242   POC_NOP,
243   (PCC_W | PCC_REGISTER),   // inCond
244   (PCC_REGISTER | PCC_STATUS), // outCond
245   PCI_MAGIC
246 };
247
248 pCodeInstruction pic16_pciADDFW = {
249   {PC_OPCODE, NULL, NULL, 0, NULL, 
250    //   genericAnalyze,
251    genericDestruct,
252    genericPrint},
253   POC_ADDFW,
254   "ADDWF",
255   2,
256   NULL, // from branch
257   NULL, // to branch
258   NULL, // label
259   NULL, // operand
260   NULL, // flow block
261   NULL, // C source 
262   3,    // num ops
263   0,0,  // dest, bit instruction
264   0,0,  // branch, skip
265   0,    // literal operand
266   1,    // RAM access bit
267   0,    // fast call/return mode select bit
268   0,    // second memory operand
269   0,    // second literal operand
270   POC_NOP,
271   (PCC_W | PCC_REGISTER),   // inCond
272   (PCC_W | PCC_STATUS), // outCond
273   PCI_MAGIC
274 };
275
276 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
277   {PC_OPCODE, NULL, NULL, 0, NULL, 
278    //   genericAnalyze,
279    genericDestruct,
280    genericPrint},
281   POC_ADDWFC,
282   "ADDWFC",
283   2,
284   NULL, // from branch
285   NULL, // to branch
286   NULL, // label
287   NULL, // operand
288   NULL, // flow block
289   NULL, // C source 
290   3,    // num ops
291   1,0,  // dest, bit instruction
292   0,0,  // branch, skip
293   0,    // literal operand
294   1,    // RAM access bit
295   0,    // fast call/return mode select bit
296   0,    // second memory operand
297   0,    // second literal operand
298   POC_NOP,
299   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
300   (PCC_REGISTER | PCC_STATUS), // outCond
301   PCI_MAGIC
302 };
303
304 pCodeInstruction pic16_pciADDFWC = {
305   {PC_OPCODE, NULL, NULL, 0, NULL, 
306    //   genericAnalyze,
307    genericDestruct,
308    genericPrint},
309   POC_ADDFWC,
310   "ADDWFC",
311   2,
312   NULL, // from branch
313   NULL, // to branch
314   NULL, // label
315   NULL, // operand
316   NULL, // flow block
317   NULL, // C source 
318   3,    // num ops
319   0,0,  // dest, bit instruction
320   0,0,  // branch, skip
321   0,    // literal operand
322   1,    // RAM access bit
323   0,    // fast call/return mode select bit
324   0,    // second memory operand
325   0,    // second literal operand
326   POC_NOP,
327   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
328   (PCC_W | PCC_STATUS), // outCond
329   PCI_MAGIC
330 };
331
332 pCodeInstruction pic16_pciADDLW = {
333   {PC_OPCODE, NULL, NULL, 0, NULL, 
334    //   genericAnalyze,
335    genericDestruct,
336    genericPrint},
337   POC_ADDLW,
338   "ADDLW",
339   2,
340   NULL, // from branch
341   NULL, // to branch
342   NULL, // label
343   NULL, // operand
344   NULL, // flow block
345   NULL, // C source 
346   1,    // num ops
347   0,0,  // dest, bit instruction
348   0,0,  // branch, skip
349   1,    // literal operand
350   0,    // RAM access bit
351   0,    // fast call/return mode select bit
352   0,    // second memory operand
353   0,    // second literal operand
354   POC_NOP,
355   (PCC_W | PCC_LITERAL),   // inCond
356   (PCC_W | PCC_STATUS), // outCond
357   PCI_MAGIC
358 };
359
360 pCodeInstruction pic16_pciANDLW = {
361   {PC_OPCODE, NULL, NULL, 0, NULL, 
362    //   genericAnalyze,
363    genericDestruct,
364    genericPrint},
365   POC_ANDLW,
366   "ANDLW",
367   2,
368   NULL, // from branch
369   NULL, // to branch
370   NULL, // label
371   NULL, // operand
372   NULL, // flow block
373   NULL, // C source 
374   1,    // num ops
375   0,0,  // dest, bit instruction
376   0,0,  // branch, skip
377   1,    // literal operand
378   0,    // RAM access bit
379   0,    // fast call/return mode select bit
380   0,    // second memory operand
381   0,    // second literal operand
382   POC_NOP,
383   (PCC_W | PCC_LITERAL),   // inCond
384   (PCC_W | PCC_Z | PCC_N), // outCond
385   PCI_MAGIC
386 };
387
388 pCodeInstruction pic16_pciANDWF = {
389   {PC_OPCODE, NULL, NULL, 0, NULL, 
390    //   genericAnalyze,
391    genericDestruct,
392    genericPrint},
393   POC_ANDWF,
394   "ANDWF",
395   2,
396   NULL, // from branch
397   NULL, // to branch
398   NULL, // label
399   NULL, // operand
400   NULL, // flow block
401   NULL, // C source 
402   3,    // num ops
403   1,0,  // dest, bit instruction
404   0,0,  // branch, skip
405   0,    // literal operand
406   1,    // RAM access bit
407   0,    // fast call/return mode select bit
408   0,    // second memory operand
409   0,    // second literal operand
410   POC_NOP,
411   (PCC_W | PCC_REGISTER),   // inCond
412   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
413   PCI_MAGIC
414 };
415
416 pCodeInstruction pic16_pciANDFW = {
417   {PC_OPCODE, NULL, NULL, 0, NULL, 
418    //   genericAnalyze,
419    genericDestruct,
420    genericPrint},
421   POC_ANDFW,
422   "ANDWF",
423   2,
424   NULL, // from branch
425   NULL, // to branch
426   NULL, // label
427   NULL, // operand
428   NULL, // flow block
429   NULL, // C source 
430   3,    // num ops
431   0,0,  // dest, bit instruction
432   0,0,  // branch, skip
433   0,    // literal operand
434   1,    // RAM access bit
435   0,    // fast call/return mode select bit
436   0,    // second memory operand
437   0,    // second literal operand
438   POC_NOP,
439   (PCC_W | PCC_REGISTER),   // inCond
440   (PCC_W | PCC_Z | PCC_N) // outCond
441 };
442
443 pCodeInstruction pic16_pciBC = { // mdubuc - New
444   {PC_OPCODE, NULL, NULL, 0, NULL, 
445    //   genericAnalyze,
446    genericDestruct,
447    genericPrint},
448   POC_BC,
449   "BC",
450   2,
451   NULL, // from branch
452   NULL, // to branch
453   NULL, // label
454   NULL, // operand
455   NULL, // flow block
456   NULL, // C source 
457   1,    // num ops
458   0,0,  // dest, bit instruction
459   1,0,  // branch, skip
460   0,    // literal operand
461   0,    // RAM access bit
462   0,    // fast call/return mode select bit
463   0,    // second memory operand
464   0,    // second literal operand
465   POC_NOP,
466   (PCC_REL_ADDR | PCC_C),   // inCond
467   PCC_NONE,    // outCond
468   PCI_MAGIC
469 };
470
471 pCodeInstruction pic16_pciBCF = {
472   {PC_OPCODE, NULL, NULL, 0, NULL, 
473    //   genericAnalyze,
474    genericDestruct,
475    genericPrint},
476   POC_BCF,
477   "BCF",
478   2,
479   NULL, // from branch
480   NULL, // to branch
481   NULL, // label
482   NULL, // operand
483   NULL, // flow block
484   NULL, // C source 
485   3,    // num ops
486   1,1,  // dest, bit instruction
487   0,0,  // branch, skip
488   0,    // literal operand
489   1,    // RAM access bit
490   0,    // fast call/return mode select bit
491   0,    // second memory operand
492   0,    // second literal operand
493   POC_BSF,
494   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
495   PCC_REGISTER, // outCond
496   PCI_MAGIC
497 };
498
499 pCodeInstruction pic16_pciBN = { // mdubuc - New
500   {PC_OPCODE, NULL, NULL, 0, NULL, 
501    //   genericAnalyze,
502    genericDestruct,
503    genericPrint},
504   POC_BN,
505   "BN",
506   2,
507   NULL, // from branch
508   NULL, // to branch
509   NULL, // label
510   NULL, // operand
511   NULL, // flow block
512   NULL, // C source 
513   1,    // num ops
514   0,0,  // dest, bit instruction
515   1,0,  // branch, skip
516   0,    // literal operand
517   0,    // RAM access bit
518   0,    // fast call/return mode select bit
519   0,    // second memory operand
520   0,    // second literal operand
521   POC_NOP,
522   (PCC_REL_ADDR | PCC_N),   // inCond
523   PCC_NONE   , // outCond
524   PCI_MAGIC
525 };
526
527 pCodeInstruction pic16_pciBNC = { // mdubuc - New
528   {PC_OPCODE, NULL, NULL, 0, NULL, 
529    //   genericAnalyze,
530    genericDestruct,
531    genericPrint},
532   POC_BNC,
533   "BNC",
534   2,
535   NULL, // from branch
536   NULL, // to branch
537   NULL, // label
538   NULL, // operand
539   NULL, // flow block
540   NULL, // C source 
541   1,    // num ops
542   0,0,  // dest, bit instruction
543   1,0,  // branch, skip
544   0,    // literal operand
545   0,    // RAM access bit
546   0,    // fast call/return mode select bit
547   0,    // second memory operand
548   0,    // second literal operand
549   POC_NOP,
550   (PCC_REL_ADDR | PCC_C),   // inCond
551   PCC_NONE   , // outCond
552   PCI_MAGIC
553 };
554
555 pCodeInstruction pic16_pciBNN = { // mdubuc - New
556   {PC_OPCODE, NULL, NULL, 0, NULL, 
557    //   genericAnalyze,
558    genericDestruct,
559    genericPrint},
560   POC_BNN,
561   "BNN",
562   2,
563   NULL, // from branch
564   NULL, // to branch
565   NULL, // label
566   NULL, // operand
567   NULL, // flow block
568   NULL, // C source 
569   1,    // num ops
570   0,0,  // dest, bit instruction
571   1,0,  // branch, skip
572   0,    // literal operand
573   0,    // RAM access bit
574   0,    // fast call/return mode select bit
575   0,    // second memory operand
576   0,    // second literal operand
577   POC_NOP,
578   (PCC_REL_ADDR | PCC_N),   // inCond
579   PCC_NONE   , // outCond
580   PCI_MAGIC
581 };
582
583 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
584   {PC_OPCODE, NULL, NULL, 0, NULL, 
585    //   genericAnalyze,
586    genericDestruct,
587    genericPrint},
588   POC_BNOV,
589   "BNOV",
590   2,
591   NULL, // from branch
592   NULL, // to branch
593   NULL, // label
594   NULL, // operand
595   NULL, // flow block
596   NULL, // C source 
597   1,    // num ops
598   0,0,  // dest, bit instruction
599   1,0,  // branch, skip
600   0,    // literal operand
601   0,    // RAM access bit
602   0,    // fast call/return mode select bit
603   0,    // second memory operand
604   0,    // second literal operand
605   POC_NOP,
606   (PCC_REL_ADDR | PCC_OV),   // inCond
607   PCC_NONE   , // outCond
608   PCI_MAGIC
609 };
610
611 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
612   {PC_OPCODE, NULL, NULL, 0, NULL, 
613    //   genericAnalyze,
614    genericDestruct,
615    genericPrint},
616   POC_BNZ,
617   "BNZ",
618   2,
619   NULL, // from branch
620   NULL, // to branch
621   NULL, // label
622   NULL, // operand
623   NULL, // flow block
624   NULL, // C source 
625   1,    // num ops
626   0,0,  // dest, bit instruction
627   1,0,  // branch, skip
628   0,    // literal operand
629   0,    // RAM access bit
630   0,    // fast call/return mode select bit
631   0,    // second memory operand
632   0,    // second literal operand
633   POC_NOP,
634   (PCC_REL_ADDR | PCC_Z),   // inCond
635   PCC_NONE   , // outCond
636   PCI_MAGIC
637 };
638
639 pCodeInstruction pic16_pciBOV = { // mdubuc - New
640   {PC_OPCODE, NULL, NULL, 0, NULL, 
641    //   genericAnalyze,
642    genericDestruct,
643    genericPrint},
644   POC_BOV,
645   "BOV",
646   2,
647   NULL, // from branch
648   NULL, // to branch
649   NULL, // label
650   NULL, // operand
651   NULL, // flow block
652   NULL, // C source 
653   1,    // num ops
654   0,0,  // dest, bit instruction
655   1,0,  // branch, skip
656   0,    // literal operand
657   0,    // RAM access bit
658   0,    // fast call/return mode select bit
659   0,    // second memory operand
660   0,    // second literal operand
661   POC_NOP,
662   (PCC_REL_ADDR | PCC_OV),   // inCond
663   PCC_NONE , // outCond
664   PCI_MAGIC
665 };
666
667 pCodeInstruction pic16_pciBRA = { // mdubuc - New
668   {PC_OPCODE, NULL, NULL, 0, NULL, 
669    //   genericAnalyze,
670    genericDestruct,
671    genericPrint},
672   POC_BRA,
673   "BRA",
674   2,
675   NULL, // from branch
676   NULL, // to branch
677   NULL, // label
678   NULL, // operand
679   NULL, // flow block
680   NULL, // C source 
681   1,    // num ops
682   0,0,  // dest, bit instruction
683   1,0,  // branch, skip
684   0,    // literal operand
685   0,    // RAM access bit
686   0,    // fast call/return mode select bit
687   0,    // second memory operand
688   0,    // second literal operand
689   POC_NOP,
690   PCC_REL_ADDR,   // inCond
691   PCC_NONE   , // outCond
692   PCI_MAGIC
693 };
694
695 pCodeInstruction pic16_pciBSF = {
696   {PC_OPCODE, NULL, NULL, 0, NULL, 
697    //   genericAnalyze,
698    genericDestruct,
699    genericPrint},
700   POC_BSF,
701   "BSF",
702   2,
703   NULL, // from branch
704   NULL, // to branch
705   NULL, // label
706   NULL, // operand
707   NULL, // flow block
708   NULL, // C source 
709   3,    // num ops
710   1,1,  // dest, bit instruction
711   0,0,  // branch, skip
712   0,    // literal operand
713   1,    // RAM access bit
714   0,    // fast call/return mode select bit
715   0,    // second memory operand
716   0,    // second literal operand
717   POC_BCF,
718   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
719   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
720   PCI_MAGIC
721 };
722
723 pCodeInstruction pic16_pciBTFSC = {
724   {PC_OPCODE, NULL, NULL, 0, NULL, 
725    //   AnalyzeSKIP,
726    genericDestruct,
727    genericPrint},
728   POC_BTFSC,
729   "BTFSC",
730   2,
731   NULL, // from branch
732   NULL, // to branch
733   NULL, // label
734   NULL, // operand
735   NULL, // flow block
736   NULL, // C source 
737   3,    // num ops
738   0,1,  // dest, bit instruction
739   1,1,  // branch, skip
740   0,    // literal operand
741   1,    // RAM access bit
742   0,    // fast call/return mode select bit
743   0,    // second memory operand
744   0,    // second literal operand
745   POC_BTFSS,
746   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
747   PCC_EXAMINE_PCOP, // outCond
748   PCI_MAGIC
749 };
750
751 pCodeInstruction pic16_pciBTFSS = {
752   {PC_OPCODE, NULL, NULL, 0, NULL, 
753    //   AnalyzeSKIP,
754    genericDestruct,
755    genericPrint},
756   POC_BTFSS,
757   "BTFSS",
758   2,
759   NULL, // from branch
760   NULL, // to branch
761   NULL, // label
762   NULL, // operand
763   NULL, // flow block
764   NULL, // C source 
765   3,    // num ops
766   0,1,  // dest, bit instruction
767   1,1,  // branch, skip
768   0,    // literal operand
769   1,    // RAM access bit
770   0,    // fast call/return mode select bit
771   0,    // second memory operand
772   0,    // second literal operand
773   POC_BTFSC,
774   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
775   PCC_EXAMINE_PCOP, // outCond
776   PCI_MAGIC
777 };
778
779 pCodeInstruction pic16_pciBTG = { // mdubuc - New
780   {PC_OPCODE, NULL, NULL, 0, NULL, 
781    //   genericAnalyze,
782    genericDestruct,
783    genericPrint},
784   POC_BTG,
785   "BTG",
786   2,
787   NULL, // from branch
788   NULL, // to branch
789   NULL, // label
790   NULL, // operand
791   NULL, // flow block
792   NULL, // C source 
793   3,    // num ops
794   0,1,  // dest, bit instruction
795   0,0,  // branch, skip
796   0,    // literal operand
797   1,    // RAM access bit
798   0,    // fast call/return mode select bit
799   0,    // second memory operand
800   0,    // second literal operand
801   POC_NOP,
802   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
803   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
804   PCI_MAGIC
805 };
806
807 pCodeInstruction pic16_pciBZ = { // mdubuc - New
808   {PC_OPCODE, NULL, NULL, 0, NULL, 
809    //   genericAnalyze,
810    genericDestruct,
811    genericPrint},
812   POC_BZ,
813   "BZ",
814   2,
815   NULL, // from branch
816   NULL, // to branch
817   NULL, // label
818   NULL, // operand
819   NULL, // flow block
820   NULL, // C source 
821   1,    // num ops
822   0,0,  // dest, bit instruction
823   1,0,  // branch, skip
824   0,    // literal operand
825   0,    // RAM access bit
826   0,    // fast call/return mode select bit
827   0,    // second memory operand
828   0,    // second literal operand
829   POC_NOP,
830   (PCC_REL_ADDR | PCC_Z),   // inCond
831   PCC_NONE, // outCond
832   PCI_MAGIC
833 };
834
835 pCodeInstruction pic16_pciCALL = {
836   {PC_OPCODE, NULL, NULL, 0, NULL, 
837    //   genericAnalyze,
838    genericDestruct,
839    genericPrint},
840   POC_CALL,
841   "CALL",
842   4,
843   NULL, // from branch
844   NULL, // to branch
845   NULL, // label
846   NULL, // operand
847   NULL, // flow block
848   NULL, // C source 
849   2,    // num ops
850   0,0,  // dest, bit instruction
851   1,0,  // branch, skip
852   0,    // literal operand
853   0,    // RAM access bit
854   1,    // fast call/return mode select bit
855   0,    // second memory operand
856   0,    // second literal operand
857   POC_NOP,
858   PCC_NONE, // inCond
859   PCC_NONE, // outCond
860   PCI_MAGIC
861 };
862
863 pCodeInstruction pic16_pciCOMF = {
864   {PC_OPCODE, NULL, NULL, 0, NULL, 
865    //   genericAnalyze,
866    genericDestruct,
867    genericPrint},
868   POC_COMF,
869   "COMF",
870   2,
871   NULL, // from branch
872   NULL, // to branch
873   NULL, // label
874   NULL, // operand
875   NULL, // flow block
876   NULL, // C source 
877   3,    // num ops
878   1,0,  // dest, bit instruction
879   0,0,  // branch, skip
880   0,    // literal operand
881   1,    // RAM access bit
882   0,    // fast call/return mode select bit
883   0,    // second memory operand
884   0,    // second literal operand
885   POC_NOP,
886   PCC_REGISTER,  // inCond
887   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
888   PCI_MAGIC
889 };
890
891 pCodeInstruction pic16_pciCOMFW = {
892   {PC_OPCODE, NULL, NULL, 0, NULL, 
893    //   genericAnalyze,
894    genericDestruct,
895    genericPrint},
896   POC_COMFW,
897   "COMF",
898   2,
899   NULL, // from branch
900   NULL, // to branch
901   NULL, // label
902   NULL, // operand
903   NULL, // flow block
904   NULL, // C source 
905   3,    // num ops
906   0,0,  // dest, bit instruction
907   0,0,  // branch, skip
908   0,    // literal operand
909   1,    // RAM access bit
910   0,    // fast call/return mode select bit
911   0,    // second memory operand
912   0,    // second literal operand
913   POC_NOP,
914   PCC_REGISTER,  // inCond
915   (PCC_W | PCC_Z | PCC_N) , // outCond
916   PCI_MAGIC
917 };
918
919 pCodeInstruction pic16_pciCLRF = {
920   {PC_OPCODE, NULL, NULL, 0, NULL, 
921    //   genericAnalyze,
922    genericDestruct,
923    genericPrint},
924   POC_CLRF,
925   "CLRF",
926   2,
927   NULL, // from branch
928   NULL, // to branch
929   NULL, // label
930   NULL, // operand
931   NULL, // flow block
932   NULL, // C source 
933   2,    // num ops
934   0,0,  // dest, bit instruction
935   0,0,  // branch, skip
936   0,    // literal operand
937   1,    // RAM access bit
938   0,    // fast call/return mode select bit
939   0,    // second memory operand
940   0,    // second literal operand
941   POC_NOP,
942   PCC_NONE, // inCond
943   (PCC_REGISTER | PCC_Z), // outCond
944   PCI_MAGIC
945 };
946
947 pCodeInstruction pic16_pciCLRWDT = {
948   {PC_OPCODE, NULL, NULL, 0, NULL, 
949    //   genericAnalyze,
950    genericDestruct,
951    genericPrint},
952   POC_CLRWDT,
953   "CLRWDT",
954   2,
955   NULL, // from branch
956   NULL, // to branch
957   NULL, // label
958   NULL, // operand
959   NULL, // flow block
960   NULL, // C source 
961   0,    // num ops
962   0,0,  // dest, bit instruction
963   0,0,  // branch, skip
964   0,    // literal operand
965   0,    // RAM access bit
966   0,    // fast call/return mode select bit
967   0,    // second memory operand
968   0,    // second literal operand
969   POC_NOP,
970   PCC_NONE, // inCond
971   PCC_NONE , // outCond
972   PCI_MAGIC
973 };
974
975 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
976   {PC_OPCODE, NULL, NULL, 0, NULL, 
977    //   genericAnalyze,
978    genericDestruct,
979    genericPrint},
980   POC_CPFSEQ,
981   "CPFSEQ",
982   2,
983   NULL, // from branch
984   NULL, // to branch
985   NULL, // label
986   NULL, // operand
987   NULL, // flow block
988   NULL, // C source 
989   2,    // num ops
990   0,0,  // dest, bit instruction
991   1,1,  // branch, skip
992   0,    // literal operand
993   1,    // RAM access bit
994   0,    // fast call/return mode select bit
995   0,    // second memory operand
996   0,    // second literal operand
997   POC_NOP,
998   (PCC_W | PCC_REGISTER), // inCond
999   PCC_NONE , // outCond
1000   PCI_MAGIC
1001 };
1002
1003 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1004   {PC_OPCODE, NULL, NULL, 0, NULL, 
1005    //   genericAnalyze,
1006    genericDestruct,
1007    genericPrint},
1008   POC_CPFSGT,
1009   "CPFSGT",
1010   2,
1011   NULL, // from branch
1012   NULL, // to branch
1013   NULL, // label
1014   NULL, // operand
1015   NULL, // flow block
1016   NULL, // C source 
1017   2,    // num ops
1018   0,0,  // dest, bit instruction
1019   1,1,  // branch, skip
1020   0,    // literal operand
1021   1,    // RAM access bit
1022   0,    // fast call/return mode select bit
1023   0,    // second memory operand
1024   0,    // second literal operand
1025   POC_NOP,
1026   (PCC_W | PCC_REGISTER), // inCond
1027   PCC_NONE , // outCond
1028   PCI_MAGIC
1029 };
1030
1031 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1032   {PC_OPCODE, NULL, NULL, 0, NULL, 
1033    //   genericAnalyze,
1034    genericDestruct,
1035    genericPrint},
1036   POC_CPFSLT,
1037   "CPFSLT",
1038   2,
1039   NULL, // from branch
1040   NULL, // to branch
1041   NULL, // label
1042   NULL, // operand
1043   NULL, // flow block
1044   NULL, // C source 
1045   2,    // num ops
1046   1,0,  // dest, bit instruction
1047   1,1,  // branch, skip
1048   0,    // literal operand
1049   1,    // RAM access bit
1050   0,    // fast call/return mode select bit
1051   0,    // second memory operand
1052   0,    // second literal operand
1053   POC_NOP,
1054   (PCC_W | PCC_REGISTER), // inCond
1055   PCC_NONE , // outCond
1056   PCI_MAGIC
1057 };
1058
1059 pCodeInstruction pic16_pciDAW = {
1060   {PC_OPCODE, NULL, NULL, 0, NULL, 
1061    //   genericAnalyze,
1062    genericDestruct,
1063    genericPrint},
1064   POC_DAW,
1065   "DAW",
1066   2,
1067   NULL, // from branch
1068   NULL, // to branch
1069   NULL, // label
1070   NULL, // operand
1071   NULL, // flow block
1072   NULL, // C source 
1073   0,    // num ops
1074   0,0,  // dest, bit instruction
1075   0,0,  // branch, skip
1076   0,    // literal operand
1077   0,    // RAM access bit
1078   0,    // fast call/return mode select bit
1079   0,    // second memory operand
1080   0,    // second literal operand
1081   POC_NOP,
1082   PCC_W, // inCond
1083   (PCC_W | PCC_C), // outCond
1084   PCI_MAGIC
1085 };
1086
1087 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1088   {PC_OPCODE, NULL, NULL, 0, NULL, 
1089    //   genericAnalyze,
1090    genericDestruct,
1091    genericPrint},
1092   POC_DCFSNZ,
1093   "DCFSNZ",
1094   2,
1095   NULL, // from branch
1096   NULL, // to branch
1097   NULL, // label
1098   NULL, // operand
1099   NULL, // flow block
1100   NULL, // C source 
1101   3,    // num ops
1102   1,0,  // dest, bit instruction
1103   1,1,  // branch, skip
1104   0,    // literal operand
1105   1,    // RAM access bit
1106   0,    // fast call/return mode select bit
1107   0,    // second memory operand
1108   0,    // second literal operand
1109   POC_NOP,
1110   PCC_REGISTER, // inCond
1111   PCC_REGISTER , // outCond
1112   PCI_MAGIC
1113 };
1114
1115 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1116   {PC_OPCODE, NULL, NULL, 0, NULL, 
1117    //   genericAnalyze,
1118    genericDestruct,
1119    genericPrint},
1120   POC_DCFSNZW,
1121   "DCFSNZ",
1122   2,
1123   NULL, // from branch
1124   NULL, // to branch
1125   NULL, // label
1126   NULL, // operand
1127   NULL, // flow block
1128   NULL, // C source 
1129   3,    // num ops
1130   0,0,  // dest, bit instruction
1131   1,1,  // branch, skip
1132   0,    // literal operand
1133   1,    // RAM access bit
1134   0,    // fast call/return mode select bit
1135   0,    // second memory operand
1136   0,    // second literal operand
1137   POC_NOP,
1138   PCC_REGISTER, // inCond
1139   PCC_W , // outCond
1140   PCI_MAGIC
1141 };
1142
1143 pCodeInstruction pic16_pciDECF = {
1144   {PC_OPCODE, NULL, NULL, 0, NULL, 
1145    //   genericAnalyze,
1146    genericDestruct,
1147    genericPrint},
1148   POC_DECF,
1149   "DECF",
1150   2,
1151   NULL, // from branch
1152   NULL, // to branch
1153   NULL, // label
1154   NULL, // operand
1155   NULL, // flow block
1156   NULL, // C source 
1157   3,    // num ops
1158   1,0,  // dest, bit instruction
1159   0,0,  // branch, skip
1160   0,    // literal operand
1161   1,    // RAM access bit
1162   0,    // fast call/return mode select bit
1163   0,    // second memory operand
1164   0,    // second literal operand
1165   POC_NOP,
1166   PCC_REGISTER,   // inCond
1167   (PCC_REGISTER | PCC_STATUS)  , // outCond
1168   PCI_MAGIC
1169 };
1170
1171 pCodeInstruction pic16_pciDECFW = {
1172   {PC_OPCODE, NULL, NULL, 0, NULL, 
1173    //   genericAnalyze,
1174    genericDestruct,
1175    genericPrint},
1176   POC_DECFW,
1177   "DECF",
1178   2,
1179   NULL, // from branch
1180   NULL, // to branch
1181   NULL, // label
1182   NULL, // operand
1183   NULL, // flow block
1184   NULL, // C source 
1185   3,    // num ops
1186   0,0,  // dest, bit instruction
1187   0,0,  // branch, skip
1188   0,    // literal operand
1189   1,    // RAM access bit
1190   0,    // fast call/return mode select bit
1191   0,    // second memory operand
1192   0,    // second literal operand
1193   POC_NOP,
1194   PCC_REGISTER,   // inCond
1195   (PCC_W | PCC_STATUS)  , // outCond
1196   PCI_MAGIC
1197 };
1198
1199 pCodeInstruction pic16_pciDECFSZ = {
1200   {PC_OPCODE, NULL, NULL, 0, NULL, 
1201    //   AnalyzeSKIP,
1202    genericDestruct,
1203    genericPrint},
1204   POC_DECFSZ,
1205   "DECFSZ",
1206   2,
1207   NULL, // from branch
1208   NULL, // to branch
1209   NULL, // label
1210   NULL, // operand
1211   NULL, // flow block
1212   NULL, // C source 
1213   3,    // num ops
1214   1,0,  // dest, bit instruction
1215   1,1,  // branch, skip
1216   0,    // literal operand
1217   1,    // RAM access bit
1218   0,    // fast call/return mode select bit
1219   0,    // second memory operand
1220   0,    // second literal operand
1221   POC_NOP,
1222   PCC_REGISTER,   // inCond
1223   PCC_REGISTER   , // outCond
1224   PCI_MAGIC
1225 };
1226
1227 pCodeInstruction pic16_pciDECFSZW = {
1228   {PC_OPCODE, NULL, NULL, 0, NULL, 
1229    //   AnalyzeSKIP,
1230    genericDestruct,
1231    genericPrint},
1232   POC_DECFSZW,
1233   "DECFSZ",
1234   2,
1235   NULL, // from branch
1236   NULL, // to branch
1237   NULL, // label
1238   NULL, // operand
1239   NULL, // flow block
1240   NULL, // C source 
1241   3,    // num ops
1242   0,0,  // dest, bit instruction
1243   1,1,  // branch, skip
1244   0,    // literal operand
1245   1,    // RAM access bit
1246   0,    // fast call/return mode select bit
1247   0,    // second memory operand
1248   0,    // second literal operand
1249   POC_NOP,
1250   PCC_REGISTER,   // inCond
1251   PCC_W          , // outCond
1252   PCI_MAGIC
1253 };
1254
1255 pCodeInstruction pic16_pciGOTO = {
1256   {PC_OPCODE, NULL, NULL, 0, NULL, 
1257    //   AnalyzeGOTO,
1258    genericDestruct,
1259    genericPrint},
1260   POC_GOTO,
1261   "GOTO",
1262   4,
1263   NULL, // from branch
1264   NULL, // to branch
1265   NULL, // label
1266   NULL, // operand
1267   NULL, // flow block
1268   NULL, // C source 
1269   1,    // num ops
1270   0,0,  // dest, bit instruction
1271   1,0,  // branch, skip
1272   0,    // literal operand
1273   0,    // RAM access bit
1274   0,    // fast call/return mode select bit
1275   0,    // second memory operand
1276   0,    // second literal operand
1277   POC_NOP,
1278   PCC_REL_ADDR,   // inCond
1279   PCC_NONE   , // outCond
1280   PCI_MAGIC
1281 };
1282
1283 pCodeInstruction pic16_pciINCF = {
1284   {PC_OPCODE, NULL, NULL, 0, NULL, 
1285    //   genericAnalyze,
1286    genericDestruct,
1287    genericPrint},
1288   POC_INCF,
1289   "INCF",
1290   2,
1291   NULL, // from branch
1292   NULL, // to branch
1293   NULL, // label
1294   NULL, // operand
1295   NULL, // flow block
1296   NULL, // C source 
1297   3,    // num ops
1298   1,0,  // dest, bit instruction
1299   0,0,  // branch, skip
1300   0,    // literal operand
1301   1,    // RAM access bit
1302   0,    // fast call/return mode select bit
1303   0,    // second memory operand
1304   0,    // second literal operand
1305   POC_NOP,
1306   PCC_REGISTER,   // inCond
1307   (PCC_REGISTER | PCC_STATUS), // outCond
1308   PCI_MAGIC
1309 };
1310
1311 pCodeInstruction pic16_pciINCFW = {
1312   {PC_OPCODE, NULL, NULL, 0, NULL, 
1313    //   genericAnalyze,
1314    genericDestruct,
1315    genericPrint},
1316   POC_INCFW,
1317   "INCF",
1318   2,
1319   NULL, // from branch
1320   NULL, // to branch
1321   NULL, // label
1322   NULL, // operand
1323   NULL, // flow block
1324   NULL, // C source 
1325   3,    // num ops
1326   0,0,  // dest, bit instruction
1327   0,0,  // branch, skip
1328   0,    // literal operand
1329   1,    // RAM access bit
1330   0,    // fast call/return mode select bit
1331   0,    // second memory operand
1332   0,    // second literal operand
1333   POC_NOP,
1334   PCC_REGISTER,   // inCond
1335   (PCC_W | PCC_STATUS)  , // outCond
1336   PCI_MAGIC
1337 };
1338
1339 pCodeInstruction pic16_pciINCFSZ = {
1340   {PC_OPCODE, NULL, NULL, 0, NULL, 
1341    //   AnalyzeSKIP,
1342    genericDestruct,
1343    genericPrint},
1344   POC_INCFSZ,
1345   "INCFSZ",
1346   2,
1347   NULL, // from branch
1348   NULL, // to branch
1349   NULL, // label
1350   NULL, // operand
1351   NULL, // flow block
1352   NULL, // C source 
1353   3,    // num ops
1354   1,0,  // dest, bit instruction
1355   1,1,  // branch, skip
1356   0,    // literal operand
1357   1,    // RAM access bit
1358   0,    // fast call/return mode select bit
1359   0,    // second memory operand
1360   0,    // second literal operand
1361   POC_INFSNZ,
1362   PCC_REGISTER,   // inCond
1363   PCC_REGISTER   , // outCond
1364   PCI_MAGIC
1365 };
1366
1367 pCodeInstruction pic16_pciINCFSZW = {
1368   {PC_OPCODE, NULL, NULL, 0, NULL, 
1369    //   AnalyzeSKIP,
1370    genericDestruct,
1371    genericPrint},
1372   POC_INCFSZW,
1373   "INCFSZ",
1374   2,
1375   NULL, // from branch
1376   NULL, // to branch
1377   NULL, // label
1378   NULL, // operand
1379   NULL, // flow block
1380   NULL, // C source 
1381   3,    // num ops
1382   0,0,  // dest, bit instruction
1383   1,1,  // branch, skip
1384   0,    // literal operand
1385   1,    // RAM access bit
1386   0,    // fast call/return mode select bit
1387   0,    // second memory operand
1388   0,    // second literal operand
1389   POC_INFSNZW,
1390   PCC_REGISTER,   // inCond
1391   PCC_W          , // outCond
1392   PCI_MAGIC
1393 };
1394
1395 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1396   {PC_OPCODE, NULL, NULL, 0, NULL, 
1397    //   AnalyzeSKIP,
1398    genericDestruct,
1399    genericPrint},
1400   POC_INFSNZ,
1401   "INFSNZ",
1402   2,
1403   NULL, // from branch
1404   NULL, // to branch
1405   NULL, // label
1406   NULL, // operand
1407   NULL, // flow block
1408   NULL, // C source 
1409   3,    // num ops
1410   1,0,  // dest, bit instruction
1411   1,1,  // branch, skip
1412   0,    // literal operand
1413   1,    // RAM access bit
1414   0,    // fast call/return mode select bit
1415   0,    // second memory operand
1416   0,    // second literal operand
1417   POC_INCFSZ,
1418   PCC_REGISTER,   // inCond
1419   PCC_REGISTER   , // outCond
1420   PCI_MAGIC
1421 };
1422
1423 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1424   {PC_OPCODE, NULL, NULL, 0, NULL, 
1425    //   AnalyzeSKIP,
1426    genericDestruct,
1427    genericPrint},
1428   POC_INFSNZW,
1429   "INFSNZ",
1430   2,
1431   NULL, // from branch
1432   NULL, // to branch
1433   NULL, // label
1434   NULL, // operand
1435   NULL, // flow block
1436   NULL, // C source 
1437   3,    // num ops
1438   0,0,  // dest, bit instruction
1439   1,1,  // branch, skip
1440   0,    // literal operand
1441   1,    // RAM access bit
1442   0,    // fast call/return mode select bit
1443   0,    // second memory operand
1444   0,    // second literal operand
1445   POC_INCFSZW,
1446   PCC_REGISTER,   // inCond
1447   PCC_W          , // outCond
1448   PCI_MAGIC
1449 };
1450
1451 pCodeInstruction pic16_pciIORWF = {
1452   {PC_OPCODE, NULL, NULL, 0, NULL, 
1453    //   genericAnalyze,
1454    genericDestruct,
1455    genericPrint},
1456   POC_IORWF,
1457   "IORWF",
1458   2,
1459   NULL, // from branch
1460   NULL, // to branch
1461   NULL, // label
1462   NULL, // operand
1463   NULL, // flow block
1464   NULL, // C source 
1465   3,    // num ops
1466   1,0,  // dest, bit instruction
1467   0,0,  // branch, skip
1468   0,    // literal operand
1469   1,    // RAM access bit
1470   0,    // fast call/return mode select bit
1471   0,    // second memory operand
1472   0,    // second literal operand
1473   POC_NOP,
1474   (PCC_W | PCC_REGISTER),   // inCond
1475   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1476   PCI_MAGIC
1477 };
1478
1479 pCodeInstruction pic16_pciIORFW = {
1480   {PC_OPCODE, NULL, NULL, 0, NULL, 
1481    //   genericAnalyze,
1482    genericDestruct,
1483    genericPrint},
1484   POC_IORFW,
1485   "IORWF",
1486   2,
1487   NULL, // from branch
1488   NULL, // to branch
1489   NULL, // label
1490   NULL, // operand
1491   NULL, // flow block
1492   NULL, // C source 
1493   3,    // num ops
1494   0,0,  // dest, bit instruction
1495   0,0,  // branch, skip
1496   0,    // literal operand
1497   1,    // RAM access bit
1498   0,    // fast call/return mode select bit
1499   0,    // second memory operand
1500   0,    // second literal operand
1501   POC_NOP,
1502   (PCC_W | PCC_REGISTER),   // inCond
1503   (PCC_W | PCC_Z | PCC_N), // outCond
1504   PCI_MAGIC
1505 };
1506
1507 pCodeInstruction pic16_pciIORLW = {
1508   {PC_OPCODE, NULL, NULL, 0, NULL, 
1509    //   genericAnalyze,
1510    genericDestruct,
1511    genericPrint},
1512   POC_IORLW,
1513   "IORLW",
1514   2,
1515   NULL, // from branch
1516   NULL, // to branch
1517   NULL, // label
1518   NULL, // operand
1519   NULL, // flow block
1520   NULL, // C source 
1521   1,    // num ops
1522   0,0,  // dest, bit instruction
1523   0,0,  // branch, skip
1524   1,    // literal operand
1525   0,    // RAM access bit
1526   0,    // fast call/return mode select bit
1527   0,    // second memory operand
1528   0,    // second literal operand
1529   POC_NOP,
1530   (PCC_W | PCC_LITERAL),   // inCond
1531   (PCC_W | PCC_Z | PCC_N), // outCond
1532   PCI_MAGIC
1533 };
1534
1535 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1536   {PC_OPCODE, NULL, NULL, 0, NULL, 
1537    //   genericAnalyze,
1538    genericDestruct,
1539    genericPrint},
1540   POC_LFSR,
1541   "LFSR",
1542   4,
1543   NULL, // from branch
1544   NULL, // to branch
1545   NULL, // label
1546   NULL, // operand
1547   NULL, // flow block
1548   NULL, // C source 
1549   2,    // num ops
1550   0,0,  // dest, bit instruction
1551   0,0,  // branch, skip
1552   1,    // literal operand
1553   0,    // RAM access bit
1554   0,    // fast call/return mode select bit
1555   0,    // second memory operand
1556   1,    // second literal operand
1557   POC_NOP,
1558   PCC_LITERAL, // inCond
1559   PCC_NONE, // outCond
1560   PCI_MAGIC
1561 };
1562
1563 pCodeInstruction pic16_pciMOVF = {
1564   {PC_OPCODE, NULL, NULL, 0, NULL, 
1565    //   genericAnalyze,
1566    genericDestruct,
1567    genericPrint},
1568   POC_MOVF,
1569   "MOVF",
1570   2,
1571   NULL, // from branch
1572   NULL, // to branch
1573   NULL, // label
1574   NULL, // operand
1575   NULL, // flow block
1576   NULL, // C source 
1577   3,    // num ops
1578   1,0,  // dest, bit instruction
1579   0,0,  // branch, skip
1580   0,    // literal operand
1581   1,    // RAM access bit
1582   0,    // fast call/return mode select bit
1583   0,    // second memory operand
1584   0,    // second literal operand
1585   POC_NOP,
1586   PCC_REGISTER,   // inCond
1587   (PCC_Z | PCC_N), // outCond
1588   PCI_MAGIC
1589 };
1590
1591 pCodeInstruction pic16_pciMOVFW = {
1592   {PC_OPCODE, NULL, NULL, 0, NULL, 
1593    //   genericAnalyze,
1594    genericDestruct,
1595    genericPrint},
1596   POC_MOVFW,
1597   "MOVF",
1598   2,
1599   NULL, // from branch
1600   NULL, // to branch
1601   NULL, // label
1602   NULL, // operand
1603   NULL, // flow block
1604   NULL, // C source 
1605   3,    // num ops
1606   0,0,  // dest, bit instruction
1607   0,0,  // branch, skip
1608   0,    // literal operand
1609   1,    // RAM access bit
1610   0,    // fast call/return mode select bit
1611   0,    // second memory operand
1612   0,    // second literal operand
1613   POC_NOP,
1614   PCC_REGISTER,   // inCond
1615   (PCC_W | PCC_N | PCC_Z), // outCond
1616   PCI_MAGIC
1617 };
1618
1619 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1620   {PC_OPCODE, NULL, NULL, 0, NULL, 
1621    //   genericAnalyze,
1622    genericDestruct,
1623    genericPrint},
1624   POC_MOVFF,
1625   "MOVFF",
1626   4,
1627   NULL, // from branch
1628   NULL, // to branch
1629   NULL, // label
1630   NULL, // operand
1631   NULL, // flow block
1632   NULL, // C source 
1633   2,    // num ops
1634   0,0,  // dest, bit instruction
1635   0,0,  // branch, skip
1636   0,    // literal operand
1637   0,    // RAM access bit
1638   0,    // fast call/return mode select bit
1639   1,    // second memory operand
1640   0,    // second literal operand
1641   POC_NOP,
1642   PCC_REGISTER,   // inCond
1643   PCC_REGISTER2, // outCond
1644   PCI_MAGIC
1645 };
1646
1647 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1648   {PC_OPCODE, NULL, NULL, 0, NULL, 
1649    genericDestruct,
1650    genericPrint},
1651   POC_MOVLB,
1652   "MOVLB",
1653   2,
1654   NULL, // from branch
1655   NULL, // to branch
1656   NULL, // label
1657   NULL, // operand
1658   NULL, // flow block
1659   NULL, // C source 
1660   1,    // num ops
1661   0,0,  // dest, bit instruction
1662   0,0,  // branch, skip
1663   1,    // literal operand
1664   0,    // RAM access bit
1665   0,    // fast call/return mode select bit
1666   0,    // second memory operand
1667   0,    // second literal operand
1668   POC_NOP,
1669   (PCC_NONE | PCC_LITERAL),   // inCond
1670   PCC_REGISTER, // outCond - BSR
1671   PCI_MAGIC
1672 };
1673
1674 pCodeInstruction pic16_pciMOVLW = {
1675   {PC_OPCODE, NULL, NULL, 0, NULL, 
1676    genericDestruct,
1677    genericPrint},
1678   POC_MOVLW,
1679   "MOVLW",
1680   2,
1681   NULL, // from branch
1682   NULL, // to branch
1683   NULL, // label
1684   NULL, // operand
1685   NULL, // flow block
1686   NULL, // C source 
1687   1,    // num ops
1688   0,0,  // dest, bit instruction
1689   0,0,  // branch, skip
1690   1,    // literal operand
1691   0,    // RAM access bit
1692   0,    // fast call/return mode select bit
1693   0,    // second memory operand
1694   0,    // second literal operand
1695   POC_NOP,
1696   (PCC_NONE | PCC_LITERAL),   // inCond
1697   PCC_W, // outCond
1698   PCI_MAGIC
1699 };
1700
1701 pCodeInstruction pic16_pciMOVWF = {
1702   {PC_OPCODE, NULL, NULL, 0, NULL, 
1703    //   genericAnalyze,
1704    genericDestruct,
1705    genericPrint},
1706   POC_MOVWF,
1707   "MOVWF",
1708   2,
1709   NULL, // from branch
1710   NULL, // to branch
1711   NULL, // label
1712   NULL, // operand
1713   NULL, // flow block
1714   NULL, // C source 
1715   2,    // num ops
1716   0,0,  // dest, bit instruction
1717   0,0,  // branch, skip
1718   0,    // literal operand
1719   1,    // RAM access bit
1720   0,    // fast call/return mode select bit
1721   0,    // second memory operand
1722   0,    // second literal operand
1723   POC_NOP,
1724   PCC_W,   // inCond
1725   PCC_REGISTER, // outCond
1726   PCI_MAGIC
1727 };
1728
1729 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1730   {PC_OPCODE, NULL, NULL, 0, NULL, 
1731    genericDestruct,
1732    genericPrint},
1733   POC_MULLW,
1734   "MULLW",
1735   2,
1736   NULL, // from branch
1737   NULL, // to branch
1738   NULL, // label
1739   NULL, // operand
1740   NULL, // flow block
1741   NULL, // C source 
1742   1,    // num ops
1743   0,0,  // dest, bit instruction
1744   0,0,  // branch, skip
1745   1,    // literal operand
1746   0,    // RAM access bit
1747   0,    // fast call/return mode select bit
1748   0,    // second memory operand
1749   0,    // second literal operand
1750   POC_NOP,
1751   (PCC_W | PCC_LITERAL),   // inCond
1752   PCC_NONE, // outCond - PROD
1753   PCI_MAGIC
1754 };
1755
1756 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1757   {PC_OPCODE, NULL, NULL, 0, NULL, 
1758    genericDestruct,
1759    genericPrint},
1760   POC_MULWF,
1761   "MULWF",
1762   2,
1763   NULL, // from branch
1764   NULL, // to branch
1765   NULL, // label
1766   NULL, // operand
1767   NULL, // flow block
1768   NULL, // C source 
1769   2,    // num ops
1770   0,0,  // dest, bit instruction
1771   0,0,  // branch, skip
1772   0,    // literal operand
1773   1,    // RAM access bit
1774   0,    // fast call/return mode select bit
1775   0,    // second memory operand
1776   0,    // second literal operand
1777   POC_NOP,
1778   (PCC_W | PCC_REGISTER),   // inCond
1779   PCC_REGISTER, // outCond - PROD
1780   PCI_MAGIC
1781 };
1782
1783 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1784   {PC_OPCODE, NULL, NULL, 0, NULL, 
1785    genericDestruct,
1786    genericPrint},
1787   POC_NEGF,
1788   "NEGF",
1789   2,
1790   NULL, // from branch
1791   NULL, // to branch
1792   NULL, // label
1793   NULL, // operand
1794   NULL, // flow block
1795   NULL, // C source 
1796   2,    // num ops
1797   0,0,  // dest, bit instruction
1798   0,0,  // branch, skip
1799   0,    // literal operand
1800   1,    // RAM access bit
1801   0,    // fast call/return mode select bit
1802   0,    // second memory operand
1803   0,    // second literal operand
1804   POC_NOP,
1805   PCC_REGISTER, // inCond
1806   (PCC_REGISTER | PCC_STATUS), // outCond
1807   PCI_MAGIC
1808 };
1809
1810 pCodeInstruction pic16_pciNOP = {
1811   {PC_OPCODE, NULL, NULL, 0, NULL, 
1812    genericDestruct,
1813    genericPrint},
1814   POC_NOP,
1815   "NOP",
1816   2,
1817   NULL, // from branch
1818   NULL, // to branch
1819   NULL, // label
1820   NULL, // operand
1821   NULL, // flow block
1822   NULL, // C source 
1823   0,    // num ops
1824   0,0,  // dest, bit instruction
1825   0,0,  // branch, skip
1826   0,    // literal operand
1827   0,    // RAM access bit
1828   0,    // fast call/return mode select bit
1829   0,    // second memory operand
1830   0,    // second literal operand
1831   POC_NOP,
1832   PCC_NONE,   // inCond
1833   PCC_NONE, // outCond
1834   PCI_MAGIC
1835 };
1836
1837 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1838   {PC_OPCODE, NULL, NULL, 0, NULL, 
1839    genericDestruct,
1840    genericPrint},
1841   POC_POP,
1842   "POP",
1843   2,
1844   NULL, // from branch
1845   NULL, // to branch
1846   NULL, // label
1847   NULL, // operand
1848   NULL, // flow block
1849   NULL, // C source 
1850   0,    // num ops
1851   0,0,  // dest, bit instruction
1852   0,0,  // branch, skip
1853   0,    // literal operand
1854   0,    // RAM access bit
1855   0,    // fast call/return mode select bit
1856   0,    // second memory operand
1857   0,    // second literal operand
1858   POC_NOP,
1859   PCC_NONE,  // inCond
1860   PCC_NONE  , // outCond
1861   PCI_MAGIC
1862 };
1863
1864 pCodeInstruction pic16_pciPUSH = {
1865   {PC_OPCODE, NULL, NULL, 0, NULL, 
1866    genericDestruct,
1867    genericPrint},
1868   POC_PUSH,
1869   "PUSH",
1870   2,
1871   NULL, // from branch
1872   NULL, // to branch
1873   NULL, // label
1874   NULL, // operand
1875   NULL, // flow block
1876   NULL, // C source 
1877   0,    // num ops
1878   0,0,  // dest, bit instruction
1879   0,0,  // branch, skip
1880   0,    // literal operand
1881   0,    // RAM access bit
1882   0,    // fast call/return mode select bit
1883   0,    // second memory operand
1884   0,    // second literal operand
1885   POC_NOP,
1886   PCC_NONE,  // inCond
1887   PCC_NONE  , // outCond
1888   PCI_MAGIC
1889 };
1890
1891 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1892   {PC_OPCODE, NULL, NULL, 0, NULL, 
1893    genericDestruct,
1894    genericPrint},
1895   POC_RCALL,
1896   "RCALL",
1897   2,
1898   NULL, // from branch
1899   NULL, // to branch
1900   NULL, // label
1901   NULL, // operand
1902   NULL, // flow block
1903   NULL, // C source 
1904   1,    // num ops
1905   0,0,  // dest, bit instruction
1906   1,0,  // branch, skip
1907   0,    // literal operand
1908   0,    // RAM access bit
1909   0,    // fast call/return mode select bit
1910   0,    // second memory operand
1911   0,    // second literal operand
1912   POC_NOP,
1913   PCC_REL_ADDR,  // inCond
1914   PCC_NONE  , // outCond
1915   PCI_MAGIC
1916 };
1917
1918 pCodeInstruction pic16_pciRETFIE = {
1919   {PC_OPCODE, NULL, NULL, 0, NULL, 
1920    //   AnalyzeRETURN,
1921    genericDestruct,
1922    genericPrint},
1923   POC_RETFIE,
1924   "RETFIE",
1925   2,
1926   NULL, // from branch
1927   NULL, // to branch
1928   NULL, // label
1929   NULL, // operand
1930   NULL, // flow block
1931   NULL, // C source 
1932   1,    // num ops
1933   0,0,  // dest, bit instruction
1934   1,0,  // branch, skip
1935   0,    // literal operand
1936   0,    // RAM access bit
1937   1,    // fast call/return mode select bit
1938   0,    // second memory operand
1939   0,    // second literal operand
1940   POC_NOP,
1941   PCC_NONE,   // inCond
1942   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1943   PCI_MAGIC
1944 };
1945
1946 pCodeInstruction pic16_pciRETLW = {
1947   {PC_OPCODE, NULL, NULL, 0, NULL, 
1948    //   AnalyzeRETURN,
1949    genericDestruct,
1950    genericPrint},
1951   POC_RETLW,
1952   "RETLW",
1953   2,
1954   NULL, // from branch
1955   NULL, // to branch
1956   NULL, // label
1957   NULL, // operand
1958   NULL, // flow block
1959   NULL, // C source 
1960   1,    // num ops
1961   0,0,  // dest, bit instruction
1962   1,0,  // branch, skip
1963   1,    // literal operand
1964   0,    // RAM access bit
1965   0,    // fast call/return mode select bit
1966   0,    // second memory operand
1967   0,    // second literal operand
1968   POC_NOP,
1969   PCC_LITERAL,   // inCond
1970   PCC_W, // outCond
1971   PCI_MAGIC
1972 };
1973
1974 pCodeInstruction pic16_pciRETURN = {
1975   {PC_OPCODE, NULL, NULL, 0, NULL, 
1976    //   AnalyzeRETURN,
1977    genericDestruct,
1978    genericPrint},
1979   POC_RETURN,
1980   "RETURN",
1981   2,
1982   NULL, // from branch
1983   NULL, // to branch
1984   NULL, // label
1985   NULL, // operand
1986   NULL, // flow block
1987   NULL, // C source 
1988   1,    // num ops
1989   0,0,  // dest, bit instruction
1990   1,0,  // branch, skip
1991   0,    // literal operand
1992   0,    // RAM access bit
1993   1,    // fast call/return mode select bit
1994   0,    // second memory operand
1995   0,    // second literal operand
1996   POC_NOP,
1997   PCC_NONE,   // inCond
1998   PCC_NONE, // outCond
1999   PCI_MAGIC
2000 };
2001 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2002   {PC_OPCODE, NULL, NULL, 0, NULL, 
2003    //   genericAnalyze,
2004    genericDestruct,
2005    genericPrint},
2006   POC_RLCF,
2007   "RLCF",
2008   2,
2009   NULL, // from branch
2010   NULL, // to branch
2011   NULL, // label
2012   NULL, // operand
2013   NULL, // flow block
2014   NULL, // C source 
2015   3,    // num ops
2016   1,0,  // dest, bit instruction
2017   0,0,  // branch, skip
2018   0,    // literal operand
2019   1,    // RAM access bit
2020   0,    // fast call/return mode select bit
2021   0,    // second memory operand
2022   0,    // second literal operand
2023   POC_NOP,
2024   (PCC_C | PCC_REGISTER),   // inCond
2025   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2026   PCI_MAGIC
2027 };
2028
2029 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2030   {PC_OPCODE, NULL, NULL, 0, NULL, 
2031    //   genericAnalyze,
2032    genericDestruct,
2033    genericPrint},
2034   POC_RLCFW,
2035   "RLCF",
2036   2,
2037   NULL, // from branch
2038   NULL, // to branch
2039   NULL, // label
2040   NULL, // operand
2041   NULL, // flow block
2042   NULL, // C source 
2043   3,    // num ops
2044   0,0,  // dest, bit instruction
2045   0,0,  // branch, skip
2046   0,    // literal operand
2047   1,    // RAM access bit
2048   0,    // fast call/return mode select bit
2049   0,    // second memory operand
2050   0,    // second literal operand
2051   POC_NOP,
2052   (PCC_C | PCC_REGISTER),   // inCond
2053   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2054   PCI_MAGIC
2055 };
2056
2057 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2058   {PC_OPCODE, NULL, NULL, 0, NULL, 
2059    //   genericAnalyze,
2060    genericDestruct,
2061    genericPrint},
2062   POC_RLNCF,
2063   "RLNCF",
2064   2,
2065   NULL, // from branch
2066   NULL, // to branch
2067   NULL, // label
2068   NULL, // operand
2069   NULL, // flow block
2070   NULL, // C source 
2071   3,    // num ops
2072   1,0,  // dest, bit instruction
2073   0,0,  // branch, skip
2074   0,    // literal operand
2075   1,    // RAM access bit
2076   0,    // fast call/return mode select bit
2077   0,    // second memory operand
2078   0,    // second literal operand
2079   POC_NOP,
2080   PCC_REGISTER,   // inCond
2081   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2082   PCI_MAGIC
2083 };
2084 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2085   {PC_OPCODE, NULL, NULL, 0, NULL, 
2086    //   genericAnalyze,
2087    genericDestruct,
2088    genericPrint},
2089   POC_RLNCFW,
2090   "RLNCF",
2091   2,
2092   NULL, // from branch
2093   NULL, // to branch
2094   NULL, // label
2095   NULL, // operand
2096   NULL, // flow block
2097   NULL, // C source 
2098   3,    // num ops
2099   0,0,  // dest, bit instruction
2100   0,0,  // branch, skip
2101   0,    // literal operand
2102   1,    // RAM access bit
2103   0,    // fast call/return mode select bit
2104   0,    // second memory operand
2105   0,    // second literal operand
2106   POC_NOP,
2107   PCC_REGISTER,   // inCond
2108   (PCC_W | PCC_Z | PCC_N), // outCond
2109   PCI_MAGIC
2110 };
2111 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2112   {PC_OPCODE, NULL, NULL, 0, NULL, 
2113    //   genericAnalyze,
2114    genericDestruct,
2115    genericPrint},
2116   POC_RRCF,
2117   "RRCF",
2118   2,
2119   NULL, // from branch
2120   NULL, // to branch
2121   NULL, // label
2122   NULL, // operand
2123   NULL, // flow block
2124   NULL, // C source 
2125   3,    // num ops
2126   1,0,  // dest, bit instruction
2127   0,0,  // branch, skip
2128   0,    // literal operand
2129   1,    // RAM access bit
2130   0,    // fast call/return mode select bit
2131   0,    // second memory operand
2132   0,    // second literal operand
2133   POC_NOP,
2134   (PCC_C | PCC_REGISTER),   // inCond
2135   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2136   PCI_MAGIC
2137 };
2138 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2139   {PC_OPCODE, NULL, NULL, 0, NULL, 
2140    //   genericAnalyze,
2141    genericDestruct,
2142    genericPrint},
2143   POC_RRCFW,
2144   "RRCF",
2145   2,
2146   NULL, // from branch
2147   NULL, // to branch
2148   NULL, // label
2149   NULL, // operand
2150   NULL, // flow block
2151   NULL, // C source 
2152   3,    // num ops
2153   0,0,  // dest, bit instruction
2154   0,0,  // branch, skip
2155   0,    // literal operand
2156   1,    // RAM access bit
2157   0,    // fast call/return mode select bit
2158   0,    // second memory operand
2159   0,    // second literal operand
2160   POC_NOP,
2161   (PCC_C | PCC_REGISTER),   // inCond
2162   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2163   PCI_MAGIC
2164 };
2165 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2166   {PC_OPCODE, NULL, NULL, 0, NULL, 
2167    //   genericAnalyze,
2168    genericDestruct,
2169    genericPrint},
2170   POC_RRNCF,
2171   "RRNCF",
2172   2,
2173   NULL, // from branch
2174   NULL, // to branch
2175   NULL, // label
2176   NULL, // operand
2177   NULL, // flow block
2178   NULL, // C source 
2179   3,    // num ops
2180   1,0,  // dest, bit instruction
2181   0,0,  // branch, skip
2182   0,    // literal operand
2183   1,    // RAM access bit
2184   0,    // fast call/return mode select bit
2185   0,    // second memory operand
2186   0,    // second literal operand
2187   POC_NOP,
2188   PCC_REGISTER,   // inCond
2189   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2190   PCI_MAGIC
2191 };
2192
2193 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2194   {PC_OPCODE, NULL, NULL, 0, NULL, 
2195    //   genericAnalyze,
2196    genericDestruct,
2197    genericPrint},
2198   POC_RRNCFW,
2199   "RRNCF",
2200   2,
2201   NULL, // from branch
2202   NULL, // to branch
2203   NULL, // label
2204   NULL, // operand
2205   NULL, // flow block
2206   NULL, // C source 
2207   3,    // num ops
2208   0,0,  // dest, bit instruction
2209   0,0,  // branch, skip
2210   0,    // literal operand
2211   1,    // RAM access bit
2212   0,    // fast call/return mode select bit
2213   0,    // second memory operand
2214   0,    // second literal operand
2215   POC_NOP,
2216   PCC_REGISTER,   // inCond
2217   (PCC_W | PCC_Z | PCC_N), // outCond
2218   PCI_MAGIC
2219 };
2220
2221 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2222   {PC_OPCODE, NULL, NULL, 0, NULL, 
2223    //   genericAnalyze,
2224    genericDestruct,
2225    genericPrint},
2226   POC_SETF,
2227   "SETF",
2228   2,
2229   NULL, // from branch
2230   NULL, // to branch
2231   NULL, // label
2232   NULL, // operand
2233   NULL, // flow block
2234   NULL, // C source 
2235   2,    // num ops
2236   0,0,  // dest, bit instruction
2237   0,0,  // branch, skip
2238   0,    // literal operand
2239   1,    // RAM access bit
2240   0,    // fast call/return mode select bit
2241   0,    // second memory operand
2242   0,    // second literal operand
2243   POC_NOP,
2244   PCC_NONE,  // inCond
2245   PCC_REGISTER  , // outCond
2246   PCI_MAGIC
2247 };
2248
2249 pCodeInstruction pic16_pciSUBLW = {
2250   {PC_OPCODE, NULL, NULL, 0, NULL, 
2251    //   genericAnalyze,
2252    genericDestruct,
2253    genericPrint},
2254   POC_SUBLW,
2255   "SUBLW",
2256   2,
2257   NULL, // from branch
2258   NULL, // to branch
2259   NULL, // label
2260   NULL, // operand
2261   NULL, // flow block
2262   NULL, // C source 
2263   1,    // num ops
2264   0,0,  // dest, bit instruction
2265   0,0,  // branch, skip
2266   1,    // literal operand
2267   0,    // RAM access bit
2268   0,    // fast call/return mode select bit
2269   0,    // second memory operand
2270   0,    // second literal operand
2271   POC_NOP,
2272   (PCC_W | PCC_LITERAL),   // inCond
2273   (PCC_W | PCC_STATUS), // outCond
2274   PCI_MAGIC
2275 };
2276
2277 pCodeInstruction pic16_pciSUBFWB = {
2278   {PC_OPCODE, NULL, NULL, 0, NULL, 
2279    //   genericAnalyze,
2280    genericDestruct,
2281    genericPrint},
2282   POC_SUBFWB,
2283   "SUBFWB",
2284   2,
2285   NULL, // from branch
2286   NULL, // to branch
2287   NULL, // label
2288   NULL, // operand
2289   NULL, // flow block
2290   NULL, // C source 
2291   3,    // num ops
2292   1,0,  // dest, bit instruction
2293   0,0,  // branch, skip
2294   0,    // literal operand
2295   1,    // RAM access bit
2296   0,    // fast call/return mode select bit
2297   0,    // second memory operand
2298   0,    // second literal operand
2299   POC_NOP,
2300   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2301   (PCC_W | PCC_STATUS), // outCond
2302   PCI_MAGIC
2303 };
2304
2305 pCodeInstruction pic16_pciSUBWF = {
2306   {PC_OPCODE, NULL, NULL, 0, NULL, 
2307    //   genericAnalyze,
2308    genericDestruct,
2309    genericPrint},
2310   POC_SUBWF,
2311   "SUBWF",
2312   2,
2313   NULL, // from branch
2314   NULL, // to branch
2315   NULL, // label
2316   NULL, // operand
2317   NULL, // flow block
2318   NULL, // C source 
2319   3,    // num ops
2320   1,0,  // dest, bit instruction
2321   0,0,  // branch, skip
2322   0,    // literal operand
2323   1,    // RAM access bit
2324   0,    // fast call/return mode select bit
2325   0,    // second memory operand
2326   0,    // second literal operand
2327   POC_NOP,
2328   (PCC_W | PCC_REGISTER),   // inCond
2329   (PCC_REGISTER | PCC_STATUS), // outCond
2330   PCI_MAGIC
2331 };
2332
2333 pCodeInstruction pic16_pciSUBFW = {
2334   {PC_OPCODE, NULL, NULL, 0, NULL, 
2335    //   genericAnalyze,
2336    genericDestruct,
2337    genericPrint},
2338   POC_SUBFW,
2339   "SUBWF",
2340   2,
2341   NULL, // from branch
2342   NULL, // to branch
2343   NULL, // label
2344   NULL, // operand
2345   NULL, // flow block
2346   NULL, // C source 
2347   3,    // num ops
2348   0,0,  // dest, bit instruction
2349   0,0,  // branch, skip
2350   0,    // literal operand
2351   1,    // RAM access bit
2352   0,    // fast call/return mode select bit
2353   0,    // second memory operand
2354   0,    // second literal operand
2355   POC_NOP,
2356   (PCC_W | PCC_REGISTER),   // inCond
2357   (PCC_W | PCC_STATUS), // outCond
2358   PCI_MAGIC
2359 };
2360
2361 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2362   {PC_OPCODE, NULL, NULL, 0, NULL, 
2363    //   genericAnalyze,
2364    genericDestruct,
2365    genericPrint},
2366   POC_SUBFWB_D1,
2367   "SUBFWB",
2368   2,
2369   NULL, // from branch
2370   NULL, // to branch
2371   NULL, // label
2372   NULL, // operand
2373   NULL, // flow block
2374   NULL, // C source 
2375   3,    // num ops
2376   1,0,  // dest, bit instruction
2377   0,0,  // branch, skip
2378   0,    // literal operand
2379   1,    // RAM access bit
2380   0,    // fast call/return mode select bit
2381   0,    // second memory operand
2382   0,    // second literal operand
2383   POC_NOP,
2384   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2385   (PCC_REGISTER | PCC_STATUS), // outCond
2386   PCI_MAGIC
2387 };
2388
2389 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2390   {PC_OPCODE, NULL, NULL, 0, NULL, 
2391    //   genericAnalyze,
2392    genericDestruct,
2393    genericPrint},
2394   POC_SUBFWB_D0,
2395   "SUBFWB",
2396   2,
2397   NULL, // from branch
2398   NULL, // to branch
2399   NULL, // label
2400   NULL, // operand
2401   NULL, // flow block
2402   NULL, // C source 
2403   3,    // num ops
2404   0,0,  // dest, bit instruction
2405   0,0,  // branch, skip
2406   0,    // literal operand
2407   1,    // RAM access bit
2408   0,    // fast call/return mode select bit
2409   0,    // second memory operand
2410   0,    // second literal operand
2411   POC_NOP,
2412   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2413   (PCC_W | PCC_STATUS), // outCond
2414   PCI_MAGIC
2415 };
2416
2417 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2418   {PC_OPCODE, NULL, NULL, 0, NULL, 
2419    //   genericAnalyze,
2420    genericDestruct,
2421    genericPrint},
2422   POC_SUBWFB_D1,
2423   "SUBWFB",
2424   2,
2425   NULL, // from branch
2426   NULL, // to branch
2427   NULL, // label
2428   NULL, // operand
2429   NULL, // flow block
2430   NULL, // C source 
2431   3,    // num ops
2432   1,0,  // dest, bit instruction
2433   0,0,  // branch, skip
2434   0,    // literal operand
2435   1,    // RAM access bit
2436   0,    // fast call/return mode select bit
2437   0,    // second memory operand
2438   0,    // second literal operand
2439   POC_NOP,
2440   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2441   (PCC_REGISTER | PCC_STATUS), // outCond
2442   PCI_MAGIC
2443 };
2444
2445 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2446   {PC_OPCODE, NULL, NULL, 0, NULL, 
2447    //   genericAnalyze,
2448    genericDestruct,
2449    genericPrint},
2450   POC_SUBWFB_D0,
2451   "SUBWFB",
2452   2,
2453   NULL, // from branch
2454   NULL, // to branch
2455   NULL, // label
2456   NULL, // operand
2457   NULL, // flow block
2458   NULL, // C source 
2459   3,    // num ops
2460   0,0,  // dest, bit instruction
2461   0,0,  // branch, skip
2462   0,    // literal operand
2463   1,    // RAM access bit
2464   0,    // fast call/return mode select bit
2465   0,    // second memory operand
2466   0,    // second literal operand
2467   POC_NOP,
2468   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2469   (PCC_W | PCC_STATUS), // outCond
2470   PCI_MAGIC
2471 };
2472
2473 pCodeInstruction pic16_pciSWAPF = {
2474   {PC_OPCODE, NULL, NULL, 0, NULL, 
2475    //   genericAnalyze,
2476    genericDestruct,
2477    genericPrint},
2478   POC_SWAPF,
2479   "SWAPF",
2480   2,
2481   NULL, // from branch
2482   NULL, // to branch
2483   NULL, // label
2484   NULL, // operand
2485   NULL, // flow block
2486   NULL, // C source 
2487   3,    // num ops
2488   1,0,  // dest, bit instruction
2489   0,0,  // branch, skip
2490   0,    // literal operand
2491   1,    // RAM access bit
2492   0,    // fast call/return mode select bit
2493   0,    // second memory operand
2494   0,    // second literal operand
2495   POC_NOP,
2496   (PCC_REGISTER),   // inCond
2497   (PCC_REGISTER), // outCond
2498   PCI_MAGIC
2499 };
2500
2501 pCodeInstruction pic16_pciSWAPFW = {
2502   {PC_OPCODE, NULL, NULL, 0, NULL, 
2503    //   genericAnalyze,
2504    genericDestruct,
2505    genericPrint},
2506   POC_SWAPFW,
2507   "SWAPF",
2508   2,
2509   NULL, // from branch
2510   NULL, // to branch
2511   NULL, // label
2512   NULL, // operand
2513   NULL, // flow block
2514   NULL, // C source 
2515   3,    // num ops
2516   0,0,  // dest, bit instruction
2517   0,0,  // branch, skip
2518   0,    // literal operand
2519   1,    // RAM access bit
2520   0,    // fast call/return mode select bit
2521   0,    // second memory operand
2522   0,    // second literal operand
2523   POC_NOP,
2524   (PCC_REGISTER),   // inCond
2525   (PCC_W), // outCond
2526   PCI_MAGIC
2527 };
2528
2529 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2530   {PC_OPCODE, NULL, NULL, 0, NULL, 
2531    genericDestruct,
2532    genericPrint},
2533   POC_TBLRD,
2534   "TBLRD*",
2535   2,
2536   NULL, // from branch
2537   NULL, // to branch
2538   NULL, // label
2539   NULL, // operand
2540   NULL, // flow block
2541   NULL, // C source 
2542   0,    // num ops
2543   0,0,  // dest, bit instruction
2544   0,0,  // branch, skip
2545   0,    // literal operand
2546   0,    // RAM access bit
2547   0,    // fast call/return mode select bit
2548   0,    // second memory operand
2549   0,    // second literal operand
2550   POC_NOP,
2551   PCC_NONE,  // inCond
2552   PCC_NONE  , // outCond
2553   PCI_MAGIC
2554 };
2555
2556 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2557   {PC_OPCODE, NULL, NULL, 0, NULL, 
2558    genericDestruct,
2559    genericPrint},
2560   POC_TBLRD_POSTINC,
2561   "TBLRD*+",
2562   2,
2563   NULL, // from branch
2564   NULL, // to branch
2565   NULL, // label
2566   NULL, // operand
2567   NULL, // flow block
2568   NULL, // C source 
2569   0,    // num ops
2570   0,0,  // dest, bit instruction
2571   0,0,  // branch, skip
2572   0,    // literal operand
2573   0,    // RAM access bit
2574   0,    // fast call/return mode select bit
2575   0,    // second memory operand
2576   0,    // second literal operand
2577   POC_NOP,
2578   PCC_NONE,  // inCond
2579   PCC_NONE  , // outCond
2580   PCI_MAGIC
2581 };
2582
2583 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2584   {PC_OPCODE, NULL, NULL, 0, NULL, 
2585    genericDestruct,
2586    genericPrint},
2587   POC_TBLRD_POSTDEC,
2588   "TBLRD*-",
2589   2,
2590   NULL, // from branch
2591   NULL, // to branch
2592   NULL, // label
2593   NULL, // operand
2594   NULL, // flow block
2595   NULL, // C source 
2596   0,    // num ops
2597   0,0,  // dest, bit instruction
2598   0,0,  // branch, skip
2599   0,    // literal operand
2600   0,    // RAM access bit
2601   0,    // fast call/return mode select bit
2602   0,    // second memory operand
2603   0,    // second literal operand
2604   POC_NOP,
2605   PCC_NONE,  // inCond
2606   PCC_NONE  , // outCond
2607   PCI_MAGIC
2608 };
2609
2610 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2611   {PC_OPCODE, NULL, NULL, 0, NULL, 
2612    genericDestruct,
2613    genericPrint},
2614   POC_TBLRD_PREINC,
2615   "TBLRD+*",
2616   2,
2617   NULL, // from branch
2618   NULL, // to branch
2619   NULL, // label
2620   NULL, // operand
2621   NULL, // flow block
2622   NULL, // C source 
2623   0,    // num ops
2624   0,0,  // dest, bit instruction
2625   0,0,  // branch, skip
2626   0,    // literal operand
2627   0,    // RAM access bit
2628   0,    // fast call/return mode select bit
2629   0,    // second memory operand
2630   0,    // second literal operand
2631   POC_NOP,
2632   PCC_NONE,  // inCond
2633   PCC_NONE  , // outCond
2634   PCI_MAGIC
2635 };
2636
2637 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2638   {PC_OPCODE, NULL, NULL, 0, NULL, 
2639    genericDestruct,
2640    genericPrint},
2641   POC_TBLWT,
2642   "TBLWT*",
2643   2,
2644   NULL, // from branch
2645   NULL, // to branch
2646   NULL, // label
2647   NULL, // operand
2648   NULL, // flow block
2649   NULL, // C source 
2650   0,    // num ops
2651   0,0,  // dest, bit instruction
2652   0,0,  // branch, skip
2653   0,    // literal operand
2654   0,    // RAM access bit
2655   0,    // fast call/return mode select bit
2656   0,    // second memory operand
2657   0,    // second literal operand
2658   POC_NOP,
2659   PCC_NONE,  // inCond
2660   PCC_NONE  , // outCond
2661   PCI_MAGIC
2662 };
2663
2664 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2665   {PC_OPCODE, NULL, NULL, 0, NULL, 
2666    genericDestruct,
2667    genericPrint},
2668   POC_TBLWT_POSTINC,
2669   "TBLWT*+",
2670   2,
2671   NULL, // from branch
2672   NULL, // to branch
2673   NULL, // label
2674   NULL, // operand
2675   NULL, // flow block
2676   NULL, // C source 
2677   0,    // num ops
2678   0,0,  // dest, bit instruction
2679   0,0,  // branch, skip
2680   0,    // literal operand
2681   0,    // RAM access bit
2682   0,    // fast call/return mode select bit
2683   0,    // second memory operand
2684   0,    // second literal operand
2685   POC_NOP,
2686   PCC_NONE,  // inCond
2687   PCC_NONE  , // outCond
2688   PCI_MAGIC
2689 };
2690
2691 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2692   {PC_OPCODE, NULL, NULL, 0, NULL, 
2693    genericDestruct,
2694    genericPrint},
2695   POC_TBLWT_POSTDEC,
2696   "TBLWT*-",
2697   2,
2698   NULL, // from branch
2699   NULL, // to branch
2700   NULL, // label
2701   NULL, // operand
2702   NULL, // flow block
2703   NULL, // C source 
2704   0,    // num ops
2705   0,0,  // dest, bit instruction
2706   0,0,  // branch, skip
2707   0,    // literal operand
2708   0,    // RAM access bit
2709   0,    // fast call/return mode select bit
2710   0,    // second memory operand
2711   0,    // second literal operand
2712   POC_NOP,
2713   PCC_NONE,  // inCond
2714   PCC_NONE  , // outCond
2715   PCI_MAGIC
2716 };
2717
2718 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2719   {PC_OPCODE, NULL, NULL, 0, NULL, 
2720    genericDestruct,
2721    genericPrint},
2722   POC_TBLWT_PREINC,
2723   "TBLWT+*",
2724   2,
2725   NULL, // from branch
2726   NULL, // to branch
2727   NULL, // label
2728   NULL, // operand
2729   NULL, // flow block
2730   NULL, // C source 
2731   0,    // num ops
2732   0,0,  // dest, bit instruction
2733   0,0,  // branch, skip
2734   0,    // literal operand
2735   0,    // RAM access bit
2736   0,    // fast call/return mode select bit
2737   0,    // second memory operand
2738   0,    // second literal operand
2739   POC_NOP,
2740   PCC_NONE,  // inCond
2741   PCC_NONE  , // outCond
2742   PCI_MAGIC
2743 };
2744
2745 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2746   {PC_OPCODE, NULL, NULL, 0, NULL, 
2747    //   genericAnalyze,
2748    genericDestruct,
2749    genericPrint},
2750   POC_TSTFSZ,
2751   "TSTFSZ",
2752   2,
2753   NULL, // from branch
2754   NULL, // to branch
2755   NULL, // label
2756   NULL, // operand
2757   NULL, // flow block
2758   NULL, // C source 
2759   2,    // num ops
2760   0,0,  // dest, bit instruction
2761   1,1,  // branch, skip
2762   0,    // literal operand
2763   1,    // RAM access bit
2764   0,    // fast call/return mode select bit
2765   0,    // second memory operand
2766   0,    // second literal operand
2767   POC_NOP,
2768   PCC_REGISTER,   // inCond
2769   PCC_NONE, // outCond
2770   PCI_MAGIC
2771 };
2772
2773 pCodeInstruction pic16_pciXORWF = {
2774   {PC_OPCODE, NULL, NULL, 0, NULL, 
2775    //   genericAnalyze,
2776    genericDestruct,
2777    genericPrint},
2778   POC_XORWF,
2779   "XORWF",
2780   2,
2781   NULL, // from branch
2782   NULL, // to branch
2783   NULL, // label
2784   NULL, // operand
2785   NULL, // flow block
2786   NULL, // C source 
2787   3,    // num ops
2788   1,0,  // dest, bit instruction
2789   0,0,  // branch, skip
2790   0,    // literal operand
2791   1,    // RAM access bit
2792   0,    // fast call/return mode select bit
2793   0,    // second memory operand
2794   0,    // second literal operand
2795   POC_NOP,
2796   (PCC_W | PCC_REGISTER),   // inCond
2797   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2798   PCI_MAGIC
2799 };
2800
2801 pCodeInstruction pic16_pciXORFW = {
2802   {PC_OPCODE, NULL, NULL, 0, NULL, 
2803    //   genericAnalyze,
2804    genericDestruct,
2805    genericPrint},
2806   POC_XORFW,
2807   "XORWF",
2808   2,
2809   NULL, // from branch
2810   NULL, // to branch
2811   NULL, // label
2812   NULL, // operand
2813   NULL, // flow block
2814   NULL, // C source 
2815   3,    // num ops
2816   0,0,  // dest, bit instruction
2817   0,0,  // branch, skip
2818   0,    // literal operand
2819   1,    // RAM access bit
2820   0,    // fast call/return mode select bit
2821   0,    // second memory operand
2822   0,    // second literal operand
2823   POC_NOP,
2824   (PCC_W | PCC_REGISTER),   // inCond
2825   (PCC_W | PCC_Z | PCC_N), // outCond
2826   PCI_MAGIC
2827 };
2828
2829 pCodeInstruction pic16_pciXORLW = {
2830   {PC_OPCODE, NULL, NULL, 0, NULL, 
2831    //   genericAnalyze,
2832    genericDestruct,
2833    genericPrint},
2834   POC_XORLW,
2835   "XORLW",
2836   2,
2837   NULL, // from branch
2838   NULL, // to branch
2839   NULL, // label
2840   NULL, // operand
2841   NULL, // flow block
2842   NULL, // C source 
2843   1,    // num ops
2844   0,0,  // dest, bit instruction
2845   0,0,  // branch, skip
2846   1,    // literal operand
2847   1,    // RAM access bit
2848   0,    // fast call/return mode select bit
2849   0,    // second memory operand
2850   0,    // second literal operand
2851   POC_NOP,
2852   (PCC_W | PCC_LITERAL),   // inCond
2853   (PCC_W | PCC_Z | PCC_N), // outCond
2854   PCI_MAGIC
2855 };
2856
2857
2858 pCodeInstruction pic16_pciBANKSEL = {
2859   {PC_OPCODE, NULL, NULL, 0, NULL, 
2860    genericDestruct,
2861    genericPrint},
2862   POC_BANKSEL,
2863   "BANKSEL",
2864   2,
2865   NULL, // from branch
2866   NULL, // to branch
2867   NULL, // label
2868   NULL, // operand
2869   NULL, // flow block
2870   NULL, // C source 
2871   0,    // num ops
2872   0,0,  // dest, bit instruction
2873   0,0,  // branch, skip
2874   0,    // literal operand
2875   0,    // RAM access bit
2876   0,    // fast call/return mode select bit
2877   0,    // second memory operand
2878   0,    // second literal operand
2879   POC_NOP,
2880   PCC_NONE,   // inCond
2881   PCC_NONE, // outCond
2882   PCI_MAGIC
2883 };
2884
2885
2886 #define MAX_PIC16MNEMONICS 100
2887 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2888
2889 //#define USE_VSNPRINTF
2890 #if OPT_DISABLE_PIC
2891
2892 #ifdef USE_VSNPRINTF
2893   // Alas, vsnprintf is not ANSI standard, and does not exist
2894   // on Solaris (and probably other non-Gnu flavored Unixes).
2895
2896 /*-----------------------------------------------------------------*/
2897 /* SAFE_snprintf - like snprintf except the string pointer is      */
2898 /*                 after the string has been printed to. This is   */
2899 /*                 useful for printing to string as though if it   */
2900 /*                 were a stream.                                  */
2901 /*-----------------------------------------------------------------*/
2902 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2903 {
2904   va_list val;
2905   int len;
2906
2907   if(!str || !*str)
2908     return;
2909
2910   va_start(val, format);
2911
2912   vsnprintf(*str, *size, format, val);
2913
2914   va_end (val);
2915
2916   len = strlen(*str);
2917   if(len > *size) {
2918     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2919     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2920   }
2921
2922   *str += len;
2923   *size -= len;
2924
2925 }
2926
2927 #else
2928 // This version is *not* safe, despite the name.
2929
2930 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2931 {
2932   va_list val;
2933   int len;
2934   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2935
2936   if(!str || !*str)
2937     return;
2938
2939   va_start(val, format);
2940
2941   vsprintf(buffer, format, val);
2942   va_end (val);
2943
2944   len = strlen(buffer);
2945   if(len > *size) {
2946     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2947     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2948   }
2949
2950   strcpy(*str, buffer);
2951   *str += len;
2952   *size -= len;
2953
2954 }
2955
2956 #endif    //  USE_VSNPRINTF
2957 #endif
2958
2959 extern set *externs;
2960 extern  void pic16_initStack(int base_address, int size);
2961 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2962 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2963 extern void pic16_init_pic(char *);
2964
2965 void  pic16_pCodeInitRegisters(void)
2966 {
2967   static int initialized=0;
2968
2969         if(initialized)
2970                 return;
2971         
2972         initialized = 1;
2973
2974 //      pic16_initStack(0xfff, 8);
2975         pic16_init_pic(port->processor);
2976
2977         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2978         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2979         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2980         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2981         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2982         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2983         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2984
2985         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2986         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2987         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2988
2989         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2990         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2991         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2992         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2993
2994         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2995         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2996         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2997         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2998         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2999         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3000
3001         pic16_stackpnt_lo = &pic16_pc_fsr1l;
3002         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3003         pic16_stack_postdec = &pic16_pc_postdec1;
3004         pic16_stack_postinc = &pic16_pc_postinc1;
3005         pic16_stack_preinc = &pic16_pc_preinc1;
3006         pic16_stack_plusw = &pic16_pc_plusw1;
3007         
3008         pic16_framepnt_lo = &pic16_pc_fsr2l;
3009         pic16_framepnt_hi = &pic16_pc_fsr2h;
3010         pic16_frame_postdec = &pic16_pc_postdec2;
3011         pic16_frame_postinc = &pic16_pc_postinc2;
3012         pic16_frame_preinc = &pic16_pc_preinc2;
3013         pic16_frame_plusw = &pic16_pc_plusw2;
3014
3015         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3016         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3017         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3018         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3019         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3020         
3021         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3022         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3023         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3024         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3025         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3026
3027         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3028         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3029         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3030         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3031         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3032         
3033         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3034         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3035
3036
3037         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3038         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3039         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3040         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3041
3042         
3043         pic16_pc_status.rIdx = IDX_STATUS;
3044         pic16_pc_intcon.rIdx = IDX_INTCON;
3045         pic16_pc_pcl.rIdx = IDX_PCL;
3046         pic16_pc_pclath.rIdx = IDX_PCLATH;
3047         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3048         pic16_pc_wreg.rIdx = IDX_WREG;
3049         pic16_pc_bsr.rIdx = IDX_BSR;
3050
3051         pic16_pc_tosl.rIdx = IDX_TOSL;
3052         pic16_pc_tosh.rIdx = IDX_TOSH;
3053         pic16_pc_tosu.rIdx = IDX_TOSU;
3054
3055         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3056         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3057         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3058         pic16_pc_tablat.rIdx = IDX_TABLAT;
3059
3060         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3061         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3062         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3063         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3064         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3065         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3066         pic16_pc_indf0.rIdx = IDX_INDF0;
3067         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3068         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3069         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3070         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3071         pic16_pc_indf1.rIdx = IDX_INDF1;
3072         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3073         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3074         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3075         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3076         pic16_pc_indf2.rIdx = IDX_INDF2;
3077         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3078         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3079         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3080         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3081         pic16_pc_prodl.rIdx = IDX_PRODL;
3082         pic16_pc_prodh.rIdx = IDX_PRODH;
3083         
3084         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3085         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3086         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3087         
3088         pic16_pc_kzero.rIdx = IDX_KZ;
3089         pic16_pc_wsave.rIdx = IDX_WSAVE;
3090         pic16_pc_ssave.rIdx = IDX_SSAVE;
3091
3092         pic16_pc_eecon1.rIdx = IDX_EECON1;
3093         pic16_pc_eecon2.rIdx = IDX_EECON2;
3094         pic16_pc_eedata.rIdx = IDX_EEDATA;
3095         pic16_pc_eeadr.rIdx = IDX_EEADR;
3096         
3097         
3098         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3099         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3100
3101         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3102         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3103
3104         /* probably should put this in a separate initialization routine */
3105         pb_dead_pcodes = newpBlock();
3106
3107 }
3108
3109 #if OPT_DISABLE_PIC
3110 /*-----------------------------------------------------------------*/
3111 /*  mnem2key - convert a pic mnemonic into a hash key              */
3112 /*   (BTW - this spreads the mnemonics quite well)                 */
3113 /*                                                                 */
3114 /*-----------------------------------------------------------------*/
3115
3116 int mnem2key(unsigned char const *mnem)
3117 {
3118   int key = 0;
3119
3120   if(!mnem)
3121     return 0;
3122
3123   while(*mnem) {
3124
3125     key += toupper(*mnem++) +1;
3126
3127   }
3128
3129   return (key & 0x1f);
3130
3131 }
3132 #endif
3133
3134 void pic16initMnemonics(void)
3135 {
3136   int i = 0;
3137   int key;
3138   //  char *str;
3139   pCodeInstruction *pci;
3140
3141   if(mnemonics_initialized)
3142     return;
3143
3144   // NULL out the array before making the assignments
3145   // since we check the array contents below this initialization.
3146
3147   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3148     pic16Mnemonics[i] = NULL;
3149   }
3150
3151   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3152   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3153   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3154   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3155   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3156   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3157   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3158   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3159   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3160   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3161   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3162   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3163   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3164   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3165   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3166   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3167   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3168   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3169   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3170   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3171   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3172   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3173   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3174   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3175   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3176   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3177   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3178   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3179   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3180   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3181   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3182   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3183   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3184   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3185   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3186   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3187   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3188   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3189   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3190   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3191   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3192   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3193   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3194   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3195   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3196   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3197   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3198   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3199   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3200   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3201   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3202   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3203   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3204   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3205   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3206   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3207   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3208   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3209   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3210   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3211   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3212   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3213   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3214   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3215   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3216   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3217   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3218   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3219   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3220   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3221   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3222   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3223   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3224   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3225   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3226   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3227   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3228   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3229   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3230   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3231   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3232   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3233   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3234   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3235   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3236   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3237   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3238   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3239   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3240   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3241   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3242   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3243   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3244   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3245
3246   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3247     if(pic16Mnemonics[i])
3248       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3249   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3250
3251   while(pci) {
3252     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3253     pci = hTabNextItem(pic16MnemonicsHash, &key);
3254   }
3255
3256   mnemonics_initialized = 1;
3257 }
3258
3259 int pic16_getpCodePeepCommand(char *cmd);
3260
3261 int pic16_getpCode(char *mnem,unsigned dest)
3262 {
3263
3264   pCodeInstruction *pci;
3265   int key = mnem2key((unsigned char *)mnem);
3266
3267   if(!mnemonics_initialized)
3268     pic16initMnemonics();
3269
3270   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3271
3272   while(pci) {
3273
3274     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3275       if((pci->num_ops <= 1)
3276         || (pci->isModReg == dest)
3277         || (pci->isBitInst)
3278         || (pci->num_ops <= 2 && pci->isAccess)
3279         || (pci->num_ops <= 2 && pci->isFastCall)
3280         || (pci->num_ops <= 2 && pci->is2MemOp)
3281         || (pci->num_ops <= 2 && pci->is2LitOp) )
3282         return(pci->op);
3283     }
3284
3285     pci = hTabNextItemWK (pic16MnemonicsHash);
3286   
3287   }
3288
3289   return -1;
3290 }
3291
3292 /*-----------------------------------------------------------------*
3293  * pic16initpCodePeepCommands
3294  *
3295  *-----------------------------------------------------------------*/
3296 void pic16initpCodePeepCommands(void)
3297 {
3298
3299   int key, i;
3300   peepCommand *pcmd;
3301
3302   i = 0;
3303   do {
3304     hTabAddItem(&pic16pCodePeepCommandsHash, 
3305                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3306     i++;
3307   } while (peepCommands[i].cmd);
3308
3309   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3310
3311   while(pcmd) {
3312     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3313     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3314   }
3315
3316 }
3317
3318 /*-----------------------------------------------------------------
3319  *
3320  *
3321  *-----------------------------------------------------------------*/
3322
3323 int pic16_getpCodePeepCommand(char *cmd)
3324 {
3325
3326   peepCommand *pcmd;
3327   int key = mnem2key((unsigned char *)cmd);
3328
3329
3330   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3331
3332   while(pcmd) {
3333     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3334     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3335       return pcmd->id;
3336     }
3337
3338     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3339   
3340   }
3341
3342   return -1;
3343 }
3344
3345 static char getpBlock_dbName(pBlock *pb)
3346 {
3347   if(!pb)
3348     return 0;
3349
3350   if(pb->cmemmap)
3351     return pb->cmemmap->dbName;
3352
3353   return pb->dbName;
3354 }
3355 void pic16_pBlockConvert2ISR(pBlock *pb)
3356 {
3357         if(!pb)return;
3358
3359         if(pb->cmemmap)pb->cmemmap = NULL;
3360
3361         pb->dbName = 'I';
3362
3363         if(pic16_pcode_verbose)
3364                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3365 }
3366
3367 void pic16_pBlockConvert2Absolute(pBlock *pb)
3368 {
3369         if(!pb)return;
3370         if(pb->cmemmap)pb->cmemmap = NULL;
3371         
3372         pb->dbName = 'A';
3373         
3374         if(pic16_pcode_verbose)
3375                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3376 }
3377   
3378 /*-----------------------------------------------------------------*/
3379 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3380 /*                   instances to the front of the doubly linked   */
3381 /*                   list of pBlocks                               */
3382 /*-----------------------------------------------------------------*/
3383
3384 void pic16_movepBlock2Head(char dbName)
3385 {
3386   pBlock *pb;
3387
3388
3389   /* this can happen in sources without code,
3390    * only variable definitions */
3391   if(!the_pFile)return;
3392
3393   pb = the_pFile->pbHead;
3394
3395   while(pb) {
3396
3397     if(getpBlock_dbName(pb) == dbName) {
3398       pBlock *pbn = pb->next;
3399       pb->next = the_pFile->pbHead;
3400       the_pFile->pbHead->prev = pb;
3401       the_pFile->pbHead = pb;
3402
3403       if(pb->prev)
3404         pb->prev->next = pbn;
3405
3406       // If the pBlock that we just moved was the last
3407       // one in the link of all of the pBlocks, then we
3408       // need to point the tail to the block just before
3409       // the one we moved.
3410       // Note: if pb->next is NULL, then pb must have 
3411       // been the last pBlock in the chain.
3412
3413       if(pbn)
3414         pbn->prev = pb->prev;
3415       else
3416         the_pFile->pbTail = pb->prev;
3417
3418       pb = pbn;
3419
3420     } else
3421       pb = pb->next;
3422
3423   }
3424
3425 }
3426
3427 void pic16_copypCode(FILE *of, char dbName)
3428 {
3429   pBlock *pb;
3430
3431         if(!of || !the_pFile)
3432                 return;
3433
3434         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3435                 if(getpBlock_dbName(pb) == dbName) {
3436 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3437                         pBlockStats(of,pb);
3438                         pic16_printpBlock(of,pb);
3439                 }
3440         }
3441
3442 }
3443 void pic16_pcode_test(void)
3444 {
3445
3446   DFPRINTF((stderr,"pcode is alive!\n"));
3447
3448   //initMnemonics();
3449
3450   if(the_pFile) {
3451
3452     pBlock *pb;
3453     FILE *pFile;
3454     char buffer[100];
3455
3456     /* create the file name */
3457     strcpy(buffer,dstFileName);
3458     strcat(buffer,".p");
3459
3460     if( !(pFile = fopen(buffer, "w" ))) {
3461       werror(E_FILE_OPEN_ERR,buffer);
3462       exit(1);
3463     }
3464
3465     fprintf(pFile,"pcode dump\n\n");
3466
3467     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3468       fprintf(pFile,"\n\tNew pBlock\n\n");
3469       if(pb->cmemmap)
3470         fprintf(pFile,"%s",pb->cmemmap->sname);
3471       else
3472         fprintf(pFile,"internal pblock");
3473
3474       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3475       pic16_printpBlock(pFile,pb);
3476     }
3477   }
3478 }
3479
3480
3481 unsigned long pic16_countInstructions(void)
3482 {
3483   pBlock *pb;
3484   pCode *pc;
3485   unsigned long isize=0;
3486
3487     if(!the_pFile)return -1;
3488     
3489     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3490       for(pc = pb->pcHead; pc; pc = pc->next) {
3491         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3492       }
3493     }
3494   return (isize);
3495 }
3496
3497
3498 /*-----------------------------------------------------------------*/
3499 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3500 /*      ister, RegCond will return the bit being referenced.       */
3501 /*                                                                 */
3502 /* fixme - why not just OR in the pcop bit field                   */
3503 /*-----------------------------------------------------------------*/
3504
3505 static int RegCond(pCodeOp *pcop)
3506 {
3507
3508   if(!pcop)
3509     return 0;
3510
3511   if(!pcop->name)return 0;
3512
3513   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3514     switch(PCORB(pcop)->bit) {
3515     case PIC_C_BIT:
3516       return PCC_C;
3517     case PIC_DC_BIT:
3518         return PCC_DC;
3519     case PIC_Z_BIT:
3520       return PCC_Z;
3521     }
3522
3523   }
3524
3525   return 0;
3526 }
3527
3528 /*-----------------------------------------------------------------*/
3529 /* 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((unsigned char)*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((unsigned char)*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 /* Allow for 12 bit literals, required for LFSR */
4073 pCodeOp *pic16_newpCodeOpLit12(int lit)
4074 {
4075   char *s = buffer;
4076   pCodeOp *pcop;
4077
4078
4079   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4080   pcop->type = PO_LITERAL;
4081
4082   pcop->name = NULL;
4083   //if(lit>=0)
4084     sprintf(s,"0x%03x", ((unsigned int)lit) & 0x0fff);
4085   //else
4086   //  sprintf(s, "%i", lit);
4087   
4088   if(s)
4089     pcop->name = Safe_strdup(s);
4090
4091   ((pCodeOpLit *)pcop)->lit = lit;
4092
4093   return pcop;
4094 }
4095
4096 /*-----------------------------------------------------------------*/
4097 /*-----------------------------------------------------------------*/
4098 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4099 {
4100   char *s = buffer, tbuf[256], *tb=tbuf;
4101   pCodeOp *pcop;
4102
4103
4104   tb = pic16_get_op(arg2, NULL, 0);
4105   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4106   pcop->type = PO_LITERAL;
4107
4108   pcop->name = NULL;
4109   //if(lit>=0) {
4110     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4111     if(s)
4112       pcop->name = Safe_strdup(s);
4113   //}
4114
4115   ((pCodeOpLit2 *)pcop)->lit = lit;
4116   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4117
4118   return pcop;
4119 }
4120
4121 /*-----------------------------------------------------------------*/
4122 /*-----------------------------------------------------------------*/
4123 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4124 {
4125   pCodeOp *pcop;
4126
4127         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4128         pcop->type = PO_IMMEDIATE;
4129         if(name) {
4130                 regs *r = pic16_dirregWithName(name);
4131                 pcop->name = Safe_strdup(name);
4132                 PCOI(pcop)->r = r;
4133                 
4134                 if(r) {
4135 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4136                         PCOI(pcop)->rIdx = r->rIdx;
4137                 } else {
4138 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4139                         PCOI(pcop)->rIdx = -1;
4140                 }
4141 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4142         } else {
4143                 pcop->name = NULL;
4144         }
4145
4146         PCOI(pcop)->index = index;
4147         PCOI(pcop)->offset = offset;
4148         PCOI(pcop)->_const = code_space;
4149
4150   return pcop;
4151 }
4152
4153 /*-----------------------------------------------------------------*/
4154 /*-----------------------------------------------------------------*/
4155 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4156 {
4157   char *s = buffer;
4158   pCodeOp *pcop;
4159
4160
4161   if(!pcwb || !subtype) {
4162     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4163     exit(1);
4164   }
4165
4166   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4167   pcop->type = PO_WILD;
4168   sprintf(s,"%%%d",id);
4169   pcop->name = Safe_strdup(s);
4170
4171   PCOW(pcop)->id = id;
4172   PCOW(pcop)->pcwb = pcwb;
4173   PCOW(pcop)->subtype = subtype;
4174   PCOW(pcop)->matched = NULL;
4175
4176   PCOW(pcop)->pcop2 = NULL;
4177   
4178   return pcop;
4179 }
4180
4181 /*-----------------------------------------------------------------*/
4182 /*-----------------------------------------------------------------*/
4183 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4184 {
4185   char *s = buffer;
4186   pCodeOp *pcop;
4187
4188
4189         if(!pcwb || !subtype || !subtype2) {
4190                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4191                 exit(1);
4192         }
4193
4194         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4195         pcop->type = PO_WILD;
4196         sprintf(s,"%%%d",id);
4197         pcop->name = Safe_strdup(s);
4198
4199         PCOW(pcop)->id = id;
4200         PCOW(pcop)->pcwb = pcwb;
4201         PCOW(pcop)->subtype = subtype;
4202         PCOW(pcop)->matched = NULL;
4203
4204         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4205
4206         if(!subtype2->name) {
4207                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4208                 PCOW2(pcop)->pcop.type = PO_WILD;
4209                 sprintf(s, "%%%d", id2);
4210                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4211                 PCOW2(pcop)->id = id2;
4212                 PCOW2(pcop)->subtype = subtype2;
4213
4214 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4215 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4216         } else {
4217                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4218
4219 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4220 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4221         }
4222   
4223
4224
4225   return pcop;
4226 }
4227
4228
4229 /*-----------------------------------------------------------------*/
4230 /*-----------------------------------------------------------------*/
4231 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4232 {
4233   pCodeOp *pcop;
4234   
4235   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4236   pcop->type = PO_GPR_BIT;
4237   if(s)
4238     pcop->name = Safe_strdup(s);   
4239   else
4240     pcop->name = NULL;
4241
4242   PCORB(pcop)->bit = bit;
4243   PCORB(pcop)->inBitSpace = inBitSpace;
4244   PCORB(pcop)->subtype = subt;
4245
4246   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4247   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4248 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4249 //  PCOR(pcop)->rIdx = 0;
4250   return pcop;
4251 }
4252
4253 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4254 {
4255   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4256                                 bit, 0, PO_GPR_REGISTER);
4257 }
4258
4259
4260 /*-----------------------------------------------------------------*
4261  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4262  *
4263  * If rIdx >=0 then a specific register from the set of registers
4264  * will be selected. If rIdx <0, then a new register will be searched
4265  * for.
4266  *-----------------------------------------------------------------*/
4267
4268 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4269 {
4270   pCodeOp *pcop;
4271   regs *r;
4272
4273   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4274
4275   pcop->name = NULL;
4276
4277   if(rIdx >= 0) {
4278         r = pic16_regWithIdx(rIdx);
4279         if(!r)
4280                 r = pic16_allocWithIdx(rIdx);
4281   } else {
4282     r = pic16_findFreeReg(REG_GPR);
4283
4284     if(!r) {
4285         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4286                 __FUNCTION__, __LINE__);
4287         exit(-1);
4288     }
4289   }
4290
4291   PCOR(pcop)->rIdx = rIdx;
4292   PCOR(pcop)->r = r;
4293   pcop->type = PCOR(pcop)->r->pc_type;
4294
4295   return pcop;
4296 }
4297
4298 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4299 {
4300   pCodeOp *pcop;
4301   regs *r;
4302   
4303     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4304     pcop->name = NULL;
4305     
4306     r = pic16_findFreeReg(REG_GPR);
4307
4308     while(r) {
4309       if(!bitVectBitValue(bv, r->rIdx)) {
4310         PCOR(pcop)->r = r;
4311         PCOR(pcop)->rIdx = r->rIdx;
4312         pcop->type = r->pc_type;
4313         return (pcop);
4314       }
4315       
4316       r = pic16_findFreeRegNext(REG_GPR, r);
4317     }
4318   
4319   return NULL;
4320 }
4321
4322       
4323
4324 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4325 {
4326   pCodeOp *pcop;
4327   regs *r;
4328
4329         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4330         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4331         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4332         pcop->type = PCOR(pcop)->r->pc_type;
4333         pcop->name = PCOR(pcop)->r->name;
4334
4335 //      if(pic16_pcode_verbose) {
4336 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4337 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4338 //      }
4339
4340   return pcop;
4341 }
4342
4343 /*-----------------------------------------------------------------*/
4344 /*-----------------------------------------------------------------*/
4345 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4346 {
4347   pCodeOpOpt *pcop;
4348
4349         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4350         
4351         pcop->type = type;
4352         pcop->key = Safe_strdup( key );
4353
4354   return (PCOP(pcop));
4355 }
4356
4357 /*-----------------------------------------------------------------*/
4358 /*-----------------------------------------------------------------*/
4359 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4360 {
4361   pCodeOpLocalReg *pcop;
4362
4363         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4364         
4365         pcop->type = type;
4366
4367   return (PCOP(pcop));
4368 }
4369
4370
4371 /*-----------------------------------------------------------------*/
4372 /*-----------------------------------------------------------------*/
4373
4374 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4375 {
4376   pCodeOp *pcop;
4377
4378   switch(type) {
4379   case PO_BIT:
4380   case PO_GPR_BIT:
4381     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4382     break;
4383
4384   case PO_LITERAL:
4385     pcop = pic16_newpCodeOpLit(-1);
4386     break;
4387
4388   case PO_LABEL:
4389     pcop = pic16_newpCodeOpLabel(NULL,-1);
4390     break;
4391   case PO_GPR_TEMP:
4392     pcop = pic16_newpCodeOpReg(-1);
4393     break;
4394
4395   case PO_GPR_REGISTER:
4396     if(name)
4397       pcop = pic16_newpCodeOpRegFromStr(name);
4398     else
4399       pcop = pic16_newpCodeOpReg(-1);
4400     break;
4401
4402   default:
4403     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4404     pcop->type = type;
4405     if(name)
4406       pcop->name = Safe_strdup(name);   
4407     else
4408       pcop->name = NULL;
4409   }
4410
4411   return pcop;
4412 }
4413
4414 /* This is a multiple of two as gpasm pads DB directives to even length,
4415  * thus the data would be interleaved with \0 bytes...
4416  * This is a multiple of three in order to have arrays of 3-byte pointers
4417  * continuously in memory (without 0-padding at the lines' end).
4418  * This is rather 12 than 6 in order not to split up 4-byte data types
4419  * in arrays right in the middle of a 4-byte word. */
4420 #define DB_ITEMS_PER_LINE       12
4421
4422 typedef struct DBdata
4423   {
4424     int count;
4425     char buffer[512];
4426   } DBdata;
4427
4428 struct DBdata DBd;
4429 static int DBd_init = -1;
4430
4431 /*-----------------------------------------------------------------*/
4432 /*    Initialiase "DB" data buffer                                 */
4433 /*-----------------------------------------------------------------*/
4434 void pic16_initDB(void)
4435 {
4436         DBd_init = -1;
4437 }
4438
4439
4440 /*-----------------------------------------------------------------*/
4441 /*    Flush pending "DB" data to a pBlock                          */
4442 /*                                                                 */
4443 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4444 /*-----------------------------------------------------------------*/
4445 void pic16_flushDB(char ptype, void *p)
4446 {
4447         if (DBd.count>0) {
4448                 if(ptype == 'p')
4449                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4450                 else
4451                 if(ptype == 'f')
4452                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4453                 else {
4454                         /* sanity check */
4455                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4456                 }
4457
4458                 DBd.count = 0;
4459                 DBd.buffer[0] = '\0';
4460         }
4461 }
4462
4463
4464 /*-----------------------------------------------------------------*/
4465 /*    Add "DB" directives to a pBlock                              */
4466 /*-----------------------------------------------------------------*/
4467 void pic16_emitDB(int c, char ptype, void *p)
4468 {
4469   int l;
4470
4471         if (DBd_init<0) {
4472          // we need to initialize
4473                 DBd_init = 0;
4474                 DBd.count = 0;
4475                 DBd.buffer[0] = '\0';
4476         }
4477
4478         l = strlen(DBd.buffer);
4479         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4480
4481 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4482         
4483         DBd.count++;
4484         if (DBd.count>= DB_ITEMS_PER_LINE)
4485                 pic16_flushDB(ptype, p);
4486 }
4487
4488 void pic16_emitDS(char *s, char ptype, void *p)
4489 {
4490   int l;
4491
4492         if (DBd_init<0) {
4493          // we need to initialize
4494                 DBd_init = 0;
4495                 DBd.count = 0;
4496                 DBd.buffer[0] = '\0';
4497         }
4498
4499         l = strlen(DBd.buffer);
4500         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4501
4502 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4503
4504         DBd.count++;    //=strlen(s);
4505         if (DBd.count>=DB_ITEMS_PER_LINE)
4506                 pic16_flushDB(ptype, p);
4507 }
4508
4509
4510 /*-----------------------------------------------------------------*/
4511 /*-----------------------------------------------------------------*/
4512 void pic16_pCodeConstString(char *name, char *value)
4513 {
4514   pBlock *pb;
4515   char *item;
4516   static set *emittedSymbols = NULL;
4517
4518   if(!name || !value)
4519     return;
4520
4521   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4522   if (emittedSymbols) {
4523     /* scan set for name */
4524     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4525     {
4526       if (!strcmp (item,name)) {
4527         //fprintf (stderr, "%s already emitted\n", name);
4528         return;
4529       } // if
4530     } // for
4531   } // if
4532   addSet (&emittedSymbols, Safe_strdup (name));
4533
4534   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4535
4536   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4537
4538   pic16_addpBlock(pb);
4539
4540 //  sprintf(buffer,"; %s = ", name);
4541 //  strcat(buffer, value);
4542 //  fputs(buffer, stderr);
4543
4544 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4545   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4546
4547   do {
4548         pic16_emitDB(*value, 'p', (void *)pb);
4549   }while (*value++);
4550   pic16_flushDB('p', (void *)pb);
4551 }
4552
4553 /*-----------------------------------------------------------------*/
4554 /*-----------------------------------------------------------------*/
4555 #if 0
4556 static void pCodeReadCodeTable(void)
4557 {
4558   pBlock *pb;
4559
4560   fprintf(stderr, " %s\n",__FUNCTION__);
4561
4562   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4563
4564   pic16_addpBlock(pb);
4565
4566   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4567   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4568   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4569   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4570
4571   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4572   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4573   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4574   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4575
4576
4577 }
4578 #endif
4579 /*-----------------------------------------------------------------*/
4580 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4581 /*-----------------------------------------------------------------*/
4582 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4583 {
4584
4585   if(!pc)
4586     return;
4587
4588   if(!pb->pcHead) {
4589     /* If this is the first pcode to be added to a block that
4590      * was initialized with a NULL pcode, then go ahead and
4591      * make this pcode the head and tail */
4592     pb->pcHead  = pb->pcTail = pc;
4593   } else {
4594     //    if(pb->pcTail)
4595     pb->pcTail->next = pc;
4596
4597     pc->prev = pb->pcTail;
4598     pc->pb = pb;
4599
4600     pb->pcTail = pc;
4601   }
4602 }
4603
4604 /*-----------------------------------------------------------------*/
4605 /* pic16_addpBlock - place a pBlock into the pFile                 */
4606 /*-----------------------------------------------------------------*/
4607 void pic16_addpBlock(pBlock *pb)
4608 {
4609   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4610
4611   if(!the_pFile) {
4612     /* First time called, we'll pass through here. */
4613     //_ALLOC(the_pFile,sizeof(pFile));
4614     the_pFile = Safe_calloc(1,sizeof(pFile));
4615     the_pFile->pbHead = the_pFile->pbTail = pb;
4616     the_pFile->functions = NULL;
4617     return;
4618   }
4619
4620   the_pFile->pbTail->next = pb;
4621   pb->prev = the_pFile->pbTail;
4622   pb->next = NULL;
4623   the_pFile->pbTail = pb;
4624 }
4625
4626 /*-----------------------------------------------------------------*/
4627 /* removepBlock - remove a pBlock from the pFile                   */
4628 /*-----------------------------------------------------------------*/
4629 static void removepBlock(pBlock *pb)
4630 {
4631   pBlock *pbs;
4632
4633   if(!the_pFile)
4634     return;
4635
4636
4637   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4638
4639   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4640     if(pbs == pb) {
4641
4642       if(pbs == the_pFile->pbHead)
4643         the_pFile->pbHead = pbs->next;
4644
4645       if (pbs == the_pFile->pbTail) 
4646         the_pFile->pbTail = pbs->prev;
4647
4648       if(pbs->next)
4649         pbs->next->prev = pbs->prev;
4650
4651       if(pbs->prev)
4652         pbs->prev->next = pbs->next;
4653
4654       return;
4655
4656     }
4657   }
4658
4659   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4660
4661 }
4662
4663 /*-----------------------------------------------------------------*/
4664 /* printpCode - write the contents of a pCode to a file            */
4665 /*-----------------------------------------------------------------*/
4666 static void printpCode(FILE *of, pCode *pc)
4667 {
4668
4669   if(!pc || !of)
4670     return;
4671
4672   if(pc->print) {
4673     pc->print(of,pc);
4674     return;
4675   }
4676
4677   fprintf(of,"warning - unable to print pCode\n");
4678 }
4679
4680 /*-----------------------------------------------------------------*/
4681 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4682 /*-----------------------------------------------------------------*/
4683 void pic16_printpBlock(FILE *of, pBlock *pb)
4684 {
4685   pCode *pc;
4686
4687         if(!pb)return;
4688
4689         if(!of)of=stderr;
4690
4691         for(pc = pb->pcHead; pc; pc = pc->next) {
4692                 if(isPCF(pc) && PCF(pc)->fname) {
4693                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4694                         if(pb->dbName == 'A') {
4695                           absSym *ab;
4696                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4697 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4698                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4699 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4700                                                 if(ab->address != -1)
4701                                                   fprintf(of, "\t0X%06X", ab->address);
4702                                                 break;
4703                                         }
4704                                 }
4705                         }
4706                         fprintf(of, "\n");
4707                 }
4708                 printpCode(of,pc);
4709         }
4710 }
4711
4712 /*-----------------------------------------------------------------*/
4713 /*                                                                 */
4714 /*       pCode processing                                          */
4715 /*                                                                 */
4716 /*                                                                 */
4717 /*                                                                 */
4718 /*-----------------------------------------------------------------*/
4719 pCode * pic16_findNextInstruction(pCode *pci);
4720 pCode * pic16_findPrevInstruction(pCode *pci);
4721
4722 void pic16_unlinkpCode(pCode *pc)
4723 {
4724   pCode *prev;
4725
4726   if(pc) {
4727 #ifdef PCODE_DEBUG
4728     fprintf(stderr,"Unlinking: ");
4729     printpCode(stderr, pc);
4730 #endif
4731     if(pc->prev) 
4732       pc->prev->next = pc->next;
4733     if(pc->next)
4734       pc->next->prev = pc->prev;
4735
4736     /* move C source line down (or up) */
4737     if (isPCI(pc) && PCI(pc)->cline) {
4738       prev = pic16_findNextInstruction (pc->next);
4739       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4740         PCI(prev)->cline = PCI(pc)->cline;
4741       } else {
4742         prev = pic16_findPrevInstruction (pc->prev);
4743         if (prev && isPCI(prev) && !PCI(prev)->cline)
4744           PCI(prev)->cline = PCI(pc)->cline;
4745       }
4746     }
4747     pc->prev = pc->next = NULL;
4748   }
4749 }
4750
4751 /*-----------------------------------------------------------------*/
4752 /*-----------------------------------------------------------------*/
4753
4754 static void genericDestruct(pCode *pc)
4755 {
4756
4757   pic16_unlinkpCode(pc);
4758
4759   if(isPCI(pc)) {
4760     /* For instructions, tell the register (if there's one used)
4761      * that it's no longer needed */
4762     regs *reg = pic16_getRegFromInstruction(pc);
4763     if(reg)
4764       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4765
4766         if(PCI(pc)->is2MemOp) {
4767                 reg = pic16_getRegFromInstruction2(pc);
4768                 if(reg)
4769                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4770         }
4771   }
4772
4773   /* Instead of deleting the memory used by this pCode, mark
4774    * the object as bad so that if there's a pointer to this pCode
4775    * dangling around somewhere then (hopefully) when the type is
4776    * checked we'll catch it.
4777    */
4778
4779   pc->type = PC_BAD;
4780   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4781
4782   //Safe_free(pc);
4783 }
4784
4785
4786 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4787 /*-----------------------------------------------------------------*/
4788 /*-----------------------------------------------------------------*/
4789 /* modifiers for constant immediate */
4790 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4791
4792 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4793 {
4794   regs *r;
4795   static char b[128];
4796   char *s;
4797   int use_buffer = 1;    // copy the string to the passed buffer pointer
4798
4799         if(!buffer) {
4800                 buffer = b;
4801                 size = sizeof(b);
4802                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4803         } 
4804
4805         if(pcop) {
4806                 switch(pcop->type) {
4807                         case PO_W:
4808                         case PO_WREG:
4809                         case PO_PRODL:
4810                         case PO_PRODH:
4811                         case PO_INDF0:
4812                         case PO_FSR0:
4813                                 if(use_buffer) {
4814                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4815                                         return buffer;
4816                                 }
4817                                 return PCOR(pcop)->r->name;
4818                                 break;
4819                         case PO_GPR_TEMP:
4820                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4821                                 if(use_buffer) {
4822                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4823                                         return buffer;
4824                                 }
4825                                 return r->name;
4826
4827                         case PO_IMMEDIATE:
4828                                 s = buffer;
4829                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4830                                         if(PCOI(pcop)->index) {
4831                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4832                                                         immdmod[ PCOI(pcop)->offset ],
4833                                                         pcop->name,
4834                                                         PCOI(pcop)->index);
4835                                         } else {
4836                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4837                                                         immdmod[ PCOI(pcop)->offset ],
4838                                                         pcop->name);
4839                                         }
4840                                 } else {
4841                                         if(PCOI(pcop)->index) {
4842                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4843                                                         immdmod[ 0 ],
4844                                                         pcop->name,
4845                                                         PCOI(pcop)->index);
4846                                         } else {
4847                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4848                                                         immdmod[ 0 ],
4849                                                         pcop->name);
4850                                         }
4851                                 }
4852                                 return buffer;
4853
4854                         case PO_GPR_REGISTER:
4855                         case PO_DIR:
4856                                 s = buffer;
4857 //                              size = sizeof(buffer);
4858                                 if( PCOR(pcop)->instance) {
4859                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4860                                                 pcop->name,
4861                                                 PCOR(pcop)->instance );
4862                                 } else {
4863                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4864                                 }
4865                                 return buffer;
4866                         case PO_GPR_BIT:
4867                                 s = buffer;
4868                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4869                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4870                                 } else {
4871                                         if(PCORB(pcop)->pcor.instance)
4872                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4873                                         else
4874                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4875                                 }
4876
4877                                 return (buffer);
4878                         default:
4879                                 if(pcop->name) {
4880                                         if(use_buffer) {
4881                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4882                                                 return buffer;
4883                                         }
4884                                 return pcop->name;
4885                                 }
4886
4887                 }
4888         }
4889
4890   return "NO operand1";
4891 }
4892
4893 /*-----------------------------------------------------------------*/
4894 /* pic16_get_op2 - variant to support two memory operand commands  */
4895 /*-----------------------------------------------------------------*/
4896 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4897 {
4898   regs *r;
4899   static char b[128];
4900   char *s;
4901   int use_buffer = 1;    // copy the string to the passed buffer pointer
4902
4903         if(!buffer) {
4904                 buffer = b;
4905                 size = sizeof(b);
4906                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4907         } 
4908
4909 #if 0
4910         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",
4911                 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4912                 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4913 #endif
4914
4915         if(pcop) {
4916                 switch(PCOR2(pcop)->pcop2->type) {
4917                         case PO_W:
4918                         case PO_WREG:
4919                         case PO_PRODL:
4920                         case PO_PRODH:
4921                         case PO_INDF0:
4922                         case PO_FSR0:
4923                                 if(use_buffer) {
4924                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4925                                         return buffer;
4926                                 }
4927                                 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4928                                 break;
4929                         case PO_GPR_TEMP:
4930                                 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4931
4932                                 if(use_buffer) {
4933                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4934                                         return buffer;
4935                                 }
4936                                 return r->name;
4937
4938                         case PO_IMMEDIATE:
4939                                         assert( 0 );
4940                                 break;
4941 #if 0
4942                                 s = buffer;
4943
4944                                 if(PCOI(pcop)->_const) {
4945                                         if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4946                                                 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4947                                                         pcop->name,
4948                                                         PCOI(pcop)->index,
4949                                                         8 * PCOI(pcop)->offset );
4950                                         } else
4951                                                 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4952                                 } else {
4953                                         if( PCOI(pcop)->index) {
4954                                                 SAFE_snprintf(&s,&size,"(%s + %d)",
4955                                                         pcop->name,
4956                                                         PCOI(pcop)->index );
4957                                         } else {
4958                                                 if(PCOI(pcop)->offset)
4959                                                         SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4960                                                 else
4961                                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4962                                         }
4963                                 }
4964                                 return buffer;
4965 #endif
4966                         case PO_DIR:
4967                                 s = buffer;
4968                                 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4969                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4970                                                 PCOR(PCOR2(pcop)->pcop2)->r->name,
4971                                                 PCOR(PCOR2(pcop)->pcop2)->instance );
4972                                 } else {
4973                                         SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4974                                 }
4975                                 return buffer;
4976
4977                         default:
4978                                 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4979                                         if(use_buffer) {
4980                                                 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4981                                                 return buffer;
4982                                         }
4983                                         return PCOR(PCOR2(pcop)->pcop2)->r->name;
4984                                 }
4985                 }
4986         }
4987
4988   return "NO operand2";
4989 }
4990
4991 /*-----------------------------------------------------------------*/
4992 /*-----------------------------------------------------------------*/
4993 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4994 {
4995
4996   if(pcc )
4997     return pic16_get_op(pcc->pcop,NULL,0);
4998
4999   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
5000    *   return ("ERROR Null: "__FUNCTION__);
5001    */
5002   return ("ERROR Null: pic16_get_op_from_instruction");
5003
5004 }
5005
5006 /*-----------------------------------------------------------------*/
5007 /*-----------------------------------------------------------------*/
5008 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
5009 {
5010
5011   fprintf(of,"pcodeopprint- not implemented\n");
5012 }
5013
5014 /*-----------------------------------------------------------------*/
5015 /* pic16_pCode2str - convert a pCode instruction to string               */
5016 /*-----------------------------------------------------------------*/
5017 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
5018 {
5019   char *s = str;
5020   regs *r;
5021
5022 #if 0
5023         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
5024                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
5025                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
5026 //              exit(-1);
5027         }
5028 #endif
5029
5030   switch(pc->type) {
5031
5032   case PC_OPCODE:
5033     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
5034
5035     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
5036
5037         if(PCI(pc)->is2MemOp) {
5038                 SAFE_snprintf(&s,&size, "%s, %s", 
5039                 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
5040                 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
5041                 break;
5042         }
5043
5044         if(PCI(pc)->is2LitOp) {
5045                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
5046                 break;
5047         }
5048
5049       if(PCI(pc)->isBitInst) {
5050         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
5051           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
5052             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
5053                           PCI(pc)->pcop->name ,
5054                           PCI(pc)->pcop->name );
5055           else
5056             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5057 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5058                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5059                           
5060         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5061           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5062         } else
5063           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5064         //PCI(pc)->pcop->t.bit );
5065       } else {
5066
5067         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5068           if( PCI(pc)->num_ops == 3)
5069             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5070           else
5071             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5072
5073         }
5074         else 
5075         {
5076           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5077         }
5078       }
5079         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5080           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5081             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5082
5083           r = pic16_getRegFromInstruction(pc);
5084 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5085 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5086
5087           if(PCI(pc)->isAccess) {
5088             static char *bank_spec[2][2] = {
5089               { "", ", ACCESS" },  /* gpasm uses access bank by default */
5090               { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5091             };
5092              
5093             SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !r->accessBank) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5094           }
5095         }
5096 //      
5097
5098     }
5099     break;
5100
5101   case PC_COMMENT:
5102     /* assuming that comment ends with a \n */
5103     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5104     break;
5105
5106   case PC_INFO:
5107     SAFE_snprintf(&s,&size,"; info ==>");
5108     switch( PCINF(pc)->type ) {
5109       case INF_OPTIMIZATION:
5110           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5111           break;
5112       case INF_LOCALREGS:
5113           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5114           break;
5115     }; break;
5116
5117   case PC_INLINE:
5118     /* assuming that inline code ends with a \n */
5119     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5120     break;
5121
5122   case PC_LABEL:
5123     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5124     break;
5125   case PC_FUNCTION:
5126     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5127     break;
5128   case PC_WILD:
5129     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5130     break;
5131   case PC_FLOW:
5132     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5133     break;
5134   case PC_CSOURCE:
5135 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5136       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5137         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5138     break;
5139   case PC_ASMDIR:
5140         if(PCAD(pc)->directive) {
5141                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5142         } else
5143         if(PCAD(pc)->arg) {
5144                 /* special case to handle inline labels without a tab */
5145                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5146         }
5147         break;
5148
5149   case PC_BAD:
5150     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5151     break;
5152   }
5153
5154   return str;
5155
5156 }
5157
5158 /*-----------------------------------------------------------------*/
5159 /* genericPrint - the contents of a pCode to a file                */
5160 /*-----------------------------------------------------------------*/
5161 static void genericPrint(FILE *of, pCode *pc)
5162 {
5163
5164   if(!pc || !of)
5165     return;
5166
5167   switch(pc->type) {
5168   case PC_COMMENT:
5169 //    fputs(((pCodeComment *)pc)->comment, of);
5170     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5171     break;
5172
5173   case PC_INFO:
5174     {
5175       pBranch *pbl = PCI(pc)->label;
5176       while(pbl && pbl->pc) {
5177         if(pbl->pc->type == PC_LABEL)
5178           pCodePrintLabel(of, pbl->pc);
5179         pbl = pbl->next;
5180       }
5181     }
5182           
5183     if(pic16_pcode_verbose) {
5184       fprintf(of, "; info ==>");
5185       switch(((pCodeInfo *)pc)->type) {
5186         case INF_OPTIMIZATION:
5187               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5188               break;
5189         case INF_LOCALREGS:
5190               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5191               break;
5192         }
5193     };
5194     
5195     break;
5196
5197   case PC_INLINE:
5198     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5199      break;
5200
5201   case PC_OPCODE:
5202     // If the opcode has a label, print that first
5203     {
5204       pBranch *pbl = PCI(pc)->label;
5205       while(pbl && pbl->pc) {
5206         if(pbl->pc->type == PC_LABEL)
5207           pCodePrintLabel(of, pbl->pc);
5208         pbl = pbl->next;
5209       }
5210     }
5211
5212     if(PCI(pc)->cline) 
5213       genericPrint(of,PCODE(PCI(pc)->cline));
5214
5215     {
5216       char str[256];
5217       
5218       pic16_pCode2str(str, 256, pc);
5219
5220       fprintf(of,"%s",str);
5221       /* Debug */
5222       if(pic16_debug_verbose) {
5223         fprintf(of, "\t;key=%03x",pc->seq);
5224         if(PCI(pc)->pcflow)
5225           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5226       }
5227     }
5228     fprintf(of, "\n");
5229     break;
5230       
5231   case PC_WILD:
5232     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5233     if(PCW(pc)->pci.label)
5234       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5235
5236     if(PCW(pc)->operand) {
5237       fprintf(of,";\toperand  ");
5238       pCodeOpPrint(of,PCW(pc)->operand );
5239     }
5240     break;
5241
5242   case PC_FLOW:
5243     if(pic16_debug_verbose) {
5244       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5245       if(PCFL(pc)->ancestor)
5246         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5247       fprintf(of,"\n");
5248
5249     }
5250     break;
5251
5252   case PC_CSOURCE:
5253 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5254     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5255         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5256          
5257     break;
5258
5259   case PC_ASMDIR:
5260         {
5261           pBranch *pbl = PCAD(pc)->pci.label;
5262                 while(pbl && pbl->pc) {
5263                         if(pbl->pc->type == PC_LABEL)
5264                                 pCodePrintLabel(of, pbl->pc);
5265                         pbl = pbl->next;
5266                 }
5267         }
5268         if(PCAD(pc)->directive) {
5269                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5270         } else
5271         if(PCAD(pc)->arg) {
5272                 /* special case to handle inline labels without tab */
5273                 fprintf(of, "%s\n", PCAD(pc)->arg);
5274         }
5275         break;
5276         
5277   case PC_LABEL:
5278   default:
5279     fprintf(of,"unknown pCode type %d\n",pc->type);
5280   }
5281
5282 }
5283
5284 /*-----------------------------------------------------------------*/
5285 /* pCodePrintFunction - prints function begin/end                  */
5286 /*-----------------------------------------------------------------*/
5287
5288 static void pCodePrintFunction(FILE *of, pCode *pc)
5289 {
5290
5291   if(!pc || !of)
5292     return;
5293
5294 #if 0
5295   if( ((pCodeFunction *)pc)->modname) 
5296     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5297 #endif
5298
5299   if(!PCF(pc)->absblock) {
5300       if(PCF(pc)->fname) {
5301       pBranch *exits = PCF(pc)->to;
5302       int i=0;
5303
5304       fprintf(of,"%s:", PCF(pc)->fname);
5305     
5306       if(pic16_pcode_verbose)
5307         fprintf(of, "\t;Function start");
5308     
5309       fprintf(of, "\n");
5310     
5311       while(exits) {
5312         i++;
5313         exits = exits->next;
5314       }
5315       //if(i) i--;
5316
5317       if(pic16_pcode_verbose)
5318         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5319     
5320     } else {
5321         if((PCF(pc)->from && 
5322                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5323                 PCF(PCF(pc)->from->pc)->fname) ) {
5324
5325                 if(pic16_pcode_verbose)
5326                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5327         } else {
5328                 if(pic16_pcode_verbose)
5329                         fprintf(of,"; exit point [can't find entry point]\n");
5330         }
5331         fprintf(of, "\n");
5332     }
5333   }
5334 }
5335 /*-----------------------------------------------------------------*/
5336 /* pCodePrintLabel - prints label                                  */
5337 /*-----------------------------------------------------------------*/
5338
5339 static void pCodePrintLabel(FILE *of, pCode *pc)
5340 {
5341
5342   if(!pc || !of)
5343     return;
5344
5345   if(PCL(pc)->label) 
5346     fprintf(of,"%s:\n",PCL(pc)->label);
5347   else if (PCL(pc)->key >=0) 
5348     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5349   else
5350     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5351
5352 }
5353 /*-----------------------------------------------------------------*/
5354 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5355 /*                         remove it if it is found.               */
5356 /*-----------------------------------------------------------------*/
5357 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5358 {
5359   pBranch *b, *bprev;
5360
5361
5362   bprev = NULL;
5363
5364   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5365     b = PCI(pcl)->label;
5366   else {
5367     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5368     exit(1);
5369
5370   }
5371
5372   //fprintf (stderr, "%s \n",__FUNCTION__);
5373   //pcl->print(stderr,pcl);
5374   //pc->print(stderr,pc);
5375   while(b) {
5376     if(b->pc == pc) {
5377       //fprintf (stderr, "found label\n");
5378       //pc->print(stderr, pc);
5379
5380       /* Found a label */
5381       if(bprev) {
5382         bprev->next = b->next;  /* Not first pCode in chain */
5383 //      Safe_free(b);
5384       } else {
5385         pc->destruct(pc);
5386         PCI(pcl)->label = b->next;   /* First pCode in chain */
5387 //      Safe_free(b);
5388       }
5389       return;  /* A label can't occur more than once */
5390     }
5391     bprev = b;
5392     b = b->next;
5393   }
5394
5395 }
5396
5397 /*-----------------------------------------------------------------*/
5398 /*-----------------------------------------------------------------*/
5399 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5400 {
5401   pBranch *b;
5402
5403   if(!h)
5404     return n;
5405
5406   if(h == n)
5407     return n;
5408
5409   b = h;
5410   while(b->next)
5411     b = b->next;
5412
5413   b->next = n;
5414
5415   return h;
5416   
5417 }  
5418 /*-----------------------------------------------------------------*/
5419 /* pBranchLink - given two pcodes, this function will link them    */
5420 /*               together through their pBranches                  */
5421 /*-----------------------------------------------------------------*/
5422 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5423 {
5424   pBranch *b;
5425
5426   // Declare a new branch object for the 'from' pCode.
5427
5428   //_ALLOC(b,sizeof(pBranch));
5429   b = Safe_calloc(1,sizeof(pBranch));
5430   b->pc = PCODE(t);             // The link to the 'to' pCode.
5431   b->next = NULL;
5432
5433   f->to = pic16_pBranchAppend(f->to,b);
5434
5435   // Now do the same for the 'to' pCode.
5436
5437   //_ALLOC(b,sizeof(pBranch));
5438   b = Safe_calloc(1,sizeof(pBranch));
5439   b->pc = PCODE(f);
5440   b->next = NULL;
5441
5442   t->from = pic16_pBranchAppend(t->from,b);
5443   
5444 }
5445
5446 #if 1
5447 /*-----------------------------------------------------------------*/
5448 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5449 /*               a pCode                                           */
5450 /*-----------------------------------------------------------------*/
5451 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5452 {
5453   while(pb) {
5454
5455     if(pb->pc == pc)
5456       return pb;
5457
5458     pb = pb->next;
5459   }
5460
5461   return NULL;
5462 }
5463
5464 /*-----------------------------------------------------------------*/
5465 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5466 /*-----------------------------------------------------------------*/
5467 void pic16_pCodeUnlink(pCode *pc)
5468 {
5469   pBranch *pb1,*pb2;
5470   pCode *pc1;
5471
5472   if(!pc->prev || !pc->next) {
5473     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5474     exit(1);
5475   }
5476   
5477   /* move C source line down (or up) */
5478   if (isPCI(pc) && PCI(pc)->cline) {
5479     pc1 = pic16_findNextInstruction (pc->next);
5480     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5481       PCI(pc1)->cline = PCI(pc)->cline;
5482     } else {
5483       pc1 = pic16_findPrevInstruction (pc->prev);
5484       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5485         PCI(pc1)->cline = PCI(pc)->cline;
5486     }
5487   }
5488
5489   /* first remove the pCode from the chain */
5490   pc->prev->next = pc->next;
5491   pc->next->prev = pc->prev;
5492
5493   pc->prev = pc->next = NULL;
5494
5495   /* Now for the hard part... */
5496
5497   /* Remove the branches */
5498
5499   pb1 = PCI(pc)->from;
5500   while(pb1) {
5501     pc1 = pb1->pc;    /* Get the pCode that branches to the
5502                        * one we're unlinking */
5503
5504     /* search for the link back to this pCode (the one we're
5505      * unlinking) */
5506     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5507       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5508
5509       /* if the pCode we're unlinking contains multiple 'to'
5510        * branches (e.g. this a skip instruction) then we need
5511        * to copy these extra branches to the chain. */
5512       if(PCI(pc)->to->next)
5513         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5514     }
5515     
5516     pb1 = pb1->next;
5517   }
5518
5519
5520 }
5521 #endif
5522 /*-----------------------------------------------------------------*/
5523 /*-----------------------------------------------------------------*/
5524 #if 0
5525 static void genericAnalyze(pCode *pc)
5526 {
5527   switch(pc->type) {
5528   case PC_WILD:
5529   case PC_COMMENT:
5530     return;
5531   case PC_LABEL:
5532   case PC_FUNCTION:
5533   case PC_OPCODE:
5534     {
5535       // Go through the pCodes that are in pCode chain and link
5536       // them together through the pBranches. Note, the pCodes
5537       // are linked together as a contiguous stream like the 
5538       // assembly source code lines. The linking here mimics this
5539       // except that comments are not linked in.
5540       // 
5541       pCode *npc = pc->next;
5542       while(npc) {
5543         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5544           pBranchLink(pc,npc);
5545           return;
5546         } else
5547           npc = npc->next;
5548       }
5549       /* reached the end of the pcode chain without finding
5550        * an instruction we could link to. */
5551     }
5552     break;
5553   case PC_FLOW:
5554     fprintf(stderr,"analyze PC_FLOW\n");
5555
5556     return;
5557   case PC_BAD:
5558     fprintf(stderr,,";A bad pCode is being used\n");
5559
5560   }
5561 }
5562 #endif
5563
5564 /*-----------------------------------------------------------------*/
5565 /*-----------------------------------------------------------------*/
5566 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5567 {
5568   pBranch *pbr;
5569
5570   if(pc->type == PC_LABEL) {
5571     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5572       return TRUE;
5573   }
5574   if((pc->type == PC_OPCODE)
5575         || (pc->type == PC_ASMDIR)
5576         ) {
5577     pbr = PCI(pc)->label;
5578     while(pbr) {
5579       if(pbr->pc->type == PC_LABEL) {
5580         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5581           return TRUE;
5582       }
5583       pbr = pbr->next;
5584     }
5585   }
5586
5587   return FALSE;
5588 }
5589
5590 /*-----------------------------------------------------------------*/
5591 /*-----------------------------------------------------------------*/
5592 static int checkLabel(pCode *pc)
5593 {
5594   pBranch *pbr;
5595
5596   if(pc && isPCI(pc)) {
5597     pbr = PCI(pc)->label;
5598     while(pbr) {
5599       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5600         return TRUE;
5601
5602       pbr = pbr->next;
5603     }
5604   }
5605
5606   return FALSE;
5607 }
5608
5609 /*-----------------------------------------------------------------*/
5610 /* findLabelinpBlock - Search the pCode for a particular label     */
5611 /*-----------------------------------------------------------------*/
5612 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5613 {
5614   pCode  *pc;
5615
5616   if(!pb)
5617     return NULL;
5618
5619   for(pc = pb->pcHead; pc; pc = pc->next) 
5620     if(compareLabel(pc,pcop_label))
5621       return pc;
5622     
5623   return NULL;
5624 }
5625 #if 0
5626 /*-----------------------------------------------------------------*/
5627 /* findLabel - Search the pCode for a particular label             */
5628 /*-----------------------------------------------------------------*/
5629 static pCode * findLabel(pCodeOpLabel *pcop_label)
5630 {
5631   pBlock *pb;
5632   pCode  *pc;
5633
5634   if(!the_pFile)
5635     return NULL;
5636
5637   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5638     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5639       return pc;
5640   }
5641
5642   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5643   return NULL;
5644 }
5645 #endif
5646 /*-----------------------------------------------------------------*/
5647 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5648 /*                 in the linked list                              */
5649 /*-----------------------------------------------------------------*/
5650 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5651 {
5652
5653   while(pc) {
5654     if(pc->type == pct)
5655       return pc;
5656
5657     pc = pc->next;
5658   }
5659
5660   return NULL;
5661 }
5662
5663 /*-----------------------------------------------------------------*/
5664 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5665 /*                 in the linked list                              */
5666 /*-----------------------------------------------------------------*/
5667 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5668 {
5669
5670   while(pc) {
5671     if(pc->type == pct)
5672       return pc;
5673
5674     pc = pc->prev;
5675   }
5676
5677   return NULL;
5678 }
5679
5680
5681 //#define PCODE_DEBUG
5682 /*-----------------------------------------------------------------*/
5683 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5684 /*                       in the linked list                        */
5685 /*-----------------------------------------------------------------*/
5686 pCode * pic16_findNextInstruction(pCode *pci)
5687 {
5688   pCode *pc = pci;
5689
5690   while(pc) {
5691     if((pc->type == PC_OPCODE)
5692         || (pc->type == PC_WILD)
5693         || (pc->type == PC_ASMDIR)
5694         )
5695       return pc;
5696
5697 #ifdef PCODE_DEBUG
5698     fprintf(stderr,"pic16_findNextInstruction:  ");
5699     printpCode(stderr, pc);
5700 #endif
5701     pc = pc->next;
5702   }
5703
5704   //fprintf(stderr,"Couldn't find instruction\n");
5705   return NULL;
5706 }
5707
5708 /*-----------------------------------------------------------------*/
5709 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5710 /*                       in the linked list                        */
5711 /*-----------------------------------------------------------------*/
5712 pCode * pic16_findPrevInstruction(pCode *pci)
5713 {
5714   pCode *pc = pci;
5715
5716   while(pc) {
5717
5718     if((pc->type == PC_OPCODE)
5719         || (pc->type == PC_WILD)
5720         || (pc->type == PC_ASMDIR)
5721         )
5722       return pc;
5723       
5724
5725 #ifdef PCODE_DEBUG
5726     fprintf(stderr,"pic16_findPrevInstruction:  ");
5727     printpCode(stderr, pc);
5728 #endif
5729     pc = pc->prev;
5730   }
5731
5732   //fprintf(stderr,"Couldn't find instruction\n");
5733   return NULL;
5734 }
5735
5736 #undef PCODE_DEBUG
5737
5738 #if 0
5739 /*-----------------------------------------------------------------*/
5740 /* findFunctionEnd - given a pCode find the end of the function    */
5741 /*                   that contains it                              */
5742 /*-----------------------------------------------------------------*/
5743 static pCode * findFunctionEnd(pCode *pc)
5744 {
5745
5746   while(pc) {
5747     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5748       return pc;
5749
5750     pc = pc->next;
5751   }
5752
5753   fprintf(stderr,"Couldn't find function end\n");
5754   return NULL;
5755 }
5756 #endif
5757 #if 0
5758 /*-----------------------------------------------------------------*/
5759 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5760 /*                instruction with which it is associated.         */
5761 /*-----------------------------------------------------------------*/
5762 static void AnalyzeLabel(pCode *pc)
5763 {
5764
5765   pic16_pCodeUnlink(pc);
5766
5767 }
5768 #endif
5769
5770 #if 0
5771 static void AnalyzeGOTO(pCode *pc)
5772 {
5773
5774   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5775
5776 }
5777
5778 static void AnalyzeSKIP(pCode *pc)
5779 {
5780
5781   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5782   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5783
5784 }
5785
5786 static void AnalyzeRETURN(pCode *pc)
5787 {
5788
5789   //  branch_link(pc,findFunctionEnd(pc->next));
5790
5791 }
5792
5793 #endif
5794
5795 /*-------------------------------------------------------------------*/
5796 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5797 /*                            if one is present. This is the common  */
5798 /*                            part of pic16_getRegFromInstruction(2) */
5799 /*-------------------------------------------------------------------*/
5800
5801 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5802   if (!pcop) return NULL;
5803   
5804   switch(pcop->type) {
5805   case PO_PRODL:
5806   case PO_PRODH:
5807   case PO_INDF0:
5808   case PO_FSR0:
5809   case PO_W:
5810   case PO_WREG:
5811   case PO_STATUS:
5812   case PO_INTCON:
5813   case PO_PCL:
5814   case PO_PCLATH:
5815   case PO_PCLATU:
5816   case PO_BSR:
5817     return PCOR(pcop)->r;
5818
5819   case PO_SFR_REGISTER:
5820     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5821     return PCOR(pcop)->r;
5822
5823   case PO_BIT:
5824   case PO_GPR_TEMP:
5825 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5826     return PCOR(pcop)->r;
5827
5828   case PO_IMMEDIATE:
5829 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5830
5831     if(PCOI(pcop)->r)
5832       return (PCOI(pcop)->r);
5833     else
5834       return NULL;
5835     
5836   case PO_GPR_BIT:
5837     return PCOR(pcop)->r;
5838
5839   case PO_GPR_REGISTER:
5840   case PO_DIR:
5841 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5842     return PCOR(pcop)->r;
5843
5844   case PO_LITERAL:
5845     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5846     break;
5847
5848   case PO_REL_ADDR:
5849   case PO_LABEL:
5850     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5851     break;
5852     
5853   case PO_CRY:
5854   case PO_STR:
5855     /* this should never turn up */
5856     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5857     break;
5858     
5859   case PO_WILD:
5860     break;
5861     
5862   default:
5863         fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5864 //      assert( 0 );
5865         break;
5866   }
5867
5868   return NULL;
5869 }
5870
5871 /*-----------------------------------------------------------------*/
5872 /*-----------------------------------------------------------------*/
5873 regs * pic16_getRegFromInstruction(pCode *pc)
5874 {
5875
5876   if(!pc                   || 
5877      !isPCI(pc)            ||
5878      !PCI(pc)->pcop        ||
5879      PCI(pc)->num_ops == 0 ||
5880      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5881     return NULL;
5882
5883 #if 0
5884   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5885         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5886 #endif
5887
5888   return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5889 }
5890
5891 /*-------------------------------------------------------------------------------*/
5892 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5893 /*-------------------------------------------------------------------------------*/
5894 regs * pic16_getRegFromInstruction2(pCode *pc)
5895 {
5896
5897   if(!pc                   || 
5898      !isPCI(pc)            ||
5899      !PCI(pc)->pcop        ||
5900      PCI(pc)->num_ops == 0 ||
5901      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5902     return NULL;
5903
5904
5905 #if 0
5906   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5907         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5908 #endif
5909
5910   return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5911 }
5912
5913 /*-----------------------------------------------------------------*/
5914 /*-----------------------------------------------------------------*/
5915
5916 static void AnalyzepBlock(pBlock *pb)
5917 {
5918   pCode *pc;
5919
5920   if(!pb)
5921     return;
5922
5923   /* Find all of the registers used in this pBlock 
5924    * by looking at each instruction and examining it's
5925    * operands
5926    */
5927   for(pc = pb->pcHead; pc; pc = pc->next) {
5928
5929     /* Is this an instruction with operands? */
5930     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5931
5932       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5933
5934         /* Loop through all of the registers declared so far in
5935            this block and see if we find this one there */
5936
5937         regs *r = setFirstItem(pb->tregisters);
5938
5939         while(r) {
5940           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5941             PCOR(PCI(pc)->pcop)->r = r;
5942             break;
5943           }
5944           r = setNextItem(pb->tregisters);
5945         }
5946
5947         if(!r) {
5948           /* register wasn't found */
5949           //r = Safe_calloc(1, sizeof(regs));
5950           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5951           //addSet(&pb->tregisters, r);
5952           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5953           //PCOR(PCI(pc)->pcop)->r = r;
5954           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5955         }/* else 
5956           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5957          */
5958       }
5959       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5960         if(PCOR(PCI(pc)->pcop)->r) {
5961           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5962           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5963         } else {
5964           if(PCI(pc)->pcop->name)
5965             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5966           else
5967             fprintf(stderr,"ERROR: NULL register\n");
5968         }
5969       }
5970     }
5971
5972
5973   }
5974 }
5975
5976 /*-----------------------------------------------------------------*/
5977 /* */
5978 /*-----------------------------------------------------------------*/
5979 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5980
5981 static void InsertpFlow(pCode *pc, pCode **pflow)
5982 {
5983   if(*pflow)
5984     PCFL(*pflow)->end = pc;
5985
5986   if(!pc || !pc->next)
5987     return;
5988
5989   *pflow = pic16_newpCodeFlow();
5990   pic16_pCodeInsertAfter(pc, *pflow);
5991 }
5992
5993 /*-----------------------------------------------------------------*/
5994 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5995 /*                         the flow blocks.                        */
5996 /*
5997  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5998  * point the instruction flow changes. 
5999  */
6000 /*-----------------------------------------------------------------*/
6001 void pic16_BuildFlow(pBlock *pb)
6002 {
6003   pCode *pc;
6004   pCode *last_pci=NULL;
6005   pCode *pflow=NULL;
6006   int seq = 0;
6007
6008   if(!pb)
6009     return;
6010
6011   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
6012   /* Insert a pCodeFlow object at the beginning of a pBlock */
6013
6014   InsertpFlow(pb->pcHead, &pflow);
6015
6016   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
6017   //pflow->next = pb->pcHead;  /* Make the current head the next object */
6018   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
6019   //pb->pcHead = pflow;        /* Make the Flow object the head */
6020   //pflow->pb = pb;
6021
6022   for( pc = pic16_findNextInstruction(pb->pcHead);
6023        pc != NULL;
6024        pc=pic16_findNextInstruction(pc)) { 
6025
6026     pc->seq = seq++;
6027     PCI(pc)->pcflow = PCFL(pflow);
6028
6029     //fprintf(stderr," build: ");
6030     //pflow->print(stderr,pflow);
6031
6032     if (checkLabel(pc)) { 
6033
6034       /* This instruction marks the beginning of a
6035        * new flow segment */
6036
6037       pc->seq = 0;
6038       seq = 1;
6039
6040       /* If the previous pCode is not a flow object, then 
6041        * insert a new flow object. (This check prevents 
6042        * two consecutive flow objects from being insert in
6043        * the case where a skip instruction preceeds an
6044        * instruction containing a label.) */
6045
6046       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
6047         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
6048
6049       PCI(pc)->pcflow = PCFL(pflow);
6050       
6051     }
6052
6053     if( PCI(pc)->isSkip) {
6054
6055       /* The two instructions immediately following this one 
6056        * mark the beginning of a new flow segment */
6057
6058       while(pc && PCI(pc)->isSkip) {
6059
6060         PCI(pc)->pcflow = PCFL(pflow);
6061         pc->seq = seq-1;
6062         seq = 1;
6063
6064         InsertpFlow(pc, &pflow);
6065         pc=pic16_findNextInstruction(pc->next);
6066       }
6067
6068       seq = 0;
6069
6070       if(!pc)
6071         break;
6072
6073       PCI(pc)->pcflow = PCFL(pflow);
6074       pc->seq = 0;
6075       InsertpFlow(pc, &pflow);
6076
6077     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6078
6079       InsertpFlow(pc, &pflow);
6080       seq = 0;
6081
6082     }
6083     last_pci = pc;
6084     pc = pc->next;
6085   }
6086
6087   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6088   if(pflow)
6089     PCFL(pflow)->end = pb->pcTail;
6090 }
6091
6092 /*-------------------------------------------------------------------*/
6093 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6094 /*                           the flow blocks.                        */
6095 /*
6096  * unBuildFlow removes pCodeFlow objects from a pCode chain
6097  */
6098 /*-----------------------------------------------------------------*/
6099 static void unBuildFlow(pBlock *pb)
6100 {
6101   pCode *pc,*pcnext;
6102
6103   if(!pb)
6104     return;
6105
6106   pc = pb->pcHead;
6107
6108   while(pc) {
6109     pcnext = pc->next;
6110
6111     if(isPCI(pc)) {
6112
6113       pc->seq = 0;
6114       if(PCI(pc)->pcflow) {
6115         //Safe_free(PCI(pc)->pcflow);
6116         PCI(pc)->pcflow = NULL;
6117       }
6118
6119     } else if(isPCFL(pc) )
6120       pc->destruct(pc);
6121
6122     pc = pcnext;
6123   }
6124
6125
6126 }
6127 #if 0
6128 /*-----------------------------------------------------------------*/
6129 /*-----------------------------------------------------------------*/
6130 static void dumpCond(int cond)
6131 {
6132
6133   static char *pcc_str[] = {
6134     //"PCC_NONE",
6135     "PCC_REGISTER",
6136     "PCC_C",
6137     "PCC_Z",
6138     "PCC_DC",
6139     "PCC_OV",
6140     "PCC_N",
6141     "PCC_W",
6142     "PCC_EXAMINE_PCOP",
6143     "PCC_LITERAL",
6144     "PCC_REL_ADDR"
6145   };
6146
6147   int ncond = sizeof(pcc_str) / sizeof(char *);
6148   int i,j;
6149
6150   fprintf(stderr, "0x%04X\n",cond);
6151
6152   for(i=0,j=1; i<ncond; i++, j<<=1)
6153     if(cond & j)
6154       fprintf(stderr, "  %s\n",pcc_str[i]);
6155
6156 }
6157 #endif
6158
6159 #if 0
6160 /*-----------------------------------------------------------------*/
6161 /*-----------------------------------------------------------------*/
6162 static void FlowStats(pCodeFlow *pcflow)
6163 {
6164
6165   pCode *pc;
6166
6167   if(!isPCFL(pcflow))
6168     return;
6169
6170   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6171
6172   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6173
6174   if(!pc) {
6175     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6176     return;
6177   }
6178
6179
6180   fprintf(stderr, "  FlowStats inCond: ");
6181   dumpCond(pcflow->inCond);
6182   fprintf(stderr, "  FlowStats outCond: ");
6183   dumpCond(pcflow->outCond);
6184
6185 }
6186 #endif
6187 /*-----------------------------------------------------------------*
6188  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6189  *    if it affects the banking bits. 
6190  * 
6191  * return: -1 == Banking bits are unaffected by this pCode.
6192  *
6193  * return: > 0 == Banking bits are affected.
6194  *
6195  *  If the banking bits are affected, then the returned value describes
6196  * which bits are affected and how they're affected. The lower half
6197  * of the integer maps to the bits that are affected, the upper half
6198  * to whether they're set or cleared.
6199  *
6200  *-----------------------------------------------------------------*/
6201
6202 static int isBankInstruction(pCode *pc)
6203 {
6204   regs *reg;
6205   int bank = -1;
6206
6207   if(!isPCI(pc))
6208     return 0;
6209
6210   if( PCI(pc)->op == POC_MOVLB ||
6211       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6212     bank = PCOL(pc)->lit;
6213   }
6214
6215   return 1;
6216 }
6217
6218
6219 /*-----------------------------------------------------------------*/
6220 /*-----------------------------------------------------------------*/
6221 static void FillFlow(pCodeFlow *pcflow)
6222 {
6223
6224   pCode *pc;
6225   int cur_bank;
6226
6227   if(!isPCFL(pcflow))
6228     return;
6229
6230   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6231
6232   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6233
6234   if(!pc) {
6235     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6236     return;
6237   }
6238
6239   cur_bank = -1;
6240
6241   do {
6242     isBankInstruction(pc);
6243     pc = pc->next;
6244   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6245
6246 /*
6247   if(!pc ) {
6248     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6249   } else {
6250     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6251     pc->print(stderr,pc);
6252   }
6253
6254   fprintf(stderr, "  FillFlow inCond: ");
6255   dumpCond(pcflow->inCond);
6256   fprintf(stderr, "  FillFlow outCond: ");
6257   dumpCond(pcflow->outCond);
6258 */
6259 }
6260
6261 /*-----------------------------------------------------------------*/
6262 /*-----------------------------------------------------------------*/
6263 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6264 {
6265   pCodeFlowLink *fromLink, *toLink;
6266
6267   if(!from || !to || !to->pcflow || !from->pcflow)
6268     return;
6269
6270   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6271   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6272
6273   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6274   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6275
6276 }
6277
6278 pCode *pic16_getJumptabpCode (pCode *pc) {
6279   pCode *pcinf;
6280
6281   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6282   //pc->print (stderr, pc);
6283   pcinf = pc;
6284   while (pcinf) {
6285     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6286     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6287       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6288       case OPT_JUMPTABLE_BEGIN:
6289         /* leading begin of jump table -- in one */
6290         pcinf = pic16_findPrevInstruction (pcinf);
6291         return pcinf;
6292         break;
6293         
6294       case OPT_JUMPTABLE_END:
6295         /* leading end of jumptable -- not in one */
6296         return NULL;
6297         break;
6298         
6299       default:
6300         /* ignore all other PCInfos */
6301         break;
6302       }
6303     }
6304     pcinf = pcinf->prev;
6305   }
6306
6307   /* no PCInfo found -- not in a jumptable */
6308   return NULL;
6309 }
6310
6311 /*-----------------------------------------------------------------*
6312  * void LinkFlow(pBlock *pb)
6313  *
6314  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6315  * non-branching segments. In LinkFlow, we determine the execution
6316  * order of these segments. For example, if one of the segments ends
6317  * with a skip, then we know that there are two possible flow segments
6318  * to which control may be passed.
6319  *-----------------------------------------------------------------*/
6320 static void LinkFlow(pBlock *pb)
6321 {
6322   pCode *pc=NULL;
6323   pCode *pcflow;
6324   pCode *pct;
6325   pCode *jumptab_pre = NULL;
6326
6327   //fprintf(stderr,"linkflow \n");
6328
6329   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6330        pcflow != NULL;
6331        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6332
6333     if(!isPCFL(pcflow))
6334       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6335
6336     //fprintf(stderr," link: ");
6337     //pcflow->print(stderr,pcflow);
6338
6339     //FillFlow(PCFL(pcflow));
6340
6341     pc = PCFL(pcflow)->end;
6342
6343     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6344     if(isPCI_SKIP(pc)) {
6345 //      fprintf(stderr, "ends with skip\n");
6346 //      pc->print(stderr,pc);
6347
6348       pct=pic16_findNextInstruction(pc->next);
6349       LinkFlow_pCode(PCI(pc),PCI(pct));
6350       pct=pic16_findNextInstruction(pct->next);
6351       LinkFlow_pCode(PCI(pc),PCI(pct));
6352       continue;
6353     }
6354
6355     if(isPCI_BRANCH(pc)) {
6356       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6357
6358       /* handle GOTOs in jumptables */
6359       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6360         /* link to previous flow */
6361         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6362         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6363       }
6364
6365       switch (PCI(pc)->op) {
6366       case POC_GOTO:
6367       case POC_BRA:
6368       case POC_RETURN:
6369       case POC_RETLW:
6370       case POC_RETFIE:
6371               /* unconditional branches -- do not link to next instruction */
6372               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6373               break;
6374               
6375       case POC_CALL:
6376       case POC_RCALL:
6377               /* unconditional calls -- link to next instruction */
6378               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6379               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6380               break;
6381               
6382       case POC_BC:
6383       case POC_BN:
6384       case POC_BNC:
6385       case POC_BNN:
6386       case POC_BNOV:
6387       case POC_BNZ:
6388       case POC_BOV:
6389       case POC_BZ:
6390               /* conditional branches -- also link to next instruction */
6391               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6392               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6393               break;
6394               
6395       default:
6396               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6397               assert (0 && "unhandled branching instruction");
6398               break;
6399       }
6400
6401       //fprintf(stderr, "ends with branch\n  ");
6402       //pc->print(stderr,pc);
6403
6404       if(!(pcol && isPCOLAB(pcol))) {
6405         if((PCI(pc)->op != POC_RETLW)
6406                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6407         
6408                 /* continue if label is '$' which assembler knows how to parse */
6409                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6410
6411                 if(pic16_pcode_verbose) {
6412                         pc->print(stderr,pc);
6413                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6414                 }
6415         }
6416         continue;
6417       }
6418
6419       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6420         LinkFlow_pCode(PCI(pc),PCI(pct));
6421       else
6422         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6423                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6424
6425 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6426
6427       continue;
6428     }
6429
6430     if(isPCI(pc)) {
6431       //fprintf(stderr, "ends with non-branching instruction:\n");
6432       //pc->print(stderr,pc);
6433
6434       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6435
6436       continue;
6437     }
6438
6439     if(pc) {
6440       //fprintf(stderr, "ends with unknown\n");
6441       //pc->print(stderr,pc);
6442       continue;
6443     }
6444
6445     //fprintf(stderr, "ends with nothing: ERROR\n");
6446     
6447   }
6448 }
6449 /*-----------------------------------------------------------------*/
6450 /*-----------------------------------------------------------------*/
6451
6452 /*-----------------------------------------------------------------*/
6453 /*-----------------------------------------------------------------*/
6454 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6455 {
6456
6457   if(!pc || !pcflow)
6458     return 0;
6459
6460   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6461     return 0;
6462
6463   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6464     return 1;
6465
6466   return 0;
6467 }
6468
6469
6470
6471
6472
6473 /*-----------------------------------------------------------------*/
6474 /* insertBankSwitch - inserts a bank switch statement in the       */
6475 /*                    assembly listing                             */
6476 /*                                                                 */
6477 /* position == 0: insert before                                    */
6478 /* position == 1: insert after pc                                  */
6479 /* position == 2: like 0 but previous was a skip instruction       */
6480 /*-----------------------------------------------------------------*/
6481 pCodeOp *pic16_popGetLabel(unsigned int key);
6482 extern int pic16_labelOffset;
6483
6484 static void insertBankSwitch(unsigned char position, pCode *pc)
6485 {
6486   pCode *new_pc;
6487
6488         if(!pc)
6489                 return;
6490
6491         /* emit BANKSEL [symbol] */
6492
6493
6494         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6495         
6496 //      position = 0;           // position is always before (sanity check!)
6497
6498 #if 0
6499         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6500         pc->print(stderr, pc);
6501 #endif
6502
6503         switch(position) {
6504                 case 1: {
6505                         /* insert the bank switch after this pc instruction */
6506                         pCode *pcnext = pic16_findNextInstruction(pc);
6507
6508                                 pic16_pCodeInsertAfter(pc, new_pc);
6509                                 if(pcnext)pc = pcnext;
6510                 }; break;
6511                 
6512                 case 0:
6513                         /* insert the bank switch BEFORE this pc instruction */
6514                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6515                         break;
6516
6517                 case 2: {
6518                           symbol *tlbl;
6519                           pCode *pcnext, *pcprev, *npci, *ppc;
6520                           PIC_OPCODE ipci;
6521                           int ofs1=0, ofs2=0, len=0;
6522                           
6523                         /* just like 0, but previous was a skip instruction,
6524                          * so some care should be taken */
6525                           
6526                                 pic16_labelOffset += 10000;
6527                                 tlbl = newiTempLabel(NULL);
6528                                 
6529                                 /* invert skip instruction */
6530                                 pcprev = pic16_findPrevInstruction(pc->prev);
6531                                 ipci = PCI(pcprev)->inverted_op;
6532                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6533
6534 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6535
6536                                 /* copy info from old pCode */
6537                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6538                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6539                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6540                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6541                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6542                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6543                                 
6544                                 /* unlink old pCode */
6545                                 ppc = pcprev->prev;
6546                                 ppc->next = pcprev->next;
6547                                 pcprev->next->prev = ppc;
6548                                 pic16_pCodeInsertAfter(ppc, npci);
6549                                 
6550                                 /* extra instructions to handle invertion */
6551                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6552                                 pic16_pCodeInsertAfter(npci, pcnext);
6553                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6554                                 
6555                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6556                                 pic16_pCodeInsertAfter(pc, pcnext);
6557                         }; break;
6558         }
6559         
6560
6561         /* Move the label, if there is one */
6562         if(PCI(pc)->label) {
6563 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6564 //                      __FILE__, __LINE__, pc, new_pc);
6565                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6566                 PCI(pc)->label = NULL;
6567         }
6568 }
6569
6570
6571 /*-----------------------------------------------------------------*/
6572 /*int compareBankFlow - compare the banking requirements between   */
6573 /*  flow objects. */
6574 /*-----------------------------------------------------------------*/
6575 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6576 {
6577
6578   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6579     return 0;
6580
6581   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6582     return 0;
6583
6584   if(pcflow->firstBank == -1)
6585     return 0;
6586
6587
6588   if(pcflowLink->pcflow->firstBank == -1) {
6589     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6590                                         pcflowLink->pcflow->to : 
6591                                         pcflowLink->pcflow->from);
6592     return compareBankFlow(pcflow, pctl, toORfrom);
6593   }
6594
6595   if(toORfrom) {
6596     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6597       return 0;
6598
6599     pcflowLink->bank_conflict++;
6600     pcflowLink->pcflow->FromConflicts++;
6601     pcflow->ToConflicts++;
6602   } else {
6603     
6604     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6605       return 0;
6606
6607     pcflowLink->bank_conflict++;
6608     pcflowLink->pcflow->ToConflicts++;
6609     pcflow->FromConflicts++;
6610
6611   }
6612   /*
6613   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6614           pcflowLink->pcflow->pc.seq,
6615           pcflowLink->pcflow->FromConflicts,
6616           pcflowLink->pcflow->ToConflicts);
6617   */
6618   return 1;
6619
6620 }
6621
6622 #if 0
6623 /*-----------------------------------------------------------------*/
6624 /*-----------------------------------------------------------------*/
6625 static void DumpFlow(pBlock *pb)
6626 {
6627   pCode *pc=NULL;
6628   pCode *pcflow;
6629   pCodeFlowLink *pcfl;
6630
6631
6632   fprintf(stderr,"Dump flow \n");
6633   pb->pcHead->print(stderr, pb->pcHead);
6634
6635   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6636   pcflow->print(stderr,pcflow);
6637
6638   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6639        pcflow != NULL;
6640        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6641
6642     if(!isPCFL(pcflow)) {
6643       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6644       continue;
6645     }
6646     fprintf(stderr,"dumping: ");
6647     pcflow->print(stderr,pcflow);
6648     FlowStats(PCFL(pcflow));
6649
6650     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6651
6652       pc = PCODE(pcfl->pcflow);
6653
6654       fprintf(stderr, "    from seq %d:\n",pc->seq);
6655       if(!isPCFL(pc)) {
6656         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6657         pc->print(stderr,pc);
6658       }
6659
6660     }
6661
6662     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6663
6664       pc = PCODE(pcfl->pcflow);
6665
6666       fprintf(stderr, "    to seq %d:\n",pc->seq);
6667       if(!isPCFL(pc)) {
6668         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6669         pc->print(stderr,pc);
6670       }
6671
6672     }
6673
6674   }
6675
6676 }
6677 #endif
6678 /*-----------------------------------------------------------------*/
6679 /*-----------------------------------------------------------------*/
6680 static int OptimizepBlock(pBlock *pb)
6681 {
6682   pCode *pc, *pcprev;
6683   int matches =0;
6684
6685   if(!pb || !peepOptimizing)
6686     return 0;
6687
6688   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6689 /*
6690   for(pc = pb->pcHead; pc; pc = pc->next)
6691     matches += pic16_pCodePeepMatchRule(pc);
6692 */
6693
6694   pc = pic16_findNextInstruction(pb->pcHead);
6695   if(!pc)
6696     return 0;
6697
6698   pcprev = pc->prev;
6699   do {
6700
6701
6702     if(pic16_pCodePeepMatchRule(pc)) {
6703
6704       matches++;
6705
6706       if(pcprev)
6707         pc = pic16_findNextInstruction(pcprev->next);
6708       else 
6709         pc = pic16_findNextInstruction(pb->pcHead);
6710     } else
6711       pc = pic16_findNextInstruction(pc->next);
6712   } while(pc);
6713
6714   if(matches)
6715     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6716   return matches;
6717
6718 }
6719
6720 /*-----------------------------------------------------------------*/
6721 /*-----------------------------------------------------------------*/
6722 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6723 {
6724   pCode *pc;
6725
6726   for(pc = pcs; pc; pc = pc->next) {
6727
6728     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6729        (PCI(pc)->pcop) && 
6730        (PCI(pc)->pcop->type == PO_LABEL) &&
6731        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6732       return pc;
6733   }
6734  
6735
6736   return NULL;
6737 }
6738
6739 /*-----------------------------------------------------------------*/
6740 /*-----------------------------------------------------------------*/
6741 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6742 {
6743
6744   char *s=NULL;
6745
6746   if(isPCI(pc) && 
6747      (PCI(pc)->pcop) && 
6748      (PCI(pc)->pcop->type == PO_LABEL)) {
6749
6750     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6751
6752 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6753 //    if(pcol->pcop.name)
6754 //      Safe_free(pcol->pcop.name);
6755
6756     /* If the key is negative, then we (probably) have a label to
6757      * a function and the name is already defined */
6758        
6759     if(pcl->key>0)
6760       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6761     else 
6762       s = pcl->label;
6763
6764     //sprintf(buffer,"_%05d_DS_",pcl->key);
6765     if(!s) {
6766       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6767     }
6768     pcol->pcop.name = Safe_strdup(s);
6769     pcol->key = pcl->key;
6770     //pc->print(stderr,pc);
6771
6772   }
6773
6774
6775 }
6776
6777 /*-----------------------------------------------------------------*/
6778 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6779 /*                            pCode chain if they're not used.     */
6780 /*-----------------------------------------------------------------*/
6781 static void pBlockRemoveUnusedLabels(pBlock *pb)
6782 {
6783   pCode *pc; pCodeLabel *pcl;
6784
6785   if(!pb)
6786     return;
6787
6788   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6789
6790     pBranch *pbr = PCI(pc)->label;
6791     if(pbr && pbr->next) {
6792       pCode *pcd = pb->pcHead;
6793
6794 //      fprintf(stderr, "multiple labels\n");
6795 //      pc->print(stderr,pc);
6796
6797       pbr = pbr->next;
6798       while(pbr) {
6799
6800         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6801           //fprintf(stderr,"Used by:\n");
6802           //pcd->print(stderr,pcd);
6803
6804           exchangeLabels(PCL(pbr->pc),pcd);
6805
6806           pcd = pcd->next;
6807         }
6808         pbr = pbr->next;
6809       }
6810     }
6811   }
6812
6813   for(pc = pb->pcHead; pc; pc = pc->next) {
6814
6815     if(isPCL(pc)) // pc->type == PC_LABEL)
6816       pcl = PCL(pc);
6817     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6818       pcl = PCL(PCI(pc)->label->pc);
6819     else continue;
6820
6821 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6822
6823     /* This pCode is a label, so search the pBlock to see if anyone
6824      * refers to it */
6825
6826     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6827         && (!pcl->force)) {
6828     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6829       /* Couldn't find an instruction that refers to this label
6830        * So, unlink the pCode label from it's pCode chain
6831        * and destroy the label */
6832 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6833
6834       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6835       if(pc->type == PC_LABEL) {
6836         pic16_unlinkpCode(pc);
6837         pCodeLabelDestruct(pc);
6838       } else {
6839         unlinkpCodeFromBranch(pc, PCODE(pcl));
6840         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6841           Safe_free(pc->label);
6842         }*/
6843       }
6844
6845     }
6846   }
6847
6848 }
6849
6850
6851 /*-----------------------------------------------------------------*/
6852 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6853 /*                     chain and put them into pBranches that are  */
6854 /*                     associated with the appropriate pCode       */
6855 /*                     instructions.                               */
6856 /*-----------------------------------------------------------------*/
6857 void pic16_pBlockMergeLabels(pBlock *pb)
6858 {
6859   pBranch *pbr;
6860   pCode *pc, *pcnext=NULL;
6861
6862   if(!pb)
6863     return;
6864
6865   /* First, Try to remove any unused labels */
6866   //pBlockRemoveUnusedLabels(pb);
6867
6868   /* Now loop through the pBlock and merge the labels with the opcodes */
6869
6870   pc = pb->pcHead;
6871   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6872
6873   while(pc) {
6874     pCode *pcn = pc->next;
6875
6876     if(pc->type == PC_LABEL) {
6877
6878 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6879 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6880
6881       if((pcnext = pic16_findNextInstruction(pc) )) {
6882
6883 //              pcnext->print(stderr, pcnext);
6884
6885         // Unlink the pCode label from it's pCode chain
6886         pic16_unlinkpCode(pc);
6887         
6888 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6889         // And link it into the instruction's pBranch labels. (Note, since
6890         // it's possible to have multiple labels associated with one instruction
6891         // we must provide a means to accomodate the additional labels. Thus
6892         // the labels are placed into the singly-linked list "label" as 
6893         // opposed to being a single member of the pCodeInstruction.)
6894
6895         //_ALLOC(pbr,sizeof(pBranch));
6896 #if 1
6897         pbr = Safe_calloc(1,sizeof(pBranch));
6898         pbr->pc = pc;
6899         pbr->next = NULL;
6900
6901         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6902 #endif
6903       } else {
6904         if(pic16_pcode_verbose)
6905         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6906       }
6907     } else if(pc->type == PC_CSOURCE) {
6908
6909       /* merge the source line symbolic info into the next instruction */
6910       if((pcnext = pic16_findNextInstruction(pc) )) {
6911
6912         // Unlink the pCode label from it's pCode chain
6913         pic16_unlinkpCode(pc);
6914         PCI(pcnext)->cline = PCCS(pc);
6915         //fprintf(stderr, "merging CSRC\n");
6916         //genericPrint(stderr,pcnext);
6917       }
6918
6919     }
6920     pc = pcn;
6921   }
6922   pBlockRemoveUnusedLabels(pb);
6923
6924 }
6925
6926 /*-----------------------------------------------------------------*/
6927 /*-----------------------------------------------------------------*/
6928 static int OptimizepCode(char dbName)
6929 {
6930 #define MAX_PASSES 4
6931
6932   int matches = 0;
6933   int passes = 0;
6934   pBlock *pb;
6935
6936   if(!the_pFile)
6937     return 0;
6938
6939   DFPRINTF((stderr," Optimizing pCode\n"));
6940
6941   do {
6942     matches = 0;
6943     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6944       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6945         matches += OptimizepBlock(pb);
6946     }
6947   }
6948   while(matches && ++passes < MAX_PASSES);
6949
6950   return matches;
6951 }
6952
6953
6954
6955 const char *pic16_pCodeOpType(pCodeOp *pcop);
6956 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6957
6958
6959 /*-----------------------------------------------------------------*/
6960 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6961 /*-----------------------------------------------------------------*/
6962
6963 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6964 {
6965   pCodeOp *pcop=NULL;
6966
6967 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6968
6969   if(pc->name) {
6970         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6971   } else {
6972     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6973   }
6974
6975   assert(pcop != NULL);
6976
6977   if( !( (pcop->type == PO_LABEL) ||
6978          (pcop->type == PO_LITERAL) ||
6979          (pcop->type == PO_STR) ))
6980     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6981     PCOR(pcop)->r->wasUsed = 1;
6982     PCOR(pcop)->instance = PCOR(pc)->instance;
6983
6984   return pcop;
6985 }
6986
6987
6988 /*----------------------------------------------------------------------*
6989  * pic16_areRegsSame - check to see if the names of two registers match *
6990  *----------------------------------------------------------------------*/
6991 int pic16_areRegsSame(regs *r1, regs *r2)
6992 {
6993         if(!strcmp(r1->name, r2->name))return 1;
6994
6995   return 0;
6996 }
6997
6998
6999 /*-----------------------------------------------------------------*/
7000 /*-----------------------------------------------------------------*/
7001 static void pic16_FixRegisterBanking(pBlock *pb)
7002 {
7003   pCode *pc=NULL;
7004   pCode *pcprev=NULL;
7005   regs *reg, *prevreg;
7006   unsigned char flag=0;
7007   
7008         if(!pb)
7009                 return;
7010
7011         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
7012         if(!pc)return;
7013
7014         /* loop through all of the flow blocks with in one pblock */
7015
7016 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
7017
7018         prevreg = NULL;
7019         do {
7020                 /* at this point, pc should point to a PC_FLOW object */
7021                 /* for each flow block, determine the register banking 
7022                  * requirements */
7023
7024                 
7025                 /* if label, then might come from other point, force banksel */
7026                 if(isPCL(pc))prevreg = NULL;
7027                 
7028                 if(!isPCI(pc))goto loop;
7029
7030                 if(PCI(pc)->label)prevreg = NULL;
7031
7032                 if(PCI(pc)->is2MemOp)goto loop;
7033
7034                 /* if goto, then force banksel */
7035 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
7036        
7037                 reg = pic16_getRegFromInstruction(pc);
7038
7039 #if 0
7040                 pc->print(stderr, pc);
7041                 fprintf(stderr, "reg = %p\n", reg);
7042
7043                 if(reg) {
7044                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
7045                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
7046                                 reg->address,reg->isBitField, reg->isFixed);
7047                 }
7048 #endif
7049
7050                 /* now make some tests to make sure that instruction needs bank switch */
7051
7052                 /* if no register exists, and if not a bit opcode goto loop */
7053                 if(!reg) {
7054                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
7055                 }
7056                  
7057                 if(isPCI_SKIP(pc)) {
7058 //                      fprintf(stderr, "instruction is SKIP instruction\n");
7059 //                prevreg = NULL;
7060                 }
7061                 if(reg && isACCESS_BANK(reg))goto loop;
7062
7063                 if(!isBankInstruction(pc))goto loop;
7064
7065                 if(isPCI_LIT(pc))goto loop;
7066          
7067                 if(PCI(pc)->op == POC_CALL)goto loop;
7068
7069                 /* Examine the instruction before this one to make sure it is
7070                  * not a skip type instruction */
7071                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7072
7073                 flag = 0;               /* add before this instruction */
7074                 
7075                 /* if previous instruction is a skip one, then set flag
7076                  * to 2 and call insertBankSwitch */
7077                 if(pcprev && isPCI_SKIP(pcprev)) {
7078                   flag=2;       //goto loop
7079 //                prevreg = NULL;
7080                 }
7081                  
7082                 if(pic16_options.opt_banksel>0) {
7083                   char op1[128], op2[128];
7084                   
7085                     if(prevreg) {
7086                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7087                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7088                       if(!strcmp(op1, op2))goto loop;
7089                     }
7090                 }
7091                 prevreg = reg;
7092                 insertBankSwitch(flag, pc);
7093
7094 //              fprintf(stderr, "BANK SWITCH inserted\n");
7095                 
7096 loop:
7097                 pcprev = pc;
7098                 pc = pc->next;
7099         } while (pc);
7100 }
7101
7102 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7103
7104 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7105 int instrSize (pCode *pc)
7106 {
7107   if (!pc) return 0;
7108
7109   if (isPCAD(pc)) {
7110     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7111     return 4; // assumes only regular instructions using <= 4 bytes
7112   }
7113
7114   if (isPCI(pc)) return PCI(pc)->isize;
7115
7116   return 0;
7117 }
7118
7119 /* Returns 1 if pc is referenced by the given label (either
7120  * pc is the label itself or is an instruction with an attached
7121  * label).
7122  * Returns 0 if pc is not preceeded by the specified label.
7123  */
7124 int isLabel (pCode *pc, char *label)
7125 {
7126   if (!pc) return 0;
7127
7128   // label attached to the pCode?  
7129   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7130     pBranch *lab = NULL;
7131     lab = PCI(pc)->label;
7132
7133     while (lab) {
7134       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7135         return 1;
7136       }
7137       lab = lab->next;
7138     } // while
7139   } // if
7140
7141   // is inline assembly label?
7142   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7143     // do not compare trailing ':'
7144     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7145       return 1;
7146     }
7147   } // if
7148   
7149   // is pCodeLabel?
7150   if (isPCL(pc)) {
7151       if (strcmp(PCL(pc)->label,label) == 0) {
7152       return 1;
7153     }
7154   } // if
7155   
7156   // no label/no label attached/wrong label(s)
7157   return 0;
7158 }
7159
7160 /* Returns the distance to the given label in terms of words.
7161  * Labels are searched only within -max .. max words from pc.
7162  * Returns max if the label could not be found or
7163  * its distance from pc in (-max..+max).
7164  */
7165 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7166   int dist = instrSize(pc);
7167   pCode *curr = pc;
7168
7169   // search backwards
7170   while (dist < max && curr && !isLabel (curr, label)) {
7171     curr = curr->prev;
7172     dist += instrSize(curr); // sizeof (instruction)
7173   } // while
7174   if (curr && dist < max) {
7175     if (target != NULL) *target = curr;
7176     return -dist;
7177   }
7178
7179   dist = 0;
7180   curr = pic16_findNextInstruction (pc->next);
7181   //search forwards
7182   while (dist < max && curr && !isLabel (curr, label)) {
7183     dist += instrSize(curr); // sizeof (instruction)
7184     curr = curr->next;
7185   } // while
7186   if (curr && dist < max) {
7187     if (target != NULL) *target = curr;
7188     return dist;
7189   }
7190
7191   if (target != NULL) *target = NULL;
7192   return max;
7193 }
7194
7195 /* Returns -1 if pc does NOT denote an instruction like
7196  * BTFS[SC] STATUS,i
7197  * Otherwise we return 
7198  *   (a) 0x10 + i for BTFSS
7199  *   (b) 0x00 + i for BTFSC
7200  */
7201 int isSkipOnStatus (pCode *pc)
7202 {
7203   int res = -1;
7204   pCodeOp *pcop;
7205   if (!pc || !isPCI(pc)) return -1;
7206   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7207   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7208   else return -1;
7209
7210   pcop = PCI(pc)->pcop;
7211
7212   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7213     return res + ((pCodeOpRegBit *)pcop)->bit;
7214   }
7215
7216   return -1;
7217 }
7218
7219 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7220  * returns 0 otherwise. */
7221 int isConditionalBranch (pCode *pc)
7222 {
7223   if (!pc || !isPCI_BRANCH(pc)) return 0;
7224
7225   switch (PCI(pc)->op) {
7226   case POC_BC:
7227   case POC_BZ:
7228   case POC_BOV:
7229   case POC_BN:
7230   case POC_BNC:
7231   case POC_BNZ:
7232   case POC_BNOV:
7233   case POC_BNN:
7234     return 1;
7235
7236   default:
7237     break;
7238   } // switch
7239
7240   return 0;
7241 }
7242
7243 /* Returns 1 if pc has a label attached to it.
7244  * This can be either a label stored in the pCode itself (.label)
7245  * or a label making up its own pCode preceding this pc.
7246  * Returns 0 if pc cannot be reached directly via a label.
7247  */
7248 int hasNoLabel (pCode *pc)
7249 {
7250   pCode *prev;
7251   if (!pc) return 1;
7252
7253   // are there any label pCodes between pc and the previous instruction?
7254   prev = pic16_findPrevInstruction (pc->prev);
7255   while (pc && pc != prev) {
7256     // pCode with attached label?
7257     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7258         && PCI(pc)->label) {
7259       return 0;
7260     }
7261     // is inline assembly label?
7262     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7263     if (isPCW(pc) && PCW(pc)->label) return 0;
7264
7265     // pCodeLabel?
7266     if (isPCL(pc)) return 0;
7267
7268     pc = pc->prev;
7269   } // if
7270
7271   // no label found
7272   return 1;
7273 }
7274
7275 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7276   char buf[512];
7277   va_list va;
7278
7279   va_start (va, fmt);
7280   vsprintf (buf, fmt, va);
7281   va_end (va);
7282
7283   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7284 }
7285
7286 /* Replaces the old pCode with the new one, moving the labels,
7287  * C source line and probably flow information to the new pCode.
7288  */
7289 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7290   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7291     return;
7292
7293   /* first move all labels from old to new */
7294   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7295   PCI(oldPC)->label = NULL;
7296   
7297 #if 0
7298   /* move C source line (if possible) */
7299   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7300     PCI(newPC)->cline = PCI(oldPC)->cline;
7301 #endif
7302
7303   /* keep flow information intact */
7304   newPC->seq = oldPC->seq;
7305   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7306   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7307     PCI(newPC)->pcflow->end = newPC;
7308   }
7309
7310   /* insert a comment stating which pCode has been replaced */
7311 #if 1
7312   if (pic16_pcode_verbose || pic16_debug_verbose) {
7313     char pc_str[256];
7314     pic16_pCode2str (pc_str, 256, oldPC);
7315     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7316   }
7317 #endif
7318   
7319   /* insert new pCode into pBlock */
7320   pic16_pCodeInsertAfter (oldPC, newPC);
7321   pic16_unlinkpCode (oldPC);
7322   
7323   /* destruct replaced pCode */
7324   oldPC->destruct (oldPC);
7325 }
7326
7327 /* Returns the inverted conditional branch (if any) or NULL.
7328  * pcop must be set to the new jump target.
7329  */
7330 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7331 {
7332   pCode *newBcc;
7333
7334   if (!bcc || !isPCI(bcc)) return NULL;
7335
7336   switch (PCI(bcc)->op) {
7337   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7338   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7339   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7340   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7341   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7342   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7343   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7344   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7345   default:
7346     newBcc = NULL;
7347   }
7348   return newBcc;
7349 }
7350
7351 #define MAX_DIST_GOTO         0x7FFFFFFF
7352 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7353 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7354 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7355 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7356
7357 /* Follows GOTO/BRA instructions to their target instructions, stores the
7358  * final destination (not a GOTO or BRA instruction) in target and returns
7359  * the distance from the original pc to *target.
7360  */
7361 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7362         pCode *curr = pc;
7363         pCode *last = NULL;
7364         pCodeOp *lastPCOP = NULL;
7365         int dist = 0;
7366         int depth = 0;
7367
7368         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7369
7370         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7371         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7372                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7373                 last = curr;
7374                 lastPCOP = PCI(curr)->pcop;
7375                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7376                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7377         } // while
7378
7379         if (target) *target = last;
7380         if (pcop) *pcop = lastPCOP;
7381         return dist;
7382 }
7383
7384 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7385  * Otherwise the first pCode after the jumptable (after
7386  * the OPT_JUMPTABLE_END tag) is returned.
7387  */
7388 pCode *skipJumptables (pCode *pc, int *isJumptable)
7389 {
7390   *isJumptable = 0;
7391   if (!pc) return NULL;
7392   
7393   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7394     *isJumptable = 1;
7395     //fprintf (stderr, "SKIPPING jumptable\n");
7396     do {
7397       //pc->print(stderr, pc);
7398       pc = pc->next;
7399     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7400                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7401     //fprintf (stderr, "<<JUMPTAB:\n");
7402     // skip OPT_END as well
7403     if (pc) pc = pc->next;
7404   } // while
7405
7406   return pc;
7407 }
7408
7409 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7410 {
7411   int isJumptab;
7412   *isJumptable = 0;
7413   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7414     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7415     pc = skipJumptables (pc, &isJumptab);
7416     if (isJumptab) {
7417         // pc is the first pCode after the jumptable
7418         *isJumptable = 1;
7419     } else {
7420         // pc has not been changed by skipJumptables()
7421         pc = pc->next;
7422     }
7423   } // while
7424   
7425   return pc;
7426 }
7427
7428 /* Turn GOTOs into BRAs if distance between GOTO and label
7429  * is less than 1024 bytes.
7430  *
7431  * This method is especially useful if GOTOs after BTFS[SC]
7432  * can be turned into BRAs as GOTO would cost another NOP
7433  * if skipped.
7434  */
7435 void pic16_OptimizeJumps ()
7436 {
7437   pCode *pc;
7438   pCode *pc_prev = NULL;
7439   pCode *pc_next = NULL;
7440   pBlock *pb;
7441   pCode *target;
7442   int change, iteration, isJumptab;
7443   int isHandled = 0;
7444   char *label;
7445   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7446   
7447   if (!the_pFile) return;
7448   
7449   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7450   
7451   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7452     int matchedInvertRule = 1;
7453     iteration = 1;
7454     do {
7455       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7456       change = 0;
7457       pc = pic16_findNextInstruction (pb->pcHead);
7458     
7459       while (pc) {
7460         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7461         if (isJumptab) {
7462                 // skip jumptable, i.e. start over with no pc_prev!     
7463                 pc_prev = NULL;
7464                 pc = pc_next;
7465                 continue;
7466         } // if
7467
7468         /* (1) resolve chained jumps
7469          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7470          * (a) leave dead code in and
7471          * (b) skip over the dead code with an (unneccessary) jump.
7472          */
7473         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7474           pCodeOp *lastTargetOp = NULL;
7475           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7476           int maxDist = MAX_DIST_BCC;
7477           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7478           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7479           
7480           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7481           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7482               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7483             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7484             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7485             PCI(pc)->pcop->name = lastTargetOp->name;
7486             change++;
7487             opt_gotochain++;
7488           } // if
7489         } // if
7490
7491
7492         if (IS_GOTO(pc)) {
7493           int dist;
7494           int condBraType = isSkipOnStatus(pc_prev);
7495           label = PCI(pc)->pcop->name;
7496           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7497           if (dist < 0) dist = -dist;
7498           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7499           isHandled = 0;
7500           
7501           
7502           /* (2) remove "GOTO label; label:" */
7503           if (isLabel (pc_next, label)) {
7504             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7505             // first remove all preceeding SKIP instructions
7506             while (pc_prev && isPCI_SKIP(pc_prev)) {
7507               // attach labels on this instruction to pc_next
7508               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7509               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7510               PCI(pc_prev)->label = NULL;
7511               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7512               pic16_unlinkpCode (pc_prev);
7513               pc_prev = pic16_findPrevInstruction (pc);
7514             } // while
7515             // now remove the redundant goto itself
7516             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7517             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7518             pic16_unlinkpCode (pc);
7519             pc = pic16_findPrevInstruction(pc_next->prev);
7520             isHandled = 1; // do not perform further optimizations
7521             opt_gotonext++;
7522             change++;
7523           } // if
7524           
7525           
7526           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7527           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7528             if (dist < MAX_DIST_BCC) {
7529               pCode *bcc = NULL;
7530               switch (condBraType) {
7531               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7532                 // no BDC on DIGIT CARRY available
7533               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7534               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7535               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7536               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7537                 // no BNDC on DIGIT CARRY available
7538               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7539               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7540               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7541               default:
7542                 // no replacement possible
7543                 bcc = NULL;
7544                 break;
7545               } // switch
7546               if (bcc) {
7547                 // ATTENTION: keep labels attached to BTFSx!
7548                 // HINT: GOTO is label free (checked above)
7549                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7550                 isHandled = 1; // do not perform further optimizations
7551                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7552                 pic16_pCodeReplace (pc_prev, bcc);
7553                 pc->destruct(pc);
7554                 pc = bcc;
7555                 opt_cond++;
7556                 change++;
7557               } // if
7558             } else {
7559               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7560               cond_toofar++;
7561             } // if
7562           } // if
7563
7564           if (!isHandled) {
7565             // (4) eliminate the following (common) tripel:
7566             //           <pred.>;
7567             //  labels1: Bcc label2;
7568             //           GOTO somewhere;    ; <-- instruction referenced by pc
7569             //  label2:  <cont.>
7570             // and replace it by
7571             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7572             //  label2:  <cont.>
7573             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7574             //            to <cont.> instead
7575             // ATTENTION: This optimization is only valid if <pred.> is
7576             //            not a skip operation!
7577             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7578             // ATTENTION: no label may be attached to the GOTO instruction!
7579             if (isConditionalBranch(pc_prev)
7580                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7581                 && (dist < MAX_DIST_BCC)
7582                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7583                 && hasNoLabel(pc)) {
7584               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7585             
7586               if (newBcc) {
7587                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7588                 isHandled = 1; // do not perform further optimizations
7589                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7590                 pic16_pCodeReplace (pc_prev, newBcc);
7591                 pc->destruct(pc);
7592                 pc = newBcc;
7593                 opt_reorder++;
7594                 change++;
7595                 matchedInvertRule++;
7596               }
7597             }
7598           }
7599           
7600           /* (5) now just turn GOTO into BRA */ 
7601           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7602             if (dist < MAX_DIST_BRA) {
7603               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7604               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7605               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7606               pic16_pCodeReplace (pc, newBra);
7607               pc = newBra;
7608               opt++;
7609               change++;
7610             } else {
7611               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7612               toofar++;
7613             }
7614           } // if (!isHandled)
7615         } // if
7616
7617         pc_prev = pc;
7618         pc = pc_next;
7619       } // while (pc)
7620       
7621       pBlockRemoveUnusedLabels (pb);
7622       
7623       // This line enables goto chain resolution!
7624       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7625
7626       iteration++;
7627     } while (change); /* fixpoint iteration per pBlock */
7628   } // for (pb)
7629   
7630   // emit some statistics concerning goto-optimization
7631 #if 0
7632   if (pic16_debug_verbose || pic16_pcode_verbose) {
7633     fprintf (stderr, "optimize-goto:\n"
7634              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7635              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7636              "\t%5d conditional \"skipping\" jumps inverted\n"
7637              "\t%5d GOTOs to next instruction removed\n"
7638              "\t%5d chained GOTOs resolved\n",
7639              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7640   } // if
7641 #endif
7642   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7643 }
7644
7645 #undef IS_GOTO
7646 #undef MAX_JUMPCHAIN_DEPTH
7647 #undef MAX_DIST_GOTO
7648 #undef MAX_DIST_BRA
7649 #undef MAX_DIST_BCC
7650
7651 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7652
7653 static void pBlockDestruct(pBlock *pb)
7654 {
7655
7656   if(!pb)
7657     return;
7658
7659
7660 //  Safe_free(pb);
7661
7662 }
7663
7664 /*-----------------------------------------------------------------*/
7665 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7666 /*                                  name dbName and combine them   */
7667 /*                                  into one block                 */
7668 /*-----------------------------------------------------------------*/
7669 static void mergepBlocks(char dbName)
7670 {
7671
7672   pBlock *pb, *pbmerged = NULL,*pbn;
7673
7674   pb = the_pFile->pbHead;
7675
7676   //fprintf(stderr," merging blocks named %c\n",dbName);
7677   while(pb) {
7678
7679     pbn = pb->next;
7680     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7681     if( getpBlock_dbName(pb) == dbName) {
7682
7683       //fprintf(stderr," merged block %c\n",dbName);
7684
7685       if(!pbmerged) {
7686         pbmerged = pb;
7687       } else {
7688         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7689         /* pic16_addpCode2pBlock doesn't handle the tail: */
7690         pbmerged->pcTail = pb->pcTail;
7691
7692         pb->prev->next = pbn;
7693         if(pbn) 
7694           pbn->prev = pb->prev;
7695
7696
7697         pBlockDestruct(pb);
7698       }
7699       //pic16_printpBlock(stderr, pbmerged);
7700     } 
7701     pb = pbn;
7702   }
7703
7704 }
7705
7706 /*-----------------------------------------------------------------*/
7707 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7708 /*                                                                 */
7709 /* level 0 == minimal optimization                                 */
7710 /*   optimize registers that are used only by two instructions     */
7711 /* level 1 == maximal optimization                                 */
7712 /*   optimize by looking at pairs of instructions that use the     */
7713 /*   register.                                                     */
7714 /*-----------------------------------------------------------------*/
7715
7716 static void AnalyzeFlow(int level)
7717 {
7718   static int times_called=0;
7719   pBlock *pb;
7720
7721     if(!the_pFile) {
7722       /* remove unused allocated registers before exiting */
7723       pic16_RemoveUnusedRegisters();
7724       return;
7725     }
7726
7727
7728     /* if this is not the first time this function has been called,
7729      * then clean up old flow information */
7730     if(times_called++) {
7731       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7732         unBuildFlow(pb);
7733         pic16_RegsUnMapLiveRanges();
7734     }
7735     GpcFlowSeq = 1;
7736
7737     /* Phase 2 - Flow Analysis - Register Banking
7738      *
7739      * In this phase, the individual flow blocks are examined
7740      * and register banking is fixed.
7741      */
7742
7743 #if 0
7744     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7745       pic16_FixRegisterBanking(pb);
7746 #endif
7747
7748     /* Phase 2 - Flow Analysis
7749      *
7750      * In this phase, the pCode is partition into pCodeFlow 
7751      * blocks. The flow blocks mark the points where a continuous
7752      * stream of instructions changes flow (e.g. because of
7753      * a call or goto or whatever).
7754      */
7755
7756     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7757       pic16_BuildFlow(pb);
7758
7759
7760     /* Phase 2 - Flow Analysis - linking flow blocks
7761      *
7762      * In this phase, the individual flow blocks are examined
7763      * to determine their order of excution.
7764      */
7765
7766     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7767       LinkFlow(pb);
7768
7769 #if 1
7770         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7771                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7772                         pic16_createDF (pb);
7773 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7774                         pic16_vcg_dump_default (pb);
7775 #endif
7776                         //pic16_destructDF (pb);
7777                 }
7778
7779                 pic16_df_stats ();
7780                 if (0) releaseStack (); // releasing is costly...
7781         }
7782 #endif
7783
7784     /* Phase 3 - Flow Analysis - Flow Tree
7785      *
7786      * In this phase, the individual flow blocks are examined
7787      * to determine their order of execution.
7788      */
7789
7790     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7791       pic16_BuildFlowTree(pb);
7792
7793
7794     /* Phase x - Flow Analysis - Used Banks
7795      *
7796      * In this phase, the individual flow blocks are examined
7797      * to determine the Register Banks they use
7798      */
7799
7800 #if 0
7801     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7802       FixBankFlow(pb);
7803 #endif
7804
7805
7806     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7807       pic16_pCodeRegMapLiveRanges(pb);
7808
7809     pic16_RemoveUnusedRegisters();
7810     pic16_removeUnusedRegistersDF ();
7811
7812   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7813     pic16_pCodeRegOptimizeRegUsage(level);
7814
7815
7816 #if 0
7817     if(!options.nopeep)
7818       OptimizepCode('*');
7819 #endif
7820
7821 #if 0
7822     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7823       DumpFlow(pb);
7824 #endif
7825
7826     /* debug stuff */ 
7827     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7828       pCode *pcflow;
7829       
7830         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7831           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7832           pcflow = pcflow->next) {
7833             FillFlow(PCFL(pcflow));
7834         }
7835     }
7836
7837 #if 0
7838     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7839       pCode *pcflow;
7840
7841         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7842           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7843           pcflow = pcflow->next) {
7844             FlowStats(PCFL(pcflow));
7845         }
7846     }
7847 #endif
7848 }
7849
7850 /* VR -- no need to analyze banking in flow, but left here :
7851  *      1. because it may be used in the future for other purposes
7852  *      2. because if omitted we'll miss some optimization done here
7853  *
7854  * Perhaps I should rename it to something else
7855  */
7856
7857 /*-----------------------------------------------------------------*/
7858 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7859 /*                  assigned to the registers.                     */
7860 /*                                                                 */
7861 /*-----------------------------------------------------------------*/
7862
7863 void pic16_AnalyzeBanking(void)
7864 {
7865   pBlock  *pb;
7866
7867     /* Phase x - Flow Analysis - Used Banks
7868      *
7869      * In this phase, the individual flow blocks are examined
7870      * to determine the Register Banks they use
7871      */
7872
7873     AnalyzeFlow(0);
7874     AnalyzeFlow(1);
7875
7876     if(!options.nopeep)
7877       OptimizepCode('*');
7878
7879
7880     if(!the_pFile)return;
7881
7882     if(!pic16_options.no_banksel) {
7883       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7884 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7885         pic16_FixRegisterBanking(pb);
7886       }
7887     }
7888 }
7889
7890 /*-----------------------------------------------------------------*/
7891 /* buildCallTree - Look at the flow and extract all of the calls.  */
7892 /*-----------------------------------------------------------------*/
7893 static set *register_usage(pBlock *pb);
7894
7895 static void buildCallTree(void    )
7896 {
7897   pBranch *pbr;
7898   pBlock  *pb;
7899   pCode   *pc;
7900   regs *r;
7901   
7902   if(!the_pFile)
7903     return;
7904
7905
7906
7907   /* Now build the call tree.
7908      First we examine all of the pCodes for functions.
7909      Keep in mind that the function boundaries coincide
7910      with pBlock boundaries. 
7911
7912      The algorithm goes something like this:
7913      We have two nested loops. The outer loop iterates
7914      through all of the pBlocks/functions. The inner
7915      loop iterates through all of the pCodes for
7916      a given pBlock. When we begin iterating through
7917      a pBlock, the variable pc_fstart, pCode of the start
7918      of a function, is cleared. We then search for pCodes
7919      of type PC_FUNCTION. When one is encountered, we
7920      initialize pc_fstart to this and at the same time
7921      associate a new pBranch object that signifies a 
7922      branch entry. If a return is found, then this signifies
7923      a function exit point. We'll link the pCodes of these
7924      returns to the matching pc_fstart.
7925
7926      When we're done, a doubly linked list of pBranches
7927      will exist. The head of this list is stored in
7928      `the_pFile', which is the meta structure for all
7929      of the pCode. Look at the pic16_printCallTree function
7930      on how the pBranches are linked together.
7931
7932    */
7933   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7934     pCode *pc_fstart=NULL;
7935     for(pc = pb->pcHead; pc; pc = pc->next) {
7936
7937         if(isPCI(pc) && pc_fstart) {
7938                 if(PCI(pc)->is2MemOp) {
7939                         r = pic16_getRegFromInstruction2(pc);
7940                         if(r && !strcmp(r->name, "POSTDEC1"))
7941                                 PCF(pc_fstart)->stackusage++;
7942                 } else {
7943                         r = pic16_getRegFromInstruction(pc);
7944                         if(r && !strcmp(r->name, "PREINC1"))
7945                                 PCF(pc_fstart)->stackusage--;
7946                 }
7947         }
7948
7949       if(isPCF(pc)) {
7950         if (PCF(pc)->fname) {
7951         char buf[16];
7952
7953           sprintf(buf, "%smain", port->fun_prefix);
7954           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7955             //fprintf(stderr," found main \n");
7956             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7957             pb->dbName = 'M';
7958           }
7959
7960           pbr = Safe_calloc(1,sizeof(pBranch));
7961           pbr->pc = pc_fstart = pc;
7962           pbr->next = NULL;
7963
7964           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7965
7966           // Here's a better way of doing the same:
7967           addSet(&pb->function_entries, pc);
7968
7969         } else {
7970           // Found an exit point in a function, e.g. return
7971           // (Note, there may be more than one return per function)
7972           if(pc_fstart)
7973             pBranchLink(PCF(pc_fstart), PCF(pc));
7974
7975           addSet(&pb->function_exits, pc);
7976         }
7977       } else if(isCALL(pc)) {
7978         addSet(&pb->function_calls,pc);
7979       }
7980     }
7981   }
7982
7983
7984 #if 0
7985   /* This is not needed because currently all register used
7986    * by a function are stored in stack -- VR */
7987    
7988   /* Re-allocate the registers so that there are no collisions
7989    * between local variables when one function call another */
7990
7991   // this is weird...
7992   //  pic16_deallocateAllRegs();
7993
7994   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7995     if(!pb->visited)
7996       register_usage(pb);
7997   }
7998 #endif
7999
8000 }
8001
8002 /*-----------------------------------------------------------------*/
8003 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
8004 /*                all of the logical connections.                  */
8005 /*                                                                 */
8006 /* Essentially what's done here is that the pCode flow is          */
8007 /* determined.                                                     */
8008 /*-----------------------------------------------------------------*/
8009
8010 void pic16_AnalyzepCode(char dbName)
8011 {
8012   pBlock *pb;
8013   int i,changes;
8014
8015   if(!the_pFile)
8016     return;
8017
8018   mergepBlocks('D');
8019
8020
8021   /* Phase 1 - Register allocation and peep hole optimization
8022    *
8023    * The first part of the analysis is to determine the registers
8024    * that are used in the pCode. Once that is done, the peep rules
8025    * are applied to the code. We continue to loop until no more
8026    * peep rule optimizations are found (or until we exceed the
8027    * MAX_PASSES threshold). 
8028    *
8029    * When done, the required registers will be determined.
8030    *
8031    */
8032   i = 0;
8033   do {
8034
8035     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
8036     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
8037
8038     /* First, merge the labels with the instructions */
8039     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8040       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
8041
8042         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
8043         //fprintf(stderr," analyze and merging block %c\n",dbName);
8044         pic16_pBlockMergeLabels(pb);
8045         AnalyzepBlock(pb);
8046       } else {
8047         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
8048       }
8049     }
8050
8051         if(!options.nopeep)
8052                 changes = OptimizepCode(dbName);
8053         else changes = 0;
8054
8055   } while(changes && (i++ < MAX_PASSES));
8056
8057   
8058   buildCallTree();
8059 }
8060
8061
8062 /* convert a series of movff's of local regs to stack, with a single call to
8063  * a support functions which does the same thing via loop */
8064 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8065 {
8066   pBranch *pbr;
8067   pCode *pc, *pct;
8068   char *fname[]={"__lr_store", "__lr_restore"};
8069
8070 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8071
8072     pct = pic16_findNextInstruction(pcstart->next);
8073     do {
8074       pc = pct;
8075       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8076 //      pc->print(stderr, pc);
8077       if(isPCI(pc) && PCI(pc)->label) {
8078         pbr = PCI(pc)->label;
8079         while(pbr && pbr->pc) {
8080           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8081           pbr = pbr->next;
8082         }
8083
8084 //        pc->print(stderr, pc);
8085         /* unlink pCode */
8086         pc->prev->next = pct;
8087         pct->prev = pc->prev;
8088 //        pc->next = NULL;
8089 //        pc->prev = NULL;
8090       }
8091     } while ((pc) && (pc != pcend));
8092
8093     /* unlink movff instructions */
8094     pcstart->next = pcend;
8095     pcend->prev = pcstart;
8096
8097     pc = pcstart;
8098 //    if(!entry) {
8099 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8100 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8101 //    }
8102                 
8103     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8104     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8105     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8106
8107 //    if(!entry) {
8108 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8109 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8110 //    }
8111
8112     
8113     {
8114       symbol *sym;
8115
8116         sym = newSymbol( fname[ entry?0:1 ], 0 );
8117         strcpy(sym->rname, fname[ entry?0:1 ]);
8118         checkAddSym(&externs, sym);
8119         
8120 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8121     }
8122
8123 }
8124
8125 /*-----------------------------------------------------------------*/
8126 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8127 /*    local registers to a support function call                   */
8128 /*-----------------------------------------------------------------*/
8129 void pic16_OptimizeLocalRegs(void)
8130 {
8131   pBlock  *pb;
8132   pCode   *pc;
8133   pCodeInfo *pci;
8134   pCodeOpLocalReg *pclr;
8135   int regCount=0;
8136   int inRegCount=0;
8137   regs *r, *lastr=NULL, *firstr=NULL;
8138   pCode *pcstart=NULL, *pcend=NULL;
8139   int inEntry=0;
8140   char *curFunc=NULL;
8141
8142         /* Overview:
8143          *   local_regs begin mark
8144          *      MOVFF r0x01, POSTDEC1
8145          *      MOVFF r0x02, POSTDEC1
8146          *      ...
8147          *      ...
8148          *      MOVFF r0x0n, POSTDEC1
8149          *   local_regs end mark
8150          *
8151          * convert the above to the below:
8152          *      MOVLW   starting_register_index
8153          *      MOVWF   PRODL
8154          *      MOVLW   register_count
8155          *      call    __save_registers_in_stack
8156          */
8157
8158     if(!the_pFile)
8159       return;
8160
8161     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8162       inRegCount = regCount = 0;
8163       firstr = lastr = NULL;
8164       for(pc = pb->pcHead; pc; pc = pc->next) {
8165
8166         /* hold current function name */
8167         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8168         
8169         if(pc && (pc->type == PC_INFO)) {
8170           pci = PCINF(pc);
8171
8172           if(pci->type == INF_LOCALREGS) {
8173             pclr = PCOLR(pci->oper1);
8174             
8175             if((pclr->type == LR_ENTRY_BEGIN)
8176               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8177             else inEntry = 0;
8178             
8179             switch(pclr->type) {
8180               case LR_ENTRY_BEGIN:
8181               case LR_EXIT_BEGIN:
8182                         inRegCount = 1; regCount = 0;
8183                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8184                         firstr = lastr = NULL;
8185                         break;
8186               
8187               case LR_ENTRY_END:
8188               case LR_EXIT_END:
8189                         inRegCount = -1;
8190                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8191
8192 #if 1
8193                         if(curFunc && inWparamList(curFunc+1)) {
8194                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8195                                         filename, curFunc);
8196                         } else {
8197                           if(regCount>2) {
8198                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8199                               firstr, inEntry);
8200                           }
8201                         }
8202 #endif
8203                         firstr = lastr = NULL;
8204                         break;
8205             }
8206             
8207             if(inRegCount == -1) {
8208 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8209               regCount = 0;
8210               inRegCount = 0;
8211             }
8212           }
8213         } else {
8214           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8215             if(inEntry)
8216               r = pic16_getRegFromInstruction(pc);
8217             else
8218               r = pic16_getRegFromInstruction2(pc);
8219             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8220               if(!firstr)firstr = r;
8221               regCount++;
8222 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8223             }
8224           }
8225         }
8226       }
8227     }
8228 }
8229               
8230             
8231
8232
8233
8234 /*-----------------------------------------------------------------*/
8235 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8236 /*                   function                                      */
8237 /*-----------------------------------------------------------------*/
8238 static bool ispCodeFunction(pCode *pc)
8239 {
8240
8241   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8242     return 1;
8243
8244   return 0;
8245 }
8246
8247 /*-----------------------------------------------------------------*/
8248 /* findFunction - Search for a function by name (given the name)   */
8249 /*                in the set of all functions that are in a pBlock */
8250 /* (note - I expect this to change because I'm planning to limit   */
8251 /*  pBlock's to just one function declaration                      */
8252 /*-----------------------------------------------------------------*/
8253 static pCode *findFunction(char *fname)
8254 {
8255   pBlock *pb;
8256   pCode *pc;
8257   if(!fname)
8258     return NULL;
8259
8260   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8261
8262     pc = setFirstItem(pb->function_entries);
8263     while(pc) {
8264     
8265       if((pc->type == PC_FUNCTION) &&
8266          (PCF(pc)->fname) && 
8267          (strcmp(fname, PCF(pc)->fname)==0))
8268         return pc;
8269
8270       pc = setNextItem(pb->function_entries);
8271
8272     }
8273
8274   }
8275   return NULL;
8276 }
8277
8278 static void MarkUsedRegisters(set *regset)
8279 {
8280
8281   regs *r1,*r2;
8282
8283   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8284 //      fprintf(stderr, "marking register = %s\t", r1->name);
8285     r2 = pic16_regWithIdx(r1->rIdx);
8286 //      fprintf(stderr, "to register = %s\n", r2->name);
8287     r2->isFree = 0;
8288     r2->wasUsed = 1;
8289   }
8290 }
8291
8292 static void pBlockStats(FILE *of, pBlock *pb)
8293 {
8294
8295   pCode *pc;
8296   regs  *r;
8297
8298         if(!pic16_pcode_verbose)return;
8299         
8300   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8301
8302   // for now just print the first element of each set
8303   pc = setFirstItem(pb->function_entries);
8304   if(pc) {
8305     fprintf(of,";entry:  ");
8306     pc->print(of,pc);
8307   }
8308   pc = setFirstItem(pb->function_exits);
8309   if(pc) {
8310     fprintf(of,";has an exit\n");
8311     //pc->print(of,pc);
8312   }
8313
8314   pc = setFirstItem(pb->function_calls);
8315   if(pc) {
8316     fprintf(of,";functions called:\n");
8317
8318     while(pc) {
8319       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8320         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8321       }
8322       pc = setNextItem(pb->function_calls);
8323     }
8324   }
8325
8326   r = setFirstItem(pb->tregisters);
8327   if(r) {
8328     int n = elementsInSet(pb->tregisters);
8329
8330     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8331
8332     while (r) {
8333       fprintf(of,   ";   %s\n",r->name);
8334       r = setNextItem(pb->tregisters);
8335     }
8336   }
8337   
8338   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8339 }
8340
8341 /*-----------------------------------------------------------------*/
8342 /*-----------------------------------------------------------------*/
8343 #if 0
8344 static void sequencepCode(void)
8345 {
8346   pBlock *pb;
8347   pCode *pc;
8348
8349
8350   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8351
8352     pb->seq = GpCodeSequenceNumber+1;
8353
8354     for( pc = pb->pcHead; pc; pc = pc->next)
8355       pc->seq = ++GpCodeSequenceNumber;
8356   }
8357
8358 }
8359 #endif
8360
8361 /*-----------------------------------------------------------------*/
8362 /*-----------------------------------------------------------------*/
8363 static set *register_usage(pBlock *pb)
8364 {
8365   pCode *pc,*pcn;
8366   set *registers=NULL;
8367   set *registersInCallPath = NULL;
8368
8369   /* check recursion */
8370
8371   pc = setFirstItem(pb->function_entries);
8372
8373   if(!pc)
8374     return registers;
8375
8376   pb->visited = 1;
8377
8378   if(pc->type != PC_FUNCTION)
8379     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8380
8381   pc = setFirstItem(pb->function_calls);
8382   for( ; pc; pc = setNextItem(pb->function_calls)) {
8383
8384     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8385       char *dest = pic16_get_op_from_instruction(PCI(pc));
8386
8387       pcn = findFunction(dest);
8388       if(pcn) 
8389         registersInCallPath = register_usage(pcn->pb);
8390     } else
8391       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8392
8393   }
8394
8395 #ifdef PCODE_DEBUG
8396   pBlockStats(stderr,pb);  // debug
8397 #endif
8398
8399   // Mark the registers in this block as used.
8400
8401   MarkUsedRegisters(pb->tregisters);
8402   if(registersInCallPath) {
8403     /* registers were used in the functions this pBlock has called */
8404     /* so now, we need to see if these collide with the ones we are */
8405     /* using here */
8406
8407     regs *r1,*r2, *newreg;
8408
8409     DFPRINTF((stderr,"comparing registers\n"));
8410
8411     r1 = setFirstItem(registersInCallPath);
8412     while(r1) {
8413
8414       r2 = setFirstItem(pb->tregisters);
8415
8416       while(r2 && (r1->type != REG_STK)) {
8417
8418         if(r2->rIdx == r1->rIdx) {
8419           newreg = pic16_findFreeReg(REG_GPR);
8420
8421
8422           if(!newreg) {
8423             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8424             exit(1);
8425           }
8426
8427           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8428                   r1->rIdx, newreg->rIdx));
8429           r2->rIdx = newreg->rIdx;
8430           //if(r2->name) Safe_free(r2->name);
8431           if(newreg->name)
8432             r2->name = Safe_strdup(newreg->name);
8433           else
8434             r2->name = NULL;
8435           newreg->isFree = 0;
8436           newreg->wasUsed = 1;
8437         }
8438         r2 = setNextItem(pb->tregisters);
8439       }
8440
8441       r1 = setNextItem(registersInCallPath);
8442     }
8443
8444     /* Collisions have been resolved. Now free the registers in the call path */
8445     r1 = setFirstItem(registersInCallPath);
8446     while(r1) {
8447       if(r1->type != REG_STK) {
8448         newreg = pic16_regWithIdx(r1->rIdx);
8449         newreg->isFree = 1;
8450       }
8451       r1 = setNextItem(registersInCallPath);
8452     }
8453
8454   }// else
8455   //    MarkUsedRegisters(pb->registers);
8456
8457   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8458 #ifdef PCODE_DEBUG
8459   if(registers) 
8460     DFPRINTF((stderr,"returning regs\n"));
8461   else
8462     DFPRINTF((stderr,"not returning regs\n"));
8463
8464   DFPRINTF((stderr,"pBlock after register optim.\n"));
8465   pBlockStats(stderr,pb);  // debug
8466 #endif
8467
8468   return registers;
8469 }
8470
8471 /*-----------------------------------------------------------------*/
8472 /* pct2 - writes the call tree to a file                           */
8473 /*                                                                 */
8474 /*-----------------------------------------------------------------*/
8475 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8476 {
8477   pCode *pc,*pcn;
8478   int i;
8479   //  set *registersInCallPath = NULL;
8480
8481   if(!of)
8482     return;
8483
8484   if(indent > 10) {
8485         fprintf(of, "recursive function\n");
8486     return; //recursion ?
8487   }
8488
8489   pc = setFirstItem(pb->function_entries);
8490
8491   if(!pc)
8492     return;
8493
8494   pb->visited = 0;
8495
8496   for(i=0;i<indent;i++)   // Indentation
8497         fputs("+   ", of);
8498   fputs("+- ", of);
8499
8500   if(pc->type == PC_FUNCTION) {
8501     usedstack += PCF(pc)->stackusage;
8502     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8503   } else return;  // ???
8504
8505
8506   pc = setFirstItem(pb->function_calls);
8507   for( ; pc; pc = setNextItem(pb->function_calls)) {
8508
8509     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8510       char *dest = pic16_get_op_from_instruction(PCI(pc));
8511
8512       pcn = findFunction(dest);
8513       if(pcn) 
8514         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8515     } else
8516       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8517
8518   }
8519
8520
8521 }
8522
8523
8524 /*-----------------------------------------------------------------*/
8525 /* pic16_printCallTree - writes the call tree to a file                  */
8526 /*                                                                 */
8527 /*-----------------------------------------------------------------*/
8528
8529 void pic16_printCallTree(FILE *of)
8530 {
8531   pBranch *pbr;
8532   pBlock  *pb;
8533   pCode   *pc;
8534
8535   if(!the_pFile)
8536     return;
8537
8538   if(!of)
8539     of = stderr;
8540
8541   fprintf(of, "\npBlock statistics\n");
8542   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8543     pBlockStats(of,pb);
8544
8545
8546   fprintf(of,"Call Tree\n");
8547   pbr = the_pFile->functions;
8548   while(pbr) {
8549     if(pbr->pc) {
8550       pc = pbr->pc;
8551       if(!ispCodeFunction(pc))
8552         fprintf(of,"bug in call tree");
8553
8554
8555       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8556
8557       while(pc->next && !ispCodeFunction(pc->next)) {
8558         pc = pc->next;
8559         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8560           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8561       }
8562     }
8563
8564     pbr = pbr->next;
8565   }
8566
8567
8568   fprintf(of,"\n**************\n\na better call tree\n");
8569   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8570 //    if(pb->visited)
8571       pct2(of,pb,0,0);
8572   }
8573
8574   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8575     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8576   }
8577 }
8578
8579
8580
8581 /*-----------------------------------------------------------------*/
8582 /*                                                                 */
8583 /*-----------------------------------------------------------------*/
8584
8585 static void InlineFunction(pBlock *pb)
8586 {
8587   pCode *pc;
8588   pCode *pc_call;
8589
8590   if(!pb)
8591     return;
8592
8593   pc = setFirstItem(pb->function_calls);
8594
8595   for( ; pc; pc = setNextItem(pb->function_calls)) {
8596
8597     if(isCALL(pc)) {
8598       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8599       pCode *pct;
8600       pCode *pce;
8601
8602       pBranch *pbr;
8603
8604       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8605         
8606         //fprintf(stderr,"Cool can inline:\n");
8607         //pcn->print(stderr,pcn);
8608
8609         //fprintf(stderr,"recursive call Inline\n");
8610         InlineFunction(pcn->pb);
8611         //fprintf(stderr,"return from recursive call Inline\n");
8612
8613         /*
8614           At this point, *pc points to a CALL mnemonic, and
8615           *pcn points to the function that is being called.
8616
8617           To in-line this call, we need to remove the CALL
8618           and RETURN(s), and link the function pCode in with
8619           the CALLee pCode.
8620
8621         */
8622
8623
8624         /* Remove the CALL */
8625         pc_call = pc;
8626         pc = pc->prev;
8627
8628         /* remove callee pBlock from the pBlock linked list */
8629         removepBlock(pcn->pb);
8630
8631         pce = pcn;
8632         while(pce) {
8633           pce->pb = pb;
8634           pce = pce->next;
8635         }
8636
8637         /* Remove the Function pCode */
8638         pct = pic16_findNextInstruction(pcn->next);
8639
8640         /* Link the function with the callee */
8641         pc->next = pcn->next;
8642         pcn->next->prev = pc;
8643         
8644         /* Convert the function name into a label */
8645
8646         pbr = Safe_calloc(1,sizeof(pBranch));
8647         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8648         pbr->next = NULL;
8649         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8650         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8651
8652         /* turn all of the return's except the last into goto's */
8653         /* check case for 2 instruction pBlocks */
8654         pce = pic16_findNextInstruction(pcn->next);
8655         while(pce) {
8656           pCode *pce_next = pic16_findNextInstruction(pce->next);
8657
8658           if(pce_next == NULL) {
8659             /* found the last return */
8660             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8661
8662             //fprintf(stderr,"found last return\n");
8663             //pce->print(stderr,pce);
8664             pce->prev->next = pc_call->next;
8665             pc_call->next->prev = pce->prev;
8666             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8667                                                       PCI(pce)->label);
8668           }
8669
8670           pce = pce_next;
8671         }
8672
8673
8674       }
8675     } else
8676       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8677
8678   }
8679
8680 }
8681
8682 /*-----------------------------------------------------------------*/
8683 /*                                                                 */
8684 /*-----------------------------------------------------------------*/
8685
8686 void pic16_InlinepCode(void)
8687 {
8688
8689   pBlock  *pb;
8690   pCode   *pc;
8691
8692   if(!the_pFile)
8693     return;
8694
8695   if(!functionInlining)
8696     return;
8697
8698   /* Loop through all of the function definitions and count the
8699    * number of times each one is called */
8700   //fprintf(stderr,"inlining %d\n",__LINE__);
8701
8702   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8703
8704     pc = setFirstItem(pb->function_calls);
8705
8706     for( ; pc; pc = setNextItem(pb->function_calls)) {
8707
8708       if(isCALL(pc)) {
8709         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8710         if(pcn && isPCF(pcn)) {
8711           PCF(pcn)->ncalled++;
8712         }
8713       } else
8714         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8715
8716     }
8717   }
8718
8719   //fprintf(stderr,"inlining %d\n",__LINE__);
8720
8721   /* Now, Loop through the function definitions again, but this
8722    * time inline those functions that have only been called once. */
8723   
8724   InlineFunction(the_pFile->pbHead);
8725   //fprintf(stderr,"inlining %d\n",__LINE__);
8726
8727   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8728     unBuildFlow(pb);
8729
8730 }
8731
8732 char *pic_optype_names[]={
8733         "PO_NONE",         // No operand e.g. NOP
8734         "PO_W",              // The working register (as a destination)
8735         "PO_WREG",           // The working register (as a file register)
8736         "PO_STATUS",         // The 'STATUS' register
8737         "PO_BSR",            // The 'BSR' register
8738         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8739                              // of three)
8740         "PO_INDF0",          // The Indirect register
8741         "PO_INTCON",         // Interrupt Control register
8742         "PO_GPR_REGISTER",   // A general purpose register
8743         "PO_GPR_BIT",        // A bit of a general purpose register
8744         "PO_GPR_TEMP",       // A general purpose temporary register
8745         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8746         "PO_PCL",            // Program counter Low register
8747         "PO_PCLATH",         // Program counter Latch high register
8748         "PO_PCLATU",         // Program counter Latch upper register
8749         "PO_PRODL",          // Product Register Low
8750         "PO_PRODH",          // Product Register High
8751         "PO_LITERAL",        // A constant
8752         "PO_REL_ADDR",       // A relative address
8753         "PO_IMMEDIATE",      //  (8051 legacy)
8754         "PO_DIR",            // Direct memory (8051 legacy)
8755         "PO_CRY",            // bit memory (8051 legacy)
8756         "PO_BIT",            // bit operand.
8757         "PO_STR",            //  (8051 legacy)
8758         "PO_LABEL",
8759         "PO_WILD"            // Wild card operand in peep optimizer
8760 };
8761
8762
8763 char *dumpPicOptype(PIC_OPTYPE type)
8764 {
8765         return (pic_optype_names[ type ]);
8766 }
8767
8768
8769 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8770 #include "graph.h"
8771
8772 #define MAX_COMMON_BANK_SIZE    32
8773 #define FIRST_PSEUDO_BANK_NR  1000
8774
8775 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8776 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8777 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8778 Graph *adj = NULL;
8779
8780 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8781
8782 typedef struct {
8783   pseudoBankNr bank;  // number assigned to this pseudoBank
8784   unsigned int size;  // number of operands assigned to this bank
8785   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8786 } pseudoBank;
8787
8788 /*----------------------------------------------------------------------*/
8789 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8790 /*----------------------------------------------------------------------*/
8791 unsigned int hashSymbol (const char *str)
8792 {
8793   unsigned int res = 0;
8794   if (!str) return 0;
8795
8796   while (*str) {
8797     res ^= (*str);
8798     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8799     str++;
8800   } // while
8801
8802   return res;
8803 }
8804
8805 /*-----------------------------------------------------------------------*/
8806 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8807 /*-----------------------------------------------------------------------*/
8808 int compareSymbol (const void *sym1, const void *sym2)
8809 {
8810   char *s1 = (char*) sym1;
8811   char *s2 = (char*) sym2;
8812   
8813   return (strcmp (s1,s2) == 0);
8814 }
8815
8816 /*-----------------------------------------------------------------------*/
8817 /* comparePre - return 1 iff p1 == p2                                    */
8818 /*-----------------------------------------------------------------------*/
8819 int comparePtr (const void *p1, const void *p2)
8820 {
8821   return (p1 == p2);
8822 }
8823
8824 /*----------------------------------------------------------*/
8825 /* getSymbolFromOperand - return a pointer to the symbol in */
8826 /*                        the given operand and its length  */
8827 /*----------------------------------------------------------*/
8828 char *getSymbolFromOperand (char *op, int *len)
8829 {
8830   char *sym, *curr;
8831   *len = 0;
8832
8833   if (!op) return NULL;
8834
8835   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8836   sym = op;
8837   if (*sym == '(') sym++;
8838
8839   curr = sym;
8840   while (((*curr >= 'A') && (*curr <= 'Z'))
8841          || ((*curr >= 'a') && (*curr <= 'z'))
8842          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8843          || (*curr == '_')) {
8844     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8845     curr++;
8846     (*len)++;
8847   } // while
8848
8849   return sym;
8850 }
8851
8852 /*--------------------------------------------------------------------------*/
8853 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8854 /*--------------------------------------------------------------------------*/
8855 char *getSymFromBank (pseudoBankNr bank)
8856 {
8857   assert (bank2sym);
8858
8859   if (bank < 0) return "<INVALID BANK NR>";
8860   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8861 }
8862
8863 /*-----------------------------------------------------------------------*/
8864 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8865 /*                           bank number (uses hTab sym2bank), if the    */
8866 /*                           symbol is not yet assigned a pseudo bank it */
8867 /*                           is assigned one here                        */
8868 /*-----------------------------------------------------------------------*/
8869 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8870 {
8871   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8872   pseudoBankNr bank;
8873   unsigned int hash;
8874
8875   assert (sym2bank);
8876
8877   hash = hashSymbol (op) % sym2bank->size;
8878   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8879   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8880
8881   if (bank == UNKNOWN_BANK) {
8882     // create a pseudo bank for the operand
8883     bank = next_bank++;
8884     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8885     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8886     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8887     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8888   } else {
8889     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8890   } // if
8891
8892   assert (bank >= 0);
8893
8894   return bank;
8895 }
8896
8897 /*--------------------------------------------------------------------*/
8898 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8899 /*--------------------------------------------------------------------*/
8900 int isBanksel (pCode *pc)
8901 {
8902   if (!pc) return 0;
8903
8904   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8905     // BANKSEL <variablename>  or  MOVLB <banknr>
8906     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8907     return 1;
8908   }
8909
8910   // check for inline assembler BANKSELs
8911   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8912                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8913     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8914     return 1;
8915   }
8916
8917   // assume pc is no BANKSEL instruction
8918   return 0;
8919 }
8920
8921 /*---------------------------------------------------------------------------------*/
8922 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8923 /*                  This method can not guarantee to find all modifications of the */
8924 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8925 /*                  generated plus some cases.                                     */
8926 /*---------------------------------------------------------------------------------*/
8927 int invalidatesBSR(pCode *pc)
8928 {
8929   // assembler directives invalidate BSR (well, they might, we don't know)
8930   if (isPCAD(pc)) return 1;
8931
8932   // only ASMDIRs and pCodeInstructions can invalidate BSR
8933   if (!isPCI(pc)) return 0;
8934
8935   // we have a pCodeInstruction
8936
8937   // check for BSR modifying instructions
8938   switch (PCI(pc)->op) {
8939   case POC_CALL:
8940   case POC_RCALL:
8941   case POC_MOVLB:
8942   case POC_RETFIE:  // might be used as CALL replacement
8943   case POC_RETLW:   // might be used as CALL replacement
8944   case POC_RETURN:  // might be used as CALL replacement
8945   case POC_BANKSEL:
8946     return 1;
8947     break;
8948
8949   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8950     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8951     break;
8952   } // switch
8953
8954   // no change of BSR possible/probable
8955   return 0;
8956 }
8957
8958 /*------------------------------------------------------------*/
8959 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8960 /*                      the symbol referenced in this BANKSEL */
8961 /*------------------------------------------------------------*/
8962 pseudoBankNr getBankFromBanksel (pCode *pc)
8963 {
8964   char *sym;
8965   int data = (int)NULL;
8966
8967   if (!pc) return INVALID_BANK;
8968   
8969   if (isPCAD(pc) && PCAD(pc)->directive) {
8970     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8971       // get symbolname from PCAD(pc)->arg
8972       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8973       sym = PCAD(pc)->arg;
8974       data = getPseudoBankNrFromOperand (sym);
8975       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8976     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8977       // get (literal) bank number from PCAD(pc)->arg
8978       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8979       assert (0 && "not yet implemented - turn off banksel optimization for now");
8980     }
8981   } else if (isPCI(pc)) {
8982     if (PCI(pc)->op == POC_BANKSEL) {
8983       // get symbolname from PCI(pc)->pcop->name (?)
8984       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8985       sym = PCI(pc)->pcop->name;
8986       data = getPseudoBankNrFromOperand (sym);
8987       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8988     } else if (PCI(pc)->op == POC_MOVLB) {
8989       // get (literal) bank number from PCI(pc)->pcop->name
8990       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8991       assert (0 && "not yet implemented - turn off banksel optimization for now");
8992     }
8993   }
8994   
8995   if (data == 0)
8996     // no assigned bank could be found
8997     return UNKNOWN_BANK;
8998   else
8999     return data;
9000 }
9001
9002 /*------------------------------------------------------------------------------*/
9003 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
9004 /*------------------------------------------------------------------------------*/
9005 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
9006 {
9007   pseudoBank *data;
9008
9009   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
9010
9011   do {
9012     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
9013     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
9014     if (data) {
9015       if (data->bank != bank)
9016         bank = data->bank;
9017       else
9018         data = NULL;
9019     }
9020   } while (data);
9021   
9022   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
9023   return bank;
9024 }
9025
9026 /*------------------------------------------------------------------*/
9027 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
9028 /*                        bank is selected at a given pCode         */
9029 /*------------------------------------------------------------------*/
9030
9031 /* Create a graph with pseudo banks as its nodes and switches between
9032  * these as edges (with the edge weight representing the absolute
9033  * number of BANKSELs from one to the other).
9034  * Removes redundand BANKSELs instead iff mod == 1.
9035  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
9036  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
9037  * pseudo BSR.
9038  * TODO: check ALL instructions operands if they modify BSR directly...
9039  *
9040  * pb - the pBlock to annotate
9041  * mod  - select either graph creation (0) or BANKSEL removal (1)
9042  */
9043 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
9044 {
9045   pCode *pc, *pc_next;
9046   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
9047   int isBankselect = 0;
9048   unsigned int banksels=0;
9049   
9050   if (!pb) return 0;
9051
9052   pc = pic16_findNextInstruction(pb->pcHead);
9053   while (pc) {
9054     isBankselect = isBanksel (pc);
9055     pc_next = pic16_findNextInstruction (pc->next);
9056
9057     if (!hasNoLabel (pc)) {
9058       // we don't know our predecessors -- assume different BSRs
9059       prevBSR = UNKNOWN_BANK;
9060       pseudoBSR = UNKNOWN_BANK;
9061       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9062     } // if
9063
9064     // check if this is a BANKSEL instruction
9065     if (isBankselect) {
9066       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9067       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9068       if (mod) {
9069         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9070           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9071           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9072           pic16_unlinkpCode (pc);
9073           banksels++;
9074         }
9075       } else {
9076         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9077         banksels++;
9078       }
9079     } // if
9080
9081     if (!isBankselect && invalidatesBSR(pc)) {
9082       // check if this instruction invalidates the pseudoBSR
9083       pseudoBSR = UNKNOWN_BANK;
9084       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9085     } // if
9086
9087     prevBSR = pseudoBSR;
9088     pc = pc_next;
9089   } // while
9090
9091   return banksels;
9092 }
9093
9094 /*------------------------------------------------------------------------------------*/
9095 /* assignToSameBank - returns 0 on success or an error code                           */
9096 /*  1 - common bank would be too large                                                */
9097 /*  2 - assignment to fixed (absolute) bank not performed                             */
9098 /*                                                                                    */
9099 /* This functions assumes that unsplittable operands are already assigned to the same */
9100 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9101 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9102 /* TODO: Symbols with an abslute address must be handled specially!                   */
9103 /*------------------------------------------------------------------------------------*/
9104 int assignToSameBank (int bank0, int bank1, int doAbs)
9105 {
9106   int eff0, eff1, dummy;
9107   pseudoBank *pbank0, *pbank1;
9108   hashtItem *hitem;
9109
9110   eff0 = getEffectiveBank (bank0);
9111   eff1 = getEffectiveBank (bank1);
9112
9113   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9114
9115   // nothing to do if already same bank
9116   if (eff0 == eff1) return 0;
9117
9118   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9119     return 2;
9120
9121   // ensure eff0 < eff1
9122   if (eff0 > eff1) {
9123     // swap eff0 and eff1
9124     dummy = eff0;
9125     eff0 = eff1;
9126     eff1 = dummy;
9127     dummy = bank0;
9128     bank0 = bank1;
9129     bank1 = dummy;
9130   } // if
9131
9132   // now assign bank eff1 to bank eff0
9133   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9134   if (!pbank0) {
9135     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9136     pbank0->bank = eff0;
9137     pbank0->size = 1;
9138     pbank0->ref = 1;
9139     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9140   } // if
9141
9142   pbank1 = NULL;
9143   hitem = hTabSearch (coerce, eff1 % coerce->size);
9144   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9145     hitem = hitem->next;
9146
9147   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9148
9149 #if 0
9150   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9151            pbank0->bank, pbank0->size,
9152            getSymFromBank (eff0), getSymFromBank (eff1));
9153 #endif
9154
9155   if (pbank1) {
9156     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9157 #if 0
9158       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9159                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9160                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9161                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9162 #endif
9163       return 1;
9164     } // if
9165     pbank0->size += pbank1->size;
9166     pbank1->ref--;
9167     if (pbank1->ref == 0) Safe_free (pbank1);
9168   } else {
9169     pbank0->size++;
9170   } // if
9171
9172   if (hitem)
9173     hitem->item = pbank0;
9174   else  
9175     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9176   pbank0->ref++;
9177
9178   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9179
9180   return 0;
9181 }
9182
9183 /*----------------------------------------------------------------*/
9184 /* mergeGraphNodes - combines two nodes into one and modifies all */
9185 /*                   edges to and from the nodes accordingly      */
9186 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9187 /* then also (B,A) must be an edge (possibly with weight 0).      */
9188 /*----------------------------------------------------------------*/
9189 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9190 {
9191   GraphEdge *edge, *backedge, *nextedge;
9192   GraphNode *node;
9193   int backweight;
9194
9195   assert (node1 && node2);
9196   assert (node1 != node2);
9197   
9198   // add all edges starting at node2 to node1
9199   edge = node2->edge;
9200   while (edge) {
9201     nextedge = edge->next;
9202     node = edge->node;
9203     backedge = getGEdge (node, node2);
9204     if (backedge)
9205       backweight = backedge->weight;
9206     else
9207       backweight = 0;
9208     // insert edges (node1,node) and (node,node1)
9209     addGEdge2 (node1, node, edge->weight, backweight);
9210     // remove edges (node, node2) and (node2, node)
9211     remGEdge (node2, node);
9212     remGEdge (node, node2);
9213     edge = nextedge;
9214   } // while
9215   
9216   // now node2 should not be referenced by any other GraphNode...
9217   //remGNode (adj, node2->data, node2->hash);
9218 }
9219
9220 /*----------------------------------------------------------------*/
9221 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9222 /*----------------------------------------------------------------*/
9223 void showGraph (Graph *g)
9224 {
9225   GraphNode *node;
9226   GraphEdge *edge;
9227   pseudoBankNr bankNr;
9228   pseudoBank *pbank;
9229   unsigned int size;
9230
9231   node = g->node;
9232   while (node) {
9233     edge = node->edge;
9234     bankNr = getEffectiveBank (node->hash);
9235     assert (bankNr >= 0);
9236     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9237     if (pbank) {
9238       bankNr = pbank->bank;
9239       size = pbank->size;
9240     } else {
9241       size = 1;
9242     }
9243     
9244     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9245
9246     while (edge) {
9247       if (edge->weight > 0)
9248         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9249       edge = edge->next;
9250     } // while (edge)
9251     node = node->next;
9252   } // while (node)
9253 }
9254
9255 /*---------------------------------------------------------------*/
9256 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9257 /*---------------------------------------------------------------*/
9258 void pic16_OptimizeBanksel ()
9259 {
9260   GraphNode *node, *node1, *node1next;
9261
9262 #if 0
9263   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9264   GraphEdge *edge, *backedge;
9265   GraphEdge *max;
9266   int maxWeight, weight, mergeMore, absMaxWeight;
9267   pseudoBankNr curr0, curr1;
9268 #endif
9269   pseudoBank *pbank;
9270   pseudoBankNr bankNr;
9271   char *base_symbol0, *base_symbol1;
9272   int len0, len1;
9273   pBlock *pb;
9274   set *set;
9275   regs *reg;
9276   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9277
9278   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9279
9280   if (!the_pFile || !the_pFile->pbHead) return;
9281
9282   adj = newGraph (NULL);
9283   sym2bank = newHashTable ( 255 );
9284   bank2sym = newHashTable ( 255 );
9285   coerce = newHashTable ( 255 );
9286
9287   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9288   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9289     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9290   } // for pb
9291
9292 #if 1
9293   // assign symbols with absolute addresses to their respective bank nrs
9294   set = pic16_fix_udata;
9295   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9296     bankNr = reg->address >> 8;
9297     node = getOrAddGNode (adj, NULL, bankNr);
9298     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9299     assignToSameBank (node->hash, bankNr, 1);
9300     
9301     assert (bankNr >= 0);
9302     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9303     if (!pbank) {
9304       pbank = Safe_calloc (1, sizeof (pseudoBank));
9305       pbank->bank = reg->address >> 8; //FIXED_BANK;
9306       pbank->size = 1;
9307       pbank->ref = 1;
9308       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9309     } else {
9310       assert (pbank->bank == (reg->address >> 8));
9311       pbank->bank = reg->address >> 8; //FIXED_BANK;
9312     }
9313     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9314   } // for reg
9315 #endif
9316
9317 #if 1
9318   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9319   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9320   node = adj->node;
9321   while (node) {
9322     if (node->hash < 0) { node = node->next; continue; }
9323     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9324     node1 = node->next;
9325     while (node1) {
9326       if (node1->hash < 0) { node1 = node1->next; continue; }
9327       node1next = node1->next;
9328       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9329       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9330         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9331         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9332         if (assignToSameBank (node->hash, node1->hash, 0)) {
9333           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9334           assert (0 && "Could not assign a symbol to a bank!");
9335         }
9336         mergeGraphNodes (node, node1);
9337         /*
9338         if (node->hash < node1->hash)
9339           mergeGraphNodes (node, node1);
9340         else
9341           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9342         */
9343       } // if
9344       node1 = node1next;
9345     } // while (node1)
9346     node = node->next;
9347   } // while (node)
9348 #endif
9349
9350 #if 0
9351   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9352   // assign tightly coupled operands to the same (pseudo) bank
9353   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9354   mergeMore = 1;
9355   absMaxWeight = 0;
9356   while (mergeMore) {
9357     node = adj->node;
9358     max = NULL;
9359     maxWeight = 0;
9360     while (node) {
9361       curr0 = getEffectiveBank (node->hash);
9362       if (curr0 < 0) { node = node->next; continue; }
9363       edge = node->edge;
9364       while (edge) {
9365         assert (edge->src == node);
9366         backedge = getGEdge (edge->node, edge->src);
9367         weight = edge->weight + (backedge ? backedge->weight : 0);
9368         curr1 = getEffectiveBank (edge->node->hash);
9369         if (curr1 < 0) { edge = edge->next; continue; }
9370
9371         // merging is only useful if the items are not assigned to the same bank already...
9372         if (curr0 != curr1 && weight > maxWeight) {
9373           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9374           maxWeight = weight;
9375           max = edge;
9376         } // if
9377         edge = edge->next;
9378       } // while
9379       node = node->next;
9380     } // while
9381     
9382     if (maxWeight > 0) {
9383 #if 0
9384       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9385                max->src->hash, getSymFromBank (max->src->hash),
9386                max->node->hash, getSymFromBank (max->node->hash));
9387 #endif
9388
9389       node = getGNode (adj, max->src->data, max->src->hash);
9390       node1 = getGNode (adj, max->node->data, max->node->hash);
9391
9392       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9393         if (max->src->hash < max->node->hash)
9394           mergeGraphNodes (node, node1);
9395         else
9396           mergeGraphNodes (node1, node);
9397       } else {
9398         remGEdge (node, node1);
9399         remGEdge (node1, node);
9400         //mergeMore = 0;
9401       }
9402
9403     } else {
9404       mergeMore = 0;
9405     }
9406   } // while
9407 #endif
9408
9409 #if 1  
9410   // remove redundant BANKSELs
9411   //fprintf (stderr, "removing redundant BANKSELs\n");
9412   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9413     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9414   } // for pb
9415 #endif
9416
9417 #if 0
9418   fprintf (stderr, "display graph\n");
9419   showGraph ();
9420 #endif
9421
9422   deleteGraph (adj);
9423   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9424 }
9425
9426 /*** END of stuff belonging to the BANKSEL optimization ***/
9427
9428
9429
9430 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9431
9432 typedef unsigned int symbol_t;
9433 typedef unsigned int valnum_t;
9434 //typedef unsigned int hash_t;
9435
9436 #ifndef INT_TO_PTR
9437 #define INT_TO_PTR(x) (((char *) 0) + (x))
9438 #endif
9439
9440 #ifndef PTR_TO_INT
9441 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9442 #endif
9443
9444 static int pic16_regIsLocal (regs *r);
9445 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9446
9447 /* statistics */
9448 static unsigned int pic16_df_removed_pcodes = 0;
9449 static unsigned int pic16_df_saved_bytes = 0;
9450 static unsigned int df_findall_sameflow = 0;
9451 static unsigned int df_findall_otherflow = 0;
9452 static unsigned int df_findall_in_vals = 0;
9453
9454 static void pic16_df_stats () {
9455   return;
9456   if (pic16_debug_verbose || pic16_pcode_verbose) {
9457     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9458     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9459     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9460   }
9461 }
9462
9463 /* Remove a pCode iff possible:
9464  * - previous pCode is no SKIP
9465  * - pc has no label
9466  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9467 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9468   pCode *pcprev, *pcnext;
9469   char buf[256], *total=NULL;
9470   int len;
9471   
9472   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9473
9474   pcprev = pic16_findPrevInstruction (pc->prev);
9475   pcnext = pic16_findNextInstruction (pc->next);
9476   
9477   /* move labels to next instruction (if possible) */
9478   if (PCI(pc)->label && !pcnext) return 0;
9479
9480   /* if this is a SKIP with side-effects -- do not remove */
9481   /* XXX: might try to replace this one with the side-effect only version */
9482   if (isPCI_SKIP(pc)
9483         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9484   {
9485     pCode *newpc;
9486     switch (PCI(pc)->op)
9487     {
9488     case POC_INCFSZ:
9489     case POC_INFSNZ:
9490       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9491       pic16_pCodeReplace( pc, newpc );
9492       return 1;
9493       break;
9494     case POC_INCFSZW:
9495       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9496       pic16_pCodeReplace( pc, newpc );
9497       return 1;
9498       break;
9499     case POC_DECFSZ:
9500     case POC_DCFSNZ:
9501       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9502       pic16_pCodeReplace( pc, newpc );
9503       return 1;
9504       break;
9505     case POC_DECFSZW:
9506       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9507       pic16_pCodeReplace( pc, newpc );
9508       return 1;
9509       break;
9510     default:
9511       return 0;
9512     }
9513     return 0;
9514   }
9515
9516   /* if previous instruction is a skip -- do not remove */
9517   if (pcprev && isPCI_SKIP(pcprev)) {
9518     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9519       /* preceeding SKIP could not be removed -- keep this instruction! */
9520       return 0;
9521     }
9522   }
9523
9524   if (PCI(pc)->label) {
9525     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9526     //pc->print (stderr, pc);
9527     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9528     PCI(pc)->label = NULL;
9529   }
9530   
9531   /* update statistics */
9532   pic16_df_removed_pcodes++;
9533   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9534   
9535   /* remove the pCode */
9536   pic16_pCode2str (buf, 256, pc);
9537   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9538   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9539     len = strlen (buf) + strlen (comment) + 10;
9540     total = (char *) Safe_malloc (len);
9541     SNPRINTF (total, len, "%s: %s", comment, buf);
9542     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9543     Safe_free (total);
9544   }
9545
9546   /* actually unlink it from the pBlock -- also remove from to/from lists */
9547   pic16_pCodeUnlink (pc);
9548
9549   /* remove the pCode -- release registers */
9550   pc->destruct (pc);
9551
9552   /* report success */
9553   return 1;
9554 }
9555
9556
9557 /* ======================================================================== */
9558 /* === SYMBOL HANDLING ==================================================== */
9559 /* ======================================================================== */
9560
9561 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9562 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9563 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9564
9565 /** Calculate a hash for a given string.
9566  * If len == 0 the string is assumed to be NUL terminated. */
9567 static hash_t symbolHash (const char *str, unsigned int len) {
9568   hash_t hash = 0;
9569   if (!len) {
9570     while (*str) {
9571       hash = (hash << 2) ^ *str;
9572       str++;
9573     } // while
9574   } else {
9575     while (len--) {
9576       hash = (hash << 2) ^ *str;
9577       str++;
9578     }
9579   }
9580   return hash;
9581 }
9582
9583 /** Return 1 iff strings v1 and v2 are identical. */
9584 static int symcmp (const void *v1, const void *v2) {
9585   return !strcmp ((const char *) v1, (const char *) v2);
9586 }
9587
9588 /** Return 1 iff pointers v1 and v2 are identical. */
9589 static int ptrcmp (const void *v1, const void *v2) {
9590   return (v1 == v2);
9591 }
9592
9593 enum {  SPO_WREG=0x1000,
9594         SPO_STATUS,
9595         SPO_PRODL,
9596         SPO_PRODH,
9597         SPO_INDF0,
9598         SPO_POSTDEC0,
9599         SPO_POSTINC0,
9600         SPO_PREINC0,
9601         SPO_PLUSW0,
9602         SPO_INDF1,
9603         SPO_POSTDEC1,
9604         SPO_POSTINC1,
9605         SPO_PREINC1,
9606         SPO_PLUSW1,
9607         SPO_INDF2,
9608         SPO_POSTDEC2,
9609         SPO_POSTINC2,
9610         SPO_PREINC2,
9611         SPO_PLUSW2,
9612         SPO_STKPTR,
9613         SPO_TOSL,
9614         SPO_TOSH,
9615         SPO_TOSU,
9616         SPO_BSR,
9617         SPO_FSR0L,
9618         SPO_FSR0H,
9619         SPO_FSR1L,
9620         SPO_FSR1H,
9621         SPO_FSR2L,
9622         SPO_FSR2H,
9623         SPO_PCL,
9624         SPO_PCLATH,
9625         SPO_PCLATU,
9626         SPO_TABLAT,
9627         SPO_TBLPTRL,
9628         SPO_TBLPTRH,
9629         SPO_TBLPTRU,
9630         SPO_LAST
9631 };
9632
9633 /* Return the unique symbol_t for the given string. */
9634 static symbol_t symFromStr (const char *str) {
9635   hash_t hash;
9636   char *res;
9637   symbol_t sym;
9638
9639   if (!map_symToStr) {
9640     int i;
9641     struct { char *name; symbol_t sym; } predefsyms[] = {
9642         {"WREG", SPO_WREG},
9643         {"STATUS", SPO_STATUS},
9644         {"PRODL", SPO_PRODL},
9645         {"PRODH", SPO_PRODH},
9646         {"INDF0", SPO_INDF0},
9647         {"POSTDEC0", SPO_POSTDEC0},
9648         {"POSTINC0", SPO_POSTINC0},
9649         {"PREINC0", SPO_PREINC0},
9650         {"PLUSW0", SPO_PLUSW0},
9651         {"INDF1", SPO_INDF1},
9652         {"POSTDEC1", SPO_POSTDEC1},
9653         {"POSTINC1", SPO_POSTINC1},
9654         {"PREINC1", SPO_PREINC1},
9655         {"PLUSW1", SPO_PLUSW1},
9656         {"INDF2", SPO_INDF2},
9657         {"POSTDEC2", SPO_POSTDEC2},
9658         {"POSTINC2", SPO_POSTINC2},
9659         {"PREINC2", SPO_PREINC2},
9660         {"PLUSW2", SPO_PLUSW2},
9661         {"STKPTR", SPO_STKPTR},
9662         {"TOSL", SPO_TOSL},
9663         {"TOSH", SPO_TOSH},
9664         {"TOSU", SPO_TOSU},
9665         {"BSR", SPO_BSR},
9666         {"FSR0L", SPO_FSR0L},
9667         {"FSR0H", SPO_FSR0H},
9668         {"FSR1L", SPO_FSR1L},
9669         {"FSR1H", SPO_FSR1H},
9670         {"FSR2L", SPO_FSR2L},
9671         {"FSR2H", SPO_FSR2H},
9672         {"PCL", SPO_PCL},
9673         {"PCLATH", SPO_PCLATH},
9674         {"PCLATU", SPO_PCLATU},
9675         {"TABLAT", SPO_TABLAT},
9676         {"TBLPTRL", SPO_TBLPTRL},
9677         {"TBLPTRH", SPO_TBLPTRH},
9678         {"TBLPTRU", SPO_TBLPTRU},
9679         {NULL, 0}
9680     };
9681
9682     map_strToSym = newHashTable (128);
9683     map_symToStr = newHashTable (128);
9684
9685     for (i=0; predefsyms[i].name; i++) {
9686       char *name;
9687
9688       /* enter new symbol */
9689       sym = predefsyms[i].sym;
9690       name = predefsyms[i].name;
9691       res = Safe_strdup (name);
9692       hash = symbolHash (name, 0);
9693
9694       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9695       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9696     } // for i
9697   }
9698
9699   hash = symbolHash (str, 0) % map_strToSym->size;
9700   
9701   /* find symbol in table */
9702   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9703   if (sym) {
9704     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9705     return sym;
9706   }
9707
9708   /* enter new symbol */
9709   sym = nextSymbol++;
9710   res = Safe_strdup (str);
9711
9712   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9713   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9714
9715   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9716   
9717   return sym;
9718 }
9719
9720 #if 1
9721 static const char *strFromSym (symbol_t sym) {
9722   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9723 }
9724 #endif
9725
9726 /* ======================================================================== */
9727 /* === DEFINITION MAP HANDLING ============================================ */
9728 /* ======================================================================== */
9729
9730 /* A defmap provides information about which symbol is defined by which pCode.
9731  * The most recent definitions are prepended to the list, so that the most
9732  * recent definition can be found by forward scanning the list.
9733  * pc2: MOVFF r0x00, r0x01
9734  * pc1: INCF r0x01
9735  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9736  *
9737  * We attach one defmap to each flow object, and each pCode will occur at
9738  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9739  * used to find definitions for a pCode in its own defmap that precede pCode.
9740  */
9741
9742 typedef struct defmap_s {
9743   symbol_t sym;                 /** symbol this item refers to */
9744   union {
9745     struct {
9746       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9747       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9748       int isRead:1;             /** sym/mask is read */
9749       int isWrite:1;            /** sym/mask is written */
9750     } access;
9751     int accessmethod;
9752   } acc;
9753   pCode *pc;                    /** pCode this symbol is refrenced at */
9754   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9755   valnum_t val;                 /** new unique number for this value (if isWrite) */
9756   struct defmap_s *prev, *next; /** link to previous an next definition */
9757 } defmap_t;
9758
9759 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9760 static int defmap_free_count = 0;               /** number of released defmap items */
9761
9762 /* Returns a defmap_t with the specified data; this will be the new list head.
9763  * next - pointer to the current list head */
9764 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9765   defmap_t *map;
9766   
9767   if (defmap_free) {
9768     map = defmap_free;
9769     defmap_free = map->next;
9770     --defmap_free_count;
9771   } else {
9772     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9773   }
9774   map->sym = sym;
9775   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9776   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9777   map->acc.access.isRead = (isRead != 0);
9778   map->acc.access.isWrite = (isWrite != 0);
9779   map->pc = pc;
9780   map->in_val = 0;
9781   map->val = (isWrite ? val : 0);
9782   map->prev = NULL;
9783   map->next = next;
9784   if (next) next->prev = map;
9785   
9786   return map;
9787 }
9788
9789 /* Returns a copy of the single defmap item. */
9790 static defmap_t *copyDefmap (defmap_t *map) {
9791   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9792   memcpy (res, map, sizeof (defmap_t));
9793   res->next = NULL;
9794   res->prev = NULL;
9795   return res;
9796 }
9797
9798 /* Insert a defmap item after the specified one. */
9799 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9800   if (!ref || !newItem) return 1;
9801
9802   newItem->next = ref->next;
9803   newItem->prev = ref;
9804   ref->next = newItem;
9805   if (newItem->next) newItem->next->prev = newItem;
9806   
9807   return 0;
9808 }
9809
9810 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9811  * item is copied before insertion into chain and therefore left untouched.
9812  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9813 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9814   defmap_t *dummy;
9815   dummy = *head;
9816   while (dummy && (dummy->sym != item->sym
9817                           || dummy->pc != item->pc
9818                           || dummy->acc.accessmethod != item->acc.accessmethod
9819                           || dummy->val != item->val
9820                           || dummy->in_val != item->in_val)) {
9821     dummy = dummy->next;
9822   } // while
9823
9824   /* item already present? */
9825   if (dummy) return 0;
9826   
9827   /* otherwise: insert copy of item */
9828   dummy = copyDefmap (item);
9829   dummy->next = *head;
9830   if (*head) (*head)->prev = dummy;
9831   *head = dummy;
9832
9833   return 1;
9834 }
9835
9836 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9837 static void deleteDefmap (defmap_t *map) {
9838   if (!map) return;
9839   
9840   /* unlink from chain -- fails for the first item (head is not updated!) */
9841   if (map->next) map->next->prev = map->prev;
9842   if (map->prev) map->prev->next = map->next;
9843
9844   /* clear map */
9845   memset (map, 0, sizeof (defmap_t));
9846
9847   /* save for future use */
9848   map->next = defmap_free;
9849   defmap_free = map;
9850   ++defmap_free_count;
9851 }
9852
9853 /* Release all defmaps referenced from map. */
9854 static void deleteDefmapChain (defmap_t **_map) {
9855   defmap_t *map, *next;
9856
9857   if (!_map) return;
9858
9859   map = *_map;
9860   
9861   /* find list head */
9862   while (map && map->prev) map = map->prev;
9863
9864   /* delete all items */
9865   while (map) {
9866     next = map->next;
9867     deleteDefmap (map);
9868     map = next;
9869   } // while
9870
9871   *_map = NULL;
9872 }
9873
9874 /* Free all defmap items. */
9875 static void freeDefmap (defmap_t **_map) {
9876   defmap_t *next;
9877   defmap_t *map;
9878
9879   if (!_map) return;
9880
9881   map = (*_map);
9882   
9883   /* find list head */
9884   while (map->prev) map = map->prev;
9885
9886   /* release all items */
9887   while (map) {
9888     next = map->next;
9889     Safe_free (map);
9890     map = next;
9891   }
9892
9893   (*_map) = NULL;
9894 }
9895
9896 /* Returns the most recent definition for the given symbol preceeding pc.
9897  * If no definition is found, NULL is returned. 
9898  * If pc == NULL the whole list is scanned. */
9899 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9900   defmap_t *curr = map;
9901
9902   if (pc) {
9903     /* skip all definitions up to pc */
9904     while (curr && (curr->pc != pc)) curr = curr->next;
9905
9906     /* pc not in the list -- scan the whole list for definitions */
9907     if (!curr) {
9908       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9909       curr = map;
9910     } else {
9911       /* skip all definitions performed by pc */
9912       while (curr && (curr->pc == pc)) curr = curr->next;
9913     }
9914   } // if (pc)
9915
9916   /* find definition for sym */
9917   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9918     curr = curr->next;
9919   }
9920
9921   return curr;
9922 }
9923
9924 #if 0
9925 /* Returns the first use (read) of the given symbol AFTER pc.
9926  * If no such use is found, NULL is returned.
9927  * If pc == NULL the whole list is scanned. */
9928 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9929   defmap_t *curr = map, *prev = NULL;
9930   
9931   if (pc) {
9932     /* skip all definitions up to pc */
9933     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9934
9935     /* pc not in the list -- scan the whole list for definitions */
9936     if (!curr) {
9937       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9938       curr = prev;
9939     }
9940   } else {
9941     /* find end of list */
9942     while (curr && curr->next) curr = curr->next;
9943   } // if (pc)
9944
9945   /* find use of sym (scan list backwards) */
9946   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9947
9948   return curr;
9949 }
9950 #endif
9951
9952 /* Return the defmap entry for sym AT pc. 
9953  * If none is found, NULL is returned.
9954  * If more than one entry is found an assertion is triggered. */
9955 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9956   defmap_t *res = NULL;
9957
9958   /* find entries for pc */
9959   while (map && map->pc != pc) map = map->next;
9960
9961   /* find first entry for sym @ pc */
9962   while (map && map->pc == pc && map->sym != sym) map = map->next;
9963
9964   /* no entry found */
9965   if (!map) return NULL;
9966
9967   /* check for more entries */
9968   res = map;
9969   map = map->next;
9970   while (map && map->pc == pc) {
9971     /* more than one entry for sym @ pc found? */
9972     assert (map->sym != sym);
9973     map = map->next;
9974   }
9975
9976   /* return single entry for sym @ pc */
9977   return res;
9978 }
9979
9980 /* Modifies the definition of sym at pCode to newval.
9981  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9982  */
9983 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9984   defmap_t *m  = map;
9985
9986   /* find definitions of pc */
9987   while (m && m->pc != pc) m = m->next;
9988
9989   /* find definition of sym at pc */
9990   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9991   
9992   /* no definition found */
9993   if (!m) return 1;
9994
9995   /* redefine */
9996   m->val = newval;
9997
9998   /* update following uses of sym */
9999   while (m && m->pc == pc) m = m->prev;
10000   while (m) {
10001     if (m->sym == sym) {
10002       m->in_val = newval;
10003       if (m->acc.access.isWrite) m = NULL;
10004     } // if
10005     if (m) m = m->prev;
10006   } // while
10007   
10008   return 0;
10009 }
10010
10011 /* ======================================================================== */
10012 /* === STACK ROUTINES ===================================================== */
10013 /* ======================================================================== */
10014
10015 typedef struct stack_s {
10016   void *data;
10017   struct stack_s *next;
10018 } stackitem_t;
10019
10020 typedef stackitem_t *dynstack_t;
10021 static stackitem_t *free_stackitems = NULL;
10022
10023 /* Create a stack with one item. */
10024 static dynstack_t *newStack () {
10025   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
10026   *s = NULL;
10027   return s;
10028 }
10029
10030 /* Remove a stack -- its items are only marked free. */
10031 static void deleteStack (dynstack_t *s) {
10032   stackitem_t *i;
10033
10034   while (*s) {
10035     i = *s;
10036     *s = (*s)->next;
10037     i->next = free_stackitems;
10038     free_stackitems = i;
10039   } // while
10040   Safe_free (s);
10041 }
10042
10043 /* Release all stackitems. */
10044 static void releaseStack () {
10045   stackitem_t *i;
10046   
10047   while (free_stackitems) {
10048     i = free_stackitems->next;
10049     Safe_free(free_stackitems);
10050     free_stackitems = i;
10051   } // while
10052 }
10053
10054 static void stackPush (dynstack_t *stack, void *data) {
10055   stackitem_t *i;
10056   
10057   if (free_stackitems) {
10058     i = free_stackitems;
10059     free_stackitems = free_stackitems->next;
10060   } else {
10061     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
10062   }
10063   i->data = data;
10064   i->next = *stack;
10065   *stack = i;
10066 }
10067
10068 static void *stackPop (dynstack_t *stack) {
10069   void *data;
10070   stackitem_t *i;
10071   
10072   if (stack && *stack) {
10073     data = (*stack)->data;
10074     i = *stack;
10075     *stack = (*stack)->next;
10076     i->next = free_stackitems;
10077     free_stackitems = i;
10078     return data;
10079   } else {
10080     return NULL;
10081   }
10082 }
10083
10084 #if 0
10085 static int stackContains (dynstack_t *s, void *data) {
10086   stackitem_t *i;
10087   if (!s) return 0;
10088   i = *s;
10089   while (i) {
10090     if (i->data == data) return 1;
10091     i = i->next;
10092   } // while
10093
10094   /* not found */
10095   return 0;
10096 }
10097 #endif
10098
10099 static int stackIsEmpty (dynstack_t *s) {
10100   return (*s == NULL);
10101 }
10102
10103
10104 typedef struct {
10105   pCodeFlow *flow;
10106   defmap_t *lastdef;
10107 } state_t;
10108
10109 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10110   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10111   s->flow = flow;
10112   s->lastdef = lastdef;
10113   return s;
10114 }
10115
10116 static void deleteState (state_t *s) {
10117   Safe_free (s);
10118 }
10119
10120 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10121   stackitem_t *i;
10122
10123   /* scan working list for state */
10124   if (todo) {
10125     i = *todo;
10126     while (i) {
10127       /* is i == state? -- state not new */
10128       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10129       i = i->next;
10130     } // while
10131   }
10132
10133   if (done) {
10134     i = *done;
10135     while (i) {
10136       /* is i == state? -- state not new */
10137       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10138       i = i->next;
10139     } // while
10140   }
10141
10142   /* not found -- state is new */
10143   return 1;
10144 }
10145
10146 static inline valnum_t newValnum ();
10147
10148 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10149   pCode *pc;
10150
10151   if (!pb) return "<unknown function>";
10152
10153   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10154   if (pc && isPCF(pc)) return PCF(pc)->fname;
10155   else return "<unknown function>";
10156 }
10157
10158 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10159   defmap_t *map;
10160   pCodeFlow *pcfl;
10161
10162   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10163
10164   /* find initial value (assigning pc == NULL) */
10165   map = PCFL(pcfl)->in_vals;
10166   while (map && map->sym != sym) map = map->next;
10167
10168   /* initial value already present? */
10169   if (map) {
10170     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10171     return map;
10172   }
10173
10174   /* create a new initial value */
10175   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10176   PCFL(pcfl)->in_vals = map;
10177   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10178   return map;
10179
10180 #if 0
10181   /* insert map as last item in pcfl's defmap */
10182   if (!prev) prev = PCFL(pcfl)->defmap;
10183   if (!prev) {
10184     PCFL(pcfl)->defmap = map;
10185   } else {
10186     while (prev->next) prev = prev->next;
10187     prev->next = map;
10188     map->prev = prev;
10189   }
10190
10191   return map;
10192 #endif
10193 }
10194
10195 /* Find all reaching definitions for sym at pc. 
10196  * A new (!) list of definitions is returned.
10197  * Returns the number of reaching definitions found.
10198  * The defining defmap entries are returned in *chain.
10199  */
10200 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10201   defmap_t *map;
10202   defmap_t *res;
10203
10204   pCodeFlow *curr;
10205   pCodeFlowLink *succ;
10206   state_t *state;
10207   dynstack_t *todo;     /** stack of state_t */
10208   dynstack_t *done;     /** stack of state_t */
10209
10210   int firstState, n_defs;
10211   
10212   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10213   assert (chain);
10214
10215   /* initialize return list */
10216   *chain = NULL;
10217
10218   /* wildcard symbol? */
10219   if (!sym) return 0;
10220   
10221   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10222   
10223   map = PCI(pc)->pcflow->defmap;
10224
10225   res = defmapFindDef (map, sym, pc);
10226   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10227
10228 #define USE_PRECALCED_INVALS 1
10229 #if USE_PRECALCED_INVALS
10230   if (!res && PCI(pc)->pcflow->in_vals) {
10231     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10232     if (res) {
10233       //fprintf  (stderr, "found def in init values\n");
10234       df_findall_in_vals++;
10235     }
10236   }
10237 #endif
10238
10239   if (res) {
10240     // found a single definition (in pc's flow)
10241     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10242     defmapAddCopyIfNew (chain, res);
10243     df_findall_sameflow++;
10244     return 1;
10245   }
10246
10247 #if USE_PRECALCED_INVALS
10248   else {
10249     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10250     return 1;
10251   }
10252
10253 #endif
10254   
10255 #define FORWARD_FLOW_ANALYSIS 1
10256 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10257   /* no definition found in pc's flow preceeding pc */
10258   todo = newStack ();
10259   done = newStack ();
10260   n_defs = 0; firstState = 1;
10261   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10262
10263   while (!stackIsEmpty (todo)) {
10264     state = (state_t *) stackPop (todo);
10265     stackPush (done, state);
10266     curr = state->flow;
10267     res = state->lastdef;
10268     //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);
10269
10270     /* there are no definitions BEFORE pc in pc's flow (see above) */
10271     if (curr == PCI(pc)->pcflow) {
10272       if (!res) {
10273         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10274         res = pic16_pBlockAddInval (pc->pb, sym);
10275         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10276         res = NULL;
10277       } else {
10278         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10279         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10280       }
10281     }
10282
10283     /* save last definition of sym in this flow as initial def in successors */
10284     res = defmapFindDef (curr->defmap, sym, NULL);
10285     if (!res) res = state->lastdef;
10286     
10287     /* add successors to working list */
10288     state = newState (NULL, NULL);
10289     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10290     while (succ) {
10291       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10292       state->flow = succ->pcflow;
10293       state->lastdef = res;
10294       if (stateIsNew (state, todo, done)) {
10295         stackPush (todo, state);
10296         state = newState (NULL, NULL);
10297       } // if
10298       succ = (pCodeFlowLink *) setNextItem (curr->to);
10299     } // while
10300     deleteState (state);
10301   } // while
10302
10303 #else // !FORWARD_FLOW_ANALYSIS 
10304
10305   /* no definition found in pc's flow preceeding pc */
10306   todo = newStack ();
10307   done = newStack ();
10308   n_defs = 0; firstState = 1;
10309   stackPush (todo, newState (PCI(pc)->pcflow, res));
10310
10311   while (!stackIsEmpty (todo)) {
10312     state = (state_t *) stackPop (todo);
10313     curr = state->flow;
10314
10315     if (firstState) {
10316       firstState = 0;
10317       /* only check predecessor flows */
10318     } else {
10319       /* get (last) definition of sym in this flow */
10320       res = defmapFindDef (curr->defmap, sym, NULL);
10321     }
10322
10323     if (res) {
10324       /* definition found */
10325       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10326       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10327     } else {
10328       /* no definition found -- check predecessor flows */
10329       state = newState (NULL, NULL);
10330       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10331
10332       /* if no flow predecessor available -- sym might be uninitialized */
10333       if (!succ) {
10334         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10335         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10336         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10337         deleteDefmap (res); res = NULL;
10338       }
10339       
10340       while (succ) {
10341         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10342         state->flow = succ->pcflow;
10343         state->lastdef = res;
10344         if (stateIsNew (state, todo, done)) {
10345           stackPush (todo, state);
10346           state = newState (NULL, NULL);
10347         } // if
10348         succ = (pCodeFlowLink *) setNextItem (curr->from);
10349       } // while
10350       deleteState (state);
10351     }
10352   } // while
10353
10354 #endif
10355
10356   /* clean up done stack */
10357   while (!stackIsEmpty(done)) {
10358     deleteState ((state_t *) stackPop (done));
10359   } // while
10360   deleteStack (done);
10361
10362   /* return number of items in result set */
10363   if (n_defs == 0) {
10364     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10365   } else if (n_defs == 1) {
10366     assert (*chain);
10367     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10368   } else if (n_defs > 0) {
10369     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10370 #if 0
10371     res = *chain;
10372     while (res) {
10373       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10374       res = res->next;
10375     } // while
10376 #endif
10377   }
10378   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10379   df_findall_otherflow++;
10380   return n_defs;
10381 }
10382
10383 /* ======================================================================== */
10384 /* === VALUE NUMBER HANDLING ============================================== */
10385 /* ======================================================================== */
10386
10387 static valnum_t nextValnum = 0x1000;
10388 static hTab *map_symToValnum = NULL;
10389
10390 /** Return a new value number. */
10391 static inline valnum_t newValnum () {
10392   return (nextValnum += 4);
10393 }
10394
10395 static valnum_t valnumFromStr (const char *str) {
10396   symbol_t sym;
10397   valnum_t val;
10398   void *res;
10399   
10400   sym = symFromStr (str);
10401
10402   if (!map_symToValnum) {
10403     map_symToValnum = newHashTable (128);
10404   } // if
10405
10406   /* literal already known? */
10407   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10408
10409   /* return existing valnum */
10410   if (res) return (valnum_t) PTR_TO_INT(res);
10411   
10412   /* create new valnum */
10413   val = newValnum();
10414   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10415   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10416   return val;
10417 }
10418
10419 /* Create a valnum for a literal. */
10420 static valnum_t valnumFromLit (unsigned int lit) {
10421   return ((valnum_t) 0x100 + (lit & 0x0FF));
10422 }
10423
10424 /* Return the (positive) literal value represented by val
10425  * or -1 iff val is no known literal's valnum. */
10426 static int litFromValnum (valnum_t val) {
10427   if (val >= 0x100 && val < 0x200) {
10428     /* valnum is a (known) literal */
10429     return val & 0x00FF;
10430   } else {
10431     /* valnum is not a known literal */
10432     return -1;
10433   }
10434 }
10435
10436 #if 0
10437 /* Sanity check - all flows in a block must be reachable from initial flow. */
10438 static int verifyAllFlowsReachable (pBlock *pb) {
10439   set *reached;
10440   set *flowInBlock;
10441   set *checked;
10442   pCode *pc;
10443   pCodeFlow *pcfl;
10444   pCodeFlowLink *succ;
10445   int res;
10446
10447   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10448
10449   reached = NULL;
10450   flowInBlock = NULL;
10451   checked = NULL;
10452   /* mark initial flow as reached (and "not needs to be reached") */
10453   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10454   assert (pc);
10455   addSetHead (&reached, pc);
10456   addSetHead (&checked, pc);
10457   
10458   /* mark all further flows in block as "need to be reached" */
10459   pc = pb->pcHead;
10460   do {
10461     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10462     pc = pic16_findNextInstruction (pc->next);
10463   } while (pc);
10464
10465   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10466     /* mark as reached and "not need to be reached" */
10467     deleteSetItem (&reached, pcfl);
10468     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10469     
10470     /* flow is no longer considered unreachable */
10471     deleteSetItem (&flowInBlock, pcfl);
10472
10473     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10474       if (!isinSet (checked, succ->pcflow)) {
10475         /* flow has never been reached before */
10476         addSetHead (&reached, succ->pcflow);
10477         addSetHead (&checked, succ->pcflow);
10478       } // if
10479     } // for succ
10480   } // while
10481
10482   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10483
10484   /* by now every flow should have been reached
10485    * --> flowInBlock should be empty */
10486   res = (flowInBlock == NULL);
10487
10488 #if 1
10489   if (flowInBlock) {
10490           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10491     while (flowInBlock) {
10492       pcfl = indexSet (flowInBlock, 0);
10493       fprintf (stderr, "not reached: flow %p\n", pcfl);
10494       deleteSetItem (&flowInBlock, pcfl);
10495     } // while
10496   }
10497 #endif
10498   
10499   /* clean up */
10500   deleteSet (&reached);
10501   deleteSet (&flowInBlock);
10502   deleteSet (&checked);
10503   
10504   /* if we reached every flow, succ is NULL by now... */
10505   //assert (res); // will fire on unreachable code...
10506   return (res);
10507 }
10508 #endif
10509
10510 /* Checks a flow for accesses to sym AFTER pc.
10511  * 
10512  * Returns -1 if the symbol is read in this flow (before redefinition),
10513  * returns 0 if the symbol is redefined in this flow or
10514  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10515  */
10516 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10517   defmap_t *map, *mappc;
10518
10519   /* find pc or start of definitions */
10520   map = pcfl->defmap;
10521   while (map && (map->pc != pc) && map->next) map = map->next;
10522   /* if we found pc -- ignore it */
10523   while (map && map->pc == pc) map = map->prev;
10524
10525   /* scan list backwards (first definition first) */
10526   while (map && mask) {
10527 //    if (map->sym == sym) {
10528       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10529       mappc = map;
10530       /* scan list for reads at this pc first */
10531       while (map && map->pc == mappc->pc) {
10532         /* is the symbol (partially) read? */
10533         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10534           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10535           return -1;
10536         }
10537         map = map->prev;
10538       } // while
10539       map = mappc;
10540
10541       while (map && map->pc == mappc->pc) {
10542         /* honor (partial) redefinitions of sym */
10543         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10544           mask &= ~map->acc.access.mask;
10545           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10546         }
10547         map = map->prev;
10548       } // while
10549 //    } // if
10550     /* map already points to the first defmap for the next pCode */
10551     //map = mappc->prev;
10552   } // while
10553
10554   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10555    * is still alive; return the appropriate mask of alive bits */
10556   return mask;
10557 }
10558
10559 /* Check whether a symbol is alive (AFTER pc). */
10560 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10561   int mask, visit;
10562   defmap_t *map;
10563   dynstack_t *todo, *done;
10564   state_t *state;
10565   pCodeFlow *pcfl;
10566   pCodeFlowLink *succ;
10567
10568   mask = 0x00ff;
10569   
10570   assert (isPCI(pc));
10571   pcfl = PCI(pc)->pcflow;
10572   map = pcfl->defmap;
10573
10574   todo = newStack ();
10575   done = newStack ();
10576   
10577   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10578   stackPush (todo, state);
10579   visit = 0;
10580   
10581   while (!stackIsEmpty (todo)) {
10582     state = (state_t *) stackPop (todo);
10583     pcfl = state->flow;
10584     mask = PTR_TO_INT(state->lastdef);
10585     if (visit) stackPush (done, state); else deleteState(state);
10586     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10587     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10588     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10589     visit++;
10590
10591     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10592     if (mask == 0) continue;
10593
10594     /* symbol is (partially) read before redefinition in flow */
10595     if (mask == -1) break;
10596
10597     /* symbol is neither read nor completely redefined -- check successor flows */
10598     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10599       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10600       if (stateIsNew (state, todo, done)) {
10601         stackPush (todo, state);
10602       } else {
10603         deleteState (state);
10604       }
10605     } // for
10606   } // while
10607
10608   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10609   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10610
10611   /* symbol is read in at least one flow -- is alive */
10612   if (mask == -1) return 1;
10613
10614   /* symbol is read in no flow */
10615   return 0;
10616 }
10617
10618 /* Returns whether access to the given symbol has side effects. */
10619 static int pic16_symIsSpecial (symbol_t sym) {
10620   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10621   switch (sym) {
10622   case SPO_INDF0:
10623   case SPO_PLUSW0:
10624   case SPO_POSTINC0:
10625   case SPO_POSTDEC0:
10626   case SPO_PREINC0:
10627   case SPO_INDF1:
10628   case SPO_PLUSW1:
10629   case SPO_POSTINC1:
10630   case SPO_POSTDEC1:
10631   case SPO_PREINC1:
10632   case SPO_INDF2:
10633   case SPO_PLUSW2:
10634   case SPO_POSTINC2:
10635   case SPO_POSTDEC2:
10636   case SPO_PREINC2:
10637   case SPO_PCL:
10638           return 1;
10639   default:
10640           /* no special effects known */
10641           return 0;
10642   } // switch
10643
10644   return 0;
10645 }
10646
10647 /* Check whether a register should be considered local (to the current function) or not. */
10648 static int pic16_regIsLocal (regs *r) {
10649   symbol_t sym;
10650   if (r) {
10651     if (r->type == REG_TMP) return 1;
10652
10653     sym = symFromStr (r->name);
10654     switch (sym) {
10655     case SPO_WREG:
10656     case SPO_FSR0L: // used in ptrget/ptrput
10657     case SPO_FSR0H: // ... as well
10658     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10659     case SPO_FSR1H: // ... as well
10660     case SPO_FSR2L: // used as frame pointer
10661     case SPO_FSR2H: // ... as well
10662     case SPO_PRODL: // used to return values from functions
10663     case SPO_PRODH: // ... as well
10664       /* these registers (and some more...) are considered local */
10665       return 1;
10666       break;
10667     default:
10668       /* for unknown regs: check is marked local, leave if not */
10669       if (r->isLocal) {
10670         return 1;
10671       } else {
10672         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10673         return 0;
10674       }
10675     } // switch
10676   } // if
10677
10678   /* if in doubt, assume non-local... */
10679   return 0;
10680 }
10681
10682 /* Check all symbols touched by pc whether their newly assigned values are read.
10683  * Returns 0 if no symbol is used later on, 1 otherwise. */
10684 static int pic16_pCodeIsAlive (pCode *pc) {
10685   pCodeInstruction *pci;
10686   defmap_t *map, *lastpc;
10687   regs *checkreg;
10688   
10689   /* we can only handle PCIs */
10690   if (!isPCI(pc)) return 1;
10691
10692   //pc->print (stderr, pc);
10693
10694   pci = PCI(pc);
10695   assert (pci && pci->pcflow && pci->pcflow->defmap);
10696
10697   /* NEVER remove instructions with implicit side effects */
10698   switch (pci->op) {
10699   case POC_TBLRD:
10700   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10701   case POC_TBLRD_POSTDEC:
10702   case POC_TBLRD_PREINC:
10703   case POC_TBLWT:               /* modify program memory */
10704   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10705   case POC_TBLWT_POSTDEC:
10706   case POC_TBLWT_PREINC:
10707   case POC_CLRWDT:              /* clear watchdog timer */
10708   case POC_PUSH:                /* should be safe to remove though... */
10709   case POC_POP:                 /* should be safe to remove though... */
10710   case POC_CALL:
10711   case POC_RCALL:
10712   case POC_RETFIE:
10713   case POC_RETURN:
10714     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10715     return 1;
10716
10717   default:
10718     /* no special instruction */
10719     break;
10720   } // switch
10721
10722   /* prevent us from removing assignments to non-local variables */
10723   checkreg = NULL;
10724   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10725   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10726
10727   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10728     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10729     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10730     //pc->print (stderr, pc);
10731     return 1;
10732   }
10733   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10734     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10735     return 1;
10736   }
10737   
10738 #if 1
10739   /* OVERKILL: prevent us from removing reads from non-local variables 
10740    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10741    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10742   checkreg = NULL;
10743   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10744   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10745
10746   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10747     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10748     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10749     //pc->print (stderr, pc);
10750     return 1;
10751   }
10752   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10753     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10754     return 1;
10755   }
10756 #endif
10757   
10758   /* now check that the defined symbols are not used */
10759   map = pci->pcflow->defmap;
10760   
10761   /* find items for pc */
10762   while (map && map->pc != pc) map = map->next;
10763
10764   /* no entries found? something is fishy with DF analysis... -- play safe */
10765   if (!map) {
10766     if (pic16_pcode_verbose) {
10767       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10768     }
10769     return 1;
10770   }
10771
10772   /* remember first item assigned to pc for later use */
10773   lastpc = map;
10774   
10775   /* check all symbols being modified by pc */
10776   while (map && map->pc == pc) {
10777     if (map->sym == 0) { map = map->next; continue; }
10778
10779     /* keep pc if it references special symbols (like POSTDEC0) */
10780 #if 0
10781     {
10782       char buf[256];
10783       pic16_pCode2str (buf, 256, pc);
10784       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10785     }
10786 #endif
10787     if (pic16_symIsSpecial (map->sym)) {
10788       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10789       return 1;
10790     }
10791     if (map->acc.access.isWrite) {
10792       if (pic16_isAlive (map->sym, pc)) {
10793         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10794         return 1;
10795       }
10796     }
10797     map = map->next;
10798   } // while
10799
10800   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10801 #if 0
10802   {
10803     char buf[256];
10804     pic16_pCode2str (buf, 256, pc);
10805     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10806   }
10807 #endif
10808   return 0;
10809 }
10810
10811 /* Adds implied operands to the list.
10812  * sym - operand being accessed in the pCode
10813  * list - list to append the operand
10814  * isRead - set to 1 iff sym is read in pCode
10815  * listRead - set to 1 iff all operands being read are to be listed
10816  *
10817  * Returns 0 for "normal" operands, 1 for special operands.
10818  */
10819 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10820   /* check whether accessing REG accesses other REGs as well */
10821   switch (sym) {
10822   case SPO_INDF0:
10823     /* reads FSR0x */
10824     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10825     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10826     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10827     break;
10828     
10829   case SPO_PLUSW0:
10830     /* reads FSR0x and WREG */
10831     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10832     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10833     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10834     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10835     break;
10836     
10837   case SPO_POSTDEC0:
10838   case SPO_POSTINC0:
10839   case SPO_PREINC0:
10840     /* reads/modifies FSR0x */
10841     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10842     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10843     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10844     break;
10845
10846   case SPO_INDF1:
10847     /* reads FSR1x */
10848     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10849     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10850     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10851     break;
10852     
10853   case SPO_PLUSW1:
10854     /* reads FSR1x and WREG */
10855     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10856     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10857     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10858     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10859     break;
10860     
10861   case SPO_POSTDEC1:
10862   case SPO_POSTINC1:
10863   case SPO_PREINC1:
10864     /* reads/modifies FSR1x */
10865     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10866     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10867     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10868     break;
10869
10870   case SPO_INDF2:
10871     /* reads FSR2x */
10872     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10873     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10874     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10875     break;
10876     
10877   case SPO_PLUSW2:
10878     /* reads FSR2x and WREG */
10879     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10880     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10881     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10882     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10883     break;
10884     
10885   case SPO_POSTDEC2:
10886   case SPO_POSTINC2:
10887   case SPO_PREINC2:
10888     /* reads/modifies FSR2x */
10889     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10890     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10891     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10892     break;
10893
10894   case SPO_PCL:
10895     /* modifies PCLATH and PCLATU */
10896     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10897     if (isRead) {
10898       /* reading PCL updates PCLATx */
10899       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10900       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10901     }
10902     if (isWrite) {
10903       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10904       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10905       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10906     }
10907     break;
10908
10909   default:
10910     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10911     /* nothing special */
10912     return 0;
10913     break;
10914   }
10915
10916   /* has been a special operand */
10917   return 1;
10918 }
10919
10920 static symbol_t pic16_fsrsym_idx[][2] = {
10921     {SPO_FSR0L, SPO_FSR0H},
10922     {SPO_FSR1L, SPO_FSR1H},
10923     {SPO_FSR2L, SPO_FSR2H}
10924 };
10925
10926 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10927 static void mergeDefmapSymbols (defmap_t *list) { 
10928   defmap_t *ref, *curr, *temp;
10929
10930   /* now make sure that each symbol occurs at most once per pc */
10931   ref = list;
10932   while (ref && (ref->pc == list->pc)) {
10933     curr = ref->next;
10934     while (curr && (curr->pc == list->pc)) {
10935       if (curr->sym == ref->sym) {
10936         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10937         /* found a symbol occuring twice... merge the two */
10938         if (curr->acc.access.isRead) {
10939           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10940           ref->acc.access.isRead = 1;
10941           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10942         }
10943         if (curr->acc.access.isWrite) {
10944           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10945           ref->acc.access.isWrite = 1;
10946           ref->acc.access.mask |= curr->acc.access.mask;
10947         }
10948         temp = curr;
10949         curr = curr->next;
10950         deleteDefmap (temp);
10951         continue; // do not skip curr!
10952       } // if
10953       curr = curr->next;
10954     } // while
10955     ref = ref->next;
10956   } // while
10957 }
10958
10959 /** Prepend list with the reads and definitions performed by pc. */
10960 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10961   pCodeInstruction *pci;
10962   int cond, inCond, outCond;
10963   int mask = 0xff, smask;
10964   int isSpecial, isSpecial2;
10965   symbol_t sym, sym2;
10966   char *name;
10967
10968   if (isPCAD(pc)) {
10969     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10970     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10971     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10972     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10973     return list;
10974   }
10975   assert (isPCI(pc));
10976   pci = PCI(pc);
10977   
10978   /* handle bit instructions */
10979   if (pci->isBitInst) {
10980     assert (pci->pcop->type == PO_GPR_BIT);
10981     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10982   }
10983
10984   /* handle (additional) implicit arguments */
10985   switch (pci->op) {
10986   case POC_LFSR:
10987     {
10988       int lit;
10989       valnum_t val;
10990       lit = PCOL(pci->pcop)->lit;
10991       assert (lit >= 0 && lit < 3);
10992       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10993       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10994       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10995       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10996       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...
10997     }
10998     break;
10999
11000   case POC_MOVLB: // BSR
11001   case POC_BANKSEL: // BSR
11002     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
11003     break;
11004
11005   case POC_MULWF: // PRODx
11006   case POC_MULLW: // PRODx
11007     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
11008     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
11009     break;
11010
11011   case POC_POP: // TOS, STKPTR
11012     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11013     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
11014     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
11015     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
11016     break;
11017     
11018   case POC_PUSH: // STKPTR
11019     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11020     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
11021     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
11022     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
11023     break;
11024     
11025   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
11026   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
11027     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11028     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11029     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11030     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
11031
11032     /* needs correctly set-up stack pointer */
11033     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11034     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11035     break;
11036
11037   case POC_RETLW: // return values: WREG, PRODx, FSR0L
11038     /* pseudo read on (possible) return values */
11039     // WREG is handled below via outCond
11040     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11041     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11042     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11043
11044     /* caller's stack pointers must be restored */
11045     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11046     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11047     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11048     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11049     break;
11050
11051   case POC_RETURN: // return values; WREG, PRODx, FSR0L
11052   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
11053     /* pseudo read on (possible) return values */
11054     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
11055     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
11056     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
11057     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
11058
11059     /* caller's stack pointers must be restored */
11060     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
11061     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
11062     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
11063     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
11064     break;
11065     
11066   case POC_TBLRD:
11067     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11068     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11069     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11070     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11071     break;
11072     
11073   case POC_TBLRD_POSTINC:
11074   case POC_TBLRD_POSTDEC:
11075   case POC_TBLRD_PREINC:
11076     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11077     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11078     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11079     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11080     break;
11081     
11082   case POC_TBLWT:
11083     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11084     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11085     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11086     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11087     break;
11088     
11089   case POC_TBLWT_POSTINC:
11090   case POC_TBLWT_POSTDEC:
11091   case POC_TBLWT_PREINC:
11092     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11093     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11094     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11095     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11096     break;
11097     
11098   default:
11099     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11100     break;
11101   } // switch
11102
11103   /* handle explicit arguments */
11104   inCond = pci->inCond;
11105   outCond = pci->outCond;
11106   cond = inCond | outCond;
11107   if (cond & PCC_W) {
11108     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11109   } // if
11110
11111   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11112   if (inCond & PCC_STATUS) {
11113     smask = 0;
11114     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11115     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11116     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11117     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11118     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11119
11120     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11121     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11122   } // if
11123   
11124   if (outCond & PCC_STATUS) {
11125     smask = 0;
11126     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11127     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11128     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11129     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11130     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11131
11132     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11133     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11134   } // if
11135   
11136   isSpecial = isSpecial2 = 0;
11137   sym = sym2 = 0;
11138   if (cond & PCC_REGISTER) {
11139     name = pic16_get_op (pci->pcop, NULL, 0);
11140     sym = symFromStr (name);
11141     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11142     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11143   }
11144
11145   if (cond & PCC_REGISTER2) {
11146     name = pic16_get_op2 (pci->pcop, NULL, 0);
11147     sym2 = symFromStr (name);
11148     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11149     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11150   }
11151
11152  
11153   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11154   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11155
11156   mergeDefmapSymbols (list);
11157   
11158   return list;
11159 }
11160
11161 #if 0
11162 static void printDefmap (defmap_t *map) {
11163   defmap_t *curr;
11164
11165   curr = map;
11166   fprintf (stderr, "defmap @ %p:\n", curr);
11167   while (curr) {
11168     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11169                     curr->acc.access.isRead ? "R" : " ",
11170                     curr->acc.access.isWrite ? "W": " ",
11171                     curr->in_val, curr->val,
11172                     curr->acc.access.in_mask, curr->acc.access.mask,
11173                     strFromSym(curr->sym), curr->sym,
11174                     curr->pc);
11175     curr = curr->next;
11176   } // while
11177   fprintf (stderr, "<EOL>\n");
11178 }
11179 #endif
11180
11181 /* Add "additional" definitions to uniq.
11182  * 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.
11183  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11184  *
11185  * If symbols defined in additional are not present in uniq, a definition is created.
11186  * Otherwise the present definition is altered to reflect the newer assignments.
11187  *
11188  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11189  *       before     `------- noted in additional --------'      after
11190  *
11191  * I assume that each symbol occurs AT MOST ONCE in uniq.
11192  *
11193  */
11194 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11195   defmap_t *curr;
11196   defmap_t *old;
11197   int change = 0;
11198
11199   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11200   /* find tail of additional list (holds the first assignment) */
11201   curr = additional;
11202   while (curr && curr->next) curr = curr->next;
11203
11204   /* update uniq */
11205   do {
11206     /* find next assignment in additionals */
11207     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11208
11209     if (!curr) break;
11210
11211     /* find item in uniq */
11212     old = *uniq;
11213     //printDefmap (*uniq);
11214     while (old && (old->sym != curr->sym)) old = old->next;
11215
11216     if (old) {
11217       /* definition found -- replace */
11218       if (old->val != curr->val) {
11219         old->val = curr->val;
11220         change++;
11221       } // if
11222     } else {
11223       /* new definition */
11224       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11225       change++;
11226     }
11227
11228     curr = curr->prev;
11229   } while (1);
11230
11231   /* return 0 iff uniq remained unchanged */
11232   return change;
11233 }
11234
11235 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11236  * lists of its predecessor flows. 
11237  * Initially *combined should be NULL, alt_in will be copied to combined.
11238  * If *combined != NULL, combined will be altered:
11239  * - for symbols defined in *combined but not in alt_in,
11240  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11241  * - for symbols defined in alt_in but not in *combined,
11242  *   a 0 definition is created (value unknown, either INIT or alt).
11243  * - for symbols defined in both, *combined is:
11244  *   > left unchanged if *combined->val == alt_in->val or
11245  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11246  * 
11247  * I assume that each symbol occurs AT MOST ONCE in each list!
11248  */
11249 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11250   defmap_t *curr;
11251   defmap_t *old;
11252   int change = 0;
11253   valnum_t val;
11254
11255   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11256   
11257   if (!(*combined)) {
11258     return defmapUpdateUniqueSym (combined, alt_in);
11259   } // if
11260   
11261   /* merge the two */
11262   curr = alt_in;
11263   while (curr) {
11264     /* find symbols definition in *combined */
11265     old = *combined;
11266     while (old && (old->sym != curr->sym)) old = old->next;
11267
11268     if (old) {
11269       /* definition found */
11270       if (old->val && (old->val != curr->val)) {
11271         old->val = 0; /* value unknown */
11272         change++;
11273       }
11274     } else {
11275       /* no definition found -- can be either INIT or alt_in's value */
11276       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11277       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11278       if (val != curr->val) change++;
11279     }
11280
11281     curr = curr->next;
11282   } // while (curr)
11283
11284   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11285   old = *combined;
11286   while (old) {
11287     if (old->val != 0) {
11288       /* find definition in alt_in */
11289       curr = alt_in;
11290       while (curr && curr->sym != old->sym) curr = curr->next;
11291       if (!curr) {
11292         /* symbol defined in *combined only -- can be either INIT or *combined */
11293         val = pic16_pBlockAddInval (pb, old->sym)->val;
11294         if (old->val != val) {
11295           old->val = 0;
11296           change++;
11297         }
11298       } // if
11299     } // if
11300
11301     old = old->next;
11302   } // while
11303
11304   return change;
11305 }
11306
11307 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11308   defmap_t *curr1, *curr2;
11309   symbol_t sym;
11310   
11311   /* identical maps are equal */
11312   if (map1 == map2) return 0;
11313
11314   if (!map1) return -1;
11315   if (!map2) return 1;
11316
11317   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11318   
11319   /* check length */
11320   curr1 = map1;
11321   curr2 = map2;
11322   while (curr1 && curr2) {
11323     curr1 = curr1->next;
11324     curr2 = curr2->next;
11325   } // while
11326
11327   /* one of them longer? */
11328   if (curr1) return 1;
11329   if (curr2) return -1;
11330
11331   /* both lists are of equal length -- compare (in O(n^2)) */
11332   curr1 = map1;
11333   while (curr1) {
11334     sym = curr1->sym;
11335     curr2 = map2;
11336     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11337     if (!curr2) return 1; // symbol not found in curr2
11338     if (curr2->val != curr1->val) return 1; // values differ
11339
11340     /* compare next symbol */
11341     curr1 = curr1->next;
11342   } // while
11343
11344   /* no difference found */
11345   return 0;
11346 }
11347
11348
11349 /* Prepare a list of all reaching definitions per flow.
11350  * This is done using a forward dataflow analysis.
11351  */
11352 static void createReachingDefinitions (pBlock *pb) {
11353   defmap_t *out_vals, *in_vals;
11354   pCode *pc;
11355   pCodeFlow *pcfl;
11356   pCodeFlowLink *link;
11357   set *todo;
11358   set *blacklist;
11359
11360   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11361   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11362     if (isPCFL(pc)) {
11363       deleteDefmapChain (&PCFL(pc)->in_vals);
11364       deleteDefmapChain (&PCFL(pc)->out_vals);
11365       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11366     } // if
11367   } // for
11368   
11369   pc = pic16_findNextInstruction (pb->pcHead);
11370   todo = NULL; blacklist = NULL;
11371   addSetHead (&todo, PCI(pc)->pcflow);
11372
11373   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11374   while (elementsInSet (todo)) {
11375     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11376     pcfl = PCFL(indexSet (todo, 0));
11377     deleteSetItem (&todo, pcfl);
11378     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11379     in_vals = NULL;
11380     out_vals = NULL;
11381
11382     if (isinSet (blacklist, pcfl)) {
11383             fprintf (stderr, "ignoring blacklisted flow\n");
11384       continue;
11385     }
11386     
11387     /* create in_vals from predecessors out_vals */
11388     link = setFirstItem (pcfl->from);
11389     while (link) {
11390       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11391       link = setNextItem (pcfl->from);
11392     } // while
11393
11394     //printDefmap (in_vals); 
11395     //printDefmap (pcfl->in_vals); 
11396
11397     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11398       //fprintf (stderr, "in_vals changed\n");
11399       /* in_vals changed -- update out_vals */
11400       deleteDefmapChain (&pcfl->in_vals);
11401       pcfl->in_vals = in_vals;
11402
11403       /* create out_val from in_val and defmap */
11404       out_vals = NULL;
11405       defmapUpdateUniqueSym (&out_vals, in_vals);
11406       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11407
11408       /* is out_vals different from pcfl->out_vals */
11409       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11410         //fprintf (stderr, "out_vals changed\n");
11411         deleteDefmapChain (&pcfl->out_vals);
11412         pcfl->out_vals = out_vals;
11413
11414         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11415           addSet (&blacklist, pcfl);
11416         } // if
11417         
11418         /* reschedule all successors */
11419         link = setFirstItem (pcfl->to);
11420         while (link) {
11421           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11422           addSetIfnotP (&todo, link->pcflow);
11423           link = setNextItem (pcfl->to);
11424         } // while
11425       } else {
11426         deleteDefmapChain (&out_vals);        
11427       }// if
11428     } else {
11429       deleteDefmapChain (&in_vals);         
11430     } // if
11431   } // while
11432 }
11433
11434 #if 0
11435 static void showAllDefs (symbol_t sym, pCode *pc) {
11436   defmap_t *map;
11437   int count;
11438
11439   assert (isPCI(pc));
11440   count = defmapFindAll (sym, pc, &map);
11441
11442   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11443   while (map) {
11444 #if 1
11445     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11446 #else
11447     { char buf[256];
11448     pic16_pCode2str (buf, 256, map->pc);
11449     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11450 #endif
11451     map = map->next;
11452   }
11453   deleteDefmapChain (&map);
11454 }
11455 #endif
11456
11457 /* safepCodeUnlink and remove pc from defmap. */
11458 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11459   defmap_t *map, *next, **head;
11460   int res, ispci;
11461   
11462   ispci = isPCI(pc);
11463   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11464   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11465   res = pic16_safepCodeUnlink (pc, comment);
11466
11467   if (res && map) {
11468     /* remove pc from defmap */
11469     while (map) {
11470       next = map->next;
11471       if (map->pc == pc) {
11472         if (!map->prev && head) *head = map->next;
11473         deleteDefmap (map);
11474       } // if
11475       map = next;
11476     }
11477   }
11478
11479   return res;
11480 }
11481       
11482 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11483   defmap_t *map;
11484   /* This breaks the defmap chain's references to pCodes... fix it! */
11485   map = PCI(pc)->pcflow->defmap;
11486
11487   while (map && map->pc != pc) map = map->next;
11488   
11489   while (map && map->pc == pc) {
11490     map->pc = newpc;
11491     map = map->next;
11492   } // while
11493 }
11494
11495 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11496  * write accesses (isRead == 0). */
11497 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11498   defmap_t *map, *map_start;
11499   defmap_t *copy;
11500   if (!isPCI(pc)) return;
11501   if (sym == newsym) return;
11502   
11503   map = PCI(pc)->pcflow->defmap;
11504
11505   while (map && map->pc != pc) map = map->next;
11506   map_start = map;
11507   while (map && map->pc == pc) {
11508     if (map->sym == sym) {
11509       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11510       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11511         /* only one kind of access handled... this is easy */
11512         map->sym = newsym;
11513       } else {
11514         /* must copy defmap entry before replacing symbol... */
11515         copy = copyDefmap (map);
11516         if (isRead) {
11517           map->acc.access.isRead = 0;
11518           copy->acc.access.isWrite = 0;
11519         } else {
11520           map->acc.access.isWrite = 0;
11521           copy->acc.access.isRead = 0;
11522         }
11523         copy->sym = newsym;
11524         /* insert copy into defmap chain */
11525         defmapInsertAfter (map, copy);
11526       }
11527     }
11528     map = map->next;
11529   } // while
11530
11531   /* as this might introduce multiple defmap entries for newsym... */
11532   mergeDefmapSymbols (map_start);
11533 }
11534
11535 /* Assign "better" valnums to results. */
11536 static void assignValnums (pCode *pc) {
11537   pCodeInstruction *pci;
11538   pCode *newpc;
11539   symbol_t sym1, sym2;
11540   int cond, isSpecial1, isSpecial2, count, mask, lit;
11541   defmap_t *list, *val, *oldval, *dummy;
11542   regs *reg1 = NULL, *reg2 = NULL;
11543   valnum_t litnum;
11544
11545   /* only works for pCodeInstructions... */
11546   if (!isPCI(pc)) return;
11547
11548   pci = PCI(pc);
11549   cond = pci->inCond | pci->outCond;
11550   list = pci->pcflow->defmap;
11551   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11552
11553   if (cond & PCC_REGISTER) {
11554     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11555     reg1 = pic16_getRegFromInstruction (pc);
11556     isSpecial1 = pic16_symIsSpecial (sym1);
11557   }
11558   if (cond & PCC_REGISTER2) {
11559     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11560     reg2 = pic16_getRegFromInstruction (pc);
11561     isSpecial2 = pic16_symIsSpecial (sym2);
11562   }
11563
11564   /* determine input values */
11565   val = list;
11566   while (val && val->pc != pc) val = val->next;
11567   //list = val; /* might save some time later... */
11568   while (val && val->pc == pc) {
11569     val->in_val = 0;
11570     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11571       /* get valnum for sym */
11572       count = defmapFindAll (val->sym, pc, &oldval);
11573       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11574       if (count == 1) {
11575         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11576           val->in_val = oldval->val;
11577         } else {
11578           val->in_val = 0;
11579         }
11580       } else if (count == 0) {
11581         /* no definition found */
11582         val->in_val = 0;
11583       } else {
11584         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11585         assert (oldval);
11586         dummy = oldval->next;
11587         mask = oldval->acc.access.mask;
11588         val->in_val = oldval->val;
11589         while (dummy && (dummy->val == val->in_val)) {
11590           mask &= dummy->acc.access.mask;
11591           dummy = dummy->next;
11592         } // while
11593
11594         /* found other values or to restictive mask */
11595         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11596           val->in_val = 0;
11597         }
11598       }
11599       if (count > 0) deleteDefmapChain (&oldval);
11600     } // if
11601     val = val->next;
11602   }
11603
11604   /* handle valnum assignment */
11605   switch (pci->op) {
11606   case POC_CLRF: /* modifies STATUS (Z) */
11607     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11608       oldval = defmapCurr (list, sym1, pc);
11609       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11610         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11611         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11612       }
11613       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11614     }
11615     break;
11616
11617   case POC_SETF: /* SETF does not touch STATUS */
11618     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11619       oldval = defmapCurr (list, sym1, pc);
11620       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11621         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11622         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11623       }
11624       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11625     }
11626     break;
11627     
11628   case POC_MOVLW: /* does not touch STATUS */
11629     oldval = defmapCurr (list, SPO_WREG, pc);
11630     if (pci->pcop->type == PO_LITERAL) {
11631       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11632       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11633     } else {
11634       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11635       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11636     }
11637     if (oldval && oldval->in_val == litnum) {
11638       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11639       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11640     }
11641     defmapUpdate (list, SPO_WREG, pc, litnum);
11642     break;
11643
11644   case POC_ANDLW: /* modifies STATUS (Z,N) */
11645   case POC_IORLW: /* modifies STATUS (Z,N) */
11646   case POC_XORLW: /* modifies STATUS (Z,N) */
11647     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11648     if (pci->pcop->type == PO_LITERAL) {
11649       int vallit = -1;
11650       lit = (unsigned char) PCOL(pci->pcop)->lit;
11651       val = defmapCurr (list, SPO_WREG, pc);
11652       if (val) vallit = litFromValnum (val->in_val);
11653       if (vallit != -1) {
11654         /* xxxLW <literal>, WREG contains a known literal */
11655         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11656         if (pci->op == POC_ANDLW) {
11657           lit &= vallit;
11658         } else if (pci->op == POC_IORLW) {
11659           lit |= vallit;
11660         } else if (pci->op == POC_XORLW) {
11661           lit ^= vallit;
11662         } else {
11663           assert (0 && "invalid operation");
11664         }
11665         if (vallit == lit) {
11666           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11667           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11668         }
11669         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11670       } // if
11671     }
11672     break;
11673
11674   case POC_LFSR:
11675     {
11676       /* check if old value matches new value */
11677       int lit;
11678       int ok = 1;
11679       assert (pci->pcop->type == PO_LITERAL);
11680       
11681       lit = PCOL(pci->pcop)->lit;
11682       
11683       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11684       
11685       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11686         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11687       } else {
11688         /* cannot remove this LFSR */
11689         ok = 0;      
11690       } // if
11691       
11692       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11693       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11694         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11695       } else {
11696         ok = 0;
11697       } // if
11698
11699       if (ok) {
11700         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11701       }
11702     }
11703     break;
11704     
11705   case POC_MOVWF: /* does not touch flags */
11706     /* find value of WREG */
11707     val = defmapCurr (list, SPO_WREG, pc);
11708     oldval = defmapCurr (list, sym1, pc);
11709     if (val) lit = litFromValnum (val->in_val);
11710     else lit = -1;
11711     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11712     
11713     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11714       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11715       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11716       if (lit == 0) {
11717         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11718       } else {
11719         assert (lit == 0x0ff);
11720         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11721       }
11722       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11723       pic16_pCodeReplace (pc, newpc);
11724       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11725       pic16_fixDefmap (pc, newpc);
11726       pc = newpc;
11727         
11728       /* This breaks the defmap chain's references to pCodes... fix it! */
11729       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11730       if (!val->acc.access.isWrite) {
11731         deleteDefmap (val);     // delete reference to WREG as in value
11732         val = NULL;
11733       } else {
11734         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11735       }
11736       oldval = PCI(pc)->pcflow->defmap;
11737       while (oldval) {
11738         if (oldval->pc == pc) oldval->pc = newpc;
11739           oldval = oldval->next;
11740       } // while
11741     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11742       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11743       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11744     }
11745     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11746     break;
11747     
11748   case POC_MOVFW: /* modifies STATUS (Z,N) */
11749     /* find value of REG */
11750     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11751       val = defmapCurr (list, sym1, pc);
11752       oldval = defmapCurr (list, SPO_WREG, pc);
11753       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11754         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11755         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11756       }
11757       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11758     }
11759     break;
11760
11761   case POC_MOVFF: /* does not touch STATUS */
11762     /* find value of REG */
11763     val = defmapCurr (list, sym1, pc);
11764     oldval = defmapCurr (list, sym2, pc);
11765     if (val) lit = litFromValnum (val->in_val);
11766     else lit = -1;
11767     newpc = NULL;
11768     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11769       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11770       if (lit == 0) {
11771         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11772       } else if (lit == 0x00ff) {
11773         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11774       } else {
11775         newpc = NULL;
11776       }
11777       if (newpc) {
11778         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11779         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11780         pic16_pCodeReplace (pc, newpc); 
11781         defmapReplaceSymRef (pc, sym1, 0, 1);
11782         pic16_fixDefmap (pc, newpc);
11783         pc = newpc;
11784         break; // do not process instruction as MOVFF...
11785       }
11786     } else if (!isSpecial1 && !isSpecial2
11787                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11788                 && val && oldval && (val->in_val != 0)) {
11789       if (val->in_val == oldval->in_val) {
11790         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11791         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11792       } else {
11793         if (!pic16_isAlive (sym1, pc)) {
11794           defmap_t *copy = NULL;
11795           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11796            * This should help eliminate
11797            *   MOVFF A,B
11798            *   <do something not changing A or using B>
11799            *   MOVFF B,C
11800            *   <B is not alive anymore>
11801            * and turn it into
11802            *   <do something not changing A or using B>
11803            *   MOVFF A,C
11804            */
11805
11806           /* scan defmap for symbols storing sym1's value */
11807           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11808           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11809             /* unique reaching definition for sym found */
11810             if (copy->val && copy->val == val->in_val) {
11811               //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);
11812               if (copy->sym == SPO_WREG) {
11813                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11814               } else {
11815                 pCodeOp *pcop = NULL;
11816                 /* the code below fails if we try to replace
11817                  *   MOVFF PRODL, r0x03
11818                  *   MOVFF r0x03, PCLATU
11819                  * with
11820                  *   MOVFF PRODL, PCLATU
11821                  * as copy(PRODL) contains has pc==NULL, by name fails...
11822                  */
11823                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11824                 
11825                 if (copy->pc && PCI(copy->pc)->pcop)
11826                   pcop = PCI(copy->pc)->pcop;
11827 #if 0
11828                 /* This code is broken--see above. */
11829                 else
11830                 {
11831                   const char *symname = strFromSym(copy->sym);
11832                   
11833                   assert( symname );
11834                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11835                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11836                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11837                 }
11838 #endif
11839                 assert( pcop );
11840                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11841                         pcop,
11842                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11843               }
11844               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11845               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11846               pic16_pCodeReplace (pc, newpc); 
11847               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11848               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11849               pic16_fixDefmap (pc, newpc);
11850               pc = newpc;
11851             }
11852           }
11853           deleteDefmapChain (&copy);
11854         }
11855       }
11856       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11857     }
11858     break;
11859
11860   default:
11861     /* cannot optimize */
11862     break;
11863   } // switch
11864 }
11865
11866 static void pic16_destructDF (pBlock *pb) {
11867   pCode *pc, *next;
11868
11869   /* remove old defmaps */
11870   pc = pic16_findNextInstruction (pb->pcHead);
11871   while (pc) {
11872     next = pic16_findNextInstruction (pc->next);
11873
11874     assert (isPCI(pc) || isPCAD(pc));
11875     assert (PCI(pc)->pcflow);
11876     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11877     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11878     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11879     
11880     pc = next;
11881   } // while
11882   
11883   if (defmap_free || defmap_free_count) {
11884     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11885     freeDefmap (&defmap_free);
11886     defmap_free_count = 0;
11887   }
11888 }
11889
11890 /* Checks whether a pBlock contains ASMDIRs. */
11891 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11892   pCode *pc;
11893
11894   pc = pic16_findNextInstruction (pb->pcHead);
11895   while (pc) {
11896     if (isPCAD(pc)) return 1;
11897
11898     pc = pic16_findNextInstruction (pc->next);
11899   } // while
11900
11901   /* no PCADs found */
11902   return 0;
11903 }
11904
11905 #if 1
11906 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11907 static int pic16_removeUnusedRegistersDF () {
11908   pCode *pc, *pc2;
11909   pBlock *pb;
11910   regs *reg1, *reg2, *reg3;
11911   set *seenRegs = NULL;
11912   int cond, i;
11913   int islocal, change = 0;
11914
11915   /* no pBlocks? */
11916   if (!the_pFile || !the_pFile->pbHead) return 0;
11917   
11918   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11919     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11920 #if 1
11921     /* find set of using pCodes per register */
11922     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11923                     pc = pic16_findNextInstruction(pc->next)) {
11924
11925       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11926       reg1 = reg2 = NULL;
11927       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11928       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11929
11930       if (reg1) {
11931         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11932         addSetIfnotP (&seenRegs, reg1);
11933         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11934       }
11935       if (reg2) {
11936         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11937         addSetIfnotP (&seenRegs, reg2);
11938         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11939       }
11940     } // for pc
11941 #endif
11942     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11943       /* may not use pic16_regIsLocal() here -- in interrupt routines
11944        * WREG, PRODx, FSR0x must be saved */
11945       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11946       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11947         pc = pc2 = NULL;
11948         for (i=0; i < 2; i++) {
11949           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11950           if (!pc2) pc2 = pc;
11951           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11952           reg2 = pic16_getRegFromInstruction (pc);
11953           reg3 = pic16_getRegFromInstruction2 (pc);
11954           if (!reg2 || !reg3
11955               || (reg2->rIdx != pic16_stack_preinc->rIdx
11956                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11957           if (i == 1) {
11958             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11959             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11960             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11961             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11962           }
11963         } // for
11964       } // if
11965       deleteSet (&reg1->reglives.usedpCodes);
11966     } // for reg1
11967
11968     deleteSet (&seenRegs);
11969   } // for pb
11970
11971   return change;
11972 }
11973 #endif
11974
11975 /* Set up pCodeFlow's defmap_ts. 
11976  * Needs correctly set up to/from fields. */
11977 static void pic16_createDF (pBlock *pb) {
11978   pCode *pc, *next;
11979   int change=0;
11980
11981   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11982
11983   pic16_destructDF (pb);
11984
11985   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11986   if (pic16_pBlockHasAsmdirs (pb)) {
11987     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11988     return;
11989   }
11990
11991   /* integrity check -- we need to reach all flows to guarantee
11992    * correct data flow analysis (reaching definitions, aliveness) */
11993 #if 0
11994   if (!verifyAllFlowsReachable (pb)) {
11995     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11996     return;
11997   }
11998 #endif
11999   
12000   /* establish new defmaps */
12001   pc = pic16_findNextInstruction (pb->pcHead);
12002   while (pc) {
12003     next = pic16_findNextInstruction (pc->next);
12004
12005     assert (PCI(pc)->pcflow);
12006     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
12007
12008     pc = next;
12009   } // while
12010
12011   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
12012   createReachingDefinitions (pb);
12013   
12014 #if 1
12015   /* assign better valnums */
12016   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
12017   pc = pic16_findNextInstruction (pb->pcHead);
12018   while (pc) {
12019     next = pic16_findNextInstruction (pc->next);
12020
12021     assert (PCI(pc)->pcflow);
12022     assignValnums (pc);
12023
12024     pc = next;
12025   } // while
12026 #endif
12027
12028 #if 1
12029   /* remove dead pCodes */
12030   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
12031   do {
12032     change = 0;
12033     pc = pic16_findNextInstruction (pb->pcHead);
12034     while (pc) {
12035       next = pic16_findNextInstruction (pc->next);
12036
12037       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
12038         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
12039       }
12040
12041       pc = next;
12042     } // while
12043   } while (change);
12044 #endif
12045 }
12046
12047 /* ======================================================================== */
12048 /* === VCG DUMPER ROUTINES ================================================ */
12049 /* ======================================================================== */
12050 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12051 hTab *dumpedNodes = NULL;
12052
12053 /** Dump VCG header into of. */
12054 static void pic16_vcg_init (FILE *of) {
12055   /* graph defaults */
12056   fprintf (of, "graph:{\n");
12057   fprintf (of, "title:\"graph1\"\n");
12058   fprintf (of, "label:\"graph1\"\n");
12059   fprintf (of, "color:white\n");
12060   fprintf (of, "textcolor:black\n");
12061   fprintf (of, "bordercolor:black\n");
12062   fprintf (of, "borderwidth:1\n");
12063   fprintf (of, "textmode:center\n");
12064
12065   fprintf (of, "layoutalgorithm:dfs\n");
12066   fprintf (of, "late_edge_labels:yes\n");
12067   fprintf (of, "display_edge_labels:yes\n");
12068   fprintf (of, "dirty_edge_labels:yes\n");
12069   fprintf (of, "finetuning:yes\n");
12070   fprintf (of, "ignoresingles:no\n");
12071   fprintf (of, "straight_phase:yes\n");
12072   fprintf (of, "priority_phase:yes\n");
12073   fprintf (of, "manhattan_edges:yes\n");
12074   fprintf (of, "smanhattan_edges:no\n");
12075   fprintf (of, "nearedges:no\n");
12076   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12077   fprintf (of, "port_sharing:no\n");
12078   fprintf (of, "arrowmode:free\n"); // fixed|free
12079   fprintf (of, "crossingphase2:yes\n");
12080   fprintf (of, "crossingoptimization:yes\n");
12081   fprintf (of, "edges:yes\n");
12082   fprintf (of, "nodes:yes\n");
12083   fprintf (of, "splines:no\n");
12084   
12085   /* node defaults */
12086   fprintf (of, "node.color:lightyellow\n");
12087   fprintf (of, "node.textcolor:black\n");
12088   fprintf (of, "node.textmode:center\n");
12089   fprintf (of, "node.shape:box\n");
12090   fprintf (of, "node.bordercolor:black\n");
12091   fprintf (of, "node.borderwidth:1\n");
12092
12093   /* edge defaults */
12094   fprintf (of, "edge.textcolor:black\n");
12095   fprintf (of, "edge.color:black\n");
12096   fprintf (of, "edge.thickness:1\n");
12097   fprintf (of, "edge.arrowcolor:black\n");
12098   fprintf (of, "edge.backarrowcolor:black\n");
12099   fprintf (of, "edge.arrowsize:15\n");
12100   fprintf (of, "edge.backarrowsize:15\n");
12101   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12102   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12103   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12104   
12105   fprintf (of, "\n");
12106
12107   /* prepare data structures */
12108   if (dumpedNodes) {
12109     hTabDeleteAll (dumpedNodes);
12110     dumpedNodes = NULL;
12111   }
12112   dumpedNodes = newHashTable (128);
12113 }
12114
12115 /** Dump VCG footer into of. */
12116 static void pic16_vcg_close (FILE *of) {
12117   fprintf (of, "}\n");
12118 }
12119
12120 #define BUF_SIZE 128
12121 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12122
12123 #if 0
12124 static int ptrcmp (const void *p1, const void *p2) {
12125   return p1 == p2;
12126 }
12127 #endif
12128
12129 /** Dump a pCode node as VCG to of. */
12130 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12131   char buf[BUF_SIZE];
12132
12133   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12134     // dumped already
12135     return;
12136   }
12137   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12138   //fprintf (stderr, "dumping %p\n", pc);
12139  
12140   /* only dump pCodeInstructions and Flow nodes */
12141   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12142     
12143   /* emit node */
12144   fprintf (of, "node:{");
12145   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12146   fprintf (of, "label:\"%s\n", pcTitle(pc));
12147   if (isPCFL(pc)) {
12148     fprintf (of, "<PCFLOW>");
12149   } else if (isPCI(pc) || isPCAD(pc)) {
12150     pc->print (of, pc);
12151   } else {
12152     fprintf (of, "<!PCI>");
12153   }
12154   fprintf (of, "\" ");
12155   fprintf (of, "}\n");
12156   
12157   if (1 && isPCFL(pc)) {
12158     defmap_t *map, *prev;
12159     unsigned int i;
12160     map = PCFL(pc)->defmap;
12161     i=0;
12162     while (map) {
12163       if (map->sym != 0) {
12164         i++;
12165       
12166         /* emit definition node */
12167         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12168         fprintf (of, "label:\"");
12169
12170         prev = map;
12171         do {
12172           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));
12173           prev = map;
12174           map = map->next;
12175         } while (map && prev->pc == map->pc);
12176         map = prev;
12177         
12178         fprintf (of, "\" ");
12179       
12180         fprintf (of, "color:green ");
12181         fprintf (of, "}\n");
12182
12183         /* emit edge to previous definition */
12184         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12185         if (i == 1) {
12186           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12187         } else {
12188           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12189         }
12190         fprintf (of, "color:green ");
12191         fprintf (of, "}\n");
12192
12193         if (map->pc) {
12194           pic16_vcg_dumpnode (map->pc, of);
12195           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12196           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12197         }
12198       }
12199       map = map->next;
12200     } // while
12201   }
12202
12203   /* emit additional nodes (e.g. operands) */
12204 }
12205
12206 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12207 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12208   char buf[BUF_SIZE];
12209   pCodeInstruction *pci;
12210   pBranch *curr;
12211   int i;
12212   
12213   if (1 && isPCFL(pc)) {
12214     /* emit edges to flow successors */
12215     void *pcfl;
12216     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12217     pcfl = setFirstItem (PCFL(pc)->to);
12218     while (pcfl) {
12219       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12220       pic16_vcg_dumpnode (pc, of);
12221       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12222       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12223       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12224       pcfl = setNextItem (PCFL(pc)->to);
12225     } // while
12226   } // if
12227   
12228   if (!isPCI(pc) && !isPCAD(pc)) return;
12229
12230   pci = PCI(pc);
12231   
12232   /* emit control flow edges (forward only) */
12233   curr = pci->to;
12234   i=0;
12235   while (curr) {
12236     pic16_vcg_dumpnode (curr->pc, of);
12237     fprintf (of, "edge:{");
12238     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12239     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12240     fprintf (of, "color:red ");
12241     fprintf (of, "}\n");
12242     curr = curr->next;
12243   } // while
12244
12245 #if 1
12246   /* dump "flow" edge (link pCode according to pBlock order) */
12247   {
12248     pCode *pcnext;
12249     pcnext = pic16_findNextInstruction (pc->next);
12250     if (pcnext) {
12251       pic16_vcg_dumpnode (pcnext, of);
12252       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12253       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12254     }
12255   }
12256 #endif
12257   
12258 #if 0
12259   /* emit flow */
12260   if (pci->pcflow) {
12261     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12262     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12263     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12264   }
12265 #endif
12266   
12267   /* emit data flow edges (backward only) */
12268   /* TODO: gather data flow information... */
12269 }
12270
12271 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12272   pCode *pc;
12273
12274   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12275   if (pic16_pBlockHasAsmdirs (pb)) {
12276     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12277     return;
12278   }
12279
12280   for (pc=pb->pcHead; pc; pc = pc->next) {
12281     pic16_vcg_dumpnode (pc, of);
12282   } // for pc
12283   
12284   for (pc=pb->pcHead; pc; pc = pc->next) {
12285     pic16_vcg_dumpedges (pc, of);
12286   } // for pc
12287 }
12288
12289 static void pic16_vcg_dump_default (pBlock *pb) {
12290   FILE *of;
12291   char buf[BUF_SIZE];
12292   pCode *pc;
12293
12294   /* get function name */
12295   pc = pb->pcHead;
12296   while (pc && !isPCF(pc)) pc = pc->next;
12297   if (pc) {
12298     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12299   } else {
12300     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12301   }
12302
12303   //fprintf (stderr, "now dumping %s\n", buf);
12304   of = fopen (buf, "w");
12305   pic16_vcg_init (of);
12306   pic16_vcg_dump (of, pb);
12307   pic16_vcg_close (of);
12308   fclose (of);
12309 }
12310 #endif
12311
12312 /*** END of helpers for pCode dataflow optimizations ***/