📄 bldrv.c
字号:
#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 + -