From 5c1849722546813bae3fe6002ce8961dfd14f2f1 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 4 Dec 2018 13:46:35 -0800 Subject: Add --dmi-rti and --abstract-rti to test OpenOCD. Optionally make spike behave more like real hardware, to automatically test OpenOCD's handling of such hardware. --- riscv/debug_module.cc | 17 +++++++++++-- riscv/debug_module.h | 15 +++++++++-- riscv/jtag_dtm.cc | 70 ++++++++++++++++++++++++++++++--------------------- riscv/jtag_dtm.h | 9 ++++++- riscv/sim.cc | 6 +++-- riscv/sim.h | 3 ++- spike_main/spike.cc | 16 ++++++++++-- 7 files changed, 98 insertions(+), 38 deletions(-) diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc index 96de3c8..081b606 100644 --- a/riscv/debug_module.cc +++ b/riscv/debug_module.cc @@ -18,11 +18,12 @@ ///////////////////////// debug_module_t debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits, - bool require_authentication) : + bool require_authentication, unsigned abstract_rti) : progbufsize(progbufsize), program_buffer_bytes(4 + 4*progbufsize), max_bus_master_bits(max_bus_master_bits), require_authentication(require_authentication), + abstract_rti(abstract_rti), debug_progbuf_start(debug_data_start - program_buffer_bytes), debug_abstract_start(debug_progbuf_start - debug_abstract_size*4), custom_base(0), @@ -183,7 +184,7 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) if (dmcontrol.hartsel == id) { if (0 == (debug_rom_flags[id] & (1 << DEBUG_ROM_FLAG_GO))){ if (dmcontrol.hartsel == id) { - abstractcs.busy = false; + abstract_command_completed = true; } } } @@ -488,6 +489,16 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value) return true; } +void debug_module_t::run_test_idle() +{ + if (rti_remaining > 0) { + rti_remaining--; + } + if (rti_remaining == 0 && abstractcs.busy && abstract_command_completed) { + abstractcs.busy = false; + } +} + bool debug_module_t::perform_abstract_command() { if (abstractcs.cmderr != CMDERR_NONE) @@ -629,6 +640,8 @@ bool debug_module_t::perform_abstract_command() } debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO; + rti_remaining = abstract_rti; + abstract_command_completed = false; abstractcs.busy = true; } else { diff --git a/riscv/debug_module.h b/riscv/debug_module.h index 5b43ed6..472ae8e 100644 --- a/riscv/debug_module.h +++ b/riscv/debug_module.h @@ -81,9 +81,13 @@ class debug_module_t : public abstract_device_t * follows: * 1. Read a 32-bit value from authdata: * 2. Write the value that was read back, plus one, to authdata. + * + * abstract_rti is extra run-test/idle cycles that each abstract command + * takes to execute. Useful for testing OpenOCD. */ - debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits, - bool require_authentication); + debug_module_t(sim_t *sim, unsigned progbufsize, + unsigned max_bus_master_bits, bool require_authentication, + unsigned abstract_rti); ~debug_module_t(); void add_device(bus_t *bus); @@ -97,6 +101,9 @@ class debug_module_t : public abstract_device_t bool dmi_read(unsigned address, uint32_t *value); bool dmi_write(unsigned address, uint32_t value); + // Called for every cycle the JTAG TAP spends in Run-Test/Idle. + void run_test_idle(); + // Called when one of the attached harts was reset. void proc_reset(unsigned id); @@ -110,6 +117,7 @@ class debug_module_t : public abstract_device_t unsigned program_buffer_bytes; unsigned max_bus_master_bits; bool require_authentication; + unsigned abstract_rti; static const unsigned debug_data_start = 0x380; unsigned debug_progbuf_start; @@ -159,6 +167,9 @@ class debug_module_t : public abstract_device_t processor_t *current_proc() const; void reset(); bool perform_abstract_command(); + + bool abstract_command_completed; + unsigned rti_remaining; }; #endif diff --git a/riscv/jtag_dtm.cc b/riscv/jtag_dtm.cc index 365528a..3e44c5e 100644 --- a/riscv/jtag_dtm.cc +++ b/riscv/jtag_dtm.cc @@ -38,8 +38,8 @@ enum { #define DMI_OP_WRITE 2 #define DMI_OP_RESERVED 3 -jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) : - dm(dm), +jtag_dtm_t::jtag_dtm_t(debug_module_t *dm, unsigned required_rti_cycles) : + dm(dm), required_rti_cycles(required_rti_cycles), _tck(false), _tms(false), _tdi(false), _tdo(false), dtmcontrol((abits << DTM_DTMCS_ABITS_OFFSET) | 1), dmi(DMI_OP_STATUS_SUCCESS << DTM_DMI_OP_OFFSET), @@ -49,6 +49,9 @@ jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) : void jtag_dtm_t::reset() { _state = TEST_LOGIC_RESET; + busy_stuck = false; + rti_remaining = 0; + dmi = 0; } void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) { @@ -88,6 +91,11 @@ void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) { } _state = next[_state][_tms]; switch (_state) { + case RUN_TEST_IDLE: + if (rti_remaining > 0) + rti_remaining--; + dm->run_test_idle(); + break; case TEST_LOGIC_RESET: ir = IR_IDCODE; break; @@ -151,34 +159,40 @@ 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, DMI_OP); - uint32_t data = get_field(dr, DMI_DATA); - unsigned address = get_field(dr, DMI_ADDRESS); - - dmi = dr; - - bool success = true; - if (op == DMI_OP_READ) { - uint32_t value; - if (dm->dmi_read(address, &value)) { - dmi = set_field(dmi, DMI_DATA, value); - } else { - success = false; - } - } else if (op == DMI_OP_WRITE) { - success = dm->dmi_write(address, data); - } - - if (success) { - dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_SUCCESS); + if (ir == IR_DTMCONTROL) { + if (dr & DTMCONTROL_DBUSRESET) + reset(); + } else if (ir == IR_DBUS) { + if (rti_remaining > 0 || busy_stuck) { + dmi = DMI_OP_STATUS_BUSY; + busy_stuck = true; + } else { + unsigned op = get_field(dr, DMI_OP); + uint32_t data = get_field(dr, DMI_DATA); + unsigned address = get_field(dr, DMI_ADDRESS); + + dmi = dr; + + bool success = true; + if (op == DMI_OP_READ) { + uint32_t value; + if (dm->dmi_read(address, &value)) { + dmi = set_field(dmi, DMI_DATA, value); } else { - dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_FAILED); + success = false; } - D(fprintf(stderr, "dmi=0x%lx\n", dmi)); + } else if (op == DMI_OP_WRITE) { + success = dm->dmi_write(address, data); } - break; + + if (success) { + dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_SUCCESS); + } else { + dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_FAILED); + } + D(fprintf(stderr, "dmi=0x%lx\n", dmi)); + + rti_remaining = required_rti_cycles; + } } } diff --git a/riscv/jtag_dtm.h b/riscv/jtag_dtm.h index 063e3f4..3482b8a 100644 --- a/riscv/jtag_dtm.h +++ b/riscv/jtag_dtm.h @@ -29,7 +29,7 @@ class jtag_dtm_t static const unsigned idcode = 0xdeadbeef; public: - jtag_dtm_t(debug_module_t *dm); + jtag_dtm_t(debug_module_t *dm, unsigned required_rti_cycles); void reset(); void set_pins(bool tck, bool tms, bool tdi); @@ -40,6 +40,9 @@ class jtag_dtm_t private: debug_module_t *dm; + // The number of Run-Test/Idle cycles required before a DMI access is + // complete. + unsigned required_rti_cycles; bool _tck, _tms, _tdi, _tdo; uint32_t ir; const unsigned ir_length = 5; @@ -51,6 +54,10 @@ class jtag_dtm_t const unsigned abits = 6; uint32_t dtmcontrol; uint64_t dmi; + // Number of Run-Test/Idle cycles needed before we call this access + // complete. + unsigned rti_remaining; + bool busy_stuck; jtag_state_t _state; diff --git a/riscv/sim.cc b/riscv/sim.cc index 44223a7..ddc9bce 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -28,11 +28,13 @@ sim_t::sim_t(const char* isa, size_t nprocs, bool halted, reg_t start_pc, std::vector> mems, const std::vector& args, std::vector const hartids, unsigned progsize, - unsigned max_bus_master_bits, bool require_authentication) + unsigned max_bus_master_bits, bool require_authentication, + suseconds_t abstract_delay_usec) : htif_t(args), mems(mems), procs(std::max(nprocs, size_t(1))), start_pc(start_pc), current_step(0), current_proc(0), debug(false), histogram_enabled(false), dtb_enabled(true), remote_bitbang(NULL), - debug_module(this, progsize, max_bus_master_bits, require_authentication) + debug_module(this, progsize, max_bus_master_bits, require_authentication, + abstract_delay_usec) { signal(SIGINT, &handle_signal); diff --git a/riscv/sim.h b/riscv/sim.h index e42808b..6521573 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -23,7 +23,8 @@ public: sim_t(const char* isa, size_t _nprocs, bool halted, reg_t start_pc, std::vector> mems, const std::vector& args, const std::vector hartids, - unsigned progsize, unsigned max_bus_master_bits, bool require_authentication); + unsigned progsize, unsigned max_bus_master_bits, + bool require_authentication, suseconds_t abstract_delay_usec); ~sim_t(); // run the simulation to completion diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 3e5c7e6..fa974d0 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -42,6 +42,10 @@ static void help() fprintf(stderr, " --debug-sba= Debug bus master supports up to " " wide accesses [default 0]\n"); fprintf(stderr, " --debug-auth Debug module requires debugger to authenticate\n"); + fprintf(stderr, " --dmi-rti= Number of Run-Test/Idle cycles " + "required for a DMI access [default 0]\n"); + fprintf(stderr, " --abstract-rti= Number of Run-Test/Idle cycles " + "required for an abstract command to execute [default 0]\n"); exit(1); } @@ -98,6 +102,8 @@ int main(int argc, char** argv) unsigned progsize = 2; unsigned max_bus_master_bits = 0; bool require_authentication = false; + unsigned dmi_rti = 0; + unsigned abstract_rti = 0; std::vector hartids; auto const hartids_parser = [&](const char *s) { @@ -145,6 +151,10 @@ int main(int argc, char** argv) [&](const char* s){max_bus_master_bits = atoi(s);}); parser.option(0, "debug-auth", 0, [&](const char* s){require_authentication = true;}); + parser.option(0, "dmi-rti", 1, + [&](const char* s){dmi_rti = atoi(s);}); + parser.option(0, "abstract-rti", 1, + [&](const char* s){abstract_rti = atoi(s);}); auto argv1 = parser.parse(argv); std::vector htif_args(argv1, (const char*const*)argv + argc); @@ -155,9 +165,11 @@ int main(int argc, char** argv) help(); sim_t s(isa, nprocs, halted, start_pc, mems, htif_args, std::move(hartids), - progsize, max_bus_master_bits, require_authentication); + progsize, max_bus_master_bits, require_authentication, + abstract_rti); std::unique_ptr remote_bitbang((remote_bitbang_t *) NULL); - std::unique_ptr jtag_dtm(new jtag_dtm_t(&s.debug_module)); + std::unique_ptr jtag_dtm( + new jtag_dtm_t(&s.debug_module, dmi_rti)); if (use_rbb) { remote_bitbang.reset(new remote_bitbang_t(rbb_port, &(*jtag_dtm))); s.set_remote_bitbang(&(*remote_bitbang)); -- cgit v1.1