mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-13 21:11:02 +00:00
added cpld info shell commands (#1703)
* added cpld info shell commands * fixed reset
This commit is contained in:
@@ -147,9 +147,12 @@ void CPLD::sector_select(const uint16_t id) {
|
||||
}
|
||||
|
||||
bool CPLD::idcode_ok() {
|
||||
return (get_idcode() == idcode);
|
||||
}
|
||||
|
||||
uint32_t CPLD::get_idcode() {
|
||||
shift_ir(instruction_t::IDCODE);
|
||||
const auto idcode_read = jtag.shift_dr(idcode_length, 0);
|
||||
return (idcode_read == idcode);
|
||||
return jtag.shift_dr(idcode_length, 0);
|
||||
}
|
||||
|
||||
std::array<uint16_t, 5> CPLD::read_silicon_id() {
|
||||
@@ -208,6 +211,16 @@ void CPLD::program_block(
|
||||
}
|
||||
}
|
||||
|
||||
void CPLD::prepare_read(uint16_t block) {
|
||||
sector_select(block);
|
||||
shift_ir(instruction_t::ISC_READ);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
}
|
||||
|
||||
uint32_t CPLD::read() {
|
||||
return jtag.shift_dr(16, 0xffff) & 0xfbff;
|
||||
}
|
||||
|
||||
bool CPLD::verify_block(
|
||||
const uint16_t id,
|
||||
const uint16_t* const data,
|
||||
@@ -265,5 +278,59 @@ bool CPLD::is_blank() {
|
||||
return block_0_blank && block_1_blank;
|
||||
}
|
||||
|
||||
bool CPLD::AGM_enter_maintenance_mode() {
|
||||
shift_ir(instruction_t::AGM_STAGE_1);
|
||||
jtag.runtest_tck(100);
|
||||
shift_ir(instruction_t::AGM_STAGE_2);
|
||||
jtag.runtest_tck(100);
|
||||
shift_ir(instruction_t::AGM_STAGE_1);
|
||||
jtag.runtest_tck(100);
|
||||
|
||||
shift_ir(instruction_t::AGM_SET_REGISTER);
|
||||
jtag.runtest_tck(100);
|
||||
jtag.shift_dr(8, 0x0);
|
||||
jtag.runtest_tck(100);
|
||||
|
||||
shift_ir(instruction_t::AGM_PROGRAM);
|
||||
jtag.runtest_tck(100);
|
||||
jtag.shift_dr(32, 0x203f0044uL, 0x80000000);
|
||||
|
||||
shift_ir(instruction_t::IDCODE);
|
||||
jtag.runtest_tck(100);
|
||||
auto idcode = jtag.shift_dr(idcode_length, 0);
|
||||
|
||||
return idcode == 0x00025610;
|
||||
}
|
||||
|
||||
void CPLD::AGM_exit_maintenance_mode() {
|
||||
shift_ir(instruction_t::AGM_RESET);
|
||||
jtag.runtest_tck(100);
|
||||
}
|
||||
|
||||
void CPLD::AGM_enter_read_mode() {
|
||||
shift_ir(instruction_t::AGM_SET_REGISTER);
|
||||
jtag.runtest_tck(100);
|
||||
jtag.shift_dr(8, 0xf0);
|
||||
jtag.runtest_tck(100);
|
||||
|
||||
shift_ir(instruction_t::AGM_READ);
|
||||
jtag.runtest_tck(100);
|
||||
}
|
||||
|
||||
uint32_t CPLD::AGM_encode_address(uint32_t address, uint32_t trailer) {
|
||||
uint32_t p = trailer;
|
||||
for (size_t i = 0; i < 18; i++) {
|
||||
auto address_bit = (address >> i) & 0x01;
|
||||
p |= address_bit << (31 - i);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
uint32_t CPLD::AGM_read(uint32_t address) {
|
||||
auto encoded_address = AGM_encode_address(address * 4, 0xC0);
|
||||
return jtag.shift_dr(32, encoded_address, 0x0);
|
||||
}
|
||||
|
||||
} /* namespace max5 */
|
||||
} /* namespace cpld */
|
||||
|
@@ -60,6 +60,7 @@ class CPLD {
|
||||
}
|
||||
|
||||
bool idcode_ok();
|
||||
uint32_t get_idcode();
|
||||
|
||||
void enable();
|
||||
|
||||
@@ -90,6 +91,15 @@ class CPLD {
|
||||
|
||||
std::pair<bool, uint8_t> boundary_scan();
|
||||
|
||||
void prepare_read(uint16_t block);
|
||||
uint32_t read();
|
||||
|
||||
bool AGM_enter_maintenance_mode();
|
||||
void AGM_exit_maintenance_mode();
|
||||
void AGM_enter_read_mode();
|
||||
uint32_t AGM_encode_address(uint32_t address, uint32_t trailer);
|
||||
uint32_t AGM_read(uint32_t address);
|
||||
|
||||
private:
|
||||
using idcode_t = uint32_t;
|
||||
static constexpr size_t idcode_length = 32;
|
||||
@@ -115,6 +125,13 @@ class CPLD {
|
||||
ISC_ADDRESS_SHIFT = 0b1000000011, // 0x203
|
||||
ISC_READ = 0b1000000101, // 0x205
|
||||
ISC_NOOP = 0b1000010000, // 0x210
|
||||
AGM_RESET = 0x3f7,
|
||||
AGM_STAGE_1 = 0x3f8,
|
||||
AGM_STAGE_2 = 0x3f9,
|
||||
AGM_PROGRAM = 0x3fa,
|
||||
AGM_SET_REGISTER = 0x3fc,
|
||||
AGM_READ = 0x3fd,
|
||||
AGM_ERASE = 0x3fe,
|
||||
};
|
||||
|
||||
void shift_ir(const instruction_t instruction) {
|
||||
|
@@ -19,6 +19,7 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "cpld_xilinx.hpp"
|
||||
|
||||
namespace cpld {
|
||||
@@ -47,6 +48,25 @@ void XC2C64A::write_sram(const verify_blocks_t& blocks) {
|
||||
}
|
||||
|
||||
bool XC2C64A::verify_sram(const verify_blocks_t& blocks) {
|
||||
prepare_read_sram();
|
||||
|
||||
const jtag::tap::bits_t empty_row{block_length};
|
||||
|
||||
auto error = false;
|
||||
for (const auto& block : blocks) {
|
||||
tap.shift({&block.id, block_id_length}, true);
|
||||
tap.state(state_t::run_test_idle);
|
||||
|
||||
tap.state(state_t::shift_dr);
|
||||
error |= tap.shift(empty_row, {block.data.data(), block_length}, {block.mask.data(), block_length}, false, nullptr);
|
||||
}
|
||||
|
||||
finalize_read_sram(blocks[0].id);
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
void XC2C64A::prepare_read_sram() {
|
||||
tap.set_repeat(0);
|
||||
tap.set_end_ir(state_t::run_test_idle);
|
||||
tap.set_end_dr(state_t::run_test_idle);
|
||||
@@ -61,17 +81,25 @@ bool XC2C64A::verify_sram(const verify_blocks_t& blocks) {
|
||||
|
||||
tap.state(state_t::shift_dr);
|
||||
tap.shift(empty_row, false);
|
||||
}
|
||||
|
||||
auto error = false;
|
||||
for (const auto& block : blocks) {
|
||||
tap.shift({&block.id, block_id_length}, true);
|
||||
tap.state(state_t::run_test_idle);
|
||||
std::array<bool, 274> XC2C64A::read_block_sram(verify_block_t block) {
|
||||
tap.shift({&block.id, block_id_length}, true);
|
||||
tap.state(state_t::run_test_idle);
|
||||
|
||||
tap.state(state_t::shift_dr);
|
||||
error |= tap.shift(empty_row, {block.data.data(), block_length}, {block.mask.data(), block_length}, false);
|
||||
}
|
||||
// Redundant operation to finish the row.
|
||||
tap.shift({&blocks[0].id, block_id_length}, true);
|
||||
tap.state(state_t::shift_dr);
|
||||
const jtag::tap::bits_t empty_row{block_length};
|
||||
std::vector<bool> from_device;
|
||||
|
||||
tap.shift(empty_row, {block.data.data(), block_length}, {block.mask.data(), block_length}, false, &from_device);
|
||||
|
||||
std::array<bool, block_length> ret;
|
||||
std::copy_n(std::make_move_iterator(from_device.begin()), block_length, ret.begin());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void XC2C64A::finalize_read_sram(block_id_t id) {
|
||||
tap.shift({&id, block_id_length}, true);
|
||||
tap.state(state_t::run_test_idle);
|
||||
tap.set_end_dr(state_t::run_test_idle);
|
||||
|
||||
@@ -79,8 +107,6 @@ bool XC2C64A::verify_sram(const verify_blocks_t& blocks) {
|
||||
bypass();
|
||||
|
||||
tap.state(state_t::test_logic_reset);
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
bool XC2C64A::verify_eeprom(const verify_blocks_t& blocks) {
|
||||
@@ -133,6 +159,44 @@ void XC2C64A::init_from_eeprom() {
|
||||
tap.state(state_t::test_logic_reset);
|
||||
}
|
||||
|
||||
void XC2C64A::prepare_read_eeprom() {
|
||||
tap.set_repeat(0);
|
||||
tap.set_end_ir(state_t::run_test_idle);
|
||||
tap.set_end_dr(state_t::run_test_idle);
|
||||
|
||||
reset();
|
||||
bypass();
|
||||
enable();
|
||||
|
||||
shift_ir(instruction_t::ISC_READ);
|
||||
}
|
||||
|
||||
std::array<bool, 274> XC2C64A::read_block_eeprom(block_id_t id) {
|
||||
const jtag::tap::bits_t empty_row{block_length};
|
||||
|
||||
tap.set_end_dr(state_t::pause_dr);
|
||||
tap.shift_dr({&id, block_id_length});
|
||||
tap.set_end_ir(state_t::run_test_idle);
|
||||
tap.wait(state_t::pause_dr, state_t::pause_dr, 20);
|
||||
tap.set_end_ir(state_t::run_test_idle);
|
||||
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
|
||||
|
||||
std::vector<bool> from_device = tap.shift_dr_read(empty_row);
|
||||
|
||||
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
|
||||
|
||||
std::array<bool, block_length> ret;
|
||||
std::copy_n(std::make_move_iterator(from_device.begin()), block_length, ret.begin());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void XC2C64A::finalize_read_eeprom() {
|
||||
disable();
|
||||
bypass();
|
||||
|
||||
tap.state(state_t::test_logic_reset);
|
||||
}
|
||||
|
||||
bool XC2C64A::shift_ir(const instruction_t instruction) {
|
||||
const ir_t ir_buffer = toUType(instruction);
|
||||
const jtag::tap::bits_t bits{&ir_buffer, ir_length};
|
||||
|
@@ -68,6 +68,13 @@ class XC2C64A {
|
||||
bool verify_eeprom(const verify_blocks_t& blocks);
|
||||
void init_from_eeprom();
|
||||
|
||||
void prepare_read_eeprom();
|
||||
void prepare_read_sram();
|
||||
std::array<bool, block_length> read_block_eeprom(block_id_t id);
|
||||
std::array<bool, block_length> read_block_sram(verify_block_t block);
|
||||
void finalize_read_eeprom();
|
||||
void finalize_read_sram(block_id_t id);
|
||||
|
||||
private:
|
||||
static constexpr size_t idcode_length = 32;
|
||||
using idcode_t = uint32_t;
|
||||
|
@@ -37,4 +37,15 @@ uint32_t JTAG::shift(const size_t count, uint32_t value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t JTAG::shift_header(const size_t count, uint32_t value) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto tdo = target.clock(
|
||||
0,
|
||||
value & 1);
|
||||
value >>= 1;
|
||||
value |= tdo << (count - 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} /* namespace jtag */
|
||||
|
@@ -89,10 +89,29 @@ class JTAG {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t shift_dr(const size_t count, const uint32_t address, const uint32_t value) {
|
||||
/* Run-Test/Idle -> Select-DR-Scan */
|
||||
target.clock(1, 0);
|
||||
/* Scan -> Capture -> Shift */
|
||||
target.clock(0, 0);
|
||||
target.clock(0, 0);
|
||||
|
||||
shift_header(count, address);
|
||||
const auto result = shift(count, value);
|
||||
|
||||
/* Exit1 -> Update */
|
||||
target.clock(1, 0);
|
||||
/* Update -> Run-Test/Idle */
|
||||
target.clock(0, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
Target& target;
|
||||
|
||||
uint32_t shift(const size_t count, uint32_t value);
|
||||
uint32_t shift_header(const size_t count, uint32_t value);
|
||||
};
|
||||
|
||||
} /* namespace jtag */
|
||||
|
@@ -191,6 +191,10 @@ bool TAPMachine::shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected, c
|
||||
return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_dr, _end_dr, _run_test);
|
||||
}
|
||||
|
||||
std::vector<bool> TAPMachine::shift_dr_read(const bits_t& tdi_value) {
|
||||
return shift_data_read(tdi_value, state_t::shift_dr, _end_dr, _run_test);
|
||||
}
|
||||
|
||||
void TAPMachine::state(const state_t state) {
|
||||
if (state == state_t::test_logic_reset) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
@@ -227,7 +231,7 @@ void TAPMachine::shift_start(const state_t state) {
|
||||
advance_to_state(state);
|
||||
}
|
||||
|
||||
bool TAPMachine::shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms) {
|
||||
bool TAPMachine::shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms, std::vector<bool>* from_device) {
|
||||
if (tdo_expected.length() != tdo_mask.length()) {
|
||||
return false;
|
||||
}
|
||||
@@ -239,6 +243,10 @@ bool TAPMachine::shift(const bits_t& tdi, const bits_t& tdo_expected, const bits
|
||||
for (uint32_t i = 0; i < tdi.length(); i++) {
|
||||
const auto tms = end_tms & (i == (tdi.length() - 1));
|
||||
const auto tdo = clock(tms, tdi[i]);
|
||||
|
||||
if (from_device != nullptr)
|
||||
from_device->push_back(tdo);
|
||||
|
||||
if (tdo_expected && tdo_mask) {
|
||||
tdo_error |= (tdo & tdo_mask[i]) != (tdo_expected[i] & tdo_mask[i]);
|
||||
}
|
||||
@@ -258,7 +266,15 @@ void TAPMachine::shift_end(const state_t end_state, const uint32_t end_delay) {
|
||||
|
||||
bool TAPMachine::shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay) {
|
||||
shift_start(state);
|
||||
const auto result = shift(tdi, tdo_expected, tdo_mask, true);
|
||||
const auto result = shift(tdi, tdo_expected, tdo_mask, true, nullptr);
|
||||
shift_end(end_state, end_delay);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<bool> TAPMachine::shift_data_read(const bits_t& tdi, const state_t state, const state_t end_state, const uint32_t end_delay) {
|
||||
shift_start(state);
|
||||
std::vector<bool> result;
|
||||
shift(tdi, {}, {}, true, &result);
|
||||
shift_end(end_state, end_delay);
|
||||
return result;
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace jtag {
|
||||
namespace tap {
|
||||
@@ -113,13 +114,14 @@ class TAPMachine {
|
||||
void set_end_dr(const state_t state);
|
||||
|
||||
bool shift(const bits_t& tdi, const bool end_tms) {
|
||||
return shift(tdi, {}, {}, end_tms);
|
||||
return shift(tdi, {}, {}, end_tms, nullptr);
|
||||
}
|
||||
|
||||
bool shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms);
|
||||
bool shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms, std::vector<bool>* from_device);
|
||||
|
||||
bool shift_ir(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
|
||||
bool shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
|
||||
std::vector<bool> shift_dr_read(const bits_t& tdi_value);
|
||||
|
||||
void state(const state_t state);
|
||||
|
||||
@@ -142,6 +144,7 @@ class TAPMachine {
|
||||
void shift_end(const state_t end_state, const uint32_t end_delay);
|
||||
|
||||
bool shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay);
|
||||
std::vector<bool> shift_data_read(const bits_t& tdi, const state_t state, const state_t end_state, const uint32_t end_delay);
|
||||
};
|
||||
|
||||
} /* namespace tap */
|
||||
|
Reference in New Issue
Block a user