diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/mpc/screen.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/mpc/screen.c')
| -rw-r--r-- | os/mpc/screen.c | 832 |
1 files changed, 832 insertions, 0 deletions
diff --git a/os/mpc/screen.c b/os/mpc/screen.c new file mode 100644 index 00000000..59fff7f6 --- /dev/null +++ b/os/mpc/screen.c @@ -0,0 +1,832 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#include <draw.h> +#include <memdraw.h> +#include <cursor.h> + +#include "screen.h" + +enum { + Backgnd = 0xFF, /* white */ + Foregnd = 0x00, /* black */ +}; + +Cursor arrow = { + { -1, -1 }, + { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, + 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, + 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, + 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, + }, + { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, + 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, + 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, + 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, + }, +}; + +static Memdata xgdata; +static Memimage xgscreen = +{ + {0, 0, 0, 0}, /* r */ + {0, 0, 0, 0}, /* clipr */ + 8, /* depth */ + 1, /* nchan */ + CMAP8, /* chan */ + nil, /* cmap */ + &xgdata, /* data */ + 0, /* zero */ + 0, /* width */ + nil, /* layer */ + 0, /* flags */ +}; + +int novgascreen; /* optionally set by configuration file */ +static int lcdpdpar; /* value to load into io->pdpar */ + +Memimage *gscreen; +Memimage *conscol; +Memimage *back; + +static Memsubfont *memdefont; +static Lock palettelock; /* access to DAC registers */ +static Lock screenlock; +static int h; +static Point curpos; +static Rectangle window; + +typedef struct SWcursor SWcursor; +static SWcursor *swc = nil; +SWcursor* swcurs_create(ulong *, int, int, Rectangle, int); +void swcurs_destroy(SWcursor*); +void swcurs_enable(SWcursor*); +void swcurs_disable(SWcursor*); +void swcurs_hide(SWcursor*); +void swcurs_unhide(SWcursor*); +void swcurs_load(SWcursor*, Cursor*); + +static void screenputc(char*); +static void scroll(void); +static void setscreen(Mode*); +static void cursorlock(Rectangle); +static void cursorunlock(void); +static void lcdinit(Mode*); +static void lcdsetrgb(int, ulong, ulong, ulong); + +/* + * Called by main(). + */ +void +screeninit(void) +{ + Mode m; + +novgascreen=1; return; + + /* default size and parameters */ + memset(&m.lcd, 0, sizeof(m.lcd)); + m.x = 640; + m.y = 480; + m.d = 3; + if(novgascreen == 0 && archlcdmode(&m) >= 0){ + memdefont = getmemdefont(); + setscreen(&m); + } +} + +/* + * On 8 bit displays, load the default color map + */ +void +graphicscmap(int invert) +{ + int num, den, i, j; + int r, g, b, cr, cg, cb, v; + + for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){ + for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){ + den=r; + if(g>den) den=g; + if(b>den) den=b; + if(den==0) /* divide check -- pick grey shades */ + cr=cg=cb=v*17; + else{ + num=17*(4*den+v); + cr=r*num/den; + cg=g*num/den; + cb=b*num/den; + } + if(invert) + setcolor(255-i-(j&15), + cr*0x01010101, cg*0x01010101, cb*0x01010101); + else + setcolor(i+(j&15), + cr*0x01010101, cg*0x01010101, cb*0x01010101); + } + } +} + +/* + * reconfigure screen shape + */ +static void +setscreen(Mode *mode) +{ + int h; + + if(swc) + swcurs_destroy(swc); + + gscreen = &xgscreen; + xgdata.ref = 1; + lcdinit(mode); + xgdata.bdata = (uchar*)mode->aperture; + if(xgdata.bdata == nil) + panic("setscreen: vga soft memory"); + + gscreen->r = Rect(0, 0, mode->x, mode->y); + gscreen->clipr = gscreen->r; + gscreen->depth = 1<<mode->d; + gscreen->width = wordsperline(gscreen->r, gscreen->depth); + memimageinit(); + memdefont = getmemdefont(); + + memsetchan(gscreen, CMAP8); + back = memwhite; + conscol = memblack; + memimagedraw(gscreen, gscreen->r, memwhite, ZP, memopaque, ZP, SoverD); + graphicscmap(0); + + /* get size for a system window */ + h = memdefont->height; + window = insetrect(gscreen->r, 4); + window.max.y = window.min.y+(Dy(window)/h)*h; + curpos = window.min; +// screenclear(); + + graphicscmap(0); + +// swc = swcurs_create(gscreendata.data, gscreen.width, gscreen.ldepth, gscreen.r, 1); + + drawcursor(nil); +} + +enum { + ScreenCached = 1 /* non-zero if screen region not write-through */ +}; + +void +flushmemscreen(Rectangle r) +{ + if(rectclip(&r, gscreen->r) == 0) + return; + if(r.min.x >= r.max.x || r.min.y >= r.max.y) + return; + if(ScreenCached) + dcflush((ulong*)gscreen->data->bdata + gscreen->width*r.min.y, gscreen->width*Dy(r)); +} + +/* + * export screen to interpreter + */ +uchar* +attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen) +{ + *r = gscreen->r; + *d = gscreen->depth; + *chan = gscreen->chan; + *width = gscreen->width; + *softscreen = ScreenCached; + + return (uchar*)gscreen->data->bdata; +} + +void +detachscreen(void) +{ +} + +/* + * write a string to the screen + */ +void +screenputs(char *s, int n) +{ + int i; + Rune r; + char buf[4]; + + if(novgascreen || xgdata.bdata == nil || memdefont == nil) + return; + if(islo() == 0) { + /* don't deadlock trying to print in interrupt */ + if(!canlock(&screenlock)) + return; + } else + lock(&screenlock); + + while(n > 0) { + i = chartorune(&r, s); + if(i == 0){ + s++; + --n; + continue; + } + memmove(buf, s, i); + buf[i] = 0; + n -= i; + s += i; + screenputc(buf); + } + /* Only OK for now */ + flushmemscreen(gscreen->r); + + unlock(&screenlock); +} + +static void +scroll(void) +{ + int o; + Point p; + Rectangle r; + + o = 4*memdefont->height; + r = Rpt(window.min, Pt(window.max.x, window.max.y-o)); + p = Pt(window.min.x, window.min.y+o); + memimagedraw(gscreen, r, gscreen, p, nil, p, SoverD); + flushmemscreen(r); + r = Rpt(Pt(window.min.x, window.max.y-o), window.max); + memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD); + flushmemscreen(r); + + curpos.y -= o; +} + +static void +clearline(void) +{ + Rectangle r; + int yloc = curpos.y; + + r = Rpt(Pt(window.min.x, window.min.y + yloc), + Pt(window.max.x, window.min.y+yloc+memdefont->height)); + memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD); +} + +static void +screenputc(char *buf) +{ + Point p; + int h, w, pos; + Rectangle r; + static int *xp; + static int xbuf[256]; + + h = memdefont->height; + if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)]) + xp = xbuf; + + switch(buf[0]) { + case '\n': + if(curpos.y+h >= window.max.y) + scroll(); + curpos.y += h; + /* fall through */ + case '\r': + xp = xbuf; + curpos.x = window.min.x; + break; + case '\t': + if(curpos.x == window.min.x) + clearline(); + p = memsubfontwidth(memdefont, " "); + w = p.x; + *xp++ = curpos.x; + pos = (curpos.x-window.min.x)/w; + pos = 8-(pos%8); + r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y+h); + memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD); + flushmemscreen(r); + curpos.x += pos*w; + break; + case '\b': + if(xp <= xbuf) + break; + xp--; + r = Rpt(Pt(*xp, curpos.y), Pt(curpos.x, curpos.y + h)); + memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD); + flushmemscreen(r); + curpos.x = *xp; + break; + case '\0': + break; + default: + p = memsubfontwidth(memdefont, buf); + w = p.x; + + if(curpos.x >= window.max.x-w) + screenputc("\n"); + + if(curpos.x == window.min.x) + clearline(); + if(xp < xbuf+nelem(xbuf)) + *xp++ = curpos.x; + r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y+h); + memimagedraw(gscreen, r, back, ZP, nil, ZP, SoverD); + memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf); + flushmemscreen(r); + curpos.x += w; + } +} + +int +setcolor(ulong p, ulong r, ulong g, ulong b) +{ + ulong x; + + if(gscreen->depth >= 8) + x = 0xFF; + else + x = 0xF; + p &= x; + p ^= x; + lock(&palettelock); + lcdsetrgb(p, r, g, b); + unlock(&palettelock); + return ~0; +} + +void +getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb) +{ + /* TO DO */ + *pr = *pg = *pb = 0; +} + +/* + * See section 5.2.1 (page 5-6) of the MPC823 manual + */ +static uchar lcdclock[17] = { /* (a<<2)|b => divisor of (1<<a)*((b<<1)+1) */ + 0, 0, (1<<2), 1, + (2<<2), 2, (1<<2)|1, 3, + (3<<2), (1<<2)|2, (1<<2)|2, (2<<2)|1, + (2<<2)|1, (1<<2)|3, (1<<2)|3, (4<<2), + (4<<2) +}; + +enum { + /* lccr */ + Enable = 1<<0, + + /* lchcr */ + BigEndian = 1<<24, + AT7 = 7<<21, /* access type */ + + /* sdcr */ + LAM = 1<<6, /* ``LCD aggressive mode'' */ +}; + +/* + * initialise MPC8xx LCD controller incorporating board or display-specific values in Mode.lcd + */ +static void +lcdinit(Mode *mode) +{ + IMM *io; + int i, d; + long hz; + + io = m->iomem; + mode->aperture = xspanalloc(mode->x*mode->y, 16, 0); + mode->apsize = mode->x*mode->y; + + io->sdcr = 1; /* MPC823 errata: turn off LAM before disabling controller */ + eieio(); + io->lcfaa = PADDR(mode->aperture); + io->lccr = (((mode->x*mode->y*(1<<mode->d)+127)/128) << 17) | (mode->d << 5) | mode->lcd.flags; + switch(mode->d){ + default: + case 0: + /* monochrome/greyscale identity map */ + for(i=0; i<16; i++) + io->lcdmap[i] = i; + break; + case 2: + /* 4-bit grey scale map */ + for(i=0; i<16; i++) + io->lcdmap[0] = (i<<8)|(i<<4)|i; + break; + case 3: + /* 8-bit linear map */ + for(i=0; i<256; i++) + io->lcdmap[i] = (i<<8)|(i<<4)|i; + break; + } + + io->lcvcr = (mode->y << 11) | (mode->lcd.vpw<<28) | (mode->lcd.ac<<21) | mode->lcd.wbf; + io->lchcr = (mode->x<<10) | BigEndian | mode->lcd.wbl; + + hz = m->cpuhz; + d = hz/mode->lcd.freq; + if(hz/d > mode->lcd.freq) + d++; + if(d >= 16) + d = 16; + + /* + * enable LCD outputs + */ + io->pddat = 0; + lcdpdpar = 0x1fff & ~mode->lcd.notpdpar; + io->pdpar = lcdpdpar; + io->pddir = 0x1fff; + io->pbpar |= IBIT(31) | IBIT(19) | IBIT(17); + io->pbdir |= IBIT(31) | IBIT(19) | IBIT(17); + io->pbodr &= ~(IBIT(31) | IBIT(19) | IBIT(17)); + + /* + * with the data cache off, early revisions of the 823 did not require + * the `aggressive' DMA priority to avoid flicker, but flicker is obvious + * on the 823A when the cache is on, so LAM is now set + */ + io->sdcr = (io->sdcr & ~0xF) | LAM; /* LAM=1, LAID=0, RAID=0 */ + +// gscreen.width = gscreen.width; /* access external memory before enabling (mpc823 errata) */ + eieio(); + io->sccrk = KEEP_ALIVE_KEY; + eieio(); + io->sccr = (io->sccr & ~0x1F) | lcdclock[d]; + eieio(); + io->sccrk= ~KEEP_ALIVE_KEY; + io->lcsr = 7; /* clear status */ + eieio(); + io->lccr |= Enable; + archbacklight(1); +} + +static void +lcdsetrgb(int p, ulong r, ulong g, ulong b) +{ + r >>= 28; + g >>= 28; + b >>= 28; + m->iomem->lcdmap[p&0xFF] = (r<<8) | (g<<4) | b; +} + +void +blankscreen(int blank) +{ + USED(blank); /* TO DO */ +} + +/* + * enable/disable LCD panel (eg, when using video subsystem) + */ +void +lcdpanel(int on) +{ + IMM *io; + + if(on){ + archbacklight(1); + io = ioplock(); + io->pddat = 0; + io->pdpar = lcdpdpar; + io->pddir = 0x1fff; + io->lccr |= Enable; + iopunlock(); + }else{ + io = ioplock(); + io->sdcr = 1; /* MPC823 errata: turn off LAM before disabling controller */ + eieio(); + io->pddir = 0; + eieio(); + io->lccr &= ~Enable; + iopunlock(); + archbacklight(0); + } +} + +/* + * Software cursor code. Interim version (for baseline). + * we may want to replace code here by memdraw primitives. + */ + +enum { + CUR_ENA = 0x01, /* cursor is enabled */ + CUR_DRW = 0x02, /* cursor is currently drawn */ + CUR_SWP = 0x10, /* bit swap */ + CURSWID = 16, + CURSHGT = 16, +}; + +typedef struct SWcursor { + ulong *fb; /* screen frame buffer */ + Rectangle r; + int d; /* ldepth of screen */ + int width; /* width of screen in ulongs */ + int x; + int y; + int hotx; + int hoty; + uchar cbwid; /* cursor byte width */ + uchar f; /* flags */ + uchar cwid; + uchar chgt; + int hidecount; + uchar data[CURSWID*CURSHGT]; + uchar mask[CURSWID*CURSHGT]; + uchar save[CURSWID*CURSHGT]; +} SWcursor; + +static Rectangle cursoroffrect; +static int cursorisoff; + +static void swcursorflush(int, int); +static void swcurs_draw_or_undraw(SWcursor *); + +static void +cursorupdate0(void) +{ + int inrect, x, y; + Point m; + + m = mousexy(); + x = m.x - swc->hotx; + y = m.y - swc->hoty; + inrect = (x >= cursoroffrect.min.x && x < cursoroffrect.max.x + && y >= cursoroffrect.min.y && y < cursoroffrect.max.y); + if (cursorisoff == inrect) + return; + cursorisoff = inrect; + if (inrect) + swcurs_hide(swc); + else { + swc->hidecount = 0; + swcurs_draw_or_undraw(swc); + } + swcursorflush(m.x, m.y); +} + +void +cursorupdate(Rectangle r) +{ + lock(&screenlock); + r.min.x -= 16; + r.min.y -= 16; + cursoroffrect = r; + if (swc) + cursorupdate0(); + unlock(&screenlock); +} + +void +cursorenable(void) +{ + Point m; + + lock(&screenlock); + if(swc) { + swcurs_enable(swc); + m = mousexy(); + swcursorflush(m.x, m.y); + } + unlock(&screenlock); +} + +void +cursordisable(void) +{ + Point m; + + lock(&screenlock); + if(swc) { + swcurs_disable(swc); + m = mousexy(); + swcursorflush(m.x, m.y); + } + unlock(&screenlock); +} + +void +drawcursor(Drawcursor* c) +{ + Point p; + Cursor curs, *cp; + int j, i, h, bpl; + uchar *bc, *bs, *cclr, *cset; + + if(!swc) + return; + + /* Set the default system cursor */ + if(!c || c->data == nil) + cp = &arrow /*&crosshair_black*/; + else { + cp = &curs; + p.x = c->hotx; + p.y = c->hoty; + cp->offset = p; + bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1); + + h = (c->maxy-c->miny)/2; + if(h > 16) + h = 16; + + bc = c->data; + bs = c->data + h*bpl; + + cclr = cp->clr; + cset = cp->set; + for(i = 0; i < h; i++) { + for(j = 0; j < 2; j++) { + cclr[j] = bc[j]; + cset[j] = bs[j]; + } + bc += bpl; + bs += bpl; + cclr += 2; + cset += 2; + } + } + + if(swc) { + swcurs_load(swc, cp); + p = mousexy(); + swcursorflush(p.x, p.y); + } +} + +SWcursor* +swcurs_create(ulong *fb, int width, int ldepth, Rectangle r, int bitswap) +{ + SWcursor *swc = (SWcursor*)malloc(sizeof(SWcursor)); + swc->fb = fb; + swc->r = r; + swc->d = ldepth; + swc->width = width; + swc->f = bitswap ? CUR_SWP : 0; + swc->x = swc->y = 0; + swc->hotx = swc->hoty = 0; + swc->hidecount = 0; + return swc; +} + +void +swcurs_destroy(SWcursor *swc) +{ + swcurs_disable(swc); + free(swc); +} + +static void +swcursorflush(int x, int y) +{ + Rectangle r; + + /* XXX a little too paranoid here */ + r.min.x = x-16; + r.min.y = y-16; + r.max.x = x+17; + r.max.y = y+17; + flushmemscreen(r); +} + +static void +swcurs_draw_or_undraw(SWcursor *swc) +{ + uchar *p; + uchar *cs; + int w, vw; + int x1 = swc->r.min.x; + int y1 = swc->r.min.y; + int x2 = swc->r.max.x; + int y2 = swc->r.max.y; + int xp = swc->x - swc->hotx; + int yp = swc->y - swc->hoty; + int ofs; + + if(((swc->f & CUR_ENA) && (swc->hidecount <= 0)) + == ((swc->f & CUR_DRW) != 0)) + return; + w = swc->cbwid*BI2BY/(1 << swc->d); + x1 = xp < x1 ? x1 : xp; + y1 = yp < y1 ? y1 : yp; + x2 = xp+w >= x2 ? x2 : xp+w; + y2 = yp+swc->chgt >= y2 ? y2 : yp+swc->chgt; + if(x2 <= x1 || y2 <= y1) + return; + p = (uchar*)(swc->fb + swc->width*y1) + + x1*(1 << swc->d)/BI2BY; + y2 -= y1; + x2 = (x2-x1)*(1 << swc->d)/BI2BY; + vw = swc->width*BY2WD - x2; + w = swc->cbwid - x2; + ofs = swc->cbwid*(y1-yp)+(x1-xp); + cs = swc->save + ofs; + if((swc->f ^= CUR_DRW) & CUR_DRW) { + uchar *cm = swc->mask + ofs; + uchar *cd = swc->data + ofs; + while(y2--) { + x1 = x2; + while(x1--) { + *p = ((*cs++ = *p) & *cm++) ^ *cd++; + p++; + } + cs += w; + cm += w; + cd += w; + p += vw; + } + } else { + while(y2--) { + x1 = x2; + while(x1--) + *p++ = *cs++; + cs += w; + p += vw; + } + } +} + +void +swcurs_hide(SWcursor *swc) +{ + ++swc->hidecount; + swcurs_draw_or_undraw(swc); +} + +void +swcurs_unhide(SWcursor *swc) +{ + if (--swc->hidecount < 0) + swc->hidecount = 0; + swcurs_draw_or_undraw(swc); +} + +void +swcurs_enable(SWcursor *swc) +{ + swc->f |= CUR_ENA; + swcurs_draw_or_undraw(swc); +} + +void +swcurs_disable(SWcursor *swc) +{ + swc->f &= ~CUR_ENA; + swcurs_draw_or_undraw(swc); +} + +void +swcurs_load(SWcursor *swc, Cursor *c) +{ + int i, k; + uchar *bc, *bs, *cd, *cm; + static uchar bdv[4] = {0,Backgnd,Foregnd,0xff}; + static uchar bmv[4] = {0xff,0,0,0xff}; + int bits = 1<<swc->d; + uchar mask = (1<<bits)-1; + int bswp = (swc->f&CUR_SWP) ? 8-bits : 0; + + bc = c->clr; + bs = c->set; + + swcurs_hide(swc); + cd = swc->data; + cm = swc->mask; + swc->hotx = c->offset.x; + swc->hoty = c->offset.y; + swc->chgt = CURSHGT; + swc->cwid = CURSWID; + swc->cbwid = CURSWID*(1<<swc->d)/BI2BY; + for(i = 0; i < CURSWID/BI2BY*CURSHGT; i++) { + uchar bcb = *bc++; + uchar bsb = *bs++; + for(k=0; k<BI2BY;) { + uchar cdv = 0; + uchar cmv = 0; + int z; + for(z=0; z<BI2BY; z += bits) { + int n = ((bsb&(0x80))|((bcb&(0x80))<<1))>>7; + int s = z^bswp; + cdv |= (bdv[n]&mask) << s; + cmv |= (bmv[n]&mask) << s; + bcb <<= 1; + bsb <<= 1; + k++; + } + *cd++ = cdv; + *cm++ = cmv; + } + } + swcurs_unhide(swc); +} + |
