source: mainline/uspace/app/pcc/arch/pdp11/local2.c@ a7de7182

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a7de7182 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 15.9 KB
Line 
1/* $Id: local2.c,v 1.8 2009/07/29 12:34:19 ragge Exp $ */
2/*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29# include "pass2.h"
30# include <ctype.h>
31# include <string.h>
32
33static int spcoff;
34static int argsiz(NODE *p);
35
36void
37deflab(int label)
38{
39 printf(LABFMT ":\n", label);
40}
41
42void
43prologue(struct interpass_prolog *ipp)
44{
45 int addto;
46
47#ifdef LANG_F77
48 if (ipp->ipp_vis)
49 printf(" .globl %s\n", ipp->ipp_name);
50 printf("%s:\n", ipp->ipp_name);
51#endif
52 printf("jsr r5,csv\n");
53 addto = p2maxautooff;
54 if (addto >= AUTOINIT/SZCHAR)
55 addto -= AUTOINIT/SZCHAR;
56 if (addto & 1)
57 addto++;
58 if (addto == 2)
59 printf("tst -(sp)\n");
60 else if (addto == 4)
61 printf("cmp -(sp),-(sp)\n");
62 else if (addto > 4)
63 printf("sub $%o,sp\n", addto);
64 spcoff = 0;
65}
66
67void
68eoftn(struct interpass_prolog *ipp)
69{
70 if (spcoff)
71 comperr("spcoff == %d", spcoff);
72 if (ipp->ipp_ip.ip_lbl == 0)
73 return; /* no code needs to be generated */
74 printf("jmp cret\n");
75}
76
77/*
78 * add/sub/...
79 *
80 * Param given:
81 */
82void
83hopcode(int f, int o)
84{
85 char *str;
86
87 switch (o) {
88 case PLUS:
89 str = "add";
90 break;
91 case MINUS:
92 str = "sub";
93 break;
94 case AND:
95 str = "and";
96 break;
97 case OR:
98 str = "or";
99 break;
100 case ER:
101 str = "xor";
102 break;
103 default:
104 comperr("hopcode2: %d", o);
105 str = 0; /* XXX gcc */
106 }
107 printf("%s%c", str, f);
108}
109
110/*
111 * Return type size in bytes. Used by R2REGS, arg 2 to offset().
112 */
113int
114tlen(p) NODE *p;
115{
116 switch(p->n_type) {
117 case CHAR:
118 case UCHAR:
119 return(1);
120
121 case SHORT:
122 case USHORT:
123 return(SZSHORT/SZCHAR);
124
125 case DOUBLE:
126 return(SZDOUBLE/SZCHAR);
127
128 case INT:
129 case UNSIGNED:
130 case LONG:
131 case ULONG:
132 return(SZINT/SZCHAR);
133
134 case LONGLONG:
135 case ULONGLONG:
136 return SZLONGLONG/SZCHAR;
137
138 default:
139 if (!ISPTR(p->n_type))
140 comperr("tlen type %d not pointer");
141 return SZPOINT(p->n_type)/SZCHAR;
142 }
143}
144
145/*
146 * Emit code to compare two long numbers.
147 */
148static void
149twolcomp(NODE *p)
150{
151 int o = p->n_op;
152 int s = getlab2();
153 int e = p->n_label;
154 int cb1, cb2;
155
156 if (o >= ULE)
157 o -= (ULE-LE);
158 switch (o) {
159 case NE:
160 cb1 = 0;
161 cb2 = NE;
162 break;
163 case EQ:
164 cb1 = NE;
165 cb2 = 0;
166 break;
167 case LE:
168 case LT:
169 cb1 = GT;
170 cb2 = LT;
171 break;
172 case GE:
173 case GT:
174 cb1 = LT;
175 cb2 = GT;
176 break;
177
178 default:
179 cb1 = cb2 = 0; /* XXX gcc */
180 }
181 if (p->n_op >= ULE)
182 cb1 += 2, cb2 += 2;
183 expand(p, 0, "cmp AR,AL\n");
184 if (cb1) cbgen(cb1, s);
185 if (cb2) cbgen(cb2, e);
186 expand(p, 0, "cmp UR,UL\n");
187 cbgen(p->n_op, e);
188 deflab(s);
189}
190
191
192/*
193 * Generate compare code for long instructions when right node is 0.
194 */
195static void
196lcomp(NODE *p)
197{
198 switch (p->n_op) {
199 case EQ:
200 expand(p, FORCC, "tst AL\n");
201 printf("jne 1f\n");
202 expand(p, FORCC, "tst UL\n");
203 cbgen(EQ, p->n_label);
204 printf("1:\n");
205 break;
206 case NE:
207 expand(p, FORCC, "tst AL\n");
208 cbgen(NE, p->n_label);
209 expand(p, FORCC, "tst UL\n");
210 cbgen(NE, p->n_label);
211 break;
212 case GE:
213 expand(p, FORCC, "tst AL\n");
214 cbgen(GE, p->n_label);
215 break;
216 default:
217 comperr("lcomp %p", p);
218 }
219}
220
221void
222zzzcode(NODE *p, int c)
223{
224 switch (c) {
225 case 'A': /* print out - if not first arg */
226 if (spcoff || (p->n_type == FLOAT || p->n_type == DOUBLE))
227 printf("-");
228 spcoff += argsiz(p);
229 break;
230
231 case 'B': /* arg is pointer to block */
232 expand(p->n_left, FOREFF, "mov AL,ZA(sp)\n");
233 expand(p->n_left, FOREFF, "sub CR,(sp)\n");
234 break;
235
236 case 'C': /* subtract stack after call */
237 spcoff -= p->n_qual;
238 if (spcoff == 0 && !(p->n_flags & NLOCAL1))
239 p->n_qual -= 2;
240 if (p->n_qual == 2)
241 printf("tst (sp)+\n");
242 else if (p->n_qual == 4)
243 printf("cmp (sp)+,(sp)+\n");
244 else if (p->n_qual > 2)
245 printf("add $%o,sp\n", (int)p->n_qual);
246 break;
247
248 case 'D': /* long comparisions */
249 lcomp(p);
250 break;
251
252 case 'E': /* long move */
253 rmove(p->n_right->n_reg, p->n_left->n_reg, p->n_type);
254 break;
255
256 case 'F': /* long comparision */
257 twolcomp(p);
258 break;
259
260 case 'G': /* printout a subnode for post-inc */
261 adrput(stdout, p->n_left->n_left);
262 break;
263
264 case 'H': /* arg with post-inc */
265 expand(p->n_left->n_left, FOREFF, "mov AL,ZA(sp)\n");
266 expand(p->n_left->n_left, FOREFF, "inc AL\n");
267 break;
268
269 case 'Q': /* struct assignment, no rv */
270 printf("mov $%o,", p->n_stsize/2);
271 expand(p, INAREG, "A1\n");
272 printf("1:\n");
273 expand(p, INAREG, "mov (AR)+,(AL)+\n");
274 expand(p, INAREG, "dec A1\n");
275 printf("jne 1b\n");
276 break;
277
278 case 'R': /* struct assignment with rv */
279 printf("mov $%o,", p->n_stsize/2);
280 expand(p, INAREG, "A1\n");
281 expand(p, INAREG, "mov AR,A2\n");
282 printf("1:\n");
283 expand(p, INAREG, "mov (A2)+,(AL)+\n");
284 expand(p, INAREG, "dec A1\n");
285 printf("jne 1b\n");
286 break;
287
288 case '1': /* lower part of double regs */
289 p = getlr(p, '1');
290 printf("r%c", rnames[p->n_rval][1]);
291 break;
292
293 default:
294 comperr("zzzcode %c", c);
295 }
296}
297
298/*ARGSUSED*/
299int
300rewfld(NODE *p)
301{
302 return(1);
303}
304
305int canaddr(NODE *);
306int
307canaddr(NODE *p)
308{
309 int o = p->n_op;
310
311 if (o==NAME || o==REG || o==ICON || o==OREG ||
312 (o==UMUL && shumul(p->n_left, STARNM|SOREG)))
313 return(1);
314 return(0);
315}
316
317/*
318 * Does the bitfield shape match?
319 */
320int
321flshape(NODE *p)
322{
323 int o = p->n_op;
324
325 if (o == OREG || o == REG || o == NAME)
326 return SRDIR; /* Direct match */
327 if (o == UMUL && shumul(p->n_left, SOREG))
328 return SROREG; /* Convert into oreg */
329 return SRREG; /* put it into a register */
330}
331
332/* INTEMP shapes must not contain any temporary registers */
333/* XXX should this go away now? */
334int
335shtemp(NODE *p)
336{
337 return 0;
338#if 0
339 int r;
340
341 if (p->n_op == STARG )
342 p = p->n_left;
343
344 switch (p->n_op) {
345 case REG:
346 return (!istreg(p->n_rval));
347
348 case OREG:
349 r = p->n_rval;
350 if (R2TEST(r)) {
351 if (istreg(R2UPK1(r)))
352 return(0);
353 r = R2UPK2(r);
354 }
355 return (!istreg(r));
356
357 case UMUL:
358 p = p->n_left;
359 return (p->n_op != UMUL && shtemp(p));
360 }
361
362 if (optype(p->n_op) != LTYPE)
363 return(0);
364 return(1);
365#endif
366}
367
368static void
369negcon(FILE *fp, int con)
370{
371 if (con < 0)
372 fprintf(fp, "-"), con = -con;
373 fprintf(fp, "%o", con & 0177777);
374}
375
376void
377adrcon(CONSZ val)
378{
379 printf("$" CONFMT, val);
380}
381
382void
383conput(FILE *fp, NODE *p)
384{
385 int val = p->n_lval;
386
387 switch (p->n_op) {
388 case ICON:
389 printf("$");
390 if (p->n_name[0] != '\0') {
391 fprintf(fp, "%s", p->n_name);
392 if (val)
393 fprintf(fp, "+%o", val & 0177777);
394 } else if (p->n_type == LONG || p->n_type == ULONG)
395 negcon(fp, val >> 16);
396 else
397 negcon(fp, val);
398 return;
399
400 default:
401 comperr("illegal conput, p %p", p);
402 }
403}
404
405/*ARGSUSED*/
406void
407insput(NODE *p)
408{
409 comperr("insput");
410}
411
412/*
413 * Write out the upper address, like the upper register of a 2-register
414 * reference, or the next memory location.
415 */
416void
417upput(NODE *p, int size)
418{
419 size /= SZINT;
420 switch (p->n_op) {
421 case NAME:
422 case OREG:
423 p->n_lval += size;
424 adrput(stdout, p);
425 p->n_lval -= size;
426 break;
427 case REG:
428 printf("r%c", rnames[p->n_rval][2]);
429 break;
430 case ICON:
431 /* On PDP11 upper value is low 16 bits */
432 printf("$");
433 negcon(stdout, p->n_lval & 0177777);
434 break;
435 default:
436 comperr("upput bad op %d size %d", p->n_op, size);
437 }
438}
439
440/*
441 * output an address, with offsets, from p
442 */
443void
444adrput(FILE *io, NODE *p)
445{
446 int r;
447
448 if (p->n_op == FLD)
449 p = p->n_left;
450
451 switch (p->n_op) {
452 case NAME:
453 if (p->n_name[0] != '\0') {
454 fputs(p->n_name, io);
455 if (p->n_lval != 0)
456 fprintf(io, "+%o", (int)(p->n_lval&0177777));
457 } else
458 negcon(io, p->n_lval);
459 return;
460
461 case OREG:
462 r = p->n_rval;
463 if (p->n_name[0])
464 printf("%s%s", p->n_name, p->n_lval ? "+" : "");
465 if (R2TEST(r) && R2UPK3(r) == 0)
466 printf("*");
467 if (p->n_lval)
468 negcon(io, p->n_lval);
469 if (R2TEST(r)) {
470 fprintf(io, "(%s)", rnames[R2UPK1(r)]);
471 if (R2UPK3(r) == 1)
472 fprintf(io, "+");
473 } else
474 fprintf(io, "(%s)", rnames[p->n_rval]);
475 return;
476 case ICON:
477 /* addressable value of the constant */
478 conput(io, p);
479 return;
480
481 case REG:
482 switch (p->n_type) {
483 case LONG:
484 case ULONG:
485 fprintf(io, "r%c", rnames[p->n_rval][1]);
486 break;
487 default:
488 fprintf(io, "%s", rnames[p->n_rval]);
489 }
490 return;
491
492 case UMUL:
493 if (tshape(p, STARNM)) {
494 printf("*");
495 adrput(io, p->n_left);
496 break;
497 }
498 /* FALLTHROUGH */
499 default:
500 comperr("illegal address, op %d, node %p", p->n_op, p);
501 return;
502
503 }
504}
505
506static char *
507ccbranches[] = {
508 "jeq", /* jumpe */
509 "jne", /* jumpn */
510 "jle", /* jumple */
511 "jlt", /* jumpl */
512 "jge", /* jumpge */
513 "jgt", /* jumpg */
514 "jlos", /* jumple (jlequ) */
515 "jlo", /* jumpl (jlssu) */
516 "jhis", /* jumpge (jgequ) */
517 "jhi", /* jumpg (jgtru) */
518};
519
520
521/* printf conditional and unconditional branches */
522void
523cbgen(int o, int lab)
524{
525 if (o < EQ || o > UGT)
526 comperr("bad conditional branch: %s", opst[o]);
527 printf("%s " LABFMT "\n", ccbranches[o-EQ], lab);
528}
529
530#define IS1CON(p) ((p)->n_op == ICON && (p)->n_lval == 1)
531
532/*
533 * Move postfix operators to the next statement, unless they are
534 * within a function call or a branch.
535 */
536static void
537cvtree(NODE *p, struct interpass *ip2)
538{
539 struct interpass *ip;
540 NODE *q;
541
542 if (callop(p->n_op) || p->n_op == CBRANCH)
543 return;
544
545 if ((p->n_op == PLUS || p->n_op == MINUS) &&
546 IS1CON(p->n_right) && (q = p->n_left)->n_op == ASSIGN &&
547 treecmp(q->n_left, q->n_right->n_left) &&
548 IS1CON(q->n_right->n_right)) {
549 if ((p->n_op == PLUS && q->n_right->n_op == MINUS) ||
550 (p->n_op == MINUS && q->n_right->n_op == PLUS)) {
551 nfree(p->n_right);
552 *p = *q->n_left;
553 if (optype(p->n_op) != LTYPE)
554 p->n_left = tcopy(p->n_left);
555 ip = ipnode(q);
556 DLIST_INSERT_AFTER(ip2, ip, qelem);
557 return;
558 }
559 }
560 if (optype(p->n_op) == BITYPE)
561 cvtree(p->n_right, ip2);
562 if (optype(p->n_op) != LTYPE)
563 cvtree(p->n_left, ip2);
564}
565
566/*
567 * Convert AND to BIC.
568 */
569static void
570fixops(NODE *p, void *arg)
571{
572 static int fltwritten;
573
574 if (!fltwritten && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
575 printf(".globl fltused\n");
576 fltwritten = 1;
577 }
578 switch (p->n_op) {
579 case AND:
580 if (p->n_right->n_op == ICON) {
581 p->n_right->n_lval = ((~p->n_right->n_lval) & 0177777);
582 } else if (p->n_right->n_op == COMPL) {
583 NODE *q = p->n_right->n_left;
584 nfree(p->n_right);
585 p->n_right = q;
586 } else
587 p->n_right = mkunode(COMPL, p->n_right, 0, p->n_type);
588 break;
589 case RS:
590 p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type);
591 p->n_op = LS;
592 break;
593 case EQ:
594 case NE: /* Hack not to clear bits if FORCC */
595 if (p->n_left->n_op == AND)
596 fixops(p->n_left, 0); /* Convert an extra time */
597 break;
598 }
599}
600
601void
602myreader(struct interpass *ipole)
603{
604 struct interpass *ip;
605
606#ifdef PCC_DEBUG
607 if (x2debug) {
608 printf("myreader before\n");
609 printip(ipole);
610 }
611#endif
612 DLIST_FOREACH(ip, ipole, qelem) {
613 if (ip->type != IP_NODE)
614 continue;
615 walkf(ip->ip_node, fixops, 0);
616 canon(ip->ip_node); /* call it early */
617 }
618#ifdef PCC_DEBUG
619 if (x2debug) {
620 printf("myreader middle\n");
621 printip(ipole);
622 }
623#endif
624 DLIST_FOREACH(ip, ipole, qelem) {
625 if (ip->type == IP_NODE)
626 cvtree(ip->ip_node, ip);
627 }
628#ifdef PCC_DEBUG
629 if (x2debug) {
630 printf("myreader after\n");
631 printip(ipole);
632 }
633#endif
634}
635
636/*
637 * Remove SCONVs where the left node is an OREG with a smaller type.
638 */
639static void
640delsconv(NODE *p, void *arg)
641{
642#if 0
643 NODE *l;
644
645 if (p->n_op != SCONV || (l = p->n_left)->n_op != OREG)
646 return;
647 if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == LONG) {
648 p->n_op = OREG;
649 p->n_lval = l->n_lval; /* high word */
650 p->n_rval = l->n_rval;
651 nfree(l);
652 }
653#endif
654 /* Could do this for char etc. also */
655}
656
657void
658mycanon(NODE *p)
659{
660 walkf(p, delsconv, 0);
661}
662
663void
664myoptim(struct interpass *ip)
665{
666}
667
668void
669rmove(int s, int d, TWORD t)
670{
671 if (t < LONG || t > BTMASK) {
672 printf("mov%s %s,%s\n", t < SHORT ? "b" : "",
673 rnames[s],rnames[d]); /* XXX char should be full reg? */
674 } else if (t == LONG || t == ULONG) {
675 /* avoid trashing double regs */
676 if (d > s)
677 printf("mov r%c,r%c\nmov r%c,r%c\n",
678 rnames[s][2],rnames[d][2],
679 rnames[s][1],rnames[d][1]);
680 else
681 printf("mov r%c,r%c\nmov r%c,r%c\n",
682 rnames[s][1],rnames[d][1],
683 rnames[s][2],rnames[d][2]);
684 } else if (t == FLOAT || t == DOUBLE) {
685 printf("movf %s,%s\n", rnames[s],rnames[d]);
686 } else
687 comperr("bad float rmove: %d %d %x", s, d, t);
688
689}
690
691/*
692 * For class c, find worst-case displacement of the number of
693 * registers in the array r[] indexed by class.
694 */
695int
696COLORMAP(int c, int *r)
697{
698 switch (c) {
699 case CLASSA:
700 return (r[CLASSB] * 2 + r[CLASSA]) < 5;
701 case CLASSB:
702 if (r[CLASSB] > 1) return 0;
703 if (r[CLASSB] == 1 && r[CLASSA] > 0) return 0;
704 if (r[CLASSA] > 2) return 0;
705 return 1;
706 case CLASSC:
707 return r[CLASSC] < 8;
708 }
709 return 0;
710}
711
712char *rnames[] = {
713 "r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc",
714 "r01", "r12", "r23", "r34", "XXX", "XXX", "XXX", "XXX",
715 "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "XXX", "XXX",
716};
717
718/*
719 * Return a class suitable for a specific type.
720 */
721int
722gclass(TWORD t)
723{
724 if (t < LONG || t > BTMASK)
725 return CLASSA;
726 if (t == LONG || t == ULONG)
727 return CLASSB;
728 if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
729 return CLASSC;
730 comperr("gclass");
731 return CLASSD;
732}
733
734static int
735argsiz(NODE *p)
736{
737 TWORD t = p->n_type;
738
739 if (t == LONG || t == ULONG || t == FLOAT)
740 return 4;
741 if (t == DOUBLE)
742 return 8;
743 if (t == STRTY || t == UNIONTY)
744 return p->n_stsize;
745 return 2;
746}
747
748/*
749 * Argument specialties.
750 */
751void
752lastcall(NODE *p)
753{
754 NODE *op = p;
755 int size = 0;
756
757 /*
758 * Calculate arg sizes.
759 * Mark first arg not to have - before it.
760 */
761 p->n_qual = 0;
762 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
763 return;
764 for (p = p->n_right; p->n_op == CM; p = p->n_left) {
765 p->n_right->n_qual = 0;
766 size += argsiz(p->n_right);
767 }
768 p->n_qual = 0;
769 size += argsiz(p);
770 p = op->n_right;
771
772 if (p->n_op == CM)
773 p = p->n_right;
774 if (p->n_type == FLOAT || p->n_type == DOUBLE ||
775 p->n_type == STRTY || p->n_type == UNIONTY)
776 op->n_flags |= NLOCAL1; /* Does not use stack slot */
777 else
778 op->n_flags &= ~NLOCAL1;
779 op->n_qual = size; /* XXX */
780}
781
782static int
783is1con(NODE *p)
784{
785 if (p->n_op == ICON && p->n_lval == 1)
786 return 1;
787 return 0;
788}
789
790/*
791 * Special shapes.
792 */
793int
794special(NODE *p, int shape)
795{
796 CONSZ s;
797
798 switch (shape) {
799 case SANDSCON:
800 s = ~p->n_lval;
801 if (s < 65536 || s > -65537)
802 return SRDIR;
803 break;
804 case SINCB: /* Check if subject for post-inc */
805 if (p->n_op == ASSIGN && p->n_right->n_op == PLUS &&
806 treecmp(p->n_left, p->n_right->n_left) &&
807 is1con(p->n_right->n_right))
808 return SRDIR;
809 break;
810 case SARGSUB:
811 if (p->n_op == MINUS && p->n_right->n_op == ICON &&
812 p->n_left->n_op == REG)
813 return SRDIR;
814 break;
815 case SARGINC:
816 if (p->n_op == MINUS && is1con(p->n_right))
817 return special(p->n_left, SINCB);
818 break;
819 }
820 return SRNOPE;
821}
822
823/*
824 * Target-dependent command-line options.
825 */
826void
827mflags(char *str)
828{
829}
830
831/*
832 * Do something target-dependent for xasm arguments.
833 */
834int
835myxasm(struct interpass *ip, NODE *p)
836{
837 return 0;
838}
839
840int
841fldexpand(NODE *p, int cookie, char **cp)
842{
843 return 0;
844}
845
Note: See TracBrowser for help on using the repository browser.