#include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "cg6.h" static struct { const char *name; int type; #define RT_FB 1 #define RT_BT 2 int off; int namelen; #define FBREG(name) { #name, RT_FB, offsetof(struct cg6fb,name) } #define BTREG(name) { "bt" #name, RT_BT, offsetof(struct brooktree,name) } } fbreg[] = { FBREG(mode), FBREG(clip), FBREG(s), FBREG(draw), FBREG(blit), FBREG(font), FBREG(x0), FBREG(y0), FBREG(z0), FBREG(color0), FBREG(x1), FBREG(y1), FBREG(z1), FBREG(color1), FBREG(x2), FBREG(y2), FBREG(z2), FBREG(color2), FBREG(x3), FBREG(y3), FBREG(z3), FBREG(color3), FBREG(offx), FBREG(offy), FBREG(incx), FBREG(incy), FBREG(clipminx), FBREG(clipminy), FBREG(clipmaxx), FBREG(clipmaxy), FBREG(fg), FBREG(bg), FBREG(alu), FBREG(pm), FBREG(pixelm), FBREG(patalign), { "pat0", RT_FB, offsetof(struct cg6fb,pattern[0]) }, { "pat1", RT_FB, offsetof(struct cg6fb,pattern[1]) }, { "pat2", RT_FB, offsetof(struct cg6fb,pattern[2]) }, { "pat3", RT_FB, offsetof(struct cg6fb,pattern[3]) }, { "pat4", RT_FB, offsetof(struct cg6fb,pattern[4]) }, { "pat5", RT_FB, offsetof(struct cg6fb,pattern[5]) }, { "pat6", RT_FB, offsetof(struct cg6fb,pattern[6]) }, { "pat7", RT_FB, offsetof(struct cg6fb,pattern[7]) }, FBREG(apointx), FBREG(apointy), FBREG(apointz), FBREG(rpointx), FBREG(rpointy), FBREG(rpointz), FBREG(pointr), FBREG(pointg), FBREG(pointb), FBREG(pointa), FBREG(alinex), FBREG(aliney), FBREG(alinez), FBREG(rlinex), FBREG(rliney), FBREG(rlinez), FBREG(liner), FBREG(lineg), FBREG(lineb), FBREG(linea), FBREG(atrix), FBREG(atriy), FBREG(atriz), FBREG(rtrix), FBREG(rtriy), FBREG(rtriz), FBREG(trir), FBREG(trig), FBREG(trib), FBREG(tria), FBREG(aquadx), FBREG(aquady), FBREG(aquadz), FBREG(rquadx), FBREG(rquady), FBREG(rquadz), FBREG(quadr), FBREG(quadg), FBREG(quadb), FBREG(quada), FBREG(arectx), FBREG(arecty), FBREG(arectz), FBREG(rrectx), FBREG(rrecty), FBREG(rrectz), FBREG(rectr), FBREG(rectg), FBREG(rectb), FBREG(recta), BTREG(addr), BTREG(cmap), BTREG(ctrl), BTREG(omap), { 0 } }; typedef struct def DEF; typedef struct xfile XFILE; typedef struct vstack VSTACK; struct vstack { VSTACK *link; unsigned long int val; } ; struct xfile { XFILE *link; FILE *fp; } ; struct def { DEF *link; DEF *xlink; char *name; int namelen; unsigned int flags; #define DF_DEFINING 0x00000001 #define DF_RUNNING 0x00000002 int nlines; char **lines; int xx; } ; static VSTACK *vstack; static XFILE *xfiles; static DEF *defs; static DEF *xdefs; static DEF *defining; static const char *fbpath = "/dev/cgsix0"; static int fd; static char regset[sizeof(struct cg6fb)+sizeof(struct brooktree)]; static struct cg6fb fbshadow; static volatile struct cg6fb *fb; static struct brooktree btshadow; static volatile struct brooktree *bt; static volatile unsigned char *vram; static struct fbcmap oldcm; static unsigned char oldcm_r[256]; static unsigned char oldcm_g[256]; static unsigned char oldcm_b[256]; static void drawwait(void) { while ((fb->draw & 0xa0000000) == 0xa0000000) ; } #define DRAWWAIT() drawwait() static void blitwait(void) { while ((fb->blit & 0xa0000000) == 0xa0000000) ; } #define BLITWAIT() blitwait() static void idlewait(void) { while (fb->s & 0x10000000) ; } #define IDLEWAIT() idlewait() static void setreg(int off, int type, unsigned long int val, int size) { volatile void *b; void *s; int setoff; switch (type) { case RT_FB: b = fb; s = &fbshadow; setoff = 0; break; case RT_BT: b = bt; s = &btshadow; setoff = sizeof(struct cg6fb); break; default: abort(); break; } switch (size) { case 1: *((volatile unsigned char *)(off+(volatile char *)b)) = val; *((unsigned char *)(off+setoff+(char *)s)) = val; break; case 2: *((volatile unsigned short int *)(off+(volatile char *)b)) = val; *((unsigned short int *)(off+setoff+(char *)s)) = val; break; case 4: *((volatile unsigned long int *)(off+(volatile char *)b)) = val; *((unsigned long int *)(off+setoff+(char *)s)) = val; break; default: abort(); break; } memset(®set[off+setoff],1,size); } #define SETREG(name,val) setreg(offsetof(struct cg6fb,name),RT_FB,val,sizeof(fb->name)) static void savecmap(void) { oldcm.index = 0; oldcm.count = 256; oldcm.red = &oldcm_r[0]; oldcm.green = &oldcm_g[0]; oldcm.blue = &oldcm_b[0]; if (ioctl(fd,FBIOGETCMAP,&oldcm) < 0) { fprintf(stderr,"%s: FBIOGETCMAP: %s\n",__progname,strerror(errno)); exit(1); } } static void cmcube(void) { int i; bt->addr = 0; for (i=0;i<256;i++) { bt->cmap = (((i & 7) * 0111) >> 1) << 24; bt->cmap = ((((i >> 3) & 7) * 0111) >> 1) << 24; bt->cmap = ((i >> 6) * 0x55) << 24; } } static void cmgray(void) { int i; bt->addr = 0; for (i=0;i<256;i++) { bt->cmap = i << 24; bt->cmap = i << 24; bt->cmap = i << 24; } } static void cmbit(int bit) { int i; int v; bit = 1 << bit; bt->addr = 0; for (i=0;i<256;i++) { v = (i & bit) ? 0xff000000 : 0; bt->cmap = v; bt->cmap = v; bt->cmap = v; } } static void restorecmap(void) { oldcm.index = 0; oldcm.count = 256; oldcm.red = &oldcm_r[0]; oldcm.green = &oldcm_g[0]; oldcm.blue = &oldcm_b[0]; ioctl(fd,FBIOPUTCMAP,&oldcm); } static void openfb(void) { void *mrv; struct fbgattr a; fd = open(fbpath,O_RDWR,0); if (fd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } if ( (ioctl(fd,FBIOGATTR,&a) < 0) || (a.fbtype.fb_type != FBTYPE_SUNFAST_COLOR) || (a.fbtype.fb_width != 1152) || (a.fbtype.fb_height != 900) || (a.fbtype.fb_depth != 8) ) { close(fd); fprintf(stderr,"%s: %s: not a cgsix\n",__progname,fbpath); exit(1); } savecmap(); mrv = mmap(0,0x16000+a.fbtype.fb_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x70000000); if (mrv == MAP_FAILED) { fprintf(stderr,"%s: can't mmap %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } fb = mrv; bt = (void *)(0x2000+(unsigned char *)mrv); vram = 0x16000 + (unsigned char *)mrv; bzero(®set[0],sizeof(regset)); SETREG(bg,0); SETREG(pixelm,~0U); SETREG(s,0); SETREG(alu, 0xc0000000 /* GX_PLANE_MASK */ | 0x20000000 /* GX_PIXEL_ONES */ | 0x00800000 /* GX_ATTR_SUPP (?) */ | 0x00000000 /* GX_RAST_BOOL (?) */ | 0x00000000 /* GX_PLOT_PLOT (?) */ | 0x08000000 /* GX_PATTERN_ONES */ | 0x01000000 /* GX_POLYG_OVERLAP */ | 0x0000ff00 /* ALU = set to fg color */ ); SETREG(clip,0); SETREG(offx,0); SETREG(offy,0); SETREG(clipminx,0); SETREG(clipminy,0); SETREG(clipmaxx,1151); SETREG(clipmaxy,899); SETREG(fg,0); SETREG(pm,~0U); IDLEWAIT(); } static char *skipws(char *s) { while (*s && isspace(*s)) s ++; return(s); } static char *skipnws(char *s) { while (*s && !isspace(*s)) s ++; return(s); } static void cmd_map(char *lp, int forreal) { char *arg; int al; arg = lp; lp = skipnws(arg); al = lp - arg; if ((al == 1) && (arg[0] == '?')) { printf("map cube\nmap gray\nmap bit 0-7\n"); } else if ((al == 4) && !bcmp(arg,"cube",4)) { if (forreal) cmcube(); } else if ((al == 4) && !bcmp(arg,"gray",4)) { if (forreal) cmgray(); } else if ((al == 3) && !bcmp(arg,"bit",3)) { if (forreal) cmbit(atoi(lp)); } else { printf("unrecognized map subcommand: %s\n",arg); printf("Use `map ?' for a list\n"); } } static void chgreg(int regno, char *valstr, int forreal) { signed long long int qval; char *end; if (! *valstr) { printf("No value given\n"); usage:; printf("Usage: %s new-value\n",fbreg[regno].name); return; } qval = strtoq(valstr,&end,0); if (*end) if ((qval > 0xffffffffULL) || (qval < -(signed long long int)0x80000000ULL)) { printf("Value out of range\n"); goto usage; } if (forreal) setreg(fbreg[regno].off,fbreg[regno].type,qval,4); } static void cmd_show(char *lp) { int n; int ch; int i; int j; int oo; char *b; if (*lp) { printf("`show' takes no arguments\n"); return; } for (n=0;fbreg[n].name;n++) ; ch = (n + 3) >> 2; for (i=0;i= ch) printf(" | "); printf("%-8s ",fbreg[j].name); switch (fbreg[j].type) { case RT_FB: oo = 0; b = (void *)&fbshadow; break; case RT_BT: oo = sizeof(struct cg6fb); b = (void *)&btshadow; break; } if (regset[fbreg[j].off+oo]) { printf("%08lx",*(unsigned long int *)(fbreg[j].off+b)); } else { printf("--------"); } } printf("\n"); } } static void showreg(int x) { int oo; volatile char *b; char *s; unsigned long int v; switch (fbreg[x].type) { case RT_FB: oo = 0; b = (volatile void *) fb; s = (void *) &fbshadow; break; case RT_BT: oo = sizeof(struct cg6fb); b = (volatile void *) bt; s = (void *) &btshadow; break; } v = *(volatile unsigned long int *)(fbreg[x].off+b); printf("%-8s %08lx\n",fbreg[x].name,v); *(unsigned long int *)(fbreg[x].off+s) = v; memset(®set[oo+fbreg[x].off],1,4); } static void fbreg_lengths(void) { int i; if (fbreg[0].namelen == 0) { for (i=0;fbreg[i].name;i++) fbreg[i].namelen = strlen(fbreg[i].name); } } static void cmd_r(char *lp, int forreal) { char *arg; int al; int i; arg = lp; lp = skipnws(arg); al = lp - arg; lp = skipws(lp); if (*lp) { printf("junk after register name: %s\n",lp); return; } fbreg_lengths(); for (i=0;fbreg[i].name;i++) { if ((al == fbreg[i].namelen) && !bcmp(arg,fbreg[i].name,al)) { if (forreal) showreg(i); break; } } if (! fbreg[i].name) { printf("unrecognized register name: %s\n",arg); printf("Use `show' for a list\n"); } } static DEF *def_find(const char *name, int namelen, int create) { DEF *d; for (d=defs;d;d=d->link) { if ((d->namelen == namelen) && !bcmp(d->name,name,namelen)) { return(d); } } if (create) { d = malloc(sizeof(DEF)); d->name = malloc(namelen+1); bcopy(name,d->name,namelen); d->name[namelen] = '\0'; d->namelen = namelen; d->flags = 0; d->nlines = 0; d->lines = 0; d->link = defs; defs = d; } return(d); } static void def_free_lines(DEF *d) { int i; for (i=d->nlines-1;i>=0;i--) free(d->lines[i]); d->nlines = 0; } static void def_remove(DEF *arg) { DEF **dp; DEF *d; def_free_lines(arg); free(arg->lines); for (dp=&defs;(d=*dp)&&(d!=arg);dp=&d->link) ; if (! d) abort(); *dp = d->link; free(arg->name); free(arg); } static void cmd_def(char *lp, int op) #define DEFOP_DEF 1 #define DEFOP_REDEF 2 #define DEFOP_APPEND 3 #define DEFOP_UNDEF 4 { char *arg; int al; DEF *d; arg = lp; lp = skipnws(arg); al = lp - arg; if (al == 0) { printf("must give a name\n"); return; } if (defining) { printf("already defining %s\n",defining->name); return; } d = def_find(arg,al,0); if (d) { if (d->flags & DF_DEFINING) { printf("currently being defined\n"); return; } if (d->flags & DF_RUNNING) { printf("currently being executed\n"); return; } } switch (op) { default: abort(); break; case DEFOP_DEF: if (d) { printf("already defined\n"); return; } d = def_find(arg,al,1); break; case DEFOP_REDEF: if (! d) d = def_find(arg,al,1); def_free_lines(d); break; case DEFOP_APPEND: if (! d) { printf("not defined\n"); return; } break; case DEFOP_UNDEF: if (! d) { printf("not defined\n"); return; } def_remove(d); break; } d->flags |= DF_DEFINING; defining = d; } static void cmd_end(char *lp) { if (*lp) { printf("`end' takes no arguments\n"); return; } if (defining) { defining->flags &= ~DF_DEFINING; defining = 0; } else { printf("not defining\n"); } } static void def_save(DEF *d, const char *l) { d->lines = realloc(d->lines,(d->nlines+1)*sizeof(*d->lines)); d->lines[d->nlines++] = strdup(l); } static void trimnl(char *s) { int len; len = strlen(s); while ((len > 0) && (s[len-1] == '\n')) s[--len] = '\0'; } static void cmd_push(char *lp, int forreal) { char *arg; int al; int i; int useshadow; char *s; volatile char *b; unsigned long int v; VSTACK *vs; int oo; arg = lp; lp = skipnws(arg); al = lp - arg; lp = skipws(lp); if (*lp) { printf("junk after register name: %s\n",lp); return; } fbreg_lengths(); useshadow = 1; if ((al > 1) && (arg[0] == '!')) { arg ++; al --; useshadow = 0; } for (i=0;fbreg[i].name;i++) { if ((al == fbreg[i].namelen) && !bcmp(arg,fbreg[i].name,al)) { if (forreal) { switch (fbreg[i].type) { case RT_FB: oo = 0; s = (void *) &fbshadow; b = (volatile void *) fb; break; case RT_BT: oo = sizeof(struct cg6fb); s = (void *) &btshadow; b = (volatile void *) bt; break; } if (useshadow) { if (! regset[oo+fbreg[i].off]) { printf("%s not set - use !%s to read register\n",fbreg[i].name,fbreg[i].name); return; } v = *(unsigned long int *)(s+fbreg[i].off); } else { v = *(volatile unsigned long int *)(b+fbreg[i].off); } } else { v = 0; } break; } } if (! fbreg[i].name) { printf("unrecognized register name: %s\n",arg); printf("Use `show' for a list\n"); } vs = malloc(sizeof(VSTACK)); vs->val = v; vs->link = vstack; vstack = vs; } static void cmd_pop(char *lp, int forreal) { char *arg; int al; int i; unsigned long int v; VSTACK *vs; arg = lp; lp = skipnws(arg); al = lp - arg; lp = skipws(lp); if (*lp) { printf("junk after register name: %s\n",lp); return; } fbreg_lengths(); for (i=0;fbreg[i].name;i++) { if ((al == fbreg[i].namelen) && !bcmp(arg,fbreg[i].name,al)) { vs = vstack; if (! vs) { printf("value stack underflow\n"); return; } v = vs->val; vstack = vs->link; free(vs); if (forreal) setreg(fbreg[i].off,fbreg[i].type,v,4); break; } } if (! fbreg[i].name) { printf("unrecognized register name: %s\n",arg); printf("Use `show' for a list\n"); } } static int docmd(void) { char line[1024]; char *lp; char *cmd; int cl; if (xdefs) { if (xdefs->xx >= xdefs->nlines) { xdefs->flags &= ~DF_RUNNING; xdefs = xdefs->xlink; return(1); } strcpy(&line[0],xdefs->lines[xdefs->xx++]); } else if (xfiles) { if (! fgets(&line[0],sizeof(line),xfiles->fp)) { XFILE *xf; fclose(xfiles->fp); xf = xfiles; xfiles = xf->link; free(xf); return(1); } trimnl(&line[0]); } else { if (defining) { printf("poke [%s]> ",defining->name); } else { printf("poke> "); } if (! fgets(&line[0],sizeof(line),stdin)) return(0); trimnl(&line[0]); } lp = skipws(&line[0]); if (! *lp) return(1); if (*lp == '@') { FILE *f; XFILE *xf; f = fopen(lp+1,"r"); if (f == 0) { printf("can't read %s: %s\n",lp+1,strerror(errno)); } else { xf = malloc(sizeof(XFILE)); xf->fp = f; xf->link = xfiles; xfiles = xf; } return(1); } cmd = lp; lp = skipnws(cmd); cl = lp - cmd; lp = skipws(lp); if ((cl == 1) && (cmd[0] == '?')) { printf("map [cube|gray|bit ] (set colormap)\n"); printf(" (set register, see \"show\" for names)\n"); printf("show (show register names and last set/read values)\n"); printf("r (read register, show value)\n"); printf("def (define user-defined command )\n"); printf("end (end user-defined command definition)\n"); printf("@filename (read commands from a file)\n"); if (defs == 0) { printf("No user-defined commands currently defined.\n"); } else { DEF *d; printf("User-defined:"); for (d=defs;d;d=d->link) printf(" %s",d->name); printf("\n"); } } else if ((cl == 3) && !bcmp(cmd,"map",3)) { if (defining) def_save(defining,cmd); cmd_map(lp,!defining); } else if ((cl == 4) && !bcmp(cmd,"show",4)) { cmd_show(lp); } else if ((cl == 4) && !bcmp(cmd,"draw",4)) { if (defining) def_save(defining,cmd); else DRAWWAIT(); } else if ((cl == 4) && !bcmp(cmd,"blit",4)) { if (defining) def_save(defining,cmd); else BLITWAIT(); } else if ((cl == 3) && !bcmp(cmd,"def",3)) { cmd_def(lp,DEFOP_DEF); } else if ((cl == 5) && !bcmp(cmd,"redef",5)) { cmd_def(lp,DEFOP_REDEF); } else if ((cl == 6) && !bcmp(cmd,"append",6)) { cmd_def(lp,DEFOP_APPEND); } else if ((cl == 5) && !bcmp(cmd,"undef",5)) { cmd_def(lp,DEFOP_UNDEF); } else if ((cl == 3) && !bcmp(cmd,"end",3)) { cmd_end(lp); } else if ((cl == 4) && !bcmp(cmd,"push",4)) { if (defining) def_save(defining,cmd); cmd_push(lp,!defining); } else if ((cl == 3) && !bcmp(cmd,"pop",3)) { if (defining) def_save(defining,cmd); cmd_pop(lp,!defining); } else if ((cl == 1) && (cmd[0] == 'r')) { if (defining) def_save(defining,cmd); cmd_r(lp,!defining); } else { int i; fbreg_lengths(); for (i=0;fbreg[i].name;i++) { if ((cl == fbreg[i].namelen) && !bcmp(cmd,fbreg[i].name,cl)) { if (defining) def_save(defining,cmd); chgreg(i,lp,!defining); break; } } if (! fbreg[i].name) { DEF *d; for (d=defs;d;d=d->link) { if ((cl == d->namelen) && !bcmp(cmd,d->name,cl)) { if (d->flags & DF_RUNNING) { printf("recursive call to %s\n",d->name); } else if (d->flags & DF_DEFINING) { printf("recursive call within definition of %s\n",d->name); } else { if (defining) def_save(defining,cmd); d->xlink = xdefs; xdefs = d; d->flags |= DF_RUNNING; d->xx = 0; } break; } } if (! d) { printf("unrecognized command: %s\n",cmd); printf("Use `?' for a list\n"); } } } return(1); } static void initdefs(void) { defs = 0; xdefs = 0; defining = 0; } int main(void); int main(void) { openfb(); cmcube(); initdefs(); xfiles = 0; vstack = 0; while (docmd()) ; restorecmap(); exit(0); }