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 }