⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bldrv.c

📁 用来将电脑连接到电视荧幕, 并以15Khz输出的源码, 请只用在支援15Khz的荧幕上, 以免伤害荧幕
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "define.h"
#include "mode15k.h"
#include "drv15k.h"



#define Blade3D    0x9880
#define BladeXP    0x9910

static int DetectBlade3D(void);



/* 3C4 */
#define OldNewModeControl 0x0B

#define NewMode2 0x0D
#define NewMode1 0x0E
#define Protection 0x11
#define MCLKLow 0x16
#define MCLKHigh 0x17
#define ClockLow 0x18
#define ClockHigh 0x19

/* 3x4 */

#define InterlacedVsyncAdjust 0x19
#define HorizontalParamOverflow 0x2B

#define Offset 0x13
#define CRTCModuleTest 0x1E
#define CRTHiOrd 0x27
#define AddColReg 0x29


/* 3CE */

#define MiscInternalControlReg 0x2F



static DWORD REFFREQ  =  14318180;
static DWORD VCO_MAX  = 230000000;
static DWORD VCO_MIN  = 14318180 * 3.5;
static DWORD VCLK_MAX = 230000000;



static int DetectBlade3D(void);
static int DetectBladeXP(void);

static void NewMode(void);
static void UnprotectRegisters(void);

static double GetCurrentDotClock(void);
static double GetCurrentMClock(void);
static double GetPixelClockDivider(void);
static void SetPixelClockDivider(int d0);

static DWORD GetHTotal(void);
static DWORD GetVTotal(void);


static void SetHSyncSkewInMisc(int flag);
static void SetBladeExtRegister(CRTCPARAM *cp);
static WORD GetBladeBytesPerLine(void);
static void SetBladeBytesPerLine(WORD d0);
static void SetBladeInterlace(int flag, CRTCPARAM* cp);

static void SetBladeVClock(int Num, int DeN, int PS, int PCDiv);
static long GetBladeVclkParam(long vclk, int *Num, int *DeN, int *PS, int *PCDiv);

static void SetDoubleScan(int flag);

DWORD GetBladeScreenStartAddress(void);
void SetBladeScreenStartAddress(DWORD d0);
static int GetDoubleLogicalLineWidth(void);
static void SetDoubleLogicalLineWidth(int flag);






int  GetInterlaceStatus(void);
void SetInterlaceStatus(int d0);

static void SetDoubleScan(int flag);

static WORD DeviceType = 0;
static int InterlaceStatus = 0;

unsigned int findblade(void);

int DetectBlade(void)
{
	int result = 0;

	DeviceType = (WORD)findblade() & 0xFFFF;
	switch(DeviceType){
		case Blade3D:
			if(DetectBlade3D() != 0){
				REFFREQ =  14318180;
				VCO_MAX = 230000000;
				VCO_MIN = (DWORD)(REFFREQ * 3.5);		// It seems that Blade3D still has this limitation
				VCLK_MAX = 230000000;
				result = 1;
			}
			break;
		case BladeXP:
			if(DetectBladeXP() != 0){
				REFFREQ =  14318180;
				VCO_MAX = 270000000;
				VCO_MIN = (DWORD)(REFFREQ * 3.5);
				VCLK_MAX = 270000000;
				result = 1;
			}
			break;
	}
	return result;
}


int SetBlade(int xres, int yres, int center_x, int center_y, int hsyncdelay, int hdispdelay)
{
	CRTCPARAM cp;
	int Num;
	int DeN;
	int PS;
	int PCDiv;


	GetMode15KHz(&cp, xres, yres);
	AdjustCenter(&cp, center_x, center_y);

	NewMode();
	UnprotectRegisters();

	cp.dotclockHz = GetBladeVclkParam(cp.dotclockHz, &Num, &DeN, &PS, &PCDiv);
	cp.vert001Hz  = CalcVert001Hz(cp.dotclockHz, cp.HTotal,
								  cp.VTotal, cp.interlace);
	cp.horzHz	  = CalcHorizontalHz(cp.dotclockHz, cp.HTotal);

	cp.HBStart = cp.HDisp;
	cp.HBEnd   = cp.HSEnd;
	cp.VBStart = cp.VDisp;
	cp.VBEnd   = cp.VSEnd;

	DisableGenerateSignal();
	SetInterlaceStatus(0);
	SetGenericVGARegister(&cp, hsyncdelay, hdispdelay);
	SetBladeExtRegister(&cp);
	SetHSyncSkewInMisc(0);
	SetBladeVClock(Num, DeN, PS, PCDiv);
	EnableGenerateSignal();

	return 1;
}

