Merge branch 'master' into dc11-serial

This commit is contained in:
folkert van heusden 2024-05-09 16:14:36 +02:00
commit 588807869c
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
4 changed files with 136 additions and 83 deletions

18
cpu.cpp
View file

@ -18,6 +18,12 @@
#define IS_0(x, wm) ((wm) == wm_byte ? ((x) & 0xff) == 0 : (x) == 0)
// see https://retrocomputing.stackexchange.com/questions/6960/what-was-the-clock-speed-and-ips-for-the-original-pdp-11
constexpr const double pdp11_clock_cycle = 150; // ns, for the 11/70
constexpr const double pdp11_MHz = 1000.0 / pdp11_clock_cycle;
constexpr const double pdp11_avg_cycles_per_instruction = (1 + 5) / 2.0;
constexpr const double pdp11_estimated_mips = pdp11_MHz / pdp11_avg_cycles_per_instruction;
cpu::cpu(bus *const b, std::atomic_uint32_t *const event) : b(b), event(event)
{
reset();
@ -97,15 +103,15 @@ std::tuple<double, double, uint64_t, uint32_t, double> cpu::get_mips_rel_speed(c
double mips = t_diff ? instr_count / double(t_diff) : 0;
// see https://retrocomputing.stackexchange.com/questions/6960/what-was-the-clock-speed-and-ips-for-the-original-pdp-11
constexpr double pdp11_clock_cycle = 150; // ns, for the 11/70
constexpr double pdp11_MHz = 1000.0 / pdp11_clock_cycle;
constexpr double pdp11_avg_cycles_per_instruction = (1 + 5) / 2.0;
constexpr double pdp11_estimated_mips = pdp11_MHz / pdp11_avg_cycles_per_instruction;
return { mips, mips * 100 / pdp11_estimated_mips, instr_count, t_diff, wait_time };
}
uint32_t cpu::get_effective_run_time(const uint64_t instruction_count) const
{
// division is to go from ns to ms
return instruction_count * pdp11_avg_cycles_per_instruction * pdp11_clock_cycle / 1000000l;
}
void cpu::add_to_stack_trace(const uint16_t p)
{
auto da = disassemble(p);

2
cpu.h
View file

@ -133,6 +133,8 @@ public:
uint64_t get_instructions_executed_count() const;
uint64_t get_wait_time() const { return wait_time; }
std::tuple<double, double, uint64_t, uint32_t, double> get_mips_rel_speed(const std::optional<uint64_t> & instruction_count, const std::optional<uint64_t> & t_diff_1s) const;
// how many ms would've really passed when executing `instruction_count` instructions
uint32_t get_effective_run_time(const uint64_t instruction_count) const;
bool get_debug() const { return debug_mode; }
void set_debug(const bool d) { debug_mode = d; stacktrace.clear(); }

View file

@ -78,13 +78,46 @@ std::optional<disk_backend *> select_nbd_server(console *const cnsl)
}
#endif
std::optional<std::string> select_host_file(console *const c)
void start_disk(console *const cnsl)
{
for(;;) {
static bool disk_started = false;
if (disk_started)
return;
#if defined(ESP32)
cnsl->put_string_lf(format("MISO: %d", int(MISO)));
cnsl->put_string_lf(format("MOSI: %d", int(MOSI)));
cnsl->put_string_lf(format("SCK : %d", int(SCK )));
cnsl->put_string_lf(format("SS : %d", int(SS )));
#endif
#if defined(SHA2017)
if (SD.begin(21, SD_SCK_MHZ(10)))
disk_started = true;
else
SD.initErrorHalt();
#elif !defined(BUILD_FOR_RP2040)
if (SD.begin(SS, SD_SCK_MHZ(15)))
disk_started = true;
else {
auto err = SD.sdErrorCode();
if (err)
cnsl->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData()));
else
cnsl->put_string_lf("Failed to initialize SD card");
}
#endif
}
void ls_l(console *const cnsl)
{
start_disk(cnsl);
#if defined(linux)
DIR *dir = opendir(".");
if (!dir) {
c->put_string_lf("Cannot access directory");
cnsl->put_string_lf("Cannot access directory");
return { };
}
@ -93,7 +126,7 @@ std::optional<std::string> select_host_file(console *const c)
struct stat st { };
if (stat(dr->d_name, &st) == 0)
c->put_string_lf(format("%s\t\t%ld", dr->d_name, st.st_size));
cnsl->put_string_lf(format("%s\t\t%ld", dr->d_name, st.st_size));
}
closedir(dir);
@ -106,9 +139,9 @@ std::optional<std::string> select_host_file(console *const c)
break;
if (!entry.isDirectory()) {
c->put_string(entry.name());
c->put_string("\t\t");
c->put_string_lf(format("%ld", entry.size()));
cnsl->put_string(entry.name());
cnsl->put_string("\t\t");
cnsl->put_string_lf(format("%ld", entry.size()));
}
entry.close();
@ -117,16 +150,22 @@ std::optional<std::string> select_host_file(console *const c)
#else
SD.ls("/", LS_DATE | LS_SIZE | LS_R);
#endif
}
c->flush_input();
std::optional<std::string> select_host_file(console *const cnsl)
{
for(;;) {
ls_l(cnsl);
std::string selected_file = c->read_line("Enter filename (or empty to abort): ");
cnsl->flush_input();
std::string selected_file = cnsl->read_line("Enter filename (or empty to abort): ");
if (selected_file.empty())
return { };
c->put_string("Opening file: ");
c->put_string_lf(selected_file.c_str());
cnsl->put_string("Opening file: ");
cnsl->put_string_lf(selected_file.c_str());
bool can_open_file = false;
@ -143,41 +182,23 @@ std::optional<std::string> select_host_file(console *const c)
if (can_open_file)
return selected_file;
c->put_string_lf("open failed");
cnsl->put_string_lf("open failed");
}
}
// disk image files
std::optional<disk_backend *> select_disk_file(console *const c)
std::optional<disk_backend *> select_disk_file(console *const cnsl)
{
start_disk(cnsl);
#if IS_POSIX || defined(_WIN32)
c->put_string_lf("Files in current directory: ");
cnsl->put_string_lf("Files in current directory: ");
#else
c->put_string_lf(format("MISO: %d", int(MISO)));
c->put_string_lf(format("MOSI: %d", int(MOSI)));
c->put_string_lf(format("SCK : %d", int(SCK )));
c->put_string_lf(format("SS : %d", int(SS )));
c->put_string_lf("Files on SD-card:");
#if defined(SHA2017)
if (!SD.begin(21, SD_SCK_MHZ(10)))
SD.initErrorHalt();
#elif !defined(BUILD_FOR_RP2040)
if (!SD.begin(SS, SD_SCK_MHZ(15))) {
auto err = SD.sdErrorCode();
if (err)
c->put_string_lf(format("SDerror: 0x%x, data: 0x%x", err, SD.sdErrorData()));
else
c->put_string_lf("Failed to initialize SD card");
return { };
}
#endif
cnsl->put_string_lf("Files on SD-card:");
#endif
for(;;) {
auto selected_file = select_host_file(c);
auto selected_file = select_host_file(cnsl);
if (selected_file.has_value() == false)
break;
@ -189,8 +210,8 @@ std::optional<disk_backend *> select_disk_file(console *const c)
#endif
if (!temp->begin(false)) {
c->put_string("Cannot use: ");
c->put_string_lf(selected_file.value().c_str());
cnsl->put_string("Cannot use: ");
cnsl->put_string_lf(selected_file.value().c_str());
delete temp;
@ -987,6 +1008,19 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
continue;
}
else if (parts[0] == "bic" && parts.size() == 2) {
auto rc = load_tape(b, parts[1].c_str());
if (rc.has_value()) {
c->setPC(rc.value());
cnsl->put_string_lf("BIC/LDA file loaded");
}
else {
cnsl->put_string_lf("BIC/LDA failed to load");
}
continue;
}
else if (parts[0] == "lt") {
if (parts.size() == 2)
tm11_load_tape(cnsl, b, parts[1]);
@ -995,6 +1029,11 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
continue;
}
else if (cmd == "dir" || cmd == "ls") {
ls_l(cnsl);
continue;
}
else if (cmd == "ult") {
tm11_unload_tape(b);
@ -1053,6 +1092,8 @@ void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const sto
"setmem - set memory (a=) to value (v=), both in octal, one byte",
"toggle - set switch (s=, 0...15 (decimal)) of the front panel to state (t=, 0 or 1)",
"cls - clear screen",
"dir - list files",
"bic - run BIC/LDA file",
"lt - load tape (parameter is filename)",
"ult - unload tape",
"stats - show run statistics",

View file

@ -68,22 +68,26 @@ void kw11_l::operator()()
TRACE("Starting KW11-L thread");
uint64_t prev_cycle_count = b->getCpu()->get_instructions_executed_count();
while(!stop_flag) {
if (*cnsl->get_running_flag()) {
myusleep(1000000 / 100); // 100 Hz
uint64_t current_cycle_count = b->getCpu()->get_instructions_executed_count();
uint32_t took_ms = b->getCpu()->get_effective_run_time(current_cycle_count - prev_cycle_count);
if (took_ms >= 1000 / 50) {
set_lf_crs_b7();
if (get_lf_crs() & 64)
b->getCpu()->queue_interrupt(6, 0100);
// TODO: depending on cpu cycles processed
#if defined(ESP32)
myusleep(1000000 / 20); // 50ms
#else
myusleep(1000000 / 50); // 20ms
#endif
prev_cycle_count = current_cycle_count;
}
}
else {
myusleep(1000000 / 10); // 100ms
myusleep(1000000 / 10); // 10 Hz
}
}