1 /*-------------------------------------------------------------------------
3 pcode.c - post code generation
5 Written By - Scott Dattalo scott@dattalo.com
6 Ported to PIC16 By - Martin Dubuc m.dubuc@rogers.com
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
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.
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 -------------------------------------------------------------------------*/
25 #include "common.h" // Include everything in the SDCC src directory
31 #include "pcodeflow.h"
35 extern char *pic16_aopGet (struct asmop *aop, int offset, bool bit16, bool dname);
37 #if defined(__BORLANDC__) || defined(_MSC_VER)
38 #define STRCASECMP stricmp
41 #define STRCASECMP strcasecmp
44 #define DUMP_DF_GRAPHS 0
46 /****************************************************************/
47 /****************************************************************/
49 static peepCommand peepCommands[] = {
51 {NOTBITSKIP, "_NOTBITSKIP_"},
52 {BITSKIP, "_BITSKIP_"},
53 {INVERTBITSKIP, "_INVERTBITSKIP_"},
60 // Eventually this will go into device dependent files:
61 pCodeOpReg pic16_pc_status = {{PO_STATUS, "STATUS"}, -1, NULL,0,NULL};
62 pCodeOpReg pic16_pc_intcon = {{PO_INTCON, "INTCON"}, -1, NULL,0,NULL};
63 pCodeOpReg pic16_pc_pcl = {{PO_PCL, "PCL"}, -1, NULL,0,NULL};
64 pCodeOpReg pic16_pc_pclath = {{PO_PCLATH, "PCLATH"}, -1, NULL,0,NULL};
65 pCodeOpReg pic16_pc_pclatu = {{PO_PCLATU, "PCLATU"}, -1, NULL,0,NULL}; // patch 14
66 pCodeOpReg pic16_pc_wreg = {{PO_WREG, "WREG"}, -1, NULL,0,NULL};
67 pCodeOpReg pic16_pc_bsr = {{PO_BSR, "BSR"}, -1, NULL,0,NULL};
69 pCodeOpReg pic16_pc_tosl = {{PO_SFR_REGISTER, "TOSL"}, -1, NULL,0,NULL}; // patch 14
70 pCodeOpReg pic16_pc_tosh = {{PO_SFR_REGISTER, "TOSH"}, -1, NULL,0,NULL}; //
71 pCodeOpReg pic16_pc_tosu = {{PO_SFR_REGISTER, "TOSU"}, -1, NULL,0,NULL}; // patch 14
73 pCodeOpReg pic16_pc_tblptrl = {{PO_SFR_REGISTER, "TBLPTRL"}, -1, NULL,0,NULL}; // patch 15
74 pCodeOpReg pic16_pc_tblptrh = {{PO_SFR_REGISTER, "TBLPTRH"}, -1, NULL,0,NULL}; //
75 pCodeOpReg pic16_pc_tblptru = {{PO_SFR_REGISTER, "TBLPTRU"}, -1, NULL,0,NULL}; //
76 pCodeOpReg pic16_pc_tablat = {{PO_SFR_REGISTER, "TABLAT"}, -1, NULL,0,NULL}; // patch 15
78 //pCodeOpReg pic16_pc_fsr0 = {{PO_FSR0, "FSR0"}, -1, NULL,0,NULL}; //deprecated !
80 pCodeOpReg pic16_pc_fsr0l = {{PO_FSR0, "FSR0L"}, -1, NULL, 0, NULL};
81 pCodeOpReg pic16_pc_fsr0h = {{PO_FSR0, "FSR0H"}, -1, NULL, 0, NULL};
82 pCodeOpReg pic16_pc_fsr1l = {{PO_FSR0, "FSR1L"}, -1, NULL, 0, NULL};
83 pCodeOpReg pic16_pc_fsr1h = {{PO_FSR0, "FSR1H"}, -1, NULL, 0, NULL};
84 pCodeOpReg pic16_pc_fsr2l = {{PO_FSR0, "FSR2L"}, -1, NULL, 0, NULL};
85 pCodeOpReg pic16_pc_fsr2h = {{PO_FSR0, "FSR2H"}, -1, NULL, 0, NULL};
87 pCodeOpReg pic16_pc_indf0 = {{PO_INDF0, "INDF0"}, -1, NULL,0,NULL};
88 pCodeOpReg pic16_pc_postinc0 = {{PO_INDF0, "POSTINC0"}, -1, NULL, 0, NULL};
89 pCodeOpReg pic16_pc_postdec0 = {{PO_INDF0, "POSTDEC0"}, -1, NULL, 0, NULL};
90 pCodeOpReg pic16_pc_preinc0 = {{PO_INDF0, "PREINC0"}, -1, NULL, 0, NULL};
91 pCodeOpReg pic16_pc_plusw0 = {{PO_INDF0, "PLUSW0"}, -1, NULL, 0, NULL};
93 pCodeOpReg pic16_pc_indf1 = {{PO_INDF0, "INDF1"}, -1, NULL,0,NULL};
94 pCodeOpReg pic16_pc_postinc1 = {{PO_INDF0, "POSTINC1"}, -1, NULL, 0, NULL};
95 pCodeOpReg pic16_pc_postdec1 = {{PO_INDF0, "POSTDEC1"}, -1, NULL, 0, NULL};
96 pCodeOpReg pic16_pc_preinc1 = {{PO_INDF0, "PREINC1"}, -1, NULL, 0, NULL};
97 pCodeOpReg pic16_pc_plusw1 = {{PO_INDF0, "PLUSW1"}, -1, NULL, 0, NULL};
99 pCodeOpReg pic16_pc_indf2 = {{PO_INDF0, "INDF2"}, -1, NULL,0,NULL};
100 pCodeOpReg pic16_pc_postinc2 = {{PO_INDF0, "POSTINC2"}, -1, NULL, 0, NULL};
101 pCodeOpReg pic16_pc_postdec2 = {{PO_INDF0, "POSTDEC2"}, -1, NULL, 0, NULL};
102 pCodeOpReg pic16_pc_preinc2 = {{PO_INDF0, "PREINC2"}, -1, NULL, 0, NULL};
103 pCodeOpReg pic16_pc_plusw2 = {{PO_INDF0, "PLUSW2"}, -1, NULL, 0, NULL};
105 pCodeOpReg pic16_pc_prodl = {{PO_PRODL, "PRODL"}, -1, NULL, 0, NULL};
106 pCodeOpReg pic16_pc_prodh = {{PO_PRODH, "PRODH"}, -1, NULL, 0, NULL};
108 /* EEPROM registers */
109 pCodeOpReg pic16_pc_eecon1 = {{PO_SFR_REGISTER, "EECON1"}, -1, NULL, 0, NULL};
110 pCodeOpReg pic16_pc_eecon2 = {{PO_SFR_REGISTER, "EECON2"}, -1, NULL, 0, NULL};
111 pCodeOpReg pic16_pc_eedata = {{PO_SFR_REGISTER, "EEDATA"}, -1, NULL, 0, NULL};
112 pCodeOpReg pic16_pc_eeadr = {{PO_SFR_REGISTER, "EEADR"}, -1, NULL, 0, NULL};
114 pCodeOpReg pic16_pc_kzero = {{PO_GPR_REGISTER, "KZ"}, -1, NULL,0,NULL};
115 pCodeOpReg pic16_pc_wsave = {{PO_GPR_REGISTER, "WSAVE"}, -1, NULL,0,NULL};
116 pCodeOpReg pic16_pc_ssave = {{PO_GPR_REGISTER, "SSAVE"}, -1, NULL,0,NULL};
118 pCodeOpReg *pic16_stackpnt_lo;
119 pCodeOpReg *pic16_stackpnt_hi;
120 pCodeOpReg *pic16_stack_postinc;
121 pCodeOpReg *pic16_stack_postdec;
122 pCodeOpReg *pic16_stack_preinc;
123 pCodeOpReg *pic16_stack_plusw;
125 pCodeOpReg *pic16_framepnt_lo;
126 pCodeOpReg *pic16_framepnt_hi;
127 pCodeOpReg *pic16_frame_postinc;
128 pCodeOpReg *pic16_frame_postdec;
129 pCodeOpReg *pic16_frame_preinc;
130 pCodeOpReg *pic16_frame_plusw;
132 pCodeOpReg pic16_pc_gpsimio = {{PO_GPR_REGISTER, "GPSIMIO"}, -1, NULL, 0, NULL};
133 pCodeOpReg pic16_pc_gpsimio2 = {{PO_GPR_REGISTER, "GPSIMIO2"}, -1, NULL, 0, NULL};
135 char *OPT_TYPE_STR[] = { "begin", "end", "jumptable_begin", "jumptable_end" };
136 char *LR_TYPE_STR[] = { "entry begin", "entry end", "exit begin", "exit end" };
139 static int mnemonics_initialized = 0;
142 static hTab *pic16MnemonicsHash = NULL;
143 static hTab *pic16pCodePeepCommandsHash = NULL;
145 static pFile *the_pFile = NULL;
146 static pBlock *pb_dead_pcodes = NULL;
148 /* Hardcoded flags to change the behavior of the PIC port */
149 static int peepOptimizing = 1; /* run the peephole optimizer if nonzero */
150 static int functionInlining = 1; /* inline functions if nonzero */
151 int pic16_debug_verbose = 0; /* Set true to inundate .asm file */
153 int pic16_pcode_verbose = 0;
155 //static int GpCodeSequenceNumber = 1;
156 static int GpcFlowSeq = 1;
158 extern void pic16_RemoveUnusedRegisters(void);
159 extern void pic16_RegsUnMapLiveRanges(void);
160 extern void pic16_BuildFlowTree(pBlock *pb);
161 extern void pic16_pCodeRegOptimizeRegUsage(int level);
162 extern int pic16_picIsInitialized(void);
163 extern void SAFE_snprintf(char **str, size_t *size, const char *format, ...);
164 extern int mnem2key(char const *mnem);
166 /****************************************************************/
167 /* Forward declarations */
168 /****************************************************************/
170 void pic16_unlinkpCode(pCode *pc);
172 static void genericAnalyze(pCode *pc);
173 static void AnalyzeGOTO(pCode *pc);
174 static void AnalyzeSKIP(pCode *pc);
175 static void AnalyzeRETURN(pCode *pc);
178 static void genericDestruct(pCode *pc);
179 static void genericPrint(FILE *of,pCode *pc);
181 static void pCodePrintLabel(FILE *of, pCode *pc);
182 static void pCodePrintFunction(FILE *of, pCode *pc);
183 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
184 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc);
185 char *pic16_get_op(pCodeOp *pcop,char *buff,size_t buf_size);
186 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
187 int pic16_pCodePeepMatchRule(pCode *pc);
188 static void pBlockStats(FILE *of, pBlock *pb);
189 static pBlock *newpBlock(void);
190 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
191 extern pCodeOp *pic16_popCopyReg(pCodeOpReg *pc);
192 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval);
193 void pic16_pCodeRegMapLiveRanges(pBlock *pb);
194 void OptimizeLocalRegs(void);
195 pCodeOp *pic16_popGet2p(pCodeOp *src, pCodeOp *dst);
197 char *dumpPicOptype(PIC_OPTYPE type);
199 pCodeOp *pic16_popGetLit2(int, pCodeOp *);
200 pCodeOp *pic16_popGetLit(int);
201 pCodeOp *pic16_popGetWithString(char *);
202 extern int inWparamList(char *s);
204 /** data flow optimization helpers **/
205 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
206 static void pic16_vcg_dump (FILE *of, pBlock *pb);
207 static void pic16_vcg_dump_default (pBlock *pb);
209 static int pic16_pCodeIsAlive (pCode *pc);
210 static void pic16_df_stats ();
211 static void pic16_createDF (pBlock *pb);
212 static int pic16_removeUnusedRegistersDF ();
213 static void pic16_destructDF (pBlock *pb);
214 static void releaseStack ();
216 /****************************************************************/
217 /* PIC Instructions */
218 /****************************************************************/
220 pCodeInstruction pic16_pciADDWF = {
221 {PC_OPCODE, NULL, NULL, 0, NULL,
235 1,0, // dest, bit instruction
237 0, // literal operand
239 0, // fast call/return mode select bit
240 0, // second memory operand
241 0, // second literal operand
243 (PCC_W | PCC_REGISTER), // inCond
244 (PCC_REGISTER | PCC_STATUS), // outCond
248 pCodeInstruction pic16_pciADDFW = {
249 {PC_OPCODE, NULL, NULL, 0, NULL,
263 0,0, // dest, bit instruction
265 0, // literal operand
267 0, // fast call/return mode select bit
268 0, // second memory operand
269 0, // second literal operand
271 (PCC_W | PCC_REGISTER), // inCond
272 (PCC_W | PCC_STATUS), // outCond
276 pCodeInstruction pic16_pciADDWFC = { // mdubuc - New
277 {PC_OPCODE, NULL, NULL, 0, NULL,
291 1,0, // dest, bit instruction
293 0, // literal operand
295 0, // fast call/return mode select bit
296 0, // second memory operand
297 0, // second literal operand
299 (PCC_W | PCC_REGISTER | PCC_C), // inCond
300 (PCC_REGISTER | PCC_STATUS), // outCond
304 pCodeInstruction pic16_pciADDFWC = {
305 {PC_OPCODE, NULL, NULL, 0, NULL,
319 0,0, // dest, bit instruction
321 0, // literal operand
323 0, // fast call/return mode select bit
324 0, // second memory operand
325 0, // second literal operand
327 (PCC_W | PCC_REGISTER | PCC_C), // inCond
328 (PCC_W | PCC_STATUS), // outCond
332 pCodeInstruction pic16_pciADDLW = {
333 {PC_OPCODE, NULL, NULL, 0, NULL,
347 0,0, // dest, bit instruction
349 1, // literal operand
351 0, // fast call/return mode select bit
352 0, // second memory operand
353 0, // second literal operand
355 (PCC_W | PCC_LITERAL), // inCond
356 (PCC_W | PCC_STATUS), // outCond
360 pCodeInstruction pic16_pciANDLW = {
361 {PC_OPCODE, NULL, NULL, 0, NULL,
375 0,0, // dest, bit instruction
377 1, // literal operand
379 0, // fast call/return mode select bit
380 0, // second memory operand
381 0, // second literal operand
383 (PCC_W | PCC_LITERAL), // inCond
384 (PCC_W | PCC_Z | PCC_N), // outCond
388 pCodeInstruction pic16_pciANDWF = {
389 {PC_OPCODE, NULL, NULL, 0, NULL,
403 1,0, // dest, bit instruction
405 0, // literal operand
407 0, // fast call/return mode select bit
408 0, // second memory operand
409 0, // second literal operand
411 (PCC_W | PCC_REGISTER), // inCond
412 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
416 pCodeInstruction pic16_pciANDFW = {
417 {PC_OPCODE, NULL, NULL, 0, NULL,
431 0,0, // dest, bit instruction
433 0, // literal operand
435 0, // fast call/return mode select bit
436 0, // second memory operand
437 0, // second literal operand
439 (PCC_W | PCC_REGISTER), // inCond
440 (PCC_W | PCC_Z | PCC_N) // outCond
443 pCodeInstruction pic16_pciBC = { // mdubuc - New
444 {PC_OPCODE, NULL, NULL, 0, NULL,
458 0,0, // dest, bit instruction
460 0, // literal operand
462 0, // fast call/return mode select bit
463 0, // second memory operand
464 0, // second literal operand
466 (PCC_REL_ADDR | PCC_C), // inCond
471 pCodeInstruction pic16_pciBCF = {
472 {PC_OPCODE, NULL, NULL, 0, NULL,
486 1,1, // dest, bit instruction
488 0, // literal operand
490 0, // fast call/return mode select bit
491 0, // second memory operand
492 0, // second literal operand
494 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
495 PCC_REGISTER, // outCond
499 pCodeInstruction pic16_pciBN = { // mdubuc - New
500 {PC_OPCODE, NULL, NULL, 0, NULL,
514 0,0, // dest, bit instruction
516 0, // literal operand
518 0, // fast call/return mode select bit
519 0, // second memory operand
520 0, // second literal operand
522 (PCC_REL_ADDR | PCC_N), // inCond
523 PCC_NONE , // outCond
527 pCodeInstruction pic16_pciBNC = { // mdubuc - New
528 {PC_OPCODE, NULL, NULL, 0, NULL,
542 0,0, // dest, bit instruction
544 0, // literal operand
546 0, // fast call/return mode select bit
547 0, // second memory operand
548 0, // second literal operand
550 (PCC_REL_ADDR | PCC_C), // inCond
551 PCC_NONE , // outCond
555 pCodeInstruction pic16_pciBNN = { // mdubuc - New
556 {PC_OPCODE, NULL, NULL, 0, NULL,
570 0,0, // dest, bit instruction
572 0, // literal operand
574 0, // fast call/return mode select bit
575 0, // second memory operand
576 0, // second literal operand
578 (PCC_REL_ADDR | PCC_N), // inCond
579 PCC_NONE , // outCond
583 pCodeInstruction pic16_pciBNOV = { // mdubuc - New
584 {PC_OPCODE, NULL, NULL, 0, NULL,
598 0,0, // dest, bit instruction
600 0, // literal operand
602 0, // fast call/return mode select bit
603 0, // second memory operand
604 0, // second literal operand
606 (PCC_REL_ADDR | PCC_OV), // inCond
607 PCC_NONE , // outCond
611 pCodeInstruction pic16_pciBNZ = { // mdubuc - New
612 {PC_OPCODE, NULL, NULL, 0, NULL,
626 0,0, // dest, bit instruction
628 0, // literal operand
630 0, // fast call/return mode select bit
631 0, // second memory operand
632 0, // second literal operand
634 (PCC_REL_ADDR | PCC_Z), // inCond
635 PCC_NONE , // outCond
639 pCodeInstruction pic16_pciBOV = { // mdubuc - New
640 {PC_OPCODE, NULL, NULL, 0, NULL,
654 0,0, // dest, bit instruction
656 0, // literal operand
658 0, // fast call/return mode select bit
659 0, // second memory operand
660 0, // second literal operand
662 (PCC_REL_ADDR | PCC_OV), // inCond
663 PCC_NONE , // outCond
667 pCodeInstruction pic16_pciBRA = { // mdubuc - New
668 {PC_OPCODE, NULL, NULL, 0, NULL,
682 0,0, // dest, bit instruction
684 0, // literal operand
686 0, // fast call/return mode select bit
687 0, // second memory operand
688 0, // second literal operand
690 PCC_REL_ADDR, // inCond
691 PCC_NONE , // outCond
695 pCodeInstruction pic16_pciBSF = {
696 {PC_OPCODE, NULL, NULL, 0, NULL,
710 1,1, // dest, bit instruction
712 0, // literal operand
714 0, // fast call/return mode select bit
715 0, // second memory operand
716 0, // second literal operand
718 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
719 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
723 pCodeInstruction pic16_pciBTFSC = {
724 {PC_OPCODE, NULL, NULL, 0, NULL,
738 0,1, // dest, bit instruction
740 0, // literal operand
742 0, // fast call/return mode select bit
743 0, // second memory operand
744 0, // second literal operand
746 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
747 PCC_EXAMINE_PCOP, // outCond
751 pCodeInstruction pic16_pciBTFSS = {
752 {PC_OPCODE, NULL, NULL, 0, NULL,
766 0,1, // dest, bit instruction
768 0, // literal operand
770 0, // fast call/return mode select bit
771 0, // second memory operand
772 0, // second literal operand
774 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
775 PCC_EXAMINE_PCOP, // outCond
779 pCodeInstruction pic16_pciBTG = { // mdubuc - New
780 {PC_OPCODE, NULL, NULL, 0, NULL,
794 0,1, // dest, bit instruction
796 0, // literal operand
798 0, // fast call/return mode select bit
799 0, // second memory operand
800 0, // second literal operand
802 (PCC_REGISTER | PCC_EXAMINE_PCOP), // inCond
803 (PCC_REGISTER | PCC_EXAMINE_PCOP), // outCond
807 pCodeInstruction pic16_pciBZ = { // mdubuc - New
808 {PC_OPCODE, NULL, NULL, 0, NULL,
822 0,0, // dest, bit instruction
824 0, // literal operand
826 0, // fast call/return mode select bit
827 0, // second memory operand
828 0, // second literal operand
830 (PCC_REL_ADDR | PCC_Z), // inCond
835 pCodeInstruction pic16_pciCALL = {
836 {PC_OPCODE, NULL, NULL, 0, NULL,
850 0,0, // dest, bit instruction
852 0, // literal operand
854 1, // fast call/return mode select bit
855 0, // second memory operand
856 0, // second literal operand
863 pCodeInstruction pic16_pciCOMF = {
864 {PC_OPCODE, NULL, NULL, 0, NULL,
878 1,0, // dest, bit instruction
880 0, // literal operand
882 0, // fast call/return mode select bit
883 0, // second memory operand
884 0, // second literal operand
886 PCC_REGISTER, // inCond
887 (PCC_REGISTER | PCC_Z | PCC_N) , // outCond
891 pCodeInstruction pic16_pciCOMFW = {
892 {PC_OPCODE, NULL, NULL, 0, NULL,
906 0,0, // dest, bit instruction
908 0, // literal operand
910 0, // fast call/return mode select bit
911 0, // second memory operand
912 0, // second literal operand
914 PCC_REGISTER, // inCond
915 (PCC_W | PCC_Z | PCC_N) , // outCond
919 pCodeInstruction pic16_pciCLRF = {
920 {PC_OPCODE, NULL, NULL, 0, NULL,
934 0,0, // dest, bit instruction
936 0, // literal operand
938 0, // fast call/return mode select bit
939 0, // second memory operand
940 0, // second literal operand
943 (PCC_REGISTER | PCC_Z), // outCond
947 pCodeInstruction pic16_pciCLRWDT = {
948 {PC_OPCODE, NULL, NULL, 0, NULL,
962 0,0, // dest, bit instruction
964 0, // literal operand
966 0, // fast call/return mode select bit
967 0, // second memory operand
968 0, // second literal operand
971 PCC_NONE , // outCond
975 pCodeInstruction pic16_pciCPFSEQ = { // mdubuc - New
976 {PC_OPCODE, NULL, NULL, 0, NULL,
990 0,0, // dest, bit instruction
992 0, // literal operand
994 0, // fast call/return mode select bit
995 0, // second memory operand
996 0, // second literal operand
998 (PCC_W | PCC_REGISTER), // inCond
999 PCC_NONE , // outCond
1003 pCodeInstruction pic16_pciCPFSGT = { // mdubuc - New
1004 {PC_OPCODE, NULL, NULL, 0, NULL,
1011 NULL, // from branch
1018 0,0, // dest, bit instruction
1019 1,1, // branch, skip
1020 0, // literal operand
1021 1, // RAM access bit
1022 0, // fast call/return mode select bit
1023 0, // second memory operand
1024 0, // second literal operand
1026 (PCC_W | PCC_REGISTER), // inCond
1027 PCC_NONE , // outCond
1031 pCodeInstruction pic16_pciCPFSLT = { // mdubuc - New
1032 {PC_OPCODE, NULL, NULL, 0, NULL,
1039 NULL, // from branch
1046 1,0, // dest, bit instruction
1047 1,1, // branch, skip
1048 0, // literal operand
1049 1, // RAM access bit
1050 0, // fast call/return mode select bit
1051 0, // second memory operand
1052 0, // second literal operand
1054 (PCC_W | PCC_REGISTER), // inCond
1055 PCC_NONE , // outCond
1059 pCodeInstruction pic16_pciDAW = {
1060 {PC_OPCODE, NULL, NULL, 0, NULL,
1067 NULL, // from branch
1074 0,0, // dest, bit instruction
1075 0,0, // branch, skip
1076 0, // literal operand
1077 0, // RAM access bit
1078 0, // fast call/return mode select bit
1079 0, // second memory operand
1080 0, // second literal operand
1083 (PCC_W | PCC_C), // outCond
1087 pCodeInstruction pic16_pciDCFSNZ = { // mdubuc - New
1088 {PC_OPCODE, NULL, NULL, 0, NULL,
1095 NULL, // from branch
1102 1,0, // dest, bit instruction
1103 1,1, // branch, skip
1104 0, // literal operand
1105 1, // RAM access bit
1106 0, // fast call/return mode select bit
1107 0, // second memory operand
1108 0, // second literal operand
1110 PCC_REGISTER, // inCond
1111 PCC_REGISTER , // outCond
1115 pCodeInstruction pic16_pciDCFSNZW = { // mdubuc - New
1116 {PC_OPCODE, NULL, NULL, 0, NULL,
1123 NULL, // from branch
1130 0,0, // dest, bit instruction
1131 1,1, // branch, skip
1132 0, // literal operand
1133 1, // RAM access bit
1134 0, // fast call/return mode select bit
1135 0, // second memory operand
1136 0, // second literal operand
1138 PCC_REGISTER, // inCond
1143 pCodeInstruction pic16_pciDECF = {
1144 {PC_OPCODE, NULL, NULL, 0, NULL,
1151 NULL, // from branch
1158 1,0, // dest, bit instruction
1159 0,0, // branch, skip
1160 0, // literal operand
1161 1, // RAM access bit
1162 0, // fast call/return mode select bit
1163 0, // second memory operand
1164 0, // second literal operand
1166 PCC_REGISTER, // inCond
1167 (PCC_REGISTER | PCC_STATUS) , // outCond
1171 pCodeInstruction pic16_pciDECFW = {
1172 {PC_OPCODE, NULL, NULL, 0, NULL,
1179 NULL, // from branch
1186 0,0, // dest, bit instruction
1187 0,0, // branch, skip
1188 0, // literal operand
1189 1, // RAM access bit
1190 0, // fast call/return mode select bit
1191 0, // second memory operand
1192 0, // second literal operand
1194 PCC_REGISTER, // inCond
1195 (PCC_W | PCC_STATUS) , // outCond
1199 pCodeInstruction pic16_pciDECFSZ = {
1200 {PC_OPCODE, NULL, NULL, 0, NULL,
1207 NULL, // from branch
1214 1,0, // dest, bit instruction
1215 1,1, // branch, skip
1216 0, // literal operand
1217 1, // RAM access bit
1218 0, // fast call/return mode select bit
1219 0, // second memory operand
1220 0, // second literal operand
1222 PCC_REGISTER, // inCond
1223 PCC_REGISTER , // outCond
1227 pCodeInstruction pic16_pciDECFSZW = {
1228 {PC_OPCODE, NULL, NULL, 0, NULL,
1235 NULL, // from branch
1242 0,0, // dest, bit instruction
1243 1,1, // branch, skip
1244 0, // literal operand
1245 1, // RAM access bit
1246 0, // fast call/return mode select bit
1247 0, // second memory operand
1248 0, // second literal operand
1250 PCC_REGISTER, // inCond
1255 pCodeInstruction pic16_pciGOTO = {
1256 {PC_OPCODE, NULL, NULL, 0, NULL,
1263 NULL, // from branch
1270 0,0, // dest, bit instruction
1271 1,0, // branch, skip
1272 0, // literal operand
1273 0, // RAM access bit
1274 0, // fast call/return mode select bit
1275 0, // second memory operand
1276 0, // second literal operand
1278 PCC_REL_ADDR, // inCond
1279 PCC_NONE , // outCond
1283 pCodeInstruction pic16_pciINCF = {
1284 {PC_OPCODE, NULL, NULL, 0, NULL,
1291 NULL, // from branch
1298 1,0, // dest, bit instruction
1299 0,0, // branch, skip
1300 0, // literal operand
1301 1, // RAM access bit
1302 0, // fast call/return mode select bit
1303 0, // second memory operand
1304 0, // second literal operand
1306 PCC_REGISTER, // inCond
1307 (PCC_REGISTER | PCC_STATUS), // outCond
1311 pCodeInstruction pic16_pciINCFW = {
1312 {PC_OPCODE, NULL, NULL, 0, NULL,
1319 NULL, // from branch
1326 0,0, // dest, bit instruction
1327 0,0, // branch, skip
1328 0, // literal operand
1329 1, // RAM access bit
1330 0, // fast call/return mode select bit
1331 0, // second memory operand
1332 0, // second literal operand
1334 PCC_REGISTER, // inCond
1335 (PCC_W | PCC_STATUS) , // outCond
1339 pCodeInstruction pic16_pciINCFSZ = {
1340 {PC_OPCODE, NULL, NULL, 0, NULL,
1347 NULL, // from branch
1354 1,0, // dest, bit instruction
1355 1,1, // branch, skip
1356 0, // literal operand
1357 1, // RAM access bit
1358 0, // fast call/return mode select bit
1359 0, // second memory operand
1360 0, // second literal operand
1362 PCC_REGISTER, // inCond
1363 PCC_REGISTER , // outCond
1367 pCodeInstruction pic16_pciINCFSZW = {
1368 {PC_OPCODE, NULL, NULL, 0, NULL,
1375 NULL, // from branch
1382 0,0, // dest, bit instruction
1383 1,1, // branch, skip
1384 0, // literal operand
1385 1, // RAM access bit
1386 0, // fast call/return mode select bit
1387 0, // second memory operand
1388 0, // second literal operand
1390 PCC_REGISTER, // inCond
1395 pCodeInstruction pic16_pciINFSNZ = { // mdubuc - New
1396 {PC_OPCODE, NULL, NULL, 0, NULL,
1403 NULL, // from branch
1410 1,0, // dest, bit instruction
1411 1,1, // branch, skip
1412 0, // literal operand
1413 1, // RAM access bit
1414 0, // fast call/return mode select bit
1415 0, // second memory operand
1416 0, // second literal operand
1418 PCC_REGISTER, // inCond
1419 PCC_REGISTER , // outCond
1423 pCodeInstruction pic16_pciINFSNZW = { // vrokas - New
1424 {PC_OPCODE, NULL, NULL, 0, NULL,
1431 NULL, // from branch
1438 0,0, // dest, bit instruction
1439 1,1, // branch, skip
1440 0, // literal operand
1441 1, // RAM access bit
1442 0, // fast call/return mode select bit
1443 0, // second memory operand
1444 0, // second literal operand
1446 PCC_REGISTER, // inCond
1451 pCodeInstruction pic16_pciIORWF = {
1452 {PC_OPCODE, NULL, NULL, 0, NULL,
1459 NULL, // from branch
1466 1,0, // dest, bit instruction
1467 0,0, // branch, skip
1468 0, // literal operand
1469 1, // RAM access bit
1470 0, // fast call/return mode select bit
1471 0, // second memory operand
1472 0, // second literal operand
1474 (PCC_W | PCC_REGISTER), // inCond
1475 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
1479 pCodeInstruction pic16_pciIORFW = {
1480 {PC_OPCODE, NULL, NULL, 0, NULL,
1487 NULL, // from branch
1494 0,0, // dest, bit instruction
1495 0,0, // branch, skip
1496 0, // literal operand
1497 1, // RAM access bit
1498 0, // fast call/return mode select bit
1499 0, // second memory operand
1500 0, // second literal operand
1502 (PCC_W | PCC_REGISTER), // inCond
1503 (PCC_W | PCC_Z | PCC_N), // outCond
1507 pCodeInstruction pic16_pciIORLW = {
1508 {PC_OPCODE, NULL, NULL, 0, NULL,
1515 NULL, // from branch
1522 0,0, // dest, bit instruction
1523 0,0, // branch, skip
1524 1, // literal operand
1525 0, // RAM access bit
1526 0, // fast call/return mode select bit
1527 0, // second memory operand
1528 0, // second literal operand
1530 (PCC_W | PCC_LITERAL), // inCond
1531 (PCC_W | PCC_Z | PCC_N), // outCond
1535 pCodeInstruction pic16_pciLFSR = { // mdubuc - New
1536 {PC_OPCODE, NULL, NULL, 0, NULL,
1543 NULL, // from branch
1550 0,0, // dest, bit instruction
1551 0,0, // branch, skip
1552 1, // literal operand
1553 0, // RAM access bit
1554 0, // fast call/return mode select bit
1555 0, // second memory operand
1556 1, // second literal operand
1558 PCC_LITERAL, // inCond
1559 PCC_NONE, // outCond
1563 pCodeInstruction pic16_pciMOVF = {
1564 {PC_OPCODE, NULL, NULL, 0, NULL,
1571 NULL, // from branch
1578 1,0, // dest, bit instruction
1579 0,0, // branch, skip
1580 0, // literal operand
1581 1, // RAM access bit
1582 0, // fast call/return mode select bit
1583 0, // second memory operand
1584 0, // second literal operand
1586 PCC_REGISTER, // inCond
1587 (PCC_Z | PCC_N), // outCond
1591 pCodeInstruction pic16_pciMOVFW = {
1592 {PC_OPCODE, NULL, NULL, 0, NULL,
1599 NULL, // from branch
1606 0,0, // dest, bit instruction
1607 0,0, // branch, skip
1608 0, // literal operand
1609 1, // RAM access bit
1610 0, // fast call/return mode select bit
1611 0, // second memory operand
1612 0, // second literal operand
1614 PCC_REGISTER, // inCond
1615 (PCC_W | PCC_N | PCC_Z), // outCond
1619 pCodeInstruction pic16_pciMOVFF = { // mdubuc - New
1620 {PC_OPCODE, NULL, NULL, 0, NULL,
1627 NULL, // from branch
1634 0,0, // dest, bit instruction
1635 0,0, // branch, skip
1636 0, // literal operand
1637 0, // RAM access bit
1638 0, // fast call/return mode select bit
1639 1, // second memory operand
1640 0, // second literal operand
1642 PCC_REGISTER, // inCond
1643 PCC_REGISTER2, // outCond
1647 pCodeInstruction pic16_pciMOVLB = { // mdubuc - New
1648 {PC_OPCODE, NULL, NULL, 0, NULL,
1654 NULL, // from branch
1661 0,0, // dest, bit instruction
1662 0,0, // branch, skip
1663 1, // literal operand
1664 0, // RAM access bit
1665 0, // fast call/return mode select bit
1666 0, // second memory operand
1667 0, // second literal operand
1669 (PCC_NONE | PCC_LITERAL), // inCond
1670 PCC_REGISTER, // outCond - BSR
1674 pCodeInstruction pic16_pciMOVLW = {
1675 {PC_OPCODE, NULL, NULL, 0, NULL,
1681 NULL, // from branch
1688 0,0, // dest, bit instruction
1689 0,0, // branch, skip
1690 1, // literal operand
1691 0, // RAM access bit
1692 0, // fast call/return mode select bit
1693 0, // second memory operand
1694 0, // second literal operand
1696 (PCC_NONE | PCC_LITERAL), // inCond
1701 pCodeInstruction pic16_pciMOVWF = {
1702 {PC_OPCODE, NULL, NULL, 0, NULL,
1709 NULL, // from branch
1716 0,0, // dest, bit instruction
1717 0,0, // branch, skip
1718 0, // literal operand
1719 1, // RAM access bit
1720 0, // fast call/return mode select bit
1721 0, // second memory operand
1722 0, // second literal operand
1725 PCC_REGISTER, // outCond
1729 pCodeInstruction pic16_pciMULLW = { // mdubuc - New
1730 {PC_OPCODE, NULL, NULL, 0, NULL,
1736 NULL, // from branch
1743 0,0, // dest, bit instruction
1744 0,0, // branch, skip
1745 1, // literal operand
1746 0, // RAM access bit
1747 0, // fast call/return mode select bit
1748 0, // second memory operand
1749 0, // second literal operand
1751 (PCC_W | PCC_LITERAL), // inCond
1752 PCC_NONE, // outCond - PROD
1756 pCodeInstruction pic16_pciMULWF = { // mdubuc - New
1757 {PC_OPCODE, NULL, NULL, 0, NULL,
1763 NULL, // from branch
1770 0,0, // dest, bit instruction
1771 0,0, // branch, skip
1772 0, // literal operand
1773 1, // RAM access bit
1774 0, // fast call/return mode select bit
1775 0, // second memory operand
1776 0, // second literal operand
1778 (PCC_W | PCC_REGISTER), // inCond
1779 PCC_REGISTER, // outCond - PROD
1783 pCodeInstruction pic16_pciNEGF = { // mdubuc - New
1784 {PC_OPCODE, NULL, NULL, 0, NULL,
1790 NULL, // from branch
1797 0,0, // dest, bit instruction
1798 0,0, // branch, skip
1799 0, // literal operand
1800 1, // RAM access bit
1801 0, // fast call/return mode select bit
1802 0, // second memory operand
1803 0, // second literal operand
1805 PCC_REGISTER, // inCond
1806 (PCC_REGISTER | PCC_STATUS), // outCond
1810 pCodeInstruction pic16_pciNOP = {
1811 {PC_OPCODE, NULL, NULL, 0, NULL,
1817 NULL, // from branch
1824 0,0, // dest, bit instruction
1825 0,0, // branch, skip
1826 0, // literal operand
1827 0, // RAM access bit
1828 0, // fast call/return mode select bit
1829 0, // second memory operand
1830 0, // second literal operand
1833 PCC_NONE, // outCond
1837 pCodeInstruction pic16_pciPOP = { // mdubuc - New
1838 {PC_OPCODE, NULL, NULL, 0, NULL,
1844 NULL, // from branch
1851 0,0, // dest, bit instruction
1852 0,0, // branch, skip
1853 0, // literal operand
1854 0, // RAM access bit
1855 0, // fast call/return mode select bit
1856 0, // second memory operand
1857 0, // second literal operand
1860 PCC_NONE , // outCond
1864 pCodeInstruction pic16_pciPUSH = {
1865 {PC_OPCODE, NULL, NULL, 0, NULL,
1871 NULL, // from branch
1878 0,0, // dest, bit instruction
1879 0,0, // branch, skip
1880 0, // literal operand
1881 0, // RAM access bit
1882 0, // fast call/return mode select bit
1883 0, // second memory operand
1884 0, // second literal operand
1887 PCC_NONE , // outCond
1891 pCodeInstruction pic16_pciRCALL = { // mdubuc - New
1892 {PC_OPCODE, NULL, NULL, 0, NULL,
1898 NULL, // from branch
1905 0,0, // dest, bit instruction
1906 1,0, // branch, skip
1907 0, // literal operand
1908 0, // RAM access bit
1909 0, // fast call/return mode select bit
1910 0, // second memory operand
1911 0, // second literal operand
1913 PCC_REL_ADDR, // inCond
1914 PCC_NONE , // outCond
1918 pCodeInstruction pic16_pciRETFIE = {
1919 {PC_OPCODE, NULL, NULL, 0, NULL,
1926 NULL, // from branch
1933 0,0, // dest, bit instruction
1934 1,0, // branch, skip
1935 0, // literal operand
1936 0, // RAM access bit
1937 1, // fast call/return mode select bit
1938 0, // second memory operand
1939 0, // second literal operand
1942 PCC_NONE, // outCond (not true... affects the GIE bit too)
1946 pCodeInstruction pic16_pciRETLW = {
1947 {PC_OPCODE, NULL, NULL, 0, NULL,
1954 NULL, // from branch
1961 0,0, // dest, bit instruction
1962 1,0, // branch, skip
1963 1, // literal operand
1964 0, // RAM access bit
1965 0, // fast call/return mode select bit
1966 0, // second memory operand
1967 0, // second literal operand
1969 PCC_LITERAL, // inCond
1974 pCodeInstruction pic16_pciRETURN = {
1975 {PC_OPCODE, NULL, NULL, 0, NULL,
1982 NULL, // from branch
1989 0,0, // dest, bit instruction
1990 1,0, // branch, skip
1991 0, // literal operand
1992 0, // RAM access bit
1993 1, // fast call/return mode select bit
1994 0, // second memory operand
1995 0, // second literal operand
1998 PCC_NONE, // outCond
2001 pCodeInstruction pic16_pciRLCF = { // mdubuc - New
2002 {PC_OPCODE, NULL, NULL, 0, NULL,
2009 NULL, // from branch
2016 1,0, // dest, bit instruction
2017 0,0, // branch, skip
2018 0, // literal operand
2019 1, // RAM access bit
2020 0, // fast call/return mode select bit
2021 0, // second memory operand
2022 0, // second literal operand
2024 (PCC_C | PCC_REGISTER), // inCond
2025 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2029 pCodeInstruction pic16_pciRLCFW = { // mdubuc - New
2030 {PC_OPCODE, NULL, NULL, 0, NULL,
2037 NULL, // from branch
2044 0,0, // dest, bit instruction
2045 0,0, // branch, skip
2046 0, // literal operand
2047 1, // RAM access bit
2048 0, // fast call/return mode select bit
2049 0, // second memory operand
2050 0, // second literal operand
2052 (PCC_C | PCC_REGISTER), // inCond
2053 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2057 pCodeInstruction pic16_pciRLNCF = { // mdubuc - New
2058 {PC_OPCODE, NULL, NULL, 0, NULL,
2065 NULL, // from branch
2072 1,0, // dest, bit instruction
2073 0,0, // branch, skip
2074 0, // literal operand
2075 1, // RAM access bit
2076 0, // fast call/return mode select bit
2077 0, // second memory operand
2078 0, // second literal operand
2080 PCC_REGISTER, // inCond
2081 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2084 pCodeInstruction pic16_pciRLNCFW = { // mdubuc - New
2085 {PC_OPCODE, NULL, NULL, 0, NULL,
2092 NULL, // from branch
2099 0,0, // dest, bit instruction
2100 0,0, // branch, skip
2101 0, // literal operand
2102 1, // RAM access bit
2103 0, // fast call/return mode select bit
2104 0, // second memory operand
2105 0, // second literal operand
2107 PCC_REGISTER, // inCond
2108 (PCC_W | PCC_Z | PCC_N), // outCond
2111 pCodeInstruction pic16_pciRRCF = { // mdubuc - New
2112 {PC_OPCODE, NULL, NULL, 0, NULL,
2119 NULL, // from branch
2126 1,0, // dest, bit instruction
2127 0,0, // branch, skip
2128 0, // literal operand
2129 1, // RAM access bit
2130 0, // fast call/return mode select bit
2131 0, // second memory operand
2132 0, // second literal operand
2134 (PCC_C | PCC_REGISTER), // inCond
2135 (PCC_REGISTER | PCC_C | PCC_Z | PCC_N), // outCond
2138 pCodeInstruction pic16_pciRRCFW = { // mdubuc - New
2139 {PC_OPCODE, NULL, NULL, 0, NULL,
2146 NULL, // from branch
2153 0,0, // dest, bit instruction
2154 0,0, // branch, skip
2155 0, // literal operand
2156 1, // RAM access bit
2157 0, // fast call/return mode select bit
2158 0, // second memory operand
2159 0, // second literal operand
2161 (PCC_C | PCC_REGISTER), // inCond
2162 (PCC_W | PCC_C | PCC_Z | PCC_N), // outCond
2165 pCodeInstruction pic16_pciRRNCF = { // mdubuc - New
2166 {PC_OPCODE, NULL, NULL, 0, NULL,
2173 NULL, // from branch
2180 1,0, // dest, bit instruction
2181 0,0, // branch, skip
2182 0, // literal operand
2183 1, // RAM access bit
2184 0, // fast call/return mode select bit
2185 0, // second memory operand
2186 0, // second literal operand
2188 PCC_REGISTER, // inCond
2189 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2193 pCodeInstruction pic16_pciRRNCFW = { // mdubuc - New
2194 {PC_OPCODE, NULL, NULL, 0, NULL,
2201 NULL, // from branch
2208 0,0, // dest, bit instruction
2209 0,0, // branch, skip
2210 0, // literal operand
2211 1, // RAM access bit
2212 0, // fast call/return mode select bit
2213 0, // second memory operand
2214 0, // second literal operand
2216 PCC_REGISTER, // inCond
2217 (PCC_W | PCC_Z | PCC_N), // outCond
2221 pCodeInstruction pic16_pciSETF = { // mdubuc - New
2222 {PC_OPCODE, NULL, NULL, 0, NULL,
2229 NULL, // from branch
2236 0,0, // dest, bit instruction
2237 0,0, // branch, skip
2238 0, // literal operand
2239 1, // RAM access bit
2240 0, // fast call/return mode select bit
2241 0, // second memory operand
2242 0, // second literal operand
2245 PCC_REGISTER , // outCond
2249 pCodeInstruction pic16_pciSUBLW = {
2250 {PC_OPCODE, NULL, NULL, 0, NULL,
2257 NULL, // from branch
2264 0,0, // dest, bit instruction
2265 0,0, // branch, skip
2266 1, // literal operand
2267 0, // RAM access bit
2268 0, // fast call/return mode select bit
2269 0, // second memory operand
2270 0, // second literal operand
2272 (PCC_W | PCC_LITERAL), // inCond
2273 (PCC_W | PCC_STATUS), // outCond
2277 pCodeInstruction pic16_pciSUBFWB = {
2278 {PC_OPCODE, NULL, NULL, 0, NULL,
2285 NULL, // from branch
2292 1,0, // dest, bit instruction
2293 0,0, // branch, skip
2294 0, // literal operand
2295 1, // RAM access bit
2296 0, // fast call/return mode select bit
2297 0, // second memory operand
2298 0, // second literal operand
2300 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2301 (PCC_W | PCC_STATUS), // outCond
2305 pCodeInstruction pic16_pciSUBWF = {
2306 {PC_OPCODE, NULL, NULL, 0, NULL,
2313 NULL, // from branch
2320 1,0, // dest, bit instruction
2321 0,0, // branch, skip
2322 0, // literal operand
2323 1, // RAM access bit
2324 0, // fast call/return mode select bit
2325 0, // second memory operand
2326 0, // second literal operand
2328 (PCC_W | PCC_REGISTER), // inCond
2329 (PCC_REGISTER | PCC_STATUS), // outCond
2333 pCodeInstruction pic16_pciSUBFW = {
2334 {PC_OPCODE, NULL, NULL, 0, NULL,
2341 NULL, // from branch
2348 0,0, // dest, bit instruction
2349 0,0, // branch, skip
2350 0, // literal operand
2351 1, // RAM access bit
2352 0, // fast call/return mode select bit
2353 0, // second memory operand
2354 0, // second literal operand
2356 (PCC_W | PCC_REGISTER), // inCond
2357 (PCC_W | PCC_STATUS), // outCond
2361 pCodeInstruction pic16_pciSUBFWB_D1 = { // mdubuc - New
2362 {PC_OPCODE, NULL, NULL, 0, NULL,
2369 NULL, // from branch
2376 1,0, // dest, bit instruction
2377 0,0, // branch, skip
2378 0, // literal operand
2379 1, // RAM access bit
2380 0, // fast call/return mode select bit
2381 0, // second memory operand
2382 0, // second literal operand
2384 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2385 (PCC_REGISTER | PCC_STATUS), // outCond
2389 pCodeInstruction pic16_pciSUBFWB_D0 = { // mdubuc - New
2390 {PC_OPCODE, NULL, NULL, 0, NULL,
2397 NULL, // from branch
2404 0,0, // dest, bit instruction
2405 0,0, // branch, skip
2406 0, // literal operand
2407 1, // RAM access bit
2408 0, // fast call/return mode select bit
2409 0, // second memory operand
2410 0, // second literal operand
2412 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2413 (PCC_W | PCC_STATUS), // outCond
2417 pCodeInstruction pic16_pciSUBWFB_D1 = { // mdubuc - New
2418 {PC_OPCODE, NULL, NULL, 0, NULL,
2425 NULL, // from branch
2432 1,0, // dest, bit instruction
2433 0,0, // branch, skip
2434 0, // literal operand
2435 1, // RAM access bit
2436 0, // fast call/return mode select bit
2437 0, // second memory operand
2438 0, // second literal operand
2440 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2441 (PCC_REGISTER | PCC_STATUS), // outCond
2445 pCodeInstruction pic16_pciSUBWFB_D0 = { // mdubuc - New
2446 {PC_OPCODE, NULL, NULL, 0, NULL,
2453 NULL, // from branch
2460 0,0, // dest, bit instruction
2461 0,0, // branch, skip
2462 0, // literal operand
2463 1, // RAM access bit
2464 0, // fast call/return mode select bit
2465 0, // second memory operand
2466 0, // second literal operand
2468 (PCC_W | PCC_REGISTER | PCC_C), // inCond
2469 (PCC_W | PCC_STATUS), // outCond
2473 pCodeInstruction pic16_pciSWAPF = {
2474 {PC_OPCODE, NULL, NULL, 0, NULL,
2481 NULL, // from branch
2488 1,0, // dest, bit instruction
2489 0,0, // branch, skip
2490 0, // literal operand
2491 1, // RAM access bit
2492 0, // fast call/return mode select bit
2493 0, // second memory operand
2494 0, // second literal operand
2496 (PCC_REGISTER), // inCond
2497 (PCC_REGISTER), // outCond
2501 pCodeInstruction pic16_pciSWAPFW = {
2502 {PC_OPCODE, NULL, NULL, 0, NULL,
2509 NULL, // from branch
2516 0,0, // dest, bit instruction
2517 0,0, // branch, skip
2518 0, // literal operand
2519 1, // RAM access bit
2520 0, // fast call/return mode select bit
2521 0, // second memory operand
2522 0, // second literal operand
2524 (PCC_REGISTER), // inCond
2529 pCodeInstruction pic16_pciTBLRD = { // patch 15
2530 {PC_OPCODE, NULL, NULL, 0, NULL,
2536 NULL, // from branch
2543 0,0, // dest, bit instruction
2544 0,0, // branch, skip
2545 0, // literal operand
2546 0, // RAM access bit
2547 0, // fast call/return mode select bit
2548 0, // second memory operand
2549 0, // second literal operand
2552 PCC_NONE , // outCond
2556 pCodeInstruction pic16_pciTBLRD_POSTINC = { // patch 15
2557 {PC_OPCODE, NULL, NULL, 0, NULL,
2563 NULL, // from branch
2570 0,0, // dest, bit instruction
2571 0,0, // branch, skip
2572 0, // literal operand
2573 0, // RAM access bit
2574 0, // fast call/return mode select bit
2575 0, // second memory operand
2576 0, // second literal operand
2579 PCC_NONE , // outCond
2583 pCodeInstruction pic16_pciTBLRD_POSTDEC = { // patch 15
2584 {PC_OPCODE, NULL, NULL, 0, NULL,
2590 NULL, // from branch
2597 0,0, // dest, bit instruction
2598 0,0, // branch, skip
2599 0, // literal operand
2600 0, // RAM access bit
2601 0, // fast call/return mode select bit
2602 0, // second memory operand
2603 0, // second literal operand
2606 PCC_NONE , // outCond
2610 pCodeInstruction pic16_pciTBLRD_PREINC = { // patch 15
2611 {PC_OPCODE, NULL, NULL, 0, NULL,
2617 NULL, // from branch
2624 0,0, // dest, bit instruction
2625 0,0, // branch, skip
2626 0, // literal operand
2627 0, // RAM access bit
2628 0, // fast call/return mode select bit
2629 0, // second memory operand
2630 0, // second literal operand
2633 PCC_NONE , // outCond
2637 pCodeInstruction pic16_pciTBLWT = { // patch 15
2638 {PC_OPCODE, NULL, NULL, 0, NULL,
2644 NULL, // from branch
2651 0,0, // dest, bit instruction
2652 0,0, // branch, skip
2653 0, // literal operand
2654 0, // RAM access bit
2655 0, // fast call/return mode select bit
2656 0, // second memory operand
2657 0, // second literal operand
2660 PCC_NONE , // outCond
2664 pCodeInstruction pic16_pciTBLWT_POSTINC = { // patch 15
2665 {PC_OPCODE, NULL, NULL, 0, NULL,
2671 NULL, // from branch
2678 0,0, // dest, bit instruction
2679 0,0, // branch, skip
2680 0, // literal operand
2681 0, // RAM access bit
2682 0, // fast call/return mode select bit
2683 0, // second memory operand
2684 0, // second literal operand
2687 PCC_NONE , // outCond
2691 pCodeInstruction pic16_pciTBLWT_POSTDEC = { // patch 15
2692 {PC_OPCODE, NULL, NULL, 0, NULL,
2698 NULL, // from branch
2705 0,0, // dest, bit instruction
2706 0,0, // branch, skip
2707 0, // literal operand
2708 0, // RAM access bit
2709 0, // fast call/return mode select bit
2710 0, // second memory operand
2711 0, // second literal operand
2714 PCC_NONE , // outCond
2718 pCodeInstruction pic16_pciTBLWT_PREINC = { // patch 15
2719 {PC_OPCODE, NULL, NULL, 0, NULL,
2725 NULL, // from branch
2732 0,0, // dest, bit instruction
2733 0,0, // branch, skip
2734 0, // literal operand
2735 0, // RAM access bit
2736 0, // fast call/return mode select bit
2737 0, // second memory operand
2738 0, // second literal operand
2741 PCC_NONE , // outCond
2745 pCodeInstruction pic16_pciTSTFSZ = { // mdubuc - New
2746 {PC_OPCODE, NULL, NULL, 0, NULL,
2753 NULL, // from branch
2760 0,0, // dest, bit instruction
2761 1,1, // branch, skip
2762 0, // literal operand
2763 1, // RAM access bit
2764 0, // fast call/return mode select bit
2765 0, // second memory operand
2766 0, // second literal operand
2768 PCC_REGISTER, // inCond
2769 PCC_NONE, // outCond
2773 pCodeInstruction pic16_pciXORWF = {
2774 {PC_OPCODE, NULL, NULL, 0, NULL,
2781 NULL, // from branch
2788 1,0, // dest, bit instruction
2789 0,0, // branch, skip
2790 0, // literal operand
2791 1, // RAM access bit
2792 0, // fast call/return mode select bit
2793 0, // second memory operand
2794 0, // second literal operand
2796 (PCC_W | PCC_REGISTER), // inCond
2797 (PCC_REGISTER | PCC_Z | PCC_N), // outCond
2801 pCodeInstruction pic16_pciXORFW = {
2802 {PC_OPCODE, NULL, NULL, 0, NULL,
2809 NULL, // from branch
2816 0,0, // dest, bit instruction
2817 0,0, // branch, skip
2818 0, // literal operand
2819 1, // RAM access bit
2820 0, // fast call/return mode select bit
2821 0, // second memory operand
2822 0, // second literal operand
2824 (PCC_W | PCC_REGISTER), // inCond
2825 (PCC_W | PCC_Z | PCC_N), // outCond
2829 pCodeInstruction pic16_pciXORLW = {
2830 {PC_OPCODE, NULL, NULL, 0, NULL,
2837 NULL, // from branch
2844 0,0, // dest, bit instruction
2845 0,0, // branch, skip
2846 1, // literal operand
2847 1, // RAM access bit
2848 0, // fast call/return mode select bit
2849 0, // second memory operand
2850 0, // second literal operand
2852 (PCC_W | PCC_LITERAL), // inCond
2853 (PCC_W | PCC_Z | PCC_N), // outCond
2858 pCodeInstruction pic16_pciBANKSEL = {
2859 {PC_OPCODE, NULL, NULL, 0, NULL,
2865 NULL, // from branch
2872 0,0, // dest, bit instruction
2873 0,0, // branch, skip
2874 0, // literal operand
2875 0, // RAM access bit
2876 0, // fast call/return mode select bit
2877 0, // second memory operand
2878 0, // second literal operand
2881 PCC_NONE, // outCond
2886 #define MAX_PIC16MNEMONICS 100
2887 pCodeInstruction *pic16Mnemonics[MAX_PIC16MNEMONICS];
2889 //#define USE_VSNPRINTF
2892 #ifdef USE_VSNPRINTF
2893 // Alas, vsnprintf is not ANSI standard, and does not exist
2894 // on Solaris (and probably other non-Gnu flavored Unixes).
2896 /*-----------------------------------------------------------------*/
2897 /* SAFE_snprintf - like snprintf except the string pointer is */
2898 /* after the string has been printed to. This is */
2899 /* useful for printing to string as though if it */
2900 /* were a stream. */
2901 /*-----------------------------------------------------------------*/
2902 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2910 va_start(val, format);
2912 vsnprintf(*str, *size, format, val);
2918 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2919 fprintf(stderr,"len = %d is > str size %d\n",len,*size);
2928 // This version is *not* safe, despite the name.
2930 void SAFE_snprintf(char **str, size_t *size, const char *format, ...)
2934 static char buffer[1024]; /* grossly conservative, but still not inherently safe */
2939 va_start(val, format);
2941 vsprintf(buffer, format, val);
2944 len = strlen(buffer);
2946 fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
2947 fprintf(stderr,"len = %d is > str size %d\n",len, (int) *size);
2950 strcpy(*str, buffer);
2956 #endif // USE_VSNPRINTF
2959 extern set *externs;
2960 extern void pic16_initStack(int base_address, int size);
2961 extern regs *pic16_allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
2962 extern regs *pic16_allocInternalRegister(int rIdx, char * name, short po_type, int alias);
2963 extern void pic16_init_pic(char *);
2965 void pic16_pCodeInitRegisters(void)
2967 static int initialized=0;
2974 // pic16_initStack(0xfff, 8);
2975 pic16_init_pic(port->processor);
2977 pic16_pc_status.r = pic16_allocProcessorRegister(IDX_STATUS,"STATUS", PO_STATUS, 0x80);
2978 pic16_pc_pcl.r = pic16_allocProcessorRegister(IDX_PCL,"PCL", PO_PCL, 0x80);
2979 pic16_pc_pclath.r = pic16_allocProcessorRegister(IDX_PCLATH,"PCLATH", PO_PCLATH, 0x80);
2980 pic16_pc_pclatu.r = pic16_allocProcessorRegister(IDX_PCLATU,"PCLATU", PO_PCLATU, 0x80);
2981 pic16_pc_intcon.r = pic16_allocProcessorRegister(IDX_INTCON,"INTCON", PO_INTCON, 0x80);
2982 pic16_pc_wreg.r = pic16_allocProcessorRegister(IDX_WREG,"WREG", PO_WREG, 0x80);
2983 pic16_pc_bsr.r = pic16_allocProcessorRegister(IDX_BSR,"BSR", PO_BSR, 0x80);
2985 pic16_pc_tosl.r = pic16_allocProcessorRegister(IDX_TOSL,"TOSL", PO_SFR_REGISTER, 0x80);
2986 pic16_pc_tosh.r = pic16_allocProcessorRegister(IDX_TOSH,"TOSH", PO_SFR_REGISTER, 0x80);
2987 pic16_pc_tosu.r = pic16_allocProcessorRegister(IDX_TOSU,"TOSU", PO_SFR_REGISTER, 0x80);
2989 pic16_pc_tblptrl.r = pic16_allocProcessorRegister(IDX_TBLPTRL,"TBLPTRL", PO_SFR_REGISTER, 0x80);
2990 pic16_pc_tblptrh.r = pic16_allocProcessorRegister(IDX_TBLPTRH,"TBLPTRH", PO_SFR_REGISTER, 0x80);
2991 pic16_pc_tblptru.r = pic16_allocProcessorRegister(IDX_TBLPTRU,"TBLPTRU", PO_SFR_REGISTER, 0x80);
2992 pic16_pc_tablat.r = pic16_allocProcessorRegister(IDX_TABLAT,"TABLAT", PO_SFR_REGISTER, 0x80);
2994 pic16_pc_fsr0l.r = pic16_allocProcessorRegister(IDX_FSR0L, "FSR0L", PO_FSR0, 0x80);
2995 pic16_pc_fsr0h.r = pic16_allocProcessorRegister(IDX_FSR0H, "FSR0H", PO_FSR0, 0x80);
2996 pic16_pc_fsr1l.r = pic16_allocProcessorRegister(IDX_FSR1L, "FSR1L", PO_FSR0, 0x80);
2997 pic16_pc_fsr1h.r = pic16_allocProcessorRegister(IDX_FSR1H, "FSR1H", PO_FSR0, 0x80);
2998 pic16_pc_fsr2l.r = pic16_allocProcessorRegister(IDX_FSR2L, "FSR2L", PO_FSR0, 0x80);
2999 pic16_pc_fsr2h.r = pic16_allocProcessorRegister(IDX_FSR2H, "FSR2H", PO_FSR0, 0x80);
3001 pic16_stackpnt_lo = &pic16_pc_fsr1l;
3002 pic16_stackpnt_hi = &pic16_pc_fsr1h;
3003 pic16_stack_postdec = &pic16_pc_postdec1;
3004 pic16_stack_postinc = &pic16_pc_postinc1;
3005 pic16_stack_preinc = &pic16_pc_preinc1;
3006 pic16_stack_plusw = &pic16_pc_plusw1;
3008 pic16_framepnt_lo = &pic16_pc_fsr2l;
3009 pic16_framepnt_hi = &pic16_pc_fsr2h;
3010 pic16_frame_postdec = &pic16_pc_postdec2;
3011 pic16_frame_postinc = &pic16_pc_postinc2;
3012 pic16_frame_preinc = &pic16_pc_preinc2;
3013 pic16_frame_plusw = &pic16_pc_plusw2;
3015 pic16_pc_indf0.r = pic16_allocProcessorRegister(IDX_INDF0,"INDF0", PO_INDF0, 0x80);
3016 pic16_pc_postinc0.r = pic16_allocProcessorRegister(IDX_POSTINC0, "POSTINC0", PO_INDF0, 0x80);
3017 pic16_pc_postdec0.r = pic16_allocProcessorRegister(IDX_POSTDEC0, "POSTDEC0", PO_INDF0, 0x80);
3018 pic16_pc_preinc0.r = pic16_allocProcessorRegister(IDX_PREINC0, "PREINC0", PO_INDF0, 0x80);
3019 pic16_pc_plusw0.r = pic16_allocProcessorRegister(IDX_PLUSW0, "PLUSW0", PO_INDF0, 0x80);
3021 pic16_pc_indf1.r = pic16_allocProcessorRegister(IDX_INDF1,"INDF1", PO_INDF0, 0x80);
3022 pic16_pc_postinc1.r = pic16_allocProcessorRegister(IDX_POSTINC1, "POSTINC1", PO_INDF0, 0x80);
3023 pic16_pc_postdec1.r = pic16_allocProcessorRegister(IDX_POSTDEC1, "POSTDEC1", PO_INDF0, 0x80);
3024 pic16_pc_preinc1.r = pic16_allocProcessorRegister(IDX_PREINC1, "PREINC1", PO_INDF0, 0x80);
3025 pic16_pc_plusw1.r = pic16_allocProcessorRegister(IDX_PLUSW1, "PLUSW1", PO_INDF0, 0x80);
3027 pic16_pc_indf2.r = pic16_allocProcessorRegister(IDX_INDF2,"INDF2", PO_INDF0, 0x80);
3028 pic16_pc_postinc2.r = pic16_allocProcessorRegister(IDX_POSTINC2, "POSTINC2", PO_INDF0, 0x80);
3029 pic16_pc_postdec2.r = pic16_allocProcessorRegister(IDX_POSTDEC2, "POSTDEC2", PO_INDF0, 0x80);
3030 pic16_pc_preinc2.r = pic16_allocProcessorRegister(IDX_PREINC2, "PREINC2", PO_INDF0, 0x80);
3031 pic16_pc_plusw2.r = pic16_allocProcessorRegister(IDX_PLUSW2, "PLUSW2", PO_INDF0, 0x80);
3033 pic16_pc_prodl.r = pic16_allocProcessorRegister(IDX_PRODL, "PRODL", PO_PRODL, 0x80);
3034 pic16_pc_prodh.r = pic16_allocProcessorRegister(IDX_PRODH, "PRODH", PO_PRODH, 0x80);
3037 pic16_pc_eecon1.r = pic16_allocProcessorRegister(IDX_EECON1, "EECON1", PO_SFR_REGISTER, 0x80);
3038 pic16_pc_eecon2.r = pic16_allocProcessorRegister(IDX_EECON2, "EECON2", PO_SFR_REGISTER, 0x80);
3039 pic16_pc_eedata.r = pic16_allocProcessorRegister(IDX_EEDATA, "EEDATA", PO_SFR_REGISTER, 0x80);
3040 pic16_pc_eeadr.r = pic16_allocProcessorRegister(IDX_EEADR, "EEADR", PO_SFR_REGISTER, 0x80);
3043 pic16_pc_status.rIdx = IDX_STATUS;
3044 pic16_pc_intcon.rIdx = IDX_INTCON;
3045 pic16_pc_pcl.rIdx = IDX_PCL;
3046 pic16_pc_pclath.rIdx = IDX_PCLATH;
3047 pic16_pc_pclatu.rIdx = IDX_PCLATU;
3048 pic16_pc_wreg.rIdx = IDX_WREG;
3049 pic16_pc_bsr.rIdx = IDX_BSR;
3051 pic16_pc_tosl.rIdx = IDX_TOSL;
3052 pic16_pc_tosh.rIdx = IDX_TOSH;
3053 pic16_pc_tosu.rIdx = IDX_TOSU;
3055 pic16_pc_tblptrl.rIdx = IDX_TBLPTRL;
3056 pic16_pc_tblptrh.rIdx = IDX_TBLPTRH;
3057 pic16_pc_tblptru.rIdx = IDX_TBLPTRU;
3058 pic16_pc_tablat.rIdx = IDX_TABLAT;
3060 pic16_pc_fsr0l.rIdx = IDX_FSR0L;
3061 pic16_pc_fsr0h.rIdx = IDX_FSR0H;
3062 pic16_pc_fsr1l.rIdx = IDX_FSR1L;
3063 pic16_pc_fsr1h.rIdx = IDX_FSR1H;
3064 pic16_pc_fsr2l.rIdx = IDX_FSR2L;
3065 pic16_pc_fsr2h.rIdx = IDX_FSR2H;
3066 pic16_pc_indf0.rIdx = IDX_INDF0;
3067 pic16_pc_postinc0.rIdx = IDX_POSTINC0;
3068 pic16_pc_postdec0.rIdx = IDX_POSTDEC0;
3069 pic16_pc_preinc0.rIdx = IDX_PREINC0;
3070 pic16_pc_plusw0.rIdx = IDX_PLUSW0;
3071 pic16_pc_indf1.rIdx = IDX_INDF1;
3072 pic16_pc_postinc1.rIdx = IDX_POSTINC1;
3073 pic16_pc_postdec1.rIdx = IDX_POSTDEC1;
3074 pic16_pc_preinc1.rIdx = IDX_PREINC1;
3075 pic16_pc_plusw1.rIdx = IDX_PLUSW1;
3076 pic16_pc_indf2.rIdx = IDX_INDF2;
3077 pic16_pc_postinc2.rIdx = IDX_POSTINC2;
3078 pic16_pc_postdec2.rIdx = IDX_POSTDEC2;
3079 pic16_pc_preinc2.rIdx = IDX_PREINC2;
3080 pic16_pc_plusw2.rIdx = IDX_PLUSW2;
3081 pic16_pc_prodl.rIdx = IDX_PRODL;
3082 pic16_pc_prodh.rIdx = IDX_PRODH;
3084 pic16_pc_kzero.r = pic16_allocInternalRegister(IDX_KZ,"KZ",PO_GPR_REGISTER,0);
3085 pic16_pc_ssave.r = pic16_allocInternalRegister(IDX_SSAVE,"SSAVE", PO_GPR_REGISTER, 0);
3086 pic16_pc_wsave.r = pic16_allocInternalRegister(IDX_WSAVE,"WSAVE", PO_GPR_REGISTER, 0);
3088 pic16_pc_kzero.rIdx = IDX_KZ;
3089 pic16_pc_wsave.rIdx = IDX_WSAVE;
3090 pic16_pc_ssave.rIdx = IDX_SSAVE;
3092 pic16_pc_eecon1.rIdx = IDX_EECON1;
3093 pic16_pc_eecon2.rIdx = IDX_EECON2;
3094 pic16_pc_eedata.rIdx = IDX_EEDATA;
3095 pic16_pc_eeadr.rIdx = IDX_EEADR;
3098 pic16_pc_gpsimio.r = pic16_allocProcessorRegister(IDX_GPSIMIO, "GPSIMIO", PO_GPR_REGISTER, 0x80);
3099 pic16_pc_gpsimio2.r = pic16_allocProcessorRegister(IDX_GPSIMIO2, "GPSIMIO2", PO_GPR_REGISTER, 0x80);
3101 pic16_pc_gpsimio.rIdx = IDX_GPSIMIO;
3102 pic16_pc_gpsimio2.rIdx = IDX_GPSIMIO2;
3104 /* probably should put this in a separate initialization routine */
3105 pb_dead_pcodes = newpBlock();
3110 /*-----------------------------------------------------------------*/
3111 /* mnem2key - convert a pic mnemonic into a hash key */
3112 /* (BTW - this spreads the mnemonics quite well) */
3114 /*-----------------------------------------------------------------*/
3116 int mnem2key(char const *mnem)
3125 key += toupper(*mnem++) +1;
3129 return (key & 0x1f);
3134 void pic16initMnemonics(void)
3139 pCodeInstruction *pci;
3141 if(mnemonics_initialized)
3144 // NULL out the array before making the assignments
3145 // since we check the array contents below this initialization.
3147 for (i = 0; i < MAX_PIC16MNEMONICS; i++) {
3148 pic16Mnemonics[i] = NULL;
3151 pic16Mnemonics[POC_ADDLW] = &pic16_pciADDLW;
3152 pic16Mnemonics[POC_ADDWF] = &pic16_pciADDWF;
3153 pic16Mnemonics[POC_ADDFW] = &pic16_pciADDFW;
3154 pic16Mnemonics[POC_ADDWFC] = &pic16_pciADDWFC;
3155 pic16Mnemonics[POC_ADDFWC] = &pic16_pciADDFWC;
3156 pic16Mnemonics[POC_ANDLW] = &pic16_pciANDLW;
3157 pic16Mnemonics[POC_ANDWF] = &pic16_pciANDWF;
3158 pic16Mnemonics[POC_ANDFW] = &pic16_pciANDFW;
3159 pic16Mnemonics[POC_BC] = &pic16_pciBC;
3160 pic16Mnemonics[POC_BCF] = &pic16_pciBCF;
3161 pic16Mnemonics[POC_BN] = &pic16_pciBN;
3162 pic16Mnemonics[POC_BNC] = &pic16_pciBNC;
3163 pic16Mnemonics[POC_BNN] = &pic16_pciBNN;
3164 pic16Mnemonics[POC_BNOV] = &pic16_pciBNOV;
3165 pic16Mnemonics[POC_BNZ] = &pic16_pciBNZ;
3166 pic16Mnemonics[POC_BOV] = &pic16_pciBOV;
3167 pic16Mnemonics[POC_BRA] = &pic16_pciBRA;
3168 pic16Mnemonics[POC_BSF] = &pic16_pciBSF;
3169 pic16Mnemonics[POC_BTFSC] = &pic16_pciBTFSC;
3170 pic16Mnemonics[POC_BTFSS] = &pic16_pciBTFSS;
3171 pic16Mnemonics[POC_BTG] = &pic16_pciBTG;
3172 pic16Mnemonics[POC_BZ] = &pic16_pciBZ;
3173 pic16Mnemonics[POC_CALL] = &pic16_pciCALL;
3174 pic16Mnemonics[POC_CLRF] = &pic16_pciCLRF;
3175 pic16Mnemonics[POC_CLRWDT] = &pic16_pciCLRWDT;
3176 pic16Mnemonics[POC_COMF] = &pic16_pciCOMF;
3177 pic16Mnemonics[POC_COMFW] = &pic16_pciCOMFW;
3178 pic16Mnemonics[POC_CPFSEQ] = &pic16_pciCPFSEQ;
3179 pic16Mnemonics[POC_CPFSGT] = &pic16_pciCPFSGT;
3180 pic16Mnemonics[POC_CPFSLT] = &pic16_pciCPFSLT;
3181 pic16Mnemonics[POC_DAW] = &pic16_pciDAW;
3182 pic16Mnemonics[POC_DCFSNZ] = &pic16_pciDCFSNZ;
3183 pic16Mnemonics[POC_DECF] = &pic16_pciDECF;
3184 pic16Mnemonics[POC_DECFW] = &pic16_pciDECFW;
3185 pic16Mnemonics[POC_DECFSZ] = &pic16_pciDECFSZ;
3186 pic16Mnemonics[POC_DECFSZW] = &pic16_pciDECFSZW;
3187 pic16Mnemonics[POC_GOTO] = &pic16_pciGOTO;
3188 pic16Mnemonics[POC_INCF] = &pic16_pciINCF;
3189 pic16Mnemonics[POC_INCFW] = &pic16_pciINCFW;
3190 pic16Mnemonics[POC_INCFSZ] = &pic16_pciINCFSZ;
3191 pic16Mnemonics[POC_INCFSZW] = &pic16_pciINCFSZW;
3192 pic16Mnemonics[POC_INFSNZ] = &pic16_pciINFSNZ;
3193 pic16Mnemonics[POC_INFSNZW] = &pic16_pciINFSNZW;
3194 pic16Mnemonics[POC_IORWF] = &pic16_pciIORWF;
3195 pic16Mnemonics[POC_IORFW] = &pic16_pciIORFW;
3196 pic16Mnemonics[POC_IORLW] = &pic16_pciIORLW;
3197 pic16Mnemonics[POC_LFSR] = &pic16_pciLFSR;
3198 pic16Mnemonics[POC_MOVF] = &pic16_pciMOVF;
3199 pic16Mnemonics[POC_MOVFW] = &pic16_pciMOVFW;
3200 pic16Mnemonics[POC_MOVFF] = &pic16_pciMOVFF;
3201 pic16Mnemonics[POC_MOVLB] = &pic16_pciMOVLB;
3202 pic16Mnemonics[POC_MOVLW] = &pic16_pciMOVLW;
3203 pic16Mnemonics[POC_MOVWF] = &pic16_pciMOVWF;
3204 pic16Mnemonics[POC_MULLW] = &pic16_pciMULLW;
3205 pic16Mnemonics[POC_MULWF] = &pic16_pciMULWF;
3206 pic16Mnemonics[POC_NEGF] = &pic16_pciNEGF;
3207 pic16Mnemonics[POC_NOP] = &pic16_pciNOP;
3208 pic16Mnemonics[POC_POP] = &pic16_pciPOP;
3209 pic16Mnemonics[POC_PUSH] = &pic16_pciPUSH;
3210 pic16Mnemonics[POC_RCALL] = &pic16_pciRCALL;
3211 pic16Mnemonics[POC_RETFIE] = &pic16_pciRETFIE;
3212 pic16Mnemonics[POC_RETLW] = &pic16_pciRETLW;
3213 pic16Mnemonics[POC_RETURN] = &pic16_pciRETURN;
3214 pic16Mnemonics[POC_RLCF] = &pic16_pciRLCF;
3215 pic16Mnemonics[POC_RLCFW] = &pic16_pciRLCFW;
3216 pic16Mnemonics[POC_RLNCF] = &pic16_pciRLNCF;
3217 pic16Mnemonics[POC_RLNCFW] = &pic16_pciRLNCFW;
3218 pic16Mnemonics[POC_RRCF] = &pic16_pciRRCF;
3219 pic16Mnemonics[POC_RRCFW] = &pic16_pciRRCFW;
3220 pic16Mnemonics[POC_RRNCF] = &pic16_pciRRNCF;
3221 pic16Mnemonics[POC_RRNCFW] = &pic16_pciRRNCFW;
3222 pic16Mnemonics[POC_SETF] = &pic16_pciSETF;
3223 pic16Mnemonics[POC_SUBLW] = &pic16_pciSUBLW;
3224 pic16Mnemonics[POC_SUBWF] = &pic16_pciSUBWF;
3225 pic16Mnemonics[POC_SUBFW] = &pic16_pciSUBFW;
3226 pic16Mnemonics[POC_SUBWFB_D0] = &pic16_pciSUBWFB_D0;
3227 pic16Mnemonics[POC_SUBWFB_D1] = &pic16_pciSUBWFB_D1;
3228 pic16Mnemonics[POC_SUBFWB_D0] = &pic16_pciSUBFWB_D0;
3229 pic16Mnemonics[POC_SUBFWB_D1] = &pic16_pciSUBFWB_D1;
3230 pic16Mnemonics[POC_SWAPF] = &pic16_pciSWAPF;
3231 pic16Mnemonics[POC_SWAPFW] = &pic16_pciSWAPFW;
3232 pic16Mnemonics[POC_TBLRD] = &pic16_pciTBLRD;
3233 pic16Mnemonics[POC_TBLRD_POSTINC] = &pic16_pciTBLRD_POSTINC;
3234 pic16Mnemonics[POC_TBLRD_POSTDEC] = &pic16_pciTBLRD_POSTDEC;
3235 pic16Mnemonics[POC_TBLRD_PREINC] = &pic16_pciTBLRD_PREINC;
3236 pic16Mnemonics[POC_TBLWT] = &pic16_pciTBLWT;
3237 pic16Mnemonics[POC_TBLWT_POSTINC] = &pic16_pciTBLWT_POSTINC;
3238 pic16Mnemonics[POC_TBLWT_POSTDEC] = &pic16_pciTBLWT_POSTDEC;
3239 pic16Mnemonics[POC_TBLWT_PREINC] = &pic16_pciTBLWT_PREINC;
3240 pic16Mnemonics[POC_TSTFSZ] = &pic16_pciTSTFSZ;
3241 pic16Mnemonics[POC_XORLW] = &pic16_pciXORLW;
3242 pic16Mnemonics[POC_XORWF] = &pic16_pciXORWF;
3243 pic16Mnemonics[POC_XORFW] = &pic16_pciXORFW;
3244 pic16Mnemonics[POC_BANKSEL] = &pic16_pciBANKSEL;
3246 for(i=0; i<MAX_PIC16MNEMONICS; i++)
3247 if(pic16Mnemonics[i])
3248 hTabAddItem(&pic16MnemonicsHash, mnem2key(pic16Mnemonics[i]->mnemonic), pic16Mnemonics[i]);
3249 pci = hTabFirstItem(pic16MnemonicsHash, &key);
3252 DFPRINTF((stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic));
3253 pci = hTabNextItem(pic16MnemonicsHash, &key);
3256 mnemonics_initialized = 1;
3259 int pic16_getpCodePeepCommand(char *cmd);
3261 int pic16_getpCode(char *mnem,unsigned dest)
3264 pCodeInstruction *pci;
3265 int key = mnem2key(mnem);
3267 if(!mnemonics_initialized)
3268 pic16initMnemonics();
3270 pci = hTabFirstItemWK(pic16MnemonicsHash, key);
3274 if(STRCASECMP(pci->mnemonic, mnem) == 0) {
3275 if((pci->num_ops <= 1)
3276 || (pci->isModReg == dest)
3278 || (pci->num_ops <= 2 && pci->isAccess)
3279 || (pci->num_ops <= 2 && pci->isFastCall)
3280 || (pci->num_ops <= 2 && pci->is2MemOp)
3281 || (pci->num_ops <= 2 && pci->is2LitOp) )
3285 pci = hTabNextItemWK (pic16MnemonicsHash);
3292 /*-----------------------------------------------------------------*
3293 * pic16initpCodePeepCommands
3295 *-----------------------------------------------------------------*/
3296 void pic16initpCodePeepCommands(void)
3304 hTabAddItem(&pic16pCodePeepCommandsHash,
3305 mnem2key(peepCommands[i].cmd), &peepCommands[i]);
3307 } while (peepCommands[i].cmd);
3309 pcmd = hTabFirstItem(pic16pCodePeepCommandsHash, &key);
3312 //fprintf(stderr, "peep command %s key %d\n",pcmd->cmd,pcmd->id);
3313 pcmd = hTabNextItem(pic16pCodePeepCommandsHash, &key);
3318 /*-----------------------------------------------------------------
3321 *-----------------------------------------------------------------*/
3323 int pic16_getpCodePeepCommand(char *cmd)
3327 int key = mnem2key(cmd);
3330 pcmd = hTabFirstItemWK(pic16pCodePeepCommandsHash, key);
3333 // fprintf(stderr," comparing %s to %s\n",pcmd->cmd,cmd);
3334 if(STRCASECMP(pcmd->cmd, cmd) == 0) {
3338 pcmd = hTabNextItemWK (pic16pCodePeepCommandsHash);
3345 static char getpBlock_dbName(pBlock *pb)
3351 return pb->cmemmap->dbName;
3355 void pic16_pBlockConvert2ISR(pBlock *pb)
3359 if(pb->cmemmap)pb->cmemmap = NULL;
3363 if(pic16_pcode_verbose)
3364 fprintf(stderr, "%s:%d converting to 'I'interrupt pBlock\n", __FILE__, __LINE__);
3367 void pic16_pBlockConvert2Absolute(pBlock *pb)
3370 if(pb->cmemmap)pb->cmemmap = NULL;
3374 if(pic16_pcode_verbose)
3375 fprintf(stderr, "%s:%d converting to 'A'bsolute pBlock\n", __FILE__, __LINE__);
3378 /*-----------------------------------------------------------------*/
3379 /* pic16_movepBlock2Head - given the dbname of a pBlock, move all */
3380 /* instances to the front of the doubly linked */
3381 /* list of pBlocks */
3382 /*-----------------------------------------------------------------*/
3384 void pic16_movepBlock2Head(char dbName)
3389 /* this can happen in sources without code,
3390 * only variable definitions */
3391 if(!the_pFile)return;
3393 pb = the_pFile->pbHead;
3397 if(getpBlock_dbName(pb) == dbName) {
3398 pBlock *pbn = pb->next;
3399 pb->next = the_pFile->pbHead;
3400 the_pFile->pbHead->prev = pb;
3401 the_pFile->pbHead = pb;
3404 pb->prev->next = pbn;
3406 // If the pBlock that we just moved was the last
3407 // one in the link of all of the pBlocks, then we
3408 // need to point the tail to the block just before
3409 // the one we moved.
3410 // Note: if pb->next is NULL, then pb must have
3411 // been the last pBlock in the chain.
3414 pbn->prev = pb->prev;
3416 the_pFile->pbTail = pb->prev;
3427 void pic16_copypCode(FILE *of, char dbName)
3431 if(!of || !the_pFile)
3434 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3435 if(getpBlock_dbName(pb) == dbName) {
3436 // fprintf(stderr, "%s:%d: output of pb= 0x%p\n", __FILE__, __LINE__, pb);
3438 pic16_printpBlock(of,pb);
3443 void pic16_pcode_test(void)
3446 DFPRINTF((stderr,"pcode is alive!\n"));
3456 /* create the file name */
3457 strcpy(buffer,dstFileName);
3458 strcat(buffer,".p");
3460 if( !(pFile = fopen(buffer, "w" ))) {
3461 werror(E_FILE_OPEN_ERR,buffer);
3465 fprintf(pFile,"pcode dump\n\n");
3467 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3468 fprintf(pFile,"\n\tNew pBlock\n\n");
3470 fprintf(pFile,"%s",pb->cmemmap->sname);
3472 fprintf(pFile,"internal pblock");
3474 fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
3475 pic16_printpBlock(pFile,pb);
3481 unsigned long pic16_countInstructions(void)
3485 unsigned long isize=0;
3487 if(!the_pFile)return -1;
3489 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
3490 for(pc = pb->pcHead; pc; pc = pc->next) {
3491 if(isPCI(pc) || isPCAD(pc))isize += PCI(pc)->isize;
3498 /*-----------------------------------------------------------------*/
3499 /* int RegCond(pCodeOp *pcop) - if pcop points to the STATUS reg- */
3500 /* ister, RegCond will return the bit being referenced. */
3502 /* fixme - why not just OR in the pcop bit field */
3503 /*-----------------------------------------------------------------*/
3505 static int RegCond(pCodeOp *pcop)
3511 if(!pcop->name)return 0;
3513 if(pcop->type == PO_GPR_BIT && !strcmp(pcop->name, pic16_pc_status.pcop.name)) {
3514 switch(PCORB(pcop)->bit) {
3528 /*-----------------------------------------------------------------*/
3529 /* pic16_newpCode - create and return a newly initialized pCode */
3531 /* fixme - rename this */
3533 /* The purpose of this routine is to create a new Instruction */
3534 /* pCode. This is called by gen.c while the assembly code is being */
3538 /* PIC_OPCODE op - the assembly instruction we wish to create. */
3539 /* (note that the op is analogous to but not the */
3540 /* same thing as the opcode of the instruction.) */
3541 /* pCdoeOp *pcop - pointer to the operand of the instruction. */
3544 /* a pointer to the new malloc'd pCode is returned. */
3548 /*-----------------------------------------------------------------*/
3549 pCode *pic16_newpCode (PIC_OPCODE op, pCodeOp *pcop)
3551 pCodeInstruction *pci ;
3553 if(!mnemonics_initialized)
3554 pic16initMnemonics();
3556 pci = Safe_calloc(1, sizeof(pCodeInstruction));
3558 if((op>=0) && (op < MAX_PIC16MNEMONICS) && pic16Mnemonics[op]) {
3559 memcpy(pci, pic16Mnemonics[op], sizeof(pCodeInstruction));
3562 if(pci->inCond & PCC_EXAMINE_PCOP)
3563 pci->inCond |= RegCond(pcop);
3565 if(pci->outCond & PCC_EXAMINE_PCOP)
3566 pci->outCond |= RegCond(pcop);
3568 pci->pc.prev = pci->pc.next = NULL;
3569 return (pCode *)pci;
3572 fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
3578 /*-----------------------------------------------------------------*/
3579 /* pic16_newpCodeWild - create a "wild" as in wild card pCode */
3581 /* Wild pcodes are used during the peep hole optimizer to serve */
3582 /* as place holders for any instruction. When a snippet of code is */
3583 /* compared to a peep hole rule, the wild card opcode will match */
3584 /* any instruction. However, the optional operand and label are */
3585 /* additional qualifiers that must also be matched before the */
3586 /* line (of assembly code) is declared matched. Note that the */
3587 /* operand may be wild too. */
3589 /* Note, a wild instruction is specified just like a wild var: */
3590 /* %4 ; A wild instruction, */
3591 /* See the peeph.def file for additional examples */
3593 /*-----------------------------------------------------------------*/
3595 pCode *pic16_newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
3600 pcw = Safe_calloc(1,sizeof(pCodeWild));
3602 pcw->pci.pc.type = PC_WILD;
3603 pcw->pci.pc.prev = pcw->pci.pc.next = NULL;
3604 pcw->pci.from = pcw->pci.to = pcw->pci.label = NULL;
3605 pcw->pci.pc.pb = NULL;
3607 // pcw->pci.pc.analyze = genericAnalyze;
3608 pcw->pci.pc.destruct = genericDestruct;
3609 pcw->pci.pc.print = genericPrint;
3611 pcw->id = pCodeID; // this is the 'n' in %n
3612 pcw->operand = optional_operand;
3613 pcw->label = optional_label;
3615 pcw->mustBeBitSkipInst = 0;
3616 pcw->mustNotBeBitSkipInst = 0;
3617 pcw->invertBitSkipInst = 0;
3619 return ( (pCode *)pcw);
3623 /*-----------------------------------------------------------------*/
3624 /* newPcodeInlineP - create a new pCode from a char string */
3625 /*-----------------------------------------------------------------*/
3628 pCode *pic16_newpCodeInlineP(char *cP)
3633 pcc = Safe_calloc(1,sizeof(pCodeComment));
3635 pcc->pc.type = PC_INLINE;
3636 pcc->pc.prev = pcc->pc.next = NULL;
3637 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3640 // pcc->pc.analyze = genericAnalyze;
3641 pcc->pc.destruct = genericDestruct;
3642 pcc->pc.print = genericPrint;
3645 pcc->comment = Safe_strdup(cP);
3647 pcc->comment = NULL;
3649 return ( (pCode *)pcc);
3653 /*-----------------------------------------------------------------*/
3654 /* newPcodeCharP - create a new pCode from a char string */
3655 /*-----------------------------------------------------------------*/
3657 pCode *pic16_newpCodeCharP(char *cP)
3662 pcc = Safe_calloc(1,sizeof(pCodeComment));
3664 pcc->pc.type = PC_COMMENT;
3665 pcc->pc.prev = pcc->pc.next = NULL;
3666 //pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
3669 // pcc->pc.analyze = genericAnalyze;
3670 pcc->pc.destruct = genericDestruct;
3671 pcc->pc.print = genericPrint;
3674 pcc->comment = Safe_strdup(cP);
3676 pcc->comment = NULL;
3678 return ( (pCode *)pcc);
3682 /*-----------------------------------------------------------------*/
3683 /* pic16_newpCodeFunction - */
3684 /*-----------------------------------------------------------------*/
3687 pCode *pic16_newpCodeFunction(char *mod,char *f)
3691 pcf = Safe_calloc(1,sizeof(pCodeFunction));
3693 pcf->pc.type = PC_FUNCTION;
3694 pcf->pc.prev = pcf->pc.next = NULL;
3695 //pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
3698 // pcf->pc.analyze = genericAnalyze;
3699 pcf->pc.destruct = genericDestruct;
3700 pcf->pc.print = pCodePrintFunction;
3706 pcf->modname = Safe_calloc(1,strlen(mod)+1);
3707 strcpy(pcf->modname,mod);
3709 pcf->modname = NULL;
3712 pcf->fname = Safe_calloc(1,strlen(f)+1);
3713 strcpy(pcf->fname,f);
3717 pcf->stackusage = 0;
3719 return ( (pCode *)pcf);
3722 /*-----------------------------------------------------------------*/
3723 /* pic16_newpCodeFlow */
3724 /*-----------------------------------------------------------------*/
3725 static void destructpCodeFlow(pCode *pc)
3727 if(!pc || !isPCFL(pc))
3734 pic16_unlinkpCode(pc);
3736 deleteSet(&PCFL(pc)->registers);
3737 deleteSet(&PCFL(pc)->from);
3738 deleteSet(&PCFL(pc)->to);
3740 /* Instead of deleting the memory used by this pCode, mark
3741 * the object as bad so that if there's a pointer to this pCode
3742 * dangling around somewhere then (hopefully) when the type is
3743 * checked we'll catch it.
3747 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3753 pCode *pic16_newpCodeFlow(void )
3757 //_ALLOC(pcflow,sizeof(pCodeFlow));
3758 pcflow = Safe_calloc(1,sizeof(pCodeFlow));
3760 pcflow->pc.type = PC_FLOW;
3761 pcflow->pc.prev = pcflow->pc.next = NULL;
3762 pcflow->pc.pb = NULL;
3764 // pcflow->pc.analyze = genericAnalyze;
3765 pcflow->pc.destruct = destructpCodeFlow;
3766 pcflow->pc.print = genericPrint;
3768 pcflow->pc.seq = GpcFlowSeq++;
3770 pcflow->from = pcflow->to = NULL;
3772 pcflow->inCond = PCC_NONE;
3773 pcflow->outCond = PCC_NONE;
3775 pcflow->firstBank = -1;
3776 pcflow->lastBank = -1;
3778 pcflow->FromConflicts = 0;
3779 pcflow->ToConflicts = 0;
3783 pcflow->registers = newSet();
3785 return ( (pCode *)pcflow);
3789 /*-----------------------------------------------------------------*/
3790 /*-----------------------------------------------------------------*/
3791 pCodeFlowLink *pic16_newpCodeFlowLink(pCodeFlow *pcflow)
3793 pCodeFlowLink *pcflowLink;
3795 pcflowLink = Safe_calloc(1,sizeof(pCodeFlowLink));
3797 pcflowLink->pcflow = pcflow;
3798 pcflowLink->bank_conflict = 0;
3803 /*-----------------------------------------------------------------*/
3804 /* pic16_newpCodeCSource - create a new pCode Source Symbol */
3805 /*-----------------------------------------------------------------*/
3807 pCode *pic16_newpCodeCSource(int ln, char *f, char *l)
3812 pccs = Safe_calloc(1,sizeof(pCodeCSource));
3814 pccs->pc.type = PC_CSOURCE;
3815 pccs->pc.prev = pccs->pc.next = NULL;
3818 pccs->pc.destruct = genericDestruct;
3819 pccs->pc.print = genericPrint;
3821 pccs->line_number = ln;
3823 pccs->line = Safe_strdup(l);
3828 pccs->file_name = Safe_strdup(f);
3830 pccs->file_name = NULL;
3832 return ( (pCode *)pccs);
3837 /*******************************************************************/
3838 /* pic16_newpCodeAsmDir - create a new pCode Assembler Directive */
3839 /* added by VR 6-Jun-2003 */
3840 /*******************************************************************/
3842 pCode *pic16_newpCodeAsmDir(char *asdir, char *argfmt, ...)
3849 pcad = Safe_calloc(1, sizeof(pCodeAsmDir));
3850 pcad->pci.pc.type = PC_ASMDIR;
3851 pcad->pci.pc.prev = pcad->pci.pc.next = NULL;
3852 pcad->pci.pc.pb = NULL;
3853 pcad->pci.isize = 2;
3854 pcad->pci.pc.destruct = genericDestruct;
3855 pcad->pci.pc.print = genericPrint;
3857 if(asdir && *asdir) {
3859 while(isspace(*asdir))asdir++; // strip any white space from the beginning
3861 pcad->directive = Safe_strdup( asdir );
3864 va_start(ap, argfmt);
3866 memset(buffer, 0, sizeof(buffer));
3867 if(argfmt && *argfmt)
3868 vsprintf(buffer, argfmt, ap);
3872 while(isspace(*lbp))lbp++;
3875 pcad->arg = Safe_strdup( lbp );
3877 return ((pCode *)pcad);
3880 /*-----------------------------------------------------------------*/
3881 /* pCodeLabelDestruct - free memory used by a label. */
3882 /*-----------------------------------------------------------------*/
3883 static void pCodeLabelDestruct(pCode *pc)
3889 // if((pc->type == PC_LABEL) && PCL(pc)->label)
3890 // Safe_free(PCL(pc)->label);
3892 /* Instead of deleting the memory used by this pCode, mark
3893 * the object as bad so that if there's a pointer to this pCode
3894 * dangling around somewhere then (hopefully) when the type is
3895 * checked we'll catch it.
3899 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
3905 pCode *pic16_newpCodeLabel(char *name, int key)
3911 pcl = Safe_calloc(1,sizeof(pCodeLabel) );
3913 pcl->pc.type = PC_LABEL;
3914 pcl->pc.prev = pcl->pc.next = NULL;
3915 //pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
3918 // pcl->pc.analyze = genericAnalyze;
3919 pcl->pc.destruct = pCodeLabelDestruct;
3920 pcl->pc.print = pCodePrintLabel;
3927 sprintf(s,"_%05d_DS_",key);
3932 pcl->label = Safe_strdup(s);
3934 // if(pic16_pcode_verbose)
3935 // fprintf(stderr, "%s:%d label name: %s\n", __FILE__, __LINE__, pcl->label);
3938 return ( (pCode *)pcl);
3942 pCode *pic16_newpCodeLabelFORCE(char *name, int key)
3944 pCodeLabel *pcl = (pCodeLabel *)pic16_newpCodeLabel(name, key);
3948 return ( (pCode *)pcl );
3951 pCode *pic16_newpCodeInfo(INFO_TYPE type, pCodeOp *pcop)
3955 pci = Safe_calloc(1, sizeof(pCodeInfo));
3956 pci->pci.pc.type = PC_INFO;
3957 pci->pci.pc.prev = pci->pci.pc.next = NULL;
3958 pci->pci.pc.pb = NULL;
3959 pci->pci.label = NULL;
3961 pci->pci.pc.destruct = genericDestruct;
3962 pci->pci.pc.print = genericPrint;
3967 return ((pCode *)pci);
3971 /*-----------------------------------------------------------------*/
3972 /* newpBlock - create and return a pointer to a new pBlock */
3973 /*-----------------------------------------------------------------*/
3974 static pBlock *newpBlock(void)
3979 PpB = Safe_calloc(1,sizeof(pBlock) );
3980 PpB->next = PpB->prev = NULL;
3982 PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
3983 PpB->tregisters = NULL;
3985 PpB->FlowTree = NULL;
3991 /*-----------------------------------------------------------------*/
3992 /* pic16_newpCodeChain - create a new chain of pCodes */
3993 /*-----------------------------------------------------------------*
3995 * This function will create a new pBlock and the pointer to the
3996 * pCode that is passed in will be the first pCode in the block.
3997 *-----------------------------------------------------------------*/
4000 pBlock *pic16_newpCodeChain(memmap *cm,char c, pCode *pc)
4003 pBlock *pB = newpBlock();
4005 pB->pcHead = pB->pcTail = pc;
4014 /*-----------------------------------------------------------------*/
4015 /* pic16_newpCodeOpLabel - Create a new label given the key */
4016 /* Note, a negative key means that the label is part of wild card */
4017 /* (and hence a wild card label) used in the pCodePeep */
4018 /* optimizations). */
4019 /*-----------------------------------------------------------------*/
4021 pCodeOp *pic16_newpCodeOpLabel(char *name, int key)
4024 static int label_key=-1;
4028 pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
4029 pcop->type = PO_LABEL;
4034 sprintf(s=buffer,"_%05d_DS_",key);
4036 s = name, key = label_key--;
4039 pcop->name = Safe_strdup(s);
4041 ((pCodeOpLabel *)pcop)->key = key;
4043 //fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",key,((s)?s:""));
4047 /*-----------------------------------------------------------------*/
4048 /*-----------------------------------------------------------------*/
4049 pCodeOp *pic16_newpCodeOpLit(int lit)
4055 pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
4056 pcop->type = PO_LITERAL;
4060 sprintf(s,"0x%02hhx", (unsigned char)lit);
4062 // sprintf(s, "%i", lit);
4065 pcop->name = Safe_strdup(s);
4067 ((pCodeOpLit *)pcop)->lit = lit;
4072 /*-----------------------------------------------------------------*/
4073 /*-----------------------------------------------------------------*/
4074 pCodeOp *pic16_newpCodeOpLit2(int lit, pCodeOp *arg2)
4076 char *s = buffer, tbuf[256], *tb=tbuf;
4080 tb = pic16_get_op(arg2, NULL, 0);
4081 pcop = Safe_calloc(1,sizeof(pCodeOpLit2) );
4082 pcop->type = PO_LITERAL;
4086 sprintf(s,"0x%02x, %s", (unsigned char)lit, tb);
4088 pcop->name = Safe_strdup(s);
4091 ((pCodeOpLit2 *)pcop)->lit = lit;
4092 ((pCodeOpLit2 *)pcop)->arg2 = arg2;
4097 /*-----------------------------------------------------------------*/
4098 /*-----------------------------------------------------------------*/
4099 pCodeOp *pic16_newpCodeOpImmd(char *name, int offset, int index, int code_space)
4103 pcop = Safe_calloc(1,sizeof(pCodeOpImmd) );
4104 pcop->type = PO_IMMEDIATE;
4106 regs *r = pic16_dirregWithName(name);
4107 pcop->name = Safe_strdup(name);
4111 // fprintf(stderr, "%s:%d %s reg %s exists (r: %p)\n",__FILE__, __LINE__, __FUNCTION__, name, r);
4112 PCOI(pcop)->rIdx = r->rIdx;
4114 // fprintf(stderr, "%s:%d %s reg %s doesn't exist\n", __FILE__, __LINE__, __FUNCTION__, name);
4115 PCOI(pcop)->rIdx = -1;
4117 // fprintf(stderr,"%s %s %d\n",__FUNCTION__,name,offset);
4122 PCOI(pcop)->index = index;
4123 PCOI(pcop)->offset = offset;
4124 PCOI(pcop)->_const = code_space;
4129 /*-----------------------------------------------------------------*/
4130 /*-----------------------------------------------------------------*/
4131 pCodeOp *pic16_newpCodeOpWild(int id, pCodeWildBlock *pcwb, pCodeOp *subtype)
4137 if(!pcwb || !subtype) {
4138 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4142 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4143 pcop->type = PO_WILD;
4144 sprintf(s,"%%%d",id);
4145 pcop->name = Safe_strdup(s);
4147 PCOW(pcop)->id = id;
4148 PCOW(pcop)->pcwb = pcwb;
4149 PCOW(pcop)->subtype = subtype;
4150 PCOW(pcop)->matched = NULL;
4152 PCOW(pcop)->pcop2 = NULL;
4157 /*-----------------------------------------------------------------*/
4158 /*-----------------------------------------------------------------*/
4159 pCodeOp *pic16_newpCodeOpWild2(int id, int id2, pCodeWildBlock *pcwb, pCodeOp *subtype, pCodeOp *subtype2)
4165 if(!pcwb || !subtype || !subtype2) {
4166 fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
4170 pcop = Safe_calloc(1,sizeof(pCodeOpWild));
4171 pcop->type = PO_WILD;
4172 sprintf(s,"%%%d",id);
4173 pcop->name = Safe_strdup(s);
4175 PCOW(pcop)->id = id;
4176 PCOW(pcop)->pcwb = pcwb;
4177 PCOW(pcop)->subtype = subtype;
4178 PCOW(pcop)->matched = NULL;
4180 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4182 if(!subtype2->name) {
4183 PCOW(pcop)->pcop2 = Safe_calloc(1, sizeof(pCodeOpWild));
4184 PCOW2(pcop)->pcop.type = PO_WILD;
4185 sprintf(s, "%%%d", id2);
4186 PCOW2(pcop)->pcop.name = Safe_strdup(s);
4187 PCOW2(pcop)->id = id2;
4188 PCOW2(pcop)->subtype = subtype2;
4190 // fprintf(stderr, "%s:%d %s [wild,wild] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4191 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4193 PCOW2(pcop)->pcop2 = pic16_pCodeOpCopy( subtype2 );
4195 // fprintf(stderr, "%s:%d %s [wild,str] for name: %s (%d)\tname2: %s (%d)\n", __FILE__, __LINE__, __FUNCTION__,
4196 // pcop->name, id, PCOW2(pcop)->pcop.name, id2);
4205 /*-----------------------------------------------------------------*/
4206 /*-----------------------------------------------------------------*/
4207 pCodeOp *pic16_newpCodeOpBit(char *s, int bit, int inBitSpace, PIC_OPTYPE subt)
4211 pcop = Safe_calloc(1,sizeof(pCodeOpRegBit) );
4212 pcop->type = PO_GPR_BIT;
4214 pcop->name = Safe_strdup(s);
4218 PCORB(pcop)->bit = bit;
4219 PCORB(pcop)->inBitSpace = inBitSpace;
4220 PCORB(pcop)->subtype = subt;
4222 /* pCodeOpBit is derived from pCodeOpReg. We need to init this too */
4223 PCOR(pcop)->r = pic16_regWithName(s); //NULL;
4224 // fprintf(stderr, "%s:%d %s for reg: %s\treg= %p\n", __FILE__, __LINE__, __FUNCTION__, s, PCOR(pcop)->r);
4225 // PCOR(pcop)->rIdx = 0;
4229 pCodeOp *pic16_newpCodeOpBit_simple (struct asmop *op, int offs, int bit)
4231 return pic16_newpCodeOpBit (pic16_aopGet(op,offs,FALSE,FALSE),
4232 bit, 0, PO_GPR_REGISTER);
4236 /*-----------------------------------------------------------------*
4237 * pCodeOp *pic16_newpCodeOpReg(int rIdx) - allocate a new register
4239 * If rIdx >=0 then a specific register from the set of registers
4240 * will be selected. If rIdx <0, then a new register will be searched
4242 *-----------------------------------------------------------------*/
4244 pCodeOp *pic16_newpCodeOpReg(int rIdx)
4248 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4253 PCOR(pcop)->rIdx = rIdx;
4254 PCOR(pcop)->r = pic16_regWithIdx(rIdx);
4256 PCOR(pcop)->r = pic16_findFreeReg(REG_GPR);
4259 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4261 fprintf(stderr, "%s:%d Could not find a free GPR register\n",
4262 __FUNCTION__, __LINE__);
4267 pcop->type = PCOR(pcop)->r->pc_type;
4272 pCodeOp *pic16_newpCodeOpRegNotVect(bitVect *bv)
4277 pcop = Safe_calloc(1, sizeof(pCodeOpReg));
4280 r = pic16_findFreeReg(REG_GPR);
4283 if(!bitVectBitValue(bv, r->rIdx)) {
4285 PCOR(pcop)->rIdx = r->rIdx;
4286 pcop->type = r->pc_type;
4290 r = pic16_findFreeRegNext(REG_GPR, r);
4298 pCodeOp *pic16_newpCodeOpRegFromStr(char *name)
4303 pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
4304 PCOR(pcop)->r = r = pic16_allocRegByName(name, 1, NULL);
4305 PCOR(pcop)->rIdx = PCOR(pcop)->r->rIdx;
4306 pcop->type = PCOR(pcop)->r->pc_type;
4307 pcop->name = PCOR(pcop)->r->name;
4309 // if(pic16_pcode_verbose) {
4310 // fprintf(stderr, "%s:%d %s allocates register %s rIdx:0x%02x\n",
4311 // __FILE__, __LINE__, __FUNCTION__, r->name, r->rIdx);
4317 /*-----------------------------------------------------------------*/
4318 /*-----------------------------------------------------------------*/
4319 pCodeOp *pic16_newpCodeOpOpt(OPT_TYPE type, char *key)
4323 pcop = Safe_calloc(1, sizeof(pCodeOpOpt));
4326 pcop->key = Safe_strdup( key );
4328 return (PCOP(pcop));
4331 /*-----------------------------------------------------------------*/
4332 /*-----------------------------------------------------------------*/
4333 pCodeOp *pic16_newpCodeOpLocalRegs(LR_TYPE type)
4335 pCodeOpLocalReg *pcop;
4337 pcop = Safe_calloc(1, sizeof(pCodeOpLocalReg));
4341 return (PCOP(pcop));
4345 /*-----------------------------------------------------------------*/
4346 /*-----------------------------------------------------------------*/
4348 pCodeOp *pic16_newpCodeOp(char *name, PIC_OPTYPE type)
4355 pcop = pic16_newpCodeOpBit(name, -1,0, type);
4359 pcop = pic16_newpCodeOpLit(-1);
4363 pcop = pic16_newpCodeOpLabel(NULL,-1);
4366 pcop = pic16_newpCodeOpReg(-1);
4369 case PO_GPR_REGISTER:
4371 pcop = pic16_newpCodeOpRegFromStr(name);
4373 pcop = pic16_newpCodeOpReg(-1);
4377 pcop = Safe_calloc(1,sizeof(pCodeOp) );
4380 pcop->name = Safe_strdup(name);
4388 /* This is a multiple of two as gpasm pads DB directives to even length,
4389 * thus the data would be interleaved with \0 bytes...
4390 * This is a multiple of three in order to have arrays of 3-byte pointers
4391 * continuously in memory (without 0-padding at the lines' end).
4392 * This is rather 12 than 6 in order not to split up 4-byte data types
4393 * in arrays right in the middle of a 4-byte word. */
4394 #define DB_ITEMS_PER_LINE 12
4396 typedef struct DBdata
4403 static int DBd_init = -1;
4405 /*-----------------------------------------------------------------*/
4406 /* Initialiase "DB" data buffer */
4407 /*-----------------------------------------------------------------*/
4408 void pic16_initDB(void)
4414 /*-----------------------------------------------------------------*/
4415 /* Flush pending "DB" data to a pBlock */
4417 /* ptype - type of p pointer, 'f' file pointer, 'p' pBlock pointer */
4418 /*-----------------------------------------------------------------*/
4419 void pic16_flushDB(char ptype, void *p)
4423 pic16_addpCode2pBlock(((pBlock *)p),pic16_newpCodeAsmDir("DB", "%s", DBd.buffer));
4426 fprintf(((FILE *)p), "\tdb\t%s\n", DBd.buffer);
4429 fprintf(stderr, "PIC16 port error: could not emit initial value data\n");
4433 DBd.buffer[0] = '\0';
4438 /*-----------------------------------------------------------------*/
4439 /* Add "DB" directives to a pBlock */
4440 /*-----------------------------------------------------------------*/
4441 void pic16_emitDB(char c, char ptype, void *p)
4446 // we need to initialize
4449 DBd.buffer[0] = '\0';
4452 l = strlen(DBd.buffer);
4453 sprintf(DBd.buffer+l,"%s0x%02x", (DBd.count>0?", ":""), c & 0xff);
4455 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4458 if (DBd.count>= DB_ITEMS_PER_LINE)
4459 pic16_flushDB(ptype, p);
4462 void pic16_emitDS(char *s, char ptype, void *p)
4467 // we need to initialize
4470 DBd.buffer[0] = '\0';
4473 l = strlen(DBd.buffer);
4474 sprintf(DBd.buffer+l,"%s%s", (DBd.count>0?", ":""), s);
4476 // fprintf(stderr, "%s:%d DBbuffer: '%s'\n", __FILE__, __LINE__, DBd.buffer);
4478 DBd.count++; //=strlen(s);
4479 if (DBd.count>=DB_ITEMS_PER_LINE)
4480 pic16_flushDB(ptype, p);
4484 /*-----------------------------------------------------------------*/
4485 /*-----------------------------------------------------------------*/
4486 void pic16_pCodeConstString(char *name, char *value)
4490 static set *emittedSymbols = NULL;
4495 /* keep track of emitted symbols to avoid multiple definition of str_<nr> */
4496 if (emittedSymbols) {
4497 /* scan set for name */
4498 for (item = setFirstItem (emittedSymbols); item; item = setNextItem (emittedSymbols))
4500 if (!strcmp (item,name)) {
4501 //fprintf (stderr, "%s already emitted\n", name);
4506 addSet (&emittedSymbols, Safe_strdup (name));
4508 //fprintf(stderr, " %s %s %s\n",__FUNCTION__,name,value);
4510 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4512 pic16_addpBlock(pb);
4514 // sprintf(buffer,"; %s = ", name);
4515 // strcat(buffer, value);
4516 // fputs(buffer, stderr);
4518 // pic16_addpCode2pBlock(pb,pic16_newpCodeCharP(buffer));
4519 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel(name,-1));
4522 pic16_emitDB(*value, 'p', (void *)pb);
4524 pic16_flushDB('p', (void *)pb);
4527 /*-----------------------------------------------------------------*/
4528 /*-----------------------------------------------------------------*/
4530 static void pCodeReadCodeTable(void)
4534 fprintf(stderr, " %s\n",__FUNCTION__);
4536 pb = pic16_newpCodeChain(NULL, 'P',pic16_newpCodeCharP("; Starting pCode block"));
4538 pic16_addpBlock(pb);
4540 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; ReadCodeTable - built in function"));
4541 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Inputs: temp1,temp2 = code pointer"));
4542 pic16_addpCode2pBlock(pb,pic16_newpCodeCharP("; Outpus: W (from RETLW at temp2:temp1)"));
4543 pic16_addpCode2pBlock(pb,pic16_newpCodeLabel("ReadCodeTable:",-1));
4545 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp2")));
4546 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCLATH")));
4547 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVFW,pic16_newpCodeOpRegFromStr("temp1")));
4548 pic16_addpCode2pBlock(pb,pic16_newpCode(POC_MOVWF,pic16_newpCodeOpRegFromStr("PCL")));
4553 /*-----------------------------------------------------------------*/
4554 /* pic16_addpCode2pBlock - place the pCode into the pBlock linked list */
4555 /*-----------------------------------------------------------------*/
4556 void pic16_addpCode2pBlock(pBlock *pb, pCode *pc)
4563 /* If this is the first pcode to be added to a block that
4564 * was initialized with a NULL pcode, then go ahead and
4565 * make this pcode the head and tail */
4566 pb->pcHead = pb->pcTail = pc;
4569 pb->pcTail->next = pc;
4571 pc->prev = pb->pcTail;
4578 /*-----------------------------------------------------------------*/
4579 /* pic16_addpBlock - place a pBlock into the pFile */
4580 /*-----------------------------------------------------------------*/
4581 void pic16_addpBlock(pBlock *pb)
4583 // fprintf(stderr," Adding pBlock: dbName =%c\n",getpBlock_dbName(pb));
4586 /* First time called, we'll pass through here. */
4587 //_ALLOC(the_pFile,sizeof(pFile));
4588 the_pFile = Safe_calloc(1,sizeof(pFile));
4589 the_pFile->pbHead = the_pFile->pbTail = pb;
4590 the_pFile->functions = NULL;
4594 the_pFile->pbTail->next = pb;
4595 pb->prev = the_pFile->pbTail;
4597 the_pFile->pbTail = pb;
4600 /*-----------------------------------------------------------------*/
4601 /* removepBlock - remove a pBlock from the pFile */
4602 /*-----------------------------------------------------------------*/
4603 static void removepBlock(pBlock *pb)
4611 //fprintf(stderr," Removing pBlock: dbName =%c\n",getpBlock_dbName(pb));
4613 for(pbs = the_pFile->pbHead; pbs; pbs = pbs->next) {
4616 if(pbs == the_pFile->pbHead)
4617 the_pFile->pbHead = pbs->next;
4619 if (pbs == the_pFile->pbTail)
4620 the_pFile->pbTail = pbs->prev;
4623 pbs->next->prev = pbs->prev;
4626 pbs->prev->next = pbs->next;
4633 fprintf(stderr, "Warning: call to %s:%s didn't find pBlock\n",__FILE__,__FUNCTION__);
4637 /*-----------------------------------------------------------------*/
4638 /* printpCode - write the contents of a pCode to a file */
4639 /*-----------------------------------------------------------------*/
4640 static void printpCode(FILE *of, pCode *pc)
4651 fprintf(of,"warning - unable to print pCode\n");
4654 /*-----------------------------------------------------------------*/
4655 /* pic16_printpBlock - write the contents of a pBlock to a file */
4656 /*-----------------------------------------------------------------*/
4657 void pic16_printpBlock(FILE *of, pBlock *pb)
4665 for(pc = pb->pcHead; pc; pc = pc->next) {
4666 if(isPCF(pc) && PCF(pc)->fname) {
4667 fprintf(of, "S_%s_%s\tcode", PCF(pc)->modname, PCF(pc)->fname);
4668 if(pb->dbName == 'A') {
4670 for(ab=setFirstItem(absSymSet); ab; ab=setNextItem(absSymSet)) {
4671 // fprintf(stderr, "%s:%d testing %s <-> %s\n", __FILE__, __LINE__, PCF(pc)->fname, ab->name);
4672 if(!strcmp(ab->name, PCF(pc)->fname)) {
4673 // fprintf(stderr, "%s:%d address = %x\n", __FILE__, __LINE__, ab->address);
4674 if(ab->address != -1)
4675 fprintf(of, "\t0X%06X", ab->address);
4686 /*-----------------------------------------------------------------*/
4688 /* pCode processing */
4692 /*-----------------------------------------------------------------*/
4693 pCode * pic16_findNextInstruction(pCode *pci);
4694 pCode * pic16_findPrevInstruction(pCode *pci);
4696 void pic16_unlinkpCode(pCode *pc)
4702 fprintf(stderr,"Unlinking: ");
4703 printpCode(stderr, pc);
4706 pc->prev->next = pc->next;
4708 pc->next->prev = pc->prev;
4710 /* move C source line down (or up) */
4711 if (isPCI(pc) && PCI(pc)->cline) {
4712 prev = pic16_findNextInstruction (pc->next);
4713 if (prev && isPCI(prev) && !PCI(prev)->cline) {
4714 PCI(prev)->cline = PCI(pc)->cline;
4716 prev = pic16_findPrevInstruction (pc->prev);
4717 if (prev && isPCI(prev) && !PCI(prev)->cline)
4718 PCI(prev)->cline = PCI(pc)->cline;
4721 pc->prev = pc->next = NULL;
4725 /*-----------------------------------------------------------------*/
4726 /*-----------------------------------------------------------------*/
4728 static void genericDestruct(pCode *pc)
4731 pic16_unlinkpCode(pc);
4734 /* For instructions, tell the register (if there's one used)
4735 * that it's no longer needed */
4736 regs *reg = pic16_getRegFromInstruction(pc);
4738 deleteSetItem (&(reg->reglives.usedpCodes),pc);
4740 if(PCI(pc)->is2MemOp) {
4741 reg = pic16_getRegFromInstruction2(pc);
4743 deleteSetItem(&(reg->reglives.usedpCodes), pc);
4747 /* Instead of deleting the memory used by this pCode, mark
4748 * the object as bad so that if there's a pointer to this pCode
4749 * dangling around somewhere then (hopefully) when the type is
4750 * checked we'll catch it.
4754 pic16_addpCode2pBlock(pb_dead_pcodes, pc);
4760 void DEBUGpic16_emitcode (char *inst,char *fmt, ...);
4761 /*-----------------------------------------------------------------*/
4762 /*-----------------------------------------------------------------*/
4763 /* modifiers for constant immediate */
4764 const char *immdmod[3]={"LOW", "HIGH", "UPPER"};
4766 char *pic16_get_op(pCodeOp *pcop,char *buffer, size_t size)
4771 int use_buffer = 1; // copy the string to the passed buffer pointer
4776 use_buffer = 0; // Don't bother copying the string to the buffer.
4780 switch(pcop->type) {
4788 SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
4791 return PCOR(pcop)->r->name;
4794 r = pic16_regWithIdx(PCOR(pcop)->r->rIdx);
4796 SAFE_snprintf(&buffer,&size,"%s",r->name);
4803 if(PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4804 if(PCOI(pcop)->index) {
4805 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4806 immdmod[ PCOI(pcop)->offset ],
4810 SAFE_snprintf(&s,&size,"%s(%s)",
4811 immdmod[ PCOI(pcop)->offset ],
4815 if(PCOI(pcop)->index) {
4816 SAFE_snprintf(&s,&size, "%s(%s + %d)",
4821 SAFE_snprintf(&s,&size, "%s(%s)",
4828 case PO_GPR_REGISTER:
4831 // size = sizeof(buffer);
4832 if( PCOR(pcop)->instance) {
4833 SAFE_snprintf(&s,&size,"(%s + %d)",
4835 PCOR(pcop)->instance );
4837 SAFE_snprintf(&s,&size,"%s",pcop->name);
4842 if(PCORB(pcop)->subtype == PO_GPR_TEMP) {
4843 SAFE_snprintf(&s, &size, "%s", pcop->name);
4845 if(PCORB(pcop)->pcor.instance)
4846 SAFE_snprintf(&s, &size, "(%s + %d)", pcop->name, PCORB(pcop)->pcor.instance);
4848 SAFE_snprintf(&s, &size, "%s", pcop->name);
4855 SAFE_snprintf(&buffer,&size,"%s",pcop->name);
4864 return "NO operand1";
4867 /*-----------------------------------------------------------------*/
4868 /* pic16_get_op2 - variant to support two memory operand commands */
4869 /*-----------------------------------------------------------------*/
4870 char *pic16_get_op2(pCodeOp *pcop,char *buffer, size_t size)
4875 int use_buffer = 1; // copy the string to the passed buffer pointer
4880 use_buffer = 0; // Don't bother copying the string to the buffer.
4884 fprintf(stderr, "%s:%d second operand %s is %d\tPO_DIR(%d) PO_GPR_TEMP(%d) PO_IMMEDIATE(%d) PO_INDF0(%d) PO_FSR0(%d)\n",
4885 __FUNCTION__, __LINE__, PCOR(PCOR2(pcop)->pcop2)->r->name, PCOR2(pcop)->pcop2->type,
4886 PO_DIR, PO_GPR_TEMP, PO_IMMEDIATE, PO_INDF0, PO_FSR0);
4890 switch(PCOR2(pcop)->pcop2->type) {
4898 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4901 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4904 r = pic16_regWithIdx(PCOR(PCOR2(pcop)->pcop2)->r->rIdx);
4907 SAFE_snprintf(&buffer,&size,"%s",r->name);
4918 if(PCOI(pcop)->_const) {
4919 if( PCOI(pcop)->offset && PCOI(pcop)->offset<4) {
4920 SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
4923 8 * PCOI(pcop)->offset );
4925 SAFE_snprintf(&s,&size,"LOW(%s+%d)",pcop->name,PCOI(pcop)->index);
4927 if( PCOI(pcop)->index) {
4928 SAFE_snprintf(&s,&size,"(%s + %d)",
4930 PCOI(pcop)->index );
4932 if(PCOI(pcop)->offset)
4933 SAFE_snprintf(&s,&size,"(%s >> %d)&0xff",pcop->name, 8*PCOI(pcop)->offset);
4935 SAFE_snprintf(&s,&size,"%s",pcop->name);
4942 if( PCOR(PCOR2(pcop)->pcop2)->instance) {
4943 SAFE_snprintf(&s,&size,"(%s + %d)",
4944 PCOR(PCOR2(pcop)->pcop2)->r->name,
4945 PCOR(PCOR2(pcop)->pcop2)->instance );
4947 SAFE_snprintf(&s,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4952 if(PCOR(PCOR2(pcop)->pcop2)->r->name) {
4954 SAFE_snprintf(&buffer,&size,"%s",PCOR(PCOR2(pcop)->pcop2)->r->name);
4957 return PCOR(PCOR2(pcop)->pcop2)->r->name;
4962 return "NO operand2";
4965 /*-----------------------------------------------------------------*/
4966 /*-----------------------------------------------------------------*/
4967 static char *pic16_get_op_from_instruction( pCodeInstruction *pcc)
4971 return pic16_get_op(pcc->pcop,NULL,0);
4973 /* gcc 3.2: warning: concatenation of string literals with __FUNCTION__ is deprecated
4974 * return ("ERROR Null: "__FUNCTION__);
4976 return ("ERROR Null: pic16_get_op_from_instruction");
4980 /*-----------------------------------------------------------------*/
4981 /*-----------------------------------------------------------------*/
4982 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
4985 fprintf(of,"pcodeopprint- not implemented\n");
4988 /*-----------------------------------------------------------------*/
4989 /* pic16_pCode2str - convert a pCode instruction to string */
4990 /*-----------------------------------------------------------------*/
4991 char *pic16_pCode2str(char *str, size_t size, pCode *pc)
4997 if(isPCI(pc) && (PCI(pc)->pci_magic != PCI_MAGIC)) {
4998 fprintf(stderr, "%s:%d: pCodeInstruction initialization error in instruction %s, magic is %x (defaut: %x)\n",
4999 __FILE__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pci_magic, PCI_MAGIC);
5007 SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
5009 if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
5011 if(PCI(pc)->is2MemOp) {
5012 SAFE_snprintf(&s,&size, "%s, %s",
5013 pic16_get_op(PCOP(PCI(pc)->pcop), NULL, 0),
5014 pic16_get_op2(PCOP(PCI(pc)->pcop), NULL, 0));
5018 if(PCI(pc)->is2LitOp) {
5019 SAFE_snprintf(&s,&size, "%s", PCOP(PCI(pc)->pcop)->name);
5023 if(PCI(pc)->isBitInst) {
5024 if(PCI(pc)->pcop->type != PO_GPR_BIT) {
5025 if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
5026 SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)",
5027 PCI(pc)->pcop->name ,
5028 PCI(pc)->pcop->name );
5030 SAFE_snprintf(&s,&size,"%s,%d", pic16_get_op_from_instruction(PCI(pc)),
5031 // (((pCodeOpRegBit *)(PCI(pc)->pcop))->pcor.instance),
5032 (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit ));
5034 } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5035 SAFE_snprintf(&s,&size,"%s, %d", pic16_get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
5037 SAFE_snprintf(&s,&size,"%s,0 ; ?bug", pic16_get_op_from_instruction(PCI(pc)));
5038 //PCI(pc)->pcop->t.bit );
5041 if(PCI(pc)->pcop->type == PO_GPR_BIT) {
5042 if( PCI(pc)->num_ops == 3)
5043 SAFE_snprintf(&s,&size,"(%s >> 3),%c",pic16_get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
5045 SAFE_snprintf(&s,&size,"(1 << (%s & 7))",pic16_get_op_from_instruction(PCI(pc)));
5050 SAFE_snprintf(&s,&size,"%s", pic16_get_op_from_instruction(PCI(pc)));
5053 if( PCI(pc)->num_ops == 3 || ((PCI(pc)->num_ops == 2) && (PCI(pc)->isAccess))) {
5054 if(PCI(pc)->num_ops == 3 && !PCI(pc)->isBitInst)
5055 SAFE_snprintf(&s,&size,", %c", ( (PCI(pc)->isModReg) ? 'F':'W'));
5057 r = pic16_getRegFromInstruction(pc);
5058 // fprintf(stderr, "%s:%d reg = %p\tname= %s, accessBank= %d\n",
5059 // __FUNCTION__, __LINE__, r, (r)?r->name:"<null>", (r)?r->accessBank:-1);
5061 if(PCI(pc)->isAccess) {
5062 static char *bank_spec[2][2] = {
5063 { "", ", ACCESS" }, /* gpasm uses access bank by default */
5064 { ", B", ", BANKED" }/* MPASM (should) use BANKED by default */
5067 SAFE_snprintf(&s,&size,"%s", bank_spec[(r && !r->accessBank) ? 1 : 0][pic16_mplab_comp ? 1 : 0]);
5076 /* assuming that comment ends with a \n */
5077 SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
5081 SAFE_snprintf(&s,&size,"; info ==>");
5082 switch( PCINF(pc)->type ) {
5083 case INF_OPTIMIZATION:
5084 SAFE_snprintf(&s,&size, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5087 SAFE_snprintf(&s,&size, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5092 /* assuming that inline code ends with a \n */
5093 SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
5097 SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
5100 SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
5103 SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
5106 SAFE_snprintf(&s,&size,";\t--FLOW change\n");
5109 // SAFE_snprintf(&s,&size,";#CSRC\t%s %d\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5110 SAFE_snprintf(&s,&size,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5111 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5114 if(PCAD(pc)->directive) {
5115 SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5118 /* special case to handle inline labels without a tab */
5119 SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
5124 SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
5132 /*-----------------------------------------------------------------*/
5133 /* genericPrint - the contents of a pCode to a file */
5134 /*-----------------------------------------------------------------*/
5135 static void genericPrint(FILE *of, pCode *pc)
5143 // fputs(((pCodeComment *)pc)->comment, of);
5144 fprintf(of,"; %s\n", ((pCodeComment *)pc)->comment);
5149 pBranch *pbl = PCI(pc)->label;
5150 while(pbl && pbl->pc) {
5151 if(pbl->pc->type == PC_LABEL)
5152 pCodePrintLabel(of, pbl->pc);
5157 if(pic16_pcode_verbose) {
5158 fprintf(of, "; info ==>");
5159 switch(((pCodeInfo *)pc)->type) {
5160 case INF_OPTIMIZATION:
5161 fprintf(of, " [optimization] %s\n", OPT_TYPE_STR[ PCOO(PCINF(pc)->oper1)->type ]);
5164 fprintf(of, " [localregs] %s\n", LR_TYPE_STR[ PCOLR(PCINF(pc)->oper1)->type ]);
5172 fprintf(of,"%s\n", ((pCodeComment *)pc)->comment);
5176 // If the opcode has a label, print that first
5178 pBranch *pbl = PCI(pc)->label;
5179 while(pbl && pbl->pc) {
5180 if(pbl->pc->type == PC_LABEL)
5181 pCodePrintLabel(of, pbl->pc);
5187 genericPrint(of,PCODE(PCI(pc)->cline));
5192 pic16_pCode2str(str, 256, pc);
5194 fprintf(of,"%s",str);
5196 if(pic16_debug_verbose) {
5197 fprintf(of, "\t;key=%03x",pc->seq);
5199 fprintf(of,", flow seq=%03x",PCI(pc)->pcflow->pc.seq);
5206 fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
5207 if(PCW(pc)->pci.label)
5208 pCodePrintLabel(of, PCW(pc)->pci.label->pc);
5210 if(PCW(pc)->operand) {
5211 fprintf(of,";\toperand ");
5212 pCodeOpPrint(of,PCW(pc)->operand );
5217 if(pic16_debug_verbose) {
5218 fprintf(of,";<>Start of new flow, seq=0x%x",pc->seq);
5219 if(PCFL(pc)->ancestor)
5220 fprintf(of," ancestor = 0x%x", PCODE(PCFL(pc)->ancestor)->seq);
5227 // fprintf(of,";#CSRC\t%s %d\t\t%s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
5228 fprintf(of,"%s\t.line\t%d; %s\t%s\n", ((pic16_mplab_comp || !options.debug)?";":""),
5229 PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
5235 pBranch *pbl = PCAD(pc)->pci.label;
5236 while(pbl && pbl->pc) {
5237 if(pbl->pc->type == PC_LABEL)
5238 pCodePrintLabel(of, pbl->pc);
5242 if(PCAD(pc)->directive) {
5243 fprintf(of, "\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
5246 /* special case to handle inline labels without tab */
5247 fprintf(of, "%s\n", PCAD(pc)->arg);
5253 fprintf(of,"unknown pCode type %d\n",pc->type);
5258 /*-----------------------------------------------------------------*/
5259 /* pCodePrintFunction - prints function begin/end */
5260 /*-----------------------------------------------------------------*/
5262 static void pCodePrintFunction(FILE *of, pCode *pc)
5269 if( ((pCodeFunction *)pc)->modname)
5270 fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
5273 if(!PCF(pc)->absblock) {
5274 if(PCF(pc)->fname) {
5275 pBranch *exits = PCF(pc)->to;
5278 fprintf(of,"%s:", PCF(pc)->fname);
5280 if(pic16_pcode_verbose)
5281 fprintf(of, "\t;Function start");
5287 exits = exits->next;
5291 if(pic16_pcode_verbose)
5292 fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
5295 if((PCF(pc)->from &&
5296 PCF(pc)->from->pc->type == PC_FUNCTION &&
5297 PCF(PCF(pc)->from->pc)->fname) ) {
5299 if(pic16_pcode_verbose)
5300 fprintf(of,"; exit point of %s\n",PCF(PCF(pc)->from->pc)->fname);
5302 if(pic16_pcode_verbose)
5303 fprintf(of,"; exit point [can't find entry point]\n");
5309 /*-----------------------------------------------------------------*/
5310 /* pCodePrintLabel - prints label */
5311 /*-----------------------------------------------------------------*/
5313 static void pCodePrintLabel(FILE *of, pCode *pc)
5320 fprintf(of,"%s:\n",PCL(pc)->label);
5321 else if (PCL(pc)->key >=0)
5322 fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
5324 fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
5327 /*-----------------------------------------------------------------*/
5328 /* unlinkpCodeFromBranch - Search for a label in a pBranch and */
5329 /* remove it if it is found. */
5330 /*-----------------------------------------------------------------*/
5331 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
5338 if(pcl->type == PC_OPCODE || pcl->type == PC_INLINE || pcl->type == PC_ASMDIR)
5339 b = PCI(pcl)->label;
5341 fprintf(stderr, "LINE %d. can't unlink from non opcode\n",__LINE__);
5346 //fprintf (stderr, "%s \n",__FUNCTION__);
5347 //pcl->print(stderr,pcl);
5348 //pc->print(stderr,pc);
5351 //fprintf (stderr, "found label\n");
5352 //pc->print(stderr, pc);
5356 bprev->next = b->next; /* Not first pCode in chain */
5360 PCI(pcl)->label = b->next; /* First pCode in chain */
5363 return; /* A label can't occur more than once */
5371 /*-----------------------------------------------------------------*/
5372 /*-----------------------------------------------------------------*/
5373 pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n)
5392 /*-----------------------------------------------------------------*/
5393 /* pBranchLink - given two pcodes, this function will link them */
5394 /* together through their pBranches */
5395 /*-----------------------------------------------------------------*/
5396 static void pBranchLink(pCodeFunction *f, pCodeFunction *t)
5400 // Declare a new branch object for the 'from' pCode.
5402 //_ALLOC(b,sizeof(pBranch));
5403 b = Safe_calloc(1,sizeof(pBranch));
5404 b->pc = PCODE(t); // The link to the 'to' pCode.
5407 f->to = pic16_pBranchAppend(f->to,b);
5409 // Now do the same for the 'to' pCode.
5411 //_ALLOC(b,sizeof(pBranch));
5412 b = Safe_calloc(1,sizeof(pBranch));
5416 t->from = pic16_pBranchAppend(t->from,b);
5421 /*-----------------------------------------------------------------*/
5422 /* pBranchFind - find the pBranch in a pBranch chain that contains */
5424 /*-----------------------------------------------------------------*/
5425 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
5438 /*-----------------------------------------------------------------*/
5439 /* pic16_pCodeUnlink - Unlink the given pCode from its pCode chain. */
5440 /*-----------------------------------------------------------------*/
5441 void pic16_pCodeUnlink(pCode *pc)
5446 if(!pc->prev || !pc->next) {
5447 fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
5451 /* move C source line down (or up) */
5452 if (isPCI(pc) && PCI(pc)->cline) {
5453 pc1 = pic16_findNextInstruction (pc->next);
5454 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline) {
5455 PCI(pc1)->cline = PCI(pc)->cline;
5457 pc1 = pic16_findPrevInstruction (pc->prev);
5458 if (pc1 && isPCI(pc1) && !PCI(pc1)->cline)
5459 PCI(pc1)->cline = PCI(pc)->cline;
5463 /* first remove the pCode from the chain */
5464 pc->prev->next = pc->next;
5465 pc->next->prev = pc->prev;
5467 pc->prev = pc->next = NULL;
5469 /* Now for the hard part... */
5471 /* Remove the branches */
5473 pb1 = PCI(pc)->from;
5475 pc1 = pb1->pc; /* Get the pCode that branches to the
5476 * one we're unlinking */
5478 /* search for the link back to this pCode (the one we're
5480 if((pb2 = pBranchFind(PCI(pc1)->to,pc))) {
5481 pb2->pc = PCI(pc)->to->pc; // make the replacement
5483 /* if the pCode we're unlinking contains multiple 'to'
5484 * branches (e.g. this a skip instruction) then we need
5485 * to copy these extra branches to the chain. */
5486 if(PCI(pc)->to->next)
5487 pic16_pBranchAppend(pb2, PCI(pc)->to->next);
5496 /*-----------------------------------------------------------------*/
5497 /*-----------------------------------------------------------------*/
5499 static void genericAnalyze(pCode *pc)
5509 // Go through the pCodes that are in pCode chain and link
5510 // them together through the pBranches. Note, the pCodes
5511 // are linked together as a contiguous stream like the
5512 // assembly source code lines. The linking here mimics this
5513 // except that comments are not linked in.
5515 pCode *npc = pc->next;
5517 if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
5518 pBranchLink(pc,npc);
5523 /* reached the end of the pcode chain without finding
5524 * an instruction we could link to. */
5528 fprintf(stderr,"analyze PC_FLOW\n");
5532 fprintf(stderr,,";A bad pCode is being used\n");
5538 /*-----------------------------------------------------------------*/
5539 /*-----------------------------------------------------------------*/
5540 static int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
5544 if(pc->type == PC_LABEL) {
5545 if( ((pCodeLabel *)pc)->key == pcop_label->key)
5548 if((pc->type == PC_OPCODE)
5549 || (pc->type == PC_ASMDIR)
5551 pbr = PCI(pc)->label;
5553 if(pbr->pc->type == PC_LABEL) {
5554 if( ((pCodeLabel *)(pbr->pc))->key == pcop_label->key)
5564 /*-----------------------------------------------------------------*/
5565 /*-----------------------------------------------------------------*/
5566 static int checkLabel(pCode *pc)
5570 if(pc && isPCI(pc)) {
5571 pbr = PCI(pc)->label;
5573 if(isPCL(pbr->pc) && (PCL(pbr->pc)->key >= 0))
5583 /*-----------------------------------------------------------------*/
5584 /* findLabelinpBlock - Search the pCode for a particular label */
5585 /*-----------------------------------------------------------------*/
5586 static pCode * findLabelinpBlock(pBlock *pb,pCodeOpLabel *pcop_label)
5593 for(pc = pb->pcHead; pc; pc = pc->next)
5594 if(compareLabel(pc,pcop_label))
5600 /*-----------------------------------------------------------------*/
5601 /* findLabel - Search the pCode for a particular label */
5602 /*-----------------------------------------------------------------*/
5603 static pCode * findLabel(pCodeOpLabel *pcop_label)
5611 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
5612 if( (pc = findLabelinpBlock(pb,pcop_label)) != NULL)
5616 fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
5620 /*-----------------------------------------------------------------*/
5621 /* pic16_findNextpCode - given a pCode, find the next of type 'pct' */
5622 /* in the linked list */
5623 /*-----------------------------------------------------------------*/
5624 pCode * pic16_findNextpCode(pCode *pc, PC_TYPE pct)
5637 /*-----------------------------------------------------------------*/
5638 /* findPrevpCode - given a pCode, find the previous of type 'pct' */
5639 /* in the linked list */
5640 /*-----------------------------------------------------------------*/
5641 static pCode * findPrevpCode(pCode *pc, PC_TYPE pct)
5655 //#define PCODE_DEBUG
5656 /*-----------------------------------------------------------------*/
5657 /* pic16_findNextInstruction - given a pCode, find the next instruction */
5658 /* in the linked list */
5659 /*-----------------------------------------------------------------*/
5660 pCode * pic16_findNextInstruction(pCode *pci)
5665 if((pc->type == PC_OPCODE)
5666 || (pc->type == PC_WILD)
5667 || (pc->type == PC_ASMDIR)
5672 fprintf(stderr,"pic16_findNextInstruction: ");
5673 printpCode(stderr, pc);
5678 //fprintf(stderr,"Couldn't find instruction\n");
5682 /*-----------------------------------------------------------------*/
5683 /* pic16_findPrevInstruction - given a pCode, find the next instruction */
5684 /* in the linked list */
5685 /*-----------------------------------------------------------------*/
5686 pCode * pic16_findPrevInstruction(pCode *pci)
5692 if((pc->type == PC_OPCODE)
5693 || (pc->type == PC_WILD)
5694 || (pc->type == PC_ASMDIR)
5700 fprintf(stderr,"pic16_findPrevInstruction: ");
5701 printpCode(stderr, pc);
5706 //fprintf(stderr,"Couldn't find instruction\n");
5713 /*-----------------------------------------------------------------*/
5714 /* findFunctionEnd - given a pCode find the end of the function */
5715 /* that contains it */
5716 /*-----------------------------------------------------------------*/
5717 static pCode * findFunctionEnd(pCode *pc)
5721 if(pc->type == PC_FUNCTION && !(PCF(pc)->fname))
5727 fprintf(stderr,"Couldn't find function end\n");
5732 /*-----------------------------------------------------------------*/
5733 /* AnalyzeLabel - if the pCode is a label, then merge it with the */
5734 /* instruction with which it is associated. */
5735 /*-----------------------------------------------------------------*/
5736 static void AnalyzeLabel(pCode *pc)
5739 pic16_pCodeUnlink(pc);
5745 static void AnalyzeGOTO(pCode *pc)
5748 pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
5752 static void AnalyzeSKIP(pCode *pc)
5755 pBranchLink(pc,pic16_findNextInstruction(pc->next));
5756 pBranchLink(pc,pic16_findNextInstruction(pc->next->next));
5760 static void AnalyzeRETURN(pCode *pc)
5763 // branch_link(pc,findFunctionEnd(pc->next));
5769 /*-------------------------------------------------------------------*/
5770 /* pic16_getRegFrompCodeOp - extract the register from a pCodeOp */
5771 /* if one is present. This is the common */
5772 /* part of pic16_getRegFromInstruction(2) */
5773 /*-------------------------------------------------------------------*/
5775 regs * pic16_getRegFrompCodeOp (pCodeOp *pcop) {
5776 if (!pcop) return NULL;
5778 switch(pcop->type) {
5791 return PCOR(pcop)->r;
5793 case PO_SFR_REGISTER:
5794 //fprintf (stderr, "%s - SFR\n", __FUNCTION__);
5795 return PCOR(pcop)->r;
5799 // fprintf(stderr, "pic16_getRegFromInstruction - bit or temp\n");
5800 return PCOR(pcop)->r;
5803 // return pic16_dirregWithName(PCOI(pcop)->r->name);
5806 return (PCOI(pcop)->r);
5811 return PCOR(pcop)->r;
5813 case PO_GPR_REGISTER:
5815 // fprintf(stderr, "pic16_getRegFromInstruction - dir\n");
5816 return PCOR(pcop)->r;
5819 //fprintf(stderr, "pic16_getRegFromInstruction - literal\n");
5824 //fprintf (stderr, "%s - label or address: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5829 /* this should never turn up */
5830 //fprintf (stderr, "%s - unused pCodeOp->type: %d (%s)\n", __FUNCTION__, pcop->type, dumpPicOptype(pcop->type));
5837 fprintf(stderr, "pic16_getRegFromInstruction - unknown reg type %d (%s)\n",pcop->type, dumpPicOptype (pcop->type));
5845 /*-----------------------------------------------------------------*/
5846 /*-----------------------------------------------------------------*/
5847 regs * pic16_getRegFromInstruction(pCode *pc)
5853 PCI(pc)->num_ops == 0 ||
5854 (PCI(pc)->num_ops == 1 && PCI(pc)->isFastCall))
5858 fprintf(stderr, "pic16_getRegFromInstruction - reg type %s (%d)\n",
5859 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5862 return pic16_getRegFrompCodeOp (PCI(pc)->pcop);
5865 /*-------------------------------------------------------------------------------*/
5866 /* pic16_getRegFromInstruction2 - variant to support two memory operand commands */
5867 /*-------------------------------------------------------------------------------*/
5868 regs * pic16_getRegFromInstruction2(pCode *pc)
5874 PCI(pc)->num_ops == 0 ||
5875 (PCI(pc)->num_ops == 1)) // accept only 2 operand commands
5880 fprintf(stderr, "pic16_getRegFromInstruction2 - reg type %s (%d)\n",
5881 dumpPicOptype( PCI(pc)->pcop->type), PCI(pc)->pcop->type);
5884 return pic16_getRegFrompCodeOp (PCOR2(PCI(pc)->pcop)->pcop2);
5887 /*-----------------------------------------------------------------*/
5888 /*-----------------------------------------------------------------*/
5890 static void AnalyzepBlock(pBlock *pb)
5897 /* Find all of the registers used in this pBlock
5898 * by looking at each instruction and examining it's
5901 for(pc = pb->pcHead; pc; pc = pc->next) {
5903 /* Is this an instruction with operands? */
5904 if(pc->type == PC_OPCODE && PCI(pc)->pcop) {
5906 if(PCI(pc)->pcop->type == PO_GPR_TEMP) {
5908 /* Loop through all of the registers declared so far in
5909 this block and see if we find this one there */
5911 regs *r = setFirstItem(pb->tregisters);
5914 if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
5915 PCOR(PCI(pc)->pcop)->r = r;
5918 r = setNextItem(pb->tregisters);
5922 /* register wasn't found */
5923 //r = Safe_calloc(1, sizeof(regs));
5924 //memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
5925 //addSet(&pb->tregisters, r);
5926 addSet(&pb->tregisters, PCOR(PCI(pc)->pcop)->r);
5927 //PCOR(PCI(pc)->pcop)->r = r;
5928 //fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
5930 fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
5933 if(PCI(pc)->pcop->type == PO_GPR_REGISTER) {
5934 if(PCOR(PCI(pc)->pcop)->r) {
5935 pic16_allocWithIdx (PCOR(PCI(pc)->pcop)->r->rIdx);
5936 DFPRINTF((stderr,"found register in pblock: reg 0x%x\n",PCOR(PCI(pc)->pcop)->r->rIdx));
5938 if(PCI(pc)->pcop->name)
5939 fprintf(stderr,"ERROR: %s is a NULL register\n",PCI(pc)->pcop->name );
5941 fprintf(stderr,"ERROR: NULL register\n");
5950 /*-----------------------------------------------------------------*/
5952 /*-----------------------------------------------------------------*/
5953 #define PCI_HAS_LABEL(x) ((x) && (PCI(x)->label != NULL))
5955 static void InsertpFlow(pCode *pc, pCode **pflow)
5958 PCFL(*pflow)->end = pc;
5960 if(!pc || !pc->next)
5963 *pflow = pic16_newpCodeFlow();
5964 pic16_pCodeInsertAfter(pc, *pflow);
5967 /*-----------------------------------------------------------------*/
5968 /* pic16_BuildFlow(pBlock *pb) - examine the code in a pBlock and build */
5969 /* the flow blocks. */
5971 * pic16_BuildFlow inserts pCodeFlow objects into the pCode chain at each
5972 * point the instruction flow changes.
5974 /*-----------------------------------------------------------------*/
5975 void pic16_BuildFlow(pBlock *pb)
5978 pCode *last_pci=NULL;
5985 //fprintf (stderr,"build flow start seq %d ",GpcFlowSeq);
5986 /* Insert a pCodeFlow object at the beginning of a pBlock */
5988 InsertpFlow(pb->pcHead, &pflow);
5990 //pflow = pic16_newpCodeFlow(); /* Create a new Flow object */
5991 //pflow->next = pb->pcHead; /* Make the current head the next object */
5992 //pb->pcHead->prev = pflow; /* let the current head point back to the flow object */
5993 //pb->pcHead = pflow; /* Make the Flow object the head */
5996 for( pc = pic16_findNextInstruction(pb->pcHead);
5998 pc=pic16_findNextInstruction(pc)) {
6001 PCI(pc)->pcflow = PCFL(pflow);
6003 //fprintf(stderr," build: ");
6004 //pflow->print(stderr,pflow);
6006 if (checkLabel(pc)) {
6008 /* This instruction marks the beginning of a
6009 * new flow segment */
6014 /* If the previous pCode is not a flow object, then
6015 * insert a new flow object. (This check prevents
6016 * two consecutive flow objects from being insert in
6017 * the case where a skip instruction preceeds an
6018 * instruction containing a label.) */
6020 if(last_pci && (PCI(last_pci)->pcflow == PCFL(pflow)))
6021 InsertpFlow(pic16_findPrevInstruction(pc->prev), &pflow);
6023 PCI(pc)->pcflow = PCFL(pflow);
6027 if( PCI(pc)->isSkip) {
6029 /* The two instructions immediately following this one
6030 * mark the beginning of a new flow segment */
6032 while(pc && PCI(pc)->isSkip) {
6034 PCI(pc)->pcflow = PCFL(pflow);
6038 InsertpFlow(pc, &pflow);
6039 pc=pic16_findNextInstruction(pc->next);
6047 PCI(pc)->pcflow = PCFL(pflow);
6049 InsertpFlow(pc, &pflow);
6051 } else if ( PCI(pc)->isBranch && !checkLabel(pic16_findNextInstruction(pc->next))) {
6053 InsertpFlow(pc, &pflow);
6061 //fprintf (stderr,",end seq %d",GpcFlowSeq);
6063 PCFL(pflow)->end = pb->pcTail;
6066 /*-------------------------------------------------------------------*/
6067 /* unBuildFlow(pBlock *pb) - examine the code in a pBlock and build */
6068 /* the flow blocks. */
6070 * unBuildFlow removes pCodeFlow objects from a pCode chain
6072 /*-----------------------------------------------------------------*/
6073 static void unBuildFlow(pBlock *pb)
6088 if(PCI(pc)->pcflow) {
6089 //Safe_free(PCI(pc)->pcflow);
6090 PCI(pc)->pcflow = NULL;
6093 } else if(isPCFL(pc) )
6102 /*-----------------------------------------------------------------*/
6103 /*-----------------------------------------------------------------*/
6104 static void dumpCond(int cond)
6107 static char *pcc_str[] = {
6121 int ncond = sizeof(pcc_str) / sizeof(char *);
6124 fprintf(stderr, "0x%04X\n",cond);
6126 for(i=0,j=1; i<ncond; i++, j<<=1)
6128 fprintf(stderr, " %s\n",pcc_str[i]);
6134 /*-----------------------------------------------------------------*/
6135 /*-----------------------------------------------------------------*/
6136 static void FlowStats(pCodeFlow *pcflow)
6144 fprintf(stderr, " FlowStats - flow block (seq=%d)\n", pcflow->pc.seq);
6146 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6149 fprintf(stderr, " FlowStats - empty flow (seq=%d)\n", pcflow->pc.seq);
6154 fprintf(stderr, " FlowStats inCond: ");
6155 dumpCond(pcflow->inCond);
6156 fprintf(stderr, " FlowStats outCond: ");
6157 dumpCond(pcflow->outCond);
6161 /*-----------------------------------------------------------------*
6162 * int isBankInstruction(pCode *pc) - examine the pCode *pc to determine
6163 * if it affects the banking bits.
6165 * return: -1 == Banking bits are unaffected by this pCode.
6167 * return: > 0 == Banking bits are affected.
6169 * If the banking bits are affected, then the returned value describes
6170 * which bits are affected and how they're affected. The lower half
6171 * of the integer maps to the bits that are affected, the upper half
6172 * to whether they're set or cleared.
6174 *-----------------------------------------------------------------*/
6176 static int isBankInstruction(pCode *pc)
6184 if( PCI(pc)->op == POC_MOVLB ||
6185 (( (reg = pic16_getRegFromInstruction(pc)) != NULL) && isBSR_REG(reg))) {
6186 bank = PCOL(pc)->lit;
6193 /*-----------------------------------------------------------------*/
6194 /*-----------------------------------------------------------------*/
6195 static void FillFlow(pCodeFlow *pcflow)
6204 // fprintf(stderr, " FillFlow - flow block (seq=%d)\n", pcflow->pc.seq);
6206 pc = pic16_findNextpCode(PCODE(pcflow), PC_OPCODE);
6209 //fprintf(stderr, " FillFlow - empty flow (seq=%d)\n", pcflow->pc.seq);
6216 isBankInstruction(pc);
6218 } while (pc && (pc != pcflow->end) && !isPCFL(pc));
6222 fprintf(stderr, " FillFlow - Bad end of flow\n");
6224 fprintf(stderr, " FillFlow - Ending flow with\n ");
6225 pc->print(stderr,pc);
6228 fprintf(stderr, " FillFlow inCond: ");
6229 dumpCond(pcflow->inCond);
6230 fprintf(stderr, " FillFlow outCond: ");
6231 dumpCond(pcflow->outCond);
6235 /*-----------------------------------------------------------------*/
6236 /*-----------------------------------------------------------------*/
6237 static void LinkFlow_pCode(pCodeInstruction *from, pCodeInstruction *to)
6239 pCodeFlowLink *fromLink, *toLink;
6241 if(!from || !to || !to->pcflow || !from->pcflow)
6244 fromLink = pic16_newpCodeFlowLink(from->pcflow);
6245 toLink = pic16_newpCodeFlowLink(to->pcflow);
6247 addSetIfnotP(&(from->pcflow->to), toLink); //to->pcflow);
6248 addSetIfnotP(&(to->pcflow->from), fromLink); //from->pcflow);
6252 pCode *pic16_getJumptabpCode (pCode *pc) {
6255 //fprintf (stderr, "%s - start for %p in %p", __FUNCTION__, pc, isPCI(pc) ? PCI(pc)->pcflow : NULL);
6256 //pc->print (stderr, pc);
6259 if (isPCI(pcinf) && PCI(pcinf)->op != POC_GOTO) return NULL;
6260 if (pcinf->type == PC_INFO && PCINF(pcinf)->type == INF_OPTIMIZATION) {
6261 switch (PCOO(PCINF(pcinf)->oper1)->type) {
6262 case OPT_JUMPTABLE_BEGIN:
6263 /* leading begin of jump table -- in one */
6264 pcinf = pic16_findPrevInstruction (pcinf);
6268 case OPT_JUMPTABLE_END:
6269 /* leading end of jumptable -- not in one */
6274 /* ignore all other PCInfos */
6278 pcinf = pcinf->prev;
6281 /* no PCInfo found -- not in a jumptable */
6285 /*-----------------------------------------------------------------*
6286 * void LinkFlow(pBlock *pb)
6288 * In pic16_BuildFlow, the PIC code has been partitioned into contiguous
6289 * non-branching segments. In LinkFlow, we determine the execution
6290 * order of these segments. For example, if one of the segments ends
6291 * with a skip, then we know that there are two possible flow segments
6292 * to which control may be passed.
6293 *-----------------------------------------------------------------*/
6294 static void LinkFlow(pBlock *pb)
6299 pCode *jumptab_pre = NULL;
6301 //fprintf(stderr,"linkflow \n");
6303 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6305 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6308 fprintf(stderr, "LinkFlow - pcflow is not a flow object ");
6310 //fprintf(stderr," link: ");
6311 //pcflow->print(stderr,pcflow);
6313 //FillFlow(PCFL(pcflow));
6315 pc = PCFL(pcflow)->end;
6317 //fprintf(stderr, "LinkFlow - flow block (seq=%d) ", pcflow->seq);
6318 if(isPCI_SKIP(pc)) {
6319 // fprintf(stderr, "ends with skip\n");
6320 // pc->print(stderr,pc);
6322 pct=pic16_findNextInstruction(pc->next);
6323 LinkFlow_pCode(PCI(pc),PCI(pct));
6324 pct=pic16_findNextInstruction(pct->next);
6325 LinkFlow_pCode(PCI(pc),PCI(pct));
6329 if(isPCI_BRANCH(pc)) {
6330 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6332 /* handle GOTOs in jumptables */
6333 if ((jumptab_pre = pic16_getJumptabpCode (pc)) != NULL) {
6334 /* link to previous flow */
6335 //fprintf (stderr, "linked jumptable GOTO to predecessor %p\n", PCI(jumptab_pre)->pcflow);
6336 LinkFlow_pCode (PCI(jumptab_pre), PCI(pc));
6339 switch (PCI(pc)->op) {
6345 /* unconditional branches -- do not link to next instruction */
6346 //fprintf (stderr, "%s: flow ended by unconditional branch\n", __FUNCTION__);
6351 /* unconditional calls -- link to next instruction */
6352 //fprintf (stderr, "%s: flow ended by CALL\n", __FUNCTION__);
6353 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6364 /* conditional branches -- also link to next instruction */
6365 //fprintf (stderr, "%s: flow ended by conditional branch\n", __FUNCTION__);
6366 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6370 fprintf (stderr, "%s: unhandled op %u (%s)\n", __FUNCTION__, PCI(pc)->op , PCI(pc)->mnemonic);
6371 assert (0 && "unhandled branching instruction");
6375 //fprintf(stderr, "ends with branch\n ");
6376 //pc->print(stderr,pc);
6378 if(!(pcol && isPCOLAB(pcol))) {
6379 if((PCI(pc)->op != POC_RETLW)
6380 && (PCI(pc)->op != POC_RETURN) && (PCI(pc)->op != POC_CALL) && (PCI(pc)->op != POC_RCALL) && (PCI(pc)->op != POC_RETFIE) ) {
6382 /* continue if label is '$' which assembler knows how to parse */
6383 if(((PCI(pc)->pcop->type == PO_STR) && !strcmp(PCI(pc)->pcop->name, "$")))continue;
6385 if(pic16_pcode_verbose) {
6386 pc->print(stderr,pc);
6387 fprintf(stderr, "ERROR: %s, branch instruction doesn't have label\n",__FUNCTION__);
6393 if( (pct = findLabelinpBlock(pb,pcol)) != NULL)
6394 LinkFlow_pCode(PCI(pc),PCI(pct));
6396 fprintf(stderr, "ERROR: %s, couldn't find label. key=%d,lab=%s\n",
6397 __FUNCTION__,pcol->key,((PCOP(pcol)->name)?PCOP(pcol)->name:"-"));
6399 // fprintf(stderr,"pic16_newpCodeOpLabel: key=%d, name=%s\n",pcol->key,(PCOP(pcol)->name)?(PCOP(pcol)->name):"<unknown>");
6405 //fprintf(stderr, "ends with non-branching instruction:\n");
6406 //pc->print(stderr,pc);
6408 LinkFlow_pCode(PCI(pc),PCI(pic16_findNextInstruction(pc->next)));
6414 //fprintf(stderr, "ends with unknown\n");
6415 //pc->print(stderr,pc);
6419 //fprintf(stderr, "ends with nothing: ERROR\n");
6423 /*-----------------------------------------------------------------*/
6424 /*-----------------------------------------------------------------*/
6426 /*-----------------------------------------------------------------*/
6427 /*-----------------------------------------------------------------*/
6428 int pic16_isPCinFlow(pCode *pc, pCode *pcflow)
6434 if((!isPCI(pc) && !isPCAD(pc)) || !PCI(pc)->pcflow || !isPCFL(pcflow) )
6437 if( PCI(pc)->pcflow->pc.seq == pcflow->seq)
6447 /*-----------------------------------------------------------------*/
6448 /* insertBankSwitch - inserts a bank switch statement in the */
6449 /* assembly listing */
6451 /* position == 0: insert before */
6452 /* position == 1: insert after pc */
6453 /* position == 2: like 0 but previous was a skip instruction */
6454 /*-----------------------------------------------------------------*/
6455 pCodeOp *pic16_popGetLabel(unsigned int key);
6456 extern int pic16_labelOffset;
6458 static void insertBankSwitch(unsigned char position, pCode *pc)
6465 /* emit BANKSEL [symbol] */
6468 new_pc = pic16_newpCodeAsmDir("BANKSEL", "%s", pic16_get_op_from_instruction(PCI(pc)));
6470 // position = 0; // position is always before (sanity check!)
6473 fprintf(stderr, "%s:%d: inserting bank switch (pos: %d)\n", __FUNCTION__, __LINE__, position);
6474 pc->print(stderr, pc);
6479 /* insert the bank switch after this pc instruction */
6480 pCode *pcnext = pic16_findNextInstruction(pc);
6482 pic16_pCodeInsertAfter(pc, new_pc);
6483 if(pcnext)pc = pcnext;
6487 /* insert the bank switch BEFORE this pc instruction */
6488 pic16_pCodeInsertAfter(pc->prev, new_pc);
6493 pCode *pcnext, *pcprev, *npci, *ppc;
6495 int ofs1=0, ofs2=0, len=0;
6497 /* just like 0, but previous was a skip instruction,
6498 * so some care should be taken */
6500 pic16_labelOffset += 10000;
6501 tlbl = newiTempLabel(NULL);
6503 /* invert skip instruction */
6504 pcprev = pic16_findPrevInstruction(pc->prev);
6505 ipci = PCI(pcprev)->inverted_op;
6506 npci = pic16_newpCode(ipci, PCI(pcprev)->pcop);
6508 // fprintf(stderr, "%s:%d old OP: %d\tnew OP: %d\n", __FILE__, __LINE__, PCI(pcprev)->op, ipci);
6510 /* copy info from old pCode */
6511 ofs1 = ofs2 = sizeof( pCode ) + sizeof(PIC_OPCODE);
6512 len = sizeof(pCodeInstruction) - ofs1 - sizeof( char const * const *);
6513 ofs1 += strlen( PCI(pcprev)->mnemonic) + 1;
6514 ofs2 += strlen( PCI(npci)->mnemonic) + 1;
6515 memcpy(&PCI(npci)->from, &PCI(pcprev)->from, (char *)(&(PCI(npci)->pci_magic)) - (char *)(&(PCI(npci)->from)));
6516 PCI(npci)->op = PCI(pcprev)->inverted_op;
6518 /* unlink old pCode */
6520 ppc->next = pcprev->next;
6521 pcprev->next->prev = ppc;
6522 pic16_pCodeInsertAfter(ppc, npci);
6524 /* extra instructions to handle invertion */
6525 pcnext = pic16_newpCode(POC_BRA, pic16_popGetLabel(tlbl->key));
6526 pic16_pCodeInsertAfter(npci, pcnext);
6527 pic16_pCodeInsertAfter(pc->prev, new_pc);
6529 pcnext = pic16_newpCodeLabel(NULL,tlbl->key+100+pic16_labelOffset);
6530 pic16_pCodeInsertAfter(pc, pcnext);
6535 /* Move the label, if there is one */
6536 if(PCI(pc)->label) {
6537 // fprintf(stderr, "%s:%d: moving label due to bank switch directive src= 0x%p dst= 0x%p\n",
6538 // __FILE__, __LINE__, pc, new_pc);
6539 PCAD(new_pc)->pci.label = PCI(pc)->label;
6540 PCI(pc)->label = NULL;
6545 /*-----------------------------------------------------------------*/
6546 /*int compareBankFlow - compare the banking requirements between */
6548 /*-----------------------------------------------------------------*/
6549 static int compareBankFlow(pCodeFlow *pcflow, pCodeFlowLink *pcflowLink, int toORfrom)
6552 if(!pcflow || !pcflowLink || !pcflowLink->pcflow)
6555 if(!isPCFL(pcflow) || !isPCFL(pcflowLink->pcflow))
6558 if(pcflow->firstBank == -1)
6562 if(pcflowLink->pcflow->firstBank == -1) {
6563 pCodeFlowLink *pctl = setFirstItem( toORfrom ?
6564 pcflowLink->pcflow->to :
6565 pcflowLink->pcflow->from);
6566 return compareBankFlow(pcflow, pctl, toORfrom);
6570 if(pcflow->lastBank == pcflowLink->pcflow->firstBank)
6573 pcflowLink->bank_conflict++;
6574 pcflowLink->pcflow->FromConflicts++;
6575 pcflow->ToConflicts++;
6578 if(pcflow->firstBank == pcflowLink->pcflow->lastBank)
6581 pcflowLink->bank_conflict++;
6582 pcflowLink->pcflow->ToConflicts++;
6583 pcflow->FromConflicts++;
6587 fprintf(stderr,"compare flow found conflict: seq %d from conflicts %d, to conflicts %d\n",
6588 pcflowLink->pcflow->pc.seq,
6589 pcflowLink->pcflow->FromConflicts,
6590 pcflowLink->pcflow->ToConflicts);
6597 /*-----------------------------------------------------------------*/
6598 /*-----------------------------------------------------------------*/
6599 static void DumpFlow(pBlock *pb)
6603 pCodeFlowLink *pcfl;
6606 fprintf(stderr,"Dump flow \n");
6607 pb->pcHead->print(stderr, pb->pcHead);
6609 pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6610 pcflow->print(stderr,pcflow);
6612 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
6614 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
6616 if(!isPCFL(pcflow)) {
6617 fprintf(stderr, "DumpFlow - pcflow is not a flow object ");
6620 fprintf(stderr,"dumping: ");
6621 pcflow->print(stderr,pcflow);
6622 FlowStats(PCFL(pcflow));
6624 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6626 pc = PCODE(pcfl->pcflow);
6628 fprintf(stderr, " from seq %d:\n",pc->seq);
6630 fprintf(stderr,"oops dumpflow - from is not a pcflow\n");
6631 pc->print(stderr,pc);
6636 for(pcfl = setFirstItem(PCFL(pcflow)->to); pcfl; pcfl=setNextItem(PCFL(pcflow)->to)) {
6638 pc = PCODE(pcfl->pcflow);
6640 fprintf(stderr, " to seq %d:\n",pc->seq);
6642 fprintf(stderr,"oops dumpflow - to is not a pcflow\n");
6643 pc->print(stderr,pc);
6652 /*-----------------------------------------------------------------*/
6653 /*-----------------------------------------------------------------*/
6654 static int OptimizepBlock(pBlock *pb)
6659 if(!pb || !peepOptimizing)
6662 DFPRINTF((stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb)));
6664 for(pc = pb->pcHead; pc; pc = pc->next)
6665 matches += pic16_pCodePeepMatchRule(pc);
6668 pc = pic16_findNextInstruction(pb->pcHead);
6676 if(pic16_pCodePeepMatchRule(pc)) {
6681 pc = pic16_findNextInstruction(pcprev->next);
6683 pc = pic16_findNextInstruction(pb->pcHead);
6685 pc = pic16_findNextInstruction(pc->next);
6689 DFPRINTF((stderr," Optimizing pBlock: %c - matches=%d\n",getpBlock_dbName(pb),matches));
6694 /*-----------------------------------------------------------------*/
6695 /*-----------------------------------------------------------------*/
6696 static pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
6700 for(pc = pcs; pc; pc = pc->next) {
6702 if(((pc->type == PC_OPCODE) || (pc->type == PC_INLINE) || (pc->type == PC_ASMDIR)) &&
6704 (PCI(pc)->pcop->type == PO_LABEL) &&
6705 (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
6713 /*-----------------------------------------------------------------*/
6714 /*-----------------------------------------------------------------*/
6715 static void exchangeLabels(pCodeLabel *pcl, pCode *pc)
6722 (PCI(pc)->pcop->type == PO_LABEL)) {
6724 pCodeOpLabel *pcol = PCOLAB(PCI(pc)->pcop);
6726 // fprintf(stderr,"changing label key from %d to %d\n",pcol->key, pcl->key);
6727 // if(pcol->pcop.name)
6728 // Safe_free(pcol->pcop.name);
6730 /* If the key is negative, then we (probably) have a label to
6731 * a function and the name is already defined */
6734 sprintf(s=buffer,"_%05d_DS_",pcl->key);
6738 //sprintf(buffer,"_%05d_DS_",pcl->key);
6740 fprintf(stderr, "ERROR %s:%d function label is null\n",__FUNCTION__,__LINE__);
6742 pcol->pcop.name = Safe_strdup(s);
6743 pcol->key = pcl->key;
6744 //pc->print(stderr,pc);
6751 /*-----------------------------------------------------------------*/
6752 /* pBlockRemoveUnusedLabels - remove the pCode labels from the */
6753 /* pCode chain if they're not used. */
6754 /*-----------------------------------------------------------------*/
6755 static void pBlockRemoveUnusedLabels(pBlock *pb)
6757 pCode *pc; pCodeLabel *pcl;
6762 for(pc = pb->pcHead; (pc=pic16_findNextInstruction(pc->next)) != NULL; ) {
6764 pBranch *pbr = PCI(pc)->label;
6765 if(pbr && pbr->next) {
6766 pCode *pcd = pb->pcHead;
6768 // fprintf(stderr, "multiple labels\n");
6769 // pc->print(stderr,pc);
6774 while ( (pcd = findInstructionUsingLabel(PCL(PCI(pc)->label->pc), pcd)) != NULL) {
6775 //fprintf(stderr,"Used by:\n");
6776 //pcd->print(stderr,pcd);
6778 exchangeLabels(PCL(pbr->pc),pcd);
6787 for(pc = pb->pcHead; pc; pc = pc->next) {
6789 if(isPCL(pc)) // pc->type == PC_LABEL)
6791 else if (isPCI(pc) && PCI(pc)->label) //((pc->type == PC_OPCODE) && PCI(pc)->label)
6792 pcl = PCL(PCI(pc)->label->pc);
6795 // fprintf(stderr," found A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6797 /* This pCode is a label, so search the pBlock to see if anyone
6800 if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))
6802 //if( !findInstructionUsingLabel(pcl, pb->pcHead)) {
6803 /* Couldn't find an instruction that refers to this label
6804 * So, unlink the pCode label from it's pCode chain
6805 * and destroy the label */
6806 // fprintf(stderr," removed A LABEL !!! key = %d, %s\n", pcl->key,pcl->label);
6808 DFPRINTF((stderr," !!! REMOVED A LABEL !!! key = %d, %s\n", pcl->key,pcl->label));
6809 if(pc->type == PC_LABEL) {
6810 pic16_unlinkpCode(pc);
6811 pCodeLabelDestruct(pc);
6813 unlinkpCodeFromBranch(pc, PCODE(pcl));
6814 /*if(pc->label->next == NULL && pc->label->pc == NULL) {
6815 Safe_free(pc->label);
6825 /*-----------------------------------------------------------------*/
6826 /* pic16_pBlockMergeLabels - remove the pCode labels from the pCode */
6827 /* chain and put them into pBranches that are */
6828 /* associated with the appropriate pCode */
6830 /*-----------------------------------------------------------------*/
6831 void pic16_pBlockMergeLabels(pBlock *pb)
6834 pCode *pc, *pcnext=NULL;
6839 /* First, Try to remove any unused labels */
6840 //pBlockRemoveUnusedLabels(pb);
6842 /* Now loop through the pBlock and merge the labels with the opcodes */
6845 // for(pc = pb->pcHead; pc; pc = pc->next) {
6848 pCode *pcn = pc->next;
6850 if(pc->type == PC_LABEL) {
6852 // fprintf(stderr," checking merging label %s\n",PCL(pc)->label);
6853 // fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
6855 if((pcnext = pic16_findNextInstruction(pc) )) {
6857 // pcnext->print(stderr, pcnext);
6859 // Unlink the pCode label from it's pCode chain
6860 pic16_unlinkpCode(pc);
6862 // fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
6863 // And link it into the instruction's pBranch labels. (Note, since
6864 // it's possible to have multiple labels associated with one instruction
6865 // we must provide a means to accomodate the additional labels. Thus
6866 // the labels are placed into the singly-linked list "label" as
6867 // opposed to being a single member of the pCodeInstruction.)
6869 //_ALLOC(pbr,sizeof(pBranch));
6871 pbr = Safe_calloc(1,sizeof(pBranch));
6875 PCI(pcnext)->label = pic16_pBranchAppend(PCI(pcnext)->label,pbr);
6878 if(pic16_pcode_verbose)
6879 fprintf(stderr, "WARNING: couldn't associate label %s with an instruction\n",PCL(pc)->label);
6881 } else if(pc->type == PC_CSOURCE) {
6883 /* merge the source line symbolic info into the next instruction */
6884 if((pcnext = pic16_findNextInstruction(pc) )) {
6886 // Unlink the pCode label from it's pCode chain
6887 pic16_unlinkpCode(pc);
6888 PCI(pcnext)->cline = PCCS(pc);
6889 //fprintf(stderr, "merging CSRC\n");
6890 //genericPrint(stderr,pcnext);
6896 pBlockRemoveUnusedLabels(pb);
6900 /*-----------------------------------------------------------------*/
6901 /*-----------------------------------------------------------------*/
6902 static int OptimizepCode(char dbName)
6904 #define MAX_PASSES 4
6913 DFPRINTF((stderr," Optimizing pCode\n"));
6917 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
6918 if('*' == dbName || getpBlock_dbName(pb) == dbName)
6919 matches += OptimizepBlock(pb);
6922 while(matches && ++passes < MAX_PASSES);
6929 const char *pic16_pCodeOpType(pCodeOp *pcop);
6930 const char *pic16_pCodeOpSubType(pCodeOp *pcop);
6933 /*-----------------------------------------------------------------*/
6934 /* pic16_popCopyGPR2Bit - copy a pcode operator */
6935 /*-----------------------------------------------------------------*/
6937 pCodeOp *pic16_popCopyGPR2Bit(pCodeOp *pc, int bitval)
6941 // fprintf(stderr, "%s:%d pc type: %s\tname: %s\n", __FILE__, __LINE__, pic16_pCodeOpType(pc), pc->name);
6944 pcop = pic16_newpCodeOpBit(pc->name, bitval, 0, pc->type);
6946 if(PCOR(pc)->r)pcop = pic16_newpCodeOpBit(PCOR(pc)->r->name, bitval, 0, pc->type);
6949 assert(pcop != NULL);
6951 if( !( (pcop->type == PO_LABEL) ||
6952 (pcop->type == PO_LITERAL) ||
6953 (pcop->type == PO_STR) ))
6954 PCOR(pcop)->r = PCOR(pc)->r; /* This is dangerous... */
6955 PCOR(pcop)->r->wasUsed = 1;
6956 PCOR(pcop)->instance = PCOR(pc)->instance;
6962 /*----------------------------------------------------------------------*
6963 * pic16_areRegsSame - check to see if the names of two registers match *
6964 *----------------------------------------------------------------------*/
6965 int pic16_areRegsSame(regs *r1, regs *r2)
6967 if(!strcmp(r1->name, r2->name))return 1;
6973 /*-----------------------------------------------------------------*/
6974 /*-----------------------------------------------------------------*/
6975 static void pic16_FixRegisterBanking(pBlock *pb)
6979 regs *reg, *prevreg;
6980 unsigned char flag=0;
6985 pc = pic16_findNextpCode(pb->pcHead, PC_OPCODE);
6988 /* loop through all of the flow blocks with in one pblock */
6990 // fprintf(stderr,"%s:%d: Register banking\n", __FUNCTION__, __LINE__);
6994 /* at this point, pc should point to a PC_FLOW object */
6995 /* for each flow block, determine the register banking
6999 /* if label, then might come from other point, force banksel */
7000 if(isPCL(pc))prevreg = NULL;
7002 if(!isPCI(pc))goto loop;
7004 if(PCI(pc)->label)prevreg = NULL;
7006 if(PCI(pc)->is2MemOp)goto loop;
7008 /* if goto, then force banksel */
7009 // if(PCI(pc)->op == POC_GOTO)prevreg = NULL;
7011 reg = pic16_getRegFromInstruction(pc);
7014 pc->print(stderr, pc);
7015 fprintf(stderr, "reg = %p\n", reg);
7018 fprintf(stderr, "%s:%d: %s %d\n",__FUNCTION__, __LINE__, reg->name, reg->rIdx);
7019 fprintf(stderr, "addr = 0x%03x, bit=%d\tfix=%d\n",
7020 reg->address,reg->isBitField, reg->isFixed);
7024 /* now make some tests to make sure that instruction needs bank switch */
7026 /* if no register exists, and if not a bit opcode goto loop */
7028 if(!(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_BIT))goto loop;
7031 if(isPCI_SKIP(pc)) {
7032 // fprintf(stderr, "instruction is SKIP instruction\n");
7035 if(reg && isACCESS_BANK(reg))goto loop;
7037 if(!isBankInstruction(pc))goto loop;
7039 if(isPCI_LIT(pc))goto loop;
7041 if(PCI(pc)->op == POC_CALL)goto loop;
7043 /* Examine the instruction before this one to make sure it is
7044 * not a skip type instruction */
7045 pcprev = findPrevpCode(pc->prev, PC_OPCODE);
7047 flag = 0; /* add before this instruction */
7049 /* if previous instruction is a skip one, then set flag
7050 * to 2 and call insertBankSwitch */
7051 if(pcprev && isPCI_SKIP(pcprev)) {
7056 if(pic16_options.opt_banksel>0) {
7057 char op1[128], op2[128];
7060 strcpy(op1, pic16_get_op_from_instruction(PCI(pc)));
7061 strcpy(op2, pic16_get_op_from_instruction(PCI(pcprev)));
7062 if(!strcmp(op1, op2))goto loop;
7066 insertBankSwitch(flag, pc);
7068 // fprintf(stderr, "BANK SWITCH inserted\n");
7076 /** ADDITIONS BY RAPHAEL NEIDER, 2004-11-16: GOTO OPTIMIZATIONS **/
7078 /* Returns the (maximum of the) number of bytes used by the specified pCode. */
7079 int instrSize (pCode *pc)
7084 if (!PCAD(pc)->directive || strlen (PCAD(pc)->directive) < 3) return 0;
7085 return 4; // assumes only regular instructions using <= 4 bytes
7088 if (isPCI(pc)) return PCI(pc)->isize;
7093 /* Returns 1 if pc is referenced by the given label (either
7094 * pc is the label itself or is an instruction with an attached
7096 * Returns 0 if pc is not preceeded by the specified label.
7098 int isLabel (pCode *pc, char *label)
7102 // label attached to the pCode?
7103 if (isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO) {
7104 pBranch *lab = NULL;
7105 lab = PCI(pc)->label;
7108 if (isPCL(lab->pc) && strcmp(PCL(lab->pc)->label, label) == 0) {
7115 // is inline assembly label?
7116 if (isPCAD(pc) && PCAD(pc)->directive == NULL && PCAD(pc)->arg) {
7117 // do not compare trailing ':'
7118 if (strncmp (PCAD(pc)->arg, label, strlen (label)) == 0) {
7125 if (strcmp(PCL(pc)->label,label) == 0) {
7130 // no label/no label attached/wrong label(s)
7134 /* Returns the distance to the given label in terms of words.
7135 * Labels are searched only within -max .. max words from pc.
7136 * Returns max if the label could not be found or
7137 * its distance from pc in (-max..+max).
7139 int findpCodeLabel (pCode *pc, char *label, int max, pCode **target) {
7140 int dist = instrSize(pc);
7144 while (dist < max && curr && !isLabel (curr, label)) {
7146 dist += instrSize(curr); // sizeof (instruction)
7148 if (curr && dist < max) {
7149 if (target != NULL) *target = curr;
7154 curr = pic16_findNextInstruction (pc->next);
7156 while (dist < max && curr && !isLabel (curr, label)) {
7157 dist += instrSize(curr); // sizeof (instruction)
7160 if (curr && dist < max) {
7161 if (target != NULL) *target = curr;
7165 if (target != NULL) *target = NULL;
7169 /* Returns -1 if pc does NOT denote an instruction like
7171 * Otherwise we return
7172 * (a) 0x10 + i for BTFSS
7173 * (b) 0x00 + i for BTFSC
7175 int isSkipOnStatus (pCode *pc)
7179 if (!pc || !isPCI(pc)) return -1;
7180 if (PCI(pc)->op == POC_BTFSS) res = 0x10;
7181 else if (PCI(pc)->op == POC_BTFSC) res = 0x00;
7184 pcop = PCI(pc)->pcop;
7186 if (pcop->type == PO_STATUS || (pcop->type == PO_GPR_BIT && strcmp(pcop->name, "STATUS") == 0)) {
7187 return res + ((pCodeOpRegBit *)pcop)->bit;
7193 /* Returns 1 if pc is one of BC, BZ, BOV, BN, BNC, BNZ, BNOV or BNN,
7194 * returns 0 otherwise. */
7195 int isConditionalBranch (pCode *pc)
7197 if (!pc || !isPCI_BRANCH(pc)) return 0;
7199 switch (PCI(pc)->op) {
7217 /* Returns 1 if pc has a label attached to it.
7218 * This can be either a label stored in the pCode itself (.label)
7219 * or a label making up its own pCode preceding this pc.
7220 * Returns 0 if pc cannot be reached directly via a label.
7222 int hasNoLabel (pCode *pc)
7227 // are there any label pCodes between pc and the previous instruction?
7228 prev = pic16_findPrevInstruction (pc->prev);
7229 while (pc && pc != prev) {
7230 // pCode with attached label?
7231 if ((isPCI(pc) || isPCAD(pc) || isPCW(pc) || pc->type == PC_INFO)
7232 && PCI(pc)->label) {
7235 // is inline assembly label?
7236 if (isPCAD(pc) && PCAD(pc)->directive == NULL) return 0;
7237 if (isPCW(pc) && PCW(pc)->label) return 0;
7240 if (isPCL(pc)) return 0;
7249 static void pic16_InsertCommentAfter (pCode *pc, const char *fmt, ...) {
7254 vsprintf (buf, fmt, va);
7257 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(buf));
7260 /* Replaces the old pCode with the new one, moving the labels,
7261 * C source line and probably flow information to the new pCode.
7263 void pic16_pCodeReplace (pCode *oldPC, pCode *newPC) {
7264 if (!oldPC || !newPC || !isPCI(oldPC) || !isPCI(newPC))
7267 /* first move all labels from old to new */
7268 PCI(newPC)->label = pic16_pBranchAppend (PCI(oldPC)->label, PCI(newPC)->label);
7269 PCI(oldPC)->label = NULL;
7272 /* move C source line (if possible) */
7273 if (PCI(oldPC)->cline && !PCI(newPC)->cline)
7274 PCI(newPC)->cline = PCI(oldPC)->cline;
7277 /* keep flow information intact */
7278 newPC->seq = oldPC->seq;
7279 PCI(newPC)->pcflow = PCI(oldPC)->pcflow;
7280 if (PCI(newPC)->pcflow && PCI(newPC)->pcflow->end == oldPC) {
7281 PCI(newPC)->pcflow->end = newPC;
7284 /* insert a comment stating which pCode has been replaced */
7286 if (pic16_pcode_verbose || pic16_debug_verbose) {
7288 pic16_pCode2str (pc_str, 256, oldPC);
7289 pic16_InsertCommentAfter (oldPC->prev, "%s: replaced %s", __FUNCTION__, pc_str);
7293 /* insert new pCode into pBlock */
7294 pic16_pCodeInsertAfter (oldPC, newPC);
7295 pic16_unlinkpCode (oldPC);
7297 /* destruct replaced pCode */
7298 oldPC->destruct (oldPC);
7301 /* Returns the inverted conditional branch (if any) or NULL.
7302 * pcop must be set to the new jump target.
7304 pCode *getNegatedBcc (pCode *bcc, pCodeOp *pcop)
7308 if (!bcc || !isPCI(bcc)) return NULL;
7310 switch (PCI(bcc)->op) {
7311 case POC_BC: newBcc = pic16_newpCode (POC_BNC , pcop); break;
7312 case POC_BZ: newBcc = pic16_newpCode (POC_BNZ , pcop); break;
7313 case POC_BOV: newBcc = pic16_newpCode (POC_BNOV, pcop); break;
7314 case POC_BN: newBcc = pic16_newpCode (POC_BNN , pcop); break;
7315 case POC_BNC: newBcc = pic16_newpCode (POC_BC , pcop); break;
7316 case POC_BNZ: newBcc = pic16_newpCode (POC_BZ , pcop); break;
7317 case POC_BNOV: newBcc = pic16_newpCode (POC_BOV , pcop); break;
7318 case POC_BNN: newBcc = pic16_newpCode (POC_BN , pcop); break;
7325 #define MAX_DIST_GOTO 0x7FFFFFFF
7326 #define MAX_DIST_BRA 1020 // maximum offset (in bytes) possible with BRA
7327 #define MAX_DIST_BCC 120 // maximum offset (in bytes) possible with Bcc
7328 #define MAX_JUMPCHAIN_DEPTH 16 // number of GOTOs to follow in resolveJumpChain() (to prevent endless loops)
7329 #define IS_GOTO(arg) ((arg) && isPCI(arg) && (PCI(arg)->op == POC_GOTO || PCI(arg)->op == POC_BRA))
7331 /* Follows GOTO/BRA instructions to their target instructions, stores the
7332 * final destination (not a GOTO or BRA instruction) in target and returns
7333 * the distance from the original pc to *target.
7335 int resolveJumpChain (pCode *pc, pCode **target, pCodeOp **pcop) {
7338 pCodeOp *lastPCOP = NULL;
7342 //fprintf (stderr, "%s:%d: -=-", __FUNCTION__, __LINE__);
7344 /* only follow unconditional branches, except for the initial pCode (which may be a conditional branch) */
7345 while (curr && (last != curr) && (depth++ < MAX_JUMPCHAIN_DEPTH) && isPCI(curr)
7346 && (PCI(curr)->op == POC_GOTO || PCI(curr)->op == POC_BRA || (curr == pc && isConditionalBranch(curr)))) {
7348 lastPCOP = PCI(curr)->pcop;
7349 dist = findpCodeLabel (pc, PCI(curr)->pcop->name, MAX_DIST_GOTO, &curr);
7350 //fprintf (stderr, "last:%p, curr:%p, label:%s\n", last, curr, PCI(last)->pcop->name);
7353 if (target) *target = last;
7354 if (pcop) *pcop = lastPCOP;
7358 /* Returns pc if it is not a OPT_JUMPTABLE_BEGIN INFO pCode.
7359 * Otherwise the first pCode after the jumptable (after
7360 * the OPT_JUMPTABLE_END tag) is returned.
7362 pCode *skipJumptables (pCode *pc, int *isJumptable)
7365 if (!pc) return NULL;
7367 while (pc->type == PC_INFO && PCINF(pc)->type == INF_OPTIMIZATION && PCOO(PCINF(pc)->oper1)->type == OPT_JUMPTABLE_BEGIN) {
7369 //fprintf (stderr, "SKIPPING jumptable\n");
7371 //pc->print(stderr, pc);
7373 } while (pc && (pc->type != PC_INFO || PCINF(pc)->type != INF_OPTIMIZATION
7374 || PCOO(PCINF(pc)->oper1)->type != OPT_JUMPTABLE_END));
7375 //fprintf (stderr, "<<JUMPTAB:\n");
7376 // skip OPT_END as well
7377 if (pc) pc = pc->next;
7383 pCode *pic16_findNextInstructionSkipJumptables (pCode *pc, int *isJumptable)
7387 while (pc && !isPCI(pc) && !isPCAD(pc) && !isPCW(pc)) {
7388 // set pc to the first pCode after a jumptable, leave pc untouched otherwise
7389 pc = skipJumptables (pc, &isJumptab);
7391 // pc is the first pCode after the jumptable
7394 // pc has not been changed by skipJumptables()
7402 /* Turn GOTOs into BRAs if distance between GOTO and label
7403 * is less than 1024 bytes.
7405 * This method is especially useful if GOTOs after BTFS[SC]
7406 * can be turned into BRAs as GOTO would cost another NOP
7409 void pic16_OptimizeJumps ()
7412 pCode *pc_prev = NULL;
7413 pCode *pc_next = NULL;
7416 int change, iteration, isJumptab;
7419 int opt=0, toofar=0, opt_cond = 0, cond_toofar=0, opt_reorder = 0, opt_gotonext = 0, opt_gotochain = 0;
7421 if (!the_pFile) return;
7423 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7425 for (pb = the_pFile->pbHead; pb != NULL; pb = pb->next) {
7426 int matchedInvertRule = 1;
7429 //fprintf (stderr, "%s:%d: iterating over pBlock %p\n", __FUNCTION__, __LINE__, pb);
7431 pc = pic16_findNextInstruction (pb->pcHead);
7434 pc_next = pic16_findNextInstructionSkipJumptables (pc->next, &isJumptab);
7436 // skip jumptable, i.e. start over with no pc_prev!
7442 /* (1) resolve chained jumps
7443 * Do not perform this until pattern (4) is no longer present! Otherwise we will
7444 * (a) leave dead code in and
7445 * (b) skip over the dead code with an (unneccessary) jump.
7447 if (!matchedInvertRule && (IS_GOTO(pc) || isConditionalBranch(pc))) {
7448 pCodeOp *lastTargetOp = NULL;
7449 int newDist = resolveJumpChain (pc, &target, &lastTargetOp);
7450 int maxDist = MAX_DIST_BCC;
7451 if (PCI(pc)->op == POC_BRA) maxDist = MAX_DIST_BRA;
7452 if (PCI(pc)->op == POC_GOTO) maxDist = MAX_DIST_GOTO;
7454 /* be careful NOT to make the jump instruction longer (might break previously shortened jumps!) */
7455 if (lastTargetOp && newDist <= maxDist && lastTargetOp != PCI(pc)->pcop
7456 && strcmp (lastTargetOp->name, PCI(pc)->pcop->name) != 0) {
7457 //fprintf (stderr, "(1) ");pc->print(stderr, pc); fprintf (stderr, " --> %s\n", lastTargetOp->name);
7458 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(1) jump chain resolved")); }
7459 PCI(pc)->pcop->name = lastTargetOp->name;
7468 int condBraType = isSkipOnStatus(pc_prev);
7469 label = PCI(pc)->pcop->name;
7470 dist = findpCodeLabel(pc, label, MAX_DIST_BRA, &target);
7471 if (dist < 0) dist = -dist;
7472 //fprintf (stderr, "distance: %d (", dist); pc->print(stderr, pc);fprintf (stderr, ")\n");
7476 /* (2) remove "GOTO label; label:" */
7477 if (isLabel (pc_next, label)) {
7478 //fprintf (stderr, "(2) GOTO next instruction: ");pc->print(stderr, pc);fprintf (stderr, " --> ");pc_next->print(stderr, pc_next); fprintf(stderr, "\n");
7479 // first remove all preceeding SKIP instructions
7480 while (pc_prev && isPCI_SKIP(pc_prev)) {
7481 // attach labels on this instruction to pc_next
7482 //fprintf (stderr, "(2) preceeding SKIP removed: ");pc_prev->print(stderr, pc_prev);fprintf(stderr, "\n");
7483 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc_prev)->label, PCI(pc_next)->label);
7484 PCI(pc_prev)->label = NULL;
7485 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("(2) SKIP removed")); }
7486 pic16_unlinkpCode (pc_prev);
7487 pc_prev = pic16_findPrevInstruction (pc);
7489 // now remove the redundant goto itself
7490 PCI(pc_next)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pc_next)->label);
7491 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP("(2) GOTO next instruction removed")); }
7492 pic16_unlinkpCode (pc);
7493 pc = pic16_findPrevInstruction(pc_next->prev);
7494 isHandled = 1; // do not perform further optimizations
7500 /* (3) turn BTFSx STATUS,i; GOTO label into Bcc label if possible */
7501 if (!isHandled && condBraType != -1 && hasNoLabel(pc)) {
7502 if (dist < MAX_DIST_BCC) {
7504 switch (condBraType) {
7505 case 0x00: bcc = pic16_newpCode (POC_BC, PCI(pc)->pcop);break;
7506 // no BDC on DIGIT CARRY available
7507 case 0x02: bcc = pic16_newpCode (POC_BZ, PCI(pc)->pcop);break;
7508 case 0x03: bcc = pic16_newpCode (POC_BOV, PCI(pc)->pcop);break;
7509 case 0x04: bcc = pic16_newpCode (POC_BN, PCI(pc)->pcop);break;
7510 case 0x10: bcc = pic16_newpCode (POC_BNC, PCI(pc)->pcop);break;
7511 // no BNDC on DIGIT CARRY available
7512 case 0x12: bcc = pic16_newpCode (POC_BNZ, PCI(pc)->pcop);break;
7513 case 0x13: bcc = pic16_newpCode (POC_BNOV, PCI(pc)->pcop);break;
7514 case 0x14: bcc = pic16_newpCode (POC_BNN, PCI(pc)->pcop);break;
7516 // no replacement possible
7521 // ATTENTION: keep labels attached to BTFSx!
7522 // HINT: GOTO is label free (checked above)
7523 //fprintf (stderr, "%s:%d: (3) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(bcc)->mnemonic, label);
7524 isHandled = 1; // do not perform further optimizations
7525 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(3) conditional branch introduced")); }
7526 pic16_pCodeReplace (pc_prev, bcc);
7533 //fprintf (stderr, "(%d, too far for Bcc)\n", dist);
7539 // (4) eliminate the following (common) tripel:
7541 // labels1: Bcc label2;
7542 // GOTO somewhere; ; <-- instruction referenced by pc
7544 // and replace it by
7545 // labels1: B#(cc) somewhere; ; #(cc) is the negated condition cc
7547 // ATTENTION: all labels pointing to "Bcc label2" must be attached
7548 // to <cont.> instead
7549 // ATTENTION: This optimization is only valid if <pred.> is
7550 // not a skip operation!
7551 // ATTENTION: somewhere must be within MAX_DIST_BCC bytes!
7552 // ATTENTION: no label may be attached to the GOTO instruction!
7553 if (isConditionalBranch(pc_prev)
7554 && (!isPCI_SKIP(pic16_findPrevInstruction(pc_prev->prev)))
7555 && (dist < MAX_DIST_BCC)
7556 && isLabel(pc_next,PCI(pc_prev)->pcop->name)
7557 && hasNoLabel(pc)) {
7558 pCode *newBcc = getNegatedBcc (pc_prev, PCI(pc)->pcop);
7561 //fprintf (stderr, "%s:%d: (4) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBcc)->mnemonic, label);
7562 isHandled = 1; // do not perform further optimizations
7563 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc_prev->prev, pic16_newpCodeCharP("(4) conditional skipping branch inverted")); }
7564 pic16_pCodeReplace (pc_prev, newBcc);
7569 matchedInvertRule++;
7574 /* (5) now just turn GOTO into BRA */
7575 if (!isHandled && (PCI(pc)->op == POC_GOTO)) {
7576 if (dist < MAX_DIST_BRA) {
7577 pCode *newBra = pic16_newpCode (POC_BRA, PCI(pc)->pcop);
7578 //fprintf (stderr, "%s:%d: (5) turning %s %s into %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, label, PCI(newBra)->mnemonic, label);
7579 if (pic16_pcode_verbose) { pic16_pCodeInsertAfter(pc->prev, pic16_newpCodeCharP("(5) GOTO replaced by BRA")); }
7580 pic16_pCodeReplace (pc, newBra);
7585 //fprintf (stderr, "(%d, too far for BRA)\n", dist);
7588 } // if (!isHandled)
7595 pBlockRemoveUnusedLabels (pb);
7597 // This line enables goto chain resolution!
7598 if (matchedInvertRule > 1) matchedInvertRule = 1; else matchedInvertRule = 0;
7601 } while (change); /* fixpoint iteration per pBlock */
7604 // emit some statistics concerning goto-optimization
7606 if (pic16_debug_verbose || pic16_pcode_verbose) {
7607 fprintf (stderr, "optimize-goto:\n"
7608 "\t%5d GOTO->BRA; (%d GOTOs too far)\n"
7609 "\t%5d BTFSx, GOTO->Bcc (%d too far)\n"
7610 "\t%5d conditional \"skipping\" jumps inverted\n"
7611 "\t%5d GOTOs to next instruction removed\n"
7612 "\t%5d chained GOTOs resolved\n",
7613 opt, toofar, opt_cond, cond_toofar, opt_reorder, opt_gotonext, opt_gotochain);
7616 //fprintf (stderr, "%s:%d: %s\n", __FILE__, __LINE__, __FUNCTION__);
7620 #undef MAX_JUMPCHAIN_DEPTH
7621 #undef MAX_DIST_GOTO
7625 /** END OF RAPHAEL NEIDER'S ADDITIONS **/
7627 static void pBlockDestruct(pBlock *pb)
7638 /*-----------------------------------------------------------------*/
7639 /* void mergepBlocks(char dbName) - Search for all pBlocks with the*/
7640 /* name dbName and combine them */
7641 /* into one block */
7642 /*-----------------------------------------------------------------*/
7643 static void mergepBlocks(char dbName)
7646 pBlock *pb, *pbmerged = NULL,*pbn;
7648 pb = the_pFile->pbHead;
7650 //fprintf(stderr," merging blocks named %c\n",dbName);
7654 //fprintf(stderr,"looking at %c\n",getpBlock_dbName(pb));
7655 if( getpBlock_dbName(pb) == dbName) {
7657 //fprintf(stderr," merged block %c\n",dbName);
7662 pic16_addpCode2pBlock(pbmerged, pb->pcHead);
7663 /* pic16_addpCode2pBlock doesn't handle the tail: */
7664 pbmerged->pcTail = pb->pcTail;
7666 pb->prev->next = pbn;
7668 pbn->prev = pb->prev;
7673 //pic16_printpBlock(stderr, pbmerged);
7680 /*-----------------------------------------------------------------*/
7681 /* AnalyzeFlow - Examine the flow of the code and optimize */
7683 /* level 0 == minimal optimization */
7684 /* optimize registers that are used only by two instructions */
7685 /* level 1 == maximal optimization */
7686 /* optimize by looking at pairs of instructions that use the */
7688 /*-----------------------------------------------------------------*/
7690 static void AnalyzeFlow(int level)
7692 static int times_called=0;
7696 /* remove unused allocated registers before exiting */
7697 pic16_RemoveUnusedRegisters();
7702 /* if this is not the first time this function has been called,
7703 * then clean up old flow information */
7704 if(times_called++) {
7705 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7707 pic16_RegsUnMapLiveRanges();
7711 /* Phase 2 - Flow Analysis - Register Banking
7713 * In this phase, the individual flow blocks are examined
7714 * and register banking is fixed.
7718 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7719 pic16_FixRegisterBanking(pb);
7722 /* Phase 2 - Flow Analysis
7724 * In this phase, the pCode is partition into pCodeFlow
7725 * blocks. The flow blocks mark the points where a continuous
7726 * stream of instructions changes flow (e.g. because of
7727 * a call or goto or whatever).
7730 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7731 pic16_BuildFlow(pb);
7734 /* Phase 2 - Flow Analysis - linking flow blocks
7736 * In this phase, the individual flow blocks are examined
7737 * to determine their order of excution.
7740 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7744 if (pic16_options.opt_flags & OF_OPTIMIZE_DF) {
7745 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7746 pic16_createDF (pb);
7747 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
7748 pic16_vcg_dump_default (pb);
7750 //pic16_destructDF (pb);
7754 if (0) releaseStack (); // releasing is costly...
7758 /* Phase 3 - Flow Analysis - Flow Tree
7760 * In this phase, the individual flow blocks are examined
7761 * to determine their order of execution.
7764 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7765 pic16_BuildFlowTree(pb);
7768 /* Phase x - Flow Analysis - Used Banks
7770 * In this phase, the individual flow blocks are examined
7771 * to determine the Register Banks they use
7775 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7780 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7781 pic16_pCodeRegMapLiveRanges(pb);
7783 pic16_RemoveUnusedRegisters();
7784 pic16_removeUnusedRegistersDF ();
7786 // for(pb = the_pFile->pbHead; pb; pb = pb->next)
7787 pic16_pCodeRegOptimizeRegUsage(level);
7796 for(pb = the_pFile->pbHead; pb; pb = pb->next)
7801 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7804 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7805 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7806 pcflow = pcflow->next) {
7807 FillFlow(PCFL(pcflow));
7812 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7815 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
7816 (pcflow = pic16_findNextpCode(pcflow, PC_FLOW)) != NULL;
7817 pcflow = pcflow->next) {
7818 FlowStats(PCFL(pcflow));
7824 /* VR -- no need to analyze banking in flow, but left here :
7825 * 1. because it may be used in the future for other purposes
7826 * 2. because if omitted we'll miss some optimization done here
7828 * Perhaps I should rename it to something else
7831 /*-----------------------------------------------------------------*/
7832 /* pic16_AnalyzeBanking - Called after the memory addresses have been */
7833 /* assigned to the registers. */
7835 /*-----------------------------------------------------------------*/
7837 void pic16_AnalyzeBanking(void)
7841 /* Phase x - Flow Analysis - Used Banks
7843 * In this phase, the individual flow blocks are examined
7844 * to determine the Register Banks they use
7854 if(!the_pFile)return;
7856 if(!pic16_options.no_banksel) {
7857 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7858 // fprintf(stderr, "%s:%d: Fix register banking in pb= 0x%p\n", __FILE__, __LINE__, pb);
7859 pic16_FixRegisterBanking(pb);
7864 /*-----------------------------------------------------------------*/
7865 /* buildCallTree - Look at the flow and extract all of the calls. */
7866 /*-----------------------------------------------------------------*/
7867 static set *register_usage(pBlock *pb);
7869 static void buildCallTree(void )
7881 /* Now build the call tree.
7882 First we examine all of the pCodes for functions.
7883 Keep in mind that the function boundaries coincide
7884 with pBlock boundaries.
7886 The algorithm goes something like this:
7887 We have two nested loops. The outer loop iterates
7888 through all of the pBlocks/functions. The inner
7889 loop iterates through all of the pCodes for
7890 a given pBlock. When we begin iterating through
7891 a pBlock, the variable pc_fstart, pCode of the start
7892 of a function, is cleared. We then search for pCodes
7893 of type PC_FUNCTION. When one is encountered, we
7894 initialize pc_fstart to this and at the same time
7895 associate a new pBranch object that signifies a
7896 branch entry. If a return is found, then this signifies
7897 a function exit point. We'll link the pCodes of these
7898 returns to the matching pc_fstart.
7900 When we're done, a doubly linked list of pBranches
7901 will exist. The head of this list is stored in
7902 `the_pFile', which is the meta structure for all
7903 of the pCode. Look at the pic16_printCallTree function
7904 on how the pBranches are linked together.
7907 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7908 pCode *pc_fstart=NULL;
7909 for(pc = pb->pcHead; pc; pc = pc->next) {
7911 if(isPCI(pc) && pc_fstart) {
7912 if(PCI(pc)->is2MemOp) {
7913 r = pic16_getRegFromInstruction2(pc);
7914 if(r && !strcmp(r->name, "POSTDEC1"))
7915 PCF(pc_fstart)->stackusage++;
7917 r = pic16_getRegFromInstruction(pc);
7918 if(r && !strcmp(r->name, "PREINC1"))
7919 PCF(pc_fstart)->stackusage--;
7924 if (PCF(pc)->fname) {
7927 sprintf(buf, "%smain", port->fun_prefix);
7928 if(STRCASECMP(PCF(pc)->fname, buf) == 0) {
7929 //fprintf(stderr," found main \n");
7930 pb->cmemmap = NULL; /* FIXME do we need to free ? */
7934 pbr = Safe_calloc(1,sizeof(pBranch));
7935 pbr->pc = pc_fstart = pc;
7938 the_pFile->functions = pic16_pBranchAppend(the_pFile->functions,pbr);
7940 // Here's a better way of doing the same:
7941 addSet(&pb->function_entries, pc);
7944 // Found an exit point in a function, e.g. return
7945 // (Note, there may be more than one return per function)
7947 pBranchLink(PCF(pc_fstart), PCF(pc));
7949 addSet(&pb->function_exits, pc);
7951 } else if(isCALL(pc)) {
7952 addSet(&pb->function_calls,pc);
7959 /* This is not needed because currently all register used
7960 * by a function are stored in stack -- VR */
7962 /* Re-allocate the registers so that there are no collisions
7963 * between local variables when one function call another */
7966 // pic16_deallocateAllRegs();
7968 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
7976 /*-----------------------------------------------------------------*/
7977 /* pic16_AnalyzepCode - parse the pCode that has been generated and form */
7978 /* all of the logical connections. */
7980 /* Essentially what's done here is that the pCode flow is */
7982 /*-----------------------------------------------------------------*/
7984 void pic16_AnalyzepCode(char dbName)
7995 /* Phase 1 - Register allocation and peep hole optimization
7997 * The first part of the analysis is to determine the registers
7998 * that are used in the pCode. Once that is done, the peep rules
7999 * are applied to the code. We continue to loop until no more
8000 * peep rule optimizations are found (or until we exceed the
8001 * MAX_PASSES threshold).
8003 * When done, the required registers will be determined.
8009 DFPRINTF((stderr," Analyzing pCode: PASS #%d\n",i+1));
8010 //fprintf(stderr," Analyzing pCode: PASS #%d\n",i+1);
8012 /* First, merge the labels with the instructions */
8013 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8014 if('*' == dbName || getpBlock_dbName(pb) == dbName) {
8016 DFPRINTF((stderr," analyze and merging block %c\n",dbName));
8017 //fprintf(stderr," analyze and merging block %c\n",dbName);
8018 pic16_pBlockMergeLabels(pb);
8021 DFPRINTF((stderr," skipping block analysis dbName=%c blockname=%c\n",dbName,getpBlock_dbName));
8026 changes = OptimizepCode(dbName);
8029 } while(changes && (i++ < MAX_PASSES));
8036 /* convert a series of movff's of local regs to stack, with a single call to
8037 * a support functions which does the same thing via loop */
8038 static void pic16_convertLocalRegs2Support(pCode *pcstart, pCode *pcend, int count, regs *r, int entry)
8042 char *fname[]={"__lr_store", "__lr_restore"};
8044 // pc = pic16_newpCode(POC_CALL, pic16_popGetFromString( (entry?fname[0]:fname[1]) ));
8046 pct = pic16_findNextInstruction(pcstart->next);
8049 pct = pc->next; //pic16_findNextInstruction(pc->next);
8050 // pc->print(stderr, pc);
8051 if(isPCI(pc) && PCI(pc)->label) {
8052 pbr = PCI(pc)->label;
8053 while(pbr && pbr->pc) {
8054 PCI(pcstart)->label = pic16_pBranchAppend(PCI(pcstart)->label, pbr);
8058 // pc->print(stderr, pc);
8060 pc->prev->next = pct;
8061 pct->prev = pc->prev;
8065 } while ((pc) && (pc != pcend));
8067 /* unlink movff instructions */
8068 pcstart->next = pcend;
8069 pcend->prev = pcstart;
8073 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8074 // pic16_popCopyReg(&pic16_pc_fsr0l), pic16_popCopyReg(pic16_framepnt_lo)))); pc = pct;
8077 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_LFSR, pic16_popGetLit2(0, pic16_popGetWithString(r->name)))); pc = pct;
8078 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_MOVLW, pic16_popGetLit( count ))); pc = pct;
8079 pic16_pCodeInsertAfter(pc, pct=pic16_newpCode(POC_CALL, pic16_popGetWithString( fname[ (entry==1?0:1) ] ))); pc = pct;
8082 // pic16_pCodeInsertAfter(pc, pct = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
8083 // pic16_popCopyReg(pic16_framepnt_lo), pic16_popCopyReg(&pic16_pc_fsr0l)))); pc = pct;
8090 sym = newSymbol( fname[ entry?0:1 ], 0 );
8091 strcpy(sym->rname, fname[ entry?0:1 ]);
8092 checkAddSym(&externs, sym);
8094 // fprintf(stderr, "%s:%d adding extern symbol %s in externs\n", __FILE__, __LINE__, fname[ entry?0:1 ]);
8099 /*-----------------------------------------------------------------*/
8100 /* OptimizeLocalRegs - turn sequence of MOVFF instructions for */
8101 /* local registers to a support function call */
8102 /*-----------------------------------------------------------------*/
8103 void pic16_OptimizeLocalRegs(void)
8108 pCodeOpLocalReg *pclr;
8111 regs *r, *lastr=NULL, *firstr=NULL;
8112 pCode *pcstart=NULL, *pcend=NULL;
8117 * local_regs begin mark
8118 * MOVFF r0x01, POSTDEC1
8119 * MOVFF r0x02, POSTDEC1
8122 * MOVFF r0x0n, POSTDEC1
8123 * local_regs end mark
8125 * convert the above to the below:
8126 * MOVLW starting_register_index
8128 * MOVLW register_count
8129 * call __save_registers_in_stack
8135 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8136 inRegCount = regCount = 0;
8137 firstr = lastr = NULL;
8138 for(pc = pb->pcHead; pc; pc = pc->next) {
8140 /* hold current function name */
8141 if(pc && isPCF(pc))curFunc = PCF(pc)->fname;
8143 if(pc && (pc->type == PC_INFO)) {
8146 if(pci->type == INF_LOCALREGS) {
8147 pclr = PCOLR(pci->oper1);
8149 if((pclr->type == LR_ENTRY_BEGIN)
8150 || (pclr->type == LR_ENTRY_END))inEntry = 1;
8153 switch(pclr->type) {
8154 case LR_ENTRY_BEGIN:
8156 inRegCount = 1; regCount = 0;
8157 pcstart = pc; //pic16_findNextInstruction(pc->next);
8158 firstr = lastr = NULL;
8164 pcend = pc; //pic16_findPrevInstruction(pc->prev);
8167 if(curFunc && inWparamList(curFunc+1)) {
8168 fprintf(stderr, "sdcc: %s: warning: disabling lr-support for functionn %s\n",
8172 pic16_convertLocalRegs2Support(pcstart, pcend, regCount,
8177 firstr = lastr = NULL;
8181 if(inRegCount == -1) {
8182 // fprintf(stderr, "%s:%d registers used [%s] %d\n", __FILE__, __LINE__, inEntry?"entry":"exit", regCount);
8188 if(isPCI(pc) && (PCI(pc)->op == POC_MOVFF) && (inRegCount == 1)) {
8190 r = pic16_getRegFromInstruction(pc);
8192 r = pic16_getRegFromInstruction2(pc);
8193 if(r && (r->type == REG_GPR) && (r->pc_type == PO_GPR_TEMP)) {
8194 if(!firstr)firstr = r;
8196 // fprintf(stderr, "%s:%d\t%s\t%i\t%d/%d\n", __FILE__, __LINE__, r->name, r->rIdx);
8208 /*-----------------------------------------------------------------*/
8209 /* ispCodeFunction - returns true if *pc is the pCode of a */
8211 /*-----------------------------------------------------------------*/
8212 static bool ispCodeFunction(pCode *pc)
8215 if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
8221 /*-----------------------------------------------------------------*/
8222 /* findFunction - Search for a function by name (given the name) */
8223 /* in the set of all functions that are in a pBlock */
8224 /* (note - I expect this to change because I'm planning to limit */
8225 /* pBlock's to just one function declaration */
8226 /*-----------------------------------------------------------------*/
8227 static pCode *findFunction(char *fname)
8234 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8236 pc = setFirstItem(pb->function_entries);
8239 if((pc->type == PC_FUNCTION) &&
8241 (strcmp(fname, PCF(pc)->fname)==0))
8244 pc = setNextItem(pb->function_entries);
8252 static void MarkUsedRegisters(set *regset)
8257 for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
8258 // fprintf(stderr, "marking register = %s\t", r1->name);
8259 r2 = pic16_regWithIdx(r1->rIdx);
8260 // fprintf(stderr, "to register = %s\n", r2->name);
8266 static void pBlockStats(FILE *of, pBlock *pb)
8272 if(!pic16_pcode_verbose)return;
8274 fprintf(of,";***\n; pBlock Stats: dbName = %c\n;***\n",getpBlock_dbName(pb));
8276 // for now just print the first element of each set
8277 pc = setFirstItem(pb->function_entries);
8279 fprintf(of,";entry: ");
8282 pc = setFirstItem(pb->function_exits);
8284 fprintf(of,";has an exit\n");
8288 pc = setFirstItem(pb->function_calls);
8290 fprintf(of,";functions called:\n");
8293 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8294 fprintf(of,"; %s\n",pic16_get_op_from_instruction(PCI(pc)));
8296 pc = setNextItem(pb->function_calls);
8300 r = setFirstItem(pb->tregisters);
8302 int n = elementsInSet(pb->tregisters);
8304 fprintf(of,";%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
8307 fprintf(of, "; %s\n",r->name);
8308 r = setNextItem(pb->tregisters);
8312 fprintf(of, "; uses %d bytes of stack\n", 1+ elementsInSet(pb->tregisters));
8315 /*-----------------------------------------------------------------*/
8316 /*-----------------------------------------------------------------*/
8318 static void sequencepCode(void)
8324 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8326 pb->seq = GpCodeSequenceNumber+1;
8328 for( pc = pb->pcHead; pc; pc = pc->next)
8329 pc->seq = ++GpCodeSequenceNumber;
8335 /*-----------------------------------------------------------------*/
8336 /*-----------------------------------------------------------------*/
8337 static set *register_usage(pBlock *pb)
8340 set *registers=NULL;
8341 set *registersInCallPath = NULL;
8343 /* check recursion */
8345 pc = setFirstItem(pb->function_entries);
8352 if(pc->type != PC_FUNCTION)
8353 fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
8355 pc = setFirstItem(pb->function_calls);
8356 for( ; pc; pc = setNextItem(pb->function_calls)) {
8358 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8359 char *dest = pic16_get_op_from_instruction(PCI(pc));
8361 pcn = findFunction(dest);
8363 registersInCallPath = register_usage(pcn->pb);
8365 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8370 pBlockStats(stderr,pb); // debug
8373 // Mark the registers in this block as used.
8375 MarkUsedRegisters(pb->tregisters);
8376 if(registersInCallPath) {
8377 /* registers were used in the functions this pBlock has called */
8378 /* so now, we need to see if these collide with the ones we are */
8381 regs *r1,*r2, *newreg;
8383 DFPRINTF((stderr,"comparing registers\n"));
8385 r1 = setFirstItem(registersInCallPath);
8388 r2 = setFirstItem(pb->tregisters);
8390 while(r2 && (r1->type != REG_STK)) {
8392 if(r2->rIdx == r1->rIdx) {
8393 newreg = pic16_findFreeReg(REG_GPR);
8397 DFPRINTF((stderr,"Bummer, no more registers.\n"));
8401 DFPRINTF((stderr,"Cool found register collision nIdx=%d moving to %d\n",
8402 r1->rIdx, newreg->rIdx));
8403 r2->rIdx = newreg->rIdx;
8404 //if(r2->name) Safe_free(r2->name);
8406 r2->name = Safe_strdup(newreg->name);
8410 newreg->wasUsed = 1;
8412 r2 = setNextItem(pb->tregisters);
8415 r1 = setNextItem(registersInCallPath);
8418 /* Collisions have been resolved. Now free the registers in the call path */
8419 r1 = setFirstItem(registersInCallPath);
8421 if(r1->type != REG_STK) {
8422 newreg = pic16_regWithIdx(r1->rIdx);
8425 r1 = setNextItem(registersInCallPath);
8429 // MarkUsedRegisters(pb->registers);
8431 registers = unionSets(pb->tregisters, registersInCallPath, THROW_NONE);
8434 DFPRINTF((stderr,"returning regs\n"));
8436 DFPRINTF((stderr,"not returning regs\n"));
8438 DFPRINTF((stderr,"pBlock after register optim.\n"));
8439 pBlockStats(stderr,pb); // debug
8445 /*-----------------------------------------------------------------*/
8446 /* pct2 - writes the call tree to a file */
8448 /*-----------------------------------------------------------------*/
8449 static void pct2(FILE *of,pBlock *pb,int indent,int usedstack)
8453 // set *registersInCallPath = NULL;
8459 fprintf(of, "recursive function\n");
8460 return; //recursion ?
8463 pc = setFirstItem(pb->function_entries);
8470 for(i=0;i<indent;i++) // Indentation
8474 if(pc->type == PC_FUNCTION) {
8475 usedstack += PCF(pc)->stackusage;
8476 fprintf(of,"%s (stack: %i)\n",PCF(pc)->fname, usedstack);
8477 } else return; // ???
8480 pc = setFirstItem(pb->function_calls);
8481 for( ; pc; pc = setNextItem(pb->function_calls)) {
8483 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
8484 char *dest = pic16_get_op_from_instruction(PCI(pc));
8486 pcn = findFunction(dest);
8488 pct2(of,pcn->pb,indent+1, usedstack); // + PCF(pcn)->stackusage);
8490 fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8498 /*-----------------------------------------------------------------*/
8499 /* pic16_printCallTree - writes the call tree to a file */
8501 /*-----------------------------------------------------------------*/
8503 void pic16_printCallTree(FILE *of)
8515 fprintf(of, "\npBlock statistics\n");
8516 for(pb = the_pFile->pbHead; pb; pb = pb->next )
8520 fprintf(of,"Call Tree\n");
8521 pbr = the_pFile->functions;
8525 if(!ispCodeFunction(pc))
8526 fprintf(of,"bug in call tree");
8529 fprintf(of,"Function: %s\n", PCF(pc)->fname);
8531 while(pc->next && !ispCodeFunction(pc->next)) {
8533 if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
8534 fprintf(of,"\t%s\n",pic16_get_op_from_instruction(PCI(pc)));
8542 fprintf(of,"\n**************\n\na better call tree\n");
8543 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8548 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8549 fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
8555 /*-----------------------------------------------------------------*/
8557 /*-----------------------------------------------------------------*/
8559 static void InlineFunction(pBlock *pb)
8567 pc = setFirstItem(pb->function_calls);
8569 for( ; pc; pc = setNextItem(pb->function_calls)) {
8572 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8578 if(pcn && isPCF(pcn) && (PCF(pcn)->ncalled == 0)) { /* change 0 to 1 to enable inlining */
8580 //fprintf(stderr,"Cool can inline:\n");
8581 //pcn->print(stderr,pcn);
8583 //fprintf(stderr,"recursive call Inline\n");
8584 InlineFunction(pcn->pb);
8585 //fprintf(stderr,"return from recursive call Inline\n");
8588 At this point, *pc points to a CALL mnemonic, and
8589 *pcn points to the function that is being called.
8591 To in-line this call, we need to remove the CALL
8592 and RETURN(s), and link the function pCode in with
8598 /* Remove the CALL */
8602 /* remove callee pBlock from the pBlock linked list */
8603 removepBlock(pcn->pb);
8611 /* Remove the Function pCode */
8612 pct = pic16_findNextInstruction(pcn->next);
8614 /* Link the function with the callee */
8615 pc->next = pcn->next;
8616 pcn->next->prev = pc;
8618 /* Convert the function name into a label */
8620 pbr = Safe_calloc(1,sizeof(pBranch));
8621 pbr->pc = pic16_newpCodeLabel(PCF(pcn)->fname, -1);
8623 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,pbr);
8624 PCI(pct)->label = pic16_pBranchAppend(PCI(pct)->label,PCI(pc_call)->label);
8626 /* turn all of the return's except the last into goto's */
8627 /* check case for 2 instruction pBlocks */
8628 pce = pic16_findNextInstruction(pcn->next);
8630 pCode *pce_next = pic16_findNextInstruction(pce->next);
8632 if(pce_next == NULL) {
8633 /* found the last return */
8634 pCode *pc_call_next = pic16_findNextInstruction(pc_call->next);
8636 //fprintf(stderr,"found last return\n");
8637 //pce->print(stderr,pce);
8638 pce->prev->next = pc_call->next;
8639 pc_call->next->prev = pce->prev;
8640 PCI(pc_call_next)->label = pic16_pBranchAppend(PCI(pc_call_next)->label,
8650 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8656 /*-----------------------------------------------------------------*/
8658 /*-----------------------------------------------------------------*/
8660 void pic16_InlinepCode(void)
8669 if(!functionInlining)
8672 /* Loop through all of the function definitions and count the
8673 * number of times each one is called */
8674 //fprintf(stderr,"inlining %d\n",__LINE__);
8676 for(pb = the_pFile->pbHead; pb; pb = pb->next) {
8678 pc = setFirstItem(pb->function_calls);
8680 for( ; pc; pc = setNextItem(pb->function_calls)) {
8683 pCode *pcn = findFunction(pic16_get_op_from_instruction(PCI(pc)));
8684 if(pcn && isPCF(pcn)) {
8685 PCF(pcn)->ncalled++;
8688 fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
8693 //fprintf(stderr,"inlining %d\n",__LINE__);
8695 /* Now, Loop through the function definitions again, but this
8696 * time inline those functions that have only been called once. */
8698 InlineFunction(the_pFile->pbHead);
8699 //fprintf(stderr,"inlining %d\n",__LINE__);
8701 for(pb = the_pFile->pbHead; pb; pb = pb->next)
8706 char *pic_optype_names[]={
8707 "PO_NONE", // No operand e.g. NOP
8708 "PO_W", // The working register (as a destination)
8709 "PO_WREG", // The working register (as a file register)
8710 "PO_STATUS", // The 'STATUS' register
8711 "PO_BSR", // The 'BSR' register
8712 "PO_FSR0", // The "file select register" (in PIC18 family it's one
8714 "PO_INDF0", // The Indirect register
8715 "PO_INTCON", // Interrupt Control register
8716 "PO_GPR_REGISTER", // A general purpose register
8717 "PO_GPR_BIT", // A bit of a general purpose register
8718 "PO_GPR_TEMP", // A general purpose temporary register
8719 "PO_SFR_REGISTER", // A special function register (e.g. PORTA)
8720 "PO_PCL", // Program counter Low register
8721 "PO_PCLATH", // Program counter Latch high register
8722 "PO_PCLATU", // Program counter Latch upper register
8723 "PO_PRODL", // Product Register Low
8724 "PO_PRODH", // Product Register High
8725 "PO_LITERAL", // A constant
8726 "PO_REL_ADDR", // A relative address
8727 "PO_IMMEDIATE", // (8051 legacy)
8728 "PO_DIR", // Direct memory (8051 legacy)
8729 "PO_CRY", // bit memory (8051 legacy)
8730 "PO_BIT", // bit operand.
8731 "PO_STR", // (8051 legacy)
8733 "PO_WILD" // Wild card operand in peep optimizer
8737 char *dumpPicOptype(PIC_OPTYPE type)
8739 return (pic_optype_names[ type ]);
8743 /*** BEGIN of stuff belonging to the BANKSEL optimization ***/
8746 #define MAX_COMMON_BANK_SIZE 32
8747 #define FIRST_PSEUDO_BANK_NR 1000
8749 hTab *sym2bank = NULL; // <OPERAND NAME> --> <PSEUDO BANK NR>
8750 hTab *bank2sym = NULL; // <PSEUDO BANK NR> --> <OPERAND NAME>
8751 hTab *coerce = NULL; // <PSEUDO BANK NR> --> <&PSEUDOBANK>
8754 typedef enum { INVALID_BANK = -1, UNKNOWN_BANK = -2, FIXED_BANK = -3 } pseudoBankNr;
8757 pseudoBankNr bank; // number assigned to this pseudoBank
8758 unsigned int size; // number of operands assigned to this bank
8759 unsigned int ref; // number of symbols referring to this pseudoBank (for garbage collection)
8762 /*----------------------------------------------------------------------*/
8763 /* hashSymbol - hash function used to map SYMBOLs (or operands) to ints */
8764 /*----------------------------------------------------------------------*/
8765 unsigned int hashSymbol (const char *str)
8767 unsigned int res = 0;
8772 res = (res << 4) | (res >> (8 * sizeof(unsigned int) - 4));
8779 /*-----------------------------------------------------------------------*/
8780 /* compareSymbol - return 1 iff sym1 equals sym2 */
8781 /*-----------------------------------------------------------------------*/
8782 int compareSymbol (const void *sym1, const void *sym2)
8784 char *s1 = (char*) sym1;
8785 char *s2 = (char*) sym2;
8787 return (strcmp (s1,s2) == 0);
8790 /*-----------------------------------------------------------------------*/
8791 /* comparePre - return 1 iff p1 == p2 */
8792 /*-----------------------------------------------------------------------*/
8793 int comparePtr (const void *p1, const void *p2)
8798 /*----------------------------------------------------------*/
8799 /* getSymbolFromOperand - return a pointer to the symbol in */
8800 /* the given operand and its length */
8801 /*----------------------------------------------------------*/
8802 char *getSymbolFromOperand (char *op, unsigned int *len)
8807 if (!op) return NULL;
8809 // we recognize two forms of operands: SYMBOL and (SYMBOL + offset)
8811 if (*sym == '(') sym++;
8814 while (((*curr >= 'A') && (*curr <= 'Z'))
8815 || ((*curr >= 'a') && (*curr <= 'z'))
8816 || ((curr != sym) && (*curr >= '0') && (*curr <= '9'))
8817 || (*curr == '_')) {
8818 // find end of symbol [A-Za-z_]?[A-Za-z0-9]*
8826 /*--------------------------------------------------------------------------*/
8827 /* getSymFromBank - get (one) name of a symbol assigned to the given bank */
8828 /*--------------------------------------------------------------------------*/
8829 char *getSymFromBank (pseudoBankNr bank)
8833 if (bank < 0) return "<INVALID BANK NR>";
8834 return hTabFindByKey (bank2sym, bank % bank2sym->size, (void *) bank, &comparePtr);
8837 /*-----------------------------------------------------------------------*/
8838 /* getPseudoBsrFromOperand - maps a string to its corresponding pseudo */
8839 /* bank number (uses hTab sym2bank), if the */
8840 /* symbol is not yet assigned a pseudo bank it */
8841 /* is assigned one here */
8842 /*-----------------------------------------------------------------------*/
8843 pseudoBankNr getPseudoBankNrFromOperand (const char *op)
8845 static pseudoBankNr next_bank = FIRST_PSEUDO_BANK_NR;
8851 hash = hashSymbol (op) % sym2bank->size;
8852 bank = (pseudoBankNr) hTabFindByKey (sym2bank, hash, op, &compareSymbol);
8853 if (bank == (pseudoBankNr)NULL) bank = UNKNOWN_BANK;
8855 if (bank == UNKNOWN_BANK) {
8856 // create a pseudo bank for the operand
8858 hTabAddItemLong (&sym2bank, hash, (char *)op, (void *)bank);
8859 hTabAddItemLong (&bank2sym, bank, (void *) bank, (void *)op);
8860 getOrAddGNode (adj, NULL, bank); // adds the node if it does not exist yet
8861 //fprintf (stderr, "%s:%d: adding %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8863 //fprintf (stderr, "%s:%d: found %s with hash %u in bank %u\n", __FUNCTION__, __LINE__, op, hash, bank);
8871 /*--------------------------------------------------------------------*/
8872 /* isBanksel - check whether the given pCode is a BANKSEL instruction */
8873 /*--------------------------------------------------------------------*/
8874 int isBanksel (pCode *pc)
8878 if (isPCI(pc) && (PCI(pc)->op == POC_BANKSEL || PCI(pc)->op == POC_MOVLB)) {
8879 // BANKSEL <variablename> or MOVLB <banknr>
8880 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8884 // check for inline assembler BANKSELs
8885 if (isPCAD(pc) && PCAD(pc)->directive && (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0 ||
8886 STRCASECMP(PCAD(pc)->directive,"MOVLB") == 0)) {
8887 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8891 // assume pc is no BANKSEL instruction
8895 /*---------------------------------------------------------------------------------*/
8896 /* invalidatesBSR - check whether the pCodeInstruction passed in modifies the BSR */
8897 /* This method can not guarantee to find all modifications of the */
8898 /* BSR (e.g. via INDirection registers) but covers all compiler */
8899 /* generated plus some cases. */
8900 /*---------------------------------------------------------------------------------*/
8901 int invalidatesBSR(pCode *pc)
8903 // assembler directives invalidate BSR (well, they might, we don't know)
8904 if (isPCAD(pc)) return 1;
8906 // only ASMDIRs and pCodeInstructions can invalidate BSR
8907 if (!isPCI(pc)) return 0;
8909 // we have a pCodeInstruction
8911 // check for BSR modifying instructions
8912 switch (PCI(pc)->op) {
8916 case POC_RETFIE: // might be used as CALL replacement
8917 case POC_RETLW: // might be used as CALL replacement
8918 case POC_RETURN: // might be used as CALL replacement
8923 default: // other instruction do not change BSR unless BSR is an explicit operand!
8924 // TODO: check for BSR as an explicit operand (e.g. INCF BSR,F), which should be rather unlikely...!
8928 // no change of BSR possible/probable
8932 /*------------------------------------------------------------*/
8933 /* getBankFromBanksel - return the pseudo bank nr assigned to */
8934 /* the symbol referenced in this BANKSEL */
8935 /*------------------------------------------------------------*/
8936 pseudoBankNr getBankFromBanksel (pCode *pc)
8939 int data = (int)NULL;
8941 if (!pc) return INVALID_BANK;
8943 if (isPCAD(pc) && PCAD(pc)->directive) {
8944 if (STRCASECMP(PCAD(pc)->directive,"BANKSEL") == 0) {
8945 // get symbolname from PCAD(pc)->arg
8946 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8947 sym = PCAD(pc)->arg;
8948 data = getPseudoBankNrFromOperand (sym);
8949 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8950 } else if (STRCASECMP(PCAD(pc)->directive,"MOVLB")) {
8951 // get (literal) bank number from PCAD(pc)->arg
8952 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCAD(pc)->directive, PCAD(pc)->arg);
8953 assert (0 && "not yet implemented - turn off banksel optimization for now");
8955 } else if (isPCI(pc)) {
8956 if (PCI(pc)->op == POC_BANKSEL) {
8957 // get symbolname from PCI(pc)->pcop->name (?)
8958 //fprintf (stderr, "%s:%d: BANKSEL found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8959 sym = PCI(pc)->pcop->name;
8960 data = getPseudoBankNrFromOperand (sym);
8961 //fprintf (stderr, "symbol: %s, data=%i\n", sym, data);
8962 } else if (PCI(pc)->op == POC_MOVLB) {
8963 // get (literal) bank number from PCI(pc)->pcop->name
8964 fprintf (stderr, "%s:%d: MOVLB found: %s %s\n", __FUNCTION__, __LINE__, PCI(pc)->mnemonic, PCI(pc)->pcop->name);
8965 assert (0 && "not yet implemented - turn off banksel optimization for now");
8970 // no assigned bank could be found
8971 return UNKNOWN_BANK;
8976 /*------------------------------------------------------------------------------*/
8977 /* getEffectiveBank - resolves the currently assigned effective pseudo bank nr */
8978 /*------------------------------------------------------------------------------*/
8979 pseudoBankNr getEffectiveBank (pseudoBankNr bank)
8983 if (bank < FIRST_PSEUDO_BANK_NR) return bank;
8986 //fprintf (stderr, "%s:%d: bank=%d\n", __FUNCTION__, __LINE__, bank);
8987 data = (pseudoBank *) hTabFindByKey (coerce, bank % coerce->size, (void *) bank, &comparePtr);
8989 if (data->bank != bank)
8996 //fprintf (stderr, "%s:%d: effective bank=%d\n", __FUNCTION__, __LINE__, bank);
9000 /*------------------------------------------------------------------*/
9001 /* attachBsrInfo2pBlock - create a look-up table as to which pseudo */
9002 /* bank is selected at a given pCode */
9003 /*------------------------------------------------------------------*/
9005 /* Create a graph with pseudo banks as its nodes and switches between
9006 * these as edges (with the edge weight representing the absolute
9007 * number of BANKSELs from one to the other).
9008 * Removes redundand BANKSELs instead iff mod == 1.
9009 * BANKSELs update the pseudo BSR, labels invalidate the current BSR
9010 * value (setting it to 0=UNNKOWN), (R)CALLs also invalidate the
9012 * TODO: check ALL instructions operands if they modify BSR directly...
9014 * pb - the pBlock to annotate
9015 * mod - select either graph creation (0) or BANKSEL removal (1)
9017 unsigned int attachBsrInfo2pBlock (pBlock *pb, int mod)
9019 pCode *pc, *pc_next;
9020 unsigned int prevBSR = UNKNOWN_BANK, pseudoBSR = UNKNOWN_BANK;
9021 int isBankselect = 0;
9022 unsigned int banksels=0;
9026 pc = pic16_findNextInstruction(pb->pcHead);
9028 isBankselect = isBanksel (pc);
9029 pc_next = pic16_findNextInstruction (pc->next);
9031 if (!hasNoLabel (pc)) {
9032 // we don't know our predecessors -- assume different BSRs
9033 prevBSR = UNKNOWN_BANK;
9034 pseudoBSR = UNKNOWN_BANK;
9035 //fprintf (stderr, "invalidated by label at "); pc->print (stderr, pc);
9038 // check if this is a BANKSEL instruction
9040 pseudoBSR = getEffectiveBank (getBankFromBanksel(pc));
9041 //fprintf (stderr, "BANKSEL via "); pc->print (stderr, pc);
9043 if (prevBSR == pseudoBSR && pseudoBSR >= 0) {
9044 //fprintf (stderr, "removing redundant "); pc->print (stderr, pc);
9045 if (1 || pic16_pcode_verbose) pic16_pCodeInsertAfter (pc->prev, pic16_newpCodeCharP("removed redundant BANKSEL"));
9046 pic16_unlinkpCode (pc);
9050 addGEdge2 (getOrAddGNode (adj, NULL, prevBSR), getOrAddGNode (adj, NULL, pseudoBSR), 1, 0);
9055 if (!isBankselect && invalidatesBSR(pc)) {
9056 // check if this instruction invalidates the pseudoBSR
9057 pseudoBSR = UNKNOWN_BANK;
9058 //fprintf (stderr, "invalidated via "); pc->print (stderr, pc);
9061 prevBSR = pseudoBSR;
9068 /*------------------------------------------------------------------------------------*/
9069 /* assignToSameBank - returns 0 on success or an error code */
9070 /* 1 - common bank would be too large */
9071 /* 2 - assignment to fixed (absolute) bank not performed */
9073 /* This functions assumes that unsplittable operands are already assigned to the same */
9074 /* bank (e.g. all objects being referenced as (SYMBOL + offset) must be in the same */
9075 /* bank so that we can make sure the bytes are laid out sequentially in memory) */
9076 /* TODO: Symbols with an abslute address must be handled specially! */
9077 /*------------------------------------------------------------------------------------*/
9078 int assignToSameBank (int bank0, int bank1, int doAbs)
9080 int eff0, eff1, dummy;
9081 pseudoBank *pbank0, *pbank1;
9084 eff0 = getEffectiveBank (bank0);
9085 eff1 = getEffectiveBank (bank1);
9087 //fprintf (stderr, "%s:%d: bank0=%d/%d, bank1=%d/%d, doAbs=%d\n", __FUNCTION__, __LINE__, bank0, eff0, bank1, eff1, doAbs);
9089 // nothing to do if already same bank
9090 if (eff0 == eff1) return 0;
9092 if (!doAbs && (eff0 < FIRST_PSEUDO_BANK_NR || eff1 < FIRST_PSEUDO_BANK_NR))
9095 // ensure eff0 < eff1
9097 // swap eff0 and eff1
9106 // now assign bank eff1 to bank eff0
9107 pbank0 = (pseudoBank *) hTabFindByKey (coerce, eff0 % coerce->size, (void *)((char*)0+eff0), &comparePtr);
9109 pbank0 = Safe_calloc (1, sizeof (pseudoBank));
9110 pbank0->bank = eff0;
9113 hTabAddItemLong (&coerce, eff0 % coerce->size, (void *)((char*)0+eff0), (void *) pbank0);
9117 hitem = hTabSearch (coerce, eff1 % coerce->size);
9118 while (hitem && hitem->pkey != (void *)((char*)0+eff1))
9119 hitem = hitem->next;
9121 if (hitem) pbank1 = (pseudoBank *) hitem->item;
9124 fprintf (stderr, "bank #%d/%d & bank #%d/%d --> bank #%d: %u (%s & %s)\n", bank0, eff0, bank1, eff1,
9125 pbank0->bank, pbank0->size,
9126 getSymFromBank (eff0), getSymFromBank (eff1));
9130 if (pbank0->size + pbank1->size > MAX_COMMON_BANK_SIZE) {
9132 fprintf (stderr, "bank #%d: %u, bank #%d: %u --> bank #%d': %u > %u (%s,%s)\n",
9133 pbank0->bank, pbank0->size, pbank1->bank, pbank1->size,
9134 pbank0->bank, pbank0->size + pbank1->size, MAX_COMMON_BANK_SIZE,
9135 getSymFromBank (pbank0->bank), getSymFromBank (pbank1->bank));
9139 pbank0->size += pbank1->size;
9141 if (pbank1->ref == 0) Safe_free (pbank1);
9147 hitem->item = pbank0;
9149 hTabAddItemLong (&coerce, eff1 % coerce->size, (void *)((char*)0+eff1), (void *) pbank0);
9152 //fprintf (stderr, "%s:%d: leaving.\n", __FUNCTION__, __LINE__);
9157 /*----------------------------------------------------------------*/
9158 /* mergeGraphNodes - combines two nodes into one and modifies all */
9159 /* edges to and from the nodes accordingly */
9160 /* This method needs complete backedges, i.e. if (A,B) is an edge */
9161 /* then also (B,A) must be an edge (possibly with weight 0). */
9162 /*----------------------------------------------------------------*/
9163 void mergeGraphNodes (GraphNode *node1, GraphNode *node2)
9165 GraphEdge *edge, *backedge, *nextedge;
9169 assert (node1 && node2);
9170 assert (node1 != node2);
9172 // add all edges starting at node2 to node1
9175 nextedge = edge->next;
9177 backedge = getGEdge (node, node2);
9179 backweight = backedge->weight;
9182 // insert edges (node1,node) and (node,node1)
9183 addGEdge2 (node1, node, edge->weight, backweight);
9184 // remove edges (node, node2) and (node2, node)
9185 remGEdge (node2, node);
9186 remGEdge (node, node2);
9190 // now node2 should not be referenced by any other GraphNode...
9191 //remGNode (adj, node2->data, node2->hash);
9194 /*----------------------------------------------------------------*/
9195 /* showGraph - dump the current BANKSEL graph as a node/edge list */
9196 /*----------------------------------------------------------------*/
9197 void showGraph (Graph *g)
9201 pseudoBankNr bankNr;
9208 bankNr = getEffectiveBank (node->hash);
9209 assert (bankNr >= 0);
9210 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9212 bankNr = pbank->bank;
9218 fprintf (stderr, "edges from %s (bank %u, size %u) to:\n", getSymFromBank (node->hash), bankNr, size);
9221 if (edge->weight > 0)
9222 fprintf (stderr, " %4u x %s\n", edge->weight, getSymFromBank (edge->node->hash));
9229 /*---------------------------------------------------------------*/
9230 /* pic16_OptimizeBanksel - remove redundant BANKSEL instructions */
9231 /*---------------------------------------------------------------*/
9232 void pic16_OptimizeBanksel ()
9234 GraphNode *node, *node1, *node1next;
9237 // needed for more effective bank assignment (needs adjusted pic16_emit_usection())
9238 GraphEdge *edge, *backedge;
9240 int maxWeight, weight, mergeMore, absMaxWeight;
9241 pseudoBankNr curr0, curr1;
9244 pseudoBankNr bankNr;
9245 char *base_symbol0, *base_symbol1;
9250 unsigned int bankselsTotal = 0, bankselsRemoved = 0;
9252 //fprintf (stderr, "%s:%s:%d: entered.\n", __FILE__, __FUNCTION__, __LINE__);
9254 if (!the_pFile || !the_pFile->pbHead) return;
9256 adj = newGraph (NULL);
9257 sym2bank = newHashTable ( 255 );
9258 bank2sym = newHashTable ( 255 );
9259 coerce = newHashTable ( 255 );
9261 // create graph of BANKSEL relationships (node = operands, edge (A,B) iff BANKSEL B follows BANKSEL A)
9262 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9263 bankselsTotal += attachBsrInfo2pBlock (pb, 0);
9267 // assign symbols with absolute addresses to their respective bank nrs
9268 set = pic16_fix_udata;
9269 for (reg = setFirstItem (set); reg; reg = setNextItem (set)) {
9270 bankNr = reg->address >> 8;
9271 node = getOrAddGNode (adj, NULL, bankNr);
9272 bankNr = (pseudoBankNr) getEffectiveBank (getPseudoBankNrFromOperand(reg->name));
9273 assignToSameBank (node->hash, bankNr, 1);
9275 assert (bankNr >= 0);
9276 pbank = (pseudoBank *) hTabFindByKey (coerce, bankNr % coerce->size, (void *) bankNr, &comparePtr);
9278 pbank = Safe_calloc (1, sizeof (pseudoBank));
9279 pbank->bank = reg->address >> 8; //FIXED_BANK;
9282 hTabAddItemLong (&coerce, bankNr % coerce->size, (void *) bankNr, pbank);
9284 assert (pbank->bank == (reg->address >> 8));
9285 pbank->bank = reg->address >> 8; //FIXED_BANK;
9287 //fprintf (stderr, "ABS: %s (%d bytes) at %x in bank %u\n", reg->name, reg->size, reg->address, bankNr);
9292 // assign operands referring to the same symbol (which is not given an absolute address) to the same bank
9293 //fprintf (stderr, "assign operands with the same symbol to the same bank\n");
9296 if (node->hash < 0) { node = node->next; continue; }
9297 base_symbol0 = getSymbolFromOperand (getSymFromBank (getEffectiveBank(node->hash)), &len0);
9300 if (node1->hash < 0) { node1 = node1->next; continue; }
9301 node1next = node1->next;
9302 base_symbol1 = getSymbolFromOperand (getSymFromBank (getEffectiveBank (node1->hash)), &len1);
9303 if (len0 == len1 && len0 > 0 && strncmp (base_symbol0, base_symbol1, len0) == 0) {
9304 // TODO: check for symbols with absolute addresses -- these might be placed across bank boundaries!
9305 //fprintf (stderr, "merging %s and %s\n", getSymFromBank (getEffectiveBank(node->hash)), getSymFromBank (getEffectiveBank(node1->hash)));
9306 if (assignToSameBank (node->hash, node1->hash, 0)) {
9307 fprintf (stderr, "%s(%d) == %s(%d)\n", base_symbol0, len0, base_symbol1, len1);
9308 assert (0 && "Could not assign a symbol to a bank!");
9310 mergeGraphNodes (node, node1);
9312 if (node->hash < node1->hash)
9313 mergeGraphNodes (node, node1);
9315 mergeGraphNodes (node1, node); // this removes node so node->next will fail...
9325 // >>> THIS ALSO NEEDS AN UPDATED pic16_emit_usection() TO REFLECT THE BANK ASSIGNMENTS <<<
9326 // assign tightly coupled operands to the same (pseudo) bank
9327 //fprintf (stderr, "assign tightly coupled operands to the same bank\n");
9335 curr0 = getEffectiveBank (node->hash);
9336 if (curr0 < 0) { node = node->next; continue; }
9339 assert (edge->src == node);
9340 backedge = getGEdge (edge->node, edge->src);
9341 weight = edge->weight + (backedge ? backedge->weight : 0);
9342 curr1 = getEffectiveBank (edge->node->hash);
9343 if (curr1 < 0) { edge = edge->next; continue; }
9345 // merging is only useful if the items are not assigned to the same bank already...
9346 if (curr0 != curr1 && weight > maxWeight) {
9347 if (maxWeight > absMaxWeight) absMaxWeight = maxWeight;
9356 if (maxWeight > 0) {
9358 fprintf (stderr, "%s:%d: merging (%4u) %d(%s) and %d(%s)\n", __FUNCTION__, __LINE__, maxWeight,
9359 max->src->hash, getSymFromBank (max->src->hash),
9360 max->node->hash, getSymFromBank (max->node->hash));
9363 node = getGNode (adj, max->src->data, max->src->hash);
9364 node1 = getGNode (adj, max->node->data, max->node->hash);
9366 if (0 == assignToSameBank (max->src->hash, max->node->hash, 0)) {
9367 if (max->src->hash < max->node->hash)
9368 mergeGraphNodes (node, node1);
9370 mergeGraphNodes (node1, node);
9372 remGEdge (node, node1);
9373 remGEdge (node1, node);
9384 // remove redundant BANKSELs
9385 //fprintf (stderr, "removing redundant BANKSELs\n");
9386 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
9387 bankselsRemoved += attachBsrInfo2pBlock (pb, 1);
9392 fprintf (stderr, "display graph\n");
9397 //fprintf (stderr, "%s:%s:%d: leaving, %u/%u BANKSELs removed...\n", __FILE__, __FUNCTION__, __LINE__, bankselsRemoved, bankselsTotal);
9400 /*** END of stuff belonging to the BANKSEL optimization ***/
9404 /*** BEGIN of helpers for pCode dataflow optimizations ***/
9406 typedef unsigned int symbol_t;
9407 typedef unsigned int valnum_t;
9408 //typedef unsigned int hash_t;
9411 #define INT_TO_PTR(x) (((char *) 0) + (x))
9415 #define PTR_TO_INT(x) (((char *)(x)) - ((char *) 0))
9419 static unsigned int pic16_df_removed_pcodes = 0;
9420 static unsigned int pic16_df_saved_bytes = 0;
9421 static unsigned int df_findall_sameflow = 0;
9422 static unsigned int df_findall_otherflow = 0;
9423 static unsigned int df_findall_in_vals = 0;
9425 static void pic16_df_stats () {
9427 if (pic16_debug_verbose || pic16_pcode_verbose) {
9428 fprintf (stderr, "PIC16: dataflow analysis removed %u instructions (%u bytes)\n", pic16_df_removed_pcodes, pic16_df_saved_bytes);
9429 fprintf (stderr, "findAll: same flow %u (%u in_vals), other flow %u\n", df_findall_sameflow, df_findall_in_vals, df_findall_otherflow);
9430 //pic16_df_removed_pcodes = pic16_df_saved_bytes = 0;
9434 /* Remove a pCode iff possible:
9435 * - previous pCode is no SKIP
9437 * Returns 1 iff the pCode has been removed, 0 otherwise. */
9438 static int pic16_safepCodeUnlink (pCode *pc, char *comment) {
9439 pCode *pcprev, *pcnext;
9440 char buf[256], *total=NULL;
9443 if (!comment) comment = "=DF= pCode removed by pic16_safepCodeUnlink";
9445 pcprev = pic16_findPrevInstruction (pc->prev);
9446 pcnext = pic16_findNextInstruction (pc->next);
9448 /* if previous instruction is a skip -- do not remove */
9449 if (pcprev && isPCI_SKIP(pcprev)) return 0;
9451 /* move labels to next instruction (if possible) */
9452 if (PCI(pc)->label && !pcnext) return 0;
9454 if (PCI(pc)->label) {
9455 //fprintf (stderr, "%s: moving label(s)\n", __FUNCTION__);
9456 //pc->print (stderr, pc);
9457 PCI(pcnext)->label = pic16_pBranchAppend (PCI(pc)->label, PCI(pcnext)->label);
9458 PCI(pc)->label = NULL;
9461 /* update statistics */
9462 pic16_df_removed_pcodes++;
9463 if (isPCI(pc)) pic16_df_saved_bytes += PCI(pc)->isize;
9465 /* remove the pCode */
9466 pic16_pCode2str (buf, 256, pc);
9467 //fprintf (stderr, "%s: removing pCode: %s\n", __FUNCTION__, buf);
9468 if (0 || pic16_debug_verbose || pic16_pcode_verbose) {
9469 len = strlen (buf) + strlen (comment) + 10;
9470 total = (char *) Safe_malloc (len);
9471 SNPRINTF (total, len, "%s: %s", comment, buf);
9472 pic16_pCodeInsertAfter (pc, pic16_newpCodeCharP(total));
9476 /* actually unlink it from the pBlock -- also remove from to/from lists */
9477 pic16_pCodeUnlink (pc);
9479 /* remove the pCode -- release registers */
9482 /* report success */
9487 /* ======================================================================== */
9488 /* === SYMBOL HANDLING ==================================================== */
9489 /* ======================================================================== */
9491 static hTab *map_strToSym = NULL; /** (char *) --> symbol_t */
9492 static hTab *map_symToStr = NULL; /** symbol_t -> (char *) */
9493 static symbol_t nextSymbol = 0x2000; /** next symbol_t assigned to the next generated symbol */
9495 /** Calculate a hash for a given string.
9496 * If len == 0 the string is assumed to be NUL terminated. */
9497 static hash_t symbolHash (const char *str, unsigned int len) {
9501 hash = (hash << 2) ^ *str;
9506 hash = (hash << 2) ^ *str;
9513 /** Return 1 iff strings v1 and v2 are identical. */
9514 static int symcmp (const void *v1, const void *v2) {
9515 return !strcmp ((const char *) v1, (const char *) v2);
9518 /** Return 1 iff pointers v1 and v2 are identical. */
9519 static int ptrcmp (const void *v1, const void *v2) {
9523 enum { SPO_WREG=0x1000,
9563 /* Return the unique symbol_t for the given string. */
9564 static symbol_t symFromStr (const char *str) {
9569 if (!map_symToStr) {
9571 struct { char *name; symbol_t sym; } predefsyms[] = {
9573 {"STATUS", SPO_STATUS},
9574 {"PRODL", SPO_PRODL},
9575 {"PRODH", SPO_PRODH},
9576 {"INDF0", SPO_INDF0},
9577 {"POSTDEC0", SPO_POSTDEC0},
9578 {"POSTINC0", SPO_POSTINC0},
9579 {"PREINC0", SPO_PREINC0},
9580 {"PLUSW0", SPO_PLUSW0},
9581 {"INDF1", SPO_INDF1},
9582 {"POSTDEC1", SPO_POSTDEC1},
9583 {"POSTINC1", SPO_POSTINC1},
9584 {"PREINC1", SPO_PREINC1},
9585 {"PLUSW1", SPO_PLUSW1},
9586 {"INDF2", SPO_INDF2},
9587 {"POSTDEC2", SPO_POSTDEC2},
9588 {"POSTINC2", SPO_POSTINC2},
9589 {"PREINC2", SPO_PREINC2},
9590 {"PLUSW2", SPO_PLUSW2},
9591 {"STKPTR", SPO_STKPTR},
9596 {"FSR0L", SPO_FSR0L},
9597 {"FSR0H", SPO_FSR0H},
9598 {"FSR1L", SPO_FSR1L},
9599 {"FSR1H", SPO_FSR1H},
9600 {"FSR2L", SPO_FSR2L},
9601 {"FSR2H", SPO_FSR2H},
9603 {"PCLATH", SPO_PCLATH},
9604 {"PCLATU", SPO_PCLATU},
9605 {"TABLAT", SPO_TABLAT},
9606 {"TBLPTRL", SPO_TBLPTRL},
9607 {"TBLPTRH", SPO_TBLPTRH},
9608 {"TBLPTRU", SPO_TBLPTRU},
9612 map_strToSym = newHashTable (128);
9613 map_symToStr = newHashTable (128);
9615 for (i=0; predefsyms[i].name; i++) {
9618 /* enter new symbol */
9619 sym = predefsyms[i].sym;
9620 name = predefsyms[i].name;
9621 res = Safe_strdup (name);
9622 hash = symbolHash (name, 0);
9624 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9625 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9629 hash = symbolHash (str, 0) % map_strToSym->size;
9631 /* find symbol in table */
9632 sym = PTR_TO_INT(hTabFindByKey (map_strToSym, hash, str, &symcmp));
9634 //fprintf (stderr, "found symbol %x for %s\n", sym, str);
9638 /* enter new symbol */
9640 res = Safe_strdup (str);
9642 hTabAddItemLong (&map_strToSym, hash, res, INT_TO_PTR(sym));
9643 hTabAddItemLong (&map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), res);
9645 //fprintf (stderr, "created symbol %x for %s\n", sym, res);
9651 static const char *strFromSym (symbol_t sym) {
9652 return (const char *) hTabFindByKey (map_symToStr, sym % map_symToStr->size, INT_TO_PTR(sym), &ptrcmp);
9656 /* ======================================================================== */
9657 /* === DEFINITION MAP HANDLING ============================================ */
9658 /* ======================================================================== */
9660 /* A defmap provides information about which symbol is defined by which pCode.
9661 * The most recent definitions are prepended to the list, so that the most
9662 * recent definition can be found by forward scanning the list.
9663 * pc2: MOVFF r0x00, r0x01
9665 * head --> ("r0x01",pc1,42) --> ("STATUS",pc1,44) --> ("r0x01",pc2,28) --> NULL
9667 * We attach one defmap to each flow object, and each pCode will occur at
9668 * least once in its flow's defmap (maybe defining the 0 symbol). This can be
9669 * used to find definitions for a pCode in its own defmap that precede pCode.
9672 typedef struct defmap_s {
9673 symbol_t sym; /** symbol this item refers to */
9676 unsigned int in_mask:8; /** mask leaving in accessed bits */
9677 unsigned int mask:8; /** mask leaving in modified bits (if isWrite) */
9678 int isRead:1; /** sym/mask is read */
9679 int isWrite:1; /** sym/mask is written */
9683 pCode *pc; /** pCode this symbol is refrenced at */
9684 valnum_t in_val; /** valnum_t of symbol's previous value (the one read at pc) */
9685 valnum_t val; /** new unique number for this value (if isWrite) */
9686 struct defmap_s *prev, *next; /** link to previous an next definition */
9689 static defmap_t *defmap_free = NULL; /** list of unused defmaps */
9690 static int defmap_free_count = 0; /** number of released defmap items */
9692 /* Returns a defmap_t with the specified data; this will be the new list head.
9693 * next - pointer to the current list head */
9694 static defmap_t *newDefmap (symbol_t sym, int in_mask, int mask, int isRead, int isWrite, pCode *pc, valnum_t val, defmap_t *next) {
9699 defmap_free = map->next;
9700 --defmap_free_count;
9702 map = (defmap_t *) Safe_calloc (1, sizeof (defmap_t));
9705 map->acc.access.in_mask = (isRead ? (in_mask ? in_mask : 0xFF) : 0x00);
9706 map->acc.access.mask = (isWrite ? (mask ? mask : 0xFF) : 0x00);
9707 map->acc.access.isRead = (isRead != 0);
9708 map->acc.access.isWrite = (isWrite != 0);
9711 map->val = (isWrite ? val : 0);
9714 if (next) next->prev = map;
9719 /* Returns a copy of the single defmap item. */
9720 static defmap_t *copyDefmap (defmap_t *map) {
9721 defmap_t *res = (defmap_t *) Safe_malloc (sizeof (defmap_t));
9722 memcpy (res, map, sizeof (defmap_t));
9728 /* Insert a defmap item after the specified one. */
9729 static int defmapInsertAfter (defmap_t *ref, defmap_t *newItem) {
9730 if (!ref || !newItem) return 1;
9732 newItem->next = ref->next;
9733 newItem->prev = ref;
9734 ref->next = newItem;
9735 if (newItem->next) newItem->next->prev = newItem;
9740 /* Check whether item (or an identical one) is already in the chain and add it if neccessary.
9741 * item is copied before insertion into chain and therefore left untouched.
9742 * Returns 1 iff the item has been inserted into the list, 0 otherwise. */
9743 static int defmapAddCopyIfNew (defmap_t **head, defmap_t *item) {
9746 while (dummy && (dummy->sym != item->sym
9747 || dummy->pc != item->pc
9748 || dummy->acc.accessmethod != item->acc.accessmethod
9749 || dummy->val != item->val
9750 || dummy->in_val != item->in_val)) {
9751 dummy = dummy->next;
9754 /* item already present? */
9755 if (dummy) return 0;
9757 /* otherwise: insert copy of item */
9758 dummy = copyDefmap (item);
9759 dummy->next = *head;
9760 if (*head) (*head)->prev = dummy;
9766 /* Releases a defmap. This also removes the map from its chain -- update the head manually! */
9767 static void deleteDefmap (defmap_t *map) {
9770 /* unlink from chain -- fails for the first item (head is not updated!) */
9771 if (map->next) map->next->prev = map->prev;
9772 if (map->prev) map->prev->next = map->next;
9775 memset (map, 0, sizeof (defmap_t));
9777 /* save for future use */
9778 map->next = defmap_free;
9780 ++defmap_free_count;
9783 /* Release all defmaps referenced from map. */
9784 static void deleteDefmapChain (defmap_t **_map) {
9785 defmap_t *map, *next;
9791 /* find list head */
9792 while (map && map->prev) map = map->prev;
9794 /* delete all items */
9804 /* Free all defmap items. */
9805 static void freeDefmap (defmap_t **_map) {
9813 /* find list head */
9814 while (map->prev) map = map->prev;
9816 /* release all items */
9826 /* Returns the most recent definition for the given symbol preceeding pc.
9827 * If no definition is found, NULL is returned.
9828 * If pc == NULL the whole list is scanned. */
9829 static defmap_t *defmapFindDef (defmap_t *map, symbol_t sym, pCode *pc) {
9830 defmap_t *curr = map;
9833 /* skip all definitions up to pc */
9834 while (curr && (curr->pc != pc)) curr = curr->next;
9836 /* pc not in the list -- scan the whole list for definitions */
9838 fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9841 /* skip all definitions performed by pc */
9842 while (curr && (curr->pc == pc)) curr = curr->next;
9846 /* find definition for sym */
9847 while (curr && (!curr->acc.access.isWrite || (curr->sym != sym))) {
9855 /* Returns the first use (read) of the given symbol AFTER pc.
9856 * If no such use is found, NULL is returned.
9857 * If pc == NULL the whole list is scanned. */
9858 static defmap_t *defmapFindUse (defmap_t *map, symbol_t sym, pCode *pc) {
9859 defmap_t *curr = map, *prev = NULL;
9862 /* skip all definitions up to pc */
9863 while (curr && (curr->pc != pc)) { prev = curr; curr = curr->next; }
9865 /* pc not in the list -- scan the whole list for definitions */
9867 //fprintf (stderr, "pc %p not found in defmap -- scanning whole list for symbol '%s'\n", pc, strFromSym (sym));
9871 /* find end of list */
9872 while (curr && curr->next) curr = curr->next;
9875 /* find use of sym (scan list backwards) */
9876 while (curr && (!curr->acc.access.isRead || (curr->sym != sym))) curr = curr->prev;
9882 /* Return the defmap entry for sym AT pc.
9883 * If none is found, NULL is returned.
9884 * If more than one entry is found an assertion is triggered. */
9885 static defmap_t *defmapCurr (defmap_t *map, symbol_t sym, pCode *pc) {
9886 defmap_t *res = NULL;
9888 /* find entries for pc */
9889 while (map && map->pc != pc) map = map->next;
9891 /* find first entry for sym @ pc */
9892 while (map && map->pc == pc && map->sym != sym) map = map->next;
9894 /* no entry found */
9895 if (!map) return NULL;
9897 /* check for more entries */
9900 while (map && map->pc == pc) {
9901 /* more than one entry for sym @ pc found? */
9902 assert (map->sym != sym);
9906 /* return single entry for sym @ pc */
9910 /* Modifies the definition of sym at pCode to newval.
9911 * Returns 0 on success, 1 if no definition of sym in pc has been found.
9913 static int defmapUpdate (defmap_t *map, symbol_t sym, pCode *pc, valnum_t newval) {
9916 /* find definitions of pc */
9917 while (m && m->pc != pc) m = m->next;
9919 /* find definition of sym at pc */
9920 while (m && m->pc == pc && (!m->acc.access.isWrite || (m->sym != sym))) m = m->next;
9922 /* no definition found */
9928 /* update following uses of sym */
9929 while (m && m->pc == pc) m = m->prev;
9931 if (m->sym == sym) {
9933 if (m->acc.access.isWrite) m = NULL;
9941 /* ======================================================================== */
9942 /* === STACK ROUTINES ===================================================== */
9943 /* ======================================================================== */
9945 typedef struct stack_s {
9947 struct stack_s *next;
9950 typedef stackitem_t *dynstack_t;
9951 static stackitem_t *free_stackitems = NULL;
9953 /* Create a stack with one item. */
9954 static dynstack_t *newStack () {
9955 dynstack_t *s = (dynstack_t *) Safe_malloc (sizeof (dynstack_t));
9960 /* Remove a stack -- its items are only marked free. */
9961 static void deleteStack (dynstack_t *s) {
9967 i->next = free_stackitems;
9968 free_stackitems = i;
9973 /* Release all stackitems. */
9974 static void releaseStack () {
9977 while (free_stackitems) {
9978 i = free_stackitems->next;
9979 Safe_free(free_stackitems);
9980 free_stackitems = i;
9984 static void stackPush (dynstack_t *stack, void *data) {
9987 if (free_stackitems) {
9988 i = free_stackitems;
9989 free_stackitems = free_stackitems->next;
9991 i = (stackitem_t *) Safe_calloc (1, sizeof (stackitem_t));
9998 static void *stackPop (dynstack_t *stack) {
10002 if (stack && *stack) {
10003 data = (*stack)->data;
10005 *stack = (*stack)->next;
10006 i->next = free_stackitems;
10007 free_stackitems = i;
10015 static int stackContains (dynstack_t *s, void *data) {
10020 if (i->data == data) return 1;
10029 static int stackIsEmpty (dynstack_t *s) {
10030 return (*s == NULL);
10039 static state_t *newState (pCodeFlow *flow, defmap_t *lastdef) {
10040 state_t *s = (state_t *) Safe_calloc (1, sizeof (state_t));
10042 s->lastdef = lastdef;
10046 static void deleteState (state_t *s) {
10050 static int stateIsNew (state_t *state, dynstack_t *todo, dynstack_t *done) {
10053 /* scan working list for state */
10057 /* is i == state? -- state not new */
10058 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10066 /* is i == state? -- state not new */
10067 if ((((state_t *) (i->data))->flow == state->flow) && (((state_t *) (i->data))->lastdef == state->lastdef)) return 0;
10072 /* not found -- state is new */
10076 static inline valnum_t newValnum ();
10078 const char *pic16_pBlockGetFunctionName (pBlock *pb) {
10081 if (!pb) return "<unknown function>";
10083 pc = pic16_findNextpCode (pb->pcHead, PC_FUNCTION);
10084 if (pc && isPCF(pc)) return PCF(pc)->fname;
10085 else return "<unknown function>";
10088 static defmap_t *pic16_pBlockAddInval (pBlock *pb, symbol_t sym) {
10092 pcfl = PCI(pic16_findNextInstruction (pb->pcHead))->pcflow;
10094 /* find initial value (assigning pc == NULL) */
10095 map = PCFL(pcfl)->in_vals;
10096 while (map && map->sym != sym) map = map->next;
10098 /* initial value already present? */
10100 //fprintf (stderr, "found init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10104 /* create a new initial value */
10105 map = newDefmap (sym, 0x00, 0xff, 0, 1, NULL, newValnum(), PCFL(pcfl)->in_vals);
10106 PCFL(pcfl)->in_vals = map;
10107 //fprintf (stderr, "Created init value for sym %s (%x): %u\n", strFromSym(sym), sym, map->val);
10111 /* insert map as last item in pcfl's defmap */
10112 if (!prev) prev = PCFL(pcfl)->defmap;
10114 PCFL(pcfl)->defmap = map;
10116 while (prev->next) prev = prev->next;
10125 /* Find all reaching definitions for sym at pc.
10126 * A new (!) list of definitions is returned.
10127 * Returns the number of reaching definitions found.
10128 * The defining defmap entries are returned in *chain.
10130 static int defmapFindAll (symbol_t sym, pCode *pc, defmap_t **chain) {
10135 pCodeFlowLink *succ;
10137 dynstack_t *todo; /** stack of state_t */
10138 dynstack_t *done; /** stack of state_t */
10140 int firstState, n_defs;
10142 assert (pc && isPCI(pc) && PCI(pc)->pcflow);
10145 /* initialize return list */
10148 /* wildcard symbol? */
10149 if (!sym) return 0;
10151 //fprintf (stderr, "Searching definition of sym %s(%x) @ pc %p(%p)\n", strFromSym(sym), sym, pc, pc->pb);
10153 map = PCI(pc)->pcflow->defmap;
10155 res = defmapFindDef (map, sym, pc);
10156 //if (res) fprintf (stderr, "found def in own flow @ pc %p\n", res->pc);
10158 #define USE_PRECALCED_INVALS 1
10159 #if USE_PRECALCED_INVALS
10160 if (!res && PCI(pc)->pcflow->in_vals) {
10161 res = defmapFindDef (PCI(pc)->pcflow->in_vals, sym, NULL);
10163 //fprintf (stderr, "found def in init values\n");
10164 df_findall_in_vals++;
10170 // found a single definition (in pc's flow)
10171 //fprintf (stderr, "unique definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10172 defmapAddCopyIfNew (chain, res);
10173 df_findall_sameflow++;
10177 #if USE_PRECALCED_INVALS
10179 defmapAddCopyIfNew (chain, pic16_pBlockAddInval (pc->pb, sym));
10185 #define FORWARD_FLOW_ANALYSIS 1
10186 #if defined FORWARD_FLOW_ANALYSIS && FORWARD_FLOW_ANALYSIS
10187 /* no definition found in pc's flow preceeding pc */
10188 todo = newStack ();
10189 done = newStack ();
10190 n_defs = 0; firstState = 1;
10191 stackPush (todo, newState (PCI(pic16_findNextInstruction(pc->pb->pcHead))->pcflow, res));
10193 while (!stackIsEmpty (todo)) {
10194 state = (state_t *) stackPop (todo);
10195 stackPush (done, state);
10196 curr = state->flow;
10197 res = state->lastdef;
10198 //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);
10200 /* there are no definitions BEFORE pc in pc's flow (see above) */
10201 if (curr == PCI(pc)->pcflow) {
10203 //fprintf (stderr, "symbol %s(%x) might be used uninitialized at %p\n", strFromSym(sym), sym, pc);
10204 res = pic16_pBlockAddInval (pc->pb, sym);
10205 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10208 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10209 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10213 /* save last definition of sym in this flow as initial def in successors */
10214 res = defmapFindDef (curr->defmap, sym, NULL);
10215 if (!res) res = state->lastdef;
10217 /* add successors to working list */
10218 state = newState (NULL, NULL);
10219 succ = (pCodeFlowLink *) setFirstItem (curr->to);
10221 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10222 state->flow = succ->pcflow;
10223 state->lastdef = res;
10224 if (stateIsNew (state, todo, done)) {
10225 stackPush (todo, state);
10226 state = newState (NULL, NULL);
10228 succ = (pCodeFlowLink *) setNextItem (curr->to);
10230 deleteState (state);
10233 #else // !FORWARD_FLOW_ANALYSIS
10235 /* no definition found in pc's flow preceeding pc */
10236 todo = newStack ();
10237 done = newStack ();
10238 n_defs = 0; firstState = 1;
10239 stackPush (todo, newState (PCI(pc)->pcflow, res));
10241 while (!stackIsEmpty (todo)) {
10242 state = (state_t *) stackPop (todo);
10243 curr = state->flow;
10247 /* only check predecessor flows */
10249 /* get (last) definition of sym in this flow */
10250 res = defmapFindDef (curr->defmap, sym, NULL);
10254 /* definition found */
10255 //fprintf (stderr, "reaching definition for %s @ %p found @ %p (val: %x)\n", strFromSym(sym), pc, res->pc, res->val);
10256 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10258 /* no definition found -- check predecessor flows */
10259 state = newState (NULL, NULL);
10260 succ = (pCodeFlowLink *) setFirstItem (curr->from);
10262 /* if no flow predecessor available -- sym might be uninitialized */
10264 //fprintf (stder, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10265 res = newDefmap (sym, 0xff, 0, 1, NULL, 0, *chain);
10266 if (defmapAddCopyIfNew (chain, res)) n_defs++;
10267 deleteDefmap (res); res = NULL;
10271 //fprintf (stderr, " %p --> %p with %x\n", curr, succ->pcflow, res ? res->val : 0);
10272 state->flow = succ->pcflow;
10273 state->lastdef = res;
10274 if (stateIsNew (state, todo, done)) {
10275 stackPush (todo, state);
10276 state = newState (NULL, NULL);
10278 succ = (pCodeFlowLink *) setNextItem (curr->from);
10280 deleteState (state);
10286 /* clean up done stack */
10287 while (!stackIsEmpty(done)) {
10288 deleteState ((state_t *) stackPop (done));
10290 deleteStack (done);
10292 /* return number of items in result set */
10294 //fprintf (stderr, "sym %s might be used uninitialized at %p\n", strFromSym (sym), pc);
10295 } else if (n_defs == 1) {
10297 //fprintf (stderr, "sym %s at %p always defined as %x @ %p\n", strFromSym(sym), pc, (*chain)->val, (*chain)->pc);
10298 } else if (n_defs > 0) {
10299 //fprintf (stderr, "%u definitions for sym %s at %p found:\n", n_defs, strFromSym(sym), pc);
10303 fprintf (stderr, " as %4x @ %p\n", res->val, res->pc);
10308 //fprintf (stderr, "%u definitions for sym %s at %p found\n", n_defs, strFromSym(sym), pc);
10309 df_findall_otherflow++;
10313 /* ======================================================================== */
10314 /* === VALUE NUMBER HANDLING ============================================== */
10315 /* ======================================================================== */
10317 static valnum_t nextValnum = 0x1000;
10318 static hTab *map_symToValnum = NULL;
10320 /** Return a new value number. */
10321 static inline valnum_t newValnum () {
10322 return (nextValnum += 4);
10325 static valnum_t valnumFromStr (const char *str) {
10330 sym = symFromStr (str);
10332 if (!map_symToValnum) {
10333 map_symToValnum = newHashTable (128);
10336 /* literal already known? */
10337 res = hTabFindByKey (map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), &ptrcmp);
10339 /* return existing valnum */
10340 if (res) return (valnum_t) PTR_TO_INT(res);
10342 /* create new valnum */
10344 hTabAddItemLong (&map_symToValnum, sym % map_symToValnum->size, INT_TO_PTR(sym), INT_TO_PTR(val));
10345 //fprintf (stderr, "NEW VALNUM %x for symbol %s\n", val, str);
10349 /* Create a valnum for a literal. */
10350 static valnum_t valnumFromLit (unsigned int lit) {
10351 return ((valnum_t) 0x100 + (lit & 0x0FF));
10354 /* Return the (positive) literal value represented by val
10355 * or -1 iff val is no known literal's valnum. */
10356 static int litFromValnum (valnum_t val) {
10357 if (val >= 0x100 && val < 0x200) {
10358 /* valnum is a (known) literal */
10359 return val & 0x00FF;
10361 /* valnum is not a known literal */
10367 /* Sanity check - all flows in a block must be reachable from initial flow. */
10368 static int verifyAllFlowsReachable (pBlock *pb) {
10374 pCodeFlowLink *succ;
10377 //fprintf (stderr, "%s - started for %s.\n" ,__FUNCTION__, pic16_pBlockGetFunctionName (pb));
10380 flowInBlock = NULL;
10382 /* mark initial flow as reached (and "not needs to be reached") */
10383 pc = pic16_findNextpCode (pb->pcHead, PC_FLOW);
10385 addSetHead (&reached, pc);
10386 addSetHead (&checked, pc);
10388 /* mark all further flows in block as "need to be reached" */
10391 if (isPCI(pc)) addSetIfnotP (&flowInBlock, PCI(pc)->pcflow);
10392 pc = pic16_findNextInstruction (pc->next);
10395 while (reached && (pcfl = (pCodeFlow *)indexSet (reached, 0)) != NULL) {
10396 /* mark as reached and "not need to be reached" */
10397 deleteSetItem (&reached, pcfl);
10398 //fprintf (stderr, "%s - checking %p\n" ,__FUNCTION__, pcfl);
10400 /* flow is no longer considered unreachable */
10401 deleteSetItem (&flowInBlock, pcfl);
10403 for (succ = setFirstItem (pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10404 if (!isinSet (checked, succ->pcflow)) {
10405 /* flow has never been reached before */
10406 addSetHead (&reached, succ->pcflow);
10407 addSetHead (&checked, succ->pcflow);
10412 //fprintf (stderr, "%s - finished\n", __FUNCTION__);
10414 /* by now every flow should have been reached
10415 * --> flowInBlock should be empty */
10416 res = (flowInBlock == NULL);
10420 fprintf (stderr, "not all flows reached in %s:\n", pic16_pBlockGetFunctionName (pb));
10421 while (flowInBlock) {
10422 pcfl = indexSet (flowInBlock, 0);
10423 fprintf (stderr, "not reached: flow %p\n", pcfl);
10424 deleteSetItem (&flowInBlock, pcfl);
10430 deleteSet (&reached);
10431 deleteSet (&flowInBlock);
10432 deleteSet (&checked);
10434 /* if we reached every flow, succ is NULL by now... */
10435 //assert (res); // will fire on unreachable code...
10440 /* Checks a flow for accesses to sym AFTER pc.
10442 * Returns -1 if the symbol is read in this flow (before redefinition),
10443 * returns 0 if the symbol is redefined in this flow or
10444 * returns a mask [0x01 -- 0xFF] indicating the bits still alive after this flow.
10446 int pic16_isAliveInFlow (symbol_t sym, int mask, pCodeFlow *pcfl, pCode *pc) {
10447 defmap_t *map, *mappc;
10449 /* find pc or start of definitions */
10450 map = pcfl->defmap;
10451 while (map && (map->pc != pc) && map->next) map = map->next;
10452 /* if we found pc -- ignore it */
10453 while (map && map->pc == pc) map = map->prev;
10455 /* scan list backwards (first definition first) */
10456 while (map && mask) {
10457 // if (map->sym == sym) {
10458 //fprintf (stderr, "%s: accessing sym %s in pc %p/map %p\n", __FUNCTION__, strFromSym(sym), map->pc, map);
10460 /* scan list for reads at this pc first */
10461 while (map && map->pc == mappc->pc) {
10462 /* is the symbol (partially) read? */
10463 if ((map->sym == sym) && (map->acc.access.isRead && ((map->acc.access.in_mask & mask) != 0))) {
10464 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s read at pc %p\n", __FUNCTION__, strFromSym (sym), map->pc);
10471 while (map && map->pc == mappc->pc) {
10472 /* honor (partial) redefinitions of sym */
10473 if ((map->sym == sym) && (map->acc.access.isWrite)) {
10474 mask &= ~map->acc.access.mask;
10475 //if (sym != SPO_STATUS) fprintf (stderr, "%s: symbol %s redefined at pc %p, alive mask: %x\n", __FUNCTION__, strFromSym (sym), map->pc, mask);
10480 /* map already points to the first defmap for the next pCode */
10481 //map = mappc->prev;
10484 /* the symbol is not completely redefined in this flow and not accessed -- symbol
10485 * is still alive; return the appropriate mask of alive bits */
10489 /* Check whether a symbol is alive (AFTER pc). */
10490 static int pic16_isAlive (symbol_t sym, pCode *pc) {
10493 dynstack_t *todo, *done;
10496 pCodeFlowLink *succ;
10500 assert (isPCI(pc));
10501 pcfl = PCI(pc)->pcflow;
10502 map = pcfl->defmap;
10504 todo = newStack ();
10505 done = newStack ();
10507 state = newState (pcfl, (defmap_t *) INT_TO_PTR(mask));
10508 stackPush (todo, state);
10511 while (!stackIsEmpty (todo)) {
10512 state = (state_t *) stackPop (todo);
10513 pcfl = state->flow;
10514 mask = PTR_TO_INT(state->lastdef);
10515 if (visit) stackPush (done, state); else deleteState(state);
10516 //fprintf (stderr, "%s: checking flow %p for symbol %s (%x)/%x\n", __FUNCTION__, pcfl, strFromSym(sym), sym, mask);
10517 // make sure flows like A(i1,i2,pc,i3,...) --> A with pc reading and writing sym are handled correctly!
10518 mask = pic16_isAliveInFlow (sym, mask, pcfl, visit == 0 ? pc : NULL);
10521 /* symbol is redefined in flow before use -- not alive in this flow (maybe in others?) */
10522 if (mask == 0) continue;
10524 /* symbol is (partially) read before redefinition in flow */
10525 if (mask == -1) break;
10527 /* symbol is neither read nor completely redefined -- check successor flows */
10528 for (succ = setFirstItem(pcfl->to); succ; succ = setNextItem (pcfl->to)) {
10529 state = newState (succ->pcflow, (defmap_t *) INT_TO_PTR(mask));
10530 if (stateIsNew (state, todo, done)) {
10531 stackPush (todo, state);
10533 deleteState (state);
10538 while (!stackIsEmpty (todo)) deleteState ((state_t *) stackPop (todo));
10539 while (!stackIsEmpty (done)) deleteState ((state_t *) stackPop (done));
10541 /* symbol is read in at least one flow -- is alive */
10542 if (mask == -1) return 1;
10544 /* symbol is read in no flow */
10548 /* Returns whether access to the given symbol has side effects. */
10549 static int pic16_symIsSpecial (symbol_t sym) {
10550 //fprintf (stderr, "%s: sym=%x\n", __FUNCTION__, sym);
10570 /* no special effects known */
10577 /* Check whether a register should be considered local (to the current function) or not. */
10578 static int pic16_regIsLocal (regs *r) {
10581 sym = symFromStr (r->name);
10584 case SPO_FSR0L: // used in ptrget/ptrput
10585 case SPO_FSR0H: // ... as well
10586 case SPO_FSR1L: // used as stack pointer... (so not really local but shared among function calls)
10587 case SPO_FSR1H: // ... as well
10588 case SPO_FSR2L: // used as frame pointer
10589 case SPO_FSR2H: // ... as well
10590 case SPO_PRODL: // used to return values from functions
10591 case SPO_PRODH: // ... as well
10592 /* these registers (and some more...) are considered local */
10596 /* for unknown regs: check is marked local, leave if not */
10600 //fprintf (stderr, "%s: non-local reg used: %s\n", __FUNCTION__, r->name);
10606 /* if in doubt, assume non-local... */
10610 /* Check all symbols touched by pc whether their newly assigned values are read.
10611 * Returns 0 if no symbol is used later on, 1 otherwise. */
10612 static int pic16_pCodeIsAlive (pCode *pc) {
10613 pCodeInstruction *pci;
10614 defmap_t *map, *lastpc;
10617 /* we can only handle PCIs */
10618 if (!isPCI(pc)) return 1;
10620 //pc->print (stderr, pc);
10623 assert (pci && pci->pcflow && pci->pcflow->defmap);
10625 /* NEVER remove instructions with implicit side effects */
10628 case POC_TBLRD_POSTINC: /* modify TBLPTRx */
10629 case POC_TBLRD_POSTDEC:
10630 case POC_TBLRD_PREINC:
10631 case POC_TBLWT: /* modify program memory */
10632 case POC_TBLWT_POSTINC: /* modify TBLPTRx */
10633 case POC_TBLWT_POSTDEC:
10634 case POC_TBLWT_PREINC:
10635 case POC_CLRWDT: /* clear watchdog timer */
10636 case POC_PUSH: /* should be safe to remove though... */
10637 case POC_POP: /* should be safe to remove though... */
10642 //fprintf (stderr, "%s: instruction with implicit side effects not removed: %s\n", __FUNCTION__, pci->mnemonic);
10646 /* no special instruction */
10650 /* prevent us from removing assignments to non-local variables */
10652 if (PCI(pc)->outCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10653 else if (PCI(pc)->outCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10655 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10656 /* assignment to DIRECT operand like "BSF (_global + 1),6" */
10657 //fprintf (stderr, "%s: assignment to register detected, but register not available!\n", __FUNCTION__);
10658 //pc->print (stderr, pc);
10661 if ((PCI(pc)->outCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10662 //fprintf (stderr, "%s: dest-reg not local %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10667 /* OVERKILL: prevent us from removing reads from non-local variables
10668 * THIS IS HERE TO AVOID PROBLEMS WITH VOLATILE OPERANDS ONLY!
10669 * Once registers get a "isVolatile" field this might be handled more efficiently... */
10671 if (PCI(pc)->inCond & PCC_REGISTER) checkreg = pic16_getRegFromInstruction (pc);
10672 else if (PCI(pc)->inCond & PCC_REGISTER2) checkreg = pic16_getRegFromInstruction2(pc);
10674 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !checkreg) {
10675 /* read from DIRECT operand like "BTFSS (_global + 1),6" -- might be volatile */
10676 //fprintf (stderr, "%s: read from register detected, but register not available!\n", __FUNCTION__);
10677 //pc->print (stderr, pc);
10680 if ((PCI(pc)->inCond & (PCC_REGISTER | PCC_REGISTER2)) && !pic16_regIsLocal (checkreg)) {
10681 //fprintf (stderr, "%s: src-reg not local: %s\n", __FUNCTION__, checkreg ? checkreg->name : "<unknown>");
10686 /* now check that the defined symbols are not used */
10687 map = pci->pcflow->defmap;
10689 /* find items for pc */
10690 while (map && map->pc != pc) map = map->next;
10692 /* no entries found? something is fishy with DF analysis... -- play safe */
10693 if (!map) { fprintf (stderr, "%s: defmap not found\n", __FUNCTION__); return 1; }
10695 /* remember first item assigned to pc for later use */
10698 /* check all symbols being modified by pc */
10699 while (map && map->pc == pc) {
10700 if (map->sym == 0) { map = map->next; continue; }
10702 /* keep pc if it references special symbols (like POSTDEC0) */
10706 pic16_pCode2str (buf, 256, pc);
10707 fprintf (stderr, "%s: checking for sym %x(%s) at pc %p (%s)\n", __FUNCTION__, map->sym, strFromSym (map->sym), pc, buf);
10710 if (pic16_symIsSpecial (map->sym)) {
10711 //fprintf (stderr, "%s: special sym\n", __FUNCTION__);
10714 if (map->acc.access.isWrite) {
10715 if (pic16_isAlive (map->sym, pc)) {
10716 //fprintf (stderr, "%s(%s): pCode is alive (sym %s still used)\n", __FUNCTION__, pic16_pBlockGetFunctionName (pc->pb),strFromSym (map->sym));
10723 /* no use for any of the pc-assigned symbols found -- pCode is dead and can be removed */
10727 pic16_pCode2str (buf, 256, pc);
10728 fprintf (stderr, "%s: pCode %p (%s) is dead.\n", __FUNCTION__, pc, buf);
10734 /* Adds implied operands to the list.
10735 * sym - operand being accessed in the pCode
10736 * list - list to append the operand
10737 * isRead - set to 1 iff sym is read in pCode
10738 * listRead - set to 1 iff all operands being read are to be listed
10740 * Returns 0 for "normal" operands, 1 for special operands.
10742 static int fixupSpecialOperands (symbol_t sym, int in_mask, int mask, pCode *pc, valnum_t val, defmap_t **list, int isRead, int isWrite) {
10743 /* check whether accessing REG accesses other REGs as well */
10747 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10748 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10749 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10753 /* reads FSR0x and WREG */
10754 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10755 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10756 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 0, pc, 0, *list);
10757 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 0, pc, 0, *list);
10763 /* reads/modifies FSR0x */
10764 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10765 *list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10766 *list = newDefmap (SPO_FSR0H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10771 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10772 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10773 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10777 /* reads FSR1x and WREG */
10778 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10779 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10780 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 0, pc, 0, *list);
10781 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 0, pc, 0, *list);
10787 /* reads/modifies FSR1x */
10788 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10789 *list = newDefmap (SPO_FSR1L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10790 *list = newDefmap (SPO_FSR1H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10795 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10796 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10797 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10801 /* reads FSR2x and WREG */
10802 *list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, *list);
10803 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10804 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 0, pc, 0, *list);
10805 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 0, pc, 0, *list);
10811 /* reads/modifies FSR2x */
10812 *list = newDefmap (sym, 0xff, 0xff, 0, 0, pc, 0, *list);
10813 *list = newDefmap (SPO_FSR2L, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10814 *list = newDefmap (SPO_FSR2H, 0xff, 0xff, 1, 1, pc, newValnum (), *list);
10818 /* modifies PCLATH and PCLATU */
10819 *list = newDefmap (SPO_PCL, 0xff, 0xff, isRead, isWrite, pc, newValnum (), *list);
10821 /* reading PCL updates PCLATx */
10822 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10823 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 0, 1, pc, newValnum (), *list);
10826 /* writing PCL implicitly reads PCLATx (computed GOTO) */
10827 *list = newDefmap (SPO_PCLATH, 0xff, 0xff, 1, 0, pc, 0, *list);
10828 *list = newDefmap (SPO_PCLATU, 0xff, 0xff, 1, 0, pc, 0, *list);
10833 *list = newDefmap (sym, in_mask, mask, isRead, isWrite, pc, val, *list);
10834 /* nothing special */
10839 /* has been a special operand */
10843 static symbol_t pic16_fsrsym_idx[][2] = {
10844 {SPO_FSR0L, SPO_FSR0H},
10845 {SPO_FSR1L, SPO_FSR1H},
10846 {SPO_FSR2L, SPO_FSR2H}
10849 /* Merge multiple defmap entries for the same symbol for list's pCode. */
10850 static void mergeDefmapSymbols (defmap_t *list) {
10851 defmap_t *ref, *curr, *temp;
10853 /* now make sure that each symbol occurs at most once per pc */
10855 while (ref && (ref->pc == list->pc)) {
10857 while (curr && (curr->pc == list->pc)) {
10858 if (curr->sym == ref->sym) {
10859 //fprintf (stderr, "Merging defmap entries for symbol %s\n", strFromSym (ref->sym));
10860 /* found a symbol occuring twice... merge the two */
10861 if (curr->acc.access.isRead) {
10862 //if (ref->acc.access.isRead) fprintf (stderr, "symbol %s was marked twice as read at pc %p\n", strFromSym (ref->sym), ref->pc);
10863 ref->acc.access.isRead = 1;
10864 ref->acc.access.in_mask |= curr->acc.access.in_mask;
10866 if (curr->acc.access.isWrite) {
10867 //if (ref->acc.access.isWrite) fprintf (stderr, "symbol %s was marked twice as written at pc %p\n", strFromSym (ref->sym), ref->pc);
10868 ref->acc.access.isWrite = 1;
10869 ref->acc.access.mask |= curr->acc.access.mask;
10873 deleteDefmap (temp);
10874 continue; // do not skip curr!
10882 /** Prepend list with the reads and definitions performed by pc. */
10883 static defmap_t *createDefmap (pCode *pc, defmap_t *list) {
10884 pCodeInstruction *pci;
10885 int cond, inCond, outCond;
10886 int mask = 0xff, smask;
10887 int isSpecial, isSpecial2;
10888 symbol_t sym, sym2;
10892 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
10893 /* TODO: mark this defmap node as an ASMDIR -- any values might be read/modified */
10894 fprintf (stderr, "ASMDIRs not supported by data flow analysis!\n");
10895 list = newDefmap (0, 0xff, 0xff, 0, 0, pc, 0, list);
10898 assert (isPCI(pc));
10901 /* handle bit instructions */
10902 if (pci->isBitInst) {
10903 assert (pci->pcop->type == PO_GPR_BIT);
10904 mask = 1U << (PCORB(PCI(pc)->pcop)->bit);
10907 /* handle (additional) implicit arguments */
10913 lit = PCOL(pci->pcop)->lit;
10914 assert (lit >= 0 && lit < 3);
10915 //fprintf (stderr, "LFSR: %s // %s\n", pci->pcop->name, pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10916 val = valnumFromStr (pic16_get_op(((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0));
10917 //fprintf (stderr, "LFSR lit=%u, symval=%4x\n", lit, val);
10918 list = newDefmap (pic16_fsrsym_idx[lit][0], 0x00, 0xff, 0, 1, pc, val, list);
10919 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...
10923 case POC_MOVLB: // BSR
10924 case POC_BANKSEL: // BSR
10925 list = newDefmap (SPO_BSR, 0x00, 0xff, 0, 1, pc, valnumFromStr (pic16_get_op (((pCodeOpLit2 *)(pci->pcop))->arg2, NULL, 0)), list);
10928 case POC_MULWF: // PRODx
10929 case POC_MULLW: // PRODx
10930 list = newDefmap (SPO_PRODH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10931 list = newDefmap (SPO_PRODL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10934 case POC_POP: // TOS, STKPTR
10935 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10936 list = newDefmap (SPO_TOSL, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10937 list = newDefmap (SPO_TOSH, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10938 list = newDefmap (SPO_TOSU, 0x00, 0xff, 0, 1, pc, newValnum (), list);
10941 case POC_PUSH: // STKPTR
10942 list = newDefmap (SPO_STKPTR, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10943 list = newDefmap (SPO_TOSL, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10944 list = newDefmap (SPO_TOSH, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10945 list = newDefmap (SPO_TOSU, 0xff, 0xff, 0, 1, pc, newValnum (), list);
10948 case POC_CALL: // return values (and arguments?): WREG, PRODx, FSR0L
10949 case POC_RCALL: // return values (and arguments?): WREG, PRODx, FSR0L
10950 list = newDefmap (SPO_WREG, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10951 list = newDefmap (SPO_PRODL, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10952 list = newDefmap (SPO_PRODH, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10953 list = newDefmap (SPO_FSR0L, 0xff, 0xff, 1, 1, pc, newValnum (), list);
10955 /* needs correctly set-up stack pointer */
10956 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10957 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10960 case POC_RETLW: // return values: WREG, PRODx, FSR0L
10961 /* pseudo read on (possible) return values */
10962 // WREG is handled below via outCond
10963 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10964 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10965 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10967 /* caller's stack pointers must be restored */
10968 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10969 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10970 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10971 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10974 case POC_RETURN: // return values; WREG, PRODx, FSR0L
10975 case POC_RETFIE: // return value: WREG, PRODx, FSR0L
10976 /* pseudo read on (possible) return values */
10977 list = newDefmap (SPO_WREG, 0xff, 0x00, 1, 0, pc, 0, list);
10978 list = newDefmap (SPO_PRODL, 0xff, 0x00, 1, 0, pc, 0, list);
10979 list = newDefmap (SPO_PRODH, 0xff, 0x00, 1, 0, pc, 0, list);
10980 list = newDefmap (SPO_FSR0L, 0xff, 0x00, 1, 0, pc, 0, list);
10982 /* caller's stack pointers must be restored */
10983 list = newDefmap (SPO_FSR1L, 0xff, 0x00, 1, 0, pc, 0, list);
10984 list = newDefmap (SPO_FSR1H, 0xff, 0x00, 1, 0, pc, 0, list);
10985 list = newDefmap (SPO_FSR2L, 0xff, 0x00, 1, 0, pc, 0, list);
10986 list = newDefmap (SPO_FSR2H, 0xff, 0x00, 1, 0, pc, 0, list);
10990 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
10991 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
10992 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
10993 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
10996 case POC_TBLRD_POSTINC:
10997 case POC_TBLRD_POSTDEC:
10998 case POC_TBLRD_PREINC:
10999 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11000 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11001 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11002 list = newDefmap (SPO_TABLAT, 0x00, 0xff, 0, 1, pc, newValnum(), list);
11006 list = newDefmap (SPO_TBLPTRL, 0xff, 0x00, 1, 0, pc, 0, list);
11007 list = newDefmap (SPO_TBLPTRH, 0xff, 0x00, 1, 0, pc, 0, list);
11008 list = newDefmap (SPO_TBLPTRU, 0xff, 0x00, 1, 0, pc, 0, list);
11009 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11012 case POC_TBLWT_POSTINC:
11013 case POC_TBLWT_POSTDEC:
11014 case POC_TBLWT_PREINC:
11015 list = newDefmap (SPO_TBLPTRL, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11016 list = newDefmap (SPO_TBLPTRH, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11017 list = newDefmap (SPO_TBLPTRU, 0xff, 0xff, 1, 1, pc, newValnum(), list);
11018 list = newDefmap (SPO_TABLAT, 0xff, 0x00, 1, 0, pc, 0, list);
11022 /* many instruction implicitly read BSR... -- THIS IS IGNORED! */
11026 /* handle explicit arguments */
11027 inCond = pci->inCond;
11028 outCond = pci->outCond;
11029 cond = inCond | outCond;
11030 if (cond & PCC_W) {
11031 list = newDefmap (symFromStr ("WREG"), mask, mask, inCond & PCC_W, outCond & PCC_W, pc, newValnum (), list);
11034 /* keep STATUS read BEFORE STATUS write in the list (still neccessary?) */
11035 if (inCond & PCC_STATUS) {
11037 if (inCond & PCC_C) smask |= 1U << PIC_C_BIT;
11038 if (inCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11039 if (inCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11040 if (inCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11041 if (inCond & PCC_N) smask |= 1U << PIC_N_BIT;
11043 list = newDefmap (symFromStr ("STATUS"), smask, 0x00, 1, 0, pc, 0, list);
11044 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11047 if (outCond & PCC_STATUS) {
11049 if (outCond & PCC_C) smask |= 1U << PIC_C_BIT;
11050 if (outCond & PCC_DC) smask |= 1U << PIC_DC_BIT;
11051 if (outCond & PCC_Z) smask |= 1U << PIC_Z_BIT;
11052 if (outCond & PCC_OV) smask |= 1U << PIC_OV_BIT;
11053 if (outCond & PCC_N) smask |= 1U << PIC_N_BIT;
11055 list = newDefmap (symFromStr ("STATUS"), 0x00, smask, 0, 1, pc, newValnum (), list);
11056 //fprintf (stderr, "pc %p: def STATUS & %02x\n", pc, smask);
11059 isSpecial = isSpecial2 = 0;
11061 if (cond & PCC_REGISTER) {
11062 name = pic16_get_op (pci->pcop, NULL, 0);
11063 sym = symFromStr (name);
11064 isSpecial = fixupSpecialOperands (sym, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER, outCond & PCC_REGISTER);
11065 //fprintf (stderr, "pc %p: def REG %s(%x) & %02x\n", pc, name, sym, mask);
11068 if (cond & PCC_REGISTER2) {
11069 name = pic16_get_op2 (pci->pcop, NULL, 0);
11070 sym2 = symFromStr (name);
11071 isSpecial2 = fixupSpecialOperands (sym2, mask, mask, pc, newValnum(), &list, inCond & PCC_REGISTER2, outCond & PCC_REGISTER2);
11072 //fprintf (stderr, "pc %p: def REG2 %s(%x) & %02x\n", pc, name, sym2, mask);
11076 /* make sure there is at least one entry for each pc (needed by list traversal routines) */
11077 list = newDefmap (0, 0x00, 0x00, 0, 0, pc, 0, list);
11079 mergeDefmapSymbols (list);
11085 static void printDefmap (defmap_t *map) {
11089 fprintf (stderr, "defmap @ %p:\n", curr);
11091 fprintf (stderr, "%s%s: %4x|%4x / %02x|%02x, sym %s(%x) @ pc %p\n",
11092 curr->acc.access.isRead ? "R" : " ",
11093 curr->acc.access.isWrite ? "W": " ",
11094 curr->in_val, curr->val,
11095 curr->acc.access.in_mask, curr->acc.access.mask,
11096 strFromSym(curr->sym), curr->sym,
11100 fprintf (stderr, "<EOL>\n");
11104 /* Add "additional" definitions to uniq.
11105 * 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.
11106 * This can also be used to create a uniq (out)list from a flow's defmap by passing *uniq==NULL.
11108 * If symbols defined in additional are not present in uniq, a definition is created.
11109 * Otherwise the present definition is altered to reflect the newer assignments.
11111 * flow: <uniq> --> assign1 --> assign2 --> assign3 --> ... --> <uniq'>
11112 * before `------- noted in additional --------' after
11114 * I assume that each symbol occurs AT MOST ONCE in uniq.
11117 static int defmapUpdateUniqueSym (defmap_t **uniq, defmap_t *additional) {
11122 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *uniq, additional);
11123 /* find tail of additional list (holds the first assignment) */
11125 while (curr && curr->next) curr = curr->next;
11129 /* find next assignment in additionals */
11130 while (curr && !curr->acc.access.isWrite) curr = curr->prev;
11134 /* find item in uniq */
11136 //printDefmap (*uniq);
11137 while (old && (old->sym != curr->sym)) old = old->next;
11140 /* definition found -- replace */
11141 if (old->val != curr->val) {
11142 old->val = curr->val;
11146 /* new definition */
11147 *uniq = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, curr->val, *uniq);
11154 /* return 0 iff uniq remained unchanged */
11158 /* Creates the in_value list of a flow by (iteratively) merging the out_value
11159 * lists of its predecessor flows.
11160 * Initially *combined should be NULL, alt_in will be copied to combined.
11161 * If *combined != NULL, combined will be altered:
11162 * - for symbols defined in *combined but not in alt_in,
11163 * *combined is altered to 0 (value unknown, either *combined or INIT).
11164 * - for symbols defined in alt_in but not in *combined,
11165 * a 0 definition is created (value unknown, either INIT or alt).
11166 * - for symbols defined in both, *combined is:
11167 * > left unchanged if *combined->val == alt_in->val or
11168 * > modified to 0 otherwise (value unknown, either alt or *combined).
11170 * I assume that each symbol occurs AT MOST ONCE in each list!
11172 static int defmapCombineFlows (defmap_t **combined, defmap_t *alt_in, pBlock *pb) {
11178 //fprintf (stderr, "%s: merging %p & %p\n", __FUNCTION__, *combined, alt_in);
11180 if (!(*combined)) {
11181 return defmapUpdateUniqueSym (combined, alt_in);
11184 /* merge the two */
11187 /* find symbols definition in *combined */
11189 while (old && (old->sym != curr->sym)) old = old->next;
11192 /* definition found */
11193 if (old->val && (old->val != curr->val)) {
11194 old->val = 0; /* value unknown */
11198 /* no definition found -- can be either INIT or alt_in's value */
11199 val = pic16_pBlockAddInval (pb, curr->sym)->val;
11200 *combined = newDefmap (curr->sym, 0x00, 0xff, 0, 1, NULL, (val == curr->val) ? val : 0, *combined);
11201 if (val != curr->val) change++;
11207 /* update symbols from *combined that are NOT defined in alt_in -- can be either *combined's value or INIT */
11210 if (old->val != 0) {
11211 /* find definition in alt_in */
11213 while (curr && curr->sym != old->sym) curr = curr->next;
11215 /* symbol defined in *combined only -- can be either INIT or *combined */
11216 val = pic16_pBlockAddInval (pb, old->sym)->val;
11217 if (old->val != val) {
11230 static int defmapCompareUnique (defmap_t *map1, defmap_t *map2) {
11231 defmap_t *curr1, *curr2;
11234 /* identical maps are equal */
11235 if (map1 == map2) return 0;
11237 if (!map1) return -1;
11238 if (!map2) return 1;
11240 //fprintf (stderr, "%s: comparing %p & %p\n", __FUNCTION__, map1, map2);
11245 while (curr1 && curr2) {
11246 curr1 = curr1->next;
11247 curr2 = curr2->next;
11250 /* one of them longer? */
11251 if (curr1) return 1;
11252 if (curr2) return -1;
11254 /* both lists are of equal length -- compare (in O(n^2)) */
11259 while (curr2 && curr2->sym != sym) curr2 = curr2->next;
11260 if (!curr2) return 1; // symbol not found in curr2
11261 if (curr2->val != curr1->val) return 1; // values differ
11263 /* compare next symbol */
11264 curr1 = curr1->next;
11267 /* no difference found */
11272 /* Prepare a list of all reaching definitions per flow.
11273 * This is done using a forward dataflow analysis.
11275 static void createReachingDefinitions (pBlock *pb) {
11276 defmap_t *out_vals, *in_vals;
11279 pCodeFlowLink *link;
11283 /* initialize out_vals to unique'fied defmaps per pCodeFlow */
11284 for (pc = pic16_findNextInstruction (pb->pcHead); pc; pc = pic16_findNextInstruction (pc->next)) {
11286 deleteDefmapChain (&PCFL(pc)->in_vals);
11287 deleteDefmapChain (&PCFL(pc)->out_vals);
11288 defmapUpdateUniqueSym (&PCFL(pc)->out_vals, PCFL(pc)->defmap);
11292 pc = pic16_findNextInstruction (pb->pcHead);
11293 todo = NULL; blacklist = NULL;
11294 addSetHead (&todo, PCI(pc)->pcflow);
11296 //fprintf (stderr, "%s: function %s()\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11297 while (elementsInSet (todo)) {
11298 //fprintf (stderr, "%u items in todo-set\n", elementsInSet (todo));
11299 pcfl = PCFL(indexSet (todo, 0));
11300 deleteSetItem (&todo, pcfl);
11301 //fprintf (stderr, "%s: checking %p\n", __FUNCTION__, pcfl);
11305 if (isinSet (blacklist, pcfl)) {
11306 fprintf (stderr, "ignoring blacklisted flow\n");
11310 /* create in_vals from predecessors out_vals */
11311 link = setFirstItem (pcfl->from);
11313 defmapCombineFlows (&in_vals, link->pcflow->out_vals, pb);
11314 link = setNextItem (pcfl->from);
11317 //printDefmap (in_vals);
11318 //printDefmap (pcfl->in_vals);
11320 if (!pcfl->in_vals || !pcfl->out_vals || defmapCompareUnique (in_vals, pcfl->in_vals)) {
11321 //fprintf (stderr, "in_vals changed\n");
11322 /* in_vals changed -- update out_vals */
11323 deleteDefmapChain (&pcfl->in_vals);
11324 pcfl->in_vals = in_vals;
11326 /* create out_val from in_val and defmap */
11328 defmapUpdateUniqueSym (&out_vals, in_vals);
11329 defmapUpdateUniqueSym (&out_vals, pcfl->defmap);
11331 /* is out_vals different from pcfl->out_vals */
11332 if (!pcfl->out_vals || defmapCompareUnique (out_vals, pcfl->out_vals)) {
11333 //fprintf (stderr, "out_vals changed\n");
11334 deleteDefmapChain (&pcfl->out_vals);
11335 pcfl->out_vals = out_vals;
11337 if (pcfl->out_vals == NULL && pcfl->in_vals == NULL) {
11338 addSet (&blacklist, pcfl);
11341 /* reschedule all successors */
11342 link = setFirstItem (pcfl->to);
11344 //fprintf (stderr, " %p --> %p\n", pcfl, link->pcflow);
11345 addSetIfnotP (&todo, link->pcflow);
11346 link = setNextItem (pcfl->to);
11349 deleteDefmapChain (&out_vals);
11352 deleteDefmapChain (&in_vals);
11358 static void showAllDefs (symbol_t sym, pCode *pc) {
11362 assert (isPCI(pc));
11363 count = defmapFindAll (sym, pc, &map);
11365 fprintf (stderr, "sym %s(%x) @ %p defined as (val@pc): ", strFromSym(sym), sym, pc);
11368 fprintf (stderr, "(%x @ %p) ", map->val, map->pc);
11371 pic16_pCode2str (buf, 256, map->pc);
11372 fprintf (stderr, "\n (%x @ %p(%s)) ", map->val, map->pc, buf);
11376 deleteDefmapChain (&map);
11380 /* safepCodeUnlink and remove pc from defmap. */
11381 static int pic16_safepCodeRemove (pCode *pc, char *comment) {
11382 defmap_t *map, *next, **head;
11386 map = isPCI(pc) ? PCI(pc)->pcflow->defmap : NULL;
11387 head = isPCI(pc) ? &PCI(pc)->pcflow->defmap : NULL;
11388 res = pic16_safepCodeUnlink (pc, comment);
11391 /* remove pc from defmap */
11394 if (map->pc == pc) {
11395 if (!map->prev && head) *head = map->next;
11396 deleteDefmap (map);
11405 void pic16_fixDefmap (pCode *pc, pCode *newpc) {
11407 /* This breaks the defmap chain's references to pCodes... fix it! */
11408 map = PCI(pc)->pcflow->defmap;
11410 while (map && map->pc != pc) map = map->next;
11412 while (map && map->pc == pc) {
11418 /* Replace a defmap entry for sym with newsym for read accesses (isRead == 1) or
11419 * write accesses (isRead == 0). */
11420 void defmapReplaceSymRef (pCode *pc, symbol_t sym, symbol_t newsym, int isRead) {
11421 defmap_t *map, *map_start;
11423 if (!isPCI(pc)) return;
11424 if (sym == newsym) return;
11426 map = PCI(pc)->pcflow->defmap;
11428 while (map && map->pc != pc) map = map->next;
11430 while (map && map->pc == pc) {
11431 if (map->sym == sym) {
11432 assert ((isRead && map->acc.access.isRead) || ((!isRead) && (map->acc.access.isWrite)));
11433 if (!(map->acc.access.isRead && map->acc.access.isWrite)) {
11434 /* only one kind of access handled... this is easy */
11437 /* must copy defmap entry before replacing symbol... */
11438 copy = copyDefmap (map);
11440 map->acc.access.isRead = 0;
11441 copy->acc.access.isWrite = 0;
11443 map->acc.access.isWrite = 0;
11444 copy->acc.access.isRead = 0;
11446 copy->sym = newsym;
11447 /* insert copy into defmap chain */
11448 defmapInsertAfter (map, copy);
11454 /* as this might introduce multiple defmap entries for newsym... */
11455 mergeDefmapSymbols (map_start);
11458 /* Assign "better" valnums to results. */
11459 static void assignValnums (pCode *pc) {
11460 pCodeInstruction *pci;
11462 symbol_t sym1, sym2;
11463 int cond, isSpecial1, isSpecial2, count, mask, lit;
11464 defmap_t *list, *val, *oldval, *dummy;
11465 regs *reg1 = NULL, *reg2 = NULL;
11468 /* only works for pCodeInstructions... */
11469 if (!isPCI(pc)) return;
11472 cond = pci->inCond | pci->outCond;
11473 list = pci->pcflow->defmap;
11474 sym1 = sym2 = isSpecial1 = isSpecial2 = 0;
11476 if (cond & PCC_REGISTER) {
11477 sym1 = symFromStr (pic16_get_op (pci->pcop, NULL, 0));
11478 reg1 = pic16_getRegFromInstruction (pc);
11479 isSpecial1 = pic16_symIsSpecial (sym1);
11481 if (cond & PCC_REGISTER2) {
11482 sym2 = symFromStr (pic16_get_op2 (pci->pcop, NULL, 0));
11483 reg2 = pic16_getRegFromInstruction (pc);
11484 isSpecial2 = pic16_symIsSpecial (sym2);
11487 /* determine input values */
11489 while (val && val->pc != pc) val = val->next;
11490 //list = val; /* might save some time later... */
11491 while (val && val->pc == pc) {
11493 if (val->sym != 0 && (1 || val->acc.access.isRead)) {
11494 /* get valnum for sym */
11495 count = defmapFindAll (val->sym, pc, &oldval);
11496 //fprintf (stderr, "%d defs for sym %s\n", count, strFromSym (val->sym));
11498 if ((val->acc.access.in_mask & oldval->acc.access.mask) == val->acc.access.in_mask) {
11499 val->in_val = oldval->val;
11503 } else if (count == 0) {
11504 /* no definition found */
11507 /* multiple definition(s) found -- value not known (unless always the same valnum) */
11509 dummy = oldval->next;
11510 mask = oldval->acc.access.mask;
11511 val->in_val = oldval->val;
11512 while (dummy && (dummy->val == val->in_val)) {
11513 mask &= dummy->acc.access.mask;
11514 dummy = dummy->next;
11517 /* found other values or to restictive mask */
11518 if (dummy || ((mask & val->acc.access.in_mask) != val->acc.access.in_mask)) {
11522 if (count > 0) deleteDefmapChain (&oldval);
11527 /* handle valnum assignment */
11529 case POC_CLRF: /* modifies STATUS (Z) */
11530 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11531 oldval = defmapCurr (list, sym1, pc);
11532 if (oldval && (litFromValnum (oldval->in_val) == 0)) {
11533 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11534 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant CLRF removed");
11536 defmapUpdate (list, sym1, pc, valnumFromLit(0));
11540 case POC_SETF: /* SETF does not touch STATUS */
11541 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11542 oldval = defmapCurr (list, sym1, pc);
11543 if (oldval && (litFromValnum (oldval->in_val) == 0x00FF)) {
11544 //fprintf (stderr, "%s: REG (%s) already set up correctly (%x)\n", pci->mnemonic, strFromSym(sym1), oldval->in_val);
11545 pic16_safepCodeRemove (pc, "=DF= redundant SETF removed");
11547 defmapUpdate (list, sym1, pc, valnumFromLit (0x00FF));
11551 case POC_MOVLW: /* does not touch STATUS */
11552 oldval = defmapCurr (list, SPO_WREG, pc);
11553 if (pci->pcop->type == PO_LITERAL) {
11554 //fprintf (stderr, "MOVLW: literal %u\n", PCOL(pci->pcop)->lit);
11555 litnum = valnumFromLit ((unsigned char)PCOL(pci->pcop)->lit);
11557 //fprintf (stderr, "MOVLW: %s\n", pic16_get_op (pci->pcop, NULL, 0));
11558 litnum = valnumFromStr (pic16_get_op (pci->pcop, NULL, 0));
11560 if (oldval && oldval->in_val == litnum) {
11561 //fprintf (stderr, "%s: W already set up correctly (%x)\n", PCI(pc)->mnemonic, oldval->in_val);
11562 pic16_safepCodeRemove (pc, "=DF= redundant MOVLW removed");
11564 defmapUpdate (list, SPO_WREG, pc, litnum);
11567 case POC_ANDLW: /* modifies STATUS (Z,N) */
11568 case POC_IORLW: /* modifies STATUS (Z,N) */
11569 case POC_XORLW: /* modifies STATUS (Z,N) */
11570 /* can be optimized iff WREG contains a known literal (0x100 - 0x1FF) */
11571 if (pci->pcop->type == PO_LITERAL) {
11573 lit = (unsigned char) PCOL(pci->pcop)->lit;
11574 val = defmapCurr (list, SPO_WREG, pc);
11575 if (val) vallit = litFromValnum (val->in_val);
11576 if (vallit != -1) {
11577 /* xxxLW <literal>, WREG contains a known literal */
11578 //fprintf (stderr, "%s 0x%02x, WREG: 0x%x\n", pci->mnemonic, lit, vallit);
11579 if (pci->op == POC_ANDLW) {
11581 } else if (pci->op == POC_IORLW) {
11583 } else if (pci->op == POC_XORLW) {
11586 assert (0 && "invalid operation");
11588 if (vallit == lit) {
11589 //fprintf (stderr, "%s: W already set up correctly (%x = val %x)\n", pci->mnemonic, vallit, val->in_val);
11590 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant ANDLW/IORLW/XORLW removed");
11592 defmapUpdate (list, SPO_WREG, pc, valnumFromLit (lit));
11599 /* check if old value matches new value */
11602 assert (pci->pcop->type == PO_LITERAL);
11604 lit = PCOL(pci->pcop)->lit;
11606 val = defmapCurr (list, pic16_fsrsym_idx[lit][0], pc);
11608 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11609 //fprintf (stderr, "FSR%dL already set up correctly at %p (%x)\n", lit, pc, val->val);
11611 /* cannot remove this LFSR */
11615 val = defmapCurr (list, pic16_fsrsym_idx[lit][1], pc);
11616 if (val && (val->in_val != 0) && (val->in_val == val->val)) {
11617 //fprintf (stderr, "FSR%dH already set up correctly at %p (%x)\n", lit, pc, val->val);
11623 pic16_safepCodeRemove (pc, "=DF= redundant LFSR removed");
11628 case POC_MOVWF: /* does not touch flags */
11629 /* find value of WREG */
11630 val = defmapCurr (list, SPO_WREG, pc);
11631 oldval = defmapCurr (list, sym1, pc);
11632 if (val) lit = litFromValnum (val->in_val);
11634 //fprintf (stderr, "MOVWF: lit: %i (%x, %x)\n", lit, lit, val->in_val);
11636 if ((lit == 0 || lit == 0x0ff) && !pic16_isAlive (SPO_STATUS, pc)) {
11637 /* might replace with CLRF/SETF (will possibly make previous MOVLW 0x00/0xff unneccessary --> dead code elimination) */
11638 //fprintf (stderr, "replacing MOVWF with CLRF/SETF\n");
11640 newpc = pic16_newpCode (POC_CLRF, pic16_pCodeOpCopy (pci->pcop));
11642 assert (lit == 0x0ff);
11643 newpc = pic16_newpCode (POC_SETF, pic16_pCodeOpCopy (pci->pcop));
11645 if (pic16_debug_verbose || pic16_pcode_verbose) pic16_InsertCommentAfter (pc->prev, "=DF= MOVWF: replaced by CLRF/SETF");
11646 pic16_pCodeReplace (pc, newpc);
11647 defmapReplaceSymRef (pc, SPO_WREG, 0, 1);
11648 pic16_fixDefmap (pc, newpc);
11651 /* This breaks the defmap chain's references to pCodes... fix it! */
11652 if (!val->prev) PCI(pc)->pcflow->defmap = val->next;
11653 if (!val->acc.access.isWrite) {
11654 deleteDefmap (val); // delete reference to WREG as in value
11657 val->acc.access.isRead = 0; // delete reference to WREG as in value
11659 oldval = PCI(pc)->pcflow->defmap;
11661 if (oldval->pc == pc) oldval->pc = newpc;
11662 oldval = oldval->next;
11664 } else if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11665 //fprintf (stderr, "MOVWF: F (%s) already set up correctly (%x) at %p\n", strFromSym (sym1), oldval->in_val, pc);
11666 pic16_safepCodeRemove (pc, "=DF= redundant MOVWF removed");
11668 if (val) defmapUpdate (list, sym1, pc, val->in_val);
11671 case POC_MOVFW: /* modifies STATUS (Z,N) */
11672 /* find value of REG */
11673 if (!isSpecial1 && pic16_regIsLocal (reg1)) {
11674 val = defmapCurr (list, sym1, pc);
11675 oldval = defmapCurr (list, SPO_WREG, pc);
11676 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11677 //fprintf (stderr, "MOVFW: W already set up correctly (%x) at %p\n", oldval->in_val, pc);
11678 if (!pic16_isAlive (SPO_STATUS, pc)) pic16_safepCodeRemove (pc, "=DF= redundant MOVFW removed");
11680 if (val) defmapUpdate (list, SPO_WREG, pc, val->in_val);
11684 case POC_MOVFF: /* does not touch STATUS */
11685 /* find value of REG */
11686 val = defmapCurr (list, sym1, pc);
11687 oldval = defmapCurr (list, sym2, pc);
11688 if (val) lit = litFromValnum (val->in_val);
11691 if (!isSpecial1 && pic16_regIsLocal (reg1) && val && oldval && !pic16_isAlive (SPO_STATUS, pc)) {
11692 //pc->print (stderr, pc); fprintf (stderr, "lit: %d (%x, %x)\n", lit, lit, val->in_val);
11694 newpc = pic16_newpCode (POC_CLRF, PCOR2(pci->pcop)->pcop2);
11695 } else if (lit == 0x00ff) {
11696 newpc = pic16_newpCode (POC_SETF, PCOR2(pci->pcop)->pcop2);
11701 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: replaced by CRLF/SETF");
11702 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11703 pic16_pCodeReplace (pc, newpc);
11704 defmapReplaceSymRef (pc, sym1, 0, 1);
11705 pic16_fixDefmap (pc, newpc);
11707 break; // do not process instruction as MOVFF...
11709 } else if (!isSpecial1 && !isSpecial2 && pic16_regIsLocal (reg1) && pic16_regIsLocal (reg2)) {
11710 if (val && oldval && (val->in_val != 0) && (val->in_val == oldval->in_val)) {
11711 //fprintf (stderr, "MOVFF: F2 (%s) already set up correctly (%x) at %p\n", strFromSym (sym2), oldval->in_val, pc);
11712 pic16_safepCodeRemove (pc, "=DF= redundant MOVFF removed");
11714 if (!pic16_isAlive (sym1, pc)) {
11715 defmap_t *copy = NULL;
11716 /* If there is another symbol S storing sym1's value we should assign from S thus shortening the liferange of sym1.
11717 * This should help eliminate
11719 * <do something not changing A or using B>
11721 * <B is not alive anymore>
11723 * <do something not changing A or using B>
11727 /* scan defmap for symbols storing sym1's value */
11728 while (oldval && (oldval->pc == pc || oldval->in_val != val->in_val)) oldval = oldval->next;
11729 if (oldval && (oldval->sym != sym1) && defmapFindAll (oldval->sym, pc, ©) == 1) {
11730 /* unique reaching definition for sym found */
11731 if (copy->val && copy->val == val->in_val) {
11732 //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);
11733 if (copy->sym == SPO_WREG) {
11734 newpc = pic16_newpCode (POC_MOVWF, pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2));
11736 newpc = pic16_newpCode(POC_MOVFF, pic16_popGet2p(
11737 // /*TODO: change to copy->pc's out symbol*/pic16_pCodeOpCopy (pci->pcop),
11738 pic16_pCodeOpCopy (PCI(copy->pc)->pcop),
11739 pic16_pCodeOpCopy (PCOR2(pci->pcop)->pcop2)));
11741 pic16_InsertCommentAfter (pc->prev, "=DF= MOVFF: SRC op %s replaced by %s", strFromSym(sym1), strFromSym(copy->sym));
11742 pic16_df_saved_bytes += PCI(pc)->isize - PCI(newpc)->isize;
11743 pic16_pCodeReplace (pc, newpc);
11744 assert (val->sym == sym1 && val->acc.access.isRead && !val->acc.access.isWrite);
11745 defmapReplaceSymRef (pc, sym1, copy->sym, 1);
11746 pic16_fixDefmap (pc, newpc);
11750 deleteDefmapChain (©);
11753 if (val) defmapUpdate (list, sym2, pc, val->in_val);
11758 /* cannot optimize */
11763 static void pic16_destructDF (pBlock *pb) {
11766 /* remove old defmaps */
11767 pc = pic16_findNextInstruction (pb->pcHead);
11769 next = pic16_findNextInstruction (pc->next);
11771 assert (isPCI(pc) || isPCAD(pc));
11772 assert (PCI(pc)->pcflow);
11773 deleteDefmapChain (&PCI(pc)->pcflow->defmap);
11774 deleteDefmapChain (&PCI(pc)->pcflow->in_vals);
11775 deleteDefmapChain (&PCI(pc)->pcflow->out_vals);
11780 if (defmap_free || defmap_free_count) {
11781 //fprintf (stderr, "released defmaps: %u -- freeing up memory\n", defmap_free_count);
11782 freeDefmap (&defmap_free);
11783 defmap_free_count = 0;
11787 /* Checks whether a pBlock contains ASMDIRs. */
11788 static int pic16_pBlockHasAsmdirs (pBlock *pb) {
11791 pc = pic16_findNextInstruction (pb->pcHead);
11793 if (isPCAD(pc)) return 1;
11795 pc = pic16_findNextInstruction (pc->next);
11798 /* no PCADs found */
11803 /* Remove MOVFF r0x??, POSTDEC1 and MOVFF PREINC1, r0x?? for otherwise unused registers. */
11804 static int pic16_removeUnusedRegistersDF () {
11807 regs *reg1, *reg2, *reg3;
11808 set *seenRegs = NULL;
11810 int islocal, change = 0;
11813 if (!the_pFile || !the_pFile->pbHead) return 0;
11815 for (pb = the_pFile->pbHead; pb; pb = pb->next) {
11816 //fprintf (stderr, "%s: examining function %s\n", __FUNCTION__, pic16_pBlockGetFunctionName (pb));
11818 /* find set of using pCodes per register */
11819 for (pc = pic16_findNextInstruction (pb->pcHead); pc;
11820 pc = pic16_findNextInstruction(pc->next)) {
11822 cond = PCI(pc)->inCond | PCI(pc)->outCond;
11823 reg1 = reg2 = NULL;
11824 if (cond & PCC_REGISTER) reg1 = pic16_getRegFromInstruction (pc);
11825 if (cond & PCC_REGISTER2) reg2 = pic16_getRegFromInstruction2 (pc);
11828 if (!isinSet (seenRegs, reg1)) reg1->reglives.usedpCodes = NULL;
11829 addSetIfnotP (&seenRegs, reg1);
11830 addSetIfnotP (®1->reglives.usedpCodes, pc);
11833 if (!isinSet (seenRegs, reg2)) reg2->reglives.usedpCodes = NULL;
11834 addSetIfnotP (&seenRegs, reg2);
11835 addSetIfnotP (®2->reglives.usedpCodes, pc);
11839 for (reg1 = setFirstItem (seenRegs); reg1; reg1 = setNextItem (seenRegs)) {
11840 /* may not use pic16_regIsLocal() here -- in interrupt routines
11841 * WREG, PRODx, FSR0x must be saved */
11842 islocal = (reg1->isLocal || reg1->rIdx == pic16_framepnt_lo->rIdx || reg1->rIdx == pic16_framepnt_hi->rIdx);
11843 if (islocal && elementsInSet (reg1->reglives.usedpCodes) == 2) {
11845 for (i=0; i < 2; i++) {
11846 pc = (pCode *) indexSet(reg1->reglives.usedpCodes, i);
11847 if (!pc2) pc2 = pc;
11848 if (!isPCI(pc) || !PCI(pc)->op == POC_MOVFF) continue;
11849 reg2 = pic16_getRegFromInstruction (pc);
11850 reg3 = pic16_getRegFromInstruction2 (pc);
11852 || (reg2->rIdx != pic16_stack_preinc->rIdx
11853 && reg3->rIdx != pic16_stack_postdec->rIdx)) break;
11855 /* both pCodes are MOVFF R,POSTDEC1 / MOVFF PREINC1,R */
11856 //fprintf (stderr, "%s: removing local register %s from %s\n", __FUNCTION__, reg1->name, pic16_pBlockGetFunctionName (pb));
11857 pic16_safepCodeRemove (pc, "removed unused local reg IN");
11858 pic16_safepCodeRemove (pc2, "removed unused local reg OUT");
11862 deleteSet (®1->reglives.usedpCodes);
11865 deleteSet (&seenRegs);
11872 /* Set up pCodeFlow's defmap_ts.
11873 * Needs correctly set up to/from fields. */
11874 static void pic16_createDF (pBlock *pb) {
11878 //fprintf (stderr, "creating DF for pb %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11880 pic16_destructDF (pb);
11882 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
11883 if (pic16_pBlockHasAsmdirs (pb)) {
11884 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
11888 /* integrity check -- we need to reach all flows to guarantee
11889 * correct data flow analysis (reaching definitions, aliveness) */
11891 if (!verifyAllFlowsReachable (pb)) {
11892 fprintf (stderr, "not all flows reachable -- aborting dataflow analysis for %s!\n", pic16_pBlockGetFunctionName (pb));
11897 /* establish new defmaps */
11898 pc = pic16_findNextInstruction (pb->pcHead);
11900 next = pic16_findNextInstruction (pc->next);
11902 assert (PCI(pc)->pcflow);
11903 PCI(pc)->pcflow->defmap = createDefmap (pc, PCI(pc)->pcflow->defmap);
11908 //fprintf (stderr, "%s: creating reaching definitions...\n", __FUNCTION__);
11909 createReachingDefinitions (pb);
11912 /* assign better valnums */
11913 //fprintf (stderr, "assigning valnums for pb %p\n", pb);
11914 pc = pic16_findNextInstruction (pb->pcHead);
11916 next = pic16_findNextInstruction (pc->next);
11918 assert (PCI(pc)->pcflow);
11919 assignValnums (pc);
11926 /* remove dead pCodes */
11927 //fprintf (stderr, "removing dead pCodes in %p (%s)\n", pb, pic16_pBlockGetFunctionName (pb));
11930 pc = pic16_findNextInstruction (pb->pcHead);
11932 next = pic16_findNextInstruction (pc->next);
11934 if (isPCI(pc) && !isPCI_BRANCH(pc) && !pic16_pCodeIsAlive (pc)) {
11935 change += pic16_safepCodeRemove (pc, "=DF= removed dead pCode");
11945 /* ======================================================================= */
11946 /* === DEPRECATED CONTROL FLOW CREATION ROUTINES ========================= */
11947 /* ======================================================================= */
11951 /* connect pCode f anf t via their to/from pBranches */
11952 static void pic16_pCodeLink (pCode *f, pCode *t) {
11954 pCodeInstruction *_f, *_t;
11956 if (!f || !t) return;
11959 fprintf (stderr, "linking:\n");
11960 f->print(stderr, f);
11961 f->print(stderr, t);
11964 assert (isPCI(f) || isPCAD(f));
11965 assert (isPCI(t) || isPCAD(t));
11969 /* define t to be CF successor of f */
11970 br = Safe_malloc (sizeof (pBranch));
11973 _f->to = pic16_pBranchAppend (_f->to, br);
11975 /* define f to be CF predecessor of t */
11976 br = Safe_malloc (sizeof (pBranch));
11979 _t->from = pic16_pBranchAppend (_t->from, br);
11981 /* also update pcflow information */
11982 if (_f->pcflow && _t->pcflow && _f->pcflow != _t->pcflow) {
11983 //fprintf (stderr, "creating flow %p --> %p\n", _f->pcflow, _t->pcflow);
11984 LinkFlow_pCode (_f, _t);
11988 static void pic16_destructCF (pBlock *pb) {
11992 /* remove old CF information */
11996 while (PCI(pc)->to) {
11997 br = PCI(pc)->to->next;
11998 Safe_free (PCI(pc)->to);
12001 while (PCI(pc)->from) {
12002 br = PCI(pc)->from->next;
12003 Safe_free (PCI(pc)->from);
12004 PCI(pc)->from = br;
12006 } else if (isPCFL(pc)) {
12007 deleteSet (&PCFL(pc)->to);
12008 deleteSet (&PCFL(pc)->from);
12016 /* Set up pCodeInstruction's to and from pBranches. */
12017 static void pic16_createCF (pBlock *pb) {
12019 pCode *next, *dest;
12022 //fprintf (stderr, "creating CF for %p\n", pb);
12024 pic16_destructCF (pb);
12026 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12027 if (pic16_pBlockHasAsmdirs (pb)) {
12028 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12032 pc = pic16_findNextInstruction(pb->pcHead);
12034 next = pic16_findNextInstruction(pc->next);
12035 if (isPCI_SKIP(pc)) {
12036 pic16_pCodeLink(pc, next);
12037 pic16_pCodeLink(pc, pic16_findNextInstruction(next->next));
12038 } else if (isPCI_BRANCH(pc)) {
12039 // Bcc, BRA, CALL, GOTO
12040 if (PCI(pc)->pcop) {
12041 switch (PCI(pc)->pcop->type) {
12043 label = PCOLAB(PCI(pc)->pcop)->pcop.name;
12044 dest = findLabelinpBlock (pc->pb, PCOLAB(PCI(pc)->pcop));
12048 /* needed for GOTO ___irq_handler */
12049 label = PCI(pc)->pcop->name;
12054 assert (0 && "invalid label format");
12062 switch (PCI(pc)->op) {
12065 if (dest != NULL) {
12066 pic16_pCodeLink(pc, dest);
12068 //fprintf (stderr, "jump target \"%s\" not found!\n", label);
12074 pic16_pCodeLink(pc, next);
12084 if (dest != NULL) {
12085 pic16_pCodeLink(pc, dest);
12087 //fprintf (stderr, "jump target \"%s\"not found!\n", label);
12089 pic16_pCodeLink(pc, next);
12092 fprintf (stderr, "BRANCH instruction: %s\n", PCI(pc)->mnemonic);
12093 assert (0 && "unhandled branch instruction");
12097 pic16_pCodeLink (pc, next);
12104 /* ======================================================================== */
12105 /* === VCG DUMPER ROUTINES ================================================ */
12106 /* ======================================================================== */
12107 #if defined (DUMP_DF_GRAPHS) && DUMP_DF_GRAPHS > 0
12108 hTab *dumpedNodes = NULL;
12110 /** Dump VCG header into of. */
12111 static void pic16_vcg_init (FILE *of) {
12112 /* graph defaults */
12113 fprintf (of, "graph:{\n");
12114 fprintf (of, "title:\"graph1\"\n");
12115 fprintf (of, "label:\"graph1\"\n");
12116 fprintf (of, "color:white\n");
12117 fprintf (of, "textcolor:black\n");
12118 fprintf (of, "bordercolor:black\n");
12119 fprintf (of, "borderwidth:1\n");
12120 fprintf (of, "textmode:center\n");
12122 fprintf (of, "layoutalgorithm:dfs\n");
12123 fprintf (of, "late_edge_labels:yes\n");
12124 fprintf (of, "display_edge_labels:yes\n");
12125 fprintf (of, "dirty_edge_labels:yes\n");
12126 fprintf (of, "finetuning:yes\n");
12127 fprintf (of, "ignoresingles:no\n");
12128 fprintf (of, "straight_phase:yes\n");
12129 fprintf (of, "priority_phase:yes\n");
12130 fprintf (of, "manhattan_edges:yes\n");
12131 fprintf (of, "smanhattan_edges:no\n");
12132 fprintf (of, "nearedges:no\n");
12133 fprintf (of, "node_alignment:center\n"); // bottom|top|center
12134 fprintf (of, "port_sharing:no\n");
12135 fprintf (of, "arrowmode:free\n"); // fixed|free
12136 fprintf (of, "crossingphase2:yes\n");
12137 fprintf (of, "crossingoptimization:yes\n");
12138 fprintf (of, "edges:yes\n");
12139 fprintf (of, "nodes:yes\n");
12140 fprintf (of, "splines:no\n");
12142 /* node defaults */
12143 fprintf (of, "node.color:lightyellow\n");
12144 fprintf (of, "node.textcolor:black\n");
12145 fprintf (of, "node.textmode:center\n");
12146 fprintf (of, "node.shape:box\n");
12147 fprintf (of, "node.bordercolor:black\n");
12148 fprintf (of, "node.borderwidth:1\n");
12150 /* edge defaults */
12151 fprintf (of, "edge.textcolor:black\n");
12152 fprintf (of, "edge.color:black\n");
12153 fprintf (of, "edge.thickness:1\n");
12154 fprintf (of, "edge.arrowcolor:black\n");
12155 fprintf (of, "edge.backarrowcolor:black\n");
12156 fprintf (of, "edge.arrowsize:15\n");
12157 fprintf (of, "edge.backarrowsize:15\n");
12158 fprintf (of, "edge.arrowstyle:line\n"); // none|solid|line
12159 fprintf (of, "edge.backarrowstyle:none\n"); // none|solid|line
12160 fprintf (of, "edge.linestyle:continuous\n"); // continuous|solid|dotted|dashed|invisible
12162 fprintf (of, "\n");
12164 /* prepare data structures */
12166 hTabDeleteAll (dumpedNodes);
12167 dumpedNodes = NULL;
12169 dumpedNodes = newHashTable (128);
12172 /** Dump VCG footer into of. */
12173 static void pic16_vcg_close (FILE *of) {
12174 fprintf (of, "}\n");
12177 #define BUF_SIZE 128
12178 #define pcTitle(pc) (SNPRINTF (buf, BUF_SIZE, "n_%p, %p/%u", PCODE(pc), isPCI(pc) ? PCI(pc)->pcflow : NULL, PCODE(pc)->seq), &buf[0])
12181 static int ptrcmp (const void *p1, const void *p2) {
12186 /** Dump a pCode node as VCG to of. */
12187 static void pic16_vcg_dumpnode (pCode *pc, FILE *of) {
12188 char buf[BUF_SIZE];
12190 if (hTabFindByKey (dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, ptrcmp)) {
12194 hTabAddItemLong (&dumpedNodes, (((char *) pc - (char *) 0)>>2) % 128, pc, pc);
12195 //fprintf (stderr, "dumping %p\n", pc);
12197 /* only dump pCodeInstructions and Flow nodes */
12198 if (!isPCI(pc) && !isPCAD(pc) && !isPCFL(pc)) return;
12201 fprintf (of, "node:{");
12202 fprintf (of, "title:\"%s\" ", pcTitle(pc));
12203 fprintf (of, "label:\"%s\n", pcTitle(pc));
12205 fprintf (of, "<PCFLOW>");
12206 } else if (isPCI(pc) || isPCAD(pc)) {
12207 pc->print (of, pc);
12209 fprintf (of, "<!PCI>");
12211 fprintf (of, "\" ");
12212 fprintf (of, "}\n");
12214 if (1 && isPCFL(pc)) {
12215 defmap_t *map, *prev;
12217 map = PCFL(pc)->defmap;
12220 if (map->sym != 0) {
12223 /* emit definition node */
12224 fprintf (of, "node:{title:\"%s_def%u\" ", pcTitle(pc), i);
12225 fprintf (of, "label:\"");
12229 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));
12232 } while (map && prev->pc == map->pc);
12235 fprintf (of, "\" ");
12237 fprintf (of, "color:green ");
12238 fprintf (of, "}\n");
12240 /* emit edge to previous definition */
12241 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12243 fprintf (of, "targetname:\"%s\" ", pcTitle(pc));
12245 fprintf (of, "targetname:\"%s_def%u\" ", pcTitle(pc), i-1);
12247 fprintf (of, "color:green ");
12248 fprintf (of, "}\n");
12251 pic16_vcg_dumpnode (map->pc, of);
12252 fprintf (of, "edge:{sourcename:\"%s_def%u\" ", pcTitle(pc), i);
12253 fprintf (of, "targetname:\"%s\" linestyle:dashed color:lightgreen}\n", pcTitle(map->pc));
12260 /* emit additional nodes (e.g. operands) */
12263 /** Dump a pCode's edges (control flow/data flow) as VCG to of. */
12264 static void pic16_vcg_dumpedges (pCode *pc, FILE *of) {
12265 char buf[BUF_SIZE];
12266 pCodeInstruction *pci;
12270 if (1 && isPCFL(pc)) {
12271 /* emit edges to flow successors */
12273 //fprintf (stderr, "PCFLOWe @ %p\n", pc);
12274 pcfl = setFirstItem (PCFL(pc)->to);
12276 pcfl = ((pCodeFlowLink *) (pcfl))->pcflow;
12277 pic16_vcg_dumpnode (pc, of);
12278 pic16_vcg_dumpnode ((pCode *) pcfl, of);
12279 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12280 fprintf (of, "targetname:\"%s\" color:lightred linestyle:dashed}\n", pcTitle(pcfl));
12281 pcfl = setNextItem (PCFL(pc)->to);
12285 if (!isPCI(pc) && !isPCAD(pc)) return;
12289 /* emit control flow edges (forward only) */
12293 pic16_vcg_dumpnode (curr->pc, of);
12294 fprintf (of, "edge:{");
12295 fprintf (of, "sourcename:\"%s\" ", pcTitle(pc));
12296 fprintf (of, "targetname:\"%s\" ", pcTitle(curr->pc));
12297 fprintf (of, "color:red ");
12298 fprintf (of, "}\n");
12303 /* dump "flow" edge (link pCode according to pBlock order) */
12306 pcnext = pic16_findNextInstruction (pc->next);
12308 pic16_vcg_dumpnode (pcnext, of);
12309 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12310 fprintf (of, "targetname:\"%s\" color:red linestyle:solid}\n", pcTitle(pcnext));
12318 pic16_vcg_dumpnode (&pci->pcflow->pc, of);
12319 fprintf (of, "edge:{sourcename:\"%s\" ", pcTitle(pc));
12320 fprintf (of, "targetname:\"%s\" color:lightblue linestyle:dashed}\n", pcTitle (pci->pcflow));
12324 /* emit data flow edges (backward only) */
12325 /* TODO: gather data flow information... */
12328 static void pic16_vcg_dump (FILE *of, pBlock *pb) {
12331 /* check pBlock: do not analyze pBlocks with ASMDIRs (for now...) */
12332 if (pic16_pBlockHasAsmdirs (pb)) {
12333 //fprintf (stderr, "%s: pBlock contains ASMDIRs -- data flow analysis not performed!\n", __FUNCTION__);
12337 for (pc=pb->pcHead; pc; pc = pc->next) {
12338 pic16_vcg_dumpnode (pc, of);
12341 for (pc=pb->pcHead; pc; pc = pc->next) {
12342 pic16_vcg_dumpedges (pc, of);
12346 static void pic16_vcg_dump_default (pBlock *pb) {
12348 char buf[BUF_SIZE];
12351 /* get function name */
12353 while (pc && !isPCF(pc)) pc = pc->next;
12355 SNPRINTF (buf, BUF_SIZE, "%s_%s.vcg", PCF(pc)->modname, PCF(pc)->fname);
12357 SNPRINTF (buf, BUF_SIZE, "pb_%p.vcg", pb);
12360 //fprintf (stderr, "now dumping %s\n", buf);
12361 of = fopen (buf, "w");
12362 pic16_vcg_init (of);
12363 pic16_vcg_dump (of, pb);
12364 pic16_vcg_close (of);
12369 /*** END of helpers for pCode dataflow optimizations ***/