#include #include #include #include #include #include #include "io/model.h" #include "isa/isa.h" bool iomodel::interact(std::array &ctlregs) { auto [ebegin, eend] = log.equal_range(time); for (auto e = ebegin; e != eend; ++e) { auto &r = ctlregs[e->second.reg]; r &= ~e->second.mask; r |= e->second.value; } ++time; if (ctlregs[TT_BITS] & TTO_TX) { std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) & 0x7f) << std::flush; ctlregs[TT_BITS] &= ~TTO_TX & ~TTO_DATA; log.emplace(time + TT_OUTPUT_DELAY, event(TT_BITS, TTO_FLAG, 0)); } bool interrupt = false; if (ctlregs[TT_FLAGS] & TTF_INT_ENABLE) { if (ctlregs[TT_BITS] & TTI_FLAG) interrupt = true; if (ctlregs[TT_BITS] & TTO_FLAG) interrupt = true; } if (interrupt) ctlregs[FLAGS] |= FLAG_INT_REQUEST; else ctlregs[FLAGS] &= ~FLAG_INT_REQUEST; interrupt = interrupt && (ctlregs[FLAGS] & FLAG_INT_ENABLE); if (ctlregs[FLAGS] & FLAG_INT_ENABLE_DELAY) ctlregs[FLAGS] |= FLAG_INT_ENABLE; if (interrupt) { ctlregs[FLAGS_SAVED] = ctlregs[FLAGS]; ctlregs[FLAGS] = 0; ctlregs[HALTED] = 0; } return interrupt; } void iomodel::load_evt(std::istream &fh) { // File format: // +time advances time by relative increment // regname=value/mask adds event that sets regname = (regname & ~mask) | value // regname=value adds event that sets regname = value // FIXME: add assertions // FIXME: add DMA for (std::string line; std::getline(fh, line); ) { auto hashpos = line.find('#'); line = line.substr(0, hashpos); if (auto nwspos = line.find_first_not_of(" \t"); nwspos != std::string::npos) line = line.substr(nwspos); if (auto nwspos = line.find_last_not_of(" \t"); nwspos != std::string::npos) line = line.substr(0, nwspos + 1); if (line.size() == 0) continue; if (line[0] == '+') { char *end = nullptr; auto step = std::strtoull(line.c_str(), &end, 0); assert(end && *end == '\0'); load_time += step; } else { auto eqpos = line.find('='); assert(eqpos != std::string::npos); auto regname = line.substr(0, eqpos); ctlreg reg = ctlreg_map.at(regname); std::uint_fast32_t value, mask; auto slashpos = line.find('/', eqpos); auto valuestr = line.substr(eqpos + 1, slashpos - (eqpos + 1)); char *end = nullptr; value = std::strtoull(valuestr.c_str(), &end, 0); assert(end && *end == '\0'); if (slashpos == std::string::npos) { mask = ~(std::uint_fast32_t)0; } else { auto maskstr = line.substr(slashpos + 1); mask = std::strtoull(maskstr.c_str(), &end, 0); assert(end && *end == '\0'); } log.emplace(load_time, event(reg, value, mask)); } } } std::ostream & iomodel::write_evt(std::ostream &fh) { std::uint64_t time = 0; for (const auto &e : log) { if (e.first != time) { fh << fmt::format("+{}\n", e.first - time); time = e.first; } if (e.second.mask == ~(std::uint_fast32_t)0) { fh << fmt::format("{}=0x{:x}\n", ctlreg_names[e.second.reg], e.second.value); } else { fh << fmt::format("{}=0x{:x}/0x{:x}\n", ctlreg_names[e.second.reg], e.second.value, e.second.mask); } } return fh; }