diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index a5e7266..6f6785b 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -132,3 +132,5 @@ $(DOC_DIR)/%_man_page.txt : $(DOC_DIR)/%.1 .PHONY: Debug Debug: all +.PHONY: Debug-scsishark +Debug-scsishark: $(SCSISHARK) diff --git a/src/raspberrypi/scsishark.cpp b/src/raspberrypi/scsishark.cpp index eb23257..2c67575 100644 --- a/src/raspberrypi/scsishark.cpp +++ b/src/raspberrypi/scsishark.cpp @@ -5,7 +5,7 @@ // // Powered by XM6 TypeG Technology. // Copyright (C) 2016-2020 GIMONS -// [ RaSCSI main ] +// [ SCSI Shark main] // //--------------------------------------------------------------------------- @@ -16,7 +16,6 @@ #include "disk.h" #include "gpiobus.h" #include "spdlog/spdlog.h" -//#include #include //--------------------------------------------------------------------------- @@ -24,31 +23,17 @@ // Constant declarations // //--------------------------------------------------------------------------- -#define CtrlMax 8 // Maximum number of SCSI controllers -#define UnitNum 2 // Number of units around controller -#ifdef BAREMETAL -#define FPRT(fp, ...) printf( __VA_ARGS__ ) -#else #define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ ) -#endif // BAREMETAL //--------------------------------------------------------------------------- // // Variable declarations // //--------------------------------------------------------------------------- +static BYTE prev_value[32] = {0xFF}; static volatile BOOL running; // Running flag static volatile BOOL active; // Processing flag -SASIDEV *ctrl[CtrlMax]; // Controller -Disk *disk[CtrlMax * UnitNum]; // Disk GPIOBUS *bus; // GPIO Bus -#ifdef BAREMETAL -FATFS fatfs; // FatFS -#else -int monsocket; // Monitor Socket -pthread_t monthread; // Monitor Thread -static void *MonThread(void *param); -#endif // BAREMETAL typedef struct data_capture{ DWORD data; timeval timestamp; @@ -60,14 +45,21 @@ typedef struct data_capture{ data_capture data_buffer[MAX_BUFF_SIZE]; int data_idx = 0; +// 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 SECONDS_1 (1000 * 1000) -#define SECONDS_3 (3 * 1000 * 1000) -#define WAIT_FOR_EQUAL(x,y,timeout) { DWORD now = SysTimer::GetTimerLow(); while ((SysTimer::GetTimerLow() - now) < timeout) { bus->Aquire();if (x == y) {break;}}} - - -#ifndef BAREMETAL //--------------------------------------------------------------------------- // // Signal Processing @@ -78,7 +70,6 @@ void KillHandler(int sig) // Stop instruction running = FALSE; } -#endif // BAREMETAL //--------------------------------------------------------------------------- // @@ -87,7 +78,7 @@ void KillHandler(int sig) //--------------------------------------------------------------------------- void Banner(int argc, char* argv[]) { - FPRT(stdout,"SCSI Target Emulator RaSCSI(*^..^*) "); + FPRT(stdout,"SCSI Shark Capture Tool - part of RaSCSI(*^..^*) "); FPRT(stdout,"version %01d.%01d%01d(%s, %s)\n", (int)((VERSION >> 8) & 0xf), (int)((VERSION >> 4) & 0xf), @@ -96,30 +87,19 @@ void Banner(int argc, char* argv[]) __TIME__); FPRT(stdout,"Powered by XM6 TypeG Technology / "); FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n"); + FPRT(stdout,"Copyright (C) 2020 akuker\n"); FPRT(stdout,"Connect type : %s\n", CONNECT_DESC); + FPRT(stdout,"\nPress CTRL-C to stop collecting data.\n"); + FPRT(stdout," log.csv - CSV listing of the data collected\n"); + FPRT(stdout," log.vcd - Value Change Dump file that can be opened with GTKWave\n"); + if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){ FPRT(stdout,"\n"); - FPRT(stdout,"Usage: %s [-IDn FILE] ...\n\n", argv[0]); - FPRT(stdout," n is SCSI identification number(0-7).\n"); - FPRT(stdout," FILE is disk image file.\n\n"); - FPRT(stdout,"Usage: %s [-HDn FILE] ...\n\n", argv[0]); - FPRT(stdout," n is X68000 SASI HD number(0-15).\n"); - FPRT(stdout," FILE is disk image file.\n\n"); - FPRT(stdout," Image type is detected based on file extension.\n"); - FPRT(stdout," hdf : SASI HD image(XM6 SASI HD image)\n"); - FPRT(stdout," hds : SCSI HD image(XM6 SCSI HD image)\n"); - FPRT(stdout," hdn : SCSI HD image(NEC GENUINE)\n"); - FPRT(stdout," hdi : SCSI HD image(Anex86 HD image)\n"); - FPRT(stdout," nhd : SCSI HD image(T98Next HD image)\n"); - FPRT(stdout," hda : SCSI HD image(APPLE GENUINE)\n"); - FPRT(stdout," mos : SCSI MO image(XM6 SCSI MO image)\n"); - FPRT(stdout," iso : SCSI CD image(ISO 9660 image)\n"); + FPRT(stdout,"Usage: %s ...\n\n", argv[0]); -#ifndef BAREMETAL exit(0); -#endif // BAREMETAL } } @@ -130,36 +110,6 @@ void Banner(int argc, char* argv[]) //--------------------------------------------------------------------------- BOOL Init() { - int i; - -#ifndef BAREMETAL - struct sockaddr_in server; - int yes; - - // Create socket for monitor - monsocket = socket(PF_INET, SOCK_STREAM, 0); - memset(&server, 0, sizeof(server)); - server.sin_family = PF_INET; - server.sin_port = htons(6868); - server.sin_addr.s_addr = htonl(INADDR_ANY); - - // allow address reuse - yes = 1; - if (setsockopt( - monsocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0){ - return FALSE; - } - - // Bind - if (bind(monsocket, (struct sockaddr *)&server, - sizeof(struct sockaddr_in)) < 0) { - FPRT(stderr, "Error : Already running?\n"); - return FALSE; - } - - // Create Monitor Thread - pthread_create(&monthread, NULL, MonThread, NULL); - // Interrupt handler settings if (signal(SIGINT, KillHandler) == SIG_ERR) { return FALSE; @@ -170,7 +120,6 @@ BOOL Init() if (signal(SIGTERM, KillHandler) == SIG_ERR) { return FALSE; } -#endif // BAREMETAL // GPIOBUS creation bus = new GPIOBUS(); @@ -183,16 +132,6 @@ BOOL Init() // Bus Reset bus->Reset(); - // Controller initialization - for (i = 0; i < CtrlMax; i++) { - ctrl[i] = NULL; - } - - // Disk Initialization - for (i = 0; i < CtrlMax; i++) { - disk[i] = NULL; - } - // Other running = FALSE; active = FALSE; @@ -200,40 +139,6 @@ BOOL Init() return TRUE; } -#define PIN_ACT 4 // ACTIVE -#define PIN_ENB 5 // ENABLE -#define PIN_IND -1 // INITIATOR CTRL DIRECTION -#define PIN_TAD -1 // TARGET CTRL DIRECTION -#define PIN_DTD -1 // DATA DIRECTION - -// Control signal output logic -#define ACT_ON TRUE // ACTIVE SIGNAL ON -#define ENB_ON TRUE // ENABLE SIGNAL ON -#define IND_IN FALSE // INITIATOR SIGNAL INPUT -#define TAD_IN FALSE // TARGET SIGNAL INPUT -#define DTD_IN TRUE // DATA SIGNAL INPUT - -// SCSI signal pin assignment -#define PIN_DT0 10 // Data 0 -#define PIN_DT1 11 // Data 1 -#define PIN_DT2 12 // Data 2 -#define PIN_DT3 13 // Data 3 -#define PIN_DT4 14 // Data 4 -#define PIN_DT5 15 // Data 5 -#define PIN_DT6 16 // Data 6 -#define PIN_DT7 17 // Data 7 -#define PIN_DP 18 // Data parity -#define PIN_ATN 19 // ATN -#define PIN_RST 20 // RST -#define PIN_ACK 21 // ACK -#define PIN_REQ 22 // REQ -#define PIN_MSG 23 // MSG -#define PIN_CD 24 // CD -#define PIN_IO 25 // IO -#define PIN_BSY 26 // BSY -#define PIN_SEL 27 // SEL - - BOOL get_pin_value(DWORD data, int pin) { return (data >> pin) & 1; @@ -256,88 +161,141 @@ BYTE get_data_field(DWORD data) } -int pin_nums[] = {PIN_BSY,PIN_SEL,PIN_CD,PIN_IO,PIN_MSG,PIN_REQ,PIN_ACK,PIN_ATN,PIN_RST,PIN_DT0}; +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); + } +} -std::string pin_names[] = {"BSY","SEL","CD","IO","MSG","REQ","ACK","ATN","RST","DAT"}; +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 dump_data() +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; + printf("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, "$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); + i++; + } + fclose(fp); +} + + + +void create_comma_separated_file() { int i = 0; timeval time_diff; FILE *fp; timeval start_time = data_buffer[0].timestamp; - fp = fopen("log.txt","w"); + printf("Creating log.csv\n"); + fp = fopen("log.csv","w"); - fprintf(fp, "idx\traw\ttimestamp\tBSY\tSEL\tC/D\tI/O\tMSG\tREQ\tACK\tATN\tRST\tData..\n"); + fprintf(fp, "idx,raw,timestamp,BSY,SEL,C/D,I/O,MSG,,REQ,ACK,ATN,RST,Data\n"); while(i < data_idx) { timersub(&(data_buffer[i].timestamp), &start_time, &time_diff); - //timediff = difftime(data_buffer[i].timestamp, start_time); - fprintf(fp, "%d\t%08lX\t%ld:%ld\t",data_idx, data_buffer[i].data, time_diff.tv_sec, time_diff.tv_usec); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_BSY)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_SEL)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_CD)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_IO)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_MSG)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_REQ)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_ACK)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_ATN)); - fprintf(fp, "%d\t", get_pin_value(data_buffer[i].data, PIN_RST)); - fprintf(fp, "%02X\t", get_data_field(data_buffer[i].data)); + fprintf(fp, "%d,%08lX,%ld.%ld,",data_idx, data_buffer[i].data, time_diff.tv_sec, time_diff.tv_usec); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_BSY)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_SEL)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_CD)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_IO)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_MSG)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_REQ)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_ACK)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_ATN)); + fprintf(fp, "%d,", get_pin_value(data_buffer[i].data, PIN_RST)); + fprintf(fp, "%02X,", get_data_field(data_buffer[i].data)); fprintf(fp, "\n"); i++; } fclose(fp); - - - i=0; - printf("Creating timing_drawer.txt\n"); - fp = fopen("timing_drawer.txt","w"); - while(i < data_idx) - { - timersub(&(data_buffer[i].timestamp), &start_time, &time_diff); - //timediff = difftime(data_buffer[i].timestamp, start_time); - fprintf(fp, "TIME=%ld:%ld;", time_diff.tv_sec, time_diff.tv_usec); - fprintf(fp, "BSY=%d;", get_pin_value(data_buffer[i].data, PIN_BSY)); - fprintf(fp, "SEL=%d;", get_pin_value(data_buffer[i].data, PIN_SEL)); - fprintf(fp, "CD=%d;", get_pin_value(data_buffer[i].data, PIN_CD)); - fprintf(fp, "IO=%d;", get_pin_value(data_buffer[i].data, PIN_IO)); - fprintf(fp, "MSG=%d;", get_pin_value(data_buffer[i].data, PIN_MSG)); - fprintf(fp, "REQ=%d;", get_pin_value(data_buffer[i].data, PIN_REQ)); - fprintf(fp, "ACK=%d;", get_pin_value(data_buffer[i].data, PIN_ACK)); - fprintf(fp, "ATN=%d;", get_pin_value(data_buffer[i].data, PIN_ATN)); - fprintf(fp, "RST=%d;", get_pin_value(data_buffer[i].data, PIN_RST)); - fprintf(fp, "DATA=%02X.", get_data_field(data_buffer[i].data)); - fprintf(fp, "\n"); - i++; - } - fclose(fp); - - - -// -// fp = fopen("log2.txt","w"); -// -// for(int pin=0; pin < ARRAY_SIZE(pin_names); pin++) -// { -// i=0; -// while(i < data_idx) -// { -// char this_point = ((get_pin_value(data_buffer[i].data), pin_nums[pin]) == TRUE) ? "-", "_"; -// fprintf(fp, this_point) -// } -// -// -// -// -// } - - - - } @@ -349,31 +307,10 @@ void dump_data() //--------------------------------------------------------------------------- void Cleanup() { - int i; printf("In cleanup....\n"); - - - - dump_data(); - - - - // Delete the disks - for (i = 0; i < CtrlMax * UnitNum; i++) { - if (disk[i]) { - delete disk[i]; - disk[i] = NULL; - } - } - - // Delete the Controllers - for (i = 0; i < CtrlMax; i++) { - if (ctrl[i]) { - delete ctrl[i]; - ctrl[i] = NULL; - } - } + create_comma_separated_file(); + create_value_change_dump(); // Cleanup the Bus bus->Cleanup(); @@ -381,12 +318,6 @@ void Cleanup() // Discard the GPIOBUS object delete bus; -#ifndef BAREMETAL - // Close the monitor socket - if (monsocket >= 0) { - close(monsocket); - } -#endif // BAREMETAL } //--------------------------------------------------------------------------- @@ -396,611 +327,10 @@ void Cleanup() //--------------------------------------------------------------------------- void Reset() { - int i; - - // Reset all of the controllers - for (i = 0; i < CtrlMax; i++) { - if (ctrl[i]) { - ctrl[i]->Reset(); - } - } - // Reset the bus bus->Reset(); } -//--------------------------------------------------------------------------- -// -// List Devices -// -//--------------------------------------------------------------------------- -void ListDevice(FILE *fp) -{ - int i; - int id; - int un; - Disk *pUnit; - Filepath filepath; - BOOL find; - char type[5]; - - find = FALSE; - type[4] = 0; - for (i = 0; i < CtrlMax * UnitNum; i++) { - // Initialize ID and unit number - id = i / UnitNum; - un = i % UnitNum; - pUnit = disk[i]; - - // skip if unit does not exist or null disk - if (pUnit == NULL || pUnit->IsNULL()) { - continue; - } - - // Output the header - if (!find) { - FPRT(fp, "\n"); - FPRT(fp, "+----+----+------+-------------------------------------\n"); - FPRT(fp, "| ID | UN | TYPE | DEVICE STATUS\n"); - FPRT(fp, "+----+----+------+-------------------------------------\n"); - find = TRUE; - } - - // ID,UNIT,Type,Device Status - type[0] = (char)(pUnit->GetID() >> 24); - type[1] = (char)(pUnit->GetID() >> 16); - type[2] = (char)(pUnit->GetID() >> 8); - type[3] = (char)(pUnit->GetID()); - FPRT(fp, "| %d | %d | %s | ", id, un, type); - - // mount status output - if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) { - FPRT(fp, "%s", "HOST BRIDGE"); - } else { - pUnit->GetPath(filepath); - FPRT(fp, "%s", - (pUnit->IsRemovable() && !pUnit->IsReady()) ? - "NO MEDIA" : filepath.GetPath()); - } - - // Write protection status - if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) { - FPRT(fp, "(WRITEPROTECT)"); - } - - // Goto the next line - FPRT(fp, "\n"); - } - - // If there is no controller, find will be null - if (!find) { - FPRT(fp, "No device is installed.\n"); - return; - } - - FPRT(fp, "+----+----+------+-------------------------------------\n"); -} - -//--------------------------------------------------------------------------- -// -// Controller Mapping -// -//--------------------------------------------------------------------------- -void MapControler(FILE *fp, Disk **map) -{ - int i; - int j; - int unitno; - int sasi_num; - int scsi_num; - - // Replace the changed unit - for (i = 0; i < CtrlMax; i++) { - for (j = 0; j < UnitNum; j++) { - unitno = i * UnitNum + j; - if (disk[unitno] != map[unitno]) { - // Check if the original unit exists - if (disk[unitno]) { - // Disconnect it from the controller - if (ctrl[i]) { - ctrl[i]->SetUnit(j, NULL); - } - - // Free the Unit - delete disk[unitno]; - } - - // Setup a new unit - disk[unitno] = map[unitno]; - } - } - } - - // Reconfigure all of the controllers - for (i = 0; i < CtrlMax; i++) { - // Examine the unit configuration - sasi_num = 0; - scsi_num = 0; - for (j = 0; j < UnitNum; j++) { - unitno = i * UnitNum + j; - // branch by unit type - if (disk[unitno]) { - if (disk[unitno]->IsSASI()) { - // Drive is SASI, so increment SASI count - sasi_num++; - } else { - // Drive is SCSI, so increment SCSI count - scsi_num++; - } - } - - // Remove the unit - if (ctrl[i]) { - ctrl[i]->SetUnit(j, NULL); - } - } - - // If there are no units connected - if (sasi_num == 0 && scsi_num == 0) { - if (ctrl[i]) { - delete ctrl[i]; - ctrl[i] = NULL; - continue; - } - } - - // Mixture of SCSI and SASI - if (sasi_num > 0 && scsi_num > 0) { - FPRT(fp, "Error : SASI and SCSI can't be mixed\n"); - continue; - } - - if (sasi_num > 0) { - // Only SASI Unit(s) - - // Release the controller if it is not SASI - if (ctrl[i] && !ctrl[i]->IsSASI()) { - delete ctrl[i]; - ctrl[i] = NULL; - } - - // Create a new SASI controller - if (!ctrl[i]) { - ctrl[i] = new SASIDEV(); - ctrl[i]->Connect(i, bus); - } - } else { - // Only SCSI Unit(s) - - // Release the controller if it is not SCSI - if (ctrl[i] && !ctrl[i]->IsSCSI()) { - delete ctrl[i]; - ctrl[i] = NULL; - } - - // Create a new SCSI controller - if (!ctrl[i]) { - ctrl[i] = new SCSIDEV(); - ctrl[i]->Connect(i, bus); - } - } - - // connect all units - for (j = 0; j < UnitNum; j++) { - unitno = i * UnitNum + j; - if (disk[unitno]) { - // Add the unit connection - ctrl[i]->SetUnit(j, disk[unitno]); - } - } - } -} - -//--------------------------------------------------------------------------- -// -// Command Processing -// -//--------------------------------------------------------------------------- -BOOL ProcessCmd(FILE *fp, int id, int un, int cmd, int type, char *file) -{ - Disk *map[CtrlMax * UnitNum]; - int len; - char *ext; - Filepath filepath; - Disk *pUnit; - - // Copy the Unit List - memcpy(map, disk, sizeof(disk)); - - // Check the Controller Number - if (id < 0 || id >= CtrlMax) { - FPRT(fp, "Error : Invalid ID\n"); - return FALSE; - } - - // Check the Unit Number - if (un < 0 || un >= UnitNum) { - FPRT(fp, "Error : Invalid unit number\n"); - return FALSE; - } - - // Connect Command - if (cmd == 0) { // ATTACH - // Distinguish between SASI and SCSI - ext = NULL; - pUnit = NULL; - if (type == 0) { - // Passed the check - if (!file) { - return FALSE; - } - - // Check that command is at least 5 characters long - len = strlen(file); - if (len < 5) { - return FALSE; - } - - // Check the extension - if (file[len - 4] != '.') { - return FALSE; - } - - // If the extension is not SASI type, replace with SCSI - ext = &file[len - 3]; - if (xstrcasecmp(ext, "hdf") != 0) { - type = 1; - } - } - - // Create a new drive, based upon type - switch (type) { - case 0: // HDF - pUnit = new SASIHD(); - break; - case 1: // HDS/HDN/HDI/NHD/HDA - if (ext == NULL) { - break; - } - if (xstrcasecmp(ext, "hdn") == 0 || - xstrcasecmp(ext, "hdi") == 0 || xstrcasecmp(ext, "nhd") == 0) { - pUnit = new SCSIHD_NEC(); - } else if (xstrcasecmp(ext, "hda") == 0) { - pUnit = new SCSIHD_APPLE(); - } else { - pUnit = new SCSIHD(); - } - break; - case 2: // MO - pUnit = new SCSIMO(); - break; - case 3: // CD - pUnit = new SCSICD(); - break; - case 4: // BRIDGE - pUnit = new SCSIBR(); - break; - default: - FPRT(fp, "Error : Invalid device type\n"); - return FALSE; - } - - // drive checks files - if (type <= 1 || (type <= 3 && xstrcasecmp(file, "-") != 0)) { - // Set the Path - filepath.SetPath(file); - - // Open the file path - if (!pUnit->Open(filepath)) { - FPRT(fp, "Error : File open error [%s]\n", file); - delete pUnit; - return FALSE; - } - } - - // Set the cache to write-through - pUnit->SetCacheWB(FALSE); - - // Replace with the newly created unit - map[id * UnitNum + un] = pUnit; - - // Re-map the controller - MapControler(fp, map); - return TRUE; - } - - // Is this a valid command? - if (cmd > 4) { - FPRT(fp, "Error : Invalid command\n"); - return FALSE; - } - - // Does the controller exist? - if (ctrl[id] == NULL) { - FPRT(fp, "Error : No such device\n"); - return FALSE; - } - - // Does the unit exist? - pUnit = disk[id * UnitNum + un]; - if (pUnit == NULL) { - FPRT(fp, "Error : No such device\n"); - return FALSE; - } - - // Disconnect Command - if (cmd == 1) { // DETACH - // Free the existing unit - map[id * UnitNum + un] = NULL; - - // Re-map the controller - MapControler(fp, map); - return TRUE; - } - - // Valid only for MO or CD - if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O') && - pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) { - FPRT(fp, "Error : Operation denied(Deveice isn't removable)\n"); - return FALSE; - } - - switch (cmd) { - case 2: // INSERT - // Set the file path - filepath.SetPath(file); - - // Open the file - if (!pUnit->Open(filepath)) { - FPRT(fp, "Error : File open error [%s]\n", file); - return FALSE; - } - break; - - case 3: // EJECT - pUnit->Eject(TRUE); - break; - - case 4: // PROTECT - if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) { - FPRT(fp, "Error : Operation denied(Deveice isn't MO)\n"); - return FALSE; - } - pUnit->WriteP(!pUnit->IsWriteP()); - break; - default: - ASSERT(FALSE); - return FALSE; - } - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Argument Parsing -// -//--------------------------------------------------------------------------- -BOOL ParseArgument(int argc, char* argv[]) -{ -#ifdef BAREMETAL - FRESULT fr; - FIL fp; - char line[512]; -#else - int i; -#endif // BAREMETAL - int id; - int un; - int type; - char *argID; - char *argPath; - int len; - char *ext; - -#ifdef BAREMETAL - // Mount the SD card - fr = f_mount(&fatfs, "", 1); - if (fr != FR_OK) { - FPRT(stderr, "Error : SD card mount failed.\n"); - return FALSE; - } - - // If there is no setting file, the processing is interrupted - fr = f_open(&fp, "rascsi.ini", FA_READ); - if (fr != FR_OK) { - return FALSE; - } -#else - // If the ID and path are not specified, the processing is interrupted - if (argc < 3) { - return TRUE; - } - i = 1; - argc--; -#endif // BAREMETAL - - // Start Decoding - - while (TRUE) { -#ifdef BAREMETAL - // Get one Line - memset(line, 0x00, sizeof(line)); - if (f_gets(line, sizeof(line) -1, &fp) == NULL) { - break; - } - - // Delete the CR/LF - len = strlen(line); - while (len > 0) { - if (line[len - 1] != '\r' && line[len - 1] != '\n') { - break; - } - line[len - 1] = '\0'; - len--; - } -#else - if (argc < 2) { - break; - } - - argc -= 2; -#endif // BAREMETAL - - // Get the ID and Path -#ifdef BAREMETAL - argID = &line[0]; - argPath = &line[4]; - line[3] = '\0'; - - // Check if the line is an empty string - if (argID[0] == '\0' || argPath[0] == '\0') { - continue; - } -#else - argID = argv[i++]; - argPath = argv[i++]; - - // Check if the argument is invalid - if (argID[0] != '-') { - FPRT(stderr, - "Error : Invalid argument(-IDn or -HDn) [%s]\n", argID); - goto parse_error; - } - argID++; -#endif // BAREMETAL - - if (strlen(argID) == 3 && xstrncasecmp(argID, "id", 2) == 0) { - // ID or ID Format - - // Check that the ID number is valid (0-7) - if (argID[2] < '0' || argID[2] > '7') { - FPRT(stderr, - "Error : Invalid argument(IDn n=0-7) [%c]\n", argID[2]); - goto parse_error; - } - - // The ID unit is good - id = argID[2] - '0'; - un = 0; - } else if (xstrncasecmp(argID, "hd", 2) == 0) { - // HD or HD format - - if (strlen(argID) == 3) { - // Check that the HD number is valid (0-9) - if (argID[2] < '0' || argID[2] > '9') { - FPRT(stderr, - "Error : Invalid argument(HDn n=0-15) [%c]\n", argID[2]); - goto parse_error; - } - - // ID was confirmed - id = (argID[2] - '0') / UnitNum; - un = (argID[2] - '0') % UnitNum; - } else if (strlen(argID) == 4) { - // Check that the HD number is valid (10-15) - if (argID[2] != '1' || argID[3] < '0' || argID[3] > '5') { - FPRT(stderr, - "Error : Invalid argument(HDn n=0-15) [%c]\n", argID[2]); - goto parse_error; - } - - // The ID unit is good - create the id and unit number - id = ((argID[3] - '0') + 10) / UnitNum; - un = ((argID[3] - '0') + 10) % UnitNum; -#ifdef BAREMETAL - argPath++; -#endif // BAREMETAL - } else { - FPRT(stderr, - "Error : Invalid argument(IDn or HDn) [%s]\n", argID); - goto parse_error; - } - } else { - FPRT(stderr, - "Error : Invalid argument(IDn or HDn) [%s]\n", argID); - goto parse_error; - } - - // Skip if there is already an active device - if (disk[id * UnitNum + un] && - !disk[id * UnitNum + un]->IsNULL()) { - continue; - } - - // Initialize device type - type = -1; - - // Check ethernet and host bridge - if (xstrcasecmp(argPath, "bridge") == 0) { - type = 4; - } else { - // Check the path length - len = strlen(argPath); - if (len < 5) { - FPRT(stderr, - "Error : Invalid argument(File path is short) [%s]\n", - argPath); - goto parse_error; - } - - // Does the file have an extension? - if (argPath[len - 4] != '.') { - FPRT(stderr, - "Error : Invalid argument(No extension) [%s]\n", argPath); - goto parse_error; - } - - // Figure out what the type is - ext = &argPath[len - 3]; - if (xstrcasecmp(ext, "hdf") == 0 || - xstrcasecmp(ext, "hds") == 0 || - xstrcasecmp(ext, "hdn") == 0 || - xstrcasecmp(ext, "hdi") == 0 || xstrcasecmp(ext, "nhd") == 0 || - xstrcasecmp(ext, "hda") == 0) { - // HD(SASI/SCSI) - type = 0; - } else if (strcasecmp(ext, "mos") == 0) { - // MO - type = 2; - } else if (strcasecmp(ext, "iso") == 0) { - // CD - type = 3; - } else { - // Cannot determine the file type - FPRT(stderr, - "Error : Invalid argument(file type) [%s]\n", ext); - goto parse_error; - } - } - - // Execute the command - if (!ProcessCmd(stderr, id, un, 0, type, argPath)) { - goto parse_error; - } - } - -#ifdef BAREMETAL - // Close the configuration file - f_close(&fp); -#endif // BAREMETAL - - // Display the device list - ListDevice(stdout); - - return TRUE; - -parse_error: - -#ifdef BAREMETAL - // Close the configuration file - f_close(&fp); -#endif // BAREMETAL - - return FALSE; -} - -#ifndef BAREMETAL //--------------------------------------------------------------------------- // // Pin the thread to a specific CPU @@ -1024,122 +354,6 @@ void FixCpu(int cpu) } } -//--------------------------------------------------------------------------- -// -// Monitor Thread -// -//--------------------------------------------------------------------------- -static void *MonThread(void *param) -{ - struct sched_param schedparam; - struct sockaddr_in client; - socklen_t len; - int fd; - FILE *fp; - char buf[BUFSIZ]; - char *p; - int i; - char *argv[5]; - int id; - int un; - int cmd; - int type; - char *file; - - // Scheduler Settings - schedparam.sched_priority = 0; - sched_setscheduler(0, SCHED_IDLE, &schedparam); - - // Set the affinity to a specific processor core - FixCpu(2); - - // Wait for the execution to start - while (!running) { - usleep(1); - } - - // Setup the monitor socket to receive commands - listen(monsocket, 1); - - while (1) { - // Wait for connection - memset(&client, 0, sizeof(client)); - len = sizeof(client); - fd = accept(monsocket, (struct sockaddr*)&client, &len); - if (fd < 0) { - break; - } - - // Fetch the command - fp = fdopen(fd, "r+"); - p = fgets(buf, BUFSIZ, fp); - - // Failed to get the command - if (!p) { - goto next; - } - - // Remove the newline character - p[strlen(p) - 1] = 0; - - // List all of the devices - if (xstrncasecmp(p, "list", 4) == 0) { - ListDevice(fp); - goto next; - } - - // Parameter separation - argv[0] = p; - for (i = 1; i < 5; i++) { - // Skip parameter values - while (*p && (*p != ' ')) { - p++; - } - - // Replace spaces with null characters - while (*p && (*p == ' ')) { - *p++ = 0; - } - - // The parameters were lost - if (!*p) { - break; - } - - // Recognized as a parameter - argv[i] = p; - } - - // Failed to get all parameters - if (i < 5) { - goto next; - } - - // ID, unit, command, type, file - id = atoi(argv[0]); - un = atoi(argv[1]); - cmd = atoi(argv[2]); - type = atoi(argv[3]); - file = argv[4]; - - // Wait until we becom idle - while (active) { - usleep(500 * 1000); - } - - // Execute the command - ProcessCmd(fp, id, un, cmd, type, file); - -next: - // Release the connection - fclose(fp); - close(fd); - } - - return NULL; -} -#endif // BAREMETAL - static DWORD high_bits = 0x0; static DWORD low_bits = 0xFFFFFFFF; @@ -1163,15 +377,8 @@ int main(int argc, char* argv[]) DWORD prev_low = low_bits; DWORD prev_sample = 0xFFFFFFFF; DWORD this_sample = 0; - //int i; int ret; -// int actid; - //DWORD now; - //BUS::phase_t phase; -// BYTE data; -#ifndef BAREMETAL - struct sched_param schparam; -#endif // BAREMETAL + struct sched_param schparam; spdlog::set_level(spdlog::level::trace); spdlog::trace("Entering the function with {0:x}{1:X} arguments", argc,20); @@ -1189,32 +396,12 @@ int main(int argc, char* argv[]) // Reset Reset(); -#ifdef BAREMETAL - // BUSY assert (to hold the host side) - bus->SetBSY(TRUE); -#endif - - // Argument parsing - if (!ParseArgument(argc, argv)) { - ret = EINVAL; - goto err_exit; - } - -#ifdef BAREMETAL - // Release the busy signal - bus->SetBSY(FALSE); -#endif - -#ifndef BAREMETAL // Set the affinity to a specific processor core FixCpu(3); -#ifdef USE_SEL_EVENT_ENABLE // Scheduling policy setting (highest priority) schparam.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(0, SCHED_FIFO, &schparam); -#endif // USE_SEL_EVENT_ENABLE -#endif // BAREMETAL // Start execution running = TRUE; @@ -1249,226 +436,12 @@ int main(int argc, char* argv[]) prev_sample = this_sample; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - continue; -//////// -//////// // Target sending data -//////// if(!bus->GetIO() && bus->GetREQ() && bus->GetACK()) -//////// { -//////// BYTE data = bus->GetDAT(); -//////// printf("+%02X ",data); -//////// -//////// -//////// -//////// DWORD now = SysTimer::GetTimerLow(); -//////// while ((SysTimer::GetTimerLow() - now) < SECONDS_1/100) -//////// { -//////// bus->Aquire(); -//////// if (bus->GetACK() == FALSE) { -//////// break; -//////// } -//////// } -//////// -//////// if(bus->GetACK() != FALSE) -//////// { -//////// spdlog::warn("got an invalid req/ack sequence for target sending data"); -//////// } -//////// } -//////// -//////// -//////// -//////// if(bus->GetIO() && bus->GetREQ() && !bus->GetACK()) -//////// { -//////// BYTE data = bus->GetDAT(); -//////// printf("-%02X ",data); -//////// -//////// -//////// DWORD now = SysTimer::GetTimerLow(); -//////// while ((SysTimer::GetTimerLow() - now) < SECONDS_1/100) -//////// { -//////// bus->Aquire(); -//////// if (bus->GetREQ() == FALSE) { -//////// break; -//////// } -//////// } -//////// -//////// if(bus->GetREQ() != TRUE) -//////// { -//////// spdlog::warn("REQ didn't de-assert when I wanted it to."); -//////// } -//////// -//////// -//////// } -//////// -//////// continue; -//////// -//////// // Wait until BSY is released as there is a possibility for the -//////// // initiator to assert it while setting the ID (for up to 3 seconds) -//////// if (bus->GetSEL() ) { -//////// BYTE data = bus->GetDAT(); -//////// printf("SEL is asserted. Data: %02X, BSY: %d, SEL %d\n", data, bus->GetBSY(), bus->GetSEL()); -//////// now = SysTimer::GetTimerLow(); -//////// while ((SysTimer::GetTimerLow() - now) < 3 * 1000 * 1000) { -//////// bus->Aquire(); -//////// if (!bus->GetSEL()) { -//////// printf("SEL is clear. Data: %02X, BSY: %d, SEL %d\n", data, bus->GetBSY(), bus->GetSEL()); -//////// break; -//////// } -//////// } -//////// } -//////// else{ -//////// -//////// continue; -//////// } -////////// spdlog::trace("Busy: {}",bus->GetBSY()); -//////// -//////// -//////// // For monitor mode, we just want to make sure the initiator -//////// // released the BSY signal within 3 seconds. If it hasn't -//////// // the initiator is misbehaving -////////// if (bus->GetBSY()) { -////////// spdlog::warn("The initiator (%d) did not release the BSY signal after 3 seconds", bus->GetDAT()); -////////// continue; -////////// } -//////// -////////////////////// -////////////////////// // Stop because it the bus is busy or another device responded -////////////////////// if (bus->GetBSY() || !bus->GetSEL()) { -////////////////////// continue; -////////////////////// } -// -// // Notify all controllers -// data = bus->GetDAT(); -//// spdlog::trace("Data is {x}",data); -// for (i = 0; i < CtrlMax; i++) { -// if (!ctrl[i] || (data & (1 << i)) == 0) { -// continue; -// } -//// spdlog::trace("Found an active controller! Let's do some selection {}", i); -// // Find the target that has moved to the selection phase -// if (ctrl[i]->Process() == BUS::selection) { -// // Get the target ID -// actid = i; -// -// // Bus Selection phase -// phase = BUS::selection; -// break; -// } -// } -// -// // Return to bus monitoring if the selection phase has not started -// if (phase != BUS::selection) { -// continue; -// } -// -// // Start target device -// active = TRUE; -// spdlog::trace("Found a target device {} ID:{}",actid, ctrl[actid]->GetID()); -// -//#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL) -// // Scheduling policy setting (highest priority) -// schparam.sched_priority = sched_get_priority_max(SCHED_FIFO); -// sched_setscheduler(0, SCHED_FIFO, &schparam); -//#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL -// -// // Loop until the bus is free -// while (running) { -// // Target drive -// phase = ctrl[actid]->Process(); -// -// // End when the bus is free -// if (phase == BUS::busfree) { -// break; -// } -// } -// -//#if !defined(USE_SEL_EVENT_ENABLE) && !defined(BAREMETAL) -// // Set the scheduling priority back to normal -// schparam.sched_priority = 0; -// sched_setscheduler(0, SCHED_OTHER, &schparam); -//#endif // !USE_SEL_EVENT_ENABLE && !BAREMETAL -// -// // End the target travel -// active = FALSE; } -err_exit: // Cleanup Cleanup(); init_exit: -#if !defined(BAREMETAL) exit(ret); -#else - return ret; -#endif // BAREMETAL }