2020-02-28 16:04:28 +00:00
|
|
|
/*
|
|
|
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
2021-10-23 19:00:31 +00:00
|
|
|
Copyright (C) 2018-21 divingkatae and maximum
|
2020-02-28 16:04:28 +00:00
|
|
|
(theweirdo) spatium
|
|
|
|
|
|
|
|
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program 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
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2019-08-27 12:14:12 +00:00
|
|
|
|
2019-08-28 00:39:29 +00:00
|
|
|
/** VIA-CUDA combo device emulation.
|
|
|
|
|
|
|
|
Author: Max Poliakovski 2019
|
|
|
|
|
|
|
|
Versatile interface adapter (VIA) is an old I/O controller that can be found
|
|
|
|
in nearly every Macintosh computer. In the 68k era, VIA was used to control
|
|
|
|
various peripherial devices. In a Power Macintosh, its function is limited
|
|
|
|
to the I/O interface for the Cuda MCU. I therefore decided to put VIA
|
|
|
|
emulation code here.
|
|
|
|
|
|
|
|
Cuda MCU is a multipurpose IC built around a custom version of the Motorola
|
|
|
|
MC68HC05 microcontroller. It provides several functions including:
|
|
|
|
- Apple Desktop Bus (ADB) master
|
|
|
|
- I2C bus master
|
|
|
|
- Realtime clock (RTC)
|
2019-09-21 12:54:53 +00:00
|
|
|
- parameter RAM (first generation of the Power Macintosh)
|
2019-08-28 00:39:29 +00:00
|
|
|
- power management
|
|
|
|
|
|
|
|
MC68HC05 doesn't provide any dedicated hardware for serial communication
|
|
|
|
protocols. All signals required for ADB and I2C will be generated by Cuda
|
|
|
|
firmware using bit banging (https://en.wikipedia.org/wiki/Bit_banging).
|
|
|
|
*/
|
|
|
|
|
2019-08-27 12:14:12 +00:00
|
|
|
#ifndef VIACUDA_H
|
|
|
|
#define VIACUDA_H
|
|
|
|
|
2021-10-23 18:17:47 +00:00
|
|
|
#include <devices/common/adb/adb.h>
|
|
|
|
#include <devices/common/hwcomponent.h>
|
|
|
|
#include <devices/common/i2c/i2c.h>
|
|
|
|
#include <devices/common/nvram.h>
|
|
|
|
|
2021-10-13 22:01:30 +00:00
|
|
|
#include <memory>
|
2020-03-14 13:23:46 +00:00
|
|
|
|
2019-08-27 12:14:12 +00:00
|
|
|
/** VIA register offsets. */
|
|
|
|
enum {
|
|
|
|
VIA_B = 0x00, /* input/output register B */
|
|
|
|
VIA_A = 0x01, /* input/output register A */
|
|
|
|
VIA_DIRB = 0x02, /* direction B */
|
|
|
|
VIA_DIRA = 0x03, /* direction A */
|
|
|
|
VIA_T1CL = 0x04, /* low-order timer 1 counter */
|
|
|
|
VIA_T1CH = 0x05, /* high-order timer 1 counter */
|
|
|
|
VIA_T1LL = 0x06, /* low-order timer 1 latches */
|
|
|
|
VIA_T1LH = 0x07, /* high-order timer 1 latches */
|
|
|
|
VIA_T2CL = 0x08, /* low-order timer 2 latches */
|
|
|
|
VIA_T2CH = 0x09, /* high-order timer 2 counter */
|
|
|
|
VIA_SR = 0x0A, /* shift register */
|
|
|
|
VIA_ACR = 0x0B, /* auxiliary control register */
|
|
|
|
VIA_PCR = 0x0C, /* periheral control register */
|
|
|
|
VIA_IFR = 0x0D, /* interrupt flag register */
|
|
|
|
VIA_IER = 0x0E, /* interrupt enable register */
|
|
|
|
VIA_ANH = 0x0F, /* input/output register A, no handshake */
|
|
|
|
};
|
|
|
|
|
2019-09-21 12:54:53 +00:00
|
|
|
/** Cuda communication signals. */
|
|
|
|
enum {
|
|
|
|
CUDA_TIP = 0x20, /* transaction in progress: 0 - true, 1 - false */
|
|
|
|
CUDA_BYTEACK = 0x10, /* byte acknowledge: 0 - true, 1 - false */
|
|
|
|
CUDA_TREQ = 0x08 /* Cuda requests transaction from host */
|
|
|
|
};
|
|
|
|
|
2019-10-07 01:18:18 +00:00
|
|
|
/** Cuda packet types. */
|
|
|
|
enum {
|
|
|
|
CUDA_PKT_ADB = 0,
|
|
|
|
CUDA_PKT_PSEUDO = 1,
|
|
|
|
CUDA_PKT_ERROR = 2,
|
|
|
|
CUDA_PKT_TICK = 3,
|
|
|
|
CUDA_PKT_POWER = 4
|
|
|
|
};
|
|
|
|
|
2019-09-21 12:54:53 +00:00
|
|
|
/** Cuda pseudo commands. */
|
|
|
|
enum {
|
2020-05-12 18:55:45 +00:00
|
|
|
CUDA_START_STOP_AUTOPOLL = 0x01, /* start/stop device auto-polling */
|
2021-10-17 20:31:54 +00:00
|
|
|
CUDA_READ_MCU_MEM = 0x02, /* read internal Cuda memory */
|
2020-05-12 18:55:45 +00:00
|
|
|
CUDA_READ_PRAM = 0x07, /* read parameter RAM */
|
2021-10-17 20:31:54 +00:00
|
|
|
CUDA_WRITE_MCU_MEM = 0x08, /* write internal Cuda memory */
|
2020-05-12 18:55:45 +00:00
|
|
|
CUDA_WRITE_PRAM = 0x0C, /* write parameter RAM */
|
|
|
|
CUDA_SET_AUTOPOLL_RATE = 0x14, /* set auto-polling rate */
|
|
|
|
CUDA_GET_AUTOPOLL_RATE = 0x16, /* get auto-polling rate */
|
|
|
|
CUDA_READ_WRITE_I2C = 0x22, /* read/write I2C device */
|
|
|
|
CUDA_COMB_FMT_I2C = 0x25, /* combined format I2C transaction */
|
|
|
|
CUDA_OUT_PB0 = 0x26, /* output one bit to Cuda's PB0 line */
|
2019-09-21 12:54:53 +00:00
|
|
|
};
|
|
|
|
|
2019-10-07 01:18:18 +00:00
|
|
|
/** Cuda error codes. */
|
|
|
|
enum {
|
2020-03-15 12:28:35 +00:00
|
|
|
CUDA_ERR_BAD_PKT = 1, /* invalid packet type */
|
|
|
|
CUDA_ERR_BAD_CMD = 2, /* invalid pseudo command */
|
|
|
|
CUDA_ERR_BAD_SIZE = 3, /* invalid packet size */
|
2021-10-13 22:01:30 +00:00
|
|
|
CUDA_ERR_BAD_PAR = 4, /* invalid parameter */
|
2020-03-15 12:28:35 +00:00
|
|
|
CUDA_ERR_I2C = 5 /* invalid I2C data or no acknowledge */
|
2019-10-07 01:18:18 +00:00
|
|
|
};
|
|
|
|
|
2021-10-17 20:31:54 +00:00
|
|
|
/** PRAM addresses within Cuda's internal memory */
|
|
|
|
#define CUDA_PRAM_START 0x100 // starting address of PRAM
|
|
|
|
#define CUDA_PRAM_END 0x1FF // last byte of PRAM
|
|
|
|
#define CUDA_ROM_START 0xF00 // starting address of ROM containing Cuda FW
|
|
|
|
|
|
|
|
/** Latest Cuda Firmware version. */
|
|
|
|
#define CUDA_FW_VERSION_MAJOR 0x0002
|
|
|
|
#define CUDA_FW_VERSION_MINOR 0x0029
|
2019-09-21 12:54:53 +00:00
|
|
|
|
2020-05-12 18:55:45 +00:00
|
|
|
class ViaCuda : public HWComponent, public I2CBus {
|
2019-08-27 12:14:12 +00:00
|
|
|
public:
|
2020-01-15 17:15:08 +00:00
|
|
|
ViaCuda();
|
2021-10-13 22:01:30 +00:00
|
|
|
~ViaCuda() = default;
|
2019-08-27 12:14:12 +00:00
|
|
|
|
2020-03-14 13:23:46 +00:00
|
|
|
bool supports_type(HWCompType type) {
|
|
|
|
return (type == HWCompType::ADB_HOST || type == HWCompType::I2C_HOST);
|
|
|
|
};
|
|
|
|
|
2019-08-27 12:14:12 +00:00
|
|
|
uint8_t read(int reg);
|
|
|
|
void write(int reg, uint8_t value);
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint8_t via_regs[16]; /* VIA virtual registers */
|
|
|
|
|
2019-09-21 12:54:53 +00:00
|
|
|
/* Cuda state. */
|
|
|
|
uint8_t old_tip;
|
|
|
|
uint8_t old_byteack;
|
|
|
|
uint8_t treq;
|
|
|
|
uint8_t in_buf[16];
|
|
|
|
int32_t in_count;
|
|
|
|
uint8_t out_buf[16];
|
|
|
|
int32_t out_count;
|
|
|
|
int32_t out_pos;
|
2020-04-27 00:50:40 +00:00
|
|
|
uint8_t poll_rate;
|
2019-09-21 12:54:53 +00:00
|
|
|
|
2021-10-17 20:31:54 +00:00
|
|
|
bool is_open_ended; // true if current transaction is open-ended
|
|
|
|
uint8_t curr_i2c_addr; // current I2C address
|
|
|
|
uint8_t cur_pram_addr; // current PRAM address, range 0...FF
|
2020-03-15 12:28:35 +00:00
|
|
|
|
|
|
|
void (ViaCuda::*out_handler)(void);
|
|
|
|
void (ViaCuda::*next_out_handler)(void);
|
|
|
|
|
2021-10-13 22:01:30 +00:00
|
|
|
std::unique_ptr<NVram> pram_obj;
|
2020-04-22 21:14:49 +00:00
|
|
|
ADB_Bus* adb_obj;
|
2020-01-13 03:31:10 +00:00
|
|
|
|
2019-08-27 12:14:12 +00:00
|
|
|
void print_enabled_ints(); /* print enabled VIA interrupts and their sources */
|
2019-09-21 12:54:53 +00:00
|
|
|
|
2020-03-04 14:46:51 +00:00
|
|
|
void init();
|
|
|
|
bool ready();
|
2019-09-21 12:54:53 +00:00
|
|
|
void assert_sr_int();
|
2020-03-04 14:46:51 +00:00
|
|
|
void write(uint8_t new_state);
|
|
|
|
void response_header(uint32_t pkt_type, uint32_t pkt_flag);
|
|
|
|
void error_response(uint32_t error);
|
|
|
|
void process_packet();
|
2020-03-05 00:12:27 +00:00
|
|
|
void process_adb_command(uint8_t cmd_byte, int data_count);
|
2020-03-04 14:46:51 +00:00
|
|
|
void pseudo_command(int cmd, int data_count);
|
2019-10-07 01:18:18 +00:00
|
|
|
|
2020-03-15 12:28:35 +00:00
|
|
|
void null_out_handler(void);
|
2021-10-13 22:01:30 +00:00
|
|
|
void pram_out_handler(void);
|
2020-03-15 12:28:35 +00:00
|
|
|
void out_buf_handler(void);
|
|
|
|
void i2c_handler(void);
|
|
|
|
|
2019-10-07 01:18:18 +00:00
|
|
|
/* I2C related methods */
|
2020-03-04 14:46:51 +00:00
|
|
|
void i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf, int in_bytes);
|
2020-05-12 18:55:45 +00:00
|
|
|
void i2c_comb_transaction(
|
|
|
|
uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1, const uint8_t* in_buf, int in_bytes);
|
2019-08-27 12:14:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* VIACUDA_H */
|