Rev 796 |
Blame |
Compare with Previous |
Last modification |
View Log
| Download
| RSS feed
| ?url?
#include "std.h"
#include "emul.h"
#include "vars.h"
#include "memory.h"
#include "draw.h"
#include "atm.h"
static void atm_memswap()
{
if (!conf.atm.mem_swap) return;
// swap memory address bits A5-A7 and A8-A10
for (unsigned start_page = 0; start_page < conf.ramsize*1024; start_page += 2048) {
unsigned char buffer[2048], *bank = memory + start_page;
for (unsigned addr = 0; addr < 2048; addr++)
buffer[addr] = bank[(addr & 0x1F) + ((addr >> 3) & 0xE0) + ((addr << 3) & 0x700)];
memcpy(bank, buffer, 2048);
}
}
static void AtmApplySideEffectsWhenChangeVideomode(unsigned char val)
{
int NewVideoMode = (val & 7);
int OldVideoMode = (comp.pFF77 & 7);
// Êîíñòàíòû ìîæíî çàäàòü æ¸ñòêî, ïîòîìó ÷òî ìåæäó ìîäåëÿìè ÀÒÌ2 îíè íå ìåíÿþòñÿ.
const int tScanlineWidth = 224;
const int tScreenWidth = 320/2;
const int tEachBorderWidth = (tScanlineWidth - tScreenWidth)/2;
const int iLinesAboveBorder = 56;
int iRayLine = cpu.t / tScanlineWidth;
int iRayOffset = cpu.t % tScanlineWidth;
/*
static int iLastLine = 0;
if ( iLastLine > iRayLine )
{
printf("\nNew Frame Begin\n");
__debugbreak();
}
iLastLine = iRayLine;
printf("%d->%d %d %d\n", OldVideoMode, NewVideoMode, iRayLine, iRayOffset);
*/
if (OldVideoMode == 3 || NewVideoMode == 3)
{
// Ïåðåêëþ÷åíèå èç/â sinclair ðåæèì íå èìååò ïîëåçíûõ ïîáî÷íûõ ýôôåêòîâ
// (ïî ñëîâàì AlCo äàæå ñèíõðà ñáèâàåòñÿ)
for(unsigned y = 0; y < 200; y++)
{
AtmVideoCtrl.Scanlines[y+56].VideoMode = NewVideoMode;
AtmVideoCtrl.Scanlines[y+56].Offset = int(((y & ~7U) << 3) + 0x01C0);
}
return;
}
if (OldVideoMode != 6 && NewVideoMode != 6)
{
// Íàñ èíòåðåñóþò òîëüêî ïåðåêëþ÷åíèÿ ìåæäó òåêñòîâûì ðåæèìîì è ðàñøèðåííûìè ãðàôè÷åñêèìè.
// Òåêñòîâîãî ðåæèìà íåò íè äî, íè ïîñëå ïåðåêëþ÷åíèÿ.
// Ñëåäîâàòåëüíî, íåò è ïîáî÷íûõ ýôôåêòîâ.
// Ðàñïðîñòðàíÿåì íîâûé âèäåîðåæèì íà íåîòðèñîâàííûå ñêàíëèíèè
if (iRayOffset >= tEachBorderWidth)
++iRayLine;
while (iRayLine < 256)
{
AtmVideoCtrl.Scanlines[iRayLine++].VideoMode = NewVideoMode;
}
// printf("%d->%d SKIPPED!\n", OldVideoMode, NewVideoMode);
return;
}
//
// Òåðìèíîëîãèÿ è êîíñòàíòû:
// Ýêðàí ñîäåðæèò 312 ñêàíëèíèé, ïî 224òàêòà (noturbo) â êàæäîé.
//
// "ñòðîêà" - ìëàäøèå 3 áèòà íîìåðà îòðèñîâûâàåìîé âèäåîêîíòðîëëåðîì (ëó÷îì) ñêàíëèíèè
// "àäðåñ" - òåêóùèé àäðåñ â âèäåîïàìÿòè, ñ êîòîðîãî âûáèðàåò áàéòû âèäåîêîíòðîëëåð
// àäðåñ ìåíÿåòñÿ ñ ãðàíóëÿðíîñòüþ +8 èëè +64
// "ýêðàí" - ðàñòðîâàÿ êàðòèíêà. Ñî âñåõ ñòîðîí îêðóæåíà "áîðäþðîì".
// Ðàçìåðû áîðäþðà:
// ñâåðõó è ñíèçó îò ðàñòðà: 56 ñêàíëèíèé
// ñëåâà è ñïðàâà îò ðàñòðà: 32 òàêòà (64ïèêñåëÿ).
//
// +64 ïðîèñõîäèò, êîãäà CROW 1->0, òî åñòü:
// ëèáî â òåêñòìîäå ïðè ïåðåõîäå ñî ñòðîêè 7 íà ñòðîêó 0,
// ëèáî ïðè ïåðåêëþ÷åíèè òåêñòìîä->ãðàôèêà ïðè àäðåñå A5=0,
// ëèáî ïðè ïåðåêëþ÷åíèè ãðàôèêà->òåêñòìîä ïðè àäðåñå A5=1 è ñòðîêå 0..3
//
// +8 ïðîèñõîäèò íà ðàñòðå â êîíöå 64-áëîêà ïèêñåëåé (êàæäûå 32òàêòà) íåçàâèñèìî îò ðåæèìà
// (ÂÀÆÍÎ: +8 íå çàâðàïëåíû âíóòðè A3..A5 à ïðîèçâîäÿò ÷åñòíîå ñëîæåíèå ñ àäðåñîì.)
//
// ñáðîñ A3..A5 (íàêîïëåííûõ +8) ïðîèñõîäèò, êîãäà RCOL 1->0, òî åñòü:
// ëèáî â òåêñòìîäå ïðè ïåðåõîäå ñ ðàñòðà íà áîðäþð,
// ëèáî íà áîðäþðå ïðè ïåðåêëþ÷åíèè ãðàôèêà->òåêñòìîä
//
if (iRayLine >= 256)
{
return;
}
// Ïîëó÷èì îôôñåò òåêóùåé ñêàíëèíèè (ôàêòè÷åñêè âèäåîàäðåñ å¸ íà÷àëà)
int Offset = AtmVideoCtrl.Scanlines[iRayLine].Offset;
// Âû÷èñëèì ðåàëüíûé âèäåîàäðåñ, ñ ó÷¸òîì èíêðåìåíòîâ ïðè îòðèñîâêå ðàñòðà.
// Òàêæå îïðåäåëèì, êóäà ïðèìåíÿåì +64 èíêðåìåíòû ïðè ïåðåêëþ÷åíèè âèäåîðåæèìà:
// - Åñëè ëó÷ íà áîðäþðå ñâåðõó îò ðàñòðà èëè íà áîðäþðå ñëåâà îò ðàñòðà - èçìåíÿåì îôôñåò äëÿ òåêóùåé ñêàíëèíèè
// - Åñëè ëó÷ íà ðàñòðå èëè íà áîðäþðå ñïðàâà îò ðàñòðà - èçìåíÿåì îôôñåò äëÿ ñëåäóþùåé ñêàíëèíèè
if ( iRayLine < iLinesAboveBorder || iRayOffset < tEachBorderWidth )
{
// Ëó÷ íà áîðäþðå. Ëèáî ñâåðõó îò ðàñòðà, ëèáî ñëåâà îò ðàñòðà.
// Âñå èçìåíåíèÿ ïðèìåíÿåì ê òåêóùåé ñêàíëèíèè.
// Îáðàáîòàåì ïåðåêëþ÷åíèå âèäåîðåæèìà.
if ( NewVideoMode == 6 )
{
// Ïåðåêëþ÷åíèå  òåêñòîâûé ðåæèì.
if ( (Offset & 32) // ïðîâåðêà óñëîâèÿ "ïðè àäðåñå A5=1"
&& (iRayLine & 7) < 4 // ïðîâåðêà óñëîâèÿ "â ñòðîêå 0..3"
)
{
// printf("CASE-1: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
Offset += 64;
AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
}
AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
// Ïîñëå ïðîõîäà âñåõ òî÷åê ðàñòðà òåêóùåé ñêàíëèíèè â òåêñòîâîì ðåæèìå áóäóò ñáðîøåíû A3..A5
Offset &= (~0x38); // Ñáðîñ A3..A5
// printf("CASE-1a, reset A3..A5: 0x%.4x\n", Offset);
// Ðàññ÷¸ò âèäåîàäðåñîâ äëÿ íèæëåæàùèõ ñêàíëèíèé
while (++iRayLine < 256)
{
if ( 0 == (iRayLine & 7))
{
Offset += 64;
}
AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
}
} else {
// Ïåðåêëþ÷åíèå ÈÇ òåêñòîâîãî ðåæèìà.
if ( 0 == (Offset & 32) ) // ïðîâåðêà óñëîâèÿ "ïðè àäðåñå A5=0"
{
// printf("CASE-2: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
Offset += 64;
AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
}
AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
// Ðàññ÷¸ò âèäåîàäðåñîâ äëÿ íèæëåæàùèõ ñêàíëèíèé
while (++iRayLine < 256)
{
AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
}
}
} else {
// Ëó÷ ðèñóåò ðàñòð, ëèáî áîðäþð ñïðàâà îò ðàñòðà.
// Âû÷èñëÿåì òåêóùåå çíà÷åíèå âèäåîàäðåñà
// Ïðèáàâëÿåì ê âèäåîàäðåñó âñå +64 èíêðåìåíòû,
// ñäåëàííûå â õîäå îòðèñîâêè ðàñòðà äàííîé ñêàíëèíèè
if (iRayLine == AtmVideoCtrl.CurrentRayLine)
{
Offset += AtmVideoCtrl.IncCounter_InRaster;
} else {
// Ñ÷¸ò÷èê èíêðåìåíòîâ óñòàðåë (ò.ê. íàêðó÷åí íà ñêàíëèíèþ îòëè÷íóþ îò òåêóùåé)
// Èíèöèàëèçèðóåì åãî äëÿ òåêóùåé ñêàíëèíèè.
AtmVideoCtrl.CurrentRayLine = iRayLine;
AtmVideoCtrl.IncCounter_InRaster = 0;
AtmVideoCtrl.IncCounter_InBorder = 0;
}
// Ïðèáàâëÿåì ê âèäåîàäðåñó âñå +8 èíêðåìåíòû, ïðîèçîøåäøèå ïðè îòðèñîâêå ðàñòðà
bool bRayInRaster = iRayOffset < (tScreenWidth + tEachBorderWidth);
int iScanlineRemainder = 0; // Ñêîëüêî +8 èíêðåìåíòîâ åù¸ áóäåò ñäåëàíî äî êîíöà ñêàíëèíèè
// (ò.å. óæå ïîñëå ïåðåêëþ÷åíèÿ âèäåîðåæèìà)
if ( bRayInRaster )
{
// Ëó÷ ðèñóåò ðàñòð.
// Ïðèáàâëÿåì ê òåêóùåìó âèäåîàäðåñó ñòîëüêî +8,
// ñêîëüêî áûëî ïîëíîñòüþ îòðèñîâàííûõ 64ïèêñåëüíûõ áëîêà.
int iIncValue = 8 * ((iRayOffset-tEachBorderWidth)/32);
iScanlineRemainder = 40 - iIncValue;
// printf("CASE-4: 0x%.4x Incremented (+%d) on line %d\n", Offset, iIncValue, iRayLine);
Offset += iIncValue;
} else {
// Îòðèñîâêà ðàñòðà ëó÷îì çàâåðøåíà.
// Ò.å. âñå 5-ÿòü 64-ïèêñåëüíûõ áëîêà áûëè ïðîéäåíû. Ïðèáàâëÿåì ê àäðåñó +40.
// printf("CASE-5: 0x%.4x Incremented (+40) on line %d\n", Offset, iRayLine);
Offset += 40;
// Åñëè ïðåäûäóùèì ðåæèìîì áûë òåêñòîâûé ðåæèì,
// Òî ïðè ïåðåõîäå ñ ðàñòðà íà áîðäþð äîëæíû áûòü ñáðîøåíû A3..A5
if (OldVideoMode == 6)
{
Offset &= (~0x38); // Ñáðîñ A3..A5
// printf("CASE-5a, reset A3..A5: 0x%.4x\n", Offset);
}
}
// Ïðèáàâëÿåì ê âèäåîàäðåñó âñå +64 èíêðåìåíòû,
// ñäåëàííûå â õîäå îòðèñîâêè áîðäþðà çà ðàñòðîì äàííîé ñêàíëèíèè
Offset += AtmVideoCtrl.IncCounter_InBorder;
// Òåêóùåå çíà÷åíèå âèäåîàäðåñà âû÷èñëåíî.
// Îáðàáàòûâàåì ïåðåêëþ÷åíèå âèäåîðåæèìà.
int OffsetInc = 0;
if ( NewVideoMode == 6 )
{
// Ïåðåêëþ÷åíèå  òåêñòîâûé ðåæèì.
if ( (Offset & 32) // ïðîâåðêà óñëîâèÿ "ïðè àäðåñå A5=1"
&& (iRayLine & 7) < 4 // ïðîâåðêà óñëîâèÿ "â ñòðîêå 0..3"
)
{
OffsetInc = 64;
// printf("CASE-6: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
Offset += OffsetInc;
}
// Ðàññ÷¸ò âèäåîàäðåñîâ äëÿ íèæëåæàùèõ ñêàíëèíèé
Offset += iScanlineRemainder;
while (++iRayLine < 256)
{
if ( 0 == (iRayLine & 7))
Offset += 64;
AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
}
} else {
// Ïåðåêëþ÷åíèå ÈÇ òåêñòîâîãî ðåæèìà.
if ( 0 == (Offset & 32) ) // ïðîâåðêà óñëîâèÿ "ïðè àäðåñå A5=0"
{
OffsetInc = 64;
// printf("CASE-7: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
Offset += OffsetInc;
}
// Ðàññ÷¸ò âèäåîàäðåñîâ äëÿ íèæëåæàùèõ ñêàíëèíèé
Offset += iScanlineRemainder;
while (++iRayLine < 256)
{
AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
Offset += 40;
}
}
// çàïîìèíàåì ñäåëàííûé èíêðåìåíò íà ñëó÷àé,
// åñëè èõ áóäåò íåñêîëüêî â õîäå îòðèñîâêè òåêóùåé ñêàíëèíèè.
if ( bRayInRaster )
{
AtmVideoCtrl.IncCounter_InRaster += OffsetInc;
} else {
AtmVideoCtrl.IncCounter_InBorder += OffsetInc;
}
}
}
void set_atm_FF77(unsigned port, unsigned char val)
{
if ((comp.pFF77 ^ val) & 1)
atm_memswap();
if ((comp.pFF77 & 7) ^ (val & 7))
{
// Ïðîèñõîäèò ïåðåêëþ÷åíèå âèäåîðåæèìà
AtmApplySideEffectsWhenChangeVideomode(val);
}
comp.pFF77 = val;
comp.aFF77 = port;
cpu.int_gate = (comp.pFF77 & 0x20) != false;
set_banks();
}
void set_atm_aFE(unsigned char addr)
{
unsigned char old_aFE = comp.aFE;
comp.aFE = addr;
if ((addr ^ old_aFE) & 0x40) atm_memswap();
if ((addr ^ old_aFE) & 0x80) set_banks();
}
static u8 atm_pal[0x10] = { 0 };
void atm_writepal(unsigned char val)
{
assert(comp.border_attr < 0x10);
atm_pal[comp.border_attr] = val;
// Ïðåîáðàçîâàíèå ïàëèòðû â ôîðìàò ULA+
u8 PalIdx = ((comp.border_attr & 8) << 1) | (comp.border_attr & 7);
comp.comp_pal[PalIdx + 0*8] =
comp.comp_pal[PalIdx + 1*8] =
comp.comp_pal[PalIdx + 3*8] =
comp.comp_pal[PalIdx + 5*8] = u8(t.atm_pal_map[val]);
temp.comp_pal_changed = 1;
}
u8 atm_readpal()
{
return atm_pal[comp.border_attr];
}
unsigned char atm450_z(unsigned t)
{
// PAL hardware gives 3 zeros in secret short time intervals
if (conf.frame < 80000) { // NORMAL SPEED mode
if ((unsigned)(t-7200) < 40 || (unsigned)(t-7284) < 40 || (unsigned)(t-7326) < 40) return 0;
} else { // TURBO mode
if ((unsigned)(t-21514) < 40 || (unsigned)(t-21703) < 80 || (unsigned)(t-21808) < 40) return 0;
}
return 0x80;
}