mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-06-19 11:29:29 +00:00
Merge pull request #40 from joevt/master
Gazelle fixes, PCI changes and additions, MMIO changes, etc.
This commit is contained in:
commit
e510c11be2
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -29,3 +29,6 @@ build
|
||||||
build-*
|
build-*
|
||||||
*.dir
|
*.dir
|
||||||
*.user
|
*.user
|
||||||
|
DerivedData
|
||||||
|
*.xcodeproj/project.xcworkspace
|
||||||
|
*.xcodeproj/xcuserdata
|
||||||
|
|
|
@ -34,13 +34,13 @@ inline void _u32xu64(uint32_t a, uint64_t b, uint64_t &hi, uint32_t &lo)
|
||||||
{
|
{
|
||||||
uint64_t p0 = (b & 0xffffffff) * a;
|
uint64_t p0 = (b & 0xffffffff) * a;
|
||||||
uint64_t p1 = (b >> 32) * a;
|
uint64_t p1 = (b >> 32) * a;
|
||||||
lo = p0;
|
lo = (uint32_t)p0;
|
||||||
hi = (p0 >> 32) + p1;
|
hi = (p0 >> 32) + p1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void _u64xu64(uint64_t a, uint64_t b, uint64_t &hi, uint64_t &lo)
|
inline void _u64xu64(uint64_t a, uint64_t b, uint64_t &hi, uint64_t &lo)
|
||||||
{
|
{
|
||||||
uint32_t p0h; uint64_t p0l; _u32xu64(b, a, p0h, p0l);
|
uint32_t p0h; uint64_t p0l; _u32xu64((uint32_t)b, a, p0h, p0l);
|
||||||
uint64_t p1h; uint32_t p1l; _u32xu64(b >> 32, a, p1h, p1l);
|
uint64_t p1h; uint32_t p1l; _u32xu64(b >> 32, a, p1h, p1l);
|
||||||
lo = p0l + ((uint64_t)p1l << 32);
|
lo = p0l + ((uint64_t)p1l << 32);
|
||||||
hi = p0h + p1h + (lo < p0l);
|
hi = p0h + p1h + (lo < p0l);
|
||||||
|
|
|
@ -32,7 +32,7 @@ TimerManager* TimerManager::timer_manager;
|
||||||
uint32_t TimerManager::add_oneshot_timer(uint64_t timeout, timer_cb cb)
|
uint32_t TimerManager::add_oneshot_timer(uint64_t timeout, timer_cb cb)
|
||||||
{
|
{
|
||||||
if (!timeout || timeout <= MIN_TIMEOUT_NS) {
|
if (!timeout || timeout <= MIN_TIMEOUT_NS) {
|
||||||
LOG_F(WARNING, "One-shot timer too short, timeout=%llu ns", timeout);
|
LOG_F(WARNING, "One-shot timer too short, timeout=%llu ns", (long long unsigned)timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimerInfo* ti = new TimerInfo;
|
TimerInfo* ti = new TimerInfo;
|
||||||
|
@ -58,7 +58,7 @@ uint32_t TimerManager::add_oneshot_timer(uint64_t timeout, timer_cb cb)
|
||||||
uint32_t TimerManager::add_cyclic_timer(uint64_t interval, timer_cb cb)
|
uint32_t TimerManager::add_cyclic_timer(uint64_t interval, timer_cb cb)
|
||||||
{
|
{
|
||||||
if (!interval || interval <= MIN_TIMEOUT_NS) {
|
if (!interval || interval <= MIN_TIMEOUT_NS) {
|
||||||
LOG_F(WARNING, "Cyclic timer interval too short, timeout=%llu ns", interval);
|
LOG_F(WARNING, "Cyclic timer interval too short, timeout=%llu ns", (long long unsigned)interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimerInfo* ti = new TimerInfo;
|
TimerInfo* ti = new TimerInfo;
|
||||||
|
|
|
@ -45,7 +45,7 @@ inline void power_setsoov(uint32_t a, uint32_t b, uint32_t d) {
|
||||||
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
|
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
|
||||||
static inline uint32_t power_rot_mask(unsigned rot_mb, unsigned rot_me) {
|
static inline uint32_t power_rot_mask(unsigned rot_mb, unsigned rot_me) {
|
||||||
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
||||||
uint32_t m2 = 0xFFFFFFFFUL << (31 - rot_me);
|
uint32_t m2 = (uint32_t)(0xFFFFFFFFUL << (31 - rot_me));
|
||||||
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ABORT_F("Unknown exception occured: %X\n", exception_type);
|
ABORT_F("Unknown exception occured: %X\n", (unsigned)exception_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -849,38 +849,38 @@ uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
|
||||||
try {
|
try {
|
||||||
if (reg_name_u == "PC") {
|
if (reg_name_u == "PC") {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.pc = val;
|
ppc_state.pc = (uint32_t)val;
|
||||||
return ppc_state.pc;
|
return ppc_state.pc;
|
||||||
}
|
}
|
||||||
if (reg_name_u == "MSR") {
|
if (reg_name_u == "MSR") {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.msr = val;
|
ppc_state.msr = (uint32_t)val;
|
||||||
return ppc_state.msr;
|
return ppc_state.msr;
|
||||||
}
|
}
|
||||||
if (reg_name_u == "CR") {
|
if (reg_name_u == "CR") {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.cr = val;
|
ppc_state.cr = (uint32_t)val;
|
||||||
return ppc_state.cr;
|
return ppc_state.cr;
|
||||||
}
|
}
|
||||||
if (reg_name_u == "FPSCR") {
|
if (reg_name_u == "FPSCR") {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.fpscr = val;
|
ppc_state.fpscr = (uint32_t)val;
|
||||||
return ppc_state.fpscr;
|
return ppc_state.fpscr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg_name_u.substr(0, 1) == "R") {
|
if (reg_name_u.substr(0, 1) == "R") {
|
||||||
reg_num_str = reg_name_u.substr(1);
|
reg_num_str = reg_name_u.substr(1);
|
||||||
reg_num = stoul(reg_num_str, NULL, 0);
|
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
|
||||||
if (reg_num < 32) {
|
if (reg_num < 32) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.gpr[reg_num] = val;
|
ppc_state.gpr[reg_num] = (uint32_t)val;
|
||||||
return ppc_state.gpr[reg_num];
|
return ppc_state.gpr[reg_num];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg_name_u.substr(0, 1) == "FR") {
|
if (reg_name_u.substr(0, 1) == "FR") {
|
||||||
reg_num_str = reg_name_u.substr(2);
|
reg_num_str = reg_name_u.substr(2);
|
||||||
reg_num = stoul(reg_num_str, NULL, 0);
|
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
|
||||||
if (reg_num < 32) {
|
if (reg_num < 32) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.fpr[reg_num].int64_r = val;
|
ppc_state.fpr[reg_num].int64_r = val;
|
||||||
|
@ -890,20 +890,20 @@ uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
|
||||||
|
|
||||||
if (reg_name_u.substr(0, 3) == "SPR") {
|
if (reg_name_u.substr(0, 3) == "SPR") {
|
||||||
reg_num_str = reg_name_u.substr(3);
|
reg_num_str = reg_name_u.substr(3);
|
||||||
reg_num = stoul(reg_num_str, NULL, 0);
|
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
|
||||||
if (reg_num < 1024) {
|
if (reg_num < 1024) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.spr[reg_num] = val;
|
ppc_state.spr[reg_num] = (uint32_t)val;
|
||||||
return ppc_state.spr[reg_num];
|
return ppc_state.spr[reg_num];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg_name_u.substr(0, 2) == "SR") {
|
if (reg_name_u.substr(0, 2) == "SR") {
|
||||||
reg_num_str = reg_name_u.substr(2);
|
reg_num_str = reg_name_u.substr(2);
|
||||||
reg_num = stoul(reg_num_str, NULL, 0);
|
reg_num = (unsigned)stoul(reg_num_str, NULL, 0);
|
||||||
if (reg_num < 16) {
|
if (reg_num < 16) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.sr[reg_num] = val;
|
ppc_state.sr[reg_num] = (uint32_t)val;
|
||||||
return ppc_state.sr[reg_num];
|
return ppc_state.sr[reg_num];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -911,7 +911,7 @@ uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
|
||||||
spr = SPRName2Num.find(reg_name_u);
|
spr = SPRName2Num.find(reg_name_u);
|
||||||
if (spr != SPRName2Num.end()) {
|
if (spr != SPRName2Num.end()) {
|
||||||
if (is_write)
|
if (is_write)
|
||||||
ppc_state.spr[spr->second] = val;
|
ppc_state.spr[spr->second] = (uint32_t)val;
|
||||||
return ppc_state.spr[spr->second];
|
return ppc_state.spr[spr->second];
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
@ -125,11 +125,11 @@ static BATResult mpc601_block_address_translation(uint32_t la)
|
||||||
|
|
||||||
// logical to physical translation
|
// logical to physical translation
|
||||||
pa = bat_entry->phys_hi | (la & ~bat_entry->hi_mask);
|
pa = bat_entry->phys_hi | (la & ~bat_entry->hi_mask);
|
||||||
break;
|
return BATResult{bat_hit, prot, pa};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BATResult{bat_hit, prot, pa};
|
return BATResult{bat_hit, 0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** PowerPC-style block address translation. */
|
/** PowerPC-style block address translation. */
|
||||||
|
@ -742,6 +742,7 @@ void tlb_flush_entry(uint32_t ea)
|
||||||
tlb1 = &dtlb1_mode2[0];
|
tlb1 = &dtlb1_mode2[0];
|
||||||
tlb2 = &dtlb2_mode2[0];
|
tlb2 = &dtlb2_mode2[0];
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
case 5:
|
case 5:
|
||||||
tlb1 = &dtlb1_mode3[0];
|
tlb1 = &dtlb1_mode3[0];
|
||||||
tlb2 = &dtlb2_mode3[0];
|
tlb2 = &dtlb2_mode3[0];
|
||||||
|
@ -967,7 +968,7 @@ void mmu_print_regs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_F(INFO, "");
|
LOG_F(INFO, "%s", "");
|
||||||
LOG_F(INFO, "SDR1 = 0x%X", ppc_state.spr[SPR::SDR1]);
|
LOG_F(INFO, "SDR1 = 0x%X", ppc_state.spr[SPR::SDR1]);
|
||||||
LOG_F(INFO, "Segment registers:");
|
LOG_F(INFO, "Segment registers:");
|
||||||
|
|
||||||
|
@ -1007,7 +1008,7 @@ inline T mmu_read_vmem(uint32_t guest_va)
|
||||||
// perform full address translation and refill the secondary TLB
|
// perform full address translation and refill the secondary TLB
|
||||||
tlb2_entry = dtlb2_refill(guest_va, 0);
|
tlb2_entry = dtlb2_refill(guest_va, 0);
|
||||||
if (tlb2_entry->flags & PAGE_NOPHYS) {
|
if (tlb2_entry->flags & PAGE_NOPHYS) {
|
||||||
return UnmappedVal;
|
return (T)UnmappedVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef TLB_PROFILING
|
#ifdef TLB_PROFILING
|
||||||
|
@ -1081,8 +1082,8 @@ inline void mmu_write_vmem(uint32_t guest_va, T value)
|
||||||
}
|
}
|
||||||
if (!(tlb1_entry->flags & TLBFlags::PTE_SET_C)) {
|
if (!(tlb1_entry->flags & TLBFlags::PTE_SET_C)) {
|
||||||
// perform full page address translation to update PTE.C bit
|
// perform full page address translation to update PTE.C bit
|
||||||
PATResult pat_res = page_address_translation(guest_va, false,
|
page_address_translation(guest_va, false,
|
||||||
!!(ppc_state.msr & 0x4000), true);
|
!!(ppc_state.msr & 0x4000), true);
|
||||||
tlb1_entry->flags |= TLBFlags::PTE_SET_C;
|
tlb1_entry->flags |= TLBFlags::PTE_SET_C;
|
||||||
|
|
||||||
// don't forget to update the secondary TLB as well
|
// don't forget to update the secondary TLB as well
|
||||||
|
@ -1120,8 +1121,8 @@ inline void mmu_write_vmem(uint32_t guest_va, T value)
|
||||||
|
|
||||||
if (!(tlb2_entry->flags & TLBFlags::PTE_SET_C)) {
|
if (!(tlb2_entry->flags & TLBFlags::PTE_SET_C)) {
|
||||||
// perform full page address translation to update PTE.C bit
|
// perform full page address translation to update PTE.C bit
|
||||||
PATResult pat_res = page_address_translation(guest_va, false,
|
page_address_translation(guest_va, false,
|
||||||
!!(ppc_state.msr & 0x4000), true);
|
!!(ppc_state.msr & 0x4000), true);
|
||||||
tlb2_entry->flags |= TLBFlags::PTE_SET_C;
|
tlb2_entry->flags |= TLBFlags::PTE_SET_C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -729,7 +729,7 @@ void dppc_interpreter::ppc_srawi() {
|
||||||
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
|
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
|
||||||
static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) {
|
static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) {
|
||||||
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
||||||
uint32_t m2 = 0xFFFFFFFFUL << (31 - rot_me);
|
uint32_t m2 = (uint32_t)(0xFFFFFFFFUL << (31 - rot_me));
|
||||||
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -861,11 +861,11 @@ static inline void calc_rtcl_value()
|
||||||
uint64_t new_ts = get_virt_time_ns();
|
uint64_t new_ts = get_virt_time_ns();
|
||||||
uint64_t rtc_l = new_ts - rtc_timestamp + rtc_lo;
|
uint64_t rtc_l = new_ts - rtc_timestamp + rtc_lo;
|
||||||
if (rtc_l >= ONE_BILLION_NS) { // check RTCL overflow
|
if (rtc_l >= ONE_BILLION_NS) { // check RTCL overflow
|
||||||
rtc_hi += rtc_l / ONE_BILLION_NS;
|
rtc_hi += (uint32_t)(rtc_l / ONE_BILLION_NS);
|
||||||
rtc_lo = rtc_l % ONE_BILLION_NS;
|
rtc_lo = rtc_l % ONE_BILLION_NS;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rtc_lo = rtc_l;
|
rtc_lo = (uint32_t)rtc_l;
|
||||||
}
|
}
|
||||||
rtc_timestamp = new_ts;
|
rtc_timestamp = new_ts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ using namespace std;
|
||||||
|
|
||||||
static uint32_t str2addr(string& addr_str) {
|
static uint32_t str2addr(string& addr_str) {
|
||||||
try {
|
try {
|
||||||
return stoul(addr_str, NULL, 0);
|
return (uint32_t)stoul(addr_str, NULL, 0);
|
||||||
} catch (invalid_argument& exc) {
|
} catch (invalid_argument& exc) {
|
||||||
throw invalid_argument(string("Cannot convert ") + addr_str);
|
throw invalid_argument(string("Cannot convert ") + addr_str);
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ static uint32_t str2addr(string& addr_str) {
|
||||||
|
|
||||||
static uint32_t str2num(string& num_str) {
|
static uint32_t str2num(string& num_str) {
|
||||||
try {
|
try {
|
||||||
return stol(num_str, NULL, 0);
|
return (uint32_t)stol(num_str, NULL, 0);
|
||||||
} catch (invalid_argument& exc) {
|
} catch (invalid_argument& exc) {
|
||||||
throw invalid_argument(string("Cannot convert ") + num_str);
|
throw invalid_argument(string("Cannot convert ") + num_str);
|
||||||
}
|
}
|
||||||
|
@ -512,7 +512,7 @@ void enter_debugger() {
|
||||||
}
|
}
|
||||||
} else if (cmd == "next" || cmd == "ni") {
|
} else if (cmd == "next" || cmd == "ni") {
|
||||||
addr_str = "PC";
|
addr_str = "PC";
|
||||||
addr = get_reg(addr_str) + 4;
|
addr = (uint32_t)get_reg(addr_str) + 4;
|
||||||
ppc_exec_until(addr);
|
ppc_exec_until(addr);
|
||||||
} else if (cmd == "until") {
|
} else if (cmd == "until") {
|
||||||
ss >> addr_str;
|
ss >> addr_str;
|
||||||
|
@ -588,7 +588,7 @@ void enter_debugger() {
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
addr_str = "PC";
|
addr_str = "PC";
|
||||||
addr = get_reg(addr_str);
|
addr = (uint32_t)get_reg(addr_str);
|
||||||
disasm(1, addr);
|
disasm(1, addr);
|
||||||
}
|
}
|
||||||
} catch (invalid_argument& exc) {
|
} catch (invalid_argument& exc) {
|
||||||
|
|
|
@ -75,7 +75,8 @@ private:
|
||||||
class GossamerID : public MMIODevice {
|
class GossamerID : public MMIODevice {
|
||||||
public:
|
public:
|
||||||
GossamerID(const uint16_t id) {
|
GossamerID(const uint16_t id) {
|
||||||
this->id = id, this->name = "Machine-id";
|
this->id = id;
|
||||||
|
this->name = "Machine-id";
|
||||||
supports_types(HWCompType::MMIO_DEV);
|
supports_types(HWCompType::MMIO_DEV);
|
||||||
};
|
};
|
||||||
~GossamerID() = default;
|
~GossamerID() = default;
|
||||||
|
|
|
@ -39,7 +39,7 @@ using namespace std;
|
||||||
|
|
||||||
static uint32_t str2env(string& num_str) {
|
static uint32_t str2env(string& num_str) {
|
||||||
try {
|
try {
|
||||||
return stoul(num_str, NULL, 0);
|
return (uint32_t)stoul(num_str, NULL, 0);
|
||||||
} catch (invalid_argument& exc) {
|
} catch (invalid_argument& exc) {
|
||||||
try {
|
try {
|
||||||
string num_str2 = string("0x") + num_str;
|
string num_str2 = string("0x") + num_str;
|
||||||
|
|
|
@ -298,6 +298,8 @@ void Bandit::verbose_address_space()
|
||||||
|
|
||||||
Chaos::Chaos(std::string name) : PCIHost()
|
Chaos::Chaos(std::string name) : PCIHost()
|
||||||
{
|
{
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
supports_types(HWCompType::PCI_HOST);
|
supports_types(HWCompType::PCI_HOST);
|
||||||
|
|
||||||
MemCtrlBase *mem_ctrl = dynamic_cast<MemCtrlBase *>
|
MemCtrlBase *mem_ctrl = dynamic_cast<MemCtrlBase *>
|
||||||
|
@ -308,8 +310,6 @@ Chaos::Chaos(std::string name) : PCIHost()
|
||||||
// base_addr + 0x800000 --> CONFIG_ADDR
|
// base_addr + 0x800000 --> CONFIG_ADDR
|
||||||
// base_addr + 0xC00000 --> CONFIG_DATA
|
// base_addr + 0xC00000 --> CONFIG_DATA
|
||||||
mem_ctrl->add_mmio_region(0xF0000000UL, 0x01000000, this);
|
mem_ctrl->add_mmio_region(0xF0000000UL, 0x01000000, this);
|
||||||
|
|
||||||
this->name = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Chaos::read(uint32_t rgn_start, uint32_t offset, int size)
|
uint32_t Chaos::read(uint32_t rgn_start, uint32_t offset, int size)
|
||||||
|
|
|
@ -102,7 +102,6 @@ public:
|
||||||
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
|
void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
|
||||||
uint32_t config_addr;
|
uint32_t config_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
PCIDevice::PCIDevice(std::string name)
|
PCIDevice::PCIDevice(std::string name)
|
||||||
{
|
{
|
||||||
|
this->name = name;
|
||||||
this->pci_name = name;
|
this->pci_name = name;
|
||||||
|
|
||||||
this->pci_rd_stat = [this]() { return this->status; };
|
this->pci_rd_stat = [this]() { return this->status; };
|
||||||
|
@ -188,7 +190,10 @@ int PCIDevice::attach_exp_rom_image(const std::string img_path)
|
||||||
|
|
||||||
// determine image size
|
// determine image size
|
||||||
img_file.seekg(0, std::ios::end);
|
img_file.seekg(0, std::ios::end);
|
||||||
uint32_t exp_rom_image_size = img_file.tellg();
|
size_t exp_rom_image_size = img_file.tellg();
|
||||||
|
if (exp_rom_image_size > 4*1024*1024) {
|
||||||
|
throw std::runtime_error("expansion ROM file too large");
|
||||||
|
}
|
||||||
|
|
||||||
// verify PCI struct offset
|
// verify PCI struct offset
|
||||||
uint16_t pci_struct_offset = 0;
|
uint16_t pci_struct_offset = 0;
|
||||||
|
@ -222,7 +227,7 @@ int PCIDevice::attach_exp_rom_image(const std::string img_path)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG_F(WARNING, "%s: loaded expansion rom (%d bytes adjusted to %d bytes).",
|
LOG_F(WARNING, "%s: loaded expansion rom (%d bytes adjusted to %d bytes).",
|
||||||
this->pci_name.c_str(), exp_rom_image_size, this->exp_rom_size);
|
this->pci_name.c_str(), (int)exp_rom_image_size, this->exp_rom_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->exp_bar_cfg = ~(this->exp_rom_size - 1);
|
this->exp_bar_cfg = ~(this->exp_rom_size - 1);
|
||||||
|
@ -246,7 +251,7 @@ void PCIDevice::set_bar_value(int bar_num, uint32_t value)
|
||||||
{
|
{
|
||||||
uint32_t bar_cfg = this->bars_cfg[bar_num];
|
uint32_t bar_cfg = this->bars_cfg[bar_num];
|
||||||
if (bar_cfg & 1) {
|
if (bar_cfg & 1) {
|
||||||
this->bars[bar_num] = (value & 0xFFFFFFFCUL) | 1;
|
this->bars[bar_num] = (value & 0xFFFFFFFCUL) | (bar_cfg & 3);
|
||||||
} else {
|
} else {
|
||||||
if (bar_cfg & 6) {
|
if (bar_cfg & 6) {
|
||||||
ABORT_F("Invalid or unsupported PCI space type: %d", (bar_cfg >> 1) & 3);
|
ABORT_F("Invalid or unsupported PCI space type: %d", (bar_cfg >> 1) & 3);
|
||||||
|
|
|
@ -55,6 +55,7 @@ enum {
|
||||||
PCI_VENDOR_ATI = 0x1002,
|
PCI_VENDOR_ATI = 0x1002,
|
||||||
PCI_VENDOR_MOTOROLA = 0x1057,
|
PCI_VENDOR_MOTOROLA = 0x1057,
|
||||||
PCI_VENDOR_APPLE = 0x106B,
|
PCI_VENDOR_APPLE = 0x106B,
|
||||||
|
PCI_VENDOR_NVIDIA = 0x10DE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,14 @@ bool PCIHost::pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDe
|
||||||
return mem_ctrl->add_mmio_region(start_addr, size, obj);
|
return mem_ctrl->add_mmio_region(start_addr, size, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PCIHost::pci_unregister_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj)
|
||||||
|
{
|
||||||
|
MemCtrlBase *mem_ctrl = dynamic_cast<MemCtrlBase *>
|
||||||
|
(gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
||||||
|
// FIXME: add sanity checks!
|
||||||
|
return mem_ctrl->remove_mmio_region(start_addr, size, obj);
|
||||||
|
}
|
||||||
|
|
||||||
void PCIHost::attach_pci_device(std::string& dev_name, int slot_id)
|
void PCIHost::attach_pci_device(std::string& dev_name, int slot_id)
|
||||||
{
|
{
|
||||||
if (!DeviceRegistry::device_registered(dev_name)) {
|
if (!DeviceRegistry::device_registered(dev_name)) {
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
virtual bool pci_register_device(int dev_num, PCIDevice* dev_instance);
|
virtual bool pci_register_device(int dev_num, PCIDevice* dev_instance);
|
||||||
|
|
||||||
virtual bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj);
|
virtual bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj);
|
||||||
|
virtual bool pci_unregister_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj);
|
||||||
|
|
||||||
virtual void attach_pci_device(std::string& dev_name, int slot_id);
|
virtual void attach_pci_device(std::string& dev_name, int slot_id);
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,6 @@ protected:
|
||||||
void change_bus_phase(int initiator_id);
|
void change_bus_phase(int initiator_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
|
||||||
|
|
||||||
// SCSI devices registered with this bus
|
// SCSI devices registered with this bus
|
||||||
std::array<ScsiDevice*, SCSI_MAX_DEVS> devices;
|
std::array<ScsiDevice*, SCSI_MAX_DEVS> devices;
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,12 @@ int RawFloppyImg::calc_phys_params()
|
||||||
|
|
||||||
// determine image size
|
// determine image size
|
||||||
img_file.seekg(0, img_file.end);
|
img_file.seekg(0, img_file.end);
|
||||||
this->img_size = img_file.tellg();
|
size_t img_size = img_file.tellg();
|
||||||
|
if (img_size > 2*1024*1024) {
|
||||||
|
LOG_F(ERROR, "RawFloppyImg: image size is too large to determine disk format from image size!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
this->img_size = (int)img_size;
|
||||||
img_file.seekg(0, img_file.beg);
|
img_file.seekg(0, img_file.beg);
|
||||||
|
|
||||||
img_file.close();
|
img_file.close();
|
||||||
|
@ -212,7 +217,7 @@ int DiskCopy42Img::calc_phys_params() {
|
||||||
|
|
||||||
// determine image size
|
// determine image size
|
||||||
img_file.seekg(0, img_file.end);
|
img_file.seekg(0, img_file.end);
|
||||||
this->img_size = img_file.tellg();
|
size_t img_size = img_file.tellg();
|
||||||
img_file.seekg(0, img_file.beg);
|
img_file.seekg(0, img_file.beg);
|
||||||
|
|
||||||
// get data size from image
|
// get data size from image
|
||||||
|
@ -221,11 +226,12 @@ int DiskCopy42Img::calc_phys_params() {
|
||||||
img_file.read((char *)&buf, 4);
|
img_file.read((char *)&buf, 4);
|
||||||
this->data_size = READ_DWORD_BE_U(buf);
|
this->data_size = READ_DWORD_BE_U(buf);
|
||||||
|
|
||||||
if (this->data_size > this->img_size) {
|
if (this->data_size > img_size) {
|
||||||
img_file.close();
|
img_file.close();
|
||||||
LOG_F(ERROR, "DiskCopy42Img: invalid data size %d", this->data_size);
|
LOG_F(ERROR, "DiskCopy42Img: invalid data size %d", this->data_size);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
this->img_size = (int)img_size;
|
||||||
|
|
||||||
uint8_t disk_format = 0xFFU;
|
uint8_t disk_format = 0xFFU;
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,7 @@ uint64_t MacSuperDrive::sync_to_disk()
|
||||||
track_time_ns -= this->index_delay;
|
track_time_ns -= this->index_delay;
|
||||||
|
|
||||||
// calculate current sector number from timestamp
|
// calculate current sector number from timestamp
|
||||||
int cur_sect_num = this->cur_sector = track_time_ns / this->sector_delay;
|
int cur_sect_num = this->cur_sector = (int)(track_time_ns / this->sector_delay);
|
||||||
|
|
||||||
this->sector_start_time = this->track_start_time + cur_sect_num * this->sector_delay +
|
this->sector_start_time = this->track_start_time + cur_sect_num * this->sector_delay +
|
||||||
this->index_delay;
|
this->index_delay;
|
||||||
|
|
|
@ -128,7 +128,7 @@ uint8_t Swim3Ctrl::read(uint8_t reg_offset)
|
||||||
|
|
||||||
void Swim3Ctrl::write(uint8_t reg_offset, uint8_t value)
|
void Swim3Ctrl::write(uint8_t reg_offset, uint8_t value)
|
||||||
{
|
{
|
||||||
uint8_t old_mode_reg, status_addr;
|
uint8_t status_addr;
|
||||||
|
|
||||||
switch(reg_offset) {
|
switch(reg_offset) {
|
||||||
case Swim3Reg::Timer:
|
case Swim3Reg::Timer:
|
||||||
|
|
|
@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <loguru.hpp>
|
||||||
|
|
||||||
|
|
||||||
MemCtrlBase::~MemCtrlBase() {
|
MemCtrlBase::~MemCtrlBase() {
|
||||||
|
@ -52,12 +53,74 @@ AddressMapEntry* MemCtrlBase::find_range(uint32_t addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressMapEntry* MemCtrlBase::find_range_exact(uint32_t addr, uint32_t size, MMIODevice* dev_instance) {
|
||||||
|
if (size) {
|
||||||
|
uint32_t end = addr + size - 1;
|
||||||
|
for (auto& entry : address_map) {
|
||||||
|
if (addr == entry->start && end == entry->end && (!dev_instance || dev_instance == entry->devobj) )
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressMapEntry* MemCtrlBase::find_range_contains(uint32_t addr, uint32_t size) {
|
||||||
|
if (size) {
|
||||||
|
uint32_t end = addr + size - 1;
|
||||||
|
for (auto& entry : address_map) {
|
||||||
|
if (addr >= entry->start && end <= entry->end)
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AddressMapEntry* MemCtrlBase::find_range_overlaps(uint32_t addr, uint32_t size) {
|
||||||
|
if (size) {
|
||||||
|
uint32_t end = addr + size - 1;
|
||||||
|
for (auto& entry : address_map) {
|
||||||
|
if (end >= entry->start && addr <= entry->end)
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MemCtrlBase::is_range_free(uint32_t addr, uint32_t size) {
|
||||||
|
bool result = true;
|
||||||
|
if (size) {
|
||||||
|
uint32_t end = addr + size - 1;
|
||||||
|
for (auto& entry : address_map) {
|
||||||
|
if (addr == entry->start && end == entry->end) {
|
||||||
|
LOG_F(WARNING, "memory region 0x%X..0x%X%s%s%s already exists", addr, end, entry->devobj ? " (" : "", entry->devobj ? entry->devobj->get_name().c_str() : "", entry->devobj ? ")" : "");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else if (addr >= entry->start && end <= entry->end) {
|
||||||
|
LOG_F(WARNING, "0x%X..0x%X already exists in memory region 0x%X..0x%X%s%s%s", addr, end, entry->start, entry->end, entry->devobj ? " (" : "", entry->devobj ? entry->devobj->get_name().c_str() : "", entry->devobj ? ")" : "");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else if (end >= entry->start && addr <= entry->end) {
|
||||||
|
LOG_F(ERROR, "0x%X..0x%X overlaps existing memory region 0x%X..0x%X%s%s%s", addr, end, entry->start, entry->end, entry->devobj ? " (" : "", entry->devobj ? entry->devobj->get_name().c_str() : "", entry->devobj ? ")" : "");
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MemCtrlBase::add_mem_region(
|
bool MemCtrlBase::add_mem_region(
|
||||||
uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val = 0) {
|
uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val = 0) {
|
||||||
AddressMapEntry *entry;
|
AddressMapEntry *entry;
|
||||||
|
|
||||||
/* error if a memory region for the given range already exists */
|
/* error if a memory region for the given range already exists */
|
||||||
if (find_range(start_addr) || find_range(start_addr + size))
|
if (!is_range_free(start_addr, size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint8_t* reg_content = new uint8_t[size];
|
uint8_t* reg_content = new uint8_t[size];
|
||||||
|
@ -66,8 +129,9 @@ bool MemCtrlBase::add_mem_region(
|
||||||
|
|
||||||
entry = new AddressMapEntry;
|
entry = new AddressMapEntry;
|
||||||
|
|
||||||
|
uint32_t end = start_addr + size - 1;
|
||||||
entry->start = start_addr;
|
entry->start = start_addr;
|
||||||
entry->end = start_addr + size - 1;
|
entry->end = end;
|
||||||
entry->mirror = dest_addr;
|
entry->mirror = dest_addr;
|
||||||
entry->type = type;
|
entry->type = type;
|
||||||
entry->devobj = 0;
|
entry->devobj = 0;
|
||||||
|
@ -75,6 +139,14 @@ bool MemCtrlBase::add_mem_region(
|
||||||
|
|
||||||
this->address_map.push_back(entry);
|
this->address_map.push_back(entry);
|
||||||
|
|
||||||
|
LOG_F(INFO, "Added mem region 0x%X..0x%X (%s%s%s%s) -> 0x%X", start_addr, end,
|
||||||
|
entry->type & RT_ROM ? "ROM," : "",
|
||||||
|
entry->type & RT_RAM ? "RAM," : "",
|
||||||
|
entry->type & RT_MMIO ? "MMIO," : "",
|
||||||
|
entry->type & RT_MIRROR ? "MIRROR," : "",
|
||||||
|
dest_addr
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,8 +170,9 @@ bool MemCtrlBase::add_mem_mirror(uint32_t start_addr, uint32_t dest_addr) {
|
||||||
|
|
||||||
entry = new AddressMapEntry;
|
entry = new AddressMapEntry;
|
||||||
|
|
||||||
|
uint32_t end = start_addr + (ref_entry->end - ref_entry->start);
|
||||||
entry->start = start_addr;
|
entry->start = start_addr;
|
||||||
entry->end = start_addr + (ref_entry->end - ref_entry->start);
|
entry->end = end;
|
||||||
entry->mirror = dest_addr;
|
entry->mirror = dest_addr;
|
||||||
entry->type = ref_entry->type | RT_MIRROR;
|
entry->type = ref_entry->type | RT_MIRROR;
|
||||||
entry->devobj = 0;
|
entry->devobj = 0;
|
||||||
|
@ -107,6 +180,16 @@ bool MemCtrlBase::add_mem_mirror(uint32_t start_addr, uint32_t dest_addr) {
|
||||||
|
|
||||||
this->address_map.push_back(entry);
|
this->address_map.push_back(entry);
|
||||||
|
|
||||||
|
LOG_F(INFO, "Added mem region mirror 0x%X..0x%X (%s%s%s%s) -> 0x%X : 0x%X..0x%X%s%s%s", start_addr, end,
|
||||||
|
entry->type & RT_ROM ? "ROM," : "",
|
||||||
|
entry->type & RT_RAM ? "RAM," : "",
|
||||||
|
entry->type & RT_MMIO ? "MMIO," : "",
|
||||||
|
entry->type & RT_MIRROR ? "MIRROR," : "",
|
||||||
|
dest_addr,
|
||||||
|
ref_entry->start, ref_entry->end,
|
||||||
|
ref_entry->devobj ? " (" : "", ref_entry->devobj ? ref_entry->devobj->get_name().c_str() : "", ref_entry->devobj ? ")" : ""
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,14 +212,15 @@ bool MemCtrlBase::set_data(uint32_t reg_addr, const uint8_t* data, uint32_t size
|
||||||
bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance) {
|
bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance) {
|
||||||
AddressMapEntry *entry;
|
AddressMapEntry *entry;
|
||||||
|
|
||||||
/* error if another region for the given range already exists */
|
/* error if a memory region for the given range already exists */
|
||||||
if (find_range(start_addr) || find_range(start_addr + size - 1))
|
if (!is_range_free(start_addr, size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
entry = new AddressMapEntry;
|
entry = new AddressMapEntry;
|
||||||
|
|
||||||
|
uint32_t end = start_addr + size - 1;
|
||||||
entry->start = start_addr;
|
entry->start = start_addr;
|
||||||
entry->end = start_addr + size - 1;
|
entry->end = end;
|
||||||
entry->mirror = 0;
|
entry->mirror = 0;
|
||||||
entry->type = RT_MMIO;
|
entry->type = RT_MMIO;
|
||||||
entry->devobj = dev_instance;
|
entry->devobj = dev_instance;
|
||||||
|
@ -144,9 +228,33 @@ bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice
|
||||||
|
|
||||||
this->address_map.push_back(entry);
|
this->address_map.push_back(entry);
|
||||||
|
|
||||||
|
LOG_F(INFO, "Added mmio region 0x%X..0x%X%s%s%s", start_addr, end, dev_instance ? " (" : "", dev_instance ? dev_instance->get_name().c_str() : "", dev_instance ? ")" : "");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemCtrlBase::remove_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance) {
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
uint32_t end = start_addr + size - 1;
|
||||||
|
address_map.erase(std::remove_if(address_map.begin(), address_map.end(),
|
||||||
|
[start_addr, end, dev_instance, &found](const AddressMapEntry *entry) {
|
||||||
|
bool result = (start_addr == entry->start && end == entry->end && (!dev_instance || dev_instance == entry->devobj));
|
||||||
|
found += result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
), address_map.end());
|
||||||
|
|
||||||
|
if (found == 0)
|
||||||
|
LOG_F(ERROR, "Cannot find mmio region 0x%X..0x%X%s%s%s to remove", start_addr, end, dev_instance ? " (" : "", dev_instance ? dev_instance->get_name().c_str() : "", dev_instance ? ")" : "");
|
||||||
|
else if (found > 1)
|
||||||
|
LOG_F(ERROR, "Removed %d occurrences of mmio region 0x%X..0x%X%s%s%s", found, start_addr, end, dev_instance ? " (" : "", dev_instance ? dev_instance->get_name().c_str() : "", dev_instance ? ")" : "");
|
||||||
|
else
|
||||||
|
LOG_F(INFO, "Removed mmio region 0x%X..0x%X%s%s%s", start_addr, end, dev_instance ? " (" : "", dev_instance ? dev_instance->get_name().c_str() : "", dev_instance ? ")" : "");
|
||||||
|
|
||||||
|
return (found > 0);
|
||||||
|
}
|
||||||
|
|
||||||
AddressMapEntry* MemCtrlBase::find_rom_region()
|
AddressMapEntry* MemCtrlBase::find_rom_region()
|
||||||
{
|
{
|
||||||
for (auto& entry : address_map) {
|
for (auto& entry : address_map) {
|
||||||
|
|
|
@ -68,10 +68,16 @@ public:
|
||||||
virtual bool add_mem_mirror(uint32_t start_addr, uint32_t dest_addr);
|
virtual bool add_mem_mirror(uint32_t start_addr, uint32_t dest_addr);
|
||||||
|
|
||||||
virtual bool add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance);
|
virtual bool add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance);
|
||||||
|
virtual bool remove_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance);
|
||||||
|
|
||||||
virtual bool set_data(uint32_t reg_addr, const uint8_t* data, uint32_t size);
|
virtual bool set_data(uint32_t reg_addr, const uint8_t* data, uint32_t size);
|
||||||
|
|
||||||
AddressMapEntry* find_range(uint32_t addr);
|
AddressMapEntry* find_range(uint32_t addr);
|
||||||
|
AddressMapEntry* find_range_exact(uint32_t addr, uint32_t size, MMIODevice* dev_instance);
|
||||||
|
AddressMapEntry* find_range_contains(uint32_t addr, uint32_t size);
|
||||||
|
AddressMapEntry* find_range_overlaps(uint32_t addr, uint32_t size);
|
||||||
|
bool is_range_free(uint32_t addr, uint32_t size);
|
||||||
|
|
||||||
AddressMapEntry* find_rom_region();
|
AddressMapEntry* find_rom_region();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -37,8 +37,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle"), PCIHost()
|
MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle"), PCIHost()
|
||||||
{
|
{
|
||||||
this->name = "Grackle";
|
|
||||||
|
|
||||||
supports_types(HWCompType::MEM_CTRL | HWCompType::MMIO_DEV |
|
supports_types(HWCompType::MEM_CTRL | HWCompType::MMIO_DEV |
|
||||||
HWCompType::PCI_HOST | HWCompType::PCI_DEV);
|
HWCompType::PCI_HOST | HWCompType::PCI_DEV);
|
||||||
|
|
||||||
|
@ -255,7 +253,7 @@ void MPC106::setup_ram() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->add_ram_region(0, ram_size)) {
|
if (!this->add_ram_region(0, ram_size)) {
|
||||||
LOG_F(ERROR, "MPC106 RAM allocation failed!");
|
LOG_F(WARNING, "MPC106 RAM allocation 0x%X..0x%X failed (maybe already exists?)", 0, ram_size - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ PsxCtrl::PsxCtrl(int bridge_num, std::string name)
|
||||||
// add MMIO region for the PSX control registers
|
// add MMIO region for the PSX control registers
|
||||||
add_mmio_region(0xF8000000, 0x70, this);
|
add_mmio_region(0xF8000000, 0x70, this);
|
||||||
|
|
||||||
this->sys_id = 0x30040000; // TODO: use correct value here!
|
this->sys_id = 0x10000000;
|
||||||
this->chip_rev = 0; // old PSX, what's about PSX+?
|
this->chip_rev = 0; // old PSX, what's about PSX+?
|
||||||
this->sys_config = PSX_BUS_SPEED_50;
|
this->sys_config = PSX_BUS_SPEED_50;
|
||||||
}
|
}
|
||||||
|
|
|
@ -336,7 +336,6 @@ void CharIoSocket::rcv_disable()
|
||||||
bool CharIoSocket::rcv_char_available()
|
bool CharIoSocket::rcv_char_available()
|
||||||
{
|
{
|
||||||
static int consecutivechars = 0;
|
static int consecutivechars = 0;
|
||||||
static int count = 0;
|
|
||||||
|
|
||||||
if (consecutivechars >= 15) {
|
if (consecutivechars >= 15) {
|
||||||
consecutivechars++;
|
consecutivechars++;
|
||||||
|
@ -377,7 +376,7 @@ bool CharIoSocket::rcv_char_available()
|
||||||
if (sockfd != -1) {
|
if (sockfd != -1) {
|
||||||
if (FD_ISSET(sockfd, &readfds)) {
|
if (FD_ISSET(sockfd, &readfds)) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
int received = recv(sockfd, &c, 1, 0);
|
int received = (int)recv(sockfd, &c, 1, 0);
|
||||||
if (received == -1) {
|
if (received == -1) {
|
||||||
if (acceptfd == -1) {
|
if (acceptfd == -1) {
|
||||||
//LOG_F(INFO, "socket sock read (not accepted yet) err: %s", strerror(errno)); // this happens once before accept
|
//LOG_F(INFO, "socket sock read (not accepted yet) err: %s", strerror(errno)); // this happens once before accept
|
||||||
|
@ -443,7 +442,7 @@ int CharIoSocket::xmit_char(uint8_t c)
|
||||||
CharIoSocket::rcv_char_available();
|
CharIoSocket::rcv_char_available();
|
||||||
|
|
||||||
if (acceptfd != -1) {
|
if (acceptfd != -1) {
|
||||||
int sent = send(acceptfd, &c, 1, 0);
|
int sent = (int)send(acceptfd, &c, 1, 0);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
LOG_F(INFO, "socket accept write err: %s", strerror(errno));
|
LOG_F(INFO, "socket accept write err: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
@ -463,7 +462,7 @@ int CharIoSocket::rcv_char(uint8_t *c)
|
||||||
CharIoSocket::rcv_char_available();
|
CharIoSocket::rcv_char_available();
|
||||||
|
|
||||||
if (acceptfd != -1) {
|
if (acceptfd != -1) {
|
||||||
int received = recv(acceptfd, c, 1, 0);
|
int received = (int)recv(acceptfd, c, 1, 0);
|
||||||
if (received == -1) {
|
if (received == -1) {
|
||||||
LOG_F(INFO, "socket accept read err: %s", strerror(errno));
|
LOG_F(INFO, "socket accept read err: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,6 @@ uint8_t EsccController::read(uint8_t reg_offset)
|
||||||
} else {
|
} else {
|
||||||
return this->ch_a->read_reg(this->reg_ptr);
|
return this->ch_a->read_reg(this->reg_ptr);
|
||||||
}
|
}
|
||||||
this->reg_ptr = 0;
|
|
||||||
break;
|
break;
|
||||||
case EsccReg::Port_B_Data:
|
case EsccReg::Port_B_Data:
|
||||||
return this->ch_b->receive_byte();
|
return this->ch_b->receive_byte();
|
||||||
|
|
|
@ -147,12 +147,12 @@ long sound_out_callback(cubeb_stream *stream, void *user_data,
|
||||||
out_frames = 0;
|
out_frames = 0;
|
||||||
|
|
||||||
while (req_frames > 0) {
|
while (req_frames > 0) {
|
||||||
if (!dma_ch->pull_data(req_frames << 2, &got_len, &p_in)) {
|
if (!dma_ch->pull_data((uint32_t)req_frames << 2, &got_len, &p_in)) {
|
||||||
frames = got_len >> 2;
|
frames = got_len >> 2;
|
||||||
|
|
||||||
in_buf = (int16_t*)p_in;
|
in_buf = (int16_t*)p_in;
|
||||||
|
|
||||||
for (int i = frames; i > 0; i--) {
|
for (int i = (int)frames; i > 0; i--) {
|
||||||
out_buf[0] = BYTESWAP_16(in_buf[0]);
|
out_buf[0] = BYTESWAP_16(in_buf[0]);
|
||||||
out_buf[1] = BYTESWAP_16(in_buf[1]);
|
out_buf[1] = BYTESWAP_16(in_buf[1]);
|
||||||
in_buf += 2;
|
in_buf += 2;
|
||||||
|
|
|
@ -557,7 +557,7 @@ void ATIRage::crtc_enable() {
|
||||||
void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
|
void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) {
|
||||||
uint8_t *src_buf, *src_row, *dst_row, px4;
|
uint8_t *src_buf, *src_row, *dst_row, px4;
|
||||||
|
|
||||||
int horz_offset = READ_DWORD_LE_A(&this->mm_regs[ATI_CUR_HORZ_VERT_OFF]) & 0x3F;
|
// int horz_offset = READ_DWORD_LE_A(&this->mm_regs[ATI_CUR_HORZ_VERT_OFF]) & 0x3F;
|
||||||
int vert_offset = (READ_DWORD_LE_A(&this->mm_regs[ATI_CUR_HORZ_VERT_OFF]) >> 16) & 0x3F;
|
int vert_offset = (READ_DWORD_LE_A(&this->mm_regs[ATI_CUR_HORZ_VERT_OFF]) >> 16) & 0x3F;
|
||||||
|
|
||||||
src_buf = &this->vram_ptr[(READ_DWORD_LE_A(&this->mm_regs[ATI_CUR_OFFSET]) * 8)];
|
src_buf = &this->vram_ptr[(READ_DWORD_LE_A(&this->mm_regs[ATI_CUR_OFFSET]) * 8)];
|
||||||
|
|
|
@ -59,6 +59,7 @@ ControlVideo::ControlVideo()
|
||||||
this->vendor_id = PCI_VENDOR_APPLE;
|
this->vendor_id = PCI_VENDOR_APPLE;
|
||||||
this->device_id = 3;
|
this->device_id = 3;
|
||||||
this->class_rev = 0;
|
this->class_rev = 0;
|
||||||
|
this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set)
|
||||||
this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB)
|
this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB)
|
||||||
this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB)
|
this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB)
|
||||||
|
|
||||||
|
@ -84,6 +85,10 @@ ControlVideo::ControlVideo()
|
||||||
void ControlVideo::notify_bar_change(int bar_num)
|
void ControlVideo::notify_bar_change(int bar_num)
|
||||||
{
|
{
|
||||||
switch (bar_num) {
|
switch (bar_num) {
|
||||||
|
case 0:
|
||||||
|
this->io_base = this->bars[bar_num] & ~3;
|
||||||
|
LOG_F(INFO, "Control: I/O space address set to 0x%08X", this->io_base);
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (this->regs_base != (this->bars[bar_num] & 0xFFFFFFF0UL)) {
|
if (this->regs_base != (this->bars[bar_num] & 0xFFFFFFF0UL)) {
|
||||||
this->regs_base = this->bars[bar_num] & 0xFFFFFFF0UL;
|
this->regs_base = this->bars[bar_num] & 0xFFFFFFF0UL;
|
||||||
|
@ -116,18 +121,22 @@ uint32_t ControlVideo::read(uint32_t rgn_start, uint32_t offset, int size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (offset >> 4) {
|
if (rgn_start == this->regs_base) {
|
||||||
case ControlRegs::TEST:
|
switch (offset >> 4) {
|
||||||
result = this->test;
|
case ControlRegs::TEST:
|
||||||
break;
|
result = this->test;
|
||||||
case ControlRegs::MON_SENSE:
|
break;
|
||||||
result = this->cur_mon_id << 6;
|
case ControlRegs::MON_SENSE:
|
||||||
break;
|
result = this->cur_mon_id << 6;
|
||||||
default:
|
break;
|
||||||
LOG_F(INFO, "read from 0x%08X:0x%08X", rgn_start, offset);
|
default:
|
||||||
|
LOG_F(INFO, "read from 0x%08X:0x%08X", rgn_start, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BYTESWAP_32(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BYTESWAP_32(result);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlVideo::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
|
void ControlVideo::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size)
|
||||||
|
@ -141,75 +150,77 @@ void ControlVideo::write(uint32_t rgn_start, uint32_t offset, uint32_t value, in
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = BYTESWAP_32(value);
|
if (rgn_start == this->regs_base) {
|
||||||
|
value = BYTESWAP_32(value);
|
||||||
|
|
||||||
switch (offset >> 4) {
|
switch (offset >> 4) {
|
||||||
case ControlRegs::VFPEQ:
|
case ControlRegs::VFPEQ:
|
||||||
case ControlRegs::VFP:
|
case ControlRegs::VFP:
|
||||||
case ControlRegs::VAL:
|
case ControlRegs::VAL:
|
||||||
case ControlRegs::VBP:
|
case ControlRegs::VBP:
|
||||||
case ControlRegs::VBPEQ:
|
case ControlRegs::VBPEQ:
|
||||||
case ControlRegs::VSYNC:
|
case ControlRegs::VSYNC:
|
||||||
case ControlRegs::VHLINE:
|
case ControlRegs::VHLINE:
|
||||||
case ControlRegs::PIPED:
|
case ControlRegs::PIPED:
|
||||||
case ControlRegs::HPIX:
|
case ControlRegs::HPIX:
|
||||||
case ControlRegs::HFP:
|
case ControlRegs::HFP:
|
||||||
case ControlRegs::HAL:
|
case ControlRegs::HAL:
|
||||||
case ControlRegs::HBWAY:
|
case ControlRegs::HBWAY:
|
||||||
case ControlRegs::HSP:
|
case ControlRegs::HSP:
|
||||||
case ControlRegs::HEQ:
|
case ControlRegs::HEQ:
|
||||||
case ControlRegs::HLFLN:
|
case ControlRegs::HLFLN:
|
||||||
case ControlRegs::HSERR:
|
case ControlRegs::HSERR:
|
||||||
this->swatch_params[(offset >> 4) - 1] = value;
|
this->swatch_params[(offset >> 4) - 1] = value;
|
||||||
break;
|
break;
|
||||||
case ControlRegs::TEST:
|
case ControlRegs::TEST:
|
||||||
if (this->test != value) {
|
if (this->test != value) {
|
||||||
if ((this->test & ~TEST_STROBE) != (value & ~TEST_STROBE)) {
|
if ((this->test & ~TEST_STROBE) != (value & ~TEST_STROBE)) {
|
||||||
this->test = value;
|
this->test = value;
|
||||||
this->test_shift = 0;
|
this->test_shift = 0;
|
||||||
LOG_F(9, "New TEST value: 0x%08X", this->test);
|
LOG_F(9, "New TEST value: 0x%08X", this->test);
|
||||||
} else {
|
} else {
|
||||||
LOG_F(9, "TEST strobe bit flipped, new value: 0x%08X", value);
|
LOG_F(9, "TEST strobe bit flipped, new value: 0x%08X", value);
|
||||||
this->test = value;
|
this->test = value;
|
||||||
if (++this->test_shift >= 3) {
|
if (++this->test_shift >= 3) {
|
||||||
LOG_F(9, "Received TEST reg value: 0x%08X", this->test & ~TEST_STROBE);
|
LOG_F(9, "Received TEST reg value: 0x%08X", this->test & ~TEST_STROBE);
|
||||||
if ((this->test ^ this->prev_test) & 0x400) {
|
if ((this->test ^ this->prev_test) & 0x400) {
|
||||||
if (this->test & 0x400) {
|
if (this->test & 0x400) {
|
||||||
this->disable_display();
|
this->disable_display();
|
||||||
} else {
|
} else {
|
||||||
this->enable_display();
|
this->enable_display();
|
||||||
|
}
|
||||||
|
this->prev_test = this->test;
|
||||||
}
|
}
|
||||||
this->prev_test = this->test;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case ControlRegs::GBASE:
|
||||||
|
this->fb_base = value;
|
||||||
|
break;
|
||||||
|
case ControlRegs::ROW_WORDS:
|
||||||
|
this->row_words = value;
|
||||||
|
break;
|
||||||
|
case ControlRegs::MON_SENSE:
|
||||||
|
LOG_F(9, "Control: monitor sense written with 0x%X", value);
|
||||||
|
value = (value >> 3) & 7;
|
||||||
|
this->cur_mon_id = this->display_id->read_monitor_sense(value & 7, value ^ 7);
|
||||||
|
break;
|
||||||
|
case ControlRegs::ENABLE:
|
||||||
|
this->flags = value;
|
||||||
|
break;
|
||||||
|
case ControlRegs::GSC_DIVIDE:
|
||||||
|
this->clock_divider = value;
|
||||||
|
break;
|
||||||
|
case ControlRegs::REFRESH_COUNT:
|
||||||
|
LOG_F(INFO, "Control: refresh count set to 0x%08X", value);
|
||||||
|
break;
|
||||||
|
case ControlRegs::INT_ENABLE:
|
||||||
|
this->int_enable = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_F(INFO, "write 0x%08X to 0x%08X:0x%08X", value, rgn_start, offset);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case ControlRegs::GBASE:
|
|
||||||
this->fb_base = value;
|
|
||||||
break;
|
|
||||||
case ControlRegs::ROW_WORDS:
|
|
||||||
this->row_words = value;
|
|
||||||
break;
|
|
||||||
case ControlRegs::MON_SENSE:
|
|
||||||
LOG_F(9, "Control: monitor sense written with 0x%X", value);
|
|
||||||
value = (value >> 3) & 7;
|
|
||||||
this->cur_mon_id = this->display_id->read_monitor_sense(value & 7, value ^ 7);
|
|
||||||
break;
|
|
||||||
case ControlRegs::ENABLE:
|
|
||||||
this->flags = value;
|
|
||||||
break;
|
|
||||||
case ControlRegs::GSC_DIVIDE:
|
|
||||||
this->clock_divider = value;
|
|
||||||
break;
|
|
||||||
case ControlRegs::REFRESH_COUNT:
|
|
||||||
LOG_F(INFO, "Control: refresh count set to 0x%08X", value);
|
|
||||||
break;
|
|
||||||
case ControlRegs::INT_ENABLE:
|
|
||||||
this->int_enable = value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_F(INFO, "write 0x%08X to 0x%08X:0x%08X", value, rgn_start, offset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,7 @@ private:
|
||||||
std::unique_ptr<uint8_t[]> vram_ptr;
|
std::unique_ptr<uint8_t[]> vram_ptr;
|
||||||
|
|
||||||
uint32_t vram_size;
|
uint32_t vram_size;
|
||||||
|
uint32_t io_base = 0;
|
||||||
uint32_t vram_base = 0;
|
uint32_t vram_base = 0;
|
||||||
uint32_t regs_base = 0;
|
uint32_t regs_base = 0;
|
||||||
uint32_t prev_test = 0x433;
|
uint32_t prev_test = 0x433;
|
||||||
|
|
|
@ -88,7 +88,6 @@ DisplayID::DisplayID(uint8_t std_code, uint8_t ext_code)
|
||||||
uint8_t DisplayID::read_monitor_sense(uint8_t levels, uint8_t dirs)
|
uint8_t DisplayID::read_monitor_sense(uint8_t levels, uint8_t dirs)
|
||||||
{
|
{
|
||||||
uint8_t scl, sda;
|
uint8_t scl, sda;
|
||||||
uint16_t result;
|
|
||||||
|
|
||||||
switch(this->id_kind) {
|
switch(this->id_kind) {
|
||||||
case Disp_Id_Kind::DDC2B:
|
case Disp_Id_Kind::DDC2B:
|
||||||
|
|
|
@ -36,6 +36,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
int initialize_catalyst(std::string& id)
|
int initialize_catalyst(std::string& id)
|
||||||
{
|
{
|
||||||
|
LOG_F(INFO, "Building machine catalyst");
|
||||||
|
|
||||||
PlatinumCtrl* platinum_obj;
|
PlatinumCtrl* platinum_obj;
|
||||||
|
|
||||||
PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("Bandit1"));
|
PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("Bandit1"));
|
||||||
|
|
|
@ -269,7 +269,8 @@ void MachineFactory::set_machine_settings(map<string, string> &settings) {
|
||||||
|
|
||||||
string MachineFactory::machine_name_from_rom(string& rom_filepath) {
|
string MachineFactory::machine_name_from_rom(string& rom_filepath) {
|
||||||
ifstream rom_file;
|
ifstream rom_file;
|
||||||
uint32_t file_size, config_info_offset, rom_id;
|
size_t file_size;
|
||||||
|
uint32_t config_info_offset, rom_id;
|
||||||
char rom_id_str[17];
|
char rom_id_str[17];
|
||||||
|
|
||||||
string machine_name = "";
|
string machine_name = "";
|
||||||
|
@ -354,7 +355,7 @@ int MachineFactory::load_boot_rom(string& rom_filepath) {
|
||||||
gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
||||||
|
|
||||||
if ((rom_reg = mem_ctrl->find_rom_region())) {
|
if ((rom_reg = mem_ctrl->find_rom_region())) {
|
||||||
mem_ctrl->set_data(rom_reg->start, sysrom_mem, file_size);
|
mem_ctrl->set_data(rom_reg->start, sysrom_mem, (uint32_t)file_size);
|
||||||
} else {
|
} else {
|
||||||
ABORT_F("Could not locate physical ROM region!");
|
ABORT_F("Could not locate physical ROM region!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ int get_cpu_pll_value(const uint64_t cpu_freq_hz) {
|
||||||
|
|
||||||
int initialize_gazelle(std::string& id)
|
int initialize_gazelle(std::string& id)
|
||||||
{
|
{
|
||||||
|
LOG_F(INFO, "Building machine gazelle");
|
||||||
|
|
||||||
PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("PsxPci1"));
|
PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("PsxPci1"));
|
||||||
|
|
||||||
// register O'Hare I/O controller with the main PCI bus
|
// register O'Hare I/O controller with the main PCI bus
|
||||||
|
|
|
@ -94,6 +94,8 @@ static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) {
|
||||||
|
|
||||||
int initialize_gossamer(std::string& id)
|
int initialize_gossamer(std::string& id)
|
||||||
{
|
{
|
||||||
|
LOG_F(INFO, "Building machine gossamer");
|
||||||
|
|
||||||
// get pointer to the memory controller/PCI host bridge object
|
// get pointer to the memory controller/PCI host bridge object
|
||||||
MPC106* grackle_obj = dynamic_cast<MPC106*>(gMachineObj->get_comp_by_name("Grackle"));
|
MPC106* grackle_obj = dynamic_cast<MPC106*>(gMachineObj->get_comp_by_name("Grackle"));
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ int initialize_gossamer(std::string& id)
|
||||||
|
|
||||||
gMachineObj->add_device("MachineID", std::unique_ptr<GossamerID>(new GossamerID(sys_reg)));
|
gMachineObj->add_device("MachineID", std::unique_ptr<GossamerID>(new GossamerID(sys_reg)));
|
||||||
grackle_obj->add_mmio_region(
|
grackle_obj->add_mmio_region(
|
||||||
0xFF000004, 4096, dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID")));
|
0xFF000000 + 4, 4096 - 4, dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID")));
|
||||||
|
|
||||||
// allocate ROM region
|
// allocate ROM region
|
||||||
if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) {
|
if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) {
|
||||||
|
|
|
@ -38,6 +38,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
int initialize_pdm(std::string& id)
|
int initialize_pdm(std::string& id)
|
||||||
{
|
{
|
||||||
|
LOG_F(INFO, "Building machine pdm");
|
||||||
|
|
||||||
uint16_t machine_id;
|
uint16_t machine_id;
|
||||||
|
|
||||||
// get raw pointer to HMC object
|
// get raw pointer to HMC object
|
||||||
|
|
|
@ -73,7 +73,7 @@ bool StrProperty::check_val(std::string str)
|
||||||
uint32_t IntProperty::get_int()
|
uint32_t IntProperty::get_int()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
uint32_t result = strtoul(this->get_string().c_str(), 0, 0);
|
uint32_t result = (uint32_t)strtoul(this->get_string().c_str(), 0, 0);
|
||||||
|
|
||||||
/* perform value check */
|
/* perform value check */
|
||||||
if (!this->check_val(result)) {
|
if (!this->check_val(result)) {
|
||||||
|
|
|
@ -36,6 +36,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
int initialize_tnt(std::string& id)
|
int initialize_tnt(std::string& id)
|
||||||
{
|
{
|
||||||
|
LOG_F(INFO, "Building machine tnt");
|
||||||
|
|
||||||
HammerheadCtrl* memctrl_obj;
|
HammerheadCtrl* memctrl_obj;
|
||||||
|
|
||||||
PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("Bandit1"));
|
PCIHost *pci_host = dynamic_cast<PCIHost*>(gMachineObj->get_comp_by_name("Bandit1"));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user