1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include <array>
#include <cassert>
#include <cstdint>
#include <fmt/format.h>
#include <iostream>
#include <utility>
#include "io/model.h"
#include "isa/isa.h"
bool iomodel::interact(std::uint64_t icount, std::array<std::uint_fast32_t, NUM_CTLREGS> &ctlregs, bool replay) {
auto [ebegin, eend] = log.equal_range(icount);
for (auto e = ebegin; e != eend; ++e) {
auto &r = ctlregs[e->second.reg];
r &= ~e->second.mask;
r |= e->second.value;
}
if (ctlregs[TT_BITS] & TTO_TX) {
if (!replay) {
std::cout << (char)(((ctlregs[TT_BITS] & TTO_DATA) >> TTO_DATA_SHIFT) & 0x7f) << std::flush;
log.emplace(icount + TT_OUTPUT_DELAY + 1, event(TT_BITS, TTO_FLAG, 0));
}
ctlregs[TT_BITS] &= ~TTO_TX & ~TTO_DATA;
}
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:
// +icount advances icount by relative increment
// regname=value/mask adds event that sets regname = (regname & ~mask) | value
// regname=value adds event that sets regname = value
// $x adds events that input the remaining line (excluding trailing whitespace) character-at-a-time with 1000 icounts between them
// 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_icount += step;
} else if (line[0] == '$') {
for (unsigned int i = 1; i < line.size(); ++i) {
log.emplace(load_icount, event(TT_BITS, (line[i] << 8) | TTI_FLAG, TTI_DATA | TTI_FLAG));
load_icount += 1000;
}
} 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_icount, event(reg, value, mask));
}
}
}
std::ostream & iomodel::write_evt(std::ostream &fh) {
std::uint64_t icount = 0;
for (const auto &e : log) {
if (e.first != icount) {
fh << fmt::format("+{}\n", e.first - icount);
icount = 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;
}
|