1
0
mirror of https://github.com/aap/pdp6.git synced 2026-01-11 23:53:31 +00:00
aap.pdp6/emu/dis340.c
2024-05-13 07:13:12 +02:00

1046 lines
20 KiB
C

#include "pdp6.h"
#include <SDL.h>
//#define JUSTTESTING
char *dis_ident = DIS_IDENT;
static SDL_Window *window;
static SDL_Renderer *renderer;
#define LDB(p, s, w) ((w)>>(p) & (1<<(s))-1)
#define XLDB(ppss, w) LDB((ppss)>>6 & 077, (ppss)&077, w)
#define MASK(p, s) ((1<<(s))-1 << (p))
#define DPB(b, p, s, w) ((w)&~MASK(p,s) | (b)<<(p) & MASK(p,s))
#define XDPB(b, ppss, w) DPB(b, (ppss)>>6 & 077, (ppss)&077, w)
enum Modes
{
PM,
XYM,
SM,
CM,
VM,
VCM,
IM,
SBM
};
#ifdef JUSTTESTING
#define PARAM_W(m, lp, s, sc, in) \
((in) |\
(sc)<<4 |\
(s)<<9 |\
(lp)<<11 |\
(m)<<13)
#define XYM_W(p, m, lp, i, xy) \
((xy) |\
(i)<<10 |\
(lp)<<11 |\
(m)<<13 |\
(p)<<16)
#define VM_W(e, i, y, x) \
((x) |\
(y)<<8 |\
(i)<<16 |\
(e)<<17)
#define IM_W(e, i, p1, p2, p3, p4) \
((p4) |\
(p3)<<4 |\
(p2)<<8 |\
(p1)<<12 |\
(i)<<16 |\
(e)<<17)
static word list[] = {
PARAM_W(XYM, 0, 0, 4, 017),
XYM_W(1, XYM, 0, 0, 100),
XYM_W(0, IM, 0, 1, 100),
IM_W(1, 1, 012, 012, 012, 012),
PARAM_W(VM, 0, 0, 0, 0),
VM_W(1, 1, 50, 20),
PARAM_W(XYM, 0, 0, 07, 0),
XYM_W(1, XYM, 0, 0, 950),
XYM_W(0, CM, 0, 0, 0),
036<<12 | 034<<6 | 040,
01<<12 | 02<<6 | 03,
04<<12 | 05<<6 | 06,
07<<12 | 010<<6 | 011,
012<<12 | 013<<6 | 014,
015<<12 | 016<<6 | 017,
020<<12 | 034<<6 | 033,
040<<12 | 021<<6 | 022,
023<<12 | 024<<6 | 025,
026<<12 | 027<<6 | 030,
031<<12 | 032<<6 | 0,
033<<12 | 034<<6 | 040,
041<<12 | 042<<6 | 043,
044<<12 | 045<<6 | 046,
047<<12 | 050<<6 | 051,
052<<12 | 053<<6 | 054,
055<<12 | 056<<6 | 057,
033<<12 | 034<<6 | 040,
060<<12 | 061<<6 | 062,
063<<12 | 064<<6 | 065,
066<<12 | 067<<6 | 070,
071<<12 | 072<<6 | 073,
074<<12 | 075<<6 | 076,
077<<12 | 037<<6,
PARAM_W(0, 1, 3, 0, 0),
~0
};
static word *listp = list;
#endif
typedef struct Pixel Pixel;
struct Pixel
{
u16 x, y;
u8 l;
};
typedef struct CRT CRT;
struct CRT
{
Pixel pxlist[1024*1024];
int numPixels;
int phos1List[1024*1024];
int numPhos1;
int phos2List[1024*1024];
int numPhos2;
int clearList[1024*1024];
int numClearPixels;
int tmpList[1024*1024];
int numTmp;
u8 pxvals[1024*1024]; // intensity
u8 phos1vals[1024*1024];
u8 phos2vals[1024*1024];
u32 pixels[1024*1024]; // RGB values
};
typedef struct Dis340 Dis340;
struct Dis340
{
/* 344 interface for PDP-6.
* no schematics unfortunately */
Device dev;
IOBus *bus;
int pia_data;
int pia_spec;
word ib; /* interface buffer */
int ibc; /* number of words in IB */
/* 340 display and 342 char gen */
int intdelay; /* has an intensify delay been triggered */
hword br; /* 18 bits */
int mode; /* 3 bits */
int i; /* intensity - 3 bits */
int sz; /* scale - 2 bits */
int brm; /* 7 bits */
int s; /* shift - 4 bits */
int x, y; /* 10 bits */
/* flip flops */
int stop;
int halt;
int move;
int lp_find;
int lp_flag;
int lp_enable;
int rfd;
int hef, vef;
/* br shifted for IM and CM */
int pnts;
int chrs;
/* values for BRM counting */
int brm_add;
int brm_comp;
/* 342 char gen */
int cgstate; /* 0 - inactive
* 1 - drawing character */
int shift;
int *cp; /* current char pointer */
/* simulated tube */
CRT *crt;
};
static void plotpixel(CRT *crt, int x, int y, int intensity);
static void
intensify(Dis340 *dis)
{
plotpixel(dis->crt, dis->x, 1023-dis->y, dis->i);
}
static void
rfd(Dis340 *dis)
{
dis->rfd = 1;
dis->hef = 0;
dis->vef = 0;
}
static void
escape(Dis340 *dis)
{
dis->mode = 0;
dis->lp_find = 0;
}
static void
initiate(Dis340 *dis)
{
dis->intdelay = 0;
dis->cgstate = 0;
dis->shift = 0;
dis->lp_enable = 0; // TODO: not in schematics?
dis->lp_find = 0;
dis->lp_flag = 0;
dis->stop = 0;
escape(dis);
rfd(dis);
}
static void
read_to_mode(Dis340 *dis)
{
dis->mode = LDB(13, 3, dis->br);
if((dis->br & 0010000) == 0010000)
dis->lp_enable = !!(dis->br & 04000);
}
static void
shift_s(Dis340 *dis)
{
dis->s >>= 1;
dis->pnts <<= 4;
dis->chrs <<= 6;
}
static void
count_brm(Dis340 *dis)
{
dis->brm = ((dis->brm+dis->brm_add) ^ dis->brm_comp) & 0177;
shift_s(dis);
}
static void
count_x(Dis340 *dis, int s, int r, int l)
{
if(r) dis->x += s;
if(l) dis->x -= s;
if(r || l) dis->move = 1;
if(dis->x >= 1024 || dis->x < 0) dis->hef = 1;
dis->x &= 01777;
if(dis->mode == IM && dis->s&1)
dis->halt = 1;
if(dis->mode == CM)
dis->move = 0;
}
static void
count_y(Dis340 *dis, int s, int u, int d)
{
if(u) dis->y += s;
if(d) dis->y -= s;
if(u || d) dis->move = 1; // actually in count_x
if(dis->y >= 1024 || dis->y < 0) dis->vef = 1;
dis->y &= 01777;
dis->lp_flag |= dis->lp_find && dis->lp_enable;
}
static void
getdir(int brm, int xy, int c, int *pos, int *neg)
{
int dir;
int foo;
foo = ~brm & c;
dir = foo&0001 && xy&0100 ||
foo&0002 && xy&0040 ||
foo&0004 && xy&0020 ||
foo&0010 && xy&0010 ||
foo&0020 && xy&0004 ||
foo&0040 && xy&0002 ||
foo&0100 && xy&0001;
*pos = 0;
*neg = 0;
if(dir){
if(xy & 0200)
*neg = 1;
else
*pos = 1;
}
}
#include "chargen.inc"
static void
nextchar(Dis340 *dis)
{
dis->cgstate = 0;
if(dis->s & 1)
rfd(dis);
else{
shift_s(dis);
dis->intdelay = 1;
}
}
static void
cg_count(Dis340 *dis)
{
int pnt;
int u, d, l, r;
pnt = *dis->cp++;
if(pnt == 0){
/* end of character */
end:
nextchar(dis);
return;
}
if(pnt & 040){
/* escape from char */
dis->cgstate = 0;
escape(dis);
rfd(dis);
return;
}
if(pnt & 0100)
dis->x = 0;
if(pnt & 0200){
dis->shift = 0;
goto end;
}
if(pnt & 0400){
dis->shift = 64;
goto end;
}
r = (pnt & 014) == 010;
l = (pnt & 014) == 014;
u = (pnt & 003) == 002;
d = (pnt & 003) == 003;
count_y(dis, 1<<dis->sz, u, d);
count_x(dis, 1<<dis->sz, r, l);
/* 1μs after count */
if(pnt & 020)
intensify(dis);
/* 0.5μs delay */
}
/* return whether to loop */
static void
idp(Dis340 *dis)
{
uchar pnt;
int brm, c;
int u, d, l, r;
int halt;
dis->intdelay = 0;
switch(dis->mode){
case PM:
// TODO: what is RI?
read_to_mode(dis);
/* PM PULSE */
if(dis->br & 010) dis->i = LDB(0, 3, dis->br);
if(dis->br & 0100) dis->sz = LDB(4, 2, dis->br);
if(dis->br & 02000) dis->stop = 1;
else rfd(dis);
break;
case XYM:
if(dis->lp_flag)
break;
read_to_mode(dis);
if(dis->br & 0200000){
dis->y = 0; // CLEAR Y
dis->y |= dis->br & 01777; // LOAD Y
/* if intensify 35μs delay */
}else{
/* 35μs delay */
dis->x = 0; // CLEAR X
dis->x |= dis->br & 01777; // LOAD X
}
/* 0.5μs delay */
if(dis->br & 0002000)
intensify(dis);
rfd(dis);
break;
case CM:
/* Tell CG to start */
dis->cp = chars[LDB(12, 6, dis->chrs) + dis->shift];
dis->cgstate = 1;
break;
case IM:
halt = dis->halt;
count_brm(dis);
pnt = LDB(16, 4, dis->pnts);
r = (pnt & 014) == 010;
l = (pnt & 014) == 014;
u = (pnt & 003) == 002;
d = (pnt & 003) == 003;
goto count;
case VM:
case VCM:
halt = dis->halt;
brm = dis->brm;
count_brm(dis);
/* actually the complement inputs to COUNT BRM
* but it's easier to find them out after the addition. */
c = dis->brm^brm;
getdir(brm, LDB(0, 8, dis->br), c, &r, &l);
getdir(brm, LDB(8, 8, dis->br), c, &u, &d);
count:
count_y(dis, 1<<dis->sz, u, d);
count_x(dis, 1<<dis->sz, r, l);
if(halt){
/* at COUNT X */
if(dis->br & 0400000)
escape(dis);
rfd(dis);
}else{
/* delay at COUNT BRM */
if(dis->mode == VM && dis->brm == 0177)
dis->halt = 1;
if(dis->hef || dis->vef){
escape(dis);
if(dis->mode == VCM)
rfd(dis);
}else if(!dis->rfd && !dis->lp_flag)
dis->intdelay = 1;
}
break;
/* unsupported */
case SM:
case SBM:
break;
}
}
/* figure out add and complement values for COUNT BRM */
static void
initbrm(Dis340 *dis)
{
int m;
int dx, dy, d;
dis->brm_add = 1;
dx = LDB(0, 7, dis->br);
dy = LDB(8, 7, dis->br);
d = dx > dy ? dx : dy;
for(m = 0100; m > 040; m >>= 1)
if(d & m)
break;
else
dis->brm_add *= 2;
dis->brm_comp = dis->brm_add - 1;
}
static void
data_sync(Dis340 *dis)
{
// CLR BR
dis->br = 0;
dis->rfd = 0;
// CLR BRM
dis->brm = 0;
dis->halt = 0;
dis->move = 0;
dis->s = 0; // CLEAR S
dis->hef = 0; // CLR CF
dis->vef = 0; // CLR CF
/* 2.8μs */
// READ TO S
dis->lp_flag |= dis->lp_find && dis->lp_enable;
if(dis->mode == IM) dis->s |= 010;
if(dis->mode == CM) dis->s |= 004;
// LOAD BR
dis->br |= dis->ib>>18 & RT;
//printf("DIS: %06o\n", dis->br);
dis->pnts = dis->br;
dis->chrs = dis->br;
initbrm(dis);
// SHIFT IB
dis->ib = dis->ib<<18 & LT;
dis->ibc--;
dis->intdelay = 1;
}
static void
intdelay(Dis340 *dis)
{
/* 0.5μs intensify delay */
if(dis->move && dis->br&0200000)
intensify(dis);
/* pulse after delay */
idp(dis);
}
#ifdef JUSTTESTING
static void*
disthread(void *arg)
{
Dis340 *dis;
word w;
dis = arg;
initiate(dis);
for(;;){
if(dis->rfd){
w = *listp++;
if(w == ~0)
listp = list;
else{
dis->ib = w << 18;
dis->ibc = 1;
data_sync(dis);
}
}
if(dis->intdelay)
intdelay(dis);
if(dis->cgstate)
cg_count(dis);
}
return nil;
}
#endif
/*
* CRT simulation ported from https://www.masswerk.at/minskytron/
*/
typedef struct Color Color;
struct Color
{
u8 r, g, b, a;
};
static Lock crtlock;
static Color phos1 = { 0x3d, 0xaa, 0xf7, 0xff };
static Color phos1blur = { 0, 0x63, 0xeb, 0xff };
static Color phos2 = { 0x79, 0xcc, 0x3e, 0xff };
static Color phos2aged = { 0x7e, 0xba, 0x1e, 0xff };
#define RGBA(r, g, b, a) ((r)<<24 | (g)<<16 | (b)<<8 | (a))
#define RGB(r, g, b) RGBA(r, g, b, 255);
static u8 pxintensity[8];
static Color phos1ramp[256];
static Color phos2ramp[256];
static u32 bg = 0;
static float pixelSustainPercent = 0.935;
static int pixelSustainMin = 6;
static int pixelSustainMax = 144;
static float pixelSustainSensitivity = 1.715;
static float pixelSustainRangeOffset = 0.45;
static float pixelSustainFactor;
static float pixelSustainFactorMin = 0.8;
static float pixelSustainFactorMax = 1.0;
static int blurLevelsDefault = 4;
static float blurFactorSquare = 0.3;
static float blurFactorLinear = 0.024;
static float blurFactorDiagonal = 0.3;
static int phos2AlphaCorr = 25;
static int phos2MinVal;
static int pixelIntensityMax = 240;
static int pixelIntensityMin = 8;
static int pixelHaloMinIntensity = 28;
static int intensityRange;
static int intensityOffset;
static float sustainFuzzyness = 0.015;
static float sustainFactor;
static int sustainTransferCf;
float frand(void) { return (double)rand()/RAND_MAX; }
static void
crtinit(void)
{
int i, j, ofs;
Color col1, col2;
float c;
int psm;
intensityRange = pixelIntensityMax - pixelIntensityMin;
intensityOffset = pixelIntensityMin+(1.0-pixelSustainRangeOffset)*intensityRange;
sustainTransferCf = intensityOffset * pixelSustainSensitivity;
pixelSustainFactor = pixelSustainFactorMin +
pixelSustainPercent*(pixelSustainFactorMax-pixelSustainFactorMin);
sustainFactor = pixelSustainFactor;
/* Intensities */
for(i = 0; i < 8; i++)
pxintensity[i] = pixelIntensityMin + i/7.0 * intensityRange;
/* Phosphor 1 ramp */
ofs = pxintensity[4]/4;
for(i = 0; i < ofs; i++){
phos1ramp[i] = phos1blur;
phos1ramp[i].a = i < pixelHaloMinIntensity ?
pixelHaloMinIntensity : i;
}
for(j = 0; i < 256; i++, j++){
c = (float)j/(255-ofs);
c *= c;
phos1ramp[i].r = phos1blur.r*(1.0-c) + phos1.r*c;
phos1ramp[i].g = phos1blur.g*(1.0-c) + phos1.g*c;
phos1ramp[i].b = phos1blur.b*(1.0-c) + phos1.b*c;
phos1ramp[i].a = i < pixelHaloMinIntensity ?
pixelHaloMinIntensity : i;
}
/* Phosphor 2 ramp */
col1 = phos2;
col2 = phos2aged;
c = (255-phos2AlphaCorr)/255.0;
col1.r *= c; col1.g *= c; col1.b *= c;
c = (255-phos2AlphaCorr*0.25)/255.0;
col2.r *= c; col2.g *= c; col2.b *= c;
psm = pixelSustainMax + phos2AlphaCorr;
phos2MinVal = 0;
for(i = 0; i < 256; i++){
c = i/255.0;
phos2ramp[i].r = col1.r*c + col2.r*(1.0-c);
phos2ramp[i].g = col1.g*c + col2.g*(1.0-c);
phos2ramp[i].b = col1.b*c + col2.b*(1.0-c);
phos2ramp[i].a = psm*(c + -0.5*(cos(M_PI*c) - 1))/2.0;
if(phos2ramp[i].a < 3)
phos2MinVal = i;
}
}
/* Queue pixel to display */
static void
plotpixel(CRT *crt, int x, int y, int intensity)
{
int i, v;
Pixel *px;
intensity = pxintensity[intensity];
i = 1024*y + x;
v = crt->pxvals[i];
lock(&crtlock);
if(v == 0){
/* Add new pixel */
px = &crt->pxlist[crt->numPixels++];
px->x = x;
px->y = y;
px->l = blurLevelsDefault;
crt->pxvals[i] = intensity;
}else if(intensity > v)
/* Intensify old pixel */
crt->pxvals[i] = intensity;
unlock(&crtlock);
}
/* Intensify phos1 value */
static void
renderpixel(CRT *crt, int x, int y, int a, int level)
{
int p, v, b;
float f;
p = y*1024 + x;
v = crt->phos1vals[p];
if(v >= 255) return;
if(v == 0){
// printf("adding phos1 %d\n", p);
crt->phos1List[crt->numPhos1++] = p;
}
v += a;
crt->phos1vals[p] = v > 255 ? 255 : v;
if(--level){
f = a/255.0;
b = f*f*255*blurFactorSquare + a*blurFactorLinear;
if(b > 0){
if(x < 1023) renderpixel(crt, x+1, y, b, level);
if(y < 1023) renderpixel(crt, x, y+1, b, level);
if(x > 0) renderpixel(crt, x-1, y, b, level);
if(y > 0) renderpixel(crt, x, y-1, b, level);
b *= blurFactorDiagonal;
if(b > 0){
if(y > 0){
if(x < 1023)
renderpixel(crt, x+1, y-1, b, level);
if(x > 0)
renderpixel(crt, x-1, y-1, b, level);
}
if(y < 1023){
if(x < 1023)
renderpixel(crt, x+1, y+1, b, level);
if(x > 0)
renderpixel(crt, x-1, y+1, b, level);
}
}
}
}
}
/* Intensify all phos1 values from queued pixels */
static void
renderpixels(CRT *crt)
{
int i, p;
Pixel *px;
lock(&crtlock);
px = crt->pxlist;
for(i = 0; i < crt->numPixels; i++){
p = 1024*px->y + px->x;
renderpixel(crt, px->x, px->y, crt->pxvals[p], px->l);
crt->pxvals[p] = 0;
px++;
}
crt->numPixels = 0;
unlock(&crtlock);
}
static void
drawtoscreen(CRT *crt, int i, int phos2, int phos1)
{
float c;
int r, g, b, a;
Color p1col = phos1ramp[phos1];
Color p2col = phos2ramp[phos2];
if(phos2 == 0 || phos1 == 255){
/* only Phosphor 1 */
p1col.a = (phos2 == 0 && phos1 < pixelHaloMinIntensity) ?
pixelHaloMinIntensity : phos1;
crt->pixels[i] = RGBA(p1col.r, p1col.g, p1col.b, p1col.a);
}else{
/* both phosphors */
c = p2col.a/255.0 * (1.0 - phos1/255.0);
r = (p1col.r + p2col.r*c + p1col.r + p2col.r)/2.0;
g = (p1col.g + p2col.g*c + p1col.g + p2col.g)/2.0;
b = (p1col.b + p2col.b*c + p1col.b + p2col.b)/2.0;
a = phos1 + p2col.a;
if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
if(a > 255) a = 255;
crt->pixels[i] = RGBA(r, g, b, a);
}
}
static void
render(CRT *crt)
{
int i, p, v, u;
float f;
Color c;
renderpixels(crt);
/* clear faded phos1 pixels */
for(i = 0; i < crt->numClearPixels; i++)
crt->pixels[crt->clearList[i]] = bg;
crt->numClearPixels = 0;
/* process phosphor 2 */
for(i = 0; i < crt->numPhos2; i++){
p = crt->phos2List[i];
c = phos2ramp[crt->phos2vals[p]];
crt->pixels[p] = RGBA(c.r, c.g, c.b, c.a);
}
/* process phosphor 1 */
for(i = 0; i < crt->numPhos1; i++){
p = crt->phos1List[i];
v = crt->phos1vals[p];
if(v >= pixelSustainMin){
/* Phos1 bright enough, leave a Phos2 trace */
if(crt->phos2vals[p] == 0)
crt->phos2List[crt->numPhos2++] = p;
f = v >= intensityOffset ?
1.0 :
1.0 - (float)(intensityOffset-v)/sustainTransferCf;
u = f*255;
if(crt->phos2vals[p] < u)
crt->phos2vals[p] = u;
}else if(crt->phos2vals[p] == 0)
/* Not bright enough,
* clear pixel if phos2 wasn't drawn */
crt->clearList[crt->numClearPixels++] = p;
/* Apply pixel with phos1 and phos2 values */
drawtoscreen(crt, p, crt->phos2vals[p], v);
crt->phos1vals[p] = 0;
}
crt->numPhos1 = 0;
/* fade phosphor 2 */
crt->numTmp = 0;
for(i = 0; i < crt->numPhos2; i++){
p = crt->phos2List[i];
v = crt->phos2vals[p];
v *= sustainFactor*(1.0-(frand()-0.5)*sustainFuzzyness);
if(v >= phos2MinVal){
crt->phos2vals[p] = v;
crt->tmpList[crt->numTmp++] = p;
}else{
crt->phos2vals[p] = 0;
crt->pixels[p] = bg;
}
}
memcpy(crt->phos2List, crt->tmpList, crt->numTmp*sizeof(int));
crt->numPhos2 = crt->numTmp;
}
static void*
renderthread(void *arg)
{
Dis340 *dis;
SDL_Event ev;
SDL_Texture *tex;
threadname("dis340");
dis = arg;
crtinit();
if(SDL_CreateWindowAndRenderer(1024, 1024, 0, &window, &renderer) < 0)
err("SDL_CreateWindowAndRenderer() failed: %s\n", SDL_GetError());
SDL_SetWindowTitle(window, "Type 340 display");
tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_STREAMING, 1024, 1024);
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
lock(&initlock);
awaitinit--;
unlock(&initlock);
for(;;){
#ifdef JUSTTESTING
while(SDL_PollEvent(&ev))
switch(ev.type){
case SDL_KEYDOWN:
if(ev.key.keysym.scancode == SDL_SCANCODE_Q)
exit(0);
else
initiate(dis);
break;
}
#endif
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
SDL_RenderClear(renderer);
render(dis->crt);
SDL_UpdateTexture(tex, nil, dis->crt->pixels, 1024*sizeof(u32));
SDL_RenderCopy(renderer, tex, nil, nil);
SDL_RenderPresent(renderer);
// probably not the best idea to do it like this,
// should perhaps add a time delta to render instead
SDL_Delay(30);
}
return nil;
}
#ifdef JUSTTESTING
void
main340(void)
{
static Dis340 DIS_;
static CRT CRT_;
static Dis340 *dis = &DIS_;
dis->crt = &CRT_;
threadcreate(disthread, dis);
threadcreate(renderthread, dis);
for(;;);
}
#endif
static void
recalc_dis_req(Dis340 *dis)
{
int data, spec;
u8 req_data, req_spec;
// TODO: what about RFD?
data = dis->ibc == 0 && dis->rfd;
spec = dis->lp_flag ||
dis->hef || dis->vef ||
dis->stop && dis->br&01000;
req_data = data ? 0200 >> dis->pia_data : 0;
req_spec = spec ? 0200 >> dis->pia_spec : 0;
setreq2(dis->bus, DIS, req_data | req_spec);
}
static void
discycle(void *p)
{
Dis340 *dis;
dis = p;
if(dis->rfd && dis->ibc > 0)
data_sync(dis);
if(dis->intdelay)
intdelay(dis);
if(dis->cgstate)
cg_count(dis);
recalc_dis_req(dis);
}
static void
wake_dis(void *dev)
{
Dis340 *dis;
IOBus *bus;
dis = dev;
bus = dis->bus;
if(IOB_RESET){
dis->pia_data = 0;
dis->pia_spec = 0;
dis->ib = 0;
dis->ibc = 0;
initiate(dis);
}
if(bus->devcode == DIS){
if(IOB_STATUS){
// HACK: for IO bus multiplexing. this bit means the 340 is on the 6
bus->c12 |= F0;
if(dis->lp_flag) bus->c12 |= F25;
if(dis->hef || dis->vef) bus->c12 |= F26;
if(dis->stop && dis->br&01000) bus->c12 |= F27;
// TODO: what about RFD?
if(dis->ibc == 0 && dis->rfd) bus->c12 |= F28;
bus->c12 |= (dis->pia_spec & 7) << 3;
bus->c12 |= dis->pia_data & 7;
//printf("DIS STATUS %012lo\n", bus->c12);
}
if(IOB_DATAI){
bus->c12 |= dis->x;
bus->c12 |= dis->y << 18;
//printf("DIS DATAI %012lo\n", bus->c12);
}
if(IOB_CONO_CLEAR){
//printf("DIS CONO CLEAR\n");
dis->pia_data = 0;
dis->pia_spec = 0;
}
if(IOB_CONO_SET){
dis->pia_data |= bus->c12 & 7;
dis->pia_spec |= bus->c12>>3 & 7;
if(bus->c12 & F29)
initiate(dis);
//printf("DIS CONO SET %012lo\n", bus->c12);
}
if(IOB_DATAO_CLEAR){
//printf("DIS DATAO CLEAR\n");
dis->ib = 0;
dis->ibc = 0;
}
if(IOB_DATAO_SET){
dis->ib |= bus->c12;
dis->ibc = 2;
//printf("DIS DATAO SET %012lo\n", bus->c12);
}
}
recalc_dis_req(dis);
}
static void
disioconnect(Device *dev, IOBus *bus)
{
Dis340 *dis;
dis = (Dis340*)dev;
dis->bus = bus;
bus->dev[DIS] = (Busdev){ dis, wake_dis, 0 };
}
static Device disproto = {
nil, nil, "",
nil, nil,
disioconnect,
nil, nil
};
Device*
makedis(int argc, char *argv[])
{
Dis340 *dis;
Task t;
dis = malloc(sizeof(Dis340));
memset(dis, 0, sizeof(Dis340));
dis->crt = malloc(sizeof(CRT));
memset(dis->crt, 0, sizeof(CRT));
dis->dev = disproto;
dis->dev.type = dis_ident;
/* dunno about the frequency here */
// t = (Task){ nil, discycle, dis, 50, 0 };
// t = (Task){ nil, discycle, dis, 20, 0 };
// MACDMP starts breaking if we go too high
// other programs start breaking if we go too low
// TODO: gahhhhhhh
// for now i increased the delay in MACDMP slightly
t = (Task){ nil, discycle, dis, 20, 0 };
addtask(t);
lock(&initlock);
awaitinit++;
unlock(&initlock);
/* There's a race somewhere here */
threadcreate(renderthread, dis);
return &dis->dev;
}