#include "debug_rom/debug_rom.h"
+#if 1
+# define D(x) x
+#else
+# define D(x)
+#endif
+
bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
addr = DEBUG_START + addr;
(((uint32_t) base[3]) << 24);
return value;
}
+
+uint32_t debug_module_t::dmi_read(unsigned address)
+{
+ D(fprintf(stderr, "dmi_read(0x%x)\n", address));
+ return 0xfeed;
+}
+
+void debug_module_t::dmi_write(unsigned address, uint32_t value)
+{
+ D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
+}
return halt_notification.find(hartid) != halt_notification.end();
}
+ // Debug Module Interface that the debugger (in our case through JTAG DTM)
+ // uses to access the DM.
+ uint32_t dmi_read(unsigned address);
+ void dmi_write(unsigned address, uint32_t value);
+
private:
// Track which interrupts from module to debugger are set.
std::set<uint32_t> interrupt;
#include <stdio.h>
+#include "decode.h"
#include "jtag_dtm.h"
+#include "debug_module.h"
#if 1
# define D(x) x
# define D(x)
#endif
+enum {
+ IR_IDCODE=1,
+ IR_DTMCONTROL=0x10,
+ IR_DBUS=0x11
+};
+
+#define DTMCONTROL_VERSION 0xf
+#define DTMCONTROL_ABITS (0x3f << 4)
+#define DTMCONTROL_DBUSSTAT (3<<10)
+#define DTMCONTROL_IDLE (7<<12)
+#define DTMCONTROL_DBUSRESET (1<<16)
+
+#define DBUS_OP 3
+#define DBUS_DATA (0xffffffffL<<2)
+#define DBUS_ADDRESS ((1L<<(abits+34)) - (1L<<34))
+
+#define DBUS_OP_STATUS_SUCCESS 0
+#define DBUS_OP_STATUS_RESERVED 1
+#define DBUS_OP_STATUS_FAILED 2
+#define DBUS_OP_STATUS_BUSY 3
+
+#define DBUS_OP_NOP 0
+#define DBUS_OP_READ 1
+#define DBUS_OP_READ_WRITE 2
+#define DBUS_OP_RESERVED 3
+
+jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) :
+ dm(dm),
+ dtmcontrol((abits << 4) | 1),
+ dbus(0),
+ state(TEST_LOGIC_RESET)
+{
+}
+
+void jtag_dtm_t::reset() {
+ state = TEST_LOGIC_RESET;
+}
+
void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) {
+ const jtag_state_t next[16][2] = {
+ /* TEST_LOGIC_RESET */ { RUN_TEST_IDLE, TEST_LOGIC_RESET },
+ /* RUN_TEST_IDLE */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
+ /* SELECT_DR_SCAN */ { CAPTURE_DR, SELECT_IR_SCAN },
+ /* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR },
+ /* SHIFT_DR */ { SHIFT_DR, EXIT1_DR },
+ /* EXIT1_DR */ { PAUSE_DR, UPDATE_DR },
+ /* PAUSE_DR */ { PAUSE_DR, EXIT2_DR },
+ /* EXIT2_DR */ { SHIFT_DR, UPDATE_DR },
+ /* UPDATE_DR */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
+ /* SELECT_IR_SCAN */ { CAPTURE_IR, TEST_LOGIC_RESET },
+ /* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR },
+ /* SHIFT_IR */ { SHIFT_IR, EXIT1_IR },
+ /* EXIT1_IR */ { PAUSE_IR, UPDATE_IR },
+ /* PAUSE_IR */ { PAUSE_IR, EXIT2_IR },
+ /* EXIT2_IR */ { SHIFT_IR, UPDATE_IR },
+ /* UPDATE_IR */ { RUN_TEST_IDLE, SELECT_DR_SCAN }
+ };
+
if (!_tck && tck) {
// Positive clock edge.
state = next[state][_tms];
switch (state) {
case TEST_LOGIC_RESET:
- ir = idcode_ir;
+ ir = IR_IDCODE;
break;
case CAPTURE_DR:
capture_dr();
}
}
+ D(fprintf(stderr, "state=%2d, tdi=%d, tdo=%d, tms=%d, tck=%d, ir=0x%02x, dr=0x%lx\n",
+ state, _tdi, _tdo, _tms, _tck, ir, dr));
+
_tck = tck;
_tms = tms;
_tdi = tdi;
-
- D(fprintf(stderr, "state=%2d tck=%d tms=%d tdi=%d tdo=%d ir=0x%x dr=0x%lx\n",
- state, _tck, _tms, _tdi, _tdo, ir, dr));
}
void jtag_dtm_t::capture_dr()
{
switch (ir) {
- case idcode_ir:
- dr = 0xdeadbeef;
+ case IR_IDCODE:
+ dr = idcode;
dr_length = 32;
break;
- case dtmcontrol_ir:
+ case IR_DTMCONTROL:
dr = dtmcontrol;
dr_length = 32;
+ break;
+ case IR_DBUS:
+ dr = dbus;
+ dr_length = abits + 34;
+ break;
default:
D(fprintf(stderr, "Unsupported IR: 0x%x\n", ir));
break;
void jtag_dtm_t::update_dr()
{
+ D(fprintf(stderr, "Update DR; IR=0x%x, DR=0x%lx (%d bits)\n",
+ ir, dr, dr_length));
+ switch (ir) {
+ case IR_DBUS:
+ {
+ unsigned op = get_field(dr, DBUS_OP);
+ uint32_t data = get_field(dr, DBUS_DATA);
+ unsigned address = get_field(dr, DBUS_ADDRESS);
+
+ dbus = dr;
+
+ if (op == DBUS_OP_READ || op == DBUS_OP_READ_WRITE) {
+ dbus = set_field(dbus, DBUS_DATA, dm->dmi_read(address));
+ }
+ if (op == DBUS_OP_READ_WRITE) {
+ dm->dmi_write(address, data);
+ }
+
+ dbus = set_field(dbus, DBUS_OP, DBUS_OP_STATUS_SUCCESS);
+ }
+ break;
+ }
}
#include <stdint.h>
+class debug_module_t;
+
typedef enum {
TEST_LOGIC_RESET,
RUN_TEST_IDLE,
class jtag_dtm_t
{
- static const unsigned idcode_ir = 1;
- static const unsigned idcode_dr = 0xdeadbeef;
- static const unsigned dtmcontrol_ir = 0x10;
+ static const unsigned idcode = 0xdeadbeef;
public:
- jtag_dtm_t() :
- dtmcontrol(
- (6 << 4) | // abits
- 1 // version
- ),
- state(TEST_LOGIC_RESET) {}
-
- void reset() {
- state = TEST_LOGIC_RESET;
- }
+ jtag_dtm_t(debug_module_t *dm);
+ void reset();
void set_pins(bool tck, bool tms, bool tdi);
bool tdo() const { return _tdo; }
private:
+ debug_module_t *dm;
bool _tck, _tms, _tdi, _tdo;
uint32_t ir;
const unsigned ir_length = 5;
uint64_t dr;
unsigned dr_length;
+ // abits must come before dtmcontrol so it can easily be used in the
+ // constructor.
+ const unsigned abits = 6;
uint32_t dtmcontrol;
+ uint32_t dbus;
jtag_state_t state;
void capture_dr();
void update_dr();
-
- const jtag_state_t next[16][2] = {
- /* TEST_LOGIC_RESET */ { RUN_TEST_IDLE, TEST_LOGIC_RESET },
- /* RUN_TEST_IDLE */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
- /* SELECT_DR_SCAN */ { CAPTURE_DR, SELECT_IR_SCAN },
- /* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR },
- /* SHIFT_DR */ { SHIFT_DR, EXIT1_DR },
- /* EXIT1_DR */ { PAUSE_DR, UPDATE_DR },
- /* PAUSE_DR */ { PAUSE_DR, EXIT2_DR },
- /* EXIT2_DR */ { SHIFT_DR, UPDATE_DR },
- /* UPDATE_DR */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
- /* SELECT_IR_SCAN */ { CAPTURE_IR, TEST_LOGIC_RESET },
- /* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR },
- /* SHIFT_IR */ { SHIFT_IR, EXIT1_IR },
- /* EXIT1_IR */ { PAUSE_IR, UPDATE_IR },
- /* PAUSE_IR */ { PAUSE_IR, EXIT2_IR },
- /* EXIT2_IR */ { SHIFT_IR, UPDATE_IR },
- /* UPDATE_IR */ { RUN_TEST_IDLE, SELECT_DR_SCAN }
- };
};
#endif
char send_buf[buf_size];
unsigned total_received = 0;
ssize_t bytes = read(client_fd, recv_buf, buf_size);
+ bool quit = false;
while (bytes > 0) {
total_received += bytes;
unsigned send_offset = 0;
uint8_t command = recv_buf[i];
switch (command) {
- case 'B': fprintf(stderr, "*BLINK*\n"); break;
- case 'b': fprintf(stderr, "_______\n"); break;
+ case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
+ case 'b': /* fprintf(stderr, "_______\n"); */ break;
case 'r': tap->reset(); break;
case '0': tap->set_pins(0, 0, 0); break;
case '1': tap->set_pins(0, 0, 1); break;
case '6': tap->set_pins(1, 1, 0); break;
case '7': tap->set_pins(1, 1, 1); break;
case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
+ case 'Q': quit = true; break;
default:
fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
command);
sent += bytes;
}
- if (total_received > buf_size) {
+ if (total_received > buf_size || quit) {
// Don't go forever, because that could starve the main simulation.
break;
}
strerror(errno), errno);
abort();
}
- } else if (bytes == 0) {
+ }
+ if (bytes == 0 || quit) {
// The remote disconnected.
close(client_fd);
client_fd = 0;
const char* get_config_string() { return config_string.c_str(); }
processor_t* get_core(size_t i) { return procs.at(i); }
+ debug_module_t debug_module;
+
private:
char* mem; // main memory
size_t memsz; // memory size in bytes
std::unique_ptr<rom_device_t> boot_rom;
std::unique_ptr<rtc_t> rtc;
bus_t bus;
- debug_module_t debug_module;
processor_t* get_core(const std::string& i);
void step(size_t n); // step through simulation
auto argv1 = parser.parse(argv);
std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
sim_t s(isa, nprocs, mem_mb, halted, htif_args);
- std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t());
+ std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
std::unique_ptr<remote_bitbang_t> remote_bitbang;
if (rbb_port) {
remote_bitbang.reset(new remote_bitbang_t(rbb_port, &(*jtag_dtm)));