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, ©) == 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 (©);
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 (®1->reglives.usedpCodes, pc);
11894 }
11895 if (reg2) {
11896 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11897 addSetIfnotP (&seenRegs, reg2);
11898 addSetIfnotP (®2->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 (®1->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