Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 1
#include "std.h"
2
 
3
#include "emul.h"
4
#include "vars.h"
5
#include "memory.h"
6
#include "draw.h"
7
 
8
void atm_memswap()
9
{
10
   if (!conf.atm.mem_swap) return;
11
   // swap memory address bits A5-A7 and A8-A10
12
   for (unsigned start_page = 0; start_page < conf.ramsize*1024; start_page += 2048) {
13
      unsigned char buffer[2048], *bank = memory + start_page;
14
      for (unsigned addr = 0; addr < 2048; addr++)
15
         buffer[addr] = bank[(addr & 0x1F) + ((addr >> 3) & 0xE0) + ((addr << 3) & 0x700)];
16
      memcpy(bank, buffer, 2048);
17
   }
18
}
19
 
20
void AtmApplySideEffectsWhenChangeVideomode(unsigned char val)
21
{
22
    int NewVideoMode = (val & 7);
23
    int OldVideoMode = (comp.pFF77 & 7);
24
 
25
    // Константы можно задать жёстко, потому что между моделями АТМ2 они не меняются.
26
    const int tScanlineWidth = 224;
27
    const int tScreenWidth = 320/2;
28
    const int tEachBorderWidth = (tScanlineWidth - tScreenWidth)/2;
29
    const int iLinesAboveBorder = 56;
30
 
31
    int iRayLine = cpu.t / tScanlineWidth;
32
    int iRayOffset = cpu.t % tScanlineWidth;
33
/*    
34
    static int iLastLine = 0;
35
    if ( iLastLine > iRayLine )
36
    {
37
        printf("\nNew Frame Begin\n");
38
        __debugbreak();
39
    }
40
    iLastLine = iRayLine;
41
    printf("%d->%d %d %d\n", OldVideoMode, NewVideoMode, iRayLine, iRayOffset);
42
*/
43
 
44
    if (OldVideoMode == 3 || NewVideoMode == 3)
45
    {
46
        // Переключение из/в sinclair режим не имеет полезных побочных эффектов
47
        // (по словам AlCo даже синхра сбивается)
48
        for(unsigned y = 0; y < 200; y++)
49
        {
50
            AtmVideoCtrl.Scanlines[y+56].VideoMode = NewVideoMode;
51
            AtmVideoCtrl.Scanlines[y+56].Offset = ((y & ~7) << 3) + 0x01C0;
52
        }
53
        return;
54
    }
55
 
56
    if (OldVideoMode != 6 && NewVideoMode != 6)
57
    {
58
        // Нас интересуют только переключения между текстовым режимом и расширенными графическими.
59
        // Текстового режима нет ни до, ни после переключения. 
60
        // Следовательно, нет и побочных эффектов.
61
 
62
        // Распространяем новый видеорежим на неотрисованные сканлинии
63
        if (iRayOffset >= tEachBorderWidth)
64
            ++iRayLine;
65
 
66
        while (iRayLine < 256)
67
        {
68
            AtmVideoCtrl.Scanlines[iRayLine++].VideoMode = NewVideoMode;
69
        }
70
//        printf("%d->%d SKIPPED!\n",  OldVideoMode, NewVideoMode);
71
        return;
72
    }
73
 
74
    //
75
    // Терминология и константы:
76
    // Экран содержит 312 сканлиний, по 224такта (noturbo) в каждой.
77
    //
78
    //  "строка" - младшие 3 бита номера отрисовываемой видеоконтроллером (лучом) сканлинии
79
    //  "адрес"  - текущий адрес в видеопамяти, с которого выбирает байты видеоконтроллер
80
    //             адрес меняется с гранулярностью +8 или +64
81
    //  "экран"  - растровая картинка. Со всех сторон окружена "бордюром".
82
    //             Размеры бордюра: 
83
    //          сверху и снизу от растра: 56 сканлиний
84
    //              слева и справа от растра: 32 такта (64пикселя).
85
    // 
86
    // +64 происходит, когда CROW 1->0, то есть:
87
    //  либо в текстмоде при переходе со строки 7 на строку 0,
88
    //  либо при переключении текстмод->графика при адресе A5=0,
89
    //  либо при переключении графика->текстмод при адресе A5=1 и строке 0..3
90
    //
91
    // +8 происходит на растре в конце 64-блока пикселей (каждые 32такта) независимо от режима
92
    // (ВАЖНО: +8 не завраплены внутри A3..A5 а производят честное сложение с адресом.)
93
    //
94
    // сброс A3..A5 (накопленных +8) происходит, когда RCOL 1->0, то есть:
95
    //  либо в текстмоде при переходе с растра на бордюр,
96
    //  либо на бордюре при переключении графика->текстмод
97
    //
98
 
99
 
100
    if (iRayLine >= 256)
101
    {
102
        return;
103
    }
104
 
105
    // Получим оффсет текущей сканлинии (фактически видеоадрес её начала)
106
    int Offset = AtmVideoCtrl.Scanlines[iRayLine].Offset;
107
 
108
    // Вычислим реальный видеоадрес, с учётом инкрементов при отрисовке растра.
109
    // Также определим, куда применяем +64 инкременты при переключении видеорежима:
110
    //  - Если луч на бордюре сверху от растра или на бордюре слева от растра - изменяем оффсет для текущей сканлинии
111
    //  - Если луч на растре или на бордюре справа от растра - изменяем оффсет для следующей сканлинии
112
    bool bRayOnBorder = true;
113
    if ( iRayLine < iLinesAboveBorder || iRayOffset < tEachBorderWidth )
114
    {
115
        // Луч на бордюре. Либо сверху от растра, либо слева от растра.
116
        // Все изменения применяем к текущей сканлинии.
117
 
118
        // Обработаем переключение видеорежима.
119
        if ( NewVideoMode == 6 )
120
        {
121
            // Переключение В текстовый режим.
122
            if ( (Offset & 32) //< проверка условия "при адресе A5=1"
123
                 && (iRayLine & 7) < 4 //< проверка условия "в строке 0..3"
124
               )
125
            {
126
//                printf("CASE-1: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
127
                Offset += 64;
128
                AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
129
            }
130
 
131
            AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
132
 
133
            // После прохода всех точек растра текущей сканлинии в текстовом режиме будут сброшены A3..A5
134
            Offset &= (~0x38); // Сброс A3..A5
135
//            printf("CASE-1a, reset A3..A5: 0x%.4x\n", Offset);
136
 
137
            // Рассчёт видеоадресов для нижлежащих сканлиний
138
            while (++iRayLine < 256)
139
            {
140
                if ( 0 == (iRayLine & 7))
141
                {
142
                    Offset += 64;
143
                }
144
                AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
145
                AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
146
            }
147
        } else {
148
            // Переключение ИЗ текстового режима.
149
            if ( 0 == (Offset & 32) ) //< проверка условия "при адресе A5=0"
150
            {
151
//                printf("CASE-2: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
152
                Offset += 64;
153
                AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
154
            }
155
            AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
156
 
157
            // Рассчёт видеоадресов для нижлежащих сканлиний
158
            while (++iRayLine < 256)
159
            {
160
                AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
161
                AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
162
            }
163
        }
164
    } else {
165
        // Луч рисует растр, либо бордюр справа от растра.
166
 
167
        // Вычисляем текущее значение видеоадреса
168
 
169
        // Прибавляем к видеоадресу все +64 инкременты, 
170
        // сделанные в ходе отрисовки растра данной сканлинии
171
        if (iRayLine == AtmVideoCtrl.CurrentRayLine)
172
        {
173
            Offset += AtmVideoCtrl.IncCounter_InRaster;
174
        } else {
175
            // Счётчик инкрементов устарел (т.к. накручен на сканлинию отличную от текущей)
176
            // Инициализируем его для текущей сканлинии.
177
            AtmVideoCtrl.CurrentRayLine = iRayLine;
178
            AtmVideoCtrl.IncCounter_InRaster = 0;
179
            AtmVideoCtrl.IncCounter_InBorder = 0;
180
        }
181
 
182
        // Прибавляем к видеоадресу все +8 инкременты, произошедшие при отрисовке растра
183
        bool bRayInRaster = iRayOffset < (tScreenWidth + tEachBorderWidth);
184
 
185
        int iScanlineRemainder = 0; //< Сколько +8 инкрементов ещё будет сделано до конца сканлинии 
186
                                    //  (т.е. уже после переключения видеорежима)
187
        if ( bRayInRaster )
188
        {
189
            // Луч рисует растр. 
190
            // Прибавляем к текущему видеоадресу столько +8, 
191
            // сколько было полностью отрисованных 64пиксельных блока.
192
            int iIncValue = 8 * ((iRayOffset-tEachBorderWidth)/32);
193
            iScanlineRemainder = 40 - iIncValue;
194
//            printf("CASE-4: 0x%.4x Incremented (+%d) on line %d\n", Offset, iIncValue, iRayLine);
195
            Offset += iIncValue;
196
        } else {
197
            // Отрисовка растра лучом завершена.
198
            // Т.е. все 5-ять 64-пиксельных блока были пройдены. Прибавляем к адресу +40.
199
//            printf("CASE-5: 0x%.4x Incremented (+40) on line %d\n", Offset, iRayLine);
200
            Offset += 40;
201
 
202
            // Если предыдущим режимом был текстовый режим,
203
            // То при переходе с растра на бордюр должны быть сброшены A3..A5
204
            if (OldVideoMode == 6)
205
            {
206
                Offset &= (~0x38); // Сброс A3..A5
207
//                printf("CASE-5a, reset A3..A5: 0x%.4x\n", Offset);
208
            }
209
        }
210
 
211
        // Прибавляем к видеоадресу все +64 инкременты, 
212
        // сделанные в ходе отрисовки бордюра за растром данной сканлинии
213
        Offset += AtmVideoCtrl.IncCounter_InBorder;
214
 
215
        // Текущее значение видеоадреса вычислено. 
216
        // Обрабатываем переключение видеорежима.
217
        int OffsetInc = 0;
218
        if ( NewVideoMode == 6 )
219
        {
220
            // Переключение В текстовый режим.
221
            if ( (Offset & 32) //< проверка условия "при адресе A5=1"
222
                && (iRayLine & 7) < 4 //< проверка условия "в строке 0..3"
223
                )
224
            {
225
                OffsetInc = 64;
226
//                printf("CASE-6: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
227
                Offset += OffsetInc;
228
            }
229
            // Рассчёт видеоадресов для нижлежащих сканлиний
230
            Offset += iScanlineRemainder;
231
            while (++iRayLine < 256)
232
            {
233
                if ( 0 == (iRayLine & 7))
234
                    Offset += 64;
235
                AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
236
                AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
237
            }
238
        } else {
239
            // Переключение ИЗ текстового режима.
240
            if ( 0 == (Offset & 32) ) //< проверка условия "при адресе A5=0"
241
            {
242
                OffsetInc = 64;
243
//                printf("CASE-7: 0x%.4x Incremented (+64) on line %d\n", Offset, iRayLine);
244
                Offset += OffsetInc;
245
            }
246
 
247
            // Рассчёт видеоадресов для нижлежащих сканлиний
248
            Offset += iScanlineRemainder;
249
            while (++iRayLine < 256)
250
            {
251
                AtmVideoCtrl.Scanlines[iRayLine].Offset = Offset;
252
                AtmVideoCtrl.Scanlines[iRayLine].VideoMode = NewVideoMode;
253
                Offset += 40;
254
            }
255
        }
256
 
257
        // запоминаем сделанный инкремент на случай, 
258
        // если их будет несколько в ходе отрисовки текущей сканлинии.
259
        if ( bRayInRaster )
260
        {
261
            AtmVideoCtrl.IncCounter_InRaster += OffsetInc;
262
        } else {
263
            AtmVideoCtrl.IncCounter_InBorder += OffsetInc;
264
        }
265
    }
266
}
267
 
