1 /* 2 * This file is part of libsidplayfp, a SID player engine. 3 * 4 * Copyright 2011-2020 Leandro Nini <drfiemost@users.sourceforge.net> 5 * Copyright 2009-2014 VICE Project 6 * Copyright 2007-2010 Antti Lankila 7 * Copyright 2001 Simon White 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 */ 23 24 #ifndef LIGHTPEN_H 25 #define LIGHTPEN_H 26 27 namespace libsidplayfp 28 { 29 30 /** 31 * Lightpen emulation. 32 * Does not reflect model differences. 33 */ 34 class Lightpen 35 { 36 private: 37 /// Last VIC raster line 38 unsigned int lastLine; 39 40 /// VIC cycles per line 41 unsigned int cyclesPerLine; 42 43 /// X coordinate 44 unsigned int lpx; 45 46 /// Y coordinate 47 unsigned int lpy; 48 49 /// Has light pen IRQ been triggered in this frame already? 50 bool isTriggered; 51 52 private: 53 /** 54 * Transform line cycle into x coordinate. 55 * 56 * @param lineCycle 57 * @return x position divided by two 58 */ getXpos(unsigned int lineCycle)59 uint8_t getXpos(unsigned int lineCycle) const 60 { 61 if (lineCycle < 12) 62 lineCycle += cyclesPerLine-1; 63 64 lineCycle -= 12; 65 66 return lineCycle << 2; 67 } 68 69 public: 70 /** 71 * Set VIC screen size. 72 * 73 * @param height number of raster lines 74 * @param width number of cycles per line 75 */ setScreenSize(unsigned int height,unsigned int width)76 void setScreenSize(unsigned int height, unsigned int width) 77 { 78 lastLine = height - 1; 79 cyclesPerLine = width; 80 } 81 82 /** 83 * Reset the lightpen. 84 */ reset()85 void reset() 86 { 87 lpx = 0; 88 lpy = 0; 89 isTriggered = false; 90 } 91 92 /** 93 * Return the low byte of x coordinate. 94 */ getX()95 uint8_t getX() const { return lpx; } 96 97 /** 98 * Return the low byte of y coordinate. 99 */ getY()100 uint8_t getY() const { return lpy; } 101 102 /** 103 * Retrigger lightpen on vertical blank. 104 * 105 * @param lineCycle current line cycle 106 * @param rasterY current y raster position 107 * @return true if an IRQ should be triggered 108 */ retrigger(unsigned int lineCycle,unsigned int rasterY)109 bool retrigger(unsigned int lineCycle, unsigned int rasterY) 110 { 111 const bool triggered = trigger(lineCycle, rasterY); 112 switch (cyclesPerLine) 113 { 114 case 63: 115 default: 116 lpx = 0xd1; 117 break; 118 case 65: 119 lpx = 0xd5; 120 break; 121 } 122 return triggered; 123 } 124 125 /** 126 * Trigger lightpen from CIA. 127 * 128 * @param lineCycle current line cycle 129 * @param rasterY current y raster position 130 * @return true if an IRQ should be triggered 131 */ trigger(unsigned int lineCycle,unsigned int rasterY)132 bool trigger(unsigned int lineCycle, unsigned int rasterY) 133 { 134 if (isTriggered) 135 return false; 136 137 isTriggered = true; 138 139 // don't latch on the last line, except on the first cycle 140 if ((rasterY != lastLine) || (lineCycle == 0)) 141 { 142 // Latch current coordinates 143 lpx = getXpos(lineCycle) + 2; 144 lpy = rasterY; 145 } 146 147 return true; 148 } 149 150 /** 151 * Untrigger lightpen from CIA. 152 */ untrigger()153 void untrigger() { isTriggered = false; } 154 }; 155 156 } 157 158 #endif 159