diff --git a/ApplewinExpress10.00.vcxproj.filters b/ApplewinExpress10.00.vcxproj.filters
index 29487593..69cbe148 100644
--- a/ApplewinExpress10.00.vcxproj.filters
+++ b/ApplewinExpress10.00.vcxproj.filters
@@ -212,6 +212,9 @@
Source
+
+ Source\Video
+
@@ -451,6 +454,9 @@
Source
+
+ Source\Video
+
diff --git a/source/NTSC.cpp b/source/NTSC.cpp
new file mode 100644
index 00000000..7f0b4e49
--- /dev/null
+++ b/source/NTSC.cpp
@@ -0,0 +1,1185 @@
+/*
+AppleWin : An Apple //e emulator for Windows
+
+Copyright (C) 2010-2011, William S Simms
+Copyright (C) 2014 Michael Pohoreski
+
+AppleWin is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+AppleWin is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with AppleWin; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// Includes
+ #include "StdAfx.h"
+ #include "AppleWin.h"
+ #include "CPU.h"
+ #include "Frame.h" // FRAMEBUFFER_W FRAMEBUFFER_H
+ #include "Memory.h" // MemGetMainPtr() MemGetBankPtr()
+ #include "Video.h" // g_pFramebufferbits
+
+ #include "NTSC.h"
+ #include "NTSC_CharSet.cpp"
+
+ //LPBYTE MemGetMainPtr(const WORD);
+ //LPBYTE MemGetBankPtr(const UINT nBank);
+
+// Defines
+ #define PI 3.1415926535898f
+ #define RAD_45 PI*0.25f
+ #define RAD_90 PI*0.5f
+ #define RAD_360 PI*2.f
+
+ #define DEG_TO_RAD(x) (PI*(x)/180.f) // 2PI=360, PI=180,PI/2=90,PI/4=45
+
+ #ifndef CHROMA_BLUR
+ #define CHROMA_BLUR 1 // Default: 1; 1 = blur along ~8 pixels; 0 = sharper
+ #endif
+
+ #ifndef CHROMA_FILTER
+ #define CHROMA_FILTER 1 // If no chroma blur; 0 = use chroma as-is, 1 = soft chroma blur, strong color fringes 2 = more blur, muted chroma fringe
+ #endif
+
+ #if CHROMA_BLUR
+ #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees
+ #else // sharpness is higher, less color bleed
+ #if CHROMA_FILTER == 2
+ #define CYCLESTART (PI/4.f) // PI/4 = 45 degrees // c = signal_prefilter(z);
+ #else
+ // #define CYCLESTART DEG_TO_RAD(90) // (PI*0.5) // PI/2 = 90 degrees // HGR: Great, GR: fail on brown
+ #define CYCLESTART DEG_TO_RAD(115.f) // GR perfect match of slow method
+ #endif
+ #endif
+
+ #define HGR_TEST_PATTERN 0
+
+// Globals (Public) ___________________________________________________
+ uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262
+ uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible
+
+// Globals (Private) __________________________________________________
+ static int g_nVideoCharSet = 0;
+ static int g_nVideoMixed = 0;
+ static int g_nHiresPage = 1;
+ static int g_nTextPage = 1;
+
+ // Understanding the Apple II, Timing Generation and the Video Scanner, Pg 3-11
+ // Vertical Scanning
+ // Horizontal Scanning
+ // "There are exactly 17030 (65 x 262) 6502 cycles in every television scan of an American Apple."
+ #define VIDEO_SCANNER_MAX_HORZ 65 // TODO: use Video.cpp: kHClocks
+ #define VIDEO_SCANNER_MAX_VERT 262 // TODO: use Video.cpp: kNTSCScanLines
+
+ #define VIDEO_SCANNER_HORZ_START 25 // first displayable horz scanner index
+ #define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text
+ #define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines
+
+ uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ];
+ unsigned char * g_NTSC_Lines[384]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384
+
+ static unsigned g_nTextFlashCounter = 0;
+ static unsigned g_nTextFlashMask = 0;
+
+ static unsigned g_aPixelMaskGR[16];
+ static uint16_t g_aPixelDoubleMaskHGR[128]; // hgrbits -> g_aPixelDoubleMaskHGR: 7-bit mono 280 pixels to 560 pixel doubling
+
+#define UpdateVideoAddressTXT() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] + g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400))
+#define UpdateVideoAddressHGR() g_aHorzClockMemAddress[ g_nVideoClockHorz ] = ad = (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)) // BUG? g_pHorzClockOffset
+
+ static unsigned char *vbp0;
+ static int g_nLastColumnPixelNTSC;
+ static int g_nColorBurstPixels;
+
+ #define INITIAL_COLOR_PHASE 0
+ static int g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
+ static int g_nSignalBitsNTSC = 0;
+
+ #define NTSC_NUM_PHASES 4
+ #define NTSC_NUM_SEQUENCES 4096
+ enum ColorChannel
+ { // Win32 DIB: BGRA format
+ _B = 0,
+ _G = 1,
+ _R = 2,
+ _A = 3,
+ NUM_COLOR_CHANNELS = 4
+ };
+
+ static unsigned char g_aNTSCMonoMonitor [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS];
+ static unsigned char g_aNTSCColorMonitor [NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS];
+ static unsigned char g_aNTSCMonoTelevision [NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS];
+ static unsigned char g_aNTSCColorTelevision[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES][NUM_COLOR_CHANNELS];
+
+ #define NUM_SIGZEROS 2
+ #define NUM_SIGPOLES 2
+ #define SIGGAIN 7.614490548f
+
+ #define NUM_LUMZEROS 2
+ #define NUM_LUMPOLES 2
+ //#define LUMGAIN 1.062635655e+01
+ //#define LUMCOEF1 -0.3412038399
+ //#define LUMCOEF2 0.9647813115
+ #define LUMGAIN 13.71331570f
+ #define LUMCOEF1 -0.3961075449f
+ #define LUMCOEF2 1.1044202472f
+
+ #define NUM_CHRZEROS 2
+ #define NUM_CHRPOLES 2
+ #define CHRGAIN 7.438011255f
+
+// Tables
+ static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] =
+ {
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80
+ };
+
+ static unsigned g_aClockVertOffsetsTXT[33] =
+ {
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x380
+ };
+
+ static unsigned APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
+ {
+ {0x1068,0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x1078,0x1079,0x107A,0x107B,0x107C,0x107D,0x107E,0x107F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027},
+
+ {0x1010,0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017,
+ 0x1018,0x1019,0x101A,0x101B,0x101C,0x101D,0x101E,0x101F,
+ 0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027,
+ 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F},
+
+ {0x1038,0x1038,0x1039,0x103A,0x103B,0x103C,0x103D,0x103E,0x103F,
+ 0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047,
+ 0x1048,0x1049,0x104A,0x104B,0x104C,0x104D,0x104E,0x104F,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077},
+
+ {0x1060,0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+ 0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F},
+
+ {0x1060,0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+ 0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}
+ };
+
+ static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
+ {
+ {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x106F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027},
+
+ {0x0010,0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+ 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F},
+
+ {0x0038,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077},
+
+ {0x0060,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F},
+
+ {0x0060,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}
+ };
+
+ static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0;
+
+ static void (* g_pNTSC_FuncVideoText )(long) = NTSC_UpdateVideoText40;
+ void (* g_pNTSC_FuncVideoUpdate)(long) = NTSC_UpdateVideoText40;
+
+// Prototypes
+ // prototype from CPU.h
+ //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles);
+ // prototypes from Memory.h
+ //unsigned char * MemGetAuxPtr (unsigned short);
+ //unsigned char * MemGetMainPtr (unsigned short);
+ void init_chroma_phase_table();
+ void updateColorPhase();
+ void updateVideoHorzEOL();
+
+//===========================================================================
+inline float clampZeroOne( const float & x )
+{
+ if (x < 0.f) return 0.f;
+ if (x > 1.f) return 1.f;
+ /* ...... */ return x;
+}
+
+//===========================================================================
+inline void updateColorPhase()
+{
+ g_nColorPhaseNTSC++;
+ g_nColorPhaseNTSC &= 3;
+}
+
+//===========================================================================
+void NTSC_VideoInitAppleType ()
+{
+ int model = g_Apple2Type;
+
+ // anything other than low bit set means not II/II+
+ if (model & 0xFFFE)
+ g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET;
+ else
+ g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET;
+}
+
+static void init_video_tables (void)
+{
+ /*
+ Convert 7-bit monochrome luminance to 14-bit double pixel luminance
+ Chroma will be applied later based on the color phase in ntscColorDoublePixel( luminanceBit )
+ 0x001 -> 0x0003
+ 0x002 -> 0x000C
+ 0x004 -> 0x0030
+ 0x008 -> 0x00C0
+ 0x100 -> 0x4000
+ */
+ for (uint8_t byte = 0; byte < 0x80; byte++ ) // Optimization: hgrbits second 128 entries are mirror of first 128
+ for (uint8_t bits = 0; bits < 7; bits++ ) // high bit = half pixel shift; pre-optimization: bits < 8
+ if (byte & (1 << bits)) // pow2 mask
+ g_aPixelDoubleMaskHGR[byte] |= 3 << (bits*2);
+
+ for ( uint16_t color = 0; color < 16; color++ )
+ g_aPixelMaskGR[ color ] = (color << 12) | (color << 8) | (color << 4) | (color << 0);
+}
+
+// sadly float64 precision is needed
+#define real double
+
+static real signal_prefilter (real z)
+{
+ static real xv[NUM_SIGZEROS + 1] = { 0,0,0 };
+ static real yv[NUM_SIGPOLES + 1] = { 0,0,0 };
+
+ xv[0] = xv[1];
+ xv[1] = xv[2];
+ xv[2] = z / SIGGAIN;
+ yv[0] = yv[1];
+ yv[1] = yv[2];
+ yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (-0.2718798058f * yv[0]) + (0.7465656072f * yv[1]);
+
+ return yv[2];
+}
+
+static real luma0_filter (real z)
+{
+ static real xv[NUM_LUMZEROS + 1];
+ static real yv[NUM_LUMPOLES + 1];
+
+ xv[0] = xv[1];
+ xv[1] = xv[2];
+ xv[2] = z / LUMGAIN;
+ yv[0] = yv[1];
+ yv[1] = yv[2];
+ yv[2] = xv[0] + xv[2] + (2.f * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]);
+
+ return yv[2];
+}
+
+static real luma1_filter (real z)
+{
+ static real xv[NUM_LUMZEROS + 1];
+ static real yv[NUM_LUMPOLES + 1];
+
+ xv[0] = xv[1];
+ xv[1] = xv[2];
+ xv[2] = z / LUMGAIN;
+ yv[0] = yv[1];
+ yv[1] = yv[2];
+ yv[2] = xv[0] + xv[2] + (2 * xv[1]) + (LUMCOEF1 * yv[0]) + (LUMCOEF2 * yv[1]);
+
+ return yv[2];
+}
+
+static real chroma_filter (real z)
+{
+ static real xv[NUM_CHRZEROS + 1];
+ static real yv[NUM_CHRPOLES + 1];
+
+ xv[0] = xv[1];
+ xv[1] = xv[2];
+ xv[2] = z / CHRGAIN;
+ yv[0] = yv[1];
+ yv[1] = yv[2];
+ yv[2] = xv[2] - xv[0] + (-0.7318893645f * yv[0]) + (1.2336442711f * yv[1]);
+
+ return yv[2];
+}
+
+// Build the 4 phase chroma lookup table
+// The YI'Q' colors are hard-coded
+//===========================================================================
+static void init_chroma_phase_table (void)
+{
+ int phase,s,t,n;
+ real z,y0,y1,c,i,q;
+ real phi,zz;
+ float brightness;
+ double r64,g64,b64;
+ float r32,g32,b32;
+
+ for (phase = 0; phase < 4; ++phase)
+ {
+ phi = (phase * RAD_90) + CYCLESTART;
+ for (s = 0; s < NTSC_NUM_SEQUENCES; ++s)
+ {
+ t = s;
+ y0 = y1 = c = i = q = 0.0;
+
+ for (n = 0; n < 12; ++n)
+ {
+ z = (real)(0 != (t & 0x800));
+ t = t << 1;
+
+ for(int k = 0; k < 2; k++ )
+ {
+#if CHROMA_BLUR
+ //z = z * 1.25;
+ zz = signal_prefilter(z);
+ c = chroma_filter(zz); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees
+ y0 = luma0_filter(zz);
+ y1 = luma1_filter(zz - c);
+#else // CHROMA_BLUR
+ y0 = y0 + (z - y0) / 4.0;
+ y1 = y0; // fix TV mode
+
+ #if CHROMA_FILTER == 0
+ c = z; // sharper; "Mostly" correct _if_ CYCLESTART = 115 degrees
+ #endif // CHROMA_FILTER
+ #if CHROMA_FILTER == 1 // soft chroma blur, strong color fringes
+ // NOTE: This has incorrect colors! Chroma is (115-45)=70 degrees out of phase! violet <-> orange, green <-> blue
+ c = (z - y0); // Original -- smoother, white is solid, brighter; other colors
+ // ->
+ // c = (z - (y0 + (z-y0)/4))
+ // c = z - y0 - (z-y0)/4
+ // c = z - y0 - z/4 + y0/4
+ // c = z-z/4 - y0+y0/4; // Which is clearly wrong, unless CYCLESTART DEG_TO_RAD(115)
+ // This mode looks the most accurate for white, has better color fringes
+ #endif
+ #if CHROMA_FILTER == 2 // more blur, muted chroma fringe
+ // White has too much ringing, and the color fringes are muted
+ c = signal_prefilter(z); // "Mostly" correct _if_ CYCLESTART = PI/4 = 45 degrees
+ #endif
+#endif // CHROMA_BLUR
+ c = c * 2.f;
+ i = i + (c * cos(phi) - i) / 8.f;
+ q = q + (c * sin(phi) - q) / 8.f;
+
+ phi += RAD_45; //(PI / 4);
+ if (fabs((RAD_360) - phi) < 0.001)
+ phi = phi - RAD_360; // 2 * PI;
+ } // k
+ } // samples
+
+ brightness = clampZeroOne( (float)z );
+ g_aNTSCMonoMonitor[s][_B] = (uint8_t)(brightness * 255);
+ g_aNTSCMonoMonitor[s][_G] = (uint8_t)(brightness * 255);
+ g_aNTSCMonoMonitor[s][_R] = (uint8_t)(brightness * 255);
+ g_aNTSCMonoMonitor[s][_A] = 255;
+
+ brightness = clampZeroOne( (float)y1);
+ g_aNTSCMonoTelevision[s][_B] = (uint8_t)(brightness * 255);
+ g_aNTSCMonoTelevision[s][_G] = (uint8_t)(brightness * 255);
+ g_aNTSCMonoTelevision[s][_R] = (uint8_t)(brightness * 255);
+ g_aNTSCMonoTelevision[s][_A] = 255;
+
+ /*
+ YI'V' to RGB
+
+ [r g b] = [y i v][ 1 1 1 ]
+ [0.956 -0.272 -1.105]
+ [0.621 -0.647 1.702]
+
+ [r] [1 0.956 0.621][y]
+ [g] = [1 -0.272 -0.647][i]
+ [b] [1 -1.105 1.702][v]
+ */
+ #define I_TO_R 0.956f
+ #define I_TO_G -0.272f
+ #define I_TO_B -1.105f
+
+ #define Q_TO_R 0.621f
+ #define Q_TO_G -0.647f
+ #define Q_TO_B 1.702f
+
+ r64 = y0 + (I_TO_R * i) + (Q_TO_R * q);
+ g64 = y0 + (I_TO_G * i) + (Q_TO_G * q);
+ b64 = y0 + (I_TO_B * i) + (Q_TO_B * q);
+
+ b32 = clampZeroOne( (float)b64);
+ g32 = clampZeroOne( (float)g64);
+ r32 = clampZeroOne( (float)r64);
+
+ g_aNTSCColorMonitor[phase][s][_B] = (uint8_t)(b32 * 255);
+ g_aNTSCColorMonitor[phase][s][_G] = (uint8_t)(g32 * 255);
+ g_aNTSCColorMonitor[phase][s][_R] = (uint8_t)(r32 * 255);
+ g_aNTSCColorMonitor[phase][s][_A] = 255;
+
+ r64 = y1 + (I_TO_R * i) + (Q_TO_R * q);
+ g64 = y1 + (I_TO_G * i) + (Q_TO_G * q);
+ b64 = y1 + (I_TO_B * i) + (Q_TO_B * q);
+
+ b32 = clampZeroOne( (float)b64 );
+ g32 = clampZeroOne( (float)g64 );
+ r32 = clampZeroOne( (float)r64 );
+
+ g_aNTSCColorTelevision[phase][s][_B] = (uint8_t)(b32 * 255);
+ g_aNTSCColorTelevision[phase][s][_G] = (uint8_t)(g32 * 255);
+ g_aNTSCColorTelevision[phase][s][_R] = (uint8_t)(r32 * 255);
+ g_aNTSCColorTelevision[phase][s][_A] = 255;
+ }
+ }
+}
+
+//===========================================================================
+void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
+{
+ make_csbits();
+ init_video_tables();
+ init_chroma_phase_table();
+
+ for (int y = 0; y < 384; y++)
+ g_NTSC_Lines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80;
+
+ vbp0 = g_NTSC_Lines[0]; // wsLines
+
+#if HGR_TEST_PATTERN
+// Michael -- Init HGR to almost all-possible-combinations
+// CALL-151
+// C050 C053 C057
+ unsigned char b = 0;
+ unsigned char *main, *aux;
+
+ for( unsigned page = 0; page < 2; page++ )
+ {
+ for( unsigned w = 0; w < 2; w++ ) // 16 cols
+ {
+ for( unsigned z = 0; z < 2; z++ ) // 8 cols
+ {
+ b = 0; // 4 columns * 64 rows
+ for( unsigned x = 0; x < 4; x++ ) // 4 cols
+ {
+ for( unsigned y = 0; y < 64; y++ ) // 1 col
+ {
+ unsigned y2 = y*2;
+ ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w;
+ ad += 0x2000*page;
+ main = MemGetMainPtr(ad);
+ aux = MemGetAuxPtr (ad);
+ main[0] = b; main[1] = w + page*0x80;
+ aux [0] = z; aux [1] = 0;
+
+ y2 = y*2 + 1;
+ ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z + 20*w;
+ ad += 0x2000*page;
+ main = MemGetMainPtr(ad);
+ aux = MemGetAuxPtr (ad);
+ main[0] = 0; main[1] = w + page*0x80;
+ aux [0] = b; aux [1] = 0;
+
+ b++;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+}
+
+#define SINGLEPIXEL(signal,table) \
+ do { \
+ unsigned int *cp, *mp; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \
+ *((unsigned int *)vbp0) = *cp; \
+ mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \
+ *mp = ((*cp & 0x00fcfcfc) >> 2) + 0xff000000; \
+ vbp0 += 4; \
+ } while(0)
+
+#define SINGLETVPIXEL(signal,table) \
+ do { \
+ unsigned int ntscp, prevp, betwp; \
+ unsigned int *prevlin, *between; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \
+ between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \
+ ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \
+ prevp = *prevlin; \
+ betwp = ntscp - ((ntscp & 0x00fcfcfc) >> 2); \
+ *between = betwp | 0xff000000; \
+ *((unsigned int *)vbp0) = ntscp; \
+ vbp0 += 4; \
+ } while(0)
+
+#define DOUBLEPIXEL(signal,table) \
+ do { \
+ unsigned int *cp, *mp; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ cp = (unsigned int *)(&(table[g_nSignalBitsNTSC][0])); \
+ mp = (unsigned int *)(vbp0 - 4 * FRAMEBUFFER_W); \
+ *((unsigned int *)vbp0) = *mp = *cp; \
+ vbp0 += 4; \
+ } while(0)
+
+#define DOUBLETVPIXEL(signal,table) \
+ do { \
+ unsigned int ntscp, prevp, betwp; \
+ unsigned int *prevlin, *between; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ prevlin = (unsigned int *)(vbp0 + 8 * FRAMEBUFFER_W); \
+ between = (unsigned int *)(vbp0 + 4 * FRAMEBUFFER_W); \
+ ntscp = *(unsigned int *)(&(table[g_nSignalBitsNTSC][0])); /* raw current NTSC color */ \
+ prevp = *prevlin; \
+ betwp = ((ntscp & 0x00fefefe) >> 1) + ((prevp & 0x00fefefe) >> 1); \
+ *between = betwp | 0xff000000; \
+ *((unsigned int *)vbp0) = ntscp; \
+ vbp0 += 4; \
+ } while(0)
+
+static void ntscMonoSinglePixel (int compositeSignal)
+{
+ SINGLEPIXEL(compositeSignal, g_aNTSCMonoMonitor);
+}
+
+static void ntscMonoDoublePixel (int compositeSignal)
+{
+ DOUBLEPIXEL(compositeSignal, g_aNTSCMonoMonitor);
+}
+
+static void ntscColorSinglePixel (int compositeSignal)
+{
+ SINGLEPIXEL(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+static void ntscColorDoublePixel (int compositeSignal)
+{
+ DOUBLEPIXEL(compositeSignal, g_aNTSCColorMonitor[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+
+static void ntscMonoTVSinglePixel (int compositeSignal)
+{
+ SINGLETVPIXEL(compositeSignal, g_aNTSCMonoTelevision);
+}
+
+static void ntscMonoTVDoublePixel (int compositeSignal)
+{
+ DOUBLETVPIXEL(compositeSignal, g_aNTSCMonoTelevision);
+}
+
+static void ntscColorTVSinglePixel (int compositeSignal)
+{
+ SINGLETVPIXEL(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+static void ntscColorTVDoublePixel (int compositeSignal)
+{
+ DOUBLETVPIXEL(compositeSignal, g_aNTSCColorTelevision[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+static void (*ntscMonoPixel)(int) = ntscMonoSinglePixel;
+static void (*ntscColorPixel)(int) = ntscColorSinglePixel;
+
+//===========================================================================
+void NTSC_SetVideoStyle() // (int v, int s)
+{
+ int v = g_eVideoType;
+ int s = g_uHalfScanLines;
+
+ switch (v)
+ {
+ case VT_COLOR_TVEMU: // VT_COLOR_TV: // 0:
+ if (s) {
+ ntscMonoPixel = ntscMonoTVSinglePixel;
+ ntscColorPixel = ntscColorTVSinglePixel;
+ }
+ else {
+ ntscMonoPixel = ntscMonoTVDoublePixel;
+ ntscColorPixel = ntscColorTVDoublePixel;
+ }
+ break;
+
+ case VT_COLOR_STANDARD: // VT_COLOR_MONITOR: //1:
+ default:
+ if (s) {
+ ntscMonoPixel = ntscMonoSinglePixel;
+ ntscColorPixel = ntscColorSinglePixel;
+ }
+ else {
+ ntscMonoPixel = ntscMonoDoublePixel;
+ ntscColorPixel = ntscColorDoublePixel;
+ }
+ break;
+
+ case VT_COLOR_TEXT_OPTIMIZED: // VT_MONO_TV: //2:
+ if (s) {
+ ntscMonoPixel = ntscColorPixel = ntscMonoTVSinglePixel;
+ }
+ else {
+ ntscMonoPixel = ntscColorPixel = ntscMonoTVDoublePixel;
+ }
+ break;
+
+ case VT_MONO_WHITE: //VT_MONO_MONITOR: //3:
+ if (s) {
+ ntscMonoPixel = ntscColorPixel = ntscMonoSinglePixel;
+ }
+ else {
+ ntscMonoPixel = ntscColorPixel = ntscMonoDoublePixel;
+ }
+ break;
+ }
+}
+
+int NTSC_VideoIsVbl ()
+{
+ return (g_nVideoClockVert >= VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockVert < VIDEO_SCANNER_MAX_VERT);
+}
+
+unsigned char NTSC_VideoByte (unsigned long cycle)
+{
+ unsigned char * mem;
+ mem = MemGetMainPtr(g_aHorzClockMemAddress[ g_nVideoClockHorz ]);
+ return mem[0];
+}
+
+#define VIDEO_DRAW_BITS() do { \
+ if (g_nColorBurstPixels < 2) \
+ { \
+ /* #1 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ /* #2 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ /* #3 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ /* #4 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ /* #5 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ /* #6 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ /* #7 of 7 */ \
+ ntscMonoPixel(bt & 1); bt >>= 1; \
+ ntscMonoPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1;\
+ } \
+ else \
+ { \
+ /* #1 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ /* #2 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ /* #3 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ /* #4 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ /* #5 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ /* #6 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ /* #7 of 7 */ \
+ ntscColorPixel(bt & 1); bt >>= 1; \
+ ntscColorPixel(bt & 1); g_nLastColumnPixelNTSC = bt & 1; bt >>= 1;\
+ } \
+} while(0)
+
+inline
+void updateVideoHorzEOL()
+{
+ if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
+ {
+ g_nVideoClockHorz = 0;
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ //VIDEO_DRAW_ENDLINE();
+ if (g_nColorBurstPixels < 2)
+ {
+ ntscMonoPixel(g_nLastColumnPixelNTSC);
+ ntscMonoPixel(0);
+ ntscMonoPixel(0);
+ ntscMonoPixel(0);
+ }
+ else
+ {
+ ntscColorPixel(g_nLastColumnPixelNTSC);
+ ntscColorPixel(0);
+ ntscColorPixel(0);
+ ntscColorPixel(0);
+ }
+ }
+
+ if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT)
+ {
+ g_nVideoClockVert = 0;
+ if (++g_nTextFlashCounter == 16)
+ {
+ g_nTextFlashCounter = 0;
+ g_nTextFlashMask ^= 0xffff;
+ }
+ }
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ vbp0 = g_NTSC_Lines[2*g_nVideoClockVert];
+ g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
+ g_nLastColumnPixelNTSC = 0;
+ g_nSignalBitsNTSC = 0;
+ }
+ }
+}
+
+// Light-weight Video Clock Update
+//===========================================================================
+void NTSC_VideoUpdateCycles( long cycles )
+{
+ for( ; cycles > 0; cycles-- )
+ {
+ if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
+ {
+ g_nVideoClockHorz = 0;
+ if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT)
+ {
+ g_nVideoClockVert = 0;
+ if (++g_nTextFlashCounter == 16)
+ {
+ g_nTextFlashCounter = 0;
+ g_nTextFlashMask ^= 0xffff;
+ }
+
+ // Force full refresh
+ g_pNTSC_FuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES );
+ }
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ vbp0 = g_NTSC_Lines[2*g_nVideoClockVert];
+ g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
+ g_nLastColumnPixelNTSC = 0;
+ g_nSignalBitsNTSC = 0;
+ }
+ }
+ }
+}
+
+
+//===========================================================================
+void NTSC_UpdateVideoText40 (long ticks)
+{
+ unsigned ad, bt;
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressTXT();
+
+ if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12)
+ {
+ if (g_nColorBurstPixels > 0)
+ g_nColorBurstPixels -= 1;
+ }
+ else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * main = MemGetMainPtr(ad);
+
+ bt = g_aPixelDoubleMaskHGR[(csbits[g_nVideoCharSet][main[0]][g_nVideoClockVert & 7]) & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128
+ if (0 == g_nVideoCharSet && 0x40 == (main[0] & 0xC0))
+ bt ^= g_nTextFlashMask;
+ VIDEO_DRAW_BITS();
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_UpdateVideoText80 (long ticks)
+{
+ unsigned int ad, bt, mbt, abt;
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressTXT();
+
+ if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12)
+ {
+ if (g_nColorBurstPixels > 0)
+ g_nColorBurstPixels -= 1;
+ }
+ else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * aux = MemGetAuxPtr(ad);
+ unsigned char * main = MemGetMainPtr(ad);
+
+ mbt = csbits[g_nVideoCharSet][main[0]][g_nVideoClockVert & 7];
+ if (0 == g_nVideoCharSet && 0x40 == (main[0] & 0xC0)) mbt ^= g_nTextFlashMask;
+
+ abt = csbits[g_nVideoCharSet][aux[0]][g_nVideoClockVert & 7];
+ if (0 == g_nVideoCharSet && 0x40 == (aux[0] & 0xC0)) abt ^= g_nTextFlashMask;
+
+ bt = (mbt << 7) | abt;
+ VIDEO_DRAW_BITS();
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_UpdateVideoDblLores40 (long ticks) // wsUpdateVideo7MLores
+{
+ unsigned ad, bt;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pNTSC_FuncVideoText(ticks);
+ return;
+ }
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressTXT();
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if (g_nVideoClockHorz < 16 && g_nVideoClockHorz >= 12)
+ {
+ g_nColorBurstPixels = 1024;
+ }
+ else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * main = MemGetMainPtr(ad);
+ bt = g_aPixelDoubleMaskHGR[(0xFF & g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits
+ VIDEO_DRAW_BITS();
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_UpdateVideoLores40 (long ticks)
+{
+ unsigned ad, bt;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pNTSC_FuncVideoText(ticks);
+ return;
+ }
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressTXT();
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12))
+ {
+ g_nColorBurstPixels = 1024;
+ }
+ else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * main = MemGetMainPtr(ad);
+ bt = g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> ((1 - (g_nVideoClockHorz & 1)) * 2);
+ VIDEO_DRAW_BITS();
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_UpdateVideoDblLores80 (long ticks) // wsUpdateVideoDblLores
+{
+ unsigned ad, bt, abt, mbt;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pNTSC_FuncVideoText(ticks);
+ return;
+ }
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressTXT();
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12))
+ {
+ g_nColorBurstPixels = 1024;
+ }
+ else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * aux = MemGetAuxPtr(ad);
+ unsigned char * main = MemGetMainPtr(ad);
+
+ abt = g_aPixelMaskGR[(aux [0] >> (g_nVideoClockVert & 4)) & 0xF] >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3);
+ mbt = g_aPixelMaskGR[(main[0] >> (g_nVideoClockVert & 4)) & 0xF] >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3);
+ bt = (mbt << 7) | (abt & 0x7f);
+
+ VIDEO_DRAW_BITS();
+ g_nLastColumnPixelNTSC = bt & 1;
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_UpdateVideoDblHires80 (long ticks) // wsUpdateVideoDblHires
+{
+ unsigned ad, bt;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pNTSC_FuncVideoText(ticks);
+ return;
+ }
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressHGR();
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12))
+ {
+ g_nColorBurstPixels = 1024;
+ }
+ else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * aux = MemGetAuxPtr(ad);
+ unsigned char * main = MemGetMainPtr(ad);
+
+ bt = ((main[0] & 0x7f) << 7) | (aux[0] & 0x7f);
+ bt = (bt << 1) | g_nLastColumnPixelNTSC;
+ VIDEO_DRAW_BITS();
+ g_nLastColumnPixelNTSC = bt & 1;
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+
+//===========================================================================
+void NTSC_UpdateVideoHires40 (long ticks)
+{
+ unsigned ad, bt;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pNTSC_FuncVideoText(ticks);
+ return;
+ }
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressHGR();
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12))
+ {
+ g_nColorBurstPixels = 1024;
+ }
+ else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * main = MemGetMainPtr(ad);
+
+ bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128
+ if (main[0] & 0x80) bt = (bt << 1) | g_nLastColumnPixelNTSC;
+ VIDEO_DRAW_BITS();
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_UpdateVideoDblHires40 (long ticks) // wsUpdateVideoHires0
+{
+ unsigned ad, bt;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pNTSC_FuncVideoText(ticks);
+ return;
+ }
+
+ for (; ticks; --ticks)
+ {
+ UpdateVideoAddressHGR();
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if ((g_nVideoClockHorz < 16) && (g_nVideoClockHorz >= 12))
+ {
+ g_nColorBurstPixels = 1024;
+ }
+ else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ unsigned char * main = MemGetMainPtr(ad);
+ bt = g_aPixelDoubleMaskHGR[main[0] & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128
+ VIDEO_DRAW_BITS();
+ }
+ }
+ updateVideoHorzEOL();
+ }
+}
+
+//===========================================================================
+void NTSC_SetVideoTextMode( int cols )
+{
+ if( cols == 40 )
+ g_pNTSC_FuncVideoText = NTSC_UpdateVideoText40;
+ else
+ g_pNTSC_FuncVideoText = NTSC_UpdateVideoText80;
+}
+
+//===========================================================================
+void NTSC_SetVideoMode( int bVideoModeFlags )
+{
+ g_nVideoMixed = bVideoModeFlags & VF_MIXED;
+ g_nVideoCharSet = g_nAltCharSetOffset;
+
+ g_nTextPage = 1;
+ g_nHiresPage = 1;
+ if (bVideoModeFlags & VF_PAGE2) {
+ if (0 == (bVideoModeFlags & VF_80STORE)) {
+ g_nTextPage = 2;
+ g_nHiresPage = 2;
+ }
+ }
+
+ if (bVideoModeFlags & VF_TEXT) {
+ if (bVideoModeFlags & VF_80COL)
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText80;
+ else
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoText40;
+ }
+ else if (bVideoModeFlags & VF_HIRES) {
+ if (bVideoModeFlags & VF_DHIRES)
+ if (bVideoModeFlags & VF_80COL)
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires80;
+ else
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblHires40;
+ else
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoHires40;
+ }
+ else {
+ if (bVideoModeFlags & VF_DHIRES)
+ if (bVideoModeFlags & VF_80COL)
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores80;
+ else
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoDblLores40;
+ else
+ g_pNTSC_FuncVideoUpdate = NTSC_UpdateVideoLores40;
+ }
+}
diff --git a/source/NTSC.h b/source/NTSC.h
new file mode 100644
index 00000000..d2092891
--- /dev/null
+++ b/source/NTSC.h
@@ -0,0 +1,30 @@
+#define VIDEO_SCANNER_6502_CYCLES 17030
+
+// Globals (Public)
+
+ extern uint16_t g_nVideoClockVert;
+ extern uint16_t g_nVideoClockHorz;
+ extern uint8_t* g_NTSC_pLines[384];
+ extern void (* g_pNTSC_FuncVideoUpdate)(long);
+
+// Prototypes (Public) ________________________________________________
+ extern void NTSC_SetVideoTextMode( int cols );
+ extern void NTSC_SetVideoMode( int flags );
+ extern void NTSC_SetVideoStyle();
+
+ extern void NTSC_UpdateVideoText40 (long cycles);
+ extern void NTSC_UpdateVideoText80 (long cyckes);
+ extern void NTSC_UpdateVideoLores40 (long cycles);
+ extern void NTSC_UpdateVideoDblLores40(long cycles);
+ extern void NTSC_UpdateVideoDblLores80(long cycles);
+ extern void NTSC_UpdateVideoHires40 (long cycles);
+ extern void NTSC_UpdateVideoDblHires40(long cycles);
+ extern void NTSC_UpdateVideoDblHires80(long cycles);
+
+ extern uint8_t NTSC_VideoByte(unsigned long);
+ extern void NTSC_VideoCreateDIBSection();
+ extern void NTSC_VideoInit( uint8_t *pFramebuffer );
+ extern void NTSC_VideoInitAppleType ();
+ extern int NTSC_VideoIsVbl();
+ extern void NTSC_VideoUpdateCycles( long cycles );
+
diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp
new file mode 100644
index 00000000..4648b82a
--- /dev/null
+++ b/source/NTSC_CharSet.cpp
@@ -0,0 +1,215 @@
+/*
+AppleWin : An Apple //e emulator for Windows
+
+Copyright (C) 2010-2011, William S Simms
+
+AppleWin is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+AppleWin is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with AppleWin; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "StdAfx.h"
+#include "NTSC_CharSet.h"
+
+unsigned char csbits[2][256][8];
+
+static const char *csstrs[] = {
+ " ### "," # "," #### "," ### "," #### "," ##### "," ##### "," #### ",
+ " # # "," # # "," # # "," # # "," # # "," # "," # "," # ",
+ " # # # "," # # "," # # "," # "," # # "," # "," # "," # ",
+ " # ### "," # # "," #### "," # "," # # "," #### "," #### "," # ",
+ " # ## "," ##### "," # # "," # "," # # "," # "," # "," # ## ",
+ " # "," # # "," # # "," # # "," # # "," # "," # "," # # ",
+ " #### "," # # "," #### "," ### "," #### "," ##### "," # "," #### ",
+ " "," "," "," "," "," "," "," ",
+ " # # "," ### "," # "," # # "," # "," # # "," # # "," ### ",
+ " # # "," # "," # "," # # "," # "," ## ## "," # # "," # # ",
+ " # # "," # "," # "," # # "," # "," # # # "," ## # "," # # ",
+ " ##### "," # "," # "," ## "," # "," # # # "," # # # "," # # ",
+ " # # "," # "," # "," # # "," # "," # # "," # ## "," # # ",
+ " # # "," # "," # # "," # # "," # "," # # "," # # "," # # ",
+ " # # "," ### "," ### "," # # "," ##### "," # # "," # # "," ### ",
+ " "," "," "," "," "," "," "," ",
+ " #### "," ### "," #### "," ### "," ##### "," # # "," # # "," # # ",
+ " # # "," # # "," # # "," # # "," # "," # # "," # # "," # # ",
+ " # # "," # # "," # # "," # "," # "," # # "," # # "," # # ",
+ " #### "," # # "," #### "," ### "," # "," # # "," # # "," # # # ",
+ " # "," # # # "," # # "," # "," # "," # # "," # # "," # # # ",
+ " # "," # # "," # # "," # # "," # "," # # "," # # "," ## ## ",
+ " # "," ## # "," # # "," ### "," # "," ### "," # "," # # ",
+ " "," "," "," "," "," "," "," ",
+ " # # "," # # "," ##### "," ##### "," "," ##### "," "," ",
+ " # # "," # # "," # "," ## "," # "," ## "," "," ",
+ " # # "," # # "," # "," ## "," # "," ## "," # "," ",
+ " # "," # "," # "," ## "," # "," ## "," # # "," ",
+ " # # "," # "," # "," ## "," # "," ## "," # # "," ",
+ " # # "," # "," # "," ## "," # "," ## "," "," ",
+ " # # "," # "," ##### "," ##### "," "," ##### "," "," ",
+ " "," "," "," "," "," "," "," #######",
+ " "," # "," # # "," # # "," # "," ## "," # "," # ",
+ " "," # "," # # "," # # "," #### "," ## # "," # # "," # ",
+ " "," # "," # # "," ##### "," # # "," # "," # # "," # ",
+ " "," # "," "," # # "," ### "," # "," # "," ",
+ " "," # "," "," ##### "," # # "," # "," # # # "," ",
+ " "," "," "," # # "," #### "," # ## "," # # "," ",
+ " "," # "," "," # # "," # "," ## "," ## # "," ",
+ " "," "," "," "," "," "," "," ",
+ " # "," # "," # "," "," "," "," "," ",
+ " # "," # "," # # # "," # "," "," "," "," # ",
+ " # "," # "," ### "," # "," "," "," "," # ",
+ " # "," # "," # "," ##### "," "," ##### "," "," # ",
+ " # "," # "," ### "," # "," # "," "," "," # ",
+ " # "," # "," # # # "," # "," # "," "," "," # ",
+ " # "," # "," # "," "," # "," "," # "," ",
+ " "," "," "," "," "," "," "," ",
+ " ### "," # "," ### "," ##### "," # "," ##### "," ### "," ##### ",
+ " # # "," ## "," # # "," # "," ## "," # "," # "," # ",
+ " # ## "," # "," # "," # "," # # "," #### "," # "," # ",
+ " # # # "," # "," ## "," ## "," # # "," # "," #### "," # ",
+ " ## # "," # "," # "," # "," ##### "," # "," # # "," # ",
+ " # # "," # "," # "," # # "," # "," # # "," # # "," # ",
+ " ### "," ### "," ##### "," ### "," # "," ### "," ### "," # ",
+ " "," "," "," "," "," "," "," ",
+ " ### "," ### "," "," "," # "," "," # "," ### ",
+ " # # "," # # "," "," "," # "," "," # "," # # ",
+ " # # "," # # "," # "," # "," # "," ##### "," # "," # ",
+ " ### "," #### "," "," "," # "," "," # "," # ",
+ " # # "," # "," # "," # "," # "," ##### "," # "," # ",
+ " # # "," # "," "," # "," # "," "," # "," ",
+ " ### "," ### "," "," # "," # "," "," # "," # ",
+ " "," "," "," "," "," "," "," ",
+ " # "," "," # "," "," # "," "," ## "," ",
+ " # "," "," # "," "," # "," "," # # "," ",
+ " # "," ### "," #### "," #### "," #### "," ### "," # "," #### ",
+ " "," # "," # # "," # "," # # "," # # "," #### "," # # ",
+ " "," #### "," # # "," # "," # # "," ##### "," # "," # # ",
+ " "," # # "," # # "," # "," # # "," # "," # "," #### ",
+ " "," #### "," #### "," #### "," #### "," #### "," # "," # ",
+ " "," "," "," "," "," "," "," ### ",
+ " # "," # "," # "," # "," ## "," "," "," ",
+ " # "," "," "," # "," # "," "," "," ",
+ " #### "," ## "," ## "," # # "," # "," ## ## "," #### "," ### ",
+ " # # "," # "," # "," # # "," # "," # # # "," # # "," # # ",
+ " # # "," # "," # "," ### "," # "," # # # "," # # "," # # ",
+ " # # "," # "," # "," # # "," # "," # # # "," # # "," # # ",
+ " # # "," ### "," # # "," # # "," ### "," # # "," # # "," ### ",
+ " "," "," ## "," "," "," "," "," ",
+ " "," "," "," "," # "," "," "," ",
+ " "," "," "," "," # "," "," "," ",
+ " #### "," #### "," # ### "," #### "," #### "," # # "," # # "," # # ",
+ " # # "," # # "," ## "," # "," # "," # # "," # # "," # # ",
+ " # # "," # # "," # "," ### "," # "," # # "," # # "," # # # ",
+ " #### "," #### "," # "," # "," # # "," # ## "," # # "," # # # ",
+ " # "," # "," # "," #### "," ## "," ## # "," # "," ## ## ",
+ " # "," # "," "," "," "," "," "," ",
+ " "," "," "," ### "," # "," ### "," ## # "," ",
+ " "," "," "," ## "," # "," ## "," # ## "," # # # ",
+ " # # "," # # "," ##### "," ## "," # "," ## "," "," # # ",
+ " # # "," # # "," # "," ## "," # "," ## "," "," # # # ",
+ " # "," # # "," # "," ## "," # "," ## "," "," # # ",
+ " # # "," #### "," # "," ## "," # "," ## "," "," # # # ",
+ " # # "," # "," ##### "," ### "," # "," ### "," "," ",
+ " "," ### "," "," "," # "," "," "," ",
+ " # "," # "," "," #######"," "," #######"," ###"," ",
+ " # "," # "," "," # # "," #"," ###### "," ##"," ## ",
+ " ## ## "," ## ## "," # "," # # "," # "," ##### #"," ######"," ### ",
+ " #######"," # #"," ## "," # "," # # "," ## ##"," # ## "," ",
+ " ###### "," # # "," ### "," # "," # # "," # # ###"," # ####"," ### ",
+ " ###### "," # # "," #### "," # # "," # "," ## ####"," ## "," ## ",
+ " ######"," # # #"," ## ## "," # # # "," # "," ## ####"," ###### "," # ",
+ " ## ## "," ## ## "," # #"," #######"," "," #######"," # "," ###",
+ " # "," "," # "," # "," #######"," #"," ###### "," ## # ",
+ " # "," "," # "," ### "," "," #"," ###### "," ## ",
+ " # "," "," # "," # # # "," "," # #"," ###### "," ### ",
+ " #######"," "," # "," # # #"," "," ## #"," ###### "," ######",
+ " # "," "," # # #"," # "," "," #######"," ###### "," ### ",
+ " # "," "," # # # "," # "," "," ## "," ###### "," ## ",
+ " # "," "," ### "," # "," "," # "," ###### "," # ",
+ " "," # # # "," # "," # "," "," "," ###### "," #### ##",
+ " # ##"," #"," #"," "," # "," # "," # # # "," # # # #",
+ " ## "," # #"," # #"," "," # "," # "," # # # #"," # # # ",
+ " ### "," # "," ### "," "," # "," # "," # # # "," # # # #",
+ " ###### "," #######"," ##### "," #######"," # "," #######"," # # # #"," # # # ",
+ " ### "," ##### "," #######"," "," # "," # "," # # # "," # # # #",
+ " ## "," ### "," # "," "," # "," # "," # # # #"," # # # ",
+ " # "," # #"," # #"," "," # "," # "," # # # "," # # # #",
+ " ## ####"," #"," #"," "," #######"," "," # # # #"," # # # ",
+ " "," "," #"," # "," #######"," # # "," #######"," # ",
+ " ##### "," "," #"," ### "," "," # # "," #"," # ",
+ " # #","####### "," #"," ##### "," "," ### ###"," #"," # ",
+ " # "," #"," #"," #######"," "," "," ## #"," # ",
+ " # "," #"," #"," ##### "," "," ### ###"," ## #"," # ",
+ " # "," #"," #"," ### "," "," # # "," #"," # ",
+ " #######","########"," #"," # "," "," # # "," #"," # ",
+ " "," "," #"," "," #######"," "," #######"," # ",
+};
+
+#define STRINGS_PER_CHAR 8
+#define CHARS_PER_ROW 8
+#define STRINGS_PER_CHAR_ROW (STRINGS_PER_CHAR * CHARS_PER_ROW)
+
+void make_csbits (void) {
+ int i,j;
+ int szstrs = sizeof csstrs / sizeof csstrs[0];
+ int numchars = szstrs / STRINGS_PER_CHAR;
+
+ for (i = 0; i < numchars; ++i) {
+ int si = ((i / STRINGS_PER_CHAR) * STRINGS_PER_CHAR_ROW) + (i % CHARS_PER_ROW);
+ for (j = 0; j < STRINGS_PER_CHAR; ++j)
+ {
+ const char *sp = csstrs[si];
+ unsigned char cb = 0;
+
+ si += CHARS_PER_ROW;
+
+ while (*sp) {
+ if (*sp++ != ' ') cb |= 0x80;
+ cb >>= 1;
+ }
+
+ csbits[0][i][j] = cb;
+ }
+ }
+
+ /* move mousetext */
+ for (i = 96; i < 128; ++i)
+ for (j = 0; j < 8; ++j)
+ csbits[1][i-32][j] = csbits[0][i][j];
+
+ /* move lowercase */
+ for (i = 64; i < 96; ++i)
+ for (j = 0; j < 8; ++j)
+ csbits[1][i+32][j] = csbits[1][i+160][j] =
+ csbits[0][i+160][j] = csbits[0][i][j];
+
+ /* move numbers */
+ for (i = 32; i < 64; ++i)
+ for (j = 0; j < 8; ++j)
+ csbits[1][i][j] = csbits[1][i+128][j] =
+ csbits[0][i+64][j] = csbits[0][i+128][j] = csbits[0][i][j];
+
+ /* move uppercase */
+ for (i = 0; i < 32; ++i)
+ for (j = 0; j < 8; ++j)
+ csbits[1][i][j] = csbits[1][i+128][j] = csbits[1][i+192][j] =
+ csbits[0][i+64][j] = csbits[0][i+128][j] = csbits[0][i+192][j] = csbits[0][i][j];
+
+ /* invert (skip mousetext) */
+ for (i = 0; i < 128; ++i)
+ for (j = 0; j < 8; ++j)
+ {
+ csbits[0][i][j] ^= 0xFF;
+ if (i < 64 || i >= 96)
+ csbits[1][i][j] ^= 0xFF;
+ }
+}
diff --git a/source/NTSC_CharSet.h b/source/NTSC_CharSet.h
new file mode 100644
index 00000000..97ec761d
--- /dev/null
+++ b/source/NTSC_CharSet.h
@@ -0,0 +1,27 @@
+/*
+AppleWin : An Apple //e emulator for Windows
+
+Copyright (C) 2010-2011, William S Simms
+
+AppleWin is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+AppleWin is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with AppleWin; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef INCLUDED_CS_H
+#define INCLUDED_CS_H
+
+extern unsigned char csbits[2][256][8];
+void make_csbits (void);
+
+#endif