/ MCUME_teensy41 / teensy20 / MOS6522.cpp
MOS6522.cpp
  1  #include "MOS6522.h"
  2  #include "MOS6502Memory.h"
  3  
  4  MOS6522::MOS6522() : IC()
  5  					, keyPressed(0)
  6  					, shiftPressed(false)
  7  					, cbmPressed(false) {
  8  	// Set clock speed
  9  	this->setClockSpeed(2000000);
 10  }
 11  
 12  MOS6522::~MOS6522() {
 13  
 14  }
 15  
 16  
 17  void MOS6522::setCpu(mos6502 *omos6502) {
 18  	this->omos6502 = omos6502;
 19  }
 20  
 21  void MOS6522::setKeyPressed(uint16_t key) {
 22  	/* Store high byte first 
 23  		= 0x9120 << 8 | 0x9121
 24  	*/
 25  	keyPressed = key;
 26  }
 27  
 28  void MOS6522::setShiftPressed(bool state) {
 29  	this->shiftPressed = state;
 30  }
 31  
 32  void MOS6522::setCbmPressed(bool state) {
 33  	this->cbmPressed = state;
 34  }
 35  
 36  void MOS6522::setJoyStickPressed(Vic20JoyStickButton button, bool state) {
 37  	this->joyStick[button] = state;
 38  }
 39  
 40  void MOS6522::initialize() {
 41  	// Clear joystick memory
 42  	writeWord(0x9111, 0xFF);
 43  }
 44  
 45  void MOS6522::tick() {
 46  	// Tick timer cycle
 47  	this->tickTimers();
 48  
 49  	// Handle input in this cycle
 50  	this->joy1Input();
 51  	this->joy2Input();
 52  	this->keyboardInput();
 53  
 54  	// Increment cycles counter
 55  	this->cycles += 1;
 56  }
 57  
 58  
 59  void MOS6522::joy1Input() {
 60  	// Handle joystick input on VIA1
 61  	uint8_t via1PortAValue = silentReadWord(via1PORTA);
 62      via1PortAValue |= 0x3c;
 63  	if (joyStick[Vic20JoyStickButton::Fire]) {
 64  		via1PortAValue &= ~0x20;
 65  	}
 66  
 67  	if (joyStick[Vic20JoyStickButton::Up]) {
 68  		via1PortAValue &= ~0x04;
 69  	}
 70  
 71  	if (joyStick[Vic20JoyStickButton::Down]) {
 72  		via1PortAValue &= ~0x08;
 73  	}
 74  
 75  	if (joyStick[Vic20JoyStickButton::Left]) {
 76  		via1PortAValue &= ~0x10;
 77  	}
 78  	silentWriteWord(via1PORTA, via1PortAValue);
 79  	silentWriteWord(via1PORTAMIRROR, via1PortAValue);
 80  }
 81  
 82  void MOS6522::joy2Input() {
 83  	uint8_t via2PortBValue = silentReadWord(this->via2PORTB);	
 84  	// If this bit is input, set it to default value, else leave it as it is so it won't mess up keyboard input
 85  	if (!(silentReadWord(via2PortBDDR) & 0x80)) {
 86  		via2PortBValue |= 0x80;
 87  	}
 88  	// Joystick RIGHT ison VIA 2 
 89  	if (joyStick[Vic20JoyStickButton::Right]) {
 90  		via2PortBValue &= ~0x80;
 91  	}
 92  	silentWriteWord(via2PORTB, via2PortBValue);
 93  }
 94  
 95  void MOS6522::keyboardInput() {
 96  	uint8_t via2PortAValue = silentReadWord(this->via2PORTA);
 97  	uint8_t via2PortBValue = silentReadWord(this->via2PORTB);	
 98  
 99  	// Get row and column of key press
100  	uint8_t column = (keyPressed >> 8) & 0xFF; // output
101  	uint8_t row = keyPressed & 0xFF; //input
102  
103  	// Check whether keyboard should be scanned
104  	if (via2PortBValue == 0) {
105  		// If port b is 0 then the vic is asking whether any keys are pressed on the keyboard
106  		via2PortAValue = keyPressed == 0 ? 0xFF : row;
107  	}
108  	else {
109  		// Return keyboard row depending on column state
110  		via2PortAValue = (via2PortBValue == column ? (row == 0 ? 0xFF : row) : 0xFF);
111  	}
112  
113  	if ((via2PortBValue == 0xF7) && shiftPressed) {
114  		// Return row of shift key
115  		via2PortAValue = 0xFD & (keyPressed == 0 ? 0xFF : (column == 0xF7 ? row : 0xFF));
116  	} else if (via2PortBValue == 0xDF && cbmPressed) {
117  		// Return row of cbm key
118  		via2PortAValue = 0xFE & (keyPressed == 0 ? 0xFF : (column == 0xDF ? row : 0xFF));
119  	}
120  
121  	silentWriteWord(this->via2PORTA, via2PortAValue);
122  	silentWriteWord(this->via2PORTAMIRROR, via2PortAValue);	
123  }
124  
125  void MOS6522::tickTimers() {
126  	// Grab values of timer related registers
127  	uint8_t interruptEnable = readWord(this->irqEnableAddress);
128  	uint8_t interruptFlags = readWord(this->irqFlagsAddress);
129  
130  	// Get timer values
131  	uint16_t timer1 = silentReadDWord(this->via2timer1DAddress);
132  	uint16_t timer2 = silentReadDWord(this->via1timer2DAddress);
133  	// If timer1 is active, decrement it
134  	if (timer1 > 0) {
135  		silentWriteDWord(this->via2timer1DAddress, --timer1);
136  	}
137  	if (timer1 == 0) {
138  		// Set interrupt flag
139  		interruptFlags |= 0x40;
140  		silentWriteWord(this->irqFlagsAddress, interruptFlags);
141  	}
142  
143  	// If timer2 is active and no latch, decrement it
144  	if (silentReadWord(this->via2timer2HighByteLatch) != 0) {
145  		if (timer2 > 0) {
146  			silentWriteDWord(this->via1timer2DAddress, --timer2);
147  		}
148  		if (timer2 == 0) {
149  			// Reset high byte latch
150  			silentWriteDWord(this->via1timer2DAddress, silentReadDWord(this->via2timer2LowByteLatch));
151  			silentWriteDWord(this->via2timer2HighByteLatch, 0);
152  			// Set interrupt flag
153  			interruptFlags |= 0x20;
154  			silentWriteWord(this->irqFlagsAddress, interruptFlags);
155  		}
156  	}
157  
158  	// Check if an interrupt request exists in the system
159  	if (interruptFlags & interruptEnable & 0x7F) {
160  		// Send an interrupt request to the cpu
161  		//if (omos6502->interrupt()) {
162  		if (omos6502->IRQ()) {
163  			uint8_t auxControl = readWord(this->auxControlAddress);
164  			// Post interrupt operation
165  			if (interruptFlags & 0x40) {
166  				// Determine what to do with timer based on auxiliary control register
167  				if (auxControl & 0x40) {
168  					// Continuous interrupt
169  					silentWriteDWord(this->via2timer1DAddress, silentReadDWord(this->via2timer1LowByteLatch));
170  				}
171  				// Reset interrupt flag
172  				interruptFlags  &= ~0x40;
173  				silentWriteWord(irqFlagsAddress, interruptFlags);
174  			}
175  
176  			if (interruptFlags & 0x20) {
177  				// Reset interrupt flag
178  				interruptFlags  &= ~0x20;
179  				silentWriteWord(irqFlagsAddress, interruptFlags);
180  			}
181  		}
182  	}
183  }