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