mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-23 06:29:38 +00:00
Merge branch 'master' of https://github.com/dingusdev/dingusppc
This commit is contained in:
commit
5e32b599d6
@ -173,6 +173,7 @@ extern uint64_t rtc_timestamp;
|
||||
extern uint64_t tbr_wr_value;
|
||||
extern uint32_t dec_wr_value;
|
||||
extern uint32_t tbr_freq_ghz;
|
||||
extern uint64_t tbr_period_ns;
|
||||
extern uint32_t rtc_lo, rtc_hi;
|
||||
|
||||
// Additional steps to prevent overflow?
|
||||
@ -319,6 +320,7 @@ extern bool grab_return;
|
||||
|
||||
extern bool power_on;
|
||||
extern bool int_pin;
|
||||
extern bool dec_exception_pending;
|
||||
|
||||
extern bool is_601; // For PowerPC 601 Emulation
|
||||
extern bool is_altivec; // For Altivec Emulation
|
||||
|
@ -131,7 +131,7 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
|
||||
|
||||
mmu_change_mode();
|
||||
|
||||
if (exception_type != Except_Type::EXC_EXT_INT) {
|
||||
if (exception_type != Except_Type::EXC_EXT_INT && exception_type != Except_Type::EXC_DECR) {
|
||||
longjmp(exc_env, 2); /* return to the main execution loop. */
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ uint32_t ppc_next_instruction_address; // Used for branching, setting up the
|
||||
|
||||
unsigned exec_flags; // execution control flags
|
||||
bool int_pin = false; // interrupt request pin state: true - asserted
|
||||
bool dec_exception_pending = false;
|
||||
|
||||
/* copy of local variable bb_start_la. Need for correct
|
||||
calculation of CPU cycles after setjmp that clobbers
|
||||
@ -69,7 +70,8 @@ int icnt_factor;
|
||||
uint64_t tbr_wr_timestamp; // stores vCPU virtual time of the last TBR write
|
||||
uint64_t rtc_timestamp; // stores vCPU virtual time of the last RTC write
|
||||
uint64_t tbr_wr_value; // last value written to the TBR
|
||||
uint32_t tbr_freq_ghz; // TBR/RTC driving frequency in GHz expressed as a 32 bit fraction less than 1.0.
|
||||
uint32_t tbr_freq_ghz; // TBR/RTC driving frequency in GHz expressed as a 32 bit fraction less than 1.0 (999.999999 MHz maximum).
|
||||
uint64_t tbr_period_ns; // TBR/RTC period in ns expressed as a 64 bit value with 32 fractional bits (<1 Hz minimum).
|
||||
uint64_t timebase_counter; // internal timebase counter
|
||||
uint64_t dec_wr_timestamp; // stores vCPU virtual time of the last DEC write
|
||||
uint32_t dec_wr_value; // last value written to the DEC register
|
||||
@ -768,6 +770,7 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
||||
rtc_timestamp = 0;
|
||||
tbr_wr_value = 0;
|
||||
tbr_freq_ghz = (tb_freq << 32) / NS_PER_SEC;
|
||||
tbr_period_ns = ((uint64_t)NS_PER_SEC << 32) / tb_freq;
|
||||
|
||||
exec_flags = 0;
|
||||
|
||||
|
@ -831,16 +831,16 @@ void tlb_flush_entries(TLBFlags type)
|
||||
|
||||
// Flush entries from the secondary TLBs
|
||||
for (i = 0; i < TLB_SIZE * TLB2_WAYS; i++) {
|
||||
if (dtlb2_mode1[i].flags & type) {
|
||||
dtlb2_mode1[i].tag = TLB_INVALID_TAG;
|
||||
if (m1_tlb[i].flags & type) {
|
||||
m1_tlb[i].tag = TLB_INVALID_TAG;
|
||||
}
|
||||
|
||||
if (dtlb2_mode2[i].flags & type) {
|
||||
dtlb2_mode2[i].tag = TLB_INVALID_TAG;
|
||||
if (m2_tlb[i].flags & type) {
|
||||
m2_tlb[i].tag = TLB_INVALID_TAG;
|
||||
}
|
||||
|
||||
if (dtlb2_mode3[i].flags & type) {
|
||||
dtlb2_mode3[i].tag = TLB_INVALID_TAG;
|
||||
if (m3_tlb[i].flags & type) {
|
||||
m3_tlb[i].tag = TLB_INVALID_TAG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -851,6 +851,10 @@ void dppc_interpreter::ppc_mtmsr() {
|
||||
if (ppc_state.msr & 0x8000 && int_pin) {
|
||||
LOG_F(WARNING, "MTMSR: CPU INT pending, generate CPU exception");
|
||||
ppc_exception_handler(Except_Type::EXC_EXT_INT, 0);
|
||||
} else if ((ppc_state.msr & 0x8000) && dec_exception_pending) {
|
||||
dec_exception_pending = false;
|
||||
//LOG_F(WARNING, "MTMSR: decrementer exception triggered");
|
||||
ppc_exception_handler(Except_Type::EXC_DECR, 0);
|
||||
} else {
|
||||
mmu_change_mode();
|
||||
}
|
||||
@ -894,9 +898,43 @@ static void update_timebase(uint64_t mask, uint64_t new_val)
|
||||
tbr_wr_timestamp = get_virt_time_ns();
|
||||
}
|
||||
|
||||
|
||||
static uint32_t decrementer_timer_id = 0;
|
||||
|
||||
static void trigger_decrementer_exception() {
|
||||
decrementer_timer_id = 0;
|
||||
dec_wr_value = -1;
|
||||
dec_wr_timestamp = get_virt_time_ns();
|
||||
if (ppc_state.msr & 0x8000) {
|
||||
dec_exception_pending = false;
|
||||
//LOG_F(WARNING, "decrementer exception triggered");
|
||||
ppc_exception_handler(Except_Type::EXC_DECR, 0);
|
||||
}
|
||||
else {
|
||||
//LOG_F(WARNING, "decrementer exception pending");
|
||||
dec_exception_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_decrementer(uint32_t val) {
|
||||
dec_wr_value = val;
|
||||
dec_wr_timestamp = get_virt_time_ns();
|
||||
|
||||
dec_exception_pending = false;
|
||||
|
||||
if (decrementer_timer_id) {
|
||||
//LOG_F(WARNING, "decrementer cancel timer");
|
||||
TimerManager::get_instance()->cancel_timer(decrementer_timer_id);
|
||||
}
|
||||
|
||||
uint64_t time_out;
|
||||
uint32_t time_out_lo;
|
||||
_u32xu64(val, tbr_period_ns, time_out, time_out_lo);
|
||||
//LOG_F(WARNING, "decrementer:0x%08X ns:%llu", val, time_out);
|
||||
decrementer_timer_id = TimerManager::get_instance()->add_oneshot_timer(
|
||||
time_out,
|
||||
trigger_decrementer_exception
|
||||
);
|
||||
}
|
||||
|
||||
void dppc_interpreter::ppc_mfspr() {
|
||||
@ -1401,6 +1439,15 @@ void dppc_interpreter::ppc_rfi() {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ppc_state.msr & 0x8000) && dec_exception_pending) {
|
||||
dec_exception_pending = false;
|
||||
//LOG_F(WARNING, "decrementer exception from rfi msr:0x%X", ppc_state.msr);
|
||||
uint32_t save_srr0 = ppc_state.spr[SPR::SRR0] & 0xFFFFFFFCUL;
|
||||
ppc_exception_handler(Except_Type::EXC_DECR, 0);
|
||||
ppc_state.spr[SPR::SRR0] = save_srr0;
|
||||
return;
|
||||
}
|
||||
|
||||
ppc_next_instruction_address = ppc_state.spr[SPR::SRR0] & 0xFFFFFFFCUL;
|
||||
|
||||
do_ctx_sync(); // RFI is context synchronizing
|
||||
@ -1651,19 +1698,17 @@ void dppc_interpreter::ppc_stwcx() {
|
||||
#ifdef CPU_PROFILING
|
||||
num_int_stores++;
|
||||
#endif
|
||||
// PLACEHOLDER CODE FOR STWCX - We need to check for reserve memory
|
||||
if (rc_flag == 0) {
|
||||
ppc_illegalop();
|
||||
} else {
|
||||
ppc_grab_regssab();
|
||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
||||
ppc_state.cr &= 0x0FFFFFFFUL; // clear CR0
|
||||
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3; // copy XER[SO] to CR0[SO]
|
||||
if (ppc_state.reserve) {
|
||||
mmu_write_vmem<uint32_t>(ppc_effective_address, ppc_result_d);
|
||||
//mem_write_dword(ppc_effective_address, ppc_result_d);
|
||||
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000;
|
||||
ppc_state.reserve = false;
|
||||
} else {
|
||||
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x10000000 : 0;
|
||||
ppc_state.cr |= 0x20000000UL; // set CR0[EQ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ bool OfConfigAppl::validate() {
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
uint16_t OfConfigAppl::checksum_partition() {
|
||||
uint32_t acc = 0;
|
||||
@ -178,7 +178,7 @@ const OfConfigImpl::config_dict& OfConfigAppl::get_config_vars() {
|
||||
}
|
||||
|
||||
return _config_vars;
|
||||
};
|
||||
}
|
||||
|
||||
void OfConfigAppl::update_partition() {
|
||||
// set checksum in the header to zero
|
||||
@ -300,7 +300,7 @@ bool OfConfigAppl::set_var(std::string& var_name, std::string& value) {
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
uint8_t OfConfigChrp::checksum_hdr(const uint8_t* data)
|
||||
{
|
||||
@ -391,27 +391,47 @@ const OfConfigImpl::config_dict& OfConfigChrp::get_config_vars() {
|
||||
|
||||
this->_config_vars.clear();
|
||||
|
||||
this->data_length = 0;
|
||||
|
||||
if (!this->validate())
|
||||
return _config_vars;
|
||||
|
||||
for (int pos = 0; pos < 4096;) {
|
||||
char *pname = (char *)&this->buf[pos];
|
||||
bool got_name = false;
|
||||
|
||||
// scan property name until '=' is encountered
|
||||
// or max length is reached
|
||||
for (len = 0; len < 32; pos++, len++) {
|
||||
if (pname[len] == '=' || pname[len] == '\0')
|
||||
for (len = 0; ; pos++, len++) {
|
||||
if (len >= 32) {
|
||||
cout << "name > 31 chars" << endl;
|
||||
break;
|
||||
}
|
||||
if (pos >= 4096) {
|
||||
cout << "no = sign before end of partition" << endl;
|
||||
break;
|
||||
}
|
||||
if (pname[len] == '=') {
|
||||
if (len) {
|
||||
got_name = true;
|
||||
}
|
||||
else {
|
||||
cout << "got = sign but no name" << endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (pname[len] == '\0') {
|
||||
if (len) {
|
||||
cout << "no = sign before termminating null" << endl;
|
||||
}
|
||||
else {
|
||||
// empty property name -> free space reached
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// empty property name -> free space reached
|
||||
if (!len) {
|
||||
this->data_length = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pname[len] != '=') {
|
||||
cout << "no = sign found or name > 31 chars" << endl;
|
||||
if (!got_name) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -436,8 +456,11 @@ const OfConfigImpl::config_dict& OfConfigChrp::get_config_vars() {
|
||||
|
||||
this->_config_vars.push_back(std::make_pair(prop_name, pval));
|
||||
pos++; // skip past null terminator
|
||||
|
||||
this->data_length = pos; // point to after null
|
||||
}
|
||||
|
||||
//cout << "Read " << this->data_length << " bytes from nvram." << endl;
|
||||
return this->_config_vars;
|
||||
}
|
||||
|
||||
@ -447,7 +470,7 @@ bool OfConfigChrp::update_partition() {
|
||||
memset(this->buf, 0, 4096);
|
||||
|
||||
for (auto& var : this->_config_vars) {
|
||||
if ((var.first.length() + var.second.length() + 2) >= 4096) {
|
||||
if ((pos + var.first.length() + var.second.length() + 2) > 4096) {
|
||||
cout << "No room in the partition!" << endl;
|
||||
return false;
|
||||
}
|
||||
@ -464,6 +487,7 @@ bool OfConfigChrp::update_partition() {
|
||||
this->nvram_obj->write_byte(this->data_offset + i, this->buf[i]);
|
||||
}
|
||||
|
||||
//cout << "Wrote " << pos << " bytes to nvram." << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -471,25 +495,25 @@ bool OfConfigChrp::set_var(std::string& var_name, std::string& value) {
|
||||
if (!this->validate())
|
||||
return false;
|
||||
|
||||
bool found = false;
|
||||
// see if we're about to change a flag
|
||||
if (var_name.back() == '?') {
|
||||
if (value != "true" && value != "false") {
|
||||
cout << "Flag value can be 'true' or 'false'" << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned free_space = 4096 - this->data_length;
|
||||
bool found = false;
|
||||
|
||||
// see if the user tries to change an existing property
|
||||
for (auto& var : this->_config_vars) {
|
||||
if (var.first == var_name) {
|
||||
found = true;
|
||||
|
||||
// see if we're about to change a flag
|
||||
if (var_name.back() == '?') {
|
||||
if (value != "true" && value != "false") {
|
||||
cout << "Flag value can be 'true' or 'false'" << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.length() > var.second.length()) {
|
||||
unsigned free_space = 4096 - this->data_length;
|
||||
if ((value.length() - var.second.length()) >= free_space) {
|
||||
cout << "No room for new data!" << endl;
|
||||
if ((value.length() - var.second.length()) > free_space) {
|
||||
cout << "No room for updated nvram variable!" << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -500,12 +524,15 @@ bool OfConfigChrp::set_var(std::string& var_name, std::string& value) {
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
cout << "Attempt to change unknown variable " << var_name << endl;
|
||||
return false;
|
||||
if ((var_name.length() + value.length() + 2) > free_space) {
|
||||
cout << "No room for new nvram variable!" << endl;
|
||||
return false;
|
||||
}
|
||||
this->_config_vars.push_back(std::make_pair(var_name, value));
|
||||
}
|
||||
|
||||
return this->update_partition();
|
||||
};
|
||||
}
|
||||
|
||||
int OfConfigUtils::init()
|
||||
{
|
||||
@ -541,16 +568,27 @@ bool OfConfigUtils::open_container() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void OfConfigUtils::printenv() {
|
||||
OfConfigImpl::config_dict vars;
|
||||
static std::string ReplaceAll(std::string& str, const std::string& from, const std::string& to) {
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void OfConfigUtils::printenv() {
|
||||
if (!this->open_container())
|
||||
return;
|
||||
|
||||
vars = this->cfg_impl->get_config_vars();
|
||||
OfConfigImpl::config_dict vars = this->cfg_impl->get_config_vars();
|
||||
|
||||
for (auto& var : vars) {
|
||||
cout << setw(34) << left << var.first << var.second << endl;
|
||||
std::string val = var.second;
|
||||
ReplaceAll(val, "\r\n", "\n");
|
||||
ReplaceAll(val, "\r", "\n");
|
||||
ReplaceAll(val, "\n", "\n "); // 34 spaces
|
||||
cout << setw(34) << left << var.first << val << endl; // name column has width 34
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,6 +597,8 @@ void OfConfigUtils::setenv(string var_name, string value)
|
||||
if (!this->open_container())
|
||||
return;
|
||||
|
||||
OfConfigImpl::config_dict vars = this->cfg_impl->get_config_vars();
|
||||
|
||||
if (!this->cfg_impl->set_var(var_name, value)) {
|
||||
cout << " Please try again" << endl;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user