From 514add67d8914df4342e10fcbe38279d89402fef Mon Sep 17 00:00:00 2001 From: InvisibleUp Date: Mon, 25 May 2020 21:49:45 -0400 Subject: [PATCH] Begin a WIP rewrite of VIAEMDEV.c Beyond the over-reliance on #ifdefs for servicing interrupts (which breaks pretty much everything), my gut's telling me that it's just not the best implementation. IDK. Let's see where this goes. --- _work/VIAEMDEV.c | 300 ++++++++++++++++++++++++++++++++++++++++++ src/HW/VIA/VIAEMDEV.c | 2 +- src/HW/VIA/VIAEMDEV.h | 37 +++--- src/PROGMAIN.c | 4 +- 4 files changed, 318 insertions(+), 25 deletions(-) create mode 100644 _work/VIAEMDEV.c diff --git a/_work/VIAEMDEV.c b/_work/VIAEMDEV.c new file mode 100644 index 0000000..7af177c --- /dev/null +++ b/_work/VIAEMDEV.c @@ -0,0 +1,300 @@ +/* + 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 +#include +#include +#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; + +} diff --git a/src/HW/VIA/VIAEMDEV.c b/src/HW/VIA/VIAEMDEV.c index 0791da9..1366182 100644 --- a/src/HW/VIA/VIAEMDEV.c +++ b/src/HW/VIA/VIAEMDEV.c @@ -17,7 +17,7 @@ /* Versatile Interface Adapter EMulated DEVice - Emulates the VIA found in the Mac Plus. + Emulates the Synertek SY6522 VIA found up until the Mac Plus. This code adapted from vMac by Philip Cummins. */ diff --git a/src/HW/VIA/VIAEMDEV.h b/src/HW/VIA/VIAEMDEV.h index d45b8b1..d206029 100644 --- a/src/HW/VIA/VIAEMDEV.h +++ b/src/HW/VIA/VIAEMDEV.h @@ -16,32 +16,25 @@ #ifndef VIAEMDEV_H #define VIAEMDEV_H +#include -EXPORTPROC VIA1_Zap(void); -EXPORTPROC VIA1_Reset(void); +void VIA1_Zap(void); +void VIA1_Reset(void); -EXPORTFUNC uint32_t VIA1_Access(uint32_t Data, bool WriteMem, CPTR addr); +uint32_t VIA1_Access(uint32_t Data, bool WriteMem, uint32_t addr); -EXPORTPROC VIA1_ExtraTimeBegin(void); -EXPORTPROC VIA1_ExtraTimeEnd(void); -#ifdef VIA1_iCA1_PulseNtfy -EXPORTPROC VIA1_iCA1_PulseNtfy(void); -#endif -#ifdef VIA1_iCA2_PulseNtfy -EXPORTPROC VIA1_iCA2_PulseNtfy(void); -#endif -#ifdef VIA1_iCB1_PulseNtfy -EXPORTPROC VIA1_iCB1_PulseNtfy(void); -#endif -#ifdef VIA1_iCB2_PulseNtfy -EXPORTPROC VIA1_iCB2_PulseNtfy(void); -#endif -EXPORTPROC VIA1_DoTimer1Check(void); -EXPORTPROC VIA1_DoTimer2Check(void); +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); -EXPORTFUNC uint16_t VIA1_GetT1InvertTime(void); +uint16_t VIA1_GetT1InvertTime(void); -EXPORTPROC VIA1_ShiftInData(uint8_t v); -EXPORTFUNC uint8_t VIA1_ShiftOutData(void); +void VIA1_ShiftInData(uint8_t v); +uint8_t VIA1_ShiftOutData(void); #endif diff --git a/src/PROGMAIN.c b/src/PROGMAIN.c index 590fc44..aa4ec55 100644 --- a/src/PROGMAIN.c +++ b/src/PROGMAIN.c @@ -137,8 +137,8 @@ const DevMethods_t DEVICES[] = { }, // VIA1 { - .init = NULL, - .reset = VIA1_Zap, + .init = VIA1_Zap, + .reset = VIA1_Reset, .starttick = NULL, .endtick = NULL, .subtick = NULL,