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