1 /*-------------------------------------------------------------------------
2   pcode.c - post code generation
3 
4   Copyright (C) 2000, Scott Dattalo scott@dattalo.com
5   PIC16 port:
6   Copyright (C) 2002, 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 inline
39 #endif
40 
41 #define DUMP_DF_GRAPHS 0
42 
43 /****************************************************************/
44 /****************************************************************/
45 
46 static peepCommand peepCommands[] = {
47 
48   {NOTBITSKIP, "_NOTBITSKIP_"},
49   {BITSKIP, "_BITSKIP_"},
50   {INVERTBITSKIP, "_INVERTBITSKIP_"},
51 
52   {-1, NULL}
53 };
54 
55 
56 
57 // Eventually this will go into device dependent files:
58 pCodeOpReg pic16_pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,0,NULL};
59 pCodeOpReg pic16_pc_intcon    = {{PO_INTCON,  "INTCON"}, -1, NULL,0,NULL};
60 pCodeOpReg pic16_pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,0,NULL};
61 pCodeOpReg pic16_pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_pclatu    = {{PO_PCLATU,  "PCLATU"}, -1, NULL,0,NULL}; // patch 14
63 pCodeOpReg pic16_pc_wreg      = {{PO_WREG,    "WREG"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_bsr       = {{PO_BSR,     "BSR"}, -1, NULL,0,NULL};
65 
66 pCodeOpReg pic16_pc_tosl      = {{PO_SFR_REGISTER,   "TOSL"}, -1, NULL,0,NULL}; // patch 14
67 pCodeOpReg pic16_pc_tosh      = {{PO_SFR_REGISTER,   "TOSH"}, -1, NULL,0,NULL}; //
68 pCodeOpReg pic16_pc_tosu      = {{PO_SFR_REGISTER,   "TOSU"}, -1, NULL,0,NULL}; // patch 14
69 
70 pCodeOpReg pic16_pc_tblptrl   = {{PO_SFR_REGISTER,   "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
71 pCodeOpReg pic16_pc_tblptrh   = {{PO_SFR_REGISTER,   "TBLPTRH"}, -1, NULL,0,NULL}; //
72 pCodeOpReg pic16_pc_tblptru   = {{PO_SFR_REGISTER,   "TBLPTRU"}, -1, NULL,0,NULL}; //
73 pCodeOpReg pic16_pc_tablat    = {{PO_SFR_REGISTER,   "TABLAT"}, -1, NULL,0,NULL};  // patch 15
74 
75 //pCodeOpReg pic16_pc_fsr0      = {{PO_FSR0,    "FSR0"}, -1, NULL,0,NULL}; //deprecated !
76 
77 pCodeOpReg pic16_pc_fsr0l       = {{PO_FSR0,    "FSR0L"}, -1, NULL, 0, NULL};
78 pCodeOpReg pic16_pc_fsr0h       = {{PO_FSR0,    "FSR0H"}, -1, NULL, 0, NULL};
79 pCodeOpReg pic16_pc_fsr1l       = {{PO_FSR0,    "FSR1L"}, -1, NULL, 0, NULL};
80 pCodeOpReg pic16_pc_fsr1h       = {{PO_FSR0,    "FSR1H"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr2l       = {{PO_FSR0,    "FSR2L"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr2h       = {{PO_FSR0,    "FSR2H"}, -1, NULL, 0, NULL};
83 
84 pCodeOpReg pic16_pc_indf0       = {{PO_INDF0,   "INDF0"}, -1, NULL,0,NULL};
85 pCodeOpReg pic16_pc_postinc0    = {{PO_INDF0,   "POSTINC0"}, -1, NULL, 0, NULL};
86 pCodeOpReg pic16_pc_postdec0    = {{PO_INDF0,   "POSTDEC0"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_preinc0     = {{PO_INDF0,   "PREINC0"}, -1, NULL, 0, NULL};
88 pCodeOpReg pic16_pc_plusw0      = {{PO_INDF0,   "PLUSW0"}, -1, NULL, 0, NULL};
89 
90 pCodeOpReg pic16_pc_indf1       = {{PO_INDF0,   "INDF1"}, -1, NULL,0,NULL};
91 pCodeOpReg pic16_pc_postinc1    = {{PO_INDF0,   "POSTINC1"}, -1, NULL, 0, NULL};
92 pCodeOpReg pic16_pc_postdec1    = {{PO_INDF0,   "POSTDEC1"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_preinc1     = {{PO_INDF0,   "PREINC1"}, -1, NULL, 0, NULL};
94 pCodeOpReg pic16_pc_plusw1      = {{PO_INDF0,   "PLUSW1"}, -1, NULL, 0, NULL};
95 
96 pCodeOpReg pic16_pc_indf2       = {{PO_INDF0,   "INDF2"}, -1, NULL,0,NULL};
97 pCodeOpReg pic16_pc_postinc2    = {{PO_INDF0,   "POSTINC2"}, -1, NULL, 0, NULL};
98 pCodeOpReg pic16_pc_postdec2    = {{PO_INDF0,   "POSTDEC2"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_preinc2     = {{PO_INDF0,   "PREINC2"}, -1, NULL, 0, NULL};
100 pCodeOpReg pic16_pc_plusw2      = {{PO_INDF0,   "PLUSW2"}, -1, NULL, 0, NULL};
101 
102 pCodeOpReg pic16_pc_prodl       = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_prodh       = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
104 
105 /* EEPROM registers */
106 pCodeOpReg pic16_pc_eecon1      = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
107 pCodeOpReg pic16_pc_eecon2      = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
108 pCodeOpReg pic16_pc_eedata      = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
109 pCodeOpReg pic16_pc_eeadr       = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
110 
111 pCodeOpReg pic16_pc_kzero     = {{PO_GPR_REGISTER,  "KZ"}, -1, NULL,0,NULL};
112 pCodeOpReg pic16_pc_wsave     = {{PO_GPR_REGISTER,  "WSAVE"}, -1, NULL,0,NULL};
113 pCodeOpReg pic16_pc_ssave     = {{PO_GPR_REGISTER,  "SSAVE"}, -1, NULL,0,NULL};
114 
115 pCodeOpReg *pic16_stackpnt_lo;
116 pCodeOpReg *pic16_stackpnt_hi;
117 pCodeOpReg *pic16_stack_postinc;
118 pCodeOpReg *pic16_stack_postdec;
119 pCodeOpReg *pic16_stack_preinc;
120 pCodeOpReg *pic16_stack_plusw;
121 
122 pCodeOpReg *pic16_framepnt_lo;
123 pCodeOpReg *pic16_framepnt_hi;
124 pCodeOpReg *pic16_frame_postinc;
125 pCodeOpReg *pic16_frame_postdec;
126 pCodeOpReg *pic16_frame_preinc;
127 pCodeOpReg *pic16_frame_plusw;
128 
129 pCodeOpReg pic16_pc_gpsimio   = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
130 pCodeOpReg pic16_pc_gpsimio2  = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
131 
132 static const char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
133 const char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
134 
135 
136 static int mnemonics_initialized = 0;
137 
138 
139 static hTab *pic16MnemonicsHash = NULL;
140 static hTab *pic16pCodePeepCommandsHash = NULL;
141 
142 static pFile *the_pFile = NULL;
143 static pBlock *pb_dead_pcodes = NULL;
144 
145 /* Hardcoded flags to change the behavior of the PIC port */
146 static int peepOptimizing = 1;        /* run the peephole optimizer if nonzero */
147 static int functionInlining = 1;      /* inline functions if nonzero */
148 int pic16_debug_verbose = 0;                /* Set true to inundate .asm file */
149 
150 int pic16_pcode_verbose = 0;
151 
152 //static int GpCodeSequenceNumber = 1;
153 static int GpcFlowSeq = 1;
154 
155 extern void pic16_RemoveUnusedRegisters(void);
156 extern void pic16_RegsUnMapLiveRanges(void);
157 extern void pic16_BuildFlowTree(pBlock *pb);
158 extern void pic16_pCodeRegOptimizeRegUsage(int level);
159 
160 /****************************************************************/
161 /*                      Forward declarations                    */
162 /****************************************************************/
163 
164 void pic16_unlinkpCode(pCode *pc);
165 #if 0
166 static void genericAnalyze(pCode *pc);
167 static void AnalyzeGOTO(pCode *pc);
168 static void AnalyzeSKIP(pCode *pc);
169 static void AnalyzeRETURN(pCode *pc);
170 #endif
171 
172 static void genericDestruct(pCode *pc);
173 static void genericPrint(FILE *of,pCode *pc);
174 
175 static void pCodePrintLabel(FILE *of, pCode *pc);
176 static void pCodePrintFunction(FILE *of, pCode *pc);
177 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
178 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
179 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
180 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
181 int pic16_pCodePeepMatchRule(pCode *pc);
182 static void pBlockStats(FILE *of, pBlock *pb);
183 static pBlock *newpBlock(void);
184 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
185 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
186 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
187 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
188 void OptimizeLocalRegs(void);
189 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
190 
191 const char *dumpPicOptype(PIC_OPTYPE type);
192 
193 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
194 pCodeOp *pic16_popGetLit(int);
195 pCodeOp *pic16_popGetWithString(const char *);
196 int isBanksel(pCode *pc);
197 extern int inWparamList(char *s);
198 
199 /** data flow optimization helpers **/
200 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
201 static void pic16_vcg_dump (FILE *of, pBlock *pb);
202 static void pic16_vcg_dump_default (pBlock *pb);
203 #endif
204 static int pic16_pCodeIsAlive (pCode *pc);
205 static void pic16_df_stats ();
206 static void pic16_createDF (pBlock *pb);
207 static int pic16_removeUnusedRegistersDF ();
208 static void pic16_destructDF (pBlock *pb);
209 static void releaseStack (void);
210 
211 /****************************************************************/
212 /*                    PIC Instructions                          */
213 /****************************************************************/
214 
215 pCodeInstruction pic16_pciADDWF = {
216   {PC_OPCODE, NULL, NULL, 0, NULL,
217    //   genericAnalyze,
218    genericDestruct,
219    genericPrint},
220   POC_ADDWF,
221   "ADDWF",
222   2,
223   NULL, // from branch
224   NULL, // to branch
225   NULL, // label
226   NULL, // operand
227   NULL, // flow block
228   NULL, // C source
229   3,    // num ops
230   TRUE,  // dest
231   FALSE,  // bit instruction
232   FALSE,  // branch
233   FALSE,  // skip
234   FALSE,    // literal operand
235   TRUE,    // RAM access bit
236   FALSE,    // fast call/return mode select bit
237   FALSE,    // second memory operand
238   FALSE,    // second literal operand
239   POC_NOP,
240   (PCC_W | PCC_REGISTER),   // inCond
241   (PCC_REGISTER | PCC_STATUS), // outCond
242   PCI_MAGIC
243 };
244 
245 pCodeInstruction pic16_pciADDFW = {
246   {PC_OPCODE, NULL, NULL, 0, NULL,
247    //   genericAnalyze,
248    genericDestruct,
249    genericPrint},
250   POC_ADDFW,
251   "ADDWF",
252   2,
253   NULL, // from branch
254   NULL, // to branch
255   NULL, // label
256   NULL, // operand
257   NULL, // flow block
258   NULL, // C source
259   3,    // num ops
260   FALSE,  // dest
261   FALSE,  // bit instruction
262   FALSE,  // branch
263   FALSE,  // skip
264   FALSE,    // literal operand
265   TRUE,    // RAM access bit
266   FALSE,    // fast call/return mode select bit
267   FALSE,    // second memory operand
268   FALSE,    // second literal operand
269   POC_NOP,
270   (PCC_W | PCC_REGISTER),   // inCond
271   (PCC_W | PCC_STATUS), // outCond
272   PCI_MAGIC
273 };
274 
275 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
276   {PC_OPCODE, NULL, NULL, 0, NULL,
277    //   genericAnalyze,
278    genericDestruct,
279    genericPrint},
280   POC_ADDWFC,
281   "ADDWFC",
282   2,
283   NULL, // from branch
284   NULL, // to branch
285   NULL, // label
286   NULL, // operand
287   NULL, // flow block
288   NULL, // C source
289   3,    // num ops
290   TRUE,  // dest
291   FALSE,  // bit instruction
292   FALSE,  // branch
293   FALSE,  // skip
294   FALSE,    // literal operand
295   TRUE,    // RAM access bit
296   FALSE,    // fast call/return mode select bit
297   FALSE,    // second memory operand
298   FALSE,    // second literal operand
299   POC_NOP,
300   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
301   (PCC_REGISTER | PCC_STATUS), // outCond
302   PCI_MAGIC
303 };
304 
305 pCodeInstruction pic16_pciADDFWC = {
306   {PC_OPCODE, NULL, NULL, 0, NULL,
307    //   genericAnalyze,
308    genericDestruct,
309    genericPrint},
310   POC_ADDFWC,
311   "ADDWFC",
312   2,
313   NULL, // from branch
314   NULL, // to branch
315   NULL, // label
316   NULL, // operand
317   NULL, // flow block
318   NULL, // C source
319   3,    // num ops
320   FALSE,  // dest
321   FALSE,  // bit instruction
322   FALSE,  // branch
323   FALSE,  // skip
324   FALSE,    // literal operand
325   TRUE,    // RAM access bit
326   FALSE,    // fast call/return mode select bit
327   FALSE,    // second memory operand
328   FALSE,    // second literal operand
329   POC_NOP,
330   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
331   (PCC_W | PCC_STATUS), // outCond
332   PCI_MAGIC
333 };
334 
335 pCodeInstruction pic16_pciADDLW = {
336   {PC_OPCODE, NULL, NULL, 0, NULL,
337    //   genericAnalyze,
338    genericDestruct,
339    genericPrint},
340   POC_ADDLW,
341   "ADDLW",
342   2,
343   NULL, // from branch
344   NULL, // to branch
345   NULL, // label
346   NULL, // operand
347   NULL, // flow block
348   NULL, // C source
349   1,    // num ops
350   FALSE,  // dest
351   FALSE,  // bit instruction
352   FALSE,  // branch
353   FALSE,  // skip
354   TRUE,    // literal operand
355   FALSE,    // RAM access bit
356   FALSE,    // fast call/return mode select bit
357   FALSE,    // second memory operand
358   FALSE,    // second literal operand
359   POC_NOP,
360   (PCC_W | PCC_LITERAL),   // inCond
361   (PCC_W | PCC_STATUS), // outCond
362   PCI_MAGIC
363 };
364 
365 pCodeInstruction pic16_pciANDLW = {
366   {PC_OPCODE, NULL, NULL, 0, NULL,
367    //   genericAnalyze,
368    genericDestruct,
369    genericPrint},
370   POC_ANDLW,
371   "ANDLW",
372   2,
373   NULL, // from branch
374   NULL, // to branch
375   NULL, // label
376   NULL, // operand
377   NULL, // flow block
378   NULL, // C source
379   1,    // num ops
380   FALSE,  // dest
381   FALSE,  // bit instruction
382   FALSE,  // branch
383   FALSE,  // skip
384   TRUE,    // literal operand
385   FALSE,    // RAM access bit
386   FALSE,    // fast call/return mode select bit
387   FALSE,    // second memory operand
388   FALSE,    // second literal operand
389   POC_NOP,
390   (PCC_W | PCC_LITERAL),   // inCond
391   (PCC_W | PCC_Z | PCC_N), // outCond
392   PCI_MAGIC
393 };
394 
395 pCodeInstruction pic16_pciANDWF = {
396   {PC_OPCODE, NULL, NULL, 0, NULL,
397    //   genericAnalyze,
398    genericDestruct,
399    genericPrint},
400   POC_ANDWF,
401   "ANDWF",
402   2,
403   NULL, // from branch
404   NULL, // to branch
405   NULL, // label
406   NULL, // operand
407   NULL, // flow block
408   NULL, // C source
409   3,    // num ops
410   TRUE,  // dest
411   FALSE,  // bit instruction
412   FALSE,  // branch
413   FALSE,  // skip
414   FALSE,    // literal operand
415   TRUE,    // RAM access bit
416   FALSE,    // fast call/return mode select bit
417   FALSE,    // second memory operand
418   FALSE,    // second literal operand
419   POC_NOP,
420   (PCC_W | PCC_REGISTER),   // inCond
421   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
422   PCI_MAGIC
423 };
424 
425 pCodeInstruction pic16_pciANDFW = {
426   {PC_OPCODE, NULL, NULL, 0, NULL,
427    //   genericAnalyze,
428    genericDestruct,
429    genericPrint},
430   POC_ANDFW,
431   "ANDWF",
432   2,
433   NULL, // from branch
434   NULL, // to branch
435   NULL, // label
436   NULL, // operand
437   NULL, // flow block
438   NULL, // C source
439   3,    // num ops
440   FALSE,  // dest
441   FALSE,  // bit instruction
442   FALSE,  // branch
443   FALSE,  // skip
444   FALSE,    // literal operand
445   TRUE,    // RAM access bit
446   FALSE,    // fast call/return mode select bit
447   FALSE,    // second memory operand
448   FALSE,    // second literal operand
449   POC_NOP,
450   (PCC_W | PCC_REGISTER),   // inCond
451   (PCC_W | PCC_Z | PCC_N), // outCond
452   PCI_MAGIC
453 };
454 
455 pCodeInstruction pic16_pciBC = { // mdubuc - New
456   {PC_OPCODE, NULL, NULL, 0, NULL,
457    //   genericAnalyze,
458    genericDestruct,
459    genericPrint},
460   POC_BC,
461   "BC",
462   2,
463   NULL, // from branch
464   NULL, // to branch
465   NULL, // label
466   NULL, // operand
467   NULL, // flow block
468   NULL, // C source
469   1,    // num ops
470   FALSE,  // dest
471   FALSE,  // bit instruction
472   TRUE,  // branch
473   FALSE,  // skip
474   FALSE,    // literal operand
475   FALSE,    // RAM access bit
476   FALSE,    // fast call/return mode select bit
477   FALSE,    // second memory operand
478   FALSE,    // second literal operand
479   POC_NOP,
480   (PCC_REL_ADDR | PCC_C),   // inCond
481   PCC_NONE,    // outCond
482   PCI_MAGIC
483 };
484 
485 pCodeInstruction pic16_pciBCF = {
486   {PC_OPCODE, NULL, NULL, 0, NULL,
487    //   genericAnalyze,
488    genericDestruct,
489    genericPrint},
490   POC_BCF,
491   "BCF",
492   2,
493   NULL, // from branch
494   NULL, // to branch
495   NULL, // label
496   NULL, // operand
497   NULL, // flow block
498   NULL, // C source
499   3,    // num ops
500   TRUE,  // dest
501   TRUE,  // bit instruction
502   FALSE,  // branch
503   FALSE,  // skip
504   FALSE,    // literal operand
505   TRUE,    // RAM access bit
506   FALSE,    // fast call/return mode select bit
507   FALSE,    // second memory operand
508   FALSE,    // second literal operand
509   POC_BSF,
510   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
511   PCC_REGISTER, // outCond
512   PCI_MAGIC
513 };
514 
515 pCodeInstruction pic16_pciBN = { // mdubuc - New
516   {PC_OPCODE, NULL, NULL, 0, NULL,
517    //   genericAnalyze,
518    genericDestruct,
519    genericPrint},
520   POC_BN,
521   "BN",
522   2,
523   NULL, // from branch
524   NULL, // to branch
525   NULL, // label
526   NULL, // operand
527   NULL, // flow block
528   NULL, // C source
529   1,    // num ops
530   FALSE,  // dest
531   FALSE,  // bit instruction
532   TRUE,  // branch
533   FALSE,  // skip
534   FALSE,    // literal operand
535   FALSE,    // RAM access bit
536   FALSE,    // fast call/return mode select bit
537   FALSE,    // second memory operand
538   FALSE,    // second literal operand
539   POC_NOP,
540   (PCC_REL_ADDR | PCC_N),   // inCond
541   PCC_NONE   , // outCond
542   PCI_MAGIC
543 };
544 
545 pCodeInstruction pic16_pciBNC = { // mdubuc - New
546   {PC_OPCODE, NULL, NULL, 0, NULL,
547    //   genericAnalyze,
548    genericDestruct,
549    genericPrint},
550   POC_BNC,
551   "BNC",
552   2,
553   NULL, // from branch
554   NULL, // to branch
555   NULL, // label
556   NULL, // operand
557   NULL, // flow block
558   NULL, // C source
559   1,    // num ops
560   FALSE,  // dest
561   FALSE,  // bit instruction
562   TRUE,  // branch
563   FALSE,  // skip
564   FALSE,    // literal operand
565   FALSE,    // RAM access bit
566   FALSE,    // fast call/return mode select bit
567   FALSE,    // second memory operand
568   FALSE,    // second literal operand
569   POC_NOP,
570   (PCC_REL_ADDR | PCC_C),   // inCond
571   PCC_NONE   , // outCond
572   PCI_MAGIC
573 };
574 
575 pCodeInstruction pic16_pciBNN = { // mdubuc - New
576   {PC_OPCODE, NULL, NULL, 0, NULL,
577    //   genericAnalyze,
578    genericDestruct,
579    genericPrint},
580   POC_BNN,
581   "BNN",
582   2,
583   NULL, // from branch
584   NULL, // to branch
585   NULL, // label
586   NULL, // operand
587   NULL, // flow block
588   NULL, // C source
589   1,    // num ops
590   FALSE,  // dest
591   FALSE,  // bit instruction
592   TRUE,  // branch
593   FALSE,  // skip
594   FALSE,    // literal operand
595   FALSE,    // RAM access bit
596   FALSE,    // fast call/return mode select bit
597   FALSE,    // second memory operand
598   FALSE,    // second literal operand
599   POC_NOP,
600   (PCC_REL_ADDR | PCC_N),   // inCond
601   PCC_NONE   , // outCond
602   PCI_MAGIC
603 };
604 
605 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
606   {PC_OPCODE, NULL, NULL, 0, NULL,
607    //   genericAnalyze,
608    genericDestruct,
609    genericPrint},
610   POC_BNOV,
611   "BNOV",
612   2,
613   NULL, // from branch
614   NULL, // to branch
615   NULL, // label
616   NULL, // operand
617   NULL, // flow block
618   NULL, // C source
619   1,    // num ops
620   FALSE,  // dest
621   FALSE,  // bit instruction
622   TRUE,  // branch
623   FALSE,  // skip
624   FALSE,    // literal operand
625   FALSE,    // RAM access bit
626   FALSE,    // fast call/return mode select bit
627   FALSE,    // second memory operand
628   FALSE,    // second literal operand
629   POC_NOP,
630   (PCC_REL_ADDR | PCC_OV),   // inCond
631   PCC_NONE   , // outCond
632   PCI_MAGIC
633 };
634 
635 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
636   {PC_OPCODE, NULL, NULL, 0, NULL,
637    //   genericAnalyze,
638    genericDestruct,
639    genericPrint},
640   POC_BNZ,
641   "BNZ",
642   2,
643   NULL, // from branch
644   NULL, // to branch
645   NULL, // label
646   NULL, // operand
647   NULL, // flow block
648   NULL, // C source
649   1,    // num ops
650   FALSE,  // dest
651   FALSE,  // bit instruction
652   TRUE,  // branch
653   FALSE,  // skip
654   FALSE,    // literal operand
655   FALSE,    // RAM access bit
656   FALSE,    // fast call/return mode select bit
657   FALSE,    // second memory operand
658   FALSE,    // second literal operand
659   POC_NOP,
660   (PCC_REL_ADDR | PCC_Z),   // inCond
661   PCC_NONE   , // outCond
662   PCI_MAGIC
663 };
664 
665 pCodeInstruction pic16_pciBOV = { // mdubuc - New
666   {PC_OPCODE, NULL, NULL, 0, NULL,
667    //   genericAnalyze,
668    genericDestruct,
669    genericPrint},
670   POC_BOV,
671   "BOV",
672   2,
673   NULL, // from branch
674   NULL, // to branch
675   NULL, // label
676   NULL, // operand
677   NULL, // flow block
678   NULL, // C source
679   1,    // num ops
680   FALSE,  // dest
681   FALSE,  // bit instruction
682   TRUE,  // branch
683   FALSE,  // skip
684   FALSE,    // literal operand
685   FALSE,    // RAM access bit
686   FALSE,    // fast call/return mode select bit
687   FALSE,    // second memory operand
688   FALSE,    // second literal operand
689   POC_NOP,
690   (PCC_REL_ADDR | PCC_OV),   // inCond
691   PCC_NONE , // outCond
692   PCI_MAGIC
693 };
694 
695 pCodeInstruction pic16_pciBRA = { // mdubuc - New
696   {PC_OPCODE, NULL, NULL, 0, NULL,
697    //   genericAnalyze,
698    genericDestruct,
699    genericPrint},
700   POC_BRA,
701   "BRA",
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   1,    // num ops
710   FALSE,  // dest
711   FALSE,  // bit instruction
712   TRUE,  // branch
713   FALSE,  // skip
714   FALSE,    // literal operand
715   FALSE,    // RAM access bit
716   FALSE,    // fast call/return mode select bit
717   FALSE,    // second memory operand
718   FALSE,    // second literal operand
719   POC_NOP,
720   PCC_REL_ADDR,   // inCond
721   PCC_NONE   , // outCond
722   PCI_MAGIC
723 };
724 
725 pCodeInstruction pic16_pciBSF = {
726   {PC_OPCODE, NULL, NULL, 0, NULL,
727    //   genericAnalyze,
728    genericDestruct,
729    genericPrint},
730   POC_BSF,
731   "BSF",
732   2,
733   NULL, // from branch
734   NULL, // to branch
735   NULL, // label
736   NULL, // operand
737   NULL, // flow block
738   NULL, // C source
739   3,    // num ops
740   TRUE,  // dest
741   TRUE,  // bit instruction
742   FALSE,  // branch
743   FALSE,  // skip
744   FALSE,    // literal operand
745   TRUE,    // RAM access bit
746   FALSE,    // fast call/return mode select bit
747   FALSE,    // second memory operand
748   FALSE,    // second literal operand
749   POC_BCF,
750   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
751   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
752   PCI_MAGIC
753 };
754 
755 pCodeInstruction pic16_pciBTFSC = {
756   {PC_OPCODE, NULL, NULL, 0, NULL,
757    //   AnalyzeSKIP,
758    genericDestruct,
759    genericPrint},
760   POC_BTFSC,
761   "BTFSC",
762   2,
763   NULL, // from branch
764   NULL, // to branch
765   NULL, // label
766   NULL, // operand
767   NULL, // flow block
768   NULL, // C source
769   3,    // num ops
770   FALSE,  // dest
771   TRUE,  // bit instruction
772   TRUE,  // branch
773   TRUE,  // skip
774   FALSE,    // literal operand
775   TRUE,    // RAM access bit
776   FALSE,    // fast call/return mode select bit
777   FALSE,    // second memory operand
778   FALSE,    // second literal operand
779   POC_BTFSS,
780   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
781   PCC_EXAMINE_PCOP, // outCond
782   PCI_MAGIC
783 };
784 
785 pCodeInstruction pic16_pciBTFSS = {
786   {PC_OPCODE, NULL, NULL, 0, NULL,
787    //   AnalyzeSKIP,
788    genericDestruct,
789    genericPrint},
790   POC_BTFSS,
791   "BTFSS",
792   2,
793   NULL, // from branch
794   NULL, // to branch
795   NULL, // label
796   NULL, // operand
797   NULL, // flow block
798   NULL, // C source
799   3,    // num ops
800   FALSE,  // dest
801   TRUE,  // bit instruction
802   TRUE,  // branch
803   TRUE,  // skip
804   FALSE,    // literal operand
805   TRUE,    // RAM access bit
806   FALSE,    // fast call/return mode select bit
807   FALSE,    // second memory operand
808   FALSE,    // second literal operand
809   POC_BTFSC,
810   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
811   PCC_EXAMINE_PCOP, // outCond
812   PCI_MAGIC
813 };
814 
815 pCodeInstruction pic16_pciBTG = { // mdubuc - New
816   {PC_OPCODE, NULL, NULL, 0, NULL,
817    //   genericAnalyze,
818    genericDestruct,
819    genericPrint},
820   POC_BTG,
821   "BTG",
822   2,
823   NULL, // from branch
824   NULL, // to branch
825   NULL, // label
826   NULL, // operand
827   NULL, // flow block
828   NULL, // C source
829   3,    // num ops
830   FALSE,  // dest
831   TRUE,  // bit instruction
832   FALSE,  // branch
833   FALSE,  // skip
834   FALSE,    // literal operand
835   TRUE,    // RAM access bit
836   FALSE,    // fast call/return mode select bit
837   FALSE,    // second memory operand
838   FALSE,    // second literal operand
839   POC_NOP,
840   (PCC_REGISTER | PCC_EXAMINE_PCOP),   // inCond
841   (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
842   PCI_MAGIC
843 };
844 
845 pCodeInstruction pic16_pciBZ = { // mdubuc - New
846   {PC_OPCODE, NULL, NULL, 0, NULL,
847    //   genericAnalyze,
848    genericDestruct,
849    genericPrint},
850   POC_BZ,
851   "BZ",
852   2,
853   NULL, // from branch
854   NULL, // to branch
855   NULL, // label
856   NULL, // operand
857   NULL, // flow block
858   NULL, // C source
859   1,    // num ops
860   FALSE,  // dest
861   FALSE,  // bit instruction
862   TRUE,  // branch
863   FALSE,  // skip
864   FALSE,    // literal operand
865   FALSE,    // RAM access bit
866   FALSE,    // fast call/return mode select bit
867   FALSE,    // second memory operand
868   FALSE,    // second literal operand
869   POC_NOP,
870   (PCC_REL_ADDR | PCC_Z),   // inCond
871   PCC_NONE, // outCond
872   PCI_MAGIC
873 };
874 
875 pCodeInstruction pic16_pciCALL = {
876   {PC_OPCODE, NULL, NULL, 0, NULL,
877    //   genericAnalyze,
878    genericDestruct,
879    genericPrint},
880   POC_CALL,
881   "CALL",
882   4,
883   NULL, // from branch
884   NULL, // to branch
885   NULL, // label
886   NULL, // operand
887   NULL, // flow block
888   NULL, // C source
889   2,    // num ops
890   FALSE,  // dest
891   FALSE,  // bit instruction
892   TRUE,  // branch
893   FALSE,  // skip
894   FALSE,    // literal operand
895   FALSE,    // RAM access bit
896   TRUE,    // fast call/return mode select bit
897   FALSE,    // second memory operand
898   FALSE,    // second literal operand
899   POC_NOP,
900   PCC_NONE, // inCond
901   PCC_NONE, // outCond
902   PCI_MAGIC
903 };
904 
905 pCodeInstruction pic16_pciCOMF = {
906   {PC_OPCODE, NULL, NULL, 0, NULL,
907    //   genericAnalyze,
908    genericDestruct,
909    genericPrint},
910   POC_COMF,
911   "COMF",
912   2,
913   NULL, // from branch
914   NULL, // to branch
915   NULL, // label
916   NULL, // operand
917   NULL, // flow block
918   NULL, // C source
919   3,    // num ops
920   TRUE,  // dest
921   FALSE,  // bit instruction
922   FALSE,  // branch
923   FALSE,  // skip
924   FALSE,    // literal operand
925   TRUE,    // RAM access bit
926   FALSE,    // fast call/return mode select bit
927   FALSE,    // second memory operand
928   FALSE,    // second literal operand
929   POC_NOP,
930   PCC_REGISTER,  // inCond
931   (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
932   PCI_MAGIC
933 };
934 
935 pCodeInstruction pic16_pciCOMFW = {
936   {PC_OPCODE, NULL, NULL, 0, NULL,
937    //   genericAnalyze,
938    genericDestruct,
939    genericPrint},
940   POC_COMFW,
941   "COMF",
942   2,
943   NULL, // from branch
944   NULL, // to branch
945   NULL, // label
946   NULL, // operand
947   NULL, // flow block
948   NULL, // C source
949   3,    // num ops
950   FALSE,  // dest
951   FALSE,  // bit instruction
952   FALSE,  // branch
953   FALSE,  // skip
954   FALSE,    // literal operand
955   TRUE,    // RAM access bit
956   FALSE,    // fast call/return mode select bit
957   FALSE,    // second memory operand
958   FALSE,    // second literal operand
959   POC_NOP,
960   PCC_REGISTER,  // inCond
961   (PCC_W | PCC_Z | PCC_N) , // outCond
962   PCI_MAGIC
963 };
964 
965 pCodeInstruction pic16_pciCLRF = {
966   {PC_OPCODE, NULL, NULL, 0, NULL,
967    //   genericAnalyze,
968    genericDestruct,
969    genericPrint},
970   POC_CLRF,
971   "CLRF",
972   2,
973   NULL, // from branch
974   NULL, // to branch
975   NULL, // label
976   NULL, // operand
977   NULL, // flow block
978   NULL, // C source
979   2,    // num ops
980   FALSE,  // dest
981   FALSE,  // bit instruction
982   FALSE,  // branch
983   FALSE,  // skip
984   FALSE,    // literal operand
985   TRUE,    // RAM access bit
986   FALSE,    // fast call/return mode select bit
987   FALSE,    // second memory operand
988   FALSE,    // second literal operand
989   POC_NOP,
990   PCC_NONE, // inCond
991   (PCC_REGISTER | PCC_Z), // outCond
992   PCI_MAGIC
993 };
994 
995 pCodeInstruction pic16_pciCLRWDT = {
996   {PC_OPCODE, NULL, NULL, 0, NULL,
997    //   genericAnalyze,
998    genericDestruct,
999    genericPrint},
1000   POC_CLRWDT,
1001   "CLRWDT",
1002   2,
1003   NULL, // from branch
1004   NULL, // to branch
1005   NULL, // label
1006   NULL, // operand
1007   NULL, // flow block
1008   NULL, // C source
1009   0,    // num ops
1010   FALSE,  // dest
1011   FALSE,  // bit instruction
1012   FALSE,  // branch
1013   FALSE,  // skip
1014   FALSE,    // literal operand
1015   FALSE,    // RAM access bit
1016   FALSE,    // fast call/return mode select bit
1017   FALSE,    // second memory operand
1018   FALSE,    // second literal operand
1019   POC_NOP,
1020   PCC_NONE, // inCond
1021   PCC_NONE , // outCond
1022   PCI_MAGIC
1023 };
1024 
1025 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
1026   {PC_OPCODE, NULL, NULL, 0, NULL,
1027    //   genericAnalyze,
1028    genericDestruct,
1029    genericPrint},
1030   POC_CPFSEQ,
1031   "CPFSEQ",
1032   2,
1033   NULL, // from branch
1034   NULL, // to branch
1035   NULL, // label
1036   NULL, // operand
1037   NULL, // flow block
1038   NULL, // C source
1039   2,    // num ops
1040   FALSE,  // dest
1041   FALSE,  // bit instruction
1042   TRUE,  // branch
1043   TRUE,  // skip
1044   FALSE,    // literal operand
1045   TRUE,    // RAM access bit
1046   FALSE,    // fast call/return mode select bit
1047   FALSE,    // second memory operand
1048   FALSE,    // second literal operand
1049   POC_NOP,
1050   (PCC_W | PCC_REGISTER), // inCond
1051   PCC_NONE , // outCond
1052   PCI_MAGIC
1053 };
1054 
1055 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1056   {PC_OPCODE, NULL, NULL, 0, NULL,
1057    //   genericAnalyze,
1058    genericDestruct,
1059    genericPrint},
1060   POC_CPFSGT,
1061   "CPFSGT",
1062   2,
1063   NULL, // from branch
1064   NULL, // to branch
1065   NULL, // label
1066   NULL, // operand
1067   NULL, // flow block
1068   NULL, // C source
1069   2,    // num ops
1070   FALSE,  // dest
1071   FALSE,  // bit instruction
1072   TRUE,  // branch
1073   TRUE,  // skip
1074   FALSE,    // literal operand
1075   TRUE,    // RAM access bit
1076   FALSE,    // fast call/return mode select bit
1077   FALSE,    // second memory operand
1078   FALSE,    // second literal operand
1079   POC_NOP,
1080   (PCC_W | PCC_REGISTER), // inCond
1081   PCC_NONE , // outCond
1082   PCI_MAGIC
1083 };
1084 
1085 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1086   {PC_OPCODE, NULL, NULL, 0, NULL,
1087    //   genericAnalyze,
1088    genericDestruct,
1089    genericPrint},
1090   POC_CPFSLT,
1091   "CPFSLT",
1092   2,
1093   NULL, // from branch
1094   NULL, // to branch
1095   NULL, // label
1096   NULL, // operand
1097   NULL, // flow block
1098   NULL, // C source
1099   2,    // num ops
1100   TRUE,  // dest
1101   FALSE,  // bit instruction
1102   TRUE,  // branch
1103   TRUE,  // skip
1104   FALSE,    // literal operand
1105   TRUE,    // RAM access bit
1106   FALSE,    // fast call/return mode select bit
1107   FALSE,    // second memory operand
1108   FALSE,    // second literal operand
1109   POC_NOP,
1110   (PCC_W | PCC_REGISTER), // inCond
1111   PCC_NONE , // outCond
1112   PCI_MAGIC
1113 };
1114 
1115 pCodeInstruction pic16_pciDAW = {
1116   {PC_OPCODE, NULL, NULL, 0, NULL,
1117    //   genericAnalyze,
1118    genericDestruct,
1119    genericPrint},
1120   POC_DAW,
1121   "DAW",
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   FALSE,    // num ops
1130   FALSE,  // dest
1131   FALSE,  // bit instruction
1132   FALSE,  // branch
1133   FALSE,  // skip
1134   FALSE,    // literal operand
1135   FALSE,    // RAM access bit
1136   FALSE,    // fast call/return mode select bit
1137   FALSE,    // second memory operand
1138   FALSE,    // second literal operand
1139   POC_NOP,
1140   PCC_W, // inCond
1141   (PCC_W | PCC_C), // outCond
1142   PCI_MAGIC
1143 };
1144 
1145 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1146   {PC_OPCODE, NULL, NULL, 0, NULL,
1147    //   genericAnalyze,
1148    genericDestruct,
1149    genericPrint},
1150   POC_DCFSNZ,
1151   "DCFSNZ",
1152   2,
1153   NULL, // from branch
1154   NULL, // to branch
1155   NULL, // label
1156   NULL, // operand
1157   NULL, // flow block
1158   NULL, // C source
1159   3,    // num ops
1160   TRUE,  // dest
1161   FALSE,  // bit instruction
1162   TRUE,  // branch
1163   TRUE,  // skip
1164   FALSE,    // literal operand
1165   TRUE,    // RAM access bit
1166   FALSE,    // fast call/return mode select bit
1167   FALSE,    // second memory operand
1168   FALSE,    // second literal operand
1169   POC_NOP,
1170   PCC_REGISTER, // inCond
1171   PCC_REGISTER , // outCond
1172   PCI_MAGIC
1173 };
1174 
1175 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1176   {PC_OPCODE, NULL, NULL, 0, NULL,
1177    //   genericAnalyze,
1178    genericDestruct,
1179    genericPrint},
1180   POC_DCFSNZW,
1181   "DCFSNZ",
1182   2,
1183   NULL, // from branch
1184   NULL, // to branch
1185   NULL, // label
1186   NULL, // operand
1187   NULL, // flow block
1188   NULL, // C source
1189   3,    // num ops
1190   FALSE,  // dest
1191   FALSE,  // bit instruction
1192   TRUE,  // branch
1193   TRUE,  // skip
1194   FALSE,    // literal operand
1195   TRUE,    // RAM access bit
1196   FALSE,    // fast call/return mode select bit
1197   FALSE,    // second memory operand
1198   FALSE,    // second literal operand
1199   POC_NOP,
1200   PCC_REGISTER, // inCond
1201   PCC_W , // outCond
1202   PCI_MAGIC
1203 };
1204 
1205 pCodeInstruction pic16_pciDECF = {
1206   {PC_OPCODE, NULL, NULL, 0, NULL,
1207    //   genericAnalyze,
1208    genericDestruct,
1209    genericPrint},
1210   POC_DECF,
1211   "DECF",
1212   2,
1213   NULL, // from branch
1214   NULL, // to branch
1215   NULL, // label
1216   NULL, // operand
1217   NULL, // flow block
1218   NULL, // C source
1219   3,    // num ops
1220   TRUE,  // dest
1221   FALSE,  // bit instruction
1222   FALSE,  // branch
1223   FALSE,  // skip
1224   FALSE,    // literal operand
1225   TRUE,    // RAM access bit
1226   FALSE,    // fast call/return mode select bit
1227   FALSE,    // second memory operand
1228   FALSE,    // second literal operand
1229   POC_NOP,
1230   PCC_REGISTER,   // inCond
1231   (PCC_REGISTER | PCC_STATUS)  , // outCond
1232   PCI_MAGIC
1233 };
1234 
1235 pCodeInstruction pic16_pciDECFW = {
1236   {PC_OPCODE, NULL, NULL, 0, NULL,
1237    //   genericAnalyze,
1238    genericDestruct,
1239    genericPrint},
1240   POC_DECFW,
1241   "DECF",
1242   2,
1243   NULL, // from branch
1244   NULL, // to branch
1245   NULL, // label
1246   NULL, // operand
1247   NULL, // flow block
1248   NULL, // C source
1249   3,    // num ops
1250   FALSE,  // dest
1251   FALSE,  // bit instruction
1252   FALSE,  // branch
1253   FALSE,  // skip
1254   FALSE,    // literal operand
1255   TRUE,    // RAM access bit
1256   FALSE,    // fast call/return mode select bit
1257   FALSE,    // second memory operand
1258   FALSE,    // second literal operand
1259   POC_NOP,
1260   PCC_REGISTER,   // inCond
1261   (PCC_W | PCC_STATUS)  , // outCond
1262   PCI_MAGIC
1263 };
1264 
1265 pCodeInstruction pic16_pciDECFSZ = {
1266   {PC_OPCODE, NULL, NULL, 0, NULL,
1267    //   AnalyzeSKIP,
1268    genericDestruct,
1269    genericPrint},
1270   POC_DECFSZ,
1271   "DECFSZ",
1272   2,
1273   NULL, // from branch
1274   NULL, // to branch
1275   NULL, // label
1276   NULL, // operand
1277   NULL, // flow block
1278   NULL, // C source
1279   3,    // num ops
1280   TRUE,  // dest
1281   FALSE,  // bit instruction
1282   TRUE,  // branch
1283   TRUE,  // skip
1284   FALSE,    // literal operand
1285   TRUE,    // RAM access bit
1286   FALSE,    // fast call/return mode select bit
1287   FALSE,    // second memory operand
1288   FALSE,    // second literal operand
1289   POC_NOP,
1290   PCC_REGISTER,   // inCond
1291   PCC_REGISTER   , // outCond
1292   PCI_MAGIC
1293 };
1294 
1295 pCodeInstruction pic16_pciDECFSZW = {
1296   {PC_OPCODE, NULL, NULL, 0, NULL,
1297    //   AnalyzeSKIP,
1298    genericDestruct,
1299    genericPrint},
1300   POC_DECFSZW,
1301   "DECFSZ",
1302   2,
1303   NULL, // from branch
1304   NULL, // to branch
1305   NULL, // label
1306   NULL, // operand
1307   NULL, // flow block
1308   NULL, // C source
1309   3,    // num ops
1310   FALSE,  // dest
1311   FALSE,  // bit instruction
1312   TRUE,  // branch
1313   TRUE,  // skip
1314   FALSE,    // literal operand
1315   TRUE,    // RAM access bit
1316   FALSE,    // fast call/return mode select bit
1317   FALSE,    // second memory operand
1318   FALSE,    // second literal operand
1319   POC_NOP,
1320   PCC_REGISTER,   // inCond
1321   PCC_W          , // outCond
1322   PCI_MAGIC
1323 };
1324 
1325 pCodeInstruction pic16_pciGOTO = {
1326   {PC_OPCODE, NULL, NULL, 0, NULL,
1327    //   AnalyzeGOTO,
1328    genericDestruct,
1329    genericPrint},
1330   POC_GOTO,
1331   "GOTO",
1332   4,
1333   NULL, // from branch
1334   NULL, // to branch
1335   NULL, // label
1336   NULL, // operand
1337   NULL, // flow block
1338   NULL, // C source
1339   1,    // num ops
1340   FALSE,  // dest
1341   FALSE,  // bit instruction
1342   TRUE,  // branch
1343   FALSE,  // skip
1344   FALSE,    // literal operand
1345   FALSE,    // RAM access bit
1346   FALSE,    // fast call/return mode select bit
1347   FALSE,    // second memory operand
1348   FALSE,    // second literal operand
1349   POC_NOP,
1350   PCC_REL_ADDR,   // inCond
1351   PCC_NONE   , // outCond
1352   PCI_MAGIC
1353 };
1354 
1355 pCodeInstruction pic16_pciINCF = {
1356   {PC_OPCODE, NULL, NULL, 0, NULL,
1357    //   genericAnalyze,
1358    genericDestruct,
1359    genericPrint},
1360   POC_INCF,
1361   "INCF",
1362   2,
1363   NULL, // from branch
1364   NULL, // to branch
1365   NULL, // label
1366   NULL, // operand
1367   NULL, // flow block
1368   NULL, // C source
1369   3,    // num ops
1370   TRUE,  // dest
1371   FALSE,  // bit instruction
1372   FALSE,  // branch
1373   FALSE,  // skip
1374   FALSE,    // literal operand
1375   TRUE,    // RAM access bit
1376   FALSE,    // fast call/return mode select bit
1377   FALSE,    // second memory operand
1378   FALSE,    // second literal operand
1379   POC_NOP,
1380   PCC_REGISTER,   // inCond
1381   (PCC_REGISTER | PCC_STATUS), // outCond
1382   PCI_MAGIC
1383 };
1384 
1385 pCodeInstruction pic16_pciINCFW = {
1386   {PC_OPCODE, NULL, NULL, 0, NULL,
1387    //   genericAnalyze,
1388    genericDestruct,
1389    genericPrint},
1390   POC_INCFW,
1391   "INCF",
1392   2,
1393   NULL, // from branch
1394   NULL, // to branch
1395   NULL, // label
1396   NULL, // operand
1397   NULL, // flow block
1398   NULL, // C source
1399   3,    // num ops
1400   FALSE,  // dest
1401   FALSE,  // bit instruction
1402   FALSE,  // branch
1403   FALSE,  // skip
1404   FALSE,    // literal operand
1405   TRUE,    // RAM access bit
1406   FALSE,    // fast call/return mode select bit
1407   FALSE,    // second memory operand
1408   FALSE,    // second literal operand
1409   POC_NOP,
1410   PCC_REGISTER,   // inCond
1411   (PCC_W | PCC_STATUS)  , // outCond
1412   PCI_MAGIC
1413 };
1414 
1415 pCodeInstruction pic16_pciINCFSZ = {
1416   {PC_OPCODE, NULL, NULL, 0, NULL,
1417    //   AnalyzeSKIP,
1418    genericDestruct,
1419    genericPrint},
1420   POC_INCFSZ,
1421   "INCFSZ",
1422   2,
1423   NULL, // from branch
1424   NULL, // to branch
1425   NULL, // label
1426   NULL, // operand
1427   NULL, // flow block
1428   NULL, // C source
1429   3,    // num ops
1430   TRUE,  // dest
1431   FALSE,  // bit instruction
1432   TRUE,  // branch
1433   TRUE,  // skip
1434   FALSE,    // literal operand
1435   TRUE,    // RAM access bit
1436   FALSE,    // fast call/return mode select bit
1437   FALSE,    // second memory operand
1438   FALSE,    // second literal operand
1439   POC_INFSNZ,
1440   PCC_REGISTER,   // inCond
1441   PCC_REGISTER   , // outCond
1442   PCI_MAGIC
1443 };
1444 
1445 pCodeInstruction pic16_pciINCFSZW = {
1446   {PC_OPCODE, NULL, NULL, 0, NULL,
1447    //   AnalyzeSKIP,
1448    genericDestruct,
1449    genericPrint},
1450   POC_INCFSZW,
1451   "INCFSZ",
1452   2,
1453   NULL, // from branch
1454   NULL, // to branch
1455   NULL, // label
1456   NULL, // operand
1457   NULL, // flow block
1458   NULL, // C source
1459   3,    // num ops
1460   FALSE,  // dest
1461   FALSE,  // bit instruction
1462   TRUE,  // branch
1463   TRUE,  // skip
1464   FALSE,    // literal operand
1465   TRUE,    // RAM access bit
1466   FALSE,    // fast call/return mode select bit
1467   FALSE,    // second memory operand
1468   FALSE,    // second literal operand
1469   POC_INFSNZW,
1470   PCC_REGISTER,   // inCond
1471   PCC_W          , // outCond
1472   PCI_MAGIC
1473 };
1474 
1475 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1476   {PC_OPCODE, NULL, NULL, 0, NULL,
1477    //   AnalyzeSKIP,
1478    genericDestruct,
1479    genericPrint},
1480   POC_INFSNZ,
1481   "INFSNZ",
1482   2,
1483   NULL, // from branch
1484   NULL, // to branch
1485   NULL, // label
1486   NULL, // operand
1487   NULL, // flow block
1488   NULL, // C source
1489   3,    // num ops
1490   TRUE,  // dest
1491   FALSE,  // bit instruction
1492   TRUE,  // branch
1493   TRUE,  // skip
1494   FALSE,    // literal operand
1495   TRUE,    // RAM access bit
1496   FALSE,    // fast call/return mode select bit
1497   FALSE,    // second memory operand
1498   FALSE,    // second literal operand
1499   POC_INCFSZ,
1500   PCC_REGISTER,   // inCond
1501   PCC_REGISTER   , // outCond
1502   PCI_MAGIC
1503 };
1504 
1505 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1506   {PC_OPCODE, NULL, NULL, 0, NULL,
1507    //   AnalyzeSKIP,
1508    genericDestruct,
1509    genericPrint},
1510   POC_INFSNZW,
1511   "INFSNZ",
1512   2,
1513   NULL, // from branch
1514   NULL, // to branch
1515   NULL, // label
1516   NULL, // operand
1517   NULL, // flow block
1518   NULL, // C source
1519   3,    // num ops
1520   FALSE,  // dest
1521   FALSE,  // bit instruction
1522   TRUE,  // branch
1523   TRUE,  // skip
1524   FALSE,    // literal operand
1525   TRUE,    // RAM access bit
1526   FALSE,    // fast call/return mode select bit
1527   FALSE,    // second memory operand
1528   FALSE,    // second literal operand
1529   POC_INCFSZW,
1530   PCC_REGISTER,   // inCond
1531   PCC_W          , // outCond
1532   PCI_MAGIC
1533 };
1534 
1535 pCodeInstruction pic16_pciIORWF = {
1536   {PC_OPCODE, NULL, NULL, 0, NULL,
1537    //   genericAnalyze,
1538    genericDestruct,
1539    genericPrint},
1540   POC_IORWF,
1541   "IORWF",
1542   2,
1543   NULL, // from branch
1544   NULL, // to branch
1545   NULL, // label
1546   NULL, // operand
1547   NULL, // flow block
1548   NULL, // C source
1549   3,    // num ops
1550   TRUE,  // dest
1551   FALSE,  // bit instruction
1552   FALSE,  // branch
1553   FALSE,  // skip
1554   FALSE,    // literal operand
1555   TRUE,    // RAM access bit
1556   FALSE,    // fast call/return mode select bit
1557   FALSE,    // second memory operand
1558   FALSE,    // second literal operand
1559   POC_NOP,
1560   (PCC_W | PCC_REGISTER),   // inCond
1561   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1562   PCI_MAGIC
1563 };
1564 
1565 pCodeInstruction pic16_pciIORFW = {
1566   {PC_OPCODE, NULL, NULL, 0, NULL,
1567    //   genericAnalyze,
1568    genericDestruct,
1569    genericPrint},
1570   POC_IORFW,
1571   "IORWF",
1572   2,
1573   NULL, // from branch
1574   NULL, // to branch
1575   NULL, // label
1576   NULL, // operand
1577   NULL, // flow block
1578   NULL, // C source
1579   3,    // num ops
1580   FALSE,  // dest
1581   FALSE,  // bit instruction
1582   FALSE,  // branch
1583   FALSE,  // skip
1584   FALSE,    // literal operand
1585   TRUE,    // RAM access bit
1586   FALSE,    // fast call/return mode select bit
1587   FALSE,    // second memory operand
1588   FALSE,    // second literal operand
1589   POC_NOP,
1590   (PCC_W | PCC_REGISTER),   // inCond
1591   (PCC_W | PCC_Z | PCC_N), // outCond
1592   PCI_MAGIC
1593 };
1594 
1595 pCodeInstruction pic16_pciIORLW = {
1596   {PC_OPCODE, NULL, NULL, 0, NULL,
1597    //   genericAnalyze,
1598    genericDestruct,
1599    genericPrint},
1600   POC_IORLW,
1601   "IORLW",
1602   2,
1603   NULL, // from branch
1604   NULL, // to branch
1605   NULL, // label
1606   NULL, // operand
1607   NULL, // flow block
1608   NULL, // C source
1609   1,    // num ops
1610   FALSE,  // dest
1611   FALSE,  // bit instruction
1612   FALSE,  // branch
1613   FALSE,  // skip
1614   TRUE,    // literal operand
1615   FALSE,    // RAM access bit
1616   FALSE,    // fast call/return mode select bit
1617   FALSE,    // second memory operand
1618   FALSE,    // second literal operand
1619   POC_NOP,
1620   (PCC_W | PCC_LITERAL),   // inCond
1621   (PCC_W | PCC_Z | PCC_N), // outCond
1622   PCI_MAGIC
1623 };
1624 
1625 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1626   {PC_OPCODE, NULL, NULL, 0, NULL,
1627    //   genericAnalyze,
1628    genericDestruct,
1629    genericPrint},
1630   POC_LFSR,
1631   "LFSR",
1632   4,
1633   NULL, // from branch
1634   NULL, // to branch
1635   NULL, // label
1636   NULL, // operand
1637   NULL, // flow block
1638   NULL, // C source
1639   2,    // num ops
1640   FALSE,  // dest
1641   FALSE,  // bit instruction
1642   FALSE,  // branch
1643   FALSE,  // skip
1644   TRUE,    // literal operand
1645   FALSE,    // RAM access bit
1646   FALSE,    // fast call/return mode select bit
1647   FALSE,    // second memory operand
1648   TRUE,    // second literal operand
1649   POC_NOP,
1650   PCC_LITERAL, // inCond
1651   PCC_NONE, // outCond
1652   PCI_MAGIC
1653 };
1654 
1655 pCodeInstruction pic16_pciMOVF = {
1656   {PC_OPCODE, NULL, NULL, 0, NULL,
1657    //   genericAnalyze,
1658    genericDestruct,
1659    genericPrint},
1660   POC_MOVF,
1661   "MOVF",
1662   2,
1663   NULL, // from branch
1664   NULL, // to branch
1665   NULL, // label
1666   NULL, // operand
1667   NULL, // flow block
1668   NULL, // C source
1669   3,    // num ops
1670   TRUE,  // dest
1671   FALSE,  // bit instruction
1672   FALSE,  // branch
1673   FALSE,  // skip
1674   FALSE,    // literal operand
1675   TRUE,    // RAM access bit
1676   FALSE,    // fast call/return mode select bit
1677   FALSE,    // second memory operand
1678   FALSE,    // second literal operand
1679   POC_NOP,
1680   PCC_REGISTER,   // inCond
1681   (PCC_Z | PCC_N), // outCond
1682   PCI_MAGIC
1683 };
1684 
1685 pCodeInstruction pic16_pciMOVFW = {
1686   {PC_OPCODE, NULL, NULL, 0, NULL,
1687    //   genericAnalyze,
1688    genericDestruct,
1689    genericPrint},
1690   POC_MOVFW,
1691   "MOVF",
1692   2,
1693   NULL, // from branch
1694   NULL, // to branch
1695   NULL, // label
1696   NULL, // operand
1697   NULL, // flow block
1698   NULL, // C source
1699   3,    // num ops
1700   FALSE,  // dest
1701   FALSE,  // bit instruction
1702   FALSE,  // branch
1703   FALSE,  // skip
1704   FALSE,    // literal operand
1705   TRUE,    // RAM access bit
1706   FALSE,    // fast call/return mode select bit
1707   FALSE,    // second memory operand
1708   FALSE,    // second literal operand
1709   POC_NOP,
1710   PCC_REGISTER,   // inCond
1711   (PCC_W | PCC_N | PCC_Z), // outCond
1712   PCI_MAGIC
1713 };
1714 
1715 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1716   {PC_OPCODE, NULL, NULL, 0, NULL,
1717    //   genericAnalyze,
1718    genericDestruct,
1719    genericPrint},
1720   POC_MOVFF,
1721   "MOVFF",
1722   4,
1723   NULL, // from branch
1724   NULL, // to branch
1725   NULL, // label
1726   NULL, // operand
1727   NULL, // flow block
1728   NULL, // C source
1729   2,    // num ops
1730   FALSE,  // dest
1731   FALSE,  // bit instruction
1732   FALSE,  // branch
1733   FALSE,  // skip
1734   FALSE,    // literal operand
1735   FALSE,    // RAM access bit
1736   FALSE,    // fast call/return mode select bit
1737   TRUE,    // second memory operand
1738   FALSE,    // second literal operand
1739   POC_NOP,
1740   PCC_REGISTER,   // inCond
1741   PCC_REGISTER2, // outCond
1742   PCI_MAGIC
1743 };
1744 
1745 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1746   {PC_OPCODE, NULL, NULL, 0, NULL,
1747    genericDestruct,
1748    genericPrint},
1749   POC_MOVLB,
1750   "MOVLB",
1751   2,
1752   NULL, // from branch
1753   NULL, // to branch
1754   NULL, // label
1755   NULL, // operand
1756   NULL, // flow block
1757   NULL, // C source
1758   1,    // num ops
1759   FALSE,  // dest
1760   FALSE,  // bit instruction
1761   FALSE,  // branch
1762   FALSE,  // skip
1763   TRUE,    // literal operand
1764   FALSE,    // RAM access bit
1765   FALSE,    // fast call/return mode select bit
1766   FALSE,    // second memory operand
1767   FALSE,    // second literal operand
1768   POC_NOP,
1769   (PCC_NONE | PCC_LITERAL),   // inCond
1770   PCC_REGISTER, // outCond - BSR
1771   PCI_MAGIC
1772 };
1773 
1774 pCodeInstruction pic16_pciMOVLW = {
1775   {PC_OPCODE, NULL, NULL, 0, NULL,
1776    genericDestruct,
1777    genericPrint},
1778   POC_MOVLW,
1779   "MOVLW",
1780   2,
1781   NULL, // from branch
1782   NULL, // to branch
1783   NULL, // label
1784   NULL, // operand
1785   NULL, // flow block
1786   NULL, // C source
1787   1,    // num ops
1788   FALSE,  // dest
1789   FALSE,  // bit instruction
1790   FALSE,  // branch
1791   FALSE,  // skip
1792   TRUE,    // literal operand
1793   FALSE,    // RAM access bit
1794   FALSE,    // fast call/return mode select bit
1795   FALSE,    // second memory operand
1796   FALSE,    // second literal operand
1797   POC_NOP,
1798   (PCC_NONE | PCC_LITERAL),   // inCond
1799   PCC_W, // outCond
1800   PCI_MAGIC
1801 };
1802 
1803 pCodeInstruction pic16_pciMOVWF = {
1804   {PC_OPCODE, NULL, NULL, 0, NULL,
1805    //   genericAnalyze,
1806    genericDestruct,
1807    genericPrint},
1808   POC_MOVWF,
1809   "MOVWF",
1810   2,
1811   NULL, // from branch
1812   NULL, // to branch
1813   NULL, // label
1814   NULL, // operand
1815   NULL, // flow block
1816   NULL, // C source
1817   2,    // num ops
1818   FALSE,  // dest
1819   FALSE,  // bit instruction
1820   FALSE,  // branch
1821   FALSE,  // skip
1822   FALSE,    // literal operand
1823   TRUE,    // RAM access bit
1824   FALSE,    // fast call/return mode select bit
1825   FALSE,    // second memory operand
1826   FALSE,    // second literal operand
1827   POC_NOP,
1828   PCC_W,   // inCond
1829   PCC_REGISTER, // outCond
1830   PCI_MAGIC
1831 };
1832 
1833 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1834   {PC_OPCODE, NULL, NULL, 0, NULL,
1835    genericDestruct,
1836    genericPrint},
1837   POC_MULLW,
1838   "MULLW",
1839   2,
1840   NULL, // from branch
1841   NULL, // to branch
1842   NULL, // label
1843   NULL, // operand
1844   NULL, // flow block
1845   NULL, // C source
1846   1,    // num ops
1847   FALSE,  // dest
1848   FALSE,  // bit instruction
1849   FALSE,  // branch
1850   FALSE,  // skip
1851   TRUE,    // literal operand
1852   FALSE,    // RAM access bit
1853   FALSE,    // fast call/return mode select bit
1854   FALSE,    // second memory operand
1855   FALSE,    // second literal operand
1856   POC_NOP,
1857   (PCC_W | PCC_LITERAL),   // inCond
1858   PCC_NONE, // outCond - PROD
1859   PCI_MAGIC
1860 };
1861 
1862 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1863   {PC_OPCODE, NULL, NULL, 0, NULL,
1864    genericDestruct,
1865    genericPrint},
1866   POC_MULWF,
1867   "MULWF",
1868   2,
1869   NULL, // from branch
1870   NULL, // to branch
1871   NULL, // label
1872   NULL, // operand
1873   NULL, // flow block
1874   NULL, // C source
1875   2,    // num ops
1876   FALSE,  // dest
1877   FALSE,  // bit instruction
1878   FALSE,  // branch
1879   FALSE,  // skip
1880   FALSE,    // literal operand
1881   TRUE,    // RAM access bit
1882   FALSE,    // fast call/return mode select bit
1883   FALSE,    // second memory operand
1884   FALSE,    // second literal operand
1885   POC_NOP,
1886   (PCC_W | PCC_REGISTER),   // inCond
1887   PCC_REGISTER, // outCond - PROD
1888   PCI_MAGIC
1889 };
1890 
1891 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1892   {PC_OPCODE, NULL, NULL, 0, NULL,
1893    genericDestruct,
1894    genericPrint},
1895   POC_NEGF,
1896   "NEGF",
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   2,    // num ops
1905   FALSE,  // dest
1906   FALSE,  // bit instruction
1907   FALSE,  // branch
1908   FALSE,  // skip
1909   FALSE,    // literal operand
1910   TRUE,    // RAM access bit
1911   FALSE,    // fast call/return mode select bit
1912   FALSE,    // second memory operand
1913   FALSE,    // second literal operand
1914   POC_NOP,
1915   PCC_REGISTER, // inCond
1916   (PCC_REGISTER | PCC_STATUS), // outCond
1917   PCI_MAGIC
1918 };
1919 
1920 pCodeInstruction pic16_pciNOP = {
1921   {PC_OPCODE, NULL, NULL, 0, NULL,
1922    genericDestruct,
1923    genericPrint},
1924   POC_NOP,
1925   "NOP",
1926   2,
1927   NULL, // from branch
1928   NULL, // to branch
1929   NULL, // label
1930   NULL, // operand
1931   NULL, // flow block
1932   NULL, // C source
1933   0,    // num ops
1934   FALSE,  // dest
1935   FALSE,  // bit instruction
1936   FALSE,  // branch
1937   FALSE,  // skip
1938   FALSE,    // literal operand
1939   FALSE,    // RAM access bit
1940   FALSE,    // fast call/return mode select bit
1941   FALSE,    // second memory operand
1942   FALSE,    // second literal operand
1943   POC_NOP,
1944   PCC_NONE,   // inCond
1945   PCC_NONE, // outCond
1946   PCI_MAGIC
1947 };
1948 
1949 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1950   {PC_OPCODE, NULL, NULL, 0, NULL,
1951    genericDestruct,
1952    genericPrint},
1953   POC_POP,
1954   "POP",
1955   2,
1956   NULL, // from branch
1957   NULL, // to branch
1958   NULL, // label
1959   NULL, // operand
1960   NULL, // flow block
1961   NULL, // C source
1962   0,    // num ops
1963   FALSE,  // dest
1964   FALSE,  // bit instruction
1965   FALSE,  // branch
1966   FALSE,  // skip
1967   FALSE,    // literal operand
1968   FALSE,    // RAM access bit
1969   FALSE,    // fast call/return mode select bit
1970   FALSE,    // second memory operand
1971   FALSE,    // second literal operand
1972   POC_NOP,
1973   PCC_NONE,  // inCond
1974   PCC_NONE  , // outCond
1975   PCI_MAGIC
1976 };
1977 
1978 pCodeInstruction pic16_pciPUSH = {
1979   {PC_OPCODE, NULL, NULL, 0, NULL,
1980    genericDestruct,
1981    genericPrint},
1982   POC_PUSH,
1983   "PUSH",
1984   2,
1985   NULL, // from branch
1986   NULL, // to branch
1987   NULL, // label
1988   NULL, // operand
1989   NULL, // flow block
1990   NULL, // C source
1991   0,    // num ops
1992   FALSE,  // dest
1993   FALSE,  // bit instruction
1994   FALSE,  // branch
1995   FALSE,  // skip
1996   FALSE,    // literal operand
1997   FALSE,    // RAM access bit
1998   FALSE,    // fast call/return mode select bit
1999   FALSE,    // second memory operand
2000   FALSE,    // second literal operand
2001   POC_NOP,
2002   PCC_NONE,  // inCond
2003   PCC_NONE  , // outCond
2004   PCI_MAGIC
2005 };
2006 
2007 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
2008   {PC_OPCODE, NULL, NULL, 0, NULL,
2009    genericDestruct,
2010    genericPrint},
2011   POC_RCALL,
2012   "RCALL",
2013   2,
2014   NULL, // from branch
2015   NULL, // to branch
2016   NULL, // label
2017   NULL, // operand
2018   NULL, // flow block
2019   NULL, // C source
2020   1,    // num ops
2021   FALSE,  // dest
2022   FALSE,  // bit instruction
2023   TRUE,  // branch
2024   FALSE,  // skip
2025   FALSE,    // literal operand
2026   FALSE,    // RAM access bit
2027   FALSE,    // fast call/return mode select bit
2028   FALSE,    // second memory operand
2029   FALSE,    // second literal operand
2030   POC_NOP,
2031   PCC_REL_ADDR,  // inCond
2032   PCC_NONE  , // outCond
2033   PCI_MAGIC
2034 };
2035 
2036 pCodeInstruction pic16_pciRETFIE = {
2037   {PC_OPCODE, NULL, NULL, 0, NULL,
2038    //   AnalyzeRETURN,
2039    genericDestruct,
2040    genericPrint},
2041   POC_RETFIE,
2042   "RETFIE",
2043   2,
2044   NULL, // from branch
2045   NULL, // to branch
2046   NULL, // label
2047   NULL, // operand
2048   NULL, // flow block
2049   NULL, // C source
2050   1,    // num ops
2051   FALSE,  // dest
2052   FALSE,  // bit instruction
2053   TRUE,  // branch
2054   FALSE,  // skip
2055   FALSE,    // literal operand
2056   FALSE,    // RAM access bit
2057   TRUE,    // fast call/return mode select bit
2058   FALSE,    // second memory operand
2059   FALSE,    // second literal operand
2060   POC_NOP,
2061   PCC_NONE,   // inCond
2062   PCC_NONE,    // outCond (not true... affects the GIE bit too)
2063   PCI_MAGIC
2064 };
2065 
2066 pCodeInstruction pic16_pciRETLW = {
2067   {PC_OPCODE, NULL, NULL, 0, NULL,
2068    //   AnalyzeRETURN,
2069    genericDestruct,
2070    genericPrint},
2071   POC_RETLW,
2072   "RETLW",
2073   2,
2074   NULL, // from branch
2075   NULL, // to branch
2076   NULL, // label
2077   NULL, // operand
2078   NULL, // flow block
2079   NULL, // C source
2080   1,    // num ops
2081   FALSE,  // dest
2082   FALSE,  // bit instruction
2083   TRUE,  // branch
2084   FALSE,  // skip
2085   TRUE,    // literal operand
2086   FALSE,    // RAM access bit
2087   FALSE,    // fast call/return mode select bit
2088   FALSE,    // second memory operand
2089   FALSE,    // second literal operand
2090   POC_NOP,
2091   PCC_LITERAL,   // inCond
2092   PCC_W, // outCond
2093   PCI_MAGIC
2094 };
2095 
2096 pCodeInstruction pic16_pciRETURN = {
2097   {PC_OPCODE, NULL, NULL, 0, NULL,
2098    //   AnalyzeRETURN,
2099    genericDestruct,
2100    genericPrint},
2101   POC_RETURN,
2102   "RETURN",
2103   2,
2104   NULL, // from branch
2105   NULL, // to branch
2106   NULL, // label
2107   NULL, // operand
2108   NULL, // flow block
2109   NULL, // C source
2110   1,    // num ops
2111   FALSE,  // dest
2112   FALSE,  // bit instruction
2113   TRUE,  // branch
2114   FALSE,  // skip
2115   FALSE,    // literal operand
2116   FALSE,    // RAM access bit
2117   TRUE,    // fast call/return mode select bit
2118   FALSE,    // second memory operand
2119   FALSE,    // second literal operand
2120   POC_NOP,
2121   PCC_NONE,   // inCond
2122   PCC_NONE, // outCond
2123   PCI_MAGIC
2124 };
2125 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2126   {PC_OPCODE, NULL, NULL, 0, NULL,
2127    //   genericAnalyze,
2128    genericDestruct,
2129    genericPrint},
2130   POC_RLCF,
2131   "RLCF",
2132   2,
2133   NULL, // from branch
2134   NULL, // to branch
2135   NULL, // label
2136   NULL, // operand
2137   NULL, // flow block
2138   NULL, // C source
2139   3,    // num ops
2140   TRUE,  // dest
2141   FALSE,  // bit instruction
2142   FALSE,  // branch
2143   FALSE,  // skip
2144   FALSE,    // literal operand
2145   TRUE,    // RAM access bit
2146   FALSE,    // fast call/return mode select bit
2147   FALSE,    // second memory operand
2148   FALSE,    // second literal operand
2149   POC_NOP,
2150   (PCC_C | PCC_REGISTER),   // inCond
2151   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2152   PCI_MAGIC
2153 };
2154 
2155 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2156   {PC_OPCODE, NULL, NULL, 0, NULL,
2157    //   genericAnalyze,
2158    genericDestruct,
2159    genericPrint},
2160   POC_RLCFW,
2161   "RLCF",
2162   2,
2163   NULL, // from branch
2164   NULL, // to branch
2165   NULL, // label
2166   NULL, // operand
2167   NULL, // flow block
2168   NULL, // C source
2169   3,    // num ops
2170   FALSE,  // dest
2171   FALSE,  // bit instruction
2172   FALSE,  // branch
2173   FALSE,  // skip
2174   FALSE,    // literal operand
2175   TRUE,    // RAM access bit
2176   FALSE,    // fast call/return mode select bit
2177   FALSE,    // second memory operand
2178   FALSE,    // second literal operand
2179   POC_NOP,
2180   (PCC_C | PCC_REGISTER),   // inCond
2181   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2182   PCI_MAGIC
2183 };
2184 
2185 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2186   {PC_OPCODE, NULL, NULL, 0, NULL,
2187    //   genericAnalyze,
2188    genericDestruct,
2189    genericPrint},
2190   POC_RLNCF,
2191   "RLNCF",
2192   2,
2193   NULL, // from branch
2194   NULL, // to branch
2195   NULL, // label
2196   NULL, // operand
2197   NULL, // flow block
2198   NULL, // C source
2199   3,    // num ops
2200   TRUE,  // dest
2201   FALSE,  // bit instruction
2202   FALSE,  // branch
2203   FALSE,  // skip
2204   FALSE,    // literal operand
2205   TRUE,    // RAM access bit
2206   FALSE,    // fast call/return mode select bit
2207   FALSE,    // second memory operand
2208   FALSE,    // second literal operand
2209   POC_NOP,
2210   PCC_REGISTER,   // inCond
2211   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2212   PCI_MAGIC
2213 };
2214 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2215   {PC_OPCODE, NULL, NULL, 0, NULL,
2216    //   genericAnalyze,
2217    genericDestruct,
2218    genericPrint},
2219   POC_RLNCFW,
2220   "RLNCF",
2221   2,
2222   NULL, // from branch
2223   NULL, // to branch
2224   NULL, // label
2225   NULL, // operand
2226   NULL, // flow block
2227   NULL, // C source
2228   3,    // num ops
2229   FALSE,  // dest
2230   FALSE,  // bit instruction
2231   FALSE,  // branch
2232   FALSE,  // skip
2233   FALSE,    // literal operand
2234   TRUE,    // RAM access bit
2235   FALSE,    // fast call/return mode select bit
2236   FALSE,    // second memory operand
2237   FALSE,    // second literal operand
2238   POC_NOP,
2239   PCC_REGISTER,   // inCond
2240   (PCC_W | PCC_Z | PCC_N), // outCond
2241   PCI_MAGIC
2242 };
2243 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2244   {PC_OPCODE, NULL, NULL, 0, NULL,
2245    //   genericAnalyze,
2246    genericDestruct,
2247    genericPrint},
2248   POC_RRCF,
2249   "RRCF",
2250   2,
2251   NULL, // from branch
2252   NULL, // to branch
2253   NULL, // label
2254   NULL, // operand
2255   NULL, // flow block
2256   NULL, // C source
2257   3,    // num ops
2258   TRUE,  // dest
2259   FALSE,  // bit instruction
2260   FALSE,  // branch
2261   FALSE,  // skip
2262   FALSE,    // literal operand
2263   TRUE,    // RAM access bit
2264   FALSE,    // fast call/return mode select bit
2265   FALSE,    // second memory operand
2266   FALSE,    // second literal operand
2267   POC_NOP,
2268   (PCC_C | PCC_REGISTER),   // inCond
2269   (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2270   PCI_MAGIC
2271 };
2272 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2273   {PC_OPCODE, NULL, NULL, 0, NULL,
2274    //   genericAnalyze,
2275    genericDestruct,
2276    genericPrint},
2277   POC_RRCFW,
2278   "RRCF",
2279   2,
2280   NULL, // from branch
2281   NULL, // to branch
2282   NULL, // label
2283   NULL, // operand
2284   NULL, // flow block
2285   NULL, // C source
2286   3,    // num ops
2287   FALSE,  // dest
2288   FALSE,  // bit instruction
2289   FALSE,  // branch
2290   FALSE,  // skip
2291   FALSE,    // literal operand
2292   TRUE,    // RAM access bit
2293   FALSE,    // fast call/return mode select bit
2294   FALSE,    // second memory operand
2295   FALSE,    // second literal operand
2296   POC_NOP,
2297   (PCC_C | PCC_REGISTER),   // inCond
2298   (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2299   PCI_MAGIC
2300 };
2301 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2302   {PC_OPCODE, NULL, NULL, 0, NULL,
2303    //   genericAnalyze,
2304    genericDestruct,
2305    genericPrint},
2306   POC_RRNCF,
2307   "RRNCF",
2308   2,
2309   NULL, // from branch
2310   NULL, // to branch
2311   NULL, // label
2312   NULL, // operand
2313   NULL, // flow block
2314   NULL, // C source
2315   3,    // num ops
2316   TRUE,  // dest
2317   FALSE,  // bit instruction
2318   FALSE,  // branch
2319   FALSE,  // skip
2320   FALSE,    // literal operand
2321   TRUE,    // RAM access bit
2322   FALSE,    // fast call/return mode select bit
2323   FALSE,    // second memory operand
2324   FALSE,    // second literal operand
2325   POC_NOP,
2326   PCC_REGISTER,   // inCond
2327   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2328   PCI_MAGIC
2329 };
2330 
2331 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2332   {PC_OPCODE, NULL, NULL, 0, NULL,
2333    //   genericAnalyze,
2334    genericDestruct,
2335    genericPrint},
2336   POC_RRNCFW,
2337   "RRNCF",
2338   2,
2339   NULL, // from branch
2340   NULL, // to branch
2341   NULL, // label
2342   NULL, // operand
2343   NULL, // flow block
2344   NULL, // C source
2345   3,    // num ops
2346   FALSE,  // dest
2347   FALSE,  // bit instruction
2348   FALSE,  // branch
2349   FALSE,  // skip
2350   FALSE,    // literal operand
2351   TRUE,    // RAM access bit
2352   FALSE,    // fast call/return mode select bit
2353   FALSE,    // second memory operand
2354   FALSE,    // second literal operand
2355   POC_NOP,
2356   PCC_REGISTER,   // inCond
2357   (PCC_W | PCC_Z | PCC_N), // outCond
2358   PCI_MAGIC
2359 };
2360 
2361 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2362   {PC_OPCODE, NULL, NULL, 0, NULL,
2363    //   genericAnalyze,
2364    genericDestruct,
2365    genericPrint},
2366   POC_SETF,
2367   "SETF",
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   2,    // num ops
2376   FALSE,  // dest
2377   FALSE,  // bit instruction
2378   FALSE,  // branch
2379   FALSE,  // skip
2380   FALSE,    // literal operand
2381   TRUE,    // RAM access bit
2382   FALSE,    // fast call/return mode select bit
2383   FALSE,    // second memory operand
2384   FALSE,    // second literal operand
2385   POC_NOP,
2386   PCC_NONE,  // inCond
2387   PCC_REGISTER  , // outCond
2388   PCI_MAGIC
2389 };
2390 
2391 pCodeInstruction pic16_pciSUBLW = {
2392   {PC_OPCODE, NULL, NULL, 0, NULL,
2393    //   genericAnalyze,
2394    genericDestruct,
2395    genericPrint},
2396   POC_SUBLW,
2397   "SUBLW",
2398   2,
2399   NULL, // from branch
2400   NULL, // to branch
2401   NULL, // label
2402   NULL, // operand
2403   NULL, // flow block
2404   NULL, // C source
2405   1,    // num ops
2406   FALSE,  // dest
2407   FALSE,  // bit instruction
2408   FALSE,  // branch
2409   FALSE,  // skip
2410   TRUE,    // literal operand
2411   FALSE,    // RAM access bit
2412   FALSE,    // fast call/return mode select bit
2413   FALSE,    // second memory operand
2414   FALSE,    // second literal operand
2415   POC_NOP,
2416   (PCC_W | PCC_LITERAL),   // inCond
2417   (PCC_W | PCC_STATUS), // outCond
2418   PCI_MAGIC
2419 };
2420 
2421 pCodeInstruction pic16_pciSUBFWB = {
2422   {PC_OPCODE, NULL, NULL, 0, NULL,
2423    //   genericAnalyze,
2424    genericDestruct,
2425    genericPrint},
2426   POC_SUBFWB,
2427   "SUBFWB",
2428   2,
2429   NULL, // from branch
2430   NULL, // to branch
2431   NULL, // label
2432   NULL, // operand
2433   NULL, // flow block
2434   NULL, // C source
2435   3,    // num ops
2436   TRUE,  // dest
2437   FALSE,  // bit instruction
2438   FALSE,  // branch
2439   FALSE,  // skip
2440   FALSE,    // literal operand
2441   TRUE,    // RAM access bit
2442   FALSE,    // fast call/return mode select bit
2443   FALSE,    // second memory operand
2444   FALSE,    // second literal operand
2445   POC_NOP,
2446   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2447   (PCC_W | PCC_STATUS), // outCond
2448   PCI_MAGIC
2449 };
2450 
2451 pCodeInstruction pic16_pciSUBWF = {
2452   {PC_OPCODE, NULL, NULL, 0, NULL,
2453    //   genericAnalyze,
2454    genericDestruct,
2455    genericPrint},
2456   POC_SUBWF,
2457   "SUBWF",
2458   2,
2459   NULL, // from branch
2460   NULL, // to branch
2461   NULL, // label
2462   NULL, // operand
2463   NULL, // flow block
2464   NULL, // C source
2465   3,    // num ops
2466   TRUE,  // dest
2467   FALSE,  // bit instruction
2468   FALSE,  // branch
2469   FALSE,  // skip
2470   FALSE,    // literal operand
2471   TRUE,    // RAM access bit
2472   FALSE,    // fast call/return mode select bit
2473   FALSE,    // second memory operand
2474   FALSE,    // second literal operand
2475   POC_NOP,
2476   (PCC_W | PCC_REGISTER),   // inCond
2477   (PCC_REGISTER | PCC_STATUS), // outCond
2478   PCI_MAGIC
2479 };
2480 
2481 pCodeInstruction pic16_pciSUBFW = {
2482   {PC_OPCODE, NULL, NULL, 0, NULL,
2483    //   genericAnalyze,
2484    genericDestruct,
2485    genericPrint},
2486   POC_SUBFW,
2487   "SUBWF",
2488   2,
2489   NULL, // from branch
2490   NULL, // to branch
2491   NULL, // label
2492   NULL, // operand
2493   NULL, // flow block
2494   NULL, // C source
2495   3,    // num ops
2496   FALSE,  // dest
2497   FALSE,  // bit instruction
2498   FALSE,  // branch
2499   FALSE,  // skip
2500   FALSE,    // literal operand
2501   TRUE,    // RAM access bit
2502   FALSE,    // fast call/return mode select bit
2503   FALSE,    // second memory operand
2504   FALSE,    // second literal operand
2505   POC_NOP,
2506   (PCC_W | PCC_REGISTER),   // inCond
2507   (PCC_W | PCC_STATUS), // outCond
2508   PCI_MAGIC
2509 };
2510 
2511 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2512   {PC_OPCODE, NULL, NULL, 0, NULL,
2513    //   genericAnalyze,
2514    genericDestruct,
2515    genericPrint},
2516   POC_SUBFWB_D1,
2517   "SUBFWB",
2518   2,
2519   NULL, // from branch
2520   NULL, // to branch
2521   NULL, // label
2522   NULL, // operand
2523   NULL, // flow block
2524   NULL, // C source
2525   3,    // num ops
2526   TRUE,  // dest
2527   FALSE,  // bit instruction
2528   FALSE,  // branch
2529   FALSE,  // skip
2530   FALSE,    // literal operand
2531   TRUE,    // RAM access bit
2532   FALSE,    // fast call/return mode select bit
2533   FALSE,    // second memory operand
2534   FALSE,    // second literal operand
2535   POC_NOP,
2536   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2537   (PCC_REGISTER | PCC_STATUS), // outCond
2538   PCI_MAGIC
2539 };
2540 
2541 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2542   {PC_OPCODE, NULL, NULL, 0, NULL,
2543    //   genericAnalyze,
2544    genericDestruct,
2545    genericPrint},
2546   POC_SUBFWB_D0,
2547   "SUBFWB",
2548   2,
2549   NULL, // from branch
2550   NULL, // to branch
2551   NULL, // label
2552   NULL, // operand
2553   NULL, // flow block
2554   NULL, // C source
2555   3,    // num ops
2556   FALSE,  // dest
2557   FALSE,  // bit instruction
2558   FALSE,  // branch
2559   FALSE,  // skip
2560   FALSE,    // literal operand
2561   TRUE,    // RAM access bit
2562   FALSE,    // fast call/return mode select bit
2563   FALSE,    // second memory operand
2564   FALSE,    // second literal operand
2565   POC_NOP,
2566   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2567   (PCC_W | PCC_STATUS), // outCond
2568   PCI_MAGIC
2569 };
2570 
2571 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2572   {PC_OPCODE, NULL, NULL, 0, NULL,
2573    //   genericAnalyze,
2574    genericDestruct,
2575    genericPrint},
2576   POC_SUBWFB_D1,
2577   "SUBWFB",
2578   2,
2579   NULL, // from branch
2580   NULL, // to branch
2581   NULL, // label
2582   NULL, // operand
2583   NULL, // flow block
2584   NULL, // C source
2585   3,    // num ops
2586   TRUE,  // dest
2587   FALSE,  // bit instruction
2588   FALSE,  // branch
2589   FALSE,  // skip
2590   FALSE,    // literal operand
2591   TRUE,    // RAM access bit
2592   FALSE,    // fast call/return mode select bit
2593   FALSE,    // second memory operand
2594   FALSE,    // second literal operand
2595   POC_NOP,
2596   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2597   (PCC_REGISTER | PCC_STATUS), // outCond
2598   PCI_MAGIC
2599 };
2600 
2601 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2602   {PC_OPCODE, NULL, NULL, 0, NULL,
2603    //   genericAnalyze,
2604    genericDestruct,
2605    genericPrint},
2606   POC_SUBWFB_D0,
2607   "SUBWFB",
2608   2,
2609   NULL, // from branch
2610   NULL, // to branch
2611   NULL, // label
2612   NULL, // operand
2613   NULL, // flow block
2614   NULL, // C source
2615   3,    // num ops
2616   FALSE,  // dest
2617   FALSE,  // bit instruction
2618   FALSE,  // branch
2619   FALSE,  // skip
2620   FALSE,    // literal operand
2621   TRUE,    // RAM access bit
2622   FALSE,    // fast call/return mode select bit
2623   FALSE,    // second memory operand
2624   FALSE,    // second literal operand
2625   POC_NOP,
2626   (PCC_W | PCC_REGISTER | PCC_C),   // inCond
2627   (PCC_W | PCC_STATUS), // outCond
2628   PCI_MAGIC
2629 };
2630 
2631 pCodeInstruction pic16_pciSWAPF = {
2632   {PC_OPCODE, NULL, NULL, 0, NULL,
2633    //   genericAnalyze,
2634    genericDestruct,
2635    genericPrint},
2636   POC_SWAPF,
2637   "SWAPF",
2638   2,
2639   NULL, // from branch
2640   NULL, // to branch
2641   NULL, // label
2642   NULL, // operand
2643   NULL, // flow block
2644   NULL, // C source
2645   3,    // num ops
2646   TRUE,  // dest
2647   FALSE,  // bit instruction
2648   FALSE,  // branch
2649   FALSE,  // skip
2650   FALSE,    // literal operand
2651   TRUE,    // RAM access bit
2652   FALSE,    // fast call/return mode select bit
2653   FALSE,    // second memory operand
2654   FALSE,    // second literal operand
2655   POC_NOP,
2656   (PCC_REGISTER),   // inCond
2657   (PCC_REGISTER), // outCond
2658   PCI_MAGIC
2659 };
2660 
2661 pCodeInstruction pic16_pciSWAPFW = {
2662   {PC_OPCODE, NULL, NULL, 0, NULL,
2663    //   genericAnalyze,
2664    genericDestruct,
2665    genericPrint},
2666   POC_SWAPFW,
2667   "SWAPF",
2668   2,
2669   NULL, // from branch
2670   NULL, // to branch
2671   NULL, // label
2672   NULL, // operand
2673   NULL, // flow block
2674   NULL, // C source
2675   3,    // num ops
2676   FALSE,  // dest
2677   FALSE,  // bit instruction
2678   FALSE,  // branch
2679   FALSE,  // skip
2680   FALSE,    // literal operand
2681   TRUE,    // RAM access bit
2682   FALSE,    // fast call/return mode select bit
2683   FALSE,    // second memory operand
2684   FALSE,    // second literal operand
2685   POC_NOP,
2686   (PCC_REGISTER),   // inCond
2687   (PCC_W), // outCond
2688   PCI_MAGIC
2689 };
2690 
2691 pCodeInstruction pic16_pciTBLRD = {     // patch 15
2692   {PC_OPCODE, NULL, NULL, 0, NULL,
2693    genericDestruct,
2694    genericPrint},
2695   POC_TBLRD,
2696   "TBLRD*",
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   FALSE,  // dest
2706   FALSE,  // bit instruction
2707   FALSE,  // branch
2708   FALSE,  // skip
2709   FALSE,    // literal operand
2710   FALSE,    // RAM access bit
2711   FALSE,    // fast call/return mode select bit
2712   FALSE,    // second memory operand
2713   FALSE,    // second literal operand
2714   POC_NOP,
2715   PCC_NONE,  // inCond
2716   PCC_NONE  , // outCond
2717   PCI_MAGIC
2718 };
2719 
2720 pCodeInstruction pic16_pciTBLRD_POSTINC = {     // patch 15
2721   {PC_OPCODE, NULL, NULL, 0, NULL,
2722    genericDestruct,
2723    genericPrint},
2724   POC_TBLRD_POSTINC,
2725   "TBLRD*+",
2726   2,
2727   NULL, // from branch
2728   NULL, // to branch
2729   NULL, // label
2730   NULL, // operand
2731   NULL, // flow block
2732   NULL, // C source
2733   0,    // num ops
2734   FALSE,  // dest
2735   FALSE,  // bit instruction
2736   FALSE,  // branch
2737   FALSE,  // skip
2738   FALSE,    // literal operand
2739   FALSE,    // RAM access bit
2740   FALSE,    // fast call/return mode select bit
2741   FALSE,    // second memory operand
2742   FALSE,    // second literal operand
2743   POC_NOP,
2744   PCC_NONE,  // inCond
2745   PCC_NONE  , // outCond
2746   PCI_MAGIC
2747 };
2748 
2749 pCodeInstruction pic16_pciTBLRD_POSTDEC = {     // patch 15
2750   {PC_OPCODE, NULL, NULL, 0, NULL,
2751    genericDestruct,
2752    genericPrint},
2753   POC_TBLRD_POSTDEC,
2754   "TBLRD*-",
2755   2,
2756   NULL, // from branch
2757   NULL, // to branch
2758   NULL, // label
2759   NULL, // operand
2760   NULL, // flow block
2761   NULL, // C source
2762   0,    // num ops
2763   FALSE,  // dest
2764   FALSE,  // bit instruction
2765   FALSE,  // branch
2766   FALSE,  // skip
2767   FALSE,    // literal operand
2768   FALSE,    // RAM access bit
2769   FALSE,    // fast call/return mode select bit
2770   FALSE,    // second memory operand
2771   FALSE,    // second literal operand
2772   POC_NOP,
2773   PCC_NONE,  // inCond
2774   PCC_NONE  , // outCond
2775   PCI_MAGIC
2776 };
2777 
2778 pCodeInstruction pic16_pciTBLRD_PREINC = {      // patch 15
2779   {PC_OPCODE, NULL, NULL, 0, NULL,
2780    genericDestruct,
2781    genericPrint},
2782   POC_TBLRD_PREINC,
2783   "TBLRD+*",
2784   2,
2785   NULL, // from branch
2786   NULL, // to branch
2787   NULL, // label
2788   NULL, // operand
2789   NULL, // flow block
2790   NULL, // C source
2791   0,    // num ops
2792   FALSE,  // dest
2793   FALSE,  // bit instruction
2794   FALSE,  // branch
2795   FALSE,  // skip
2796   FALSE,    // literal operand
2797   FALSE,    // RAM access bit
2798   FALSE,    // fast call/return mode select bit
2799   FALSE,    // second memory operand
2800   FALSE,    // second literal operand
2801   POC_NOP,
2802   PCC_NONE,  // inCond
2803   PCC_NONE  , // outCond
2804   PCI_MAGIC
2805 };
2806 
2807 pCodeInstruction pic16_pciTBLWT = {     // patch 15
2808   {PC_OPCODE, NULL, NULL, 0, NULL,
2809    genericDestruct,
2810    genericPrint},
2811   POC_TBLWT,
2812   "TBLWT*",
2813   2,
2814   NULL, // from branch
2815   NULL, // to branch
2816   NULL, // label
2817   NULL, // operand
2818   NULL, // flow block
2819   NULL, // C source
2820   0,    // num ops
2821   FALSE,  // dest
2822   FALSE,  // bit instruction
2823   FALSE,  // branch
2824   FALSE,  // skip
2825   FALSE,    // literal operand
2826   FALSE,    // RAM access bit
2827   FALSE,    // fast call/return mode select bit
2828   FALSE,    // second memory operand
2829   FALSE,    // second literal operand
2830   POC_NOP,
2831   PCC_NONE,  // inCond
2832   PCC_NONE  , // outCond
2833   PCI_MAGIC
2834 };
2835 
2836 pCodeInstruction pic16_pciTBLWT_POSTINC = {     // patch 15
2837   {PC_OPCODE, NULL, NULL, 0, NULL,
2838    genericDestruct,
2839    genericPrint},
2840   POC_TBLWT_POSTINC,
2841   "TBLWT*+",
2842   2,
2843   NULL, // from branch
2844   NULL, // to branch
2845   NULL, // label
2846   NULL, // operand
2847   NULL, // flow block
2848   NULL, // C source
2849   0,    // num ops
2850   FALSE,  // dest
2851   FALSE,  // bit instruction
2852   FALSE,  // branch
2853   FALSE,  // skip
2854   FALSE,    // literal operand
2855   FALSE,    // RAM access bit
2856   FALSE,    // fast call/return mode select bit
2857   FALSE,    // second memory operand
2858   FALSE,    // second literal operand
2859   POC_NOP,
2860   PCC_NONE,  // inCond
2861   PCC_NONE  , // outCond
2862   PCI_MAGIC
2863 };
2864 
2865 pCodeInstruction pic16_pciTBLWT_POSTDEC = {     // patch 15
2866   {PC_OPCODE, NULL, NULL, 0, NULL,
2867    genericDestruct,
2868    genericPrint},
2869   POC_TBLWT_POSTDEC,
2870   "TBLWT*-",
2871   2,
2872   NULL, // from branch
2873   NULL, // to branch
2874   NULL, // label
2875   NULL, // operand
2876   NULL, // flow block
2877   NULL, // C source
2878   0,    // num ops
2879   FALSE,  // dest
2880   FALSE,  // bit instruction
2881   FALSE,  // branch
2882   FALSE,  // skip
2883   FALSE,    // literal operand
2884   FALSE,    // RAM access bit
2885   FALSE,    // fast call/return mode select bit
2886   FALSE,    // second memory operand
2887   FALSE,    // second literal operand
2888   POC_NOP,
2889   PCC_NONE,  // inCond
2890   PCC_NONE  , // outCond
2891   PCI_MAGIC
2892 };
2893 
2894 pCodeInstruction pic16_pciTBLWT_PREINC = {      // patch 15
2895   {PC_OPCODE, NULL, NULL, 0, NULL,
2896    genericDestruct,
2897    genericPrint},
2898   POC_TBLWT_PREINC,
2899   "TBLWT+*",
2900   2,
2901   NULL, // from branch
2902   NULL, // to branch
2903   NULL, // label
2904   NULL, // operand
2905   NULL, // flow block
2906   NULL, // C source
2907   0,    // num ops
2908   FALSE,  // dest
2909   FALSE,  // bit instruction
2910   FALSE,  // branch
2911   FALSE,  // skip
2912   FALSE,    // literal operand
2913   FALSE,    // RAM access bit
2914   FALSE,    // fast call/return mode select bit
2915   FALSE,    // second memory operand
2916   FALSE,    // second literal operand
2917   POC_NOP,
2918   PCC_NONE,  // inCond
2919   PCC_NONE  , // outCond
2920   PCI_MAGIC
2921 };
2922 
2923 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2924   {PC_OPCODE, NULL, NULL, 0, NULL,
2925    //   genericAnalyze,
2926    genericDestruct,
2927    genericPrint},
2928   POC_TSTFSZ,
2929   "TSTFSZ",
2930   2,
2931   NULL, // from branch
2932   NULL, // to branch
2933   NULL, // label
2934   NULL, // operand
2935   NULL, // flow block
2936   NULL, // C source
2937   2,    // num ops
2938   FALSE,  // dest
2939   FALSE,  // bit instruction
2940   TRUE,  // branch
2941   TRUE,  // skip
2942   FALSE,    // literal operand
2943   TRUE,    // RAM access bit
2944   FALSE,    // fast call/return mode select bit
2945   FALSE,    // second memory operand
2946   FALSE,    // second literal operand
2947   POC_NOP,
2948   PCC_REGISTER,   // inCond
2949   PCC_NONE, // outCond
2950   PCI_MAGIC
2951 };
2952 
2953 pCodeInstruction pic16_pciXORWF = {
2954   {PC_OPCODE, NULL, NULL, 0, NULL,
2955    //   genericAnalyze,
2956    genericDestruct,
2957    genericPrint},
2958   POC_XORWF,
2959   "XORWF",
2960   2,
2961   NULL, // from branch
2962   NULL, // to branch
2963   NULL, // label
2964   NULL, // operand
2965   NULL, // flow block
2966   NULL, // C source
2967   3,    // num ops
2968   TRUE,  // dest
2969   FALSE,  // bit instruction
2970   FALSE,  // branch
2971   FALSE,  // skip
2972   FALSE,    // literal operand
2973   TRUE,    // RAM access bit
2974   FALSE,    // fast call/return mode select bit
2975   FALSE,    // second memory operand
2976   FALSE,    // second literal operand
2977   POC_NOP,
2978   (PCC_W | PCC_REGISTER),   // inCond
2979   (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2980   PCI_MAGIC
2981 };
2982 
2983 pCodeInstruction pic16_pciXORFW = {
2984   {PC_OPCODE, NULL, NULL, 0, NULL,
2985    //   genericAnalyze,
2986    genericDestruct,
2987    genericPrint},
2988   POC_XORFW,
2989   "XORWF",
2990   2,
2991   NULL, // from branch
2992   NULL, // to branch
2993   NULL, // label
2994   NULL, // operand
2995   NULL, // flow block
2996   NULL, // C source
2997   3,    // num ops
2998   FALSE,  // dest
2999   FALSE,  // bit instruction
3000   FALSE,  // branch
3001   FALSE,  // skip
3002   FALSE,    // literal operand
3003   TRUE,    // RAM access bit
3004   FALSE,    // fast call/return mode select bit
3005   FALSE,    // second memory operand
3006   FALSE,    // second literal operand
3007   POC_NOP,
3008   (PCC_W | PCC_REGISTER),   // inCond
3009   (PCC_W | PCC_Z | PCC_N), // outCond
3010   PCI_MAGIC
3011 };
3012 
3013 pCodeInstruction pic16_pciXORLW = {
3014   {PC_OPCODE, NULL, NULL, 0, NULL,
3015    //   genericAnalyze,
3016    genericDestruct,
3017    genericPrint},
3018   POC_XORLW,
3019   "XORLW",
3020   2,
3021   NULL, // from branch
3022   NULL, // to branch
3023   NULL, // label
3024   NULL, // operand
3025   NULL, // flow block
3026   NULL, // C source
3027   1,    // num ops
3028   FALSE,  // dest
3029   FALSE,  // bit instruction
3030   FALSE,  // branch
3031   FALSE,  // skip
3032   TRUE,    // literal operand
3033   TRUE,    // RAM access bit
3034   FALSE,    // fast call/return mode select bit
3035   FALSE,    // second memory operand
3036   FALSE,    // second literal operand
3037   POC_NOP,
3038   (PCC_W | PCC_LITERAL),   // inCond
3039   (PCC_W | PCC_Z | PCC_N), // outCond
3040   PCI_MAGIC
3041 };
3042 
3043 
3044 pCodeInstruction pic16_pciBANKSEL = {
3045   {PC_OPCODE, NULL, NULL, 0, NULL,
3046    genericDestruct,
3047    genericPrint},
3048   POC_BANKSEL,
3049   "BANKSEL",
3050   2,
3051   NULL, // from branch
3052   NULL, // to branch
3053   NULL, // label
3054   NULL, // operand
3055   NULL, // flow block
3056   NULL, // C source
3057   0,    // num ops
3058   FALSE,  // dest
3059   FALSE,  // bit instruction
3060   FALSE,  // branch
3061   FALSE,  // skip
3062   FALSE,    // literal operand
3063   FALSE,    // RAM access bit
3064   FALSE,    // fast call/return mode select bit
3065   FALSE,    // second memory operand
3066   FALSE,    // second literal operand
3067   POC_NOP,
3068   PCC_NONE,   // inCond
3069   PCC_NONE, // outCond
3070   PCI_MAGIC
3071 };
3072 
3073 
3074 #define MAX_PIC16MNEMONICS 100
3075 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
3076 
3077 extern set *externs;
3078 extern reg_info *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
3079 extern reg_info *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
3080 
pic16_pCodeInitRegisters(void)3081 void  pic16_pCodeInitRegisters(void)
3082 {
3083   static int initialized=0;
3084 
3085         if(initialized)
3086                 return;
3087 
3088         initialized = 1;
3089 
3090         pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
3091         pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
3092         pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
3093         pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
3094         pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
3095         pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
3096         pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
3097 
3098         pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
3099         pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
3100         pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
3101 
3102         pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
3103         pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
3104         pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
3105         pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
3106 
3107         pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
3108         pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
3109         pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
3110         pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
3111         pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
3112         pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3113 
3114         pic16_stackpnt_lo = &pic16_pc_fsr1l;
3115         pic16_stackpnt_hi = &pic16_pc_fsr1h;
3116         pic16_stack_postdec = &pic16_pc_postdec1;
3117         pic16_stack_postinc = &pic16_pc_postinc1;
3118         pic16_stack_preinc = &pic16_pc_preinc1;
3119         pic16_stack_plusw = &pic16_pc_plusw1;
3120 
3121         pic16_framepnt_lo = &pic16_pc_fsr2l;
3122         pic16_framepnt_hi = &pic16_pc_fsr2h;
3123         pic16_frame_postdec = &pic16_pc_postdec2;
3124         pic16_frame_postinc = &pic16_pc_postinc2;
3125         pic16_frame_preinc = &pic16_pc_preinc2;
3126         pic16_frame_plusw = &pic16_pc_plusw2;
3127 
3128         pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3129         pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3130         pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3131         pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3132         pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3133 
3134         pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3135         pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3136         pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3137         pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3138         pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3139 
3140         pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3141         pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3142         pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3143         pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3144         pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3145 
3146         pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3147         pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3148 
3149 
3150         pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3151         pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3152         pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3153         pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3154 
3155 
3156         pic16_pc_status.rIdx = IDX_STATUS;
3157         pic16_pc_intcon.rIdx = IDX_INTCON;
3158         pic16_pc_pcl.rIdx = IDX_PCL;
3159         pic16_pc_pclath.rIdx = IDX_PCLATH;
3160         pic16_pc_pclatu.rIdx = IDX_PCLATU;
3161         pic16_pc_wreg.rIdx = IDX_WREG;
3162         pic16_pc_bsr.rIdx = IDX_BSR;
3163 
3164         pic16_pc_tosl.rIdx = IDX_TOSL;
3165         pic16_pc_tosh.rIdx = IDX_TOSH;
3166         pic16_pc_tosu.rIdx = IDX_TOSU;
3167 
3168         pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3169         pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3170         pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3171         pic16_pc_tablat.rIdx = IDX_TABLAT;
3172 
3173         pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3174         pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3175         pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3176         pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3177         pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3178         pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3179         pic16_pc_indf0.rIdx = IDX_INDF0;
3180         pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3181         pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3182         pic16_pc_preinc0.rIdx = IDX_PREINC0;
3183         pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3184         pic16_pc_indf1.rIdx = IDX_INDF1;
3185         pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3186         pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3187         pic16_pc_preinc1.rIdx = IDX_PREINC1;
3188         pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3189         pic16_pc_indf2.rIdx = IDX_INDF2;
3190         pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3191         pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3192         pic16_pc_preinc2.rIdx = IDX_PREINC2;
3193         pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3194         pic16_pc_prodl.rIdx = IDX_PRODL;
3195         pic16_pc_prodh.rIdx = IDX_PRODH;
3196 
3197         pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3198         pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3199         pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3200 
3201         pic16_pc_kzero.rIdx = IDX_KZ;
3202         pic16_pc_wsave.rIdx = IDX_WSAVE;
3203         pic16_pc_ssave.rIdx = IDX_SSAVE;
3204 
3205         pic16_pc_eecon1.rIdx = IDX_EECON1;
3206         pic16_pc_eecon2.rIdx = IDX_EECON2;
3207         pic16_pc_eedata.rIdx = IDX_EEDATA;
3208         pic16_pc_eeadr.rIdx = IDX_EEADR;
3209 
3210 
3211         pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3212         pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3213 
3214         pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3215         pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3216 
3217         /* probably should put this in a separate initialization routine */
3218         pb_dead_pcodes = newpBlock();
3219 
3220 }
3221 
3222 /*-----------------------------------------------------------------*/
3223 /*  mnem2key - convert a pic mnemonic into a hash key              */
3224 /*   (BTW - this spreads the mnemonics quite well)                 */
3225 /*                                                                 */
3226 /*-----------------------------------------------------------------*/
3227 
mnem2key(unsigned char const * mnem)3228 static int mnem2key(unsigned char const *mnem)
3229 {
3230   int key = 0;
3231 
3232   if(!mnem)
3233     return 0;
3234 
3235   while(*mnem) {
3236 
3237     key += toupper(*mnem++) +1;
3238 
3239   }
3240 
3241   return (key & 0x1f);
3242 
3243 }
3244 
pic16initMnemonics(void)3245 void pic16initMnemonics(void)
3246 {
3247   int i = 0;
3248   int key;
3249   //  char *str;
3250   pCodeInstruction *pci;
3251 
3252   if(mnemonics_initialized)
3253     return;
3254 
3255   // NULL out the array before making the assignments
3256   // since we check the array contents below this initialization.
3257 
3258   for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3259     pic16Mnemonics[i] = NULL;
3260   }
3261 
3262   pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3263   pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3264   pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3265   pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3266   pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3267   pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3268   pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3269   pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3270   pic16Mnemonics[POC_BC] = &pic16_pciBC;
3271   pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3272   pic16Mnemonics[POC_BN] = &pic16_pciBN;
3273   pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3274   pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3275   pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3276   pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3277   pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3278   pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3279   pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3280   pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3281   pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3282   pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3283   pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3284   pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3285   pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3286   pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3287   pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3288   pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3289   pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3290   pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3291   pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3292   pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3293   pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3294   pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3295   pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3296   pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3297   pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3298   pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3299   pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3300   pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3301   pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3302   pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3303   pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3304   pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3305   pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3306   pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3307   pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3308   pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3309   pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3310   pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3311   pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3312   pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3313   pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3314   pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3315   pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3316   pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3317   pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3318   pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3319   pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3320   pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3321   pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3322   pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3323   pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3324   pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3325   pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3326   pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3327   pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3328   pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3329   pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3330   pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3331   pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3332   pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3333   pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3334   pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3335   pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3336   pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3337   pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3338   pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3339   pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3340   pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3341   pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3342   pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3343   pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3344   pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3345   pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3346   pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3347   pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3348   pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3349   pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3350   pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3351   pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3352   pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3353   pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3354   pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3355   pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3356 
3357   for(i=0; i<MAX_PIC16MNEMONICS; i++)
3358     if(pic16Mnemonics[i])
3359       hTabAddItem(&pic16MnemonicsHash, mnem2key((const unsigned char *)pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3360   pci = hTabFirstItem(pic16MnemonicsHash, &key);
3361 
3362   while(pci) {
3363     DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3364     pci = hTabNextItem(pic16MnemonicsHash, &key);
3365   }
3366 
3367   mnemonics_initialized = 1;
3368 }
3369 
3370 int pic16_getpCodePeepCommand(const char *cmd);
3371 
pic16_getpCode(const char * mnem,unsigned dest)3372 int pic16_getpCode(const char *mnem,unsigned dest)
3373 {
3374   pCodeInstruction *pci;
3375   int key = mnem2key((unsigned char *)mnem);
3376 
3377   if(!mnemonics_initialized)
3378     pic16initMnemonics();
3379 
3380   pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3381 
3382   while(pci) {
3383 
3384     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3385       if((pci->num_ops <= 1)
3386         || (pci->isModReg == dest)
3387         || (pci->isBitInst)
3388         || (pci->num_ops <= 2 && pci->isAccess)
3389         || (pci->num_ops <= 2 && pci->isFastCall)
3390         || (pci->num_ops <= 2 && pci->is2MemOp)
3391         || (pci->num_ops <= 2 && pci->is2LitOp) )
3392         return(pci->op);
3393     }
3394 
3395     pci = hTabNextItemWK (pic16MnemonicsHash);
3396 
3397   }
3398 
3399   return -1;
3400 }
3401 
3402 /*-----------------------------------------------------------------*
3403  * pic16initpCodePeepCommands
3404  *
3405  *-----------------------------------------------------------------*/
pic16initpCodePeepCommands(void)3406 void pic16initpCodePeepCommands(void)
3407 {
3408   int key, i;
3409   peepCommand *pcmd;
3410 
3411   i = 0;
3412   do {
3413     hTabAddItem(&pic16pCodePeepCommandsHash,
3414                 mnem2key((const unsigned char *)peepCommands[i].cmd), &peepCommands[i]);
3415     i++;
3416   } while (peepCommands[i].cmd);
3417 
3418   pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3419 
3420   while(pcmd) {
3421     //fprintf(stderr, "peep command %s  key %d\n",pcmd->cmd,pcmd->id);
3422     pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3423   }
3424 }
3425 
3426 /*-----------------------------------------------------------------
3427  *
3428  *
3429  *-----------------------------------------------------------------*/
3430 
pic16_getpCodePeepCommand(const char * cmd)3431 int pic16_getpCodePeepCommand(const char *cmd)
3432 {
3433   peepCommand *pcmd;
3434   int key = mnem2key((unsigned char *)cmd);
3435 
3436 
3437   pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3438 
3439   while(pcmd) {
3440     // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3441     if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3442       return pcmd->id;
3443     }
3444 
3445     pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3446 
3447   }
3448 
3449   return -1;
3450 }
3451 
getpBlock_dbName(pBlock * pb)3452 static char getpBlock_dbName(pBlock *pb)
3453 {
3454   if(!pb)
3455     return 0;
3456 
3457   if(pb->cmemmap)
3458     return pb->cmemmap->dbName;
3459 
3460   return pb->dbName;
3461 }
pic16_pBlockConvert2ISR(pBlock * pb)3462 void pic16_pBlockConvert2ISR(pBlock *pb)
3463 {
3464         if(!pb)return;
3465 
3466         if(pb->cmemmap)pb->cmemmap = NULL;
3467 
3468         pb->dbName = 'I';
3469 
3470         if(pic16_pcode_verbose)
3471                 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3472 }
3473 
pic16_pBlockConvert2Absolute(pBlock * pb)3474 void pic16_pBlockConvert2Absolute(pBlock *pb)
3475 {
3476         if(!pb)return;
3477         if(pb->cmemmap)pb->cmemmap = NULL;
3478 
3479         pb->dbName = 'A';
3480 
3481         if(pic16_pcode_verbose)
3482                 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3483 }
3484 
3485 /*-----------------------------------------------------------------*/
3486 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all  */
3487 /*                   instances to the front of the doubly linked   */
3488 /*                   list of pBlocks                               */
3489 /*-----------------------------------------------------------------*/
3490 
pic16_movepBlock2Head(char dbName)3491 void pic16_movepBlock2Head(char dbName)
3492 {
3493   pBlock *pb;
3494 
3495 
3496   /* this can happen in sources without code,
3497    * only variable definitions */
3498   if(!the_pFile)return;
3499 
3500   pb = the_pFile->pbHead;
3501 
3502   while(pb) {
3503 
3504     if(getpBlock_dbName(pb) == dbName) {
3505       pBlock *pbn = pb->next;
3506       pb->next = the_pFile->pbHead;
3507       the_pFile->pbHead->prev = pb;
3508       the_pFile->pbHead = pb;
3509 
3510       if(pb->prev)
3511         pb->prev->next = pbn;
3512 
3513       // If the pBlock that we just moved was the last
3514       // one in the link of all of the pBlocks, then we
3515       // need to point the tail to the block just before
3516       // the one we moved.
3517       // Note: if pb->next is NULL, then pb must have
3518       // been the last pBlock in the chain.
3519 
3520       if(pbn)
3521         pbn->prev = pb->prev;
3522       else
3523         the_pFile->pbTail = pb->prev;
3524 
3525       pb = pbn;
3526 
3527     } else
3528       pb = pb->next;
3529 
3530   }
3531 }
3532 
pic16_copypCode(FILE * of,char dbName)3533 void pic16_copypCode(FILE *of, char dbName)
3534 {
3535   pBlock *pb;
3536 
3537         if(!of || !the_pFile)
3538                 return;
3539 
3540         for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3541                 if(getpBlock_dbName(pb) == dbName) {
3542 //                      fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3543                         pBlockStats(of,pb);
3544                         pic16_printpBlock(of,pb);
3545                 }
3546         }
3547 
3548 }
pic16_pcode_test(void)3549 void pic16_pcode_test(void)
3550 {
3551   DFPRINTF((stderr,"pcode is alive!\n"));
3552 
3553   //initMnemonics();
3554 
3555   if (the_pFile) {
3556     pBlock *pb;
3557     FILE *pFile;
3558     char buffer[100];
3559 
3560     /* create the file name */
3561     SNPRINTF(buffer, sizeof(buffer), "%s.p", dstFileName);
3562 
3563     if(!(pFile = fopen(buffer, "w" ))) {
3564       werror(E_FILE_OPEN_ERR,buffer);
3565       exit(1);
3566     }
3567 
3568     fprintf(pFile,"pcode dump\n\n");
3569 
3570     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3571       fprintf(pFile,"\n\tNew pBlock\n\n");
3572       if(pb->cmemmap)
3573         fprintf(pFile,"%s",pb->cmemmap->sname);
3574       else
3575         fprintf(pFile,"internal pblock");
3576 
3577       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3578       pic16_printpBlock(pFile,pb);
3579     }
3580     fclose(pFile);
3581   }
3582 }
3583 
3584 
pic16_countInstructions(void)3585 unsigned long pic16_countInstructions(void)
3586 {
3587   pBlock *pb;
3588   pCode *pc;
3589   unsigned long isize=0;
3590 
3591     if(!the_pFile)return -1;
3592 
3593     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3594       for(pc = pb->pcHead; pc; pc = pc->next) {
3595         if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3596       }
3597     }
3598   return (isize);
3599 }
3600 
3601 
3602 /*-----------------------------------------------------------------*/
3603 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg-  */
3604 /*      ister, RegCond will return the bit being referenced.       */
3605 /*                                                                 */
3606 /* fixme - why not just OR in the pcop bit field                   */
3607 /*-----------------------------------------------------------------*/
3608 
RegCond(const pCodeOp * pcop)3609 static int RegCond(const pCodeOp *pcop)
3610 {
3611   if(!pcop)
3612     return 0;
3613 
3614   if(!pcop->name)return 0;
3615 
3616   if(pcop->type == PO_GPR_BIT  && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3617     switch(PCORB(pcop)->bit) {
3618     case PIC_C_BIT:
3619       return PCC_C;
3620     case PIC_DC_BIT:
3621         return PCC_DC;
3622     case PIC_Z_BIT:
3623       return PCC_Z;
3624     }
3625   }
3626 
3627   return 0;
3628 }
3629 
3630 
3631 /*-----------------------------------------------------------------*/
3632 /* pic16_newpCode - create and return a newly initialized pCode          */
3633 /*                                                                 */
3634 /*  fixme - rename this                                            */
3635 /*                                                                 */
3636 /* The purpose of this routine is to create a new Instruction      */
3637 /* pCode. This is called by gen.c while the assembly code is being */
3638 /* generated.                                                      */
3639 /*                                                                 */
3640 /* Inouts:                                                         */
3641 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
3642 /*                  (note that the op is analogous to but not the  */
3643 /*                  same thing as the opcode of the instruction.)  */
3644 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
3645 /*                                                                 */
3646 /* Outputs:                                                        */
3647 /*  a pointer to the new malloc'd pCode is returned.               */
3648 /*                                                                 */
3649 /*                                                                 */
3650 /*                                                                 */
3651 /*-----------------------------------------------------------------*/
pic16_newpCode(PIC_OPCODE op,pCodeOp * pcop)3652 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3653 {
3654   pCodeInstruction *pci ;
3655 
3656   if(!mnemonics_initialized)
3657     pic16initMnemonics();
3658 
3659   pci = Safe_alloc(sizeof(pCodeInstruction));
3660 
3661   if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3662     memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3663     pci->pcop = pcop;
3664 
3665     if(pci->inCond & PCC_EXAMINE_PCOP)
3666       pci->inCond  |= RegCond(pcop);
3667 
3668     if(pci->outCond & PCC_EXAMINE_PCOP)
3669       pci->outCond  |= RegCond(pcop);
3670 
3671     pci->pc.prev = pci->pc.next = NULL;
3672     return (pCode *)pci;
3673   }
3674 
3675   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3676   exit(1);
3677 
3678   return NULL;
3679 }
3680 
3681 /*-----------------------------------------------------------------*/
3682 /* pic16_newpCodeWild - create a "wild" as in wild card pCode            */
3683 /*                                                                 */
3684 /* Wild pcodes are used during the peep hole optimizer to serve    */
3685 /* as place holders for any instruction. When a snippet of code is */
3686 /* compared to a peep hole rule, the wild card opcode will match   */
3687 /* any instruction. However, the optional operand and label are    */
3688 /* additional qualifiers that must also be matched before the      */
3689 /* line (of assembly code) is declared matched. Note that the      */
3690 /* operand may be wild too.                                        */
3691 /*                                                                 */
3692 /*   Note, a wild instruction is specified just like a wild var:   */
3693 /*      %4     ; A wild instruction,                               */
3694 /*  See the peeph.def file for additional examples                 */
3695 /*                                                                 */
3696 /*-----------------------------------------------------------------*/
3697 
pic16_newpCodeWild(int pCodeID,pCodeOp * optional_operand,pCodeOp * optional_label)3698 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3699 {
3700   pCodeWild *pcw;
3701 
3702   pcw = Safe_alloc(sizeof(pCodeWild));
3703 
3704   pcw->pci.pc.type = PC_WILD;
3705   pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3706   pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3707   pcw->pci.pc.pb = NULL;
3708 
3709   //  pcw->pci.pc.analyze = genericAnalyze;
3710   pcw->pci.pc.destruct = genericDestruct;
3711   pcw->pci.pc.print = genericPrint;
3712 
3713   pcw->id = pCodeID;              // this is the 'n' in %n
3714   pcw->operand = optional_operand;
3715   pcw->label   = optional_label;
3716 
3717   pcw->mustBeBitSkipInst = FALSE;
3718   pcw->mustNotBeBitSkipInst = FALSE;
3719   pcw->invertBitSkipInst = FALSE;
3720 
3721   return ((pCode *)pcw);
3722 }
3723 
3724  /*-----------------------------------------------------------------*/
3725 /* newPcodeInlineP - create a new pCode from a char string           */
3726 /*-----------------------------------------------------------------*/
3727 
3728 
pic16_newpCodeInlineP(const char * cP)3729 pCode *pic16_newpCodeInlineP(const char *cP)
3730 {
3731   pCodeComment *pcc;
3732 
3733   pcc = Safe_alloc(sizeof(pCodeComment));
3734 
3735   pcc->pc.type = PC_INLINE;
3736   pcc->pc.prev = pcc->pc.next = NULL;
3737   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3738   pcc->pc.pb = NULL;
3739 
3740   //  pcc->pc.analyze = genericAnalyze;
3741   pcc->pc.destruct = genericDestruct;
3742   pcc->pc.print = genericPrint;
3743 
3744   pcc->comment = (cP != NULL) ? Safe_strdup(cP) : NULL;
3745 
3746   return ((pCode *)pcc);
3747 }
3748 
3749 /*-----------------------------------------------------------------*/
3750 /* newPcodeCharP - create a new pCode from a char string           */
3751 /*-----------------------------------------------------------------*/
3752 
pic16_newpCodeCharP(const char * cP)3753 pCode *pic16_newpCodeCharP(const char *cP)
3754 {
3755   pCodeComment *pcc;
3756 
3757   pcc = Safe_alloc(sizeof(pCodeComment));
3758 
3759   pcc->pc.type = PC_COMMENT;
3760   pcc->pc.prev = pcc->pc.next = NULL;
3761   //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3762   pcc->pc.pb = NULL;
3763 
3764   //  pcc->pc.analyze = genericAnalyze;
3765   pcc->pc.destruct = genericDestruct;
3766   pcc->pc.print = genericPrint;
3767 
3768   pcc->comment = (cP != NULL) ? Safe_strdup(cP) : NULL;
3769 
3770   return ((pCode *)pcc);
3771 }
3772 
3773 /*-----------------------------------------------------------------*/
3774 /* pic16_newpCodeFunction -                                              */
3775 /*-----------------------------------------------------------------*/
3776 
3777 
pic16_newpCodeFunction(const char * mod,const char * f)3778 pCode *pic16_newpCodeFunction(const char *mod, const char *f)
3779 {
3780   pCodeFunction *pcf;
3781 
3782   pcf = Safe_alloc(sizeof(pCodeFunction));
3783 
3784   pcf->pc.type = PC_FUNCTION;
3785   pcf->pc.prev = pcf->pc.next = NULL;
3786   //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3787   pcf->pc.pb = NULL;
3788 
3789   //pcf->pc.analyze = genericAnalyze;
3790   pcf->pc.destruct = genericDestruct;
3791   pcf->pc.print = pCodePrintFunction;
3792 
3793   pcf->ncalled = 0;
3794   pcf->absblock = FALSE;
3795 
3796   pcf->modname = (mod != NULL) ? Safe_strdup(mod) : NULL;
3797   pcf->fname   = (f != NULL)   ? Safe_strdup(f)   : NULL;
3798 
3799   pcf->stackusage = 0;
3800 
3801   return ((pCode *)pcf);
3802 }
3803 
3804 /*-----------------------------------------------------------------*/
3805 /* pic16_newpCodeFlow                                                    */
3806 /*-----------------------------------------------------------------*/
destructpCodeFlow(pCode * pc)3807 static void destructpCodeFlow(pCode *pc)
3808 {
3809   if(!pc || !isPCFL(pc))
3810     return;
3811 
3812 /*
3813   if(PCFL(pc)->from)
3814   if(PCFL(pc)->to)
3815 */
3816   pic16_unlinkpCode(pc);
3817 
3818   deleteSet(&PCFL(pc)->registers);
3819   deleteSet(&PCFL(pc)->from);
3820   deleteSet(&PCFL(pc)->to);
3821 
3822   /* Instead of deleting the memory used by this pCode, mark
3823    * the object as bad so that if there's a pointer to this pCode
3824    * dangling around somewhere then (hopefully) when the type is
3825    * checked we'll catch it.
3826    */
3827 
3828   pc->type = PC_BAD;
3829   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3830 
3831 //  Safe_free(pc);
3832 }
3833 
pic16_newpCodeFlow(void)3834 pCode *pic16_newpCodeFlow(void)
3835 {
3836   pCodeFlow *pcflow;
3837 
3838   //_ALLOC(pcflow,sizeof(pCodeFlow));
3839   pcflow = Safe_alloc(sizeof(pCodeFlow));
3840 
3841   pcflow->pc.type = PC_FLOW;
3842   pcflow->pc.prev = pcflow->pc.next = NULL;
3843   pcflow->pc.pb = NULL;
3844 
3845   //  pcflow->pc.analyze = genericAnalyze;
3846   pcflow->pc.destruct = destructpCodeFlow;
3847   pcflow->pc.print = genericPrint;
3848 
3849   pcflow->pc.seq = GpcFlowSeq++;
3850 
3851   pcflow->from = pcflow->to = NULL;
3852 
3853   pcflow->inCond = PCC_NONE;
3854   pcflow->outCond = PCC_NONE;
3855 
3856   pcflow->firstBank = -1;
3857   pcflow->lastBank = -1;
3858 
3859   pcflow->FromConflicts = 0;
3860   pcflow->ToConflicts = 0;
3861 
3862   pcflow->end = NULL;
3863 
3864   pcflow->registers = newSet();
3865 
3866   return ((pCode *)pcflow);
3867 }
3868 
3869 /*-----------------------------------------------------------------*/
3870 /*-----------------------------------------------------------------*/
pic16_newpCodeFlowLink(pCodeFlow * pcflow)3871 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3872 {
3873   pCodeFlowLink *pcflowLink;
3874 
3875   pcflowLink = Safe_alloc(sizeof(pCodeFlowLink));
3876 
3877   pcflowLink->pcflow = pcflow;
3878   pcflowLink->bank_conflict = 0;
3879 
3880   return pcflowLink;
3881 }
3882 
3883 /*-----------------------------------------------------------------*/
3884 /* pic16_newpCodeCSource - create a new pCode Source Symbol        */
3885 /*-----------------------------------------------------------------*/
3886 
pic16_newpCodeCSource(int ln,const char * f,const char * l)3887 pCode *pic16_newpCodeCSource(int ln, const char *f, const char *l)
3888 {
3889   pCodeCSource *pccs;
3890 
3891   pccs = Safe_alloc(sizeof(pCodeCSource));
3892 
3893   pccs->pc.type = PC_CSOURCE;
3894   pccs->pc.prev = pccs->pc.next = NULL;
3895   pccs->pc.pb = NULL;
3896 
3897   pccs->pc.destruct = genericDestruct;
3898   pccs->pc.print = genericPrint;
3899 
3900   pccs->line_number = ln;
3901   pccs->line        = (l != NULL) ? Safe_strdup(l) : NULL;
3902   pccs->file_name   = (f != NULL) ? Safe_strdup(f) : NULL;
3903 
3904   return ((pCode *)pccs);
3905 }
3906 
3907 
3908 /*******************************************************************/
3909 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive   */
3910 /*                      added by VR 6-Jun-2003                     */
3911 /*******************************************************************/
3912 
pic16_newpCodeAsmDir(const char * asdir,const char * argfmt,...)3913 pCode *pic16_newpCodeAsmDir(const char *asdir, const char *argfmt, ...)
3914 {
3915   pCodeAsmDir *pcad;
3916   va_list ap;
3917   char buffer[512];
3918   char *lbp=buffer;
3919 
3920   pcad = Safe_alloc(sizeof(pCodeAsmDir));
3921   pcad->pci.pc.type = PC_ASMDIR;
3922   pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3923   pcad->pci.pc.pb = NULL;
3924   pcad->pci.isize = 2;
3925   pcad->pci.pc.destruct = genericDestruct;
3926   pcad->pci.pc.print = genericPrint;
3927 
3928   if(asdir && *asdir) {
3929     while(isspace((const unsigned char)*asdir)) asdir++;   // strip any white space from the beginning
3930 
3931     pcad->directive = Safe_strdup(asdir);
3932   }
3933 
3934   va_start(ap, argfmt);
3935 
3936   memset(buffer, 0, sizeof(buffer));
3937   if(argfmt && *argfmt)
3938     vsprintf(buffer, argfmt, ap);
3939 
3940   va_end(ap);
3941 
3942   while(isspace((unsigned char)*lbp)) lbp++;
3943 
3944   if(lbp && *lbp)
3945     pcad->arg = Safe_strdup(lbp);
3946 
3947   return ((pCode *)pcad);
3948 }
3949 
3950 /*-----------------------------------------------------------------*/
3951 /* pCodeLabelDestruct - free memory used by a label.               */
3952 /*-----------------------------------------------------------------*/
pCodeLabelDestruct(pCode * pc)3953 static void pCodeLabelDestruct(pCode *pc)
3954 {
3955   if(!pc)
3956     return;
3957 
3958   pic16_unlinkpCode(pc);
3959 
3960 //  if((pc->type == PC_LABEL) && PCL(pc)->label)
3961 //    Safe_free(PCL(pc)->label);
3962 
3963   /* Instead of deleting the memory used by this pCode, mark
3964    * the object as bad so that if there's a pointer to this pCode
3965    * dangling around somewhere then (hopefully) when the type is
3966    * checked we'll catch it.
3967    */
3968 
3969   pc->type = PC_BAD;
3970   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3971 
3972 //  Safe_free(pc);
3973 }
3974 
pic16_newpCodeLabel(const char * name,int key)3975 pCode *pic16_newpCodeLabel(const char *name, int key)
3976 {
3977   const char *s;
3978   pCodeLabel *pcl;
3979 
3980   pcl = Safe_alloc(sizeof(pCodeLabel));
3981 
3982   pcl->pc.type = PC_LABEL;
3983   pcl->pc.prev = pcl->pc.next = NULL;
3984   //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3985   pcl->pc.pb = NULL;
3986 
3987   //  pcl->pc.analyze = genericAnalyze;
3988   pcl->pc.destruct = pCodeLabelDestruct;
3989   pcl->pc.print = pCodePrintLabel;
3990 
3991   pcl->key = key;
3992   pcl->force = FALSE;
3993 
3994   if(key>0) {
3995     SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_",key);
3996     s = buffer;
3997   } else
3998     s = name;
3999 
4000   pcl->label = (s != NULL) ? Safe_strdup(s) : NULL;
4001 
4002 //  if(pic16_pcode_verbose)
4003 //      fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
4004 
4005   return ((pCode *)pcl);
4006 }
4007 
pic16_newpCodeLabelFORCE(const char * name,int key)4008 pCode *pic16_newpCodeLabelFORCE(const char *name, int key)
4009 {
4010   pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
4011 
4012   pcl->force = TRUE;
4013 
4014   return ((pCode *)pcl);
4015 }
4016 
pic16_newpCodeInfo(INFO_TYPE type,pCodeOp * pcop)4017 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
4018 {
4019   pCodeInfo *pci;
4020 
4021   pci = Safe_alloc(sizeof(pCodeInfo));
4022   pci->pci.pc.type = PC_INFO;
4023   pci->pci.pc.prev = pci->pci.pc.next = NULL;
4024   pci->pci.pc.pb = NULL;
4025   pci->pci.label = NULL;
4026 
4027   pci->pci.pc.destruct = genericDestruct;
4028   pci->pci.pc.print = genericPrint;
4029 
4030   pci->type = type;
4031   pci->oper1 = pcop;
4032 
4033   return ((pCode *)pci);
4034 }
4035 
4036 
4037 /*-----------------------------------------------------------------*/
4038 /* newpBlock - create and return a pointer to a new pBlock         */
4039 /*-----------------------------------------------------------------*/
newpBlock(void)4040 static pBlock *newpBlock(void)
4041 {
4042   pBlock *PpB;
4043 
4044   PpB = Safe_alloc(sizeof(pBlock));
4045   PpB->next = PpB->prev = NULL;
4046 
4047   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
4048   PpB->tregisters = NULL;
4049   PpB->visited = FALSE;
4050   PpB->FlowTree = NULL;
4051 
4052   return PpB;
4053 }
4054 
4055 /*-----------------------------------------------------------------*/
4056 /* pic16_newpCodeChain - create a new chain of pCodes                    */
4057 /*-----------------------------------------------------------------*
4058  *
4059  *  This function will create a new pBlock and the pointer to the
4060  *  pCode that is passed in will be the first pCode in the block.
4061  *-----------------------------------------------------------------*/
4062 
4063 
pic16_newpCodeChain(memmap * cm,char c,pCode * pc)4064 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4065 {
4066   pBlock *pB  = newpBlock();
4067 
4068   pB->pcHead  = pB->pcTail = pc;
4069   pB->cmemmap = cm;
4070   pB->dbName  = c;
4071 
4072   return pB;
4073 }
4074 
4075 /*-----------------------------------------------------------------*/
4076 /* pic16_newpCodeOpLabel - Create a new label given the key              */
4077 /*  Note, a negative key means that the label is part of wild card */
4078 /*  (and hence a wild card label) used in the pCodePeep            */
4079 /*   optimizations).                                               */
4080 /*-----------------------------------------------------------------*/
4081 
pic16_newpCodeOpLabel(const char * name,int key)4082 pCodeOp *pic16_newpCodeOpLabel(const char *name, int key)
4083 {
4084   static int label_key = -1;
4085 
4086   const char *s;
4087 
4088   pCodeOp *pcop;
4089 
4090   pcop = Safe_alloc(sizeof(pCodeOpLabel));
4091   pcop->type = PO_LABEL;
4092 
4093   if(key>0) {
4094     SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_",key);
4095     s = buffer;
4096   }
4097   else {
4098     key = label_key--;
4099     s = name;
4100   }
4101 
4102   pcop->name = (s != NULL) ? Safe_strdup(s) : NULL;
4103 
4104   ((pCodeOpLabel *)pcop)->key = key;
4105 
4106   //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4107   return pcop;
4108 }
4109 
4110 /*-----------------------------------------------------------------*/
4111 /*-----------------------------------------------------------------*/
pic16_newpCodeOpLit(int lit)4112 pCodeOp *pic16_newpCodeOpLit(int lit)
4113 {
4114   pCodeOp *pcop;
4115 
4116   pcop = Safe_alloc(sizeof(pCodeOpLit));
4117   pcop->type = PO_LITERAL;
4118 
4119   //if(lit>=0)
4120     SNPRINTF(buffer, sizeof(buffer), "0x%02x", (unsigned char)lit);
4121   //else
4122   //  SNPRINTF(buffer, sizeof(buffer), "%i", lit);
4123 
4124   pcop->name = Safe_strdup(buffer);
4125 
4126   ((pCodeOpLit *)pcop)->lit = lit;
4127 
4128   return pcop;
4129 }
4130 
4131 /* Allow for 12 bit literals, required for LFSR */
pic16_newpCodeOpLit12(int lit)4132 pCodeOp *pic16_newpCodeOpLit12(int lit)
4133 {
4134   pCodeOp *pcop;
4135 
4136   pcop = Safe_alloc(sizeof(pCodeOpLit));
4137   pcop->type = PO_LITERAL;
4138 
4139   //if(lit>=0)
4140     SNPRINTF(buffer, sizeof(buffer), "0x%03x", ((unsigned int)lit) & 0x0fff);
4141   //else
4142   //  SNPRINTF(buffer, sizeof(buffer), "%i", lit);
4143 
4144   pcop->name = Safe_strdup(buffer);
4145 
4146   ((pCodeOpLit *)pcop)->lit = lit;
4147 
4148   return pcop;
4149 }
4150 
4151 /*-----------------------------------------------------------------*/
4152 /*-----------------------------------------------------------------*/
pic16_newpCodeOpLit2(int lit,pCodeOp * arg2)4153 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4154 {
4155   char tbuf[256], *tb = tbuf;
4156   pCodeOp *pcop;
4157 
4158   tb = pic16_get_op(arg2, NULL, 0);
4159   pcop = Safe_alloc(sizeof(pCodeOpLit2));
4160   pcop->type = PO_LITERAL;
4161 
4162   //pcop->name = NULL;
4163   //if(lit>=0) {
4164     SNPRINTF(buffer, sizeof(buffer), "0x%02x, %s", (unsigned char)lit, tb);
4165     pcop->name = Safe_strdup(buffer);
4166   //}
4167 
4168   ((pCodeOpLit2 *)pcop)->lit = lit;
4169   ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4170 
4171   return pcop;
4172 }
4173 
4174 /*-----------------------------------------------------------------*/
4175 /*-----------------------------------------------------------------*/
pic16_newpCodeOpImmd(const char * name,int offset,int index,int code_space)4176 pCodeOp *pic16_newpCodeOpImmd(const char *name, int offset, int index, int code_space)
4177 {
4178   pCodeOp *pcop;
4179 
4180         pcop = Safe_alloc(sizeof(pCodeOpImmd));
4181         pcop->type = PO_IMMEDIATE;
4182         if(name) {
4183                 reg_info *r = pic16_dirregWithName(name);
4184                 pcop->name = Safe_strdup(name);
4185                 PCOI(pcop)->r = r;
4186 
4187                 if(r) {
4188 //                      fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4189                         PCOI(pcop)->rIdx = r->rIdx;
4190                 } else {
4191 //                      fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4192                         PCOI(pcop)->rIdx = -1;
4193                 }
4194 //                      fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4195         } else {
4196                 pcop->name = NULL;
4197                 PCOI(pcop)->rIdx = -1;
4198         }
4199 
4200         PCOI(pcop)->index = index;
4201         PCOI(pcop)->offset = offset;
4202         PCOI(pcop)->_const = code_space;
4203 
4204   return pcop;
4205 }
4206 
4207 /*-----------------------------------------------------------------*/
4208 /*-----------------------------------------------------------------*/
pic16_newpCodeOpWild(int id,pCodeWildBlock * pcwb,pCodeOp * subtype)4209 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4210 {
4211   pCodeOp *pcop;
4212 
4213   if(!pcwb || !subtype) {
4214     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4215     exit(1);
4216   }
4217 
4218   pcop = Safe_alloc(sizeof(pCodeOpWild));
4219   pcop->type = PO_WILD;
4220   SNPRINTF(buffer, sizeof(buffer), "%%%d", id);
4221   pcop->name = Safe_strdup(buffer);
4222 
4223   PCOW(pcop)->id = id;
4224   PCOW(pcop)->pcwb = pcwb;
4225   PCOW(pcop)->subtype = subtype;
4226   PCOW(pcop)->matched = NULL;
4227 
4228   PCOW(pcop)->pcop2 = NULL;
4229 
4230   return pcop;
4231 }
4232 
4233 /*-----------------------------------------------------------------*/
4234 /*-----------------------------------------------------------------*/
pic16_newpCodeOpWild2(int id,int id2,pCodeWildBlock * pcwb,pCodeOp * subtype,pCodeOp * subtype2)4235 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4236 {
4237   pCodeOp *pcop;
4238 
4239         if(!pcwb || !subtype || !subtype2) {
4240                 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4241                 exit(1);
4242         }
4243 
4244         pcop = Safe_alloc(sizeof(pCodeOpWild));
4245         pcop->type = PO_WILD;
4246         SNPRINTF(buffer, sizeof(buffer), "%%%d", id);
4247         pcop->name = Safe_strdup(buffer);
4248 
4249         PCOW(pcop)->id = id;
4250         PCOW(pcop)->pcwb = pcwb;
4251         PCOW(pcop)->subtype = subtype;
4252         PCOW(pcop)->matched = NULL;
4253 
4254         PCOW(pcop)->pcop2 = Safe_alloc(sizeof(pCodeOpWild));
4255 
4256         if(!subtype2->name) {
4257                 PCOW(pcop)->pcop2 = Safe_alloc(sizeof(pCodeOpWild));
4258                 PCOW2(pcop)->pcop.type = PO_WILD;
4259                 SNPRINTF(buffer, sizeof(buffer), "%%%d", id2);
4260                 PCOW2(pcop)->pcop.name = Safe_strdup(buffer);
4261                 PCOW2(pcop)->id = id2;
4262                 PCOW2(pcop)->subtype = subtype2;
4263 
4264 //              fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4265 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4266         } else {
4267                 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy(subtype2);
4268 
4269 //              fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4270 //                              pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4271         }
4272 
4273   return pcop;
4274 }
4275 
4276 
4277 /*-----------------------------------------------------------------*/
4278 /*-----------------------------------------------------------------*/
pic16_newpCodeOpBit(const char * s,int bit,int inBitSpace,PIC_OPTYPE subt)4279 pCodeOp *pic16_newpCodeOpBit(const char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4280 {
4281   pCodeOp *pcop;
4282 
4283   pcop = Safe_alloc(sizeof(pCodeOpRegBit));
4284   pcop->type = PO_GPR_BIT;
4285   pcop->name = (s != NULL) ? Safe_strdup(s) : NULL;
4286   PCORB(pcop)->bit = bit;
4287   PCORB(pcop)->inBitSpace = inBitSpace;
4288   PCORB(pcop)->subtype = subt;
4289 
4290   /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4291   PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4292 //  fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4293 //  PCOR(pcop)->rIdx = 0;
4294   return pcop;
4295 }
4296 
pic16_newpCodeOpBit_simple(struct asmop * op,int offs,int bit)4297 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4298 {
4299   return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4300                                 bit, 0, PO_GPR_REGISTER);
4301 }
4302 
4303 
4304 /*-----------------------------------------------------------------*
4305  * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4306  *
4307  * If rIdx >=0 then a specific register from the set of registers
4308  * will be selected. If rIdx <0, then a new register will be searched
4309  * for.
4310  *-----------------------------------------------------------------*/
4311 
pic16_newpCodeOpReg(int rIdx)4312 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4313 {
4314   pCodeOp *pcop;
4315   reg_info *r;
4316 
4317   pcop = Safe_alloc(sizeof(pCodeOpReg));
4318 
4319   pcop->name = NULL;
4320 
4321   if(rIdx >= 0) {
4322         r = pic16_regWithIdx(rIdx);
4323         if(!r)
4324                 r = pic16_allocWithIdx(rIdx);
4325   } else {
4326     r = pic16_findFreeReg(REG_GPR);
4327 
4328     if(!r) {
4329         fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4330                 __FUNCTION__, __LINE__);
4331         exit(EXIT_FAILURE);
4332     }
4333   }
4334 
4335   PCOR(pcop)->rIdx = rIdx;
4336   PCOR(pcop)->r = r;
4337   pcop->type = PCOR(pcop)->r->pc_type;
4338 
4339   return pcop;
4340 }
4341 
pic16_newpCodeOpRegNotVect(bitVect * bv)4342 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4343 {
4344   pCodeOp *pcop;
4345   reg_info *r;
4346 
4347     pcop = Safe_alloc(sizeof(pCodeOpReg));
4348     pcop->name = NULL;
4349 
4350     r = pic16_findFreeReg(REG_GPR);
4351 
4352     while(r) {
4353       if(!bitVectBitValue(bv, r->rIdx)) {
4354         PCOR(pcop)->r = r;
4355         PCOR(pcop)->rIdx = r->rIdx;
4356         pcop->type = r->pc_type;
4357         return (pcop);
4358       }
4359 
4360       r = pic16_findFreeRegNext(REG_GPR, r);
4361     }
4362 
4363   return NULL;
4364 }
4365 
4366 
4367 
pic16_newpCodeOpRegFromStr(const char * name)4368 pCodeOp *pic16_newpCodeOpRegFromStr(const char *name)
4369 {
4370   pCodeOp *pcop;
4371   reg_info *r;
4372 
4373   pcop = Safe_alloc(sizeof(pCodeOpReg));
4374   PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4375   PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4376   pcop->type = PCOR(pcop)->r->pc_type;
4377   pcop->name = PCOR(pcop)->r->name;
4378 
4379 //      if(pic16_pcode_verbose) {
4380 //              fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4381 //                      __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4382 //      }
4383 
4384   return pcop;
4385 }
4386 
4387 /*-----------------------------------------------------------------*/
4388 /*-----------------------------------------------------------------*/
pic16_newpCodeOpOpt(OPT_TYPE type,const char * key)4389 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, const char *key)
4390 {
4391   pCodeOpOpt *pcop;
4392 
4393   pcop = Safe_alloc(sizeof(pCodeOpOpt));
4394 
4395   pcop->type = type;
4396   pcop->key = Safe_strdup(key);
4397 
4398   return (PCOP(pcop));
4399 }
4400 
4401 /*-----------------------------------------------------------------*/
4402 /*-----------------------------------------------------------------*/
pic16_newpCodeOpLocalRegs(LR_TYPE type)4403 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4404 {
4405   pCodeOpLocalReg *pcop;
4406 
4407   pcop = Safe_alloc(sizeof(pCodeOpLocalReg));
4408 
4409   pcop->type = type;
4410 
4411   return (PCOP(pcop));
4412 }
4413 
4414 
4415 /*-----------------------------------------------------------------*/
4416 /*-----------------------------------------------------------------*/
4417 
pic16_newpCodeOp(const char * name,PIC_OPTYPE type)4418 pCodeOp *pic16_newpCodeOp(const char *name, PIC_OPTYPE type)
4419 {
4420   pCodeOp *pcop;
4421 
4422   switch(type) {
4423   case PO_BIT:
4424   case PO_GPR_BIT:
4425     pcop = pic16_newpCodeOpBit(name, -1,0, type);
4426     break;
4427 
4428   case PO_LITERAL:
4429     pcop = pic16_newpCodeOpLit(-1);
4430     break;
4431 
4432   case PO_LABEL:
4433     pcop = pic16_newpCodeOpLabel(NULL,-1);
4434     break;
4435 
4436   case PO_GPR_TEMP:
4437     pcop = pic16_newpCodeOpReg(-1);
4438     break;
4439 
4440   case PO_GPR_REGISTER:
4441     pcop = (name != NULL) ? pic16_newpCodeOpRegFromStr(name) : pic16_newpCodeOpReg(-1);
4442     break;
4443 
4444   case PO_TWO_OPS:
4445     assert( !"Cannot create PO_TWO_OPS from string!" );
4446     pcop = NULL;
4447     break;
4448 
4449   default:
4450     pcop = Safe_alloc(sizeof(pCodeOp));
4451     pcop->type = type;
4452     pcop->name = (name != NULL) ? Safe_strdup(name) : NULL;
4453   }
4454 
4455   return pcop;
4456 }
4457 
pic16_newpCodeOp2(pCodeOp * src,pCodeOp * dst)4458 pCodeOp *pic16_newpCodeOp2(pCodeOp *src, pCodeOp *dst)
4459 {
4460   pCodeOp2 *pcop2 = Safe_alloc(sizeof(pCodeOp2));
4461   pcop2->pcop.type = PO_TWO_OPS;
4462   pcop2->pcopL = src;
4463   pcop2->pcopR = dst;
4464   return PCOP(pcop2);
4465 }
4466 
4467 /* This is a multiple of two as gpasm pads DB directives to even length,
4468  * thus the data would be interleaved with \0 bytes...
4469  * This is a multiple of three in order to have arrays of 3-byte pointers
4470  * continuously in memory (without 0-padding at the lines' end).
4471  * This is rather 12 than 6 in order not to split up 4-byte data types
4472  * in arrays right in the middle of a 4-byte word. */
4473 #define DB_ITEMS_PER_LINE       12
4474 
4475 typedef struct DBdata
4476   {
4477     int count;
4478     char buffer[512];
4479   } DBdata;
4480 
4481 struct DBdata DBd;
4482 static int DBd_init = -1;
4483 
4484 /*-----------------------------------------------------------------*/
4485 /*    Initialiase "DB" data buffer                                 */
4486 /*-----------------------------------------------------------------*/
pic16_initDB(void)4487 void pic16_initDB(void)
4488 {
4489         DBd_init = -1;
4490 }
4491 
4492 
4493 /*-----------------------------------------------------------------*/
4494 /*    Flush pending "DB" data to a pBlock                          */
4495 /*                                                                 */
4496 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4497 /*-----------------------------------------------------------------*/
pic16_flushDB(char ptype,void * p)4498 void pic16_flushDB(char ptype, void *p)
4499 {
4500         if (DBd.count>0) {
4501                 if(ptype == 'p')
4502                         pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4503                 else
4504                 if(ptype == 'f')
4505                         fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4506                 else {
4507                         /* sanity check */
4508                         fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4509                 }
4510 
4511                 DBd.count = 0;
4512                 DBd.buffer[0] = '\0';
4513         }
4514 }
4515 
4516 
4517 /*-----------------------------------------------------------------*/
4518 /*    Add "DB" directives to a pBlock                              */
4519 /*-----------------------------------------------------------------*/
pic16_emitDB(int c,char ptype,void * p)4520 void pic16_emitDB(int c, char ptype, void *p)
4521 {
4522   size_t l;
4523 
4524         if (DBd_init < 0) {
4525          // we need to initialize
4526                 DBd_init = 0;
4527                 DBd.count = 0;
4528                 DBd.buffer[0] = '\0';
4529         }
4530 
4531         l = strlen(DBd.buffer);
4532 
4533         if (sizeof(DBd.buffer) <= l) {
4534                 fprintf(stderr, "%s() -- Error: Size of DBd.buffer too small. (%zu <= %zu)\n", __func__, sizeof(DBd.buffer), l);
4535                 exit(1);
4536         }
4537 
4538         SNPRINTF(DBd.buffer + l, sizeof(DBd.buffer) - l, "%s0x%02x", ((DBd.count > 0) ? ", " : ""), c & 0xff);
4539 
4540 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4541 
4542         DBd.count++;
4543         if (DBd.count >= DB_ITEMS_PER_LINE)
4544                 pic16_flushDB(ptype, p);
4545 }
4546 
pic16_emitDS(const char * s,char ptype,void * p)4547 void pic16_emitDS(const char *s, char ptype, void *p)
4548 {
4549   size_t l;
4550 
4551         if (DBd_init < 0) {
4552          // we need to initialize
4553                 DBd_init = 0;
4554                 DBd.count = 0;
4555                 DBd.buffer[0] = '\0';
4556         }
4557 
4558         l = strlen(DBd.buffer);
4559 
4560         if (sizeof(DBd.buffer) <= l) {
4561                 fprintf(stderr, "%s() -- Error: Size of DBd.buffer too small. (%zu <= %zu)\n", __func__, sizeof(DBd.buffer), l);
4562                 exit(1);
4563         }
4564 
4565         SNPRINTF(DBd.buffer + l, sizeof(DBd.buffer) - l, "%s%s", ((DBd.count > 0) ? ", " : ""), s);
4566 
4567 //      fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4568 
4569         DBd.count++;    //=strlen(s);
4570         if (DBd.count >= DB_ITEMS_PER_LINE)
4571                 pic16_flushDB(ptype, p);
4572 }
4573 
4574 
4575 /*-----------------------------------------------------------------*/
4576 /*-----------------------------------------------------------------*/
pic16_pCodeConstString(const char * name,const char * value,unsigned length)4577 void pic16_pCodeConstString(const char *name, const char *value, unsigned length)
4578 {
4579   pBlock *pb;
4580   char *item;
4581   static set *emittedSymbols = NULL;
4582 
4583   if(!name || !value)
4584     return;
4585 
4586   /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4587   if (emittedSymbols) {
4588     /* scan set for name */
4589     for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4590     {
4591       if (!strcmp (item,name)) {
4592         //fprintf (stderr, "%s already emitted\n", name);
4593         return;
4594       } // if
4595     } // for
4596   } // if
4597   addSet (&emittedSymbols, Safe_strdup (name));
4598 
4599   //fprintf(stderr, " %s  %s  %s\n",__FUNCTION__,name,value);
4600 
4601   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4602 
4603   pic16_addpBlock(pb);
4604 
4605 //  SNPRINTF(buffer, sizeof(buffer), "; %s = %s", name, value);
4606 //  fputs(buffer, stderr);
4607 
4608 //  pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4609   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4610 
4611   while (length--)
4612     pic16_emitDB(*value++, 'p', (void *)pb);
4613 
4614   pic16_flushDB('p', (void *)pb);
4615 }
4616 
4617 /*-----------------------------------------------------------------*/
4618 /*-----------------------------------------------------------------*/
4619 #if 0
4620 static void pCodeReadCodeTable(void)
4621 {
4622   pBlock *pb;
4623 
4624   fprintf(stderr, " %s\n",__FUNCTION__);
4625 
4626   pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4627 
4628   pic16_addpBlock(pb);
4629 
4630   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4631   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4632   pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4633   pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4634 
4635   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4636   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4637   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4638   pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4639 
4640 
4641 }
4642 #endif
4643 /*-----------------------------------------------------------------*/
4644 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list   */
4645 /*-----------------------------------------------------------------*/
pic16_addpCode2pBlock(pBlock * pb,pCode * pc)4646 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4647 {
4648   if(!pc)
4649     return;
4650 
4651   if(!pb->pcHead) {
4652     /* If this is the first pcode to be added to a block that
4653      * was initialized with a NULL pcode, then go ahead and
4654      * make this pcode the head and tail */
4655     pb->pcHead  = pb->pcTail = pc;
4656   } else {
4657     //    if(pb->pcTail)
4658     pb->pcTail->next = pc;
4659 
4660     pc->prev = pb->pcTail;
4661     pc->pb = pb;
4662 
4663     pb->pcTail = pc;
4664   }
4665 }
4666 
4667 /*-----------------------------------------------------------------*/
4668 /* pic16_addpBlock - place a pBlock into the pFile                 */
4669 /*-----------------------------------------------------------------*/
pic16_addpBlock(pBlock * pb)4670 void pic16_addpBlock(pBlock *pb)
4671 {
4672   // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4673 
4674   if(!the_pFile) {
4675     /* First time called, we'll pass through here. */
4676     //_ALLOC(the_pFile,sizeof(pFile));
4677     the_pFile = Safe_alloc(sizeof(pFile));
4678     the_pFile->pbHead = the_pFile->pbTail = pb;
4679     the_pFile->functions = NULL;
4680     return;
4681   }
4682 
4683   the_pFile->pbTail->next = pb;
4684   pb->prev = the_pFile->pbTail;
4685   pb->next = NULL;
4686   the_pFile->pbTail = pb;
4687 }
4688 
4689 /*-----------------------------------------------------------------*/
4690 /* removepBlock - remove a pBlock from the pFile                   */
4691 /*-----------------------------------------------------------------*/
removepBlock(pBlock * pb)4692 static void removepBlock(pBlock *pb)
4693 {
4694   pBlock *pbs;
4695 
4696   if(!the_pFile)
4697     return;
4698 
4699   //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4700 
4701   for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4702     if(pbs == pb) {
4703 
4704       if(pbs == the_pFile->pbHead)
4705         the_pFile->pbHead = pbs->next;
4706 
4707       if (pbs == the_pFile->pbTail)
4708         the_pFile->pbTail = pbs->prev;
4709 
4710       if(pbs->next)
4711         pbs->next->prev = pbs->prev;
4712 
4713       if(pbs->prev)
4714         pbs->prev->next = pbs->next;
4715 
4716       return;
4717 
4718     }
4719   }
4720 
4721   fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4722 }
4723 
4724 /*-----------------------------------------------------------------*/
4725 /* printpCode - write the contents of a pCode to a file            */
4726 /*-----------------------------------------------------------------*/
printpCode(FILE * of,pCode * pc)4727 static void printpCode(FILE *of, pCode *pc)
4728 {
4729   if(!pc || !of)
4730     return;
4731 
4732   if(pc->print) {
4733     pc->print(of,pc);
4734     return;
4735   }
4736 
4737   fprintf(of,"warning - unable to print pCode\n");
4738 }
4739 
4740 /*-----------------------------------------------------------------*/
4741 /* pic16_printpBlock - write the contents of a pBlock to a file    */
4742 /*-----------------------------------------------------------------*/
pic16_printpBlock(FILE * of,pBlock * pb)4743 void pic16_printpBlock(FILE *of, pBlock *pb)
4744 {
4745   pCode *pc;
4746 
4747         if(!pb)return;
4748 
4749         if(!of)of=stderr;
4750 
4751         for(pc = pb->pcHead; pc; pc = pc->next) {
4752                 if(isPCF(pc) && PCF(pc)->fname) {
4753                         fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4754                         if(pb->dbName == 'A') {
4755                           absSym *ab;
4756                                 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4757 //                                      fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4758                                         if(!strcmp(ab->name, PCF(pc)->fname)) {
4759 //                                              fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4760                                                 if(ab->address != -1)
4761                                                   fprintf(of, "\t0X%06X", ab->address);
4762                                                 break;
4763                                         }
4764                                 }
4765                         }
4766                         fprintf(of, "\n");
4767                 }
4768                 printpCode(of,pc);
4769         }
4770 }
4771 
4772 /*-----------------------------------------------------------------*/
4773 /*                                                                 */
4774 /*       pCode processing                                          */
4775 /*                                                                 */
4776 /*                                                                 */
4777 /*                                                                 */
4778 /*-----------------------------------------------------------------*/
4779 pCode * pic16_findNextInstruction(pCode *pci);
4780 pCode * pic16_findPrevInstruction(pCode *pci);
4781 
pic16_unlinkpCode(pCode * pc)4782 void pic16_unlinkpCode(pCode *pc)
4783 {
4784   pCode *prev;
4785 
4786   if(pc) {
4787 #ifdef PCODE_DEBUG
4788     fprintf(stderr,"Unlinking: ");
4789     printpCode(stderr, pc);
4790 #endif
4791     if(pc->prev) {
4792       pc->prev->next = pc->next;
4793     } else if (pc->pb && (pc->pb->pcHead == pc)) {
4794         pc->pb->pcHead = pc->next;
4795     }
4796     if(pc->next) {
4797       pc->next->prev = pc->prev;
4798     } else if (pc->pb && (pc->pb->pcTail == pc)) {
4799         pc->pb->pcTail = pc->prev;
4800     }
4801 
4802     /* move C source line down (or up) */
4803     if (isPCI(pc) && PCI(pc)->cline) {
4804       prev = pic16_findNextInstruction (pc->next);
4805       if (prev && isPCI(prev) && !PCI(prev)->cline) {
4806         PCI(prev)->cline = PCI(pc)->cline;
4807       } else {
4808         prev = pic16_findPrevInstruction (pc->prev);
4809         if (prev && isPCI(prev) && !PCI(prev)->cline)
4810           PCI(prev)->cline = PCI(pc)->cline;
4811       }
4812     }
4813     pc->prev = pc->next = NULL;
4814   }
4815 }
4816 
4817 /*-----------------------------------------------------------------*/
4818 /*-----------------------------------------------------------------*/
4819 
genericDestruct(pCode * pc)4820 static void genericDestruct(pCode *pc)
4821 {
4822   pic16_unlinkpCode(pc);
4823 
4824   if(isPCI(pc)) {
4825     /* For instructions, tell the register (if there's one used)
4826      * that it's no longer needed */
4827     reg_info *reg = pic16_getRegFromInstruction(pc);
4828     if(reg)
4829       deleteSetItem (&(reg->reglives.usedpCodes),pc);
4830 
4831         if(PCI(pc)->is2MemOp) {
4832                 reg = pic16_getRegFromInstruction2(pc);
4833                 if(reg)
4834                         deleteSetItem(&(reg->reglives.usedpCodes), pc);
4835         }
4836   }
4837 
4838   /* Instead of deleting the memory used by this pCode, mark
4839    * the object as bad so that if there's a pointer to this pCode
4840    * dangling around somewhere then (hopefully) when the type is
4841    * checked we'll catch it.
4842    */
4843 
4844   pc->type = PC_BAD;
4845   pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4846 
4847   //Safe_free(pc);
4848 }
4849 
4850 
4851 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4852 /*-----------------------------------------------------------------*/
4853 /*-----------------------------------------------------------------*/
4854 /* modifiers for constant immediate */
4855 
4856 static const char *immdmod[3] = {"LOW", "HIGH", "UPPER"};
4857 
pic16_get_op(pCodeOp * pcop,char * buffer,size_t size)4858 char *pic16_get_op(pCodeOp *pcop, char *buffer, size_t size)
4859 {
4860     reg_info *r;
4861     static char b[128];
4862     char *s;
4863     int use_buffer = 1;    // copy the string to the passed buffer pointer
4864 
4865     if(!buffer) {
4866         buffer = b;
4867         size = sizeof(b);
4868         use_buffer = 0;     // Don't bother copying the string to the buffer.
4869     }
4870 
4871     if(pcop) {
4872 
4873         switch(pcop->type) {
4874             case PO_W:
4875             case PO_WREG:
4876             case PO_PRODL:
4877             case PO_PRODH:
4878             case PO_INDF0:
4879             case PO_FSR0:
4880                 if(use_buffer) {
4881                     SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
4882                     return (buffer);
4883                 }
4884                 return (PCOR(pcop)->r->name);
4885                 break;
4886             case PO_GPR_TEMP:
4887                 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4888                 if(use_buffer) {
4889                     SNPRINTF(buffer,size,"%s",r->name);
4890                     return (buffer);
4891                 }
4892                 return (r->name);
4893                 break;
4894 
4895             case PO_IMMEDIATE:
4896                 s = buffer;
4897                 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4898                     if(PCOI(pcop)->index) {
4899                         SNPRINTF(s,size, "%s(%s + %d)",
4900                                 immdmod[ PCOI(pcop)->offset ],
4901                                 pcop->name,
4902                                 PCOI(pcop)->index);
4903                     } else {
4904                         SNPRINTF(s,size,"%s(%s)",
4905                                 immdmod[ PCOI(pcop)->offset ],
4906                                 pcop->name);
4907                     }
4908                 } else {
4909                     if(PCOI(pcop)->index) {
4910                         SNPRINTF(s,size, "%s(%s + %d)",
4911                                 immdmod[ 0 ],
4912                                 pcop->name,
4913                                 PCOI(pcop)->index);
4914                     } else {
4915                         SNPRINTF(s,size, "%s(%s)",
4916                                 immdmod[ 0 ],
4917                                 pcop->name);
4918                     }
4919                 }
4920                 return (buffer);
4921                 break;
4922 
4923             case PO_GPR_REGISTER:
4924             case PO_DIR:
4925                 s = buffer;
4926                 //size = sizeof(buffer);
4927                 if( PCOR(pcop)->instance) {
4928                     SNPRINTF(s,size,"(%s + %d)",
4929                             pcop->name,
4930                             PCOR(pcop)->instance );
4931                 } else {
4932                     SNPRINTF(s,size,"%s",pcop->name);
4933                 }
4934                 return (buffer);
4935                 break;
4936 
4937             case PO_GPR_BIT:
4938                 s = buffer;
4939                 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4940                     SNPRINTF(s, size, "%s", pcop->name);
4941                 } else {
4942                     if(PCORB(pcop)->pcor.instance)
4943                         SNPRINTF(s, size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4944                     else
4945                         SNPRINTF(s, size, "%s", pcop->name);
4946                 }
4947                 return (buffer);
4948                 break;
4949 
4950             case PO_TWO_OPS:
4951                 return (pic16_get_op( PCOP2(pcop)->pcopL, use_buffer ? buffer : NULL, size ));
4952                 break;
4953 
4954             default:
4955                 if(pcop->name) {
4956                     if(use_buffer) {
4957                         SNPRINTF(buffer,size,"%s",pcop->name);
4958                         return (buffer);
4959                     }
4960                     return (pcop->name);
4961                 }
4962 
4963         }
4964         return ("unhandled type for op1");
4965     }
4966 
4967     return ("NO operand1");
4968 }
4969 
4970 /*-----------------------------------------------------------------*/
4971 /* pic16_get_op2 - variant to support two memory operand commands  */
4972 /*-----------------------------------------------------------------*/
pic16_get_op2(pCodeOp * pcop,char * buffer,size_t size)4973 char *pic16_get_op2(pCodeOp *pcop, char *buffer, size_t size)
4974 {
4975   if(pcop && pcop->type == PO_TWO_OPS) {
4976     return pic16_get_op(PCOP2(pcop)->pcopR, buffer, size);
4977   }
4978 
4979   return "NO operand2";
4980 }
4981 
4982 /*-----------------------------------------------------------------*/
4983 /*-----------------------------------------------------------------*/
pic16_get_op_from_instruction(pCodeInstruction * pcc)4984 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4985 {
4986   if(pcc)
4987     return pic16_get_op(pcc->pcop,NULL,0);
4988 
4989   /* gcc 3.2:  warning: concatenation of string literals with __FUNCTION__ is deprecated
4990    *   return ("ERROR Null: "__FUNCTION__);
4991    */
4992   return ("ERROR Null: pic16_get_op_from_instruction");
4993 }
4994 
4995 /*-----------------------------------------------------------------*/
4996 /*-----------------------------------------------------------------*/
pCodeOpPrint(FILE * of,pCodeOp * pcop)4997 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4998 {
4999   fprintf(of,"pcodeopprint- not implemented\n");
5000 }
5001 
5002 /*-----------------------------------------------------------------*/
5003 /* pic16_pCode2str - convert a pCode instruction to string               */
5004 /*-----------------------------------------------------------------*/
pic16_pCode2str(char * str,size_t size,pCode * pc)5005 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
5006 {
5007     char *s = str;
5008     reg_info *r;
5009     size_t len;
5010 
5011 #if 0
5012     if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
5013         fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
5014                 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
5015         //              exit(EXIT_FAILURE);
5016     }
5017 #endif
5018 
5019     switch(pc->type) {
5020 
5021         case PC_OPCODE:
5022             SNPRINTF(s, size, "\t%s\t", PCI(pc)->mnemonic);
5023             len = strlen(s);
5024             size -= len;
5025             s += len;
5026 
5027             if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
5028 
5029                 if (PCI(pc)->pcop->type == PO_TWO_OPS)
5030                 {
5031                     /* split into two phases due to static buffer in pic16_get_op() */
5032                     SNPRINTF(s, size, "%s", pic16_get_op((PCI(pc)->pcop), NULL, 0));
5033                     len = strlen(s);
5034                     size -= len;
5035                     s += len;
5036                     SNPRINTF(s, size, ", %s", pic16_get_op2((PCI(pc)->pcop), NULL, 0));
5037                     break;
5038                 }
5039 
5040                 if(PCI(pc)->is2LitOp) {
5041                     SNPRINTF(s,size, "%s", PCOP(PCI(pc)->pcop)->name);
5042                     break;
5043                 }
5044 
5045                 if(PCI(pc)->isBitInst) {
5046                     if(PCI(pc)->pcop->type != PO_GPR_BIT) {
5047                         if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
5048                             SNPRINTF(s,size,"(%s >> 3), (%s & 7)", PCI(pc)->pcop->name, PCI(pc)->pcop->name);
5049                         else
5050                             SNPRINTF(s,size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5051                                     (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit));
5052 
5053                     } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5054                         SNPRINTF(s,size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5055                     } else
5056                         SNPRINTF(s,size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5057                 } else {
5058 
5059                     if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5060                         if(PCI(pc)->num_ops == 3)
5061                             SNPRINTF(s,size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5062                         else
5063                             SNPRINTF(s,size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5064                     } else {
5065                         SNPRINTF(s,size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5066                     }
5067                 }
5068 
5069                 if(PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5070                     len = strlen(s);
5071                     size -= len;
5072                     s += len;
5073                     if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst) {
5074                         SNPRINTF(s,size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5075                         len = strlen(s);
5076                         size -= len;
5077                         s += len;
5078                     }
5079 
5080                     r = pic16_getRegFromInstruction(pc);
5081 
5082                     if(PCI(pc)->isAccess) {
5083                         static char *bank_spec[2][2] = {
5084                             { "", ", ACCESS" },  /* gpasm uses access bank by default */
5085                             { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5086                         };
5087 
5088                         SNPRINTF(s,size,"%s", bank_spec[(r && !isACCESS_BANK(r)) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5089                     }
5090                 }
5091             }
5092             break;
5093 
5094         case PC_COMMENT:
5095             /* assuming that comment ends with a \n */
5096             SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
5097             break;
5098 
5099         case PC_INFO:
5100             SNPRINTF(s,size,"; info ==>");
5101             len = strlen(s);
5102             size -= len;
5103             s += len;
5104             switch( PCINF(pc)->type ) {
5105                 case INF_OPTIMIZATION:
5106                     SNPRINTF(s,size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5107                     break;
5108                 case INF_LOCALREGS:
5109                     SNPRINTF(s,size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5110                     break;
5111             }; break;
5112 
5113         case PC_INLINE:
5114             /* assuming that inline code ends with a \n */
5115             SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
5116             break;
5117 
5118         case PC_LABEL:
5119             SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5120             break;
5121         case PC_FUNCTION:
5122             SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5123             break;
5124         case PC_WILD:
5125             SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5126             break;
5127         case PC_FLOW:
5128             SNPRINTF(s,size,";\t--FLOW change.\n");
5129             break;
5130         case PC_CSOURCE:
5131             SNPRINTF(s,size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5132                     PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5133             break;
5134         case PC_ASMDIR:
5135             if(PCAD(pc)->directive) {
5136                 SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5137             } else
5138                 if(PCAD(pc)->arg) {
5139                     /* special case to handle inline labels without a tab */
5140                     SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
5141                 }
5142             break;
5143 
5144         case PC_BAD:
5145             SNPRINTF(s,size,";A bad pCode is being used.\n");
5146             break;
5147     }
5148 
5149     return str;
5150 }
5151 
5152 /*-----------------------------------------------------------------*/
5153 /* genericPrint - the contents of a pCode to a file                */
5154 /*-----------------------------------------------------------------*/
genericPrint(FILE * of,pCode * pc)5155 static void genericPrint(FILE *of, pCode *pc)
5156 {
5157   if(!pc || !of)
5158     return;
5159 
5160   switch(pc->type) {
5161   case PC_COMMENT:
5162 //    fputs(((pCodeComment *)pc)->comment, of);
5163     fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5164     break;
5165 
5166   case PC_INFO:
5167     {
5168       pBranch *pbl = PCI(pc)->label;
5169       while(pbl && pbl->pc) {
5170         if(pbl->pc->type == PC_LABEL)
5171           pCodePrintLabel(of, pbl->pc);
5172         pbl = pbl->next;
5173       }
5174     }
5175 
5176     if(pic16_pcode_verbose) {
5177       fprintf(of, "; info ==>");
5178       switch(((pCodeInfo *)pc)->type) {
5179         case INF_OPTIMIZATION:
5180               fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5181               break;
5182         case INF_LOCALREGS:
5183               fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5184               break;
5185         }
5186     }
5187 
5188     break;
5189 
5190   case PC_INLINE:
5191     fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5192     break;
5193 
5194   case PC_OPCODE:
5195     // If the opcode has a label, print that first
5196     {
5197       pBranch *pbl = PCI(pc)->label;
5198       while(pbl && pbl->pc) {
5199         if(pbl->pc->type == PC_LABEL)
5200           pCodePrintLabel(of, pbl->pc);
5201         pbl = pbl->next;
5202       }
5203     }
5204 
5205     if(PCI(pc)->cline)
5206       genericPrint(of,PCODE(PCI(pc)->cline));
5207 
5208     {
5209       char str[256];
5210 
5211       pic16_pCode2str(str, sizeof(str), pc);
5212 
5213       fprintf(of,"%s",str);
5214       /* Debug */
5215       if(pic16_debug_verbose) {
5216         fprintf(of, "\t;key=%03x",pc->seq);
5217         if(PCI(pc)->pcflow)
5218           fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5219       }
5220     }
5221     fprintf(of, "\n");
5222     break;
5223 
5224   case PC_WILD:
5225     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5226     if(PCW(pc)->pci.label)
5227       pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5228 
5229     if(PCW(pc)->operand) {
5230       fprintf(of,";\toperand  ");
5231       pCodeOpPrint(of,PCW(pc)->operand );
5232     }
5233     break;
5234 
5235   case PC_FLOW:
5236     if(pic16_debug_verbose) {
5237       fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5238       if(PCFL(pc)->ancestor)
5239         fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5240       fprintf(of,"\n");
5241 
5242     }
5243     break;
5244 
5245   case PC_CSOURCE:
5246 //    fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5247     fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5248         PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5249 
5250     break;
5251 
5252   case PC_ASMDIR:
5253         {
5254           pBranch *pbl = PCAD(pc)->pci.label;
5255                 while(pbl && pbl->pc) {
5256                         if(pbl->pc->type == PC_LABEL)
5257                                 pCodePrintLabel(of, pbl->pc);
5258                         pbl = pbl->next;
5259                 }
5260         }
5261         if(PCAD(pc)->directive) {
5262                 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5263         } else
5264         if(PCAD(pc)->arg) {
5265                 /* special case to handle inline labels without tab */
5266                 fprintf(of, "%s\n", PCAD(pc)->arg);
5267         }
5268         break;
5269 
5270   case PC_LABEL:
5271   default:
5272     fprintf(of,"unknown pCode type %d\n",pc->type);
5273   }
5274 }
5275 
5276 /*-----------------------------------------------------------------*/
5277 /* pCodePrintFunction - prints function begin/end                  */
5278 /*-----------------------------------------------------------------*/
5279 
pCodePrintFunction(FILE * of,pCode * pc)5280 static void pCodePrintFunction(FILE *of, pCode *pc)
5281 {
5282   if(!pc || !of)
5283     return;
5284 
5285 #if 0
5286   if( ((pCodeFunction *)pc)->modname)
5287     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5288 #endif
5289 
5290   if(!PCF(pc)->absblock) {
5291       if(PCF(pc)->fname) {
5292       pBranch *exits = PCF(pc)->to;
5293       int i=0;
5294 
5295       fprintf(of,"%s:", PCF(pc)->fname);
5296 
5297       if(pic16_pcode_verbose)
5298         fprintf(of, "\t;Function start.");
5299 
5300       fprintf(of, "\n");
5301 
5302       while(exits) {
5303         i++;
5304         exits = exits->next;
5305       }
5306       //if(i) i--;
5307 
5308       if(pic16_pcode_verbose)
5309         fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5310 
5311     } else {
5312         if((PCF(pc)->from &&
5313                 PCF(pc)->from->pc->type == PC_FUNCTION &&
5314                 PCF(PCF(pc)->from->pc)->fname) ) {
5315 
5316                 if(pic16_pcode_verbose)
5317                         fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5318         } else {
5319                 if(pic16_pcode_verbose)
5320                         fprintf(of,"; exit point [can't find entry point]\n");
5321         }
5322         fprintf(of, "\n");
5323     }
5324   }
5325 }
5326 /*-----------------------------------------------------------------*/
5327 /* pCodePrintLabel - prints label                                  */
5328 /*-----------------------------------------------------------------*/
5329 
pCodePrintLabel(FILE * of,pCode * pc)5330 static void pCodePrintLabel(FILE *of, pCode *pc)
5331 {
5332   if(!pc || !of)
5333     return;
5334 
5335   if(PCL(pc)->label)
5336     fprintf(of,"%s:\n",PCL(pc)->label);
5337   else if (PCL(pc)->key >=0)
5338     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5339   else
5340     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5341 
5342 }
5343 /*-----------------------------------------------------------------*/
5344 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
5345 /*                         remove it if it is found.               */
5346 /*-----------------------------------------------------------------*/
unlinkpCodeFromBranch(pCode * pcl,pCode * pc)5347 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5348 {
5349   pBranch *b, *bprev;
5350 
5351   bprev = NULL;
5352 
5353   if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5354     b = PCI(pcl)->label;
5355   else {
5356     fprintf(stderr, "LINE %d. can't unlink from non opcode.\n",__LINE__);
5357     exit(1);
5358   }
5359 
5360   //fprintf (stderr, "%s \n",__FUNCTION__);
5361   //pcl->print(stderr,pcl);
5362   //pc->print(stderr,pc);
5363   while(b) {
5364     if(b->pc == pc) {
5365       //fprintf (stderr, "found label\n");
5366       //pc->print(stderr, pc);
5367 
5368       /* Found a label */
5369       if(bprev) {
5370         bprev->next = b->next;  /* Not first pCode in chain */
5371 //      Safe_free(b);
5372       } else {
5373         pc->destruct(pc);
5374         PCI(pcl)->label = b->next;   /* First pCode in chain */
5375 //      Safe_free(b);
5376       }
5377       return;  /* A label can't occur more than once */
5378     }
5379     bprev = b;
5380     b = b->next;
5381   }
5382 }
5383 
5384 /*-----------------------------------------------------------------*/
5385 /*-----------------------------------------------------------------*/
pic16_pBranchAppend(pBranch * h,pBranch * n)5386 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5387 {
5388   pBranch *b;
5389 
5390   if(!h)
5391     return n;
5392 
5393   if(h == n)
5394     return n;
5395 
5396   b = h;
5397   while(b->next)
5398     b = b->next;
5399 
5400   b->next = n;
5401 
5402   return h;
5403 }
5404 
5405 /*-----------------------------------------------------------------*/
5406 /* pBranchLink - given two pcodes, this function will link them    */
5407 /*               together through their pBranches                  */
5408 /*-----------------------------------------------------------------*/
pBranchLink(pCodeFunction * f,pCodeFunction * t)5409 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5410 {
5411   pBranch *b;
5412 
5413   // Declare a new branch object for the 'from' pCode.
5414 
5415   //_ALLOC(b,sizeof(pBranch));
5416   b = Safe_alloc(sizeof(pBranch));
5417   b->pc = PCODE(t);             // The link to the 'to' pCode.
5418   b->next = NULL;
5419 
5420   f->to = pic16_pBranchAppend(f->to,b);
5421 
5422   // Now do the same for the 'to' pCode.
5423 
5424   //_ALLOC(b,sizeof(pBranch));
5425   b = Safe_alloc(sizeof(pBranch));
5426   b->pc = PCODE(f);
5427   b->next = NULL;
5428 
5429   t->from = pic16_pBranchAppend(t->from,b);
5430 }
5431 
5432 #if 1
5433 /*-----------------------------------------------------------------*/
5434 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5435 /*               a pCode                                           */
5436 /*-----------------------------------------------------------------*/
pBranchFind(pBranch * pb,pCode * pc)5437 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5438 {
5439   while(pb) {
5440 
5441     if(pb->pc == pc)
5442       return pb;
5443 
5444     pb = pb->next;
5445   }
5446 
5447   return NULL;
5448 }
5449 
5450 /*-----------------------------------------------------------------*/
5451 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain.      */
5452 /*-----------------------------------------------------------------*/
pic16_pCodeUnlink(pCode * pc)5453 void pic16_pCodeUnlink(pCode *pc)
5454 {
5455   pBranch *pb1,*pb2;
5456   pCode *pc1;
5457 
5458   if (!pc) {
5459     return;
5460   }
5461 
5462   /* Remove the branches */
5463 
5464   pb1 = PCI(pc)->from;
5465   while(pb1) {
5466     pc1 = pb1->pc;    /* Get the pCode that branches to the
5467                        * one we're unlinking */
5468 
5469     /* search for the link back to this pCode (the one we're
5470      * unlinking) */
5471     if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5472       pb2->pc = PCI(pc)->to->pc;  // make the replacement
5473 
5474       /* if the pCode we're unlinking contains multiple 'to'
5475        * branches (e.g. this a skip instruction) then we need
5476        * to copy these extra branches to the chain. */
5477       if(PCI(pc)->to->next)
5478         pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5479     }
5480 
5481     pb1 = pb1->next;
5482   }
5483 
5484   pic16_unlinkpCode (pc);
5485 }
5486 #endif
5487 /*-----------------------------------------------------------------*/
5488 /*-----------------------------------------------------------------*/
5489 #if 0
5490 static void genericAnalyze(pCode *pc)
5491 {
5492   switch(pc->type) {
5493   case PC_WILD:
5494   case PC_COMMENT:
5495     return;
5496   case PC_LABEL:
5497   case PC_FUNCTION:
5498   case PC_OPCODE:
5499     {
5500       // Go through the pCodes that are in pCode chain and link
5501       // them together through the pBranches. Note, the pCodes
5502       // are linked together as a contiguous stream like the
5503       // assembly source code lines. The linking here mimics this
5504       // except that comments are not linked in.
5505       //
5506       pCode *npc = pc->next;
5507       while(npc) {
5508         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5509           pBranchLink(pc,npc);
5510           return;
5511         } else
5512           npc = npc->next;
5513       }
5514       /* reached the end of the pcode chain without finding
5515        * an instruction we could link to. */
5516     }
5517     break;
5518   case PC_FLOW:
5519     fprintf(stderr,"analyze PC_FLOW\n");
5520 
5521     return;
5522   case PC_BAD:
5523     fprintf(stderr,,";A bad pCode is being used\n");
5524 
5525   }
5526 }
5527 #endif
5528 
5529 /*-----------------------------------------------------------------*/
5530 /*-----------------------------------------------------------------*/
compareLabel(const pCode * pc,const pCodeOpLabel * pcop_label)5531 static int compareLabel(const pCode *pc, const pCodeOpLabel *pcop_label)
5532 {
5533   pBranch *pbr;
5534 
5535   if(pc->type == PC_LABEL) {
5536     if(((pCodeLabel *)pc)->key == pcop_label->key)
5537       return TRUE;
5538   }
5539 
5540   if((pc->type == PC_OPCODE) || (pc->type == PC_ASMDIR)) {
5541     pbr = PCI(pc)->label;
5542     while(pbr) {
5543       if(pbr->pc->type == PC_LABEL) {
5544         if(((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5545           return TRUE;
5546       }
5547       pbr = pbr->next;
5548     }
5549   }
5550 
5551   return FALSE;
5552 }
5553 
5554 /*-----------------------------------------------------------------*/
5555 /*-----------------------------------------------------------------*/
checkLabel(const pCode * pc)5556 static int checkLabel(const pCode *pc)
5557 {
5558   pBranch *pbr;
5559 
5560   if(pc && isPCI(pc)) {
5561     pbr = PCI(pc)->label;
5562     while(pbr) {
5563       if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5564         return TRUE;
5565 
5566       pbr = pbr->next;
5567     }
5568   }
5569 
5570   return FALSE;
5571 }
5572 
5573 /*-----------------------------------------------------------------*/
5574 /* findLabelinpBlock - Search the pCode for a particular label     */
5575 /*-----------------------------------------------------------------*/
findLabelinpBlock(pBlock * pb,const pCodeOpLabel * pcop_label)5576 static pCode *findLabelinpBlock(pBlock *pb, const pCodeOpLabel *pcop_label)
5577 {
5578   pCode *pc;
5579 
5580   if(!pb)
5581     return NULL;
5582 
5583   for(pc = pb->pcHead; pc; pc = pc->next)
5584     if(compareLabel(pc,pcop_label))
5585       return pc;
5586 
5587   return NULL;
5588 }
5589 #if 0
5590 /*-----------------------------------------------------------------*/
5591 /* findLabel - Search the pCode for a particular label             */
5592 /*-----------------------------------------------------------------*/
5593 static pCode *findLabel(const pCodeOpLabel *pcop_label)
5594 {
5595   pBlock *pb;
5596   pCode  *pc;
5597 
5598   if(!the_pFile)
5599     return NULL;
5600 
5601   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5602     if((pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5603       return pc;
5604   }
5605 
5606   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5607   return NULL;
5608 }
5609 #endif
5610 /*-----------------------------------------------------------------*/
5611 /* pic16_findNextpCode - given a pCode, find the next of type 'pct'      */
5612 /*                 in the linked list                              */
5613 /*-----------------------------------------------------------------*/
pic16_findNextpCode(pCode * pc,PC_TYPE pct)5614 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5615 {
5616 
5617   while(pc) {
5618     if(pc->type == pct)
5619       return pc;
5620 
5621     pc = pc->next;
5622   }
5623 
5624   return NULL;
5625 }
5626 
5627 /*-----------------------------------------------------------------*/
5628 /* findPrevpCode - given a pCode, find the previous of type 'pct'  */
5629 /*                 in the linked list                              */
5630 /*-----------------------------------------------------------------*/
findPrevpCode(pCode * pc,PC_TYPE pct)5631 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5632 {
5633 
5634   while(pc) {
5635     if(pc->type == pct)
5636       return pc;
5637 
5638     pc = pc->prev;
5639   }
5640 
5641   return NULL;
5642 }
5643 
5644 
5645 //#define PCODE_DEBUG
5646 /*-----------------------------------------------------------------*/
5647 /* pic16_findNextInstruction - given a pCode, find the next instruction  */
5648 /*                       in the linked list                        */
5649 /*-----------------------------------------------------------------*/
pic16_findNextInstruction(pCode * pci)5650 pCode * pic16_findNextInstruction(pCode *pci)
5651 {
5652   pCode *pc = pci;
5653 
5654   while(pc) {
5655     if((pc->type == PC_OPCODE)
5656         || (pc->type == PC_WILD)
5657         || (pc->type == PC_ASMDIR)
5658         )
5659       return pc;
5660 
5661 #ifdef PCODE_DEBUG
5662     fprintf(stderr,"pic16_findNextInstruction:  ");
5663     printpCode(stderr, pc);
5664 #endif
5665     pc = pc->next;
5666   }
5667 
5668   //fprintf(stderr,"Couldn't find instruction\n");
5669   return NULL;
5670 }
5671 
5672 /*-----------------------------------------------------------------*/
5673 /* pic16_findPrevInstruction - given a pCode, find the next instruction  */
5674 /*                       in the linked list                        */
5675 /*-----------------------------------------------------------------*/
pic16_findPrevInstruction(pCode * pci)5676 pCode * pic16_findPrevInstruction(pCode *pci)
5677 {
5678   pCode *pc = pci;
5679 
5680   while(pc) {
5681 
5682     if((pc->type == PC_OPCODE) || (pc->type == PC_WILD) || (pc->type == PC_ASMDIR))
5683       return pc;
5684 
5685 #ifdef PCODE_DEBUG
5686     fprintf(stderr,"pic16_findPrevInstruction:  ");
5687     printpCode(stderr, pc);
5688 #endif
5689     pc = pc->prev;
5690   }
5691 
5692   //fprintf(stderr,"Couldn't find instruction\n");
5693   return NULL;
5694 }
5695 
5696 #undef PCODE_DEBUG
5697 
5698 #if 0
5699 /*-----------------------------------------------------------------*/
5700 /* findFunctionEnd - given a pCode find the end of the function    */
5701 /*                   that contains it                              */
5702 /*-----------------------------------------------------------------*/
5703 static pCode * findFunctionEnd(pCode *pc)
5704 {
5705   while(pc) {
5706     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
5707       return pc;
5708 
5709     pc = pc->next;
5710   }
5711 
5712   fprintf(stderr,"Couldn't find function end\n");
5713   return NULL;
5714 }
5715 #endif
5716 #if 0
5717 /*-----------------------------------------------------------------*/
5718 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
5719 /*                instruction with which it is associated.         */
5720 /*-----------------------------------------------------------------*/
5721 static void AnalyzeLabel(pCode *pc)
5722 {
5723   pic16_pCodeUnlink(pc);
5724 }
5725 #endif
5726 
5727 #if 0
5728 static void AnalyzeGOTO(pCode *pc)
5729 {
5730   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5731 }
5732 
5733 static void AnalyzeSKIP(pCode *pc)
5734 {
5735   pBranchLink(pc,pic16_findNextInstruction(pc->next));
5736   pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5737 }
5738 
5739 static void AnalyzeRETURN(pCode *pc)
5740 {
5741   //  branch_link(pc,findFunctionEnd(pc->next));
5742 }
5743 
5744 #endif
5745 
5746 /*-------------------------------------------------------------------*/
5747 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp     */
5748 /*                            if one is present. This is the common  */
5749 /*                            part of pic16_getRegFromInstruction(2) */
5750 /*-------------------------------------------------------------------*/
5751 
pic16_getRegFrompCodeOp(pCodeOp * pcop)5752 reg_info * pic16_getRegFrompCodeOp (pCodeOp *pcop)
5753 {
5754   if (!pcop) return NULL;
5755 
5756   switch(pcop->type) {
5757   case PO_PRODL:
5758   case PO_PRODH:
5759   case PO_INDF0:
5760   case PO_FSR0:
5761   case PO_W:
5762   case PO_WREG:
5763   case PO_STATUS:
5764   case PO_INTCON:
5765   case PO_PCL:
5766   case PO_PCLATH:
5767   case PO_PCLATU:
5768   case PO_BSR:
5769     return PCOR(pcop)->r;
5770 
5771   case PO_SFR_REGISTER:
5772     //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5773     return PCOR(pcop)->r;
5774 
5775   case PO_BIT:
5776   case PO_GPR_TEMP:
5777 //      fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5778     return PCOR(pcop)->r;
5779 
5780   case PO_IMMEDIATE:
5781 //    return pic16_dirregWithName(PCOI(pcop)->r->name);
5782 /*    if(PCOI(pcop)->r)
5783       return (PCOI(pcop)->r);
5784     else
5785       return NULL;*/
5786     return (PCOI(pcop)->r);
5787 
5788   case PO_GPR_BIT:
5789     return PCOR(pcop)->r;
5790 
5791   case PO_GPR_REGISTER:
5792   case PO_DIR:
5793 //      fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5794     return PCOR(pcop)->r;
5795 
5796   case PO_LITERAL:
5797     //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5798     break;
5799 
5800   case PO_REL_ADDR:
5801   case PO_LABEL:
5802     //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5803     break;
5804 
5805   case PO_CRY:
5806   case PO_STR:
5807     /* this should never turn up */
5808     //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5809     break;
5810 
5811   case PO_WILD:
5812     break;
5813 
5814   case PO_TWO_OPS:
5815     return pic16_getRegFrompCodeOp( PCOP2(pcop)->pcopL );
5816     break;
5817 
5818   default:
5819         fprintf(stderr, "pic16_getRegFrompCodeOp - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5820 //      assert( 0 );
5821         break;
5822   }
5823 
5824   return NULL;
5825 }
5826 
5827 /*-----------------------------------------------------------------*/
5828 /*-----------------------------------------------------------------*/
pic16_getRegFromInstruction(pCode * pc)5829 reg_info * pic16_getRegFromInstruction(pCode *pc)
5830 {
5831   if(!pc                   ||
5832      !isPCI(pc)            ||
5833      !PCI(pc)->pcop        ||
5834      PCI(pc)->num_ops == 0 ||
5835      (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5836     return NULL;
5837 
5838 #if 0
5839   fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5840         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5841 #endif
5842 
5843   return( pic16_getRegFrompCodeOp (PCI(pc)->pcop) );
5844 }
5845 
5846 /*-------------------------------------------------------------------------------*/
5847 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5848 /*-------------------------------------------------------------------------------*/
pic16_getRegFromInstruction2(pCode * pc)5849 reg_info * pic16_getRegFromInstruction2(pCode *pc)
5850 {
5851   if(!pc                   ||
5852      !isPCI(pc)            ||
5853      !PCI(pc)->pcop        ||
5854      PCI(pc)->num_ops == 0 ||
5855      (PCI(pc)->num_ops == 1))           // accept only 2 operand commands
5856     return NULL;
5857 
5858   if (PCI(pc)->pcop->type != PO_TWO_OPS)
5859     return NULL;
5860 
5861 #if 0
5862   fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5863         dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5864 #endif
5865 
5866   return pic16_getRegFrompCodeOp (PCOP2(PCI(pc)->pcop)->pcopR);
5867 }
5868 
5869 /*-----------------------------------------------------------------*/
5870 /*-----------------------------------------------------------------*/
5871 
AnalyzepBlock(pBlock * pb)5872 static void AnalyzepBlock(pBlock *pb)
5873 {
5874   pCode *pc;
5875 
5876   if(!pb)
5877     return;
5878 
5879   /* Find all of the registers used in this pBlock
5880    * by looking at each instruction and examining it's
5881    * operands
5882    */
5883   for(pc = pb->pcHead; pc; pc = pc->next) {
5884 
5885     /* Is this an instruction with operands? */
5886     if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5887 
5888       if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5889 
5890         /* Loop through all of the registers declared so far in
5891            this block and see if we find this one there */
5892 
5893         reg_info *r = setFirstItem(pb->tregisters);
5894 
5895         while(r) {
5896           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5897             PCOR(PCI(pc)->pcop)->r = r;
5898             break;
5899           }
5900           r = setNextItem(pb->tregisters);
5901         }
5902 
5903         if(!r) {
5904           /* register wasn't found */
5905           //r = Safe_alloc(sizeof(regs));
5906           //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5907           //addSet(&pb->tregisters, r);
5908           addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5909           //PCOR(PCI(pc)->pcop)->r = r;
5910           //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5911         }/* else
5912           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5913          */
5914       }
5915       if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5916         if(PCOR(PCI(pc)->pcop)->r) {
5917           pic16_allocWithIdx(PCOR(PCI(pc)->pcop)->r->rIdx);                     /* FIXME! - VR */
5918           DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5919         } else {
5920           if(PCI(pc)->pcop->name)
5921             fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5922           else
5923             fprintf(stderr,"ERROR: NULL register\n");
5924         }
5925       }
5926     }
5927   }
5928 }
5929 
5930 /*-----------------------------------------------------------------*/
5931 /* */
5932 /*-----------------------------------------------------------------*/
5933 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5934 
InsertpFlow(pCode * pc,pCode ** pflow)5935 static void InsertpFlow(pCode *pc, pCode **pflow)
5936 {
5937   if(*pflow)
5938     PCFL(*pflow)->end = pc;
5939 
5940   if(!pc || !pc->next)
5941     return;
5942 
5943   *pflow = pic16_newpCodeFlow();
5944   pic16_pCodeInsertAfter(pc, *pflow);
5945 }
5946 
5947 /*-----------------------------------------------------------------*/
5948 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
5949 /*                         the flow blocks.                        */
5950 /*
5951  * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5952  * point the instruction flow changes.
5953  */
5954 /*-----------------------------------------------------------------*/
pic16_BuildFlow(pBlock * pb)5955 void pic16_BuildFlow(pBlock *pb)
5956 {
5957   pCode *pc;
5958   pCode *last_pci=NULL;
5959   pCode *pflow=NULL;
5960   int seq = 0;
5961 
5962   if(!pb)
5963     return;
5964 
5965   //fprintf (stderr,"build flow start seq %d  ",GpcFlowSeq);
5966   /* Insert a pCodeFlow object at the beginning of a pBlock */
5967 
5968   InsertpFlow(pb->pcHead, &pflow);
5969 
5970   //pflow = pic16_newpCodeFlow();    /* Create a new Flow object */
5971   //pflow->next = pb->pcHead;  /* Make the current head the next object */
5972   //pb->pcHead->prev = pflow;  /* let the current head point back to the flow object */
5973   //pb->pcHead = pflow;        /* Make the Flow object the head */
5974   //pflow->pb = pb;
5975 
5976   for( pc = pic16_findNextInstruction(pb->pcHead);
5977        pc != NULL;
5978        pc=pic16_findNextInstruction(pc)) {
5979 
5980     pc->seq = seq++;
5981     PCI(pc)->pcflow = PCFL(pflow);
5982 
5983     //fprintf(stderr," build: ");
5984     //pflow->print(stderr,pflow);
5985 
5986     if (checkLabel(pc)) {
5987 
5988       /* This instruction marks the beginning of a
5989        * new flow segment */
5990 
5991       pc->seq = 0;
5992       seq = 1;
5993 
5994       /* If the previous pCode is not a flow object, then
5995        * insert a new flow object. (This check prevents
5996        * two consecutive flow objects from being insert in
5997        * the case where a skip instruction preceeds an
5998        * instruction containing a label.) */
5999 
6000       if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
6001         InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
6002 
6003       PCI(pc)->pcflow = PCFL(pflow);
6004 
6005     }
6006 
6007     if( PCI(pc)->isSkip) {
6008 
6009       /* The two instructions immediately following this one
6010        * mark the beginning of a new flow segment */
6011 
6012       while(pc && PCI(pc)->isSkip) {
6013 
6014         PCI(pc)->pcflow = PCFL(pflow);
6015         pc->seq = seq-1;
6016         seq = 1;
6017 
6018         InsertpFlow(pc, &pflow);
6019         pc=pic16_findNextInstruction(pc->next);
6020       }
6021 
6022       seq = 0;
6023 
6024       if(!pc)
6025         break;
6026 
6027       PCI(pc)->pcflow = PCFL(pflow);
6028       pc->seq = 0;
6029       InsertpFlow(pc, &pflow);
6030 
6031     } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next)))  {
6032 
6033       InsertpFlow(pc, &pflow);
6034       seq = 0;
6035 
6036     }
6037     last_pci = pc;
6038     pc = pc->next;
6039   }
6040 
6041   //fprintf (stderr,",end seq %d",GpcFlowSeq);
6042   if(pflow)
6043     PCFL(pflow)->end = pb->pcTail;
6044 }
6045 
6046 /*-------------------------------------------------------------------*/
6047 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build  */
6048 /*                           the flow blocks.                        */
6049 /*
6050  * unBuildFlow removes pCodeFlow objects from a pCode chain
6051  */
6052 /*-----------------------------------------------------------------*/
unBuildFlow(pBlock * pb)6053 static void unBuildFlow(pBlock *pb)
6054 {
6055   pCode *pc,*pcnext;
6056 
6057   if(!pb)
6058     return;
6059 
6060   pc = pb->pcHead;
6061 
6062   while(pc) {
6063     pcnext = pc->next;
6064 
6065     if(isPCI(pc)) {
6066 
6067       pc->seq = 0;
6068       if(PCI(pc)->pcflow) {
6069         //Safe_free(PCI(pc)->pcflow);
6070         PCI(pc)->pcflow = NULL;
6071       }
6072 
6073     } else if(isPCFL(pc) )
6074       pc->destruct(pc);
6075 
6076     pc = pcnext;
6077   }
6078 }
6079 #if 0
6080 /*-----------------------------------------------------------------*/
6081 /*-----------------------------------------------------------------*/
6082 static void dumpCond(int cond)
6083 {
6084   static const char *pcc_str[] = {
6085     //"PCC_NONE",
6086     "PCC_REGISTER",
6087     "PCC_C",
6088     "PCC_Z",
6089     "PCC_DC",
6090     "PCC_OV",
6091     "PCC_N",
6092     "PCC_W",
6093     "PCC_EXAMINE_PCOP",
6094     "PCC_LITERAL",
6095     "PCC_REL_ADDR"
6096   };
6097 
6098   int ncond = sizeof(pcc_str) / sizeof(char *);
6099   int i,j;
6100 
6101   fprintf(stderr, "0x%04X\n",cond);
6102 
6103   for(i=0,j=1; i<ncond; i++, j<<=1) {
6104     if(cond & j) {
6105       fprintf(stderr, "  %s\n",pcc_str[i]);
6106     }
6107   }
6108 }
6109 #endif
6110 
6111 #if 0
6112 /*-----------------------------------------------------------------*/
6113 /*-----------------------------------------------------------------*/
6114 static void FlowStats(pCodeFlow *pcflow)
6115 {
6116   pCode *pc;
6117 
6118   if(!isPCFL(pcflow))
6119     return;
6120 
6121   fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6122 
6123   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6124 
6125   if(!pc) {
6126     fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6127     return;
6128   }
6129 
6130   fprintf(stderr, "  FlowStats inCond: ");
6131   dumpCond(pcflow->inCond);
6132   fprintf(stderr, "  FlowStats outCond: ");
6133   dumpCond(pcflow->outCond);
6134 }
6135 #endif
6136 /*-----------------------------------------------------------------*
6137  * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6138  *    if it affects the banking bits.
6139  *
6140  * return: -1 == Banking bits are unaffected by this pCode.
6141  *
6142  * return: > 0 == Banking bits are affected.
6143  *
6144  *  If the banking bits are affected, then the returned value describes
6145  * which bits are affected and how they're affected. The lower half
6146  * of the integer maps to the bits that are affected, the upper half
6147  * to whether they're set or cleared.
6148  *
6149  *-----------------------------------------------------------------*/
6150 
isBankInstruction(pCode * pc)6151 static int isBankInstruction(pCode *pc)
6152 {
6153   reg_info *reg;
6154 
6155   if(!isPCI(pc))
6156     return FALSE;
6157 
6158   if((PCI(pc)->op == POC_MOVLB) ||
6159      (((reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6160   }
6161 
6162   return TRUE;
6163 }
6164 
6165 
6166 /*-----------------------------------------------------------------*/
6167 /*-----------------------------------------------------------------*/
FillFlow(pCodeFlow * pcflow)6168 static void FillFlow(pCodeFlow *pcflow)
6169 {
6170   pCode *pc;
6171 
6172   if(!isPCFL(pcflow))
6173     return;
6174 
6175   //  fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6176 
6177   pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6178 
6179   if(!pc) {
6180     //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6181     return;
6182   }
6183 
6184   do {
6185     isBankInstruction(pc);
6186     pc = pc->next;
6187   } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6188 
6189 /*
6190   if(!pc ) {
6191     fprintf(stderr, "  FillFlow - Bad end of flow\n");
6192   } else {
6193     fprintf(stderr, "  FillFlow - Ending flow with\n  ");
6194     pc->print(stderr,pc);
6195   }
6196 
6197   fprintf(stderr, "  FillFlow inCond: ");
6198   dumpCond(pcflow->inCond);
6199   fprintf(stderr, "  FillFlow outCond: ");
6200   dumpCond(pcflow->outCond);
6201 */
6202 }
6203 
6204 /*-----------------------------------------------------------------*/
6205 /*-----------------------------------------------------------------*/
LinkFlow_pCode(pCodeInstruction * from,pCodeInstruction * to)6206 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6207 {
6208   pCodeFlowLink *fromLink, *toLink;
6209 
6210   if(!from || !to || !to->pcflow || !from->pcflow)
6211     return;
6212 
6213   fromLink = pic16_newpCodeFlowLink(from->pcflow);
6214   toLink   = pic16_newpCodeFlowLink(to->pcflow);
6215 
6216   addSetIfnotP(&(from->pcflow->to), toLink);   //to->pcflow);
6217   addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6218 }
6219 
pic16_getJumptabpCode(pCode * pc)6220 static pCode *pic16_getJumptabpCode (pCode *pc)
6221 {
6222   pCode *pcinf;
6223 
6224   //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6225   //pc->print (stderr, pc);
6226   pcinf = pc;
6227   while (pcinf) {
6228     if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6229     if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6230       switch (PCOO(PCINF(pcinf)->oper1)->type) {
6231       case OPT_JUMPTABLE_BEGIN:
6232         /* leading begin of jump table -- in one */
6233         pcinf = pic16_findPrevInstruction (pcinf);
6234         return pcinf;
6235         break;
6236 
6237       case OPT_JUMPTABLE_END:
6238         /* leading end of jumptable -- not in one */
6239         return NULL;
6240         break;
6241 
6242       default:
6243         /* ignore all other PCInfos */
6244         break;
6245       }
6246     }
6247     pcinf = pcinf->prev;
6248   }
6249 
6250   /* no PCInfo found -- not in a jumptable */
6251   return NULL;
6252 }
6253 
6254 /*-----------------------------------------------------------------*
6255  * void LinkFlow(pBlock *pb)
6256  *
6257  * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6258  * non-branching segments. In LinkFlow, we determine the execution
6259  * order of these segments. For example, if one of the segments ends
6260  * with a skip, then we know that there are two possible flow segments
6261  * to which control may be passed.
6262  *-----------------------------------------------------------------*/
LinkFlow(pBlock * pb)6263 static void LinkFlow(pBlock *pb)
6264 {
6265   pCode *pc=NULL;
6266   pCode *pcflow;
6267   pCode *pct;
6268   pCode *jumptab_pre = NULL;
6269 
6270   //fprintf(stderr,"linkflow \n");
6271 
6272   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6273        pcflow != NULL;
6274        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6275 
6276     if(!isPCFL(pcflow))
6277       fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6278 
6279     //fprintf(stderr," link: ");
6280     //pcflow->print(stderr,pcflow);
6281 
6282     //FillFlow(PCFL(pcflow));
6283 
6284     pc = PCFL(pcflow)->end;
6285 
6286     //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6287     if(isPCI_SKIP(pc)) {
6288 //      fprintf(stderr, "ends with skip\n");
6289 //      pc->print(stderr,pc);
6290 
6291       pct=pic16_findNextInstruction(pc->next);
6292       LinkFlow_pCode(PCI(pc),PCI(pct));
6293       pct=pic16_findNextInstruction(pct->next);
6294       LinkFlow_pCode(PCI(pc),PCI(pct));
6295       continue;
6296     }
6297 
6298     if(isPCI_BRANCH(pc)) {
6299       pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6300 
6301       /* handle GOTOs in jumptables */
6302       if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6303         /* link to previous flow */
6304         //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6305         LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6306       }
6307 
6308       switch (PCI(pc)->op) {
6309       case POC_GOTO:
6310       case POC_BRA:
6311       case POC_RETURN:
6312       case POC_RETLW:
6313       case POC_RETFIE:
6314               /* unconditional branches -- do not link to next instruction */
6315               //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6316               break;
6317 
6318       case POC_CALL:
6319       case POC_RCALL:
6320               /* unconditional calls -- link to next instruction */
6321               //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6322               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6323               break;
6324 
6325       case POC_BC:
6326       case POC_BN:
6327       case POC_BNC:
6328       case POC_BNN:
6329       case POC_BNOV:
6330       case POC_BNZ:
6331       case POC_BOV:
6332       case POC_BZ:
6333               /* conditional branches -- also link to next instruction */
6334               //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6335               LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6336               break;
6337 
6338       default:
6339               fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6340               assert (0 && "unhandled branching instruction");
6341               break;
6342       }
6343 
6344       //fprintf(stderr, "ends with branch\n  ");
6345       //pc->print(stderr,pc);
6346 
6347       if(!(pcol && isPCOLAB(pcol))) {
6348         if((PCI(pc)->op != POC_RETLW)
6349                 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6350 
6351                 /* continue if label is '$' which assembler knows how to parse */
6352                 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6353 
6354                 if(pic16_pcode_verbose) {
6355                         pc->print(stderr,pc);
6356                         fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6357                 }
6358         }
6359         continue;
6360       }
6361 
6362       if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6363         LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pct)));
6364       else
6365         fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6366                 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6367 
6368 //      fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6369 
6370       continue;
6371     }
6372 
6373     if(isPCI(pc)) {
6374       //fprintf(stderr, "ends with non-branching instruction:\n");
6375       //pc->print(stderr,pc);
6376 
6377       LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6378 
6379       continue;
6380     }
6381 
6382     if(pc) {
6383       //fprintf(stderr, "ends with unknown\n");
6384       //pc->print(stderr,pc);
6385       continue;
6386     }
6387 
6388     //fprintf(stderr, "ends with nothing: ERROR\n");
6389   }
6390 }
6391 
6392 /*-----------------------------------------------------------------*/
6393 /*-----------------------------------------------------------------*/
6394 
6395 /*-----------------------------------------------------------------*/
6396 /*-----------------------------------------------------------------*/
pic16_isPCinFlow(const pCode * pc,const pCode * pcflow)6397 int pic16_isPCinFlow(const pCode *pc, const pCode *pcflow)
6398 {
6399   if(!pc || !pcflow)
6400     return FALSE;
6401 
6402   if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6403     return FALSE;
6404 
6405   if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6406     return TRUE;
6407 
6408   return FALSE;
6409 }
6410 
6411 /*-----------------------------------------------------------------*/
6412 /* insertBankSwitch - inserts a bank switch statement in the       */
6413 /*                    assembly listing                             */
6414 /*                                                                 */
6415 /* position == 0: insert before                                    */
6416 /* position == 1: insert after pc                                  */
6417 /* position == 2: like 0 but previous was a skip instruction       */
6418 /*-----------------------------------------------------------------*/
6419 pCodeOp *pic16_popGetLabel(unsigned int key);
6420 extern int pic16_labelOffset;
6421 
insertBankSwitch(unsigned char position,pCode * pc)6422 static void insertBankSwitch(unsigned char position, pCode *pc)
6423 {
6424   pCode *new_pc;
6425 
6426         if(!pc)
6427                 return;
6428 
6429         /* emit BANKSEL [symbol] */
6430 
6431 
6432         new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6433 
6434 //      position = 0;           // position is always before (sanity check!)
6435 
6436 #if 0
6437         fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6438         pc->print(stderr, pc);
6439 #endif
6440 
6441         switch(position) {
6442                 case 1: {
6443                         /* insert the bank switch after this pc instruction */
6444                         pCode *pcnext = pic16_findNextInstruction(pc);
6445 
6446                                 pic16_pCodeInsertAfter(pc, new_pc);
6447                                 if(pcnext)pc = pcnext;
6448                 }; break;
6449 
6450                 case 0:
6451                         /* insert the bank switch BEFORE this pc instruction */
6452                         pic16_pCodeInsertAfter(pc->prev, new_pc);
6453                         break;
6454 
6455                 case 2: {
6456                           symbol *tlbl;
6457                           pCode *pcnext, *pcprev, *npci, *ppc;
6458                           PIC_OPCODE ipci;
6459                           int ofs1=0, ofs2=0;
6460 
6461                         /* just like 0, but previous was a skip instruction,
6462                          * so some care should be taken */
6463 
6464                                 pic16_labelOffset += 10000;
6465                                 tlbl = newiTempLabel(NULL);
6466 
6467                                 /* invert skip instruction */
6468                                 pcprev = pic16_findPrevInstruction(pc->prev);
6469                                 ipci = PCI(pcprev)->inverted_op;
6470                                 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6471 
6472 //                              fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6473 
6474                                 /* copy info from old pCode */
6475                                 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6476                                 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6477                                 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6478                                 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6479                                 PCI(npci)->op = PCI(pcprev)->inverted_op;
6480 
6481                                 /* unlink old pCode */
6482                                 ppc = pcprev->prev;
6483                                 ppc->next = pcprev->next;
6484                                 pcprev->next->prev = ppc;
6485                                 pic16_pCodeInsertAfter(ppc, npci);
6486 
6487                                 /* extra instructions to handle invertion */
6488                                 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6489                                 pic16_pCodeInsertAfter(npci, pcnext);
6490                                 pic16_pCodeInsertAfter(pc->prev, new_pc);
6491 
6492                                 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6493                                 pic16_pCodeInsertAfter(pc, pcnext);
6494                         }; break;
6495         }
6496 
6497 
6498         /* Move the label, if there is one */
6499         if(PCI(pc)->label) {
6500 //              fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6501 //                      __FILE__, __LINE__, pc, new_pc);
6502                 PCAD(new_pc)->pci.label = PCI(pc)->label;
6503                 PCI(pc)->label = NULL;
6504         }
6505 }
6506 
6507 
6508 #if 0
6509 /*-----------------------------------------------------------------*/
6510 /*int compareBankFlow - compare the banking requirements between   */
6511 /*  flow objects. */
6512 /*-----------------------------------------------------------------*/
6513 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6514 {
6515 
6516   if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6517     return FALSE;
6518 
6519   if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6520     return FALSE;
6521 
6522   if(pcflow->firstBank == -1)
6523     return FALSE;
6524 
6525   if(pcflowLink->pcflow->firstBank == -1) {
6526     pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6527                                         pcflowLink->pcflow->to :
6528                                         pcflowLink->pcflow->from);
6529     return compareBankFlow(pcflow, pctl, toORfrom);
6530   }
6531 
6532   if(toORfrom) {
6533     if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6534       return FALSE;
6535 
6536     pcflowLink->bank_conflict++;
6537     pcflowLink->pcflow->FromConflicts++;
6538     pcflow->ToConflicts++;
6539   } else {
6540 
6541     if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6542       return FALSE;
6543 
6544     pcflowLink->bank_conflict++;
6545     pcflowLink->pcflow->ToConflicts++;
6546     pcflow->FromConflicts++;
6547 
6548   }
6549   /*
6550   fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6551           pcflowLink->pcflow->pc.seq,
6552           pcflowLink->pcflow->FromConflicts,
6553           pcflowLink->pcflow->ToConflicts);
6554   */
6555   return TRUE;
6556 }
6557 #endif
6558 
6559 #if 0
6560 /*-----------------------------------------------------------------*/
6561 /*-----------------------------------------------------------------*/
6562 static void DumpFlow(pBlock *pb)
6563 {
6564   pCode *pc=NULL;
6565   pCode *pcflow;
6566   pCodeFlowLink *pcfl;
6567 
6568   fprintf(stderr,"Dump flow \n");
6569   pb->pcHead->print(stderr, pb->pcHead);
6570 
6571   pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6572   pcflow->print(stderr,pcflow);
6573 
6574   for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6575        pcflow != NULL;
6576        pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6577 
6578     if(!isPCFL(pcflow)) {
6579       fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6580       continue;
6581     }
6582     fprintf(stderr,"dumping: ");
6583     pcflow->print(stderr,pcflow);
6584     FlowStats(PCFL(pcflow));
6585 
6586     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6587 
6588       pc = PCODE(pcfl->pcflow);
6589 
6590       fprintf(stderr, "    from seq %d:\n",pc->seq);
6591       if(!isPCFL(pc)) {
6592         fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6593         pc->print(stderr,pc);
6594       }
6595     }
6596 
6597     for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6598 
6599       pc = PCODE(pcfl->pcflow);
6600 
6601       fprintf(stderr, "    to seq %d:\n",pc->seq);
6602       if(!isPCFL(pc)) {
6603         fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6604         pc->print(stderr,pc);
6605       }
6606     }
6607   }
6608 }
6609 #endif
6610 /*-----------------------------------------------------------------*/
6611 /*-----------------------------------------------------------------*/
OptimizepBlock(pBlock * pb)6612 static int OptimizepBlock(pBlock *pb)
6613 {
6614   pCode *pc, *pcprev;
6615   int matches =0;
6616 
6617   if(!pb || !peepOptimizing)
6618     return 0;
6619 
6620   DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6621 /*
6622   for(pc = pb->pcHead; pc; pc = pc->next)
6623     matches += pic16_pCodePeepMatchRule(pc);
6624 */
6625 
6626   pc = pic16_findNextInstruction(pb->pcHead);
6627   if(!pc)
6628     return 0;
6629 
6630   pcprev = pc->prev;
6631   do {
6632     if(pic16_pCodePeepMatchRule(pc)) {
6633       matches++;
6634 
6635       if(pcprev)
6636         pc = pic16_findNextInstruction(pcprev->next);
6637       else
6638         pc = pic16_findNextInstruction(pb->pcHead);
6639     } else
6640       pc = pic16_findNextInstruction(pc->next);
6641   } while(pc);
6642 
6643   if(matches)
6644     DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6645 
6646   return matches;
6647 }
6648 
6649 /*-----------------------------------------------------------------*/
6650 /*-----------------------------------------------------------------*/
findInstructionUsingLabel(pCodeLabel * pcl,pCode * pcs)6651 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6652 {
6653   pCode *pc;
6654 
6655   for(pc = pcs; pc; pc = pc->next) {
6656 
6657     if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6658        (PCI(pc)->pcop) &&
6659        (PCI(pc)->pcop->type == PO_LABEL) &&
6660        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6661       return pc;
6662   }
6663 
6664   return NULL;
6665 }
6666 
6667 /*-----------------------------------------------------------------*/
6668 /*-----------------------------------------------------------------*/
exchangeLabels(pCodeLabel * pcl,pCode * pc)6669 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6670 {
6671   const char *s;
6672 
6673   if(isPCI(pc) &&
6674      (PCI(pc)->pcop) &&
6675      (PCI(pc)->pcop->type == PO_LABEL)) {
6676 
6677     pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6678 
6679 //      fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6680 //    if(pcol->pcop.name)
6681 //      Safe_free(pcol->pcop.name);
6682 
6683     /* If the key is negative, then we (probably) have a label to
6684      * a function and the name is already defined */
6685 
6686     if(pcl->key>0) {
6687       SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_", pcl->key);
6688       s = buffer;
6689     }
6690     else
6691       s = pcl->label;
6692 
6693     //SNPRINTF(buffer, sizeof(buffer), "_%05d_DS_",pcl->key);
6694     if(!s) {
6695       fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6696     }
6697     pcol->pcop.name = Safe_strdup(s);
6698     pcol->key = pcl->key;
6699     //pc->print(stderr,pc);
6700   }
6701 }
6702 
6703 /*-----------------------------------------------------------------*/
6704 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
6705 /*                            pCode chain if they're not used.     */
6706 /*-----------------------------------------------------------------*/
pBlockRemoveUnusedLabels(pBlock * pb)6707 static void pBlockRemoveUnusedLabels(pBlock *pb)
6708 {
6709   pCode *pc;
6710   pCodeLabel *pcl;
6711 
6712   if(!pb || !pb->pcHead)
6713     return;
6714 
6715   for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6716 
6717     pBranch *pbr = PCI(pc)->label;
6718     if(pbr && pbr->next) {
6719       pCode *pcd = pb->pcHead;
6720 
6721 //      fprintf(stderr, "multiple labels\n");
6722 //      pc->print(stderr,pc);
6723 
6724       pbr = pbr->next;
6725       while(pbr) {
6726 
6727         while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6728           //fprintf(stderr,"Used by:\n");
6729           //pcd->print(stderr,pcd);
6730 
6731           exchangeLabels(PCL(pbr->pc),pcd);
6732 
6733           pcd = pcd->next;
6734         }
6735         pbr = pbr->next;
6736       }
6737     }
6738   }
6739 
6740   for(pc = pb->pcHead; pc; pc = pc->next) {
6741 
6742     if(isPCL(pc)) // pc->type == PC_LABEL)
6743       pcl = PCL(pc);
6744     else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6745       pcl = PCL(PCI(pc)->label->pc);
6746     else continue;
6747 
6748 //      fprintf(stderr," found  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6749 
6750     /* This pCode is a label, so search the pBlock to see if anyone
6751      * refers to it */
6752 
6753     if((pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6754         && (!pcl->force)) {
6755     //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6756       /* Couldn't find an instruction that refers to this label
6757        * So, unlink the pCode label from it's pCode chain
6758        * and destroy the label */
6759 //      fprintf(stderr," removed  A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6760 
6761       DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6762       if(pc->type == PC_LABEL) {
6763         pic16_unlinkpCode(pc);
6764         pCodeLabelDestruct(pc);
6765       } else {
6766         unlinkpCodeFromBranch(pc, PCODE(pcl));
6767         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6768           Safe_free(pc->label);
6769         }*/
6770       }
6771     }
6772   }
6773 }
6774 
6775 /*-----------------------------------------------------------------*/
6776 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode      */
6777 /*                     chain and put them into pBranches that are  */
6778 /*                     associated with the appropriate pCode       */
6779 /*                     instructions.                               */
6780 /*-----------------------------------------------------------------*/
pic16_pBlockMergeLabels(pBlock * pb)6781 void pic16_pBlockMergeLabels(pBlock *pb)
6782 {
6783   pBranch *pbr;
6784   pCode *pc, *pcnext=NULL;
6785 
6786   if(!pb)
6787     return;
6788 
6789   /* First, Try to remove any unused labels */
6790   //pBlockRemoveUnusedLabels(pb);
6791 
6792   /* Now loop through the pBlock and merge the labels with the opcodes */
6793 
6794   pc = pb->pcHead;
6795   //  for(pc = pb->pcHead; pc; pc = pc->next) {
6796 
6797   while(pc) {
6798     pCode *pcn = pc->next;
6799 
6800     if(pc->type == PC_LABEL) {
6801 
6802 //      fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6803 //      fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6804 
6805       if((pcnext = pic16_findNextInstruction(pc) )) {
6806 
6807 //              pcnext->print(stderr, pcnext);
6808 
6809         // Unlink the pCode label from it's pCode chain
6810         pic16_unlinkpCode(pc);
6811 
6812 //      fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6813         // And link it into the instruction's pBranch labels. (Note, since
6814         // it's possible to have multiple labels associated with one instruction
6815         // we must provide a means to accomodate the additional labels. Thus
6816         // the labels are placed into the singly-linked list "label" as
6817         // opposed to being a single member of the pCodeInstruction.)
6818 
6819         //_ALLOC(pbr,sizeof(pBranch));
6820 #if 1
6821         pbr = Safe_alloc(sizeof(pBranch));
6822         pbr->pc = pc;
6823         pbr->next = NULL;
6824 
6825         PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6826 #endif
6827       } else {
6828         if(pic16_pcode_verbose)
6829         fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6830       }
6831     } else if(pc->type == PC_CSOURCE) {
6832 
6833       /* merge the source line symbolic info into the next instruction */
6834       if((pcnext = pic16_findNextInstruction(pc) )) {
6835 
6836         // Unlink the pCode label from it's pCode chain
6837         pic16_unlinkpCode(pc);
6838         PCI(pcnext)->cline = PCCS(pc);
6839         //fprintf(stderr, "merging CSRC\n");
6840         //genericPrint(stderr,pcnext);
6841       }
6842     }
6843     pc = pcn;
6844   }
6845 
6846   pBlockRemoveUnusedLabels(pb);
6847 }
6848 
6849 /*-----------------------------------------------------------------*/
6850 /*-----------------------------------------------------------------*/
OptimizepCode(char dbName)6851 static int OptimizepCode(char dbName)
6852 {
6853 #define MAX_PASSES 4
6854 
6855   int matches = 0;
6856   int passes = 0;
6857   pBlock *pb;
6858 
6859   if(!the_pFile)
6860     return 0;
6861 
6862   DFPRINTF((stderr," Optimizing pCode\n"));
6863 
6864   do {
6865     matches = 0;
6866     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6867       if('*' == dbName || getpBlock_dbName(pb) == dbName)
6868         matches += OptimizepBlock(pb);
6869     }
6870   }
6871   while(matches && ++passes < MAX_PASSES);
6872 
6873   return matches;
6874 }
6875 
6876 const char *pic16_pCodeOpType(pCodeOp *pcop);
6877 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6878 
6879 /*-----------------------------------------------------------------*/
6880 /* pic16_popCopyGPR2Bit - copy a pcode operator                          */
6881 /*-----------------------------------------------------------------*/
6882 
pic16_popCopyGPR2Bit(pCodeOp * pc,int bitval)6883 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6884 {
6885   pCodeOp *pcop=NULL;
6886 
6887 //  fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6888 
6889   if(pc->name) {
6890         pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6891   } else {
6892     if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6893   }
6894 
6895   assert(pcop != NULL);
6896 
6897   if( !( (pcop->type == PO_LABEL) ||
6898          (pcop->type == PO_LITERAL) ||
6899          (pcop->type == PO_STR) ))
6900     PCOR(pcop)->r = PCOR(pc)->r;  /* This is dangerous... */
6901     PCOR(pcop)->r->wasUsed = 1;
6902     PCOR(pcop)->instance = PCOR(pc)->instance;
6903 
6904   return pcop;
6905 }
6906 
6907 
6908 /*----------------------------------------------------------------------*
6909  * pic16_areRegsSame - check to see if the names of two registers match *
6910  *----------------------------------------------------------------------*/
6911 
6912 #if 0
6913 static int pic16_areRegsSame(const reg_info *r1, const reg_info *r2)
6914 {
6915   return ((strcmp(r1->name, r2->name) == 0) ? TRUE : FALSE);
6916 }
6917 #endif
6918 
6919 /*-----------------------------------------------------------------*/
6920 /*-----------------------------------------------------------------*/
pic16_FixRegisterBanking(pBlock * pb)6921 static void pic16_FixRegisterBanking(pBlock *pb)
6922 {
6923   pCode *pc=NULL;
6924   pCode *pcprev=NULL;
6925   reg_info *reg, *prevreg;
6926   unsigned char flag=0;
6927 
6928         if(!pb)
6929                 return;
6930 
6931         pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6932         if(!pc)return;
6933 
6934         /* loop through all of the flow blocks with in one pblock */
6935 
6936 //      fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6937 
6938         prevreg = NULL;
6939         do {
6940                 /* at this point, pc should point to a PC_FLOW object */
6941                 /* for each flow block, determine the register banking
6942                  * requirements */
6943 
6944 
6945                 /* if label, then might come from other point, force banksel */
6946                 if(isPCL(pc))prevreg = NULL;
6947 
6948                 if(!isPCI(pc))goto loop;
6949 
6950                 if(PCI(pc)->label)prevreg = NULL;
6951 
6952                 if(PCI(pc)->is2MemOp)goto loop;
6953 
6954                 /* if goto, then force banksel */
6955 //              if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
6956 
6957                 reg = pic16_getRegFromInstruction(pc);
6958 
6959 #if 0
6960                 pc->print(stderr, pc);
6961                 fprintf(stderr, "reg = %p\n", reg);
6962 
6963                 if(reg) {
6964                         fprintf(stderr, "%s:%d:  %s  %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
6965                         fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
6966                                 reg->address,reg->isBitField, reg->isFixed);
6967                 }
6968 #endif
6969 
6970                 /* now make some tests to make sure that instruction needs bank switch */
6971 
6972                 /* if no register exists, and if not a bit opcode goto loop */
6973                 if(!reg) {
6974                         if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
6975                 }
6976 
6977                 if(isPCI_SKIP(pc)) {
6978 //                      fprintf(stderr, "instruction is SKIP instruction\n");
6979 //                prevreg = NULL;
6980                 }
6981                 if(reg && isACCESS_BANK(reg))goto loop;
6982 
6983                 if(!isBankInstruction(pc))goto loop;
6984 
6985                 if(isPCI_LIT(pc))goto loop;
6986 
6987                 if(PCI(pc)->op == POC_CALL)goto loop;
6988 
6989                 /* Examine the instruction before this one to make sure it is
6990                  * not a skip type instruction */
6991                 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
6992 
6993                 flag = 0;               /* add before this instruction */
6994 
6995                 /* if previous instruction is a skip one, then set flag
6996                  * to 2 and call insertBankSwitch */
6997                 if(pcprev && isPCI_SKIP(pcprev)) {
6998                   flag=2;       //goto loop
6999 //                prevreg = NULL;
7000                 }
7001 
7002                 if(pic16_options.opt_banksel>0) {
7003                   char op1[128], op2[128];
7004 
7005                     if(prevreg) {
7006                       strncpy(op1, pic16_get_op_from_instruction(PCI(pc)), sizeof(op1) - 1);
7007                       op1[sizeof(op1) - 1] = '\0';
7008 
7009                       strncpy(op2, pic16_get_op_from_instruction(PCI(pcprev)), sizeof(op2) - 1);
7010                       op2[sizeof(op2) - 1] = '\0';
7011 
7012                       if(!strcmp(op1, op2))goto loop;
7013                     }
7014                 }
7015                 prevreg = reg;
7016                 insertBankSwitch(flag, pc);
7017 
7018 //              fprintf(stderr, "BANK SWITCH inserted\n");
7019 
7020 loop:
7021                 pcprev = pc;
7022                 pc = pc->next;
7023         } while (pc);
7024 }
7025 
7026 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7027 
7028 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
instrSize(pCode * pc)7029 static int instrSize (pCode *pc)
7030 {
7031   if (!pc) return 0;
7032 
7033   if (isPCAD(pc)) {
7034     if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7035     return 4; // assumes only regular instructions using <= 4 bytes
7036   }
7037 
7038   if (isPCI(pc)) return PCI(pc)->isize;
7039 
7040   return 0;
7041 }
7042 
7043 /* Returns 1 if pc is referenced by the given label (either
7044  * pc is the label itself or is an instruction with an attached
7045  * label).
7046  * Returns 0 if pc is not preceeded by the specified label.
7047  */
isLabel(const pCode * pc,const char * label)7048 static int isLabel (const pCode *pc, const char *label)
7049 {
7050   if (!pc) return FALSE;
7051 
7052   // label attached to the pCode?
7053   if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7054     pBranch *lab = NULL;
7055     lab = PCI(pc)->label;
7056 
7057     while (lab) {
7058       if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7059         return TRUE;
7060       }
7061       lab = lab->next;
7062     }
7063   }
7064 
7065   // is inline assembly label?
7066   if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7067     // do not compare trailing ':'
7068     if (strncmp(PCAD(pc)->arg, label, strlen(label)) == 0) {
7069       return TRUE;
7070     }
7071   }
7072 
7073   // is pCodeLabel?
7074   if (isPCL(pc)) {
7075       if (strcmp(PCL(pc)->label, label) == 0) {
7076       return TRUE;
7077     }
7078   }
7079 
7080   // no label/no label attached/wrong label(s)
7081   return FALSE;
7082 }
7083 
7084 /* Returns the distance to the given label in terms of words.
7085  * Labels are searched only within -max .. max words from pc.
7086  * Returns max if the label could not be found or
7087  * its distance from pc in (-max..+max).
7088  */
findpCodeLabel(pCode * pc,char * label,int max,pCode ** target)7089 static int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7090   int dist = instrSize(pc);
7091   pCode *curr = pc;
7092 
7093   // search backwards
7094   while (dist < max && curr && !isLabel (curr, label)) {
7095     curr = curr->prev;
7096     dist += instrSize(curr); // sizeof (instruction)
7097   } // while
7098   if (curr && dist < max) {
7099     if (target != NULL) *target = curr;
7100     return -dist;
7101   }
7102 
7103   dist = 0;
7104   curr = pic16_findNextInstruction (pc->next);
7105   //search forwards
7106   while (dist < max && curr && !isLabel (curr, label)) {
7107     dist += instrSize(curr); // sizeof (instruction)
7108     curr = curr->next;
7109   } // while
7110   if (curr && dist < max) {
7111     if (target != NULL) *target = curr;
7112     return dist;
7113   }
7114 
7115   if (target != NULL) *target = NULL;
7116   return max;
7117 }
7118 
7119 /* Returns -1 if pc does NOT denote an instruction like
7120  * BTFS[SC] STATUS,i
7121  * Otherwise we return
7122  *   (a) 0x10 + i for BTFSS
7123  *   (b) 0x00 + i for BTFSC
7124  */
isSkipOnStatus(const pCode * pc)7125 static int isSkipOnStatus (const pCode *pc)
7126 {
7127   int res = -1;
7128   pCodeOp *pcop;
7129 
7130   if (!pc || !isPCI(pc)) return -1;
7131 
7132   if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7133   else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7134   else return -1;
7135 
7136   pcop = PCI(pc)->pcop;
7137 
7138   if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7139     return (res + ((pCodeOpRegBit *)pcop)->bit);
7140   }
7141 
7142   return -1;
7143 }
7144 
7145 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7146  * returns 0 otherwise. */
isConditionalBranch(const pCode * pc)7147 static int isConditionalBranch (const pCode *pc)
7148 {
7149   if (!pc || !isPCI_BRANCH(pc)) return FALSE;
7150 
7151   switch (PCI(pc)->op) {
7152   case POC_BC:
7153   case POC_BZ:
7154   case POC_BOV:
7155   case POC_BN:
7156   case POC_BNC:
7157   case POC_BNZ:
7158   case POC_BNOV:
7159   case POC_BNN:
7160     return TRUE;
7161 
7162   default:
7163     break;
7164   } // switch
7165 
7166   return FALSE;
7167 }
7168 
7169 /* Returns 1 if pc has a label attached to it.
7170  * This can be either a label stored in the pCode itself (.label)
7171  * or a label making up its own pCode preceding this pc.
7172  * Returns 0 if pc cannot be reached directly via a label.
7173  */
hasNoLabel(const pCode * pc)7174 const int hasNoLabel (const pCode *pc)
7175 {
7176   pCode *prev;
7177 
7178   if (!pc) return TRUE;
7179 
7180   // are there any label pCodes between pc and the previous instruction?
7181   prev = pic16_findPrevInstruction (pc->prev);
7182   while (pc && pc != prev) {
7183     // pCode with attached label?
7184     if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7185         && PCI(pc)->label) {
7186       return FALSE;
7187     }
7188     // is inline assembly label?
7189     if (isPCAD(pc) && PCAD(pc)->directive == NULL) return FALSE;
7190     if (isPCW(pc) && PCW(pc)->label) return FALSE;
7191 
7192     // pCodeLabel?
7193     if (isPCL(pc)) return FALSE;
7194 
7195     pc = pc->prev;
7196   } // if
7197 
7198   // no label found
7199   return TRUE;
7200 }
7201 
pic16_InsertCommentAfter(pCode * pc,const char * fmt,...)7202 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7203   char buf[512];
7204   va_list va;
7205 
7206   va_start (va, fmt);
7207   vsprintf (buf, fmt, va);
7208   va_end (va);
7209 
7210   pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7211 }
7212 
7213 /* Replaces the old pCode with the new one, moving the labels,
7214  * C source line and probably flow information to the new pCode.
7215  */
pic16_pCodeReplace(pCode * oldPC,pCode * newPC)7216 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7217   if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7218     return;
7219 
7220   /* first move all labels from old to new */
7221   PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7222   PCI(oldPC)->label = NULL;
7223 
7224 #if 0
7225   /* move C source line (if possible) */
7226   if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7227     PCI(newPC)->cline = PCI(oldPC)->cline;
7228 #endif
7229 
7230   /* keep flow information intact */
7231   newPC->seq = oldPC->seq;
7232   PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7233   if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7234     PCI(newPC)->pcflow->end = newPC;
7235   }
7236 
7237   /* insert a comment stating which pCode has been replaced */
7238 #if 1
7239   if (pic16_pcode_verbose || pic16_debug_verbose) {
7240     char pc_str[256];
7241 
7242     pic16_pCode2str (pc_str, sizeof(pc_str), oldPC);
7243     pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7244   }
7245 #endif
7246 
7247   /* insert new pCode into pBlock */
7248   pic16_pCodeInsertAfter (oldPC, newPC);
7249   pic16_unlinkpCode (oldPC);
7250 
7251   /* destruct replaced pCode */
7252   oldPC->destruct (oldPC);
7253 }
7254 
7255 /* Returns the inverted conditional branch (if any) or NULL.
7256  * pcop must be set to the new jump target.
7257  */
getNegatedBcc(const pCode * bcc,pCodeOp * pcop)7258 static pCode *getNegatedBcc (const pCode *bcc, pCodeOp *pcop)
7259 {
7260   pCode *newBcc;
7261 
7262   if (!bcc || !isPCI(bcc)) return NULL;
7263 
7264   switch (PCI(bcc)->op) {
7265   case POC_BC:   newBcc = pic16_newpCode (POC_BNC , pcop); break;
7266   case POC_BZ:   newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7267   case POC_BOV:  newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7268   case POC_BN:   newBcc = pic16_newpCode (POC_BNN , pcop); break;
7269   case POC_BNC:  newBcc = pic16_newpCode (POC_BC  , pcop); break;
7270   case POC_BNZ:  newBcc = pic16_newpCode (POC_BZ  , pcop); break;
7271   case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7272   case POC_BNN:  newBcc = pic16_newpCode (POC_BN  , pcop); break;
7273   default:
7274     newBcc = NULL;
7275   }
7276   return newBcc;
7277 }
7278 
7279 #define MAX_DIST_GOTO         0x7FFFFFFF
7280 #define MAX_DIST_BRA                1020        // maximum offset (in bytes) possible with BRA
7281 #define MAX_DIST_BCC                 120        // maximum offset (in bytes) possible with Bcc
7282 #define MAX_JUMPCHAIN_DEPTH           16        // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7283 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7284 
7285 /* Follows GOTO/BRA instructions to their target instructions, stores the
7286  * final destination (not a GOTO or BRA instruction) in target and returns
7287  * the distance from the original pc to *target.
7288  */
resolveJumpChain(pCode * pc,pCode ** target,pCodeOp ** pcop)7289 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7290         pCode *curr = pc;
7291         pCode *last = NULL;
7292         pCodeOp *lastPCOP = NULL;
7293         int dist = 0;
7294         int depth = 0;
7295 
7296         //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7297 
7298         /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7299         while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7300                         && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7301                 last = curr;
7302                 lastPCOP = PCI(curr)->pcop;
7303                 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7304                 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7305         } // while
7306 
7307         if (target) *target = last;
7308         if (pcop) *pcop = lastPCOP;
7309         return dist;
7310 }
7311 
7312 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7313  * Otherwise the first pCode after the jumptable (after
7314  * the OPT_JUMPTABLE_END tag) is returned.
7315  */
skipJumptables(pCode * pc,int * isJumptable)7316 pCode *skipJumptables (pCode *pc, int *isJumptable)
7317 {
7318   *isJumptable = 0;
7319 
7320   while (pc && pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7321     *isJumptable = 1;
7322     //fprintf (stderr, "SKIPPING jumptable\n");
7323     do {
7324       //pc->print(stderr, pc);
7325       pc = pc->next;
7326     } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7327                     || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7328     //fprintf (stderr, "<<JUMPTAB:\n");
7329     // skip OPT_END as well
7330     if (pc) pc = pc->next;
7331   } // while
7332 
7333   return pc;
7334 }
7335 
pic16_findNextInstructionSkipJumptables(pCode * pc,int * isJumptable)7336 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7337 {
7338   int isJumptab;
7339 
7340   *isJumptable = 0;
7341   while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7342     // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7343     pc = skipJumptables (pc, &isJumptab);
7344     if (isJumptab) {
7345         // pc is the first pCode after the jumptable
7346         *isJumptable = 1;
7347     } else {
7348         // pc has not been changed by skipJumptables()
7349         pc = pc->next;
7350     }
7351   } // while
7352 
7353   return pc;
7354 }
7355 
7356 /* Turn GOTOs into BRAs if distance between GOTO and label
7357  * is less than 1024 bytes.
7358  *
7359  * This method is especially useful if GOTOs after BTFS[SC]
7360  * can be turned into BRAs as GOTO would cost another NOP
7361  * if skipped.
7362  */
pic16_OptimizeJumps(void)7363 void pic16_OptimizeJumps (void)
7364 {
7365   pCode *pc;
7366   pCode *pc_prev = NULL;
7367   pCode *pc_next = NULL;
7368   pBlock *pb;
7369   pCode *target;
7370   int change, iteration, isJumptab;
7371   int isHandled = 0;
7372   char *label;
7373   int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7374 
7375   if (!the_pFile) return;
7376 
7377   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7378 
7379   for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7380     int matchedInvertRule = 1;
7381     iteration = 1;
7382     do {
7383       //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7384       change = 0;
7385       pc = pic16_findNextInstruction (pb->pcHead);
7386 
7387       while (pc) {
7388         pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7389         if (isJumptab) {
7390                 // skip jumptable, i.e. start over with no pc_prev!
7391                 pc_prev = NULL;
7392                 pc = pc_next;
7393                 continue;
7394         } // if
7395 
7396         /* (1) resolve chained jumps
7397          * Do not perform this until pattern (4) is no longer present! Otherwise we will
7398          * (a) leave dead code in and
7399          * (b) skip over the dead code with an (unneccessary) jump.
7400          */
7401         if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7402           pCodeOp *lastTargetOp = NULL;
7403           int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7404           int maxDist = MAX_DIST_BCC;
7405           if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7406           if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7407 
7408           /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7409           if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7410               && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7411             //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7412             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7413             PCI(pc)->pcop->name = lastTargetOp->name;
7414             change++;
7415             opt_gotochain++;
7416           } // if
7417         } // if
7418 
7419 
7420         if (IS_GOTO(pc)) {
7421           int dist;
7422           int condBraType = isSkipOnStatus(pc_prev);
7423           label = PCI(pc)->pcop->name;
7424           dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7425           if (dist < 0) dist = -dist;
7426           //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7427           isHandled = 0;
7428 
7429 
7430           /* (2) remove "GOTO label; label:" */
7431           if (isLabel (pc_next, label)) {
7432             //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7433             // first remove all preceeding SKIP instructions
7434             while (pc_prev && isPCI_SKIP(pc_prev)) {
7435               // attach labels on this instruction to pc_next
7436               //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7437               PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7438               PCI(pc_prev)->label = NULL;
7439               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7440               pic16_unlinkpCode (pc_prev);
7441               pc_prev = pic16_findPrevInstruction (pc);
7442             } // while
7443             // now remove the redundant goto itself
7444             PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7445             if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7446             pic16_unlinkpCode (pc);
7447             pc = pic16_findPrevInstruction(pc_next->prev);
7448             isHandled = 1; // do not perform further optimizations
7449             opt_gotonext++;
7450             change++;
7451           } // if
7452 
7453 
7454           /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7455           if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7456             if (dist < MAX_DIST_BCC) {
7457               pCode *bcc = NULL;
7458               switch (condBraType) {
7459               case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7460                 // no BDC on DIGIT CARRY available
7461               case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7462               case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7463               case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7464               case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7465                 // no BNDC on DIGIT CARRY available
7466               case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7467               case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7468               case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7469               default:
7470                 // no replacement possible
7471                 bcc = NULL;
7472                 break;
7473               } // switch
7474               if (bcc) {
7475                 // ATTENTION: keep labels attached to BTFSx!
7476                 // HINT: GOTO is label free (checked above)
7477                 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7478                 isHandled = 1; // do not perform further optimizations
7479                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7480                 pic16_pCodeReplace (pc_prev, bcc);
7481                 pc->destruct(pc);
7482                 pc = bcc;
7483                 opt_cond++;
7484                 change++;
7485               } // if
7486             } else {
7487               //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7488               cond_toofar++;
7489             } // if
7490           } // if
7491 
7492           if (!isHandled) {
7493             // (4) eliminate the following (common) tripel:
7494             //           <pred.>;
7495             //  labels1: Bcc label2;
7496             //           GOTO somewhere;    ; <-- instruction referenced by pc
7497             //  label2:  <cont.>
7498             // and replace it by
7499             //  labels1: B#(cc) somewhere;  ; #(cc) is the negated condition cc
7500             //  label2:  <cont.>
7501             // ATTENTION: all labels pointing to "Bcc label2" must be attached
7502             //            to <cont.> instead
7503             // ATTENTION: This optimization is only valid if <pred.> is
7504             //            not a skip operation!
7505             // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7506             // ATTENTION: no label may be attached to the GOTO instruction!
7507             if (isConditionalBranch(pc_prev)
7508                 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7509                 && (dist < MAX_DIST_BCC)
7510                 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7511                 && hasNoLabel(pc)) {
7512               pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7513 
7514               if (newBcc) {
7515                 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7516                 isHandled = 1; // do not perform further optimizations
7517                 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7518                 pic16_pCodeReplace (pc_prev, newBcc);
7519                 pc->destruct(pc);
7520                 pc = newBcc;
7521                 opt_reorder++;
7522                 change++;
7523                 matchedInvertRule++;
7524               }
7525             }
7526           }
7527 
7528           /* (5) now just turn GOTO into BRA */
7529           if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7530             if (dist < MAX_DIST_BRA) {
7531               pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7532               //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7533               if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7534               pic16_pCodeReplace (pc, newBra);
7535               pc = newBra;
7536               opt++;
7537               change++;
7538             } else {
7539               //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7540               toofar++;
7541             }
7542           } // if (!isHandled)
7543         } // if
7544 
7545         pc_prev = pc;
7546         pc = pc_next;
7547       } // while (pc)
7548 
7549       pBlockRemoveUnusedLabels (pb);
7550 
7551       // This line enables goto chain resolution!
7552       if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7553 
7554       iteration++;
7555     } while (change); /* fixpoint iteration per pBlock */
7556   } // for (pb)
7557 
7558   // emit some statistics concerning goto-optimization
7559 #if 0
7560   if (pic16_debug_verbose || pic16_pcode_verbose) {
7561     fprintf (stderr, "optimize-goto:\n"
7562              "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7563              "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7564              "\t%5d conditional \"skipping\" jumps inverted\n"
7565              "\t%5d GOTOs to next instruction removed\n"
7566              "\t%5d chained GOTOs resolved\n",
7567              opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7568   } // if
7569 #endif
7570   //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7571 }
7572 
7573 #undef IS_GOTO
7574 #undef MAX_JUMPCHAIN_DEPTH
7575 #undef MAX_DIST_GOTO
7576 #undef MAX_DIST_BRA
7577 #undef MAX_DIST_BCC
7578 
7579 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7580 
pBlockDestruct(pBlock * pb)7581 static void pBlockDestruct(pBlock *pb)
7582 {
7583   if(!pb)
7584     return;
7585 
7586 //  Safe_free(pb);
7587 }
7588 
7589 /*-----------------------------------------------------------------*/
7590 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7591 /*                                  name dbName and combine them   */
7592 /*                                  into one block                 */
7593 /*-----------------------------------------------------------------*/
mergepBlocks(char dbName)7594 static void mergepBlocks(char dbName)
7595 {
7596   pBlock *pb, *pbmerged = NULL,*pbn;
7597 
7598   pb = the_pFile->pbHead;
7599 
7600   //fprintf(stderr," merging blocks named %c\n",dbName);
7601   while(pb) {
7602 
7603     pbn = pb->next;
7604     //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7605     if( getpBlock_dbName(pb) == dbName) {
7606 
7607       //fprintf(stderr," merged block %c\n",dbName);
7608 
7609       if(!pbmerged) {
7610         pbmerged = pb;
7611       } else {
7612         pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7613         /* pic16_addpCode2pBlock doesn't handle the tail: */
7614         pbmerged->pcTail = pb->pcTail;
7615 
7616         pb->prev->next = pbn;
7617         if(pbn)
7618           pbn->prev = pb->prev;
7619 
7620         pBlockDestruct(pb);
7621       }
7622       //pic16_printpBlock(stderr, pbmerged);
7623     }
7624     pb = pbn;
7625   }
7626 }
7627 
7628 /*-----------------------------------------------------------------*/
7629 /* AnalyzeFlow - Examine the flow of the code and optimize         */
7630 /*                                                                 */
7631 /* level 0 == minimal optimization                                 */
7632 /*   optimize registers that are used only by two instructions     */
7633 /* level 1 == maximal optimization                                 */
7634 /*   optimize by looking at pairs of instructions that use the     */
7635 /*   register.                                                     */
7636 /*-----------------------------------------------------------------*/
7637 
AnalyzeFlow(int level)7638 static void AnalyzeFlow(int level)
7639 {
7640   static int times_called=0;
7641   pBlock *pb;
7642 
7643     if(!the_pFile) {
7644       /* remove unused allocated registers before exiting */
7645       pic16_RemoveUnusedRegisters();
7646       return;
7647     }
7648 
7649     /* if this is not the first time this function has been called,
7650      * then clean up old flow information */
7651     if(times_called++) {
7652       for(pb = the_pFile->pbHead; pb; pb = pb->next)
7653         unBuildFlow(pb);
7654         pic16_RegsUnMapLiveRanges();
7655     }
7656     GpcFlowSeq = 1;
7657 
7658     /* Phase 2 - Flow Analysis - Register Banking
7659      *
7660      * In this phase, the individual flow blocks are examined
7661      * and register banking is fixed.
7662      */
7663 
7664 #if 0
7665     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7666       pic16_FixRegisterBanking(pb);
7667 #endif
7668 
7669     /* Phase 2 - Flow Analysis
7670      *
7671      * In this phase, the pCode is partition into pCodeFlow
7672      * blocks. The flow blocks mark the points where a continuous
7673      * stream of instructions changes flow (e.g. because of
7674      * a call or goto or whatever).
7675      */
7676 
7677     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7678       pic16_BuildFlow(pb);
7679 
7680     /* Phase 2 - Flow Analysis - linking flow blocks
7681      *
7682      * In this phase, the individual flow blocks are examined
7683      * to determine their order of excution.
7684      */
7685 
7686     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7687       LinkFlow(pb);
7688 
7689 #if 1
7690         if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7691                 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7692                         pic16_createDF (pb);
7693 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7694                         pic16_vcg_dump_default (pb);
7695 #endif
7696                         //pic16_destructDF (pb);
7697                 }
7698 
7699                 pic16_df_stats ();
7700                 if (0) releaseStack (); // releasing is costly...
7701         }
7702 #endif
7703 
7704     /* Phase 3 - Flow Analysis - Flow Tree
7705      *
7706      * In this phase, the individual flow blocks are examined
7707      * to determine their order of execution.
7708      */
7709 
7710     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7711       pic16_BuildFlowTree(pb);
7712 
7713 
7714     /* Phase x - Flow Analysis - Used Banks
7715      *
7716      * In this phase, the individual flow blocks are examined
7717      * to determine the Register Banks they use
7718      */
7719 
7720 #if 0
7721     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7722       FixBankFlow(pb);
7723 #endif
7724 
7725 
7726     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7727       pic16_pCodeRegMapLiveRanges(pb);
7728 
7729     pic16_RemoveUnusedRegisters();
7730     pic16_removeUnusedRegistersDF ();
7731 
7732   //  for(pb = the_pFile->pbHead; pb; pb = pb->next)
7733     pic16_pCodeRegOptimizeRegUsage(level);
7734 
7735 
7736 #if 0
7737     if(!options.nopeep)
7738       OptimizepCode('*');
7739 #endif
7740 
7741 #if 0
7742     for(pb = the_pFile->pbHead; pb; pb = pb->next)
7743       DumpFlow(pb);
7744 #endif
7745 
7746     /* debug stuff */
7747     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7748       pCode *pcflow;
7749 
7750         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7751           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7752           pcflow = pcflow->next) {
7753             FillFlow(PCFL(pcflow));
7754         }
7755     }
7756 
7757 #if 0
7758     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7759       pCode *pcflow;
7760 
7761         for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7762           (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7763           pcflow = pcflow->next) {
7764             FlowStats(PCFL(pcflow));
7765         }
7766     }
7767 #endif
7768 }
7769 
7770 /* VR -- no need to analyze banking in flow, but left here :
7771  *      1. because it may be used in the future for other purposes
7772  *      2. because if omitted we'll miss some optimization done here
7773  *
7774  * Perhaps I should rename it to something else
7775  */
7776 
7777 /*-----------------------------------------------------------------*/
7778 /* pic16_AnalyzeBanking - Called after the memory addresses have been    */
7779 /*                  assigned to the registers.                     */
7780 /*                                                                 */
7781 /*-----------------------------------------------------------------*/
7782 
pic16_AnalyzeBanking(void)7783 void pic16_AnalyzeBanking(void)
7784 {
7785   pBlock  *pb;
7786 
7787     /* Phase x - Flow Analysis - Used Banks
7788      *
7789      * In this phase, the individual flow blocks are examined
7790      * to determine the Register Banks they use
7791      */
7792 
7793     AnalyzeFlow(0);
7794     AnalyzeFlow(1);
7795 
7796     if(!options.nopeep)
7797       OptimizepCode('*');
7798 
7799 
7800     if(!the_pFile)return;
7801 
7802     if(!pic16_options.no_banksel) {
7803       for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7804 //        fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7805         pic16_FixRegisterBanking(pb);
7806       }
7807     }
7808 }
7809 
7810 /*-----------------------------------------------------------------*/
7811 /* buildCallTree - Look at the flow and extract all of the calls.  */
7812 /*-----------------------------------------------------------------*/
7813 #if 0
7814 static set *register_usage(pBlock *pb);
7815 #endif
7816 
buildCallTree(void)7817 static void buildCallTree(void)
7818 {
7819   pBranch *pbr;
7820   pBlock  *pb;
7821   pCode   *pc;
7822   reg_info *r;
7823 
7824   if(!the_pFile)
7825     return;
7826 
7827 
7828 
7829   /* Now build the call tree.
7830      First we examine all of the pCodes for functions.
7831      Keep in mind that the function boundaries coincide
7832      with pBlock boundaries.
7833 
7834      The algorithm goes something like this:
7835      We have two nested loops. The outer loop iterates
7836      through all of the pBlocks/functions. The inner
7837      loop iterates through all of the pCodes for
7838      a given pBlock. When we begin iterating through
7839      a pBlock, the variable pc_fstart, pCode of the start
7840      of a function, is cleared. We then search for pCodes
7841      of type PC_FUNCTION. When one is encountered, we
7842      initialize pc_fstart to this and at the same time
7843      associate a new pBranch object that signifies a
7844      branch entry. If a return is found, then this signifies
7845      a function exit point. We'll link the pCodes of these
7846      returns to the matching pc_fstart.
7847 
7848      When we're done, a doubly linked list of pBranches
7849      will exist. The head of this list is stored in
7850      `the_pFile', which is the meta structure for all
7851      of the pCode. Look at the pic16_printCallTree function
7852      on how the pBranches are linked together.
7853 
7854    */
7855   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7856     pCode *pc_fstart=NULL;
7857     for(pc = pb->pcHead; pc; pc = pc->next) {
7858 
7859         if(isPCI(pc) && pc_fstart) {
7860                 if(PCI(pc)->is2MemOp) {
7861                         r = pic16_getRegFromInstruction2(pc);
7862                         if(r && !strcmp(r->name, "POSTDEC1"))
7863                                 PCF(pc_fstart)->stackusage++;
7864                 } else {
7865                         r = pic16_getRegFromInstruction(pc);
7866                         if(r && !strcmp(r->name, "PREINC1"))
7867                                 PCF(pc_fstart)->stackusage--;
7868                 }
7869         }
7870 
7871       if(isPCF(pc)) {
7872         if (PCF(pc)->fname) {
7873           char buf[16];
7874 
7875           SNPRINTF(buf, sizeof(buf), "%smain", port->fun_prefix);
7876           if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7877             //fprintf(stderr," found main \n");
7878             pb->cmemmap = NULL;  /* FIXME do we need to free ? */
7879             pb->dbName = 'M';
7880           }
7881 
7882           pbr = Safe_alloc(sizeof(pBranch));
7883           pbr->pc = pc_fstart = pc;
7884           pbr->next = NULL;
7885 
7886           the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7887 
7888           // Here's a better way of doing the same:
7889           addSet(&pb->function_entries, pc);
7890 
7891         } else {
7892           // Found an exit point in a function, e.g. return
7893           // (Note, there may be more than one return per function)
7894           if(pc_fstart)
7895             pBranchLink(PCF(pc_fstart), PCF(pc));
7896 
7897           addSet(&pb->function_exits, pc);
7898         }
7899       } else if(isCALL(pc)) {
7900         addSet(&pb->function_calls,pc);
7901       }
7902     }
7903   }
7904 
7905 
7906 #if 0
7907   /* This is not needed because currently all register used
7908    * by a function are stored in stack -- VR */
7909 
7910   /* Re-allocate the registers so that there are no collisions
7911    * between local variables when one function call another */
7912 
7913   // this is weird...
7914   //  pic16_deallocateAllRegs();
7915 
7916   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7917     if(!pb->visited)
7918       register_usage(pb);
7919   }
7920 #endif
7921 
7922 }
7923 
7924 /*-----------------------------------------------------------------*/
7925 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7926 /*                all of the logical connections.                  */
7927 /*                                                                 */
7928 /* Essentially what's done here is that the pCode flow is          */
7929 /* determined.                                                     */
7930 /*-----------------------------------------------------------------*/
7931 
pic16_AnalyzepCode(char dbName)7932 void pic16_AnalyzepCode(char dbName)
7933 {
7934   pBlock *pb;
7935   int i,changes;
7936 
7937   if(!the_pFile)
7938     return;
7939 
7940   mergepBlocks('D');
7941 
7942 
7943   /* Phase 1 - Register allocation and peep hole optimization
7944    *
7945    * The first part of the analysis is to determine the registers
7946    * that are used in the pCode. Once that is done, the peep rules
7947    * are applied to the code. We continue to loop until no more
7948    * peep rule optimizations are found (or until we exceed the
7949    * MAX_PASSES threshold).
7950    *
7951    * When done, the required registers will be determined.
7952    *
7953    */
7954   i = 0;
7955   do {
7956 
7957     DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
7958     //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
7959 
7960     /* First, merge the labels with the instructions */
7961     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7962       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
7963 
7964         DFPRINTF((stderr," analyze and merging block %c\n",dbName));
7965         //fprintf(stderr," analyze and merging block %c\n",dbName);
7966         pic16_pBlockMergeLabels(pb);
7967         AnalyzepBlock(pb);
7968       } else {
7969         DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
7970       }
7971     }
7972 
7973         if(!options.nopeep)
7974                 changes = OptimizepCode(dbName);
7975         else changes = 0;
7976 
7977   } while(changes && (i++ < MAX_PASSES));
7978 
7979 
7980   buildCallTree();
7981 }
7982 
7983 
7984 /* convert a series of movff's of local regs to stack, with a single call to
7985  * a support functions which does the same thing via loop */
pic16_convertLocalRegs2Support(pCode * pcstart,pCode * pcend,int count,reg_info * r,int entry)7986 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, reg_info *r, int entry)
7987 {
7988   pBranch *pbr;
7989   pCode *pc, *pct;
7990   char *fname[]={"__lr_store", "__lr_restore"};
7991 
7992 //    pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
7993 
7994     pct = pic16_findNextInstruction(pcstart->next);
7995     do {
7996       pc = pct;
7997       pct = pc->next;   //pic16_findNextInstruction(pc->next);
7998 //      pc->print(stderr, pc);
7999       if(isPCI(pc) && PCI(pc)->label) {
8000         pbr = PCI(pc)->label;
8001         while(pbr && pbr->pc) {
8002           PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8003           pbr = pbr->next;
8004         }
8005 
8006 //        pc->print(stderr, pc);
8007         /* unlink pCode */
8008         pc->prev->next = pct;
8009         pct->prev = pc->prev;
8010 //        pc->next = NULL;
8011 //        pc->prev = NULL;
8012       }
8013     } while (pc != pcend);
8014 
8015     /* unlink movff instructions */
8016     pcstart->next = pcend;
8017     pcend->prev = pcstart;
8018 
8019     pc = pcstart;
8020 //    if(!entry) {
8021 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8022 //              pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8023 //    }
8024 
8025     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8026     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8027     pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8028 
8029 //    if(!entry) {
8030 //      pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8031 //              pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8032 //    }
8033 
8034 
8035     {
8036       symbol *sym;
8037 
8038         sym = newSymbol( fname[ entry?0:1 ], 0 );
8039         strcpy(sym->rname, fname[ entry?0:1 ]);
8040         checkAddSym(&externs, sym);
8041 
8042 //        fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8043     }
8044 }
8045 
8046 /*-----------------------------------------------------------------*/
8047 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for     */
8048 /*    local registers to a support function call                   */
8049 /*-----------------------------------------------------------------*/
pic16_OptimizeLocalRegs(void)8050 void pic16_OptimizeLocalRegs(void)
8051 {
8052   pBlock  *pb;
8053   pCode   *pc;
8054   pCodeInfo *pci;
8055   pCodeOpLocalReg *pclr;
8056   int regCount=0;
8057   int inRegCount=0;
8058   reg_info *r, *lastr=NULL, *firstr=NULL;
8059   pCode *pcstart=NULL, *pcend=NULL;
8060   int inEntry=0;
8061   char *curFunc=NULL;
8062 
8063         /* Overview:
8064          *   local_regs begin mark
8065          *      MOVFF r0x01, POSTDEC1
8066          *      MOVFF r0x02, POSTDEC1
8067          *      ...
8068          *      ...
8069          *      MOVFF r0x0n, POSTDEC1
8070          *   local_regs end mark
8071          *
8072          * convert the above to the below:
8073          *      MOVLW   starting_register_index
8074          *      MOVWF   PRODL
8075          *      MOVLW   register_count
8076          *      call    __save_registers_in_stack
8077          */
8078 
8079     if(!the_pFile)
8080       return;
8081 
8082     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8083       inRegCount = regCount = 0;
8084       firstr = lastr = NULL;
8085       for(pc = pb->pcHead; pc; pc = pc->next) {
8086 
8087         /* hold current function name */
8088         if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8089 
8090         if(pc && (pc->type == PC_INFO)) {
8091           pci = PCINF(pc);
8092 
8093           if(pci->type == INF_LOCALREGS) {
8094             pclr = PCOLR(pci->oper1);
8095 
8096             if((pclr->type == LR_ENTRY_BEGIN)
8097               || (pclr->type == LR_ENTRY_END))inEntry = 1;
8098             else inEntry = 0;
8099 
8100             switch(pclr->type) {
8101               case LR_ENTRY_BEGIN:
8102               case LR_EXIT_BEGIN:
8103                         inRegCount = 1; regCount = 0;
8104                         pcstart = pc;   //pic16_findNextInstruction(pc->next);
8105                         firstr = lastr = NULL;
8106                         break;
8107 
8108               case LR_ENTRY_END:
8109               case LR_EXIT_END:
8110                         inRegCount = -1;
8111                         pcend = pc;     //pic16_findPrevInstruction(pc->prev);
8112 
8113 #if 1
8114                         if(curFunc && inWparamList(curFunc+1)) {
8115                           fprintf(stderr, "sdcc: %s: warning: disabling lr-support for function %s\n",
8116                                         filename, curFunc);
8117                         } else {
8118                           if(regCount>2) {
8119                             pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8120                               firstr, inEntry);
8121                           }
8122                         }
8123 #endif
8124                         firstr = lastr = NULL;
8125                         break;
8126             }
8127 
8128             if(inRegCount == -1) {
8129 //              fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8130               regCount = 0;
8131               inRegCount = 0;
8132             }
8133           }
8134         } else {
8135           if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8136             if(inEntry)
8137               r = pic16_getRegFromInstruction(pc);
8138             else
8139               r = pic16_getRegFromInstruction2(pc);
8140             if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8141               if(!firstr)firstr = r;
8142               regCount++;
8143 //              fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8144             }
8145           }
8146         }
8147       }
8148     }
8149 }
8150 
8151 /*-----------------------------------------------------------------*/
8152 /* ispCodeFunction - returns true if *pc is the pCode of a         */
8153 /*                   function                                      */
8154 /*-----------------------------------------------------------------*/
ispCodeFunction(pCode * pc)8155 static bool ispCodeFunction(pCode *pc)
8156 {
8157 
8158   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8159     return 1;
8160 
8161   return 0;
8162 }
8163 
8164 /*-----------------------------------------------------------------*/
8165 /* findFunction - Search for a function by name (given the name)   */
8166 /*                in the set of all functions that are in a pBlock */
8167 /* (note - I expect this to change because I'm planning to limit   */
8168 /*  pBlock's to just one function declaration                      */
8169 /*-----------------------------------------------------------------*/
findFunction(char * fname)8170 static pCode *findFunction(char *fname)
8171 {
8172   pBlock *pb;
8173   pCode *pc;
8174   if(!fname)
8175     return NULL;
8176 
8177   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8178 
8179     pc = setFirstItem(pb->function_entries);
8180     while(pc) {
8181 
8182       if((pc->type == PC_FUNCTION) &&
8183          (PCF(pc)->fname) &&
8184          (strcmp(fname, PCF(pc)->fname)==0))
8185         return pc;
8186 
8187       pc = setNextItem(pb->function_entries);
8188 
8189     }
8190 
8191   }
8192   return NULL;
8193 }
8194 
8195 #if 0
8196 static void MarkUsedRegisters(set *regset)
8197 {
8198 
8199   regs *r1,*r2;
8200 
8201   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8202 //      fprintf(stderr, "marking register = %s\t", r1->name);
8203     r2 = pic16_regWithIdx(r1->rIdx);
8204 //      fprintf(stderr, "to register = %s\n", r2->name);
8205     r2->isFree = 0;
8206     r2->wasUsed = 1;
8207   }
8208 }
8209 #endif
8210 
pBlockStats(FILE * of,pBlock * pb)8211 static void pBlockStats(FILE *of, pBlock *pb)
8212 {
8213   pCode *pc;
8214   reg_info  *r;
8215 
8216         if(!pic16_pcode_verbose)return;
8217 
8218   fprintf(of,";***\n;  pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8219 
8220   // for now just print the first element of each set
8221   pc = setFirstItem(pb->function_entries);
8222   if(pc) {
8223     fprintf(of,";entry:  ");
8224     pc->print(of,pc);
8225   }
8226   pc = setFirstItem(pb->function_exits);
8227   if(pc) {
8228     fprintf(of,";has an exit\n");
8229     //pc->print(of,pc);
8230   }
8231 
8232   pc = setFirstItem(pb->function_calls);
8233   if(pc) {
8234     fprintf(of,";functions called:\n");
8235 
8236     while(pc) {
8237       if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8238         fprintf(of,";   %s\n",pic16_get_op_from_instruction(PCI(pc)));
8239       }
8240       pc = setNextItem(pb->function_calls);
8241     }
8242   }
8243 
8244   r = setFirstItem(pb->tregisters);
8245   if(r) {
8246     int n = elementsInSet(pb->tregisters);
8247 
8248     fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8249 
8250     while (r) {
8251       fprintf(of,   ";   %s\n",r->name);
8252       r = setNextItem(pb->tregisters);
8253     }
8254   }
8255 
8256   fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8257 }
8258 
8259 /*-----------------------------------------------------------------*/
8260 /*-----------------------------------------------------------------*/
8261 #if 0
8262 static void sequencepCode(void)
8263 {
8264   pBlock *pb;
8265   pCode *pc;
8266 
8267 
8268   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8269 
8270     pb->seq = GpCodeSequenceNumber+1;
8271 
8272     for( pc = pb->pcHead; pc; pc = pc->next)
8273       pc->seq = ++GpCodeSequenceNumber;
8274   }
8275 }
8276 #endif
8277 
8278 #if 0
8279 /*-----------------------------------------------------------------*/
8280 /*-----------------------------------------------------------------*/
8281 static set *register_usage(pBlock *pb)
8282 {
8283   pCode *pc,*pcn;
8284   set *registers=NULL;
8285   set *registersInCallPath = NULL;
8286 
8287   /* check recursion */
8288 
8289   pc = setFirstItem(pb->function_entries);
8290 
8291   if(!pc)
8292     return registers;
8293 
8294   pb->visited = TRUE;
8295 
8296   if(pc->type != PC_FUNCTION)
8297     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8298 
8299   pc = setFirstItem(pb->function_calls);
8300   for( ; pc; pc = setNextItem(pb->function_calls)) {
8301 
8302     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8303       char *dest = pic16_get_op_from_instruction(PCI(pc));
8304 
8305       pcn = findFunction(dest);
8306       if(pcn)
8307         registersInCallPath = register_usage(pcn->pb);
8308     } else
8309       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8310 
8311   }
8312 
8313 #ifdef PCODE_DEBUG
8314   pBlockStats(stderr,pb);  // debug
8315 #endif
8316 
8317   // Mark the registers in this block as used.
8318 
8319   MarkUsedRegisters(pb->tregisters);
8320   if(registersInCallPath) {
8321     /* registers were used in the functions this pBlock has called */
8322     /* so now, we need to see if these collide with the ones we are */
8323     /* using here */
8324 
8325     regs *r1,*r2, *newreg;
8326 
8327     DFPRINTF((stderr,"comparing registers\n"));
8328 
8329     r1 = setFirstItem(registersInCallPath);
8330     while(r1) {
8331 
8332       r2 = setFirstItem(pb->tregisters);
8333 
8334       while(r2 && (r1->type != REG_STK)) {
8335 
8336         if(r2->rIdx == r1->rIdx) {
8337           newreg = pic16_findFreeReg(REG_GPR);
8338 
8339 
8340           if(!newreg) {
8341             DFPRINTF((stderr,"Bummer, no more registers.\n"));
8342             exit(1);
8343           }
8344 
8345           DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8346                   r1->rIdx, newreg->rIdx));
8347           r2->rIdx = newreg->rIdx;
8348           //if(r2->name) Safe_free(r2->name);
8349           if(newreg->name)
8350             r2->name = Safe_strdup(newreg->name);
8351           else
8352             r2->name = NULL;
8353           newreg->isFree = 0;
8354           newreg->wasUsed = 1;
8355         }
8356         r2 = setNextItem(pb->tregisters);
8357       }
8358 
8359       r1 = setNextItem(registersInCallPath);
8360     }
8361 
8362     /* Collisions have been resolved. Now free the registers in the call path */
8363     r1 = setFirstItem(registersInCallPath);
8364     while(r1) {
8365       if(r1->type != REG_STK) {
8366         newreg = pic16_regWithIdx(r1->rIdx);
8367         newreg->isFree = 1;
8368       }
8369       r1 = setNextItem(registersInCallPath);
8370     }
8371 
8372   }// else
8373   //    MarkUsedRegisters(pb->registers);
8374 
8375   registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8376 #ifdef PCODE_DEBUG
8377   if(registers)
8378     DFPRINTF((stderr,"returning regs\n"));
8379   else
8380     DFPRINTF((stderr,"not returning regs\n"));
8381 
8382   DFPRINTF((stderr,"pBlock after register optim.\n"));
8383   pBlockStats(stderr,pb);  // debug
8384 #endif
8385 
8386   return registers;
8387 }
8388 #endif
8389 
8390 /*-----------------------------------------------------------------*/
8391 /* pct2 - writes the call tree to a file                           */
8392 /*                                                                 */
8393 /*-----------------------------------------------------------------*/
pct2(FILE * of,pBlock * pb,int indent,int usedstack)8394 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8395 {
8396   pCode *pc,*pcn;
8397   int i;
8398   //  set *registersInCallPath = NULL;
8399 
8400   if(!of)
8401     return;
8402 
8403   if(indent > 10) {
8404         fprintf(of, "recursive function\n");
8405     return; //recursion ?
8406   }
8407 
8408   pc = setFirstItem(pb->function_entries);
8409 
8410   if(!pc)
8411     return;
8412 
8413   pb->visited = FALSE;
8414 
8415   for(i=0;i<indent;i++)   // Indentation
8416         fputs("+   ", of);
8417   fputs("+- ", of);
8418 
8419   if(pc->type == PC_FUNCTION) {
8420     usedstack += PCF(pc)->stackusage;
8421     fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8422   } else return;  // ???
8423 
8424 
8425   pc = setFirstItem(pb->function_calls);
8426   for( ; pc; pc = setNextItem(pb->function_calls)) {
8427 
8428     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8429       char *dest = pic16_get_op_from_instruction(PCI(pc));
8430 
8431       pcn = findFunction(dest);
8432       if(pcn)
8433         pct2(of,pcn->pb,indent+1, usedstack);   // + PCF(pcn)->stackusage);
8434     } else
8435       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8436 
8437   }
8438 }
8439 
8440 
8441 /*-----------------------------------------------------------------*/
8442 /* pic16_printCallTree - writes the call tree to a file                  */
8443 /*                                                                 */
8444 /*-----------------------------------------------------------------*/
8445 
pic16_printCallTree(FILE * of)8446 void pic16_printCallTree(FILE *of)
8447 {
8448   pBranch *pbr;
8449   pBlock  *pb;
8450   pCode   *pc;
8451 
8452   if(!the_pFile)
8453     return;
8454 
8455   if(!of)
8456     of = stderr;
8457 
8458   fprintf(of, "\npBlock statistics\n");
8459   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
8460     pBlockStats(of,pb);
8461 
8462 
8463   fprintf(of,"Call Tree\n");
8464   pbr = the_pFile->functions;
8465   while(pbr) {
8466     if(pbr->pc) {
8467       pc = pbr->pc;
8468       if(!ispCodeFunction(pc))
8469         fprintf(of,"bug in call tree");
8470 
8471 
8472       fprintf(of,"Function: %s\n", PCF(pc)->fname);
8473 
8474       while(pc->next && !ispCodeFunction(pc->next)) {
8475         pc = pc->next;
8476         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8477           fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8478       }
8479     }
8480 
8481     pbr = pbr->next;
8482   }
8483 
8484 
8485   fprintf(of,"\n**************\n\na better call tree\n");
8486   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8487 //    if(pb->visited)
8488       pct2(of,pb,0,0);
8489   }
8490 
8491   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8492     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8493   }
8494 }
8495 
8496 
8497 
8498 /*-----------------------------------------------------------------*/
8499 /*                                                                 */
8500 /*-----------------------------------------------------------------*/
8501 
InlineFunction(pBlock * pb)8502 static void InlineFunction(pBlock *pb)
8503 {
8504   pCode *pc;
8505   pCode *pc_call;
8506 
8507   if(!pb)
8508     return;
8509 
8510   pc = setFirstItem(pb->function_calls);
8511 
8512   for( ; pc; pc = setNextItem(pb->function_calls)) {
8513 
8514     if(isCALL(pc)) {
8515       pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8516       pCode *pct;
8517       pCode *pce;
8518 
8519       pBranch *pbr;
8520 
8521       if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) {               /* change 0 to 1 to enable inlining */
8522 
8523         //fprintf(stderr,"Cool can inline:\n");
8524         //pcn->print(stderr,pcn);
8525 
8526         //fprintf(stderr,"recursive call Inline\n");
8527         InlineFunction(pcn->pb);
8528         //fprintf(stderr,"return from recursive call Inline\n");
8529 
8530         /*
8531           At this point, *pc points to a CALL mnemonic, and
8532           *pcn points to the function that is being called.
8533 
8534           To in-line this call, we need to remove the CALL
8535           and RETURN(s), and link the function pCode in with
8536           the CALLee pCode.
8537 
8538         */
8539 
8540 
8541         /* Remove the CALL */
8542         pc_call = pc;
8543         pc = pc->prev;
8544 
8545         /* remove callee pBlock from the pBlock linked list */
8546         removepBlock(pcn->pb);
8547 
8548         pce = pcn;
8549         while(pce) {
8550           pce->pb = pb;
8551           pce = pce->next;
8552         }
8553 
8554         /* Remove the Function pCode */
8555         pct = pic16_findNextInstruction(pcn->next);
8556 
8557         /* Link the function with the callee */
8558         pc->next = pcn->next;
8559         pcn->next->prev = pc;
8560 
8561         /* Convert the function name into a label */
8562 
8563         pbr = Safe_alloc(sizeof(pBranch));
8564         pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8565         pbr->next = NULL;
8566         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8567         PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8568 
8569         /* turn all of the return's except the last into goto's */
8570         /* check case for 2 instruction pBlocks */
8571         pce = pic16_findNextInstruction(pcn->next);
8572         while(pce) {
8573           pCode *pce_next = pic16_findNextInstruction(pce->next);
8574 
8575           if(pce_next == NULL) {
8576             /* found the last return */
8577             pCode *pc_call_next =  pic16_findNextInstruction(pc_call->next);
8578 
8579             //fprintf(stderr,"found last return\n");
8580             //pce->print(stderr,pce);
8581             pce->prev->next = pc_call->next;
8582             pc_call->next->prev = pce->prev;
8583             PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8584                                                       PCI(pce)->label);
8585           }
8586 
8587           pce = pce_next;
8588         }
8589       }
8590     } else
8591       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8592   }
8593 }
8594 
8595 /*-----------------------------------------------------------------*/
8596 /*                                                                 */
8597 /*-----------------------------------------------------------------*/
8598 
pic16_InlinepCode(void)8599 void pic16_InlinepCode(void)
8600 {
8601   pBlock  *pb;
8602   pCode   *pc;
8603 
8604   if(!the_pFile)
8605     return;
8606 
8607   if(!functionInlining)
8608     return;
8609 
8610   /* Loop through all of the function definitions and count the
8611    * number of times each one is called */
8612   //fprintf(stderr,"inlining %d\n",__LINE__);
8613 
8614   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8615 
8616     pc = setFirstItem(pb->function_calls);
8617 
8618     for( ; pc; pc = setNextItem(pb->function_calls)) {
8619 
8620       if(isCALL(pc)) {
8621         pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8622         if(pcn && isPCF(pcn)) {
8623           PCF(pcn)->ncalled++;
8624         }
8625       } else
8626         fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8627 
8628     }
8629   }
8630 
8631   //fprintf(stderr,"inlining %d\n",__LINE__);
8632 
8633   /* Now, Loop through the function definitions again, but this
8634    * time inline those functions that have only been called once. */
8635 
8636   InlineFunction(the_pFile->pbHead);
8637   //fprintf(stderr,"inlining %d\n",__LINE__);
8638 
8639   for(pb = the_pFile->pbHead; pb; pb = pb->next)
8640     unBuildFlow(pb);
8641 }
8642 
8643 static const char *pic_optype_names[] = {
8644         "PO_NONE",         // No operand e.g. NOP
8645         "PO_W",              // The working register (as a destination)
8646         "PO_WREG",           // The working register (as a file register)
8647         "PO_STATUS",         // The 'STATUS' register
8648         "PO_BSR",            // The 'BSR' register
8649         "PO_FSR0",           // The "file select register" (in PIC18 family it's one
8650                              // of three)
8651         "PO_INDF0",          // The Indirect register
8652         "PO_INTCON",         // Interrupt Control register
8653         "PO_GPR_REGISTER",   // A general purpose register
8654         "PO_GPR_BIT",        // A bit of a general purpose register
8655         "PO_GPR_TEMP",       // A general purpose temporary register
8656         "PO_SFR_REGISTER",   // A special function register (e.g. PORTA)
8657         "PO_PCL",            // Program counter Low register
8658         "PO_PCLATH",         // Program counter Latch high register
8659         "PO_PCLATU",         // Program counter Latch upper register
8660         "PO_PRODL",          // Product Register Low
8661         "PO_PRODH",          // Product Register High
8662         "PO_LITERAL",        // A constant
8663         "PO_REL_ADDR",       // A relative address
8664         "PO_IMMEDIATE",      //  (8051 legacy)
8665         "PO_DIR",            // Direct memory (8051 legacy)
8666         "PO_CRY",            // bit memory (8051 legacy)
8667         "PO_BIT",            // bit operand.
8668         "PO_STR",            //  (8051 legacy)
8669         "PO_LABEL",
8670         "PO_WILD",           // Wild card operand in peep optimizer
8671         "PO_TWO_OPS"         // combine two operands
8672 };
8673 
8674 
dumpPicOptype(PIC_OPTYPE type)8675 const char *dumpPicOptype(PIC_OPTYPE type)
8676 {
8677         assert( type >= 0 && type < sizeof(pic_optype_names)/sizeof( char *) );
8678         return (pic_optype_names[ type ]);
8679 }
8680 
8681 
8682 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8683 #include "graph.h"
8684 
8685 #define MAX_COMMON_BANK_SIZE    32
8686 #define FIRST_PSEUDO_BANK_NR  1000
8687 
8688 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8689 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8690 hTab *coerce = NULL;   // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8691 Graph *adj = NULL;
8692 
8693 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8694 
8695 typedef struct {
8696   pseudoBankNr bank;  // number assigned to this pseudoBank
8697   unsigned int size;  // number of operands assigned to this bank
8698   unsigned int ref;   // number of symbols referring to this pseudoBank (for garbage collection)
8699 } pseudoBank;
8700 
8701 /*----------------------------------------------------------------------*/
8702 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8703 /*----------------------------------------------------------------------*/
hashSymbol(const char * str)8704 unsigned int hashSymbol (const char *str)
8705 {
8706   unsigned int res = 0;
8707   if (!str) return 0;
8708 
8709   while (*str) {
8710     res ^= (*str);
8711     res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8712     str++;
8713   } // while
8714 
8715   return res;
8716 }
8717 
8718 /*-----------------------------------------------------------------------*/
8719 /* compareSymbol - return 1 iff sym1 equals sym2                         */
8720 /*-----------------------------------------------------------------------*/
compareSymbol(const void * sym1,const void * sym2)8721 int compareSymbol (const void *sym1, const void *sym2)
8722 {
8723   char *s1 = (char*) sym1;
8724   char *s2 = (char*) sym2;
8725 
8726   return (strcmp (s1,s2) == 0);
8727 }
8728 
8729 /*-----------------------------------------------------------------------*/
8730 /* comparePre - return 1 iff p1 == p2                                    */
8731 /*-----------------------------------------------------------------------*/
comparePtr(const void * p1,const void * p2)8732 int comparePtr (const void *p1, const void *p2)
8733 {
8734   return (p1 == p2);
8735 }
8736 
8737 /*----------------------------------------------------------*/
8738 /* getSymbolFromOperand - return a pointer to the symbol in */
8739 /*                        the given operand and its length  */
8740 /*----------------------------------------------------------*/
getSymbolFromOperand(char * op,int * len)8741 char *getSymbolFromOperand (char *op, int *len)
8742 {
8743   char *sym, *curr;
8744   *len = 0;
8745 
8746   if (!op) return NULL;
8747 
8748   // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8749   sym = op;
8750   if (*sym == '(') sym++;
8751 
8752   curr = sym;
8753   while (((*curr >= 'A') && (*curr <= 'Z'))
8754          || ((*curr >= 'a') && (*curr <= 'z'))
8755          || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8756          || (*curr == '_')) {
8757     // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8758     curr++;
8759     (*len)++;
8760   } // while
8761 
8762   return sym;
8763 }
8764 
8765 /*--------------------------------------------------------------------------*/
8766 /* getSymFromBank - get (one) name of a symbol assigned to the given bank   */
8767 /*--------------------------------------------------------------------------*/
getSymFromBank(pseudoBankNr bank)8768 char *getSymFromBank (pseudoBankNr bank)
8769 {
8770   assert (bank2sym);
8771 
8772   if (bank < 0) return "<INVALID BANK NR>";
8773   return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8774 }
8775 
8776 /*-----------------------------------------------------------------------*/
8777 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo   */
8778 /*                           bank number (uses hTab sym2bank), if the    */
8779 /*                           symbol is not yet assigned a pseudo bank it */
8780 /*                           is assigned one here                        */
8781 /*-----------------------------------------------------------------------*/
getPseudoBankNrFromOperand(const char * op)8782 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8783 {
8784   static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8785   pseudoBankNr bank;
8786   unsigned int hash;
8787 
8788   assert (sym2bank);
8789 
8790   hash = hashSymbol (op) % sym2bank->size;
8791   bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8792   if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8793 
8794   if (bank == UNKNOWN_BANK) {
8795     // create a pseudo bank for the operand
8796     bank = next_bank++;
8797     hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8798     hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8799     getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8800     //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8801   } else {
8802     //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8803   } // if
8804 
8805   assert (bank >= 0);
8806 
8807   return bank;
8808 }
8809 
8810 /*--------------------------------------------------------------------*/
8811 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8812 /*--------------------------------------------------------------------*/
isBanksel(pCode * pc)8813 int isBanksel (pCode *pc)
8814 {
8815   if (!pc) return 0;
8816 
8817   if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8818     // BANKSEL <variablename>  or  MOVLB <banknr>
8819     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8820     return 1;
8821   }
8822 
8823   // check for inline assembler BANKSELs
8824   if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8825                                             STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8826     //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8827     return 1;
8828   }
8829 
8830   // assume pc is no BANKSEL instruction
8831   return 0;
8832 }
8833 
8834 /*---------------------------------------------------------------------------------*/
8835 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR  */
8836 /*                  This method can not guarantee to find all modifications of the */
8837 /*                  BSR (e.g. via INDirection registers) but covers all compiler   */
8838 /*                  generated plus some cases.                                     */
8839 /*---------------------------------------------------------------------------------*/
invalidatesBSR(pCode * pc)8840 int invalidatesBSR(pCode *pc)
8841 {
8842   // assembler directives invalidate BSR (well, they might, we don't know)
8843   if (isPCAD(pc)) return 1;
8844 
8845   // only ASMDIRs and pCodeInstructions can invalidate BSR
8846   if (!isPCI(pc)) return 0;
8847 
8848   // we have a pCodeInstruction
8849 
8850   // check for BSR modifying instructions
8851   switch (PCI(pc)->op) {
8852   case POC_CALL:
8853   case POC_RCALL:
8854   case POC_MOVLB:
8855   case POC_RETFIE:  // might be used as CALL replacement
8856   case POC_RETLW:   // might be used as CALL replacement
8857   case POC_RETURN:  // might be used as CALL replacement
8858   case POC_BANKSEL:
8859     return 1;
8860     break;
8861 
8862   default:          // other instruction do not change BSR unless BSR is an explicit operand!
8863     // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8864     break;
8865   } // switch
8866 
8867   // no change of BSR possible/probable
8868   return 0;
8869 }
8870 
8871 /*------------------------------------------------------------*/
8872 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8873 /*                      the symbol referenced in this BANKSEL */
8874 /*------------------------------------------------------------*/
getBankFromBanksel(pCode * pc)8875 pseudoBankNr getBankFromBanksel (pCode *pc)
8876 {
8877   char *sym;
8878   int data = 0;
8879 
8880   if (!pc) return INVALID_BANK;
8881 
8882   if (isPCAD(pc) && PCAD(pc)->directive) {
8883     if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8884       // get symbolname from PCAD(pc)->arg
8885       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8886       sym = PCAD(pc)->arg;
8887       data = getPseudoBankNrFromOperand (sym);
8888       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8889     } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8890       // get (literal) bank number from PCAD(pc)->arg
8891       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8892       assert (0 && "not yet implemented - turn off banksel optimization for now");
8893     }
8894   } else if (isPCI(pc)) {
8895     if (PCI(pc)->op == POC_BANKSEL) {
8896       // get symbolname from PCI(pc)->pcop->name (?)
8897       //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8898       sym = PCI(pc)->pcop->name;
8899       data = getPseudoBankNrFromOperand (sym);
8900       //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8901     } else if (PCI(pc)->op == POC_MOVLB) {
8902       // get (literal) bank number from PCI(pc)->pcop->name
8903       fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8904       assert (0 && "not yet implemented - turn off banksel optimization for now");
8905     }
8906   }
8907 
8908   if (data == 0)
8909     // no assigned bank could be found
8910     return UNKNOWN_BANK;
8911   else
8912     return data;
8913 }
8914 
8915 /*------------------------------------------------------------------------------*/
8916 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr  */
8917 /*------------------------------------------------------------------------------*/
getEffectiveBank(pseudoBankNr bank)8918 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8919 {
8920   pseudoBank *data;
8921 
8922   if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8923 
8924   do {
8925     //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8926     data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8927     if (data) {
8928       if (data->bank != bank)
8929         bank = data->bank;
8930       else
8931         data = NULL;
8932     }
8933   } while (data);
8934 
8935   //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
8936   return bank;
8937 }
8938 
8939 /*------------------------------------------------------------------*/
8940 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
8941 /*                        bank is selected at a given pCode         */
8942 /*------------------------------------------------------------------*/
8943 
8944 /* Create a graph with pseudo banks as its nodes and switches between
8945  * these as edges (with the edge weight representing the absolute
8946  * number of BANKSELs from one to the other).
8947  * Removes redundand BANKSELs instead iff mod == 1.
8948  * BANKSELs update the pseudo BSR, labels invalidate the current BSR
8949  * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
8950  * pseudo BSR.
8951  * TODO: check ALL instructions operands if they modify BSR directly...
8952  *
8953  * pb - the pBlock to annotate
8954  * mod  - select either graph creation (0) or BANKSEL removal (1)
8955  */
attachBsrInfo2pBlock(pBlock * pb,int mod)8956 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
8957 {
8958   pCode *pc, *pc_next;
8959   unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
8960   int isBankselect = 0;
8961   unsigned int banksels=0;
8962 
8963   if (!pb) return 0;
8964 
8965   pc = pic16_findNextInstruction(pb->pcHead);
8966   while (pc) {
8967     isBankselect = isBanksel (pc);
8968     pc_next = pic16_findNextInstruction (pc->next);
8969 
8970     if (!hasNoLabel (pc)) {
8971       // we don't know our predecessors -- assume different BSRs
8972       prevBSR = UNKNOWN_BANK;
8973       pseudoBSR = UNKNOWN_BANK;
8974       //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
8975     } // if
8976 
8977     // check if this is a BANKSEL instruction
8978     if (isBankselect) {
8979       pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
8980       //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
8981       if (mod) {
8982         if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
8983           //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
8984           if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
8985           pic16_unlinkpCode (pc);
8986           banksels++;
8987         }
8988       } else {
8989         addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
8990         banksels++;
8991       }
8992     } // if
8993 
8994     if (!isBankselect && invalidatesBSR(pc)) {
8995       // check if this instruction invalidates the pseudoBSR
8996       pseudoBSR = UNKNOWN_BANK;
8997       //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
8998     } // if
8999 
9000     prevBSR = pseudoBSR;
9001     pc = pc_next;
9002   } // while
9003 
9004   return banksels;
9005 }
9006 
9007 /*------------------------------------------------------------------------------------*/
9008 /* assignToSameBank - returns 0 on success or an error code                           */
9009 /*  1 - common bank would be too large                                                */
9010 /*  2 - assignment to fixed (absolute) bank not performed                             */
9011 /*                                                                                    */
9012 /* This functions assumes that unsplittable operands are already assigned to the same */
9013 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same   */
9014 /* bank so that we can make sure the bytes are laid out sequentially in memory)       */
9015 /* TODO: Symbols with an abslute address must be handled specially!                   */
9016 /*------------------------------------------------------------------------------------*/
assignToSameBank(int bank0,int bank1,int doAbs,int force)9017 int assignToSameBank (int bank0, int bank1, int doAbs, int force)
9018 {
9019   int eff0, eff1, dummy;
9020   pseudoBank *pbank0, *pbank1;
9021   hashtItem *hitem;
9022 
9023   eff0 = getEffectiveBank (bank0);
9024   eff1 = getEffectiveBank (bank1);
9025 
9026   //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9027 
9028   // nothing to do if already same bank
9029   if (eff0 == eff1) return 0;
9030 
9031   if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9032     return 2;
9033 
9034   // ensure eff0 < eff1
9035   if (eff0 > eff1) {
9036     // swap eff0 and eff1
9037     dummy = eff0;
9038     eff0 = eff1;
9039     eff1 = dummy;
9040     dummy = bank0;
9041     bank0 = bank1;
9042     bank1 = dummy;
9043   } // if
9044 
9045   // now assign bank eff1 to bank eff0
9046   pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9047   if (!pbank0) {
9048     pbank0 = Safe_alloc(sizeof(pseudoBank));
9049     pbank0->bank = eff0;
9050     pbank0->size = 1;
9051     pbank0->ref = 1;
9052     hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9053   } // if
9054 
9055   pbank1 = NULL;
9056   hitem = hTabSearch (coerce, eff1 % coerce->size);
9057   while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9058     hitem = hitem->next;
9059 
9060   if (hitem) pbank1 = (pseudoBank *) hitem->item;
9061 
9062 #if 0
9063   fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9064            pbank0->bank, pbank0->size,
9065            getSymFromBank (eff0), getSymFromBank (eff1));
9066 #endif
9067 
9068   if (pbank1) {
9069     if (!force && (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE)) {
9070 #if 0
9071       fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9072                pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9073                pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9074                getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9075 #endif
9076       return 1;
9077     } // if
9078     pbank0->size += pbank1->size;
9079     pbank1->ref--;
9080     if (pbank1->ref == 0) Safe_free (pbank1);
9081   } else {
9082     pbank0->size++;
9083   } // if
9084 
9085   if (hitem)
9086     hitem->item = pbank0;
9087   else
9088     hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9089   pbank0->ref++;
9090 
9091   //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9092 
9093   return 0;
9094 }
9095 
9096 /*----------------------------------------------------------------*/
9097 /* mergeGraphNodes - combines two nodes into one and modifies all */
9098 /*                   edges to and from the nodes accordingly      */
9099 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9100 /* then also (B,A) must be an edge (possibly with weight 0).      */
9101 /*----------------------------------------------------------------*/
mergeGraphNodes(GraphNode * node1,GraphNode * node2)9102 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9103 {
9104   GraphEdge *edge, *backedge, *nextedge;
9105   GraphNode *node;
9106   int backweight;
9107 
9108   assert (node1 && node2);
9109   assert (node1 != node2);
9110 
9111   // add all edges starting at node2 to node1
9112   edge = node2->edge;
9113   while (edge) {
9114     nextedge = edge->next;
9115     node = edge->node;
9116     backedge = getGEdge (node, node2);
9117     if (backedge)
9118       backweight = backedge->weight;
9119     else
9120       backweight = 0;
9121     // insert edges (node1,node) and (node,node1)
9122     addGEdge2 (node1, node, edge->weight, backweight);
9123     // remove edges (node, node2) and (node2, node)
9124     remGEdge (node2, node);
9125     remGEdge (node, node2);
9126     edge = nextedge;
9127   } // while
9128 
9129   // now node2 should not be referenced by any other GraphNode...
9130   //remGNode (adj, node2->data, node2->hash);
9131 }
9132 
9133 /*----------------------------------------------------------------*/
9134 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9135 /*----------------------------------------------------------------*/
showGraph(Graph * g)9136 void showGraph (Graph *g)
9137 {
9138   GraphNode *node;
9139   GraphEdge *edge;
9140   pseudoBankNr bankNr;
9141   pseudoBank *pbank;
9142   unsigned int size;
9143 
9144   node = g->node;
9145   while (node) {
9146     edge = node->edge;
9147     bankNr = getEffectiveBank (node->hash);
9148     assert (bankNr >= 0);
9149     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9150     if (pbank) {
9151       bankNr = pbank->bank;
9152       size = pbank->size;
9153     } else {
9154       size = 1;
9155     }
9156 
9157     fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9158 
9159     while (edge) {
9160       if (edge->weight > 0)
9161         fprintf (stderr, "  %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9162       edge = edge->next;
9163     } // while (edge)
9164     node = node->next;
9165   } // while (node)
9166 }
9167 
9168 /*---------------------------------------------------------------*/
9169 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9170 /*---------------------------------------------------------------*/
pic16_OptimizeBanksel()9171 void pic16_OptimizeBanksel ()
9172 {
9173   GraphNode *node, *node1, *node1next;
9174 
9175 #if 0
9176   // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9177   GraphEdge *edge, *backedge;
9178   GraphEdge *max;
9179   int maxWeight, weight, mergeMore, absMaxWeight;
9180   pseudoBankNr curr0, curr1;
9181 #endif
9182   pseudoBank *pbank;
9183   pseudoBankNr bankNr;
9184   char *base_symbol0, *base_symbol1;
9185   int len0, len1;
9186   pBlock *pb;
9187   set *set;
9188   reg_info *reg;
9189   unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9190 
9191   //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9192 
9193   if (!the_pFile || !the_pFile->pbHead) return;
9194 
9195   adj = newGraph (NULL);
9196   sym2bank = newHashTable ( 255 );
9197   bank2sym = newHashTable ( 255 );
9198   coerce = newHashTable ( 255 );
9199 
9200   // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9201   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9202     bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9203   } // for pb
9204 
9205 #if 1
9206   // assign symbols with absolute addresses to their respective bank nrs
9207   set = pic16_fix_udata;
9208   for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9209     bankNr = reg->address >> 8;
9210     node = getOrAddGNode (adj, NULL, bankNr);
9211     bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9212     assignToSameBank (node->hash, bankNr, 1, 1);
9213 
9214     assert (bankNr >= 0);
9215     pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9216     if (!pbank) {
9217       pbank = Safe_alloc(sizeof(pseudoBank));
9218       pbank->bank = reg->address >> 8; //FIXED_BANK;
9219       pbank->size = 1;
9220       pbank->ref = 1;
9221       hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9222     } else {
9223       assert (pbank->bank == (reg->address >> 8));
9224       pbank->bank = reg->address >> 8; //FIXED_BANK;
9225       pbank->size++;
9226     }
9227     //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9228   } // for reg
9229 #endif
9230 
9231 #if 1
9232   // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9233   //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9234   node = adj->node;
9235   while (node) {
9236     if (node->hash < 0) { node = node->next; continue; }
9237     base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9238     node1 = node->next;
9239     while (node1) {
9240       if (node1->hash < 0) { node1 = node1->next; continue; }
9241       node1next = node1->next;
9242       base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9243       if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9244         int res;
9245         // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9246         //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9247         if (0 != (res = assignToSameBank (node->hash, node1->hash, 0, 1))) {
9248           fprintf (stderr, "%s(%d) == %s(%d), res=%d\n", base_symbol0, len0, base_symbol1, len1, res);
9249           assert (0 && "Could not assign a symbol to a bank!");
9250         }
9251         mergeGraphNodes (node, node1);
9252         /*
9253         if (node->hash < node1->hash)
9254           mergeGraphNodes (node, node1);
9255         else
9256           mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9257         */
9258       } // if
9259       node1 = node1next;
9260     } // while (node1)
9261     node = node->next;
9262   } // while (node)
9263 #endif
9264 
9265 #if 0
9266   // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9267   // assign tightly coupled operands to the same (pseudo) bank
9268   //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9269   mergeMore = 1;
9270   absMaxWeight = 0;
9271   while (mergeMore) {
9272     node = adj->node;
9273     max = NULL;
9274     maxWeight = 0;
9275     while (node) {
9276       curr0 = getEffectiveBank (node->hash);
9277       if (curr0 < 0) { node = node->next; continue; }
9278       edge = node->edge;
9279       while (edge) {
9280         assert (edge->src == node);
9281         backedge = getGEdge (edge->node, edge->src);
9282         weight = edge->weight + (backedge ? backedge->weight : 0);
9283         curr1 = getEffectiveBank (edge->node->hash);
9284         if (curr1 < 0) { edge = edge->next; continue; }
9285 
9286         // merging is only useful if the items are not assigned to the same bank already...
9287         if (curr0 != curr1 && weight > maxWeight) {
9288           if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9289           maxWeight = weight;
9290           max = edge;
9291         } // if
9292         edge = edge->next;
9293       } // while
9294       node = node->next;
9295     } // while
9296 
9297     if (maxWeight > 0) {
9298 #if 0
9299       fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9300                max->src->hash, getSymFromBank (max->src->hash),
9301                max->node->hash, getSymFromBank (max->node->hash));
9302 #endif
9303 
9304       node = getGNode (adj, max->src->data, max->src->hash);
9305       node1 = getGNode (adj, max->node->data, max->node->hash);
9306 
9307       if (0 == assignToSameBank (max->src->hash, max->node->hash, 0, 0)) {
9308         if (max->src->hash < max->node->hash)
9309           mergeGraphNodes (node, node1);
9310         else
9311           mergeGraphNodes (node1, node);
9312       } else {
9313         remGEdge (node, node1);
9314         remGEdge (node1, node);
9315         //mergeMore = 0;
9316       }
9317 
9318     } else {
9319       mergeMore = 0;
9320     }
9321   } // while
9322 #endif
9323 
9324 #if 1
9325   // remove redundant BANKSELs
9326   //fprintf (stderr, "removing redundant BANKSELs\n");
9327   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9328     bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9329   } // for pb
9330 #endif
9331 
9332 #if 0
9333   fprintf (stderr, "display graph\n");
9334   showGraph ();
9335 #endif
9336 
9337   deleteGraph (adj);
9338   //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9339 }
9340 
9341 /*** END of stuff belonging to the BANKSEL optimization ***/
9342 
9343 
9344 
9345 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9346 
9347 typedef unsigned int symbol_t;
9348 typedef unsigned int valnum_t;
9349 //typedef unsigned int hash_t;
9350 
9351 #ifndef INT_TO_PTR
9352 #define INT_TO_PTR(x) (((char *) 0) + (x))
9353 #endif
9354 
9355 #ifndef PTR_TO_INT
9356 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9357 #endif
9358 
9359 static int pic16_regIsLocal (reg_info *r);
9360 static int pic16_safepCodeRemove (pCode *pc, char *comment);
9361 
9362 /* statistics */
9363 static unsigned int pic16_df_removed_pcodes = 0;
9364 static unsigned int pic16_df_saved_bytes = 0;
9365 static unsigned int df_findall_sameflow = 0;
9366 static unsigned int df_findall_otherflow = 0;
9367 static unsigned int df_findall_in_vals = 0;
9368 
pic16_df_stats()9369 static void pic16_df_stats () {
9370   return;
9371   if (pic16_debug_verbose || pic16_pcode_verbose) {
9372     fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9373     fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9374     //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9375   }
9376 }
9377 
9378 /* Remove a pCode iff possible:
9379  * - previous pCode is no SKIP
9380  * - pc has no label
9381  * Returns 1 iff the pCode has been removed, 0 otherwise. */
pic16_safepCodeUnlink(pCode * pc,char * comment)9382 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9383   pCode *pcprev, *pcnext;
9384   char buf[256], *total=NULL;
9385   int len;
9386 
9387   if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9388 
9389   pcprev = pic16_findPrevInstruction (pc->prev);
9390   pcnext = pic16_findNextInstruction (pc->next);
9391 
9392   /* move labels to next instruction (if possible) */
9393   if (PCI(pc)->label && !pcnext) return 0;
9394 
9395   /* if this is a SKIP with side-effects -- do not remove */
9396   /* XXX: might try to replace this one with the side-effect only version */
9397   if (isPCI_SKIP(pc)
9398         && ((PCI(pc)->outCond & (PCC_REGISTER | PCC_W)) != 0))
9399   {
9400     pCode *newpc;
9401     switch (PCI(pc)->op)
9402     {
9403     case POC_INCFSZ:
9404     case POC_INFSNZ:
9405       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9406       pic16_pCodeReplace( pc, newpc );
9407       return 1;
9408       break;
9409     case POC_INCFSZW:
9410       newpc = pic16_newpCode(POC_INCFW, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9411       pic16_pCodeReplace( pc, newpc );
9412       return 1;
9413       break;
9414     case POC_DECFSZ:
9415     case POC_DCFSNZ:
9416       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9417       pic16_pCodeReplace( pc, newpc );
9418       return 1;
9419       break;
9420     case POC_DECFSZW:
9421       newpc = pic16_newpCode(POC_INCF, pic16_pCodeOpCopy( PCI(pc)->pcop ) );
9422       pic16_pCodeReplace( pc, newpc );
9423       return 1;
9424       break;
9425     default:
9426       return 0;
9427     }
9428     return 0;
9429   }
9430 
9431   /* if previous instruction is a skip -- do not remove */
9432   if (pcprev && isPCI_SKIP(pcprev)) {
9433     if (!pic16_safepCodeUnlink (pcprev, "=DF= removed now unused SKIP")) {
9434       /* preceeding SKIP could not be removed -- keep this instruction! */
9435       return 0;
9436     }
9437   }
9438 
9439   if (PCI(pc)->label) {
9440     //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9441     //pc->print (stderr, pc);
9442     PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9443     PCI(pc)->label = NULL;
9444   }
9445 
9446   /* update statistics */
9447   pic16_df_removed_pcodes++;
9448   if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9449 
9450   /* remove the pCode */
9451   pic16_pCode2str (buf, 256, pc);
9452   //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9453   if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9454     len = strlen (buf) + strlen (comment) + 10;
9455     total = (char *) Safe_malloc (len);
9456     SNPRINTF (total, len, "%s: %s", comment, buf);
9457     pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9458     Safe_free (total);
9459   }
9460 
9461   /* actually unlink it from the pBlock -- also remove from to/from lists */
9462   pic16_pCodeUnlink (pc);
9463 
9464   /* remove the pCode -- release registers */
9465   pc->destruct (pc);
9466 
9467   /* report success */
9468   return 1;
9469 }
9470 
9471 
9472 /* ======================================================================== */
9473 /* === SYMBOL HANDLING ==================================================== */
9474 /* ======================================================================== */
9475 
9476 static hTab *map_strToSym = NULL;               /** (char *) --> symbol_t */
9477 static hTab *map_symToStr = NULL;               /** symbol_t -> (char *) */
9478 static symbol_t nextSymbol = 0x2000;            /** next symbol_t assigned to the next generated symbol */
9479 
9480 /** Calculate a hash for a given string.
9481  * If len == 0 the string is assumed to be NUL terminated. */
symbolHash(const char * str,unsigned int len)9482 static hash_t symbolHash (const char *str, unsigned int len) {
9483   hash_t hash = 0;
9484   if (!len) {
9485     while (*str) {
9486       hash = (hash << 2) ^ *str;
9487       str++;
9488     } // while
9489   } else {
9490     while (len--) {
9491       hash = (hash << 2) ^ *str;
9492       str++;
9493     }
9494   }
9495   return hash;
9496 }
9497 
9498 /** Return 1 iff strings v1 and v2 are identical. */
symcmp(const void * v1,const void * v2)9499 static int symcmp (const void *v1, const void *v2) {
9500   return !strcmp ((const char *) v1, (const char *) v2);
9501 }
9502 
9503 /** Return 1 iff pointers v1 and v2 are identical. */
ptrcmp(const void * v1,const void * v2)9504 static int ptrcmp (const void *v1, const void *v2) {
9505   return (v1 == v2);
9506 }
9507 
9508 enum {  SPO_WREG=0x1000,
9509         SPO_STATUS,
9510         SPO_PRODL,
9511         SPO_PRODH,
9512         SPO_INDF0,
9513         SPO_POSTDEC0,
9514         SPO_POSTINC0,
9515         SPO_PREINC0,
9516         SPO_PLUSW0,
9517         SPO_INDF1,
9518         SPO_POSTDEC1,
9519         SPO_POSTINC1,
9520         SPO_PREINC1,
9521         SPO_PLUSW1,
9522         SPO_INDF2,
9523         SPO_POSTDEC2,
9524         SPO_POSTINC2,
9525         SPO_PREINC2,
9526         SPO_PLUSW2,
9527         SPO_STKPTR,
9528         SPO_TOSL,
9529         SPO_TOSH,
9530         SPO_TOSU,
9531         SPO_BSR,
9532         SPO_FSR0L,
9533         SPO_FSR0H,
9534         SPO_FSR1L,
9535         SPO_FSR1H,
9536         SPO_FSR2L,
9537         SPO_FSR2H,
9538         SPO_PCL,
9539         SPO_PCLATH,
9540         SPO_PCLATU,
9541         SPO_TABLAT,
9542         SPO_TBLPTRL,
9543         SPO_TBLPTRH,
9544         SPO_TBLPTRU,
9545         SPO_LAST
9546 };
9547 
9548 /* Return the unique symbol_t for the given string. */
symFromStr(const char * str)9549 static symbol_t symFromStr (const char *str) {
9550   hash_t hash;
9551   char *res;
9552   symbol_t sym;
9553 
9554   if (!map_symToStr) {
9555     int i;
9556     struct { char *name; symbol_t sym; } predefsyms[] = {
9557         {"WREG", SPO_WREG},
9558         {"STATUS", SPO_STATUS},
9559         {"PRODL", SPO_PRODL},
9560         {"PRODH", SPO_PRODH},
9561         {"INDF0", SPO_INDF0},
9562         {"POSTDEC0", SPO_POSTDEC0},
9563         {"POSTINC0", SPO_POSTINC0},
9564         {"PREINC0", SPO_PREINC0},
9565         {"PLUSW0", SPO_PLUSW0},
9566         {"INDF1", SPO_INDF1},
9567         {"POSTDEC1", SPO_POSTDEC1},
9568         {"POSTINC1", SPO_POSTINC1},
9569         {"PREINC1", SPO_PREINC1},
9570         {"PLUSW1", SPO_PLUSW1},
9571         {"INDF2", SPO_INDF2},
9572         {"POSTDEC2", SPO_POSTDEC2},
9573         {"POSTINC2", SPO_POSTINC2},
9574         {"PREINC2", SPO_PREINC2},
9575         {"PLUSW2", SPO_PLUSW2},
9576         {"STKPTR", SPO_STKPTR},
9577         {"TOSL", SPO_TOSL},
9578         {"TOSH", SPO_TOSH},
9579         {"TOSU", SPO_TOSU},
9580         {"BSR", SPO_BSR},
9581         {"FSR0L", SPO_FSR0L},
9582         {"FSR0H", SPO_FSR0H},
9583         {"FSR1L", SPO_FSR1L},
9584         {"FSR1H", SPO_FSR1H},
9585         {"FSR2L", SPO_FSR2L},
9586         {"FSR2H", SPO_FSR2H},
9587         {"PCL", SPO_PCL},
9588         {"PCLATH", SPO_PCLATH},
9589         {"PCLATU", SPO_PCLATU},
9590         {"TABLAT", SPO_TABLAT},
9591         {"TBLPTRL", SPO_TBLPTRL},
9592         {"TBLPTRH", SPO_TBLPTRH},
9593         {"TBLPTRU", SPO_TBLPTRU},
9594         {NULL, 0}
9595     };
9596 
9597     map_strToSym = newHashTable (128);
9598     map_symToStr = newHashTable (128);
9599 
9600     for (i=0; predefsyms[i].name; i++) {
9601       char *name;
9602 
9603       /* enter new symbol */
9604       sym = predefsyms[i].sym;
9605       name = predefsyms[i].name;
9606       res = Safe_strdup (name);
9607       hash = symbolHash (name, 0);
9608 
9609       hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9610       hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9611     } // for i
9612   }
9613 
9614   hash = symbolHash (str, 0) % map_strToSym->size;
9615 
9616   /* find symbol in table */
9617   sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9618   if (sym) {
9619     //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9620     return sym;
9621   }
9622 
9623   /* enter new symbol */
9624   sym = nextSymbol++;
9625   res = Safe_strdup (str);
9626 
9627   hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9628   hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9629 
9630   //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9631 
9632   return sym;
9633 }
9634 
9635 #if 1
strFromSym(symbol_t sym)9636 static const char *strFromSym (symbol_t sym) {
9637   return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9638 }
9639 #endif
9640 
9641 /* ======================================================================== */
9642 /* === DEFINITION MAP HANDLING ============================================ */
9643 /* ======================================================================== */
9644 
9645 /* A defmap provides information about which symbol is defined by which pCode.
9646  * The most recent definitions are prepended to the list, so that the most
9647  * recent definition can be found by forward scanning the list.
9648  * pc2: MOVFF r0x00, r0x01
9649  * pc1: INCF r0x01
9650  * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9651  *
9652  * We attach one defmap to each flow object, and each pCode will occur at
9653  * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9654  * used to find definitions for a pCode in its own defmap that precede pCode.
9655  */
9656 
9657 typedef struct defmap_s {
9658   symbol_t sym;                 /** symbol this item refers to */
9659   union {
9660     struct {
9661       unsigned int in_mask:8;   /** mask leaving in accessed bits */
9662       unsigned int mask:8;      /** mask leaving in modified bits (if isWrite) */
9663       int isRead:1;             /** sym/mask is read */
9664       int isWrite:1;            /** sym/mask is written */
9665     } access;
9666     int accessmethod;
9667   } acc;
9668   pCode *pc;                    /** pCode this symbol is refrenced at */
9669   valnum_t in_val;              /** valnum_t of symbol's previous value (the one read at pc) */
9670   valnum_t val;                 /** new unique number for this value (if isWrite) */
9671   struct defmap_s *prev, *next; /** link to previous an next definition */
9672 } defmap_t;
9673 
9674 static defmap_t *defmap_free = NULL;            /** list of unused defmaps */
9675 static int defmap_free_count = 0;               /** number of released defmap items */
9676 
9677 /* Returns a defmap_t with the specified data; this will be the new list head.
9678  * next - pointer to the current list head */
newDefmap(symbol_t sym,int in_mask,int mask,int isRead,int isWrite,pCode * pc,valnum_t val,defmap_t * next)9679 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9680   defmap_t *map;
9681 
9682   if (defmap_free) {
9683     map = defmap_free;
9684     defmap_free = map->next;
9685     --defmap_free_count;
9686   } else {
9687     map = (defmap_t *)Safe_alloc(sizeof(defmap_t));
9688   }
9689   map->sym = sym;
9690   map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9691   map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9692   map->acc.access.isRead = (isRead != 0);
9693   map->acc.access.isWrite = (isWrite != 0);
9694   map->pc = pc;
9695   map->in_val = 0;
9696   map->val = (isWrite ? val : 0);
9697   map->prev = NULL;
9698   map->next = next;
9699   if (next) next->prev = map;
9700 
9701   return map;
9702 }
9703 
9704 /* Returns a copy of the single defmap item. */
copyDefmap(defmap_t * map)9705 static defmap_t *copyDefmap (defmap_t *map) {
9706   defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9707   memcpy (res, map, sizeof (defmap_t));
9708   res->next = NULL;
9709   res->prev = NULL;
9710   return res;
9711 }
9712 
9713 /* Insert a defmap item after the specified one. */
defmapInsertAfter(defmap_t * ref,defmap_t * newItem)9714 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9715   if (!ref || !newItem) return 1;
9716 
9717   newItem->next = ref->next;
9718   newItem->prev = ref;
9719   ref->next = newItem;
9720   if (newItem->next) newItem->next->prev = newItem;
9721 
9722   return 0;
9723 }
9724 
9725 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9726  * item is copied before insertion into chain and therefore left untouched.
9727  * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
defmapAddCopyIfNew(defmap_t ** head,defmap_t * item)9728 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9729   defmap_t *dummy;
9730   dummy = *head;
9731   while (dummy && (dummy->sym != item->sym
9732                           || dummy->pc != item->pc
9733                           || dummy->acc.accessmethod != item->acc.accessmethod
9734                           || dummy->val != item->val
9735                           || dummy->in_val != item->in_val)) {
9736     dummy = dummy->next;
9737   } // while
9738 
9739   /* item already present? */
9740   if (dummy) return 0;
9741 
9742   /* otherwise: insert copy of item */
9743   dummy = copyDefmap (item);
9744   dummy->next = *head;
9745   if (*head) (*head)->prev = dummy;
9746   *head = dummy;
9747 
9748   return 1;
9749 }
9750 
9751 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
deleteDefmap(defmap_t * map)9752 static void deleteDefmap (defmap_t *map) {
9753   if (!map) return;
9754 
9755   /* unlink from chain -- fails for the first item (head is not updated!) */
9756   if (map->next) map->next->prev = map->prev;
9757   if (map->prev) map->prev->next = map->next;
9758 
9759   /* clear map */
9760   memset (map, 0, sizeof (defmap_t));
9761 
9762   /* save for future use */
9763   map->next = defmap_free;
9764   defmap_free = map;
9765   ++defmap_free_count;
9766 }
9767 
9768 /* Release all defmaps referenced from map. */
deleteDefmapChain(defmap_t ** _map)9769 static void deleteDefmapChain (defmap_t **_map) {
9770   defmap_t *map, *next;
9771 
9772   if (!_map) return;
9773 
9774   map = *_map;
9775 
9776   /* find list head */
9777   while (map && map->prev) map = map->prev;
9778 
9779   /* delete all items */
9780   while (map) {
9781     next = map->next;
9782     deleteDefmap (map);
9783     map = next;
9784   } // while
9785 
9786   *_map = NULL;
9787 }
9788 
9789 /* Free all defmap items. */
freeDefmap(defmap_t ** _map)9790 static void freeDefmap (defmap_t **_map) {
9791   defmap_t *next;
9792   defmap_t *map;
9793 
9794   if (!_map) return;
9795 
9796   map = (*_map);
9797 
9798   /* find list head */
9799   while (map->prev) map = map->prev;
9800 
9801   /* release all items */
9802   while (map) {
9803     next = map->next;
9804     Safe_free (map);
9805     map = next;
9806   }
9807 
9808   (*_map) = NULL;
9809 }
9810 
9811 /* Returns the most recent definition for the given symbol preceeding pc.
9812  * If no definition is found, NULL is returned.
9813  * If pc == NULL the whole list is scanned. */
defmapFindDef(defmap_t * map,symbol_t sym,pCode * pc)9814 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9815   defmap_t *curr = map;
9816 
9817   if (pc) {
9818     /* skip all definitions up to pc */
9819     while (curr && (curr->pc != pc)) curr = curr->next;
9820 
9821     /* pc not in the list -- scan the whole list for definitions */
9822     if (!curr) {
9823       fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9824       curr = map;
9825     } else {
9826       /* skip all definitions performed by pc */
9827       while (curr && (curr->pc == pc)) curr = curr->next;
9828     }
9829   } // if (pc)
9830 
9831   /* find definition for sym */
9832   while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9833     curr = curr->next;
9834   }
9835 
9836   return curr;
9837 }
9838 
9839 #if 0
9840 /* Returns the first use (read) of the given symbol AFTER pc.
9841  * If no such use is found, NULL is returned.
9842  * If pc == NULL the whole list is scanned. */
9843 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9844   defmap_t *curr = map, *prev = NULL;
9845 
9846   if (pc) {
9847     /* skip all definitions up to pc */
9848     while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9849 
9850     /* pc not in the list -- scan the whole list for definitions */
9851     if (!curr) {
9852       //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9853       curr = prev;
9854     }
9855   } else {
9856     /* find end of list */
9857     while (curr && curr->next) curr = curr->next;
9858   } // if (pc)
9859 
9860   /* find use of sym (scan list backwards) */
9861   while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9862 
9863   return curr;
9864 }
9865 #endif
9866 
9867 /* Return the defmap entry for sym AT pc.
9868  * If none is found, NULL is returned.
9869  * If more than one entry is found an assertion is triggered. */
defmapCurr(defmap_t * map,symbol_t sym,pCode * pc)9870 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9871   defmap_t *res = NULL;
9872 
9873   /* find entries for pc */
9874   while (map && map->pc != pc) map = map->next;
9875 
9876   /* find first entry for sym @ pc */
9877   while (map && map->pc == pc && map->sym != sym) map = map->next;
9878 
9879   /* no entry found */
9880   if (!map) return NULL;
9881 
9882   /* check for more entries */
9883   res = map;
9884   map = map->next;
9885   while (map && map->pc == pc) {
9886     /* more than one entry for sym @ pc found? */
9887     assert (map->sym != sym);
9888     map = map->next;
9889   }
9890 
9891   /* return single entry for sym @ pc */
9892   return res;
9893 }
9894 
9895 /* Modifies the definition of sym at pCode to newval.
9896  * Returns 0 on success, 1 if no definition of sym in pc has been found.
9897  */
defmapUpdate(defmap_t * map,symbol_t sym,pCode * pc,valnum_t newval)9898 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9899   defmap_t *m  = map;
9900 
9901   /* find definitions of pc */
9902   while (m && m->pc != pc) m = m->next;
9903 
9904   /* find definition of sym at pc */
9905   while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9906 
9907   /* no definition found */
9908   if (!m) return 1;
9909 
9910   /* redefine */
9911   m->val = newval;
9912 
9913   /* update following uses of sym */
9914   while (m && m->pc == pc) m = m->prev;
9915   while (m) {
9916     if (m->sym == sym) {
9917       m->in_val = newval;
9918       if (m->acc.access.isWrite) m = NULL;
9919     } // if
9920     if (m) m = m->prev;
9921   } // while
9922 
9923   return 0;
9924 }
9925 
9926 /* ======================================================================== */
9927 /* === STACK ROUTINES ===================================================== */
9928 /* ======================================================================== */
9929 
9930 typedef struct stack_s {
9931   void *data;
9932   struct stack_s *next;
9933 } stackitem_t;
9934 
9935 typedef stackitem_t *dynstack_t;
9936 static stackitem_t *free_stackitems = NULL;
9937 
9938 /* Create a stack with one item. */
newStack()9939 static dynstack_t *newStack () {
9940   dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9941   *s = NULL;
9942   return s;
9943 }
9944 
9945 /* Remove a stack -- its items are only marked free. */
deleteStack(dynstack_t * s)9946 static void deleteStack (dynstack_t *s) {
9947   stackitem_t *i;
9948 
9949   while (*s) {
9950     i = *s;
9951     *s = (*s)->next;
9952     i->next = free_stackitems;
9953     free_stackitems = i;
9954   } // while
9955   Safe_free (s);
9956 }
9957 
9958 /* Release all stackitems. */
releaseStack()9959 static void releaseStack () {
9960   stackitem_t *i;
9961 
9962   while (free_stackitems) {
9963     i = free_stackitems->next;
9964     Safe_free(free_stackitems);
9965     free_stackitems = i;
9966   } // while
9967 }
9968 
stackPush(dynstack_t * stack,void * data)9969 static void stackPush (dynstack_t *stack, void *data) {
9970   stackitem_t *i;
9971 
9972   if (free_stackitems) {
9973     i = free_stackitems;
9974     free_stackitems = free_stackitems->next;
9975   } else {
9976     i = (stackitem_t *)Safe_alloc(sizeof(stackitem_t));
9977   }
9978   i->data = data;
9979   i->next = *stack;
9980   *stack = i;
9981 }
9982 
stackPop(dynstack_t * stack)9983 static void *stackPop (dynstack_t *stack) {
9984   void *data;
9985   stackitem_t *i;
9986 
9987   if (stack && *stack) {
9988     data = (*stack)->data;
9989     i = *stack;
9990     *stack = (*stack)->next;
9991     i->next = free_stackitems;
9992     free_stackitems = i;
9993     return data;
9994   } else {
9995     return NULL;
9996   }
9997 }
9998 
9999 #if 0
10000 static int stackContains (dynstack_t *s, void *data) {
10001   stackitem_t *i;
10002   if (!s) return 0;
10003   i = *s;
10004   while (i) {
10005     if (i->data == data) return 1;
10006     i = i->next;
10007   } // while
10008 
10009   /* not found */
10010   return 0;
10011 }
10012 #endif
10013 
stackIsEmpty(dynstack_t * s)10014 static int stackIsEmpty (dynstack_t *s) {
10015   return (*s == NULL);
10016 }
10017 
10018 
10019 typedef struct {
10020   pCodeFlow *flow;
10021   defmap_t *lastdef;
10022 } state_t;
10023 
newState(pCodeFlow * flow,defmap_t * lastdef)10024 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10025   state_t *s = (state_t *)Safe_alloc(sizeof(state_t));
10026   s->flow = flow;
10027   s->lastdef = lastdef;
10028   return s;
10029 }
10030 
deleteState(state_t * s)10031 static void deleteState (state_t *s) {
10032   Safe_free (s);
10033 }
10034 
stateIsNew(state_t * state,dynstack_t * todo,dynstack_t * done)10035 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10036   stackitem_t *i;
10037 
10038   /* scan working list for state */
10039   if (todo) {
10040     i = *todo;
10041     while (i) {
10042       /* is i == state? -- state not new */
10043       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10044       i = i->next;
10045     } // while
10046   }
10047 
10048   if (done) {
10049     i = *done;
10050     while (i) {
10051       /* is i == state? -- state not new */
10052       if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10053       i = i->next;
10054     } // while
10055   }
10056 
10057   /* not found -- state is new */
10058   return 1;
10059 }
10060 
10061 static inline valnum_t newValnum ();
10062 
pic16_pBlockGetFunctionName(pBlock * pb)10063 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10064   pCode *pc;
10065 
10066   if (!pb) return "<unknown function>";
10067 
10068   pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10069   if (pc && isPCF(pc)) return PCF(pc)->fname;
10070   else return "<unknown function>";
10071 }
10072 
pic16_pBlockAddInval(pBlock * pb,symbol_t sym)10073 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10074   defmap_t *map;
10075   pCodeFlow *pcfl;
10076 
10077   assert(pb);
10078 
10079   pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10080 
10081   /* find initial value (assigning pc == NULL) */
10082   map = PCFL(pcfl)->in_vals;
10083   while (map && map->sym != sym) map = map->next;
10084 
10085   /* initial value already present? */
10086   if (map) {
10087     //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10088     return map;
10089   }
10090 
10091   /* create a new initial value */
10092   map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10093   PCFL(pcfl)->in_vals = map;
10094   //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10095   return map;
10096 
10097 #if 0
10098   /* insert map as last item in pcfl's defmap */
10099   if (!prev) prev = PCFL(pcfl)->defmap;
10100   if (!prev) {
10101     PCFL(pcfl)->defmap = map;
10102   } else {
10103     while (prev->next) prev = prev->next;
10104     prev->next = map;
10105     map->prev = prev;
10106   }
10107 
10108   return map;
10109 #endif
10110 }
10111 
10112 /* Find all reaching definitions for sym at pc.
10113  * A new (!) list of definitions is returned.
10114  * Returns the number of reaching definitions found.
10115  * The defining defmap entries are returned in *chain.
10116  */
defmapFindAll(symbol_t sym,pCode * pc,defmap_t ** chain)10117 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10118   defmap_t *map;
10119   defmap_t *res;
10120 
10121   pCodeFlow *curr;
10122   pCodeFlowLink *succ;
10123   state_t *state;
10124   dynstack_t *todo;     /** stack of state_t */
10125   dynstack_t *done;     /** stack of state_t */
10126 
10127   int n_defs;
10128 
10129   assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10130   assert (chain);
10131 
10132   /* initialize return list */
10133   *chain = NULL;
10134 
10135   /* wildcard symbol? */
10136   if (!sym) return 0;
10137 
10138   //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10139 
10140   map = PCI(pc)->pcflow->defmap;
10141 
10142   res = defmapFindDef (map, sym, pc);
10143   //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10144 
10145 #define USE_PRECALCED_INVALS 1
10146 #if USE_PRECALCED_INVALS
10147   if (!res && PCI(pc)->pcflow->in_vals) {
10148     res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10149     if (res) {
10150       //fprintf  (stderr, "found def in init values\n");
10151       df_findall_in_vals++;
10152     }
10153   }
10154 #endif
10155 
10156   if (res) {
10157     // found a single definition (in pc's flow)
10158     //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10159     defmapAddCopyIfNew (chain, res);
10160     df_findall_sameflow++;
10161     return 1;
10162   }
10163 
10164 #if USE_PRECALCED_INVALS
10165   else {
10166     defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10167     return 1;
10168   }
10169 
10170 #endif
10171 
10172 #define FORWARD_FLOW_ANALYSIS 1
10173 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10174   /* no definition found in pc's flow preceeding pc */
10175   todo = newStack ();
10176   done = newStack ();
10177   n_defs = 0;
10178   stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10179 
10180   while (!stackIsEmpty (todo)) {
10181     state = (state_t *) stackPop (todo);
10182     stackPush (done, state);
10183     curr = state->flow;
10184     res = state->lastdef;
10185     //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);
10186 
10187     /* there are no definitions BEFORE pc in pc's flow (see above) */
10188     if (curr == PCI(pc)->pcflow) {
10189       if (!res) {
10190         //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10191         res = pic16_pBlockAddInval (pc->pb, sym);
10192         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10193         res = NULL;
10194       } else {
10195         //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10196         if (defmapAddCopyIfNew (chain, res)) n_defs++;
10197       }
10198     }
10199 
10200     /* save last definition of sym in this flow as initial def in successors */
10201     res = defmapFindDef (curr->defmap, sym, NULL);
10202     if (!res) res = state->lastdef;
10203 
10204     /* add successors to working list */
10205     state = newState (NULL, NULL);
10206     succ = (pCodeFlowLink *) setFirstItem (curr->to);
10207     while (succ) {
10208       //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10209       state->flow = succ->pcflow;
10210       state->lastdef = res;
10211       if (stateIsNew (state, todo, done)) {
10212         stackPush (todo, state);
10213         state = newState (NULL, NULL);
10214       } // if
10215       succ = (pCodeFlowLink *) setNextItem (curr->to);
10216     } // while
10217     deleteState (state);
10218   } // while
10219 
10220 #else // !FORWARD_FLOW_ANALYSIS
10221 
10222     {
10223       int firstState = 1;
10224 
10225       /* no definition found in pc's flow preceeding pc */
10226       todo = newStack ();
10227       done = newStack ();
10228       n_defs = 0;
10229       stackPush (todo, newState (PCI(pc)->pcflow, res));
10230 
10231       while (!stackIsEmpty (todo)) {
10232           state = (state_t *) stackPop (todo);
10233           curr = state->flow;
10234 
10235           if (firstState) {
10236               firstState = 0;
10237               /* only check predecessor flows */
10238           } else {
10239               /* get (last) definition of sym in this flow */
10240               res = defmapFindDef (curr->defmap, sym, NULL);
10241           }
10242 
10243           if (res) {
10244               /* definition found */
10245               //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10246               if (defmapAddCopyIfNew (chain, res)) n_defs++;
10247           } else {
10248               /* no definition found -- check predecessor flows */
10249               state = newState (NULL, NULL);
10250               succ = (pCodeFlowLink *) setFirstItem (curr->from);
10251 
10252               /* if no flow predecessor available -- sym might be uninitialized */
10253               if (!succ) {
10254                   //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10255                   res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10256                   if (defmapAddCopyIfNew (chain, res)) n_defs++;
10257                   deleteDefmap (res); res = NULL;
10258               }
10259 
10260               while (succ) {
10261                   //fprintf (stderr, "  %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10262                   state->flow = succ->pcflow;
10263                   state->lastdef = res;
10264                   if (stateIsNew (state, todo, done)) {
10265                       stackPush (todo, state);
10266                       state = newState (NULL, NULL);
10267                   } // if
10268                   succ = (pCodeFlowLink *) setNextItem (curr->from);
10269               } // while
10270               deleteState (state);
10271           }
10272       } // while
10273     }
10274 
10275 #endif
10276 
10277   /* clean up done stack */
10278   while (!stackIsEmpty(done)) {
10279     deleteState ((state_t *) stackPop (done));
10280   } // while
10281   deleteStack (done);
10282 
10283   /* return number of items in result set */
10284   if (n_defs == 0) {
10285     //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10286   } else if (n_defs == 1) {
10287     assert (*chain);
10288     //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10289   } else if (n_defs > 0) {
10290     //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10291 #if 0
10292     res = *chain;
10293     while (res) {
10294       fprintf (stderr, "  as %4x @ %p\n", res->val, res->pc);
10295       res = res->next;
10296     } // while
10297 #endif
10298   }
10299   //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10300   df_findall_otherflow++;
10301   return n_defs;
10302 }
10303 
10304 /* ======================================================================== */
10305 /* === VALUE NUMBER HANDLING ============================================== */
10306 /* ======================================================================== */
10307 
10308 static valnum_t nextValnum = 0x1000;
10309 static hTab *map_symToValnum = NULL;
10310 
10311 /** Return a new value number. */
newValnum()10312 static inline valnum_t newValnum () {
10313   return (nextValnum += 4);
10314 }
10315 
valnumFromStr(const char * str)10316 static valnum_t valnumFromStr (const char *str) {
10317   symbol_t sym;
10318   valnum_t val;
10319   void *res;
10320 
10321   sym = symFromStr (str);
10322 
10323   if (!map_symToValnum) {
10324     map_symToValnum = newHashTable (128);
10325   } // if
10326 
10327   /* literal already known? */
10328   res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10329 
10330   /* return existing valnum */
10331   if (res) return (valnum_t) PTR_TO_INT(res);
10332 
10333   /* create new valnum */
10334   val = newValnum();
10335   hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10336   //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10337   return val;
10338 }
10339 
10340 /* Create a valnum for a literal. */
valnumFromLit(unsigned int lit)10341 static valnum_t valnumFromLit (unsigned int lit) {
10342   return ((valnum_t) 0x100 + (lit & 0x0FF));
10343 }
10344 
10345 /* Return the (positive) literal value represented by val
10346  * or -1 iff val is no known literal's valnum. */
litFromValnum(valnum_t val)10347 static int litFromValnum (valnum_t val) {
10348   if (val >= 0x100 && val < 0x200) {
10349     /* valnum is a (known) literal */
10350     return val & 0x00FF;
10351   } else {
10352     /* valnum is not a known literal */
10353     return -1;
10354   }
10355 }
10356 
10357 #if 0
10358 /* Sanity check - all flows in a block must be reachable from initial flow. */
10359 static int verifyAllFlowsReachable (pBlock *pb) {
10360   set *reached;
10361   set *flowInBlock;
10362   set *checked;
10363   pCode *pc;
10364   pCodeFlow *pcfl;
10365   pCodeFlowLink *succ;
10366   int res;
10367 
10368   //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10369 
10370   reached = NULL;
10371   flowInBlock = NULL;
10372   checked = NULL;
10373   /* mark initial flow as reached (and "not needs to be reached") */
10374   pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10375   assert (pc);
10376   addSetHead (&reached, pc);
10377   addSetHead (&checked, pc);
10378 
10379   /* mark all further flows in block as "need to be reached" */
10380   pc = pb->pcHead;
10381   do {
10382     if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10383     pc = pic16_findNextInstruction (pc->next);
10384   } while (pc);
10385 
10386   while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10387     /* mark as reached and "not need to be reached" */
10388     deleteSetItem (&reached, pcfl);
10389     //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10390 
10391     /* flow is no longer considered unreachable */
10392     deleteSetItem (&flowInBlock, pcfl);
10393 
10394     for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10395       if (!isinSet (checked, succ->pcflow)) {
10396         /* flow has never been reached before */
10397         addSetHead (&reached, succ->pcflow);
10398         addSetHead (&checked, succ->pcflow);
10399       } // if
10400     } // for succ
10401   } // while
10402 
10403   //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10404 
10405   /* by now every flow should have been reached
10406    * --> flowInBlock should be empty */
10407   res = (flowInBlock == NULL);
10408 
10409 #if 1
10410   if (flowInBlock) {
10411           fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10412     while (flowInBlock) {
10413       pcfl = indexSet (flowInBlock, 0);
10414       fprintf (stderr, "not reached: flow %p\n", pcfl);
10415       deleteSetItem (&flowInBlock, pcfl);
10416     } // while
10417   }
10418 #endif
10419 
10420   /* clean up */
10421   deleteSet (&reached);
10422   deleteSet (&flowInBlock);
10423   deleteSet (&checked);
10424 
10425   /* if we reached every flow, succ is NULL by now... */
10426   //assert (res); // will fire on unreachable code...
10427   return (res);
10428 }
10429 #endif
10430 
10431 /* Checks a flow for accesses to sym AFTER pc.
10432  *
10433  * Returns -1 if the symbol is read in this flow (before redefinition),
10434  * returns 0 if the symbol is redefined in this flow or
10435  * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10436  */
pic16_isAliveInFlow(symbol_t sym,int mask,pCodeFlow * pcfl,pCode * pc)10437 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10438   defmap_t *map, *mappc;
10439 
10440   /* find pc or start of definitions */
10441   map = pcfl->defmap;
10442   while (map && (map->pc != pc) && map->next) map = map->next;
10443   /* if we found pc -- ignore it */
10444   while (map && map->pc == pc) map = map->prev;
10445 
10446   /* scan list backwards (first definition first) */
10447   while (map && mask) {
10448 //    if (map->sym == sym) {
10449       //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10450       mappc = map;
10451       /* scan list for reads at this pc first */
10452       while (map && map->pc == mappc->pc) {
10453         /* is the symbol (partially) read? */
10454         if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10455           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10456           return -1;
10457         }
10458         map = map->prev;
10459       } // while
10460       map = mappc;
10461 
10462       while (map && map->pc == mappc->pc) {
10463         /* honor (partial) redefinitions of sym */
10464         if ((map->sym == sym) && (map->acc.access.isWrite)) {
10465           mask &= ~map->acc.access.mask;
10466           //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10467         }
10468         map = map->prev;
10469       } // while
10470 //    } // if
10471     /* map already points to the first defmap for the next pCode */
10472     //map = mappc->prev;
10473   } // while
10474 
10475   /* the symbol is not completely redefined in this flow and not accessed -- symbol
10476    * is still alive; return the appropriate mask of alive bits */
10477   return mask;
10478 }
10479 
10480 /* Check whether a symbol is alive (AFTER pc). */
pic16_isAlive(symbol_t sym,pCode * pc)10481 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10482   int mask, visit;
10483   dynstack_t *todo, *done;
10484   state_t *state;
10485   pCodeFlow *pcfl;
10486   pCodeFlowLink *succ;
10487 
10488   mask = 0x00ff;
10489 
10490   assert (isPCI(pc));
10491   pcfl = PCI(pc)->pcflow;
10492 
10493   todo = newStack ();
10494   done = newStack ();
10495 
10496   state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10497   stackPush (todo, state);
10498   visit = 0;
10499 
10500   while (!stackIsEmpty (todo)) {
10501     state = (state_t *) stackPop (todo);
10502     pcfl = state->flow;
10503     mask = PTR_TO_INT(state->lastdef);
10504     if (visit) stackPush (done, state); else deleteState(state);
10505     //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10506     // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10507     mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10508     visit++;
10509 
10510     /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10511     if (mask == 0) continue;
10512 
10513     /* symbol is (partially) read before redefinition in flow */
10514     if (mask == -1) break;
10515 
10516     /* symbol is neither read nor completely redefined -- check successor flows */
10517     for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10518       state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10519       if (stateIsNew (state, todo, done)) {
10520         stackPush (todo, state);
10521       } else {
10522         deleteState (state);
10523       }
10524     } // for
10525   } // while
10526 
10527   while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10528   while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10529 
10530   /* symbol is read in at least one flow -- is alive */
10531   if (mask == -1) return 1;
10532 
10533   /* symbol is read in no flow */
10534   return 0;
10535 }
10536 
10537 /* Returns whether access to the given symbol has side effects. */
pic16_symIsSpecial(symbol_t sym)10538 static int pic16_symIsSpecial (symbol_t sym) {
10539   //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10540   switch (sym) {
10541   case SPO_INDF0:
10542   case SPO_PLUSW0:
10543   case SPO_POSTINC0:
10544   case SPO_POSTDEC0:
10545   case SPO_PREINC0:
10546   case SPO_INDF1:
10547   case SPO_PLUSW1:
10548   case SPO_POSTINC1:
10549   case SPO_POSTDEC1:
10550   case SPO_PREINC1:
10551   case SPO_INDF2:
10552   case SPO_PLUSW2:
10553   case SPO_POSTINC2:
10554   case SPO_POSTDEC2:
10555   case SPO_PREINC2:
10556   case SPO_PCL:
10557           return 1;
10558   default:
10559           /* no special effects known */
10560           return 0;
10561   } // switch
10562 
10563   return 0;
10564 }
10565 
10566 /* Check whether a register should be considered local (to the current function) or not. */
pic16_regIsLocal(reg_info * r)10567 static int pic16_regIsLocal (reg_info *r) {
10568   symbol_t sym;
10569   if (r) {
10570     if (r->type == REG_TMP) return 1;
10571 
10572     sym = symFromStr (r->name);
10573     switch (sym) {
10574     case SPO_WREG:
10575     case SPO_FSR0L: // used in ptrget/ptrput
10576     case SPO_FSR0H: // ... as well
10577     case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10578     case SPO_FSR1H: // ... as well
10579     case SPO_FSR2L: // used as frame pointer
10580     case SPO_FSR2H: // ... as well
10581     case SPO_PRODL: // used to return values from functions
10582     case SPO_PRODH: // ... as well
10583       /* these registers (and some more...) are considered local */
10584       return 1;
10585       break;
10586     default:
10587       /* for unknown regs: check is marked local, leave if not */
10588       if (r->isLocal) {
10589         return 1;
10590       } else {
10591         //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10592         return 0;
10593       }
10594     } // switch
10595   } // if
10596 
10597   /* if in doubt, assume non-local... */
10598   return 0;
10599 }
10600 
10601 /* Check all symbols touched by pc whether their newly assigned values are read.
10602  * Returns 0 if no symbol is used later on, 1 otherwise. */
pic16_pCodeIsAlive(pCode * pc)10603 static int pic16_pCodeIsAlive (pCode *pc) {
10604   pCodeInstruction *pci;
10605   defmap_t *map;
10606   reg_info *checkreg;
10607 
10608   /* we can only handle PCIs */
10609   if (!isPCI(pc)) return 1;
10610 
10611   //pc->print (stderr, pc);
10612 
10613   pci = PCI(pc);
10614   assert (pci && pci->pcflow && pci->pcflow->defmap);
10615 
10616   /* NEVER remove instructions with implicit side effects */
10617   switch (pci->op) {
10618   case POC_TBLRD:
10619   case POC_TBLRD_POSTINC:       /* modify TBLPTRx */
10620   case POC_TBLRD_POSTDEC:
10621   case POC_TBLRD_PREINC:
10622   case POC_TBLWT:               /* modify program memory */
10623   case POC_TBLWT_POSTINC:       /* modify TBLPTRx */
10624   case POC_TBLWT_POSTDEC:
10625   case POC_TBLWT_PREINC:
10626   case POC_CLRWDT:              /* clear watchdog timer */
10627   case POC_PUSH:                /* should be safe to remove though... */
10628   case POC_POP:                 /* should be safe to remove though... */
10629   case POC_CALL:
10630   case POC_RCALL:
10631   case POC_RETFIE:
10632   case POC_RETURN:
10633     //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10634     return 1;
10635 
10636   default:
10637     /* no special instruction */
10638     break;
10639   } // switch
10640 
10641   /* prevent us from removing assignments to non-local variables */
10642   checkreg = NULL;
10643   if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10644   else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10645 
10646   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10647     /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10648     //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10649     //pc->print (stderr, pc);
10650     return 1;
10651   }
10652   if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10653     //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10654     return 1;
10655   }
10656 
10657 #if 1
10658   /* OVERKILL: prevent us from removing reads from non-local variables
10659    * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10660    * Once registers get a "isVolatile" field this might be handled more efficiently... */
10661   checkreg = NULL;
10662   if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10663   else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg =  pic16_getRegFromInstruction2(pc);
10664 
10665   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10666     /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10667     //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10668     //pc->print (stderr, pc);
10669     return 1;
10670   }
10671   if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10672     //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10673     return 1;
10674   }
10675 #endif
10676 
10677   /* now check that the defined symbols are not used */
10678   map = pci->pcflow->defmap;
10679 
10680   /* find items for pc */
10681   while (map && map->pc != pc) map = map->next;
10682 
10683   /* no entries found? something is fishy with DF analysis... -- play safe */
10684   if (!map) {
10685     if (pic16_pcode_verbose) {
10686       fprintf (stderr, "%s: defmap not found\n", __FUNCTION__);
10687     }
10688     return 1;
10689   }
10690 
10691   /* check all symbols being modified by pc */
10692   while (map && map->pc == pc) {
10693     if (map->sym == 0) { map = map->next; continue; }
10694 
10695     /* keep pc if it references special symbols (like POSTDEC0) */
10696 #if 0
10697     {
10698       char buf[256];
10699       pic16_pCode2str (buf, sizeof(buf), pc);
10700       fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10701     }
10702 #endif
10703     if (pic16_symIsSpecial (map->sym)) {
10704       //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10705       return 1;
10706     }
10707     if (map->acc.access.isWrite) {
10708       if (pic16_isAlive (map->sym, pc)) {
10709         //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10710         return 1;
10711       }
10712     }
10713     map = map->next;
10714   } // while
10715 
10716   /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10717 #if 0
10718   {
10719     char buf[256];
10720     pic16_pCode2str (buf, sizeof(buf), pc);
10721     fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10722   }
10723 #endif
10724   return 0;
10725 }
10726 
10727 /* Adds implied operands to the list.
10728  * sym - operand being accessed in the pCode
10729  * list - list to append the operand
10730  * isRead - set to 1 iff sym is read in pCode
10731  * listRead - set to 1 iff all operands being read are to be listed
10732  *
10733  * Returns 0 for "normal" operands, 1 for special operands.
10734  */
fixupSpecialOperands(symbol_t sym,int in_mask,int mask,pCode * pc,valnum_t val,defmap_t ** list,int isRead,int isWrite)10735 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10736   /* check whether accessing REG accesses other REGs as well */
10737   switch (sym) {
10738   case SPO_INDF0:
10739     /* reads FSR0x */
10740     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10741     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10742     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10743     break;
10744 
10745   case SPO_PLUSW0:
10746     /* reads FSR0x and WREG */
10747     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10748     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10749     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10750     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10751     break;
10752 
10753   case SPO_POSTDEC0:
10754   case SPO_POSTINC0:
10755   case SPO_PREINC0:
10756     /* reads/modifies FSR0x */
10757     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10758     *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10759     *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10760     break;
10761 
10762   case SPO_INDF1:
10763     /* reads FSR1x */
10764     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10765     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10766     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10767     break;
10768 
10769   case SPO_PLUSW1:
10770     /* reads FSR1x and WREG */
10771     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10772     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10773     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10774     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10775     break;
10776 
10777   case SPO_POSTDEC1:
10778   case SPO_POSTINC1:
10779   case SPO_PREINC1:
10780     /* reads/modifies FSR1x */
10781     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10782     *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10783     *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10784     break;
10785 
10786   case SPO_INDF2:
10787     /* reads FSR2x */
10788     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10789     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10790     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10791     break;
10792 
10793   case SPO_PLUSW2:
10794     /* reads FSR2x and WREG */
10795     *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10796     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10797     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10798     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10799     break;
10800 
10801   case SPO_POSTDEC2:
10802   case SPO_POSTINC2:
10803   case SPO_PREINC2:
10804     /* reads/modifies FSR2x */
10805     *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10806     *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10807     *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10808     break;
10809 
10810   case SPO_PCL:
10811     /* modifies PCLATH and PCLATU */
10812     *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10813     if (isRead) {
10814       /* reading PCL updates PCLATx */
10815       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10816       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10817     }
10818     if (isWrite) {
10819       /* writing PCL implicitly reads PCLATx (computed GOTO) */
10820       *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10821       *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10822     }
10823     break;
10824 
10825   default:
10826     *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10827     /* nothing special */
10828     return 0;
10829     break;
10830   }
10831 
10832   /* has been a special operand */
10833   return 1;
10834 }
10835 
10836 static symbol_t pic16_fsrsym_idx[][2] = {
10837     {SPO_FSR0L, SPO_FSR0H},
10838     {SPO_FSR1L, SPO_FSR1H},
10839     {SPO_FSR2L, SPO_FSR2H}
10840 };
10841 
10842 /* Merge multiple defmap entries for the same symbol for list's pCode. */
mergeDefmapSymbols(defmap_t * list)10843 static void mergeDefmapSymbols (defmap_t *list) {
10844   defmap_t *ref, *curr, *temp;
10845 
10846   /* now make sure that each symbol occurs at most once per pc */
10847   ref = list;
10848   while (ref && (ref->pc == list->pc)) {
10849     curr = ref->next;
10850     while (curr && (curr->pc == list->pc)) {
10851       if (curr->sym == ref->sym) {
10852         //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10853         /* found a symbol occuring twice... merge the two */
10854         if (curr->acc.access.isRead) {
10855           //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10856           ref->acc.access.isRead = 1;
10857           ref->acc.access.in_mask |= curr->acc.access.in_mask;
10858         }
10859         if (curr->acc.access.isWrite) {
10860           //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10861           ref->acc.access.isWrite = 1;
10862           ref->acc.access.mask |= curr->acc.access.mask;
10863         }
10864         temp = curr;
10865         curr = curr->next;
10866         deleteDefmap (temp);
10867         continue; // do not skip curr!
10868       } // if
10869       curr = curr->next;
10870     } // while
10871     ref = ref->next;
10872   } // while
10873 }
10874 
10875 /** Prepend list with the reads and definitions performed by pc. */
createDefmap(pCode * pc,defmap_t * list)10876 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10877   pCodeInstruction *pci;
10878   int cond, inCond, outCond;
10879   int mask = 0xff, smask;
10880   symbol_t sym, sym2;
10881   char *name;
10882 
10883   if (isPCAD(pc)) {
10884     /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10885     /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10886     fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10887     list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10888     return list;
10889   }
10890   assert (isPCI(pc));
10891   pci = PCI(pc);
10892 
10893   /* handle bit instructions */
10894   if (pci->isBitInst) {
10895     assert (pci->pcop->type == PO_GPR_BIT);
10896     mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10897   }
10898 
10899   /* handle (additional) implicit arguments */
10900   switch (pci->op) {
10901   case POC_LFSR:
10902     {
10903       int lit;
10904       valnum_t val;
10905       lit = PCOL(pci->pcop)->lit;
10906       assert (lit >= 0 && lit < 3);
10907       //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10908       val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10909       //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10910       list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10911       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...
10912     }
10913     break;
10914 
10915   case POC_MOVLB: // BSR
10916   case POC_BANKSEL: // BSR
10917     list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10918     break;
10919 
10920   case POC_MULWF: // PRODx
10921   case POC_MULLW: // PRODx
10922     list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10923     list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10924     break;
10925 
10926   case POC_POP: // TOS, STKPTR
10927     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10928     list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10929     list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10930     list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10931     break;
10932 
10933   case POC_PUSH: // STKPTR
10934     list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10935     list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10936     list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10937     list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10938     break;
10939 
10940   case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10941   case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10942     list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10943     list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10944     list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10945     list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10946 
10947     /* needs correctly set-up stack pointer */
10948     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10949     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10950     break;
10951 
10952   case POC_RETLW: // return values: WREG, PRODx, FSR0L
10953     /* pseudo read on (possible) return values */
10954     // WREG is handled below via outCond
10955     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10956     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10957     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10958 
10959     /* caller's stack pointers must be restored */
10960     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10961     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10962     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10963     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10964     break;
10965 
10966   case POC_RETURN: // return values; WREG, PRODx, FSR0L
10967   case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10968     /* pseudo read on (possible) return values */
10969     list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10970     list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10971     list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10972     list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10973 
10974     /* caller's stack pointers must be restored */
10975     list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10976     list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10977     list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10978     list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10979     break;
10980 
10981   case POC_TBLRD:
10982     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10983     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10984     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10985     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10986     break;
10987 
10988   case POC_TBLRD_POSTINC:
10989   case POC_TBLRD_POSTDEC:
10990   case POC_TBLRD_PREINC:
10991     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10992     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10993     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
10994     list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10995     break;
10996 
10997   case POC_TBLWT:
10998     list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10999     list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11000     list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11001     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11002     break;
11003 
11004   case POC_TBLWT_POSTINC:
11005   case POC_TBLWT_POSTDEC:
11006   case POC_TBLWT_PREINC:
11007     list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11008     list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11009     list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11010     list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11011     break;
11012 
11013   default:
11014     /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11015     break;
11016   } // switch
11017 
11018   /* handle explicit arguments */
11019   inCond = pci->inCond;
11020   outCond = pci->outCond;
11021   cond = inCond | outCond;
11022   if (cond & PCC_W) {
11023     list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11024   } // if
11025 
11026   /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11027   if (inCond & PCC_STATUS) {
11028     smask = 0;
11029     if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11030     if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11031     if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11032     if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11033     if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11034 
11035     list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11036     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11037   } // if
11038 
11039   if (outCond & PCC_STATUS) {
11040     smask = 0;
11041     if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11042     if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11043     if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11044     if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11045     if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11046 
11047     list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11048     //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11049   } // if
11050 
11051   sym = sym2 = 0;
11052   if (cond & PCC_REGISTER) {
11053     name = pic16_get_op (pci->pcop, NULL, 0);
11054     sym = symFromStr (name);
11055     fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11056     //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11057   }
11058 
11059   if (cond & PCC_REGISTER2) {
11060     name = pic16_get_op2 (pci->pcop, NULL, 0);
11061     sym2 = symFromStr (name);
11062     fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11063     //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11064   }
11065 
11066 
11067   /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11068   list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11069 
11070   mergeDefmapSymbols (list);
11071 
11072   return list;
11073 }
11074 
11075 #if 0
11076 static void printDefmap (defmap_t *map) {
11077   defmap_t *curr;
11078 
11079   curr = map;
11080   fprintf (stderr, "defmap @ %p:\n", curr);
11081   while (curr) {
11082     fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11083                     curr->acc.access.isRead ? "R" : " ",
11084                     curr->acc.access.isWrite ? "W": " ",
11085                     curr->in_val, curr->val,
11086                     curr->acc.access.in_mask, curr->acc.access.mask,
11087                     strFromSym(curr->sym), curr->sym,
11088                     curr->pc);
11089     curr = curr->next;
11090   } // while
11091   fprintf (stderr, "<EOL>\n");
11092 }
11093 #endif
11094 
11095 /* Add "additional" definitions to uniq.
11096  * 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.
11097  * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11098  *
11099  * If symbols defined in additional are not present in uniq, a definition is created.
11100  * Otherwise the present definition is altered to reflect the newer assignments.
11101  *
11102  * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11103  *       before     `------- noted in additional --------'      after
11104  *
11105  * I assume that each symbol occurs AT MOST ONCE in uniq.
11106  *
11107  */
defmapUpdateUniqueSym(defmap_t ** uniq,defmap_t * additional)11108 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11109   defmap_t *curr;
11110   defmap_t *old;
11111   int change = 0;
11112 
11113   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11114   /* find tail of additional list (holds the first assignment) */
11115   curr = additional;
11116   while (curr && curr->next) curr = curr->next;
11117 
11118   /* update uniq */
11119   do {
11120     /* find next assignment in additionals */
11121     while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11122 
11123     if (!curr) break;
11124 
11125     /* find item in uniq */
11126     old = *uniq;
11127     //printDefmap (*uniq);
11128     while (old && (old->sym != curr->sym)) old = old->next;
11129 
11130     if (old) {
11131       /* definition found -- replace */
11132       if (old->val != curr->val) {
11133         old->val = curr->val;
11134         change++;
11135       } // if
11136     } else {
11137       /* new definition */
11138       *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11139       change++;
11140     }
11141 
11142     curr = curr->prev;
11143   } while (1);
11144 
11145   /* return 0 iff uniq remained unchanged */
11146   return change;
11147 }
11148 
11149 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11150  * lists of its predecessor flows.
11151  * Initially *combined should be NULL, alt_in will be copied to combined.
11152  * If *combined != NULL, combined will be altered:
11153  * - for symbols defined in *combined but not in alt_in,
11154  *   *combined is altered to 0 (value unknown, either *combined or INIT).
11155  * - for symbols defined in alt_in but not in *combined,
11156  *   a 0 definition is created (value unknown, either INIT or alt).
11157  * - for symbols defined in both, *combined is:
11158  *   > left unchanged if *combined->val == alt_in->val or
11159  *   > modified to 0 otherwise (value unknown, either alt or *combined).
11160  *
11161  * I assume that each symbol occurs AT MOST ONCE in each list!
11162  */
defmapCombineFlows(defmap_t ** combined,defmap_t * alt_in,pBlock * pb)11163 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11164   defmap_t *curr;
11165   defmap_t *old;
11166   int change = 0;
11167   valnum_t val;
11168 
11169   //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11170 
11171   if (!(*combined)) {
11172     return defmapUpdateUniqueSym (combined, alt_in);
11173   } // if
11174 
11175   /* merge the two */
11176   curr = alt_in;
11177   while (curr) {
11178     /* find symbols definition in *combined */
11179     old = *combined;
11180     while (old && (old->sym != curr->sym)) old = old->next;
11181 
11182     if (old) {
11183       /* definition found */
11184       if (old->val && (old->val != curr->val)) {
11185         old->val = 0; /* value unknown */
11186         change++;
11187       }
11188     } else {
11189       /* no definition found -- can be either INIT or alt_in's value */
11190       val = pic16_pBlockAddInval (pb, curr->sym)->val;
11191       *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11192       if (val != curr->val) change++;
11193     }
11194 
11195     curr = curr->next;
11196   } // while (curr)
11197 
11198   /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11199   old = *combined;
11200   while (old) {
11201     if (old->val != 0) {
11202       /* find definition in alt_in */
11203       curr = alt_in;
11204       while (curr && curr->sym != old->sym) curr = curr->next;
11205       if (!curr) {
11206         /* symbol defined in *combined only -- can be either INIT or *combined */
11207         val = pic16_pBlockAddInval (pb, old->sym)->val;
11208         if (old->val != val) {
11209           old->val = 0;
11210           change++;
11211         }
11212       } // if
11213     } // if
11214 
11215     old = old->next;
11216   } // while
11217 
11218   return change;
11219 }
11220 
defmapCompareUnique(defmap_t * map1,defmap_t * map2)11221 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11222   defmap_t *curr1, *curr2;
11223   symbol_t sym;
11224 
11225   /* identical maps are equal */
11226   if (map1 == map2) return 0;
11227 
11228   if (!map1) return -1;
11229   if (!map2) return 1;
11230 
11231   //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11232 
11233   /* check length */
11234   curr1 = map1;
11235   curr2 = map2;
11236   while (curr1 && curr2) {
11237     curr1 = curr1->next;
11238     curr2 = curr2->next;
11239   } // while
11240 
11241   /* one of them longer? */
11242   if (curr1) return 1;
11243   if (curr2) return -1;
11244 
11245   /* both lists are of equal length -- compare (in O(n^2)) */
11246   curr1 = map1;
11247   while (curr1) {
11248     sym = curr1->sym;
11249     curr2 = map2;
11250     while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11251     if (!curr2) return 1; // symbol not found in curr2
11252     if (curr2->val != curr1->val) return 1; // values differ
11253 
11254     /* compare next symbol */
11255     curr1 = curr1->next;
11256   } // while
11257 
11258   /* no difference found */
11259   return 0;
11260 }
11261 
11262 
11263 /* Prepare a list of all reaching definitions per flow.
11264  * This is done using a forward dataflow analysis.
11265  */
createReachingDefinitions(pBlock * pb)11266 static void createReachingDefinitions (pBlock *pb) {
11267   defmap_t *out_vals, *in_vals;
11268   pCode *pc;
11269   pCodeFlow *pcfl;
11270   pCodeFlowLink *link;
11271   set *todo;
11272   set *blacklist;
11273 
11274   if (!pb) return;
11275 
11276   /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11277   for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11278     if (isPCFL(pc)) {
11279       deleteDefmapChain (&PCFL(pc)->in_vals);
11280       deleteDefmapChain (&PCFL(pc)->out_vals);
11281       defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11282     } // if
11283   } // for
11284 
11285   pc = pic16_findNextInstruction (pb->pcHead);
11286   if (!pc) {
11287       // empty function, avoid NULL pointer dereference
11288       return;
11289   } // if
11290   todo = NULL; blacklist = NULL;
11291   addSetHead (&todo, PCI(pc)->pcflow);
11292 
11293   //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11294   while (elementsInSet (todo)) {
11295     //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11296     pcfl = PCFL(indexSet (todo, 0));
11297     deleteSetItem (&todo, pcfl);
11298     //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11299     in_vals = NULL;
11300     out_vals = NULL;
11301 
11302     if (isinSet (blacklist, pcfl)) {
11303             fprintf (stderr, "ignoring blacklisted flow\n");
11304       continue;
11305     }
11306 
11307     /* create in_vals from predecessors out_vals */
11308     link = setFirstItem (pcfl->from);
11309     while (link) {
11310       defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11311       link = setNextItem (pcfl->from);
11312     } // while
11313 
11314     //printDefmap (in_vals);
11315     //printDefmap (pcfl->in_vals);
11316 
11317     if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11318       //fprintf (stderr, "in_vals changed\n");
11319       /* in_vals changed -- update out_vals */
11320       deleteDefmapChain (&pcfl->in_vals);
11321       pcfl->in_vals = in_vals;
11322 
11323       /* create out_val from in_val and defmap */
11324       out_vals = NULL;
11325       defmapUpdateUniqueSym (&out_vals, in_vals);
11326       defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11327 
11328       /* is out_vals different from pcfl->out_vals */
11329       if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11330         //fprintf (stderr, "out_vals changed\n");
11331         deleteDefmapChain (&pcfl->out_vals);
11332         pcfl->out_vals = out_vals;
11333 
11334         if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11335           addSet (&blacklist, pcfl);
11336         } // if
11337 
11338         /* reschedule all successors */
11339         link = setFirstItem (pcfl->to);
11340         while (link) {
11341           //fprintf (stderr, "  %p --> %p\n", pcfl, link->pcflow);
11342           addSetIfnotP (&todo, link->pcflow);
11343           link = setNextItem (pcfl->to);
11344         } // while
11345       } else {
11346         deleteDefmapChain (&out_vals);
11347       }// if
11348     } else {
11349       deleteDefmapChain (&in_vals);
11350     } // if
11351   } // while
11352 }
11353 
11354 #if 0
11355 static void showAllDefs (symbol_t sym, pCode *pc) {
11356   defmap_t *map;
11357   int count;
11358 
11359   assert (isPCI(pc));
11360   count = defmapFindAll (sym, pc, &map);
11361 
11362   fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11363   while (map) {
11364 #if 1
11365     fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11366 #else
11367     {
11368     char buf[256];
11369 
11370     pic16_pCode2str (buf, sizeof(buf), map->pc);
11371     fprintf (stderr, "\n    (%x @ %p(%s)) ", map->val, map->pc, buf);
11372     }
11373 #endif
11374     map = map->next;
11375   }
11376   deleteDefmapChain (&map);
11377 }
11378 #endif
11379 
11380 /* safepCodeUnlink and remove pc from defmap. */
pic16_safepCodeRemove(pCode * pc,char * comment)11381 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11382   defmap_t *map, *next, **head;
11383   int res;
11384 
11385   map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11386   head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11387   res = pic16_safepCodeUnlink (pc, comment);
11388 
11389   if (res && map) {
11390     /* remove pc from defmap */
11391     while (map) {
11392       next = map->next;
11393       if (map->pc == pc) {
11394         if (!map->prev && head) *head = map->next;
11395         deleteDefmap (map);
11396       } // if
11397       map = next;
11398     }
11399   }
11400 
11401   return res;
11402 }
11403 
pic16_fixDefmap(pCode * pc,pCode * newpc)11404 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11405   defmap_t *map;
11406   /* This breaks the defmap chain's references to pCodes... fix it! */
11407   map = PCI(pc)->pcflow->defmap;
11408 
11409   while (map && map->pc != pc) map = map->next;
11410 
11411   while (map && map->pc == pc) {
11412     map->pc = newpc;
11413     map = map->next;
11414   } // while
11415 }
11416 
11417 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11418  * write accesses (isRead == 0). */
defmapReplaceSymRef(pCode * pc,symbol_t sym,symbol_t newsym,int isRead)11419 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11420   defmap_t *map, *map_start;
11421   defmap_t *copy;
11422   if (!isPCI(pc)) return;
11423   if (sym == newsym) return;
11424 
11425   map = PCI(pc)->pcflow->defmap;
11426 
11427   while (map && map->pc != pc) map = map->next;
11428   map_start = map;
11429   while (map && map->pc == pc) {
11430     if (map->sym == sym) {
11431       assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11432       if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11433         /* only one kind of access handled... this is easy */
11434         map->sym = newsym;
11435       } else {
11436         /* must copy defmap entry before replacing symbol... */
11437         copy = copyDefmap (map);
11438         if (isRead) {
11439           map->acc.access.isRead = 0;
11440           copy->acc.access.isWrite = 0;
11441         } else {
11442           map->acc.access.isWrite = 0;
11443           copy->acc.access.isRead = 0;
11444         }
11445         copy->sym = newsym;
11446         /* insert copy into defmap chain */
11447         defmapInsertAfter (map, copy);
11448       }
11449     }
11450     map = map->next;
11451   } // while
11452 
11453   /* as this might introduce multiple defmap entries for newsym... */
11454   mergeDefmapSymbols (map_start);
11455 }
11456 
11457 /* Assign "better" valnums to results. */
assignValnums(pCode * pc)11458 static void assignValnums (pCode *pc) {
11459   pCodeInstruction *pci;
11460   pCode *newpc;
11461   symbol_t sym1, sym2;
11462   int cond, isSpecial1, isSpecial2, count, mask, lit;
11463   defmap_t *list, *val, *oldval, *dummy;
11464   reg_info *reg1 = NULL, *reg2 = NULL;
11465   valnum_t litnum;
11466 
11467   /* only works for pCodeInstructions... */
11468   if (!isPCI(pc)) return;
11469 
11470   pci = PCI(pc);
11471   cond = pci->inCond | pci->outCond;
11472   list = pci->pcflow->defmap;
11473   sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11474 
11475   if (cond & PCC_REGISTER) {
11476     sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11477     reg1 = pic16_getRegFromInstruction (pc);
11478     isSpecial1 = pic16_symIsSpecial (sym1);
11479   }
11480   if (cond & PCC_REGISTER2) {
11481     sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11482     reg2 = pic16_getRegFromInstruction (pc);
11483     isSpecial2 = pic16_symIsSpecial (sym2);
11484   }
11485 
11486   /* determine input values */
11487   val = list;
11488   while (val && val->pc != pc) val = val->next;
11489   //list = val; /* might save some time later... */
11490   while (val && val->pc == pc) {
11491     val->in_val = 0;
11492     if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11493       /* get valnum for sym */
11494       count = defmapFindAll (val->sym, pc, &oldval);
11495       //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11496       if (count == 1) {
11497         if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11498           val->in_val = oldval->val;
11499         } else {
11500           val->in_val = 0;
11501         }
11502       } else if (count == 0) {
11503         /* no definition found */
11504         val->in_val = 0;
11505       } else {
11506         /* multiple definition(s) found -- value not known (unless always the same valnum) */
11507         assert (oldval);
11508         dummy = oldval->next;
11509         mask = oldval->acc.access.mask;
11510         val->in_val = oldval->val;
11511         while (dummy && (dummy->val == val->in_val)) {
11512           mask &= dummy->acc.access.mask;
11513           dummy = dummy->next;
11514         } // while
11515 
11516         /* found other values or to restictive mask */
11517         if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11518           val->in_val = 0;
11519         }
11520       }
11521       if (count > 0) deleteDefmapChain (&oldval);
11522     } // if
11523     val = val->next;
11524   }
11525 
11526   /* handle valnum assignment */
11527   switch (pci->op) {
11528   case POC_CLRF: /* modifies STATUS (Z) */
11529     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11530       oldval = defmapCurr (list, sym1, pc);
11531       if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11532         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11533         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11534       }
11535       defmapUpdate (list, sym1, pc, valnumFromLit(0));
11536     }
11537     break;
11538 
11539   case POC_SETF: /* SETF does not touch STATUS */
11540     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11541       oldval = defmapCurr (list, sym1, pc);
11542       if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11543         //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11544         pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11545       }
11546       defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11547     }
11548     break;
11549 
11550   case POC_MOVLW: /* does not touch STATUS */
11551     oldval = defmapCurr (list, SPO_WREG, pc);
11552     if (pci->pcop->type == PO_LITERAL) {
11553       //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11554       litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11555     } else {
11556       //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11557       litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11558     }
11559     if (oldval && oldval->in_val == litnum) {
11560       //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11561       pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11562     }
11563     defmapUpdate (list, SPO_WREG, pc, litnum);
11564     break;
11565 
11566   case POC_ANDLW: /* modifies STATUS (Z,N) */
11567   case POC_IORLW: /* modifies STATUS (Z,N) */
11568   case POC_XORLW: /* modifies STATUS (Z,N) */
11569     /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11570     if (pci->pcop->type == PO_LITERAL) {
11571       int vallit = -1;
11572       lit = (unsigned char) PCOL(pci->pcop)->lit;
11573       val = defmapCurr (list, SPO_WREG, pc);
11574       if (val) vallit = litFromValnum (val->in_val);
11575       if (vallit != -1) {
11576         /* xxxLW <literal>, WREG contains a known literal */
11577         //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11578         if (pci->op == POC_ANDLW) {
11579           lit &= vallit;
11580         } else if (pci->op == POC_IORLW) {
11581           lit |= vallit;
11582         } else if (pci->op == POC_XORLW) {
11583           lit ^= vallit;
11584         } else {
11585           assert (0 && "invalid operation");
11586         }
11587         if (vallit == lit) {
11588           //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11589           if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11590         }
11591         defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11592       } // if
11593     }
11594     break;
11595 
11596   case POC_LFSR:
11597     {
11598       /* check if old value matches new value */
11599       int lit;
11600       int ok = TRUE;
11601       assert (pci->pcop->type == PO_LITERAL);
11602 
11603       lit = PCOL(pci->pcop)->lit;
11604 
11605       val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11606 
11607       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11608         //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11609       } else {
11610         /* cannot remove this LFSR */
11611         ok = FALSE;
11612       } // if
11613 
11614       val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11615       if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11616         //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11617       } else {
11618         ok = FALSE;
11619       } // if
11620 
11621       if (ok) {
11622         pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11623       }
11624     }
11625     break;
11626 
11627   case POC_MOVWF: /* does not touch flags */
11628     /* find value of WREG */
11629     val = defmapCurr (list, SPO_WREG, pc);
11630     oldval = defmapCurr (list, sym1, pc);
11631     if (val) lit = litFromValnum (val->in_val);
11632     else lit = -1;
11633     //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11634 
11635     if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11636       /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11637       //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11638       if (lit == 0) {
11639         newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11640       } else {
11641         assert (lit == 0x0ff);
11642         newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11643       }
11644       if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11645       pic16_pCodeReplace (pc, newpc);
11646       defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11647       pic16_fixDefmap (pc, newpc);
11648       pc = newpc;
11649 
11650       /* This breaks the defmap chain's references to pCodes... fix it! */
11651       if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11652       if (!val->acc.access.isWrite) {
11653         deleteDefmap (val);     // delete reference to WREG as in value
11654         val = NULL;
11655       } else {
11656         val->acc.access.isRead = 0;     // delete reference to WREG as in value
11657       }
11658       oldval = PCI(pc)->pcflow->defmap;
11659       while (oldval) {
11660         if (oldval->pc == pc) oldval->pc = newpc;
11661           oldval = oldval->next;
11662       } // while
11663     } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11664       //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11665       pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11666     }
11667     if (val) defmapUpdate (list, sym1, pc, val->in_val);
11668     break;
11669 
11670   case POC_MOVFW: /* modifies STATUS (Z,N) */
11671     /* find value of REG */
11672     if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11673       val = defmapCurr (list, sym1, pc);
11674       oldval = defmapCurr (list, SPO_WREG, pc);
11675       if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11676         //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11677         if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11678       } else {
11679           defmap_t *pred, *predpred;
11680           /* Optimize MOVLW immd; MOVWF reg1; [...]; MOVFW reg1
11681            * into MOVLW immd; MOVWF reg1; [...]; MOVLW immd
11682            * This might allow removal of the first two assignments. */
11683           pred = defmapFindDef (list, sym1, pc);
11684           predpred = pred ? defmapFindDef (list, SPO_WREG, pred->pc) : NULL;
11685           if (pred && predpred && (PCI(pred->pc)->op == POC_MOVWF) && (PCI(predpred->pc)->op == POC_MOVLW)
11686                 && !pic16_isAlive (SPO_STATUS, pc))
11687           {
11688               newpc = pic16_newpCode (POC_MOVLW, pic16_pCodeOpCopy (PCI(predpred->pc)->pcop));
11689 
11690               if (pic16_debug_verbose || pic16_pcode_verbose) {
11691                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFW: replaced last of MOVLW;MOVWF;MOVFW by MOVLW");
11692               } // if
11693               pic16_pCodeReplace (pc, newpc);
11694               defmapReplaceSymRef (pc, sym1, 0, 1);
11695               pic16_fixDefmap (pc, newpc);
11696               pc = newpc;
11697 
11698               /* This breaks the defmap chain's references to pCodes... fix it! */
11699               if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11700               if (!val->acc.access.isWrite) {
11701                   deleteDefmap (val);   // delete reference to reg1 as in value
11702                   val = NULL;
11703               } else {
11704                   val->acc.access.isRead = 0;   // delete reference to reg1 as in value
11705               }
11706               oldval = PCI(pc)->pcflow->defmap;
11707               while (oldval) {
11708                   if (oldval->pc == pc) oldval->pc = newpc;
11709                   oldval = oldval->next;
11710               } // while
11711           } // if
11712       }
11713       if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11714     }
11715     break;
11716 
11717   case POC_MOVFF: /* does not touch STATUS */
11718     /* find value of REG */
11719     val = defmapCurr (list, sym1, pc);
11720     oldval = defmapCurr (list, sym2, pc);
11721     if (val) lit = litFromValnum (val->in_val);
11722     else lit = -1;
11723     newpc = NULL;
11724     if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11725       //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11726       if (lit == 0) {
11727         newpc = pic16_newpCode (POC_CLRF, PCOP2(pci->pcop)->pcopR);
11728       } else if (lit == 0x00ff) {
11729         newpc = pic16_newpCode (POC_SETF, PCOP2(pci->pcop)->pcopR);
11730       } else {
11731         newpc = NULL;
11732       }
11733       if (newpc) {
11734         pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11735         pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11736         pic16_pCodeReplace (pc, newpc);
11737         defmapReplaceSymRef (pc, sym1, 0, 1);
11738         pic16_fixDefmap (pc, newpc);
11739         pc = newpc;
11740         break; // do not process instruction as MOVFF...
11741       }
11742     } else if (!isSpecial1 && !isSpecial2
11743                 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)
11744                 && val && oldval && (val->in_val != 0)) {
11745       if (val->in_val == oldval->in_val) {
11746         //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11747         pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11748       } else {
11749         if (!pic16_isAlive (sym1, pc)) {
11750           defmap_t *copy = NULL;
11751           /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11752            * This should help eliminate
11753            *   MOVFF A,B
11754            *   <do something not changing A or using B>
11755            *   MOVFF B,C
11756            *   <B is not alive anymore>
11757            * and turn it into
11758            *   <do something not changing A or using B>
11759            *   MOVFF A,C
11760            */
11761 
11762           /* scan defmap for symbols storing sym1's value */
11763           while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11764           if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, &copy) == 1) {
11765             /* unique reaching definition for sym found */
11766             if (copy->val && copy->val == val->in_val) {
11767               //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);
11768               if (copy->sym == SPO_WREG) {
11769                 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR));
11770               } else {
11771                 pCodeOp *pcop = NULL;
11772                 /* the code below fails if we try to replace
11773                  *   MOVFF PRODL, r0x03
11774                  *   MOVFF r0x03, PCLATU
11775                  * with
11776                  *   MOVFF PRODL, PCLATU
11777                  * as copy(PRODL) contains has pc==NULL, by name fails...
11778                  */
11779                 if (!copy->pc || !PCI(copy->pc)->pcop) break;
11780 
11781                 if (copy->pc && PCI(copy->pc)->pcop)
11782                   pcop = PCI(copy->pc)->pcop;
11783 #if 0
11784                 /* This code is broken--see above. */
11785                 else
11786                 {
11787                   const char *symname = strFromSym(copy->sym);
11788 
11789                   assert( symname );
11790                   pic16_InsertCommentAfter (pc->prev, "BUG-ME");
11791                   pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: newpCodeOpregFromStr(%s)", (char *)symname);
11792                   //pcop = pic16_newpCodeOpRegFromStr((char *)symname);
11793                 }
11794 #endif
11795                 assert( pcop );
11796                 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11797                         pcop,
11798                         pic16_pCodeOpCopy (PCOP2(pci->pcop)->pcopR)));
11799               }
11800               pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11801               pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11802               pic16_pCodeReplace (pc, newpc);
11803               assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11804               defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11805               pic16_fixDefmap (pc, newpc);
11806               pc = newpc;
11807             }
11808           }
11809           deleteDefmapChain (&copy);
11810         }
11811       }
11812       if (val) defmapUpdate (list, sym2, pc, val->in_val);
11813     }
11814     break;
11815 
11816   default:
11817     /* cannot optimize */
11818     break;
11819   } // switch
11820 }
11821 
pic16_destructDF(pBlock * pb)11822 static void pic16_destructDF (pBlock *pb) {
11823   pCode *pc, *next;
11824 
11825   if (!pb) return;
11826 
11827   /* remove old defmaps */
11828   pc = pic16_findNextInstruction (pb->pcHead);
11829   while (pc) {
11830     next = pic16_findNextInstruction (pc->next);
11831 
11832     assert (isPCI(pc) || isPCAD(pc));
11833     assert (PCI(pc)->pcflow);
11834     deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11835     deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11836     deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11837 
11838     pc = next;
11839   } // while
11840 
11841   if (defmap_free || defmap_free_count) {
11842     //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11843     freeDefmap (&defmap_free);
11844     defmap_free_count = 0;
11845   }
11846 }
11847 
11848 /* Checks whether a pBlock contains ASMDIRs. */
pic16_pBlockHasAsmdirs(pBlock * pb)11849 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11850   pCode *pc;
11851 
11852   if (!pb) return FALSE;
11853 
11854   pc = pic16_findNextInstruction (pb->pcHead);
11855   while (pc) {
11856     if (isPCAD(pc)) return TRUE;
11857 
11858     pc = pic16_findNextInstruction (pc->next);
11859   } // while
11860 
11861   /* no PCADs found */
11862   return FALSE;
11863 }
11864 
11865 #if 1
11866 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
pic16_removeUnusedRegistersDF()11867 static int pic16_removeUnusedRegistersDF () {
11868   pCode *pc, *pc2;
11869   pBlock *pb;
11870   reg_info *reg1, *reg2, *reg3;
11871   set *seenRegs = NULL;
11872   int cond, i;
11873   int islocal, change = 0;
11874 
11875   /* no pBlocks? */
11876   if (!the_pFile || !the_pFile->pbHead) return 0;
11877 
11878   for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11879     //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11880 #if 1
11881     /* find set of using pCodes per register */
11882     for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11883                     pc = pic16_findNextInstruction(pc->next)) {
11884 
11885       cond = PCI(pc)->inCond | PCI(pc)->outCond;
11886       reg1 = reg2 = NULL;
11887       if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11888       if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11889 
11890       if (reg1) {
11891         if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11892         addSetIfnotP (&seenRegs, reg1);
11893         addSetIfnotP (&reg1->reglives.usedpCodes, pc);
11894       }
11895       if (reg2) {
11896         if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11897         addSetIfnotP (&seenRegs, reg2);
11898         addSetIfnotP (&reg2->reglives.usedpCodes, pc);
11899       }
11900     } // for pc
11901 #endif
11902     for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11903       /* may not use pic16_regIsLocal() here -- in interrupt routines
11904        * WREG, PRODx, FSR0x must be saved */
11905       islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11906       if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11907         pc = pc2 = NULL;
11908         for (i=0; i < 2; i++) {
11909           pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11910           if (!pc2) pc2 = pc;
11911           if (!isPCI(pc) || !(PCI(pc)->op == POC_MOVFF)) continue;
11912           reg2 = pic16_getRegFromInstruction (pc);
11913           reg3 = pic16_getRegFromInstruction2 (pc);
11914           if (!reg2 || !reg3
11915               || (reg2->rIdx != pic16_stack_preinc->rIdx
11916                   && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11917           if (i == 1) {
11918             /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11919             //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11920             pic16_safepCodeRemove (pc, "removed unused local reg IN");
11921             pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11922           }
11923         } // for
11924       } // if
11925       deleteSet (&reg1->reglives.usedpCodes);
11926     } // for reg1
11927 
11928     deleteSet (&seenRegs);
11929   } // for pb
11930 
11931   return change;
11932 }
11933 #endif
11934 
11935 /* Set up pCodeFlow's defmap_ts.
11936  * Needs correctly set up to/from fields. */
pic16_createDF(pBlock * pb)11937 static void pic16_createDF (pBlock *pb) {
11938   pCode *pc, *next;
11939   int change=0;
11940 
11941   if (!pb) return;
11942 
11943   //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11944 
11945   pic16_destructDF (pb);
11946 
11947   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11948   if (pic16_pBlockHasAsmdirs (pb)) {
11949     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11950     return;
11951   }
11952 
11953   /* integrity check -- we need to reach all flows to guarantee
11954    * correct data flow analysis (reaching definitions, aliveness) */
11955 #if 0
11956   if (!verifyAllFlowsReachable (pb)) {
11957     fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11958     return;
11959   }
11960 #endif
11961 
11962   /* establish new defmaps */
11963   pc = pic16_findNextInstruction (pb->pcHead);
11964   while (pc) {
11965     next = pic16_findNextInstruction (pc->next);
11966 
11967     assert (PCI(pc)->pcflow);
11968     PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11969 
11970     pc = next;
11971   } // while
11972 
11973   //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11974   createReachingDefinitions (pb);
11975 
11976 #if 1
11977   /* assign better valnums */
11978   //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11979   pc = pic16_findNextInstruction (pb->pcHead);
11980   while (pc) {
11981     next = pic16_findNextInstruction (pc->next);
11982 
11983     assert (PCI(pc)->pcflow);
11984     assignValnums (pc);
11985 
11986     pc = next;
11987   } // while
11988 #endif
11989 
11990 #if 1
11991   /* remove dead pCodes */
11992   //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11993   do {
11994     change = 0;
11995     pc = pic16_findNextInstruction (pb->pcHead);
11996     while (pc) {
11997       next = pic16_findNextInstruction (pc->next);
11998 
11999       if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
12000         change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
12001       }
12002 
12003       pc = next;
12004     } // while
12005   } while (change);
12006 #endif
12007 }
12008 
12009 /* ======================================================================== */
12010 /* === VCG DUMPER ROUTINES ================================================ */
12011 /* ======================================================================== */
12012 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12013 hTab *dumpedNodes = NULL;
12014 
12015 /** Dump VCG header into of. */
pic16_vcg_init(FILE * of)12016 static void pic16_vcg_init (FILE *of) {
12017   /* graph defaults */
12018   fprintf (of, "graph:{\n");
12019   fprintf (of, "title:\"graph1\"\n");
12020   fprintf (of, "label:\"graph1\"\n");
12021   fprintf (of, "color:white\n");
12022   fprintf (of, "textcolor:black\n");
12023   fprintf (of, "bordercolor:black\n");
12024   fprintf (of, "borderwidth:1\n");
12025   fprintf (of, "textmode:center\n");
12026 
12027   fprintf (of, "layoutalgorithm:dfs\n");
12028   fprintf (of, "late_edge_labels:yes\n");
12029   fprintf (of, "display_edge_labels:yes\n");
12030   fprintf (of, "dirty_edge_labels:yes\n");
12031   fprintf (of, "finetuning:yes\n");
12032   fprintf (of, "ignoresingles:no\n");
12033   fprintf (of, "straight_phase:yes\n");
12034   fprintf (of, "priority_phase:yes\n");
12035   fprintf (of, "manhattan_edges:yes\n");
12036   fprintf (of, "smanhattan_edges:no\n");
12037   fprintf (of, "nearedges:no\n");
12038   fprintf (of, "node_alignment:center\n"); // bottom|top|center
12039   fprintf (of, "port_sharing:no\n");
12040   fprintf (of, "arrowmode:free\n"); // fixed|free
12041   fprintf (of, "crossingphase2:yes\n");
12042   fprintf (of, "crossingoptimization:yes\n");
12043   fprintf (of, "edges:yes\n");
12044   fprintf (of, "nodes:yes\n");
12045   fprintf (of, "splines:no\n");
12046 
12047   /* node defaults */
12048   fprintf (of, "node.color:lightyellow\n");
12049   fprintf (of, "node.textcolor:black\n");
12050   fprintf (of, "node.textmode:center\n");
12051   fprintf (of, "node.shape:box\n");
12052   fprintf (of, "node.bordercolor:black\n");
12053   fprintf (of, "node.borderwidth:1\n");
12054 
12055   /* edge defaults */
12056   fprintf (of, "edge.textcolor:black\n");
12057   fprintf (of, "edge.color:black\n");
12058   fprintf (of, "edge.thickness:1\n");
12059   fprintf (of, "edge.arrowcolor:black\n");
12060   fprintf (of, "edge.backarrowcolor:black\n");
12061   fprintf (of, "edge.arrowsize:15\n");
12062   fprintf (of, "edge.backarrowsize:15\n");
12063   fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12064   fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12065   fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12066 
12067   fprintf (of, "\n");
12068 
12069   /* prepare data structures */
12070   if (dumpedNodes) {
12071     hTabDeleteAll (dumpedNodes);
12072     dumpedNodes = NULL;
12073   }
12074   dumpedNodes = newHashTable (128);
12075 }
12076 
12077 /** Dump VCG footer into of. */
pic16_vcg_close(FILE * of)12078 static void pic16_vcg_close (FILE *of) {
12079   fprintf (of, "}\n");
12080 }
12081 
12082 #define BUF_SIZE 128
12083 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12084 
12085 #if 0
12086 static int ptrcmp (const void *p1, const void *p2) {
12087   return p1 == p2;
12088 }
12089 #endif
12090 
12091 /** Dump a pCode node as VCG to of. */
pic16_vcg_dumpnode(pCode * pc,FILE * of)12092 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12093   char buf[BUF_SIZE];
12094 
12095   if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12096     // dumped already
12097     return;
12098   }
12099   hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12100   //fprintf (stderr, "dumping %p\n", pc);
12101 
12102   /* only dump pCodeInstructions and Flow nodes */
12103   if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12104 
12105   /* emit node */
12106   fprintf (of, "node:{");
12107   fprintf (of, "title:\"%s\" ", pcTitle(pc));
12108   fprintf (of, "label:\"%s\n", pcTitle(pc));
12109   if (isPCFL(pc)) {
12110     fprintf (of, "<PCFLOW>");
12111   } else if (isPCI(pc) || isPCAD(pc)) {
12112     pc->print (of, pc);
12113   } else {
12114     fprintf (of, "<!PCI>");
12115   }
12116   fprintf (of, "\" ");
12117   fprintf (of, "}\n");
12118 
12119   if (1 && isPCFL(pc)) {
12120     defmap_t *map, *prev;
12121     unsigned int i;
12122     map = PCFL(pc)->defmap;
12123     i=0;
12124     while (map) {
12125       if (map->sym != 0) {
12126         i++;
12127 
12128         /* emit definition node */
12129         fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12130         fprintf (of, "label:\"");
12131 
12132         prev = map;
12133         do {
12134           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));
12135           prev = map;
12136           map = map->next;
12137         } while (map && prev->pc == map->pc);
12138         map = prev;
12139 
12140         fprintf (of, "\" ");
12141 
12142         fprintf (of, "color:green ");
12143         fprintf (of, "}\n");
12144 
12145         /* emit edge to previous definition */
12146         fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12147         if (i == 1) {
12148           fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12149         } else {
12150           fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12151         }
12152         fprintf (of, "color:green ");
12153         fprintf (of, "}\n");
12154 
12155         if (map->pc) {
12156           pic16_vcg_dumpnode (map->pc, of);
12157           fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12158           fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12159         }
12160       }
12161       map = map->next;
12162     } // while
12163   }
12164 
12165   /* emit additional nodes (e.g. operands) */
12166 }
12167 
12168 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
pic16_vcg_dumpedges(pCode * pc,FILE * of)12169 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12170   char buf[BUF_SIZE];
12171   pCodeInstruction *pci;
12172   pBranch *curr;
12173   int i;
12174 
12175   if (1 && isPCFL(pc)) {
12176     /* emit edges to flow successors */
12177     void *pcfl;
12178     //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12179     pcfl = setFirstItem (PCFL(pc)->to);
12180     while (pcfl) {
12181       pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12182       pic16_vcg_dumpnode (pc, of);
12183       pic16_vcg_dumpnode ((pCode *) pcfl, of);
12184       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12185       fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12186       pcfl = setNextItem (PCFL(pc)->to);
12187     } // while
12188   } // if
12189 
12190   if (!isPCI(pc) && !isPCAD(pc)) return;
12191 
12192   pci = PCI(pc);
12193 
12194   /* emit control flow edges (forward only) */
12195   curr = pci->to;
12196   i=0;
12197   while (curr) {
12198     pic16_vcg_dumpnode (curr->pc, of);
12199     fprintf (of, "edge:{");
12200     fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12201     fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12202     fprintf (of, "color:red ");
12203     fprintf (of, "}\n");
12204     curr = curr->next;
12205   } // while
12206 
12207 #if 1
12208   /* dump "flow" edge (link pCode according to pBlock order) */
12209   {
12210     pCode *pcnext;
12211     pcnext = pic16_findNextInstruction (pc->next);
12212     if (pcnext) {
12213       pic16_vcg_dumpnode (pcnext, of);
12214       fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12215       fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12216     }
12217   }
12218 #endif
12219 
12220 #if 0
12221   /* emit flow */
12222   if (pci->pcflow) {
12223     pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12224     fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12225     fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12226   }
12227 #endif
12228 
12229   /* emit data flow edges (backward only) */
12230   /* TODO: gather data flow information... */
12231 }
12232 
pic16_vcg_dump(FILE * of,pBlock * pb)12233 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12234   pCode *pc;
12235 
12236   if (!pb) return;
12237 
12238   /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12239   if (pic16_pBlockHasAsmdirs (pb)) {
12240     //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12241     return;
12242   }
12243 
12244   for (pc=pb->pcHead; pc; pc = pc->next) {
12245     pic16_vcg_dumpnode (pc, of);
12246   } // for pc
12247 
12248   for (pc=pb->pcHead; pc; pc = pc->next) {
12249     pic16_vcg_dumpedges (pc, of);
12250   } // for pc
12251 }
12252 
pic16_vcg_dump_default(pBlock * pb)12253 static void pic16_vcg_dump_default (pBlock *pb) {
12254   FILE *of;
12255   char buf[BUF_SIZE];
12256   pCode *pc;
12257 
12258   if (!pb) return;
12259 
12260   /* get function name */
12261   pc = pb->pcHead;
12262   while (pc && !isPCF(pc)) pc = pc->next;
12263   if (pc) {
12264     SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12265   } else {
12266     SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12267   }
12268 
12269   //fprintf (stderr, "now dumping %s\n", buf);
12270   of = fopen (buf, "w");
12271   pic16_vcg_init (of);
12272   pic16_vcg_dump (of, pb);
12273   pic16_vcg_close (of);
12274   fclose (of);
12275 }
12276 #endif
12277 
12278 /*** END of helpers for pCode dataflow optimizations ***/
12279