diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
index 7f79bcd738..33b54bb8e0 100644
--- a/.github/workflows/c-cpp.yml
+++ b/.github/workflows/c-cpp.yml
@@ -9,9 +9,18 @@ jobs:
steps:
- name: Install cross compile toolchain
- run: sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf
+ run: sudo apt-get install gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf binutils-arm-linux-gnueabihf libspdlog-dev
- uses: actions/checkout@v2
+ - name: dump arm gcc version
+ run: arm-linux-gnueabihf-gcc -v
+ working-directory: ./src/raspberrypi
+
+ - name: dump native gcc version
+ run: gcc -v
+ working-directory: ./src/raspberrypi
+
+
- name: make standard
run: make all DEBUG=1 CONNECT_TYPE=STANDARD
working-directory: ./src/raspberrypi
diff --git a/doc/rascsi.1 b/doc/rascsi.1
index d08cf8683d..07ab3e05bd 100644
--- a/doc/rascsi.1
+++ b/doc/rascsi.1
@@ -57,6 +57,6 @@ To create an empty, 100MB HD image, use the following command:
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800
.SH SEE ALSO
-rasctl(1), scsidump(1)
+rasctl(1), scsimon(1)
Full documentation is available at:
diff --git a/doc/rascsi_man_page.txt b/doc/rascsi_man_page.txt
index d7a26229a4..de2f98f830 100644
--- a/doc/rascsi_man_page.txt
+++ b/doc/rascsi_man_page.txt
@@ -2,7 +2,7 @@
!! ------ The native file is rascsi.1. Re-run 'make docs' after updating
-rascsi(1) General Commands Manual rascsi(1)
+rascsi(1) General Commands Manual rascsi(1)
NAME
rascsi - Emulates SCSI devices using the Raspberry Pi GPIO pins
@@ -13,10 +13,9 @@ SYNOPSIS
DESCRIPTION
rascsi Emulates SCSI devices using the Raspberry Pi GPIO pins.
- In the arguments to RaSCSI, one or more SCSI (-IDn) or SASI (-HDn) devices can be specified. The number (n)
- after the ID or HD idnetifier specifies the ID number for that device. For SCSI: The ID is limited from 0-7.
- However, typically SCSI ID 7 is reserved for the "initiator" (the host computer).Note that SASI is considered
- rare and only used on very early Sharp X68000 computers.
+ In the arguments to RaSCSI, one or more SCSI (-IDn) or SASI (-HDn) devices can be specified. The number (n) after the ID or HD idnetifier specifies the ID number for that device. For SCSI:
+ The ID is limited from 0-7. However, typically SCSI ID 7 is reserved for the "initiator" (the host computer).Note that SASI is considered rare and only used on very early Sharp X68000 com‐
+ puters.
RaSCSI will determin the type of device based upon the file extension of the FILE argument.
hdf: SASI Hard Disk image (XM6 SASI HD image - typically only used with X68000)
@@ -31,9 +30,8 @@ DESCRIPTION
For example, if you want to specify an Apple-compatible HD image on ID 0, you can use the following command:
sudo rascsi -ID0 /path/to/drive/hdimage.hda
- Once RaSCSI starts, it will open a socket (port 6868) to allow external management commands. If another
- process is using port 6868, RaSCSI will terminate, since it is likely another instance of RaSCSI. Once
- RaSCSI has initialized, the rasctl utility can be used to send commands.
+ Once RaSCSI starts, it will open a socket (port 6868) to allow external management commands. If another process is using port 6868, RaSCSI will terminate, since it is likely another in‐
+ stance of RaSCSI. Once RaSCSI has initialized, the rasctl utility can be used to send commands.
To quit RaSCSI, press Control + C. If it is running in the background, you can kill it using an INT signal.
@@ -61,8 +59,8 @@ EXAMPLES
dd if=/dev/zero of=/path/to/newimage.hda bs=512 count=204800
SEE ALSO
- rasctl(1), scsidump(1)
+ rasctl(1), scsimon(1)
Full documentation is available at:
- rascsi(1)
+ rascsi(1)
diff --git a/doc/rasctl.1 b/doc/rasctl.1
index be65b17830..1533a182a5 100644
--- a/doc/rasctl.1
+++ b/doc/rasctl.1
@@ -66,6 +66,6 @@ Request the RaSCSI process to attach a disk (assumed) to SCSI ID 0 with the cont
rasctl -i 0 -f HDIIMAGE0.HDS
.SH SEE ALSO
-rascsi(1)
+rascsi(1) scsimon(1)
Full documentation is available at:
diff --git a/doc/rasctl_man_page.txt b/doc/rasctl_man_page.txt
index 9f2d56422e..2b0498a8d8 100644
--- a/doc/rasctl_man_page.txt
+++ b/doc/rasctl_man_page.txt
@@ -2,7 +2,7 @@
!! ------ The native file is rasctl.1. Re-run 'make docs' after updating
-rascsi(1) General Commands Manual rascsi(1)
+rascsi(1) General Commands Manual rascsi(1)
NAME
rasctl - Sends management commands to the rascsi process
@@ -11,15 +11,13 @@ SYNOPSIS
rasctl -l | -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE]
DESCRIPTION
- rasctl Sends commands to the rascsi process to make configuration adjustments at runtime or to check the sta‐
- tus of the devices.
+ rasctl Sends commands to the rascsi process to make configuration adjustments at runtime or to check the status of the devices.
Either the -i or -l option should be specified at one time. Not both.
You do NOT need root privileges to use rasctl.
- Note: The command and type arguments are case insensitive. Only the first letter of the command/type are
- evaluated by the tool.
+ Note: The command and type arguments are case insensitive. Only the first letter of the command/type are evaluated by the tool.
OPTIONS
-l List all of the devices that are currently being emulated by RaSCSI, as well as their current status.
@@ -27,8 +25,7 @@ OPTIONS
-i ID ID is the SCSI ID that you want to control. (0-7)
-u UNIT
- Unit number (0 or 1). This will default to 0. This option is only used when there are multiple SCSI
- devices on a shared SCSI controller. (This is not common)
+ Unit number (0 or 1). This will default to 0. This option is only used when there are multiple SCSI devices on a shared SCSI controller. (This is not common)
-c CMD Command is the operation being requested. options are:
attach: attach disk
@@ -40,8 +37,7 @@ OPTIONS
When the command is omited, rasctl will default to the 'attach' command
-t TYPE
- Specifies the type of disk. If this disagrees with the file extension of the specified image, the TYPE
- argument is ignored. Available drive types are:
+ Specifies the type of disk. If this disagrees with the file extension of the specified image, the TYPE argument is ignored. Available drive types are:
hd: Hard disk (SCSI or SASI)
mo: Magneto-Optical disk)
cd: CD-ROM
@@ -61,13 +57,12 @@ EXAMPLES
| 0 | 1 | SCHD | /home/pi/harddisk.hda
+----+----+------+-------------------------------------
- Request the RaSCSI process to attach a disk (assumed) to SCSI ID 0 with the contents of the file system image
- "HDIIMAGE0.HDS".
+ Request the RaSCSI process to attach a disk (assumed) to SCSI ID 0 with the contents of the file system image "HDIIMAGE0.HDS".
rasctl -i 0 -f HDIIMAGE0.HDS
SEE ALSO
- rascsi(1)
+ rascsi(1) scsimon(1)
Full documentation is available at:
- rascsi(1)
+ rascsi(1)
diff --git a/doc/scsimon.1 b/doc/scsimon.1
new file mode 100644
index 0000000000..670c210387
--- /dev/null
+++ b/doc/scsimon.1
@@ -0,0 +1,27 @@
+.TH scsimon 1
+.SH NAME
+scsimon \- Acts as a data capture tool for all traffic on the SCSI bus. Data is stored in a Value Change Dump (VCD) file.
+.SH SYNOPSIS
+.B scsimon
+.SH DESCRIPTION
+.B scsimon
+Monitors all of the traffic on the SCSI bus, using a RaSCSI device. The data is cached in memory while the tool is running. A circular buffer is used so that only the most recent 1,000,000 transactions are stored. The tool will continue to run until the user presses CTRL-C, or the process receives a SIGINT signal.
+.PP
+The logged data is stored in a file called "log.vcd" in the current working directory from where scsimon was launched.
+
+Currently, scsimon doesn't accept any agruments.
+
+To quit scsimon, press Control + C.
+
+.SH OPTIONS
+.TP
+None
+
+.SH EXAMPLES
+Launch scsimon to capture all SCSI traffic available to the RaSCSI hardware:
+ scsimon
+
+.SH SEE ALSO
+rasctl(1), rascsi(1)
+
+Full documentation is available at:
diff --git a/doc/scsimon_man_page.txt b/doc/scsimon_man_page.txt
new file mode 100644
index 0000000000..0e7db3de49
--- /dev/null
+++ b/doc/scsimon_man_page.txt
@@ -0,0 +1,35 @@
+!! ------ THIS FILE IS AUTO_GENERATED! DO NOT MANUALLY UPDATE!!!
+!! ------ The native file is scsimon.1. Re-run 'make docs' after updating
+
+
+scsimon(1) General Commands Manual scsimon(1)
+
+NAME
+ scsimon - Acts as a data capture tool for all traffic on the SCSI bus. Data is stored in a Value Change Dump (VCD) file.
+
+SYNOPSIS
+ scsimon
+
+DESCRIPTION
+ scsimon Monitors all of the traffic on the SCSI bus, using a RaSCSI device. The data is cached in memory while the tool is running. A circular buffer is used so that only the most recent 1,000,000
+ transactions are stored. The tool will continue to run until the user presses CTRL-C, or the process receives a SIGINT signal.
+
+ The logged data is stored in a file called "log.vcd" in the current working directory from where scsimon was launched.
+
+ Currently, scsimon doesn't accept any agruments.
+
+ To quit scsimon, press Control + C.
+
+OPTIONS
+ None
+
+EXAMPLES
+ Launch scsimon to capture all SCSI traffic available to the RaSCSI hardware:
+ scsimon
+
+SEE ALSO
+ rasctl(1), rascsi(1)
+
+ Full documentation is available at:
+
+ scsimon(1)
diff --git a/src/raspberrypi/.gitignore b/src/raspberrypi/.gitignore
index 87d0430774..b3172ad3ab 100644
--- a/src/raspberrypi/.gitignore
+++ b/src/raspberrypi/.gitignore
@@ -4,6 +4,7 @@
*.cbp
*.layout
*.log
+*.vcd
rascsi
scsimon
rasctl
diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile
index 7f11994982..da996318cb 100644
--- a/src/raspberrypi/Makefile
+++ b/src/raspberrypi/Makefile
@@ -38,8 +38,8 @@ CXXFLAGS += -std=c++14 -iquote . -MD -MP
## STANDARD or FULLSPEC. The default is STANDARD
## * THIS IS TYPICALLY THE ONLY COMPILE OPTION YOU
## * NEED TO SPECIFY
-# If its not specified, build for STANDARD configuration
-CONNECT_TYPE ?= STANDARD
+# If its not specified, build for FULLSPEC configuration
+CONNECT_TYPE ?= FULLSPEC
ifdef CONNECT_TYPE
CFLAGS += -DCONNECT_TYPE_$(CONNECT_TYPE)
@@ -67,8 +67,7 @@ BINDIR := ./bin/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
#BIN_ALL = $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP) $(SCSIMON)
# Temporarily remove the RASDUMP and RASDUMP tools, since they're not needed
# for my specific use case. If you need them - add them back in!
-BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL)
-
+BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL) $(BINDIR)/$(SCSIMON)
SRC_RASCSI = \
rascsi.cpp \
@@ -83,6 +82,16 @@ SRC_RASCSI = \
SRC_RASCSI += $(shell find ./controllers -name '*.cpp')
SRC_RASCSI += $(shell find ./devices -name '*.cpp')
+SRC_SCSIMON = \
+ scsimon.cpp \
+ scsi.cpp \
+ gpiobus.cpp \
+ filepath.cpp \
+ fileio.cpp
+SRC_SCSIMON += $(shell find ./controllers -name '*.cpp')
+SRC_SCSIMON += $(shell find ./devices -name '*.cpp')
+
+
SRC_RASCTL = \
rasctl.cpp
# rasctl_command.cpp
@@ -113,12 +122,12 @@ OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
OBJ_SASIDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SASIDUMP:%.cpp=%.o)))
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
#OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP) $(OBJ_SCSIMON)
-OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP)
+OBJ_ALL := $(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_RASDUMP) $(OBJ_SASIDUMP) $(OBJ_SCSIMON)
# The following will include all of the auto-generated dependency files (*.d)
# if they exist. This will trigger a rebuild of a source file if a header changes
-ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI) $(OBJ_RASCTL))
+ALL_DEPS := $(patsubst %.o,%.d,$(OBJ_RASCSI) $(OBJ_RASCTL) $(OBJ_SCSIMON))
-include $(ALL_DEPS)
$(OBJDIR) $(BINDIR):
@@ -137,21 +146,21 @@ $(OBJDIR)/%.o: %.cpp | $(OBJDIR)
all: $(BIN_ALL) docs
ALL: all
-docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt
+docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) | $(BINDIR)
- $(CXX) -o $@ $(OBJ_RASCSI) -lpthread
+ $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread
-$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) $(BINDIR)
- $(CXX) -o $@ $(OBJ_RASCTL)
+$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) | $(BINDIR)
+ $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL)
-$(RASDUMP): $(OBJ_RASDUMP) $(BINDIR)
- $(CXX) -o $@ $(OBJ_RASDUMP)
+$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
+ $(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
-$(SASIDUMP): $(OBJ_SASIDUMP) $(BINDIR)
- $(CXX) -o $@ $(OBJ_SASIDUMP)
+$(BINDIR)/$(SASIDUMP): $(OBJ_SASIDUMP) | $(BINDIR)
+ $(CXX) $(CXXFLAGS) -o $@ $(OBJ_SASIDUMP)
-$(SCSIMON): $(OBJ_SCSIMON) $(BINDIR)
+$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
## clean : Remove all of the object files, intermediate
@@ -180,7 +189,7 @@ run:
## * sudo systemctl enable rascsi
## * sudo systemctl start rascsi
.PHONY: install
-install: $(MAN_PAGE_DIR)/rascsi.1 $(MAN_PAGE_DIR)/rasctl.1 $(USR_LOCAL_BIN)/$(RASCTL) $(USR_LOCAL_BIN)/$(RASCSI) $(SYSTEMD_CONF) $(RSYSLOG_CONF) $(RSYSLOG_LOG)
+install: $(MAN_PAGE_DIR)/rascsi.1 $(MAN_PAGE_DIR)/rasctl.1 $(MAN_PAGE_DIR)/scsimon.1 $(USR_LOCAL_BIN)/$(RASCTL) $(USR_LOCAL_BIN)/$(RASCSI) $(USR_LOCAL_BIN)/$(SCSIMON) $(SYSTEMD_CONF) $(RSYSLOG_CONF) $(RSYSLOG_LOG)
@echo "-- Done installing!"
$(USR_LOCAL_BIN)% : $(BINDIR)/%
diff --git a/src/raspberrypi/controllers/sasidev_ctrl.cpp b/src/raspberrypi/controllers/sasidev_ctrl.cpp
index 1f97d86752..0cd1f42065 100644
--- a/src/raspberrypi/controllers/sasidev_ctrl.cpp
+++ b/src/raspberrypi/controllers/sasidev_ctrl.cpp
@@ -296,7 +296,7 @@ BUS::phase_t FASTCALL SASIDEV::Process()
}
// Get bus information
- ctrl.bus->Aquire();
+ ((GPIOBUS*)ctrl.bus)->Aquire();
// For the monitor tool, we shouldn't need to reset. We're just logging information
// Reset
@@ -927,7 +927,7 @@ void FASTCALL SASIDEV::Error()
ASSERT(this);
// Get bus information
- ctrl.bus->Aquire();
+ ((GPIOBUS*)ctrl.bus)->Aquire();
// Reset check
if (ctrl.bus->GetRST()) {
diff --git a/src/raspberrypi/controllers/scsidev_ctrl.cpp b/src/raspberrypi/controllers/scsidev_ctrl.cpp
index c6813c6797..db237096d3 100644
--- a/src/raspberrypi/controllers/scsidev_ctrl.cpp
+++ b/src/raspberrypi/controllers/scsidev_ctrl.cpp
@@ -76,7 +76,7 @@ BUS::phase_t FASTCALL SCSIDEV::Process()
}
// Get bus information
- ctrl.bus->Aquire();
+ ((GPIOBUS*)ctrl.bus)->Aquire();
// Reset
if (ctrl.bus->GetRST()) {
@@ -488,7 +488,7 @@ void FASTCALL SCSIDEV::Error()
ASSERT(this);
// Get bus information
- ctrl.bus->Aquire();
+ ((GPIOBUS*)ctrl.bus)->Aquire();
// Reset check
if (ctrl.bus->GetRST()) {
diff --git a/src/raspberrypi/gpiobus.cpp b/src/raspberrypi/gpiobus.cpp
index af62d17152..6996bcb384 100644
--- a/src/raspberrypi/gpiobus.cpp
+++ b/src/raspberrypi/gpiobus.cpp
@@ -15,6 +15,7 @@
#include "os.h"
#include "xm6.h"
#include "gpiobus.h"
+#include "log.h"
#ifndef BAREMETAL
#ifdef __linux__
@@ -65,7 +66,7 @@ DWORD bcm_host_get_peripheral_address(void)
char buf[1024];
size_t len = sizeof(buf);
DWORD address;
-
+
if (sysctlbyname("hw.model", buf, &len, NULL, 0) ||
strstr(buf, "ARM1176JZ-S") != buf) {
// Failed to get CPU model || Not BCM2835
@@ -88,7 +89,7 @@ extern uint32_t RPi_IO_Base_Addr;
// Core frequency
extern uint32_t RPi_Core_Freq;
-#ifdef USE_SEL_EVENT_ENABLE
+#ifdef USE_SEL_EVENT_ENABLE
//---------------------------------------------------------------------------
//
// Interrupt control function
@@ -173,7 +174,7 @@ BOOL FASTCALL GPIOBUS::Init(mode_e mode)
// Open /dev/mem
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
- printf("Error: Unable to open /dev/mem. Are you running as root?\n");
+ LOGERROR("Error: Unable to open /dev/mem. Are you running as root?");
return FALSE;
}
@@ -295,6 +296,7 @@ BOOL FASTCALL GPIOBUS::Init(mode_e mode)
// GPIO chip open
fd = open("/dev/gpiochip0", 0);
if (fd == -1) {
+ LOGERROR("Unable to open /dev/gpiochip0. Is RaSCSI already running?")
return FALSE;
}
@@ -310,6 +312,7 @@ BOOL FASTCALL GPIOBUS::Init(mode_e mode)
//Get event request
if (ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &selevreq) == -1) {
+ LOGERROR("Unable to register event request. Is RaSCSI already running?")
close(fd);
return FALSE;
}
@@ -522,27 +525,6 @@ void FASTCALL GPIOBUS::Reset()
#endif // ifdef __x86_64__ || __X86__
}
-//---------------------------------------------------------------------------
-//
-// Bus signal acquisition
-//
-//---------------------------------------------------------------------------
-DWORD FASTCALL GPIOBUS::Aquire()
-{
-#if defined(__x86_64__) || defined(__X86__)
- return 0;
-#else
- signals = *level;
-
-#if SIGNAL_CONTROL_MODE < 2
- // Invert if negative logic (internal processing is unified to positive logic)
- signals = ~signals;
-#endif // SIGNAL_CONTROL_MODE
-
- return signals;
-#endif // ifdef __x86_64__ || __X86__
-}
-
//---------------------------------------------------------------------------
//
// ENB signal setting
@@ -668,6 +650,26 @@ void FASTCALL GPIOBUS::SetACK(BOOL ast)
SetSignal(PIN_ACK, ast);
}
+//---------------------------------------------------------------------------
+//
+// Get ACK signal
+//
+//---------------------------------------------------------------------------
+BOOL FASTCALL GPIOBUS::GetACT()
+{
+ return GetSignal(PIN_ACT);
+}
+
+//---------------------------------------------------------------------------
+//
+// Set ACK signal
+//
+//---------------------------------------------------------------------------
+void FASTCALL GPIOBUS::SetACT(BOOL ast)
+{
+ SetSignal(PIN_ACT, ast);
+}
+
//---------------------------------------------------------------------------
//
// Get RST signal
@@ -1173,7 +1175,7 @@ int FASTCALL GPIOBUS::SendHandShake(BYTE *buf, int count)
}
// Already waiting for REQ assertion
-
+
// Assert the ACK signal
SetSignal(PIN_ACK, ON);
@@ -1233,7 +1235,7 @@ int FASTCALL GPIOBUS::PollSelectEvent()
return -1;
}
- read(selevreq.fd, &gpev, sizeof(gpev));
+ (void)read(selevreq.fd, &gpev, sizeof(gpev));
#endif // BAREMETAL
return 0;
@@ -1417,7 +1419,7 @@ void FASTCALL GPIOBUS::SetMode(int pin, int mode)
gpio[index] = data;
gpfsel[index] = data;
}
-
+
//---------------------------------------------------------------------------
//
// Get input signal value
@@ -1427,7 +1429,7 @@ BOOL FASTCALL GPIOBUS::GetSignal(int pin)
{
return (signals >> pin) & 1;
}
-
+
//---------------------------------------------------------------------------
//
// Set output signal value
@@ -1645,6 +1647,39 @@ void FASTCALL GPIOBUS::DrvConfig(DWORD drive)
pads[PAD_0_27] = (0xFFFFFFF8 & data) | drive | 0x5a000000;
}
+
+//---------------------------------------------------------------------------
+//
+// Generic Phase Acquisition (Doesn't read GPIO)
+//
+//---------------------------------------------------------------------------
+BUS::phase_t FASTCALL GPIOBUS::GetPhaseRaw(DWORD raw_data)
+{
+ DWORD mci;
+
+ // Selection Phase
+ if (GetPinRaw(raw_data, PIN_SEL))
+ {
+ if(GetPinRaw(raw_data, PIN_IO)){
+ return BUS::reselection;
+ }else{
+ return BUS::selection;
+ }
+ }
+
+ // Bus busy phase
+ if (!GetPinRaw(raw_data, PIN_BSY)) {
+ return BUS::busfree;
+ }
+
+ // Get target phase from bus signal line
+ mci = GetPinRaw(raw_data, PIN_MSG) ? 0x04 : 0x00;
+ mci |= GetPinRaw(raw_data, PIN_CD) ? 0x02 : 0x00;
+ mci |= GetPinRaw(raw_data, PIN_IO) ? 0x01 : 0x00;
+ return GetPhase(mci);
+}
+
+
//---------------------------------------------------------------------------
//
// System timer address
diff --git a/src/raspberrypi/gpiobus.h b/src/raspberrypi/gpiobus.h
index 340c95859d..0bce816b49 100644
--- a/src/raspberrypi/gpiobus.h
+++ b/src/raspberrypi/gpiobus.h
@@ -276,6 +276,26 @@
#define PIN_SEL 23 // SEL
#endif
+#define ALL_SCSI_PINS \
+ ((1<> pin_num) & 1);
+ }
virtual BOOL FASTCALL GetBSY() = 0;
// BSYシグナル取得
@@ -125,6 +131,8 @@ class BUS
private:
static const phase_t phase_table[8];
// フェーズテーブル
+
+ static const char* phase_str_table[];
};
#endif // scsi_h
diff --git a/src/raspberrypi/scsimon.cpp b/src/raspberrypi/scsimon.cpp
new file mode 100644
index 0000000000..1f551d24b4
--- /dev/null
+++ b/src/raspberrypi/scsimon.cpp
@@ -0,0 +1,420 @@
+//---------------------------------------------------------------------------
+//
+// SCSI Target Emulator RaSCSI (*^..^*)
+// for Raspberry Pi
+//
+// Powered by XM6 TypeG Technology.
+// Copyright (C) 2016-2020 GIMONS
+// [ RaSCSI main ]
+//
+//---------------------------------------------------------------------------
+
+#include "os.h"
+#include "xm6.h"
+#include "filepath.h"
+#include "fileio.h"
+#include "devices/disk.h"
+#include "log.h"
+#include "gpiobus.h"
+#include "spdlog/spdlog.h"
+#include
+
+//---------------------------------------------------------------------------
+//
+// Constant declarations
+//
+//---------------------------------------------------------------------------
+#define MAX_BUFF_SIZE 1000000
+
+// Symbol definition for the VCD file
+// These are just arbitrary symbols. They can be anything allowed by the VCD file format,
+// as long as they're consistently used.
+#define SYMBOL_PIN_DAT '#'
+#define SYMBOL_PIN_ATN '+'
+#define SYMBOL_PIN_RST '$'
+#define SYMBOL_PIN_ACK '%'
+#define SYMBOL_PIN_REQ '^'
+#define SYMBOL_PIN_MSG '&'
+#define SYMBOL_PIN_CD '*'
+#define SYMBOL_PIN_IO '('
+#define SYMBOL_PIN_BSY ')'
+#define SYMBOL_PIN_SEL '-'
+#define SYMBOL_PIN_PHASE '='
+
+// We'll use position 0 in the prev_value array to store the previous phase
+#define PIN_PHASE 0
+
+//---------------------------------------------------------------------------
+//
+// Variable declarations
+//
+//---------------------------------------------------------------------------
+static BYTE prev_value[32] = {0xFF};
+static volatile BOOL running; // Running flag
+static volatile BOOL active; // Processing flag
+GPIOBUS *bus; // GPIO Bus
+typedef struct data_capture{
+ DWORD data;
+ timeval timestamp;
+} data_capture_t;
+
+data_capture data_buffer[MAX_BUFF_SIZE];
+int data_idx = 0;
+
+//---------------------------------------------------------------------------
+//
+// Signal Processing
+//
+//---------------------------------------------------------------------------
+void KillHandler(int sig)
+{
+ // Stop instruction
+ running = FALSE;
+}
+
+//---------------------------------------------------------------------------
+//
+// Banner Output
+//
+//---------------------------------------------------------------------------
+void Banner(int argc, char* argv[])
+{
+ LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ");
+ LOGINFO("version %01d.%01d%01d(%s, %s)",
+ (int)((VERSION >> 8) & 0xf),
+ (int)((VERSION >> 4) & 0xf),
+ (int)((VERSION ) & 0xf),
+ __DATE__,
+ __TIME__);
+ LOGINFO("Powered by XM6 TypeG Technology ");
+ LOGINFO("Copyright (C) 2016-2020 GIMONS");
+ LOGINFO("Copyright (C) 2020 akuker");
+ LOGINFO("Connect type : %s", CONNECT_DESC);
+ LOGINFO(" log.vcd - Value Change Dump file that can be opened with GTKWave");
+
+ if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
+ (argc > 1 && strcmp(argv[1], "--help") == 0)){
+ LOGINFO("Usage: %s ...", argv[0]);
+ exit(0);
+ }
+ else
+ {
+ LOGINFO(" ");
+ LOGINFO("Current running & collecting data. Press CTRL-C to stop.")
+ LOGINFO(" ");
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Initialization
+//
+//---------------------------------------------------------------------------
+BOOL Init()
+{
+ // Interrupt handler settings
+ if (signal(SIGINT, KillHandler) == SIG_ERR) {
+ return FALSE;
+ }
+ if (signal(SIGHUP, KillHandler) == SIG_ERR) {
+ return FALSE;
+ }
+ if (signal(SIGTERM, KillHandler) == SIG_ERR) {
+ return FALSE;
+ }
+
+ // GPIOBUS creation
+ bus = new GPIOBUS();
+
+ // GPIO Initialization
+ if (!bus->Init()) {
+ LOGERROR("Unable to intiailize the GPIO bus. Exiting....");
+ return FALSE;
+ }
+
+ // Bus Reset
+ bus->Reset();
+
+ // Other
+ running = FALSE;
+ active = FALSE;
+
+ return TRUE;
+}
+
+BOOL get_pin_value(DWORD data, int pin)
+{
+ return (data >> pin) & 1;
+}
+
+BYTE get_data_field(DWORD data)
+{
+ DWORD data_out;
+ data_out =
+ ((data >> (PIN_DT0 - 0)) & (1 << 0)) |
+ ((data >> (PIN_DT1 - 1)) & (1 << 1)) |
+ ((data >> (PIN_DT2 - 2)) & (1 << 2)) |
+ ((data >> (PIN_DT3 - 3)) & (1 << 3)) |
+ ((data >> (PIN_DT4 - 4)) & (1 << 4)) |
+ ((data >> (PIN_DT5 - 5)) & (1 << 5)) |
+ ((data >> (PIN_DT6 - 6)) & (1 << 6)) |
+ ((data >> (PIN_DT7 - 7)) & (1 << 7));
+
+ return (BYTE)data_out;
+}
+
+void vcd_output_if_changed_phase(FILE *fp, DWORD data, int pin, char symbol)
+{
+ BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
+ if(prev_value[pin] != new_value)
+ {
+ prev_value[pin] = new_value;
+ fprintf(fp, "s%s %c\n", GPIOBUS::GetPhaseStrRaw(new_value), symbol);
+ }
+}
+
+void vcd_output_if_changed_bool(FILE *fp, DWORD data, int pin, char symbol)
+{
+ BOOL new_value = get_pin_value(data,pin);
+ if(prev_value[pin] != new_value)
+ {
+ prev_value[pin] = new_value;
+ fprintf(fp, "%d%c\n", new_value, symbol);
+ }
+}
+
+void vcd_output_if_changed_byte(FILE *fp, DWORD data, int pin, char symbol)
+{
+ BYTE new_value = get_data_field(data);
+ if(prev_value[pin] != new_value)
+ {
+ prev_value[pin] = new_value;
+ fprintf(fp, "b%d%d%d%d%d%d%d%d %c\n",
+ get_pin_value(data,PIN_DT0),
+ get_pin_value(data,PIN_DT1),
+ get_pin_value(data,PIN_DT2),
+ get_pin_value(data,PIN_DT3),
+ get_pin_value(data,PIN_DT4),
+ get_pin_value(data,PIN_DT5),
+ get_pin_value(data,PIN_DT6),
+ get_pin_value(data,PIN_DT7), symbol);
+ }
+}
+
+
+
+void create_value_change_dump()
+{
+ time_t rawtime;
+ struct tm * timeinfo;
+ int i = 0;
+ timeval time_diff;
+ char timestamp[256];
+ FILE *fp;
+ timeval start_time = data_buffer[0].timestamp;
+ LOGINFO("Creating Value Change Dump file (log.vcd)\n");
+ fp = fopen("log.vcd","w");
+
+ // Get the current time
+ time (&rawtime);
+ timeinfo = localtime(&rawtime);
+ strftime (timestamp,sizeof(timestamp),"%d-%m-%Y %H-%M-%S",timeinfo);
+
+ fprintf(fp, "$date\n");
+ fprintf(fp, "%s\n", timestamp);
+ fprintf(fp, "$end\n");
+ fprintf(fp, "$version\n");
+ fprintf(fp, " VCD generator tool version info text.\n");
+ fprintf(fp, "$end\n");
+ fprintf(fp, "$comment\n");
+ fprintf(fp, " Any comment text.\n");
+ fprintf(fp, "$end\n");
+ fprintf(fp, "$timescale 1 us $end\n");
+ fprintf(fp, "$scope module logic $end\n");
+ fprintf(fp, "$var wire 1 %c BSY $end\n", SYMBOL_PIN_BSY);
+ fprintf(fp, "$var wire 1 %c SEL $end\n", SYMBOL_PIN_SEL);
+ fprintf(fp, "$var wire 1 %c CD $end\n", SYMBOL_PIN_CD);
+ fprintf(fp, "$var wire 1 %c IO $end\n", SYMBOL_PIN_IO);
+ fprintf(fp, "$var wire 1 %c MSG $end\n", SYMBOL_PIN_MSG);
+ fprintf(fp, "$var wire 1 %c REQ $end\n", SYMBOL_PIN_REQ);
+ fprintf(fp, "$var wire 1 %c ACK $end\n", SYMBOL_PIN_ACK);
+ fprintf(fp, "$var wire 1 %c ATN $end\n", SYMBOL_PIN_ATN);
+ fprintf(fp, "$var wire 1 %c RST $end\n", SYMBOL_PIN_RST);
+ fprintf(fp, "$var wire 8 %c data $end\n", SYMBOL_PIN_DAT);
+ fprintf(fp, "$var string 1 %c phase $end\n", SYMBOL_PIN_PHASE);
+ fprintf(fp, "$upscope $end\n");
+ fprintf(fp, "$enddefinitions $end\n");
+
+ // Initial values - default to zeros
+ fprintf(fp, "$dumpvars\n");
+ fprintf(fp, "0%c\n", SYMBOL_PIN_BSY);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_SEL);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_CD);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_IO);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_MSG);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_REQ);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_ACK);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_ATN);
+ fprintf(fp, "0%c\n", SYMBOL_PIN_RST);
+ fprintf(fp, "b00000000 %c\n", SYMBOL_PIN_DAT);
+ fprintf(fp, "$end\n");
+
+ while(i < data_idx)
+ {
+ timersub(&(data_buffer[i].timestamp), &start_time, &time_diff);
+ fprintf(fp, "#%ld\n",((time_diff.tv_sec*1000000) + time_diff.tv_usec));
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_BSY, SYMBOL_PIN_BSY);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_SEL, SYMBOL_PIN_SEL);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_CD, SYMBOL_PIN_CD);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_IO, SYMBOL_PIN_IO);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_MSG, SYMBOL_PIN_MSG);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_REQ, SYMBOL_PIN_REQ);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_ACK, SYMBOL_PIN_ACK);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_ATN, SYMBOL_PIN_ATN);
+ vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_RST, SYMBOL_PIN_RST);
+ vcd_output_if_changed_byte(fp, data_buffer[i].data, PIN_DT0, SYMBOL_PIN_DAT);
+ vcd_output_if_changed_phase(fp, data_buffer[i].data, PIN_PHASE, SYMBOL_PIN_PHASE);
+ i++;
+ }
+ fclose(fp);
+}
+
+
+
+//---------------------------------------------------------------------------
+//
+// Cleanup
+//
+//---------------------------------------------------------------------------
+void Cleanup()
+{
+
+ LOGINFO("Stoping data collection....\n");
+ create_value_change_dump();
+
+ // Cleanup the Bus
+ bus->Cleanup();
+
+ // Discard the GPIOBUS object
+ delete bus;
+
+}
+
+//---------------------------------------------------------------------------
+//
+// Reset
+//
+//---------------------------------------------------------------------------
+void Reset()
+{
+ // Reset the bus
+ bus->Reset();
+}
+
+//---------------------------------------------------------------------------
+//
+// Pin the thread to a specific CPU
+//
+//---------------------------------------------------------------------------
+void FixCpu(int cpu)
+{
+ cpu_set_t cpuset;
+ int cpus;
+
+ // Get the number of CPUs
+ CPU_ZERO(&cpuset);
+ sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
+ cpus = CPU_COUNT(&cpuset);
+
+ // Set the thread affinity
+ if (cpu < cpus) {
+ CPU_ZERO(&cpuset);
+ CPU_SET(cpu, &cpuset);
+ sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
+ }
+}
+
+#ifdef DEBUG
+static DWORD high_bits = 0x0;
+static DWORD low_bits = 0xFFFFFFFF;
+#endif
+
+//---------------------------------------------------------------------------
+//
+// Main processing
+//
+//---------------------------------------------------------------------------
+int main(int argc, char* argv[])
+{
+#ifdef DEBUG
+ DWORD prev_high = high_bits;
+ DWORD prev_low = low_bits;
+#endif
+ DWORD prev_sample = 0xFFFFFFFF;
+ DWORD this_sample = 0;
+ int ret;
+ struct sched_param schparam;
+
+ spdlog::set_level(spdlog::level::trace);
+ spdlog::set_pattern("%^[%l]%$ %v");
+ // Output the Banner
+ Banner(argc, argv);
+ memset(data_buffer,0,sizeof(data_buffer));
+
+ // Initialize
+ ret = 0;
+ if (!Init()) {
+ ret = EPERM;
+ goto init_exit;
+ }
+
+ // Reset
+ Reset();
+
+ // Set the affinity to a specific processor core
+ FixCpu(3);
+
+ // Scheduling policy setting (highest priority)
+ schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ sched_setscheduler(0, SCHED_FIFO, &schparam);
+
+ // Start execution
+ running = TRUE;
+ bus->SetACT(FALSE);
+
+ LOGDEBUG("ALL_SCSI_PINS %08X\n",ALL_SCSI_PINS);
+ // Main Loop
+ while (running) {
+ // Work initialization
+ this_sample = (bus->Aquire() & ALL_SCSI_PINS);
+
+ if(this_sample != prev_sample)
+ {
+
+#ifdef DEBUG
+ // This is intended to be a debug check to see if every pin is set
+ // high and low at some point.
+ high_bits |= this_sample;
+ low_bits &= this_sample;
+ if ((high_bits != prev_high) || (low_bits != prev_low))
+ {
+ LOGDEBUG(" %08lX %08lX\n",high_bits, low_bits);
+ }
+ prev_high = high_bits;
+ prev_low = low_bits;
+#endif
+ data_buffer[data_idx].data = this_sample;
+ (void)gettimeofday(&(data_buffer[data_idx].timestamp), NULL);
+ data_idx = (data_idx + 1) % MAX_BUFF_SIZE;
+ prev_sample = this_sample;
+ }
+
+ continue;
+ }
+
+ // Cleanup
+ Cleanup();
+
+init_exit:
+ exit(ret);
+}