void SetBladeExtRegister(CRTCPARAM *cp)
{
	BYTE d0;
	int d1;
	int interlaceoffset;

	d1 = (cp->HSStart/8) + (cp->HSEnd/8) - ((cp->HTotal/8) - 5);
	if(d1 < 0) d1 = 0;
//	  d1 = (d1 * cp->interlaceratio) / 100;
	d1 = d1 / 2;
	interlaceoffset = d1;
	SetCrtcReg(InterlacedVsyncAdjust, (BYTE)(interlaceoffset & 0xFF));

	d0 = GetCrtcReg(HorizontalParamOverflow);
	d0 = BitMov(d0, 0, (cp->HTotal	>> 3) - 5, 9);
	d0 = BitMov(d0, 1, (cp->HDisp	>> 3) - 1, 9);
	d0 = BitMov(d0, 2, interlaceoffset		 , 9);
	d0 = BitMov(d0, 3, (cp->HSStart >> 3)	 , 9);
	d0 = BitMov(d0, 4, (cp->HBStart >> 3)	 , 9);
	SetCrtcReg(HorizontalParamOverflow, d0);

	d0 = GetCrtcReg(CRTHiOrd);
	d0 = BitMov(d0, 3,				1,	0); 	// line compare bit 10
	d0 = BitMov(d0, 4, cp->VDisp  - 1, 10);
	d0 = BitMov(d0, 5, cp->VSStart	 , 10);
	d0 = BitMov(d0, 6, cp->VBStart	 , 10);
	d0 = BitMov(d0, 7, cp->VTotal - 2, 10);
	SetCrtcReg(CRTHiOrd, d0);

	SetDoubleScan(cp->doublescan);
	SetBladeInterlace(cp->interlace, cp);
	SetHVPolarity(cp->hpolarity, cp->vpolarity);
}







void SetInterlaceStatus(int d0)
{
	if(d0 != 0) d0 = 1;
	InterlaceStatus = d0;
}

int GetInterlaceStatus(void)
{
	return InterlaceStatus;
}


DWORD GetBladeScreenStartAddress(void)
{
	DWORD d0;

	d0	= (DWORD)GetCrtcReg(0x0D);
	d0 |= (DWORD)GetCrtcReg(0x0C) << 8;
	d0	= BitMov(d0, 16, GetCrtcReg(CRTCModuleTest), 5);
	d0	= BitMov(d0, 17, GetCrtcReg(CRTHiOrd), 0);
	d0	= BitMov(d0, 18, GetCrtcReg(CRTHiOrd), 1);
	d0	= BitMov(d0, 19, GetCrtcReg(CRTHiOrd), 2);
	d0	= d0 << 2;

	return d0;
}

void SetBladeScreenStartAddress(DWORD d0)
{
	DWORD d1;

	d0 = d0 >> 2;
	SetCrtcReg(0x0D, (BYTE)(d0 & 0xFF));
	SetCrtcReg(0x0C, (BYTE)((d0 >> 8)  & 0xFF));

	d1 = GetCrtcReg(CRTCModuleTest);
	d1 = BitMov(d1, 5, d0, 16);
	SetCrtcReg(CRTCModuleTest, (BYTE)d1);

	d1 = GetCrtcReg(CRTHiOrd);
	d1 = BitMov(d1, 0, d0, 17);
	d1 = BitMov(d1, 1, d0, 18);
	d1 = BitMov(d1, 2, d0, 19);
	SetCrtcReg(CRTHiOrd, (BYTE)d1);
}





WORD GetBladeBytesPerLine(void)
{
	WORD d0;

	d0 = GetCrtcReg(Offset);
	d0 = BitMov(d0, 8, GetCrtcReg(AddColReg), 4);
	d0 = BitMov(d0, 9, GetCrtcReg(AddColReg), 5);
	d0 = d0 << 3;
#if 0
	if(GetInterlaceStatus() != 0){
		d0 = d0 >> 1;
	}
#endif

	return d0;
}

void SetBladeBytesPerLine(WORD d0)
{
	BYTE d1;

#if 0
	if(GetInterlaceStatus() != 0){
		d0 = d0 << 1;
	}
#endif

	d0 = d0 >> 3;
	SetCrtcReg(Offset, (BYTE)(d0 & 0xFF));
	d1 = GetCrtcReg(AddColReg);
	d1 = (BYTE)BitMov(d1, 4, d0, 8);
	d1 = (BYTE)BitMov(d1, 5, d0, 9);
	SetCrtcReg(AddColReg, d1);
}



WORD GetBladeMaxBytesPerLine(void)
{
	return (0x3FF << 3);
}

WORD AdjustBladeBytesPerLine(WORD bpl)
{
	return (bpl + 0x0F) & ~0x0F;
}



