mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 21:29:28 +00:00
ESCC: connect NULL and STDIO backends.
This commit is contained in:
parent
d4c08bbe31
commit
e0b94e0b47
145
devices/serial/chario.cpp
Normal file
145
devices/serial/chario.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
(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/>.
|
||||
*/
|
||||
|
||||
/** Character I/O backend implementations. */
|
||||
|
||||
#include <devices/serial/chario.h>
|
||||
#include <loguru.hpp>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
|
||||
bool CharIoNull::rcv_char_available()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int CharIoNull::xmit_char(uint8_t c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CharIoNull::rcv_char(uint8_t *c)
|
||||
{
|
||||
*c = 0xFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//======================== STDIO character I/O backend ========================
|
||||
#ifndef _WIN32
|
||||
|
||||
#include<signal.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct sigaction old_act, new_act;
|
||||
struct termios orig_termios;
|
||||
|
||||
void mysig_handler(int signum)
|
||||
{
|
||||
// restore original terminal state
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
||||
|
||||
// restore original signal handler for SIGINT
|
||||
signal(SIGINT, old_act.sa_handler);
|
||||
|
||||
LOG_F(INFO, "Old terminal state restored, SIG#=%d", signum);
|
||||
|
||||
// re-post signal
|
||||
raise(signum);
|
||||
}
|
||||
|
||||
int CharIoStdin::rcv_enable()
|
||||
{
|
||||
if (this->stdio_inited)
|
||||
return 0;
|
||||
|
||||
// save original terminal state
|
||||
tcgetattr(STDIN_FILENO, &orig_termios);
|
||||
|
||||
struct termios new_termios = orig_termios;
|
||||
|
||||
new_termios.c_cflag &= ~(CSIZE | PARENB);
|
||||
new_termios.c_cflag |= CS8;
|
||||
new_termios.c_lflag &= ~(ECHO | ICANON);
|
||||
new_termios.c_iflag &= ~(ICRNL);
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
|
||||
|
||||
// save original signal handler for SIGINT
|
||||
//struct sigaction new_act;
|
||||
memset(&new_act, 0, sizeof(new_act));
|
||||
new_act.sa_handler = mysig_handler;
|
||||
sigaction(SIGINT, &new_act, &old_act);
|
||||
|
||||
// redirect SIGINT to new handler
|
||||
//signal(SIGINT, mysig_handler);
|
||||
|
||||
this->stdio_inited = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CharIoStdin::rcv_disable()
|
||||
{
|
||||
if (!this->stdio_inited)
|
||||
return;
|
||||
|
||||
// restore original terminal state
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
||||
|
||||
// restore original signal handler for SIGINT
|
||||
signal(SIGINT, old_act.sa_handler);
|
||||
|
||||
this->stdio_inited = false;
|
||||
}
|
||||
|
||||
bool CharIoStdin::rcv_char_available()
|
||||
{
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
fd_set savefds = readfds;
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
int chr;
|
||||
|
||||
int sel_rv = select(1, &readfds, NULL, NULL, &timeout);
|
||||
return sel_rv > 0;
|
||||
}
|
||||
|
||||
int CharIoStdin::xmit_char(uint8_t c)
|
||||
{
|
||||
write(STDOUT_FILENO, &c, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CharIoStdin::rcv_char(uint8_t *c)
|
||||
{
|
||||
read(STDIN_FILENO, c, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
78
devices/serial/chario.h
Normal file
78
devices/serial/chario.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
(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/>.
|
||||
*/
|
||||
|
||||
/** Character I/O definitions. */
|
||||
|
||||
#ifndef CHAR_IO_H
|
||||
#define CHAR_IO_H
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CHARIO_BE_NULL = 0, // NULL backend: swallows everything, receives nothing
|
||||
CHARIO_BE_STDIO = 1, // STDIO backend: uses STDIN for input and STDOUT for output
|
||||
};
|
||||
|
||||
/** Interface for character I/O backends. */
|
||||
class CharIoBackEnd {
|
||||
public:
|
||||
CharIoBackEnd() = default;
|
||||
virtual ~CharIoBackEnd() = default;
|
||||
|
||||
virtual int rcv_enable() { return 0; };
|
||||
virtual void rcv_disable() {};
|
||||
virtual bool rcv_char_available() = 0;
|
||||
virtual int xmit_char(uint8_t c) = 0;
|
||||
virtual int rcv_char(uint8_t *c) = 0;
|
||||
};
|
||||
|
||||
/** Null character I/O backend. */
|
||||
class CharIoNull : public CharIoBackEnd {
|
||||
public:
|
||||
CharIoNull() = default;
|
||||
~CharIoNull() = default;
|
||||
|
||||
bool rcv_char_available();
|
||||
int xmit_char(uint8_t c);
|
||||
int rcv_char(uint8_t *c);
|
||||
};
|
||||
|
||||
/** Stdin character I/O backend. */
|
||||
class CharIoStdin : public CharIoBackEnd {
|
||||
public:
|
||||
CharIoStdin() { this->stdio_inited = false; };
|
||||
~CharIoStdin() = default;
|
||||
|
||||
int rcv_enable();
|
||||
void rcv_disable();
|
||||
bool rcv_char_available();
|
||||
int xmit_char(uint8_t c);
|
||||
int rcv_char(uint8_t *c);
|
||||
|
||||
private:
|
||||
bool stdio_inited;
|
||||
};
|
||||
|
||||
#endif // CHAR_IO_H
|
@ -21,11 +21,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file Enhanced Serial Communications Controller (ESCC) emulation. */
|
||||
|
||||
#include "escc.h"
|
||||
#include <devices/serial/chario.h>
|
||||
#include <devices/serial/escc.h>
|
||||
#include <loguru.hpp>
|
||||
#include <machines/machineproperties.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/** Remap the compatible addressing scheme to MacRISC one. */
|
||||
const uint8_t compat_to_macrisc[6] = {
|
||||
@ -36,9 +39,17 @@ const uint8_t compat_to_macrisc[6] = {
|
||||
|
||||
EsccController::EsccController()
|
||||
{
|
||||
// allocate channels
|
||||
this->ch_a = std::unique_ptr<EsccChannel> (new EsccChannel("A"));
|
||||
this->ch_b = std::unique_ptr<EsccChannel> (new EsccChannel("B"));
|
||||
|
||||
// attach backends
|
||||
std::string backend_name = GET_STR_PROP("serial_backend");
|
||||
|
||||
this->ch_a->attach_backend(
|
||||
(backend_name == "stdio") ? CHARIO_BE_STDIO : CHARIO_BE_NULL);
|
||||
this->ch_b->attach_backend(CHARIO_BE_NULL);
|
||||
|
||||
this->reg_ptr = 0;
|
||||
}
|
||||
|
||||
@ -144,9 +155,25 @@ void EsccController::write_internal(EsccChannel *ch, uint8_t value)
|
||||
}
|
||||
|
||||
// ======================== ESCC Channel methods ==============================
|
||||
void EsccChannel::attach_backend(int id)
|
||||
{
|
||||
switch(id) {
|
||||
case CHARIO_BE_NULL:
|
||||
this->chario = std::unique_ptr<CharIoBackEnd> (new CharIoNull);
|
||||
break;
|
||||
case CHARIO_BE_STDIO:
|
||||
this->chario = std::unique_ptr<CharIoBackEnd> (new CharIoStdin);
|
||||
break;
|
||||
default:
|
||||
LOG_F(ERROR, "ESCC: unknown backend ID %d, using NULL instead", id);
|
||||
this->chario = std::unique_ptr<CharIoBackEnd> (new CharIoNull);
|
||||
}
|
||||
}
|
||||
|
||||
void EsccChannel::reset(bool hw_reset)
|
||||
{
|
||||
this->chario->rcv_disable();
|
||||
|
||||
this->write_regs[1] &= 0x24;
|
||||
this->write_regs[3] &= 0xFE;
|
||||
this->write_regs[4] |= 0x04;
|
||||
@ -184,15 +211,22 @@ void EsccChannel::write_reg(int reg_num, uint8_t value)
|
||||
{
|
||||
switch (reg_num) {
|
||||
case 3:
|
||||
if (value & 0x11) {
|
||||
if ((this->write_regs[3] ^ value) & 0x10) {
|
||||
this->write_regs[3] |= 0x10;
|
||||
this->read_regs[0] |= 0x10; // set SYNC_HUNT flag
|
||||
LOG_F(9, "ESCC: Hunt mode entered.");
|
||||
}
|
||||
if ((this->write_regs[3] ^ value) & 0x10) {
|
||||
this->write_regs[3] |= 0x10;
|
||||
this->read_regs[0] |= 0x10; // set SYNC_HUNT flag
|
||||
LOG_F(9, "ESCC: Hunt mode entered.");
|
||||
}
|
||||
if ((this->write_regs[3] ^ value) & 1) {
|
||||
if (value & 1) {
|
||||
this->write_regs[3] |= 0x1;
|
||||
this->chario->rcv_enable();
|
||||
LOG_F(9, "ESCC: receiver enabled.");
|
||||
} else {
|
||||
this->write_regs[3] ^= 0x1;
|
||||
this->chario->rcv_disable();
|
||||
LOG_F(9, "ESCC: receiver disabled.");
|
||||
this->write_regs[3] |= 0x10; // enter HUNT mode
|
||||
this->read_regs[0] |= 0x10; // set SYNC_HUNT flag
|
||||
}
|
||||
}
|
||||
this->write_regs[3] = (this->write_regs[3] & 0x11) | (value & 0xEE);
|
||||
@ -205,6 +239,8 @@ void EsccChannel::write_reg(int reg_num, uint8_t value)
|
||||
break;
|
||||
case 14:
|
||||
switch (value >> 5) {
|
||||
case DPLL_NULL_CMD:
|
||||
break;
|
||||
case DPLL_ENTER_SRC_MODE:
|
||||
this->dpll_active = 1;
|
||||
this->read_regs[10] &= 0x3F;
|
||||
@ -245,16 +281,28 @@ void EsccChannel::write_reg(int reg_num, uint8_t value)
|
||||
|
||||
uint8_t EsccChannel::read_reg(int reg_num)
|
||||
{
|
||||
if (!reg_num) {
|
||||
if (this->chario->rcv_char_available()) {
|
||||
this->read_regs[0] |= 1;
|
||||
}
|
||||
}
|
||||
return this->read_regs[reg_num];
|
||||
}
|
||||
|
||||
void EsccChannel::send_byte(uint8_t value)
|
||||
{
|
||||
// Put one byte into the Data FIFO
|
||||
// TODO: put one byte into the Data FIFO
|
||||
|
||||
this->chario->xmit_char(value);
|
||||
}
|
||||
|
||||
uint8_t EsccChannel::receive_byte()
|
||||
{
|
||||
// Remove one byte from the Receive FIFO
|
||||
return 0xFF;
|
||||
// TODO: remove one byte from the Receive FIFO
|
||||
|
||||
uint8_t c;
|
||||
|
||||
this->chario->rcv_char(&c);
|
||||
this->read_regs[0] &= ~1;
|
||||
return c;
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef ESCC_H
|
||||
#define ESCC_H
|
||||
|
||||
#include <devices/serial/chario.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -71,6 +73,7 @@ enum {
|
||||
|
||||
/** DPLL commands in WR14. */
|
||||
enum {
|
||||
DPLL_NULL_CMD = 0,
|
||||
DPLL_ENTER_SRC_MODE = 1,
|
||||
DPLL_RST_MISSING_CLK = 2,
|
||||
DPLL_DISABLE = 3,
|
||||
@ -91,6 +94,7 @@ public:
|
||||
EsccChannel(std::string name) { this->name = name; };
|
||||
~EsccChannel() = default;
|
||||
|
||||
void attach_backend(int id);
|
||||
void reset(bool hw_reset);
|
||||
uint8_t read_reg(int reg_num);
|
||||
void write_reg(int reg_num, uint8_t value);
|
||||
@ -107,6 +111,8 @@ private:
|
||||
uint8_t dpll_clock_src;
|
||||
uint8_t brg_active;
|
||||
uint8_t brg_clock_src;
|
||||
|
||||
std::unique_ptr<CharIoBackEnd> chario;
|
||||
};
|
||||
|
||||
/** ESCC Controller class. */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-21 divingkatae and maximum
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -69,6 +69,8 @@ static const map<uint32_t, std::tuple<string, const char*>> rom_identity = {
|
||||
|
||||
static const vector<string> WriteToggle = {"ON", "on", "OFF", "off"};
|
||||
|
||||
static const vector<string> CharIoBackends = {"null", "stdio"};
|
||||
|
||||
static const PropMap CatalystSettings = {
|
||||
{"rambank1_size",
|
||||
new IntProperty(16, vector<uint32_t>({4, 8, 16, 32, 64, 128}))},
|
||||
@ -84,6 +86,7 @@ static const PropMap CatalystSettings = {
|
||||
new StrProperty("")},
|
||||
{"fdd_img",
|
||||
new StrProperty("")},
|
||||
{"serial_backend", new StrProperty("null", CharIoBackends)},
|
||||
};
|
||||
|
||||
static const PropMap GossamerSettings = {
|
||||
@ -100,6 +103,7 @@ static const PropMap GossamerSettings = {
|
||||
{"fdd_img",
|
||||
new StrProperty("")},
|
||||
{"fdd_wr_prot", new StrProperty("OFF", WriteToggle)},
|
||||
{"serial_backend", new StrProperty("null", CharIoBackends)},
|
||||
};
|
||||
|
||||
/** Monitors supported by the PDM on-board video. */
|
||||
@ -121,6 +125,7 @@ static const PropMap PDMSettings = {
|
||||
new StrProperty("")},
|
||||
{"fdd_wr_prot",
|
||||
new StrProperty("OFF", WriteToggle)},
|
||||
{"serial_backend", new StrProperty("null", CharIoBackends)},
|
||||
};
|
||||
|
||||
static const map<string, string> PropHelp = {
|
||||
@ -132,6 +137,7 @@ static const map<string, string> PropHelp = {
|
||||
{"fdd_img", "specifies path to floppy disk image"},
|
||||
{"fdd_wr_prot", "toggles floppy disks write protection"},
|
||||
{"mon_id", "specifies which monitor to emulate"},
|
||||
{"serial_backend", "specifies the backend for the serial port"},
|
||||
};
|
||||
|
||||
static const map<string, tuple<PropMap, function<int(string&)>, string>> machines = {
|
||||
|
Loading…
Reference in New Issue
Block a user