268
void set_atm_FF77(unsigned port, unsigned char val)
269
{
270
   if ((comp.pFF77 ^ val) & 1)
271
       atm_memswap();
272
 
273
 
274
   if ((comp.pFF77 & 7) ^ (val & 7))
275
   {
276
        // Происходит переключение видеорежима
277
        AtmApplySideEffectsWhenChangeVideomode(val);
278
   }
279
 
280
   comp.pFF77 = val;
281
   comp.aFF77 = port;
282
   cpu.int_gate = (comp.pFF77 & 0x20) != false;
283
   set_banks();
284
}
285
 
286
void set_atm_aFE(unsigned char addr)
287
{
288
   unsigned char old_aFE = comp.aFE;
289
   comp.aFE = addr;
290
   if ((addr ^ old_aFE) & 0x40) atm_memswap();
291
   if ((addr ^ old_aFE) & 0x80) set_banks();
292
}
293
 
294
static u8 atm_pal[0x10] = { 0 };
295
 
296
void atm_writepal(unsigned char val)
297
{
298
   assert(comp.border_attr < 0x10);
299
   atm_pal[comp.border_attr] = val;
300
   comp.comp_pal[comp.border_attr] = t.atm_pal_map[val];
301
   temp.comp_pal_changed = 1;
302
}
303
 
304
u8 atm_readpal()
305
{
306
   return atm_pal[comp.border_attr];
307
}
308
 
309
unsigned char atm450_z(unsigned t)
310
{
311
   // PAL hardware gives 3 zeros in secret short time intervals
312
   if (conf.frame < 80000) { // NORMAL SPEED mode
313
      if ((unsigned)(t-7200) < 40 || (unsigned)(t-7284) < 40 || (unsigned)(t-7326) < 40) return 0;
314
   } else { // TURBO mode
315
      if ((unsigned)(t-21514) < 40 || (unsigned)(t-21703) < 80 || (unsigned)(t-21808) < 40) return 0;
316
   }
317
   return 0x80;
318
}