diff --git a/devices/CMakeLists.txt b/devices/CMakeLists.txt index 36a654d..c75a73a 100644 --- a/devices/CMakeLists.txt +++ b/devices/CMakeLists.txt @@ -6,6 +6,7 @@ file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/common/adb/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/common/i2c/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/common/nubus/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/common/pci/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/common/scsi/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/ethernet/*.cpp" diff --git a/devices/common/hwcomponent.h b/devices/common/hwcomponent.h index 6543b1b..50c4d15 100644 --- a/devices/common/hwcomponent.h +++ b/devices/common/hwcomponent.h @@ -39,6 +39,8 @@ enum HWCompType { I2C_DEV = 1ULL << 9, /* I2C device */ ADB_HOST = 1ULL << 12, /* ADB host */ ADB_DEV = 1ULL << 13, /* ADB device */ + PDS_DEV = 1ULL << 14, /* processor direct slot (PDS) device */ + NUBUS_DEV = 1ULL << 15, /* Nubus device */ INT_CTRL = 1ULL << 16, /* interrupt controller */ SCSI_BUS = 1ULL << 20, /* SCSI bus */ SCSI_HOST = 1ULL << 21, /* SCSI host adapter */ diff --git a/devices/common/nubus/nubusutils.cpp b/devices/common/nubus/nubusutils.cpp new file mode 100644 index 0000000..eca08a7 --- /dev/null +++ b/devices/common/nubus/nubusutils.cpp @@ -0,0 +1,146 @@ +/* +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 . +*/ + +#include +#include +#include +#include +#include "memaccess.h" + +#include +#include + +uint32_t calculate_rom_crc(uint8_t *data_ptr, int length) +{ + uint32_t sum = 0; + + for (int i = 0; i < length; i++) { + // rotate sum left by one bit + if (sum & 0x80000000UL) { + sum = (sum << 1) | 1; + } else { + sum = (sum << 1) | 0; + } + sum += data_ptr[i]; + } + + return sum; +} + +int load_declaration_rom(const std::string rom_path, int slot_num) +{ + std::ifstream rom_file; + + int result = 0; + + try { + rom_file.open(rom_path, std::ios::in | std::ios::binary); + if (rom_file.fail()) { + throw std::runtime_error("could not open declaration ROM image"); + } + + // determine image size + rom_file.seekg(0, std::ios::end); + uint32_t rom_size = rom_file.tellg(); + + // load it + auto rom_data = std::unique_ptr (new uint8_t[rom_size]); + rom_file.seekg(0, std::ios::beg); + rom_file.read((char *)rom_data.get(), rom_size); + + // verify image data + uint8_t byte_lane = rom_data[rom_size - 1]; + if ((byte_lane & 0xF) != ((byte_lane >> 4) ^ 0xF)) { + throw std::runtime_error("invalid byte lane value"); + } + + if (READ_DWORD_BE_A(&rom_data[rom_size - 6]) != 0x5A932BC7UL) { + throw std::runtime_error("invalid test pattern"); + } + + if (rom_data[rom_size - 7] != 1) { + throw std::runtime_error("unsupported format"); + } + + uint32_t crc = READ_DWORD_BE_A(&rom_data[rom_size - 12]); + int hdr_length = READ_DWORD_BE_A(&rom_data[rom_size - 16]); + + // patch the CRC field of the format header to 0 + WRITE_DWORD_BE_A(&rom_data[rom_size - 12], 0); + + uint32_t test_crc = calculate_rom_crc(rom_data.get(), hdr_length); + + // restore the CRC field value + WRITE_DWORD_BE_A(&rom_data[rom_size - 12], crc); + + if (test_crc != crc) { + throw std::runtime_error("invalid CRC"); + } + + int lanes_used = 0; + + // count meaningful lanes in a data quad + for (int i = 0; i < 4; i++) { + if (byte_lane & (1 << i)) { + lanes_used++; + } + } + + // calculate padded size = rom_size * (4 / lanes_used) + int padded_len = static_cast((float)rom_size * (4 / (float)lanes_used) + 0.5f); + + // calculate starting physical address of the ROM + uint32_t rom_phys_start = (0xF0FFFFFFUL | ((slot_num & 0xF) << 24)) - padded_len + 1; + + auto mem_crtl = dynamic_cast(gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL)); + if (!mem_crtl->add_rom_region(rom_phys_start, padded_len)) { + throw std::runtime_error("could not allocate ROM space"); + } + + int data_pos = 0; + + auto new_data = std::unique_ptr (new uint8_t[padded_len]); + + // prepare new ROM data by copying over used lanes + // and padding unused lanes with 0xFF + // NOTE: speed uncritical - don't optimize! + for (int i = 0; i < padded_len; i += 4) { + for (int b = 0; b < 4; b++) { + if (byte_lane & (1 << b)) { + new_data[i+b] = rom_data[data_pos++]; + } else { + new_data[i+b] = 0xFF; + } + } + } + + // move padded ROM data to the memory region + mem_crtl->set_data(rom_phys_start, new_data.get(), padded_len); + } + catch (const std::exception& exc) { + LOG_F(ERROR, "load_declaration_rom failed: %s", exc.what()); + result = -1; + } + + rom_file.close(); + + return result; +} diff --git a/devices/common/nubus/nubusutils.h b/devices/common/nubus/nubusutils.h new file mode 100644 index 0000000..bcee4a5 --- /dev/null +++ b/devices/common/nubus/nubusutils.h @@ -0,0 +1,30 @@ +/* +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 . +*/ + +#ifndef NUBUS_UTILS_H +#define NUBUS_UTILS_H + +#include +#include + +int load_declaration_rom(const std::string rom_path, int slot_num); + +#endif // NUBUS_UTILS_H