- }
-}
-
-/* This table lists fixes for characters that differ from the standard 6x10
- font. Each encodes a pixel, as (charindex*7 + x) + (y<<10) + (value<<15)
- where value is 0 for white and 1 for black. */
-static unsigned short a2_fixfont[] = {
- /* Fix $ */ 0x8421, 0x941d,
- /* Fix % */ 0x8024, 0x0028, 0x8425, 0x0426, 0x0825, 0x1027, 0x1426, 0x9427,
- 0x1824, 0x9828,
- /* Fix * */ 0x8049, 0x8449, 0x8849, 0x0c47, 0x0c48, 0x0c4a, 0x0c4b, 0x9049,
- 0x9449, 0x9849,
- /* Fix , */ 0x9057, 0x1458, 0x9856, 0x1857, 0x1c56,
- /* Fix . */ 0x1465, 0x1864, 0x1866, 0x1c65,
- /* Fix / */ 0x006e, 0x186a,
- /* Fix 0 */ 0x8874, 0x8c73, 0x9072,
- /* Fix 1 */ 0x0878, 0x1878, 0x187c,
- /* Fix 5 */ 0x8895, 0x0c94, 0x0c95,
- /* Fix 6 */ 0x809f, 0x8c9c, 0x109c,
- /* Fix 7 */ 0x8ca4, 0x0ca5, 0x90a3, 0x10a4,
- /* Fix 9 */ 0x08b3, 0x8cb3, 0x98b0,
- /* Fix : */ 0x04b9, 0x08b8, 0x08ba, 0x0cb9, 0x90b9, 0x14b9, 0x18b8, 0x18b9,
- 0x18ba, 0x1cb9,
- /* Fix ; */ 0x04c0, 0x08bf, 0x08c1, 0x0cc0, 0x90c0, 0x14c1, 0x98bf, 0x18c0,
- 0x1cbf,
- /* Fix < */ 0x80c8, 0x00c9, 0x84c7, 0x04c8, 0x88c6, 0x08c7, 0x8cc5, 0x0cc6,
- 0x90c6, 0x10c7,
- 0x94c7, 0x14c8, 0x98c8, 0x18c9,
- /* Fix > */ 0x80d3, 0x00d4, 0x84d4, 0x04d5, 0x88d5, 0x08d6, 0x8cd6, 0x0cd7,
- 0x90d5, 0x10d6,
- 0x94d4, 0x14d5, 0x98d3, 0x18d4,
- /* Fix @ */ 0x88e3, 0x08e4, 0x8ce4, 0x98e5,
- /* Fix B */ 0x84ef, 0x04f0, 0x88ef, 0x08f0, 0x8cef, 0x90ef, 0x10f0, 0x94ef,
- 0x14f0,
- /* Fix D */ 0x84fd, 0x04fe, 0x88fd, 0x08fe, 0x8cfd, 0x0cfe, 0x90fd, 0x10fe,
- 0x94fd, 0x14fe,
- /* Fix G */ 0x8116, 0x0516, 0x9916,
- /* Fix J */ 0x0129, 0x012a, 0x052a, 0x852b, 0x092a, 0x892b, 0x0d2a, 0x8d2b,
- 0x112a, 0x912b,
- 0x152a, 0x952b, 0x992a,
- /* Fix M */ 0x853d, 0x853f, 0x093d, 0x893e, 0x093f,
- /* Fix Q */ 0x915a, 0x155a, 0x955b, 0x155c, 0x195b, 0x995c, 0x1d5c,
- /* Fix V */ 0x8d7b, 0x0d7c, 0x0d7e, 0x8d7f, 0x917b, 0x117c, 0x117e, 0x917f,
- /* Fix [ */ 0x819e, 0x81a2, 0x859e, 0x899e, 0x8d9e, 0x919e, 0x959e, 0x999e,
- 0x99a2,
- /* Fix \ */ 0x01a5, 0x19a9,
- /* Fix ] */ 0x81ac, 0x81b0, 0x85b0, 0x89b0, 0x8db0, 0x91b0, 0x95b0, 0x99ac,
- 0x99b0,
- /* Fix ^ */ 0x01b5, 0x05b4, 0x05b6, 0x09b3, 0x89b5, 0x09b7, 0x8db4, 0x8db6,
- 0x91b3, 0x91b7,
- /* Fix _ */ 0x9db9, 0x9dbf,
- 0,
-};
-
-struct ntsc_dec {
- char pattern[600];
- int ntscy[600];
- int ntsci[600];
- int ntscq[600];
- int multi[600];
- int multq[600];
- int brightness_control;
-};
-
-/*
- First generate the I and Q reference signals, which we'll multiply by the
- input signal to accomplish the demodulation. Normally they are shifted 33
- degrees from the colorburst. I think this was convenient for
- inductor-capacitor-vacuum tube implementation.
-
- The tint control, FWIW, just adds a phase shift to the chroma signal, and
- the color control controls the amplitude.
-
- In text modes (colormode==0) the system disabled the color burst, and no
- color was detected by the monitor.
-
- freq_error gives a mismatch between the built-in oscillator and the TV's
- colorbust. Older II Plus machines seemed to occasionally get instability
- problems -- the crystal oscillator was a single transistor if I remember
- correctly -- and the frequency would vary enough that the tint would change
- across the width of the screen. The left side would be in correct tint
- because it had just gotten resynchronized with the color burst.
-*/
-static void
-ntsc_set_demod(struct ntsc_dec *it, double tint_control,
- double color_control, double brightness_control,
- double freq_error,
- int colormode)
-{
- int i;
-
- it->brightness_control=(int)(1024.0*brightness_control);
-
- for (i=0; i<600; i++) {
- double phase=90.0-90.0*i + freq_error*i/600.0 + tint_control;
- it->multi[i]=(int)(-cos(3.1415926/180.0*(phase-303)) * 65536.0 *
- color_control * colormode * 4);
- it->multq[i]=(int)(cos(3.1415926/180.0*(phase-33)) * 65536.0 *
- color_control * colormode * 4);
- }
-}
-
-/* Here we model the analog circuitry of an NTSC television. Basically, it
- splits the signal into 3 signals: Y, I and Q. Y corresponds to luminance,
- and you get it by low-pass filtering the input signal to below 3.57 MHz.
-
- I and Q are the in-phase and quadrature components of the 3.57 MHz
- subcarrier. We get them by multiplying by cos(3.57 MHz*t) and sin(3.57
- MHz*t), and low-pass filtering. Because the eye has less resolution in some
- colors than others, the I component gets low-pass filtered at 1.5 MHz and
- the Q at 0.5 MHz. The I component is approximately orange-blue, and Q is
- roughly purple-green. See http://www.ntsc-tv.com for details.
- */
-static void
-ntsc_to_yiq(struct ntsc_dec *it)
-{
- int i;
- int fyx[10],fyy[10];
- int fix[10],fiy[10];
- int fqx[10],fqy[10];
- int pixghost;
- int iny,ini,inq,pix,blank;
-
- for (i=0; i<10; i++) fyx[i]=fyy[i]=fix[i]=fiy[i]=fqx[i]=fqy[i]=0.0;
- pixghost=0;
- for (i=0; i<600; i++) {
- /* Get the video out signal, and add a teeny bit of ghosting, typical of RF
- monitor cables. This corresponds to a pretty long cable, but looks right
- to me. */
- pix=it->pattern[i]*1024;
- if (i>=20) pixghost += it->pattern[i-20]*15;
- if (i>=30) pixghost -= it->pattern[i-30]*15;
- pix += pixghost;
-
- /* Get Y, I, Q before filtering */
- iny=pix;
- ini=(pix*it->multi[i])>>16;
- inq=(pix*it->multq[i])>>16;
-
- blank = (i>=7 && i<596 ? it->brightness_control : -200);
-
- /* Now filter them. These are infinite impulse response filters calculated
- by the script at http://www-users.cs.york.ac.uk/~fisher/mkfilter. This
- is fixed-point integer DSP, son. No place for wimps. We do it in integer
- because you can count on integer being faster on most CPUs. We care
- about speed because we need to recalculate every time we blink text, and
- when we spew random bytes into screen memory. This is roughly 16.16
- fixed point arithmetic, but we scale some filter values up by a few bits
- to avoid some nasty precision errors. */
-
- /* Filter y at with a 4-pole low-pass Butterworth filter at 3.5 MHz
- with an extra zero at 3.5 MHz, from
- mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l
- Delay about 2 */
-
- fyx[0] = fyx[1]; fyx[1] = fyx[2]; fyx[2] = fyx[3];
- fyx[3] = fyx[4]; fyx[4] = fyx[5]; fyx[5] = fyx[6];
- fyx[6] = (iny * 1897) >> 13;
- fyy[0] = fyy[1]; fyy[1] = fyy[2]; fyy[2] = fyy[3];
- fyy[3] = fyy[4]; fyy[4] = fyy[5]; fyy[5] = fyy[6];
- fyy[6] = (fyx[0]+fyx[6]) + 4*(fyx[1]+fyx[5]) + 7*(fyx[2]+fyx[4]) + 8*fyx[3]
- + ((-151*fyy[2] + 8115*fyy[3] - 38312*fyy[4] + 36586*fyy[5]) >> 16);
- if (i>=2) it->ntscy[i-2] = blank + (fyy[6]>>3);
-
- /* Filter I and Q at 1.5 MHz. 3 pole Butterworth from
- mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0
- Delay about 3.
-
- The NTSC spec says the Q value should be filtered at 0.5 MHz at the
- transmit end, But the Apple's video circuitry doesn't any such thing.
- AFAIK, oldish televisions (before comb filters) simply applied a 1.5 MHz
- filter to both after the demodulator.
- */
-
- fix[0] = fix[1]; fix[1] = fix[2]; fix[2] = fix[3];
- fix[3] = (ini * 1413) >> 14;
- fiy[0] = fiy[1]; fiy[1] = fiy[2]; fiy[2] = fiy[3];
- fiy[3] = (fix[0]+fix[3]) + 3*(fix[1]+fix[2])
- + ((16559*fiy[0] - 72008*fiy[1] + 109682*fiy[2]) >> 16);
- if (i>=3) it->ntsci[i-3] = fiy[3]>>2;
-
- fqx[0] = fqx[1]; fqx[1] = fqx[2]; fqx[2] = fqx[3];
- fqx[3] = (inq * 1413) >> 14;
- fqy[0] = fqy[1]; fqy[1] = fqy[2]; fqy[2] = fqy[3];
- fqy[3] = (fqx[0]+fqx[3]) + 3*(fqx[1]+fqx[2])
- + ((16559*fqy[0] - 72008*fqy[1] + 109682*fqy[2]) >> 16);
- if (i>=3) it->ntscq[i-3] = fqy[3]>>2;
-
- }
- for (; i<610; i++) {
- if (i-2<600) it->ntscy[i-2]=0;
- if (i-3<600) it->ntsci[i-3]=0;
- if (i-9<600) it->ntscq[i-9]=0;
- }
-}
-
-enum {
- A2_CMAP_HISTBITS=5,
- A2_CMAP_LEVELS=2,
- A2_CMAP_OFFSETS=4
-};
-
-#define A2_CMAP_INDEX(COLORMODE, LEVEL, HIST, OFFSET) \
-((((COLORMODE)*A2_CMAP_LEVELS+(LEVEL))<<A2_CMAP_HISTBITS)+(HIST))* \
-A2_CMAP_OFFSETS+(OFFSET)
-
-static void
-apple2(Display *dpy, Window window, int delay)
-{
- int w,h,i,j,x,y,textrow,row,col,stepno,colormode,imgrow;
- char c,*s;
- struct timeval basetime_tv;
- double next_actiontime;
- XWindowAttributes xgwa;
- int visclass;
- int screen_xo,screen_yo;
- XImage *image=NULL;
- XGCValues gcv;
- GC gc=NULL;
- XImage *text_im=NULL;
- unsigned long colors[A2_CMAP_INDEX(1, A2_CMAP_LEVELS-1,
- (1<<A2_CMAP_HISTBITS)-1,
- A2_CMAP_OFFSETS-3)+1];
- int n_colors=0;
- int screen_plan[24];
- struct ntsc_dec *dec=NULL;
- short *raw_rgb=NULL, *rrp;
- struct apple2_state *st=NULL;
- char *typing=NULL,*printing=NULL;
- char printbuf[1024];
- char prompt=']';
- int simulate_user;
- double tint_control,color_control,brightness_control,contrast_control;
- double freq_error=0.0,freq_error_inc=0.0;
- double horiz_desync=5.0;
- int flutter_horiz_desync=0;
- int flutter_tint=0;
- double crtload[192];
- int red_invprec,red_shift,green_invprec,green_shift,blue_invprec,blue_shift;
- int fillptr, fillbyte;
- int use_shm,use_cmap,use_color;
- /* localbyteorder is 1 if MSB first, 0 otherwise */
- unsigned int localbyteorder_loc = MSBFirst<<24;
- int localbyteorder=*(char *)&localbyteorder_loc;
-#ifdef HAVE_XSHM_EXTENSION
- XShmSegmentInfo shm_info;
-#endif
-
-#ifdef HAVE_XSHM_EXTENSION
- use_shm=get_boolean_resource ("useSHM", "Boolean");
-#else
- use_shm=0;
-#endif
-
- /* Model the video controls on a standard television */
- tint_control = get_float_resource("apple2TVTint","Apple2TVTint");
- color_control = get_float_resource("apple2TVColor","Apple2TVColor")/100.0;
- brightness_control = get_float_resource("apple2TVBrightness",
- "Apple2TVBrightness") / 100.0;
- contrast_control = get_float_resource("apple2TVContrast",
- "Apple2TVContrast") / 100.0;
- simulate_user = get_boolean_resource("apple2SimulateUser",
- "Apple2SimulateUser");
-
- XGetWindowAttributes (dpy, window, &xgwa);
- visclass=xgwa.visual->class;
- red_shift=red_invprec=green_shift=green_invprec=blue_shift=blue_invprec=-1;
- if (visclass == TrueColor || xgwa.visual->class == DirectColor) {
- use_cmap=0;
- use_color=!mono_p;
- }
- else if (visclass == PseudoColor || visclass == StaticColor) {
- use_cmap=1;
- use_color=!mono_p;
- }
- else {
- use_cmap=1;
- use_color=0;
- }
-
- /* The Apple II screen was 280x192, sort of. We expand the width to 300
- pixels to allow for overscan. We then pick a size within the window
- that's an integer multiple of 300x192. The small case happens when
- we're displaying in a subwindow. Then it ends up showing the center
- of the screen, which is OK. */
- w=xgwa.width;
- h = (xgwa.height/192)*192;
- if (w<300) w=300;
- if (h==0) h=192;
-
- dec=(struct ntsc_dec *)malloc(sizeof(struct ntsc_dec));
-
- if (use_cmap) {
- int hist,offset,level;
- int colorprec=8;
-
- cmap_again:
- n_colors=0;
- /* Typically allocates 214 distinct colors, but will scale back its
- ambitions pretty far if it can't get them */
- for (colormode=0; colormode<=use_color; colormode++) {
- ntsc_set_demod(dec, tint_control, color_control, brightness_control,
- 0.0, colormode);
- for (level=0; level<2; level++) {
- for (hist=0; hist<(1<<A2_CMAP_HISTBITS); hist++) {
- for (offset=0; offset<4; offset++) {
- int interpy,interpi,interpq,r,g,b;
- int levelmult=level ? 64 : 32;
- int prec=colormode ? colorprec : (colorprec*2+2)/3;
- int precmask=(0xffff<<(16-prec))&0xffff;
- XColor col;
-
- if (A2_CMAP_INDEX(colormode,level,hist,offset) != n_colors) {
- fprintf(stderr, "apple2: internal colormap allocation error\n");
- goto bailout;
- }
-
- for (i=0; i<600; i++) dec->pattern[i]=0;
- for (i=0; i<A2_CMAP_HISTBITS; i++) {
- dec->pattern[64+offset-i]=(hist>>i)&1;
- }
-
- ntsc_to_yiq(dec);
- interpy=dec->ntscy[63+offset];
- interpi=dec->ntsci[63+offset];
- interpq=dec->ntscq[63+offset];
-
- r=(interpy + ((+68128*interpi+40894*interpq)>>16))*levelmult;
- g=(interpy + ((-18087*interpi-41877*interpq)>>16))*levelmult;
- b=(interpy + ((-72417*interpi+113312*interpq)>>16))*levelmult;
- if (r<0) r=0;
- if (r>65535) r=65535;
- if (g<0) g=0;
- if (g>65535) g=65535;
- if (b<0) b=0;
- if (b>65535) b=65535;
-
- col.red=r & precmask;
- col.green=g & precmask;
- col.blue=b & precmask;
- col.pixel=0;
- if (!XAllocColor(dpy, xgwa.colormap, &col)) {
- XFreeColors(dpy, xgwa.colormap, colors, n_colors, 0L);
- n_colors=0;
- colorprec--;
- if (colorprec<3) {
- goto bailout;
- }
- goto cmap_again;
- }
- colors[n_colors++]=col.pixel;
- }
- }
- }