* device/lib/pic16/libdev/pic18f*.c,
[fw/sdcc] / src / pic16 / pcode.c
1 /*-------------------------------------------------------------------------
2
3   pcode.c - post code generation
4
5    Written By -  Scott Dattalo scott@dattalo.com
6    Ported to PIC16 By -  Martin Dubuc m.dubuc@rogers.com
7
8    This program is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published by the
10    Free Software Foundation; either version 2, or (at your option) any
11    later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 -------------------------------------------------------------------------*/
22
23 #include <stdio.h>
24
25 #include "common.h"   // Include everything in the SDCC src directory
26 #include "newalloc.h"
27
28
29 #include "main.h"
30 #include "pcode.h"
31 #include "pcodeflow.h"
32 #include "ralloc.h"
33 #include "device.h"
34
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
36
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
38 #define STRCASECMP stricmp
39 #define inline
40 #else
41 #define STRCASECMP strcasecmp
42 #endif
43
44 #define DUMP_DF_GRAPHS 0
45
46 /****************************************************************/
47 /****************************************************************/
48
49 static peepCommand peepCommands[] = {
50
51   {NOTBITSKIP, "_NOTBITSKIP_"},
52   {BITSKIP, "_BITSKIP_"},
53   {INVERTBITSKIP, "_INVERTBITSKIP_"},
54
55   {-1, NULL}
56 };
57
58
59
60 // Eventually this will go into device dependent files:
61 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
66 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
68
69 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
71 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
72
73 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
74 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
75 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
76 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
77
78 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
79
80 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
86
87 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
88 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
92
93 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
94 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
98
99 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
100 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
104
105 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
106 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
107
108 /* EEPROM registers */
109 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
113
114 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
115 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
117
118 pCodeOpReg *pic16_stackpnt_lo;
119 pCodeOpReg *pic16_stackpnt_hi;
120 pCodeOpReg *pic16_stack_postinc;
121 pCodeOpReg *pic16_stack_postdec;
122 pCodeOpReg *pic16_stack_preinc;
123 pCodeOpReg *pic16_stack_plusw;
124
125 pCodeOpReg *pic16_framepnt_lo;
126 pCodeOpReg *pic16_framepnt_hi;
127 pCodeOpReg *pic16_frame_postinc;
128 pCodeOpReg *pic16_frame_postdec;
129 pCodeOpReg *pic16_frame_preinc;
130 pCodeOpReg *pic16_frame_plusw;
131
132 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
133 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
134
135 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
136 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
137
138
139 static int mnemonics_initialized = 0;
140
141
142 static hTab *pic16MnemonicsHash = NULL;
143 static hTab *pic16pCodePeepCommandsHash = NULL;
144
145 static pFile *the_pFile = NULL;
146 static pBlock *pb_dead_pcodes = NULL;
147
148 /* Hardcoded flags to change the behavior of the PIC port */
149 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
150 static int functionInlining = 1;      /* inline functions if nonzero */
151 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
152
153 int pic16_pcode_verbose = 0;
154
155 //static int GpCodeSequenceNumber = 1;
156 static int GpcFlowSeq = 1;
157
158 extern void pic16_RemoveUnusedRegisters(void);
159 extern void pic16_RegsUnMapLiveRanges(void);
160 extern void pic16_BuildFlowTree(pBlock *pb);
161 extern void pic16_pCodeRegOptimizeRegUsage(int level);
162 extern int pic16_picIsInitialized(void);
163 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
164 extern int mnem2key(char const *mnem);
165
166 /****************************************************************/
167 /*                      Forward declarations                    */
168 /****************************************************************/
169
170 void pic16_unlinkpCode(pCode *pc);
171 #if 0
172 static void genericAnalyze(pCode *pc);
173 static void AnalyzeGOTO(pCode *pc);
174 static void AnalyzeSKIP(pCode *pc);
175 static void AnalyzeRETURN(pCode *pc);
176 #endif
177
178 static void genericDestruct(pCode *pc);
179 static void genericPrint(FILE *of,pCode *pc);
180
181 static void pCodePrintLabel(FILE *of, pCode *pc);
182 static void pCodePrintFunction(FILE *of, pCode *pc);
183 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
184 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
185 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
186 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
187 int pic16_pCodePeepMatchRule(pCode *pc);
188 static void pBlockStats(FILE *of, pBlock *pb);
189 static pBlock *newpBlock(void);
190 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
191 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
192 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
193 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
194 void OptimizeLocalRegs(void);
195 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
196
197 char *dumpPicOptype(PIC_OPTYPE type);
198
199 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
200 pCodeOp *pic16_popGetLit(int);
201 pCodeOp *pic16_popGetWithString(char *);
202 extern int inWparamList(char *s);
203
204 /** data flow optimization helpers **/
205 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
206 static void pic16_vcg_dump (FILE *of, pBlock *pb);
207 static void pic16_vcg_dump_default (pBlock *pb);
208 #endif
209 static int pic16_pCodeIsAlive (pCode *pc);
210 static void pic16_df_stats ();
211 static void pic16_createDF (pBlock *pb);
212 static int pic16_removeUnusedRegistersDF ();
213 static void pic16_destructDF (pBlock *pb);
214 static void releaseStack ();
215
216 /****************************************************************/
217 /*                    PIC Instructions                          */
218 /****************************************************************/
219
220 pCodeInstruction pic16_pciADDWF = {
221   {PC_OPCODE, NULL, NULL, 0, NULL, 
222    //   genericAnalyze,
223    genericDestruct,
224    genericPrint},
225   POC_ADDWF,
226   "ADDWF",
227   2,
228   NULL, // from branch
229   NULL, // to branch
230   NULL, // label
231   NULL, // operand
232   NULL, // flow block
233   NULL, // C source 
234   3,    // num ops
235   1,0,  // dest, bit instruction
236   0,0,  // branch, skip
237   0,    // literal operand
238   1,    // RAM access bit
239   0,    // fast call/return mode select bit
240   0,    // second memory operand
241   0,    // second literal operand
242   POC_NOP,
243   (PCC_W | PCC_REGISTER),   // inCond
244   (PCC_REGISTER | PCC_STATUS), // outCond
245   PCI_MAGIC
246 };
247
248 pCodeInstruction pic16_pciADDFW = {
249   {PC_OPCODE, NULL, NULL, 0, NULL, 
250    //   genericAnalyze,
251    genericDestruct,
252    genericPrint},
253   POC_ADDFW,
254   "ADDWF",
255   2,
256   NULL, // from branch
257   NULL, // to branch
258   NULL, // label
259   NULL, // operand
260   NULL, // flow block
261   NULL, // C source 
262   3,    // num ops
263   0,0,  // dest, bit instruction
264   0,0,  // branch, skip
265   0,    // literal operand
266   1,    // RAM access bit
267   0,    // fast call/return mode select bit
268   0,    // second memory operand
269   0,    // second literal operand
270   POC_NOP,
271   (PCC_W | PCC_REGISTER),   // inCond
272   (PCC_W | PCC_STATUS), // outCond
273   PCI_MAGIC
274 };
275
276 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
277   {PC_OPCODE, NULL, NULL, 0, NULL, 
278    //   genericAnalyze,
279    genericDestruct,
280    genericPrint},
281   POC_ADDWFC,
282   "ADDWFC",
283   2,
284   NULL, // from branch
285   NULL, // to branch
286   NULL, // label
287   NULL, // operand
288   NULL, // flow block
289   NULL, // C source 
290   3,    // num ops
291   1,0,  // dest, bit instruction
292   0,0,  // branch, skip
293   0,    // literal operand
294   1,    // RAM access bit
295   0,    // fast call/return mode select bit
296   0,    // second memory operand
297   0,    // second literal operand
298   POC_NOP,
299   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
300   (PCC_REGISTER | PCC_STATUS), // outCond
301   PCI_MAGIC
302 };
303
304 pCodeInstruction pic16_pciADDFWC = {
305   {PC_OPCODE, NULL, NULL, 0, NULL, 
306    //   genericAnalyze,
307    genericDestruct,
308    genericPrint},
309   POC_ADDFWC,
310   "ADDWFC",
311   2,
312   NULL, // from branch
313   NULL, // to branch
314   NULL, // label
315   NULL, // operand
316   NULL, // flow block
317   NULL, // C source 
318   3,    // num ops
319   0,0,  // dest, bit instruction
320   0,0,  // branch, skip
321   0,    // literal operand
322   1,    // RAM access bit
323   0,    // fast call/return mode select bit
324   0,    // second memory operand
325   0,    // second literal operand
326   POC_NOP,
327   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
328   (PCC_W | PCC_STATUS), // outCond
329   PCI_MAGIC
330 };
331
332 pCodeInstruction pic16_pciADDLW = {
333   {PC_OPCODE, NULL, NULL, 0, NULL, 
334    //   genericAnalyze,
335    genericDestruct,
336    genericPrint},
337   POC_ADDLW,
338   "ADDLW",
339   2,
340   NULL, // from branch
341   NULL, // to branch
342   NULL, // label
343   NULL, // operand
344   NULL, // flow block
345   NULL, // C source 
346   1,    // num ops
347   0,0,  // dest, bit instruction
348   0,0,  // branch, skip
349   1,    // literal operand
350   0,    // RAM access bit
351   0,    // fast call/return mode select bit
352   0,    // second memory operand
353   0,    // second literal operand
354   POC_NOP,
355   (PCC_W | PCC_LITERAL),   // inCond
356   (PCC_W | PCC_STATUS), // outCond
357   PCI_MAGIC
358 };
359
360 pCodeInstruction pic16_pciANDLW = {
361   {PC_OPCODE, NULL, NULL, 0, NULL, 
362    //   genericAnalyze,
363    genericDestruct,
364    genericPrint},
365   POC_ANDLW,
366   "ANDLW",
367   2,
368   NULL, // from branch
369   NULL, // to branch
370   NULL, // label
371   NULL, // operand
372   NULL, // flow block
373   NULL, // C source 
374   1,    // num ops
375   0,0,  // dest, bit instruction
376   0,0,  // branch, skip
377   1,    // literal operand
378   0,    // RAM access bit
379   0,    // fast call/return mode select bit
380   0,    // second memory operand
381   0,    // second literal operand
382   POC_NOP,
383   (PCC_W | PCC_LITERAL),   // inCond
384   (PCC_W | PCC_Z | PCC_N), // outCond
385   PCI_MAGIC
386 };
387
388 pCodeInstruction pic16_pciANDWF = {
389   {PC_OPCODE, NULL, NULL, 0, NULL, 
390    //   genericAnalyze,
391    genericDestruct,
392    genericPrint},
393   POC_ANDWF,
394   "ANDWF",
395   2,
396   NULL, // from branch
397   NULL, // to branch
398   NULL, // label
399   NULL, // operand
400   NULL, // flow block
401   NULL, // C source 
402   3,    // num ops
403   1,0,  // dest, bit instruction
404   0,0,  // branch, skip
405   0,    // literal operand
406   1,    // RAM access bit
407   0,    // fast call/return mode select bit
408   0,    // second memory operand
409   0,    // second literal operand
410   POC_NOP,
411   (PCC_W | PCC_REGISTER),   // inCond
412   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
413   PCI_MAGIC
414 };
415
416 pCodeInstruction pic16_pciANDFW = {
417   {PC_OPCODE, NULL, NULL, 0, NULL, 
418    //   genericAnalyze,
419    genericDestruct,
420    genericPrint},
421   POC_ANDFW,
422   "ANDWF",
423   2,
424   NULL, // from branch
425   NULL, // to branch
426   NULL, // label
427   NULL, // operand
428   NULL, // flow block
429   NULL, // C source 
430   3,    // num ops
431   0,0,  // dest, bit instruction
432   0,0,  // branch, skip
433   0,    // literal operand
434   1,    // RAM access bit
435   0,    // fast call/return mode select bit
436   0,    // second memory operand
437   0,    // second literal operand
438   POC_NOP,
439   (PCC_W | PCC_REGISTER),   // inCond
440   (PCC_W | PCC_Z | PCC_N) // outCond
441 };
442
443 pCodeInstruction pic16_pciBC = { // mdubuc - New
444   {PC_OPCODE, NULL, NULL, 0, NULL, 
445    //   genericAnalyze,
446    genericDestruct,
447    genericPrint},
448   POC_BC,
449   "BC",
450   2,
451   NULL, // from branch
452   NULL, // to branch
453   NULL, // label
454   NULL, // operand
455   NULL, // flow block
456   NULL, // C source 
457   1,    // num ops
458   0,0,  // dest, bit instruction
459   1,0,  // branch, skip
460   0,    // literal operand
461   0,    // RAM access bit
462   0,    // fast call/return mode select bit
463   0,    // second memory operand
464   0,    // second literal operand
465   POC_NOP,
466   (PCC_REL_ADDR | PCC_C),   // inCond
467   PCC_NONE,    // outCond
468   PCI_MAGIC
469 };
470
471 pCodeInstruction pic16_pciBCF = {
472   {PC_OPCODE, NULL, NULL, 0, NULL, 
473    //   genericAnalyze,
474    genericDestruct,
475    genericPrint},
476   POC_BCF,
477   "BCF",
478   2,
479   NULL, // from branch
480   NULL, // to branch
481   NULL, // label
482   NULL, // operand
483   NULL, // flow block
484   NULL, // C source 
485   3,    // num ops
486   1,1,  // dest, bit instruction
487   0,0,  // branch, skip
488   0,    // literal operand
489   1,    // RAM access bit
490   0,    // fast call/return mode select bit
491   0,    // second memory operand
492   0,    // second literal operand
493   POC_BSF,
494   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
495   PCC_REGISTER, // outCond
496   PCI_MAGIC
497 };
498
499 pCodeInstruction pic16_pciBN = { // mdubuc - New
500   {PC_OPCODE, NULL, NULL, 0, NULL, 
501    //   genericAnalyze,
502    genericDestruct,
503    genericPrint},
504   POC_BN,
505   "BN",
506   2,
507   NULL, // from branch
508   NULL, // to branch
509   NULL, // label
510   NULL, // operand
511   NULL, // flow block
512   NULL, // C source 
513   1,    // num ops
514   0,0,  // dest, bit instruction
515   1,0,  // branch, skip
516   0,    // literal operand
517   0,    // RAM access bit
518   0,    // fast call/return mode select bit
519   0,    // second memory operand
520   0,    // second literal operand
521   POC_NOP,
522   (PCC_REL_ADDR | PCC_N),   // inCond
523   PCC_NONE   , // outCond
524   PCI_MAGIC
525 };
526
527 pCodeInstruction pic16_pciBNC = { // mdubuc - New
528   {PC_OPCODE, NULL, NULL, 0, NULL, 
529    //   genericAnalyze,
530    genericDestruct,
531    genericPrint},
532   POC_BNC,
533   "BNC",
534   2,
535   NULL, // from branch
536   NULL, // to branch
537   NULL, // label
538   NULL, // operand
539   NULL, // flow block
540   NULL, // C source 
541   1,    // num ops
542   0,0,  // dest, bit instruction
543   1,0,  // branch, skip
544   0,    // literal operand
545   0,    // RAM access bit
546   0,    // fast call/return mode select bit
547   0,    // second memory operand
548   0,    // second literal operand
549   POC_NOP,
550   (PCC_REL_ADDR | PCC_C),   // inCond
551   PCC_NONE   , // outCond
552   PCI_MAGIC
553 };
554
555 pCodeInstruction pic16_pciBNN = { // mdubuc - New
556   {PC_OPCODE, NULL, NULL, 0, NULL, 
557    //   genericAnalyze,
558    genericDestruct,
559    genericPrint},
560   POC_BNN,
561   "BNN",
562   2,
563   NULL, // from branch
564   NULL, // to branch
565   NULL, // label
566   NULL, // operand
567   NULL, // flow block
568   NULL, // C source 
569   1,    // num ops
570   0,0,  // dest, bit instruction
571   1,0,  // branch, skip
572   0,    // literal operand
573   0,    // RAM access bit
574   0,    // fast call/return mode select bit
575   0,    // second memory operand
576   0,    // second literal operand
577   POC_NOP,
578   (PCC_REL_ADDR | PCC_N),   // inCond
579   PCC_NONE   , // outCond
580   PCI_MAGIC
581 };
582
583 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
584   {PC_OPCODE, NULL, NULL, 0, NULL, 
585    //   genericAnalyze,
586    genericDestruct,
587    genericPrint},
588   POC_BNOV,
589   "BNOV",
590   2,
591   NULL, // from branch
592   NULL, // to branch
593   NULL, // label
594   NULL, // operand
595   NULL, // flow block
596   NULL, // C source 
597   1,    // num ops
598   0,0,  // dest, bit instruction
599   1,0,  // branch, skip
600   0,    // literal operand
601   0,    // RAM access bit
602   0,    // fast call/return mode select bit
603   0,    // second memory operand
604   0,    // second literal operand
605   POC_NOP,
606   (PCC_REL_ADDR | PCC_OV),   // inCond
607   PCC_NONE   , // outCond
608   PCI_MAGIC
609 };
610
611 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
612   {PC_OPCODE, NULL, NULL, 0, NULL, 
613    //   genericAnalyze,
614    genericDestruct,
615    genericPrint},
616   POC_BNZ,
617   "BNZ",
618   2,
619   NULL, // from branch
620   NULL, // to branch
621   NULL, // label
622   NULL, // operand
623   NULL, // flow block
624   NULL, // C source 
625   1,    // num ops
626   0,0,  // dest, bit instruction
627   1,0,  // branch, skip
628   0,    // literal operand
629   0,    // RAM access bit
630   0,    // fast call/return mode select bit
631   0,    // second memory operand
632   0,    // second literal operand
633   POC_NOP,
634   (PCC_REL_ADDR | PCC_Z),   // inCond
635   PCC_NONE   , // outCond
636   PCI_MAGIC
637 };
638
639 pCodeInstruction pic16_pciBOV = { // mdubuc - New
640   {PC_OPCODE, NULL, NULL, 0, NULL, 
641    //   genericAnalyze,
642    genericDestruct,
643    genericPrint},
644   POC_BOV,
645   "BOV",
646   2,
647   NULL, // from branch
648   NULL, // to branch
649   NULL, // label
650   NULL, // operand
651   NULL, // flow block
652   NULL, // C source 
653   1,    // num ops
654   0,0,  // dest, bit instruction
655   1,0,  // branch, skip
656   0,    // literal operand
657   0,    // RAM access bit
658   0,    // fast call/return mode select bit
659   0,    // second memory operand
660   0,    // second literal operand
661   POC_NOP,
662   (PCC_REL_ADDR | PCC_OV),   // inCond
663   PCC_NONE , // outCond
664   PCI_MAGIC
665 };
666
667 pCodeInstruction pic16_pciBRA = { // mdubuc - New
668   {PC_OPCODE, NULL, NULL, 0, NULL, 
669    //   genericAnalyze,
670    genericDestruct,
671    genericPrint},
672   POC_BRA,
673   "BRA",
674   2,
675   NULL, // from branch
676   NULL, // to branch
677   NULL, // label
678   NULL, // operand
679   NULL, // flow block
680   NULL, // C source 
681   1,    // num ops
682   0,0,  // dest, bit instruction
683   1,0,  // branch, skip
684   0,    // literal operand
685   0,    // RAM access bit
686   0,    // fast call/return mode select bit
687   0,    // second memory operand
688   0,    // second literal operand
689   POC_NOP,
690   PCC_REL_ADDR,   // inCond
691   PCC_NONE   , // outCond
692   PCI_MAGIC
693 };
694
695 pCodeInstruction pic16_pciBSF = {
696   {PC_OPCODE, NULL, NULL, 0, NULL, 
697    //   genericAnalyze,
698    genericDestruct,
699    genericPrint},
700   POC_BSF,
701   "BSF",
702   2,
703   NULL, // from branch
704   NULL, // to branch
705   NULL, // label
706   NULL, // operand
707   NULL, // flow block
708   NULL, // C source 
709   3,    // num ops
710   1,1,  // dest, bit instruction
711   0,0,  // branch, skip
712   0,    // literal operand
713   1,    // RAM access bit
714   0,    // fast call/return mode select bit
715   0,    // second memory operand
716   0,    // second literal operand
717   POC_BCF,
718   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
719   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
720   PCI_MAGIC
721 };
722
723 pCodeInstruction pic16_pciBTFSC = {
724   {PC_OPCODE, NULL, NULL, 0, NULL, 
725    //   AnalyzeSKIP,
726    genericDestruct,
727    genericPrint},
728   POC_BTFSC,
729   "BTFSC",
730   2,
731   NULL, // from branch
732   NULL, // to branch
733   NULL, // label
734   NULL, // operand
735   NULL, // flow block
736   NULL, // C source 
737   3,    // num ops
738   0,1,  // dest, bit instruction
739   1,1,  // branch, skip
740   0,    // literal operand
741   1,    // RAM access bit
742   0,    // fast call/return mode select bit
743   0,    // second memory operand
744   0,    // second literal operand
745   POC_BTFSS,
746   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
747   PCC_EXAMINE_PCOP, // outCond
748   PCI_MAGIC
749 };
750
751 pCodeInstruction pic16_pciBTFSS = {
752   {PC_OPCODE, NULL, NULL, 0, NULL, 
753    //   AnalyzeSKIP,
754    genericDestruct,
755    genericPrint},
756   POC_BTFSS,
757   "BTFSS",
758   2,
759   NULL, // from branch
760   NULL, // to branch
761   NULL, // label
762   NULL, // operand
763   NULL, // flow block
764   NULL, // C source 
765   3,    // num ops
766   0,1,  // dest, bit instruction
767   1,1,  // branch, skip
768   0,    // literal operand
769   1,    // RAM access bit
770   0,    // fast call/return mode select bit
771   0,    // second memory operand
772   0,    // second literal operand
773   POC_BTFSC,
774   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
775   PCC_EXAMINE_PCOP, // outCond
776   PCI_MAGIC
777 };
778
779 pCodeInstruction pic16_pciBTG = { // mdubuc - New
780   {PC_OPCODE, NULL, NULL, 0, NULL, 
781    //   genericAnalyze,
782    genericDestruct,
783    genericPrint},
784   POC_BTG,
785   "BTG",
786   2,
787   NULL, // from branch
788   NULL, // to branch
789   NULL, // label
790   NULL, // operand
791   NULL, // flow block
792   NULL, // C source 
793   3,    // num ops
794   0,1,  // dest, bit instruction
795   0,0,  // branch, skip
796   0,    // literal operand
797   1,    // RAM access bit
798   0,    // fast call/return mode select bit
799   0,    // second memory operand
800   0,    // second literal operand
801   POC_NOP,
802   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
803   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
804   PCI_MAGIC
805 };
806
807 pCodeInstruction pic16_pciBZ = { // mdubuc - New
808   {PC_OPCODE, NULL, NULL, 0, NULL, 
809    //   genericAnalyze,
810    genericDestruct,
811    genericPrint},
812   POC_BZ,
813   "BZ",
814   2,
815   NULL, // from branch
816   NULL, // to branch
817   NULL, // label
818   NULL, // operand
819   NULL, // flow block
820   NULL, // C source 
821   1,    // num ops
822   0,0,  // dest, bit instruction
823   1,0,  // branch, skip
824   0,    // literal operand
825   0,    // RAM access bit
826   0,    // fast call/return mode select bit
827   0,    // second memory operand
828   0,    // second literal operand
829   POC_NOP,
830   (PCC_REL_ADDR | PCC_Z),   // inCond
831   PCC_NONE, // outCond
832   PCI_MAGIC
833 };
834
835 pCodeInstruction pic16_pciCALL = {
836   {PC_OPCODE, NULL, NULL, 0, NULL, 
837    //   genericAnalyze,
838    genericDestruct,
839    genericPrint},
840   POC_CALL,
841   "CALL",
842   4,
843   NULL, // from branch
844   NULL, // to branch
845   NULL, // label
846   NULL, // operand
847   NULL, // flow block
848   NULL, // C source 
849   2,    // num ops
850   0,0,  // dest, bit instruction
851   1,0,  // branch, skip
852   0,    // literal operand
853   0,    // RAM access bit
854   1,    // fast call/return mode select bit
855   0,    // second memory operand
856   0,    // second literal operand
857   POC_NOP,
858   PCC_NONE, // inCond
859   PCC_NONE, // outCond
860   PCI_MAGIC
861 };
862
863 pCodeInstruction pic16_pciCOMF = {
864   {PC_OPCODE, NULL, NULL, 0, NULL, 
865    //   genericAnalyze,
866    genericDestruct,
867    genericPrint},
868   POC_COMF,
869   "COMF",
870   2,
871   NULL, // from branch
872   NULL, // to branch
873   NULL, // label
874   NULL, // operand
875   NULL, // flow block
876   NULL, // C source 
877   3,    // num ops
878   1,0,  // dest, bit instruction
879   0,0,  // branch, skip
880   0,    // literal operand
881   1,    // RAM access bit
882   0,    // fast call/return mode select bit
883   0,    // second memory operand
884   0,    // second literal operand
885   POC_NOP,
886   PCC_REGISTER,  // inCond
887   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
888   PCI_MAGIC
889 };
890
891 pCodeInstruction pic16_pciCOMFW = {
892   {PC_OPCODE, NULL, NULL, 0, NULL, 
893    //   genericAnalyze,
894    genericDestruct,
895    genericPrint},
896   POC_COMFW,
897   "COMF",
898   2,
899   NULL, // from branch
900   NULL, // to branch
901   NULL, // label
902   NULL, // operand
903   NULL, // flow block
904   NULL, // C source 
905   3,    // num ops
906   0,0,  // dest, bit instruction
907   0,0,  // branch, skip
908   0,    // literal operand
909   1,    // RAM access bit
910   0,    // fast call/return mode select bit
911   0,    // second memory operand
912   0,    // second literal operand
913   POC_NOP,
914   PCC_REGISTER,  // inCond
915   (PCC_W | PCC_Z | PCC_N) , // outCond
916   PCI_MAGIC
917 };
918
919 pCodeInstruction pic16_pciCLRF = {
920   {PC_OPCODE, NULL, NULL, 0, NULL, 
921    //   genericAnalyze,
922    genericDestruct,
923    genericPrint},
924   POC_CLRF,
925   "CLRF",
926   2,
927   NULL, // from branch
928   NULL, // to branch
929   NULL, // label
930   NULL, // operand
931   NULL, // flow block
932   NULL, // C source 
933   2,    // num ops
934   0,0,  // dest, bit instruction
935   0,0,  // branch, skip
936   0,    // literal operand
937   1,    // RAM access bit
938   0,    // fast call/return mode select bit
939   0,    // second memory operand
940   0,    // second literal operand
941   POC_NOP,
942   PCC_NONE, // inCond
943   (PCC_REGISTER | PCC_Z), // outCond
944   PCI_MAGIC
945 };
946
947 pCodeInstruction pic16_pciCLRWDT = {
948   {PC_OPCODE, NULL, NULL, 0, NULL, 
949    //   genericAnalyze,
950    genericDestruct,
951    genericPrint},
952   POC_CLRWDT,
953   "CLRWDT",
954   2,
955   NULL, // from branch
956   NULL, // to branch
957   NULL, // label
958   NULL, // operand
959   NULL, // flow block
960   NULL, // C source 
961   0,    // num ops
962   0,0,  // dest, bit instruction
963   0,0,  // branch, skip
964   0,    // literal operand
965   0,    // RAM access bit
966   0,    // fast call/return mode select bit
967   0,    // second memory operand
968   0,    // second literal operand
969   POC_NOP,
970   PCC_NONE, // inCond
971   PCC_NONE , // outCond
972   PCI_MAGIC
973 };
974
975 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
976   {PC_OPCODE, NULL, NULL, 0, NULL, 
977    //   genericAnalyze,
978    genericDestruct,
979    genericPrint},
980   POC_CPFSEQ,
981   "CPFSEQ",
982   2,
983   NULL, // from branch
984   NULL, // to branch
985   NULL, // label
986   NULL, // operand
987   NULL, // flow block
988   NULL, // C source 
989   2,    // num ops
990   0,0,  // dest, bit instruction
991   1,1,  // branch, skip
992   0,    // literal operand
993   1,    // RAM access bit
994   0,    // fast call/return mode select bit
995   0,    // second memory operand
996   0,    // second literal operand
997   POC_NOP,
998   (PCC_W | PCC_REGISTER), // inCond
999   PCC_NONE , // outCond
1000   PCI_MAGIC
1001 };
1002
1003 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1004   {PC_OPCODE, NULL, NULL, 0, NULL, 
1005    //   genericAnalyze,
1006    genericDestruct,
1007    genericPrint},
1008   POC_CPFSGT,
1009   "CPFSGT",
1010   2,
1011   NULL, // from branch
1012   NULL, // to branch
1013   NULL, // label
1014   NULL, // operand
1015   NULL, // flow block
1016   NULL, // C source 
1017   2,    // num ops
1018   0,0,  // dest, bit instruction
1019   1,1,  // branch, skip
1020   0,    // literal operand
1021   1,    // RAM access bit
1022   0,    // fast call/return mode select bit
1023   0,    // second memory operand
1024   0,    // second literal operand
1025   POC_NOP,
1026   (PCC_W | PCC_REGISTER), // inCond
1027   PCC_NONE , // outCond
1028   PCI_MAGIC
1029 };
1030
1031 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1032   {PC_OPCODE, NULL, NULL, 0, NULL, 
1033    //   genericAnalyze,
1034    genericDestruct,
1035    genericPrint},
1036   POC_CPFSLT,
1037   "CPFSLT",
1038   2,
1039   NULL, // from branch
1040   NULL, // to branch
1041   NULL, // label
1042   NULL, // operand
1043   NULL, // flow block
1044   NULL, // C source 
1045   2,    // num ops
1046   1,0,  // dest, bit instruction
1047   1,1,  // branch, skip
1048   0,    // literal operand
1049   1,    // RAM access bit
1050   0,    // fast call/return mode select bit
1051   0,    // second memory operand
1052   0,    // second literal operand
1053   POC_NOP,
1054   (PCC_W | PCC_REGISTER), // inCond
1055   PCC_NONE , // outCond
1056   PCI_MAGIC
1057 };
1058
1059 pCodeInstruction pic16_pciDAW = {
1060   {PC_OPCODE, NULL, NULL, 0, NULL, 
1061    //   genericAnalyze,
1062    genericDestruct,
1063    genericPrint},
1064   POC_DAW,
1065   "DAW",
1066   2,
1067   NULL, // from branch
1068   NULL, // to branch
1069   NULL, // label
1070   NULL, // operand
1071   NULL, // flow block
1072   NULL, // C source 
1073   0,    // num ops
1074   0,0,  // dest, bit instruction
1075   0,0,  // branch, skip
1076   0,    // literal operand
1077   0,    // RAM access bit
1078   0,    // fast call/return mode select bit
1079   0,    // second memory operand
1080   0,    // second literal operand
1081   POC_NOP,
1082   PCC_W, // inCond
1083   (PCC_W | PCC_C), // outCond
1084   PCI_MAGIC
1085 };
1086
1087 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1088   {PC_OPCODE, NULL, NULL, 0, NULL, 
1089    //   genericAnalyze,
1090    genericDestruct,
1091    genericPrint},
1092   POC_DCFSNZ,
1093   "DCFSNZ",
1094   2,
1095   NULL, // from branch
1096   NULL, // to branch
1097   NULL, // label
1098   NULL, // operand
1099   NULL, // flow block
1100   NULL, // C source 
1101   3,    // num ops
1102   1,0,  // dest, bit instruction
1103   1,1,  // branch, skip
1104   0,    // literal operand
1105   1,    // RAM access bit
1106   0,    // fast call/return mode select bit
1107   0,    // second memory operand
1108   0,    // second literal operand
1109   POC_NOP,
1110   PCC_REGISTER, // inCond
1111   PCC_REGISTER , // outCond
1112   PCI_MAGIC
1113 };
1114
1115 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1116   {PC_OPCODE, NULL, NULL, 0, NULL, 
1117    //   genericAnalyze,
1118    genericDestruct,
1119    genericPrint},
1120   POC_DCFSNZW,
1121   "DCFSNZ",
1122   2,
1123   NULL, // from branch
1124   NULL, // to branch
1125   NULL, // label
1126   NULL, // operand
1127   NULL, // flow block
1128   NULL, // C source 
1129   3,    // num ops
1130   0,0,  // dest, bit instruction
1131   1,1,  // branch, skip
1132   0,    // literal operand
1133   1,    // RAM access bit
1134   0,    // fast call/return mode select bit
1135   0,    // second memory operand
1136   0,    // second literal operand
1137   POC_NOP,
1138   PCC_REGISTER, // inCond
1139   PCC_W , // outCond
1140   PCI_MAGIC
1141 };
1142
1143 pCodeInstruction pic16_pciDECF = {
1144   {PC_OPCODE, NULL, NULL, 0, NULL, 
1145    //   genericAnalyze,
1146    genericDestruct,
1147    genericPrint},
1148   POC_DECF,
1149   "DECF",
1150   2,
1151   NULL, // from branch
1152   NULL, // to branch
1153   NULL, // label
1154   NULL, // operand
1155   NULL, // flow block
1156   NULL, // C source 
1157   3,    // num ops
1158   1,0,  // dest, bit instruction
1159   0,0,  // branch, skip
1160   0,    // literal operand
1161   1,    // RAM access bit
1162   0,    // fast call/return mode select bit
1163   0,    // second memory operand
1164   0,    // second literal operand
1165   POC_NOP,
1166   PCC_REGISTER,   // inCond
1167   (PCC_REGISTER | PCC_STATUS)  , // outCond
1168   PCI_MAGIC
1169 };
1170
1171 pCodeInstruction pic16_pciDECFW = {
1172   {PC_OPCODE, NULL, NULL, 0, NULL, 
1173    //   genericAnalyze,
1174    genericDestruct,
1175    genericPrint},
1176   POC_DECFW,
1177   "DECF",
1178   2,
1179   NULL, // from branch
1180   NULL, // to branch
1181   NULL, // label
1182   NULL, // operand
1183   NULL, // flow block
1184   NULL, // C source 
1185   3,    // num ops
1186   0,0,  // dest, bit instruction
1187   0,0,  // branch, skip
1188   0,    // literal operand
1189   1,    // RAM access bit
1190   0,    // fast call/return mode select bit
1191   0,    // second memory operand
1192   0,    // second literal operand
1193   POC_NOP,
1194   PCC_REGISTER,   // inCond
1195   (PCC_W | PCC_STATUS)  , // outCond
1196   PCI_MAGIC
1197 };
1198
1199 pCodeInstruction pic16_pciDECFSZ = {
1200   {PC_OPCODE, NULL, NULL, 0, NULL, 
1201    //   AnalyzeSKIP,
1202    genericDestruct,
1203    genericPrint},
1204   POC_DECFSZ,
1205   "DECFSZ",
1206   2,
1207   NULL, // from branch
1208   NULL, // to branch
1209   NULL, // label
1210   NULL, // operand
1211   NULL, // flow block
1212   NULL, // C source 
1213   3,    // num ops
1214   1,0,  // dest, bit instruction
1215   1,1,  // branch, skip
1216   0,    // literal operand
1217   1,    // RAM access bit
1218   0,    // fast call/return mode select bit
1219   0,    // second memory operand
1220   0,    // second literal operand
1221   POC_NOP,
1222   PCC_REGISTER,   // inCond
1223   PCC_REGISTER   , // outCond
1224   PCI_MAGIC
1225 };
1226
1227 pCodeInstruction pic16_pciDECFSZW = {
1228   {PC_OPCODE, NULL, NULL, 0, NULL, 
1229    //   AnalyzeSKIP,
1230    genericDestruct,
1231    genericPrint},
1232   POC_DECFSZW,
1233   "DECFSZ",
1234   2,
1235   NULL, // from branch
1236   NULL, // to branch
1237   NULL, // label
1238   NULL, // operand
1239   NULL, // flow block
1240   NULL, // C source 
1241   3,    // num ops
1242   0,0,  // dest, bit instruction
1243   1,1,  // branch, skip
1244   0,    // literal operand
1245   1,    // RAM access bit
1246   0,    // fast call/return mode select bit
1247   0,    // second memory operand
1248   0,    // second literal operand
1249   POC_NOP,
1250   PCC_REGISTER,   // inCond
1251   PCC_W          , // outCond
1252   PCI_MAGIC
1253 };
1254
1255 pCodeInstruction pic16_pciGOTO = {
1256   {PC_OPCODE, NULL, NULL, 0, NULL, 
1257    //   AnalyzeGOTO,
1258    genericDestruct,
1259    genericPrint},
1260   POC_GOTO,
1261   "GOTO",
1262   4,
1263   NULL, // from branch
1264   NULL, // to branch
1265   NULL, // label
1266   NULL, // operand
1267   NULL, // flow block
1268   NULL, // C source 
1269   1,    // num ops
1270   0,0,  // dest, bit instruction
1271   1,0,  // branch, skip
1272   0,    // literal operand
1273   0,    // RAM access bit
1274   0,    // fast call/return mode select bit
1275   0,    // second memory operand
1276   0,    // second literal operand
1277   POC_NOP,
1278   PCC_REL_ADDR,   // inCond
1279   PCC_NONE   , // outCond
1280   PCI_MAGIC
1281 };
1282
1283 pCodeInstruction pic16_pciINCF = {
1284   {PC_OPCODE, NULL, NULL, 0, NULL, 
1285    //   genericAnalyze,
1286    genericDestruct,
1287    genericPrint},
1288   POC_INCF,
1289   "INCF",
1290   2,
1291   NULL, // from branch
1292   NULL, // to branch
1293   NULL, // label
1294   NULL, // operand
1295   NULL, // flow block
1296   NULL, // C source 
1297   3,    // num ops
1298   1,0,  // dest, bit instruction
1299   0,0,  // branch, skip
1300   0,    // literal operand
1301   1,    // RAM access bit
1302   0,    // fast call/return mode select bit
1303   0,    // second memory operand
1304   0,    // second literal operand
1305   POC_NOP,
1306   PCC_REGISTER,   // inCond
1307   (PCC_REGISTER | PCC_STATUS), // outCond
1308   PCI_MAGIC
1309 };
1310
1311 pCodeInstruction pic16_pciINCFW = {
1312   {PC_OPCODE, NULL, NULL, 0, NULL, 
1313    //   genericAnalyze,
1314    genericDestruct,
1315    genericPrint},
1316   POC_INCFW,
1317   "INCF",
1318   2,
1319   NULL, // from branch
1320   NULL, // to branch
1321   NULL, // label
1322   NULL, // operand
1323   NULL, // flow block
1324   NULL, // C source 
1325   3,    // num ops
1326   0,0,  // dest, bit instruction
1327   0,0,  // branch, skip
1328   0,    // literal operand
1329   1,    // RAM access bit
1330   0,    // fast call/return mode select bit
1331   0,    // second memory operand
1332   0,    // second literal operand
1333   POC_NOP,
1334   PCC_REGISTER,   // inCond
1335   (PCC_W | PCC_STATUS)  , // outCond
1336   PCI_MAGIC
1337 };
1338
1339 pCodeInstruction pic16_pciINCFSZ = {
1340   {PC_OPCODE, NULL, NULL, 0, NULL, 
1341    //   AnalyzeSKIP,
1342    genericDestruct,
1343    genericPrint},
1344   POC_INCFSZ,
1345   "INCFSZ",
1346   2,
1347   NULL, // from branch
1348   NULL, // to branch
1349   NULL, // label
1350   NULL, // operand
1351   NULL, // flow block
1352   NULL, // C source 
1353   3,    // num ops
1354   1,0,  // dest, bit instruction
1355   1,1,  // branch, skip
1356   0,    // literal operand
1357   1,    // RAM access bit
1358   0,    // fast call/return mode select bit
1359   0,    // second memory operand
1360   0,    // second literal operand
1361   POC_INFSNZ,
1362   PCC_REGISTER,   // inCond
1363   PCC_REGISTER   , // outCond
1364   PCI_MAGIC
1365 };
1366
1367 pCodeInstruction pic16_pciINCFSZW = {
1368   {PC_OPCODE, NULL, NULL, 0, NULL, 
1369    //   AnalyzeSKIP,
1370    genericDestruct,
1371    genericPrint},
1372   POC_INCFSZW,
1373   "INCFSZ",
1374   2,
1375   NULL, // from branch
1376   NULL, // to branch
1377   NULL, // label
1378   NULL, // operand
1379   NULL, // flow block
1380   NULL, // C source 
1381   3,    // num ops
1382   0,0,  // dest, bit instruction
1383   1,1,  // branch, skip
1384   0,    // literal operand
1385   1,    // RAM access bit
1386   0,    // fast call/return mode select bit
1387   0,    // second memory operand
1388   0,    // second literal operand
1389   POC_INFSNZW,
1390   PCC_REGISTER,   // inCond
1391   PCC_W          , // outCond
1392   PCI_MAGIC
1393 };
1394
1395 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1396   {PC_OPCODE, NULL, NULL, 0, NULL, 
1397    //   AnalyzeSKIP,
1398    genericDestruct,
1399    genericPrint},
1400   POC_INFSNZ,
1401   "INFSNZ",
1402   2,
1403   NULL, // from branch
1404   NULL, // to branch
1405   NULL, // label
1406   NULL, // operand
1407   NULL, // flow block
1408   NULL, // C source 
1409   3,    // num ops
1410   1,0,  // dest, bit instruction
1411   1,1,  // branch, skip
1412   0,    // literal operand
1413   1,    // RAM access bit
1414   0,    // fast call/return mode select bit
1415   0,    // second memory operand
1416   0,    // second literal operand
1417   POC_INCFSZ,
1418   PCC_REGISTER,   // inCond
1419   PCC_REGISTER   , // outCond
1420   PCI_MAGIC
1421 };
1422
1423 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1424   {PC_OPCODE, NULL, NULL, 0, NULL, 
1425    //   AnalyzeSKIP,
1426    genericDestruct,
1427    genericPrint},
1428   POC_INFSNZW,
1429   "INFSNZ",
1430   2,
1431   NULL, // from branch
1432   NULL, // to branch
1433   NULL, // label
1434   NULL, // operand
1435   NULL, // flow block
1436   NULL, // C source 
1437   3,    // num ops
1438   0,0,  // dest, bit instruction
1439   1,1,  // branch, skip
1440   0,    // literal operand
1441   1,    // RAM access bit
1442   0,    // fast call/return mode select bit
1443   0,    // second memory operand
1444   0,    // second literal operand
1445   POC_INCFSZW,
1446   PCC_REGISTER,   // inCond
1447   PCC_W          , // outCond
1448   PCI_MAGIC
1449 };
1450
1451 pCodeInstruction pic16_pciIORWF = {
1452   {PC_OPCODE, NULL, NULL, 0, NULL, 
1453    //   genericAnalyze,
1454    genericDestruct,
1455    genericPrint},
1456   POC_IORWF,
1457   "IORWF",
1458   2,
1459   NULL, // from branch
1460   NULL, // to branch
1461   NULL, // label
1462   NULL, // operand
1463   NULL, // flow block
1464   NULL, // C source 
1465   3,    // num ops
1466   1,0,  // dest, bit instruction
1467   0,0,  // branch, skip
1468   0,    // literal operand
1469   1,    // RAM access bit
1470   0,    // fast call/return mode select bit
1471   0,    // second memory operand
1472   0,    // second literal operand
1473   POC_NOP,
1474   (PCC_W | PCC_REGISTER),   // inCond
1475   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1476   PCI_MAGIC
1477 };
1478
1479 pCodeInstruction pic16_pciIORFW = {
1480   {PC_OPCODE, NULL, NULL, 0, NULL, 
1481    //   genericAnalyze,
1482    genericDestruct,
1483    genericPrint},
1484   POC_IORFW,
1485   "IORWF",
1486   2,
1487   NULL, // from branch
1488   NULL, // to branch
1489   NULL, // label
1490   NULL, // operand
1491   NULL, // flow block
1492   NULL, // C source 
1493   3,    // num ops
1494   0,0,  // dest, bit instruction
1495   0,0,  // branch, skip
1496   0,    // literal operand
1497   1,    // RAM access bit
1498   0,    // fast call/return mode select bit
1499   0,    // second memory operand
1500   0,    // second literal operand
1501   POC_NOP,
1502   (PCC_W | PCC_REGISTER),   // inCond
1503   (PCC_W | PCC_Z | PCC_N), // outCond
1504   PCI_MAGIC
1505 };
1506
1507 pCodeInstruction pic16_pciIORLW = {
1508   {PC_OPCODE, NULL, NULL, 0, NULL, 
1509    //   genericAnalyze,
1510    genericDestruct,
1511    genericPrint},
1512   POC_IORLW,
1513   "IORLW",
1514   2,
1515   NULL, // from branch
1516   NULL, // to branch
1517   NULL, // label
1518   NULL, // operand
1519   NULL, // flow block
1520   NULL, // C source 
1521   1,    // num ops
1522   0,0,  // dest, bit instruction
1523   0,0,  // branch, skip
1524   1,    // literal operand
1525   0,    // RAM access bit
1526   0,    // fast call/return mode select bit
1527   0,    // second memory operand
1528   0,    // second literal operand
1529   POC_NOP,
1530   (PCC_W | PCC_LITERAL),   // inCond
1531   (PCC_W | PCC_Z | PCC_N), // outCond
1532   PCI_MAGIC
1533 };
1534
1535 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1536   {PC_OPCODE, NULL, NULL, 0, NULL, 
1537    //   genericAnalyze,
1538    genericDestruct,
1539    genericPrint},
1540   POC_LFSR,
1541   "LFSR",
1542   4,
1543   NULL, // from branch
1544   NULL, // to branch
1545   NULL, // label
1546   NULL, // operand
1547   NULL, // flow block
1548   NULL, // C source 
1549   2,    // num ops
1550   0,0,  // dest, bit instruction
1551   0,0,  // branch, skip
1552   1,    // literal operand
1553   0,    // RAM access bit
1554   0,    // fast call/return mode select bit
1555   0,    // second memory operand
1556   1,    // second literal operand
1557   POC_NOP,
1558   PCC_LITERAL, // inCond
1559   PCC_NONE, // outCond
1560   PCI_MAGIC
1561 };
1562
1563 pCodeInstruction pic16_pciMOVF = {
1564   {PC_OPCODE, NULL, NULL, 0, NULL, 
1565    //   genericAnalyze,
1566    genericDestruct,
1567    genericPrint},
1568   POC_MOVF,
1569   "MOVF",
1570   2,
1571   NULL, // from branch
1572   NULL, // to branch
1573   NULL, // label
1574   NULL, // operand
1575   NULL, // flow block
1576   NULL, // C source 
1577   3,    // num ops
1578   1,0,  // dest, bit instruction
1579   0,0,  // branch, skip
1580   0,    // literal operand
1581   1,    // RAM access bit
1582   0,    // fast call/return mode select bit
1583   0,    // second memory operand
1584   0,    // second literal operand
1585   POC_NOP,
1586   PCC_REGISTER,   // inCond
1587   (PCC_Z | PCC_N), // outCond
1588   PCI_MAGIC
1589 };
1590
1591 pCodeInstruction pic16_pciMOVFW = {
1592   {PC_OPCODE, NULL, NULL, 0, NULL, 
1593    //   genericAnalyze,
1594    genericDestruct,
1595    genericPrint},
1596   POC_MOVFW,
1597   "MOVF",
1598   2,
1599   NULL, // from branch
1600   NULL, // to branch
1601   NULL, // label
1602   NULL, // operand
1603   NULL, // flow block
1604   NULL, // C source 
1605   3,    // num ops
1606   0,0,  // dest, bit instruction
1607   0,0,  // branch, skip
1608   0,    // literal operand
1609   1,    // RAM access bit
1610   0,    // fast call/return mode select bit
1611   0,    // second memory operand
1612   0,    // second literal operand
1613   POC_NOP,
1614   PCC_REGISTER,   // inCond
1615   (PCC_W | PCC_N | PCC_Z), // outCond
1616   PCI_MAGIC
1617 };
1618
1619 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1620   {PC_OPCODE, NULL, NULL, 0, NULL, 
1621    //   genericAnalyze,
1622    genericDestruct,
1623    genericPrint},
1624   POC_MOVFF,
1625   "MOVFF",
1626   4,
1627   NULL, // from branch
1628   NULL, // to branch
1629   NULL, // label
1630   NULL, // operand
1631   NULL, // flow block
1632   NULL, // C source 
1633   2,    // num ops
1634   0,0,  // dest, bit instruction
1635   0,0,  // branch, skip
1636   0,    // literal operand
1637   0,    // RAM access bit
1638   0,    // fast call/return mode select bit
1639   1,    // second memory operand
1640   0,    // second literal operand
1641   POC_NOP,
1642   PCC_REGISTER,   // inCond
1643   PCC_REGISTER2, // outCond
1644   PCI_MAGIC
1645 };
1646
1647 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1648   {PC_OPCODE, NULL, NULL, 0, NULL, 
1649    genericDestruct,
1650    genericPrint},
1651   POC_MOVLB,
1652   "MOVLB",
1653   2,
1654   NULL, // from branch
1655   NULL, // to branch
1656   NULL, // label
1657   NULL, // operand
1658   NULL, // flow block
1659   NULL, // C source 
1660   1,    // num ops
1661   0,0,  // dest, bit instruction
1662   0,0,  // branch, skip
1663   1,    // literal operand
1664   0,    // RAM access bit
1665   0,    // fast call/return mode select bit
1666   0,    // second memory operand
1667   0,    // second literal operand
1668   POC_NOP,
1669   (PCC_NONE | PCC_LITERAL),   // inCond
1670   PCC_REGISTER, // outCond - BSR
1671   PCI_MAGIC
1672 };
1673
1674 pCodeInstruction pic16_pciMOVLW = {
1675   {PC_OPCODE, NULL, NULL, 0, NULL, 
1676    genericDestruct,
1677    genericPrint},
1678   POC_MOVLW,
1679   "MOVLW",
1680   2,
1681   NULL, // from branch
1682   NULL, // to branch
1683   NULL, // label
1684   NULL, // operand
1685   NULL, // flow block
1686   NULL, // C source 
1687   1,    // num ops
1688   0,0,  // dest, bit instruction
1689   0,0,  // branch, skip
1690   1,    // literal operand
1691   0,    // RAM access bit
1692   0,    // fast call/return mode select bit
1693   0,    // second memory operand
1694   0,    // second literal operand
1695   POC_NOP,
1696   (PCC_NONE | PCC_LITERAL),   // inCond
1697   PCC_W, // outCond
1698   PCI_MAGIC
1699 };
1700
1701 pCodeInstruction pic16_pciMOVWF = {
1702   {PC_OPCODE, NULL, NULL, 0, NULL, 
1703    //   genericAnalyze,
1704    genericDestruct,
1705    genericPrint},
1706   POC_MOVWF,
1707   "MOVWF",
1708   2,
1709   NULL, // from branch
1710   NULL, // to branch
1711   NULL, // label
1712   NULL, // operand
1713   NULL, // flow block
1714   NULL, // C source 
1715   2,    // num ops
1716   0,0,  // dest, bit instruction
1717   0,0,  // branch, skip
1718   0,    // literal operand
1719   1,    // RAM access bit
1720   0,    // fast call/return mode select bit
1721   0,    // second memory operand
1722   0,    // second literal operand
1723   POC_NOP,
1724   PCC_W,   // inCond
1725   PCC_REGISTER, // outCond
1726   PCI_MAGIC
1727 };
1728
1729 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1730   {PC_OPCODE, NULL, NULL, 0, NULL, 
1731    genericDestruct,
1732    genericPrint},
1733   POC_MULLW,
1734   "MULLW",
1735   2,
1736   NULL, // from branch
1737   NULL, // to branch
1738   NULL, // label
1739   NULL, // operand
1740   NULL, // flow block
1741   NULL, // C source 
1742   1,    // num ops
1743   0,0,  // dest, bit instruction
1744   0,0,  // branch, skip
1745   1,    // literal operand
1746   0,    // RAM access bit
1747   0,    // fast call/return mode select bit
1748   0,    // second memory operand
1749   0,    // second literal operand
1750   POC_NOP,
1751   (PCC_W | PCC_LITERAL),   // inCond
1752   PCC_NONE, // outCond - PROD
1753   PCI_MAGIC
1754 };
1755
1756 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1757   {PC_OPCODE, NULL, NULL, 0, NULL, 
1758    genericDestruct,
1759    genericPrint},
1760   POC_MULWF,
1761   "MULWF",
1762   2,
1763   NULL, // from branch
1764   NULL, // to branch
1765   NULL, // label
1766   NULL, // operand
1767   NULL, // flow block
1768   NULL, // C source 
1769   2,    // num ops
1770   0,0,  // dest, bit instruction
1771   0,0,  // branch, skip
1772   0,    // literal operand
1773   1,    // RAM access bit
1774   0,    // fast call/return mode select bit
1775   0,    // second memory operand
1776   0,    // second literal operand
1777   POC_NOP,
1778   (PCC_W | PCC_REGISTER),   // inCond
1779   PCC_REGISTER, // outCond - PROD
1780   PCI_MAGIC
1781 };
1782
1783 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1784   {PC_OPCODE, NULL, NULL, 0, NULL, 
1785    genericDestruct,
1786    genericPrint},
1787   POC_NEGF,
1788   "NEGF",
1789   2,
1790   NULL, // from branch
1791   NULL, // to branch
1792   NULL, // label
1793   NULL, // operand
1794   NULL, // flow block
1795   NULL, // C source 
1796   2,    // num ops
1797   0,0,  // dest, bit instruction
1798   0,0,  // branch, skip
1799   0,    // literal operand
1800   1,    // RAM access bit
1801   0,    // fast call/return mode select bit
1802   0,    // second memory operand
1803   0,    // second literal operand
1804   POC_NOP,
1805   PCC_REGISTER, // inCond
1806   (PCC_REGISTER | PCC_STATUS), // outCond
1807   PCI_MAGIC
1808 };
1809
1810 pCodeInstruction pic16_pciNOP = {
1811   {PC_OPCODE, NULL, NULL, 0, NULL, 
1812    genericDestruct,
1813    genericPrint},
1814   POC_NOP,
1815   "NOP",
1816   2,
1817   NULL, // from branch
1818   NULL, // to branch
1819   NULL, // label
1820   NULL, // operand
1821   NULL, // flow block
1822   NULL, // C source 
1823   0,    // num ops
1824   0,0,  // dest, bit instruction
1825   0,0,  // branch, skip
1826   0,    // literal operand
1827   0,    // RAM access bit
1828   0,    // fast call/return mode select bit
1829   0,    // second memory operand
1830   0,    // second literal operand
1831   POC_NOP,
1832   PCC_NONE,   // inCond
1833   PCC_NONE, // outCond
1834   PCI_MAGIC
1835 };
1836
1837 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1838   {PC_OPCODE, NULL, NULL, 0, NULL, 
1839    genericDestruct,
1840    genericPrint},
1841   POC_POP,
1842   "POP",
1843   2,
1844   NULL, // from branch
1845   NULL, // to branch
1846   NULL, // label
1847   NULL, // operand
1848   NULL, // flow block
1849   NULL, // C source 
1850   0,    // num ops
1851   0,0,  // dest, bit instruction
1852   0,0,  // branch, skip
1853   0,    // literal operand
1854   0,    // RAM access bit
1855   0,    // fast call/return mode select bit
1856   0,    // second memory operand
1857   0,    // second literal operand
1858   POC_NOP,
1859   PCC_NONE,  // inCond
1860   PCC_NONE  , // outCond
1861   PCI_MAGIC
1862 };
1863
1864 pCodeInstruction pic16_pciPUSH = {
1865   {PC_OPCODE, NULL, NULL, 0, NULL, 
1866    genericDestruct,
1867    genericPrint},
1868   POC_PUSH,
1869   "PUSH",
1870   2,
1871   NULL, // from branch
1872   NULL, // to branch
1873   NULL, // label
1874   NULL, // operand
1875   NULL, // flow block
1876   NULL, // C source 
1877   0,    // num ops
1878   0,0,  // dest, bit instruction
1879   0,0,  // branch, skip
1880   0,    // literal operand
1881   0,    // RAM access bit
1882   0,    // fast call/return mode select bit
1883   0,    // second memory operand
1884   0,    // second literal operand
1885   POC_NOP,
1886   PCC_NONE,  // inCond
1887   PCC_NONE  , // outCond
1888   PCI_MAGIC
1889 };
1890
1891 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1892   {PC_OPCODE, NULL, NULL, 0, NULL, 
1893    genericDestruct,
1894    genericPrint},
1895   POC_RCALL,
1896   "RCALL",
1897   2,
1898   NULL, // from branch
1899   NULL, // to branch
1900   NULL, // label
1901   NULL, // operand
1902   NULL, // flow block
1903   NULL, // C source 
1904   1,    // num ops
1905   0,0,  // dest, bit instruction
1906   1,0,  // branch, skip
1907   0,    // literal operand
1908   0,    // RAM access bit
1909   0,    // fast call/return mode select bit
1910   0,    // second memory operand
1911   0,    // second literal operand
1912   POC_NOP,
1913   PCC_REL_ADDR,  // inCond
1914   PCC_NONE  , // outCond
1915   PCI_MAGIC
1916 };
1917
1918 pCodeInstruction pic16_pciRETFIE = {
1919   {PC_OPCODE, NULL, NULL, 0, NULL, 
1920    //   AnalyzeRETURN,
1921    genericDestruct,
1922    genericPrint},
1923   POC_RETFIE,
1924   "RETFIE",
1925   2,
1926   NULL, // from branch
1927   NULL, // to branch
1928   NULL, // label
1929   NULL, // operand
1930   NULL, // flow block
1931   NULL, // C source 
1932   1,    // num ops
1933   0,0,  // dest, bit instruction
1934   1,0,  // branch, skip
1935   0,    // literal operand
1936   0,    // RAM access bit
1937   1,    // fast call/return mode select bit
1938   0,    // second memory operand
1939   0,    // second literal operand
1940   POC_NOP,
1941   PCC_NONE,   // inCond
1942   PCC_NONE,    // outCond (not true... affects the GIE bit too)
1943   PCI_MAGIC
1944 };
1945
1946 pCodeInstruction pic16_pciRETLW = {
1947   {PC_OPCODE, NULL, NULL, 0, NULL, 
1948    //   AnalyzeRETURN,
1949    genericDestruct,
1950    genericPrint},
1951   POC_RETLW,
1952   "RETLW",
1953   2,
1954   NULL, // from branch
1955   NULL, // to branch
1956   NULL, // label
1957   NULL, // operand
1958   NULL, // flow block
1959   NULL, // C source 
1960   1,    // num ops
1961   0,0,  // dest, bit instruction
1962   1,0,  // branch, skip
1963   1,    // literal operand
1964   0,    // RAM access bit
1965   0,    // fast call/return mode select bit
1966   0,    // second memory operand
1967   0,    // second literal operand
1968   POC_NOP,
1969   PCC_LITERAL,   // inCond
1970   PCC_W, // outCond
1971   PCI_MAGIC
1972 };
1973
1974 pCodeInstruction pic16_pciRETURN = {
1975   {PC_OPCODE, NULL, NULL, 0, NULL, 
1976    //   AnalyzeRETURN,
1977    genericDestruct,
1978    genericPrint},
1979   POC_RETURN,
1980   "RETURN",
1981   2,
1982   NULL, // from branch
1983   NULL, // to branch
1984   NULL, // label
1985   NULL, // operand
1986   NULL, // flow block
1987   NULL, // C source 
1988   1,    // num ops
1989   0,0,  // dest, bit instruction
1990   1,0,  // branch, skip
1991   0,    // literal operand
1992   0,    // RAM access bit
1993   1,    // fast call/return mode select bit
1994   0,    // second memory operand
1995   0,    // second literal operand
1996   POC_NOP,
1997   PCC_NONE,   // inCond
1998   PCC_NONE, // outCond
1999   PCI_MAGIC
2000 };
2001 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2002   {PC_OPCODE, NULL, NULL, 0, NULL, 
2003    //   genericAnalyze,
2004    genericDestruct,
2005    genericPrint},
2006   POC_RLCF,
2007   "RLCF",
2008   2,
2009   NULL, // from branch
2010   NULL, // to branch
2011   NULL, // label
2012   NULL, // operand
2013   NULL, // flow block
2014   NULL, // C source 
2015   3,    // num ops
2016   1,0,  // dest, bit instruction
2017   0,0,  // branch, skip
2018   0,    // literal operand
2019   1,    // RAM access bit
2020   0,    // fast call/return mode select bit
2021   0,    // second memory operand
2022   0,    // second literal operand
2023   POC_NOP,
2024   (PCC_C | PCC_REGISTER),   // inCond
2025   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2026   PCI_MAGIC
2027 };
2028
2029 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2030   {PC_OPCODE, NULL, NULL, 0, NULL, 
2031    //   genericAnalyze,
2032    genericDestruct,
2033    genericPrint},
2034   POC_RLCFW,
2035   "RLCF",
2036   2,
2037   NULL, // from branch
2038   NULL, // to branch
2039   NULL, // label
2040   NULL, // operand
2041   NULL, // flow block
2042   NULL, // C source 
2043   3,    // num ops
2044   0,0,  // dest, bit instruction
2045   0,0,  // branch, skip
2046   0,    // literal operand
2047   1,    // RAM access bit
2048   0,    // fast call/return mode select bit
2049   0,    // second memory operand
2050   0,    // second literal operand
2051   POC_NOP,
2052   (PCC_C | PCC_REGISTER),   // inCond
2053   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2054   PCI_MAGIC
2055 };
2056
2057 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2058   {PC_OPCODE, NULL, NULL, 0, NULL, 
2059    //   genericAnalyze,
2060    genericDestruct,
2061    genericPrint},
2062   POC_RLNCF,
2063   "RLNCF",
2064   2,
2065   NULL, // from branch
2066   NULL, // to branch
2067   NULL, // label
2068   NULL, // operand
2069   NULL, // flow block
2070   NULL, // C source 
2071   3,    // num ops
2072   1,0,  // dest, bit instruction
2073   0,0,  // branch, skip
2074   0,    // literal operand
2075   1,    // RAM access bit
2076   0,    // fast call/return mode select bit
2077   0,    // second memory operand
2078   0,    // second literal operand
2079   POC_NOP,
2080   PCC_REGISTER,   // inCond
2081   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2082   PCI_MAGIC
2083 };
2084 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2085   {PC_OPCODE, NULL, NULL, 0, NULL, 
2086    //   genericAnalyze,
2087    genericDestruct,
2088    genericPrint},
2089   POC_RLNCFW,
2090   "RLNCF",
2091   2,
2092   NULL, // from branch
2093   NULL, // to branch
2094   NULL, // label
2095   NULL, // operand
2096   NULL, // flow block
2097   NULL, // C source 
2098   3,    // num ops
2099   0,0,  // dest, bit instruction
2100   0,0,  // branch, skip
2101   0,    // literal operand
2102   1,    // RAM access bit
2103   0,    // fast call/return mode select bit
2104   0,    // second memory operand
2105   0,    // second literal operand
2106   POC_NOP,
2107   PCC_REGISTER,   // inCond
2108   (PCC_W | PCC_Z | PCC_N), // outCond
2109   PCI_MAGIC
2110 };
2111 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2112   {PC_OPCODE, NULL, NULL, 0, NULL, 
2113    //   genericAnalyze,
2114    genericDestruct,
2115    genericPrint},
2116   POC_RRCF,
2117   "RRCF",
2118   2,
2119   NULL, // from branch
2120   NULL, // to branch
2121   NULL, // label
2122   NULL, // operand
2123   NULL, // flow block
2124   NULL, // C source 
2125   3,    // num ops
2126   1,0,  // dest, bit instruction
2127   0,0,  // branch, skip
2128   0,    // literal operand
2129   1,    // RAM access bit
2130   0,    // fast call/return mode select bit
2131   0,    // second memory operand
2132   0,    // second literal operand
2133   POC_NOP,
2134   (PCC_C | PCC_REGISTER),   // inCond
2135   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2136   PCI_MAGIC
2137 };
2138 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2139   {PC_OPCODE, NULL, NULL, 0, NULL, 
2140    //   genericAnalyze,
2141    genericDestruct,
2142    genericPrint},
2143   POC_RRCFW,
2144   "RRCF",
2145   2,
2146   NULL, // from branch
2147   NULL, // to branch
2148   NULL, // label
2149   NULL, // operand
2150   NULL, // flow block
2151   NULL, // C source 
2152   3,    // num ops
2153   0,0,  // dest, bit instruction
2154   0,0,  // branch, skip
2155   0,    // literal operand
2156   1,    // RAM access bit
2157   0,    // fast call/return mode select bit
2158   0,    // second memory operand
2159   0,    // second literal operand
2160   POC_NOP,
2161   (PCC_C | PCC_REGISTER),   // inCond
2162   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2163   PCI_MAGIC
2164 };
2165 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2166   {PC_OPCODE, NULL, NULL, 0, NULL, 
2167    //   genericAnalyze,
2168    genericDestruct,
2169    genericPrint},
2170   POC_RRNCF,
2171   "RRNCF",
2172   2,
2173   NULL, // from branch
2174   NULL, // to branch
2175   NULL, // label
2176   NULL, // operand
2177   NULL, // flow block
2178   NULL, // C source 
2179   3,    // num ops
2180   1,0,  // dest, bit instruction
2181   0,0,  // branch, skip
2182   0,    // literal operand
2183   1,    // RAM access bit
2184   0,    // fast call/return mode select bit
2185   0,    // second memory operand
2186   0,    // second literal operand
2187   POC_NOP,
2188   PCC_REGISTER,   // inCond
2189   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2190   PCI_MAGIC
2191 };
2192
2193 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2194   {PC_OPCODE, NULL, NULL, 0, NULL, 
2195    //   genericAnalyze,
2196    genericDestruct,
2197    genericPrint},
2198   POC_RRNCFW,
2199   "RRNCF",
2200   2,
2201   NULL, // from branch
2202   NULL, // to branch
2203   NULL, // label
2204   NULL, // operand
2205   NULL, // flow block
2206   NULL, // C source 
2207   3,    // num ops
2208   0,0,  // dest, bit instruction
2209   0,0,  // branch, skip
2210   0,    // literal operand
2211   1,    // RAM access bit
2212   0,    // fast call/return mode select bit
2213   0,    // second memory operand
2214   0,    // second literal operand
2215   POC_NOP,
2216   PCC_REGISTER,   // inCond
2217   (PCC_W | PCC_Z | PCC_N), // outCond
2218   PCI_MAGIC
2219 };
2220
2221 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2222   {PC_OPCODE, NULL, NULL, 0, NULL, 
2223    //   genericAnalyze,
2224    genericDestruct,
2225    genericPrint},
2226   POC_SETF,
2227   "SETF",
2228   2,
2229   NULL, // from branch
2230   NULL, // to branch
2231   NULL, // label
2232   NULL, // operand
2233   NULL, // flow block
2234   NULL, // C source 
2235   2,    // num ops
2236   0,0,  // dest, bit instruction
2237   0,0,  // branch, skip
2238   0,    // literal operand
2239   1,    // RAM access bit
2240   0,    // fast call/return mode select bit
2241   0,    // second memory operand
2242   0,    // second literal operand
2243   POC_NOP,
2244   PCC_NONE,  // inCond
2245   PCC_REGISTER  , // outCond
2246   PCI_MAGIC
2247 };
2248
2249 pCodeInstruction pic16_pciSUBLW = {
2250   {PC_OPCODE, NULL, NULL, 0, NULL, 
2251    //   genericAnalyze,
2252    genericDestruct,
2253    genericPrint},
2254   POC_SUBLW,
2255   "SUBLW",
2256   2,
2257   NULL, // from branch
2258   NULL, // to branch
2259   NULL, // label
2260   NULL, // operand
2261   NULL, // flow block
2262   NULL, // C source 
2263   1,    // num ops
2264   0,0,  // dest, bit instruction
2265   0,0,  // branch, skip
2266   1,    // literal operand
2267   0,    // RAM access bit
2268   0,    // fast call/return mode select bit
2269   0,    // second memory operand
2270   0,    // second literal operand
2271   POC_NOP,
2272   (PCC_W | PCC_LITERAL),   // inCond
2273   (PCC_W | PCC_STATUS), // outCond
2274   PCI_MAGIC
2275 };
2276
2277 pCodeInstruction pic16_pciSUBFWB = {
2278   {PC_OPCODE, NULL, NULL, 0, NULL, 
2279    //   genericAnalyze,
2280    genericDestruct,
2281    genericPrint},
2282   POC_SUBFWB,
2283   "SUBFWB",
2284   2,
2285   NULL, // from branch
2286   NULL, // to branch
2287   NULL, // label
2288   NULL, // operand
2289   NULL, // flow block
2290   NULL, // C source 
2291   3,    // num ops
2292   1,0,  // dest, bit instruction
2293   0,0,  // branch, skip
2294   0,    // literal operand
2295   1,    // RAM access bit
2296   0,    // fast call/return mode select bit
2297   0,    // second memory operand
2298   0,    // second literal operand
2299   POC_NOP,
2300   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2301   (PCC_W | PCC_STATUS), // outCond
2302   PCI_MAGIC
2303 };
2304
2305 pCodeInstruction pic16_pciSUBWF = {
2306   {PC_OPCODE, NULL, NULL, 0, NULL, 
2307    //   genericAnalyze,
2308    genericDestruct,
2309    genericPrint},
2310   POC_SUBWF,
2311   "SUBWF",
2312   2,
2313   NULL, // from branch
2314   NULL, // to branch
2315   NULL, // label
2316   NULL, // operand
2317   NULL, // flow block
2318   NULL, // C source 
2319   3,    // num ops
2320   1,0,  // dest, bit instruction
2321   0,0,  // branch, skip
2322   0,    // literal operand
2323   1,    // RAM access bit
2324   0,    // fast call/return mode select bit
2325   0,    // second memory operand
2326   0,    // second literal operand
2327   POC_NOP,
2328   (PCC_W | PCC_REGISTER),   // inCond
2329   (PCC_REGISTER | PCC_STATUS), // outCond
2330   PCI_MAGIC
2331 };
2332
2333 pCodeInstruction pic16_pciSUBFW = {
2334   {PC_OPCODE, NULL, NULL, 0, NULL, 
2335    //   genericAnalyze,
2336    genericDestruct,
2337    genericPrint},
2338   POC_SUBFW,
2339   "SUBWF",
2340   2,
2341   NULL, // from branch
2342   NULL, // to branch
2343   NULL, // label
2344   NULL, // operand
2345   NULL, // flow block
2346   NULL, // C source 
2347   3,    // num ops
2348   0,0,  // dest, bit instruction
2349   0,0,  // branch, skip
2350   0,    // literal operand
2351   1,    // RAM access bit
2352   0,    // fast call/return mode select bit
2353   0,    // second memory operand
2354   0,    // second literal operand
2355   POC_NOP,
2356   (PCC_W | PCC_REGISTER),   // inCond
2357   (PCC_W | PCC_STATUS), // outCond
2358   PCI_MAGIC
2359 };
2360
2361 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2362   {PC_OPCODE, NULL, NULL, 0, NULL, 
2363    //   genericAnalyze,
2364    genericDestruct,
2365    genericPrint},
2366   POC_SUBFWB_D1,
2367   "SUBFWB",
2368   2,
2369   NULL, // from branch
2370   NULL, // to branch
2371   NULL, // label
2372   NULL, // operand
2373   NULL, // flow block
2374   NULL, // C source 
2375   3,    // num ops
2376   1,0,  // dest, bit instruction
2377   0,0,  // branch, skip
2378   0,    // literal operand
2379   1,    // RAM access bit
2380   0,    // fast call/return mode select bit
2381   0,    // second memory operand
2382   0,    // second literal operand
2383   POC_NOP,
2384   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2385   (PCC_REGISTER | PCC_STATUS), // outCond
2386   PCI_MAGIC
2387 };
2388
2389 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2390   {PC_OPCODE, NULL, NULL, 0, NULL, 
2391    //   genericAnalyze,
2392    genericDestruct,
2393    genericPrint},
2394   POC_SUBFWB_D0,
2395   "SUBFWB",
2396   2,
2397   NULL, // from branch
2398   NULL, // to branch
2399   NULL, // label
2400   NULL, // operand
2401   NULL, // flow block
2402   NULL, // C source 
2403   3,    // num ops
2404   0,0,  // dest, bit instruction
2405   0,0,  // branch, skip
2406   0,    // literal operand
2407   1,    // RAM access bit
2408   0,    // fast call/return mode select bit
2409   0,    // second memory operand
2410   0,    // second literal operand
2411   POC_NOP,
2412   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2413   (PCC_W | PCC_STATUS), // outCond
2414   PCI_MAGIC
2415 };
2416
2417 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2418   {PC_OPCODE, NULL, NULL, 0, NULL, 
2419    //   genericAnalyze,
2420    genericDestruct,
2421    genericPrint},
2422   POC_SUBWFB_D1,
2423   "SUBWFB",
2424   2,
2425   NULL, // from branch
2426   NULL, // to branch
2427   NULL, // label
2428   NULL, // operand
2429   NULL, // flow block
2430   NULL, // C source 
2431   3,    // num ops
2432   1,0,  // dest, bit instruction
2433   0,0,  // branch, skip
2434   0,    // literal operand
2435   1,    // RAM access bit
2436   0,    // fast call/return mode select bit
2437   0,    // second memory operand
2438   0,    // second literal operand
2439   POC_NOP,
2440   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2441   (PCC_REGISTER | PCC_STATUS), // outCond
2442   PCI_MAGIC
2443 };
2444
2445 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2446   {PC_OPCODE, NULL, NULL, 0, NULL, 
2447    //   genericAnalyze,
2448    genericDestruct,
2449    genericPrint},
2450   POC_SUBWFB_D0,
2451   "SUBWFB",
2452   2,
2453   NULL, // from branch
2454   NULL, // to branch
2455   NULL, // label
2456   NULL, // operand
2457   NULL, // flow block
2458   NULL, // C source 
2459   3,    // num ops
2460   0,0,  // dest, bit instruction
2461   0,0,  // branch, skip
2462   0,    // literal operand
2463   1,    // RAM access bit
2464   0,    // fast call/return mode select bit
2465   0,    // second memory operand
2466   0,    // second literal operand
2467   POC_NOP,
2468   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2469   (PCC_W | PCC_STATUS), // outCond
2470   PCI_MAGIC
2471 };
2472
2473 pCodeInstruction pic16_pciSWAPF = {
2474   {PC_OPCODE, NULL, NULL, 0, NULL, 
2475    //   genericAnalyze,
2476    genericDestruct,
2477    genericPrint},
2478   POC_SWAPF,
2479   "SWAPF",
2480   2,
2481   NULL, // from branch
2482   NULL, // to branch
2483   NULL, // label
2484   NULL, // operand
2485   NULL, // flow block
2486   NULL, // C source 
2487   3,    // num ops
2488   1,0,  // dest, bit instruction
2489   0,0,  // branch, skip
2490   0,    // literal operand
2491   1,    // RAM access bit
2492   0,    // fast call/return mode select bit
2493   0,    // second memory operand
2494   0,    // second literal operand
2495   POC_NOP,
2496   (PCC_REGISTER),   // inCond
2497   (PCC_REGISTER), // outCond
2498   PCI_MAGIC
2499 };
2500
2501 pCodeInstruction pic16_pciSWAPFW = {
2502   {PC_OPCODE, NULL, NULL, 0, NULL, 
2503    //   genericAnalyze,
2504    genericDestruct,
2505    genericPrint},
2506   POC_SWAPFW,
2507   "SWAPF",
2508   2,
2509   NULL, // from branch
2510   NULL, // to branch
2511   NULL, // label
2512   NULL, // operand
2513   NULL, // flow block
2514   NULL, // C source 
2515   3,    // num ops
2516   0,0,  // dest, bit instruction
2517   0,0,  // branch, skip
2518   0,    // literal operand
2519   1,    // RAM access bit
2520   0,    // fast call/return mode select bit
2521   0,    // second memory operand
2522   0,    // second literal operand
2523   POC_NOP,
2524   (PCC_REGISTER),   // inCond
2525   (PCC_W), // outCond
2526   PCI_MAGIC
2527 };
2528
2529 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2530   {PC_OPCODE, NULL, NULL, 0, NULL, 
2531    genericDestruct,
2532    genericPrint},
2533   POC_TBLRD,
2534   "TBLRD*",
2535   2,
2536   NULL, // from branch
2537   NULL, // to branch
2538   NULL, // label
2539   NULL, // operand
2540   NULL, // flow block
2541   NULL, // C source 
2542   0,    // num ops
2543   0,0,  // dest, bit instruction
2544   0,0,  // branch, skip
2545   0,    // literal operand
2546   0,    // RAM access bit
2547   0,    // fast call/return mode select bit
2548   0,    // second memory operand
2549   0,    // second literal operand
2550   POC_NOP,
2551   PCC_NONE,  // inCond
2552   PCC_NONE  , // outCond
2553   PCI_MAGIC
2554 };
2555
2556 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2557   {PC_OPCODE, NULL, NULL, 0, NULL, 
2558    genericDestruct,
2559    genericPrint},
2560   POC_TBLRD_POSTINC,
2561   "TBLRD*+",
2562   2,
2563   NULL, // from branch
2564   NULL, // to branch
2565   NULL, // label
2566   NULL, // operand
2567   NULL, // flow block
2568   NULL, // C source 
2569   0,    // num ops
2570   0,0,  // dest, bit instruction
2571   0,0,  // branch, skip
2572   0,    // literal operand
2573   0,    // RAM access bit
2574   0,    // fast call/return mode select bit
2575   0,    // second memory operand
2576   0,    // second literal operand
2577   POC_NOP,
2578   PCC_NONE,  // inCond
2579   PCC_NONE  , // outCond
2580   PCI_MAGIC
2581 };
2582
2583 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2584   {PC_OPCODE, NULL, NULL, 0, NULL, 
2585    genericDestruct,
2586    genericPrint},
2587   POC_TBLRD_POSTDEC,
2588   "TBLRD*-",
2589   2,
2590   NULL, // from branch
2591   NULL, // to branch
2592   NULL, // label
2593   NULL, // operand
2594   NULL, // flow block
2595   NULL, // C source 
2596   0,    // num ops
2597   0,0,  // dest, bit instruction
2598   0,0,  // branch, skip
2599   0,    // literal operand
2600   0,    // RAM access bit
2601   0,    // fast call/return mode select bit
2602   0,    // second memory operand
2603   0,    // second literal operand
2604   POC_NOP,
2605   PCC_NONE,  // inCond
2606   PCC_NONE  , // outCond
2607   PCI_MAGIC
2608 };
2609
2610 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2611   {PC_OPCODE, NULL, NULL, 0, NULL, 
2612    genericDestruct,
2613    genericPrint},
2614   POC_TBLRD_PREINC,
2615   "TBLRD+*",
2616   2,
2617   NULL, // from branch
2618   NULL, // to branch
2619   NULL, // label
2620   NULL, // operand
2621   NULL, // flow block
2622   NULL, // C source 
2623   0,    // num ops
2624   0,0,  // dest, bit instruction
2625   0,0,  // branch, skip
2626   0,    // literal operand
2627   0,    // RAM access bit
2628   0,    // fast call/return mode select bit
2629   0,    // second memory operand
2630   0,    // second literal operand
2631   POC_NOP,
2632   PCC_NONE,  // inCond
2633   PCC_NONE  , // outCond
2634   PCI_MAGIC
2635 };
2636
2637 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2638   {PC_OPCODE, NULL, NULL, 0, NULL, 
2639    genericDestruct,
2640    genericPrint},
2641   POC_TBLWT,
2642   "TBLWT*",
2643   2,
2644   NULL, // from branch
2645   NULL, // to branch
2646   NULL, // label
2647   NULL, // operand
2648   NULL, // flow block
2649   NULL, // C source 
2650   0,    // num ops
2651   0,0,  // dest, bit instruction
2652   0,0,  // branch, skip
2653   0,    // literal operand
2654   0,    // RAM access bit
2655   0,    // fast call/return mode select bit
2656   0,    // second memory operand
2657   0,    // second literal operand
2658   POC_NOP,
2659   PCC_NONE,  // inCond
2660   PCC_NONE  , // outCond
2661   PCI_MAGIC
2662 };
2663
2664 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2665   {PC_OPCODE, NULL, NULL, 0, NULL, 
2666    genericDestruct,
2667    genericPrint},
2668   POC_TBLWT_POSTINC,
2669   "TBLWT*+",
2670   2,
2671   NULL, // from branch
2672   NULL, // to branch
2673   NULL, // label
2674   NULL, // operand
2675   NULL, // flow block
2676   NULL, // C source 
2677   0,    // num ops
2678   0,0,  // dest, bit instruction
2679   0,0,  // branch, skip
2680   0,    // literal operand
2681   0,    // RAM access bit
2682   0,    // fast call/return mode select bit
2683   0,    // second memory operand
2684   0,    // second literal operand
2685   POC_NOP,
2686   PCC_NONE,  // inCond
2687   PCC_NONE  , // outCond
2688   PCI_MAGIC
2689 };
2690
2691 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2692   {PC_OPCODE, NULL, NULL, 0, NULL, 
2693    genericDestruct,
2694    genericPrint},
2695   POC_TBLWT_POSTDEC,
2696   "TBLWT*-",
2697   2,
2698   NULL, // from branch
2699   NULL, // to branch
2700   NULL, // label
2701   NULL, // operand
2702   NULL, // flow block
2703   NULL, // C source 
2704   0,    // num ops
2705   0,0,  // dest, bit instruction
2706   0,0,  // branch, skip
2707   0,    // literal operand
2708   0,    // RAM access bit
2709   0,    // fast call/return mode select bit
2710   0,    // second memory operand
2711   0,    // second literal operand
2712   POC_NOP,
2713   PCC_NONE,  // inCond
2714   PCC_NONE  , // outCond
2715   PCI_MAGIC
2716 };
2717
2718 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2719   {PC_OPCODE, NULL, NULL, 0, NULL, 
2720    genericDestruct,
2721    genericPrint},
2722   POC_TBLWT_PREINC,
2723   "TBLWT+*",
2724   2,
2725   NULL, // from branch
2726   NULL, // to branch
2727   NULL, // label
2728   NULL, // operand
2729   NULL, // flow block
2730   NULL, // C source 
2731   0,    // num ops
2732   0,0,  // dest, bit instruction
2733   0,0,  // branch, skip
2734   0,    // literal operand
2735   0,    // RAM access bit
2736   0,    // fast call/return mode select bit
2737   0,    // second memory operand
2738   0,    // second literal operand
2739   POC_NOP,
2740   PCC_NONE,  // inCond
2741   PCC_NONE  , // outCond
2742   PCI_MAGIC
2743 };
2744
2745 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2746   {PC_OPCODE, NULL, NULL, 0, NULL, 
2747    //   genericAnalyze,
2748    genericDestruct,
2749    genericPrint},
2750   POC_TSTFSZ,
2751   "TSTFSZ",
2752   2,
2753   NULL, // from branch
2754   NULL, // to branch
2755   NULL, // label
2756   NULL, // operand
2757   NULL, // flow block
2758   NULL, // C source 
2759   2,    // num ops
2760   0,0,  // dest, bit instruction
2761   1,1,  // branch, skip
2762   0,    // literal operand
2763   1,    // RAM access bit
2764   0,    // fast call/return mode select bit
2765   0,    // second memory operand
2766   0,    // second literal operand
2767   POC_NOP,
2768   PCC_REGISTER,   // inCond
2769   PCC_NONE, // outCond
2770   PCI_MAGIC
2771 };
2772
2773 pCodeInstruction pic16_pciXORWF = {
2774   {PC_OPCODE, NULL, NULL, 0, NULL, 
2775    //   genericAnalyze,
2776    genericDestruct,
2777    genericPrint},
2778   POC_XORWF,
2779   "XORWF",
2780   2,
2781   NULL, // from branch
2782   NULL, // to branch
2783   NULL, // label
2784   NULL, // operand
2785   NULL, // flow block
2786   NULL, // C source 
2787   3,    // num ops
2788   1,0,  // dest, bit instruction
2789   0,0,  // branch, skip
2790   0,    // literal operand
2791   1,    // RAM access bit
2792   0,    // fast call/return mode select bit
2793   0,    // second memory operand
2794   0,    // second literal operand
2795   POC_NOP,
2796   (PCC_W | PCC_REGISTER),   // inCond
2797   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2798   PCI_MAGIC
2799 };
2800
2801 pCodeInstruction pic16_pciXORFW = {
2802   {PC_OPCODE, NULL, NULL, 0, NULL, 
2803    //   genericAnalyze,
2804    genericDestruct,
2805    genericPrint},
2806   POC_XORFW,
2807   "XORWF",
2808   2,
2809   NULL, // from branch
2810   NULL, // to branch
2811   NULL, // label
2812   NULL, // operand
2813   NULL, // flow block
2814   NULL, // C source 
2815   3,    // num ops
2816   0,0,  // dest, bit instruction
2817   0,0,  // branch, skip
2818   0,    // literal operand
2819   1,    // RAM access bit
2820   0,    // fast call/return mode select bit
2821   0,    // second memory operand
2822   0,    // second literal operand
2823   POC_NOP,
2824   (PCC_W | PCC_REGISTER),   // inCond
2825   (PCC_W | PCC_Z | PCC_N), // outCond
2826   PCI_MAGIC
2827 };
2828
2829 pCodeInstruction pic16_pciXORLW = {
2830   {PC_OPCODE, NULL, NULL, 0, NULL, 
2831    //   genericAnalyze,
2832    genericDestruct,
2833    genericPrint},
2834   POC_XORLW,
2835   "XORLW",
2836   2,
2837   NULL, // from branch
2838   NULL, // to branch
2839   NULL, // label
2840   NULL, // operand
2841   NULL, // flow block
2842   NULL, // C source 
2843   1,    // num ops
2844   0,0,  // dest, bit instruction
2845   0,0,  // branch, skip
2846   1,    // literal operand
2847   1,    // RAM access bit
2848   0,    // fast call/return mode select bit
2849   0,    // second memory operand
2850   0,    // second literal operand
2851   POC_NOP,
2852   (PCC_W | PCC_LITERAL),   // inCond
2853   (PCC_W | PCC_Z | PCC_N), // outCond
2854   PCI_MAGIC
2855 };
2856
2857
2858 pCodeInstruction pic16_pciBANKSEL = {
2859   {PC_OPCODE, NULL, NULL, 0, NULL, 
2860    genericDestruct,
2861    genericPrint},
2862   POC_BANKSEL,
2863   "BANKSEL",
2864   2,
2865   NULL, // from branch
2866   NULL, // to branch
2867   NULL, // label
2868   NULL, // operand
2869   NULL, // flow block
2870   NULL, // C source 
2871   0,    // num ops
2872   0,0,  // dest, bit instruction
2873   0,0,  // branch, skip
2874   0,    // literal operand
2875   0,    // RAM access bit
2876   0,    // fast call/return mode select bit
2877   0,    // second memory operand
2878   0,    // second literal operand
2879   POC_NOP,
2880   PCC_NONE,   // inCond
2881   PCC_NONE, // outCond
2882   PCI_MAGIC
2883 };
2884
2885
2886 #define MAX_PIC16MNEMONICS 100
2887 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2888
2889 //#define USE_VSNPRINTF
2890 #if OPT_DISABLE_PIC
2891
2892 #ifdef USE_VSNPRINTF
2893   // Alas, vsnprintf is not ANSI standard, and does not exist
2894   // on Solaris (and probably other non-Gnu flavored Unixes).
2895
2896 /*-----------------------------------------------------------------*/
2897 /* SAFE_snprintf - like snprintf except the string pointer is      */
2898 /*                 after the string has been printed to. This is   */
2899 /*                 useful for printing to string as though if it   */
2900 /*                 were a stream.                                  */
2901 /*-----------------------------------------------------------------*/
2902 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2903 {
2904   va_list val;
2905   int len;
2906
2907   if(!str || !*str)
2908     return;
2909
2910   va_start(val, format);
2911
2912   vsnprintf(*str, *size, format, val);
2913
2914   va_end (val);
2915
2916   len = strlen(*str);
2917   if(len > *size) {
2918     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2919     fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2920   }
2921
2922   *str += len;
2923   *size -= len;
2924
2925 }
2926
2927 #else
2928 // This version is *not* safe, despite the name.
2929
2930 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
2931 {
2932   va_list val;
2933   int len;
2934   static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2935
2936   if(!str || !*str)
2937     return;
2938
2939   va_start(val, format);
2940
2941   vsprintf(buffer, format, val);
2942   va_end (val);
2943
2944   len = strlen(buffer);
2945   if(len > *size) {
2946     fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2947     fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2948   }
2949
2950   strcpy(*str, buffer);
2951   *str += len;
2952   *size -= len;
2953
2954 }
2955
2956 #endif    //  USE_VSNPRINTF
2957 #endif
2958
2959 extern set *externs;
2960 extern  void pic16_initStack(int base_address, int size);
2961 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2962 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2963 extern void pic16_init_pic(char *);
2964
2965 void  pic16_pCodeInitRegisters(void)
2966 {
2967   static int initialized=0;
2968
2969         if(initialized)
2970                 return;
2971         
2972         initialized = 1;
2973
2974 //      pic16_initStack(0xfff, 8);
2975         pic16_init_pic(port->processor);
2976
2977         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2978         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2979         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2980         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2981         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2982         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2983         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2984
2985         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2986         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2987         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2988
2989         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2990         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2991         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2992         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2993
2994         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2995         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2996         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2997         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2998         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2999         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3000
3001         pic16_stackpnt_lo = &pic16_pc_fsr1l;
3002         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3003         pic16_stack_postdec = &pic16_pc_postdec1;
3004         pic16_stack_postinc = &pic16_pc_postinc1;
3005         pic16_stack_preinc = &pic16_pc_preinc1;
3006         pic16_stack_plusw = &pic16_pc_plusw1;
3007         
3008         pic16_framepnt_lo = &pic16_pc_fsr2l;
3009         pic16_framepnt_hi = &pic16_pc_fsr2h;
3010         pic16_frame_postdec = &pic16_pc_postdec2;
3011         pic16_frame_postinc = &pic16_pc_postinc2;
3012         pic16_frame_preinc = &pic16_pc_preinc2;
3013         pic16_frame_plusw = &pic16_pc_plusw2;
3014
3015         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3016         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3017         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3018         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3019         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3020         
3021         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3022         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3023         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3024         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3025         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3026
3027         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3028         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3029         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3030         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3031         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3032         
3033         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3034         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3035
3036
3037         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3038         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3039         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3040         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3041
3042         
3043         pic16_pc_status.rIdx = IDX_STATUS;
3044         pic16_pc_intcon.rIdx = IDX_INTCON;
3045         pic16_pc_pcl.rIdx = IDX_PCL;
3046         pic16_pc_pclath.rIdx = IDX_PCLATH;
3047         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3048         pic16_pc_wreg.rIdx = IDX_WREG;
3049         pic16_pc_bsr.rIdx = IDX_BSR;
3050
3051         pic16_pc_tosl.rIdx = IDX_TOSL;
3052         pic16_pc_tosh.rIdx = IDX_TOSH;
3053         pic16_pc_tosu.rIdx = IDX_TOSU;
3054
3055         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3056         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3057         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3058         pic16_pc_tablat.rIdx = IDX_TABLAT;
3059
3060         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3061         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3062         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3063         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3064         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3065         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3066         pic16_pc_indf0.rIdx = IDX_INDF0;
3067         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3068         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3069         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3070         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3071         pic16_pc_indf1.rIdx = IDX_INDF1;
3072         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3073         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3074         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3075         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3076         pic16_pc_indf2.rIdx = IDX_INDF2;
3077         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3078         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3079         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3080         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3081         pic16_pc_prodl.rIdx = IDX_PRODL;
3082         pic16_pc_prodh.rIdx = IDX_PRODH;
3083         
3084         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3085         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3086         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3087         
3088         pic16_pc_kzero.rIdx = IDX_KZ;
3089         pic16_pc_wsave.rIdx = IDX_WSAVE;
3090         pic16_pc_ssave.rIdx = IDX_SSAVE;
3091
3092         pic16_pc_eecon1.rIdx = IDX_EECON1;
3093         pic16_pc_eecon2.rIdx = IDX_EECON2;
3094         pic16_pc_eedata.rIdx = IDX_EEDATA;
3095         pic16_pc_eeadr.rIdx = IDX_EEADR;
3096         
3097         
3098         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3099         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3100
3101         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3102         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3103
3104         /* probably should put this in a separate initialization routine */
3105         pb_dead_pcodes = newpBlock();
3106
3107 }
3108
3109 #if OPT_DISABLE_PIC
3110 /*-----------------------------------------------------------------*/
3111 /*  mnem2key - convert a pic mnemonic into a hash key              */
3112 /*   (BTW - this spreads the mnemonics quite well)                 */
3113 /*                                                                 */
3114 /*-----------------------------------------------------------------*/
3115
3116 int mnem2key(char const *mnem)
3117 {
3118   int key = 0;
3119
3120   if(!mnem)
3121     return 0;
3122
3123   while(*mnem) {
3124
3125     key += toupper(*mnem++) +1;
3126
3127   }
3128
3129   return (key & 0x1f);
3130
3131 }
3132 #endif
3133
3134 void pic16initMnemonics(void)
3135 {
3136   int i = 0;
3137   int key;
3138   //  char *str;
3139   pCodeInstruction *pci;
3140
3141   if(mnemonics_initialized)
3142     return;
3143
3144   // NULL out the array before making the assignments
3145   // since we check the array contents below this initialization.
3146
3147   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3148     pic16Mnemonics[i] = NULL;
3149   }
3150
3151   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3152   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3153   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3154   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3155   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3156   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3157   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3158   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3159   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3160   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3161   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3162   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3163   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3164   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3165   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3166   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3167   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3168   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3169   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3170   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3171   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3172   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3173   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3174   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3175   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3176   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3177   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3178   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3179   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3180   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3181   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3182   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3183   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3184   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3185   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3186   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3187   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3188   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3189   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3190   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3191   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3192   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3193   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3194   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3195   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3196   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3197   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3198   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3199   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3200   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3201   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3202   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3203   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3204   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3205   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3206   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3207   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3208   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3209   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3210   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3211   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3212   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3213   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3214   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3215   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3216   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3217   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3218   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3219   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3220   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3221   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3222   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3223   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3224   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3225   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3226   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3227   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3228   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3229   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3230   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3231   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3232   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3233   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3234   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3235   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3236   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3237   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3238   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3239   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3240   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3241   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3242   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3243   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3244   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3245
3246   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3247     if(pic16Mnemonics[i])
3248       hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3249   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3250
3251   while(pci) {
3252     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3253     pci = hTabNextItem(pic16MnemonicsHash, &key);
3254   }
3255
3256   mnemonics_initialized = 1;
3257 }
3258
3259 int pic16_getpCodePeepCommand(char *cmd);
3260
3261 int pic16_getpCode(char *mnem,unsigned dest)
3262 {
3263
3264   pCodeInstruction *pci;
3265   int key = mnem2key(mnem);
3266
3267   if(!mnemonics_initialized)
3268     pic16initMnemonics();
3269
3270   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3271
3272   while(pci) {
3273
3274     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3275       if((pci->num_ops <= 1)
3276         || (pci->isModReg == dest)
3277         || (pci->isBitInst)
3278         || (pci->num_ops <= 2 && pci->isAccess)
3279         || (pci->num_ops <= 2 && pci->isFastCall)
3280         || (pci->num_ops <= 2 && pci->is2MemOp)
3281         || (pci->num_ops <= 2 && pci->is2LitOp) )
3282         return(pci->op);
3283     }
3284
3285     pci = hTabNextItemWK (pic16MnemonicsHash);
3286   
3287   }
3288
3289   return -1;
3290 }
3291
3292 /*-----------------------------------------------------------------*
3293  * pic16initpCodePeepCommands
3294  *
3295  *-----------------------------------------------------------------*/
3296 void pic16initpCodePeepCommands(void)
3297 {
3298
3299   int key, i;
3300   peepCommand *pcmd;
3301
3302   i = 0;
3303   do {
3304     hTabAddItem(&pic16pCodePeepCommandsHash, 
3305                 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3306     i++;
3307   } while (peepCommands[i].cmd);
3308
3309   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3310
3311   while(pcmd) {
3312     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3313     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3314   }
3315
3316 }
3317
3318 /*-----------------------------------------------------------------
3319  *
3320  *
3321  *-----------------------------------------------------------------*/
3322
3323 int pic16_getpCodePeepCommand(char *cmd)
3324 {
3325
3326   peepCommand *pcmd;
3327   int key = mnem2key(cmd);
3328
3329
3330   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3331
3332   while(pcmd) {
3333     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3334     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3335       return pcmd->id;
3336     }
3337
3338     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3339   
3340   }
3341
3342   return -1;
3343 }
3344
3345 static char getpBlock_dbName(pBlock *pb)
3346 {
3347   if(!pb)
3348     return 0;
3349
3350   if(pb->cmemmap)
3351     return pb->cmemmap->dbName;
3352
3353   return pb->dbName;
3354 }
3355 void pic16_pBlockConvert2ISR(pBlock *pb)
3356 {
3357         if(!pb)return;
3358
3359         if(pb->cmemmap)pb->cmemmap = NULL;
3360
3361         pb->dbName = 'I';
3362
3363         if(pic16_pcode_verbose)
3364                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3365 }
3366
3367 void pic16_pBlockConvert2Absolute(pBlock *pb)
3368 {
3369         if(!pb)return;
3370         if(pb->cmemmap)pb->cmemmap = NULL;
3371         
3372         pb->dbName = 'A';
3373         
3374         if(pic16_pcode_verbose)
3375                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3376 }
3377   
3378 /*-----------------------------------------------------------------*/
3379 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3380 /*                   instances to the front of the doubly linked   */
3381 /*                   list of pBlocks                               */
3382 /*-----------------------------------------------------------------*/
3383
3384 void pic16_movepBlock2Head(char dbName)
3385 {
3386   pBlock *pb;
3387
3388
3389   /* this can happen in sources without code,
3390    * only variable definitions */
3391   if(!the_pFile)return;
3392
3393   pb = the_pFile->pbHead;
3394
3395   while(pb) {
3396
3397     if(getpBlock_dbName(pb) == dbName) {
3398       pBlock *pbn = pb->next;
3399       pb->next = the_pFile->pbHead;
3400       the_pFile->pbHead->prev = pb;
3401       the_pFile->pbHead = pb;
3402
3403       if(pb->prev)
3404         pb->prev->next = pbn;
3405
3406       // If the pBlock that we just moved was the last
3407       // one in the link of all of the pBlocks, then we
3408       // need to point the tail to the block just before
3409       // the one we moved.
3410       // Note: if pb->next is NULL, then pb must have 
3411       // been the last pBlock in the chain.
3412
3413       if(pbn)
3414         pbn->prev = pb->prev;
3415       else
3416         the_pFile->pbTail = pb->prev;
3417
3418       pb = pbn;
3419
3420     } else
3421       pb = pb->next;
3422
3423   }
3424
3425 }
3426
3427 void pic16_copypCode(FILE *of, char dbName)
3428 {
3429   pBlock *pb;
3430
3431         if(!of || !the_pFile)
3432                 return;
3433
3434         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3435                 if(getpBlock_dbName(pb) == dbName) {
3436 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3437                         pBlockStats(of,pb);
3438                         pic16_printpBlock(of,pb);
3439                 }
3440         }
3441
3442 }
3443 void pic16_pcode_test(void)
3444 {
3445
3446   DFPRINTF((stderr,"pcode is alive!\n"));
3447
3448   //initMnemonics();
3449
3450   if(the_pFile) {
3451
3452     pBlock *pb;
3453     FILE *pFile;
3454     char buffer[100];
3455
3456     /* create the file name */
3457     strcpy(buffer,dstFileName);
3458     strcat(buffer,".p");
3459
3460     if( !(pFile = fopen(buffer, "w" ))) {
3461       werror(E_FILE_OPEN_ERR,buffer);
3462       exit(1);
3463     }
3464
3465     fprintf(pFile,"pcode dump\n\n");
3466
3467     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3468       fprintf(pFile,"\n\tNew pBlock\n\n");
3469       if(pb->cmemmap)
3470         fprintf(pFile,"%s",pb->cmemmap->sname);
3471       else
3472         fprintf(pFile,"internal pblock");
3473
3474       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3475       pic16_printpBlock(pFile,pb);
3476     }
3477   }
3478 }
3479
3480
3481 unsigned long pic16_countInstructions(void)
3482 {
3483   pBlock *pb;
3484   pCode *pc;
3485   unsigned long isize=0;
3486
3487     if(!the_pFile)return -1;
3488     
3489     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3490       for(pc = pb->pcHead; pc; pc = pc->next) {
3491         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3492       }
3493     }
3494   return (isize);
3495 }
3496
3497
3498 /*-----------------------------------------------------------------*/
3499 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3500 /*      ister, RegCond will return the bit being referenced.       */
3501 /*                                                                 */
3502 /* fixme - why not just OR in the pcop bit field                   */
3503 /*-----------------------------------------------------------------*/
3504
3505 static int RegCond(pCodeOp *pcop)
3506 {
3507
3508   if(!pcop)
3509     return 0;
3510
3511   if(!pcop->name)return 0;
3512
3513   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3514     switch(PCORB(pcop)->bit) {
3515     case PIC_C_BIT:
3516       return PCC_C;
3517     case PIC_DC_BIT:
3518         return PCC_DC;
3519     case PIC_Z_BIT:
3520       return PCC_Z;
3521     }
3522
3523   }
3524
3525   return 0;
3526 }
3527
3528 /*-----------------------------------------------------------------*/
3529 /* pic16_newpCode - create and return a newly initialized pCode          */
3530 /*                                                                 */
3531 /*  fixme - rename this                                            */
3532 /*                                                                 */
3533 /* The purpose of this routine is to create a new Instruction      */
3534 /* pCode. This is called by gen.c while the assembly code is being */
3535 /* generated.                                                      */
3536 /*                                                                 */
3537 /* Inouts:                                                         */
3538 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3539 /*                  (note that the op is analogous to but not the  */
3540 /*                  same thing as the opcode of the instruction.)  */
3541 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3542 /*                                                                 */
3543 /* Outputs:                                                        */
3544 /*  a pointer to the new malloc'd pCode is returned.               */
3545 /*                                                                 */
3546 /*                                                                 */
3547 /*                                                                 */
3548 /*-----------------------------------------------------------------*/
3549 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3550 {
3551   pCodeInstruction *pci ;
3552
3553   if(!mnemonics_initialized)
3554     pic16initMnemonics();
3555     
3556   pci = Safe_calloc(1, sizeof(pCodeInstruction));
3557
3558   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3559     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3560     pci->pcop = pcop;
3561
3562     if(pci->inCond & PCC_EXAMINE_PCOP)
3563       pci->inCond  |= RegCond(pcop);
3564
3565     if(pci->outCond & PCC_EXAMINE_PCOP)
3566       pci->outCond  |= RegCond(pcop);
3567
3568     pci->pc.prev = pci->pc.next = NULL;
3569     return (pCode *)pci;
3570   }
3571
3572   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3573   exit(1);
3574
3575   return NULL;
3576 }       
3577
3578 /*-----------------------------------------------------------------*/
3579 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3580 /*                                                                 */
3581 /* Wild pcodes are used during the peep hole optimizer to serve    */
3582 /* as place holders for any instruction. When a snippet of code is */
3583 /* compared to a peep hole rule, the wild card opcode will match   */
3584 /* any instruction. However, the optional operand and label are    */
3585 /* additional qualifiers that must also be matched before the      */
3586 /* line (of assembly code) is declared matched. Note that the      */
3587 /* operand may be wild too.                                        */
3588 /*                                                                 */
3589 /*   Note, a wild instruction is specified just like a wild var:   */
3590 /*      %4     ; A wild instruction,                               */
3591 /*  See the peeph.def file for additional examples                 */
3592 /*                                                                 */
3593 /*-----------------------------------------------------------------*/
3594
3595 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3596 {
3597
3598   pCodeWild *pcw;
3599     
3600   pcw = Safe_calloc(1,sizeof(pCodeWild));
3601
3602   pcw->pci.pc.type = PC_WILD;
3603   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3604   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3605   pcw->pci.pc.pb = NULL;
3606
3607   //  pcw->pci.pc.analyze = genericAnalyze;
3608   pcw->pci.pc.destruct = genericDestruct;
3609   pcw->pci.pc.print = genericPrint;
3610
3611   pcw->id = pCodeID;              // this is the 'n' in %n
3612   pcw->operand = optional_operand;
3613   pcw->label   = optional_label;
3614
3615   pcw->mustBeBitSkipInst = 0;
3616   pcw->mustNotBeBitSkipInst = 0;
3617   pcw->invertBitSkipInst = 0;
3618
3619   return ( (pCode *)pcw);
3620   
3621 }
3622
3623  /*-----------------------------------------------------------------*/
3624 /* newPcodeInlineP - create a new pCode from a char string           */
3625 /*-----------------------------------------------------------------*/
3626
3627
3628 pCode *pic16_newpCodeInlineP(char *cP)
3629 {
3630
3631   pCodeComment *pcc ;
3632     
3633   pcc = Safe_calloc(1,sizeof(pCodeComment));
3634
3635   pcc->pc.type = PC_INLINE;
3636   pcc->pc.prev = pcc->pc.next = NULL;
3637   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3638   pcc->pc.pb = NULL;
3639
3640   //  pcc->pc.analyze = genericAnalyze;
3641   pcc->pc.destruct = genericDestruct;
3642   pcc->pc.print = genericPrint;
3643
3644   if(cP)
3645     pcc->comment = Safe_strdup(cP);
3646   else
3647     pcc->comment = NULL;
3648
3649   return ( (pCode *)pcc);
3650
3651 }
3652
3653 /*-----------------------------------------------------------------*/
3654 /* newPcodeCharP - create a new pCode from a char string           */
3655 /*-----------------------------------------------------------------*/
3656
3657 pCode *pic16_newpCodeCharP(char *cP)
3658 {
3659
3660   pCodeComment *pcc ;
3661     
3662   pcc = Safe_calloc(1,sizeof(pCodeComment));
3663
3664   pcc->pc.type = PC_COMMENT;
3665   pcc->pc.prev = pcc->pc.next = NULL;
3666   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3667   pcc->pc.pb = NULL;
3668
3669   //  pcc->pc.analyze = genericAnalyze;
3670   pcc->pc.destruct = genericDestruct;
3671   pcc->pc.print = genericPrint;
3672
3673   if(cP)
3674     pcc->comment = Safe_strdup(cP);
3675   else
3676     pcc->comment = NULL;
3677
3678   return ( (pCode *)pcc);
3679
3680 }
3681
3682 /*-----------------------------------------------------------------*/
3683 /* pic16_newpCodeFunction -                                              */
3684 /*-----------------------------------------------------------------*/
3685
3686
3687 pCode *pic16_newpCodeFunction(char *mod,char *f)
3688 {
3689   pCodeFunction *pcf;
3690
3691   pcf = Safe_calloc(1,sizeof(pCodeFunction));
3692
3693   pcf->pc.type = PC_FUNCTION;
3694   pcf->pc.prev = pcf->pc.next = NULL;
3695   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3696   pcf->pc.pb = NULL;
3697
3698   //  pcf->pc.analyze = genericAnalyze;
3699   pcf->pc.destruct = genericDestruct;
3700   pcf->pc.print = pCodePrintFunction;
3701
3702   pcf->ncalled = 0;
3703   pcf->absblock = 0;
3704   
3705   if(mod) {
3706     pcf->modname = Safe_calloc(1,strlen(mod)+1);
3707     strcpy(pcf->modname,mod);
3708   } else
3709     pcf->modname = NULL;
3710
3711   if(f) {
3712     pcf->fname = Safe_calloc(1,strlen(f)+1);
3713     strcpy(pcf->fname,f);
3714   } else
3715     pcf->fname = NULL;
3716
3717   pcf->stackusage = 0;
3718
3719   return ( (pCode *)pcf);
3720 }
3721
3722 /*-----------------------------------------------------------------*/
3723 /* pic16_newpCodeFlow                                                    */
3724 /*-----------------------------------------------------------------*/
3725 static void destructpCodeFlow(pCode *pc)
3726 {
3727   if(!pc || !isPCFL(pc))
3728     return;
3729
3730 /*
3731   if(PCFL(pc)->from)
3732   if(PCFL(pc)->to)
3733 */
3734   pic16_unlinkpCode(pc);
3735
3736   deleteSet(&PCFL(pc)->registers);
3737   deleteSet(&PCFL(pc)->from);
3738   deleteSet(&PCFL(pc)->to);
3739
3740   /* Instead of deleting the memory used by this pCode, mark
3741    * the object as bad so that if there's a pointer to this pCode
3742    * dangling around somewhere then (hopefully) when the type is
3743    * checked we'll catch it.
3744    */
3745
3746   pc->type = PC_BAD;
3747   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3748
3749 //  Safe_free(pc);
3750
3751 }
3752
3753 pCode *pic16_newpCodeFlow(void )
3754 {
3755   pCodeFlow *pcflow;
3756
3757   //_ALLOC(pcflow,sizeof(pCodeFlow));
3758   pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3759
3760   pcflow->pc.type = PC_FLOW;
3761   pcflow->pc.prev = pcflow->pc.next = NULL;
3762   pcflow->pc.pb = NULL;
3763
3764   //  pcflow->pc.analyze = genericAnalyze;
3765   pcflow->pc.destruct = destructpCodeFlow;
3766   pcflow->pc.print = genericPrint;
3767
3768   pcflow->pc.seq = GpcFlowSeq++;
3769
3770   pcflow->from = pcflow->to = NULL;
3771
3772   pcflow->inCond = PCC_NONE;
3773   pcflow->outCond = PCC_NONE;
3774
3775   pcflow->firstBank = -1;
3776   pcflow->lastBank = -1;
3777
3778   pcflow->FromConflicts = 0;
3779   pcflow->ToConflicts = 0;
3780
3781   pcflow->end = NULL;
3782
3783   pcflow->registers = newSet();
3784
3785   return ( (pCode *)pcflow);
3786
3787 }
3788
3789 /*-----------------------------------------------------------------*/
3790 /*-----------------------------------------------------------------*/
3791 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3792 {
3793   pCodeFlowLink *pcflowLink;
3794
3795   pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3796
3797   pcflowLink->pcflow = pcflow;
3798   pcflowLink->bank_conflict = 0;
3799
3800   return pcflowLink;
3801 }
3802
3803 /*-----------------------------------------------------------------*/
3804 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3805 /*-----------------------------------------------------------------*/
3806
3807 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3808 {
3809
3810   pCodeCSource *pccs;
3811     
3812   pccs = Safe_calloc(1,sizeof(pCodeCSource));
3813
3814   pccs->pc.type = PC_CSOURCE;
3815   pccs->pc.prev = pccs->pc.next = NULL;
3816   pccs->pc.pb = NULL;
3817
3818   pccs->pc.destruct = genericDestruct;
3819   pccs->pc.print = genericPrint;
3820
3821   pccs->line_number = ln;
3822   if(l)
3823     pccs->line = Safe_strdup(l);
3824   else
3825     pccs->line = NULL;
3826
3827   if(f)
3828     pccs->file_name = Safe_strdup(f);
3829   else
3830     pccs->file_name = NULL;
3831
3832   return ( (pCode *)pccs);
3833
3834 }
3835
3836
3837 /*******************************************************************/
3838 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3839 /*                      added by VR 6-Jun-2003                     */
3840 /*******************************************************************/
3841
3842 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3843 {
3844   pCodeAsmDir *pcad;
3845   va_list ap;
3846   char buffer[512];
3847   char *lbp=buffer;
3848   
3849         pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3850         pcad->pci.pc.type = PC_ASMDIR;
3851         pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3852         pcad->pci.pc.pb = NULL;
3853         pcad->pci.isize = 2;
3854         pcad->pci.pc.destruct = genericDestruct;
3855         pcad->pci.pc.print = genericPrint;
3856
3857         if(asdir && *asdir) {
3858                 
3859                 while(isspace(*asdir))asdir++;  // strip any white space from the beginning
3860                 
3861                 pcad->directive = Safe_strdup( asdir );
3862         }
3863         
3864         va_start(ap, argfmt);
3865         
3866         memset(buffer, 0, sizeof(buffer));
3867         if(argfmt && *argfmt)
3868                 vsprintf(buffer, argfmt, ap);
3869         
3870         va_end(ap);
3871         
3872         while(isspace(*lbp))lbp++;
3873         
3874         if(lbp && *lbp)
3875                 pcad->arg = Safe_strdup( lbp );
3876
3877   return ((pCode *)pcad);
3878 }
3879
3880 /*-----------------------------------------------------------------*/
3881 /* pCodeLabelDestruct - free memory used by a label.               */
3882 /*-----------------------------------------------------------------*/
3883 static void pCodeLabelDestruct(pCode *pc)
3884 {
3885
3886   if(!pc)
3887     return;
3888
3889 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3890 //    Safe_free(PCL(pc)->label);
3891
3892   /* Instead of deleting the memory used by this pCode, mark
3893    * the object as bad so that if there's a pointer to this pCode
3894    * dangling around somewhere then (hopefully) when the type is
3895    * checked we'll catch it.
3896    */
3897
3898   pc->type = PC_BAD;
3899   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3900
3901 //  Safe_free(pc);
3902
3903 }
3904
3905 pCode *pic16_newpCodeLabel(char *name, int key)
3906 {
3907
3908   char *s = buffer;
3909   pCodeLabel *pcl;
3910     
3911   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3912
3913   pcl->pc.type = PC_LABEL;
3914   pcl->pc.prev = pcl->pc.next = NULL;
3915   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3916   pcl->pc.pb = NULL;
3917
3918   //  pcl->pc.analyze = genericAnalyze;
3919   pcl->pc.destruct = pCodeLabelDestruct;
3920   pcl->pc.print = pCodePrintLabel;
3921
3922   pcl->key = key;
3923   pcl->force = 0;
3924   
3925   pcl->label = NULL;
3926   if(key>0) {
3927     sprintf(s,"_%05d_DS_",key);
3928   } else
3929     s = name;
3930
3931   if(s)
3932     pcl->label = Safe_strdup(s);
3933
3934 //  if(pic16_pcode_verbose)
3935 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3936
3937
3938   return ( (pCode *)pcl);
3939
3940 }
3941
3942 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3943 {
3944   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3945   
3946         pcl->force = 1;
3947   
3948   return ( (pCode *)pcl );
3949 }
3950
3951 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3952 {
3953   pCodeInfo *pci;
3954
3955     pci = Safe_calloc(1, sizeof(pCodeInfo));
3956     pci->pci.pc.type = PC_INFO;
3957     pci->pci.pc.prev = pci->pci.pc.next = NULL;
3958     pci->pci.pc.pb = NULL;
3959     pci->pci.label = NULL;
3960         
3961     pci->pci.pc.destruct = genericDestruct;
3962     pci->pci.pc.print = genericPrint;
3963     
3964     pci->type = type;
3965     pci->oper1 = pcop;
3966   
3967   return ((pCode *)pci);
3968 }
3969
3970
3971 /*-----------------------------------------------------------------*/
3972 /* newpBlock - create and return a pointer to a new pBlock         */
3973 /*-----------------------------------------------------------------*/
3974 static pBlock *newpBlock(void)
3975 {
3976
3977   pBlock *PpB;
3978
3979   PpB = Safe_calloc(1,sizeof(pBlock) );
3980   PpB->next = PpB->prev = NULL;
3981
3982   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3983   PpB->tregisters = NULL;
3984   PpB->visited = 0;
3985   PpB->FlowTree = NULL;
3986
3987   return PpB;
3988
3989 }
3990
3991 /*-----------------------------------------------------------------*/
3992 /* pic16_newpCodeChain - create a new chain of pCodes                    */
3993 /*-----------------------------------------------------------------*
3994  *
3995  *  This function will create a new pBlock and the pointer to the
3996  *  pCode that is passed in will be the first pCode in the block.
3997  *-----------------------------------------------------------------*/
3998
3999
4000 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4001 {
4002
4003   pBlock *pB  = newpBlock();
4004
4005   pB->pcHead  = pB->pcTail = pc;
4006   pB->cmemmap = cm;
4007   pB->dbName  = c;
4008
4009   return pB;
4010 }
4011
4012
4013
4014 /*-----------------------------------------------------------------*/
4015 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4016 /*  Note, a negative key means that the label is part of wild card */
4017 /*  (and hence a wild card label) used in the pCodePeep            */
4018 /*   optimizations).                                               */
4019 /*-----------------------------------------------------------------*/
4020
4021 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4022 {
4023   char *s=NULL;
4024   static int label_key=-1;
4025
4026   pCodeOp *pcop;
4027
4028   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4029   pcop->type = PO_LABEL;
4030
4031   pcop->name = NULL;
4032
4033   if(key>0)
4034     sprintf(s=buffer,"_%05d_DS_",key);
4035   else 
4036     s = name, key = label_key--;
4037
4038   if(s)
4039     pcop->name = Safe_strdup(s);
4040
4041   ((pCodeOpLabel *)pcop)->key = key;
4042
4043   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4044   return pcop;
4045 }
4046
4047 /*-----------------------------------------------------------------*/
4048 /*-----------------------------------------------------------------*/
4049 pCodeOp *pic16_newpCodeOpLit(int lit)
4050 {
4051   char *s = buffer;
4052   pCodeOp *pcop;
4053
4054
4055   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4056   pcop->type = PO_LITERAL;
4057
4058   pcop->name = NULL;
4059   //if(lit>=0)
4060     sprintf(s,"0x%02hhx", (unsigned char)lit);
4061   //else
4062   //  sprintf(s, "%i", lit);
4063   
4064   if(s)
4065     pcop->name = Safe_strdup(s);
4066
4067   ((pCodeOpLit *)pcop)->lit = lit;
4068
4069   return pcop;
4070 }
4071
4072 /*-----------------------------------------------------------------*/
4073 /*-----------------------------------------------------------------*/
4074 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4075 {
4076   char *s = buffer, tbuf[256], *tb=tbuf;
4077   pCodeOp *pcop;
4078
4079
4080   tb = pic16_get_op(arg2, NULL, 0);
4081   pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4082   pcop->type = PO_LITERAL;
4083
4084   pcop->name = NULL;
4085   //if(lit>=0) {
4086     sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4087     if(s)
4088       pcop->name = Safe_strdup(s);
4089   //}
4090
4091   ((pCodeOpLit2 *)pcop)->lit = lit;
4092   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4093
4094   return pcop;
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /*-----------------------------------------------------------------*/
4099 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4100 {
4101   pCodeOp *pcop;
4102
4103         pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4104         pcop->type = PO_IMMEDIATE;
4105         if(name) {
4106                 regs *r = pic16_dirregWithName(name);
4107                 pcop->name = Safe_strdup(name);
4108                 PCOI(pcop)->r = r;
4109                 
4110                 if(r) {
4111 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4112                         PCOI(pcop)->rIdx = r->rIdx;
4113                 } else {
4114 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4115                         PCOI(pcop)->rIdx = -1;
4116                 }
4117 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4118         } else {
4119                 pcop->name = NULL;
4120         }
4121
4122         PCOI(pcop)->index = index;
4123         PCOI(pcop)->offset = offset;
4124         PCOI(pcop)->_const = code_space;
4125
4126   return pcop;
4127 }
4128
4129 /*-----------------------------------------------------------------*/
4130 /*-----------------------------------------------------------------*/
4131 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4132 {
4133   char *s = buffer;
4134   pCodeOp *pcop;
4135
4136
4137   if(!pcwb || !subtype) {
4138     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4139     exit(1);
4140   }
4141
4142   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4143   pcop->type = PO_WILD;
4144   sprintf(s,"%%%d",id);
4145   pcop->name = Safe_strdup(s);
4146
4147   PCOW(pcop)->id = id;
4148   PCOW(pcop)->pcwb = pcwb;
4149   PCOW(pcop)->subtype = subtype;
4150   PCOW(pcop)->matched = NULL;
4151
4152   PCOW(pcop)->pcop2 = NULL;
4153   
4154   return pcop;
4155 }
4156
4157 /*-----------------------------------------------------------------*/
4158 /*-----------------------------------------------------------------*/
4159 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4160 {
4161   char *s = buffer;
4162   pCodeOp *pcop;
4163
4164
4165         if(!pcwb || !subtype || !subtype2) {
4166                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4167                 exit(1);
4168         }
4169
4170         pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4171         pcop->type = PO_WILD;
4172         sprintf(s,"%%%d",id);
4173         pcop->name = Safe_strdup(s);
4174
4175         PCOW(pcop)->id = id;
4176         PCOW(pcop)->pcwb = pcwb;
4177         PCOW(pcop)->subtype = subtype;
4178         PCOW(pcop)->matched = NULL;
4179
4180         PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4181
4182         if(!subtype2->name) {
4183                 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4184                 PCOW2(pcop)->pcop.type = PO_WILD;
4185                 sprintf(s, "%%%d", id2);
4186                 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4187                 PCOW2(pcop)->id = id2;
4188                 PCOW2(pcop)->subtype = subtype2;
4189
4190 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4191 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4192         } else {
4193                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4194
4195 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4196 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4197         }
4198   
4199
4200
4201   return pcop;
4202 }
4203
4204
4205 /*-----------------------------------------------------------------*/
4206 /*-----------------------------------------------------------------*/
4207 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4208 {
4209   pCodeOp *pcop;
4210   
4211   pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4212   pcop->type = PO_GPR_BIT;
4213   if(s)
4214     pcop->name = Safe_strdup(s);   
4215   else
4216     pcop->name = NULL;
4217
4218   PCORB(pcop)->bit = bit;
4219   PCORB(pcop)->inBitSpace = inBitSpace;
4220   PCORB(pcop)->subtype = subt;
4221
4222   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4223   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4224 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4225 //  PCOR(pcop)->rIdx = 0;
4226   return pcop;
4227 }
4228
4229 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4230 {
4231   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4232                                 bit, 0, PO_GPR_REGISTER);
4233 }
4234
4235
4236 /*-----------------------------------------------------------------*
4237  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4238  *
4239  * If rIdx >=0 then a specific register from the set of registers
4240  * will be selected. If rIdx <0, then a new register will be searched
4241  * for.
4242  *-----------------------------------------------------------------*/
4243
4244 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4245 {
4246   pCodeOp *pcop;
4247
4248   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4249
4250   pcop->name = NULL;
4251
4252   if(rIdx >= 0) {
4253     PCOR(pcop)->rIdx = rIdx;
4254     PCOR(pcop)->r = pic16_regWithIdx(rIdx);
4255   } else {
4256     PCOR(pcop)->r = pic16_findFreeReg(REG_GPR);
4257
4258     if(PCOR(pcop)->r)
4259       PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4260     else {
4261         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4262                 __FUNCTION__, __LINE__);
4263         exit(-1);
4264     }
4265   }
4266
4267   pcop->type = PCOR(pcop)->r->pc_type;
4268
4269   return pcop;
4270 }
4271
4272 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4273 {
4274   pCodeOp *pcop;
4275   regs *r;
4276   
4277     pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4278     pcop->name = NULL;
4279     
4280     r = pic16_findFreeReg(REG_GPR);
4281
4282     while(r) {
4283       if(!bitVectBitValue(bv, r->rIdx)) {
4284         PCOR(pcop)->r = r;
4285         PCOR(pcop)->rIdx = r->rIdx;
4286         pcop->type = r->pc_type;
4287         return (pcop);
4288       }
4289       
4290       r = pic16_findFreeRegNext(REG_GPR, r);
4291     }
4292   
4293   return NULL;
4294 }
4295
4296       
4297
4298 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4299 {
4300   pCodeOp *pcop;
4301   regs *r;
4302
4303         pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4304         PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4305         PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4306         pcop->type = PCOR(pcop)->r->pc_type;
4307         pcop->name = PCOR(pcop)->r->name;
4308
4309 //      if(pic16_pcode_verbose) {
4310 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4311 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4312 //      }
4313
4314   return pcop;
4315 }
4316
4317 /*-----------------------------------------------------------------*/
4318 /*-----------------------------------------------------------------*/
4319 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4320 {
4321   pCodeOpOpt *pcop;
4322
4323         pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4324         
4325         pcop->type = type;
4326         pcop->key = Safe_strdup( key );
4327
4328   return (PCOP(pcop));
4329 }
4330
4331 /*-----------------------------------------------------------------*/
4332 /*-----------------------------------------------------------------*/
4333 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4334 {
4335   pCodeOpLocalReg *pcop;
4336
4337         pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4338         
4339         pcop->type = type;
4340
4341   return (PCOP(pcop));
4342 }
4343
4344
4345 /*-----------------------------------------------------------------*/
4346 /*-----------------------------------------------------------------*/
4347
4348 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4349 {
4350   pCodeOp *pcop;
4351
4352   switch(type) {
4353   case PO_BIT:
4354   case PO_GPR_BIT:
4355     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4356     break;
4357
4358   case PO_LITERAL:
4359     pcop = pic16_newpCodeOpLit(-1);
4360     break;
4361
4362   case PO_LABEL:
4363     pcop = pic16_newpCodeOpLabel(NULL,-1);
4364     break;
4365   case PO_GPR_TEMP:
4366     pcop = pic16_newpCodeOpReg(-1);
4367     break;
4368
4369   case PO_GPR_REGISTER:
4370     if(name)
4371       pcop = pic16_newpCodeOpRegFromStr(name);
4372     else
4373       pcop = pic16_newpCodeOpReg(-1);
4374     break;
4375
4376   default:
4377     pcop = Safe_calloc(1,sizeof(pCodeOp) );
4378     pcop->type = type;
4379     if(name)
4380       pcop->name = Safe_strdup(name);   
4381     else
4382       pcop->name = NULL;
4383   }
4384
4385   return pcop;
4386 }
4387
4388 #define DB_ITEMS_PER_LINE       8
4389
4390 typedef struct DBdata
4391   {
4392     int count;
4393     char buffer[256];
4394   } DBdata;
4395
4396 struct DBdata DBd;
4397 static int DBd_init = -1;
4398
4399 /*-----------------------------------------------------------------*/
4400 /*    Initialiase "DB" data buffer                                 */
4401 /*-----------------------------------------------------------------*/
4402 void pic16_initDB(void)
4403 {
4404         DBd_init = -1;
4405 }
4406
4407
4408 /*-----------------------------------------------------------------*/
4409 /*    Flush pending "DB" data to a pBlock                          */
4410 /*                                                                 */
4411 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4412 /*-----------------------------------------------------------------*/
4413 void pic16_flushDB(char ptype, void *p)
4414 {
4415         if (DBd.count>0) {
4416                 if(ptype == 'p')
4417                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4418                 else
4419                 if(ptype == 'f')
4420                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4421                 else {
4422                         /* sanity check */
4423                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4424                 }
4425
4426                 DBd.count = 0;
4427                 DBd.buffer[0] = '\0';
4428         }
4429 }
4430
4431
4432 /*-----------------------------------------------------------------*/
4433 /*    Add "DB" directives to a pBlock                              */
4434 /*-----------------------------------------------------------------*/
4435 void pic16_emitDB(char c, char ptype, void *p)
4436 {
4437   int l;
4438
4439         if (DBd_init<0) {
4440          // we need to initialize
4441                 DBd_init = 0;
4442                 DBd.count = 0;
4443                 DBd.buffer[0] = '\0';
4444         }
4445
4446         l = strlen(DBd.buffer);
4447         sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4448
4449 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4450         
4451         DBd.count++;
4452         if (DBd.count>= DB_ITEMS_PER_LINE)
4453                 pic16_flushDB(ptype, p);
4454 }
4455
4456 void pic16_emitDS(char *s, char ptype, void *p)
4457 {
4458   int l;
4459
4460         if (DBd_init<0) {
4461          // we need to initialize
4462                 DBd_init = 0;
4463                 DBd.count = 0;
4464                 DBd.buffer[0] = '\0';
4465         }
4466
4467         l = strlen(DBd.buffer);
4468         sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4469
4470 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4471
4472         DBd.count++;    //=strlen(s);
4473         if (DBd.count>=16)
4474                 pic16_flushDB(ptype, p);
4475 }
4476
4477
4478 /*-----------------------------------------------------------------*/
4479 /*-----------------------------------------------------------------*/
4480 void pic16_pCodeConstString(char *name, char *value)
4481 {
4482   pBlock *pb;
4483
4484   //  fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4485
4486   if(!name || !value)
4487     return;
4488
4489   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4490
4491   pic16_addpBlock(pb);
4492
4493 //  sprintf(buffer,"; %s = ", name);
4494 //  strcat(buffer, value);
4495 //  fputs(buffer, stderr);
4496
4497 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4498   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4499
4500   do {
4501         pic16_emitDB(*value, 'p', (void *)pb);
4502   }while (*value++);
4503   pic16_flushDB('p', (void *)pb);
4504 }
4505
4506 /*-----------------------------------------------------------------*/
4507 /*-----------------------------------------------------------------*/
4508 #if 0
4509 static void pCodeReadCodeTable(void)
4510 {
4511   pBlock *pb;
4512
4513   fprintf(stderr, " %s\n",__FUNCTION__);
4514
4515   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4516
4517   pic16_addpBlock(pb);
4518
4519   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4520   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4521   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4522   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4523
4524   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4525   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4526   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4527   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4528
4529
4530 }
4531 #endif
4532 /*-----------------------------------------------------------------*/
4533 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4534 /*-----------------------------------------------------------------*/
4535 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4536 {
4537
4538   if(!pc)
4539     return;
4540
4541   if(!pb->pcHead) {
4542     /* If this is the first pcode to be added to a block that
4543      * was initialized with a NULL pcode, then go ahead and
4544      * make this pcode the head and tail */
4545     pb->pcHead  = pb->pcTail = pc;
4546   } else {
4547     //    if(pb->pcTail)
4548     pb->pcTail->next = pc;
4549
4550     pc->prev = pb->pcTail;
4551     pc->pb = pb;
4552
4553     pb->pcTail = pc;
4554   }
4555 }
4556
4557 /*-----------------------------------------------------------------*/
4558 /* pic16_addpBlock - place a pBlock into the pFile                 */
4559 /*-----------------------------------------------------------------*/
4560 void pic16_addpBlock(pBlock *pb)
4561 {
4562   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4563
4564   if(!the_pFile) {
4565     /* First time called, we'll pass through here. */
4566     //_ALLOC(the_pFile,sizeof(pFile));
4567     the_pFile = Safe_calloc(1,sizeof(pFile));
4568     the_pFile->pbHead = the_pFile->pbTail = pb;
4569     the_pFile->functions = NULL;
4570     return;
4571   }
4572
4573   the_pFile->pbTail->next = pb;
4574   pb->prev = the_pFile->pbTail;
4575   pb->next = NULL;
4576   the_pFile->pbTail = pb;
4577 }
4578
4579 /*-----------------------------------------------------------------*/
4580 /* removepBlock - remove a pBlock from the pFile                   */
4581 /*-----------------------------------------------------------------*/
4582 static void removepBlock(pBlock *pb)
4583 {
4584   pBlock *pbs;
4585
4586   if(!the_pFile)
4587     return;
4588
4589
4590   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4591
4592   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4593     if(pbs == pb) {
4594
4595       if(pbs == the_pFile->pbHead)
4596         the_pFile->pbHead = pbs->next;
4597
4598       if (pbs == the_pFile->pbTail) 
4599         the_pFile->pbTail = pbs->prev;
4600
4601       if(pbs->next)
4602         pbs->next->prev = pbs->prev;
4603
4604       if(pbs->prev)
4605         pbs->prev->next = pbs->next;
4606
4607       return;
4608
4609     }
4610   }
4611
4612   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4613
4614 }
4615
4616 /*-----------------------------------------------------------------*/
4617 /* printpCode - write the contents of a pCode to a file            */
4618 /*-----------------------------------------------------------------*/
4619 static void printpCode(FILE *of, pCode *pc)
4620 {
4621
4622   if(!pc || !of)
4623     return;
4624
4625   if(pc->print) {
4626     pc->print(of,pc);
4627     return;
4628   }
4629
4630   fprintf(of,"warning - unable to print pCode\n");
4631 }
4632
4633 /*-----------------------------------------------------------------*/
4634 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4635 /*-----------------------------------------------------------------*/
4636 void pic16_printpBlock(FILE *of, pBlock *pb)
4637 {
4638   pCode *pc;
4639
4640         if(!pb)return;
4641
4642         if(!of)of=stderr;
4643
4644         for(pc = pb->pcHead; pc; pc = pc->next) {
4645                 if(isPCF(pc) && PCF(pc)->fname) {
4646                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4647                         if(pb->dbName == 'A') {
4648                           absSym *ab;
4649                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4650 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4651                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4652 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4653                                                 if(ab->address != -1)
4654                                                   fprintf(of, "\t0X%06X", ab->address);
4655                                                 break;
4656                                         }
4657                                 }
4658                         }
4659                         fprintf(of, "\n");
4660                 }
4661                 printpCode(of,pc);
4662         }
4663 }
4664
4665 /*-----------------------------------------------------------------*/
4666 /*                                                                 */
4667 /*       pCode processing                                          */
4668 /*                                                                 */
4669 /*                                                                 */
4670 /*                                                                 */
4671 /*-----------------------------------------------------------------*/
4672 pCode * pic16_findNextInstruction(pCode *pci);
4673 pCode * pic16_findPrevInstruction(pCode *pci);
4674
4675 void pic16_unlinkpCode(pCode *pc)
4676 {
4677   pCode *prev;
4678
4679   if(pc) {
4680 #ifdef PCODE_DEBUG
4681     fprintf(stderr,"Unlinking: ");
4682     printpCode(stderr, pc);
4683 #endif
4684     if(pc->prev) 
4685       pc->prev->next = pc->next;
4686     if(pc->next)
4687       pc->next->prev = pc->prev;
4688
4689     /* move C source line down (or up) */
4690     if (isPCI(pc) && PCI(pc)->cline) {
4691       prev = pic16_findNextInstruction (pc->next);
4692       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4693         PCI(prev)->cline = PCI(pc)->cline;
4694       } else {
4695         prev = pic16_findPrevInstruction (pc->prev);
4696         if (prev && isPCI(prev) && !PCI(prev)->cline)
4697           PCI(prev)->cline = PCI(pc)->cline;
4698       }
4699     }
4700     pc->prev = pc->next = NULL;
4701   }
4702 }
4703
4704 /*-----------------------------------------------------------------*/
4705 /*-----------------------------------------------------------------*/
4706
4707 static void genericDestruct(pCode *pc)
4708 {
4709
4710   pic16_unlinkpCode(pc);
4711
4712   if(isPCI(pc)) {
4713     /* For instructions, tell the register (if there's one used)
4714      * that it's no longer needed */
4715     regs *reg = pic16_getRegFromInstruction(pc);
4716     if(reg)
4717       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4718
4719         if(PCI(pc)->is2MemOp) {
4720                 reg = pic16_getRegFromInstruction2(pc);
4721                 if(reg)
4722                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4723         }
4724   }
4725
4726   /* Instead of deleting the memory used by this pCode, mark
4727    * the object as bad so that if there's a pointer to this pCode
4728    * dangling around somewhere then (hopefully) when the type is
4729    * checked we'll catch it.
4730    */
4731
4732   pc->type = PC_BAD;
4733   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4734
4735   //Safe_free(pc);
4736 }
4737
4738
4739 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4740 /*-----------------------------------------------------------------*/
4741 /*-----------------------------------------------------------------*/
4742 /* modifiers for constant immediate */
4743 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4744
4745 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4746 {
4747   regs *r;
4748   static char b[128];
4749   char *s;
4750   int use_buffer = 1;    // copy the string to the passed buffer pointer
4751
4752         if(!buffer) {
4753                 buffer = b;
4754                 size = sizeof(b);
4755                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4756         } 
4757
4758         if(pcop) {
4759                 switch(pcop->type) {
4760                         case PO_W:
4761                         case PO_WREG:
4762                         case PO_PRODL:
4763                         case PO_PRODH:
4764                         case PO_INDF0:
4765                         case PO_FSR0:
4766                                 if(use_buffer) {
4767                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4768                                         return buffer;
4769                                 }
4770                                 return PCOR(pcop)->r->name;
4771                                 break;
4772                         case PO_GPR_TEMP:
4773                                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4774                                 if(use_buffer) {
4775                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4776                                         return buffer;
4777                                 }
4778                                 return r->name;
4779
4780                         case PO_IMMEDIATE:
4781                                 s = buffer;
4782                                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4783                                         if(PCOI(pcop)->index) {
4784                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4785                                                         immdmod[ PCOI(pcop)->offset ],
4786                                                         pcop->name,
4787                                                         PCOI(pcop)->index);
4788                                         } else {
4789                                                 SAFE_snprintf(&s,&size,"%s(%s)",
4790                                                         immdmod[ PCOI(pcop)->offset ],
4791                                                         pcop->name);
4792                                         }
4793                                 } else {
4794                                         if(PCOI(pcop)->index) {
4795                                                 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4796                                                         immdmod[ 0 ],
4797                                                         pcop->name,
4798                                                         PCOI(pcop)->index);
4799                                         } else {
4800                                                 SAFE_snprintf(&s,&size, "%s(%s)",
4801                                                         immdmod[ 0 ],
4802                                                         pcop->name);
4803                                         }
4804                                 }
4805                                 return buffer;
4806
4807                         case PO_GPR_REGISTER:
4808                         case PO_DIR:
4809                                 s = buffer;
4810 //                              size = sizeof(buffer);
4811                                 if( PCOR(pcop)->instance) {
4812                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4813                                                 pcop->name,
4814                                                 PCOR(pcop)->instance );
4815                                 } else {
4816                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4817                                 }
4818                                 return buffer;
4819                         case PO_GPR_BIT:
4820                                 s = buffer;
4821                                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4822                                         SAFE_snprintf(&s, &size, "%s", pcop->name);
4823                                 } else {
4824                                         if(PCORB(pcop)->pcor.instance)
4825                                                 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4826                                         else
4827                                                 SAFE_snprintf(&s, &size, "%s", pcop->name);
4828                                 }
4829
4830                                 return (buffer);
4831                         default:
4832                                 if(pcop->name) {
4833                                         if(use_buffer) {
4834                                                 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4835                                                 return buffer;
4836                                         }
4837                                 return pcop->name;
4838                                 }
4839
4840                 }
4841         }
4842
4843   return "NO operand1";
4844 }
4845
4846 /*-----------------------------------------------------------------*/
4847 /* pic16_get_op2 - variant to support two memory operand commands  */
4848 /*-----------------------------------------------------------------*/
4849 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4850 {
4851   regs *r;
4852   static char b[128];
4853   char *s;
4854   int use_buffer = 1;    // copy the string to the passed buffer pointer
4855
4856         if(!buffer) {
4857                 buffer = b;
4858                 size = sizeof(b);
4859                 use_buffer = 0;     // Don't bother copying the string to the buffer.
4860         } 
4861
4862 #if 0
4863         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",
4864                 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4865                 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4866 #endif
4867
4868         if(pcop) {
4869                 switch(PCOR2(pcop)->pcop2->type) {
4870                         case PO_W:
4871                         case PO_WREG:
4872                         case PO_PRODL:
4873                         case PO_PRODH:
4874                         case PO_INDF0:
4875                         case PO_FSR0:
4876                                 if(use_buffer) {
4877                                         SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4878                                         return buffer;
4879                                 }
4880                                 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4881                                 break;
4882                         case PO_GPR_TEMP:
4883                                 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4884
4885                                 if(use_buffer) {
4886                                         SAFE_snprintf(&buffer,&size,"%s",r->name);
4887                                         return buffer;
4888                                 }
4889                                 return r->name;
4890
4891                         case PO_IMMEDIATE:
4892                                         assert( 0 );
4893                                 break;
4894 #if 0
4895                                 s = buffer;
4896
4897                                 if(PCOI(pcop)->_const) {
4898                                         if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4899                                                 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4900                                                         pcop->name,
4901                                                         PCOI(pcop)->index,
4902                                                         8 * PCOI(pcop)->offset );
4903                                         } else
4904                                                 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4905                                 } else {
4906                                         if( PCOI(pcop)->index) {
4907                                                 SAFE_snprintf(&s,&size,"(%s + %d)",
4908                                                         pcop->name,
4909                                                         PCOI(pcop)->index );
4910                                         } else {
4911                                                 if(PCOI(pcop)->offset)
4912                                                         SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4913                                                 else
4914                                                         SAFE_snprintf(&s,&size,"%s",pcop->name);
4915                                         }
4916                                 }
4917                                 return buffer;
4918 #endif
4919                         case PO_DIR:
4920                                 s = buffer;
4921                                 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4922                                         SAFE_snprintf(&s,&size,"(%s + %d)",
4923                                                 PCOR(PCOR2(pcop)->pcop2)->r->name,
4924                                                 PCOR(PCOR2(pcop)->pcop2)->instance );
4925                                 } else {
4926                                         SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4927                                 }
4928                                 return buffer;
4929
4930                         default:
4931                                 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4932                                         if(use_buffer) {
4933                                                 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4934                                                 return buffer;
4935                                         }
4936                                         return PCOR(PCOR2(pcop)->pcop2)->r->name;
4937                                 }
4938                 }
4939         }
4940
4941   return "NO operand2";
4942 }
4943
4944 /*-----------------------------------------------------------------*/
4945 /*-----------------------------------------------------------------*/
4946 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4947 {
4948
4949   if(pcc )
4950     return pic16_get_op(pcc->pcop,NULL,0);
4951
4952   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated 
4953    *   return ("ERROR Null: "__FUNCTION__);
4954    */
4955   return ("ERROR Null: pic16_get_op_from_instruction");
4956
4957 }
4958
4959 /*-----------------------------------------------------------------*/
4960 /*-----------------------------------------------------------------*/
4961 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4962 {
4963
4964   fprintf(of,"pcodeopprint- not implemented\n");
4965 }
4966
4967 /*-----------------------------------------------------------------*/
4968 /* pic16_pCode2str - convert a pCode instruction to string               */
4969 /*-----------------------------------------------------------------*/
4970 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4971 {
4972   char *s = str;
4973   regs *r;
4974
4975 #if 0
4976         if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4977                 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4978                         __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
4979 //              exit(-1);
4980         }
4981 #endif
4982
4983   switch(pc->type) {
4984
4985   case PC_OPCODE:
4986     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
4987
4988     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
4989
4990         if(PCI(pc)->is2MemOp) {
4991                 SAFE_snprintf(&s,&size, "%s, %s", 
4992                 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
4993                 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
4994                 break;
4995         }
4996
4997         if(PCI(pc)->is2LitOp) {
4998                 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
4999                 break;
5000         }
5001
5002       if(PCI(pc)->isBitInst) {
5003         if(PCI(pc)->pcop->type != PO_GPR_BIT) {
5004           if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
5005             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
5006                           PCI(pc)->pcop->name ,
5007                           PCI(pc)->pcop->name );
5008           else
5009             SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5010 //                        (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5011                           (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5012                           
5013         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5014           SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5015         } else
5016           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5017         //PCI(pc)->pcop->t.bit );
5018       } else {
5019
5020         if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5021           if( PCI(pc)->num_ops == 3)
5022             SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5023           else
5024             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5025
5026         }
5027         else 
5028         {
5029           SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5030         }
5031       }
5032         if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5033           if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5034             SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5035
5036           r = pic16_getRegFromInstruction(pc);
5037 //              fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5038 //                      __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5039
5040           if(PCI(pc)->isAccess) {
5041             static char *bank_spec[2][2] = {
5042               { "", ", ACCESS" },  /* gpasm uses access bank by default */
5043               { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5044             };
5045              
5046             SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !r->accessBank) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5047           }
5048         }
5049 //      
5050
5051     }
5052     break;
5053
5054   case PC_COMMENT:
5055     /* assuming that comment ends with a \n */
5056     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5057     break;
5058
5059   case PC_INFO:
5060     SAFE_snprintf(&s,&size,"; info ==>");
5061     switch( PCINF(pc)->type ) {
5062       case INF_OPTIMIZATION:
5063           SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5064           break;
5065       case INF_LOCALREGS:
5066           SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5067           break;
5068     }; break;
5069
5070   case PC_INLINE:
5071     /* assuming that inline code ends with a \n */
5072     SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5073     break;
5074
5075   case PC_LABEL:
5076     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5077     break;
5078   case PC_FUNCTION:
5079     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5080     break;
5081   case PC_WILD:
5082     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5083     break;
5084   case PC_FLOW:
5085     SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5086     break;
5087   case PC_CSOURCE:
5088 //    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5089       SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5090         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5091     break;
5092   case PC_ASMDIR:
5093         if(PCAD(pc)->directive) {
5094                 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5095         } else
5096         if(PCAD(pc)->arg) {
5097                 /* special case to handle inline labels without a tab */
5098                 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5099         }
5100         break;
5101
5102   case PC_BAD:
5103     SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5104     break;
5105   }
5106
5107   return str;
5108
5109 }
5110
5111 /*-----------------------------------------------------------------*/
5112 /* genericPrint - the contents of a pCode to a file                */
5113 /*-----------------------------------------------------------------*/
5114 static void genericPrint(FILE *of, pCode *pc)
5115 {
5116
5117   if(!pc || !of)
5118     return;
5119
5120   switch(pc->type) {
5121   case PC_COMMENT:
5122 //    fputs(((pCodeComment *)pc)->comment, of);
5123     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5124     break;
5125
5126   case PC_INFO:
5127     {
5128       pBranch *pbl = PCI(pc)->label;
5129       while(pbl && pbl->pc) {
5130         if(pbl->pc->type == PC_LABEL)
5131           pCodePrintLabel(of, pbl->pc);
5132         pbl = pbl->next;
5133       }
5134     }
5135           
5136     if(pic16_pcode_verbose) {
5137       fprintf(of, "; info ==>");
5138       switch(((pCodeInfo *)pc)->type) {
5139         case INF_OPTIMIZATION:
5140               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5141               break;
5142         case INF_LOCALREGS:
5143               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5144               break;
5145         }
5146     };
5147     
5148     break;
5149
5150   case PC_INLINE:
5151     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5152      break;
5153
5154   case PC_OPCODE:
5155     // If the opcode has a label, print that first
5156     {
5157       pBranch *pbl = PCI(pc)->label;
5158       while(pbl && pbl->pc) {
5159         if(pbl->pc->type == PC_LABEL)
5160           pCodePrintLabel(of, pbl->pc);
5161         pbl = pbl->next;
5162       }
5163     }
5164
5165     if(PCI(pc)->cline) 
5166       genericPrint(of,PCODE(PCI(pc)->cline));
5167
5168     {
5169       char str[256];
5170       
5171       pic16_pCode2str(str, 256, pc);
5172
5173       fprintf(of,"%s",str);
5174       /* Debug */
5175       if(pic16_debug_verbose) {
5176         fprintf(of, "\t;key=%03x",pc->seq);
5177         if(PCI(pc)->pcflow)
5178           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5179       }
5180     }
5181     fprintf(of, "\n");
5182     break;
5183       
5184   case PC_WILD:
5185     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5186     if(PCW(pc)->pci.label)
5187       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5188
5189     if(PCW(pc)->operand) {
5190       fprintf(of,";\toperand  ");
5191       pCodeOpPrint(of,PCW(pc)->operand );
5192     }
5193     break;
5194
5195   case PC_FLOW:
5196     if(pic16_debug_verbose) {
5197       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5198       if(PCFL(pc)->ancestor)
5199         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5200       fprintf(of,"\n");
5201
5202     }
5203     break;
5204
5205   case PC_CSOURCE:
5206 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5207     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5208         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5209          
5210     break;
5211
5212   case PC_ASMDIR:
5213         {
5214           pBranch *pbl = PCAD(pc)->pci.label;
5215                 while(pbl && pbl->pc) {
5216                         if(pbl->pc->type == PC_LABEL)
5217                                 pCodePrintLabel(of, pbl->pc);
5218                         pbl = pbl->next;
5219                 }
5220         }
5221         if(PCAD(pc)->directive) {
5222                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5223         } else
5224         if(PCAD(pc)->arg) {
5225                 /* special case to handle inline labels without tab */
5226                 fprintf(of, "%s\n", PCAD(pc)->arg);
5227         }
5228         break;
5229         
5230   case PC_LABEL:
5231   default:
5232     fprintf(of,"unknown pCode type %d\n",pc->type);
5233   }
5234
5235 }
5236
5237 /*-----------------------------------------------------------------*/
5238 /* pCodePrintFunction - prints function begin/end                  */
5239 /*-----------------------------------------------------------------*/
5240
5241 static void pCodePrintFunction(FILE *of, pCode *pc)
5242 {
5243
5244   if(!pc || !of)
5245     return;
5246
5247 #if 0
5248   if( ((pCodeFunction *)pc)->modname) 
5249     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5250 #endif
5251
5252   if(!PCF(pc)->absblock) {
5253       if(PCF(pc)->fname) {
5254       pBranch *exits = PCF(pc)->to;
5255       int i=0;
5256
5257       fprintf(of,"%s:", PCF(pc)->fname);
5258     
5259       if(pic16_pcode_verbose)
5260         fprintf(of, "\t;Function start");
5261     
5262       fprintf(of, "\n");
5263     
5264       while(exits) {
5265         i++;
5266         exits = exits->next;
5267       }
5268       //if(i) i--;
5269
5270       if(pic16_pcode_verbose)
5271         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5272     
5273     } else {
5274         if((PCF(pc)->from && 
5275                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5276                 PCF(PCF(pc)->from->pc)->fname) ) {
5277
5278                 if(pic16_pcode_verbose)
5279                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5280         } else {
5281                 if(pic16_pcode_verbose)
5282                         fprintf(of,"; exit point [can't find entry point]\n");
5283         }
5284         fprintf(of, "\n");
5285     }
5286   }
5287 }
5288 /*-----------------------------------------------------------------*/
5289 /* pCodePrintLabel - prints label                                  */
5290 /*-----------------------------------------------------------------*/
5291
5292 static void pCodePrintLabel(FILE *of, pCode *pc)
5293 {
5294
5295   if(!pc || !of)
5296     return;
5297
5298   if(PCL(pc)->label) 
5299     fprintf(of,"%s:\n",PCL(pc)->label);
5300   else if (PCL(pc)->key >=0) 
5301     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5302   else
5303     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5304
5305 }
5306 /*-----------------------------------------------------------------*/
5307 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5308 /*                         remove it if it is found.               */
5309 /*-----------------------------------------------------------------*/
5310 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5311 {
5312   pBranch *b, *bprev;
5313
5314
5315   bprev = NULL;
5316
5317   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5318     b = PCI(pcl)->label;
5319   else {
5320     fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5321     exit(1);
5322
5323   }
5324
5325   //fprintf (stderr, "%s \n",__FUNCTION__);
5326   //pcl->print(stderr,pcl);
5327   //pc->print(stderr,pc);
5328   while(b) {
5329     if(b->pc == pc) {
5330       //fprintf (stderr, "found label\n");
5331       //pc->print(stderr, pc);
5332
5333       /* Found a label */
5334       if(bprev) {
5335         bprev->next = b->next;  /* Not first pCode in chain */
5336 //      Safe_free(b);
5337       } else {
5338         pc->destruct(pc);
5339         PCI(pcl)->label = b->next;   /* First pCode in chain */
5340 //      Safe_free(b);
5341       }
5342       return;  /* A label can't occur more than once */
5343     }
5344     bprev = b;
5345     b = b->next;
5346   }
5347
5348 }
5349
5350 /*-----------------------------------------------------------------*/
5351 /*-----------------------------------------------------------------*/
5352 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5353 {
5354   pBranch *b;
5355
5356   if(!h)
5357     return n;
5358
5359   if(h == n)
5360     return n;
5361
5362   b = h;
5363   while(b->next)
5364     b = b->next;
5365
5366   b->next = n;
5367
5368   return h;
5369   
5370 }  
5371 /*-----------------------------------------------------------------*/
5372 /* pBranchLink - given two pcodes, this function will link them    */
5373 /*               together through their pBranches                  */
5374 /*-----------------------------------------------------------------*/
5375 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5376 {
5377   pBranch *b;
5378
5379   // Declare a new branch object for the 'from' pCode.
5380
5381   //_ALLOC(b,sizeof(pBranch));
5382   b = Safe_calloc(1,sizeof(pBranch));
5383   b->pc = PCODE(t);             // The link to the 'to' pCode.
5384   b->next = NULL;
5385
5386   f->to = pic16_pBranchAppend(f->to,b);
5387
5388   // Now do the same for the 'to' pCode.
5389
5390   //_ALLOC(b,sizeof(pBranch));
5391   b = Safe_calloc(1,sizeof(pBranch));
5392   b->pc = PCODE(f);
5393   b->next = NULL;
5394
5395   t->from = pic16_pBranchAppend(t->from,b);
5396   
5397 }
5398
5399 #if 1
5400 /*-----------------------------------------------------------------*/
5401 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5402 /*               a pCode                                           */
5403 /*-----------------------------------------------------------------*/
5404 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5405 {
5406   while(pb) {
5407
5408     if(pb->pc == pc)
5409       return pb;
5410
5411     pb = pb->next;
5412   }
5413
5414   return NULL;
5415 }
5416
5417 /*-----------------------------------------------------------------*/
5418 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5419 /*-----------------------------------------------------------------*/
5420 void pic16_pCodeUnlink(pCode *pc)
5421 {
5422   pBranch *pb1,*pb2;
5423   pCode *pc1;
5424
5425   if(!pc->prev || !pc->next) {
5426     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5427     exit(1);
5428   }
5429   
5430   /* move C source line down (or up) */
5431   if (isPCI(pc) && PCI(pc)->cline) {
5432     pc1 = pic16_findNextInstruction (pc->next);
5433     if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5434       PCI(pc1)->cline = PCI(pc)->cline;
5435     } else {
5436       pc1 = pic16_findPrevInstruction (pc->prev);
5437       if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5438         PCI(pc1)->cline = PCI(pc)->cline;
5439     }
5440   }
5441
5442   /* first remove the pCode from the chain */
5443   pc->prev->next = pc->next;
5444   pc->next->prev = pc->prev;
5445
5446   pc->prev = pc->next = NULL;
5447
5448   /* Now for the hard part... */
5449
5450   /* Remove the branches */
5451
5452   pb1 = PCI(pc)->from;
5453   while(pb1) {
5454     pc1 = pb1->pc;    /* Get the pCode that branches to the
5455                        * one we're unlinking */
5456
5457     /* search for the link back to this pCode (the one we're
5458      * unlinking) */
5459     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5460       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5461
5462       /* if the pCode we're unlinking contains multiple 'to'
5463        * branches (e.g. this a skip instruction) then we need
5464        * to copy these extra branches to the chain. */
5465       if(PCI(pc)->to->next)
5466         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5467     }
5468     
5469     pb1 = pb1->next;
5470   }
5471
5472
5473 }
5474 #endif
5475 /*-----------------------------------------------------------------*/
5476 /*-----------------------------------------------------------------*/
5477 #if 0
5478 static void genericAnalyze(pCode *pc)
5479 {
5480   switch(pc->type) {
5481   case PC_WILD:
5482   case PC_COMMENT:
5483     return;
5484   case PC_LABEL:
5485   case PC_FUNCTION:
5486   case PC_OPCODE:
5487     {
5488       // Go through the pCodes that are in pCode chain and link
5489       // them together through the pBranches. Note, the pCodes
5490       // are linked together as a contiguous stream like the 
5491       // assembly source code lines. The linking here mimics this
5492       // except that comments are not linked in.
5493       // 
5494       pCode *npc = pc->next;
5495       while(npc) {
5496         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5497           pBranchLink(pc,npc);
5498           return;
5499         } else
5500           npc = npc->next;
5501       }
5502       /* reached the end of the pcode chain without finding
5503        * an instruction we could link to. */
5504     }
5505     break;
5506   case PC_FLOW:
5507     fprintf(stderr,"analyze PC_FLOW\n");
5508
5509     return;
5510   case PC_BAD:
5511     fprintf(stderr,,";A bad pCode is being used\n");
5512
5513   }
5514 }
5515 #endif
5516
5517 /*-----------------------------------------------------------------*/
5518 /*-----------------------------------------------------------------*/
5519 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5520 {
5521   pBranch *pbr;
5522
5523   if(pc->type == PC_LABEL) {
5524     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
5525       return TRUE;
5526   }
5527   if((pc->type == PC_OPCODE)
5528         || (pc->type == PC_ASMDIR)
5529         ) {
5530     pbr = PCI(pc)->label;
5531     while(pbr) {
5532       if(pbr->pc->type == PC_LABEL) {
5533         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
5534           return TRUE;
5535       }
5536       pbr = pbr->next;
5537     }
5538   }
5539
5540   return FALSE;
5541 }
5542
5543 /*-----------------------------------------------------------------*/
5544 /*-----------------------------------------------------------------*/
5545 static int checkLabel(pCode *pc)
5546 {
5547   pBranch *pbr;
5548
5549   if(pc && isPCI(pc)) {
5550     pbr = PCI(pc)->label;
5551     while(pbr) {
5552       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5553         return TRUE;
5554
5555       pbr = pbr->next;
5556     }
5557   }
5558
5559   return FALSE;
5560 }
5561
5562 /*-----------------------------------------------------------------*/
5563 /* findLabelinpBlock - Search the pCode for a particular label     */
5564 /*-----------------------------------------------------------------*/
5565 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5566 {
5567   pCode  *pc;
5568
5569   if(!pb)
5570     return NULL;
5571
5572   for(pc = pb->pcHead; pc; pc = pc->next) 
5573     if(compareLabel(pc,pcop_label))
5574       return pc;
5575     
5576   return NULL;
5577 }
5578 #if 0
5579 /*-----------------------------------------------------------------*/
5580 /* findLabel - Search the pCode for a particular label             */
5581 /*-----------------------------------------------------------------*/
5582 static pCode * findLabel(pCodeOpLabel *pcop_label)
5583 {
5584   pBlock *pb;
5585   pCode  *pc;
5586
5587   if(!the_pFile)
5588     return NULL;
5589
5590   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5591     if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5592       return pc;
5593   }
5594
5595   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5596   return NULL;
5597 }
5598 #endif
5599 /*-----------------------------------------------------------------*/
5600 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5601 /*                 in the linked list                              */
5602 /*-----------------------------------------------------------------*/
5603 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5604 {
5605
5606   while(pc) {
5607     if(pc->type == pct)
5608       return pc;
5609
5610     pc = pc->next;
5611   }
5612
5613   return NULL;
5614 }
5615
5616 /*-----------------------------------------------------------------*/
5617 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5618 /*                 in the linked list                              */
5619 /*-----------------------------------------------------------------*/
5620 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5621 {
5622
5623   while(pc) {
5624     if(pc->type == pct)
5625       return pc;
5626
5627     pc = pc->prev;
5628   }
5629
5630   return NULL;
5631 }
5632
5633
5634 //#define PCODE_DEBUG
5635 /*-----------------------------------------------------------------*/
5636 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5637 /*                       in the linked list                        */
5638 /*-----------------------------------------------------------------*/
5639 pCode * pic16_findNextInstruction(pCode *pci)
5640 {
5641   pCode *pc = pci;
5642
5643   while(pc) {
5644     if((pc->type == PC_OPCODE)
5645         || (pc->type == PC_WILD)
5646         || (pc->type == PC_ASMDIR)
5647         )
5648       return pc;
5649
5650 #ifdef PCODE_DEBUG
5651     fprintf(stderr,"pic16_findNextInstruction:  ");
5652     printpCode(stderr, pc);
5653 #endif
5654     pc = pc->next;
5655   }
5656
5657   //fprintf(stderr,"Couldn't find instruction\n");
5658   return NULL;
5659 }
5660
5661 /*-----------------------------------------------------------------*/
5662 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5663 /*                       in the linked list                        */
5664 /*-----------------------------------------------------------------*/
5665 pCode * pic16_findPrevInstruction(pCode *pci)
5666 {
5667   pCode *pc = pci;
5668
5669   while(pc) {
5670
5671     if((pc->type == PC_OPCODE)
5672         || (pc->type == PC_WILD)
5673         || (pc->type == PC_ASMDIR)
5674         )
5675       return pc;
5676       
5677
5678 #ifdef PCODE_DEBUG
5679     fprintf(stderr,"pic16_findPrevInstruction:  ");
5680     printpCode(stderr, pc);
5681 #endif
5682     pc = pc->prev;
5683   }
5684
5685   //fprintf(stderr,"Couldn't find instruction\n");
5686   return NULL;
5687 }
5688
5689 #undef PCODE_DEBUG
5690
5691 #if 0
5692 /*-----------------------------------------------------------------*/
5693 /* findFunctionEnd - given a pCode find the end of the function    */
5694 /*                   that contains it                              */
5695 /*-----------------------------------------------------------------*/
5696 static pCode * findFunctionEnd(pCode *pc)
5697 {
5698
5699   while(pc) {
5700     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5701       return pc;
5702
5703     pc = pc->next;
5704   }
5705
5706   fprintf(stderr,"Couldn't find function end\n");
5707   return NULL;
5708 }
5709 #endif
5710 #if 0
5711 /*-----------------------------------------------------------------*/
5712 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5713 /*                instruction with which it is associated.         */
5714 /*-----------------------------------------------------------------*/
5715 static void AnalyzeLabel(pCode *pc)
5716 {
5717
5718   pic16_pCodeUnlink(pc);
5719
5720 }
5721 #endif
5722
5723 #if 0
5724 static void AnalyzeGOTO(pCode *pc)
5725 {
5726
5727   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5728
5729 }
5730
5731 static void AnalyzeSKIP(pCode *pc)
5732 {
5733
5734   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5735   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5736
5737 }
5738
5739 static void AnalyzeRETURN(pCode *pc)
5740 {
5741
5742   //  branch_link(pc,findFunctionEnd(pc->next));
5743
5744 }
5745
5746 #endif
5747
5748 /*-------------------------------------------------------------------*/
5749 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5750 /*                            if one is present. This is the common  */
5751 /*                            part of pic16_getRegFromInstruction(2) */
5752 /*-------------------------------------------------------------------*/
5753
5754 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5755   if (!pcop) return NULL;
5756   
5757   switch(pcop->type) {
5758   case PO_PRODL:
5759   case PO_PRODH:
5760   case PO_INDF0:
5761   case PO_FSR0:
5762   case PO_W:
5763   case PO_WREG:
5764   case PO_STATUS:
5765   case PO_INTCON:
5766   case PO_PCL:
5767   case PO_PCLATH:
5768   case PO_PCLATU:
5769   case PO_BSR:
5770     return PCOR(pcop)->r;
5771
5772   case PO_SFR_REGISTER:
5773     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5774     return PCOR(pcop)->r;
5775
5776   case PO_BIT:
5777   case PO_GPR_TEMP:
5778 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5779     return PCOR(pcop)->r;
5780
5781   case PO_IMMEDIATE:
5782 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5783
5784     if(PCOI(pcop)->r)
5785       return (PCOI(pcop)->r);
5786     else
5787       return NULL;
5788     
5789   case PO_GPR_BIT:
5790     return PCOR(pcop)->r;
5791
5792   case PO_GPR_REGISTER:
5793   case PO_DIR:
5794 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5795     return PCOR(pcop)->r;
5796
5797   case PO_LITERAL:
5798     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5799     break;
5800
5801   case PO_REL_ADDR:
5802   case PO_LABEL:
5803     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5804     break;
5805     
5806   case PO_CRY:
5807   case PO_STR:
5808     /* this should never turn up */
5809     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5810     break;
5811     
5812   case PO_WILD:
5813     break;
5814     
5815   default:
5816         fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5817 //      assert( 0 );
5818         break;
5819   }
5820
5821   return NULL;
5822 }
5823
5824 /*-----------------------------------------------------------------*/
5825 /*-----------------------------------------------------------------*/
5826 regs * pic16_getRegFromInstruction(pCode *pc)
5827 {
5828
5829   if(!pc                   || 
5830      !isPCI(pc)            ||
5831      !PCI(pc)->pcop        ||
5832      PCI(pc)->num_ops == 0 ||
5833      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5834     return NULL;
5835
5836 #if 0
5837   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5838         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5839 #endif
5840
5841   return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5842 }
5843
5844 /*-------------------------------------------------------------------------------*/
5845 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5846 /*-------------------------------------------------------------------------------*/
5847 regs * pic16_getRegFromInstruction2(pCode *pc)
5848 {
5849
5850   if(!pc                   || 
5851      !isPCI(pc)            ||
5852      !PCI(pc)->pcop        ||
5853      PCI(pc)->num_ops == 0 ||
5854      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5855     return NULL;
5856
5857
5858 #if 0
5859   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5860         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5861 #endif
5862
5863   return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5864 }
5865
5866 /*-----------------------------------------------------------------*/
5867 /*-----------------------------------------------------------------*/
5868
5869 static void AnalyzepBlock(pBlock *pb)
5870 {
5871   pCode *pc;
5872
5873   if(!pb)
5874     return;
5875
5876   /* Find all of the registers used in this pBlock 
5877    * by looking at each instruction and examining it's
5878    * operands
5879    */
5880   for(pc = pb->pcHead; pc; pc = pc->next) {
5881
5882     /* Is this an instruction with operands? */
5883     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5884
5885       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5886
5887         /* Loop through all of the registers declared so far in
5888            this block and see if we find this one there */
5889
5890         regs *r = setFirstItem(pb->tregisters);
5891
5892         while(r) {
5893           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5894             PCOR(PCI(pc)->pcop)->r = r;
5895             break;
5896           }
5897           r = setNextItem(pb->tregisters);
5898         }
5899
5900         if(!r) {
5901           /* register wasn't found */
5902           //r = Safe_calloc(1, sizeof(regs));
5903           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5904           //addSet(&pb->tregisters, r);
5905           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5906           //PCOR(PCI(pc)->pcop)->r = r;
5907           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5908         }/* else 
5909           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5910          */
5911       }
5912       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5913         if(PCOR(PCI(pc)->pcop)->r) {
5914           pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
5915           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5916         } else {
5917           if(PCI(pc)->pcop->name)
5918             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5919           else
5920             fprintf(stderr,"ERROR: NULL register\n");
5921         }
5922       }
5923     }
5924
5925
5926   }
5927 }
5928
5929 /*-----------------------------------------------------------------*/
5930 /* */
5931 /*-----------------------------------------------------------------*/
5932 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5933
5934 static void InsertpFlow(pCode *pc, pCode **pflow)
5935 {
5936   if(*pflow)
5937     PCFL(*pflow)->end = pc;
5938
5939   if(!pc || !pc->next)
5940     return;
5941
5942   *pflow = pic16_newpCodeFlow();
5943   pic16_pCodeInsertAfter(pc, *pflow);
5944 }
5945
5946 /*-----------------------------------------------------------------*/
5947 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5948 /*                         the flow blocks.                        */
5949 /*
5950  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5951  * point the instruction flow changes. 
5952  */
5953 /*-----------------------------------------------------------------*/
5954 void pic16_BuildFlow(pBlock *pb)
5955 {
5956   pCode *pc;
5957   pCode *last_pci=NULL;
5958   pCode *pflow=NULL;
5959   int seq = 0;
5960
5961   if(!pb)
5962     return;
5963
5964   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5965   /* Insert a pCodeFlow object at the beginning of a pBlock */
5966
5967   InsertpFlow(pb->pcHead, &pflow);
5968
5969   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5970   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5971   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5972   //pb->pcHead = pflow;        /* Make the Flow object the head */
5973   //pflow->pb = pb;
5974
5975   for( pc = pic16_findNextInstruction(pb->pcHead);
5976        pc != NULL;
5977        pc=pic16_findNextInstruction(pc)) { 
5978
5979     pc->seq = seq++;
5980     PCI(pc)->pcflow = PCFL(pflow);
5981
5982     //fprintf(stderr," build: ");
5983     //pflow->print(stderr,pflow);
5984
5985     if (checkLabel(pc)) { 
5986
5987       /* This instruction marks the beginning of a
5988        * new flow segment */
5989
5990       pc->seq = 0;
5991       seq = 1;
5992
5993       /* If the previous pCode is not a flow object, then 
5994        * insert a new flow object. (This check prevents 
5995        * two consecutive flow objects from being insert in
5996        * the case where a skip instruction preceeds an
5997        * instruction containing a label.) */
5998
5999       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
6000         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
6001
6002       PCI(pc)->pcflow = PCFL(pflow);
6003       
6004     }
6005
6006     if( PCI(pc)->isSkip) {
6007
6008       /* The two instructions immediately following this one 
6009        * mark the beginning of a new flow segment */
6010
6011       while(pc && PCI(pc)->isSkip) {
6012
6013         PCI(pc)->pcflow = PCFL(pflow);
6014         pc->seq = seq-1;
6015         seq = 1;
6016
6017         InsertpFlow(pc, &pflow);
6018         pc=pic16_findNextInstruction(pc->next);
6019       }
6020
6021       seq = 0;
6022
6023       if(!pc)
6024         break;
6025
6026       PCI(pc)->pcflow = PCFL(pflow);
6027       pc->seq = 0;
6028       InsertpFlow(pc, &pflow);
6029
6030     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6031
6032       InsertpFlow(pc, &pflow);
6033       seq = 0;
6034
6035     }
6036     last_pci = pc;
6037     pc = pc->next;
6038   }
6039
6040   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6041   if(pflow)
6042     PCFL(pflow)->end = pb->pcTail;
6043 }
6044
6045 /*-------------------------------------------------------------------*/
6046 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6047 /*                           the flow blocks.                        */
6048 /*
6049  * unBuildFlow removes pCodeFlow objects from a pCode chain
6050  */
6051 /*-----------------------------------------------------------------*/
6052 static void unBuildFlow(pBlock *pb)
6053 {
6054   pCode *pc,*pcnext;
6055
6056   if(!pb)
6057     return;
6058
6059   pc = pb->pcHead;
6060
6061   while(pc) {
6062     pcnext = pc->next;
6063
6064     if(isPCI(pc)) {
6065
6066       pc->seq = 0;
6067       if(PCI(pc)->pcflow) {
6068         //Safe_free(PCI(pc)->pcflow);
6069         PCI(pc)->pcflow = NULL;
6070       }
6071
6072     } else if(isPCFL(pc) )
6073       pc->destruct(pc);
6074
6075     pc = pcnext;
6076   }
6077
6078
6079 }
6080 #if 0
6081 /*-----------------------------------------------------------------*/
6082 /*-----------------------------------------------------------------*/
6083 static void dumpCond(int cond)
6084 {
6085
6086   static char *pcc_str[] = {
6087     //"PCC_NONE",
6088     "PCC_REGISTER",
6089     "PCC_C",
6090     "PCC_Z",
6091     "PCC_DC",
6092     "PCC_OV",
6093     "PCC_N",
6094     "PCC_W",
6095     "PCC_EXAMINE_PCOP",
6096     "PCC_LITERAL",
6097     "PCC_REL_ADDR"
6098   };
6099
6100   int ncond = sizeof(pcc_str) / sizeof(char *);
6101   int i,j;
6102
6103   fprintf(stderr, "0x%04X\n",cond);
6104
6105   for(i=0,j=1; i<ncond; i++, j<<=1)
6106     if(cond & j)
6107       fprintf(stderr, "  %s\n",pcc_str[i]);
6108
6109 }
6110 #endif
6111
6112 #if 0
6113 /*-----------------------------------------------------------------*/
6114 /*-----------------------------------------------------------------*/
6115 static void FlowStats(pCodeFlow *pcflow)
6116 {
6117
6118   pCode *pc;
6119
6120   if(!isPCFL(pcflow))
6121     return;
6122
6123   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6124
6125   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6126
6127   if(!pc) {
6128     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6129     return;
6130   }
6131
6132
6133   fprintf(stderr, "  FlowStats inCond: ");
6134   dumpCond(pcflow->inCond);
6135   fprintf(stderr, "  FlowStats outCond: ");
6136   dumpCond(pcflow->outCond);
6137
6138 }
6139 #endif
6140 /*-----------------------------------------------------------------*
6141  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6142  *    if it affects the banking bits. 
6143  * 
6144  * return: -1 == Banking bits are unaffected by this pCode.
6145  *
6146  * return: > 0 == Banking bits are affected.
6147  *
6148  *  If the banking bits are affected, then the returned value describes
6149  * which bits are affected and how they're affected. The lower half
6150  * of the integer maps to the bits that are affected, the upper half
6151  * to whether they're set or cleared.
6152  *
6153  *-----------------------------------------------------------------*/
6154
6155 static int isBankInstruction(pCode *pc)
6156 {
6157   regs *reg;
6158   int bank = -1;
6159
6160   if(!isPCI(pc))
6161     return 0;
6162
6163   if( PCI(pc)->op == POC_MOVLB ||
6164       (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6165     bank = PCOL(pc)->lit;
6166   }
6167
6168   return 1;
6169 }
6170
6171
6172 /*-----------------------------------------------------------------*/
6173 /*-----------------------------------------------------------------*/
6174 static void FillFlow(pCodeFlow *pcflow)
6175 {
6176
6177   pCode *pc;
6178   int cur_bank;
6179
6180   if(!isPCFL(pcflow))
6181     return;
6182
6183   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6184
6185   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE); 
6186
6187   if(!pc) {
6188     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6189     return;
6190   }
6191
6192   cur_bank = -1;
6193
6194   do {
6195     isBankInstruction(pc);
6196     pc = pc->next;
6197   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6198
6199 /*
6200   if(!pc ) {
6201     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6202   } else {
6203     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6204     pc->print(stderr,pc);
6205   }
6206
6207   fprintf(stderr, "  FillFlow inCond: ");
6208   dumpCond(pcflow->inCond);
6209   fprintf(stderr, "  FillFlow outCond: ");
6210   dumpCond(pcflow->outCond);
6211 */
6212 }
6213
6214 /*-----------------------------------------------------------------*/
6215 /*-----------------------------------------------------------------*/
6216 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6217 {
6218   pCodeFlowLink *fromLink, *toLink;
6219
6220   if(!from || !to || !to->pcflow || !from->pcflow)
6221     return;
6222
6223   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6224   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6225
6226   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6227   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6228
6229 }
6230
6231 pCode *pic16_getJumptabpCode (pCode *pc) {
6232   pCode *pcinf;
6233
6234   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6235   //pc->print (stderr, pc);
6236   pcinf = pc;
6237   while (pcinf) {
6238     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6239     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6240       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6241       case OPT_JUMPTABLE_BEGIN:
6242         /* leading begin of jump table -- in one */
6243         pcinf = pic16_findPrevInstruction (pcinf);
6244         return pcinf;
6245         break;
6246         
6247       case OPT_JUMPTABLE_END:
6248         /* leading end of jumptable -- not in one */
6249         return NULL;
6250         break;
6251         
6252       default:
6253         /* ignore all other PCInfos */
6254         break;
6255       }
6256     }
6257     pcinf = pcinf->prev;
6258   }
6259
6260   /* no PCInfo found -- not in a jumptable */
6261   return NULL;
6262 }
6263
6264 /*-----------------------------------------------------------------*
6265  * void LinkFlow(pBlock *pb)
6266  *
6267  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6268  * non-branching segments. In LinkFlow, we determine the execution
6269  * order of these segments. For example, if one of the segments ends
6270  * with a skip, then we know that there are two possible flow segments
6271  * to which control may be passed.
6272  *-----------------------------------------------------------------*/
6273 static void LinkFlow(pBlock *pb)
6274 {
6275   pCode *pc=NULL;
6276   pCode *pcflow;
6277   pCode *pct;
6278   pCode *jumptab_pre = NULL;
6279
6280   //fprintf(stderr,"linkflow \n");
6281
6282   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6283        pcflow != NULL;
6284        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6285
6286     if(!isPCFL(pcflow))
6287       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6288
6289     //fprintf(stderr," link: ");
6290     //pcflow->print(stderr,pcflow);
6291
6292     //FillFlow(PCFL(pcflow));
6293
6294     pc = PCFL(pcflow)->end;
6295
6296     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6297     if(isPCI_SKIP(pc)) {
6298 //      fprintf(stderr, "ends with skip\n");
6299 //      pc->print(stderr,pc);
6300
6301       pct=pic16_findNextInstruction(pc->next);
6302       LinkFlow_pCode(PCI(pc),PCI(pct));
6303       pct=pic16_findNextInstruction(pct->next);
6304       LinkFlow_pCode(PCI(pc),PCI(pct));
6305       continue;
6306     }
6307
6308     if(isPCI_BRANCH(pc)) {
6309       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6310
6311       /* handle GOTOs in jumptables */
6312       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6313         /* link to previous flow */
6314         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6315         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6316       }
6317
6318       switch (PCI(pc)->op) {
6319       case POC_GOTO:
6320       case POC_BRA:
6321       case POC_RETURN:
6322       case POC_RETLW:
6323       case POC_RETFIE:
6324               /* unconditional branches -- do not link to next instruction */
6325               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6326               break;
6327               
6328       case POC_CALL:
6329       case POC_RCALL:
6330               /* unconditional calls -- link to next instruction */
6331               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6332               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6333               break;
6334               
6335       case POC_BC:
6336       case POC_BN:
6337       case POC_BNC:
6338       case POC_BNN:
6339       case POC_BNOV:
6340       case POC_BNZ:
6341       case POC_BOV:
6342       case POC_BZ:
6343               /* conditional branches -- also link to next instruction */
6344               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6345               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6346               break;
6347               
6348       default:
6349               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6350               assert (0 && "unhandled branching instruction");
6351               break;
6352       }
6353
6354       //fprintf(stderr, "ends with branch\n  ");
6355       //pc->print(stderr,pc);
6356
6357       if(!(pcol && isPCOLAB(pcol))) {
6358         if((PCI(pc)->op != POC_RETLW)
6359                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6360         
6361                 /* continue if label is '$' which assembler knows how to parse */
6362                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6363
6364                 if(pic16_pcode_verbose) {
6365                         pc->print(stderr,pc);
6366                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6367                 }
6368         }
6369         continue;
6370       }
6371
6372       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6373         LinkFlow_pCode(PCI(pc),PCI(pct));
6374       else
6375         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6376                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6377
6378 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6379
6380       continue;
6381     }
6382
6383     if(isPCI(pc)) {
6384       //fprintf(stderr, "ends with non-branching instruction:\n");
6385       //pc->print(stderr,pc);
6386
6387       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6388
6389       continue;
6390     }
6391
6392     if(pc) {
6393       //fprintf(stderr, "ends with unknown\n");
6394       //pc->print(stderr,pc);
6395       continue;
6396     }
6397
6398     //fprintf(stderr, "ends with nothing: ERROR\n");
6399     
6400   }
6401 }
6402 /*-----------------------------------------------------------------*/
6403 /*-----------------------------------------------------------------*/
6404
6405 /*-----------------------------------------------------------------*/
6406 /*-----------------------------------------------------------------*/
6407 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6408 {
6409
6410   if(!pc || !pcflow)
6411     return 0;
6412
6413   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6414     return 0;
6415
6416   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6417     return 1;
6418
6419   return 0;
6420 }
6421
6422
6423
6424
6425
6426 /*-----------------------------------------------------------------*/
6427 /* insertBankSwitch - inserts a bank switch statement in the       */
6428 /*                    assembly listing                             */
6429 /*                                                                 */
6430 /* position == 0: insert before                                    */
6431 /* position == 1: insert after pc                                  */
6432 /* position == 2: like 0 but previous was a skip instruction       */
6433 /*-----------------------------------------------------------------*/
6434 pCodeOp *pic16_popGetLabel(unsigned int key);
6435 extern int pic16_labelOffset;
6436
6437 static void insertBankSwitch(unsigned char position, pCode *pc)
6438 {
6439   pCode *new_pc;
6440
6441         if(!pc)
6442                 return;
6443
6444         /* emit BANKSEL [symbol] */
6445
6446
6447         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6448         
6449 //      position = 0;           // position is always before (sanity check!)
6450
6451 #if 0
6452         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6453         pc->print(stderr, pc);
6454 #endif
6455
6456         switch(position) {
6457                 case 1: {
6458                         /* insert the bank switch after this pc instruction */
6459                         pCode *pcnext = pic16_findNextInstruction(pc);
6460
6461                                 pic16_pCodeInsertAfter(pc, new_pc);
6462                                 if(pcnext)pc = pcnext;
6463                 }; break;
6464                 
6465                 case 0:
6466                         /* insert the bank switch BEFORE this pc instruction */
6467                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6468                         break;
6469
6470                 case 2: {
6471                           symbol *tlbl;
6472                           pCode *pcnext, *pcprev, *npci, *ppc;
6473                           PIC_OPCODE ipci;
6474                           int ofs1=0, ofs2=0, len=0;
6475                           
6476                         /* just like 0, but previous was a skip instruction,
6477                          * so some care should be taken */
6478                           
6479                                 pic16_labelOffset += 10000;
6480                                 tlbl = newiTempLabel(NULL);
6481                                 
6482                                 /* invert skip instruction */
6483                                 pcprev = pic16_findPrevInstruction(pc->prev);
6484                                 ipci = PCI(pcprev)->inverted_op;
6485                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6486
6487 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6488
6489                                 /* copy info from old pCode */
6490                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6491                                 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6492                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6493                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6494                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6495                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6496                                 
6497                                 /* unlink old pCode */
6498                                 ppc = pcprev->prev;
6499                                 ppc->next = pcprev->next;
6500                                 pcprev->next->prev = ppc;
6501                                 pic16_pCodeInsertAfter(ppc, npci);
6502                                 
6503                                 /* extra instructions to handle invertion */
6504                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6505                                 pic16_pCodeInsertAfter(npci, pcnext);
6506                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6507                                 
6508                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6509                                 pic16_pCodeInsertAfter(pc, pcnext);
6510                         }; break;
6511         }
6512         
6513
6514         /* Move the label, if there is one */
6515         if(PCI(pc)->label) {
6516 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6517 //                      __FILE__, __LINE__, pc, new_pc);
6518                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6519                 PCI(pc)->label = NULL;
6520         }
6521 }
6522
6523
6524 /*-----------------------------------------------------------------*/
6525 /*int compareBankFlow - compare the banking requirements between   */
6526 /*  flow objects. */
6527 /*-----------------------------------------------------------------*/
6528 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6529 {
6530
6531   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6532     return 0;
6533
6534   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6535     return 0;
6536
6537   if(pcflow->firstBank == -1)
6538     return 0;
6539
6540
6541   if(pcflowLink->pcflow->firstBank == -1) {
6542     pCodeFlowLink *pctl = setFirstItem( toORfrom ? 
6543                                         pcflowLink->pcflow->to : 
6544                                         pcflowLink->pcflow->from);
6545     return compareBankFlow(pcflow, pctl, toORfrom);
6546   }
6547
6548   if(toORfrom) {
6549     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6550       return 0;
6551
6552     pcflowLink->bank_conflict++;
6553     pcflowLink->pcflow->FromConflicts++;
6554     pcflow->ToConflicts++;
6555   } else {
6556     
6557     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6558       return 0;
6559
6560     pcflowLink->bank_conflict++;
6561     pcflowLink->pcflow->ToConflicts++;
6562     pcflow->FromConflicts++;
6563
6564   }
6565   /*
6566   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6567           pcflowLink->pcflow->pc.seq,
6568           pcflowLink->pcflow->FromConflicts,
6569           pcflowLink->pcflow->ToConflicts);
6570   */
6571   return 1;
6572
6573 }
6574
6575 #if 0
6576 /*-----------------------------------------------------------------*/
6577 /*-----------------------------------------------------------------*/
6578 static void DumpFlow(pBlock *pb)
6579 {
6580   pCode *pc=NULL;
6581   pCode *pcflow;
6582   pCodeFlowLink *pcfl;
6583
6584
6585   fprintf(stderr,"Dump flow \n");
6586   pb->pcHead->print(stderr, pb->pcHead);
6587
6588   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6589   pcflow->print(stderr,pcflow);
6590
6591   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
6592        pcflow != NULL;
6593        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6594
6595     if(!isPCFL(pcflow)) {
6596       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6597       continue;
6598     }
6599     fprintf(stderr,"dumping: ");
6600     pcflow->print(stderr,pcflow);
6601     FlowStats(PCFL(pcflow));
6602
6603     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6604
6605       pc = PCODE(pcfl->pcflow);
6606
6607       fprintf(stderr, "    from seq %d:\n",pc->seq);
6608       if(!isPCFL(pc)) {
6609         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6610         pc->print(stderr,pc);
6611       }
6612
6613     }
6614
6615     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6616
6617       pc = PCODE(pcfl->pcflow);
6618
6619       fprintf(stderr, "    to seq %d:\n",pc->seq);
6620       if(!isPCFL(pc)) {
6621         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6622         pc->print(stderr,pc);
6623       }
6624
6625     }
6626
6627   }
6628
6629 }
6630 #endif
6631 /*-----------------------------------------------------------------*/
6632 /*-----------------------------------------------------------------*/
6633 static int OptimizepBlock(pBlock *pb)
6634 {
6635   pCode *pc, *pcprev;
6636   int matches =0;
6637
6638   if(!pb || !peepOptimizing)
6639     return 0;
6640
6641   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6642 /*
6643   for(pc = pb->pcHead; pc; pc = pc->next)
6644     matches += pic16_pCodePeepMatchRule(pc);
6645 */
6646
6647   pc = pic16_findNextInstruction(pb->pcHead);
6648   if(!pc)
6649     return 0;
6650
6651   pcprev = pc->prev;
6652   do {
6653
6654
6655     if(pic16_pCodePeepMatchRule(pc)) {
6656
6657       matches++;
6658
6659       if(pcprev)
6660         pc = pic16_findNextInstruction(pcprev->next);
6661       else 
6662         pc = pic16_findNextInstruction(pb->pcHead);
6663     } else
6664       pc = pic16_findNextInstruction(pc->next);
6665   } while(pc);
6666
6667   if(matches)
6668     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6669   return matches;
6670
6671 }
6672
6673 /*-----------------------------------------------------------------*/
6674 /*-----------------------------------------------------------------*/
6675 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6676 {
6677   pCode *pc;
6678
6679   for(pc = pcs; pc; pc = pc->next) {
6680
6681     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) && 
6682        (PCI(pc)->pcop) && 
6683        (PCI(pc)->pcop->type == PO_LABEL) &&
6684        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6685       return pc;
6686   }
6687  
6688
6689   return NULL;
6690 }
6691
6692 /*-----------------------------------------------------------------*/
6693 /*-----------------------------------------------------------------*/
6694 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6695 {
6696
6697   char *s=NULL;
6698
6699   if(isPCI(pc) && 
6700      (PCI(pc)->pcop) && 
6701      (PCI(pc)->pcop->type == PO_LABEL)) {
6702
6703     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6704
6705 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6706 //    if(pcol->pcop.name)
6707 //      Safe_free(pcol->pcop.name);
6708
6709     /* If the key is negative, then we (probably) have a label to
6710      * a function and the name is already defined */
6711        
6712     if(pcl->key>0)
6713       sprintf(s=buffer,"_%05d_DS_",pcl->key);
6714     else 
6715       s = pcl->label;
6716
6717     //sprintf(buffer,"_%05d_DS_",pcl->key);
6718     if(!s) {
6719       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6720     }
6721     pcol->pcop.name = Safe_strdup(s);
6722     pcol->key = pcl->key;
6723     //pc->print(stderr,pc);
6724
6725   }
6726
6727
6728 }
6729
6730 /*-----------------------------------------------------------------*/
6731 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6732 /*                            pCode chain if they're not used.     */
6733 /*-----------------------------------------------------------------*/
6734 static void pBlockRemoveUnusedLabels(pBlock *pb)
6735 {
6736   pCode *pc; pCodeLabel *pcl;
6737
6738   if(!pb)
6739     return;
6740
6741   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6742
6743     pBranch *pbr = PCI(pc)->label;
6744     if(pbr && pbr->next) {
6745       pCode *pcd = pb->pcHead;
6746
6747 //      fprintf(stderr, "multiple labels\n");
6748 //      pc->print(stderr,pc);
6749
6750       pbr = pbr->next;
6751       while(pbr) {
6752
6753         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6754           //fprintf(stderr,"Used by:\n");
6755           //pcd->print(stderr,pcd);
6756
6757           exchangeLabels(PCL(pbr->pc),pcd);
6758
6759           pcd = pcd->next;
6760         }
6761         pbr = pbr->next;
6762       }
6763     }
6764   }
6765
6766   for(pc = pb->pcHead; pc; pc = pc->next) {
6767
6768     if(isPCL(pc)) // pc->type == PC_LABEL)
6769       pcl = PCL(pc);
6770     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6771       pcl = PCL(PCI(pc)->label->pc);
6772     else continue;
6773
6774 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6775
6776     /* This pCode is a label, so search the pBlock to see if anyone
6777      * refers to it */
6778
6779     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6780         && (!pcl->force)) {
6781     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6782       /* Couldn't find an instruction that refers to this label
6783        * So, unlink the pCode label from it's pCode chain
6784        * and destroy the label */
6785 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6786
6787       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6788       if(pc->type == PC_LABEL) {
6789         pic16_unlinkpCode(pc);
6790         pCodeLabelDestruct(pc);
6791       } else {
6792         unlinkpCodeFromBranch(pc, PCODE(pcl));
6793         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6794           Safe_free(pc->label);
6795         }*/
6796       }
6797
6798     }
6799   }
6800
6801 }
6802
6803
6804 /*-----------------------------------------------------------------*/
6805 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6806 /*                     chain and put them into pBranches that are  */
6807 /*                     associated with the appropriate pCode       */
6808 /*                     instructions.                               */
6809 /*-----------------------------------------------------------------*/
6810 void pic16_pBlockMergeLabels(pBlock *pb)
6811 {
6812   pBranch *pbr;
6813   pCode *pc, *pcnext=NULL;
6814
6815   if(!pb)
6816     return;
6817
6818   /* First, Try to remove any unused labels */
6819   //pBlockRemoveUnusedLabels(pb);
6820
6821   /* Now loop through the pBlock and merge the labels with the opcodes */
6822
6823   pc = pb->pcHead;
6824   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6825
6826   while(pc) {
6827     pCode *pcn = pc->next;
6828
6829     if(pc->type == PC_LABEL) {
6830
6831 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6832 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6833
6834       if((pcnext = pic16_findNextInstruction(pc) )) {
6835
6836 //              pcnext->print(stderr, pcnext);
6837
6838         // Unlink the pCode label from it's pCode chain
6839         pic16_unlinkpCode(pc);
6840         
6841 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6842         // And link it into the instruction's pBranch labels. (Note, since
6843         // it's possible to have multiple labels associated with one instruction
6844         // we must provide a means to accomodate the additional labels. Thus
6845         // the labels are placed into the singly-linked list "label" as 
6846         // opposed to being a single member of the pCodeInstruction.)
6847
6848         //_ALLOC(pbr,sizeof(pBranch));
6849 #if 1
6850         pbr = Safe_calloc(1,sizeof(pBranch));
6851         pbr->pc = pc;
6852         pbr->next = NULL;
6853
6854         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6855 #endif
6856       } else {
6857         if(pic16_pcode_verbose)
6858         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6859       }
6860     } else if(pc->type == PC_CSOURCE) {
6861
6862       /* merge the source line symbolic info into the next instruction */
6863       if((pcnext = pic16_findNextInstruction(pc) )) {
6864
6865         // Unlink the pCode label from it's pCode chain
6866         pic16_unlinkpCode(pc);
6867         PCI(pcnext)->cline = PCCS(pc);
6868         //fprintf(stderr, "merging CSRC\n");
6869         //genericPrint(stderr,pcnext);
6870       }
6871
6872     }
6873     pc = pcn;
6874   }
6875   pBlockRemoveUnusedLabels(pb);
6876
6877 }
6878
6879 /*-----------------------------------------------------------------*/
6880 /*-----------------------------------------------------------------*/
6881 static int OptimizepCode(char dbName)
6882 {
6883 #define MAX_PASSES 4
6884
6885   int matches = 0;
6886   int passes = 0;
6887   pBlock *pb;
6888
6889   if(!the_pFile)
6890     return 0;
6891
6892   DFPRINTF((stderr," Optimizing pCode\n"));
6893
6894   do {
6895     matches = 0;
6896     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6897       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6898         matches += OptimizepBlock(pb);
6899     }
6900   }
6901   while(matches && ++passes < MAX_PASSES);
6902
6903   return matches;
6904 }
6905
6906
6907
6908 const char *pic16_pCodeOpType(pCodeOp *pcop);
6909 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6910
6911
6912 /*-----------------------------------------------------------------*/
6913 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6914 /*-----------------------------------------------------------------*/
6915
6916 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6917 {
6918   pCodeOp *pcop=NULL;
6919
6920 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6921
6922   if(pc->name) {
6923         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6924   } else {
6925     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6926   }
6927
6928   assert(pcop != NULL);
6929
6930   if( !( (pcop->type == PO_LABEL) ||
6931          (pcop->type == PO_LITERAL) ||
6932          (pcop->type == PO_STR) ))
6933     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6934     PCOR(pcop)->r->wasUsed = 1;
6935     PCOR(pcop)->instance = PCOR(pc)->instance;
6936
6937   return pcop;
6938 }
6939
6940
6941 /*----------------------------------------------------------------------*
6942  * pic16_areRegsSame - check to see if the names of two registers match *
6943  *----------------------------------------------------------------------*/
6944 int pic16_areRegsSame(regs *r1, regs *r2)
6945 {
6946         if(!strcmp(r1->name, r2->name))return 1;
6947
6948   return 0;
6949 }
6950
6951
6952 /*-----------------------------------------------------------------*/
6953 /*-----------------------------------------------------------------*/
6954 static void pic16_FixRegisterBanking(pBlock *pb)
6955 {
6956   pCode *pc=NULL;
6957   pCode *pcprev=NULL;
6958   regs *reg, *prevreg;
6959   unsigned char flag=0;
6960   
6961         if(!pb)
6962                 return;
6963
6964         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6965         if(!pc)return;
6966
6967         /* loop through all of the flow blocks with in one pblock */
6968
6969 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6970
6971         prevreg = NULL;
6972         do {
6973                 /* at this point, pc should point to a PC_FLOW object */
6974                 /* for each flow block, determine the register banking 
6975                  * requirements */
6976
6977                 
6978                 /* if label, then might come from other point, force banksel */
6979                 if(isPCL(pc))prevreg = NULL;
6980                 
6981                 if(!isPCI(pc))goto loop;
6982
6983                 if(PCI(pc)->label)prevreg = NULL;
6984
6985                 if(PCI(pc)->is2MemOp)goto loop;
6986
6987                 /* if goto, then force banksel */
6988 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6989        
6990                 reg = pic16_getRegFromInstruction(pc);
6991
6992 #if 0
6993                 pc->print(stderr, pc);
6994                 fprintf(stderr, "reg = %p\n", reg);
6995
6996                 if(reg) {
6997                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6998                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6999                                 reg->address,reg->isBitField, reg->isFixed);
7000                 }
7001 #endif
7002
7003                 /* now make some tests to make sure that instruction needs bank switch */
7004
7005                 /* if no register exists, and if not a bit opcode goto loop */
7006                 if(!reg) {
7007                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
7008                 }
7009                  
7010                 if(isPCI_SKIP(pc)) {
7011 //                      fprintf(stderr, "instruction is SKIP instruction\n");
7012 //                prevreg = NULL;
7013                 }
7014                 if(reg && isACCESS_BANK(reg))goto loop;
7015
7016                 if(!isBankInstruction(pc))goto loop;
7017
7018                 if(isPCI_LIT(pc))goto loop;
7019          
7020                 if(PCI(pc)->op == POC_CALL)goto loop;
7021
7022                 /* Examine the instruction before this one to make sure it is
7023                  * not a skip type instruction */
7024                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7025
7026                 flag = 0;               /* add before this instruction */
7027                 
7028                 /* if previous instruction is a skip one, then set flag
7029                  * to 2 and call insertBankSwitch */
7030                 if(pcprev && isPCI_SKIP(pcprev)) {
7031                   flag=2;       //goto loop
7032 //                prevreg = NULL;
7033                 }
7034                  
7035                 if(pic16_options.opt_banksel>0) {
7036                   char op1[128], op2[128];
7037                   
7038                     if(prevreg) {
7039                       strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7040                       strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7041                       if(!strcmp(op1, op2))goto loop;
7042                     }
7043                 }
7044                 prevreg = reg;
7045                 insertBankSwitch(flag, pc);
7046
7047 //              fprintf(stderr, "BANK SWITCH inserted\n");
7048                 
7049 loop:
7050                 pcprev = pc;
7051                 pc = pc->next;
7052         } while (pc);
7053 }
7054
7055 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7056
7057 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7058 int instrSize (pCode *pc)
7059 {
7060   if (!pc) return 0;
7061
7062   if (isPCAD(pc)) {
7063     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7064     return 4; // assumes only regular instructions using <= 4 bytes
7065   }
7066
7067   if (isPCI(pc)) return PCI(pc)->isize;
7068
7069   return 0;
7070 }
7071
7072 /* Returns 1 if pc is referenced by the given label (either
7073  * pc is the label itself or is an instruction with an attached
7074  * label).
7075  * Returns 0 if pc is not preceeded by the specified label.
7076  */
7077 int isLabel (pCode *pc, char *label)
7078 {
7079   if (!pc) return 0;
7080
7081   // label attached to the pCode?  
7082   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7083     pBranch *lab = NULL;
7084     lab = PCI(pc)->label;
7085
7086     while (lab) {
7087       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7088         return 1;
7089       }
7090       lab = lab->next;
7091     } // while
7092   } // if
7093
7094   // is inline assembly label?
7095   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7096     // do not compare trailing ':'
7097     if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7098       return 1;
7099     }
7100   } // if
7101   
7102   // is pCodeLabel?
7103   if (isPCL(pc)) {
7104       if (strcmp(PCL(pc)->label,label) == 0) {
7105       return 1;
7106     }
7107   } // if
7108   
7109   // no label/no label attached/wrong label(s)
7110   return 0;
7111 }
7112
7113 /* Returns the distance to the given label in terms of words.
7114  * Labels are searched only within -max .. max words from pc.
7115  * Returns max if the label could not be found or
7116  * its distance from pc in (-max..+max).
7117  */
7118 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7119   int dist = instrSize(pc);
7120   pCode *curr = pc;
7121
7122   // search backwards
7123   while (dist < max && curr && !isLabel (curr, label)) {
7124     curr = curr->prev;
7125     dist += instrSize(curr); // sizeof (instruction)
7126   } // while
7127   if (curr && dist < max) {
7128     if (target != NULL) *target = curr;
7129     return -dist;
7130   }
7131
7132   dist = 0;
7133   curr = pic16_findNextInstruction (pc->next);
7134   //search forwards
7135   while (dist < max && curr && !isLabel (curr, label)) {
7136     dist += instrSize(curr); // sizeof (instruction)
7137     curr = curr->next;
7138   } // while
7139   if (curr && dist < max) {
7140     if (target != NULL) *target = curr;
7141     return dist;
7142   }
7143
7144   if (target != NULL) *target = NULL;
7145   return max;
7146 }
7147
7148 /* Returns -1 if pc does NOT denote an instruction like
7149  * BTFS[SC] STATUS,i
7150  * Otherwise we return 
7151  *   (a) 0x10 + i for BTFSS
7152  *   (b) 0x00 + i for BTFSC
7153  */
7154 int isSkipOnStatus (pCode *pc)
7155 {
7156   int res = -1;
7157   pCodeOp *pcop;
7158   if (!pc || !isPCI(pc)) return -1;
7159   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7160   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7161   else return -1;
7162
7163   pcop = PCI(pc)->pcop;
7164
7165   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7166     return res + ((pCodeOpRegBit *)pcop)->bit;
7167   }
7168
7169   return -1;
7170 }
7171
7172 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7173  * returns 0 otherwise. */
7174 int isConditionalBranch (pCode *pc)
7175 {
7176   if (!pc || !isPCI_BRANCH(pc)) return 0;
7177
7178   switch (PCI(pc)->op) {
7179   case POC_BC:
7180   case POC_BZ:
7181   case POC_BOV:
7182   case POC_BN:
7183   case POC_BNC:
7184   case POC_BNZ:
7185   case POC_BNOV:
7186   case POC_BNN:
7187     return 1;
7188
7189   default:
7190     break;
7191   } // switch
7192
7193   return 0;
7194 }
7195
7196 /* Returns 1 if pc has a label attached to it.
7197  * This can be either a label stored in the pCode itself (.label)
7198  * or a label making up its own pCode preceding this pc.
7199  * Returns 0 if pc cannot be reached directly via a label.
7200  */
7201 int hasNoLabel (pCode *pc)
7202 {
7203   pCode *prev;
7204   if (!pc) return 1;
7205
7206   // are there any label pCodes between pc and the previous instruction?
7207   prev = pic16_findPrevInstruction (pc->prev);
7208   while (pc && pc != prev) {
7209     // pCode with attached label?
7210     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7211         && PCI(pc)->label) {
7212       return 0;
7213     }
7214     // is inline assembly label?
7215     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7216     if (isPCW(pc) && PCW(pc)->label) return 0;
7217
7218     // pCodeLabel?
7219     if (isPCL(pc)) return 0;
7220
7221     pc = pc->prev;
7222   } // if
7223
7224   // no label found
7225   return 1;
7226 }
7227
7228 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7229   char buf[512];
7230   va_list va;
7231
7232   va_start (va, fmt);
7233   vsprintf (buf, fmt, va);
7234   va_end (va);
7235
7236   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7237 }
7238
7239 /* Replaces the old pCode with the new one, moving the labels,
7240  * C source line and probably flow information to the new pCode.
7241  */
7242 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7243   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7244     return;
7245
7246   /* first move all labels from old to new */
7247   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7248   PCI(oldPC)->label = NULL;
7249   
7250 #if 0
7251   /* move C source line (if possible) */
7252   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7253     PCI(newPC)->cline = PCI(oldPC)->cline;
7254 #endif
7255
7256   /* keep flow information intact */
7257   newPC->seq = oldPC->seq;
7258   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7259   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7260     PCI(newPC)->pcflow->end = newPC;
7261   }
7262
7263   /* insert a comment stating which pCode has been replaced */
7264 #if 1
7265   if (pic16_pcode_verbose || pic16_debug_verbose) {
7266     char pc_str[256];
7267     pic16_pCode2str (pc_str, 256, oldPC);
7268     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7269   }
7270 #endif
7271   
7272   /* insert new pCode into pBlock */
7273   pic16_pCodeInsertAfter (oldPC, newPC);
7274   pic16_unlinkpCode (oldPC);
7275   
7276   /* destruct replaced pCode */
7277   oldPC->destruct (oldPC);
7278 }
7279
7280 /* Returns the inverted conditional branch (if any) or NULL.
7281  * pcop must be set to the new jump target.
7282  */
7283 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7284 {
7285   pCode *newBcc;
7286
7287   if (!bcc || !isPCI(bcc)) return NULL;
7288
7289   switch (PCI(bcc)->op) {
7290   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7291   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7292   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7293   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7294   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7295   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7296   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7297   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7298   default:
7299     newBcc = NULL;
7300   }
7301   return newBcc;
7302 }
7303
7304 #define MAX_DIST_GOTO         0x7FFFFFFF
7305 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7306 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7307 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7308 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7309
7310 /* Follows GOTO/BRA instructions to their target instructions, stores the
7311  * final destination (not a GOTO or BRA instruction) in target and returns
7312  * the distance from the original pc to *target.
7313  */
7314 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7315         pCode *curr = pc;
7316         pCode *last = NULL;
7317         pCodeOp *lastPCOP = NULL;
7318         int dist = 0;
7319         int depth = 0;
7320
7321         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7322
7323         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7324         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7325                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7326                 last = curr;
7327                 lastPCOP = PCI(curr)->pcop;
7328                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7329                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7330         } // while
7331
7332         if (target) *target = last;
7333         if (pcop) *pcop = lastPCOP;
7334         return dist;
7335 }
7336
7337 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7338  * Otherwise the first pCode after the jumptable (after
7339  * the OPT_JUMPTABLE_END tag) is returned.
7340  */
7341 pCode *skipJumptables (pCode *pc, int *isJumptable)
7342 {
7343   *isJumptable = 0;
7344   if (!pc) return NULL;
7345   
7346   while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7347     *isJumptable = 1;
7348     //fprintf (stderr, "SKIPPING jumptable\n");
7349     do {
7350       //pc->print(stderr, pc);
7351       pc = pc->next;
7352     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7353                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7354     //fprintf (stderr, "<<JUMPTAB:\n");
7355     // skip OPT_END as well
7356     if (pc) pc = pc->next;
7357   } // while
7358
7359   return pc;
7360 }
7361
7362 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7363 {
7364   int isJumptab;
7365   *isJumptable = 0;
7366   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7367     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7368     pc = skipJumptables (pc, &isJumptab);
7369     if (isJumptab) {
7370         // pc is the first pCode after the jumptable
7371         *isJumptable = 1;
7372     } else {
7373         // pc has not been changed by skipJumptables()
7374         pc = pc->next;
7375     }
7376   } // while
7377   
7378   return pc;
7379 }
7380
7381 /* Turn GOTOs into BRAs if distance between GOTO and label
7382  * is less than 1024 bytes.
7383  *
7384  * This method is especially useful if GOTOs after BTFS[SC]
7385  * can be turned into BRAs as GOTO would cost another NOP
7386  * if skipped.
7387  */
7388 void pic16_OptimizeJumps ()
7389 {
7390   pCode *pc;
7391   pCode *pc_prev = NULL;
7392   pCode *pc_next = NULL;
7393   pBlock *pb;
7394   pCode *target;
7395   int change, iteration, isJumptab;
7396   int isHandled = 0;
7397   char *label;
7398   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7399   
7400   if (!the_pFile) return;
7401   
7402   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7403   
7404   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7405     int matchedInvertRule = 1;
7406     iteration = 1;
7407     do {
7408       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7409       change = 0;
7410       pc = pic16_findNextInstruction (pb->pcHead);
7411     
7412       while (pc) {
7413         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7414         if (isJumptab) {
7415                 // skip jumptable, i.e. start over with no pc_prev!     
7416                 pc_prev = NULL;
7417                 pc = pc_next;
7418                 continue;
7419         } // if
7420
7421         /* (1) resolve chained jumps
7422          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7423          * (a) leave dead code in and
7424          * (b) skip over the dead code with an (unneccessary) jump.
7425          */
7426         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7427           pCodeOp *lastTargetOp = NULL;
7428           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7429           int maxDist = MAX_DIST_BCC;
7430           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7431           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7432           
7433           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7434           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7435               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7436             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7437             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7438             PCI(pc)->pcop->name = lastTargetOp->name;
7439             change++;
7440             opt_gotochain++;
7441           } // if
7442         } // if
7443
7444
7445         if (IS_GOTO(pc)) {
7446           int dist;
7447           int condBraType = isSkipOnStatus(pc_prev);
7448           label = PCI(pc)->pcop->name;
7449           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7450           if (dist < 0) dist = -dist;
7451           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7452           isHandled = 0;
7453           
7454           
7455           /* (2) remove "GOTO label; label:" */
7456           if (isLabel (pc_next, label)) {
7457             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7458             // first remove all preceeding SKIP instructions
7459             while (pc_prev && isPCI_SKIP(pc_prev)) {
7460               // attach labels on this instruction to pc_next
7461               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7462               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7463               PCI(pc_prev)->label = NULL;
7464               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7465               pic16_unlinkpCode (pc_prev);
7466               pc_prev = pic16_findPrevInstruction (pc);
7467             } // while
7468             // now remove the redundant goto itself
7469             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7470             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7471             pic16_unlinkpCode (pc);
7472             pc = pic16_findPrevInstruction(pc_next->prev);
7473             isHandled = 1; // do not perform further optimizations
7474             opt_gotonext++;
7475             change++;
7476           } // if
7477           
7478           
7479           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7480           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7481             if (dist < MAX_DIST_BCC) {
7482               pCode *bcc = NULL;
7483               switch (condBraType) {
7484               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7485                 // no BDC on DIGIT CARRY available
7486               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7487               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7488               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7489               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7490                 // no BNDC on DIGIT CARRY available
7491               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7492               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7493               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7494               default:
7495                 // no replacement possible
7496                 bcc = NULL;
7497                 break;
7498               } // switch
7499               if (bcc) {
7500                 // ATTENTION: keep labels attached to BTFSx!
7501                 // HINT: GOTO is label free (checked above)
7502                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7503                 isHandled = 1; // do not perform further optimizations
7504                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7505                 pic16_pCodeReplace (pc_prev, bcc);
7506                 pc->destruct(pc);
7507                 pc = bcc;
7508                 opt_cond++;
7509                 change++;
7510               } // if
7511             } else {
7512               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7513               cond_toofar++;
7514             } // if
7515           } // if
7516
7517           if (!isHandled) {
7518             // (4) eliminate the following (common) tripel:
7519             //           <pred.>;
7520             //  labels1: Bcc label2;
7521             //           GOTO somewhere;    ; <-- instruction referenced by pc
7522             //  label2:  <cont.>
7523             // and replace it by
7524             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7525             //  label2:  <cont.>
7526             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7527             //            to <cont.> instead
7528             // ATTENTION: This optimization is only valid if <pred.> is
7529             //            not a skip operation!
7530             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7531             // ATTENTION: no label may be attached to the GOTO instruction!
7532             if (isConditionalBranch(pc_prev)
7533                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7534                 && (dist < MAX_DIST_BCC)
7535                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7536                 && hasNoLabel(pc)) {
7537               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7538             
7539               if (newBcc) {
7540                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7541                 isHandled = 1; // do not perform further optimizations
7542                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7543                 pic16_pCodeReplace (pc_prev, newBcc);
7544                 pc->destruct(pc);
7545                 pc = newBcc;
7546                 opt_reorder++;
7547                 change++;
7548                 matchedInvertRule++;
7549               }
7550             }
7551           }
7552           
7553           /* (5) now just turn GOTO into BRA */ 
7554           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7555             if (dist < MAX_DIST_BRA) {
7556               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7557               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7558               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7559               pic16_pCodeReplace (pc, newBra);
7560               pc = newBra;
7561               opt++;
7562               change++;
7563             } else {
7564               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7565               toofar++;
7566             }
7567           } // if (!isHandled)
7568         } // if
7569
7570         pc_prev = pc;
7571         pc = pc_next;
7572       } // while (pc)
7573       
7574       pBlockRemoveUnusedLabels (pb);
7575       
7576       // This line enables goto chain resolution!
7577       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7578
7579       iteration++;
7580     } while (change); /* fixpoint iteration per pBlock */
7581   } // for (pb)
7582   
7583   // emit some statistics concerning goto-optimization
7584 #if 0
7585   if (pic16_debug_verbose || pic16_pcode_verbose) {
7586     fprintf (stderr, "optimize-goto:\n"
7587              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7588              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7589              "\t%5d conditional \"skipping\" jumps inverted\n"
7590              "\t%5d GOTOs to next instruction removed\n"
7591              "\t%5d chained GOTOs resolved\n",
7592              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7593   } // if
7594 #endif
7595   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7596 }
7597
7598 #undef IS_GOTO
7599 #undef MAX_JUMPCHAIN_DEPTH
7600 #undef MAX_DIST_GOTO
7601 #undef MAX_DIST_BRA
7602 #undef MAX_DIST_BCC
7603
7604 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7605
7606 static void pBlockDestruct(pBlock *pb)
7607 {
7608
7609   if(!pb)
7610     return;
7611
7612
7613 //  Safe_free(pb);
7614
7615 }
7616
7617 /*-----------------------------------------------------------------*/
7618 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7619 /*                                  name dbName and combine them   */
7620 /*                                  into one block                 */
7621 /*-----------------------------------------------------------------*/
7622 static void mergepBlocks(char dbName)
7623 {
7624
7625   pBlock *pb, *pbmerged = NULL,*pbn;
7626
7627   pb = the_pFile->pbHead;
7628
7629   //fprintf(stderr," merging blocks named %c\n",dbName);
7630   while(pb) {
7631
7632     pbn = pb->next;
7633     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7634     if( getpBlock_dbName(pb) == dbName) {
7635
7636       //fprintf(stderr," merged block %c\n",dbName);
7637
7638       if(!pbmerged) {
7639         pbmerged = pb;
7640       } else {
7641         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7642         /* pic16_addpCode2pBlock doesn't handle the tail: */
7643         pbmerged->pcTail = pb->pcTail;
7644
7645         pb->prev->next = pbn;
7646         if(pbn) 
7647           pbn->prev = pb->prev;
7648
7649
7650         pBlockDestruct(pb);
7651       }
7652       //pic16_printpBlock(stderr, pbmerged);
7653     } 
7654     pb = pbn;
7655   }
7656
7657 }
7658
7659 /*-----------------------------------------------------------------*/
7660 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7661 /*                                                                 */
7662 /* level 0 == minimal optimization                                 */
7663 /*   optimize registers that are used only by two instructions     */
7664 /* level 1 == maximal optimization                                 */
7665 /*   optimize by looking at pairs of instructions that use the     */
7666 /*   register.                                                     */
7667 /*-----------------------------------------------------------------*/
7668
7669 static void AnalyzeFlow(int level)
7670 {
7671   static int times_called=0;
7672   pBlock *pb;
7673
7674     if(!the_pFile) {
7675       /* remove unused allocated registers before exiting */
7676       pic16_RemoveUnusedRegisters();
7677       return;
7678     }
7679
7680
7681     /* if this is not the first time this function has been called,
7682      * then clean up old flow information */
7683     if(times_called++) {
7684       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7685         unBuildFlow(pb);
7686         pic16_RegsUnMapLiveRanges();
7687     }
7688     GpcFlowSeq = 1;
7689
7690     /* Phase 2 - Flow Analysis - Register Banking
7691      *
7692      * In this phase, the individual flow blocks are examined
7693      * and register banking is fixed.
7694      */
7695
7696 #if 0
7697     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7698       pic16_FixRegisterBanking(pb);
7699 #endif
7700
7701     /* Phase 2 - Flow Analysis
7702      *
7703      * In this phase, the pCode is partition into pCodeFlow 
7704      * blocks. The flow blocks mark the points where a continuous
7705      * stream of instructions changes flow (e.g. because of
7706      * a call or goto or whatever).
7707      */
7708
7709     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7710       pic16_BuildFlow(pb);
7711
7712
7713     /* Phase 2 - Flow Analysis - linking flow blocks
7714      *
7715      * In this phase, the individual flow blocks are examined
7716      * to determine their order of excution.
7717      */
7718
7719     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7720       LinkFlow(pb);
7721
7722 #if 1
7723         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7724                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7725                         pic16_createDF (pb);
7726 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7727                         pic16_vcg_dump_default (pb);
7728 #endif
7729                         //pic16_destructDF (pb);
7730                 }
7731
7732                 pic16_df_stats ();
7733                 if (0) releaseStack (); // releasing is costly...
7734         }
7735 #endif
7736
7737     /* Phase 3 - Flow Analysis - Flow Tree
7738      *
7739      * In this phase, the individual flow blocks are examined
7740      * to determine their order of execution.
7741      */
7742
7743     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7744       pic16_BuildFlowTree(pb);
7745
7746
7747     /* Phase x - Flow Analysis - Used Banks
7748      *
7749      * In this phase, the individual flow blocks are examined
7750      * to determine the Register Banks they use
7751      */
7752
7753 #if 0
7754     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7755       FixBankFlow(pb);
7756 #endif
7757
7758
7759     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7760       pic16_pCodeRegMapLiveRanges(pb);
7761
7762     pic16_RemoveUnusedRegisters();
7763     pic16_removeUnusedRegistersDF ();
7764
7765   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7766     pic16_pCodeRegOptimizeRegUsage(level);
7767
7768
7769 #if 0
7770     if(!options.nopeep)
7771       OptimizepCode('*');
7772 #endif
7773
7774 #if 0
7775     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7776       DumpFlow(pb);
7777 #endif
7778
7779     /* debug stuff */ 
7780     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7781       pCode *pcflow;
7782       
7783         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7784           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7785           pcflow = pcflow->next) {
7786             FillFlow(PCFL(pcflow));
7787         }
7788     }
7789
7790 #if 0
7791     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7792       pCode *pcflow;
7793
7794         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW); 
7795           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7796           pcflow = pcflow->next) {
7797             FlowStats(PCFL(pcflow));
7798         }
7799     }
7800 #endif
7801 }
7802
7803 /* VR -- no need to analyze banking in flow, but left here :
7804  *      1. because it may be used in the future for other purposes
7805  *      2. because if omitted we'll miss some optimization done here
7806  *
7807  * Perhaps I should rename it to something else
7808  */
7809
7810 /*-----------------------------------------------------------------*/
7811 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7812 /*                  assigned to the registers.                     */
7813 /*                                                                 */
7814 /*-----------------------------------------------------------------*/
7815
7816 void pic16_AnalyzeBanking(void)
7817 {
7818   pBlock  *pb;
7819
7820     /* Phase x - Flow Analysis - Used Banks
7821      *
7822      * In this phase, the individual flow blocks are examined
7823      * to determine the Register Banks they use
7824      */
7825
7826     AnalyzeFlow(0);
7827     AnalyzeFlow(1);
7828
7829     if(!options.nopeep)
7830       OptimizepCode('*');
7831
7832
7833     if(!the_pFile)return;
7834
7835     if(!pic16_options.no_banksel) {
7836       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7837 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7838         pic16_FixRegisterBanking(pb);
7839       }
7840     }
7841 }
7842
7843 /*-----------------------------------------------------------------*/
7844 /* buildCallTree - Look at the flow and extract all of the calls.  */
7845 /*-----------------------------------------------------------------*/
7846 static set *register_usage(pBlock *pb);
7847
7848 static void buildCallTree(void    )
7849 {
7850   pBranch *pbr;
7851   pBlock  *pb;
7852   pCode   *pc;
7853   regs *r;
7854   
7855   if(!the_pFile)
7856     return;
7857
7858
7859
7860   /* Now build the call tree.
7861      First we examine all of the pCodes for functions.
7862      Keep in mind that the function boundaries coincide
7863      with pBlock boundaries. 
7864
7865      The algorithm goes something like this:
7866      We have two nested loops. The outer loop iterates
7867      through all of the pBlocks/functions. The inner
7868      loop iterates through all of the pCodes for
7869      a given pBlock. When we begin iterating through
7870      a pBlock, the variable pc_fstart, pCode of the start
7871      of a function, is cleared. We then search for pCodes
7872      of type PC_FUNCTION. When one is encountered, we
7873      initialize pc_fstart to this and at the same time
7874      associate a new pBranch object that signifies a 
7875      branch entry. If a return is found, then this signifies
7876      a function exit point. We'll link the pCodes of these
7877      returns to the matching pc_fstart.
7878
7879      When we're done, a doubly linked list of pBranches
7880      will exist. The head of this list is stored in
7881      `the_pFile', which is the meta structure for all
7882      of the pCode. Look at the pic16_printCallTree function
7883      on how the pBranches are linked together.
7884
7885    */
7886   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7887     pCode *pc_fstart=NULL;
7888     for(pc = pb->pcHead; pc; pc = pc->next) {
7889
7890         if(isPCI(pc) && pc_fstart) {
7891                 if(PCI(pc)->is2MemOp) {
7892                         r = pic16_getRegFromInstruction2(pc);
7893                         if(r && !strcmp(r->name, "POSTDEC1"))
7894                                 PCF(pc_fstart)->stackusage++;
7895                 } else {
7896                         r = pic16_getRegFromInstruction(pc);
7897                         if(r && !strcmp(r->name, "PREINC1"))
7898                                 PCF(pc_fstart)->stackusage--;
7899                 }
7900         }
7901
7902       if(isPCF(pc)) {
7903         if (PCF(pc)->fname) {
7904         char buf[16];
7905
7906           sprintf(buf, "%smain", port->fun_prefix);
7907           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7908             //fprintf(stderr," found main \n");
7909             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7910             pb->dbName = 'M';
7911           }
7912
7913           pbr = Safe_calloc(1,sizeof(pBranch));
7914           pbr->pc = pc_fstart = pc;
7915           pbr->next = NULL;
7916
7917           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7918
7919           // Here's a better way of doing the same:
7920           addSet(&pb->function_entries, pc);
7921
7922         } else {
7923           // Found an exit point in a function, e.g. return
7924           // (Note, there may be more than one return per function)
7925           if(pc_fstart)
7926             pBranchLink(PCF(pc_fstart), PCF(pc));
7927
7928           addSet(&pb->function_exits, pc);
7929         }
7930       } else if(isCALL(pc)) {
7931         addSet(&pb->function_calls,pc);
7932       }
7933     }
7934   }
7935
7936
7937 #if 0
7938   /* This is not needed because currently all register used
7939    * by a function are stored in stack -- VR */
7940    
7941   /* Re-allocate the registers so that there are no collisions
7942    * between local variables when one function call another */
7943
7944   // this is weird...
7945   //  pic16_deallocateAllRegs();
7946
7947   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7948     if(!pb->visited)
7949       register_usage(pb);
7950   }
7951 #endif
7952
7953 }
7954
7955 /*-----------------------------------------------------------------*/
7956 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7957 /*                all of the logical connections.                  */
7958 /*                                                                 */
7959 /* Essentially what's done here is that the pCode flow is          */
7960 /* determined.                                                     */
7961 /*-----------------------------------------------------------------*/
7962
7963 void pic16_AnalyzepCode(char dbName)
7964 {
7965   pBlock *pb;
7966   int i,changes;
7967
7968   if(!the_pFile)
7969     return;
7970
7971   mergepBlocks('D');
7972
7973
7974   /* Phase 1 - Register allocation and peep hole optimization
7975    *
7976    * The first part of the analysis is to determine the registers
7977    * that are used in the pCode. Once that is done, the peep rules
7978    * are applied to the code. We continue to loop until no more
7979    * peep rule optimizations are found (or until we exceed the
7980    * MAX_PASSES threshold). 
7981    *
7982    * When done, the required registers will be determined.
7983    *
7984    */
7985   i = 0;
7986   do {
7987
7988     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7989     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7990
7991     /* First, merge the labels with the instructions */
7992     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7993       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7994
7995         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7996         //fprintf(stderr," analyze and merging block %c\n",dbName);
7997         pic16_pBlockMergeLabels(pb);
7998         AnalyzepBlock(pb);
7999       } else {
8000         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
8001       }
8002     }
8003
8004         if(!options.nopeep)
8005                 changes = OptimizepCode(dbName);
8006         else changes = 0;
8007
8008   } while(changes && (i++ < MAX_PASSES));
8009
8010   
8011   buildCallTree();
8012 }
8013
8014
8015 /* convert a series of movff's of local regs to stack, with a single call to
8016  * a support functions which does the same thing via loop */
8017 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8018 {
8019   pBranch *pbr;
8020   pCode *pc, *pct;
8021   char *fname[]={"__lr_store", "__lr_restore"};
8022
8023 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8024
8025     pct = pic16_findNextInstruction(pcstart->next);
8026     do {
8027       pc = pct;
8028       pct = pc->next;   //pic16_findNextInstruction(pc->next);
8029 //      pc->print(stderr, pc);
8030       if(isPCI(pc) && PCI(pc)->label) {
8031         pbr = PCI(pc)->label;
8032         while(pbr && pbr->pc) {
8033           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8034           pbr = pbr->next;
8035         }
8036
8037 //        pc->print(stderr, pc);
8038         /* unlink pCode */
8039         pc->prev->next = pct;
8040         pct->prev = pc->prev;
8041 //        pc->next = NULL;
8042 //        pc->prev = NULL;
8043       }
8044     } while ((pc) && (pc != pcend));
8045
8046     /* unlink movff instructions */
8047     pcstart->next = pcend;
8048     pcend->prev = pcstart;
8049
8050     pc = pcstart;
8051 //    if(!entry) {
8052 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8053 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8054 //    }
8055                 
8056     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8057     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8058     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8059
8060 //    if(!entry) {
8061 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8062 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8063 //    }
8064
8065     
8066     {
8067       symbol *sym;
8068
8069         sym = newSymbol( fname[ entry?0:1 ], 0 );
8070         strcpy(sym->rname, fname[ entry?0:1 ]);
8071         checkAddSym(&externs, sym);
8072         
8073 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8074     }
8075
8076 }
8077
8078 /*-----------------------------------------------------------------*/
8079 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8080 /*    local registers to a support function call                   */
8081 /*-----------------------------------------------------------------*/
8082 void pic16_OptimizeLocalRegs(void)
8083 {
8084   pBlock  *pb;
8085   pCode   *pc;
8086   pCodeInfo *pci;
8087   pCodeOpLocalReg *pclr;
8088   int regCount=0;
8089   int inRegCount=0;
8090   regs *r, *lastr=NULL, *firstr=NULL;
8091   pCode *pcstart=NULL, *pcend=NULL;
8092   int inEntry=0;
8093   char *curFunc=NULL;
8094
8095         /* Overview:
8096          *   local_regs begin mark
8097          *      MOVFF r0x01, POSTDEC1
8098          *      MOVFF r0x02, POSTDEC1
8099          *      ...
8100          *      ...
8101          *      MOVFF r0x0n, POSTDEC1
8102          *   local_regs end mark
8103          *
8104          * convert the above to the below:
8105          *      MOVLW   starting_register_index
8106          *      MOVWF   PRODL
8107          *      MOVLW   register_count
8108          *      call    __save_registers_in_stack
8109          */
8110
8111     if(!the_pFile)
8112       return;
8113
8114     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8115       inRegCount = regCount = 0;
8116       firstr = lastr = NULL;
8117       for(pc = pb->pcHead; pc; pc = pc->next) {
8118
8119         /* hold current function name */
8120         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8121         
8122         if(pc && (pc->type == PC_INFO)) {
8123           pci = PCINF(pc);
8124
8125           if(pci->type == INF_LOCALREGS) {
8126             pclr = PCOLR(pci->oper1);
8127             
8128             if((pclr->type == LR_ENTRY_BEGIN)
8129               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8130             else inEntry = 0;
8131             
8132             switch(pclr->type) {
8133               case LR_ENTRY_BEGIN:
8134               case LR_EXIT_BEGIN:
8135                         inRegCount = 1; regCount = 0;
8136                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8137                         firstr = lastr = NULL;
8138                         break;
8139               
8140               case LR_ENTRY_END:
8141               case LR_EXIT_END:
8142                         inRegCount = -1;
8143                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8144
8145 #if 1
8146                         if(curFunc && inWparamList(curFunc+1)) {
8147                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8148                                         filename, curFunc);
8149                         } else {
8150                           if(regCount>2) {
8151                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8152                               firstr, inEntry);
8153                           }
8154                         }
8155 #endif
8156                         firstr = lastr = NULL;
8157                         break;
8158             }
8159             
8160             if(inRegCount == -1) {
8161 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8162               regCount = 0;
8163               inRegCount = 0;
8164             }
8165           }
8166         } else {
8167           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8168             if(inEntry)
8169               r = pic16_getRegFromInstruction(pc);
8170             else
8171               r = pic16_getRegFromInstruction2(pc);
8172             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8173               if(!firstr)firstr = r;
8174               regCount++;
8175 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8176             }
8177           }
8178         }
8179       }
8180     }
8181 }
8182               
8183             
8184
8185
8186
8187 /*-----------------------------------------------------------------*/
8188 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8189 /*                   function                                      */
8190 /*-----------------------------------------------------------------*/
8191 static bool ispCodeFunction(pCode *pc)
8192 {
8193
8194   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8195     return 1;
8196
8197   return 0;
8198 }
8199
8200 /*-----------------------------------------------------------------*/
8201 /* findFunction - Search for a function by name (given the name)   */
8202 /*                in the set of all functions that are in a pBlock */
8203 /* (note - I expect this to change because I'm planning to limit   */
8204 /*  pBlock's to just one function declaration                      */
8205 /*-----------------------------------------------------------------*/
8206 static pCode *findFunction(char *fname)
8207 {
8208   pBlock *pb;
8209   pCode *pc;
8210   if(!fname)
8211     return NULL;
8212
8213   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8214
8215     pc = setFirstItem(pb->function_entries);
8216     while(pc) {
8217     
8218       if((pc->type == PC_FUNCTION) &&
8219          (PCF(pc)->fname) && 
8220          (strcmp(fname, PCF(pc)->fname)==0))
8221         return pc;
8222
8223       pc = setNextItem(pb->function_entries);
8224
8225     }
8226
8227   }
8228   return NULL;
8229 }
8230
8231 static void MarkUsedRegisters(set *regset)
8232 {
8233
8234   regs *r1,*r2;
8235
8236   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8237 //      fprintf(stderr, "marking register = %s\t", r1->name);
8238     r2 = pic16_regWithIdx(r1->rIdx);
8239 //      fprintf(stderr, "to register = %s\n", r2->name);
8240     r2->isFree = 0;
8241     r2->wasUsed = 1;
8242   }
8243 }
8244
8245 static void pBlockStats(FILE *of, pBlock *pb)
8246 {
8247
8248   pCode *pc;
8249   regs  *r;
8250
8251         if(!pic16_pcode_verbose)return;
8252         
8253   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8254
8255   // for now just print the first element of each set
8256   pc = setFirstItem(pb->function_entries);
8257   if(pc) {
8258     fprintf(of,";entry:  ");
8259     pc->print(of,pc);
8260   }
8261   pc = setFirstItem(pb->function_exits);
8262   if(pc) {
8263     fprintf(of,";has an exit\n");
8264     //pc->print(of,pc);
8265   }
8266
8267   pc = setFirstItem(pb->function_calls);
8268   if(pc) {
8269     fprintf(of,";functions called:\n");
8270
8271     while(pc) {
8272       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8273         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8274       }
8275       pc = setNextItem(pb->function_calls);
8276     }
8277   }
8278
8279   r = setFirstItem(pb->tregisters);
8280   if(r) {
8281     int n = elementsInSet(pb->tregisters);
8282
8283     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8284
8285     while (r) {
8286       fprintf(of,   ";   %s\n",r->name);
8287       r = setNextItem(pb->tregisters);
8288     }
8289   }
8290   
8291   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8292 }
8293
8294 /*-----------------------------------------------------------------*/
8295 /*-----------------------------------------------------------------*/
8296 #if 0
8297 static void sequencepCode(void)
8298 {
8299   pBlock *pb;
8300   pCode *pc;
8301
8302
8303   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8304
8305     pb->seq = GpCodeSequenceNumber+1;
8306
8307     for( pc = pb->pcHead; pc; pc = pc->next)
8308       pc->seq = ++GpCodeSequenceNumber;
8309   }
8310
8311 }
8312 #endif
8313
8314 /*-----------------------------------------------------------------*/
8315 /*-----------------------------------------------------------------*/
8316 static set *register_usage(pBlock *pb)
8317 {
8318   pCode *pc,*pcn;
8319   set *registers=NULL;
8320   set *registersInCallPath = NULL;
8321
8322   /* check recursion */
8323
8324   pc = setFirstItem(pb->function_entries);
8325
8326   if(!pc)
8327     return registers;
8328
8329   pb->visited = 1;
8330
8331   if(pc->type != PC_FUNCTION)
8332     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8333
8334   pc = setFirstItem(pb->function_calls);
8335   for( ; pc; pc = setNextItem(pb->function_calls)) {
8336
8337     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8338       char *dest = pic16_get_op_from_instruction(PCI(pc));
8339
8340       pcn = findFunction(dest);
8341       if(pcn) 
8342         registersInCallPath = register_usage(pcn->pb);
8343     } else
8344       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8345
8346   }
8347
8348 #ifdef PCODE_DEBUG
8349   pBlockStats(stderr,pb);  // debug
8350 #endif
8351
8352   // Mark the registers in this block as used.
8353
8354   MarkUsedRegisters(pb->tregisters);
8355   if(registersInCallPath) {
8356     /* registers were used in the functions this pBlock has called */
8357     /* so now, we need to see if these collide with the ones we are */
8358     /* using here */
8359
8360     regs *r1,*r2, *newreg;
8361
8362     DFPRINTF((stderr,"comparing registers\n"));
8363
8364     r1 = setFirstItem(registersInCallPath);
8365     while(r1) {
8366
8367       r2 = setFirstItem(pb->tregisters);
8368
8369       while(r2 && (r1->type != REG_STK)) {
8370
8371         if(r2->rIdx == r1->rIdx) {
8372           newreg = pic16_findFreeReg(REG_GPR);
8373
8374
8375           if(!newreg) {
8376             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8377             exit(1);
8378           }
8379
8380           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8381                   r1->rIdx, newreg->rIdx));
8382           r2->rIdx = newreg->rIdx;
8383           //if(r2->name) Safe_free(r2->name);
8384           if(newreg->name)
8385             r2->name = Safe_strdup(newreg->name);
8386           else
8387             r2->name = NULL;
8388           newreg->isFree = 0;
8389           newreg->wasUsed = 1;
8390         }
8391         r2 = setNextItem(pb->tregisters);
8392       }
8393
8394       r1 = setNextItem(registersInCallPath);
8395     }
8396
8397     /* Collisions have been resolved. Now free the registers in the call path */
8398     r1 = setFirstItem(registersInCallPath);
8399     while(r1) {
8400       if(r1->type != REG_STK) {
8401         newreg = pic16_regWithIdx(r1->rIdx);
8402         newreg->isFree = 1;
8403       }
8404       r1 = setNextItem(registersInCallPath);
8405     }
8406
8407   }// else
8408   //    MarkUsedRegisters(pb->registers);
8409
8410   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8411 #ifdef PCODE_DEBUG
8412   if(registers) 
8413     DFPRINTF((stderr,"returning regs\n"));
8414   else
8415     DFPRINTF((stderr,"not returning regs\n"));
8416
8417   DFPRINTF((stderr,"pBlock after register optim.\n"));
8418   pBlockStats(stderr,pb);  // debug
8419 #endif
8420
8421   return registers;
8422 }
8423
8424 /*-----------------------------------------------------------------*/
8425 /* pct2 - writes the call tree to a file                           */
8426 /*                                                                 */
8427 /*-----------------------------------------------------------------*/
8428 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8429 {
8430   pCode *pc,*pcn;
8431   int i;
8432   //  set *registersInCallPath = NULL;
8433
8434   if(!of)
8435     return;
8436
8437   if(indent > 10) {
8438         fprintf(of, "recursive function\n");
8439     return; //recursion ?
8440   }
8441
8442   pc = setFirstItem(pb->function_entries);
8443
8444   if(!pc)
8445     return;
8446
8447   pb->visited = 0;
8448
8449   for(i=0;i<indent;i++)   // Indentation
8450         fputs("+   ", of);
8451   fputs("+- ", of);
8452
8453   if(pc->type == PC_FUNCTION) {
8454     usedstack += PCF(pc)->stackusage;
8455     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8456   } else return;  // ???
8457
8458
8459   pc = setFirstItem(pb->function_calls);
8460   for( ; pc; pc = setNextItem(pb->function_calls)) {
8461
8462     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8463       char *dest = pic16_get_op_from_instruction(PCI(pc));
8464
8465       pcn = findFunction(dest);
8466       if(pcn) 
8467         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8468     } else
8469       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8470
8471   }
8472
8473
8474 }
8475
8476
8477 /*-----------------------------------------------------------------*/
8478 /* pic16_printCallTree - writes the call tree to a file                  */
8479 /*                                                                 */
8480 /*-----------------------------------------------------------------*/
8481
8482 void pic16_printCallTree(FILE *of)
8483 {
8484   pBranch *pbr;
8485   pBlock  *pb;
8486   pCode   *pc;
8487
8488   if(!the_pFile)
8489     return;
8490
8491   if(!of)
8492     of = stderr;
8493
8494   fprintf(of, "\npBlock statistics\n");
8495   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8496     pBlockStats(of,pb);
8497
8498
8499   fprintf(of,"Call Tree\n");
8500   pbr = the_pFile->functions;
8501   while(pbr) {
8502     if(pbr->pc) {
8503       pc = pbr->pc;
8504       if(!ispCodeFunction(pc))
8505         fprintf(of,"bug in call tree");
8506
8507
8508       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8509
8510       while(pc->next && !ispCodeFunction(pc->next)) {
8511         pc = pc->next;
8512         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8513           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8514       }
8515     }
8516
8517     pbr = pbr->next;
8518   }
8519
8520
8521   fprintf(of,"\n**************\n\na better call tree\n");
8522   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8523 //    if(pb->visited)
8524       pct2(of,pb,0,0);
8525   }
8526
8527   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8528     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8529   }
8530 }
8531
8532
8533
8534 /*-----------------------------------------------------------------*/
8535 /*                                                                 */
8536 /*-----------------------------------------------------------------*/
8537
8538 static void InlineFunction(pBlock *pb)
8539 {
8540   pCode *pc;
8541   pCode *pc_call;
8542
8543   if(!pb)
8544     return;
8545
8546   pc = setFirstItem(pb->function_calls);
8547
8548   for( ; pc; pc = setNextItem(pb->function_calls)) {
8549
8550     if(isCALL(pc)) {
8551       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8552       pCode *pct;
8553       pCode *pce;
8554
8555       pBranch *pbr;
8556
8557       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8558         
8559         //fprintf(stderr,"Cool can inline:\n");
8560         //pcn->print(stderr,pcn);
8561
8562         //fprintf(stderr,"recursive call Inline\n");
8563         InlineFunction(pcn->pb);
8564         //fprintf(stderr,"return from recursive call Inline\n");
8565
8566         /*
8567           At this point, *pc points to a CALL mnemonic, and
8568           *pcn points to the function that is being called.
8569
8570           To in-line this call, we need to remove the CALL
8571           and RETURN(s), and link the function pCode in with
8572           the CALLee pCode.
8573
8574         */
8575
8576
8577         /* Remove the CALL */
8578         pc_call = pc;
8579         pc = pc->prev;
8580
8581         /* remove callee pBlock from the pBlock linked list */
8582         removepBlock(pcn->pb);
8583
8584         pce = pcn;
8585         while(pce) {
8586           pce->pb = pb;
8587           pce = pce->next;
8588         }
8589
8590         /* Remove the Function pCode */
8591         pct = pic16_findNextInstruction(pcn->next);
8592
8593         /* Link the function with the callee */
8594         pc->next = pcn->next;
8595         pcn->next->prev = pc;
8596         
8597         /* Convert the function name into a label */
8598
8599         pbr = Safe_calloc(1,sizeof(pBranch));
8600         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8601         pbr->next = NULL;
8602         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8603         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8604
8605         /* turn all of the return's except the last into goto's */
8606         /* check case for 2 instruction pBlocks */
8607         pce = pic16_findNextInstruction(pcn->next);
8608         while(pce) {
8609           pCode *pce_next = pic16_findNextInstruction(pce->next);
8610
8611           if(pce_next == NULL) {
8612             /* found the last return */
8613             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8614
8615             //fprintf(stderr,"found last return\n");
8616             //pce->print(stderr,pce);
8617             pce->prev->next = pc_call->next;
8618             pc_call->next->prev = pce->prev;
8619             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8620                                                       PCI(pce)->label);
8621           }
8622
8623           pce = pce_next;
8624         }
8625
8626
8627       }
8628     } else
8629       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8630
8631   }
8632
8633 }
8634
8635 /*-----------------------------------------------------------------*/
8636 /*                                                                 */
8637 /*-----------------------------------------------------------------*/
8638
8639 void pic16_InlinepCode(void)
8640 {
8641
8642   pBlock  *pb;
8643   pCode   *pc;
8644
8645   if(!the_pFile)
8646     return;
8647
8648   if(!functionInlining)
8649     return;
8650
8651   /* Loop through all of the function definitions and count the
8652    * number of times each one is called */
8653   //fprintf(stderr,"inlining %d\n",__LINE__);
8654
8655   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8656
8657     pc = setFirstItem(pb->function_calls);
8658
8659     for( ; pc; pc = setNextItem(pb->function_calls)) {
8660
8661       if(isCALL(pc)) {
8662         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8663         if(pcn && isPCF(pcn)) {
8664           PCF(pcn)->ncalled++;
8665         }
8666       } else
8667         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8668
8669     }
8670   }
8671
8672   //fprintf(stderr,"inlining %d\n",__LINE__);
8673
8674   /* Now, Loop through the function definitions again, but this
8675    * time inline those functions that have only been called once. */
8676   
8677   InlineFunction(the_pFile->pbHead);
8678   //fprintf(stderr,"inlining %d\n",__LINE__);
8679
8680   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8681     unBuildFlow(pb);
8682
8683 }
8684
8685 char *pic_optype_names[]={
8686         "PO_NONE",         // No operand e.g. NOP
8687         "PO_W",              // The working register (as a destination)
8688         "PO_WREG",           // The working register (as a file register)
8689         "PO_STATUS",         // The 'STATUS' register
8690         "PO_BSR",            // The 'BSR' register
8691         "PO_FSR0",           // The "file select register" (in PIC18 family it's one 
8692                              // of three)
8693         "PO_INDF0",          // The Indirect register
8694         "PO_INTCON",         // Interrupt Control register
8695         "PO_GPR_REGISTER",   // A general purpose register
8696         "PO_GPR_BIT",        // A bit of a general purpose register
8697         "PO_GPR_TEMP",       // A general purpose temporary register
8698         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8699         "PO_PCL",            // Program counter Low register
8700         "PO_PCLATH",         // Program counter Latch high register
8701         "PO_PCLATU",         // Program counter Latch upper register
8702         "PO_PRODL",          // Product Register Low
8703         "PO_PRODH",          // Product Register High
8704         "PO_LITERAL",        // A constant
8705         "PO_REL_ADDR",       // A relative address
8706         "PO_IMMEDIATE",      //  (8051 legacy)
8707         "PO_DIR",            // Direct memory (8051 legacy)
8708         "PO_CRY",            // bit memory (8051 legacy)
8709         "PO_BIT",            // bit operand.
8710         "PO_STR",            //  (8051 legacy)
8711         "PO_LABEL",
8712         "PO_WILD"            // Wild card operand in peep optimizer
8713 };
8714
8715
8716 char *dumpPicOptype(PIC_OPTYPE type)
8717 {
8718         return (pic_optype_names[ type ]);
8719 }
8720
8721
8722 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8723 #include "graph.h"
8724
8725 #define MAX_COMMON_BANK_SIZE    32
8726 #define FIRST_PSEUDO_BANK_NR  1000
8727
8728 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8729 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8730 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8731 Graph *adj = NULL;
8732
8733 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8734
8735 typedef struct {
8736   pseudoBankNr bank;  // number assigned to this pseudoBank
8737   unsigned int size;  // number of operands assigned to this bank
8738   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8739 } pseudoBank;
8740
8741 /*----------------------------------------------------------------------*/
8742 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8743 /*----------------------------------------------------------------------*/
8744 unsigned int hashSymbol (const char *str)
8745 {
8746   unsigned int res = 0;
8747   if (!str) return 0;
8748
8749   while (*str) {
8750     res ^= (*str);
8751     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8752     str++;
8753   } // while
8754
8755   return res;
8756 }
8757
8758 /*-----------------------------------------------------------------------*/
8759 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8760 /*-----------------------------------------------------------------------*/
8761 int compareSymbol (const void *sym1, const void *sym2)
8762 {
8763   char *s1 = (char*) sym1;
8764   char *s2 = (char*) sym2;
8765   
8766   return (strcmp (s1,s2) == 0);
8767 }
8768
8769 /*-----------------------------------------------------------------------*/
8770 /* comparePre - return 1 iff p1 == p2                                    */
8771 /*-----------------------------------------------------------------------*/
8772 int comparePtr (const void *p1, const void *p2)
8773 {
8774   return (p1 == p2);
8775 }
8776
8777 /*----------------------------------------------------------*/
8778 /* getSymbolFromOperand - return a pointer to the symbol in */
8779 /*                        the given operand and its length  */
8780 /*----------------------------------------------------------*/
8781 char *getSymbolFromOperand (char *op, unsigned int *len)
8782 {
8783   char *sym, *curr;
8784   *len = 0;
8785
8786   if (!op) return NULL;
8787
8788   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8789   sym = op;
8790   if (*sym == '(') sym++;
8791
8792   curr = sym;
8793   while (((*curr >= 'A') && (*curr <= 'Z'))
8794          || ((*curr >= 'a') && (*curr <= 'z'))
8795          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8796          || (*curr == '_')) {
8797     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8798     curr++;
8799     (*len)++;
8800   } // while
8801
8802   return sym;
8803 }
8804
8805 /*--------------------------------------------------------------------------*/
8806 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8807 /*--------------------------------------------------------------------------*/
8808 char *getSymFromBank (pseudoBankNr bank)
8809 {
8810   assert (bank2sym);
8811
8812   if (bank < 0) return "<INVALID BANK NR>";
8813   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8814 }
8815
8816 /*-----------------------------------------------------------------------*/
8817 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8818 /*                           bank number (uses hTab sym2bank), if the    */
8819 /*                           symbol is not yet assigned a pseudo bank it */
8820 /*                           is assigned one here                        */
8821 /*-----------------------------------------------------------------------*/
8822 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8823 {
8824   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8825   pseudoBankNr bank;
8826   unsigned int hash;
8827
8828   assert (sym2bank);
8829
8830   hash = hashSymbol (op) % sym2bank->size;
8831   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8832   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8833
8834   if (bank == UNKNOWN_BANK) {
8835     // create a pseudo bank for the operand
8836     bank = next_bank++;
8837     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8838     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8839     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8840     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8841   } else {
8842     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8843   } // if
8844
8845   assert (bank >= 0);
8846
8847   return bank;
8848 }
8849
8850 /*--------------------------------------------------------------------*/
8851 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8852 /*--------------------------------------------------------------------*/
8853 int isBanksel (pCode *pc)
8854 {
8855   if (!pc) return 0;
8856
8857   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8858     // BANKSEL <variablename>  or  MOVLB <banknr>
8859     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8860     return 1;
8861   }
8862
8863   // check for inline assembler BANKSELs
8864   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8865                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8866     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8867     return 1;
8868   }
8869
8870   // assume pc is no BANKSEL instruction
8871   return 0;
8872 }
8873
8874 /*---------------------------------------------------------------------------------*/
8875 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8876 /*                  This method can not guarantee to find all modifications of the */
8877 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8878 /*                  generated plus some cases.                                     */
8879 /*---------------------------------------------------------------------------------*/
8880 int invalidatesBSR(pCode *pc)
8881 {
8882   // assembler directives invalidate BSR (well, they might, we don't know)
8883   if (isPCAD(pc)) return 1;
8884
8885   // only ASMDIRs and pCodeInstructions can invalidate BSR
8886   if (!isPCI(pc)) return 0;
8887
8888   // we have a pCodeInstruction
8889
8890   // check for BSR modifying instructions
8891   switch (PCI(pc)->op) {
8892   case POC_CALL:
8893   case POC_RCALL:
8894   case POC_MOVLB:
8895   case POC_RETFIE:  // might be used as CALL replacement
8896   case POC_RETLW:   // might be used as CALL replacement
8897   case POC_RETURN:  // might be used as CALL replacement
8898   case POC_BANKSEL:
8899     return 1;
8900     break;
8901
8902   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8903     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8904     break;
8905   } // switch
8906
8907   // no change of BSR possible/probable
8908   return 0;
8909 }
8910
8911 /*------------------------------------------------------------*/
8912 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8913 /*                      the symbol referenced in this BANKSEL */
8914 /*------------------------------------------------------------*/
8915 pseudoBankNr getBankFromBanksel (pCode *pc)
8916 {
8917   char *sym;
8918   int data = (int)NULL;
8919
8920   if (!pc) return INVALID_BANK;
8921   
8922   if (isPCAD(pc) && PCAD(pc)->directive) {
8923     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8924       // get symbolname from PCAD(pc)->arg
8925       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8926       sym = PCAD(pc)->arg;
8927       data = getPseudoBankNrFromOperand (sym);
8928       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8929     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8930       // get (literal) bank number from PCAD(pc)->arg
8931       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8932       assert (0 && "not yet implemented - turn off banksel optimization for now");
8933     }
8934   } else if (isPCI(pc)) {
8935     if (PCI(pc)->op == POC_BANKSEL) {
8936       // get symbolname from PCI(pc)->pcop->name (?)
8937       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8938       sym = PCI(pc)->pcop->name;
8939       data = getPseudoBankNrFromOperand (sym);
8940       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8941     } else if (PCI(pc)->op == POC_MOVLB) {
8942       // get (literal) bank number from PCI(pc)->pcop->name
8943       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8944       assert (0 && "not yet implemented - turn off banksel optimization for now");
8945     }
8946   }
8947   
8948   if (data == 0)
8949     // no assigned bank could be found
8950     return UNKNOWN_BANK;
8951   else
8952     return data;
8953 }
8954
8955 /*------------------------------------------------------------------------------*/
8956 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8957 /*------------------------------------------------------------------------------*/
8958 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8959 {
8960   pseudoBank *data;
8961
8962   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8963
8964   do {
8965     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8966     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8967     if (data) {
8968       if (data->bank != bank)
8969         bank = data->bank;
8970       else
8971         data = NULL;
8972     }
8973   } while (data);
8974   
8975   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8976   return bank;
8977 }
8978
8979 /*------------------------------------------------------------------*/
8980 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8981 /*                        bank is selected at a given pCode         */
8982 /*------------------------------------------------------------------*/
8983
8984 /* Create a graph with pseudo banks as its nodes and switches between
8985  * these as edges (with the edge weight representing the absolute
8986  * number of BANKSELs from one to the other).
8987  * Removes redundand BANKSELs instead iff mod == 1.
8988  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8989  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8990  * pseudo BSR.
8991  * TODO: check ALL instructions operands if they modify BSR directly...
8992  *
8993  * pb - the pBlock to annotate
8994  * mod  - select either graph creation (0) or BANKSEL removal (1)
8995  */
8996 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8997 {
8998   pCode *pc, *pc_next;
8999   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
9000   int isBankselect = 0;
9001   unsigned int banksels=0;
9002   
9003   if (!pb) return 0;
9004
9005   pc = pic16_findNextInstruction(pb->pcHead);
9006   while (pc) {
9007     isBankselect = isBanksel (pc);
9008     pc_next = pic16_findNextInstruction (pc->next);
9009
9010     if (!hasNoLabel (pc)) {
9011       // we don't know our predecessors -- assume different BSRs
9012       prevBSR = UNKNOWN_BANK;
9013       pseudoBSR = UNKNOWN_BANK;
9014       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9015     } // if
9016
9017     // check if this is a BANKSEL instruction
9018     if (isBankselect) {
9019       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9020       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9021       if (mod) {
9022         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9023           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9024           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9025           pic16_unlinkpCode (pc);
9026           banksels++;
9027         }
9028       } else {
9029         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9030         banksels++;
9031       }
9032     } // if
9033
9034     if (!isBankselect && invalidatesBSR(pc)) {
9035       // check if this instruction invalidates the pseudoBSR
9036       pseudoBSR = UNKNOWN_BANK;
9037       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9038     } // if
9039
9040     prevBSR = pseudoBSR;
9041     pc = pc_next;
9042   } // while
9043
9044   return banksels;
9045 }
9046
9047 /*------------------------------------------------------------------------------------*/
9048 /* assignToSameBank - returns 0 on success or an error code                           */
9049 /*  1 - common bank would be too large                                                */
9050 /*  2 - assignment to fixed (absolute) bank not performed                             */
9051 /*                                                                                    */
9052 /* This functions assumes that unsplittable operands are already assigned to the same */
9053 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9054 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9055 /* TODO: Symbols with an abslute address must be handled specially!                   */
9056 /*------------------------------------------------------------------------------------*/
9057 int assignToSameBank (int bank0, int bank1, int doAbs)
9058 {
9059   int eff0, eff1, dummy;
9060   pseudoBank *pbank0, *pbank1;
9061   hashtItem *hitem;
9062
9063   eff0 = getEffectiveBank (bank0);
9064   eff1 = getEffectiveBank (bank1);
9065
9066   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9067
9068   // nothing to do if already same bank
9069   if (eff0 == eff1) return 0;
9070
9071   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9072     return 2;
9073
9074   // ensure eff0 < eff1
9075   if (eff0 > eff1) {
9076     // swap eff0 and eff1
9077     dummy = eff0;
9078     eff0 = eff1;
9079     eff1 = dummy;
9080     dummy = bank0;
9081     bank0 = bank1;
9082     bank1 = dummy;
9083   } // if
9084
9085   // now assign bank eff1 to bank eff0
9086   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9087   if (!pbank0) {
9088     pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9089     pbank0->bank = eff0;
9090     pbank0->size = 1;
9091     pbank0->ref = 1;
9092     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9093   } // if
9094
9095   pbank1 = NULL;
9096   hitem = hTabSearch (coerce, eff1 % coerce->size);
9097   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9098     hitem = hitem->next;
9099
9100   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9101
9102 #if 0
9103   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9104            pbank0->bank, pbank0->size,
9105            getSymFromBank (eff0), getSymFromBank (eff1));
9106 #endif
9107
9108   if (pbank1) {
9109     if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9110 #if 0
9111       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9112                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9113                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9114                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9115 #endif
9116       return 1;
9117     } // if
9118     pbank0->size += pbank1->size;
9119     pbank1->ref--;
9120     if (pbank1->ref == 0) Safe_free (pbank1);
9121   } else {
9122     pbank0->size++;
9123   } // if
9124
9125   if (hitem)
9126     hitem->item = pbank0;
9127   else  
9128     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9129   pbank0->ref++;
9130
9131   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9132
9133   return 0;
9134 }
9135
9136 /*----------------------------------------------------------------*/
9137 /* mergeGraphNodes - combines two nodes into one and modifies all */
9138 /*                   edges to and from the nodes accordingly      */
9139 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9140 /* then also (B,A) must be an edge (possibly with weight 0).      */
9141 /*----------------------------------------------------------------*/
9142 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9143 {
9144   GraphEdge *edge, *backedge, *nextedge;
9145   GraphNode *node;
9146   int backweight;
9147
9148   assert (node1 && node2);
9149   assert (node1 != node2);
9150   
9151   // add all edges starting at node2 to node1
9152   edge = node2->edge;
9153   while (edge) {
9154     nextedge = edge->next;
9155     node = edge->node;
9156     backedge = getGEdge (node, node2);
9157     if (backedge)
9158       backweight = backedge->weight;
9159     else
9160       backweight = 0;
9161     // insert edges (node1,node) and (node,node1)
9162     addGEdge2 (node1, node, edge->weight, backweight);
9163     // remove edges (node, node2) and (node2, node)
9164     remGEdge (node2, node);
9165     remGEdge (node, node2);
9166     edge = nextedge;
9167   } // while
9168   
9169   // now node2 should not be referenced by any other GraphNode...
9170   //remGNode (adj, node2->data, node2->hash);
9171 }
9172
9173 /*----------------------------------------------------------------*/
9174 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9175 /*----------------------------------------------------------------*/
9176 void showGraph (Graph *g)
9177 {
9178   GraphNode *node;
9179   GraphEdge *edge;
9180   pseudoBankNr bankNr;
9181   pseudoBank *pbank;
9182   unsigned int size;
9183
9184   node = g->node;
9185   while (node) {
9186     edge = node->edge;
9187     bankNr = getEffectiveBank (node->hash);
9188     assert (bankNr >= 0);
9189     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9190     if (pbank) {
9191       bankNr = pbank->bank;
9192       size = pbank->size;
9193     } else {
9194       size = 1;
9195     }
9196     
9197     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9198
9199     while (edge) {
9200       if (edge->weight > 0)
9201         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9202       edge = edge->next;
9203     } // while (edge)
9204     node = node->next;
9205   } // while (node)
9206 }
9207
9208 /*---------------------------------------------------------------*/
9209 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9210 /*---------------------------------------------------------------*/
9211 void pic16_OptimizeBanksel ()
9212 {
9213   GraphNode *node, *node1, *node1next;
9214
9215 #if 0
9216   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9217   GraphEdge *edge, *backedge;
9218   GraphEdge *max;
9219   int maxWeight, weight, mergeMore, absMaxWeight;
9220   pseudoBankNr curr0, curr1;
9221 #endif
9222   pseudoBank *pbank;
9223   pseudoBankNr bankNr;
9224   char *base_symbol0, *base_symbol1;
9225   int len0, len1;
9226   pBlock *pb;
9227   set *set;
9228   regs *reg;
9229   unsigned int bankselsTotal = 0, bankselsRemoved = 0; 
9230
9231   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9232
9233   if (!the_pFile || !the_pFile->pbHead) return;
9234
9235   adj = newGraph (NULL);
9236   sym2bank = newHashTable ( 255 );
9237   bank2sym = newHashTable ( 255 );
9238   coerce = newHashTable ( 255 );
9239
9240   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9241   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9242     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9243   } // for pb
9244
9245 #if 1
9246   // assign symbols with absolute addresses to their respective bank nrs
9247   set = pic16_fix_udata;
9248   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9249     bankNr = reg->address >> 8;
9250     node = getOrAddGNode (adj, NULL, bankNr);
9251     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9252     assignToSameBank (node->hash, bankNr, 1);
9253     
9254     assert (bankNr >= 0);
9255     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9256     if (!pbank) {
9257       pbank = Safe_calloc (1, sizeof (pseudoBank));
9258       pbank->bank = reg->address >> 8; //FIXED_BANK;
9259       pbank->size = 1;
9260       pbank->ref = 1;
9261       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9262     } else {
9263       assert (pbank->bank == (reg->address >> 8));
9264       pbank->bank = reg->address >> 8; //FIXED_BANK;
9265     }
9266     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9267   } // for reg
9268 #endif
9269
9270 #if 1
9271   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9272   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9273   node = adj->node;
9274   while (node) {
9275     if (node->hash < 0) { node = node->next; continue; }
9276     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9277     node1 = node->next;
9278     while (node1) {
9279       if (node1->hash < 0) { node1 = node1->next; continue; }
9280       node1next = node1->next;
9281       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9282       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9283         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9284         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9285         if (assignToSameBank (node->hash, node1->hash, 0)) {
9286           fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9287           assert (0 && "Could not assign a symbol to a bank!");
9288         }
9289         mergeGraphNodes (node, node1);
9290         /*
9291         if (node->hash < node1->hash)
9292           mergeGraphNodes (node, node1);
9293         else
9294           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9295         */
9296       } // if
9297       node1 = node1next;
9298     } // while (node1)
9299     node = node->next;
9300   } // while (node)
9301 #endif
9302
9303 #if 0
9304   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9305   // assign tightly coupled operands to the same (pseudo) bank
9306   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9307   mergeMore = 1;
9308   absMaxWeight = 0;
9309   while (mergeMore) {
9310     node = adj->node;
9311     max = NULL;
9312     maxWeight = 0;
9313     while (node) {
9314       curr0 = getEffectiveBank (node->hash);
9315       if (curr0 < 0) { node = node->next; continue; }
9316       edge = node->edge;
9317       while (edge) {
9318         assert (edge->src == node);
9319         backedge = getGEdge (edge->node, edge->src);
9320         weight = edge->weight + (backedge ? backedge->weight : 0);
9321         curr1 = getEffectiveBank (edge->node->hash);
9322         if (curr1 < 0) { edge = edge->next; continue; }
9323
9324         // merging is only useful if the items are not assigned to the same bank already...
9325         if (curr0 != curr1 && weight > maxWeight) {
9326           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9327           maxWeight = weight;
9328           max = edge;
9329         } // if
9330         edge = edge->next;
9331       } // while
9332       node = node->next;
9333     } // while
9334     
9335     if (maxWeight > 0) {
9336 #if 0
9337       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9338                max->src->hash, getSymFromBank (max->src->hash),
9339                max->node->hash, getSymFromBank (max->node->hash));
9340 #endif
9341
9342       node = getGNode (adj, max->src->data, max->src->hash);
9343       node1 = getGNode (adj, max->node->data, max->node->hash);
9344
9345       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9346         if (max->src->hash < max->node->hash)
9347           mergeGraphNodes (node, node1);
9348         else
9349           mergeGraphNodes (node1, node);
9350       } else {
9351         remGEdge (node, node1);
9352         remGEdge (node1, node);
9353         //mergeMore = 0;
9354       }
9355
9356     } else {
9357       mergeMore = 0;
9358     }
9359   } // while
9360 #endif
9361
9362 #if 1  
9363   // remove redundant BANKSELs
9364   //fprintf (stderr, "removing redundant BANKSELs\n");
9365   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9366     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9367   } // for pb
9368 #endif
9369
9370 #if 0
9371   fprintf (stderr, "display graph\n");
9372   showGraph ();
9373 #endif
9374
9375   deleteGraph (adj);
9376   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9377 }
9378
9379 /*** END of stuff belonging to the BANKSEL optimization ***/
9380
9381
9382
9383 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9384
9385 typedef unsigned int symbol_t;
9386 typedef unsigned int valnum_t;
9387 //typedef unsigned int hash_t;
9388
9389 #ifndef INT_TO_PTR
9390 #define INT_TO_PTR(x) (((char *) 0) + (x))
9391 #endif
9392
9393 #ifndef PTR_TO_INT
9394 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9395 #endif
9396
9397 /* statistics */
9398 static unsigned int pic16_df_removed_pcodes = 0;
9399 static unsigned int pic16_df_saved_bytes = 0;
9400 static unsigned int df_findall_sameflow = 0;
9401 static unsigned int df_findall_otherflow = 0;
9402 static unsigned int df_findall_in_vals = 0;
9403
9404 static void pic16_df_stats () {
9405   return;
9406   if (pic16_debug_verbose || pic16_pcode_verbose) {
9407     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9408     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9409     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9410   }
9411 }
9412
9413 /* Remove a pCode iff possible:
9414  * - previous pCode is no SKIP
9415  * - pc has no label
9416  * Returns 1 iff the pCode has been removed, 0 otherwise. */
9417 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9418   pCode *pcprev, *pcnext;
9419   char buf[256], *total=NULL;
9420   int len;
9421   
9422   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9423
9424   pcprev = pic16_findPrevInstruction (pc->prev);
9425   pcnext = pic16_findNextInstruction (pc->next);
9426   
9427   /* if previous instruction is a skip -- do not remove */
9428   if (pcprev && isPCI_SKIP(pcprev)) return 0;
9429
9430   /* move labels to next instruction (if possible) */
9431   if (PCI(pc)->label && !pcnext) return 0;
9432
9433   if (PCI(pc)->label) {
9434     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9435     //pc->print (stderr, pc);
9436     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9437     PCI(pc)->label = NULL;
9438   }
9439   
9440   /* update statistics */
9441   pic16_df_removed_pcodes++;
9442   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9443   
9444   /* remove the pCode */
9445   pic16_pCode2str (buf, 256, pc);
9446   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9447   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9448     len = strlen (buf) + strlen (comment) + 10;
9449     total = (char *) Safe_malloc (len);
9450     SNPRINTF (total, len, "%s: %s", comment, buf);
9451     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9452     Safe_free (total);
9453   }
9454
9455   /* actually unlink it from the pBlock -- also remove from to/from lists */
9456   pic16_pCodeUnlink (pc);
9457
9458   /* remove the pCode -- release registers */
9459   pc->destruct (pc);
9460
9461   /* report success */
9462   return 1;
9463 }
9464
9465
9466 /* ======================================================================== */
9467 /* === SYMBOL HANDLING ==================================================== */
9468 /* ======================================================================== */
9469
9470 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9471 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9472 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9473
9474 /** Calculate a hash for a given string.
9475  * If len == 0 the string is assumed to be NUL terminated. */
9476 static hash_t symbolHash (const char *str, unsigned int len) {
9477   hash_t hash = 0;
9478   if (!len) {
9479     while (*str) {
9480       hash = (hash << 2) ^ *str;
9481       str++;
9482     } // while
9483   } else {
9484     while (len--) {
9485       hash = (hash << 2) ^ *str;
9486       str++;
9487     }
9488   }
9489   return hash;
9490 }
9491
9492 /** Return 1 iff strings v1 and v2 are identical. */
9493 static int symcmp (const void *v1, const void *v2) {
9494   return !strcmp ((const char *) v1, (const char *) v2);
9495 }
9496
9497 /** Return 1 iff pointers v1 and v2 are identical. */
9498 static int ptrcmp (const void *v1, const void *v2) {
9499   return (v1 == v2);
9500 }
9501
9502 enum {  SPO_WREG=0x1000,
9503         SPO_STATUS,
9504         SPO_PRODL,
9505         SPO_PRODH,
9506         SPO_INDF0,
9507         SPO_POSTDEC0,
9508         SPO_POSTINC0,
9509         SPO_PREINC0,
9510         SPO_PLUSW0,
9511         SPO_INDF1,
9512         SPO_POSTDEC1,
9513         SPO_POSTINC1,
9514         SPO_PREINC1,
9515         SPO_PLUSW1,
9516         SPO_INDF2,
9517         SPO_POSTDEC2,
9518         SPO_POSTINC2,
9519         SPO_PREINC2,
9520         SPO_PLUSW2,
9521         SPO_STKPTR,
9522         SPO_TOSL,
9523         SPO_TOSH,
9524         SPO_TOSU,
9525         SPO_BSR,
9526         SPO_FSR0L,
9527         SPO_FSR0H,
9528         SPO_FSR1L,
9529         SPO_FSR1H,
9530         SPO_FSR2L,
9531         SPO_FSR2H,
9532         SPO_PCL,
9533         SPO_PCLATH,
9534         SPO_PCLATU,
9535         SPO_TABLAT,
9536         SPO_TBLPTRL,
9537         SPO_TBLPTRH,
9538         SPO_TBLPTRU,
9539         SPO_LAST
9540 };
9541
9542 /* Return the unique symbol_t for the given string. */
9543 static symbol_t symFromStr (const char *str) {
9544   hash_t hash;
9545   char *res;
9546   symbol_t sym;
9547
9548   if (!map_symToStr) {
9549     int i;
9550     struct { char *name; symbol_t sym; } predefsyms[] = {
9551         {"WREG", SPO_WREG},
9552         {"STATUS", SPO_STATUS},
9553         {"PRODL", SPO_PRODL},
9554         {"PRODH", SPO_PRODH},
9555         {"INDF0", SPO_INDF0},
9556         {"POSTDEC0", SPO_POSTDEC0},
9557         {"POSTINC0", SPO_POSTINC0},
9558         {"PREINC0", SPO_PREINC0},
9559         {"PLUSW0", SPO_PLUSW0},
9560         {"INDF1", SPO_INDF1},
9561         {"POSTDEC1", SPO_POSTDEC1},
9562         {"POSTINC1", SPO_POSTINC1},
9563         {"PREINC1", SPO_PREINC1},
9564         {"PLUSW1", SPO_PLUSW1},
9565         {"INDF2", SPO_INDF2},
9566         {"POSTDEC2", SPO_POSTDEC2},
9567         {"POSTINC2", SPO_POSTINC2},
9568         {"PREINC2", SPO_PREINC2},
9569         {"PLUSW2", SPO_PLUSW2},
9570         {"STKPTR", SPO_STKPTR},
9571         {"TOSL", SPO_TOSL},
9572         {"TOSH", SPO_TOSH},
9573         {"TOSU", SPO_TOSU},
9574         {"BSR", SPO_BSR},
9575         {"FSR0L", SPO_FSR0L},
9576         {"FSR0H", SPO_FSR0H},
9577         {"FSR1L", SPO_FSR1L},
9578         {"FSR1H", SPO_FSR1H},
9579         {"FSR2L", SPO_FSR2L},
9580         {"FSR2H", SPO_FSR2H},
9581         {"PCL", SPO_PCL},
9582         {"PCLATH", SPO_PCLATH},
9583         {"PCLATU", SPO_PCLATU},
9584         {"TABLAT", SPO_TABLAT},
9585         {"TBLPTRL", SPO_TBLPTRL},
9586         {"TBLPTRH", SPO_TBLPTRH},
9587         {"TBLPTRU", SPO_TBLPTRU},
9588         {NULL, 0}
9589     };
9590
9591     map_strToSym = newHashTable (128);
9592     map_symToStr = newHashTable (128);
9593
9594     for (i=0; predefsyms[i].name; i++) {
9595       char *name;
9596
9597       /* enter new symbol */
9598       sym = predefsyms[i].sym;
9599       name = predefsyms[i].name;
9600       res = Safe_strdup (name);
9601       hash = symbolHash (name, 0);
9602
9603       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9604       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9605     } // for i
9606   }
9607
9608   hash = symbolHash (str, 0) % map_strToSym->size;
9609   
9610   /* find symbol in table */
9611   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9612   if (sym) {
9613     //fprintf (stderr, "found symbol %u for %s\n", sym, str);
9614     return sym;
9615   }
9616
9617   /* enter new symbol */
9618   sym = nextSymbol++;
9619   res = Safe_strdup (str);
9620
9621   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9622   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9623
9624   //fprintf (stderr, "created symbol %u for %s\n", sym, res);
9625   
9626   return sym;
9627 }
9628
9629 #if 1
9630 static const char *strFromSym (symbol_t sym) {
9631   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9632 }
9633 #endif
9634
9635 /* ======================================================================== */
9636 /* === DEFINITION MAP HANDLING ============================================ */
9637 /* ======================================================================== */
9638
9639 /* A defmap provides information about which symbol is defined by which pCode.
9640  * The most recent definitions are prepended to the list, so that the most
9641  * recent definition can be found by forward scanning the list.
9642  * pc2: MOVFF r0x00, r0x01
9643  * pc1: INCF r0x01
9644  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9645  *
9646  * We attach one defmap to each flow object, and each pCode will occur at
9647  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9648  * used to find definitions for a pCode in its own defmap that precede pCode.
9649  */
9650
9651 typedef struct defmap_s {
9652   symbol_t sym;                 /** symbol this item refers to */
9653   union {
9654     struct {
9655       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9656       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9657       int isRead:1;             /** sym/mask is read */
9658       int isWrite:1;            /** sym/mask is written */
9659     } access;
9660     int accessmethod;
9661   } acc;
9662   pCode *pc;                    /** pCode this symbol is refrenced at */
9663   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9664   valnum_t val;                 /** new unique number for this value (if isWrite) */
9665   struct defmap_s *prev, *next; /** link to previous an next definition */
9666 } defmap_t;
9667
9668 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9669 static int defmap_free_count = 0;               /** number of released defmap items */
9670
9671 /* Returns a defmap_t with the specified data; this will be the new list head.
9672  * next - pointer to the current list head */
9673 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9674   defmap_t *map;
9675   
9676   if (defmap_free) {
9677     map = defmap_free;
9678     defmap_free = map->next;
9679     --defmap_free_count;
9680   } else {
9681     map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9682   }
9683   map->sym = sym;
9684   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9685   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9686   map->acc.access.isRead = (isRead != 0);
9687   map->acc.access.isWrite = (isWrite != 0);
9688   map->pc = pc;
9689   map->in_val = 0;
9690   map->val = (isWrite ? val : 0);
9691   map->prev = NULL;
9692   map->next = next;
9693   if (next) next->prev = map;
9694   
9695   return map;
9696 }
9697
9698 /* Returns a copy of the single defmap item. */
9699 static defmap_t *copyDefmap (defmap_t *map) {
9700   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9701   memcpy (res, map, sizeof (defmap_t));
9702   res->next = NULL;
9703   res->prev = NULL;
9704   return res;
9705 }
9706
9707 /* Insert a defmap item after the specified one. */
9708 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9709   if (!ref || !newItem) return 1;
9710
9711   newItem->next = ref->next;
9712   newItem->prev = ref;
9713   ref->next = newItem;
9714   if (newItem->next) newItem->next->prev = newItem;
9715   
9716   return 0;
9717 }
9718
9719 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9720  * item is copied before insertion into chain and therefore left untouched.
9721  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9722 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9723   defmap_t *dummy;
9724   dummy = *head;
9725   while (dummy && (dummy->sym != item->sym
9726                           || dummy->pc != item->pc
9727                           || dummy->acc.accessmethod != item->acc.accessmethod
9728                           || dummy->val != item->val
9729                           || dummy->in_val != item->in_val)) {
9730     dummy = dummy->next;
9731   } // while
9732
9733   /* item already present? */
9734   if (dummy) return 0;
9735   
9736   /* otherwise: insert copy of item */
9737   dummy = copyDefmap (item);
9738   dummy->next = *head;
9739   if (*head) (*head)->prev = dummy;
9740   *head = dummy;
9741
9742   return 1;
9743 }
9744
9745 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9746 static void deleteDefmap (defmap_t *map) {
9747   if (!map) return;
9748   
9749   /* unlink from chain -- fails for the first item (head is not updated!) */
9750   if (map->next) map->next->prev = map->prev;
9751   if (map->prev) map->prev->next = map->next;
9752
9753   /* clear map */
9754   memset (map, 0, sizeof (defmap_t));
9755
9756   /* save for future use */
9757   map->next = defmap_free;
9758   defmap_free = map;
9759   ++defmap_free_count;
9760 }
9761
9762 /* Release all defmaps referenced from map. */
9763 static void deleteDefmapChain (defmap_t **_map) {
9764   defmap_t *map, *next;
9765
9766   if (!_map) return;
9767
9768   map = *_map;
9769   
9770   /* find list head */
9771   while (map && map->prev) map = map->prev;
9772
9773   /* delete all items */
9774   while (map) {
9775     next = map->next;
9776     deleteDefmap (map);
9777     map = next;
9778   } // while
9779
9780   *_map = NULL;
9781 }
9782
9783 /* Free all defmap items. */
9784 static void freeDefmap (defmap_t **_map) {
9785   defmap_t *next;
9786   defmap_t *map;
9787
9788   if (!_map) return;
9789
9790   map = (*_map);
9791   
9792   /* find list head */
9793   while (map->prev) map = map->prev;
9794
9795   /* release all items */
9796   while (map) {
9797     next = map->next;
9798     Safe_free (map);
9799     map = next;
9800   }
9801
9802   (*_map) = NULL;
9803 }
9804
9805 /* Returns the most recent definition for the given symbol preceeding pc.
9806  * If no definition is found, NULL is returned. 
9807  * If pc == NULL the whole list is scanned. */
9808 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9809   defmap_t *curr = map;
9810
9811   if (pc) {
9812     /* skip all definitions up to pc */
9813     while (curr && (curr->pc != pc)) curr = curr->next;
9814
9815     /* pc not in the list -- scan the whole list for definitions */
9816     if (!curr) {
9817       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9818       curr = map;
9819     } else {
9820       /* skip all definitions performed by pc */
9821       while (curr && (curr->pc == pc)) curr = curr->next;
9822     }
9823   } // if (pc)
9824
9825   /* find definition for sym */
9826   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9827     curr = curr->next;
9828   }
9829
9830   return curr;
9831 }
9832
9833 #if 0
9834 /* Returns the first use (read) of the given symbol AFTER pc.
9835  * If no such use is found, NULL is returned.
9836  * If pc == NULL the whole list is scanned. */
9837 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9838   defmap_t *curr = map, *prev = NULL;
9839   
9840   if (pc) {
9841     /* skip all definitions up to pc */
9842     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9843
9844     /* pc not in the list -- scan the whole list for definitions */
9845     if (!curr) {
9846       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9847       curr = prev;
9848     }
9849   } else {
9850     /* find end of list */
9851     while (curr && curr->next) curr = curr->next;
9852   } // if (pc)
9853
9854   /* find use of sym (scan list backwards) */
9855   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9856
9857   return curr;
9858 }
9859 #endif
9860
9861 /* Return the defmap entry for sym AT pc. 
9862  * If none is found, NULL is returned.
9863  * If more than one entry is found an assertion is triggered. */
9864 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9865   defmap_t *res = NULL;
9866
9867   /* find entries for pc */
9868   while (map && map->pc != pc) map = map->next;
9869
9870   /* find first entry for sym @ pc */
9871   while (map && map->pc == pc && map->sym != sym) map = map->next;
9872
9873   /* no entry found */
9874   if (!map) return NULL;
9875
9876   /* check for more entries */
9877   res = map;
9878   map = map->next;
9879   while (map && map->pc == pc) {
9880     /* more than one entry for sym @ pc found? */
9881     assert (map->sym != sym);
9882     map = map->next;
9883   }
9884
9885   /* return single entry for sym @ pc */
9886   return res;
9887 }
9888
9889 /* Modifies the definition of sym at pCode to newval.
9890  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9891  */
9892 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9893   defmap_t *m  = map;
9894
9895   /* find definitions of pc */
9896   while (m && m->pc != pc) m = m->next;
9897
9898   /* find definition of sym at pc */
9899   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9900   
9901   /* no definition found */
9902   if (!m) return 1;
9903
9904   /* redefine */
9905   m->val = newval;
9906
9907   /* update following uses of sym */
9908   while (m && m->pc == pc) m = m->prev;
9909   while (m) {
9910     if (m->sym == sym) {
9911       m->in_val = newval;
9912       if (m->acc.access.isWrite) m = NULL;
9913     } // if
9914     if (m) m = m->prev;
9915   } // while
9916   
9917   return 0;
9918 }
9919
9920 /* ======================================================================== */
9921 /* === STACK ROUTINES ===================================================== */
9922 /* ======================================================================== */
9923
9924 typedef struct stack_s {
9925   void *data;
9926   struct stack_s *next;
9927 } stackitem_t;
9928
9929 typedef stackitem_t *dynstack_t;
9930 static stackitem_t *free_stackitems = NULL;
9931
9932 /* Create a stack with one item. */
9933 static dynstack_t *newStack () {
9934   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9935   *s = NULL;
9936   return s;
9937 }
9938
9939 /* Remove a stack -- its items are only marked free. */
9940 static void deleteStack (dynstack_t *s) {
9941   stackitem_t *i;
9942
9943   while (*s) {
9944     i = *s;
9945     *s = (*s)->next;
9946     i->next = free_stackitems;
9947     free_stackitems = i;
9948   } // while
9949   Safe_free (s);
9950 }
9951
9952 /* Release all stackitems. */
9953 static void releaseStack () {
9954   stackitem_t *i;
9955   
9956   while (free_stackitems) {
9957     i = free_stackitems->next;
9958     Safe_free(free_stackitems);
9959     free_stackitems = i;
9960   } // while
9961 }
9962
9963 static void stackPush (dynstack_t *stack, void *data) {
9964   stackitem_t *i;
9965   
9966   if (free_stackitems) {
9967     i = free_stackitems;
9968     free_stackitems = free_stackitems->next;
9969   } else {
9970     i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9971   }
9972   i->data = data;
9973   i->next = *stack;
9974   *stack = i;
9975 }
9976
9977 static void *stackPop (dynstack_t *stack) {
9978   void *data;
9979   stackitem_t *i;
9980   
9981   if (stack && *stack) {
9982     data = (*stack)->data;
9983     i = *stack;
9984     *stack = (*stack)->next;
9985     i->next = free_stackitems;
9986     free_stackitems = i;
9987     return data;
9988   } else {
9989     return NULL;
9990   }
9991 }
9992
9993 #if 0
9994 static int stackContains (dynstack_t *s, void *data) {
9995   stackitem_t *i;
9996   if (!s) return 0;
9997   i = *s;
9998   while (i) {
9999     if (i->data == data) return 1;
10000     i = i->next;
10001   } // while
10002
10003   /* not found */
10004   return 0;
10005 }
10006 #endif
10007
10008 static int stackIsEmpty (dynstack_t *s) {
10009   return (*s == NULL);
10010 }
10011
10012
10013 typedef struct {
10014   pCodeFlow *flow;
10015   defmap_t *lastdef;
10016 } state_t;
10017
10018 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10019   state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10020   s->flow = flow;
10021   s->lastdef = lastdef;
10022   return s;
10023 }
10024
10025 static void deleteState (state_t *s) {
10026   Safe_free (s);
10027 }
10028
10029 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10030   stackitem_t *i;
10031
10032   /* scan working list for state */
10033   if (todo) {
10034     i = *todo;
10035     while (i) {
10036       /* is i == state? -- state not new */
10037       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10038       i = i->next;
10039     } // while
10040   }
10041
10042   if (done) {
10043     i = *done;
10044     while (i) {
10045       /* is i == state? -- state not new */
10046       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10047       i = i->next;
10048     } // while
10049   }
10050
10051   /* not found -- state is new */
10052   return 1;
10053 }
10054
10055 static inline valnum_t newValnum ();
10056
10057 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10058   pCode *pc;
10059
10060   if (!pb) return "<unknown function>";
10061
10062   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10063   if (pc && isPCF(pc)) return PCF(pc)->fname;
10064   else return "<unknown function>";
10065 }
10066
10067 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10068   defmap_t *map;
10069   pCodeFlow *pcfl;
10070
10071   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10072
10073   /* find initial value (assigning pc == NULL) */
10074   map = PCFL(pcfl)->in_vals;
10075   while (map && map->sym != sym) map = map->next;
10076
10077   /* initial value already present? */
10078   if (map) {
10079     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10080     return map;
10081   }
10082
10083   /* create a new initial value */
10084   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10085   PCFL(pcfl)->in_vals = map;
10086   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10087   return map;
10088
10089 #if 0
10090   /* insert map as last item in pcfl's defmap */
10091   if (!prev) prev = PCFL(pcfl)->defmap;
10092   if (!prev) {
10093     PCFL(pcfl)->defmap = map;
10094   } else {
10095     while (prev->next) prev = prev->next;
10096     prev->next = map;
10097     map->prev = prev;
10098   }
10099
10100   return map;
10101 #endif
10102 }
10103
10104 /* Find all reaching definitions for sym at pc. 
10105  * A new (!) list of definitions is returned.
10106  * Returns the number of reaching definitions found.
10107  * The defining defmap entries are returned in *chain.
10108  */
10109 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10110   defmap_t *map;
10111   defmap_t *res;
10112
10113   pCodeFlow *curr;
10114   pCodeFlowLink *succ;
10115   state_t *state;
10116   dynstack_t *todo;     /** stack of state_t */
10117   dynstack_t *done;     /** stack of state_t */
10118
10119   int firstState, n_defs;
10120   
10121   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10122   assert (chain);
10123
10124   /* initialize return list */
10125   *chain = NULL;
10126
10127   /* wildcard symbol? */
10128   if (!sym) return 0;
10129   
10130   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10131   
10132   map = PCI(pc)->pcflow->defmap;
10133
10134   res = defmapFindDef (map, sym, pc);
10135   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10136
10137 #define USE_PRECALCED_INVALS 1
10138 #if USE_PRECALCED_INVALS
10139   if (!res && PCI(pc)->pcflow->in_vals) {
10140     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10141     if (res) {
10142       //fprintf  (stderr, "found def in init values\n");
10143       df_findall_in_vals++;
10144     }
10145   }
10146 #endif
10147
10148   if (res) {
10149     // found a single definition (in pc's flow)
10150     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10151     defmapAddCopyIfNew (chain, res);
10152     df_findall_sameflow++;
10153     return 1;
10154   }
10155
10156 #if USE_PRECALCED_INVALS
10157   else {
10158     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10159     return 1;
10160   }
10161
10162 #endif
10163   
10164 #define FORWARD_FLOW_ANALYSIS 1
10165 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10166   /* no definition found in pc's flow preceeding pc */
10167   todo = newStack ();
10168   done = newStack ();
10169   n_defs = 0; firstState = 1;
10170   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10171
10172   while (!stackIsEmpty (todo)) {
10173     state = (state_t *) stackPop (todo);
10174     stackPush (done, state);
10175     curr = state->flow;
10176     res = state->lastdef;
10177     //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);
10178
10179     /* there are no definitions BEFORE pc in pc's flow (see above) */
10180     if (curr == PCI(pc)->pcflow) {
10181       if (!res) {
10182         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10183         res = pic16_pBlockAddInval (pc->pb, sym);
10184         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10185         res = NULL;
10186       } else {
10187         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10188         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10189       }
10190     }
10191
10192     /* save last definition of sym in this flow as initial def in successors */
10193     res = defmapFindDef (curr->defmap, sym, NULL);
10194     if (!res) res = state->lastdef;
10195     
10196     /* add successors to working list */
10197     state = newState (NULL, NULL);
10198     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10199     while (succ) {
10200       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10201       state->flow = succ->pcflow;
10202       state->lastdef = res;
10203       if (stateIsNew (state, todo, done)) {
10204         stackPush (todo, state);
10205         state = newState (NULL, NULL);
10206       } // if
10207       succ = (pCodeFlowLink *) setNextItem (curr->to);
10208     } // while
10209     deleteState (state);
10210   } // while
10211
10212 #else // !FORWARD_FLOW_ANALYSIS 
10213
10214   /* no definition found in pc's flow preceeding pc */
10215   todo = newStack ();
10216   done = newStack ();
10217   n_defs = 0; firstState = 1;
10218   stackPush (todo, newState (PCI(pc)->pcflow, res));
10219
10220   while (!stackIsEmpty (todo)) {
10221     state = (state_t *) stackPop (todo);
10222     curr = state->flow;
10223
10224     if (firstState) {
10225       firstState = 0;
10226       /* only check predecessor flows */
10227     } else {
10228       /* get (last) definition of sym in this flow */
10229       res = defmapFindDef (curr->defmap, sym, NULL);
10230     }
10231
10232     if (res) {
10233       /* definition found */
10234       //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10235       if (defmapAddCopyIfNew (chain, res)) n_defs++;
10236     } else {
10237       /* no definition found -- check predecessor flows */
10238       state = newState (NULL, NULL);
10239       succ = (pCodeFlowLink *) setFirstItem (curr->from);
10240
10241       /* if no flow predecessor available -- sym might be uninitialized */
10242       if (!succ) {
10243         //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10244         res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10245         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10246         deleteDefmap (res); res = NULL;
10247       }
10248       
10249       while (succ) {
10250         //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10251         state->flow = succ->pcflow;
10252         state->lastdef = res;
10253         if (stateIsNew (state, todo, done)) {
10254           stackPush (todo, state);
10255           state = newState (NULL, NULL);
10256         } // if
10257         succ = (pCodeFlowLink *) setNextItem (curr->from);
10258       } // while
10259       deleteState (state);
10260     }
10261   } // while
10262
10263 #endif
10264
10265   /* clean up done stack */
10266   while (!stackIsEmpty(done)) {
10267     deleteState ((state_t *) stackPop (done));
10268   } // while
10269   deleteStack (done);
10270
10271   /* return number of items in result set */
10272   if (n_defs == 0) {
10273     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10274   } else if (n_defs == 1) {
10275     assert (*chain);
10276     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10277   } else if (n_defs > 0) {
10278     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10279 #if 0
10280     res = *chain;
10281     while (res) {
10282       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10283       res = res->next;
10284     } // while
10285 #endif
10286   }
10287   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10288   df_findall_otherflow++;
10289   return n_defs;
10290 }
10291
10292 /* ======================================================================== */
10293 /* === VALUE NUMBER HANDLING ============================================== */
10294 /* ======================================================================== */
10295
10296 static valnum_t nextValnum = 0x1000;
10297 static hTab *map_symToValnum = NULL;
10298
10299 /** Return a new value number. */
10300 static inline valnum_t newValnum () {
10301   return (nextValnum += 4);
10302 }
10303
10304 static valnum_t valnumFromStr (const char *str) {
10305   symbol_t sym;
10306   valnum_t val;
10307   void *res;
10308   
10309   sym = symFromStr (str);
10310
10311   if (!map_symToValnum) {
10312     map_symToValnum = newHashTable (128);
10313   } // if
10314
10315   /* literal already known? */
10316   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10317
10318   /* return existing valnum */
10319   if (res) return (valnum_t) PTR_TO_INT(res);
10320   
10321   /* create new valnum */
10322   val = newValnum();
10323   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10324   return val;
10325 }
10326
10327 /* Create a valnum for a literal. */
10328 static valnum_t valnumFromLit (unsigned int lit) {
10329   return ((valnum_t) 0x100 + (lit & 0x0FF));
10330 }
10331
10332 /* Return the (positive) literal value represented by val
10333  * or -1 iff val is no known literal's valnum. */
10334 static int litFromValnum (valnum_t val) {
10335   if (val >= 0x100 && val < 0x200) {
10336     /* valnum is a (known) literal */
10337     return val & 0x00FF;
10338   } else {
10339     /* valnum is not a known literal */
10340     return -1;
10341   }
10342 }
10343
10344 #if 0
10345 /* Sanity check - all flows in a block must be reachable from initial flow. */
10346 static int verifyAllFlowsReachable (pBlock *pb) {
10347   set *reached;
10348   set *flowInBlock;
10349   set *checked;
10350   pCode *pc;
10351   pCodeFlow *pcfl;
10352   pCodeFlowLink *succ;
10353   int res;
10354
10355   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10356
10357   reached = NULL;
10358   flowInBlock = NULL;
10359   checked = NULL;
10360   /* mark initial flow as reached (and "not needs to be reached") */
10361   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10362   assert (pc);
10363   addSetHead (&reached, pc);
10364   addSetHead (&checked, pc);
10365   
10366   /* mark all further flows in block as "need to be reached" */
10367   pc = pb->pcHead;
10368   do {
10369     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10370     pc = pic16_findNextInstruction (pc->next);
10371   } while (pc);
10372
10373   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10374     /* mark as reached and "not need to be reached" */
10375     deleteSetItem (&reached, pcfl);
10376     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10377     
10378     /* flow is no longer considered unreachable */
10379     deleteSetItem (&flowInBlock, pcfl);
10380
10381     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10382       if (!isinSet (checked, succ->pcflow)) {
10383         /* flow has never been reached before */
10384         addSetHead (&reached, succ->pcflow);
10385         addSetHead (&checked, succ->pcflow);
10386       } // if
10387     } // for succ
10388   } // while
10389
10390   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10391
10392   /* by now every flow should have been reached
10393    * --> flowInBlock should be empty */
10394   res = (flowInBlock == NULL);
10395
10396 #if 1
10397   if (flowInBlock) {
10398           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10399     while (flowInBlock) {
10400       pcfl = indexSet (flowInBlock, 0);
10401       fprintf (stderr, "not reached: flow %p\n", pcfl);
10402       deleteSetItem (&flowInBlock, pcfl);
10403     } // while
10404   }
10405 #endif
10406   
10407   /* clean up */
10408   deleteSet (&reached);
10409   deleteSet (&flowInBlock);
10410   deleteSet (&checked);
10411   
10412   /* if we reached every flow, succ is NULL by now... */
10413   //assert (res); // will fire on unreachable code...
10414   return (res);
10415 }
10416 #endif
10417
10418 /* Checks a flow for accesses to sym AFTER pc.
10419  * 
10420  * Returns -1 if the symbol is read in this flow (before redefinition),
10421  * returns 0 if the symbol is redefined in this flow or
10422  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10423  */
10424 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10425   defmap_t *map, *mappc;
10426
10427   /* find pc or start of definitions */
10428   map = pcfl->defmap;
10429   while (map && (map->pc != pc) && map->next) map = map->next;
10430   /* if we found pc -- ignore it */
10431   while (map && map->pc == pc) map = map->prev;
10432
10433   /* scan list backwards (first definition first) */
10434   while (map && mask) {
10435 //    if (map->sym == sym) {
10436       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10437       mappc = map;
10438       /* scan list for reads at this pc first */
10439       while (map && map->pc == mappc->pc) {
10440         /* is the symbol (partially) read? */
10441         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10442           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10443           return -1;
10444         }
10445         map = map->prev;
10446       } // while
10447       map = mappc;
10448
10449       while (map && map->pc == mappc->pc) {
10450         /* honor (partial) redefinitions of sym */
10451         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10452           mask &= ~map->acc.access.mask;
10453           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10454         }
10455         map = map->prev;
10456       } // while
10457 //    } // if
10458     /* map already points to the first defmap for the next pCode */
10459     //map = mappc->prev;
10460   } // while
10461
10462   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10463    * is still alive; return the appropriate mask of alive bits */
10464   return mask;
10465 }
10466
10467 /* Check whether a symbol is alive (AFTER pc). */
10468 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10469   int mask, visit;
10470   defmap_t *map;
10471   dynstack_t *todo, *done;
10472   state_t *state;
10473   pCodeFlow *pcfl;
10474   pCodeFlowLink *succ;
10475
10476   mask = 0x00ff;
10477   
10478   assert (isPCI(pc));
10479   pcfl = PCI(pc)->pcflow;
10480   map = pcfl->defmap;
10481
10482   todo = newStack ();
10483   done = newStack ();
10484   
10485   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10486   stackPush (todo, state);
10487   visit = 0;
10488   
10489   while (!stackIsEmpty (todo)) {
10490     state = (state_t *) stackPop (todo);
10491     pcfl = state->flow;
10492     mask = PTR_TO_INT(state->lastdef);
10493     if (visit) stackPush (done, state); else deleteState(state);
10494     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10495     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10496     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10497     visit++;
10498
10499     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10500     if (mask == 0) continue;
10501
10502     /* symbol is (partially) read before redefinition in flow */
10503     if (mask == -1) break;
10504
10505     /* symbol is neither read nor completely redefined -- check successor flows */
10506     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10507       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10508       if (stateIsNew (state, todo, done)) {
10509         stackPush (todo, state);
10510       } else {
10511         deleteState (state);
10512       }
10513     } // for
10514   } // while
10515
10516   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10517   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10518
10519   /* symbol is read in at least one flow -- is alive */
10520   if (mask == -1) return 1;
10521
10522   /* symbol is read in no flow */
10523   return 0;
10524 }
10525
10526 /* Returns whether access to the given symbol has side effects. */
10527 static int pic16_symIsSpecial (symbol_t sym) {
10528   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10529   switch (sym) {
10530   case SPO_INDF0:
10531   case SPO_PLUSW0:
10532   case SPO_POSTINC0:
10533   case SPO_POSTDEC0:
10534   case SPO_PREINC0:
10535   case SPO_INDF1:
10536   case SPO_PLUSW1:
10537   case SPO_POSTINC1:
10538   case SPO_POSTDEC1:
10539   case SPO_PREINC1:
10540   case SPO_INDF2:
10541   case SPO_PLUSW2:
10542   case SPO_POSTINC2:
10543   case SPO_POSTDEC2:
10544   case SPO_PREINC2:
10545   case SPO_PCL:
10546           return 1;
10547   default:
10548           /* no special effects known */
10549           return 0;
10550   } // switch
10551
10552   return 0;
10553 }
10554
10555 /* Check whether a register should be considered local (to the current function) or not. */
10556 static int pic16_regIsLocal (regs *r) {
10557   symbol_t sym;
10558   if (r) {
10559     sym = symFromStr (r->name);
10560     switch (sym) {
10561     case SPO_WREG:
10562     case SPO_FSR0L: // used in ptrget/ptrput
10563     case SPO_FSR0H: // ... as well
10564     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10565     case SPO_FSR1H: // ... as well
10566     case SPO_FSR2L: // used as frame pointer
10567     case SPO_FSR2H: // ... as well
10568     case SPO_PRODL: // used to return values from functions
10569     case SPO_PRODH: // ... as well
10570       /* these registers (and some more...) are considered local */
10571       return 1;
10572       break;
10573     default:
10574       /* for unknown regs: check is marked local, leave if not */
10575       if (r->isLocal) {
10576         return 1;
10577       } else {
10578         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10579         return 0;
10580       }
10581     } // switch
10582   } // if
10583
10584   /* if in doubt, assume non-local... */
10585   return 0;
10586 }
10587
10588 /* Check all symbols touched by pc whether their newly assigned values are read.
10589  * Returns 0 if no symbol is used later on, 1 otherwise. */
10590 static int pic16_pCodeIsAlive (pCode *pc) {
10591   pCodeInstruction *pci;
10592   defmap_t *map, *lastpc;
10593   regs *checkreg;
10594   
10595   /* we can only handle PCIs */
10596   if (!isPCI(pc)) return 1;
10597
10598   //pc->print (stderr, pc);
10599
10600   pci = PCI(pc);
10601   assert (pci && pci->pcflow && pci->pcflow->defmap);
10602
10603   /* NEVER remove instructions with implicit side effects */
10604   switch (pci->op) {
10605   case POC_TBLRD:
10606   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10607   case POC_TBLRD_POSTDEC:
10608   case POC_TBLRD_PREINC:
10609   case POC_TBLWT:               /* modify program memory */
10610   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10611   case POC_TBLWT_POSTDEC:
10612   case POC_TBLWT_PREINC:
10613   case POC_CLRWDT:              /* clear watchdog timer */
10614   case POC_PUSH:                /* should be safe to remove though... */
10615   case POC_POP:                 /* should be safe to remove though... */
10616   case POC_CALL:
10617   case POC_RCALL:
10618   case POC_RETFIE:
10619   case POC_RETURN:
10620     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10621     return 1;
10622
10623   default:
10624     /* no special instruction */
10625     break;
10626   } // switch
10627
10628   /* prevent us from removing assignments to non-local variables */
10629   checkreg = NULL;
10630   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10631   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10632
10633   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10634     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10635     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10636     //pc->print (stderr, pc);
10637     return 1;
10638   }
10639   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10640     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10641     return 1;
10642   }
10643   
10644 #if 1
10645   /* OVERKILL: prevent us from removing reads from non-local variables 
10646    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY! 
10647    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10648   checkreg = NULL;
10649   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10650   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10651
10652   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10653     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10654     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10655     //pc->print (stderr, pc);
10656     return 1;
10657   }
10658   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10659     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10660     return 1;
10661   }
10662 #endif
10663   
10664   /* now check that the defined symbols are not used */
10665   map = pci->pcflow->defmap;
10666   
10667   /* find items for pc */
10668   while (map && map->pc != pc) map = map->next;
10669
10670   /* no entries found? something is fishy with DF analysis... -- play safe */
10671   if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10672
10673   /* remember first item assigned to pc for later use */
10674   lastpc = map;
10675   
10676   /* check all symbols being modified by pc */
10677   while (map && map->pc == pc) {
10678     if (map->sym == 0) { map = map->next; continue; }
10679
10680     /* keep pc if it references special symbols (like POSTDEC0) */
10681 #if 0
10682     {
10683       char buf[256];
10684       pic16_pCode2str (buf, 256, pc);
10685       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10686     }
10687 #endif
10688     if (pic16_symIsSpecial (map->sym)) {
10689       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10690       return 1;
10691     }
10692     if (map->acc.access.isWrite) {
10693       if (pic16_isAlive (map->sym, pc)) {
10694         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10695         return 1;
10696       }
10697     }
10698     map = map->next;
10699   } // while
10700
10701   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10702 #if 0
10703   {
10704     char buf[256];
10705     pic16_pCode2str (buf, 256, pc);
10706     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10707   }
10708 #endif
10709   return 0;
10710 }
10711
10712 /* Adds implied operands to the list.
10713  * sym - operand being accessed in the pCode
10714  * list - list to append the operand
10715  * isRead - set to 1 iff sym is read in pCode
10716  * listRead - set to 1 iff all operands being read are to be listed
10717  *
10718  * Returns 0 for "normal" operands, 1 for special operands.
10719  */
10720 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10721   /* check whether accessing REG accesses other REGs as well */
10722   switch (sym) {
10723   case SPO_INDF0:
10724     /* reads FSR0x */
10725     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10726     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10727     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10728     break;
10729     
10730   case SPO_PLUSW0:
10731     /* reads FSR0x and WREG */
10732     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10733     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10734     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10735     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10736     break;
10737     
10738   case SPO_POSTDEC0:
10739   case SPO_POSTINC0:
10740   case SPO_PREINC0:
10741     /* reads/modifies FSR0x */
10742     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10743     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10744     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10745     break;
10746
10747   case SPO_INDF1:
10748     /* reads FSR1x */
10749     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10750     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10751     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10752     break;
10753     
10754   case SPO_PLUSW1:
10755     /* reads FSR1x and WREG */
10756     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10757     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10758     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10759     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10760     break;
10761     
10762   case SPO_POSTDEC1:
10763   case SPO_POSTINC1:
10764   case SPO_PREINC1:
10765     /* reads/modifies FSR1x */
10766     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10767     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10768     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10769     break;
10770
10771   case SPO_INDF2:
10772     /* reads FSR2x */
10773     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10774     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10775     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10776     break;
10777     
10778   case SPO_PLUSW2:
10779     /* reads FSR2x and WREG */
10780     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10781     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10782     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10783     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10784     break;
10785     
10786   case SPO_POSTDEC2:
10787   case SPO_POSTINC2:
10788   case SPO_PREINC2:
10789     /* reads/modifies FSR2x */
10790     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10791     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10792     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10793     break;
10794
10795   case SPO_PCL:
10796     /* modifies PCLATH and PCLATU */
10797     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10798     if (isRead) {
10799       /* reading PCL updates PCLATx */
10800       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10801       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10802     }
10803     if (isWrite) {
10804       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10805       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10806       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10807     }
10808     break;
10809
10810   default:
10811     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10812     /* nothing special */
10813     return 0;
10814     break;
10815   }
10816
10817   /* has been a special operand */
10818   return 1;
10819 }
10820
10821 static symbol_t pic16_fsrsym_idx[][2] = {
10822     {SPO_FSR0L, SPO_FSR0H},
10823     {SPO_FSR1L, SPO_FSR1H},
10824     {SPO_FSR2L, SPO_FSR2H}
10825 };
10826
10827 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10828 static void mergeDefmapSymbols (defmap_t *list) { 
10829   defmap_t *ref, *curr, *temp;
10830
10831   /* now make sure that each symbol occurs at most once per pc */
10832   ref = list;
10833   while (ref && (ref->pc == list->pc)) {
10834     curr = ref->next;
10835     while (curr && (curr->pc == list->pc)) {
10836       if (curr->sym == ref->sym) {
10837         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10838         /* found a symbol occuring twice... merge the two */
10839         if (curr->acc.access.isRead) {
10840           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10841           ref->acc.access.isRead = 1;
10842           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10843         }
10844         if (curr->acc.access.isWrite) {
10845           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10846           ref->acc.access.isWrite = 1;
10847           ref->acc.access.mask |= curr->acc.access.mask;
10848         }
10849         temp = curr;
10850         curr = curr->next;
10851         deleteDefmap (temp);
10852         continue; // do not skip curr!
10853       } // if
10854       curr = curr->next;
10855     } // while
10856     ref = ref->next;
10857   } // while
10858 }
10859
10860 /** Prepend list with the reads and definitions performed by pc. */
10861 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10862   pCodeInstruction *pci;
10863   int cond, inCond, outCond;
10864   int mask = 0xff, smask;
10865   int isSpecial, isSpecial2;
10866   symbol_t sym, sym2;
10867   char *name;
10868
10869   if (isPCAD(pc)) {
10870     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10871     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10872     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10873     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10874     return list;
10875   }
10876   assert (isPCI(pc));
10877   pci = PCI(pc);
10878   
10879   /* handle bit instructions */
10880   if (pci->isBitInst) {
10881     assert (pci->pcop->type == PO_GPR_BIT);
10882     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10883   }
10884
10885   /* handle (additional) implicit arguments */
10886   switch (pci->op) {
10887   case POC_LFSR:
10888     {
10889       int lit;
10890       valnum_t val;
10891       lit = PCOL(pci->pcop)->lit;
10892       assert (lit >= 0 && lit < 3);
10893       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, ((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10894       val = valnumFromStr (((pCodeOpLit2 *)(pci->pcop))->arg2->name);
10895       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10896       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10897       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...
10898     }
10899     break;
10900
10901   case POC_MOVLB: // BSR
10902   case POC_BANKSEL: // BSR
10903     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10904     break;
10905
10906   case POC_MULWF: // PRODx
10907   case POC_MULLW: // PRODx
10908     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10909     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10910     break;
10911
10912   case POC_POP: // TOS, STKPTR
10913     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10914     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10915     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10916     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10917     break;
10918     
10919   case POC_PUSH: // STKPTR
10920     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10921     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10922     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10923     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10924     break;
10925     
10926   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10927   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10928     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10929     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10930     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10931     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10932
10933     /* needs correctly set-up stack pointer */
10934     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10935     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10936     break;
10937
10938   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10939     /* pseudo read on (possible) return values */
10940     // WREG is handled below via outCond
10941     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10942     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10943     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10944
10945     /* caller's stack pointers must be restored */
10946     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10947     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10948     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10949     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10950     break;
10951
10952   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10953   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10954     /* pseudo read on (possible) return values */
10955     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10956     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10957     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10958     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10959
10960     /* caller's stack pointers must be restored */
10961     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10962     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10963     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10964     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10965     break;
10966     
10967   case POC_TBLRD:
10968     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10969     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10970     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10971     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10972     break;
10973     
10974   case POC_TBLRD_POSTINC:
10975   case POC_TBLRD_POSTDEC:
10976   case POC_TBLRD_PREINC:
10977     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10978     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10979     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10980     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10981     break;
10982     
10983   case POC_TBLWT:
10984     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10985     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10986     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10987     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10988     break;
10989     
10990   case POC_TBLWT_POSTINC:
10991   case POC_TBLWT_POSTDEC:
10992   case POC_TBLWT_PREINC:
10993     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10994     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10995     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10996     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
10997     break;
10998     
10999   default:
11000     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11001     break;
11002   } // switch
11003
11004   /* handle explicit arguments */
11005   inCond = pci->inCond;
11006   outCond = pci->outCond;
11007   cond = inCond | outCond;
11008   if (cond & PCC_W) {
11009     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11010   } // if
11011
11012   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11013   if (inCond & PCC_STATUS) {
11014     smask = 0;
11015     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11016     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11017     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11018     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11019     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11020
11021     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11022     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11023   } // if
11024   
11025   if (outCond & PCC_STATUS) {
11026     smask = 0;
11027     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11028     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11029     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11030     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11031     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11032
11033     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11034     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11035   } // if
11036   
11037   isSpecial = isSpecial2 = 0;
11038   sym = sym2 = 0;
11039   if (cond & PCC_REGISTER) {
11040     name = pic16_get_op (pci->pcop, NULL, 0);
11041     sym = symFromStr (name);
11042     isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11043     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11044   }
11045
11046   if (cond & PCC_REGISTER2) {
11047     name = pic16_get_op2 (pci->pcop, NULL, 0);
11048     sym2 = symFromStr (name);
11049     isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11050     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11051   }
11052
11053  
11054   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11055   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11056
11057   mergeDefmapSymbols (list);
11058   
11059   return list;
11060 }
11061
11062 #if 0
11063 static void printDefmap (defmap_t *map) {
11064   defmap_t *curr;
11065
11066   curr = map;
11067   fprintf (stderr, "defmap @ %p:\n", curr);
11068   while (curr) {
11069     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11070                     curr->acc.access.isRead ? "R" : " ",
11071                     curr->acc.access.isWrite ? "W": " ",
11072                     curr->in_val, curr->val,
11073                     curr->acc.access.in_mask, curr->acc.access.mask,
11074                     strFromSym(curr->sym), curr->sym,
11075                     curr->pc);
11076     curr = curr->next;
11077   } // while
11078   fprintf (stderr, "<EOL>\n");
11079 }
11080 #endif
11081
11082 /* Add "additional" definitions to uniq.
11083  * 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.
11084  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11085  *
11086  * If symbols defined in additional are not present in uniq, a definition is created.
11087  * Otherwise the present definition is altered to reflect the newer assignments.
11088  *
11089  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11090  *       before     `------- noted in additional --------'      after
11091  *
11092  * I assume that each symbol occurs AT MOST ONCE in uniq.
11093  *
11094  */
11095 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11096   defmap_t *curr;
11097   defmap_t *old;
11098   int change = 0;
11099
11100   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11101   /* find tail of additional list (holds the first assignment) */
11102   curr = additional;
11103   while (curr && curr->next) curr = curr->next;
11104
11105   /* update uniq */
11106   do {
11107     /* find next assignment in additionals */
11108     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11109
11110     if (!curr) break;
11111
11112     /* find item in uniq */
11113     old = *uniq;
11114     //printDefmap (*uniq);
11115     while (old && (old->sym != curr->sym)) old = old->next;
11116
11117     if (old) {
11118       /* definition found -- replace */
11119       if (old->val != curr->val) {
11120         old->val = curr->val;
11121         change++;
11122       } // if
11123     } else {
11124       /* new definition */
11125       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11126       change++;
11127     }
11128
11129     curr = curr->prev;
11130   } while (1);
11131
11132   /* return 0 iff uniq remained unchanged */
11133   return change;
11134 }
11135
11136 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11137  * lists of its predecessor flows. 
11138  * Initially *combined should be NULL, alt_in will be copied to combined.
11139  * If *combined != NULL, combined will be altered:
11140  * - for symbols defined in *combined but not in alt_in,
11141  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11142  * - for symbols defined in alt_in but not in *combined,
11143  *   a 0 definition is created (value unknown, either INIT or alt).
11144  * - for symbols defined in both, *combined is:
11145  *   > left unchanged if *combined->val == alt_in->val or
11146  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11147  * 
11148  * I assume that each symbol occurs AT MOST ONCE in each list!
11149  */
11150 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11151   defmap_t *curr;
11152   defmap_t *old;
11153   int change = 0;
11154   valnum_t val;
11155
11156   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11157   
11158   if (!(*combined)) {
11159     return defmapUpdateUniqueSym (combined, alt_in);
11160   } // if
11161   
11162   /* merge the two */
11163   curr = alt_in;
11164   while (curr) {
11165     /* find symbols definition in *combined */
11166     old = *combined;
11167     while (old && (old->sym != curr->sym)) old = old->next;
11168
11169     if (old) {
11170       /* definition found */
11171       if (old->val && (old->val != curr->val)) {
11172         old->val = 0; /* value unknown */
11173         change++;
11174       }
11175     } else {
11176       /* no definition found -- can be either INIT or alt_in's value */
11177       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11178       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11179       if (val != curr->val) change++;
11180     }
11181
11182     curr = curr->next;
11183   } // while (curr)
11184
11185   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11186   old = *combined;
11187   while (old) {
11188     if (old->val != 0) {
11189       /* find definition in alt_in */
11190       curr = alt_in;
11191       while (curr && curr->sym != old->sym) curr = curr->next;
11192       if (!curr) {
11193         /* symbol defined in *combined only -- can be either INIT or *combined */
11194         val = pic16_pBlockAddInval (pb, old->sym)->val;
11195         if (old->val != val) {
11196           old->val = 0;
11197           change++;
11198         }
11199       } // if
11200     } // if
11201
11202     old = old->next;
11203   } // while
11204
11205   return change;
11206 }
11207
11208 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11209   defmap_t *curr1, *curr2;
11210   symbol_t sym;
11211   
11212   /* identical maps are equal */
11213   if (map1 == map2) return 0;
11214
11215   if (!map1) return -1;
11216   if (!map2) return 1;
11217
11218   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11219   
11220   /* check length */
11221   curr1 = map1;
11222   curr2 = map2;
11223   while (curr1 && curr2) {
11224     curr1 = curr1->next;
11225     curr2 = curr2->next;
11226   } // while
11227
11228   /* one of them longer? */
11229   if (curr1) return 1;
11230   if (curr2) return -1;
11231
11232   /* both lists are of equal length -- compare (in O(n^2)) */
11233   curr1 = map1;
11234   while (curr1) {
11235     sym = curr1->sym;
11236     curr2 = map2;
11237     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11238     if (!curr2) return 1; // symbol not found in curr2
11239     if (curr2->val != curr1->val) return 1; // values differ
11240
11241     /* compare next symbol */
11242     curr1 = curr1->next;
11243   } // while
11244
11245   /* no difference found */
11246   return 0;
11247 }
11248
11249
11250 /* Prepare a list of all reaching definitions per flow.
11251  * This is done using a forward dataflow analysis.
11252  */
11253 static void createReachingDefinitions (pBlock *pb) {
11254   defmap_t *out_vals, *in_vals;
11255   pCode *pc;
11256   pCodeFlow *pcfl;
11257   pCodeFlowLink *link;
11258   set *todo;
11259   set *blacklist;
11260
11261   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11262   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11263     if (isPCFL(pc)) {
11264       deleteDefmapChain (&PCFL(pc)->in_vals);
11265       deleteDefmapChain (&PCFL(pc)->out_vals);
11266       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11267     } // if
11268   } // for
11269   
11270   pc = pic16_findNextInstruction (pb->pcHead);
11271   todo = NULL; blacklist = NULL;
11272   addSetHead (&todo, PCI(pc)->pcflow);
11273
11274   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11275   while (elementsInSet (todo)) {
11276     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11277     pcfl = PCFL(indexSet (todo, 0));
11278     deleteSetItem (&todo, pcfl);
11279     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11280     in_vals = NULL;
11281     out_vals = NULL;
11282
11283     if (isinSet (blacklist, pcfl)) {
11284             fprintf (stderr, "ignoring blacklisted flow\n");
11285       continue;
11286     }
11287     
11288     /* create in_vals from predecessors out_vals */
11289     link = setFirstItem (pcfl->from);
11290     while (link) {
11291       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11292       link = setNextItem (pcfl->from);
11293     } // while
11294
11295     //printDefmap (in_vals); 
11296     //printDefmap (pcfl->in_vals); 
11297
11298     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11299       //fprintf (stderr, "in_vals changed\n");
11300       /* in_vals changed -- update out_vals */
11301       deleteDefmapChain (&pcfl->in_vals);
11302       pcfl->in_vals = in_vals;
11303
11304       /* create out_val from in_val and defmap */
11305       out_vals = NULL;
11306       defmapUpdateUniqueSym (&out_vals, in_vals);
11307       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11308
11309       /* is out_vals different from pcfl->out_vals */
11310       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11311         //fprintf (stderr, "out_vals changed\n");
11312         deleteDefmapChain (&pcfl->out_vals);
11313         pcfl->out_vals = out_vals;
11314
11315         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11316           addSet (&blacklist, pcfl);
11317         } // if
11318         
11319         /* reschedule all successors */
11320         link = setFirstItem (pcfl->to);
11321         while (link) {
11322           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11323           addSetIfnotP (&todo, link->pcflow);
11324           link = setNextItem (pcfl->to);
11325         } // while
11326       } else {
11327         deleteDefmapChain (&out_vals);        
11328       }// if
11329     } else {
11330       deleteDefmapChain (&in_vals);         
11331     } // if
11332   } // while
11333 }
11334
11335 #if 0
11336 static void showAllDefs (symbol_t sym, pCode *pc) {
11337   defmap_t *map;
11338   int count;
11339
11340   assert (isPCI(pc));
11341   count = defmapFindAll (sym, pc, &map);
11342
11343   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11344   while (map) {
11345 #if 1
11346     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11347 #else
11348     { char buf[256];
11349     pic16_pCode2str (buf, 256, map->pc);
11350     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11351 #endif
11352     map = map->next;
11353   }
11354   deleteDefmapChain (&map);
11355 }
11356 #endif
11357
11358 /* safepCodeUnlink and remove pc from defmap. */
11359 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11360   defmap_t *map, *next, **head;
11361   int res, ispci;
11362   
11363   ispci = isPCI(pc);
11364   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11365   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11366   res = pic16_safepCodeUnlink (pc, comment);
11367
11368   if (res && map) {
11369     /* remove pc from defmap */
11370     while (map) {
11371       next = map->next;
11372       if (map->pc == pc) {
11373         if (!map->prev && head) *head = map->next;
11374         deleteDefmap (map);
11375       } // if
11376       map = next;
11377     }
11378   }
11379
11380   return res;
11381 }
11382       
11383 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11384   defmap_t *map;
11385   /* This breaks the defmap chain's references to pCodes... fix it! */
11386   map = PCI(pc)->pcflow->defmap;
11387
11388   while (map && map->pc != pc) map = map->next;
11389   
11390   while (map && map->pc == pc) {
11391     map->pc = newpc;
11392     map = map->next;
11393   } // while
11394 }
11395
11396 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11397  * write accesses (isRead == 0). */
11398 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11399   defmap_t *map, *map_start;
11400   defmap_t *copy;
11401   if (!isPCI(pc)) return;
11402   if (sym == newsym) return;
11403   
11404   map = PCI(pc)->pcflow->defmap;
11405
11406   while (map && map->pc != pc) map = map->next;
11407   map_start = map;
11408   while (map && map->pc == pc) {
11409     if (map->sym == sym) {
11410       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11411       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11412         /* only one kind of access handled... this is easy */
11413         map->sym = newsym;
11414       } else {
11415         /* must copy defmap entry before replacing symbol... */
11416         copy = copyDefmap (map);
11417         if (isRead) {
11418           map->acc.access.isRead = 0;
11419           copy->acc.access.isWrite = 0;
11420         } else {
11421           map->acc.access.isWrite = 0;
11422           copy->acc.access.isRead = 0;
11423         }
11424         copy->sym = newsym;
11425         /* insert copy into defmap chain */
11426         defmapInsertAfter (map, copy);
11427       }
11428     }
11429     map = map->next;
11430   } // while
11431
11432   /* as this might introduce multiple defmap entries for newsym... */
11433   mergeDefmapSymbols (map_start);
11434 }
11435
11436 /* Assign "better" valnums to results. */
11437 static void assignValnums (pCode *pc) {
11438   pCodeInstruction *pci;
11439   pCode *newpc;
11440   symbol_t sym1, sym2;
11441   int cond, isSpecial1, isSpecial2, count, mask, lit;
11442   defmap_t *list, *val, *oldval, *dummy;
11443   regs *reg1 = NULL, *reg2 = NULL;
11444   valnum_t litnum;
11445
11446   /* only works for pCodeInstructions... */
11447   if (!isPCI(pc)) return;
11448
11449   pci = PCI(pc);
11450   cond = pci->inCond | pci->outCond;
11451   list = pci->pcflow->defmap;
11452   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11453
11454   if (cond & PCC_REGISTER) {
11455     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11456     reg1 = pic16_getRegFromInstruction (pc);
11457     isSpecial1 = pic16_symIsSpecial (sym1);
11458   }
11459   if (cond & PCC_REGISTER2) {
11460     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11461     reg2 = pic16_getRegFromInstruction (pc);
11462     isSpecial2 = pic16_symIsSpecial (sym2);
11463   }
11464
11465   /* determine input values */
11466   val = list;
11467   while (val && val->pc != pc) val = val->next;
11468   //list = val; /* might save some time later... */
11469   while (val && val->pc == pc) {
11470     val->in_val = 0;
11471     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11472       /* get valnum for sym */
11473       count = defmapFindAll (val->sym, pc, &oldval);
11474       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11475       if (count == 1) {
11476         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11477           val->in_val = oldval->val;
11478         } else {
11479           val->in_val = 0;
11480         }
11481       } else if (count == 0) {
11482         /* no definition found */
11483         val->in_val = 0;
11484       } else {
11485         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11486         assert (oldval);
11487         dummy = oldval->next;
11488         mask = oldval->acc.access.mask;
11489         val->in_val = oldval->val;
11490         while (dummy && (dummy->val == val->in_val)) {
11491           mask &= dummy->acc.access.mask;
11492           dummy = dummy->next;
11493         } // while
11494
11495         /* found other values or to restictive mask */
11496         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11497           val->in_val = 0;
11498         }
11499       }
11500       if (count > 0) deleteDefmapChain (&oldval);
11501     } // if
11502     val = val->next;
11503   }
11504
11505   /* handle valnum assignment */
11506   switch (pci->op) {
11507   case POC_CLRF: /* modifies STATUS (Z) */
11508     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11509       oldval = defmapCurr (list, sym1, pc);
11510       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11511         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11512         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11513       }
11514       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11515     }
11516     break;
11517
11518   case POC_SETF: /* SETF does not touch STATUS */
11519     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11520       oldval = defmapCurr (list, sym1, pc);
11521       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11522         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11523         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11524       }
11525       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11526     }
11527     break;
11528     
11529   case POC_MOVLW: /* does not touch STATUS */
11530     oldval = defmapCurr (list, SPO_WREG, pc);
11531     if (pci->pcop->type == PO_LITERAL) {
11532       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11533       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11534     } else {
11535       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11536       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11537     }
11538     if (oldval && oldval->in_val == litnum) {
11539       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11540       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11541     }
11542     defmapUpdate (list, SPO_WREG, pc, litnum);
11543     break;
11544
11545   case POC_ANDLW: /* modifies STATUS (Z,N) */
11546   case POC_IORLW: /* modifies STATUS (Z,N) */
11547   case POC_XORLW: /* modifies STATUS (Z,N) */
11548     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11549     if (pci->pcop->type == PO_LITERAL) {
11550       int vallit = -1;
11551       lit = (unsigned char) PCOL(pci->pcop)->lit;
11552       val = defmapCurr (list, SPO_WREG, pc);
11553       if (val) vallit = litFromValnum (val->in_val);
11554       if (vallit != -1) {
11555         /* xxxLW <literal>, WREG contains a known literal */
11556         fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11557         if (pci->op == POC_ANDLW) {
11558           lit &= vallit;
11559         } else if (pci->op == POC_IORLW) {
11560           lit |= vallit;
11561         } else if (pci->op == POC_XORLW) {
11562           lit ^= vallit;
11563         } else {
11564           assert (0 && "invalid operation");
11565         }
11566         if (vallit == lit) {
11567           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11568           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11569         }
11570         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11571       } // if
11572     }
11573     break;
11574
11575   case POC_LFSR:
11576     {
11577       /* check if old value matches new value */
11578       int lit;
11579       int ok = 1;
11580       assert (pci->pcop->type == PO_LITERAL);
11581       
11582       lit = PCOL(pci->pcop)->lit;
11583       
11584       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11585       
11586       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11587         fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11588       } else {
11589         /* cannot remove this LFSR */
11590         ok = 0;      
11591       } // if
11592       
11593       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11594       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11595         fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11596       } else {
11597         ok = 0;
11598       } // if
11599
11600       if (ok) {
11601         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11602       }
11603     }
11604     break;
11605     
11606   case POC_MOVWF: /* does not touch flags */
11607     /* find value of WREG */
11608     val = defmapCurr (list, SPO_WREG, pc);
11609     oldval = defmapCurr (list, sym1, pc);
11610     if (val) lit = litFromValnum (val->in_val);
11611     else lit = -1;
11612     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11613     
11614     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11615       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11616       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11617       if (lit == 0) {
11618         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11619       } else {
11620         assert (lit == 0x0ff);
11621         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11622       }
11623       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11624       pic16_pCodeReplace (pc, newpc);
11625       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11626       pic16_fixDefmap (pc, newpc);
11627       pc = newpc;
11628         
11629       /* This breaks the defmap chain's references to pCodes... fix it! */
11630       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11631       if (!val->acc.access.isWrite) {
11632         deleteDefmap (val);     // delete reference to WREG as in value
11633         val = NULL;
11634       } else {
11635         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11636       }
11637       oldval = PCI(pc)->pcflow->defmap;
11638       while (oldval) {
11639         if (oldval->pc == pc) oldval->pc = newpc;
11640           oldval = oldval->next;
11641       } // while
11642     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11643       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11644       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11645     }
11646     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11647     break;
11648     
11649   case POC_MOVFW: /* modifies STATUS (Z,N) */
11650     /* find value of REG */
11651     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11652       val = defmapCurr (list, sym1, pc);
11653       oldval = defmapCurr (list, SPO_WREG, pc);
11654       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11655         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11656         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11657       }
11658       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11659     }
11660     break;
11661
11662   case POC_MOVFF: /* does not touch STATUS */
11663     /* find value of REG */
11664     val = defmapCurr (list, sym1, pc);
11665     oldval = defmapCurr (list, sym2, pc);
11666     if (val) lit = litFromValnum (val->in_val);
11667     else lit = -1;
11668     newpc = NULL;
11669     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11670       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11671       if (lit == 0) {
11672         newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11673       } else if (lit == 0x00ff) {
11674         newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11675       } else {
11676         newpc = NULL;
11677       }
11678       if (newpc) {
11679         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11680         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11681         pic16_pCodeReplace (pc, newpc); 
11682         defmapReplaceSymRef (pc, sym1, 0, 1);
11683         pic16_fixDefmap (pc, newpc);
11684         pc = newpc;
11685         break; // do not process instruction as MOVFF...
11686       }
11687     } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11688       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11689         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11690         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11691       } else {
11692         if (!pic16_isAlive (sym1, pc)) {
11693           defmap_t *copy = NULL;
11694           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11695            * This should help eliminate
11696            *   MOVFF A,B
11697            *   <do something not changing A or using B>
11698            *   MOVFF B,C
11699            *   <B is not alive anymore>
11700            * and turn it into
11701            *   <do something not changing A or using B>
11702            *   MOVFF A,C
11703            */
11704
11705           /* scan defmap for symbols storing sym1's value */
11706           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11707           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11708             /* unique reaching definition for sym found */
11709             if (copy->val && copy->val == val->in_val) {
11710               //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);
11711               if (copy->sym == SPO_WREG) {
11712                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11713               } else {
11714                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11715 //                      /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11716                         pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11717                         pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11718               }
11719               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11720               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11721               pic16_pCodeReplace (pc, newpc); 
11722               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11723               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11724               pic16_fixDefmap (pc, newpc);
11725               pc = newpc;
11726             }
11727           }
11728           deleteDefmapChain (&copy);
11729         }
11730       }
11731       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11732     }
11733     break;
11734
11735   default:
11736     /* cannot optimize */
11737     break;
11738   } // switch
11739 }
11740
11741 static void pic16_destructDF (pBlock *pb) {
11742   pCode *pc, *next;
11743
11744   /* remove old defmaps */
11745   pc = pic16_findNextInstruction (pb->pcHead);
11746   while (pc) {
11747     next = pic16_findNextInstruction (pc->next);
11748
11749     assert (isPCI(pc) || isPCAD(pc));
11750     assert (PCI(pc)->pcflow);
11751     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11752     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11753     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11754     
11755     pc = next;
11756   } // while
11757   
11758   if (defmap_free || defmap_free_count) {
11759     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11760     freeDefmap (&defmap_free);
11761     defmap_free_count = 0;
11762   }
11763 }
11764
11765 /* Checks whether a pBlock contains ASMDIRs. */
11766 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11767   pCode *pc;
11768
11769   pc = pic16_findNextInstruction (pb->pcHead);
11770   while (pc) {
11771     if (isPCAD(pc)) return 1;
11772
11773     pc = pic16_findNextInstruction (pc->next);
11774   } // while
11775
11776   /* no PCADs found */
11777   return 0;
11778 }
11779
11780 #if 1
11781 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11782 static int pic16_removeUnusedRegistersDF () {
11783   pCode *pc, *pc2;
11784   pBlock *pb;
11785   regs *reg1, *reg2, *reg3;
11786   set *seenRegs = NULL;
11787   int cond, i;
11788   int islocal, change = 0;
11789
11790   /* no pBlocks? */
11791   if (!the_pFile || !the_pFile->pbHead) return 0;
11792   
11793   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11794     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11795 #if 1
11796     /* find set of using pCodes per register */
11797     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11798                     pc = pic16_findNextInstruction(pc->next)) {
11799
11800       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11801       reg1 = reg2 = NULL;
11802       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11803       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11804
11805       if (reg1) {
11806         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11807         addSetIfnotP (&seenRegs, reg1);
11808         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11809       }
11810       if (reg2) {
11811         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11812         addSetIfnotP (&seenRegs, reg2);
11813         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11814       }
11815     } // for pc
11816 #endif
11817     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11818       /* may not use pic16_regIsLocal() here -- in interrupt routines
11819        * WREG, PRODx, FSR0x must be saved */
11820       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11821       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11822         pc = pc2 = NULL;
11823         for (i=0; i < 2; i++) {
11824           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11825           if (!pc2) pc2 = pc;
11826           if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11827           reg2 = pic16_getRegFromInstruction (pc);
11828           reg3 = pic16_getRegFromInstruction2 (pc);
11829           if (!reg2 || !reg3
11830               || (reg2->rIdx != pic16_stack_preinc->rIdx
11831                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11832           if (i == 1) {
11833             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11834             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11835             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11836             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11837           }
11838         } // for
11839       } // if
11840       deleteSet (&reg1->reglives.usedpCodes);
11841     } // for reg1
11842
11843     deleteSet (&seenRegs);
11844   } // for pb
11845
11846   return change;
11847 }
11848 #endif
11849
11850 /* Set up pCodeFlow's defmap_ts. 
11851  * Needs correctly set up to/from fields. */
11852 static void pic16_createDF (pBlock *pb) {
11853   pCode *pc, *next;
11854   int change=0;
11855
11856   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11857
11858   pic16_destructDF (pb);
11859
11860   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11861   if (pic16_pBlockHasAsmdirs (pb)) {
11862     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11863     return;
11864   }
11865
11866   /* integrity check -- we need to reach all flows to guarantee
11867    * correct data flow analysis (reaching definitions, aliveness) */
11868 #if 0
11869   if (!verifyAllFlowsReachable (pb)) {
11870     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11871     return;
11872   }
11873 #endif
11874   
11875   /* establish new defmaps */
11876   pc = pic16_findNextInstruction (pb->pcHead);
11877   while (pc) {
11878     next = pic16_findNextInstruction (pc->next);
11879
11880     assert (PCI(pc)->pcflow);
11881     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11882
11883     pc = next;
11884   } // while
11885
11886   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11887   createReachingDefinitions (pb);
11888   
11889 #if 1
11890   /* assign better valnums */
11891   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11892   pc = pic16_findNextInstruction (pb->pcHead);
11893   while (pc) {
11894     next = pic16_findNextInstruction (pc->next);
11895
11896     assert (PCI(pc)->pcflow);
11897     assignValnums (pc);
11898
11899     pc = next;
11900   } // while
11901 #endif
11902
11903 #if 1
11904   /* remove dead pCodes */
11905   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11906   do {
11907     change = 0;
11908     pc = pic16_findNextInstruction (pb->pcHead);
11909     while (pc) {
11910       next = pic16_findNextInstruction (pc->next);
11911
11912       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11913         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11914       }
11915
11916       pc = next;
11917     } // while
11918   } while (change);
11919 #endif
11920 }
11921
11922
11923 /* ======================================================================= */
11924 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11925 /* ======================================================================= */
11926
11927 #if 0
11928
11929 /* connect pCode f anf t via their to/from pBranches */
11930 static void pic16_pCodeLink (pCode *f, pCode *t) {
11931   pBranch *br;
11932   pCodeInstruction *_f, *_t;
11933
11934   if (!f || !t) return;
11935
11936 #if 0
11937   fprintf (stderr, "linking:\n");
11938   f->print(stderr, f);
11939   f->print(stderr, t);
11940 #endif
11941
11942   assert (isPCI(f) || isPCAD(f));
11943   assert (isPCI(t) || isPCAD(t));
11944   _f = PCI(f);
11945   _t = PCI(t);
11946   
11947   /* define t to be CF successor of f */
11948   br = Safe_malloc (sizeof (pBranch));
11949   br->pc = t;
11950   br->next = NULL;
11951   _f->to = pic16_pBranchAppend (_f->to, br);
11952
11953   /* define f to be CF predecessor of t */
11954   br = Safe_malloc (sizeof (pBranch));
11955   br->pc = f;
11956   br->next = NULL;
11957   _t->from = pic16_pBranchAppend (_t->from, br);
11958
11959   /* also update pcflow information */
11960   if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11961     //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11962     LinkFlow_pCode (_f, _t);
11963   } // if
11964 }
11965
11966 static void pic16_destructCF (pBlock *pb) {
11967   pCode *pc;
11968   pBranch *br;
11969
11970   /* remove old CF information */
11971   pc = pb->pcHead;
11972   while (pc) {
11973     if (isPCI(pc)) {
11974       while (PCI(pc)->to) {
11975         br = PCI(pc)->to->next;
11976         Safe_free (PCI(pc)->to);
11977         PCI(pc)->to = br;
11978       } // while
11979       while (PCI(pc)->from) {
11980         br = PCI(pc)->from->next;
11981         Safe_free (PCI(pc)->from);
11982         PCI(pc)->from = br;
11983       }
11984     } else if (isPCFL(pc)) {
11985       deleteSet (&PCFL(pc)->to);
11986       deleteSet (&PCFL(pc)->from);
11987     }
11988     pc = pc->next;
11989   }
11990   
11991   releaseStack ();
11992 }
11993
11994 /* Set up pCodeInstruction's to and from pBranches. */
11995 static void pic16_createCF (pBlock *pb) {
11996   pCode *pc;
11997   pCode *next, *dest;
11998   char *label;
11999
12000   //fprintf (stderr, "creating CF for %p\n", pb);
12001
12002   pic16_destructCF (pb);
12003
12004   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12005   if (pic16_pBlockHasAsmdirs (pb)) {
12006     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12007     return;
12008   }
12009
12010   pc = pic16_findNextInstruction(pb->pcHead);
12011   while (pc) {
12012     next = pic16_findNextInstruction(pc->next);
12013     if (isPCI_SKIP(pc)) {
12014       pic16_pCodeLink(pc, next);
12015       pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
12016     } else if (isPCI_BRANCH(pc)) {
12017       // Bcc, BRA, CALL, GOTO
12018       if (PCI(pc)->pcop) {
12019         switch (PCI(pc)->pcop->type) {
12020         case PO_LABEL:
12021           label = PCOLAB(PCI(pc)->pcop)->pcop.name;
12022           dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
12023           break;
12024         
12025         case PO_STR:
12026           /* needed for GOTO ___irq_handler */
12027           label = PCI(pc)->pcop->name;
12028           dest = NULL;
12029           break;
12030
12031         default:
12032           assert (0 && "invalid label format");
12033           break;
12034         } // switch
12035       } else {
12036         label = "NO PCOP";
12037         dest = NULL;
12038       }
12039
12040       switch (PCI(pc)->op) {
12041       case POC_BRA:
12042       case POC_GOTO:
12043         if (dest != NULL) { 
12044           pic16_pCodeLink(pc, dest);
12045         } else {
12046           //fprintf (stderr, "jump target \"%s\" not found!\n", label);
12047         }
12048         break;
12049       case POC_CALL:
12050       case POC_RETURN:
12051       case POC_RETFIE:
12052         pic16_pCodeLink(pc, next);
12053         break;
12054       case POC_BC:
12055       case POC_BNC:
12056       case POC_BZ:
12057       case POC_BNZ:
12058       case POC_BN:
12059       case POC_BNN:
12060       case POC_BOV:
12061       case POC_BNOV:
12062         if (dest != NULL) { 
12063           pic16_pCodeLink(pc, dest);
12064         } else {
12065           //fprintf (stderr, "jump target \"%s\"not found!\n", label);
12066         }
12067         pic16_pCodeLink(pc, next);
12068         break;
12069       default:
12070         fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
12071         assert (0 && "unhandled branch instruction");
12072         break;
12073       } // switch
12074     } else {
12075       pic16_pCodeLink (pc, next);
12076     }
12077     pc = next;
12078   } // while
12079 }
12080 #endif
12081
12082 /* ======================================================================== */
12083 /* === VCG DUMPER ROUTINES ================================================ */
12084 /* ======================================================================== */
12085 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12086 hTab *dumpedNodes = NULL;
12087
12088 /** Dump VCG header into of. */
12089 static void pic16_vcg_init (FILE *of) {
12090   /* graph defaults */
12091   fprintf (of, "graph:{\n");
12092   fprintf (of, "title:\"graph1\"\n");
12093   fprintf (of, "label:\"graph1\"\n");
12094   fprintf (of, "color:white\n");
12095   fprintf (of, "textcolor:black\n");
12096   fprintf (of, "bordercolor:black\n");
12097   fprintf (of, "borderwidth:1\n");
12098   fprintf (of, "textmode:center\n");
12099
12100   fprintf (of, "layoutalgorithm:dfs\n");
12101   fprintf (of, "late_edge_labels:yes\n");
12102   fprintf (of, "display_edge_labels:yes\n");
12103   fprintf (of, "dirty_edge_labels:yes\n");
12104   fprintf (of, "finetuning:yes\n");
12105   fprintf (of, "ignoresingles:no\n");
12106   fprintf (of, "straight_phase:yes\n");
12107   fprintf (of, "priority_phase:yes\n");
12108   fprintf (of, "manhattan_edges:yes\n");
12109   fprintf (of, "smanhattan_edges:no\n");
12110   fprintf (of, "nearedges:no\n");
12111   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12112   fprintf (of, "port_sharing:no\n");
12113   fprintf (of, "arrowmode:free\n"); // fixed|free
12114   fprintf (of, "crossingphase2:yes\n");
12115   fprintf (of, "crossingoptimization:yes\n");
12116   fprintf (of, "edges:yes\n");
12117   fprintf (of, "nodes:yes\n");
12118   fprintf (of, "splines:no\n");
12119   
12120   /* node defaults */
12121   fprintf (of, "node.color:lightyellow\n");
12122   fprintf (of, "node.textcolor:black\n");
12123   fprintf (of, "node.textmode:center\n");
12124   fprintf (of, "node.shape:box\n");
12125   fprintf (of, "node.bordercolor:black\n");
12126   fprintf (of, "node.borderwidth:1\n");
12127
12128   /* edge defaults */
12129   fprintf (of, "edge.textcolor:black\n");
12130   fprintf (of, "edge.color:black\n");
12131   fprintf (of, "edge.thickness:1\n");
12132   fprintf (of, "edge.arrowcolor:black\n");
12133   fprintf (of, "edge.backarrowcolor:black\n");
12134   fprintf (of, "edge.arrowsize:15\n");
12135   fprintf (of, "edge.backarrowsize:15\n");
12136   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12137   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12138   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12139   
12140   fprintf (of, "\n");
12141
12142   /* prepare data structures */
12143   if (dumpedNodes) {
12144     hTabDeleteAll (dumpedNodes);
12145     dumpedNodes = NULL;
12146   }
12147   dumpedNodes = newHashTable (128);
12148 }
12149
12150 /** Dump VCG footer into of. */
12151 static void pic16_vcg_close (FILE *of) {
12152   fprintf (of, "}\n");
12153 }
12154
12155 #define BUF_SIZE 128
12156 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12157
12158 #if 0
12159 static int ptrcmp (const void *p1, const void *p2) {
12160   return p1 == p2;
12161 }
12162 #endif
12163
12164 /** Dump a pCode node as VCG to of. */
12165 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12166   char buf[BUF_SIZE];
12167
12168   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12169     // dumped already
12170     return;
12171   }
12172   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12173   //fprintf (stderr, "dumping %p\n", pc);
12174  
12175   /* only dump pCodeInstructions and Flow nodes */
12176   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12177     
12178   /* emit node */
12179   fprintf (of, "node:{");
12180   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12181   fprintf (of, "label:\"%s\n", pcTitle(pc));
12182   if (isPCFL(pc)) {
12183     fprintf (of, "<PCFLOW>");
12184   } else if (isPCI(pc) || isPCAD(pc)) {
12185     pc->print (of, pc);
12186   } else {
12187     fprintf (of, "<!PCI>");
12188   }
12189   fprintf (of, "\" ");
12190   fprintf (of, "}\n");
12191   
12192   if (1 && isPCFL(pc)) {
12193     defmap_t *map, *prev;
12194     unsigned int i;
12195     map = PCFL(pc)->defmap;
12196     i=0;
12197     while (map) {
12198       if (map->sym != 0) {
12199         i++;
12200       
12201         /* emit definition node */
12202         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12203         fprintf (of, "label:\"");
12204
12205         prev = map;
12206         do {
12207           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));
12208           prev = map;
12209           map = map->next;
12210         } while (map && prev->pc == map->pc);
12211         map = prev;
12212         
12213         fprintf (of, "\" ");
12214       
12215         fprintf (of, "color:green ");
12216         fprintf (of, "}\n");
12217
12218         /* emit edge to previous definition */
12219         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12220         if (i == 1) {
12221           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12222         } else {
12223           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12224         }
12225         fprintf (of, "color:green ");
12226         fprintf (of, "}\n");
12227
12228         if (map->pc) {
12229           pic16_vcg_dumpnode (map->pc, of);
12230           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12231           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12232         }
12233       }
12234       map = map->next;
12235     } // while
12236   }
12237
12238   /* emit additional nodes (e.g. operands) */
12239 }
12240
12241 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12242 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12243   char buf[BUF_SIZE];
12244   pCodeInstruction *pci;
12245   pBranch *curr;
12246   int i;
12247   
12248   if (1 && isPCFL(pc)) {
12249     /* emit edges to flow successors */
12250     void *pcfl;
12251     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12252     pcfl = setFirstItem (PCFL(pc)->to);
12253     while (pcfl) {
12254       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12255       pic16_vcg_dumpnode (pc, of);
12256       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12257       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12258       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12259       pcfl = setNextItem (PCFL(pc)->to);
12260     } // while
12261   } // if
12262   
12263   if (!isPCI(pc) && !isPCAD(pc)) return;
12264
12265   pci = PCI(pc);
12266   
12267   /* emit control flow edges (forward only) */
12268   curr = pci->to;
12269   i=0;
12270   while (curr) {
12271     pic16_vcg_dumpnode (curr->pc, of);
12272     fprintf (of, "edge:{");
12273     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12274     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12275     fprintf (of, "color:red ");
12276     fprintf (of, "}\n");
12277     curr = curr->next;
12278   } // while
12279
12280 #if 1
12281   /* dump "flow" edge (link pCode according to pBlock order) */
12282   {
12283     pCode *pcnext;
12284     pcnext = pic16_findNextInstruction (pc->next);
12285     if (pcnext) {
12286       pic16_vcg_dumpnode (pcnext, of);
12287       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12288       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12289     }
12290   }
12291 #endif
12292   
12293 #if 0
12294   /* emit flow */
12295   if (pci->pcflow) {
12296     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12297     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12298     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12299   }
12300 #endif
12301   
12302   /* emit data flow edges (backward only) */
12303   /* TODO: gather data flow information... */
12304 }
12305
12306 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12307   pCode *pc;
12308
12309   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12310   if (pic16_pBlockHasAsmdirs (pb)) {
12311     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12312     return;
12313   }
12314
12315   for (pc=pb->pcHead; pc; pc = pc->next) {
12316     pic16_vcg_dumpnode (pc, of);
12317   } // for pc
12318   
12319   for (pc=pb->pcHead; pc; pc = pc->next) {
12320     pic16_vcg_dumpedges (pc, of);
12321   } // for pc
12322 }
12323
12324 static void pic16_vcg_dump_default (pBlock *pb) {
12325   FILE *of;
12326   char buf[BUF_SIZE];
12327   pCode *pc;
12328
12329   /* get function name */
12330   pc = pb->pcHead;
12331   while (pc && !isPCF(pc)) pc = pc->next;
12332   if (pc) {
12333     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12334   } else {
12335     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12336   }
12337
12338   //fprintf (stderr, "now dumping %s\n", buf);
12339   of = fopen (buf, "w");
12340   pic16_vcg_init (of);
12341   pic16_vcg_dump (of, pb);
12342   pic16_vcg_close (of);
12343   fclose (of);
12344 }
12345 #endif
12346
12347 /*** END of helpers for pCode dataflow optimizations ***/