MCUME/MCUME_pico/pico20/MOS6522.cpp

184 wiersze
4.8 KiB
C++

#include "MOS6522.h"
#include "MOS6502Memory.h"
MOS6522::MOS6522() : IC()
, keyPressed(0)
, shiftPressed(false)
, cbmPressed(false) {
// Set clock speed
this->setClockSpeed(2000000);
}
MOS6522::~MOS6522() {
}
void MOS6522::setCpu(mos6502 *omos6502) {
this->omos6502 = omos6502;
}
void MOS6522::setKeyPressed(uint16_t key) {
/* Store high byte first
= 0x9120 << 8 | 0x9121
*/
keyPressed = key;
}
void MOS6522::setShiftPressed(bool state) {
this->shiftPressed = state;
}
void MOS6522::setCbmPressed(bool state) {
this->cbmPressed = state;
}
void MOS6522::setJoyStickPressed(Vic20JoyStickButton button, bool state) {
this->joyStick[button] = state;
}
void MOS6522::initialize() {
// Clear joystick memory
writeWord(0x9111, 0xFF);
}
void MOS6522::tick() {
// Tick timer cycle
this->tickTimers();
// Handle input in this cycle
this->joy1Input();
this->joy2Input();
this->keyboardInput();
// Increment cycles counter
this->cycles += 1;
}
void MOS6522::joy1Input() {
// Handle joystick input on VIA1
uint8_t via1PortAValue = silentReadWord(via1PORTA);
via1PortAValue |= 0x3c;
if (joyStick[Vic20JoyStickButton::Fire]) {
via1PortAValue &= ~0x20;
}
if (joyStick[Vic20JoyStickButton::Up]) {
via1PortAValue &= ~0x04;
}
if (joyStick[Vic20JoyStickButton::Down]) {
via1PortAValue &= ~0x08;
}
if (joyStick[Vic20JoyStickButton::Left]) {
via1PortAValue &= ~0x10;
}
silentWriteWord(via1PORTA, via1PortAValue);
silentWriteWord(via1PORTAMIRROR, via1PortAValue);
}
void MOS6522::joy2Input() {
uint8_t via2PortBValue = silentReadWord(this->via2PORTB);
// If this bit is input, set it to default value, else leave it as it is so it won't mess up keyboard input
if (!(silentReadWord(via2PortBDDR) & 0x80)) {
via2PortBValue |= 0x80;
}
// Joystick RIGHT ison VIA 2
if (joyStick[Vic20JoyStickButton::Right]) {
via2PortBValue &= ~0x80;
}
silentWriteWord(via2PORTB, via2PortBValue);
}
void MOS6522::keyboardInput() {
uint8_t via2PortAValue = silentReadWord(this->via2PORTA);
uint8_t via2PortBValue = silentReadWord(this->via2PORTB);
// Get row and column of key press
uint8_t column = (keyPressed >> 8) & 0xFF; // output
uint8_t row = keyPressed & 0xFF; //input
// Check whether keyboard should be scanned
if (via2PortBValue == 0) {
// If port b is 0 then the vic is asking whether any keys are pressed on the keyboard
via2PortAValue = keyPressed == 0 ? 0xFF : row;
}
else {
// Return keyboard row depending on column state
via2PortAValue = (via2PortBValue == column ? (row == 0 ? 0xFF : row) : 0xFF);
}
if ((via2PortBValue == 0xF7) && shiftPressed) {
// Return row of shift key
via2PortAValue = 0xFD & (keyPressed == 0 ? 0xFF : (column == 0xF7 ? row : 0xFF));
} else if (via2PortBValue == 0xDF && cbmPressed) {
// Return row of cbm key
via2PortAValue = 0xFE & (keyPressed == 0 ? 0xFF : (column == 0xDF ? row : 0xFF));
}
silentWriteWord(this->via2PORTA, via2PortAValue);
silentWriteWord(this->via2PORTAMIRROR, via2PortAValue);
}
void MOS6522::tickTimers() {
// Grab values of timer related registers
uint8_t interruptEnable = readWord(this->irqEnableAddress);
uint8_t interruptFlags = readWord(this->irqFlagsAddress);
// Get timer values
uint16_t timer1 = silentReadDWord(this->via2timer1DAddress);
uint16_t timer2 = silentReadDWord(this->via1timer2DAddress);
// If timer1 is active, decrement it
if (timer1 > 0) {
silentWriteDWord(this->via2timer1DAddress, --timer1);
}
if (timer1 == 0) {
// Set interrupt flag
interruptFlags |= 0x40;
silentWriteWord(this->irqFlagsAddress, interruptFlags);
}
// If timer2 is active and no latch, decrement it
if (silentReadWord(this->via2timer2HighByteLatch) != 0) {
if (timer2 > 0) {
silentWriteDWord(this->via1timer2DAddress, --timer2);
}
if (timer2 == 0) {
// Reset high byte latch
silentWriteDWord(this->via1timer2DAddress, silentReadDWord(this->via2timer2LowByteLatch));
silentWriteDWord(this->via2timer2HighByteLatch, 0);
// Set interrupt flag
interruptFlags |= 0x20;
silentWriteWord(this->irqFlagsAddress, interruptFlags);
}
}
// Check if an interrupt request exists in the system
if (interruptFlags & interruptEnable & 0x7F) {
// Send an interrupt request to the cpu
//if (omos6502->interrupt()) {
if (omos6502->IRQ()) {
uint8_t auxControl = readWord(this->auxControlAddress);
// Post interrupt operation
if (interruptFlags & 0x40) {
// Determine what to do with timer based on auxiliary control register
if (auxControl & 0x40) {
// Continuous interrupt
silentWriteDWord(this->via2timer1DAddress, silentReadDWord(this->via2timer1LowByteLatch));
}
// Reset interrupt flag
interruptFlags &= ~0x40;
silentWriteWord(irqFlagsAddress, interruptFlags);
}
if (interruptFlags & 0x20) {
// Reset interrupt flag
interruptFlags &= ~0x20;
silentWriteWord(irqFlagsAddress, interruptFlags);
}
}
}
}