ref: 49261dcb404260d0a36ea64a093beb045fd2843e
parent: 3dc0a21b4add3f2f9b87dd902650f0367954a7f2
author: aiju <devnull@localhost>
date: Wed Jun 14 13:41:51 EDT 2017
vmx: slightly more vga support
--- a/sys/src/cmd/vmx/vga.c
+++ b/sys/src/cmd/vmx/vga.c
@@ -20,11 +20,79 @@
static Mousectl *mc;
static Rectangle picr;
Channel *kbdch, *mousech;
-static u16int cursorpos;
u8int mousegrab;
static uchar *sfb;
+typedef struct VGA VGA;
+struct VGA {
+ u8int miscout;
+ u8int cidx;
+ u8int aidx; /* bit 7: access flipflop */
+ u16int rdidx, wdidx; /* bit 0-1: color */
+ u8int attr[32];
+ u32int pal[256];
+ Image *col[256];
+ Image *acol[16];
+ u8int crtc[0x18];
+} vga = {
+ .miscout 1,
+ .attr { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ .crtc { [11] 15 },
+ .pal {
+ 0x000000ff, 0x0000a8ff, 0x00a800ff, 0x00a8a8ff, 0xa80000ff, 0xa800a8ff, 0xa85400ff, 0xa8a8a8ff,
+ 0x545454ff, 0x5454fcff, 0x54fc54ff, 0x54fcfcff, 0xfc5454ff, 0xfc54fcff, 0xfcfc54ff, 0xfcfcfcff,
+ 0x000000ff, 0x141414ff, 0x202020ff, 0x2c2c2cff, 0x383838ff, 0x444444ff, 0x505050ff, 0x606060ff,
+ 0x707070ff, 0x808080ff, 0x909090ff, 0xa0a0a0ff, 0xb4b4b4ff, 0xc8c8c8ff, 0xe0e0e0ff, 0xfcfcfcff,
+ 0x0000fcff, 0x4000fcff, 0x7c00fcff, 0xbc00fcff, 0xfc00fcff, 0xfc00bcff, 0xfc007cff, 0xfc0040ff,
+ 0xfc0000ff, 0xfc4000ff, 0xfc7c00ff, 0xfcbc00ff, 0xfcfc00ff, 0xbcfc00ff, 0x7cfc00ff, 0x40fc00ff,
+ 0x00fc00ff, 0x00fc40ff, 0x00fc7cff, 0x00fcbcff, 0x00fcfcff, 0x00bcfcff, 0x007cfcff, 0x0040fcff,
+ 0x7c7cfcff, 0x9c7cfcff, 0xbc7cfcff, 0xdc7cfcff, 0xfc7cfcff, 0xfc7cdcff, 0xfc7cbcff, 0xfc7c9cff,
+ 0xfc7c7cff, 0xfc9c7cff, 0xfcbc7cff, 0xfcdc7cff, 0xfcfc7cff, 0xdcfc7cff, 0xbcfc7cff, 0x9cfc7cff,
+ 0x7cfc7cff, 0x7cfc9cff, 0x7cfcbcff, 0x7cfcdcff, 0x7cfcfcff, 0x7cdcfcff, 0x7cbcfcff, 0x7c9cfcff,
+ 0xb4b4fcff, 0xc4b4fcff, 0xd8b4fcff, 0xe8b4fcff, 0xfcb4fcff, 0xfcb4e8ff, 0xfcb4d8ff, 0xfcb4c4ff,
+ 0xfcb4b4ff, 0xfcc4b4ff, 0xfcd8b4ff, 0xfce8b4ff, 0xfcfcb4ff, 0xe8fcb4ff, 0xd8fcb4ff, 0xc4fcb4ff,
+ 0xb4fcb4ff, 0xb4fcc4ff, 0xb4fcd8ff, 0xb4fce8ff, 0xb4fcfcff, 0xb4e8fcff, 0xb4d8fcff, 0xb4c4fcff,
+ 0x000070ff, 0x1c0070ff, 0x380070ff, 0x540070ff, 0x700070ff, 0x700054ff, 0x700038ff, 0x70001cff,
+ 0x700000ff, 0x701c00ff, 0x703800ff, 0x705400ff, 0x707000ff, 0x547000ff, 0x387000ff, 0x1c7000ff,
+ 0x007000ff, 0x00701cff, 0x007038ff, 0x007054ff, 0x007070ff, 0x005470ff, 0x003870ff, 0x001c70ff,
+ 0x383870ff, 0x443870ff, 0x543870ff, 0x603870ff, 0x703870ff, 0x703860ff, 0x703854ff, 0x703844ff,
+ 0x703838ff, 0x704438ff, 0x705438ff, 0x706038ff, 0x707038ff, 0x607038ff, 0x547038ff, 0x447038ff,
+ 0x387038ff, 0x387044ff, 0x387054ff, 0x387060ff, 0x387070ff, 0x386070ff, 0x385470ff, 0x384470ff,
+ 0x505070ff, 0x585070ff, 0x605070ff, 0x685070ff, 0x705070ff, 0x705068ff, 0x705060ff, 0x705058ff,
+ 0x705050ff, 0x705850ff, 0x706050ff, 0x706850ff, 0x707050ff, 0x687050ff, 0x607050ff, 0x587050ff,
+ 0x507050ff, 0x507058ff, 0x507060ff, 0x507068ff, 0x507070ff, 0x506870ff, 0x506070ff, 0x505870ff,
+ 0x000040ff, 0x100040ff, 0x200040ff, 0x300040ff, 0x400040ff, 0x400030ff, 0x400020ff, 0x400010ff,
+ 0x400000ff, 0x401000ff, 0x402000ff, 0x403000ff, 0x404000ff, 0x304000ff, 0x204000ff, 0x104000ff,
+ 0x004000ff, 0x004010ff, 0x004020ff, 0x004030ff, 0x004040ff, 0x003040ff, 0x002040ff, 0x001040ff,
+ 0x202040ff, 0x282040ff, 0x302040ff, 0x382040ff, 0x402040ff, 0x402038ff, 0x402030ff, 0x402028ff,
+ 0x402020ff, 0x402820ff, 0x403020ff, 0x403820ff, 0x404020ff, 0x384020ff, 0x304020ff, 0x284020ff,
+ 0x204020ff, 0x204028ff, 0x204030ff, 0x204038ff, 0x204040ff, 0x203840ff, 0x203040ff, 0x202840ff,
+ 0x2c2c40ff, 0x302c40ff, 0x342c40ff, 0x3c2c40ff, 0x402c40ff, 0x402c3cff, 0x402c34ff, 0x402c30ff,
+ 0x402c2cff, 0x40302cff, 0x40342cff, 0x403c2cff, 0x40402cff, 0x3c402cff, 0x34402cff, 0x30402cff,
+ 0x2c402cff, 0x2c4030ff, 0x2c4034ff, 0x2c403cff, 0x2c4040ff, 0x2c3c40ff, 0x2c3440ff, 0x2c3040ff,
+ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
+ },
+};
+
static void
+newpal(int l, int n, int dofree)
+{
+ int x;
+
+ for(; n-- > 0; l++){
+ if(dofree)
+ freeimage(vga.col[l]);
+ vga.col[l] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, vga.pal[l]);
+ }
+ for(l = 0; l < 16; l++){
+ x = vga.attr[0x14] << 4 & 0xc0 | vga.attr[l] & 0x3f;
+ if((vga.attr[0x10] & 0x80) != 0)
+ x = x & 0xcf | vga.attr[0x14] << 4 & 0x30;
+ vga.acol[l] = vga.col[x];
+ }
+}
+
+static void
screeninit(void)
{
Point p;
@@ -34,42 +102,66 @@
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
img = allocimage(display, Rect(0, 0, picw, pich), screenchan == 0 ? screen->chan : screenchan, 0, 0);
draw(screen, screen->r, bg, nil, ZP);
+ newpal(0, 256, 0);
}
u32int
vgaio(int isin, u16int port, u32int val, int sz, void *)
{
- static u8int cgaidx;
+ u32int m;
+ iowhine(isin, port, val, sz, "vga");
+ if(sz != 1) vmdebug("vga: non-byte access to port %#ux, sz=%d", port, sz);
val = (u8int) val;
switch(isin << 16 | port){
- case 0x3d4:
- cgaidx = val;
+ case 0x3c0:
+ if((vga.aidx & 0x80) != 0){
+ vmdebug("vga: attribute write %#.2x = %#.2x", vga.aidx & 0x1f, val);
+ vga.attr[vga.aidx & 0x1f] = val;
+ newpal(0, 0, 0);
+ }else
+ vga.aidx = val & 0x3f;
+ vga.aidx ^= 0x80;
return 0;
- case 0x103d4:
- return cgaidx;
+ case 0x3c2: vga.miscout = val; return 0;
+ case 0x3c7: vga.rdidx = val << 2; return 0;
+ case 0x3c8: vga.wdidx = val << 2; return 0;
+ case 0x3c9:
+ vga.pal[vga.wdidx >> 2] = vga.pal[vga.wdidx >> 2] & ~(0xff << (~vga.wdidx << 3 & 24)) | val << 2 + (~vga.wdidx << 3 & 24);
+ newpal(vga.wdidx >> 2, 1, 1);
+ vga.wdidx = vga.wdidx + 1 + (vga.wdidx >> 1 & 1) & 0x3ff;
+ return 0;
+ case 0x3d4: vga.cidx = val; return 0;
case 0x3d5:
- switch(cgaidx){
- case 14:
- cursorpos = cursorpos >> 8 | val << 8;
- break;
- case 15:
- cursorpos = cursorpos & 0xff00 | val;
- break;
+ switch(vga.cidx){
+ case 10: case 11: case 12: case 13: case 14: case 15:
+ vga.crtc[vga.cidx] = val;
+ return 0;
default:
- vmerror("write to unknown VGA register, 3d5/%#ux (val=%#ux)", cgaidx, val);
+ vmerror("write to unknown VGA register, 3d5/%#ux (val=%#ux)", vga.cidx, val);
}
return 0;
+ case 0x103c0: return vga.aidx & 0x3f;
+ case 0x103c1: return vga.attr[vga.aidx & 0x1f];
+ case 0x103c7: return vga.rdidx >> 2;
+ case 0x103c8: return vga.wdidx >> 2;
+ case 0x103c9:
+ m = vga.pal[vga.rdidx >> 2] >> (~vga.rdidx << 3 & 24) + 2;
+ vga.rdidx = vga.rdidx + 1 + (vga.rdidx >> 1 & 1) & 0x3ff;
+ return m;
+ case 0x103cc: return vga.miscout;
+ case 0x103d4: return vga.cidx;
case 0x103d5:
- switch(cgaidx){
- case 14:
- return cursorpos >> 8;
- case 15:
- return (u8int)cursorpos;
+ switch(vga.cidx){
+ case 10: case 11: case 12: case 13: case 14: case 15:
+ return vga.crtc[vga.cidx];
default:
- vmerror("read from unknown VGA register, 3d5/%#ux", cgaidx);
+ vmerror("read from unknown VGA register, 3d5/%#ux", vga.cidx);
return 0;
- }
+ }
+ case 0x103da:
+ vga.aidx &= ~0x7f;
+ return 0;
}
return iowhine(isin, port, val, sz, "vga");
}
@@ -290,22 +382,41 @@
drawtext(void)
{
Rune buf[80];
- uchar *p;
- int y, x;
- Point pt;
+ uchar *p, attr;
+ int y, x, x1;
+ Rectangle r;
+ u16int cp;
+ static uchar rbuf[80*25*2];
+ u16int sa;
- draw(img, img->r, display->black, nil, ZP);
+ sa = vga.crtc[12] << 8 | vga.crtc[13];
+ if(sa + 80*25 >= 0x10000){
+ memset(rbuf, 0, sizeof(rbuf));
+ memmove(rbuf, fb + sa * 2, 0x10000 - 80*25 - sa);
+ p = rbuf;
+ }else
+ p = fb + sa * 2;
for(y = 0; y < 25; y++){
- p = &fb[y * 160];
for(x = 0; x < 80; x++)
buf[x] = cp437[p[2*x]];
- runestringn(img, Pt(0, 16 * y), display->white, ZP, display->defaultfont, buf, 80);
+ for(x = 0; x < 80; x = x1){
+ attr = p[2*x+1];
+ for(x1 = x; x1 < 80 && p[2*x1+1] == attr; x1++)
+ ;
+ r = Rect(x * 8, y * 16, x1 * 8, (y + 1) * 16);
+ draw(img, r, vga.acol[attr >> 4], nil, ZP);
+ runestringn(img, r.min, vga.acol[attr & 0xf], ZP, display->defaultfont, buf + x, x1 - x);
+ }
+ p += 160;
}
- if(cursorpos < 80*25){
- buf[0] = cp437[fb[cursorpos*2]];
- pt = Pt(cursorpos % 80 * 8, cursorpos / 80 * 16);
- draw(img, Rect(pt.x, pt.y, pt.x + 8, pt.y + 16), display->white, nil, ZP);
- runestringn(img, pt, display->black, ZP, display->defaultfont, buf, 1);
+ cp = (vga.crtc[14] << 8 | vga.crtc[15]);
+ if(cp >= sa && cp < sa + 80*25 && (vga.crtc[10] & 0x20) == 0){
+ buf[0] = cp437[fb[cp*2]];
+ attr = fb[cp*2+1];
+ r.min = Pt((cp - sa) % 80 * 8, (cp - sa) / 80 * 16);
+ r.max = Pt(r.min.x + 8, r.min.y + (vga.crtc[11] & 0x1f) + 1);
+ r.min.y += vga.crtc[10] & 0x1f;
+ draw(img, r, vga.acol[attr & 0xf], nil, ZP);
}
draw(screen, picr, img, nil, ZP);
flushimage(display, 1);
@@ -411,11 +522,15 @@
vgainit(void)
{
char buf[512];
+ int i;
if(picw == 0) return;
fb = gptr(fbaddr, fbsz);
if(fb == nil)
sysfatal("got nil ptr for framebuffer");
+ if(textmode)
+ for(i = 0; i < 0x8000; i += 2)
+ PUT16(fb, i, 0x0700);
snprint(buf, sizeof(buf), "-dx %d -dy %d", picw+50, pich+50);
newwindow(buf);
initdraw(nil, nil, "vmx");