mirror of
https://github.com/InvisibleUp/uvmac.git
synced 2025-03-29 06:33:36 +00:00
WIP: Replace VIAEMDEV.c with rewrite
This commit is contained in:
parent
4264ff2de5
commit
02b8c9c721
300
_work/VIAEMDEV.c
300
_work/VIAEMDEV.c
@ -1,300 +0,0 @@
|
||||
/*
|
||||
VIAEMDEV.c
|
||||
|
||||
Copyright (C) 2020 InvisibleUp
|
||||
|
||||
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 Synertek SY6522 VIA found up until the Mac Plus.
|
||||
This code rewritten for target-independance and non-enum based config
|
||||
|
||||
The VIA1 contains the following functionality:
|
||||
- Two timers (1 and 2)
|
||||
- Serial-to-parallel / parallel-to-serial bi-directional shift register
|
||||
- Two 8-bit bi-directional ports (A and B)
|
||||
- Ports are per-line settable to input or output
|
||||
- Square wave generation
|
||||
- Pulse counting
|
||||
|
||||
The M68000 addresses the VIA simply via an interrupt line and a pair of
|
||||
registers, much like any other peripheal
|
||||
|
||||
Because just about everything on the Mac is attached to a VIA, it's
|
||||
important to track what device is mapped to what line on what port.
|
||||
|
||||
Summary of SY6522 pins:
|
||||
1. Phase 2 Clock (Φ2)
|
||||
Must be high for data transfer from M68k to occur
|
||||
Time base for timers, shift registers, etc.
|
||||
2. Chip select (CS1, ¬CS2)
|
||||
is a chip select line
|
||||
3. Register Select (RS0, RS1, RS2, RS3)
|
||||
Name Write Read
|
||||
0000 - ORB, IRB Port B output Port B input
|
||||
0001 - ORA, IRA Port A output Port A input
|
||||
0010 - DDRB Data Direction, port B
|
||||
0011 - DDRA Data Direction, port A
|
||||
0100 - T1L-L T1 Low-Order Latches T1 Low-Order Counter
|
||||
0101 - T1C-H T1 High-Order Counter
|
||||
0110 - T1L-L T1 Low-Order Latches
|
||||
0111 - T1L-H T1 High-Order Latches
|
||||
1000 - T2C-L T2 Low-Order Latches T2 Low-Order Counter
|
||||
1001 - T2C-H T2 High-Order Counter
|
||||
1010 - SR Shift Register
|
||||
1011 - ACR Auxillary Control Register
|
||||
1100 - PCR Peripheal Control Register
|
||||
1101 - IFR Interrupt flag
|
||||
1110 - IER Interrupt enable
|
||||
1111 - ORA Same as 0001 but no effect on handshake
|
||||
4. Read/Write line
|
||||
If low, write (processor to VIA register)
|
||||
If high, read (VIA register to processor)
|
||||
5. Data Bus (DB0-7)
|
||||
Transfers data between VIA and M68l
|
||||
6. Reset
|
||||
Clears all registers to 0.
|
||||
All I/O set to input, disablse timers, SR, interrupts, etc.
|
||||
7. IRQ
|
||||
8. Peripheal A Port (PA0 - PA7)
|
||||
8 lines. Each can be input or output, depending on value of DDRA
|
||||
9. Port A Control Lines (CA1/CA2)
|
||||
Interrupt inputs or handshake outputs
|
||||
Each line controls an internal interrupt flag w/ enable bit
|
||||
CA1 controls latching of data on P1 input
|
||||
10. Peripheal Port B (PB0 - PB7)
|
||||
Same as Port A, with timers!
|
||||
PB7 polarity can be controller by timer
|
||||
PB6 can count pulses w/ second timer
|
||||
11. Port B control lines (CB1/CB2)
|
||||
Same as CA
|
||||
Shift register serial I/O goes through one of these
|
||||
|
||||
I'm not going to bother to emulate handshaking
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "VIAEMDEV.h"
|
||||
|
||||
/* Global state */
|
||||
|
||||
typedef struct {
|
||||
uint8_t PortA_data; // Port A data
|
||||
uint8_t PortA_dir; // Direction of Port A bits (0 = in, 1 = out)
|
||||
uint8_t PortB_data; // Port A data
|
||||
uint8_t PortB_dir; // Direction of Port B bits (0 = in, 1 = out)
|
||||
uint8_t SR; // current shift register state
|
||||
uint16_t T1_C; // timer 1 count
|
||||
uint16_t T1_L; // timer 1 latches
|
||||
uint16_t T2_C; // timer 2 count
|
||||
uint16_t T2_L; // timer 2 latches
|
||||
|
||||
uint8_t AUX_T1; // Aux - Timer 1 Control (0-3)
|
||||
uint8_t AUX_T2; // Aux - Timer 2 Control (0-1)
|
||||
uint8_t AUX_SR; // Aux - SR Control (0-7)
|
||||
bool AUX_PALE; // Aux - Port A Latch Enable (0-1)
|
||||
bool AUX_PBLE; // Aux - Port B Latch Enable (0-1)
|
||||
|
||||
uint8_t PC_CB2; // Perip. - CB2 Control
|
||||
uint8_t PC_CB1; // Perip. - CB1 Edge Polarity (0 = -, 1 = +)
|
||||
uint8_t PC_CA2; // Perip. - CA2 Control
|
||||
uint8_t PC_CA1; // Perip. - CA1 Edge Polarity (0 = -, 1 = +)
|
||||
|
||||
uint8_t IF; // Interrupt Flags
|
||||
uint8_t IE; // Interrupt Enable
|
||||
} VIA1_State_t;
|
||||
|
||||
VIA1_State_t VIA1_State = {0};
|
||||
|
||||
/*
|
||||
For reference: Mac 128/512k port allocations:
|
||||
PA7 (I ) SCC ready for read
|
||||
PA6 ( O) Alt. screen buffer in use?
|
||||
PA5 ( O) Disk SEL line
|
||||
PA4 ( O) ROM low-mem overlay
|
||||
PA3 ( O) Alt. sound buffer
|
||||
PA0-2 ( O) Sound volume
|
||||
PB7 ( O) Sound on/off
|
||||
PB6 (I ) Horiz. Blank
|
||||
PB5 (I ) Mouse Y2
|
||||
PB4 (I ) Mouse X2
|
||||
PB3 (I ) Mouse button
|
||||
PB2 ( O) RTC serial enable
|
||||
RB1 ( O) RTC data-clock line
|
||||
RB0 (IO) RTC clock serial data
|
||||
|
||||
SR - Keyboard data line
|
||||
|
||||
Timer 1 - Sound generator stuff
|
||||
Timer 2 - Disk I/O events
|
||||
(or both can be for your own use!)
|
||||
|
||||
IRQ7 - IRQ (all enabled VIA interrupts)
|
||||
IRQ6 - Timer 1
|
||||
IRQ5 - Timer 2
|
||||
IRQ4 - Keyboard clock
|
||||
IRQ3 - Keyboard data bit
|
||||
IRQ2 - Keyboard data ready
|
||||
IRQ1 - VBlank
|
||||
IRQ0 - One-second interrupt from RTC
|
||||
*/
|
||||
|
||||
// Hardware reset
|
||||
void VIA1_Zap(void) {
|
||||
memset(&VIA1_State, 0, sizeof(VIA1_State));
|
||||
}
|
||||
// Software reset
|
||||
void VIA1_Reset(void) {
|
||||
VIA1_Zap();
|
||||
}
|
||||
|
||||
// Write to a register
|
||||
void VIA1_Write(uint8_t reg, uint8_t data)
|
||||
{
|
||||
switch(reg) {
|
||||
case 0: // Port B data
|
||||
VIA1_State.PortB_data = data;
|
||||
break;
|
||||
case 1: // Port A data
|
||||
case 15:
|
||||
VIA1_State.PortA_data = data;
|
||||
break;
|
||||
case 2: // Port B direction
|
||||
VIA1_State.PortB_dir = data;
|
||||
break;
|
||||
case 3: // Port A direction
|
||||
VIA1_State.PortA_dir = data;
|
||||
break;
|
||||
case 4: // Timer 1 Low-Order Counter
|
||||
case 6: // Timer 1 Low-Order Latches
|
||||
VIA1_State.T1_L &= 0xFF00 | data;
|
||||
break;
|
||||
case 5: // Timer 1 High-Order Counter
|
||||
VIA1_State.T1_L &= 0x00FF | (data << 8);
|
||||
VIA1_State.T1_C = VIA1_State.T1_L;
|
||||
VIA1_State.IF &= 0b10111111;
|
||||
break;
|
||||
case 7: // Timer 1 High-Order Latches
|
||||
VIA1_State.T1_L &= 0x00FF | (data << 8);
|
||||
break;
|
||||
case 8: // Timer 1 Low-Order Counter
|
||||
VIA1_State.T2_L &= 0xFF00 | data;
|
||||
break;
|
||||
case 9: // Timer 2 High-Order Counter
|
||||
VIA1_State.T2_L &= 0x00FF | (data << 8);
|
||||
VIA1_State.T2_C = VIA1_State.T2_L;
|
||||
VIA1_State.IF &= 0b10111111;
|
||||
break;
|
||||
case 10:
|
||||
VIA1_State.SR = data;
|
||||
break;
|
||||
case 11:
|
||||
VIA1_State.AUX_T1 = (data & 0b11000000) >> 6;
|
||||
VIA1_State.AUX_T2 = (data & 0b00100000) >> 5;
|
||||
VIA1_State.AUX_SR = (data & 0b00011100) >> 2;
|
||||
VIA1_State.AUX_PBLE = (data & 0b00000010) >> 1;
|
||||
VIA1_State.AUX_PALE = (data & 0b00000001) >> 0;
|
||||
break;
|
||||
case 12:
|
||||
VIA1_State.PC_CB2 = (data & 0b11100000) >> 5;
|
||||
VIA1_State.PC_CB1 = (data & 0b00010000) >> 4;
|
||||
VIA1_State.PC_CA2 = (data & 0b00001110) >> 1;
|
||||
VIA1_State.PC_CA1 = (data & 0b00000001) >> 0;
|
||||
break;
|
||||
case 13: // Interrupt Flag
|
||||
VIA1_State.IF = data;
|
||||
break;
|
||||
case 14: // Interrupt Enable
|
||||
VIA1_State.IE = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read to a register
|
||||
uint8_t VIA1_Read(uint8_t reg)
|
||||
{
|
||||
switch(reg) {
|
||||
case 0: // Port B data (technically incorrect but meh)
|
||||
return VIA1_State.PortB_data & ~VIA1_State.PortB_dir;
|
||||
case 1: // Port A data
|
||||
case 15:
|
||||
return VIA1_State.PortA_data & ~VIA1_State.PortA_dir;
|
||||
case 2: // Port B direction
|
||||
return VIA1_State.PortB_dir;
|
||||
case 3: // Port A direction
|
||||
return VIA1_State.PortA_dir;
|
||||
case 4: // Timer 1 Low-Order Counter
|
||||
VIA1_State.IF &= 0b10111111;
|
||||
return (VIA1_State.T1_C & 0xFF00);
|
||||
case 5: // Timer 1 High-Order Counter
|
||||
return (VIA1_State.T1_C & 0x00FF) >> 8;
|
||||
case 6: // Timer 1 Low-Order Latches
|
||||
return (VIA1_State.T1_L & 0xFF00);
|
||||
case 7: // Timer 1 High-Order Latches
|
||||
return (VIA1_State.T1_L & 0x00FF) >> 8;
|
||||
case 8: // Timer 2 Low-Order Counter
|
||||
VIA1_State.IF &= 0b11011111;
|
||||
return (VIA1_State.T2_C & 0xFF00);
|
||||
case 9: // Timer 2 High-Order Counter
|
||||
return (VIA1_State.T2_C & 0x00FF) >> 8;
|
||||
case 10:
|
||||
return VIA1_State.SR;
|
||||
case 11:
|
||||
return (
|
||||
(VIA1_State.AUX_T1 << 6) |
|
||||
(VIA1_State.AUX_T2 << 5) |
|
||||
(VIA1_State.AUX_SR << 2) |
|
||||
(VIA1_State.AUX_PBLE << 1) |
|
||||
(VIA1_State.AUX_PALE << 0)
|
||||
);
|
||||
case 12:
|
||||
return (
|
||||
(VIA1_State.PC_CB2 << 5) |
|
||||
(VIA1_State.PC_CB1 << 4) |
|
||||
(VIA1_State.PC_CA2 << 1) |
|
||||
(VIA1_State.PC_CA1 << 0)
|
||||
);
|
||||
case 13: // Interrupt Flag
|
||||
return VIA1_State.IF;
|
||||
break;
|
||||
case 14: // Interrupt Enable
|
||||
return VIA1_State.IE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Tick timers
|
||||
void VIA1_Tick() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Shift in one byte of data to keyboard shift register
|
||||
void VIA1_ShiftInData(uint8_t v)
|
||||
{
|
||||
VIA1_State.SR = v;
|
||||
// somehow signal to keyboard that we're ready
|
||||
}
|
||||
|
||||
// Shift out one byte of data from keyboard shift register
|
||||
uint8_t VIA1_ShiftOutData(void)
|
||||
{
|
||||
// signal to keyboard to get new data?
|
||||
return VIA1_State.SR;
|
||||
|
||||
}
|
113
cfg/MACPLUS.h
113
cfg/MACPLUS.h
@ -27,119 +27,6 @@
|
||||
#define kRomCheckSum3 0x4D1F8172
|
||||
#define kROM_Size 0x00020000
|
||||
|
||||
/* the Wire variables are 1/0, not true/false */
|
||||
|
||||
enum {
|
||||
|
||||
Wire_VIA1_iA0_SoundVolb0,
|
||||
#define SoundVolb0 (Wires[Wire_VIA1_iA0_SoundVolb0])
|
||||
#define VIA1_iA0 (Wires[Wire_VIA1_iA0_SoundVolb0])
|
||||
|
||||
Wire_VIA1_iA1_SoundVolb1,
|
||||
#define SoundVolb1 (Wires[Wire_VIA1_iA1_SoundVolb1])
|
||||
#define VIA1_iA1 (Wires[Wire_VIA1_iA1_SoundVolb1])
|
||||
|
||||
Wire_VIA1_iA2_SoundVolb2,
|
||||
#define SoundVolb2 (Wires[Wire_VIA1_iA2_SoundVolb2])
|
||||
#define VIA1_iA2 (Wires[Wire_VIA1_iA2_SoundVolb2])
|
||||
|
||||
Wire_VIA1_iA4_MemOverlay,
|
||||
#define MemOverlay (Wires[Wire_VIA1_iA4_MemOverlay])
|
||||
#define VIA1_iA4 (Wires[Wire_VIA1_iA4_MemOverlay])
|
||||
#define VIA1_iA4_ChangeNtfy MemOverlay_ChangeNtfy
|
||||
|
||||
Wire_VIA1_iA6_SCRNvPage2,
|
||||
#define SCRNvPage2 (Wires[Wire_VIA1_iA6_SCRNvPage2])
|
||||
#define VIA1_iA6 (Wires[Wire_VIA1_iA6_SCRNvPage2])
|
||||
|
||||
Wire_VIA1_iA5_IWMvSel,
|
||||
#define IWMvSel (Wires[Wire_VIA1_iA5_IWMvSel])
|
||||
#define VIA1_iA5 (Wires[Wire_VIA1_iA5_IWMvSel])
|
||||
|
||||
Wire_VIA1_iA7_SCCwaitrq,
|
||||
#define SCCwaitrq (Wires[Wire_VIA1_iA7_SCCwaitrq])
|
||||
#define VIA1_iA7 (Wires[Wire_VIA1_iA7_SCCwaitrq])
|
||||
|
||||
Wire_VIA1_iB0_RTCdataLine,
|
||||
#define RTCdataLine (Wires[Wire_VIA1_iB0_RTCdataLine])
|
||||
#define VIA1_iB0 (Wires[Wire_VIA1_iB0_RTCdataLine])
|
||||
#define VIA1_iB0_ChangeNtfy RTCdataLine_ChangeNtfy
|
||||
|
||||
Wire_VIA1_iB1_RTCclock,
|
||||
#define RTCclock (Wires[Wire_VIA1_iB1_RTCclock])
|
||||
#define VIA1_iB1 (Wires[Wire_VIA1_iB1_RTCclock])
|
||||
#define VIA1_iB1_ChangeNtfy RTCclock_ChangeNtfy
|
||||
|
||||
Wire_VIA1_iB2_RTCunEnabled,
|
||||
#define RTCunEnabled (Wires[Wire_VIA1_iB2_RTCunEnabled])
|
||||
#define VIA1_iB2 (Wires[Wire_VIA1_iB2_RTCunEnabled])
|
||||
#define VIA1_iB2_ChangeNtfy RTCunEnabled_ChangeNtfy
|
||||
|
||||
Wire_VIA1_iA3_SoundBuffer,
|
||||
#define SoundBuffer (Wires[Wire_VIA1_iA3_SoundBuffer])
|
||||
#define VIA1_iA3 (Wires[Wire_VIA1_iA3_SoundBuffer])
|
||||
|
||||
Wire_VIA1_iB3_MouseBtnUp,
|
||||
#define MouseBtnUp (Wires[Wire_VIA1_iB3_MouseBtnUp])
|
||||
#define VIA1_iB3 (Wires[Wire_VIA1_iB3_MouseBtnUp])
|
||||
|
||||
Wire_VIA1_iB4_MouseX2,
|
||||
#define MouseX2 (Wires[Wire_VIA1_iB4_MouseX2])
|
||||
#define VIA1_iB4 (Wires[Wire_VIA1_iB4_MouseX2])
|
||||
|
||||
Wire_VIA1_iB5_MouseY2,
|
||||
#define MouseY2 (Wires[Wire_VIA1_iB5_MouseY2])
|
||||
#define VIA1_iB5 (Wires[Wire_VIA1_iB5_MouseY2])
|
||||
|
||||
Wire_VIA1_iCB2_KybdDat,
|
||||
#define VIA1_iCB2 (Wires[Wire_VIA1_iCB2_KybdDat])
|
||||
#define VIA1_iCB2_ChangeNtfy Kybd_DataLineChngNtfy
|
||||
|
||||
Wire_VIA1_iB6_SCRNbeamInVid,
|
||||
#define SCRNbeamInVid (Wires[Wire_VIA1_iB6_SCRNbeamInVid])
|
||||
#define VIA1_iB6 (Wires[Wire_VIA1_iB6_SCRNbeamInVid])
|
||||
|
||||
Wire_VIA1_iB7_SoundDisable,
|
||||
#define SoundDisable (Wires[Wire_VIA1_iB7_SoundDisable])
|
||||
#define VIA1_iB7 (Wires[Wire_VIA1_iB7_SoundDisable])
|
||||
|
||||
Wire_VIA1_InterruptRequest,
|
||||
#define VIA1_InterruptRequest (Wires[Wire_VIA1_InterruptRequest])
|
||||
#define VIA1_interruptChngNtfy VIAorSCCinterruptChngNtfy
|
||||
|
||||
Wire_SCCInterruptRequest,
|
||||
#define SCCInterruptRequest (Wires[Wire_SCCInterruptRequest])
|
||||
#define SCCinterruptChngNtfy VIAorSCCinterruptChngNtfy
|
||||
|
||||
kNumWires
|
||||
};
|
||||
|
||||
|
||||
/* VIA configuration */
|
||||
#define VIA1_ORA_FloatVal 0xFF
|
||||
#define VIA1_ORB_FloatVal 0xFF
|
||||
#define VIA1_ORA_CanIn 0x80
|
||||
#define VIA1_ORA_CanOut 0x7F
|
||||
#define VIA1_ORB_CanIn 0x79
|
||||
#define VIA1_ORB_CanOut 0x87
|
||||
#define VIA1_IER_Never0 (1 << 1)
|
||||
#define VIA1_IER_Never1 ((1 << 3) | (1 << 4))
|
||||
#define VIA1_CB2modesAllowed 0x01
|
||||
#define VIA1_CA2modesAllowed 0x01
|
||||
|
||||
#define Mouse_Enabled SCC_InterruptsEnabled
|
||||
|
||||
#define VIA1_iCA1_PulseNtfy VIA1_iCA1_Sixtieth_PulseNtfy
|
||||
#define Sixtieth_PulseNtfy VIA1_iCA1_Sixtieth_PulseNtfy
|
||||
|
||||
#define VIA1_iCA2_PulseNtfy VIA1_iCA2_RTC_OneSecond_PulseNtfy
|
||||
#define RTC_OneSecond_PulseNtfy VIA1_iCA2_RTC_OneSecond_PulseNtfy
|
||||
|
||||
#define GetSoundInvertTime VIA1_GetT1InvertTime
|
||||
|
||||
#define KYBD_ShiftInData VIA1_ShiftOutData
|
||||
#define KYBD_ShiftOutData VIA1_ShiftInData
|
||||
|
||||
#define kExtn_Block_Base 0x00F40000
|
||||
#define kExtn_ln2Spc 5
|
||||
|
||||
|
471
src/HW/VIA/VIA notes.md
Normal file
471
src/HW/VIA/VIA notes.md
Normal file
@ -0,0 +1,471 @@
|
||||
# VIA
|
||||
|
||||
Emulates the Synertek SY6522 VIA in every system that uvMac targets.
|
||||
|
||||
The VIA contains the following functionality:
|
||||
- Two timers (1 and 2)
|
||||
- Serial-to-parallel / parallel-to-serial bi-directional shift register
|
||||
- Two 8-bit bi-directional ports (A and B)
|
||||
- Ports are per-line settable to input or output
|
||||
- Square wave generation
|
||||
- Pulse counting
|
||||
|
||||
The M68000 addresses the VIA simply via an interrupt line and a pair of
|
||||
registers, much like any other peripheal
|
||||
|
||||
Because just about everything on the Mac is attached to a VIA, it's
|
||||
important to track what device is mapped to what line on what port.
|
||||
|
||||
## Summary of SY6522 pins:
|
||||
1. Phase 2 Clock (Φ2)
|
||||
Must be high for data transfer from M68k to occur
|
||||
Time base for timers, shift registers, etc.
|
||||
2. Chip select (CS1, ¬CS2)
|
||||
is a chip select line
|
||||
3. Register Select (RS0, RS1, RS2, RS3)
|
||||
Name Write Read
|
||||
0000 - ORB, IRB Port B output Port B input
|
||||
0001 - ORA, IRA Port A output Port A input
|
||||
0010 - DDRB Data Direction, port B
|
||||
0011 - DDRA Data Direction, port A
|
||||
0100 - T1L-L T1 Low-Order Latches T1 Low-Order Counter
|
||||
0101 - T1C-H T1 High-Order Counter
|
||||
0110 - T1L-L T1 Low-Order Latches
|
||||
0111 - T1L-H T1 High-Order Latches
|
||||
1000 - T2C-L T2 Low-Order Latches T2 Low-Order Counter
|
||||
1001 - T2C-H T2 High-Order Counter
|
||||
1010 - SR Shift Register
|
||||
1011 - ACR Auxillary Control Register
|
||||
1100 - PCR Peripheal Control Register
|
||||
1101 - IFR Interrupt flag
|
||||
1110 - IER Interrupt enable
|
||||
1111 - ORA Same as 0001 but no effect on handshake
|
||||
4. Read/Write line
|
||||
If low, write (processor to VIA register)
|
||||
If high, read (VIA register to processor)
|
||||
5. Data Bus (DB0-7)
|
||||
Transfers data between VIA and M68l
|
||||
6. Reset
|
||||
Clears all registers to 0.
|
||||
All I/O set to input, disablse timers, SR, interrupts, etc.
|
||||
7. IRQ
|
||||
8. Peripheal A Port (PA0 - PA7)
|
||||
8 lines. Each can be input or output, depending on value of DDRA
|
||||
9. Port A Control Lines (CA1/CA2)
|
||||
Interrupt inputs or handshake outputs
|
||||
Each line controls an internal interrupt flag w/ enable bit
|
||||
CA1 controls latching of data on P1 input
|
||||
10. Peripheal Port B (PB0 - PB7)
|
||||
Same as Port A, with timers!
|
||||
PB7 polarity can be controller by timer
|
||||
PB6 can count pulses w/ second timer
|
||||
11. Port B control lines (CB1/CB2)
|
||||
Same as CA
|
||||
Shift register serial I/O goes through one of these
|
||||
|
||||
I'm not going to bother to emulate handshaking
|
||||
|
||||
## Notes from "Guide to Macintosh Family Hardware, Second Edition"
|
||||
|
||||
- On Mac II+, VIA circuits are custom Apple silicon, like 6522
|
||||
- VIA1 handles classic Mac functions, VIA2 handles Mac II functions
|
||||
|
||||
Mac 128k: VIA x1
|
||||
Mac 512K: VIA x1
|
||||
Mac Plus: VIA x1
|
||||
Mac SE: VIA x1
|
||||
Mac SE/30: VIA x1
|
||||
Mac Port: VIA x1
|
||||
Mac II: VIA x2
|
||||
Mac IIx: VIA x2
|
||||
Mac IIcx: VIA x2
|
||||
Mac IIci: VIA x1, RBV
|
||||
Mac IIfx: VIA x1, OSS
|
||||
|
||||
- RBV = "RAM Based Video Controller"
|
||||
- RBV is more custom Apple silicon that is a superset of VIA2
|
||||
- OSS = "Operating System Support"
|
||||
|
||||
- Operates synchronously w/ M68k
|
||||
- Timed by E clock at 783.36 kHz, generated by M68k
|
||||
- In SE/30, Mac Portable, and Mac II, synchronized w/ glue logic
|
||||
- 128k/Plus/SE need to wait for E clock to access VIA (1 us)
|
||||
- SE/30, Portable, II can access VIA w/ no delay (0.5 us)
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint8_t vBufA; // Data Register A
|
||||
uint8_t vBufB; // Data Register B
|
||||
uint8_t vDirA; // Data Direction A (0 = in, 1 = out)
|
||||
uint8_t vDirB; // Data Direction B (0 = in, 1 = out)
|
||||
uint8_t vPCR; // Peripheal Control
|
||||
uint8_t vACR; // Auxiliary Control
|
||||
uint8_t vTxx; // Event timers (multiple?)
|
||||
uint8_t vIFR; // Interrupt Flag
|
||||
uint8_t vIER; // Interrupt Enable
|
||||
uint8_t vSR; // Shift register
|
||||
} VIA1_State_t;
|
||||
```
|
||||
|
||||
## Data Register allocations
|
||||
|
||||
### Mac 128/512k/Plus ("classic Macintosh")
|
||||
Bit | Dir | Bit name | Description
|
||||
------|-----|-----------|-----------------------------------------------------
|
||||
PA7 | In | vSCCWrReq | SCC Wait/Request, channel A or B
|
||||
PA6 | Out | vPage2 | 0 = alt. screen buffer, 1 = main screen buffer
|
||||
PA5 | Out | vHeadSel | Disk SEL line (which floppy head to use)
|
||||
PA4 | Out | vOverlay | 1 = ROM overlay address map is used (startup only)
|
||||
PA3 | Out | vSndPg2 | 0 = alt. sound buffer, 1 = main sound buffer
|
||||
PA2-0 | Out | vSound | Sound Volume (bit 2 is MSB, 111 is max)
|
||||
PB7 | Out | vSndEnb | 0 = sound enabled
|
||||
PB6 | In | vH4 | 0 = video beam in display portion of line
|
||||
PB5 | In | vY2 | Mouse Y2 quadrature signal
|
||||
PB4 | In | vX2 | Mouse X2 quadrature signal
|
||||
PB3 | In | vSW | 0 = Mouse button pressed
|
||||
PB2 | Out | vTCEnb | 0 = RTC enabled
|
||||
PB1 | Out | vTCCLK | RTC data-clock line
|
||||
PB0 | I/O | rTCData | RTC serial data line
|
||||
|
||||
vSCCWrReq monitors /W/REQA and /W/REQB from SCC, with are OR'd
|
||||
together. Used to determine when SCC had read a byte during floppy disk
|
||||
operations, when SCC interrupts are disabled.
|
||||
|
||||
### Mac SE
|
||||
Bit | Dir | Bit name | Description
|
||||
------|-----|-----------|-----------------------------------------------------
|
||||
PA7 | In | vSCCWrReq | SCC Wait/Request, channel A or B
|
||||
PA6 | Out | vPage2 | 0 = alt. screen buffer, 1 = main screen buffer
|
||||
PA5 | Out | vHeadSel | Disk SEL line (which floppy/head to use)
|
||||
PA4 | Out | vDriveSel | 0 = upper, 1 = lower
|
||||
PA3 | Out | vSync | 1 = synchronous modem support, channel A
|
||||
PA2-0 | Out | vSound | Sound Volume (bit 2 is MSB, 111 is max)
|
||||
PB7 | Out | vSndEnb | 0 = sound enabled
|
||||
PB6 | In | vH4 | 0 = video beam in display portion of line
|
||||
PB5 | In | vFDesk2 | ADB state input 1 (ST1)
|
||||
PB4 | In | vFDesk1 | ADB state input 0 (ST0)
|
||||
PB3 | In | vFDBInt | 0 = ADB interrupt
|
||||
PB2 | Out | vTCEnb | 0 = RTC enabled
|
||||
PB1 | Out | vTCCLK | RTC data-clock line
|
||||
PB0 | I/O | rTCData | RTC serial data line
|
||||
|
||||
vSync, when low, makes SCC work like classic Mac models where Receive Closk
|
||||
(RTxC) signal frequency for both channels A and B are 3.672 MHz. When high,
|
||||
channel A's RTxC signal is provided by the GPi pin from the modem serial port
|
||||
connector.
|
||||
|
||||
Mouse bits are replaced with ADB bits.
|
||||
|
||||
### Mac Portable
|
||||
All bits on data register A are used as an 8-bit bidirectional data bus to
|
||||
communicate w/ the Power Manager's microprocessor.
|
||||
|
||||
Bit | Dir | Bit name | Description
|
||||
------|-----|-----------|-----------------------------------------------------
|
||||
PB7 | In | vSCCWrReq | SCC Wait/Request, channel A or B
|
||||
PB7 | Out | vSndEnb | 0 = sound enabled
|
||||
PB6 | In | vSndExt | 0 = headphones plugged in (output is stereo)
|
||||
PB5 | Out | vHeadSel | Floppy disk head select
|
||||
PB4 | Out | vDriveSel | 0 = upper, 1 = lower
|
||||
PB3 | Out | vSync | 1 = sync. modem support, channel A (like SE)
|
||||
PB2 | Out | vTest | Test signal (ignore)
|
||||
PB1 | In | vPMAck | ACK signal for Power Manager
|
||||
PB0 | Out | vPMReq | REQ signal for Power Manager
|
||||
|
||||
PB7 is vSCCWrReq only if SCC interrupts are disabled.
|
||||
vSndEnb is a purely software register. OS emulates classic behavior by reading
|
||||
and making ASC commands if needed.
|
||||
|
||||
vTest, if high, forces all power supplies to full power. Only used for testing
|
||||
by Apple service employees; do not bother implementing.
|
||||
|
||||
### Mac II, IIx, IIcx and SE/30 - VIA1
|
||||
Bit | Dir | Bit name | Description
|
||||
------|-----|-----------|-----------------------------------------------------
|
||||
PA7 | In | vSCCWrReq | SCC Wait/Request, channel A or B
|
||||
PA6 | Out | vPage2 | Screen buffer, like others. Mac SE/30 only.
|
||||
PA6 | In | CPU.ID1 | Identifies different Mac II models (not SE/30)
|
||||
PA5 | Out | vHeadSel | Disk SEL line (which floppy/head to use)
|
||||
PA4 | Out | vOverlay | 1 = ROM overlay address map is used
|
||||
PA3 | Out | vSync | 1 = synchronous modem support, channel A
|
||||
PA2-0 | | | Reserved
|
||||
PB7 | Out | vSndEnb | 0 = sound enable (for compatibility w/ old software)
|
||||
PB6 | Out | vSyncEnA | VSync ISR enabled (Mac SE/30 only)
|
||||
PB5 | Out | vFDesk2 | ADB state input 1 (ADB.ST1)
|
||||
PB4 | Out | vFDesk1 | ADB state input 0 (ADB.ST0)
|
||||
PB3 | In | vFDBInt | 0 = ADB interrupt (/ADB.INT)
|
||||
PB2 | Out | vTCEnb | 0 = RTC enabled
|
||||
PB1 | Out | vTCCLK | RTC data-clock line
|
||||
PB0 | I/O | rTCData | RTC serial data line
|
||||
|
||||
- CPU.ID1 is tied low on Mac II, IIx, and IIcx, and high on IIci/IIfx.
|
||||
- vOverlay causes TAM to in inaccessible until Overlay signal is deasserted.
|
||||
Only used during startup.
|
||||
- PA2-0 are either unused or additional machine ID bits. This is to preserve
|
||||
software compatibility.
|
||||
- PB is almost the same as the Macintosh SE.
|
||||
- vSyncEnA enables or disables interrupt $E (internal video ISR)
|
||||
This interrupt is not the 60.15Hz VBL request. That's still emulated as-is.
|
||||
Mac SE/30 system software does not use VBL. It uses $E instead.
|
||||
|
||||
### Mac IIci - VIA1
|
||||
Bit | Dir | Bit name | Description
|
||||
------|-----|-----------|-----------------------------------------------------
|
||||
PA7 | In | vSCCWrReq | SCC Wait/Request, channel A or B
|
||||
PA6 | In | CPU.ID3 | Bit 3 of 4-bit model ID
|
||||
PA5 | Out | vHeadSel | Disk SEL line (which floppy/head to use)
|
||||
PA4 | In | CPU.ID2 | Bit 2 of 4-bit model ID
|
||||
PA3 | Out | vSync | 1 = synchronous modem support, channel A
|
||||
PA2 | In | CPU.ID1 | Bit 1 of 4-bit model ID
|
||||
PA1 | In | CPU.ID0 | Bit 0 of 4-bit model ID
|
||||
PA0 | | | Reserved
|
||||
PB7 | In | /Par.Err | 0 = parity error
|
||||
PB6 | In | /Par.En | 0 = parity-checking enabled
|
||||
PB5 | Out | vFDesk2 | ADB state input 1 (ADB.ST1)
|
||||
PB4 | Out | vFDesk1 | ADB state input 0 (ADB.ST0)
|
||||
PB3 | In | vFDBInt | 0 = ADB interrupt (/ADB.INT)
|
||||
PB2 | Out | vTCEnb | 0 = RTC enabled
|
||||
PB1 | Out | vTCCLK | RTC data-clock line
|
||||
PB0 | I/O | rTCData | RTC serial data line
|
||||
|
||||
Certain models of the IIci have a "parity generation and checking" chip.
|
||||
Whenever a byte of RAM is written, the PGC stores a parity bit in bit 9.
|
||||
Whenever a byte of RAM is read, the PGC reads, compares, and raises
|
||||
/NMI and /PAR.ERR if /Par.En is enabled.
|
||||
|
||||
The parity-checking IIci models are very rare, only available via special
|
||||
order from Apple. It almost certainly is not worth emulating.
|
||||
|
||||
### Mac IIfx - VIA1
|
||||
Port A is like IIci, except *only* model ID bits are used.
|
||||
Other functions are controlled by the OSS, IOP, and BIU30.
|
||||
|
||||
Port B is the same as the II, except that the ADB lines are unused.
|
||||
|
||||
### Model ID table
|
||||
Model | Value (3..0)
|
||||
-------------------|--------------
|
||||
Mac II (early) | 0b0xxx
|
||||
Mac IIci | 0b1011
|
||||
Mac IIci w/ parity | 0b1111
|
||||
Mac IIfx | 0b1101
|
||||
|
||||
### Mac II family - VIA2
|
||||
|
||||
Renaming ports A and B -> C and D.
|
||||
|
||||
Bit | Dir | Bit name | Description
|
||||
------|-----|------------|-----------------------------------------------------
|
||||
PC7 | Out | v2RAM1 | RAM-size bit 1 (except IIci)
|
||||
PC6 | Out | v2RAM0 | RAM-size bit 0 (except IIci)
|
||||
PC6 | In | v2IRQ0 | ISR from internal video circuits (IIci only)
|
||||
PC5 | In | v2IRQ6 | ISR from expansion slot $E
|
||||
PC4 | In | v2IRQ5 | ISR from expansion slot $D
|
||||
PC3 | In | v2IRQ4 | ISR from expansion slot $C
|
||||
PC2 | In | v2IRQ3 | ISR from expansion slot $B
|
||||
PC1 | In | v2IRQ2 | ISR from expansion slot $A
|
||||
PC0 | In | v2IRQ1 | ISR from expansion slot $9
|
||||
PD7 | Out | v2VBL | 60.15 Hz timer out
|
||||
PD7 | Out | /Par.Test | 0 = parity test mode (IIci only)
|
||||
PD6 | In | v2SNDEXT | 0 = headphones inserted (output is stereo)
|
||||
PD5 | In | v2TM0A | Transfer mode bit 0 ACK from NuBus
|
||||
PD4 | In | v2TM1A | Transfer mode bit 1 ACK from NuBus
|
||||
PD3 | I/O | vFC3 | various; see notes
|
||||
PD2 | Out | v2PowerOff | 0 = shut off power
|
||||
PD1 | Out | c2BusLk | 0 = NuBus transactions are locked out
|
||||
PD0 | Out | /CEnable | 1 = disable cache card (Mac IIci)
|
||||
PD0 | Out | v2CDis | 0 = disable M68k cache (all other)
|
||||
|
||||
v2RAM indicates size of TAM ICs used in bank A.
|
||||
- 0b00: 256 Kbit
|
||||
- 0b01: 1 Mbit
|
||||
- 0b10: 4 Mbit
|
||||
- 0b11: 16 Mbit
|
||||
Determines when bank A stops and bank B begins.
|
||||
Not needed in Mac IIci; M68030's MCU is used instead. Bank B is always at
|
||||
address $0400_0000.
|
||||
|
||||
IIcx only uses slots $9, $A, and $B. IIcx only uses slots $C, $D, and $E.
|
||||
Mac SE/30 PDS cards can act like a NuBus card in slot $9, $A, or $B. $E can be
|
||||
generated by internal video logic circuits.
|
||||
|
||||
v2SNDEXT is always low in the Mac SE/30, because it always supports stereo
|
||||
sound. (Speaker is mono, but it has a hardware mixer.) Also, the SE/30 doesn't
|
||||
have a headphone jack. (much like the iPhone SE 2 ayy lmao)
|
||||
|
||||
v2TMxA store error codes from NuBus transations. They can be:
|
||||
- 0b00: No error
|
||||
- 0b01: Read/write error, handled by computer
|
||||
- 0b02: Bus timeout
|
||||
- 0b03: Bus busy; try again later
|
||||
Also, used for other NuBus transaction type/size indicators.
|
||||
|
||||
v2PowerOff is connected directly to the power supply. Stop emulation when this
|
||||
goes low.
|
||||
|
||||
v2BusLk blocks incoming NuBus messages and sends a "bus busy" response. Meant
|
||||
to keep DMA from interfering with other things.
|
||||
|
||||
Yes, PD0 is the opposite on the Mac IIci compared to every other system. Don't
|
||||
think about this too hard. (We're probably not emulating cache anyways, so it
|
||||
doesn't really matter.)
|
||||
|
||||
#### vFC3 table
|
||||
Model | Condition | Dir | Description
|
||||
------|-----------|-----|-----------------------------------------
|
||||
II | AMU in | Out | 0 = do 24->32 bit address translation
|
||||
II | PMMU in | In | 1 = PMMU accessing page table
|
||||
SE/30 | | In | Always 0
|
||||
IIx | | | not used
|
||||
IIcx | | | not used
|
||||
IIfx | | | not used
|
||||
IIci | | | 0 = flush cache (in optional cache card)
|
||||
|
||||
## Peripheral Control Register
|
||||
|
||||
Allows software to set triggering parameters for certain VIA signals.
|
||||
|
||||
### All models except Portable - VIA1
|
||||
| Bit | Dir | Description
|
||||
|-----|-----|------------------------------------------
|
||||
| 7 | I/O | Keyboard or ADB data
|
||||
| 6 | I/O | Keyboard or ADB data
|
||||
| 5 | I/O | Keyboard or ADB data
|
||||
| 4 | In | Keyboard or ADB clock (from ext. device)
|
||||
| 3 | In | One-second interrupt
|
||||
| 2 | In | One-second interrupt
|
||||
| 1 | In | One-second interrupt
|
||||
| 0 | In | VBlank Interrupt (VBL)
|
||||
|
||||
- Keyboard data line transfers data from shift register to keyboad, somehow
|
||||
- One-second interrupt generated by RTC.
|
||||
- VBL generated by a PAL at 60.15 Hz (once per 16.63 ms)
|
||||
On Mac Portable, SE/30, or II+, VBL is still 60.15 Hz but not tied to VBlank
|
||||
|
||||
### Macintosh Portable
|
||||
| Bit | Dir | Description
|
||||
|-----|-----|-------------
|
||||
| 7 | In | SCSI IRQ
|
||||
| 6 | In | SCSI IRQ
|
||||
| 5 | In | SCSI IRQ
|
||||
| 4 | In | Power manager interrupt
|
||||
| 3 | In | One-second interrupt
|
||||
| 2 | In | One-second interrupt
|
||||
| 1 | In | One-second interrupt
|
||||
| 0 | In | VBlank Interrupt (VBL)
|
||||
|
||||
### Mac SE/30 and Mac II family - VIA2
|
||||
| Bit | Dir | Description
|
||||
|-----|-----|-------------
|
||||
| 7 | I/O | SCSI IRQ
|
||||
| 6 | I/O | SCSI IRQ
|
||||
| 5 | I/O | SCSI IRQ
|
||||
| 4 | In | ASC interrupt
|
||||
| 3 | In | SCSI DRQ
|
||||
| 2 | In | SCSI DRQ
|
||||
| 1 | In | SCSI DRQ
|
||||
| 0 | In | Slot interrupt
|
||||
|
||||
- SCSI IRQ is generated by SCSI to indicate an error condition
|
||||
- SCSI DRQ indicates that SCSI is ready to transfer data.
|
||||
- ASC indicates when ASC sound buffer is ready to be reloaded.
|
||||
- Slot interrupt fires if *any* slot raises an interrupt.
|
||||
|
||||
## Auxiliary Control Register
|
||||
|
||||
Does things with VIA timers and the shift register.
|
||||
|
||||
### All Macs - VIA1 and VIA2
|
||||
| Bit | Dir | Description
|
||||
|-----|-----|-------------
|
||||
| 7 | In | Timer T1 - vSndEnb (0 = no change, 1 = invert)
|
||||
| 6 | In | Timer T1 - Mode (0 = one-shot, 1 = pulse)
|
||||
| 5 | In | Timer T2 - Mode (0 = one-shot, 1 = tick on PB6 falling edge)
|
||||
| 4 | In | Keyboard or ADB bit-shift operation (VIA1 only; not Portable)
|
||||
| 3 | In | Keyboard or ADB bit-shift operation (VIA1 only; not Portable)
|
||||
| 2 | In | Keyboard or ADB bit-shift operation (VIA1 only; not Portable)
|
||||
| 1 | In | Input data latch for DR B (1 = enable, 0 = disable)
|
||||
| 0 | In | Input data latch for DR A (1 = enable, 0 = disable)
|
||||
|
||||
- T1 can be one-shot interval timer or a pulse generator
|
||||
- In one-shot mode, decrement counter every 1.2766 us, fire ISR when 0.
|
||||
- In pulse mode, T1 can be loaded with a value that T1 will reload
|
||||
after hitting zero. Can also invert DB7 (sound enable) on each loop.
|
||||
- On VIA2, this generates the 60.15 Hz interrupt signal
|
||||
- Some games for 128k/512k/Plus used timer T1 to toggle sound on and off to
|
||||
generate a square wave. This is broken on models with the ASC.
|
||||
- T2 can be used to get the current Y position of the electron beam for the
|
||||
Mac 128k, 512k, Plus, and SE. (That's PB6)
|
||||
- On the Mac II, this interrupt on VIA 2 counts the number of times you've
|
||||
inserted your headphones. How... useful... (ditto w/ Portable on VIA1)
|
||||
- Portable uses the Power Manager as an ADB controller.
|
||||
- Bits 0 and 1, if enabled, latch any high signal until cleared. If disabled,
|
||||
the values are updated real-time.
|
||||
- Bits 0-5 are *only* modified by System software.
|
||||
- Bits 4-2 should be 0b011, or 0b000 on startup.
|
||||
|
||||
### Macintosh IIci
|
||||
There is no ACR; this is handled by the RBV.
|
||||
|
||||
## Shift Register
|
||||
Used for keyboard or ADB I/O. Not used on VIA2 or the Portable.
|
||||
|
||||
## Event timers
|
||||
This is where the current state of T1 and T2 are stored.
|
||||
See the SY6522 pin summary for details.
|
||||
|
||||
Uses the E clock generated by the M68k as reference, so these counters
|
||||
decrement every 1.2766 us.
|
||||
|
||||
Values must be stored per-byte; there is no per-word access. Writing to high
|
||||
byte *starts* the timer.
|
||||
|
||||
- T1 on VIA1 is used by system sound driver.
|
||||
- T2 on VIA1 is use by disk driver to time disk I/O events.
|
||||
- T1 on VIA2 generates VBL every 60.15 Hz
|
||||
- T2 on VIA2 is (as of 1991) unused.
|
||||
|
||||
## Interrupt Flag Register
|
||||
|
||||
### VIA1 - All except Portable
|
||||
- IRQ7 - IRQ (all enabled VIA interrupts)
|
||||
- IRQ6 - Timer 1 = 0
|
||||
- IRQ5 - Timer 2 = 0
|
||||
- IRQ4 - Keyboard/ADB clock received
|
||||
- IRQ3 - Keyboard/ADB data bit received
|
||||
- IRQ2 - Keyboard/ADB data ready (finished shifting 8 bits in or out)
|
||||
- IRQ1 - VBL
|
||||
- IRQ0 - One-second interrupt from RTC
|
||||
|
||||
### VIA1 - Portable
|
||||
- IRQ7 - IRQ (all enabled VIA interrupts)
|
||||
- IRQ6 - Timer 1 = 0
|
||||
- IRQ5 - Timer 2 = 0
|
||||
- IRQ4 - SCSI IRQ received
|
||||
- IRQ3 - Power Manager ISR received
|
||||
- IRQ2 - Not used
|
||||
- IRQ1 - VBL
|
||||
- IRQ0 - One-second interrupt from RTC
|
||||
|
||||
### VIA2
|
||||
- IRQ7 - IRQ (all enabled VIA interrupts)
|
||||
- IRQ6 - Timer 1 = 0
|
||||
- IRQ5 - Timer 2 = 0
|
||||
- IRQ4 - ASC interrupt
|
||||
- IRQ3 - SCSI IRQ
|
||||
- IRQ2 - /EXP.IRQ (Mac IIci only)
|
||||
- IRQ1 - Slot interrupt
|
||||
- IRQ0 - SCSI DRQ
|
||||
|
||||
Mac IIci uses RBV, Mac IIfx uses OSS to control interrupt functions.
|
||||
|
||||
## Interrupt Enable Register
|
||||
|
||||
Yep, that's a thing! One bit per interrupt.
|
||||
|
||||
When writing, bit 7 signals set (1) or clear (0), and the other bits apply
|
||||
that action to the corresponding IRQ. When reading, bit 7 is always 1.
|
||||
|
||||
When an interrupt is tabled, IF is still updated, but no interrupt is generated.
|
||||
|
||||
And *that's* the VIA. The whole dang thing. That wasn't too hard, huh?
|
File diff suppressed because it is too large
Load Diff
@ -1,47 +0,0 @@
|
||||
/*
|
||||
HW/VIA/VIA2EMDV.h
|
||||
|
||||
Copyright (C) 2004 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.
|
||||
*/
|
||||
|
||||
#ifndef VIA2EMDV_H
|
||||
#define VIA2EMDV_H
|
||||
|
||||
EXPORTPROC VIA2_Zap(void);
|
||||
EXPORTPROC VIA2_Reset(void);
|
||||
|
||||
EXPORTFUNC uint32_t VIA2_Access(uint32_t Data, bool WriteMem, CPTR addr);
|
||||
|
||||
EXPORTPROC VIA2_ExtraTimeBegin(void);
|
||||
EXPORTPROC VIA2_ExtraTimeEnd(void);
|
||||
#ifdef VIA2_iCA1_PulseNtfy
|
||||
EXPORTPROC VIA2_iCA1_PulseNtfy(void);
|
||||
#endif
|
||||
#ifdef VIA2_iCA2_PulseNtfy
|
||||
EXPORTPROC VIA2_iCA2_PulseNtfy(void);
|
||||
#endif
|
||||
#ifdef VIA2_iCB1_PulseNtfy
|
||||
EXPORTPROC VIA2_iCB1_PulseNtfy(void);
|
||||
#endif
|
||||
#ifdef VIA2_iCB2_PulseNtfy
|
||||
EXPORTPROC VIA2_iCB2_PulseNtfy(void);
|
||||
#endif
|
||||
EXPORTPROC VIA2_DoTimer1Check(void);
|
||||
EXPORTPROC VIA2_DoTimer2Check(void);
|
||||
|
||||
EXPORTFUNC uint16_t VIA2_GetT1InvertTime(void);
|
||||
|
||||
EXPORTPROC VIA2_ShiftInData(uint8_t v);
|
||||
EXPORTFUNC uint8_t VIA2_ShiftOutData(void);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +1,85 @@
|
||||
/*
|
||||
HW/VIA/VIAEMDEV.h
|
||||
Versatile Interface Adapter EMulated DEVice
|
||||
|
||||
Copyright (C) 2004 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.
|
||||
Emulates the Synertek SY6522 VIA in every system that uvMac targets.
|
||||
This code rewritten for target-independence and non-enum based config
|
||||
*/
|
||||
|
||||
#ifndef VIAEMDEV_H
|
||||
#define VIAEMDEV_H
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool VIA1_Zap(void);
|
||||
void VIA1_Reset(void);
|
||||
/// TYPEDEFS /////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t VIA1_Access(uint32_t Data, bool WriteMem, uint32_t addr);
|
||||
/* Mac II has two VIAs, all others have one */
|
||||
#define VIA_MAXNUM (2)
|
||||
|
||||
void VIA1_ExtraTimeBegin(void);
|
||||
void VIA1_ExtraTimeEnd(void);
|
||||
void VIA1_iCA1_PulseNtfy(void);
|
||||
void VIA1_iCA2_PulseNtfy(void);
|
||||
void VIA1_iCB1_PulseNtfy(void);
|
||||
void VIA1_iCB2_PulseNtfy(void);
|
||||
void VIA1_DoTimer1Check(void);
|
||||
void VIA1_DoTimer2Check(void);
|
||||
/* VIA interrupt handler signature */
|
||||
typedef void (*VIA_ISR_t)(void);
|
||||
|
||||
uint16_t VIA1_GetT1InvertTime(void);
|
||||
/* Names from Guide to Macintosh Family Hardware, Second Edition, pg. 159 */
|
||||
typedef struct {
|
||||
uint8_t vBufA; // Data Register A
|
||||
uint8_t vBufB; // Data Register B
|
||||
uint8_t vDirA; // Data Direction A (0 = in, 1 = out)
|
||||
uint8_t vDirB; // Data Direction B (0 = in, 1 = out)
|
||||
uint8_t vPCR; // Peripheal Control
|
||||
uint8_t vACR; // Auxiliary Control
|
||||
uint8_t vIFR; // Interrupt Flag
|
||||
uint8_t vIER; // Interrupt Enable
|
||||
uint8_t vSR; // Shift register
|
||||
uint16_t vT1L; // Timer 1 latch
|
||||
uint16_t vT1C; // Timer 1 counter
|
||||
uint16_t vT2L; // Timer 2 latch
|
||||
uint16_t vT2C; // Timer 2 counter
|
||||
VIA_ISR_t vISR[8]; // ISRs to automatically call when interrupt is raised
|
||||
} VIA_State_t;
|
||||
|
||||
void VIA1_ShiftInData(uint8_t v);
|
||||
uint8_t VIA1_ShiftOutData(void);
|
||||
/* Names from SY6522 datasheet */
|
||||
typedef enum {
|
||||
rIRB = 0, // Data Register B
|
||||
rIRA = 1, // Data Register A
|
||||
rDDRB = 2, // Data Direction B
|
||||
rDDRA = 3, // Data Direction A
|
||||
rT1CL = 4, // Timer 1 Counter (low)
|
||||
rT1CH = 5, // Timer 1 Counter (high)
|
||||
rT1LL = 6, // Timer 1 Latches (low)
|
||||
rT1LH = 7, // Timer 1 Latches (high)
|
||||
rT2CL = 8, // Timer 1 Counter (low)
|
||||
rT2CH = 9, // Timer 1 Latches (high)
|
||||
rSR = 10, // Shift Register
|
||||
rACR = 11, // Auxiliary Control
|
||||
rPCR = 12, // Peripheal Control
|
||||
rIFR = 13, // Interrupt Flag
|
||||
rIER = 14, // Interrupt Enable
|
||||
rORA = 15, // duplicate of IRA w/o handshake (unused)
|
||||
rINVALID = 16, // end of list
|
||||
} VIA_Register_t;
|
||||
|
||||
#endif
|
||||
/// PUBLIC FUNCTIONS /////////////////////////////////////////////////////////
|
||||
|
||||
// Hardware reset
|
||||
bool VIA_Zap(void);
|
||||
// Software reset
|
||||
void VIA_Reset(void);
|
||||
|
||||
// Raise an interrupt by irq number, calling registered ISR if required
|
||||
void VIA_RaiseInterrupt(uint8_t id, uint8_t irq);
|
||||
// Register a VIA interrupt service routine
|
||||
void VIA_RegisterISR(uint8_t id, uint8_t irq, VIA_ISR_t isr);
|
||||
|
||||
// Tick all timers by one step (call every 1.2766 us)
|
||||
void VIA_TickTimers();
|
||||
|
||||
// Write to a register
|
||||
void VIA_Write(uint8_t id, VIA_Register_t reg, uint8_t data);
|
||||
// Read to a register
|
||||
uint8_t VIA_Read(uint8_t id, VIA_Register_t reg);
|
||||
// Read a single bit
|
||||
bool VIA_ReadBit(uint8_t id, VIA_Register_t reg, uint8_t bit);
|
||||
// Write a single bit
|
||||
void VIA_WriteBit(uint8_t id, VIA_Register_t reg, uint8_t bit, bool set);
|
||||
|
||||
// NOTE: for these, raise the interrupt manually w/ VIA_RaiseInterrupt
|
||||
void VIA_ShiftInData(uint8_t id, uint8_t v);
|
||||
uint8_t VIA_ShiftOutData(uint8_t id);
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "HW/M68K/M68KITAB.h"
|
||||
#include "HW/M68K/MINEM68K.h"
|
||||
#include "HW/VIA/VIAEMDEV.h"
|
||||
#include "HW/VIA/VIA2EMDV.h"
|
||||
#include "HW/DISK/IWMEMDEV.h"
|
||||
#include "HW/SCC/SCCEMDEV.h"
|
||||
#include "HW/RTC/RTCEMDEV.h"
|
||||
@ -133,23 +132,13 @@ const DevMethods_t DEVICES[] = {
|
||||
},
|
||||
// VIA1
|
||||
{
|
||||
.init = VIA1_Zap,
|
||||
.reset = VIA1_Reset,
|
||||
.starttick = NULL,
|
||||
.init = VIA_Zap,
|
||||
.reset = VIA_Reset,
|
||||
.starttick = VIA_TickTimers,
|
||||
.endtick = NULL,
|
||||
.subtick = NULL,
|
||||
.timebegin = VIA1_ExtraTimeBegin,
|
||||
.timeend = VIA1_ExtraTimeEnd,
|
||||
},
|
||||
// VIA2
|
||||
{
|
||||
.init = NULL,
|
||||
.reset = EmVIA2 ? VIA2_Zap : NULL,
|
||||
.starttick = NULL,
|
||||
.endtick = NULL,
|
||||
.subtick = NULL,
|
||||
.timebegin = EmVIA2 ? VIA2_ExtraTimeBegin : NULL,
|
||||
.timeend = EmVIA2 ? VIA2_ExtraTimeEnd : NULL,
|
||||
.timebegin = NULL,
|
||||
.timeend = NULL,
|
||||
},
|
||||
// Sony disk drive
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user