static void SetDoubleScan(int flag)
{
	if(flag == 0){
		SetCrtcReg(0x09, BitMov(GetCrtcReg(0x09), 7, 0, 0));
	}else{
		SetCrtcReg(0x09, BitMov(GetCrtcReg(0x09), 7, 1, 0));
	}
}



static void SetBladeInterlace(int flag, CRTCPARAM *cp)
{
	BYTE status;

	status = cp->HTotal;	// dummy

	status = GetCrtcReg(CRTCModuleTest) & 0x04;
	if(flag == 0){
		if(status != 0){
			SetDoubleLogicalLineWidth(0);
			SetCrtcReg(CRTCModuleTest, GetCrtcReg(CRTCModuleTest) & ~0x04);
			SetInterlaceStatus(0);
		}
	}else{
		if(status == 0){
			SetDoubleLogicalLineWidth(1);
			SetCrtcReg(CRTCModuleTest, GetCrtcReg(CRTCModuleTest) | 0x04);
			SetInterlaceStatus(1);
		}
	}
}


static long GetBladeVclkParam(long vclk, int *Num, int *DeN, int *PS, int *PCDiv)
{
	double desfreq;
	double temp;
	double tempdt;
	double dt;
	int n, startn, endn;
	int m, startm, endm;
	int k, startk, endk;
	int pdindex, startpdindex, endpdindex;
	double pd;
	int powerup[4] = { 1, 2, 4, 8 };
	double pdd[4] = {1, 1.5, 2, 4 };
	double pdi[4] = {10, 15, 20, 40 };
	int d0;
	int invalid_n_value[] = {
#if 1
		 0,  1,  2,  3,  4,  5,  6,  7,
		 9, 10, 11, 12, 13, 14, 15,
		18, 19, 20, 21, 22, 23,
		27, 28, 29, 30, 31,
		36, 37, 38, 39,
		45, 46, 47,
		54, 55,
		63,
#endif
		-1
	};


	if(vclk > VCLK_MAX) vclk = VCLK_MAX;


	startn = 8;
	endn   = 247;
	startm = 2;
	endm   = 61;
	startk = 0;
	endk   = 3;
	startpdindex = 0;
	endpdindex	 = 3;

	desfreq = (double)vclk;
	dt = VCLK_MAX;
	*Num = 0;
	*DeN = 0;
	*PS  = 0;
	*PCDiv	= 0;

	for(pdindex = startpdindex; pdindex <= endpdindex; pdindex += 1){
		pd = pdd[pdindex];
		for(k = startk; k <= endk; k += 1){

	  for(n = startn; n <= endn; n += 1){
				d0 = 0;
				while(1){
					if(invalid_n_value[d0] == -1) break;
					if(invalid_n_value[d0] == n) break;
					d0 += 1;
				}
				if(invalid_n_value[d0] != -1) continue;
				for(m = startm; m <= endm; m += 1){
					temp = REFFREQ * ((double)(n + 8) / (double)(m + 2));
					if(VCO_MIN <= temp && temp <= VCO_MAX){
						temp = REFFREQ * ((double)(n + 8) / (double)((m + 2) * powerup[k]));
						temp = temp / pd;
						tempdt = desfreq - temp;
						if(tempdt < 0) tempdt *= -1;
						if(tempdt < dt){
							*Num = n;
							*DeN = m;
							*PS  = k;
							*PCDiv	= pdi[pdindex];
							dt = tempdt;
						}
					}
				}
			}
		}
	}

	n = (*Num + 8);
	m = (*DeN + 2);
	k = powerup[*PS];
	pd = (double)(*PCDiv) / 10;

#if 0
	logerror("Num %3d, DeN %3d, PS %1d, PCDiv %.1lf\n", n, m, k, pd);
	logerror("%.5lf * (Num/DeN) : %lf\n", (double)REFFREQ/1000000,
								(double)REFFREQ/1000000 *(double)n / m);
	logerror("%.5lf * (Num/DeN)/(PS * PCDiv): %lf\n", (double)REFFREQ/1000000,
								(double)REFFREQ/1000000 * (double)n/(m * k * pd));
#endif
	vclk = REFFREQ * (double)n/(m * k * pd);
//	  logerror("vclk : %lf\n", (double)vclk / 1000000.0);

	return vclk;
}



static void UnprotectRegisters(void)
{
	SetSeqReg(Protection, 0x92);
	SetSeqReg(NewMode1, 0xC0 ^ 0x02);
	SetCrtcReg(CRTCModuleTest, GetCrtcReg(CRTCModuleTest) & 0xBF);
}

void SetSeqDivider(int d0)
{
	int d1;

	d0 -= 1;
	if(d0 != 0) d0 = 1 << 3;
	d1 = GetSeqReg(0x01) & ~0x08;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -