/ MCUME_teensy41 / teensy20 / MOS6561.cpp
MOS6561.cpp
  1  #include "MOS6561.h"
  2  
  3  extern "C" {
  4  #include "emuapi.h"
  5  #include "platform_config.h"
  6  }
  7  
  8  typedef uint16_t Pixel;
  9  
 10  #define WIN_W 320 //TFT_WIDTH
 11  #define WIN_H 240 //TFT_HEIGHT
 12  
 13  
 14  // definitions for easy access to registers
 15  #define REG_COLPAGE_BASE      (0x9400) // 0x9400+0x200 = 0x9600 unexpanded
 16  
 17  #define REG_SCRPAGE_LO        ((readWord(0x9002) & 0x80)<< 2) // 0x0200
 18  #define REG_COLPAGE_LO        ((readWord(0x9002) & 0x80)<< 2) // 0x0200
 19  #define REG_NB_COLUMNS        (readWord(0x9002) & 0x7F)
 20  
 21  #define REG_RASTER_LO_RD      (0x9003) // 0x80 >> 7
 22  #define REG_DOUBLE_HEIGHT     (readWord(0x9003) & 0x01)
 23  #define REG_NB_ROWS           ((readWord(0x9003) & 0x7E) >> 1) //x2 => 46
 24  
 25  #define REG_RASTER_HI_RD      (0x9004) // << 1 // 1E00 unexpanded?
 26  
 27  #define REG_CHRMAP_PT         (readWord(0x9005) & 0x0F)
 28  #define REG_SCRPAGE_HIGH      ((readWord(0x9005) & 0xF0) << 6) // 0x2C00
 29  
 30  #define REG_AUXILIARY_COLOUR  ((readWord(0x900E) & 0xF0) >> 4)
 31  #define REG_BORDER_COLOUR     (readWord(0x900F) & 0x7)
 32  #define REG_BACKGROUND_COLOUR ((readWord(0x900F) & 0xF0) >> 4)
 33  
 34  #define REG_HORI_OFFSET       ((readWord(0x9000) & 0x7F) 
 35  #define REG_VERT_OFFSET       ((readWord(0x9001) & 0xFF) 
 36  
 37  // C  R  H  V
 38  // 16 16 +6 +16
 39  // 22 23 0  0
 40  // 24 28 -3 -9
 41  // 25 30 -3 -12
 42  // 27 33 -5 -19
 43  
 44  
 45  static Pixel vicPalette[16];
 46  static uint16_t remap[16] = {
 47    0x8000,
 48    0x8400,
 49    0x8800,
 50    0x8c00,
 51    0x0000,
 52    0x0000,
 53    0x0000,
 54    0x0000,
 55    0x0000,
 56    0x0000,
 57    0x0000,
 58    0x0000,
 59    0x1000,
 60    0x1400,
 61    0x1800,
 62    0x1c00
 63  };
 64  
 65  static Pixel linebuf[WIN_W];
 66  
 67  MOS6561::MOS6561() : IC(), curRow(0), frameReady(true) {
 68  	// Set clock speed
 69  	this->setClockSpeed(1108000);
 70  }
 71  
 72  MOS6561::~MOS6561() {
 73  }
 74  
 75  void MOS6561::initialize() {
 76  	// Initialize VIC palette
 77  	vicPalette[0] = RGBVAL16(0, 0, 0);
 78  	vicPalette[1] = RGBVAL16(255, 255, 255);
 79  	vicPalette[2] = RGBVAL16((182), (31), (33));
 80  	vicPalette[3] = RGBVAL16((77), (240), (255));
 81  	vicPalette[4] = RGBVAL16((180), (63), (255));
 82  	vicPalette[5] = RGBVAL16((68), (226), (55));
 83  	vicPalette[6] = RGBVAL16((15), (87), (247));
 84  	vicPalette[7] = RGBVAL16((220), (215), (27));
 85  	vicPalette[8] = RGBVAL16((202), (84), (0));
 86  	vicPalette[9] = RGBVAL16((233), (176), (114));
 87  	vicPalette[10] = RGBVAL16((231), (146), (147));
 88  	vicPalette[11] = RGBVAL16((154), (247), (253)); 
 89  	vicPalette[12] = RGBVAL16((224), (159), (255));
 90  	vicPalette[13] = RGBVAL16((143), (228), (147));
 91  	vicPalette[14] = RGBVAL16((130), (144), (255));
 92  	vicPalette[15] = RGBVAL16((229), (222), (133));
 93  }
 94  
 95  
 96  void MOS6561::renderBorder(uint16_t raster){
 97  	if (raster < WIN_H) {
 98  		Pixel  bcol = vicPalette[REG_BORDER_COLOUR];
 99  		Pixel * dst = &linebuf[0];
100  		for (int x=0; x < WIN_W; x++) {
101  		  *dst++ = bcol;
102  		}
103  		emu_DrawLine16(&linebuf[0], WIN_W, WIN_H, raster);
104  	}
105  }
106  
107  
108  void MOS6561::renderLine(uint16_t raster, uint16_t row, uint8_t rowHeight, uint8_t chrLine) {
109  	int curRow = row;
110  	int nbRow = REG_NB_ROWS;
111  
112  	if ( (rowHeight == 16) && (nbRow >= 23) ) {
113  		curRow = curRow/2;
114  		nbRow = nbRow/2;    
115  	}
116  
117  	if (raster < WIN_H) 
118  	{
119  		int nbCol = REG_NB_COLUMNS;
120  		int bWidth = (WIN_W - nbCol*8)/2;
121  		#define bakcol 0
122  		#define borcol 1
123  		#define forcol 2
124  		#define auxcol 3
125  		Pixel cols[4];
126  		uint16_t screenPage = (REG_SCRPAGE_HIGH & ~0x2000) + REG_SCRPAGE_LO;
127  		uint8_t * charPointer = &vicmemory[screenPage + (curRow * nbCol)];
128  		uint16_t colourPage = REG_COLPAGE_BASE + REG_COLPAGE_LO;
129  		uint8_t * colPointer = &vicmemory[colourPage + (curRow * nbCol)];
130  
131  		cols[borcol] = vicPalette[REG_BORDER_COLOUR];
132  		cols[bakcol] = vicPalette[REG_BACKGROUND_COLOUR];
133  
134  		// Border Left
135  		Pixel * dst = &linebuf[0];
136  		for (int x=0; x < bWidth; x++) {
137  		  *dst++ = cols[borcol];
138  		}
139  
140  		uint16_t chardefbase = remap[REG_CHRMAP_PT];
141  		for (int x = 0; x < nbCol; x +=1) 
142  		{
143  			uint16_t charpt = chardefbase + charPointer[x]*rowHeight + chrLine;
144  			if ( (charpt > 0x2000) && (charpt < 0x3000) )
145  			  charpt += 0x6000;
146  		  uint8_t characterByte = vicmemory[charpt];
147  		  uint8_t colour = colPointer[x] & 0x7;
148  		  uint8_t multiColour = colPointer[x] & 0x8;
149  		  cols[forcol] = vicPalette[colour];	  
150  		  if (!multiColour) {
151  			Pixel * dest = dst;
152  			for (int a = 0; a < 8; a++) {
153  			  if ((characterByte << a) & 0x80) {
154  				*dest++ = cols[forcol];
155  			  }
156  			  else {
157  				*dest++ = cols[bakcol];
158  			  }
159  			}
160  		  }
161  		  else {
162  			Pixel * dest = dst;
163  			cols[auxcol] = vicPalette[REG_AUXILIARY_COLOUR];	  
164  			for (int a = 0; a < 8; a += 2) {
165  				// Set colour
166  				Pixel col = cols[((characterByte << a) & 0xC0) >> 6];
167  				*dest++ = col;
168  				*dest++ = col;
169  			}
170  		  }
171  		  dst +=8;
172  		}
173  
174  		// Border Right
175  		for (int x=0; x < bWidth; x++) {
176  		  *dst++ = cols[borcol];
177  		} 
178  		emu_DrawLine16(&linebuf[0], WIN_W, 1, raster);     
179  	}  
180  }
181    
182  void MOS6561::renderRow(uint16_t raster, uint16_t row, uint8_t rowHeight) 
183  {
184  	int curRow = row;
185  	int nbRow = REG_NB_ROWS;
186  
187  	//printf("rows %d of %d, cols=%d, rowHeight:%d\n", curRow, nbRow, nbCol, rowHeight);
188  
189  	if ( (rowHeight == 16) && (nbRow >= 23) ) {
190  		curRow = curRow/2;
191  		nbRow = nbRow/2;    
192  	}
193  
194  	if ((raster+curRow*rowHeight) < WIN_H) 
195  	{
196  		int nbCol = REG_NB_COLUMNS;
197  		int bWidth = (WIN_W - nbCol*8)/2;
198  		#define bakcol 0
199  		#define borcol 1
200  		#define forcol 2
201  		#define auxcol 3
202  		Pixel cols[4];
203  		uint16_t screenPage = (REG_SCRPAGE_HIGH & ~0x2000) + REG_SCRPAGE_LO;
204  		uint8_t * charPointer = &vicmemory[screenPage + (curRow * nbCol)];
205  		uint16_t colourPage = REG_COLPAGE_BASE + REG_COLPAGE_LO;
206  		uint8_t * colPointer = &vicmemory[colourPage + (curRow * nbCol)];
207  
208  		cols[borcol] = vicPalette[REG_BORDER_COLOUR];
209  		cols[bakcol] = vicPalette[REG_BACKGROUND_COLOUR];
210  
211  		for (int line=0; line < rowHeight; line++) {
212  			// Border Left
213  			Pixel *  dst = &linebuf[0];
214  			for (int x=0; x < bWidth; x++) {
215  			  *dst++ = cols[borcol];
216  			}
217  
218  			uint16_t chardefbase = remap[REG_CHRMAP_PT];
219  			for (int x = 0; x < nbCol; x +=1) 
220  			{
221  				uint16_t charpt = chardefbase + charPointer[x]*rowHeight + line;
222  				if ( (charpt > 0x2000) && (charpt < 0x3000) )
223  				  charpt += 0x6000;
224  			  uint8_t characterByte = vicmemory[charpt];
225  			  uint8_t colour = colPointer[x] & 0x7;
226  			  uint8_t multiColour = colPointer[x] & 0x8;
227  			  cols[forcol] = vicPalette[colour];	  
228  			  if (!multiColour) {
229  					Pixel * dest = dst;
230  					for (int a = 0; a < 8; a++) {
231  					  if ((characterByte << a) & 0x80) {
232  							*dest++ = cols[forcol];
233  					  }
234  					  else {
235  							*dest++ = cols[bakcol];
236  					  }
237  					}
238  			  }
239  			  else {
240  					Pixel * dest = dst;
241  					cols[auxcol] = vicPalette[REG_AUXILIARY_COLOUR];	  
242  					for (int a = 0; a < 8; a += 2) {
243  						// Set colour
244  						Pixel col = cols[((characterByte << a) & 0xC0) >> 6];
245  						*dest++ = col;
246  						*dest++ = col;
247  					}
248  			  }
249  			  dst +=8;
250  			}
251  
252  			// Border Right
253  			for (int x=0; x < bWidth; x++) {
254  			  *dst++ = cols[borcol];
255  			}
256  			emu_DrawLine16(&linebuf[0], WIN_W, 1, curRow*rowHeight+line+raster);      
257  		}
258  	}  
259  }
260  
261  
262  void MOS6561::renderFrame() {
263  	this->frameReady = false;
264  }
265  
266  bool MOS6561::isFrameReady() {
267  	return this->frameReady;
268  }
269  
270  
271  void MOS6561::tick(int nbcycles) {
272  	// Increment raster counter 
273  	uint16_t raster = readWord(REG_RASTER_HI_RD) << 1 | readWord(REG_RASTER_LO_RD) >> 7;
274  	if (cycles % cyclesPerScanline == 0) {
275  		uint8_t rowHeight = (REG_DOUBLE_HEIGHT?16:8);
276  		if (raster <= lastScanline) {
277  			raster += 1;
278  		}
279  		else {
280  			raster = 0;	
281  			visScanlines = REG_NB_ROWS * rowHeight;
282  			if ( (rowHeight == 16) && (REG_NB_ROWS >= 23) ) {
283  				visScanlines = REG_NB_ROWS * 8;
284  			}
285  			firstVisibleScanline = (WIN_H-visScanlines)/2;
286  		}
287  		writeWord(REG_RASTER_LO_RD, (raster & 0x1) << 7 | (readWord(REG_RASTER_LO_RD) & 0x7F));
288  		writeWord(REG_RASTER_HI_RD, raster >> 1);
289  	
290  		if (visScanlines) {
291  			if (raster < firstVisibleScanline) {
292  				renderBorder(raster);
293  			}
294  			// If not blanking, update screen
295  			else if (raster >= firstVisibleScanline && raster < (firstVisibleScanline+visScanlines)) {
296  				// Update video  
297  				uint8_t chrLine = (raster-firstVisibleScanline) % rowHeight;
298  				//renderLine(raster, this->curRow, rowHeight, chrLine);
299  				if (chrLine == rowHeight-1) {				
300  					renderRow(firstVisibleScanline, this->curRow, rowHeight);
301  					this->curRow++;
302  					// End of screen reached
303  					if (this->curRow >= REG_NB_ROWS) {
304  						this->curRow = 0;
305  						frameReady = true;
306  					}
307  				}
308  			}
309  			else {
310  				renderBorder(raster);
311  			}
312  		}
313  	}
314  
315  	// Increment cycle counter
316  	this->cycles += nbcycles;
317  }