16#include "SubComponent.h"
19#include "DmaDebugger.h"
22#include "TimeDelayed.h"
26struct VICIIRegisters : Serializable
46 void serialize(W& worker)
63 } SERIALIZERS(serialize);
66struct SpriteSR : Serializable
72 u8 chunk1, chunk2, chunk3;
92 void serialize(W& worker)
104 } SERIALIZERS(serialize);
107class VICII final :
public SubComponent,
public Inspectable<VICIIInfo, VICIIStats> {
109 friend class C64Memory;
110 friend class DmaDebugger;
111 friend class VideoPort;
114 friend class Heatmap;
116 Descriptions descriptions = {{
119 .description =
"Video Interface Controller"
122 static constexpr VICIITraits traits[6] = {
128 .linesPerFrame = 312,
130 .cyclesPerFrame = 312 * 63,
132 .grayCodeBug =
false,
133 .delayedLpIrqs =
true
140 .linesPerFrame = 312,
142 .cyclesPerFrame = 312 * 63,
144 .grayCodeBug =
false,
145 .delayedLpIrqs =
false
152 .linesPerFrame = 312,
154 .cyclesPerFrame = 312 * 63,
157 .delayedLpIrqs =
false
164 .linesPerFrame = 262,
166 .cyclesPerFrame = 262 * 64,
168 .grayCodeBug =
false,
169 .delayedLpIrqs =
true
176 .linesPerFrame = 263,
178 .cyclesPerFrame = 263 * 65,
180 .grayCodeBug =
false,
181 .delayedLpIrqs =
false
188 .linesPerFrame = 263,
190 .cyclesPerFrame = 263 * 65,
193 .delayedLpIrqs =
false
197 ConfigOptions options = {
209 VICIIConfig config = { };
212 mutable SpriteInfo spriteInfo[8] = { };
223 DmaDebugger dmaDebugger;
243 typedef void (VICII::*ViciiFunc)(void);
244 ViciiFunc functable[6][8][66] = {};
247 ViciiFunc vicfunc[66] = {};
262 VICIIRegisters current;
263 VICIIRegisters delayed;
439 SpriteSR spriteSr[8];
448 u8 spriteSpriteCollision;
451 u8 spriteBackgroundColllision;
464 FrameFlipflops current;
465 FrameFlipflops delayed;
471 bool verticalFrameFFsetCond;
476 u16 leftComparisonVal;
481 u16 rightComparisonVal;
486 u16 upperComparisonVal;
491 u16 lowerComparisonVal;
501 bool lineMatchesIrqLine;
513 bool isVisibleColumn;
525 bool DENwasSetInLine30;
566 u8 spriteDisplayDelayed;
577 u8 cleared_bits_in_d017;
597 bool lpIrqHasOccurred;
610 MemoryType memSrc[16];
646 TimeDelayed <u16,3> baLine = TimeDelayed <u16,3> ();
666 TimeDelayed <u32,2> gAccessResult = TimeDelayed <u32,2> ();
743 u32 debugColor[6][4];
748 string dumpTexturePath =
"texture";
765 VICII& operator= (
const VICII& other) {
776 CLONE(refreshCounter)
782 CLONE_ARRAY(videoMatrix)
783 CLONE_ARRAY(colorLine)
786 CLONE_ARRAY(spriteSr)
787 CLONE(spriteSrActive)
788 CLONE(spriteSpriteCollision)
789 CLONE(spriteBackgroundColllision)
791 CLONE(verticalFrameFFsetCond)
792 CLONE(leftComparisonVal)
793 CLONE(rightComparisonVal)
794 CLONE(upperComparisonVal)
795 CLONE(lowerComparisonVal)
796 CLONE(lineMatchesIrqLine)
797 CLONE(isVisibleColumn)
800 CLONE(DENwasSetInLine30)
804 CLONE_ARRAY(spritePtr)
805 CLONE(isFirstDMAcycle)
806 CLONE(isSecondDMAcycle)
808 CLONE(spriteDisplayDelayed)
809 CLONE(spriteDmaOnOff)
811 CLONE(cleared_bits_in_d017)
812 CLONE_ARRAY(collision)
814 CLONE(lpIrqHasOccurred)
825 CLONE_ARRAY(rgbaTable)
837 updateVicFunctionTable();
849 void serialize(T& worker)
880 << spriteSpriteCollision
881 << spriteBackgroundColllision
882 << flipflops.current.vertical
883 << flipflops.current.main
884 << flipflops.delayed.vertical
885 << flipflops.delayed.main
886 << verticalFrameFFsetCond
888 << rightComparisonVal
889 << upperComparisonVal
890 << lowerComparisonVal
891 << lineMatchesIrqLine
903 << spriteDisplayDelayed
906 << cleared_bits_in_d017
921 if (isResetter(worker))
return;
937 } SERIALIZERS(serialize);
946 const Descriptions &getDescriptions()
const override {
return descriptions; }
950 void _dump(Category category, std::ostream& os)
const override;
951 void _initialize()
override;
952 void _reset(
bool hard)
override;
953 void _trackOn()
override;
954 void _trackOff()
override;
963 void cacheInfo(VICIIInfo &result)
const override;
964 void cacheStats(VICIIStats &result)
const override;
965 void clearStats()
override;
969 SpriteInfo getSpriteInfo(isize nr);
978 const VICIIConfig &getConfig()
const {
return config; }
979 const ConfigOptions &getOptions()
const override {
return options; }
980 i64 getOption(Option opt)
const override;
981 void checkOption(Option opt, i64 value)
override;
982 void setOption(Option opt, i64 value)
override;
984 bool dmaDebug()
const {
return dmaDebugger.config.dmaDebug; }
988 void updateRevision();
989 void setRevision(VICIIRevision revision);
998 void resetEmuTexture(isize nr);
999 void resetEmuTextures() { resetEmuTexture(1); resetEmuTexture(2); }
1000 void resetDmaTexture(isize nr);
1001 void resetDmaTextures() { resetDmaTexture(1); resetDmaTexture(2); }
1002 void resetTexture(u32 *p);
1004 void initFuncTable(VICIIRevision revision);
1005 void initFuncTable(VICIIRevision revision, u16 flags);
1006 ViciiFunc getViciiFunc(u16 flags, isize cycle);
1007 template <u16 flags> ViciiFunc getViciiFunc(isize cycle);
1011 void updateVicFunctionTable();
1021 const VICIITraits &getTraits()
const {
return traits[config.revision]; }
1024 bool pal()
const {
return isPAL; }
1025 bool ntsc()
const {
return isNTSC; }
1028 static bool delayedLightPenIrqs(VICIIRevision rev);
1029 bool delayedLightPenIrqs() {
return delayedLightPenIrqs(config.revision); }
1032 static double getFps(VICIIRevision rev);
1033 double getFps()
const {
return getFps(config.revision); }
1036 static isize getFrequency(VICIIRevision rev);
1037 isize getFrequency()
const {
return getFrequency(config.revision); }
1040 static isize getCyclesPerLine(VICIIRevision rev);
1041 isize getCyclesPerLine()
const {
return getCyclesPerLine(config.revision); }
1044 static isize getLinesPerFrame(VICIIRevision rev);
1045 isize getLinesPerFrame()
const {
return getLinesPerFrame(config.revision); }
1048 static isize getCyclesPerFrame(VICIIRevision rev);
1049 isize getCyclesPerFrame()
const {
return getCyclesPerFrame(config.revision); }
1052 static isize numVisibleLines(VICIIRevision rev);
1053 long numVisibleLines()
const {
return numVisibleLines(config.revision); }
1056 static bool hasGrayCodeBug(VICIIRevision rev);
1057 bool hasGrayCodeBug()
const {
return hasGrayCodeBug(config.revision); }
1060 bool isLastCycleInLine(isize cycle)
const;
1063 bool isVBlankLine(isize line)
const;
1071 u32 getColor(isize nr)
const {
return rgbaTable[nr]; }
1072 u32 getColor(isize nr, Palette palette)
const;
1075 void updatePalette();
1080 u32 *getTexture()
const;
1081 u32 *getDmaTexture()
const;
1091 u8 spypeek(u16 addr)
const;
1094 u8 getUltimax() {
return ultimax; }
1097 void setUltimax(
bool value);
1100 u8 getDataBusPhi1()
const {
return dataBusPhi1; }
1103 u8 getDataBusPhi2()
const {
return dataBusPhi2; }
1108 void switchBank(u16 addr);
1115 void updateBankAddr(u8 bank) { bankAddr = (u16)(bank << 14); }
1120 void updateBankAddr();
1126 void poke(u16 addr, u8 value);
1129 u8 memAccess(u16 addr);
1132 u8 memSpyAccess(u16 addr);
1135 bool isCharRomAddr(u16 addr)
const;
1138 template <u16 flags>
void rAccess();
1141 template <u16 flags>
void iAccess();
1144 template <u16 flags>
void cAccess();
1147 template <u16 flags>
void gAccess();
1150 u16 gAccessAddr85x();
1151 u16 gAccessAddr65x();
1156 u16 gAccessAddr(
bool bmm,
bool ecm);
1159 template <u16 flags>
void pAccess(isize sprite);
1162 template <u16 flags, isize sprite>
void sAccess1();
1163 template <u16 flags, isize sprite>
void sAccess2();
1164 template <u16 flags, isize sprite>
void sAccess3();
1169 void sFinalize(isize sprite);
1179 u16 scanline()
const;
1182 u8 rastercycle()
const;
1188 bool yCounterOverflow()
const {
return scanline() == (isPAL ? 0 : 238); }
1193 void checkForRasterIrq();
1225 void checkVerticalFrameFF();
1228 void checkFrameFlipflopsLeft(u16 comparisonValue);
1231 void checkFrameFlipflopsRight(u16 comparisonValue);
1234 void setVerticalFrameFF(
bool value);
1237 void setMainFrameFF(
bool value);
1240 u16 leftComparisonValue()
const {
return isCSEL() ? 24 : 31; }
1241 u16 rightComparisonValue()
const {
return isCSEL() ? 344 : 335; }
1242 u16 upperComparisonValue()
const {
return isRSEL() ? 51 : 55; }
1243 u16 lowerComparisonValue()
const {
return isRSEL() ? 251 : 247; }
1253 bool DENbit()
const {
return GET_BIT(reg.current.ctrl1, 4); }
1256 u8 CB13()
const {
return memSelect & 0x08; }
1259 u8 CB13CB12CB11()
const {
return memSelect & 0x0E; }
1262 u8 VM13VM12VM11VM10()
const {
return memSelect & 0xF0; }
1265 bool isCSEL()
const {
return GET_BIT(reg.current.ctrl2, 3); }
1268 bool isRSEL()
const {
return GET_BIT(reg.current.ctrl1, 3); }
1278 bool badLineCondition()
const;
1288 void updateBA(u8 value);
1293 bool BApulledDownForAtLeastThreeCycles()
const {
return baLine.delayed(); }
1296 void triggerIrq(u8 source);
1306 void setLP(
bool value);
1311 u16 lightpenX()
const;
1312 u16 lightpenY()
const;
1320 void checkForLightpenIrq();
1327 void checkForLightpenIrqAtStartOfFrame();
1337 u8 spriteDepth(isize nr)
const;
1340 u8 compareSpriteY()
const;
1352 void turnSpriteDmaOff();
1357 void turnSpriteDmaOn();
1361 void turnSpritesOnOrOff();
1366 void loadSpriteShiftRegister(isize nr);
1371 void updateSpriteShiftRegisters();
1379 void toggleExpansionFlipflop() { expansionFF ^= reg.current.sprExpandY; }
1396 void beginScanline();
1411 void processDelayedActions();
1414 template <u16 flags>
void cycle1();
1415 template <u16 flags>
void cycle2();
1416 template <u16 flags>
void cycle3();
1417 template <u16 flags>
void cycle4();
1418 template <u16 flags>
void cycle5();
1419 template <u16 flags>
void cycle6();
1420 template <u16 flags>
void cycle7();
1421 template <u16 flags>
void cycle8();
1422 template <u16 flags>
void cycle9();
1423 template <u16 flags>
void cycle10();
1424 template <u16 flags>
void cycle11();
1425 template <u16 flags>
void cycle12();
1426 template <u16 flags>
void cycle13();
1427 template <u16 flags>
void cycle14();
1428 template <u16 flags>
void cycle15();
1429 template <u16 flags>
void cycle16();
1430 template <u16 flags>
void cycle17();
1431 template <u16 flags>
void cycle18();
1432 template <u16 flags>
void cycle19to54();
1433 template <u16 flags>
void cycle55();
1434 template <u16 flags>
void cycle56();
1435 template <u16 flags>
void cycle57();
1436 template <u16 flags>
void cycle58();
1437 template <u16 flags>
void cycle59();
1438 template <u16 flags>
void cycle60();
1439 template <u16 flags>
void cycle61();
1440 template <u16 flags>
void cycle62();
1441 template <u16 flags>
void cycle63();
1442 template <u16 flags>
void cycle64();
1443 template <u16 flags>
void cycle65();
1445#define DRAW_SPRITES_DMA1 \
1446assert(isFirstDMAcycle); assert(!isSecondDMAcycle); \
1447if constexpr (!(flags & HEADLESS_CYCLE)) { drawSpritesSlowPath(); }
1449#define DRAW_SPRITES_DMA2 \
1450assert(!isFirstDMAcycle); assert(isSecondDMAcycle); \
1451if constexpr (!(flags & HEADLESS_CYCLE)) { drawSpritesSlowPath(); }
1453#define DRAW_SPRITES \
1454assert(!isFirstDMAcycle && !isSecondDMAcycle); \
1455if (spriteDisplay && !(flags & HEADLESS_CYCLE)) { drawSprites(); }
1457#define DRAW_SPRITES59 \
1458if ((spriteDisplayDelayed || spriteDisplay || isSecondDMAcycle) && !(flags & HEADLESS_CYCLE)) \
1459{ drawSpritesSlowPath(); }
1461#define DRAW if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder(); };
1462#define DRAW17 if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder17(); };
1463#define DRAW55 if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder55(); };
1464#define DRAW59 if (!vblank && !(flags & HEADLESS_CYCLE)) { drawCanvas(); drawBorder(); };
1467dataBusPhi2 = 0xFF; \
1470if (unlikely(delay)) { processDelayedActions(); }
1472#define END_VISIBLE_CYCLE \
1475#define BA_LINE(x) updateBA(x);
1488 void drawBorder17();
1491 void drawBorder55();
1495 void drawCanvasFastPath();
1496 void drawCanvasSlowPath();
1499 void drawCanvasPixel(u8 pixel, u8 mode, u8 d016);
1502 void loadShiftRegister();
1512 void drawSpritesFastPath();
1513 void drawSpritesSlowPath();
1518 template <
bool multicolor>
void drawSpriteNr(isize nr,
bool enable,
bool active);
1527 void drawSpritePixel(isize pixel, u8 enableBits, u8 freezeBits);
1530 void checkCollisions();
1538#define COLORIZE(index,color) \
1539emuTexturePtr[index] = rgbaTable[color];
1542#define SET_FRAME_PIXEL(pixel,color) { \
1543isize index = bufferoffset + pixel; \
1544COLORIZE(index, color); \
1545zBuffer[index] = DEPTH_BORDER; }
1548#define SET_FG_PIXEL(pixel,color) { \
1549isize index = bufferoffset + pixel; \
1550COLORIZE(index,color) \
1551zBuffer[index] = DEPTH_FG; }
1554#define SET_BG_PIXEL(pixel,color) { \
1555isize index = bufferoffset + pixel; \
1556COLORIZE(index,color) \
1557zBuffer[index] = DEPTH_BG; }
1560#define SET_SPRITE_PIXEL(sprite,pixel,color) { \
1561isize index = bufferoffset + pixel; \
1562if (u8 depth = spriteDepth(sprite); depth <= zBuffer[index]) { \
1563if (isVisibleColumn) COLORIZE(index, color); \
1564zBuffer[index] = depth | (zBuffer[index] & 0x10); \
1578 u16 getSpriteX(
int nr)
const {
return reg.current.sprX[nr]; }
1579 u8 getSpriteY(
int nr)
const {
return reg.current.sprY[nr]; }
static const long CLOCK_FREQUENCY
Clock frequency in Hz.
Definition Constants.h:66
static const long CLOCK_FREQUENCY
Clock frequency in Hz.
Definition Constants.h:27
static const long height
Height of the emulator texture in texels.
Definition Constants.h:105
static const long width
Width of the emulator texture in texels.
Definition Constants.h:108
VirtualC64 project namespace.
Definition CmdQueue.cpp:16
SCREEN_GEOMETRY ScreenGeometry
Type alias.
Definition VICIITypes.h:157
@ OPT_VICII_REVISION
Chip revision.
Definition OptionTypes.h:43
@ OPT_VICII_POWER_SAVE
Enable fast-paths.
Definition OptionTypes.h:45
@ OPT_VICII_SB_COLLISIONS
Check for sprite-background collisions.
Definition OptionTypes.h:50
@ OPT_GLUE_LOGIC
VICII glue-logic type.
Definition OptionTypes.h:101
@ OPT_VICII_HIDE_SPRITES
Hide some sprites.
Definition OptionTypes.h:46
@ OPT_VICII_SS_COLLISIONS
Check for sprite-sprite collisions.
Definition OptionTypes.h:49
@ OPT_VICII_GRAY_DOT_BUG
Emulate gray-dot bug.
Definition OptionTypes.h:44