/*Olivetti M24 video emulation Essentially double-res CGA*/ #include "ibm.h" #include "video.h" static uint8_t m24_ctrl; static uint32_t m24_base; void m24_out(uint16_t addr, uint8_t val) { uint8_t old; switch (addr) { case 0x3D4: crtcreg = val & 31; return; case 0x3D5: old = crtc[crtcreg]; crtc[crtcreg] = val & crtcmask[crtcreg]; if (old != val) { if (crtcreg < 0xE || crtcreg > 0x10) { fullchange = changeframecount; m24_recalctimings(); } } return; case 0x3D8: cgamode = val; return; case 0x3D9: cgacol = val; return; case 0x3de: m24_ctrl = val; m24_base = (val & 0x08) ? 0x4000 : 0; return; } } uint8_t m24_in(uint16_t addr) { switch (addr) { case 0x3D4: return crtcreg; case 0x3D5: return crtc[crtcreg]; case 0x3DA: return cgastat; } return 0xFF; } static uint8_t charbuffer[256]; void m24_write(uint32_t addr, uint8_t val) { vram[addr & 0x7FFF]=val; charbuffer[ ((int)(((dispontime - vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val; charbuffer[(((int)(((dispontime - vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val; } uint8_t m24_read(uint32_t addr) { return vram[addr & 0x7FFF]; } void m24_recalctimings() { if (cgamode & 1) { disptime = crtc[0] + 1; dispontime = crtc[1]; } else { disptime = (crtc[0] + 1) << 1; dispontime = crtc[1] << 1; } dispofftime = disptime - dispontime; // printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); dispontime *= CGACONST / 2; dispofftime *= CGACONST / 2; // printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); } static int linepos,displine; static int sc,vc; static int cgadispon; static int con,coff,cursoron,cgablink; static int vsynctime,vadj; static int m24_lineff = 0; static uint16_t ma,maback,ca; void m24_poll() { uint16_t ca=(crtc[15]|(crtc[14]<<8))&0x3FFF; int drawcursor; int x,c; int oldvc; uint8_t chr,attr; uint16_t dat,dat2,dat3,dat4; int cols[4]; int col; int oldsc; if (!linepos) { // pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine); vidtime+=dispofftime; cgastat|=1; linepos=1; oldsc=sc; if ((crtc[8]&3)==3) sc=(sc<<1)&7; if (cgadispon) { if (displineline[displine][c]=0; if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=0; else buffer->line[displine][c+(crtc[1]<<4)+8]=0; } else { buffer->line[displine][c]=(cgacol&15)+16; if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=(cgacol&15)+16; else buffer->line[displine][c+(crtc[1]<<4)+8]=(cgacol&15)+16; } } if (cgamode&1) { for (x=0;x>4)&7)+16; if ((cgablink&16) && (attr&0x80) && !drawcursor) cols[1]=cols[0]; } else { cols[1]=(attr&15)+16; cols[0]=(attr>>4)+16; } if (drawcursor) { for (c=0;c<8;c++) buffer->line[displine][(x<<3)+c+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]^15; } else { for (c=0;c<8;c++) buffer->line[displine][(x<<3)+c+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]; } ma++; } } else if (!(cgamode&2)) { for (x=0;x>4)&7)+16; if ((cgablink&16) && (attr&0x80)) cols[1]=cols[0]; } else { cols[1]=(attr&15)+16; cols[0]=(attr>>4)+16; } ma++; if (drawcursor) { for (c=0;c<8;c++) buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]^15; } else { for (c=0;c<8;c++) buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]; } } } else if (!(cgamode&16)) { cols[0]=(cgacol&15)|16; col=(cgacol&16)?24:16; if (cgamode&4) { cols[1]=col|3; cols[2]=col|4; cols[3]=col|7; } else if (cgacol&32) { cols[1]=col|3; cols[2]=col|5; cols[3]=col|7; } else { cols[1]=col|2; cols[2]=col|4; cols[3]=col|6; } for (x=0;xline[displine][(x<<4)+(c<<1)+8]= buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[dat>>14]; dat<<=2; } } } else { if (m24_ctrl & 1) { dat2 = ((sc & 1) * 0x4000) | (m24_lineff * 0x2000); cols[0]=0; cols[1]=/*(cgacol&15)*/15+16; } else { dat2 = (sc & 1) * 0x2000; cols[0]=0; cols[1]=(cgacol&15)+16; } for (x=0;xline[displine][(x<<4)+c+8]=cols[dat>>15]; dat<<=1; } } } } else { cols[0]=((cgamode&0x12)==0x12)?0:(cgacol&15)+16; if (cgamode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,cols[0]); else hline(buffer,0,displine,(crtc[1]<<4)+16,cols[0]); } if (cgamode&1) x=(crtc[1]<<3)+16; else x=(crtc[1]<<4)+16; sc=oldsc; if (vc==crtc[7] && !sc) cgastat|=8; displine++; if (displine>=720) displine=0; } else { // pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj); vidtime+=dispontime; if (cgadispon) cgastat&=~1; linepos=0; m24_lineff ^= 1; if (m24_lineff) { ma = maback; } else { if (vsynctime) { vsynctime--; if (!vsynctime) cgastat&=~8; } if (sc==(crtc[11]&31) || ((crtc[8]&3)==3 && sc==((crtc[11]&31)>>1))) { con=0; coff=1; } if (vadj) { sc++; sc&=31; ma=maback; vadj--; if (!vadj) { cgadispon=1; ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; sc=0; } } else if (sc==crtc[9] || ((crtc[8]&3)==3 && sc==(crtc[9]>>1))) { maback=ma; sc=0; oldvc=vc; vc++; vc&=127; if (vc==crtc[6]) cgadispon=0; if (oldvc==crtc[4]) { vc=0; vadj=crtc[5]; if (!vadj) cgadispon=1; if (!vadj) ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; if ((crtc[10]&0x60)==0x20) cursoron=0; else cursoron=cgablink&16; } if (vc==crtc[7]) { cgadispon=0; displine=0; vsynctime=(crtc[3]>>4)+1; if (crtc[7]) { if (cgamode&1) x=(crtc[1]<<3)+16; else x=(crtc[1]<<4)+16; lastline++; if (x!=xsize || (lastline-firstline)!=ysize) { xsize=x; ysize=lastline-firstline; if (xsize<64) xsize=656; if (ysize<32) ysize=200; updatewindowsize(xsize, ysize + 16); } startblit(); video_blit_memtoscreen_8(0, firstline - 8, xsize, (lastline - firstline) + 16); if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); readflash=0; frames++; endblit(); video_res_x = xsize - 16; video_res_y = ysize; if (cgamode & 1) { video_res_x /= 8; video_res_y /= (crtc[9] + 1) * 2; video_bpp = 0; } else if (!(cgamode & 2)) { video_res_x /= 16; video_res_y /= (crtc[9] + 1) * 2; video_bpp = 0; } else if (!(cgamode&16)) { video_res_x /= 2; video_res_y /= 2; video_bpp = 2; } else if (!(m24_ctrl & 1)) { video_res_y /= 2; video_bpp = 1; } } firstline=1000; lastline=0; cgablink++; } } else { sc++; sc&=31; ma=maback; } if ((sc==(crtc[10]&31) || ((crtc[8]&3)==3 && sc==((crtc[10]&31)>>1)))) con=1; } if (cgadispon && (cgamode&1)) { for (x=0;x<(crtc[1]<<1);x++) charbuffer[x]=vram[(((ma<<1)+x)&0x3FFF) + m24_base]; } } } int m24_init() { mem_sethandler(0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL); return 0; } GFXCARD vid_m24 = { m24_init, /*IO at 3Cx/3Dx*/ m24_out, m24_in, /*IO at 3Ax/3Bx*/ video_out_null, video_in_null, m24_poll, m24_recalctimings, video_write_null, video_write_null, m24_write, video_read_null, video_read_null, m24_read };