From 597c9271608c3d30ce193b96be3fe82966e4cc1d Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Thu, 23 Apr 2020 16:35:50 +0200 Subject: qtmips_cli: add option to connect serial port input and output to file. New options --serial-in, --serin File connected to the serial port input. --serial-out, --serout File connected to the serial port output. to provide support for B35APO subject task to write conversion of the random binary number to hexadecimal output to serial port. See the task with automatic check using qtmips_cli seminaries/qtmips/print-hex-to-uart in the repository https://gitlab.fel.cvut.cz/b35apo/stud-support/ Signed-off-by: Pavel Pisa --- qtmips_cli/chariohandler.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++ qtmips_cli/chariohandler.h | 85 +++++++++++++++++++++++ qtmips_cli/main.cpp | 57 ++++++++++++++++ qtmips_cli/qtmips_cli.pro | 6 +- 4 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 qtmips_cli/chariohandler.cpp create mode 100644 qtmips_cli/chariohandler.h diff --git a/qtmips_cli/chariohandler.cpp b/qtmips_cli/chariohandler.cpp new file mode 100644 index 0000000..6d9c6e1 --- /dev/null +++ b/qtmips_cli/chariohandler.cpp @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0+ +/******************************************************************************* + * QtMips - MIPS 32-bit Architecture Subset Simulator + * + * Implemented to support following courses: + * + * B35APO - Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b35apo + * + * B4M35PAP - Advanced Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start + * + * Copyright (c) 2017-2019 Karel Koci + * Copyright (c) 2019 Pavel Pisa + * + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ******************************************************************************/ + +#include + +CharIOHandler::CharIOHandler(QIODevice *iodev, QObject *parent) : + QIODevice(parent), fd_list() { + this->iodev = iodev; + if (!iodev->parent()) + iodev->setParent(this); + fd_specific = false; + if (iodev->isOpen()) + Super::open(iodev->openMode()); + connect(iodev, &Super::aboutToClose, this, &CharIOHandler::aboutToClose); + connect(iodev, &Super::bytesWritten, this, &CharIOHandler::bytesWritten); + connect(iodev, &Super::channelBytesWritten, this, &CharIOHandler::channelBytesWritten); + connect(iodev, &Super::channelReadyRead, this, &CharIOHandler::channelReadyRead); + connect(iodev, &Super::readChannelFinished, this, &CharIOHandler::readChannelFinished); + connect(iodev, &Super::readyRead, this, &CharIOHandler::readyRead); +} + +CharIOHandler::~CharIOHandler() { + if (iodev->parent() == this) + delete iodev; +} + +void CharIOHandler::writeByte(unsigned int data) { + char ch = (char)data; + write(&ch, 1); +} + +void CharIOHandler::writeByte(int fd, unsigned int data) { + if(!fd_specific || fd_list.contains(fd)) + writeByte(data); +} + +void CharIOHandler::readBytePoll(int fd, unsigned int &data, bool &available) { + char ch; + qint64 res; + if(!fd_specific || fd_list.contains(fd)) { + if (bytesAvailable() > 0) { + res = read(&ch, 1); + if (res > 0) { + data = ch & 0xff; + available = true; + } + } + } +} + +void CharIOHandler::insertFd(const int &fd) { + fd_list.insert(fd); +} + +void CharIOHandler::removeFd(const int &fd) { + fd_list.remove(fd); +} + +bool CharIOHandler::isSequential() const { + return iodev->isSequential(); +} + +bool CharIOHandler::open(OpenMode mode) { + if (!iodev->open(mode)) { + + return false; + } + Super::open(mode); + return true; +} + +void CharIOHandler::close() { + Super::close(); + iodev->close(); +} + +qint64 CharIOHandler::pos() const { + return iodev->pos(); +} + +qint64 CharIOHandler::size() const { + return iodev->size(); +} + +bool CharIOHandler::seek(qint64 pos) { + return iodev->seek(pos); +} + +bool CharIOHandler::atEnd() const { + return iodev->atEnd(); +} + +bool CharIOHandler::reset() { + return iodev->reset(); +} + +qint64 CharIOHandler::bytesAvailable() const { + return iodev->bytesAvailable() + Super::bytesAvailable(); +} + +qint64 CharIOHandler::bytesToWrite() const { + return iodev->bytesToWrite() + Super::bytesToWrite(); +} + +bool CharIOHandler::canReadLine() const { + return iodev->canReadLine(); +} + +bool CharIOHandler::waitForReadyRead(int msecs) { + return iodev->waitForReadyRead(msecs); +} + +bool CharIOHandler::waitForBytesWritten(int msecs) { + return iodev->waitForBytesWritten(msecs); +} + +qint64 CharIOHandler::readData(char *data, qint64 maxSize) { + return iodev->read(data, maxSize); +} + +qint64 CharIOHandler::readLineData(char *data, qint64 maxSize) { + return iodev->readLine(data, maxSize); +} + +qint64 CharIOHandler::writeData(const char *data, qint64 maxSize) { + return iodev->write(data, maxSize); +} diff --git a/qtmips_cli/chariohandler.h b/qtmips_cli/chariohandler.h new file mode 100644 index 0000000..a37a217 --- /dev/null +++ b/qtmips_cli/chariohandler.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/******************************************************************************* + * QtMips - MIPS 32-bit Architecture Subset Simulator + * + * Implemented to support following courses: + * + * B35APO - Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b35apo + * + * B4M35PAP - Advanced Computer Architectures + * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start + * + * Copyright (c) 2017-2019 Karel Koci + * Copyright (c) 2019 Pavel Pisa + * + * Faculty of Electrical Engineering (http://www.fel.cvut.cz) + * Czech Technical University (http://www.cvut.cz/) + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + ******************************************************************************/ + +#ifndef CHARIOHANDLER_H +#define CHARIOHANDLER_H + +#include +#include +#include + +class CharIOHandler : public QIODevice +{ + Q_OBJECT + + using Super = QIODevice; + +public: + explicit CharIOHandler(QIODevice *iodev, QObject *parent = nullptr); + virtual ~CharIOHandler() override; + +public slots: + void writeByte(unsigned int data); + void writeByte(int fd, unsigned int data); + void readBytePoll(int fd, unsigned int &data, bool &available); + +public: + void insertFd(const int &fd); + void removeFd(const int &fd); + + virtual bool isSequential() const override; + virtual bool open(OpenMode mode) override; + virtual void close() override; + virtual qint64 pos() const override; + virtual qint64 size() const override; + virtual bool seek(qint64 pos) override; + virtual bool atEnd() const override; + virtual bool reset() override; + virtual qint64 bytesAvailable() const override; + virtual qint64 bytesToWrite() const override; + virtual bool canReadLine() const override; + virtual bool waitForReadyRead(int msecs) override; + virtual bool waitForBytesWritten(int msecs) override; +protected: + virtual qint64 readData(char *data, qint64 maxSize) override; + virtual qint64 readLineData(char *data, qint64 maxSize) override; + virtual qint64 writeData(const char *data, qint64 maxSize) override; +private: + QIODevice *iodev; + bool fd_specific; + QSet fd_list; +}; + +#endif // CHARIOHANDLER_H diff --git a/qtmips_cli/main.cpp b/qtmips_cli/main.cpp index 2984d8c..6430695 100644 --- a/qtmips_cli/main.cpp +++ b/qtmips_cli/main.cpp @@ -44,6 +44,7 @@ #include "reporter.h" #include "msgreport.h" #include "simpleasm.h" +#include "chariohandler.h" using namespace machine; using namespace std; @@ -81,6 +82,8 @@ void create_parser(QCommandLineParser &p) { p.addOption({"read-time", "Memory read access time (cycles).", "RTIME"}); p.addOption({"write-time", "Memory read access time (cycles).", "WTIME"}); p.addOption({"burst-time", "Memory read access time (cycles).", "BTIME"}); + p.addOption({{"serial-in", "serin"}, "File connected to the serial port input.", "FNAME"}); + p.addOption({{"serial-out", "serout"}, "File connected to the serial port output.", "FNAME"}); } void configure_cache(MachineConfigCache &cacheconf, QStringList cachearg, QString which) { @@ -284,6 +287,58 @@ void configure_reporter(QCommandLineParser &p, Reporter &r, const SymbolTable *s // TODO } +void configure_serial_port(QCommandLineParser &p, SerialPort *ser_port) { + int siz; + CharIOHandler *ser_in = nullptr; + CharIOHandler *ser_out = nullptr; + + if (!ser_port) + return; + + siz = p.values("serial-in").size(); + if (siz >= 1) { + QIODevice::OpenMode mode = QFile::ReadOnly; + QFile *qf = new QFile(p.values("serial-in").at(siz - 1)); + ser_in = new CharIOHandler(qf, ser_port); + siz = p.values("serial-out").size(); + if (siz) { + if (p.values("serial-in").at(siz - 1) == p.values("serial-out").at(siz - 1)) { + mode = QFile::ReadWrite; + ser_out = ser_in; + } + } + if (!ser_in->open(mode)) { + cout << "Serial port input file cannot be open for read." << endl; + exit(1); + } + } + + if (!ser_out) { + siz = p.values("serial-out").size(); + if (siz >= 1) { + QFile *qf = new QFile(p.values("serial-out").at(siz - 1)); + ser_out = new CharIOHandler(qf, ser_port); + if (!ser_out->open(QFile::WriteOnly)) { + cout << "Serial port output file cannot be open for write." << endl; + exit(1); + } + } + } + + if (ser_in) { + ser_port->connect(ser_in, SIGNAL(readyRead()), ser_port, SLOT(rx_queue_check())); + ser_port->connect(ser_port, SIGNAL(rx_byte_pool(int,unsigned int&, bool&)), + ser_in, SLOT(readBytePoll(int,unsigned int&, bool&))); + if (ser_in->bytesAvailable()) + ser_port->rx_queue_check(); + } + + if (ser_out) { + ser_port->connect(ser_port, SIGNAL(tx_byte(unsigned int)), + ser_out, SLOT(writeByte(unsigned int))); + } +} + void load_ranges(QtMipsMachine &machine, const QStringList &ranges) { foreach (QString range_arg, ranges) { std::uint32_t start; @@ -371,6 +426,8 @@ int main(int argc, char *argv[]) { Reporter r(&app, &machine); configure_reporter(p, r, machine.symbol_table()); + configure_serial_port(p, machine.serial_port()); + if (asm_source) { MsgReport msgrep(&app); if (!assemble(machine, msgrep, p.positionalArguments()[0])) diff --git a/qtmips_cli/qtmips_cli.pro b/qtmips_cli/qtmips_cli.pro index ea692ec..eb7be14 100644 --- a/qtmips_cli/qtmips_cli.pro +++ b/qtmips_cli/qtmips_cli.pro @@ -34,9 +34,11 @@ SOURCES += \ main.cpp \ tracer.cpp \ reporter.cpp \ - msgreport.cpp + msgreport.cpp \ + chariohandler.cpp HEADERS += \ tracer.h \ reporter.h \ - msgreport.h + msgreport.h \ + chariohandler.h -- cgit v1.2.3