- Added ;#CSRC labels so that a 3rd party tool can parse the .asm output
[fw/sdcc] / src / pic / pcode.c
1 /*-------------------------------------------------------------------------
2
3    pcode.c - post code generation
4    Written By -  Scott Dattalo scott@dattalo.com
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 -------------------------------------------------------------------------*/
20
21 #include <stdio.h>
22
23 #include "common.h"   // Include everything in the SDCC src directory
24 #include "newalloc.h"
25
26
27 #include "pcode.h"
28 #include "ralloc.h"
29
30 #if defined(__BORLANDC__) || defined(_MSC_VER)
31 #define STRCASECMP stricmp
32 #else
33 #define STRCASECMP strcasecmp
34 #endif
35
36 // Eventually this will go into device dependent files:
37 pCodeOpReg pc_status    = {{PO_STATUS,  "STATUS"}, -1, NULL,NULL};
38 pCodeOpReg pc_indf      = {{PO_INDF,    "INDF"}, -1, NULL,NULL};
39 pCodeOpReg pc_fsr       = {{PO_FSR,     "FSR"}, -1, NULL,NULL};
40 pCodeOpReg pc_pcl       = {{PO_PCL,     "PCL"}, -1, NULL,NULL};
41 pCodeOpReg pc_pclath    = {{PO_PCLATH,  "PCLATH"}, -1, NULL,NULL};
42
43 static int mnemonics_initialized = 0;
44
45
46 static hTab *pic14MnemonicsHash = NULL;
47
48
49
50 static pFile *the_pFile = NULL;
51 static int peepOptimizing = 1;
52 static int GpCodeSequenceNumber = 1;
53
54 /****************************************************************/
55 /*                      Forward declarations                    */
56 /****************************************************************/
57
58 static void unlinkPC(pCode *pc);
59 static void genericAnalyze(pCode *pc);
60 static void AnalyzeGOTO(pCode *pc);
61 static void AnalyzeSKIP(pCode *pc);
62 static void AnalyzeRETURN(pCode *pc);
63
64 static void genericDestruct(pCode *pc);
65 static void genericPrint(FILE *of,pCode *pc);
66
67 static void pCodePrintLabel(FILE *of, pCode *pc);
68 static void pCodePrintFunction(FILE *of, pCode *pc);
69 static void pCodeOpPrint(FILE *of, pCodeOp *pcop);
70 static char *get_op( pCodeInstruction *pcc);
71 int pCodePeepMatchLine(pCodePeep *peepBlock, pCode *pcs, pCode *pcd);
72 int pCodePeepMatchRule(pCode *pc);
73
74
75 pCodeInstruction pciADDWF = {
76   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
77    genericAnalyze,
78    genericDestruct,
79    genericPrint},
80   POC_ADDWF,
81   "ADDWF",
82   NULL, // operand
83   2,    // num ops
84   1,0,  // dest, bit instruction
85   (PCC_W | PCC_REGISTER),   // inCond
86   (PCC_REGISTER | PCC_Z) // outCond
87 };
88
89 pCodeInstruction pciADDFW = {
90   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
91    genericAnalyze,
92    genericDestruct,
93    genericPrint},
94   POC_ADDWF,
95   "ADDWF",
96   NULL, // operand
97   2,    // num ops
98   0,0,  // dest, bit instruction
99   (PCC_W | PCC_REGISTER),   // inCond
100   (PCC_W | PCC_Z) // outCond
101 };
102
103 pCodeInstruction pciADDLW = {
104   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
105    genericAnalyze,
106    genericDestruct,
107    genericPrint},
108   POC_ADDLW,
109   "ADDLW",
110   NULL, // operand
111   1,    // num ops
112   0,0,  // dest, bit instruction
113   PCC_W,   // inCond
114   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
115 };
116
117 pCodeInstruction pciANDLW = {
118   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
119    genericAnalyze,
120    genericDestruct,
121    genericPrint},
122   POC_ANDLW,
123   "ANDLW",
124   NULL, // operand
125   1,    // num ops
126   0,0,  // dest, bit instruction
127   PCC_W,   // inCond
128   (PCC_W | PCC_Z) // outCond
129 };
130
131 pCodeInstruction pciANDWF = {
132   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
133    genericAnalyze,
134    genericDestruct,
135    genericPrint},
136   POC_ANDWF,
137   "ANDWF",
138   NULL, // operand
139   2,    // num ops
140   1,0,  // dest, bit instruction
141   (PCC_W | PCC_REGISTER),   // inCond
142   (PCC_REGISTER | PCC_Z) // outCond
143 };
144
145 pCodeInstruction pciANDFW = {
146   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
147    genericAnalyze,
148    genericDestruct,
149    genericPrint},
150   POC_ANDWF,
151   "ANDWF",
152   NULL, // operand
153   2,    // num ops
154   0,0,  // dest, bit instruction
155   (PCC_W | PCC_REGISTER),   // inCond
156   (PCC_W | PCC_Z) // outCond
157 };
158
159 pCodeInstruction pciBCF = {
160   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
161    genericAnalyze,
162    genericDestruct,
163    genericPrint},
164   POC_BCF,
165   "BCF",
166   NULL, // operand
167   2,    // num ops
168   0,1,  // dest, bit instruction
169   PCC_NONE,   // inCond
170   PCC_EXAMINE_PCOP // outCond
171 };
172
173 pCodeInstruction pciBSF = {
174   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
175    genericAnalyze,
176    genericDestruct,
177    genericPrint},
178   POC_BSF,
179   "BSF",
180   NULL, // operand
181   2,    // num ops
182   0,1,  // dest, bit instruction
183   PCC_NONE,   // inCond
184   PCC_EXAMINE_PCOP // outCond
185 };
186
187 pCodeInstruction pciBTFSC = {
188   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
189    AnalyzeSKIP,
190    genericDestruct,
191    genericPrint},
192   POC_BTFSC,
193   "BTFSC",
194   NULL, // operand
195   2,    // num ops
196   0,1,  // dest, bit instruction
197   PCC_EXAMINE_PCOP,   // inCond
198   PCC_NONE // outCond
199 };
200
201 pCodeInstruction pciBTFSS = {
202   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
203    AnalyzeSKIP,
204    genericDestruct,
205    genericPrint},
206   POC_BTFSS,
207   "BTFSS",
208   NULL, // operand
209   2,    // num ops
210   0,1,  // dest, bit instruction
211   PCC_EXAMINE_PCOP,   // inCond
212   PCC_NONE // outCond
213 };
214
215 pCodeInstruction pciCALL = {
216   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
217    genericAnalyze,
218    genericDestruct,
219    genericPrint},
220   POC_CALL,
221   "CALL",
222   NULL, // operand
223   1,    // num ops
224   0,0,  // dest, bit instruction
225   PCC_NONE, // inCond
226   PCC_NONE  // outCond
227 };
228
229 pCodeInstruction pciCOMF = {
230   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
231    genericAnalyze,
232    genericDestruct,
233    genericPrint},
234   POC_COMF,
235   "COMF",
236   NULL, // operand
237   2,    // num ops
238   1,0,  // dest, bit instruction
239   PCC_REGISTER,  // inCond
240   PCC_REGISTER   // outCond
241 };
242
243 pCodeInstruction pciCOMFW = {
244   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
245    genericAnalyze,
246    genericDestruct,
247    genericPrint},
248   POC_COMFW,
249   "COMF",
250   NULL, // operand
251   2,    // num ops
252   0,0,  // dest, bit instruction
253   PCC_REGISTER,  // inCond
254   PCC_W   // outCond
255 };
256
257 pCodeInstruction pciCLRF = {
258   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
259    genericAnalyze,
260    genericDestruct,
261    genericPrint},
262   POC_CLRF,
263   "CLRF",
264   NULL, // operand
265   1,    // num ops
266   0,0,  // dest, bit instruction
267   PCC_REGISTER, // inCond
268   PCC_REGISTER  // outCond
269 };
270
271 pCodeInstruction pciCLRW = {
272   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
273    genericAnalyze,
274    genericDestruct,
275    genericPrint},
276   POC_CLRW,
277   "CLRW",
278   NULL, // operand
279   0,    // num ops
280   0,0,  // dest, bit instruction
281   PCC_W, // inCond
282   PCC_W  // outCond
283 };
284
285 pCodeInstruction pciDECF = {
286   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
287    genericAnalyze,
288    genericDestruct,
289    genericPrint},
290   POC_DECF,
291   "DECF",
292   NULL, // operand
293   2,    // num ops
294   1,0,  // dest, bit instruction
295   PCC_REGISTER,   // inCond
296   PCC_REGISTER    // outCond
297 };
298
299 pCodeInstruction pciDECFW = {
300   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
301    genericAnalyze,
302    genericDestruct,
303    genericPrint},
304   POC_DECFW,
305   "DECF",
306   NULL, // operand
307   2,    // num ops
308   0,0,  // dest, bit instruction
309   PCC_REGISTER,   // inCond
310   PCC_W    // outCond
311 };
312
313 pCodeInstruction pciDECFSZ = {
314   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
315    AnalyzeSKIP,
316    genericDestruct,
317    genericPrint},
318   POC_DECFSZ,
319   "DECFSZ",
320   NULL, // operand
321   2,    // num ops
322   1,0,  // dest, bit instruction
323   PCC_REGISTER,   // inCond
324   PCC_REGISTER    // outCond
325 };
326
327 pCodeInstruction pciDECFSZW = {
328   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
329    AnalyzeSKIP,
330    genericDestruct,
331    genericPrint},
332   POC_DECFSZW,
333   "DECFSZ",
334   NULL, // operand
335   2,    // num ops
336   0,0,  // dest, bit instruction
337   PCC_REGISTER,   // inCond
338   PCC_W           // outCond
339 };
340
341 pCodeInstruction pciGOTO = {
342   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
343    AnalyzeGOTO,
344    genericDestruct,
345    genericPrint},
346   POC_GOTO,
347   "GOTO",
348   NULL, // operand
349   1,    // num ops
350   0,0,  // dest, bit instruction
351   PCC_NONE,   // inCond
352   PCC_NONE    // outCond
353 };
354
355
356 pCodeInstruction pciINCF = {
357   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
358    genericAnalyze,
359    genericDestruct,
360    genericPrint},
361   POC_INCF,
362   "INCF",
363   NULL, // operand
364   2,    // num ops
365   1,0,  // dest, bit instruction
366   PCC_REGISTER,   // inCond
367   PCC_REGISTER    // outCond
368 };
369
370 pCodeInstruction pciINCFW = {
371   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
372    genericAnalyze,
373    genericDestruct,
374    genericPrint},
375   POC_INCFW,
376   "INCF",
377   NULL, // operand
378   2,    // num ops
379   0,0,  // dest, bit instruction
380   PCC_REGISTER,   // inCond
381   PCC_W    // outCond
382 };
383
384 pCodeInstruction pciINCFSZ = {
385   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
386    AnalyzeSKIP,
387    genericDestruct,
388    genericPrint},
389   POC_INCFSZ,
390   "INCFSZ",
391   NULL, // operand
392   2,    // num ops
393   1,0,  // dest, bit instruction
394   PCC_REGISTER,   // inCond
395   PCC_REGISTER    // outCond
396 };
397
398 pCodeInstruction pciINCFSZW = {
399   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
400    AnalyzeSKIP,
401    genericDestruct,
402    genericPrint},
403   POC_INCFSZW,
404   "INCFSZ",
405   NULL, // operand
406   2,    // num ops
407   0,0,  // dest, bit instruction
408   PCC_REGISTER,   // inCond
409   PCC_W           // outCond
410 };
411
412 pCodeInstruction pciIORWF = {
413   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
414    genericAnalyze,
415    genericDestruct,
416    genericPrint},
417   POC_IORWF,
418   "IORWF",
419   NULL, // operand
420   2,    // num ops
421   1,0,  // dest, bit instruction
422   (PCC_W | PCC_REGISTER),   // inCond
423   (PCC_REGISTER | PCC_Z) // outCond
424 };
425
426 pCodeInstruction pciIORFW = {
427   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
428    genericAnalyze,
429    genericDestruct,
430    genericPrint},
431   POC_IORWF,
432   "IORWF",
433   NULL, // operand
434   2,    // num ops
435   0,0,  // dest, bit instruction
436   (PCC_W | PCC_REGISTER),   // inCond
437   (PCC_W | PCC_Z) // outCond
438 };
439
440 pCodeInstruction pciIORLW = {
441   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
442    genericAnalyze,
443    genericDestruct,
444    genericPrint},
445   POC_IORLW,
446   "IORLW",
447   NULL, // operand
448   1,    // num ops
449   0,0,  // dest, bit instruction
450   PCC_W,   // inCond
451   (PCC_W | PCC_Z) // outCond
452 };
453
454 pCodeInstruction pciMOVF = {
455   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
456    genericAnalyze,
457    genericDestruct,
458    genericPrint},
459   POC_MOVF,
460   "MOVF",
461   NULL, // operand
462   2,    // num ops
463   1,0,  // dest, bit instruction
464   PCC_REGISTER,   // inCond
465   PCC_Z // outCond
466 };
467
468 pCodeInstruction pciMOVFW = {
469   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
470    genericAnalyze,
471    genericDestruct,
472    genericPrint},
473   POC_MOVFW,
474   "MOVF",
475   NULL, // operand
476   2,    // num ops
477   0,0,  // dest, bit instruction
478   PCC_REGISTER,   // inCond
479   (PCC_W | PCC_Z) // outCond
480 };
481
482 pCodeInstruction pciMOVWF = {
483   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
484    genericAnalyze,
485    genericDestruct,
486    genericPrint},
487   POC_MOVWF,
488   "MOVWF",
489   NULL, // operand
490   1,    // num ops
491   0,0,  // dest, bit instruction
492   PCC_W,   // inCond
493   0 // outCond
494 };
495
496 pCodeInstruction pciMOVLW = {
497   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
498    genericAnalyze,
499    genericDestruct,
500    genericPrint},
501   POC_MOVLW,
502   "MOVLW",
503   NULL, // operand
504   1,    // num ops
505   0,0,  // dest, bit instruction
506   PCC_NONE,   // inCond
507   PCC_W // outCond
508 };
509
510 pCodeInstruction pciNEGF = {
511   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
512    genericAnalyze,
513    genericDestruct,
514    genericPrint},
515   POC_NEGF,
516   "NEGF",
517   NULL, // operand
518   1,    // num ops
519   0,0,  // dest, bit instruction
520   PCC_REGISTER,   // inCond
521   PCC_NONE // outCond
522 };
523
524
525 pCodeInstruction pciRETLW = {
526   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
527    AnalyzeRETURN,
528    genericDestruct,
529    genericPrint},
530   POC_RETLW,
531   "RETLW",
532   NULL, // operand
533   1,    // num ops
534   0,0,  // dest, bit instruction
535   PCC_NONE,   // inCond
536   PCC_W // outCond
537 };
538
539 pCodeInstruction pciRETURN = {
540   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
541    AnalyzeRETURN,
542    genericDestruct,
543    genericPrint},
544   POC_RETURN,
545   "RETURN",
546   NULL, // operand
547   0,    // num ops
548   0,0,  // dest, bit instruction
549   PCC_NONE,   // inCond
550   PCC_W // outCond
551 };
552
553
554 pCodeInstruction pciRLF = {
555   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
556    genericAnalyze,
557    genericDestruct,
558    genericPrint},
559   POC_RLF,
560   "RLF",
561   NULL, // operand
562   2,    // num ops
563   1,0,  // dest, bit instruction
564   (PCC_C | PCC_REGISTER),   // inCond
565   (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC) // outCond
566 };
567
568 pCodeInstruction pciRLFW = {
569   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
570    genericAnalyze,
571    genericDestruct,
572    genericPrint},
573   POC_RLFW,
574   "RLF",
575   NULL, // operand
576   2,    // num ops
577   0,0,  // dest, bit instruction
578   (PCC_C | PCC_REGISTER),   // inCond
579   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
580 };
581
582 pCodeInstruction pciRRF = {
583   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
584    genericAnalyze,
585    genericDestruct,
586    genericPrint},
587   POC_RRF,
588   "RRF",
589   NULL, // operand
590   2,    // num ops
591   1,0,  // dest, bit instruction
592   (PCC_C | PCC_REGISTER),   // inCond
593   (PCC_REGISTER | PCC_Z | PCC_C | PCC_DC) // outCond
594 };
595
596 pCodeInstruction pciRRFW = {
597   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
598    genericAnalyze,
599    genericDestruct,
600    genericPrint},
601   POC_RRFW,
602   "RRF",
603   NULL, // operand
604   2,    // num ops
605   0,0,  // dest, bit instruction
606   (PCC_C | PCC_REGISTER),   // inCond
607   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
608 };
609
610 pCodeInstruction pciSUBWF = {
611   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
612    genericAnalyze,
613    genericDestruct,
614    genericPrint},
615   POC_SUBWF,
616   "SUBWF",
617   NULL, // operand
618   2,    // num ops
619   1,0,  // dest, bit instruction
620   (PCC_W | PCC_REGISTER),   // inCond
621   (PCC_REGISTER | PCC_Z) // outCond
622 };
623
624 pCodeInstruction pciSUBFW = {
625   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
626    genericAnalyze,
627    genericDestruct,
628    genericPrint},
629   POC_SUBWF,
630   "SUBWF",
631   NULL, // operand
632   2,    // num ops
633   0,0,  // dest, bit instruction
634   (PCC_W | PCC_REGISTER),   // inCond
635   (PCC_W | PCC_Z) // outCond
636 };
637
638 pCodeInstruction pciSUBLW = {
639   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
640    genericAnalyze,
641    genericDestruct,
642    genericPrint},
643   POC_SUBLW,
644   "SUBLW",
645   NULL, // operand
646   1,    // num ops
647   0,0,  // dest, bit instruction
648   PCC_W,   // inCond
649   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
650 };
651
652 pCodeInstruction pciSWAPF = {
653   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
654    genericAnalyze,
655    genericDestruct,
656    genericPrint},
657   POC_SWAPF,
658   "SWAPF",
659   NULL, // operand
660   2,    // num ops
661   1,0,  // dest, bit instruction
662   (PCC_REGISTER),   // inCond
663   (PCC_REGISTER) // outCond
664 };
665
666 pCodeInstruction pciSWAPFW = {
667   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
668    genericAnalyze,
669    genericDestruct,
670    genericPrint},
671   POC_SWAPFW,
672   "SWAPF",
673   NULL, // operand
674   2,    // num ops
675   0,0,  // dest, bit instruction
676   (PCC_REGISTER),   // inCond
677   (PCC_W) // outCond
678 };
679 pCodeInstruction pciTRIS = {
680   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
681    genericAnalyze,
682    genericDestruct,
683    genericPrint},
684   POC_TRIS,
685   "TRIS",
686   NULL, // operand
687   1,    // num ops
688   0,0,  // dest, bit instruction
689   PCC_NONE,   // inCond
690   PCC_NONE
691 };
692
693
694 pCodeInstruction pciXORWF = {
695   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
696    genericAnalyze,
697    genericDestruct,
698    genericPrint},
699   POC_XORWF,
700   "XORWF",
701   NULL, // operand
702   2,    // num ops
703   1,0,  // dest, bit instruction
704   (PCC_W | PCC_REGISTER),   // inCond
705   (PCC_REGISTER | PCC_Z) // outCond
706 };
707
708 pCodeInstruction pciXORFW = {
709   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
710    genericAnalyze,
711    genericDestruct,
712    genericPrint},
713   POC_XORWF,
714   "XORWF",
715   NULL, // operand
716   2,    // num ops
717   0,0,  // dest, bit instruction
718   (PCC_W | PCC_REGISTER),   // inCond
719   (PCC_W | PCC_Z) // outCond
720 };
721
722 pCodeInstruction pciXORLW = {
723   {PC_OPCODE, NULL, NULL, 0, NULL, NULL, NULL, NULL, 
724    genericAnalyze,
725    genericDestruct,
726    genericPrint},
727   POC_XORLW,
728   "XORLW",
729   NULL, // operand
730   1,    // num ops
731   0,0,  // dest, bit instruction
732   PCC_W,   // inCond
733   (PCC_W | PCC_Z | PCC_C | PCC_DC) // outCond
734 };
735
736
737 #define MAX_PIC14MNEMONICS 100
738 pCodeInstruction *pic14Mnemonics[MAX_PIC14MNEMONICS];
739
740 /*-----------------------------------------------------------------*/
741 /* SAFE_snprintf - like snprintf except the string pointer is      */
742 /*                 after the string has been printed to. This is   */
743 /*                 useful for printing to string as though if it   */
744 /*                 were a stream.                                  */
745 /*-----------------------------------------------------------------*/
746 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
747 {
748   va_list val;
749   int len;
750
751   if(!str || !*str)
752     return;
753
754   va_start(val, format);
755 #if 0
756   // Alas, vsnprintf is not ANSI standard, and does not exist
757   // on Solaris (and probably other non-Gnu flavored Unixes).
758   vsnprintf(*str, *size, format, val);
759 #else
760   // This, of course, is *not* safe, despite the name.
761   vsprintf(*str, format, val);
762 #endif
763     
764   va_end (val);
765
766   len = strlen(*str);
767   *str += len;
768   *size -= len;
769
770 }
771
772 void  pCodeInitRegisters(void)
773 {
774
775   pc_fsr.rIdx = 4;
776   pc_fsr.r = pic14_regWithIdx(4);
777
778 }
779
780 /*-----------------------------------------------------------------*/
781 /*  mnem2key - convert a pic mnemonic into a hash key              */
782 /*   (BTW - this spreads the mnemonics quite well)                 */
783 /*                                                                 */
784 /*-----------------------------------------------------------------*/
785
786 int mnem2key(char const *mnem)
787 {
788   int key = 0;
789
790   if(!mnem)
791     return 0;
792
793   while(*mnem) {
794
795     key += toupper(*mnem++) +1;
796
797   }
798
799   return (key & 0x1f);
800
801 }
802
803 void pic14initMnemonics(void)
804 {
805   int i = 0;
806   int key;
807   //  char *str;
808   pCodeInstruction *pci;
809
810   if(mnemonics_initialized)
811     return;
812
813   pic14Mnemonics[POC_ADDLW] = &pciADDLW;
814   pic14Mnemonics[POC_ADDWF] = &pciADDWF;
815   pic14Mnemonics[POC_ADDFW] = &pciADDFW;
816   pic14Mnemonics[POC_ANDLW] = &pciANDLW;
817   pic14Mnemonics[POC_ANDWF] = &pciANDWF;
818   pic14Mnemonics[POC_ANDFW] = &pciANDFW;
819   pic14Mnemonics[POC_BCF] = &pciBCF;
820   pic14Mnemonics[POC_BSF] = &pciBSF;
821   pic14Mnemonics[POC_BTFSC] = &pciBTFSC;
822   pic14Mnemonics[POC_BTFSS] = &pciBTFSS;
823   pic14Mnemonics[POC_CALL] = &pciCALL;
824   pic14Mnemonics[POC_COMF] = &pciCOMF;
825   pic14Mnemonics[POC_COMFW] = &pciCOMFW;
826   pic14Mnemonics[POC_CLRF] = &pciCLRF;
827   pic14Mnemonics[POC_CLRW] = &pciCLRW;
828   pic14Mnemonics[POC_DECF] = &pciDECF;
829   pic14Mnemonics[POC_DECFW] = &pciDECFW;
830   pic14Mnemonics[POC_DECFSZ] = &pciDECFSZ;
831   pic14Mnemonics[POC_DECFSZW] = &pciDECFSZW;
832   pic14Mnemonics[POC_GOTO] = &pciGOTO;
833   pic14Mnemonics[POC_INCF] = &pciINCF;
834   pic14Mnemonics[POC_INCFW] = &pciINCFW;
835   pic14Mnemonics[POC_INCFSZ] = &pciINCFSZ;
836   pic14Mnemonics[POC_INCFSZW] = &pciINCFSZW;
837   pic14Mnemonics[POC_IORLW] = &pciIORLW;
838   pic14Mnemonics[POC_IORWF] = &pciIORWF;
839   pic14Mnemonics[POC_IORFW] = &pciIORFW;
840   pic14Mnemonics[POC_MOVF] = &pciMOVF;
841   pic14Mnemonics[POC_MOVFW] = &pciMOVFW;
842   pic14Mnemonics[POC_MOVLW] = &pciMOVLW;
843   pic14Mnemonics[POC_MOVWF] = &pciMOVWF;
844   pic14Mnemonics[POC_NEGF] = &pciNEGF;
845   pic14Mnemonics[POC_RETLW] = &pciRETLW;
846   pic14Mnemonics[POC_RETURN] = &pciRETURN;
847   pic14Mnemonics[POC_RLF] = &pciRLF;
848   pic14Mnemonics[POC_RLFW] = &pciRLFW;
849   pic14Mnemonics[POC_RRF] = &pciRRF;
850   pic14Mnemonics[POC_RRFW] = &pciRRFW;
851   pic14Mnemonics[POC_SUBLW] = &pciSUBLW;
852   pic14Mnemonics[POC_SUBWF] = &pciSUBWF;
853   pic14Mnemonics[POC_SUBFW] = &pciSUBFW;
854   pic14Mnemonics[POC_SWAPF] = &pciSWAPF;
855   pic14Mnemonics[POC_SWAPFW] = &pciSWAPFW;
856   pic14Mnemonics[POC_TRIS] = &pciTRIS;
857   pic14Mnemonics[POC_XORLW] = &pciXORLW;
858   pic14Mnemonics[POC_XORWF] = &pciXORWF;
859   pic14Mnemonics[POC_XORFW] = &pciXORFW;
860
861   for(i=0; i<MAX_PIC14MNEMONICS; i++)
862     if(pic14Mnemonics[i])
863       hTabAddItem(&pic14MnemonicsHash, mnem2key(pic14Mnemonics[i]->mnemonic), pic14Mnemonics[i]);
864   pci = hTabFirstItem(pic14MnemonicsHash, &key);
865
866   while(pci) {
867     fprintf( stderr, "element %d key %d, mnem %s\n",i++,key,pci->mnemonic);
868     pci = hTabNextItem(pic14MnemonicsHash, &key);
869   }
870
871   mnemonics_initialized = 1;
872 }
873
874 int getpCode(char *mnem,unsigned dest)
875 {
876
877   pCodeInstruction *pci;
878   int key = mnem2key(mnem);
879
880   if(!mnemonics_initialized)
881     pic14initMnemonics();
882
883   pci = hTabFirstItemWK(pic14MnemonicsHash, key);
884
885   while(pci) {
886
887     if(STRCASECMP(pci->mnemonic, mnem) == 0) {
888       if((pci->num_ops <= 1) || (pci->dest == dest))
889         return(pci->op);
890     }
891
892     pci = hTabNextItemWK (pic14MnemonicsHash);
893   
894   }
895
896   return -1;
897 }
898
899 char getpBlock_dbName(pBlock *pb)
900 {
901   if(!pb)
902     return 0;
903
904   if(pb->cmemmap)
905     return pb->cmemmap->dbName;
906
907   return pb->dbName;
908 }
909 /*-----------------------------------------------------------------*/
910 /* movepBlock2Head - given the dbname of a pBlock, move all        */
911 /*                   instances to the front of the doubly linked   */
912 /*                   list of pBlocks                               */
913 /*-----------------------------------------------------------------*/
914
915 void movepBlock2Head(char dbName)
916 {
917   pBlock *pb;
918
919   pb = the_pFile->pbHead;
920
921   while(pb) {
922
923     if(getpBlock_dbName(pb) == dbName) {
924       pBlock *pbn = pb->next;
925       pb->next = the_pFile->pbHead;
926       the_pFile->pbHead->prev = pb;
927       the_pFile->pbHead = pb;
928
929       if(pb->prev)
930         pb->prev->next = pbn;
931
932       // If the pBlock that we just moved was the last
933       // one in the link of all of the pBlocks, then we
934       // need to point the tail to the block just before
935       // the one we moved.
936       // Note: if pb->next is NULL, then pb must have 
937       // been the last pBlock in the chain.
938
939       if(pbn)
940         pbn->prev = pb->prev;
941       else
942         the_pFile->pbTail = pb->prev;
943
944       pb = pbn;
945
946     } else
947       pb = pb->next;
948
949   }
950
951 }
952
953 void copypCode(FILE *of, char dbName)
954 {
955   pBlock *pb;
956
957   if(!of || !the_pFile)
958     return;
959
960   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
961     if(getpBlock_dbName(pb) == dbName)
962       printpBlock(of,pb);
963   }
964
965 }
966 void pcode_test(void)
967 {
968
969   printf("pcode is alive!\n");
970
971   //initMnemonics();
972
973   if(the_pFile) {
974
975     pBlock *pb;
976     FILE *pFile;
977     char buffer[100];
978
979     /* create the file name */
980     strcpy(buffer,srcFileName);
981     strcat(buffer,".p");
982
983     if( !(pFile = fopen(buffer, "w" ))) {
984       werror(E_FILE_OPEN_ERR,buffer);
985       exit(1);
986     }
987
988     fprintf(pFile,"pcode dump\n\n");
989
990     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
991       fprintf(pFile,"\n\tNew pBlock\n\n");
992       if(pb->cmemmap)
993         fprintf(pFile,"%s",pb->cmemmap->sname);
994       else
995         fprintf(pFile,"internal pblock");
996
997       fprintf(pFile,", dbName =%c\n",getpBlock_dbName(pb));
998       printpBlock(pFile,pb);
999     }
1000   }
1001 }
1002 static int RegCond(pCodeOp *pcop)
1003 {
1004
1005   if(!pcop)
1006     return 0;
1007
1008   if(pcop->type == PO_BIT  && !strcmp(pcop->name, pc_status.pcop.name)) {
1009     switch(PCOB(pcop)->bit) {
1010     case PIC_C_BIT:
1011       return PCC_C;
1012     case PIC_DC_BIT:
1013         return PCC_DC;
1014     case PIC_Z_BIT:
1015       return PCC_Z;
1016     }
1017
1018   }
1019
1020   return 0;
1021 }
1022
1023 /*-----------------------------------------------------------------*/
1024 /* newpCode - create and return a newly initialized pCode          */
1025 /*                                                                 */
1026 /*  fixme - rename this                                            */
1027 /*                                                                 */
1028 /* The purpose of this routine is to create a new Instruction      */
1029 /* pCode. This is called by gen.c while the assembly code is being */
1030 /* generated.                                                      */
1031 /*                                                                 */
1032 /* Inouts:                                                         */
1033 /*  PIC_OPCODE op - the assembly instruction we wish to create.    */
1034 /*                  (note that the op is analogous to but not the  */
1035 /*                  same thing as the opcode of the instruction.)  */
1036 /*  pCdoeOp *pcop - pointer to the operand of the instruction.     */
1037 /*                                                                 */
1038 /* Outputs:                                                        */
1039 /*  a pointer to the new malloc'd pCode is returned.               */
1040 /*                                                                 */
1041 /*                                                                 */
1042 /*                                                                 */
1043 /*-----------------------------------------------------------------*/
1044 pCode *newpCode (PIC_OPCODE op, pCodeOp *pcop)
1045 {
1046   pCodeInstruction *pci ;
1047
1048   if(!mnemonics_initialized)
1049     pic14initMnemonics();
1050     
1051   pci = Safe_calloc(1, sizeof(pCodeInstruction));
1052
1053   if((op>=0) && (op < MAX_PIC14MNEMONICS) && pic14Mnemonics[op]) {
1054     memcpy(pci, pic14Mnemonics[op], sizeof(pCodeInstruction));
1055     pci->pcop = pcop;
1056
1057     if(pci->inCond == PCC_EXAMINE_PCOP)
1058       pci->inCond   = RegCond(pcop);
1059
1060     if(pci->outCond == PCC_EXAMINE_PCOP)
1061       pci->outCond   = RegCond(pcop);
1062
1063     return (pCode *)pci;
1064   }
1065
1066   fprintf(stderr, "pCode mnemonic error %s,%d\n",__FUNCTION__,__LINE__);
1067   exit(1);
1068
1069   return NULL;
1070 }       
1071
1072 /*-----------------------------------------------------------------*/
1073 /* newpCodeWild - create a "wild" as in wild card pCode            */
1074 /*                                                                 */
1075 /* Wild pcodes are used during the peep hole optimizer to serve    */
1076 /* as place holders for any instruction. When a snippet of code is */
1077 /* compared to a peep hole rule, the wild card opcode will match   */
1078 /* any instruction. However, the optional operand and label are    */
1079 /* additional qualifiers that must also be matched before the      */
1080 /* line (of assembly code) is declared matched. Note that the      */
1081 /* operand may be wild too.                                        */
1082 /*                                                                 */
1083 /*   Note, a wild instruction is specified just like a wild var:   */
1084 /*      %4     ; A wild instruction,                               */
1085 /*  See the peeph.def file for additional examples                 */
1086 /*                                                                 */
1087 /*-----------------------------------------------------------------*/
1088
1089 pCode *newpCodeWild(int pCodeID, pCodeOp *optional_operand, pCodeOp *optional_label)
1090 {
1091
1092   pCodeWild *pcw;
1093     
1094   pcw = Safe_calloc(1,sizeof(pCodeWild));
1095
1096   pcw->pc.type = PC_WILD;
1097   pcw->pc.prev = pcw->pc.next = NULL;
1098   pcw->pc.from = pcw->pc.to = pcw->pc.label = NULL;
1099   pcw->pc.pb = NULL;
1100
1101   pcw->pc.analyze = genericAnalyze;
1102   pcw->pc.destruct = genericDestruct;
1103   pcw->pc.print = genericPrint;
1104
1105   pcw->id = pCodeID;              // this is the 'n' in %n
1106   pcw->operand = optional_operand;
1107   pcw->label   = optional_label;
1108
1109   return ( (pCode *)pcw);
1110   
1111 }
1112
1113 /*-----------------------------------------------------------------*/
1114 /* newPcodeCharP - create a new pCode from a char string           */
1115 /*-----------------------------------------------------------------*/
1116
1117 pCode *newpCodeCharP(char *cP)
1118 {
1119
1120   pCodeComment *pcc ;
1121     
1122   pcc = Safe_calloc(1,sizeof(pCodeComment));
1123
1124   pcc->pc.type = PC_COMMENT;
1125   pcc->pc.prev = pcc->pc.next = NULL;
1126   pcc->pc.from = pcc->pc.to = pcc->pc.label = NULL;
1127   pcc->pc.pb = NULL;
1128
1129   pcc->pc.analyze = genericAnalyze;
1130   pcc->pc.destruct = genericDestruct;
1131   pcc->pc.print = genericPrint;
1132
1133   if(cP)
1134     pcc->comment = Safe_strdup(cP);
1135   else
1136     pcc->comment = NULL;
1137
1138   return ( (pCode *)pcc);
1139
1140 }
1141
1142 /*-----------------------------------------------------------------*/
1143 /* newpCodeGLabel - create a new global label                      */
1144 /*-----------------------------------------------------------------*/
1145
1146
1147 pCode *newpCodeFunction(char *mod,char *f)
1148 {
1149   pCodeFunction *pcf;
1150
1151   _ALLOC(pcf,sizeof(pCodeFunction));
1152
1153   pcf->pc.type = PC_FUNCTION;
1154   pcf->pc.prev = pcf->pc.next = NULL;
1155   pcf->pc.from = pcf->pc.to = pcf->pc.label = NULL;
1156   pcf->pc.pb = NULL;
1157
1158   pcf->pc.analyze = genericAnalyze;
1159   pcf->pc.destruct = genericDestruct;
1160   pcf->pc.print = pCodePrintFunction;
1161
1162   if(mod) {
1163     _ALLOC_ATOMIC(pcf->modname,strlen(mod)+1);
1164     strcpy(pcf->modname,mod);
1165   } else
1166     pcf->modname = NULL;
1167
1168   if(f) {
1169     _ALLOC_ATOMIC(pcf->fname,strlen(f)+1);
1170     strcpy(pcf->fname,f);
1171   } else
1172     pcf->fname = NULL;
1173
1174   return ( (pCode *)pcf);
1175
1176 }
1177
1178 static void pCodeLabelDestruct(pCode *pc)
1179 {
1180
1181   if(!pc)
1182     return;
1183
1184   if((pc->type == PC_LABEL) && PCL(pc)->label)
1185     free(PCL(pc)->label);
1186
1187   free(pc);
1188
1189 }
1190
1191 pCode *newpCodeLabel(int key)
1192 {
1193
1194   char *s = buffer;
1195   pCodeLabel *pcl;
1196     
1197   pcl = Safe_calloc(1,sizeof(pCodeLabel) );
1198
1199   pcl->pc.type = PC_LABEL;
1200   pcl->pc.prev = pcl->pc.next = NULL;
1201   pcl->pc.from = pcl->pc.to = pcl->pc.label = NULL;
1202   pcl->pc.pb = NULL;
1203
1204   pcl->pc.analyze = genericAnalyze;
1205   pcl->pc.destruct = pCodeLabelDestruct;
1206   pcl->pc.print = pCodePrintLabel;
1207
1208   pcl->key = key;
1209
1210   pcl->label = NULL;
1211   if(key>0) {
1212     sprintf(s,"_%05d_DS_",key);
1213     if(s)
1214       pcl->label = Safe_strdup(s);
1215   }
1216
1217
1218   return ( (pCode *)pcl);
1219
1220 }
1221 pCode *newpCodeLabelStr(char *str)
1222 {
1223   pCode *pc = newpCodeLabel(-1);
1224
1225   if(str)
1226     PCL(pc)->label = Safe_strdup(str);
1227   else
1228     PCL(pc)->label = NULL;
1229
1230   return pc;
1231 }
1232
1233 /*-----------------------------------------------------------------*/
1234 /* newpBlock - create and return a pointer to a new pBlock         */
1235 /*-----------------------------------------------------------------*/
1236 pBlock *newpBlock(void)
1237 {
1238
1239   pBlock *PpB;
1240
1241   PpB = Safe_calloc(1,sizeof(pBlock) );
1242   PpB->next = PpB->prev = NULL;
1243
1244   PpB->function_entries = PpB->function_exits = PpB->function_calls = NULL;
1245   PpB->registers = NULL;
1246   PpB->visited = 0;
1247
1248   return PpB;
1249
1250 }
1251
1252 /*-----------------------------------------------------------------*/
1253 /* newpCodeChai0n - create a new chain of pCodes                    */
1254 /*-----------------------------------------------------------------*
1255  *
1256  *  This function will create a new pBlock and the pointer to the
1257  *  pCode that is passed in will be the first pCode in the block.
1258  *-----------------------------------------------------------------*/
1259
1260
1261 pBlock *newpCodeChain(memmap *cm,char c, pCode *pc)
1262 {
1263
1264   pBlock *pB  = newpBlock();
1265
1266   pB->pcHead  = pB->pcTail = pc;
1267   pB->cmemmap = cm;
1268   pB->dbName  = c;
1269
1270   return pB;
1271 }
1272
1273 /*-----------------------------------------------------------------*/
1274 /* newpCodeOpLabel - Create a new label given the key              */
1275 /*  Note, a negative key means that the label is part of wild card */
1276 /*  (and hence a wild card label) used in the pCodePeep            */
1277 /*   optimizations).                                               */
1278 /*-----------------------------------------------------------------*/
1279
1280 pCodeOp *newpCodeOpLabel(int key)
1281 {
1282   char *s = buffer;
1283   pCodeOp *pcop;
1284
1285   pcop = Safe_calloc(1,sizeof(pCodeOpLabel) );
1286   pcop->type = PO_LABEL;
1287
1288   pcop->name = NULL;
1289   if(key>0) {
1290     sprintf(s,"_%05d_DS_",key);
1291     if(s)
1292       pcop->name = Safe_strdup(s);
1293   } 
1294
1295
1296   ((pCodeOpLabel *)pcop)->key = key;
1297
1298   return pcop;
1299 }
1300
1301 pCodeOp *newpCodeOpLit(int lit)
1302 {
1303   char *s = buffer;
1304   pCodeOp *pcop;
1305
1306
1307   pcop = Safe_calloc(1,sizeof(pCodeOpLit) );
1308   pcop->type = PO_LITERAL;
1309   pcop->name = NULL;
1310   if(lit>=0) {
1311     sprintf(s,"0x%02x",lit);
1312     if(s)
1313       pcop->name = Safe_strdup(s);
1314   } 
1315
1316
1317   ((pCodeOpLit *)pcop)->lit = lit;
1318
1319   return pcop;
1320 }
1321
1322 pCodeOp *newpCodeOpWild(int id, pCodePeep *pcp, pCodeOp *subtype)
1323 {
1324   char *s = buffer;
1325   pCodeOp *pcop;
1326
1327
1328   if(!pcp || !subtype) {
1329     fprintf(stderr, "Wild opcode declaration error: %s-%d\n",__FILE__,__LINE__);
1330     exit(1);
1331   }
1332
1333   pcop = Safe_calloc(1,sizeof(pCodeOpWild));
1334   pcop->type = PO_WILD;
1335   sprintf(s,"%%%d",id);
1336   pcop->name = Safe_strdup(s);
1337
1338   PCOW(pcop)->id = id;
1339   PCOW(pcop)->pcp = pcp;
1340   PCOW(pcop)->subtype = subtype;
1341   PCOW(pcop)->matched = NULL;
1342
1343   return pcop;
1344 }
1345
1346 pCodeOp *newpCodeOpBit(char *s, int bit, int inBitSpace)
1347 {
1348   pCodeOp *pcop;
1349
1350   pcop = Safe_calloc(1,sizeof(pCodeOpBit) );
1351   pcop->type = PO_BIT;
1352   if(s)
1353     pcop->name = Safe_strdup(s);   
1354   else
1355     pcop->name = NULL;
1356
1357   PCOB(pcop)->bit = bit;
1358   PCOB(pcop)->inBitSpace = inBitSpace;
1359
1360   return pcop;
1361 }
1362
1363 pCodeOp *newpCodeOpReg(int rIdx)
1364 {
1365   pCodeOp *pcop;
1366
1367   pcop = Safe_calloc(1,sizeof(pCodeOpReg) );
1368
1369   PCOR(pcop)->rIdx = rIdx;
1370   PCOR(pcop)->r = pic14_regWithIdx(rIdx);
1371   pcop->type = PCOR(pcop)->r->pc_type;
1372
1373   return pcop;
1374 }
1375
1376 /*-----------------------------------------------------------------*/
1377 /*-----------------------------------------------------------------*/
1378
1379 pCodeOp *newpCodeOp(char *name, PIC_OPTYPE type)
1380 {
1381   pCodeOp *pcop;
1382
1383   switch(type) {
1384   case PO_BIT:
1385     pcop = newpCodeOpBit(name, -1,0);
1386     break;
1387
1388   case PO_LITERAL:
1389     pcop = newpCodeOpLit(-1);
1390     break;
1391
1392   case PO_LABEL:
1393     pcop = newpCodeOpLabel(-1);
1394     break;
1395
1396   default:
1397     pcop = Safe_calloc(1,sizeof(pCodeOp) );
1398     pcop->type = type;
1399     if(name)
1400       pcop->name = Safe_strdup(name);   
1401     else
1402       pcop->name = NULL;
1403   }
1404
1405   return pcop;
1406 }
1407
1408 /*-----------------------------------------------------------------*/
1409 /* addpCode2pBlock - place the pCode into the pBlock linked list   */
1410 /*-----------------------------------------------------------------*/
1411 void addpCode2pBlock(pBlock *pb, pCode *pc)
1412 {
1413   if(!pb->pcHead) {
1414     /* If this is the first pcode to be added to a block that
1415      * was initialized with a NULL pcode, then go ahead and
1416      * make this pcode the head and tail */
1417     pb->pcHead  = pb->pcTail = pc;
1418   } else {
1419     pb->pcTail->next = pc;
1420     pc->prev = pb->pcTail;
1421     pc->next = NULL;
1422     pc->pb = pb;
1423     pb->pcTail = pc;
1424   }
1425 }
1426
1427 /*-----------------------------------------------------------------*/
1428 /* addpBlock - place a pBlock into the pFile                       */
1429 /*-----------------------------------------------------------------*/
1430 void addpBlock(pBlock *pb)
1431 {
1432
1433   if(!the_pFile) {
1434     /* First time called, we'll pass through here. */
1435     _ALLOC(the_pFile,sizeof(pFile));
1436     the_pFile->pbHead = the_pFile->pbTail = pb;
1437     the_pFile->functions = NULL;
1438     return;
1439   }
1440
1441   the_pFile->pbTail->next = pb;
1442   pb->prev = the_pFile->pbTail;
1443   pb->next = NULL;
1444   the_pFile->pbTail = pb;
1445 }
1446
1447 /*-----------------------------------------------------------------*/
1448 /* printpCode - write the contents of a pCode to a file            */
1449 /*-----------------------------------------------------------------*/
1450 void printpCode(FILE *of, pCode *pc)
1451 {
1452
1453   if(!pc || !of)
1454     return;
1455
1456   if(pc->print) {
1457     pc->print(of,pc);
1458     return;
1459   }
1460
1461   fprintf(of,"warning - unable to print pCode\n");
1462 }
1463
1464 /*-----------------------------------------------------------------*/
1465 /* printpBlock - write the contents of a pBlock to a file          */
1466 /*-----------------------------------------------------------------*/
1467 void printpBlock(FILE *of, pBlock *pb)
1468 {
1469   pCode *pc;
1470
1471   if(!pb)
1472     return;
1473
1474   if(!of)
1475     of = stderr;
1476
1477   for(pc = pb->pcHead; pc; pc = pc->next)
1478     printpCode(of,pc);
1479
1480 }
1481
1482 /*-----------------------------------------------------------------*/
1483 /*                                                                 */
1484 /*       pCode processing                                          */
1485 /*                                                                 */
1486 /*                                                                 */
1487 /*                                                                 */
1488 /*-----------------------------------------------------------------*/
1489
1490 static void unlinkPC(pCode *pc)
1491 {
1492
1493
1494   if(pc) {
1495
1496     if(pc->prev) 
1497       pc->prev->next = pc->next;
1498     if(pc->next)
1499       pc->next->prev = pc->prev;
1500
1501     pc->prev = pc->next = NULL;
1502   }
1503 }
1504 static void genericDestruct(pCode *pc)
1505 {
1506   fprintf(stderr,"warning, calling default pCode destructor\n");
1507
1508   unlinkPC(pc);
1509
1510   free(pc);
1511
1512 }
1513
1514
1515 void pBlockRegs(FILE *of, pBlock *pb)
1516 {
1517
1518   regs  *r;
1519
1520   r = setFirstItem(pb->registers);
1521   while (r) {
1522     r = setNextItem(pb->registers);
1523   }
1524 }
1525
1526
1527 static char *get_op( pCodeInstruction *pcc)
1528 {
1529   regs *r;
1530
1531   if(pcc && pcc->pcop) {
1532
1533
1534     switch(pcc->pcop->type) {
1535
1536     case PO_FSR:
1537       r = pic14_regWithIdx(PCOR(pcc->pcop)->rIdx);
1538       return r->name;
1539       break;
1540     case PO_GPR_TEMP:
1541     case PO_GPR_BIT:
1542       r = pic14_regWithIdx(PCOR(pcc->pcop)->r->rIdx);
1543       //fprintf(stderr,"getop: getting %s\nfrom:\n",r->name); //pcc->pcop->name);
1544       pBlockRegs(stderr,pcc->pc.pb);
1545       return r->name;
1546
1547     default:
1548       if  (pcc->pcop->name)
1549         return pcc->pcop->name;
1550
1551     }
1552   }
1553
1554   return "NO operand";
1555 }
1556
1557 /*-----------------------------------------------------------------*/
1558 /*-----------------------------------------------------------------*/
1559 static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
1560 {
1561
1562   fprintf(of,"pcodeopprint\n");
1563 }
1564
1565 char *pCode2str(char *str, int size, pCode *pc)
1566 {
1567   char *s = str;
1568
1569   switch(pc->type) {
1570
1571   case PC_OPCODE:
1572
1573     SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
1574
1575     if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
1576
1577       if(PCI(pc)->bit_inst) {
1578         if(PCI(pc)->pcop->type == PO_BIT) {
1579           if( (((pCodeOpBit *)(PCI(pc)->pcop))->inBitSpace) )
1580             SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", 
1581                           PCI(pc)->pcop->name ,
1582                           PCI(pc)->pcop->name );
1583           else
1584             SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)), 
1585                           (((pCodeOpBit *)(PCI(pc)->pcop))->bit ));
1586         } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
1587           SAFE_snprintf(&s,&size,"%s,%d", get_op(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
1588         }else
1589           SAFE_snprintf(&s,&size,"%s,0 ; ?bug", get_op(PCI(pc)));
1590         //PCI(pc)->pcop->t.bit );
1591       } else {
1592
1593         if(PCI(pc)->pcop->type == PO_BIT) {
1594           if( PCI(pc)->num_ops == 2)
1595             SAFE_snprintf(&s,&size,"(%s >> 3),%c",get_op(PCI(pc)),((PCI(pc)->dest) ? 'F':'W'));
1596           else
1597             SAFE_snprintf(&s,&size,"(1 << (%s & 7))",get_op(PCI(pc)));
1598
1599         }else {
1600           SAFE_snprintf(&s,&size,"%s",get_op(PCI(pc)));
1601
1602           if( PCI(pc)->num_ops == 2)
1603             SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->dest) ? 'F':'W'));
1604         }
1605       }
1606
1607     }
1608     break;
1609
1610   case PC_COMMENT:
1611     /* assuming that comment ends with a \n */
1612     SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
1613     break;
1614
1615   case PC_LABEL:
1616     SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
1617     break;
1618   case PC_FUNCTION:
1619     SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
1620     break;
1621   case PC_WILD:
1622     SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
1623     break;
1624
1625   }
1626
1627   return str;
1628
1629 }
1630
1631 /*-----------------------------------------------------------------*/
1632 /* genericPrint - the contents of a pCode to a file                */
1633 /*-----------------------------------------------------------------*/
1634 static void genericPrint(FILE *of, pCode *pc)
1635 {
1636
1637   if(!pc || !of)
1638     return;
1639
1640   switch(pc->type) {
1641   case PC_COMMENT:
1642     fprintf(of,";%s\n", ((pCodeComment *)pc)->comment);
1643     break;
1644
1645   case PC_OPCODE:
1646     // If the opcode has a label, print that first
1647     {
1648       pBranch *pbl = pc->label;
1649       while(pbl && pbl->pc) {
1650         if(pbl->pc->type == PC_LABEL)
1651           pCodePrintLabel(of, pbl->pc);
1652         pbl = pbl->next;
1653       }
1654     }
1655
1656
1657     {
1658       char str[256];
1659       
1660       pCode2str(str, 256, pc);
1661
1662       fprintf(of,"%s",str);
1663     }
1664
1665     {
1666       pBranch *dpb = pc->to;   // debug
1667       while(dpb) {
1668         switch ( dpb->pc->type) {
1669         case PC_OPCODE:
1670           fprintf(of, "\t;%s", PCI(dpb->pc)->mnemonic);
1671           break;
1672         case PC_LABEL:
1673           fprintf(of, "\t;label %d", PCL(dpb->pc)->key);
1674           break;
1675         case PC_FUNCTION:
1676           fprintf(of, "\t;function %s", ( (PCF(dpb->pc)->fname) ? (PCF(dpb->pc)->fname) : "[END]"));
1677           break;
1678         case PC_COMMENT:
1679         case PC_WILD:
1680           break;
1681         }
1682         dpb = dpb->next;
1683       }
1684       fprintf(of,"\n");
1685     }
1686
1687     break;
1688
1689   case PC_WILD:
1690     fprintf(of,";\tWild opcode: id=%d\n",PCW(pc)->id);
1691     if(pc->label)
1692       pCodePrintLabel(of, pc->label->pc);
1693
1694     if(PCW(pc)->operand) {
1695       fprintf(of,";\toperand  ");
1696       pCodeOpPrint(of,PCW(pc)->operand );
1697     }
1698     break;
1699
1700   case PC_LABEL:
1701   default:
1702     fprintf(of,"unknown pCode type %d\n",pc->type);
1703   }
1704
1705 }
1706
1707 /*-----------------------------------------------------------------*/
1708 /* pCodePrintFunction - prints function begin/end                  */
1709 /*-----------------------------------------------------------------*/
1710
1711 static void pCodePrintFunction(FILE *of, pCode *pc)
1712 {
1713
1714   if(!pc || !of)
1715     return;
1716
1717   if( ((pCodeFunction *)pc)->modname) 
1718     fprintf(of,"F_%s",((pCodeFunction *)pc)->modname);
1719
1720   if(PCF(pc)->fname) {
1721     pBranch *exits = pc->to;
1722     int i=0;
1723     fprintf(of,"%s\t;Function start\n",PCF(pc)->fname);
1724     while(exits) {
1725       i++;
1726       exits = exits->next;
1727     }
1728     //if(i) i--;
1729     fprintf(of,"; %d exit point%c\n",i, ((i==1) ? ' ':'s'));
1730     
1731   }else {
1732     if(pc->from && 
1733        pc->from->pc->type == PC_FUNCTION &&
1734        PCF(pc->from->pc)->fname) 
1735       fprintf(of,"; exit point of %s\n",PCF(pc->from->pc)->fname);
1736     else
1737       fprintf(of,"; exit point [can't find entry point]\n");
1738   }
1739 }
1740 /*-----------------------------------------------------------------*/
1741 /* pCodePrintLabel - prints label                                  */
1742 /*-----------------------------------------------------------------*/
1743
1744 static void pCodePrintLabel(FILE *of, pCode *pc)
1745 {
1746
1747   if(!pc || !of)
1748     return;
1749
1750   if(PCL(pc)->label) 
1751     fprintf(of,"%s\n",PCL(pc)->label);
1752   else if (PCL(pc)->key >=0) 
1753     fprintf(of,"_%05d_DS_:\n",PCL(pc)->key);
1754   else
1755     fprintf(of,";wild card label: id=%d\n",-PCL(pc)->key);
1756
1757 }
1758 /*-----------------------------------------------------------------*/
1759 /* unlinkpCodeFromBranch - Search for a label in a pBranch and     */
1760 /*                         remove it if it is found.               */
1761 /*-----------------------------------------------------------------*/
1762 static void unlinkpCodeFromBranch(pCode *pcl , pCode *pc)
1763 {
1764   pBranch *b, *bprev;
1765
1766   bprev = NULL;
1767   b = pcl->label;
1768   while(b) {
1769     if(b->pc == pc) {
1770
1771       /* Found a label */
1772       if(bprev) {
1773         bprev->next = b->next;  /* Not first pCode in chain */
1774         free(b);
1775       } else {
1776         pc->destruct(pc);
1777         pcl->label = b->next;   /* First pCode in chain */
1778         free(b);
1779       }
1780       return;  /* A label can't occur more than once */
1781     }
1782     bprev = b;
1783     b = b->next;
1784   }
1785
1786 }
1787
1788 static pBranch * pBranchAppend(pBranch *h, pBranch *n)
1789 {
1790   pBranch *b;
1791
1792   if(!h)
1793     return n;
1794
1795   b = h;
1796   while(b->next)
1797     b = b->next;
1798
1799   b->next = n;
1800
1801   return h;
1802   
1803 }  
1804 /*-----------------------------------------------------------------*/
1805 /* pBranchLink - given two pcodes, this function will link them    */
1806 /*               together through their pBranches                  */
1807 /*-----------------------------------------------------------------*/
1808 static void pBranchLink(pCode *f, pCode *t)
1809 {
1810   pBranch *b;
1811
1812   // Declare a new branch object for the 'from' pCode.
1813
1814   _ALLOC(b,sizeof(pBranch));
1815   b->pc = t;                    // The link to the 'to' pCode.
1816   b->next = NULL;
1817
1818   f->to = pBranchAppend(f->to,b);
1819
1820   // Now do the same for the 'to' pCode.
1821
1822   _ALLOC(b,sizeof(pBranch));
1823   b->pc = f;
1824   b->next = NULL;
1825
1826   t->from = pBranchAppend(t->from,b);
1827   
1828 }
1829
1830 #if 0
1831 /*-----------------------------------------------------------------*/
1832 /* pBranchFind - find the pBranch in a pBranch chain that contains */
1833 /*               a pCode                                           */
1834 /*-----------------------------------------------------------------*/
1835 static pBranch *pBranchFind(pBranch *pb,pCode *pc)
1836 {
1837   while(pb) {
1838
1839     if(pb->pc == pc)
1840       return pb;
1841
1842     pb = pb->next;
1843   }
1844
1845   return NULL;
1846 }
1847
1848 /*-----------------------------------------------------------------*/
1849 /* pCodeUnlink - Unlink the given pCode from its pCode chain.      */
1850 /*-----------------------------------------------------------------*/
1851 static void pCodeUnlink(pCode *pc)
1852 {
1853   pBranch *pb1,*pb2;
1854   pCode *pc1;
1855
1856   if(!pc->prev || !pc->next) {
1857     fprintf(stderr,"unlinking bad pCode in %s:%d\n",__FILE__,__LINE__);
1858     exit(1);
1859   }
1860
1861   /* first remove the pCode from the chain */
1862   pc->prev->next = pc->next;
1863   pc->next->prev = pc->prev;
1864
1865   /* Now for the hard part... */
1866
1867   /* Remove the branches */
1868
1869   pb1 = pc->from;
1870   while(pb1) {
1871     pc1 = pb1->pc;    /* Get the pCode that branches to the
1872                        * one we're unlinking */
1873
1874     /* search for the link back to this pCode (the one we're
1875      * unlinking) */
1876     if(pb2 = pBranchFind(pc1->to,pc)) {
1877       pb2->pc = pc->to->pc;  // make the replacement
1878
1879       /* if the pCode we're unlinking contains multiple 'to'
1880        * branches (e.g. this a skip instruction) then we need
1881        * to copy these extra branches to the chain. */
1882       if(pc->to->next)
1883         pBranchAppend(pb2, pc->to->next);
1884     }
1885     
1886     pb1 = pb1->next;
1887   }
1888
1889
1890 }
1891 #endif
1892 /*-----------------------------------------------------------------*/
1893 /*-----------------------------------------------------------------*/
1894 static void genericAnalyze(pCode *pc)
1895 {
1896   switch(pc->type) {
1897   case PC_WILD:
1898   case PC_COMMENT:
1899     return;
1900   case PC_LABEL:
1901   case PC_FUNCTION:
1902   case PC_OPCODE:
1903     {
1904       // Go through the pCodes that are in pCode chain and link
1905       // them together through the pBranches. Note, the pCodes
1906       // are linked together as a contiguous stream like the 
1907       // assembly source code lines. The linking here mimics this
1908       // except that comments are not linked in.
1909       // 
1910       pCode *npc = pc->next;
1911       while(npc) {
1912         if(npc->type == PC_OPCODE || npc->type == PC_LABEL) {
1913           pBranchLink(pc,npc);
1914           return;
1915         } else
1916           npc = npc->next;
1917       }
1918     }
1919   }
1920 }
1921
1922 /*-----------------------------------------------------------------*/
1923 int compareLabel(pCode *pc, pCodeOpLabel *pcop_label)
1924 {
1925   pBranch *pbr;
1926
1927   if(pc->type == PC_LABEL) {
1928     if( ((pCodeLabel *)pc)->key ==  pcop_label->key)
1929       return TRUE;
1930   }
1931   if(pc->type == PC_OPCODE) {
1932     pbr = pc->label;
1933     while(pbr) {
1934       if(pbr->pc->type == PC_LABEL) {
1935         if( ((pCodeLabel *)(pbr->pc))->key ==  pcop_label->key)
1936           return TRUE;
1937       }
1938       pbr = pbr->next;
1939     }
1940   }
1941
1942   return FALSE;
1943 }
1944
1945 /*-----------------------------------------------------------------*/
1946 /* findLabel - Search the pCode for a particular label             */
1947 /*-----------------------------------------------------------------*/
1948 pCode * findLabel(pCodeOpLabel *pcop_label)
1949 {
1950   pBlock *pb;
1951   pCode  *pc;
1952
1953   if(!the_pFile)
1954     return NULL;
1955
1956   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
1957     for(pc = pb->pcHead; pc; pc = pc->next) 
1958       if(compareLabel(pc,pcop_label))
1959         return pc;
1960     
1961   }
1962
1963   fprintf(stderr,"Couldn't find label %s", pcop_label->pcop.name);
1964   return NULL;
1965 }
1966
1967 /*-----------------------------------------------------------------*/
1968 /* findNextInstruction - given a pCode, find the next instruction  */
1969 /*                       in the linked list                        */
1970 /*-----------------------------------------------------------------*/
1971 pCode * findNextInstruction(pCode *pc)
1972 {
1973
1974   while(pc) {
1975     if((pc->type == PC_OPCODE) || (pc->type == PC_WILD))
1976       return pc;
1977
1978     pc = pc->next;
1979   }
1980
1981   fprintf(stderr,"Couldn't find instruction\n");
1982   return NULL;
1983 }
1984
1985 /*-----------------------------------------------------------------*/
1986 /* findFunctionEnd - given a pCode find the end of the function    */
1987 /*                   that contains it     t                        */
1988 /*-----------------------------------------------------------------*/
1989 pCode * findFunctionEnd(pCode *pc)
1990 {
1991
1992   while(pc) {
1993     if(pc->type == PC_FUNCTION &&  !(PCF(pc)->fname))
1994       return pc;
1995
1996     pc = pc->next;
1997   }
1998
1999   fprintf(stderr,"Couldn't find function end\n");
2000   return NULL;
2001 }
2002
2003 #if 0
2004 /*-----------------------------------------------------------------*/
2005 /* AnalyzeLabel - if the pCode is a label, then merge it with the  */
2006 /*                instruction with which it is associated.         */
2007 /*-----------------------------------------------------------------*/
2008 static void AnalyzeLabel(pCode *pc)
2009 {
2010
2011   pCodeUnlink(pc);
2012
2013 }
2014 #endif
2015
2016 static void AnalyzeGOTO(pCode *pc)
2017 {
2018
2019   pBranchLink(pc,findLabel( (pCodeOpLabel *) (PCI(pc)->pcop) ));
2020
2021 }
2022
2023 static void AnalyzeSKIP(pCode *pc)
2024 {
2025
2026   pBranchLink(pc,findNextInstruction(pc->next));
2027   pBranchLink(pc,findNextInstruction(pc->next->next));
2028
2029 }
2030
2031 static void AnalyzeRETURN(pCode *pc)
2032 {
2033
2034   //  branch_link(pc,findFunctionEnd(pc->next));
2035
2036 }
2037
2038
2039 void AnalyzepBlock(pBlock *pb)
2040 {
2041   pCode *pc;
2042
2043   if(!pb)
2044     return;
2045
2046   /* Find all of the registers used in this pBlock */
2047   for(pc = pb->pcHead; pc; pc = pc->next) {
2048     if(pc->type == PC_OPCODE) {
2049       if(PCI(pc)->pcop && PCI(pc)->pcop->type == PO_GPR_TEMP) {
2050
2051         /* Loop through all of the registers declared so far in
2052            this block and see if we find this new there */
2053
2054         regs *r = setFirstItem(pb->registers);
2055
2056         while(r) {
2057           if(r->rIdx == PCOR(PCI(pc)->pcop)->r->rIdx) {
2058             PCOR(PCI(pc)->pcop)->r = r;
2059             break;
2060           }
2061           r = setNextItem(pb->registers);
2062         }
2063
2064         if(!r) {
2065           /* register wasn't found */
2066           r = Safe_calloc(1, sizeof(regs));
2067           memcpy(r,PCOR(PCI(pc)->pcop)->r, sizeof(regs));
2068           addSet(&pb->registers, r);
2069           PCOR(PCI(pc)->pcop)->r = r;
2070           fprintf(stderr,"added register to pblock: reg %d\n",r->rIdx);
2071         } else 
2072           fprintf(stderr,"found register in pblock: reg %d\n",r->rIdx);
2073       }
2074     }
2075   }
2076 }
2077
2078 int OptimizepBlock(pBlock *pb)
2079 {
2080   pCode *pc;
2081   int matches =0;
2082
2083   if(!pb || !peepOptimizing)
2084     return 0;
2085
2086   fprintf(stderr," Optimizing pBlock: %c\n",getpBlock_dbName(pb));
2087   for(pc = pb->pcHead; pc; pc = pc->next)
2088     matches += pCodePeepMatchRule(pc);
2089
2090   return matches;
2091
2092 }
2093
2094 /*-----------------------------------------------------------------*/
2095 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2096 /*-----------------------------------------------------------------*/
2097 pCode * findInstructionUsingLabel(pCodeLabel *pcl, pCode *pcs)
2098 {
2099   pCode *pc;
2100
2101   for(pc = pcs; pc; pc = pc->next) {
2102
2103     if((pc->type == PC_OPCODE) && 
2104        (PCI(pc)->pcop) && 
2105        (PCI(pc)->pcop->type == PO_LABEL) &&
2106        (PCOLAB(PCI(pc)->pcop)->key == pcl->key))
2107       return pc;
2108   }
2109  
2110
2111   return NULL;
2112 }
2113
2114 /*-----------------------------------------------------------------*/
2115 /* pBlockRemoveUnusedLabels - remove the pCode labels from the     */
2116 /*                            pCode chain if they're not used.     */
2117 /*-----------------------------------------------------------------*/
2118 void pBlockRemoveUnusedLabels(pBlock *pb)
2119 {
2120   pCode *pc; pCodeLabel *pcl;
2121
2122   if(!pb)
2123     return;
2124
2125   for(pc = pb->pcHead; pc; pc = pc->next) {
2126
2127     if(pc->type == PC_LABEL)
2128       pcl = PCL(pc);
2129     else if (pc->label)
2130       pcl = PCL(pc->label->pc);
2131     else continue;
2132
2133       /* This pCode is a label, so search the pBlock to see if anyone
2134        * refers to it */
2135
2136     if( (pcl->key>0) && (!findInstructionUsingLabel(pcl, pb->pcHead))) {
2137       /* Couldn't find an instruction that refers to this label
2138        * So, unlink the pCode label from it's pCode chain
2139        * and destroy the label */
2140
2141       fprintf(stderr," !!! REMOVED A LABEL !!! key = %d\n", pcl->key);
2142
2143       if(pc->type == PC_LABEL) {
2144         unlinkPC(pc);
2145         pCodeLabelDestruct(pc);
2146       } else {
2147         unlinkpCodeFromBranch(pc, PCODE(pcl));
2148         /*if(pc->label->next == NULL && pc->label->pc == NULL) {
2149           free(pc->label);
2150         }*/
2151       }
2152
2153     }
2154   }
2155
2156 }
2157
2158
2159 /*-----------------------------------------------------------------*/
2160 /* pBlockMergeLabels - remove the pCode labels from the pCode      */
2161 /*                     chain and put them into pBranches that are  */
2162 /*                     associated with the appropriate pCode       */
2163 /*                     instructions.                               */
2164 /*-----------------------------------------------------------------*/
2165 void pBlockMergeLabels(pBlock *pb)
2166 {
2167   pBranch *pbr;
2168   pCode *pc, *pcnext=NULL;
2169
2170   if(!pb)
2171     return;
2172
2173   /* First, Try to remove any unused labels */
2174   //pBlockRemoveUnusedLabels(pb);
2175
2176   /* Now loop through the pBlock and merge the labels with the opcodes */
2177
2178   for(pc = pb->pcHead; pc; pc = pc->next) {
2179
2180     if(pc->type == PC_LABEL) {
2181       fprintf(stderr,"Checking label key = %d\n",PCL(pc)->key);
2182       if( !(pcnext = findNextInstruction(pc)) ) 
2183         return;  // Couldn't find an instruction associated with this label
2184
2185       // Unlink the pCode label from it's pCode chain
2186       unlinkPC(pc);
2187
2188       fprintf(stderr,"Merged label key = %d\n",PCL(pc)->key);
2189       // And link it into the instruction's pBranch labels. (Note, since
2190       // it's possible to have multiple labels associated with one instruction
2191       // we must provide a means to accomodate the additional labels. Thus
2192       // the labels are placed into the singly-linked list "label" as 
2193       // opposed to being a single member of the pCodeInstruction.)
2194
2195       _ALLOC(pbr,sizeof(pBranch));
2196       pbr->pc = pc;
2197       pbr->next = NULL;
2198
2199       pcnext->label = pBranchAppend(pcnext->label,pbr);
2200       if(pcnext->prev) 
2201         pc = pcnext->prev;
2202       else
2203         pc = pcnext;
2204     }
2205
2206   }
2207   pBlockRemoveUnusedLabels(pb);
2208
2209 }
2210
2211 /*-----------------------------------------------------------------*/
2212 /*-----------------------------------------------------------------*/
2213 void OptimizepCode(char dbName)
2214 {
2215 #define MAX_PASSES 4
2216
2217   int matches = 0;
2218   int passes = 0;
2219   pBlock *pb;
2220
2221   if(!the_pFile)
2222     return;
2223
2224   fprintf(stderr," Optimizing pCode\n");
2225
2226   do {
2227     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2228       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2229         matches += OptimizepBlock(pb);
2230     }
2231   }
2232   while(matches && ++passes < MAX_PASSES);
2233
2234 }
2235
2236 /*-----------------------------------------------------------------*/
2237 /* AnalyzepCode - parse the pCode that has been generated and form */
2238 /*                all of the logical connections.                  */
2239 /*                                                                 */
2240 /* Essentially what's done here is that the pCode flow is          */
2241 /* determined.                                                     */
2242 /*-----------------------------------------------------------------*/
2243
2244 void AnalyzepCode(char dbName)
2245 {
2246   pBlock *pb;
2247   pCode *pc;
2248   pBranch *pbr;
2249
2250   int i,changes;
2251
2252   if(!the_pFile)
2253     return;
2254
2255   fprintf(stderr," Analyzing pCode");
2256
2257   changes = 0;
2258   i = 0;
2259   do {
2260     /* First, merge the labels with the instructions */
2261     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2262       if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2263
2264         fprintf(stderr," analyze and merging block %c\n",dbName);
2265         pBlockMergeLabels(pb);
2266         AnalyzepBlock(pb);
2267       }
2268     }
2269
2270     for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2271       if('*' == dbName || getpBlock_dbName(pb) == dbName)
2272         changes += OptimizepBlock(pb);
2273     }
2274       
2275   } while(changes && (i++ < MAX_PASSES));
2276
2277   /* Now build the call tree.
2278      First we examine all of the pCodes for functions.
2279      Keep in mind that the function boundaries coincide
2280      with pBlock boundaries. 
2281
2282      The algorithm goes something like this:
2283      We have two nested loops. The outer loop iterates
2284      through all of the pBlocks/functions. The inner
2285      loop iterates through all of the pCodes for
2286      a given pBlock. When we begin iterating through
2287      a pBlock, the variable pc_fstart, pCode of the start
2288      of a function, is cleared. We then search for pCodes
2289      of type PC_FUNCTION. When one is encountered, we
2290      initialize pc_fstart to this and at the same time
2291      associate a new pBranch object that signifies a 
2292      branch entry. If a return is found, then this signifies
2293      a function exit point. We'll link the pCodes of these
2294      returns to the matching pc_fstart.
2295
2296      When we're done, a doubly linked list of pBranches
2297      will exist. The head of this list is stored in
2298      `the_pFile', which is the meta structure for all
2299      of the pCode. Look at the printCallTree function
2300      on how the pBranches are linked together.
2301
2302    */
2303   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2304     if('*' == dbName || getpBlock_dbName(pb) == dbName) {
2305       pCode *pc_fstart=NULL;
2306       for(pc = pb->pcHead; pc; pc = pc->next) {
2307         if(pc->type == PC_FUNCTION) {
2308           if (PCF(pc)->fname) {
2309             // I'm not liking this....
2310             // Found the beginning of a function.
2311             _ALLOC(pbr,sizeof(pBranch));
2312             pbr->pc = pc_fstart = pc;
2313             pbr->next = NULL;
2314
2315             the_pFile->functions = pBranchAppend(the_pFile->functions,pbr);
2316
2317             // Here's a better way of doing the same:
2318             addSet(&pb->function_entries, pc);
2319
2320           } else {
2321             // Found an exit point in a function, e.g. return
2322             // (Note, there may be more than one return per function)
2323             if(pc_fstart)
2324               pBranchLink(pc_fstart, pc);
2325
2326             addSet(&pb->function_exits, pc);
2327           }
2328         } else  if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2329           addSet(&pb->function_calls,pc);
2330         }
2331       }
2332     }
2333   }
2334 }
2335
2336 /*-----------------------------------------------------------------*/
2337 /* ispCodeFunction - returns true if *pc is the pCode of a         */
2338 /*                   function                                      */
2339 /*-----------------------------------------------------------------*/
2340 bool ispCodeFunction(pCode *pc)
2341 {
2342
2343   if(pc && pc->type == PC_FUNCTION && PCF(pc)->fname)
2344     return 1;
2345
2346   return 0;
2347 }
2348
2349 /*-----------------------------------------------------------------*/
2350 /* findFunction - Search for a function by name (given the name)   */
2351 /*                in the set of all functions that are in a pBlock */
2352 /* (note - I expect this to change because I'm planning to limit   */
2353 /*  pBlock's to just one function declaration                      */
2354 /*-----------------------------------------------------------------*/
2355 pCode *findFunction(char *fname)
2356 {
2357   pBlock *pb;
2358   pCode *pc;
2359   if(!fname)
2360     return NULL;
2361
2362   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2363
2364     pc = setFirstItem(pb->function_entries);
2365     while(pc) {
2366     
2367       if((pc->type == PC_FUNCTION) &&
2368          (PCF(pc)->fname) && 
2369          (strcmp(fname, PCF(pc)->fname)==0))
2370         return pc;
2371
2372       pc = setNextItem(pb->function_entries);
2373
2374     }
2375
2376   }
2377   return NULL;
2378 }
2379
2380 void MarkUsedRegisters(set *regset)
2381 {
2382
2383   regs *r1,*r2;
2384
2385   for(r1=setFirstItem(regset); r1; r1=setNextItem(regset)) {
2386     r2 = pic14_regWithIdx(r1->rIdx);
2387     r2->isFree = 0;
2388     r2->wasUsed = 1;
2389   }
2390 }
2391
2392 void pBlockStats(FILE *of, pBlock *pb)
2393 {
2394
2395   pCode *pc;
2396   regs  *r;
2397
2398   fprintf(of,"***\n  pBlock Stats\n***\n");
2399
2400   // for now just print the first element of each set
2401   pc = setFirstItem(pb->function_entries);
2402   if(pc) {
2403     fprintf(of,"entry\n");
2404     pc->print(of,pc);
2405   }
2406   pc = setFirstItem(pb->function_exits);
2407   if(pc) {
2408     fprintf(of,"has an exit\n");
2409     pc->print(of,pc);
2410   }
2411
2412   pc = setFirstItem(pb->function_calls);
2413   if(pc) {
2414     fprintf(of,"functions called\n");
2415
2416     while(pc) {
2417       pc->print(of,pc);
2418       pc = setNextItem(pb->function_calls);
2419     }
2420   }
2421
2422   r = setFirstItem(pb->registers);
2423   if(r) {
2424     int n = elementsInSet(pb->registers);
2425
2426     fprintf(of,"%d compiler assigned register%c:\n",n, ( (n!=1) ? 's' : ' '));
2427
2428     while (r) {
2429       fprintf(of,"   %s\n",r->name);
2430       r = setNextItem(pb->registers);
2431     }
2432   }
2433 }
2434
2435 /*-----------------------------------------------------------------*/
2436 /*-----------------------------------------------------------------*/
2437 void sequencepCode(void)
2438 {
2439   pBlock *pb;
2440   pCode *pc;
2441
2442
2443   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2444
2445     pb->seq = GpCodeSequenceNumber+1;
2446
2447     for( pc = pb->pcHead; pc; pc = pc->next)
2448       pc->seq = ++GpCodeSequenceNumber;
2449   }
2450
2451 }
2452
2453 /*-----------------------------------------------------------------*/
2454 /*-----------------------------------------------------------------*/
2455 set *register_usage(pBlock *pb)
2456 {
2457   pCode *pc,*pcn;
2458   set *registers=NULL;
2459   set *registersInCallPath = NULL;
2460
2461   /* check recursion */
2462
2463   pc = setFirstItem(pb->function_entries);
2464
2465   if(!pc)
2466     return registers;
2467
2468   pb->visited = 1;
2469
2470   if(pc->type != PC_FUNCTION)
2471     fprintf(stderr,"%s, first pc is not a function???\n",__FUNCTION__);
2472
2473   pc = setFirstItem(pb->function_calls);
2474   for( ; pc; pc = setNextItem(pb->function_calls)) {
2475
2476     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2477       char *dest = get_op(PCI(pc));
2478
2479       pcn = findFunction(dest);
2480       if(pcn) 
2481         registersInCallPath = register_usage(pcn->pb);
2482     } else
2483       fprintf(stderr,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2484
2485   }
2486
2487
2488   pBlockStats(stderr,pb);  // debug
2489
2490   // Mark the registers in this block as used.
2491
2492   MarkUsedRegisters(pb->registers);
2493   if(registersInCallPath) {
2494     /* registers were used in the functions this pBlock has called */
2495     /* so now, we need to see if these collide with the ones we are */
2496     /* using here */
2497
2498     regs *r1,*r2, *newreg;
2499
2500     fprintf(stderr,"comparing registers\n");
2501
2502     r1 = setFirstItem(registersInCallPath);
2503     while(r1) {
2504
2505       r2 = setFirstItem(pb->registers);
2506
2507       while(r2) {
2508
2509         if(r2->rIdx == r1->rIdx) {
2510           newreg = pic14_findFreeReg();
2511
2512
2513           if(!newreg) {
2514             fprintf(stderr,"Bummer, no more registers.\n");
2515             exit(1);
2516           }
2517
2518           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2519                   r1->rIdx, newreg->rIdx);
2520           r2->rIdx = newreg->rIdx;
2521           //if(r2->name) free(r2->name);
2522           if(newreg->name)
2523             r2->name = Safe_strdup(newreg->name);
2524           else
2525             r2->name = NULL;
2526           newreg->isFree = 0;
2527           newreg->wasUsed = 1;
2528         }
2529         r2 = setNextItem(pb->registers);
2530       }
2531
2532       r1 = setNextItem(registersInCallPath);
2533     }
2534
2535     /* Collisions have been resolved. Now free the registers in the call path */
2536     r1 = setFirstItem(registersInCallPath);
2537     while(r1) {
2538       newreg = pic14_regWithIdx(r1->rIdx);
2539       newreg->isFree = 1;
2540       r1 = setNextItem(registersInCallPath);
2541     }
2542
2543   }// else
2544   //    MarkUsedRegisters(pb->registers);
2545
2546   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2547
2548   if(registers) 
2549     fprintf(stderr,"returning regs\n");
2550   else
2551     fprintf(stderr,"not returning regs\n");
2552
2553   fprintf(stderr,"pBlock after register optim.\n");
2554   pBlockStats(stderr,pb);  // debug
2555
2556
2557   return registers;
2558 }
2559
2560 /*-----------------------------------------------------------------*/
2561 /* printCallTree - writes the call tree to a file                  */
2562 /*                                                                 */
2563 /*-----------------------------------------------------------------*/
2564 void pct2(FILE *of,pBlock *pb,int indent)
2565 {
2566   pCode *pc,*pcn;
2567   int i;
2568   //  set *registersInCallPath = NULL;
2569
2570   if(!of)
2571     return;// registers;
2572
2573   if(indent > 10)
2574     return; // registers;   //recursion ?
2575
2576   pc = setFirstItem(pb->function_entries);
2577
2578   if(!pc)
2579     return;
2580
2581   pb->visited = 0;
2582
2583   for(i=0;i<indent;i++)   // Indentation
2584     fputc(' ',of);
2585
2586   if(pc->type == PC_FUNCTION)
2587     fprintf(of,"%s\n",PCF(pc)->fname);
2588   else
2589     return;  // ???
2590
2591
2592   pc = setFirstItem(pb->function_calls);
2593   for( ; pc; pc = setNextItem(pb->function_calls)) {
2594
2595     if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) {
2596       char *dest = get_op(PCI(pc));
2597
2598       pcn = findFunction(dest);
2599       if(pcn) 
2600         pct2(of,pcn->pb,indent+1);
2601     } else
2602       fprintf(of,"BUG? pCode isn't a POC_CALL %d\n",__LINE__);
2603
2604   }
2605
2606
2607 }
2608
2609 #if 0
2610   fprintf(stderr,"pBlock before register optim.\n");
2611   pBlockStats(stderr,pb);  // debug
2612
2613   if(registersInCallPath) {
2614     /* registers were used in the functions this pBlock has called */
2615     /* so now, we need to see if these collide with the ones we are using here */
2616
2617     regs *r1,*r2, *newreg;
2618
2619     fprintf(stderr,"comparing registers\n");
2620
2621     r1 = setFirstItem(registersInCallPath);
2622     while(r1) {
2623
2624       r2 = setFirstItem(pb->registers);
2625
2626       while(r2) {
2627
2628         if(r2->rIdx == r1->rIdx) {
2629           newreg = pic14_findFreeReg();
2630
2631
2632           if(!newreg) {
2633             fprintf(stderr,"Bummer, no more registers.\n");
2634             exit(1);
2635           }
2636
2637           fprintf(stderr,"Cool found register collision nIdx=%d moving to %d\n",
2638                   r1->rIdx, newreg->rIdx);
2639           r2->rIdx = newreg->rIdx;
2640           //if(r2->name) free(r2->name);
2641           if(newreg->name)
2642             r2->name = Safe_strdup(newreg->name);
2643           else
2644             r2->name = NULL;
2645           newreg->isFree = 0;
2646           newreg->wasUsed = 1;
2647         }
2648         r2 = setNextItem(pb->registers);
2649       }
2650
2651       r1 = setNextItem(registersInCallPath);
2652     }
2653
2654     /* Collisions have been resolved. Now free the registers in the call path */
2655     r1 = setFirstItem(registersInCallPath);
2656     while(r1) {
2657       newreg = pic14_regWithIdx(r1->rIdx);
2658       newreg->isFree = 1;
2659       r1 = setNextItem(registersInCallPath);
2660     }
2661
2662   } else
2663     MarkUsedRegisters(pb->registers);
2664
2665   registers = unionSets(pb->registers, registersInCallPath, THROW_NONE);
2666
2667   if(registers) 
2668     fprintf(stderr,"returning regs\n");
2669   else
2670     fprintf(stderr,"not returning regs\n");
2671
2672   fprintf(stderr,"pBlock after register optim.\n");
2673   pBlockStats(stderr,pb);  // debug
2674
2675
2676   return registers;
2677
2678 #endif
2679
2680
2681 /*-----------------------------------------------------------------*/
2682 /* printCallTree - writes the call tree to a file                  */
2683 /*                                                                 */
2684 /*-----------------------------------------------------------------*/
2685
2686 void printCallTree(FILE *of)
2687 {
2688   pBranch *pbr;
2689   pBlock  *pb;
2690   pCode   *pc;
2691
2692   if(!the_pFile)
2693     return;
2694
2695   if(!of)
2696     of = stderr;
2697
2698   fprintf(of, "\npBlock statistics\n");
2699   for(pb = the_pFile->pbHead; pb;  pb = pb->next )
2700     pBlockStats(stderr,pb);
2701
2702
2703
2704   fprintf(of,"Call Tree\n");
2705   pbr = the_pFile->functions;
2706   while(pbr) {
2707     if(pbr->pc) {
2708       pc = pbr->pc;
2709       if(!ispCodeFunction(pc))
2710         fprintf(of,"bug in call tree");
2711
2712
2713       fprintf(of,"Function: %s\n", PCF(pc)->fname);
2714
2715       while(pc->next && !ispCodeFunction(pc->next)) {
2716         pc = pc->next;
2717         if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL)
2718           fprintf(of,"\t%s\n",get_op(PCI(pc)));
2719       }
2720     }
2721
2722     pbr = pbr->next;
2723   }
2724
2725
2726   /* Re-allocate the registers so that there are no collisions
2727    * between local variables when one function call another */
2728
2729   pic14_deallocateAllRegs();
2730
2731   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2732     if(!pb->visited)
2733       register_usage(pb);
2734   }
2735
2736   fprintf(of,"\n**************\n\na better call tree\n");
2737   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2738     if(pb->visited)
2739       pct2(of,pb,0);
2740   }
2741
2742   for(pb = the_pFile->pbHead; pb; pb = pb->next) {
2743     fprintf(of,"block dbname: %c\n", getpBlock_dbName(pb));
2744   }
2745 }