minivmac4ios/Mini vMac/mnvm_core/VIAEMDEV.c
2019-05-03 21:21:30 +02:00

1225 lines
26 KiB
C

/*
VIAEMDEV.c
Copyright (C) 2008 Philip Cummins, Paul C. Pratt
You can redistribute this file and/or modify it under the terms
of version 2 of the GNU General Public License as published by
the Free Software Foundation. You should have received a copy
of the license along with this file; see the file COPYING.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
license for more details.
*/
/*
Versatile Interface Adapter EMulated DEVice
Emulates the VIA found in the Mac Plus.
This code adapted from vMac by Philip Cummins.
*/
#ifndef AllFiles
#include "SYSDEPNS.h"
#include "MYOSGLUE.h"
#include "EMCONFIG.h"
#include "GLOBGLUE.h"
#endif
#include "VIAEMDEV.h"
/*
ReportAbnormalID unused 0x0410 - 0x04FF
*/
#ifdef VIA1_iA0_ChangeNtfy
IMPORTPROC VIA1_iA0_ChangeNtfy(void);
#endif
#ifdef VIA1_iA1_ChangeNtfy
IMPORTPROC VIA1_iA1_ChangeNtfy(void);
#endif
#ifdef VIA1_iA2_ChangeNtfy
IMPORTPROC VIA1_iA2_ChangeNtfy(void);
#endif
#ifdef VIA1_iA3_ChangeNtfy
IMPORTPROC VIA1_iA3_ChangeNtfy(void);
#endif
#ifdef VIA1_iA4_ChangeNtfy
IMPORTPROC VIA1_iA4_ChangeNtfy(void);
#endif
#ifdef VIA1_iA5_ChangeNtfy
IMPORTPROC VIA1_iA5_ChangeNtfy(void);
#endif
#ifdef VIA1_iA6_ChangeNtfy
IMPORTPROC VIA1_iA6_ChangeNtfy(void);
#endif
#ifdef VIA1_iA7_ChangeNtfy
IMPORTPROC VIA1_iA7_ChangeNtfy(void);
#endif
#ifdef VIA1_iB0_ChangeNtfy
IMPORTPROC VIA1_iB0_ChangeNtfy(void);
#endif
#ifdef VIA1_iB1_ChangeNtfy
IMPORTPROC VIA1_iB1_ChangeNtfy(void);
#endif
#ifdef VIA1_iB2_ChangeNtfy
IMPORTPROC VIA1_iB2_ChangeNtfy(void);
#endif
#ifdef VIA1_iB3_ChangeNtfy
IMPORTPROC VIA1_iB3_ChangeNtfy(void);
#endif
#ifdef VIA1_iB4_ChangeNtfy
IMPORTPROC VIA1_iB4_ChangeNtfy(void);
#endif
#ifdef VIA1_iB5_ChangeNtfy
IMPORTPROC VIA1_iB5_ChangeNtfy(void);
#endif
#ifdef VIA1_iB6_ChangeNtfy
IMPORTPROC VIA1_iB6_ChangeNtfy(void);
#endif
#ifdef VIA1_iB7_ChangeNtfy
IMPORTPROC VIA1_iB7_ChangeNtfy(void);
#endif
#ifdef VIA1_iCB2_ChangeNtfy
IMPORTPROC VIA1_iCB2_ChangeNtfy(void);
#endif
#define Ui3rPowOf2(p) (1 << (p))
#define Ui3rTestBit(i, p) (((i) & Ui3rPowOf2(p)) != 0)
#define VIA1_ORA_CanInOrOut (VIA1_ORA_CanIn | VIA1_ORA_CanOut)
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 7)
#ifdef VIA1_iA7
#error "VIA1_iA7 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 6)
#ifdef VIA1_iA6
#error "VIA1_iA6 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 5)
#ifdef VIA1_iA5
#error "VIA1_iA5 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 4)
#ifdef VIA1_iA4
#error "VIA1_iA4 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 3)
#ifdef VIA1_iA3
#error "VIA1_iA3 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 2)
#ifdef VIA1_iA2
#error "VIA1_iA2 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 1)
#ifdef VIA1_iA1
#error "VIA1_iA1 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORA_CanInOrOut, 0)
#ifdef VIA1_iA0
#error "VIA1_iA0 defined but not used"
#endif
#endif
#define VIA1_ORB_CanInOrOut (VIA1_ORB_CanIn | VIA1_ORB_CanOut)
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 7)
#ifdef VIA1_iB7
#error "VIA1_iB7 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 6)
#ifdef VIA1_iB6
#error "VIA1_iB6 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 5)
#ifdef VIA1_iB5
#error "VIA1_iB5 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 4)
#ifdef VIA1_iB4
#error "VIA1_iB4 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 3)
#ifdef VIA1_iB3
#error "VIA1_iB3 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 2)
#ifdef VIA1_iB2
#error "VIA1_iB2 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 1)
#ifdef VIA1_iB1
#error "VIA1_iB1 defined but not used"
#endif
#endif
#if ! Ui3rTestBit(VIA1_ORB_CanInOrOut, 0)
#ifdef VIA1_iB0
#error "VIA1_iB0 defined but not used"
#endif
#endif
typedef struct {
ui5b T1C_F; /* Timer 1 Counter Fixed Point */
ui5b T2C_F; /* Timer 2 Counter Fixed Point */
ui3b ORB; /* Buffer B */
/* ui3b ORA_H; Buffer A with Handshake */
ui3b DDR_B; /* Data Direction Register B */
ui3b DDR_A; /* Data Direction Register A */
ui3b T1L_L; /* Timer 1 Latch Low */
ui3b T1L_H; /* Timer 1 Latch High */
ui3b T2L_L; /* Timer 2 Latch Low */
ui3b SR; /* Shift Register */
ui3b ACR; /* Auxiliary Control Register */
ui3b PCR; /* Peripheral Control Register */
ui3b IFR; /* Interrupt Flag Register */
ui3b IER; /* Interrupt Enable Register */
ui3b ORA; /* Buffer A */
} VIA1_Ty;
LOCALVAR VIA1_Ty VIA1_D;
#define kIntCA2 0 /* One_Second */
#define kIntCA1 1 /* Vertical_Blanking */
#define kIntSR 2 /* Keyboard_Data_Ready */
#define kIntCB2 3 /* Keyboard_Data */
#define kIntCB1 4 /* Keyboard_Clock */
#define kIntT2 5 /* Timer_2 */
#define kIntT1 6 /* Timer_1 */
#define VIA1_dolog (dbglog_HAVE && 0)
/* VIA1_Get_ORA : VIA Get Port A Data */
/*
This function queries VIA Port A interfaced hardware
about their status
*/
LOCALFUNC ui3b VIA1_Get_ORA(ui3b Selection)
{
ui3b Value = (~ VIA1_ORA_CanIn) & Selection & VIA1_ORA_FloatVal;
#if Ui3rTestBit(VIA1_ORA_CanIn, 7)
if (Ui3rTestBit(Selection, 7)) {
Value |= (VIA1_iA7 << 7);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 6)
if (Ui3rTestBit(Selection, 6)) {
Value |= (VIA1_iA6 << 6);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 5)
if (Ui3rTestBit(Selection, 5)) {
Value |= (VIA1_iA5 << 5);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 4)
if (Ui3rTestBit(Selection, 4)) {
Value |= (VIA1_iA4 << 4);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 3)
if (Ui3rTestBit(Selection, 3)) {
Value |= (VIA1_iA3 << 3);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 2)
if (Ui3rTestBit(Selection, 2)) {
Value |= (VIA1_iA2 << 2);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 1)
if (Ui3rTestBit(Selection, 1)) {
Value |= (VIA1_iA1 << 1);
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanIn, 0)
if (Ui3rTestBit(Selection, 0)) {
Value |= (VIA1_iA0 << 0);
}
#endif
return Value;
}
/* VIA1_Get_ORB : VIA Get Port B Data */
/*
This function queries VIA Port B interfaced hardware
about their status
*/
LOCALFUNC ui3b VIA1_Get_ORB(ui3b Selection)
{
ui3b Value = (~ VIA1_ORB_CanIn) & Selection & VIA1_ORB_FloatVal;
#if Ui3rTestBit(VIA1_ORB_CanIn, 7)
if (Ui3rTestBit(Selection, 7)) {
Value |= (VIA1_iB7 << 7);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 6)
if (Ui3rTestBit(Selection, 6)) {
Value |= (VIA1_iB6 << 6);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 5)
if (Ui3rTestBit(Selection, 5)) {
Value |= (VIA1_iB5 << 5);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 4)
if (Ui3rTestBit(Selection, 4)) {
Value |= (VIA1_iB4 << 4);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 3)
if (Ui3rTestBit(Selection, 3)) {
Value |= (VIA1_iB3 << 3);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 2)
if (Ui3rTestBit(Selection, 2)) {
Value |= (VIA1_iB2 << 2);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 1)
if (Ui3rTestBit(Selection, 1)) {
Value |= (VIA1_iB1 << 1);
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanIn, 0)
if (Ui3rTestBit(Selection, 0)) {
Value |= (VIA1_iB0 << 0);
}
#endif
return Value;
}
#define ViaORcheckBit(p, x) \
(Ui3rTestBit(Selection, p) && \
((v = (Data >> p) & 1) != x))
LOCALPROC VIA1_Put_ORA(ui3b Selection, ui3b Data)
{
#if 0 != VIA1_ORA_CanOut
ui3b v;
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 7)
if (ViaORcheckBit(7, VIA1_iA7)) {
VIA1_iA7 = v;
#ifdef VIA1_iA7_ChangeNtfy
VIA1_iA7_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 6)
if (ViaORcheckBit(6, VIA1_iA6)) {
VIA1_iA6 = v;
#ifdef VIA1_iA6_ChangeNtfy
VIA1_iA6_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 5)
if (ViaORcheckBit(5, VIA1_iA5)) {
VIA1_iA5 = v;
#ifdef VIA1_iA5_ChangeNtfy
VIA1_iA5_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 4)
if (ViaORcheckBit(4, VIA1_iA4)) {
VIA1_iA4 = v;
#ifdef VIA1_iA4_ChangeNtfy
VIA1_iA4_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 3)
if (ViaORcheckBit(3, VIA1_iA3)) {
VIA1_iA3 = v;
#ifdef VIA1_iA3_ChangeNtfy
VIA1_iA3_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 2)
if (ViaORcheckBit(2, VIA1_iA2)) {
VIA1_iA2 = v;
#ifdef VIA1_iA2_ChangeNtfy
VIA1_iA2_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 1)
if (ViaORcheckBit(1, VIA1_iA1)) {
VIA1_iA1 = v;
#ifdef VIA1_iA1_ChangeNtfy
VIA1_iA1_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORA_CanOut, 0)
if (ViaORcheckBit(0, VIA1_iA0)) {
VIA1_iA0 = v;
#ifdef VIA1_iA0_ChangeNtfy
VIA1_iA0_ChangeNtfy();
#endif
}
#endif
}
LOCALPROC VIA1_Put_ORB(ui3b Selection, ui3b Data)
{
#if 0 != VIA1_ORB_CanOut
ui3b v;
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 7)
if (ViaORcheckBit(7, VIA1_iB7)) {
VIA1_iB7 = v;
#ifdef VIA1_iB7_ChangeNtfy
VIA1_iB7_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 6)
if (ViaORcheckBit(6, VIA1_iB6)) {
VIA1_iB6 = v;
#ifdef VIA1_iB6_ChangeNtfy
VIA1_iB6_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 5)
if (ViaORcheckBit(5, VIA1_iB5)) {
VIA1_iB5 = v;
#ifdef VIA1_iB5_ChangeNtfy
VIA1_iB5_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 4)
if (ViaORcheckBit(4, VIA1_iB4)) {
VIA1_iB4 = v;
#ifdef VIA1_iB4_ChangeNtfy
VIA1_iB4_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 3)
if (ViaORcheckBit(3, VIA1_iB3)) {
VIA1_iB3 = v;
#ifdef VIA1_iB3_ChangeNtfy
VIA1_iB3_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 2)
if (ViaORcheckBit(2, VIA1_iB2)) {
VIA1_iB2 = v;
#ifdef VIA1_iB2_ChangeNtfy
VIA1_iB2_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 1)
if (ViaORcheckBit(1, VIA1_iB1)) {
VIA1_iB1 = v;
#ifdef VIA1_iB1_ChangeNtfy
VIA1_iB1_ChangeNtfy();
#endif
}
#endif
#if Ui3rTestBit(VIA1_ORB_CanOut, 0)
if (ViaORcheckBit(0, VIA1_iB0)) {
VIA1_iB0 = v;
#ifdef VIA1_iB0_ChangeNtfy
VIA1_iB0_ChangeNtfy();
#endif
}
#endif
}
LOCALPROC VIA1_SetDDR_A(ui3b Data)
{
ui3b floatbits = VIA1_D.DDR_A & ~ Data;
ui3b unfloatbits = Data & ~ VIA1_D.DDR_A;
if (floatbits != 0) {
VIA1_Put_ORA(floatbits, VIA1_ORA_FloatVal);
}
VIA1_D.DDR_A = Data;
if (unfloatbits != 0) {
VIA1_Put_ORA(unfloatbits, VIA1_D.ORA);
}
if ((Data & ~ VIA1_ORA_CanOut) != 0) {
ReportAbnormalID(0x0401,
"Set VIA1_D.DDR_A unexpected direction");
}
}
LOCALPROC VIA1_SetDDR_B(ui3b Data)
{
ui3b floatbits = VIA1_D.DDR_B & ~ Data;
ui3b unfloatbits = Data & ~ VIA1_D.DDR_B;
if (floatbits != 0) {
VIA1_Put_ORB(floatbits, VIA1_ORB_FloatVal);
}
VIA1_D.DDR_B = Data;
if (unfloatbits != 0) {
VIA1_Put_ORB(unfloatbits, VIA1_D.ORB);
}
if ((Data & ~ VIA1_ORB_CanOut) != 0) {
ReportAbnormalID(0x0402,
"Set VIA1_D.DDR_B unexpected direction");
}
}
LOCALPROC VIA1_CheckInterruptFlag(void)
{
ui3b NewInterruptRequest =
((VIA1_D.IFR & VIA1_D.IER) != 0) ? 1 : 0;
if (NewInterruptRequest != VIA1_InterruptRequest) {
VIA1_InterruptRequest = NewInterruptRequest;
#ifdef VIA1_interruptChngNtfy
VIA1_interruptChngNtfy();
#endif
}
}
LOCALVAR ui3b VIA1_T1_Active = 0;
LOCALVAR ui3b VIA1_T2_Active = 0;
LOCALVAR blnr VIA1_T1IntReady = falseblnr;
LOCALPROC VIA1_Clear(void)
{
VIA1_D.ORA = 0; VIA1_D.DDR_A = 0;
VIA1_D.ORB = 0; VIA1_D.DDR_B = 0;
VIA1_D.T1L_L = VIA1_D.T1L_H = 0x00;
VIA1_D.T2L_L = 0x00;
VIA1_D.T1C_F = 0;
VIA1_D.T2C_F = 0;
VIA1_D.SR = VIA1_D.ACR = 0x00;
VIA1_D.PCR = VIA1_D.IFR = VIA1_D.IER = 0x00;
VIA1_T1_Active = VIA1_T2_Active = 0x00;
VIA1_T1IntReady = falseblnr;
}
GLOBALPROC VIA1_Zap(void)
{
VIA1_Clear();
VIA1_InterruptRequest = 0;
}
GLOBALPROC VIA1_Reset(void)
{
VIA1_SetDDR_A(0);
VIA1_SetDDR_B(0);
VIA1_Clear();
VIA1_CheckInterruptFlag();
}
LOCALPROC VIA1_SetInterruptFlag(ui3b VIA_Int)
{
VIA1_D.IFR |= ((ui3b)1 << VIA_Int);
VIA1_CheckInterruptFlag();
}
LOCALPROC VIA1_ClrInterruptFlag(ui3b VIA_Int)
{
VIA1_D.IFR &= ~ ((ui3b)1 << VIA_Int);
VIA1_CheckInterruptFlag();
}
#ifdef _VIA_Debug
#include <stdio.h>
#endif
GLOBALPROC VIA1_ShiftInData(ui3b v)
{
/*
external hardware generates 8 pulses on CB1,
writes 8 bits to CB2
*/
ui3b ShiftMode = (VIA1_D.ACR & 0x1C) >> 2;
if (ShiftMode != 3) {
#if ExtraAbnormalReports
if (ShiftMode == 0) {
/* happens on reset */
} else {
ReportAbnormalID(0x0403, "VIA Not ready to shift in");
/*
Observed (rarely) in Crystal Quest played
at 1x speed in "-t mc64".
*/
}
#endif
} else {
VIA1_D.SR = v;
VIA1_SetInterruptFlag(kIntSR);
VIA1_SetInterruptFlag(kIntCB1);
}
}
GLOBALFUNC ui3b VIA1_ShiftOutData(void)
{
/*
external hardware generates 8 pulses on CB1,
reads 8 bits from CB2
*/
if (((VIA1_D.ACR & 0x1C) >> 2) != 7) {
ReportAbnormalID(0x0404, "VIA Not ready to shift out");
return 0;
} else {
VIA1_SetInterruptFlag(kIntSR);
VIA1_SetInterruptFlag(kIntCB1);
VIA1_iCB2 = (VIA1_D.SR & 1);
return VIA1_D.SR;
}
}
#define CyclesPerViaTime (10 * kMyClockMult)
#define CyclesScaledPerViaTime (kCycleScale * CyclesPerViaTime)
LOCALVAR blnr VIA1_T1Running = trueblnr;
LOCALVAR iCountt VIA1_T1LastTime = 0;
GLOBALPROC VIA1_DoTimer1Check(void)
{
if (VIA1_T1Running) {
iCountt NewTime = GetCuriCount();
iCountt deltaTime = (NewTime - VIA1_T1LastTime);
if (deltaTime != 0) {
ui5b Temp = VIA1_D.T1C_F; /* Get Timer 1 Counter */
ui5b deltaTemp =
(deltaTime / CyclesPerViaTime) << (16 - kLn2CycleScale);
/* may overflow */
ui5b NewTemp = Temp - deltaTemp;
if ((deltaTime > (0x00010000UL * CyclesScaledPerViaTime))
|| ((Temp <= deltaTemp) && (Temp != 0)))
{
if ((VIA1_D.ACR & 0x40) != 0) { /* Free Running? */
/* Reload Counter from Latches */
ui4b v = (VIA1_D.T1L_H << 8) + VIA1_D.T1L_L;
ui4b ntrans = 1 + ((v == 0) ? 0 :
(((deltaTemp - Temp) / v) >> 16));
NewTemp += (((ui5b)v * ntrans) << 16);
#if Ui3rTestBit(VIA1_ORB_CanOut, 7)
if ((VIA1_D.ACR & 0x80) != 0) { /* invert ? */
if ((ntrans & 1) != 0) {
VIA1_iB7 ^= 1;
#ifdef VIA1_iB7_ChangeNtfy
VIA1_iB7_ChangeNtfy();
#endif
}
}
#endif
VIA1_SetInterruptFlag(kIntT1);
#if VIA1_dolog && 1
dbglog_WriteNote("VIA1 Timer 1 Interrupt");
#endif
} else {
if (VIA1_T1_Active == 1) {
VIA1_T1_Active = 0;
VIA1_SetInterruptFlag(kIntT1);
#if VIA1_dolog && 1
dbglog_WriteNote("VIA1 Timer 1 Interrupt");
#endif
}
}
}
VIA1_D.T1C_F = NewTemp;
VIA1_T1LastTime = NewTime;
}
VIA1_T1IntReady = falseblnr;
if ((VIA1_D.IFR & (1 << kIntT1)) == 0) {
if (((VIA1_D.ACR & 0x40) != 0) || (VIA1_T1_Active == 1)) {
ui5b NewTemp = VIA1_D.T1C_F; /* Get Timer 1 Counter */
ui5b NewTimer;
#ifdef _VIA_Debug
fprintf(stderr, "posting Timer1Check, %d, %d\n",
Temp, GetCuriCount());
#endif
if (NewTemp == 0) {
NewTimer = (0x00010000UL * CyclesScaledPerViaTime);
} else {
NewTimer =
(1 + (NewTemp >> (16 - kLn2CycleScale)))
* CyclesPerViaTime;
}
ICT_add(kICT_VIA1_Timer1Check, NewTimer);
VIA1_T1IntReady = trueblnr;
}
}
}
}
LOCALPROC CheckT1IntReady(void)
{
if (VIA1_T1Running) {
blnr NewT1IntReady = falseblnr;
if ((VIA1_D.IFR & (1 << kIntT1)) == 0) {
if (((VIA1_D.ACR & 0x40) != 0) || (VIA1_T1_Active == 1)) {
NewT1IntReady = trueblnr;
}
}
if (VIA1_T1IntReady != NewT1IntReady) {
VIA1_T1IntReady = NewT1IntReady;
if (NewT1IntReady) {
VIA1_DoTimer1Check();
}
}
}
}
GLOBALFUNC ui4b VIA1_GetT1InvertTime(void)
{
ui4b v;
if ((VIA1_D.ACR & 0xC0) == 0xC0) {
v = (VIA1_D.T1L_H << 8) + VIA1_D.T1L_L;
} else {
v = 0;
}
return v;
}
LOCALVAR blnr VIA1_T2Running = trueblnr;
LOCALVAR blnr VIA1_T2C_ShortTime = falseblnr;
LOCALVAR iCountt VIA1_T2LastTime = 0;
GLOBALPROC VIA1_DoTimer2Check(void)
{
if (VIA1_T2Running) {
iCountt NewTime = GetCuriCount();
ui5b Temp = VIA1_D.T2C_F; /* Get Timer 2 Counter */
iCountt deltaTime = (NewTime - VIA1_T2LastTime);
ui5b deltaTemp = (deltaTime / CyclesPerViaTime)
<< (16 - kLn2CycleScale); /* may overflow */
ui5b NewTemp = Temp - deltaTemp;
if (VIA1_T2_Active == 1) {
if ((deltaTime > (0x00010000UL * CyclesScaledPerViaTime))
|| ((Temp <= deltaTemp) && (Temp != 0)))
{
VIA1_T2C_ShortTime = falseblnr;
VIA1_T2_Active = 0;
VIA1_SetInterruptFlag(kIntT2);
#if VIA1_dolog && 1
dbglog_WriteNote("VIA1 Timer 2 Interrupt");
#endif
} else {
ui5b NewTimer;
#ifdef _VIA_Debug
fprintf(stderr, "posting Timer2Check, %d, %d\n",
Temp, GetCuriCount());
#endif
if (NewTemp == 0) {
NewTimer = (0x00010000UL * CyclesScaledPerViaTime);
} else {
NewTimer = (1 + (NewTemp >> (16 - kLn2CycleScale)))
* CyclesPerViaTime;
}
ICT_add(kICT_VIA1_Timer2Check, NewTimer);
}
}
VIA1_D.T2C_F = NewTemp;
VIA1_T2LastTime = NewTime;
}
}
#define kORB 0x00
#define kORA_H 0x01
#define kDDR_B 0x02
#define kDDR_A 0x03
#define kT1C_L 0x04
#define kT1C_H 0x05
#define kT1L_L 0x06
#define kT1L_H 0x07
#define kT2_L 0x08
#define kT2_H 0x09
#define kSR 0x0A
#define kACR 0x0B
#define kPCR 0x0C
#define kIFR 0x0D
#define kIER 0x0E
#define kORA 0x0F
GLOBALFUNC ui5b VIA1_Access(ui5b Data, blnr WriteMem, CPTR addr)
{
switch (addr) {
case kORB :
#if VIA1_CB2modesAllowed != 0x01
if ((VIA1_D.PCR & 0xE0) == 0)
#endif
{
VIA1_ClrInterruptFlag(kIntCB2);
}
VIA1_ClrInterruptFlag(kIntCB1);
if (WriteMem) {
VIA1_D.ORB = Data;
VIA1_Put_ORB(VIA1_D.DDR_B, VIA1_D.ORB);
} else {
Data = (VIA1_D.ORB & VIA1_D.DDR_B)
| VIA1_Get_ORB(~ VIA1_D.DDR_B);
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kORB", Data, WriteMem);
#endif
break;
case kDDR_B :
if (WriteMem) {
VIA1_SetDDR_B(Data);
} else {
Data = VIA1_D.DDR_B;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kDDR_B", Data, WriteMem);
#endif
break;
case kDDR_A :
if (WriteMem) {
VIA1_SetDDR_A(Data);
} else {
Data = VIA1_D.DDR_A;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kDDR_A", Data, WriteMem);
#endif
break;
case kT1C_L :
if (WriteMem) {
VIA1_D.T1L_L = Data;
} else {
VIA1_ClrInterruptFlag(kIntT1);
VIA1_DoTimer1Check();
Data = (VIA1_D.T1C_F & 0x00FF0000) >> 16;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kT1C_L", Data, WriteMem);
#endif
break;
case kT1C_H :
if (WriteMem) {
VIA1_D.T1L_H = Data;
VIA1_ClrInterruptFlag(kIntT1);
VIA1_D.T1C_F = (Data << 24) + (VIA1_D.T1L_L << 16);
if ((VIA1_D.ACR & 0x40) == 0) {
VIA1_T1_Active = 1;
}
VIA1_T1LastTime = GetCuriCount();
VIA1_DoTimer1Check();
} else {
VIA1_DoTimer1Check();
Data = (VIA1_D.T1C_F & 0xFF000000) >> 24;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kT1C_H", Data, WriteMem);
#endif
break;
case kT1L_L :
if (WriteMem) {
VIA1_D.T1L_L = Data;
} else {
Data = VIA1_D.T1L_L;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kT1L_L", Data, WriteMem);
#endif
break;
case kT1L_H :
if (WriteMem) {
VIA1_D.T1L_H = Data;
} else {
Data = VIA1_D.T1L_H;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kT1L_H", Data, WriteMem);
#endif
break;
case kT2_L :
if (WriteMem) {
VIA1_D.T2L_L = Data;
} else {
VIA1_ClrInterruptFlag(kIntT2);
VIA1_DoTimer2Check();
Data = (VIA1_D.T2C_F & 0x00FF0000) >> 16;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kT2_L", Data, WriteMem);
#endif
break;
case kT2_H :
if (WriteMem) {
VIA1_D.T2C_F = (Data << 24) + (VIA1_D.T2L_L << 16);
VIA1_ClrInterruptFlag(kIntT2);
VIA1_T2_Active = 1;
if ((VIA1_D.T2C_F < (128UL << 16))
&& (VIA1_D.T2C_F != 0))
{
VIA1_T2C_ShortTime = trueblnr;
VIA1_T2Running = trueblnr;
/*
Running too many instructions during
a short timer interval can crash when
playing sounds in System 7. So
in this case don't let timer pause.
*/
}
VIA1_T2LastTime = GetCuriCount();
VIA1_DoTimer2Check();
} else {
VIA1_DoTimer2Check();
Data = (VIA1_D.T2C_F & 0xFF000000) >> 24;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kT2_H", Data, WriteMem);
#endif
break;
case kSR:
#ifdef _VIA_Debug
fprintf(stderr, "VIA1_D.SR: %d, %d, %d\n",
WriteMem, ((VIA1_D.ACR & 0x1C) >> 2), Data);
#endif
if (WriteMem) {
VIA1_D.SR = Data;
}
VIA1_ClrInterruptFlag(kIntSR);
switch ((VIA1_D.ACR & 0x1C) >> 2) {
case 3 : /* Shifting In */
break;
case 6 : /* shift out under o2 clock */
if ((! WriteMem) || (VIA1_D.SR != 0)) {
ReportAbnormalID(0x0405,
"VIA shift mode 6, non zero");
} else {
#ifdef _VIA_Debug
fprintf(stderr, "posting Foo2Task\n");
#endif
if (VIA1_iCB2 != 0) {
VIA1_iCB2 = 0;
#ifdef VIA1_iCB2_ChangeNtfy
VIA1_iCB2_ChangeNtfy();
#endif
}
}
#if 0 /* possibly should do this. seems not to affect anything. */
VIA1_SetInterruptFlag(kIntSR); /* don't wait */
#endif
break;
case 7 : /* Shifting Out */
break;
}
if (! WriteMem) {
Data = VIA1_D.SR;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kSR", Data, WriteMem);
#endif
break;
case kACR:
if (WriteMem) {
#if 1
if ((VIA1_D.ACR & 0x10) != ((ui3b)Data & 0x10)) {
/* shift direction has changed */
if ((Data & 0x10) == 0) {
/*
no longer an output,
set data to float value
*/
if (VIA1_iCB2 == 0) {
VIA1_iCB2 = 1;
#ifdef VIA1_iCB2_ChangeNtfy
VIA1_iCB2_ChangeNtfy();
#endif
}
}
}
#endif
VIA1_D.ACR = Data;
if ((VIA1_D.ACR & 0x20) != 0) {
/* Not pulse counting? */
ReportAbnormalID(0x0406,
"Set VIA1_D.ACR T2 Timer pulse counting");
}
switch ((VIA1_D.ACR & 0xC0) >> 6) {
/* case 1: happens in early System 6 */
case 2:
ReportAbnormalID(0x0407,
"Set VIA1_D.ACR T1 Timer mode 2");
break;
}
CheckT1IntReady();
switch ((VIA1_D.ACR & 0x1C) >> 2) {
case 0: /* this isn't sufficient */
VIA1_ClrInterruptFlag(kIntSR);
break;
case 1:
case 2:
case 4:
case 5:
ReportAbnormalID(0x0408,
"Set VIA1_D.ACR shift mode 1,2,4,5");
break;
default:
break;
}
if ((VIA1_D.ACR & 0x03) != 0) {
ReportAbnormalID(0x0409,
"Set VIA1_D.ACR T2 Timer latching enabled");
}
} else {
Data = VIA1_D.ACR;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kACR", Data, WriteMem);
#endif
break;
case kPCR:
if (WriteMem) {
VIA1_D.PCR = Data;
#define Ui3rSetContains(s, i) (((s) & (1 << (i))) != 0)
if (! Ui3rSetContains(VIA1_CB2modesAllowed,
(VIA1_D.PCR >> 5) & 0x07))
{
ReportAbnormalID(0x040A,
"Set VIA1_D.PCR CB2 Control mode?");
}
if ((VIA1_D.PCR & 0x10) != 0) {
ReportAbnormalID(0x040B,
"Set VIA1_D.PCR CB1 INTERRUPT CONTROL?");
}
if (! Ui3rSetContains(VIA1_CA2modesAllowed,
(VIA1_D.PCR >> 1) & 0x07))
{
ReportAbnormalID(0x040C,
"Set VIA1_D.PCR CA2 INTERRUPT CONTROL?");
}
if ((VIA1_D.PCR & 0x01) != 0) {
ReportAbnormalID(0x040D,
"Set VIA1_D.PCR CA1 INTERRUPT CONTROL?");
}
} else {
Data = VIA1_D.PCR;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kPCR", Data, WriteMem);
#endif
break;
case kIFR:
if (WriteMem) {
VIA1_D.IFR = VIA1_D.IFR & ((~ Data) & 0x7F);
/* Clear Flag Bits */
VIA1_CheckInterruptFlag();
CheckT1IntReady();
} else {
Data = VIA1_D.IFR;
if ((VIA1_D.IFR & VIA1_D.IER) != 0) {
Data |= 0x80;
}
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kIFR", Data, WriteMem);
#endif
break;
case kIER :
if (WriteMem) {
if ((Data & 0x80) == 0) {
VIA1_D.IER = VIA1_D.IER & ((~ Data) & 0x7F);
/* Clear Enable Bits */
#if 0 != VIA1_IER_Never0
/*
of course, will be 0 initially,
this just checks not cleared later.
*/
if ((Data & VIA1_IER_Never0) != 0) {
ReportAbnormalID(0x040E, "IER Never0 clr");
}
#endif
} else {
VIA1_D.IER = VIA1_D.IER | (Data & 0x7F);
/* Set Enable Bits */
#if 0 != VIA1_IER_Never1
if ((VIA1_D.IER & VIA1_IER_Never1) != 0) {
ReportAbnormalID(0x040F, "IER Never1 set");
}
#endif
}
VIA1_CheckInterruptFlag();
} else {
Data = VIA1_D.IER | 0x80;
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kIER", Data, WriteMem);
#endif
break;
case kORA :
case kORA_H :
if ((VIA1_D.PCR & 0xE) == 0) {
VIA1_ClrInterruptFlag(kIntCA2);
}
VIA1_ClrInterruptFlag(kIntCA1);
if (WriteMem) {
VIA1_D.ORA = Data;
VIA1_Put_ORA(VIA1_D.DDR_A, VIA1_D.ORA);
} else {
Data = (VIA1_D.ORA & VIA1_D.DDR_A)
| VIA1_Get_ORA(~ VIA1_D.DDR_A);
}
#if VIA1_dolog && 1
dbglog_Access("VIA1_Access kORA", Data, WriteMem);
#endif
break;
}
return Data;
}
GLOBALPROC VIA1_ExtraTimeBegin(void)
{
if (VIA1_T1Running) {
VIA1_DoTimer1Check(); /* run up to this moment */
VIA1_T1Running = falseblnr;
}
if (VIA1_T2Running & (! VIA1_T2C_ShortTime)) {
VIA1_DoTimer2Check(); /* run up to this moment */
VIA1_T2Running = falseblnr;
}
}
GLOBALPROC VIA1_ExtraTimeEnd(void)
{
if (! VIA1_T1Running) {
VIA1_T1Running = trueblnr;
VIA1_T1LastTime = GetCuriCount();
VIA1_DoTimer1Check();
}
if (! VIA1_T2Running) {
VIA1_T2Running = trueblnr;
VIA1_T2LastTime = GetCuriCount();
VIA1_DoTimer2Check();
}
}
/* VIA Interrupt Interface */
#ifdef VIA1_iCA1_PulseNtfy
GLOBALPROC VIA1_iCA1_PulseNtfy(void)
{
VIA1_SetInterruptFlag(kIntCA1);
}
#endif
#ifdef VIA1_iCA2_PulseNtfy
GLOBALPROC VIA1_iCA2_PulseNtfy(void)
{
VIA1_SetInterruptFlag(kIntCA2);
}
#endif
#ifdef VIA1_iCB1_PulseNtfy
GLOBALPROC VIA1_iCB1_PulseNtfy(void)
{
VIA1_SetInterruptFlag(kIntCB1);
}
#endif
#ifdef VIA1_iCB2_PulseNtfy
GLOBALPROC VIA1_iCB2_PulseNtfy(void)
{
VIA1_SetInterruptFlag(kIntCB2);
}
#endif