/* * Protocol: * * On stdin: accept a stream of displays. Each consists of a stream of * blocks, with "special" blocks marked by a 0x00 * byte as what would otherwise be the first byte of (note that * can never begin with a 0x00 byte). specifies the * number of vector-generator locations included in and is * encoded thus: * len in [1..127] one byte, len * len in [128..0x2000] two bytes: (len&0x7f)|0x80, len>>7 * is the address of the first vector generator block in * ; it is sent as two bytes, big-endian, with only the 0x1ffe * bits significant. consists of two-byte pairs, each a * vector-generator word sent in the byte order the 6502 sees them. * * All vector-generator memory is set to all-0x00 on startup. * * Special blocks: * * 0x00 0x01 * End of display * * 0x00 0x02 b0 * 0x00 0x03 b0 b1 * ... * 0x00 0x11 b0 b1 ... b15 * Load colour lookup. The second byte is one more than * the number of following bytes; the following bytes are * each 0xXV, where X is an offset into the colour lookup * and V is the value to be stored there. V has not yet * gone through the bit-permuting and inverting table. On * startup, the table is loaded as if with 0x00 0x11 0x00 * 0x10 0x20 0x30 ... 0xe0 0xf0. * * On stdout, generates a stream of key and display events. Key * presses are sent as the raw keycode; key releases are sent as the * raw keycode |ed with 0x80. When a display has been fully rendered, * a 0x00 is sent. (Note that 0x00 is not a valid raw keycode.) */ #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "cg6.h" static const char *fbpath = "/dev/cgsix0"; static const char *kbpath = "/dev/kbd0"; static unsigned char cmap[16][3] = { { 0, 0, 0 }, { 0, 0, 255 }, { 0, 255, 0 }, { 0, 255, 255 }, { 255, 0, 0 }, { 255, 0, 255 }, { 255, 255, 0 }, { 255, 255, 255 }, { 160, 160, 160 }, { 0, 0, 255 }, { 0, 255, 0 }, { 0, 255, 255 }, { 255, 0, 0 }, { 255, 0, 255 }, { 255, 255, 0 }, { 255, 255, 255 } }; #define RPSIZE 64 static unsigned long int randpool[RPSIZE]; static int rp; static int rmp; static int fbfd; static int kbfd; static volatile struct cg6fbc *fb; static volatile struct brooktree *bt; static volatile unsigned char *vram; static int iphase; #define IPH_LENA 1 #define IPH_LENB 2 #define IPH_ADDRA 3 #define IPH_ADDRB 4 #define IPH_PAIRA 5 #define IPH_PAIRB 6 #define IPH_SPEC 7 #define IPH_SETCL 8 static int ilen; static int iaddr; static unsigned char vgmem[0x4000]; static unsigned char colour_lookup[32]; static int drawbit; static int snapshot; #define NHIST 256 static unsigned char hist[NHIST][0x4020]; static int histp; /* The assembly part of the vector generator */ extern int s_vg(const unsigned char *, volatile struct cg6fbc *, unsigned int, const unsigned char *, unsigned int); static void drain(void) { while (fb->s & 0x10000000) ; } static void setupfb(void) { void *mrv; struct fbgattr a; fbfd = open(fbpath,O_RDWR,0); if (fbfd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } if ( (ioctl(fbfd,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(fbfd); fprintf(stderr,"%s: %s: not a cg6\n",__progname,fbpath); exit(1); } mrv = mmap(0,0x16000+a.fbtype.fb_size,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,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; drawbit = 0; fb->bg = 0; fb->pixelm = ~0; fb->s = 0; fb->mode = MODE_NORMAL | MODE_COLOR8; fb->alu = ALU_NORMAL | ALU_FG; fb->clip = 0; fb->offx = 0; fb->offy = 0; fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; fb->pm = ~0; drain(); fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; #ifdef NODOUBLEBUFFER fb->pm = ~0; #else fb->pm = 15; #endif } static void setupkb(void) { int type; int mode; kbfd = open(kbpath,O_RDWR,0); if (kbfd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,kbpath,strerror(errno)); exit(1); } if ( (ioctl(kbfd,KIOCTYPE,&type) < 0) || (type != KB_SUN3) ) { close(kbfd); fprintf(stderr,"%s: %s isn't a type-3\n",__progname,kbpath); exit(1); } mode = 1; ioctl(kbfd,KIOCSDIRECT,&mode); mode = TR_UNTRANS_EVENT; ioctl(kbfd,KIOCTRANS,&mode); mode = 1; ioctl(kbfd,FIONBIO,&mode); } static void setupin(void) { int mode; mode = 1; ioctl(0,FIONBIO,&mode); iphase = IPH_LENA; } static unsigned long int rnd(void) { int prp; prp = rp++; if (rp >= RPSIZE) rp = 0; randpool[prp] += randpool[rp]; return(randpool[prp]); } static void initrandom(void) { int i; struct timeval tv; randpool[0] = 1; randpool[1] = getpid(); gettimeofday(&tv,0); randpool[2] = tv.tv_sec; randpool[3] = tv.tv_usec; for (i=4;i> 1) ^ ((v & 1) ? 0xedb88320 : 0); randpool[rmp] = v; rmp ++; if (rmp >= RPSIZE) rmp = 0; } } static int checkkb(void) { struct firm_event ev; int r; r = read(kbfd,&ev,sizeof(ev)); if (r == sizeof(ev)) { unsigned char c; rnd_tweak(&ev,sizeof(ev)); c = (ev.id & 0x7f) | ((ev.value == VKEY_UP) ? 0x80 : 0); switch (c) { case 8: /* F3 */ snapshot = 1; break; case 8|0x80: break; default: write(1,&c,1); break; } return(1); } return(0); } static void set_cl(int x, int v, int bank) { static int map[16] = { 7, 15, 3, 11, 6, 14, 2, 10, 5, 13, 1, 9, 4, 12, 0, 8 }; colour_lookup[x+(bank<<4)] = map[v&0xf]; } static void setupvg(void) { int i; bzero(&vgmem,sizeof(vgmem)); for (i=0;i<16;i++) { set_cl(i,0,0); set_cl(i,0,1); } histp = 0; } static void setcmap(int bit) { int i; int v; bt->addr = 0; for (i=0;i<=255;i++) { v = (bit ? (i >> 4) : i) & 15; bt->cmap = cmap[v][0] * 0x01000000; bt->cmap = cmap[v][1] * 0x01000000; bt->cmap = cmap[v][2] * 0x01000000; } } static void draw(void) { while ((fb->draw & 0xa0000000) == 0xa0000000) ; } static void fbrect(int fg, int x1, int y1, int x2, int y2) { fb->fg = 0x11 * fg; fb->arecty = y1; fb->arectx = x1; fb->arecty = y2; fb->arectx = x2; draw(); } static void render(void) { drain(); setcmap(drawbit); drawbit = ! drawbit; #ifndef NODOUBLEBUFFER fb->pm = drawbit ? 0xf0 : 0x0f; #endif fb->alu = ALU_NORMAL | ALU_FG; fbrect(0,0,0,1151,899); if (histp < 1) histp = NHIST-1; else histp --; bcopy(&vgmem[0],&hist[histp][0],0x4000); bcopy(&colour_lookup[0],&hist[histp][0x4000],32); if (snapshot) { FILE *f; char fn[32]; int i; for (i=0;i<256;i++) { sprintf(&fn[0],"vgsnap/%03d",i); f = fopen(&fn[0],"w"); if (f) { fwrite(&hist[(histp+i)%NHIST],1,0x4020,f); fclose(f); } } snapshot = 0; } fb->alu = ALU_NORMAL | ALU_FG | ALU_DST; s_vg(&vgmem[0],fb,rnd(),&colour_lookup[0],0x20000); s_vg(&vgmem[0x2000],fb,rnd(),&colour_lookup[16],0x20000); } static void iproc(unsigned char c) { switch (iphase) { case IPH_LENA: if (c == 0) { iphase = IPH_SPEC; } else if (c < 128) { ilen = c; iphase = IPH_ADDRA; } else { ilen = c & 0x7f; iphase = IPH_LENB; } break; case IPH_LENB: ilen |= c << 7; iphase = IPH_ADDRA; break; case IPH_ADDRA: iaddr = c << 8; iphase = IPH_ADDRB; break; case IPH_ADDRB: iaddr = (iaddr | c) & 0x3ffe; iphase = IPH_PAIRA; break; case IPH_PAIRA: vgmem[iaddr] = c; iphase = IPH_PAIRB; break; case IPH_PAIRB: vgmem[iaddr+1] = c; if (ilen > 1) { ilen --; iphase = IPH_PAIRA; iaddr = (iaddr + 2) & 0x3ffe; } else { iphase = IPH_LENA; } break; case IPH_SPEC: switch (c) { case 0x01: render(); write(1,"",1); iphase = IPH_LENA; break; case 0x02: ilen = 32; iphase = IPH_SETCL; break; default: fprintf(stderr,"%s: bad special byte 0x%02x\n",__progname,c); exit(1); break; } break; case IPH_SETCL: set_cl(c>>4,c&15,(ilen>16)?0:1); if (ilen > 1) { ilen --; } else { iphase = IPH_LENA; } break; } } static int checkin(void) { char ibuf[8192]; int n; int i; n = read(0,&ibuf[0],sizeof(ibuf)); if (n < 0) { switch (errno) { case EINTR: return(1); break; case EWOULDBLOCK: return(0); break; default: fprintf(stderr,"%s: input read error: %s\n",__progname,strerror(errno)); exit(1); break; } } if (n == 0) { fprintf(stderr,"%s: input EOF\n",__progname); exit(1); } for (i=0;i