Defer write-only USB transactions to better utilize bus
This commit is contained in:
parent
077d730c63
commit
c32e4f094e
|
|
@ -43,20 +43,37 @@ enum CH347JtagSig {
|
|||
SIG_TMS = 0b10,
|
||||
SIG_TDI = 0b10000,
|
||||
};
|
||||
|
||||
static void LIBUSB_CALL sync_cb(struct libusb_transfer *transfer) {
|
||||
int *complete = (int *)transfer->user_data;
|
||||
*complete = true;
|
||||
}
|
||||
|
||||
int CH347Jtag::usb_xfer(unsigned wlen, unsigned rlen, unsigned *ract) {
|
||||
wcomplete = 0;
|
||||
// defer should only be used with rlen == 0
|
||||
|
||||
int CH347Jtag::usb_xfer(unsigned wlen, unsigned rlen, unsigned *ract, bool defer) {
|
||||
if (_verbose) {
|
||||
fprintf(stderr, "obuf - _obuf = %ld\n", obuf - _obuf);
|
||||
fprintf(stderr, "obuf[%d] = {", wlen);
|
||||
for (unsigned i = 0; i < wlen; ++i) {
|
||||
fprintf(stderr, "%02x ", obuf[i]);
|
||||
}
|
||||
fprintf(stderr, "}\n\n");
|
||||
}
|
||||
|
||||
if (defer) {
|
||||
obuf += wlen;
|
||||
return 0;
|
||||
}
|
||||
// write out whole buffer
|
||||
wlen += obuf - _obuf;
|
||||
obuf = _obuf;
|
||||
|
||||
if (wlen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
wcomplete = 0;
|
||||
libusb_fill_bulk_transfer(wtrans, dev_handle, CH347JTAG_WRITE_EP, obuf,
|
||||
wlen, sync_cb, &wcomplete, CH347JTAG_TIMEOUT);
|
||||
int r = libusb_submit_transfer(wtrans);
|
||||
|
|
@ -131,12 +148,14 @@ wait_rcompletion:
|
|||
}
|
||||
|
||||
int CH347Jtag::setClk(const uint8_t &factor) {
|
||||
// flush the obuf
|
||||
usb_xfer(0, 0, 0, false); // is called from constructor, don't replace with virtual flush()
|
||||
memset(obuf, 0, 16);
|
||||
obuf[0] = CMD_CLK;
|
||||
obuf[1] = 6;
|
||||
obuf[4] = factor;
|
||||
unsigned actual = 0;
|
||||
int rv = usb_xfer(9, 4, &actual);
|
||||
int rv = usb_xfer(9, 4, &actual, false);
|
||||
if (rv || actual != 4)
|
||||
return -1;
|
||||
if (ibuf[0] != 0xd0 || ibuf[3] != 0)
|
||||
|
|
@ -145,7 +164,7 @@ int CH347Jtag::setClk(const uint8_t &factor) {
|
|||
}
|
||||
|
||||
CH347Jtag::CH347Jtag(uint32_t clkHZ, int8_t verbose):
|
||||
_verbose(verbose>1), dev_handle(NULL), usb_ctx(NULL)
|
||||
_verbose(verbose>1), dev_handle(NULL), usb_ctx(NULL), obuf(_obuf)
|
||||
{
|
||||
int actual_length = 0;
|
||||
struct libusb_device_descriptor desc;
|
||||
|
|
@ -241,24 +260,25 @@ int CH347Jtag::_setClkFreq(uint32_t clkHZ)
|
|||
|
||||
int CH347Jtag::writeTMS(const uint8_t *tms, uint32_t len, bool flush_buffer)
|
||||
{
|
||||
(void) flush_buffer;
|
||||
|
||||
if (get_obuf_length() < (int)(len * 2 + 4)) { // check if there is enough room left
|
||||
flush();
|
||||
}
|
||||
uint8_t *ptr = obuf;
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
if (ptr == obuf) {
|
||||
*ptr++ = CMD_BITS_WO;
|
||||
ptr += 2; // leave place for length;
|
||||
}
|
||||
uint8_t x = /*SIG_TDI |*/ ((tms[i >> 3] & (1 << (i & 7))) ? SIG_TMS : 0);
|
||||
uint8_t x = ((tms[i >> 3] & (1 << (i & 7))) ? SIG_TMS : 0);
|
||||
*ptr++ = x;
|
||||
*ptr++ = x | SIG_TCK;
|
||||
unsigned wlen = ptr - obuf;
|
||||
if (wlen > sizeof(obuf) - 3 || i == len - 1) {
|
||||
int wlen = ptr - obuf;
|
||||
if (wlen + 1 >= get_obuf_length() || i == len - 1) {
|
||||
*ptr++ = x; // clear TCK
|
||||
++wlen;
|
||||
wlen = ptr - obuf;
|
||||
obuf[1] = wlen - 3;
|
||||
obuf[2] = (wlen - 3) >> 8;
|
||||
int ret = usb_xfer(wlen, 0, 0);
|
||||
int ret = usb_xfer(wlen, 0, 0, !flush_buffer);
|
||||
if (ret < 0) {
|
||||
cerr << "writeTMS: usb bulk write failed: " <<
|
||||
libusb_strerror(static_cast<libusb_error>(ret)) << endl;
|
||||
|
|
@ -275,9 +295,14 @@ int CH347Jtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t len)
|
|||
uint8_t bits = 0;
|
||||
if (tms) bits |= SIG_TMS;
|
||||
if (tdi) bits |= SIG_TDI;
|
||||
if (!bits && len > 7) {
|
||||
if (!bits && len > 8) {
|
||||
return writeTDI(0, 0, len, false);
|
||||
}
|
||||
|
||||
if (get_obuf_length() < (int)(len * 2 + 4)) {
|
||||
flush();
|
||||
}
|
||||
|
||||
uint8_t *ptr = obuf;
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
if (ptr == obuf) {
|
||||
|
|
@ -286,13 +311,13 @@ int CH347Jtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t len)
|
|||
}
|
||||
*ptr++ = bits;
|
||||
*ptr++ = bits | SIG_TCK;
|
||||
unsigned wlen = ptr - obuf;
|
||||
if (wlen > sizeof(obuf) - 3 || i == len - 1) {
|
||||
int wlen = ptr - obuf;
|
||||
if (wlen + 1 >= get_obuf_length() || i == len - 1) {
|
||||
*ptr++ = bits; // clear TCK
|
||||
++wlen;
|
||||
wlen = ptr - obuf;
|
||||
obuf[1] = wlen - 3;
|
||||
obuf[2] = (wlen - 3) >> 8;
|
||||
int ret = usb_xfer(wlen, 0, 0);
|
||||
int ret = usb_xfer(wlen, 0, 0, true);
|
||||
if (ret < 0) {
|
||||
cerr << "writeCLK: usb bulk write failed: " <<
|
||||
libusb_strerror(static_cast<libusb_error>(ret)) << endl;
|
||||
|
|
@ -306,17 +331,20 @@ int CH347Jtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t len)
|
|||
|
||||
int CH347Jtag::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||
{
|
||||
if (!len)
|
||||
if (len == 0)
|
||||
return 0;
|
||||
unsigned bytes = (len - ((end)?1:0)) / 8;
|
||||
unsigned bytes = (len - (end ? 1 : 0)) / 8;
|
||||
unsigned bits = len - bytes * 8;
|
||||
uint8_t *rptr = rx;
|
||||
const uint8_t *tptr = tx;
|
||||
const uint8_t *txend = tx + bytes;
|
||||
uint8_t cmd = (rx) ? CMD_BYTES_WR : CMD_BYTES_WO;
|
||||
uint8_t cmd = (rx != nullptr) ? CMD_BYTES_WR : CMD_BYTES_WO;
|
||||
while (tptr < txend) {
|
||||
unsigned avail = sizeof(obuf) - 3;
|
||||
unsigned chunk = (txend - tptr < avail)? txend - tptr: avail;
|
||||
if (get_obuf_length() < 4) {
|
||||
flush();
|
||||
}
|
||||
int avail = get_obuf_length() - 3;
|
||||
int chunk = (txend - tptr < avail)? txend - tptr: avail;
|
||||
if (tx) {
|
||||
memcpy(&obuf[3], tptr, chunk);
|
||||
} else {
|
||||
|
|
@ -328,7 +356,7 @@ int CH347Jtag::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
|||
obuf[1] = chunk;
|
||||
obuf[2] = chunk >> 8;
|
||||
unsigned actual_length = 0;
|
||||
int ret = usb_xfer(chunk + 3, (rx) ? chunk + 3 : 0, &actual_length);
|
||||
int ret = usb_xfer(chunk + 3, (rx) ? chunk + 3 : 0, &actual_length, rx == 0 && get_obuf_length());
|
||||
if (ret < 0) {
|
||||
cerr << "writeTDI: usb bulk read failed: " <<
|
||||
libusb_strerror(static_cast<libusb_error>(ret)) << endl;
|
||||
|
|
@ -348,9 +376,12 @@ int CH347Jtag::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
|||
if (bits == 0)
|
||||
return EXIT_SUCCESS;
|
||||
cmd = (rx) ? CMD_BITS_WR : CMD_BITS_WO;
|
||||
if (get_obuf_length() < (int)(4 + bits * 2)) {
|
||||
flush();
|
||||
}
|
||||
uint8_t *ptr = &obuf[3];
|
||||
uint8_t x = 0;
|
||||
const uint8_t *bptr = &tx[bytes];
|
||||
const uint8_t *bptr = tx + bytes;
|
||||
for (unsigned i = 0; i < bits; ++i) {
|
||||
uint8_t txb = (tx) ? bptr[i >> 3] : 0;
|
||||
uint8_t _tdi = (txb & (1 << (i & 7))) ? SIG_TDI : 0;
|
||||
|
|
@ -366,7 +397,7 @@ int CH347Jtag::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
|||
obuf[0] = cmd;
|
||||
obuf[1] = wlen - 3;
|
||||
obuf[2] = (wlen - 3) >> 8;
|
||||
int ret = usb_xfer(wlen, (rx) ? (bits + 3) : 0, &actual_length);
|
||||
int ret = usb_xfer(wlen, (rx) ? (bits + 3) : 0, &actual_length, rx == nullptr);
|
||||
|
||||
if (ret < 0) {
|
||||
cerr << "writeTDI: usb bulk read failed: " <<
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ class CH347Jtag : public JtagInterface {
|
|||
/* clk */
|
||||
int toggleClk(uint8_t tms, uint8_t tdo, uint32_t clk_len) override;
|
||||
|
||||
int get_buffer_size() override { return 0;}
|
||||
int get_buffer_size() override {return get_obuf_length();}
|
||||
|
||||
bool isFull() override { return false;}
|
||||
bool isFull() override {return get_obuf_length() == 0;}
|
||||
|
||||
int flush() override {return 0;}
|
||||
int flush() override {return usb_xfer(0, 0, 0, false);}
|
||||
|
||||
private:
|
||||
bool _verbose;
|
||||
|
|
@ -37,6 +37,8 @@ class CH347Jtag : public JtagInterface {
|
|||
struct libusb_transfer *wtrans, *rtrans;
|
||||
int rcomplete, wcomplete;
|
||||
uint8_t ibuf[512];
|
||||
uint8_t obuf[512];
|
||||
int usb_xfer(unsigned wlen, unsigned rlen, unsigned *actual);
|
||||
uint8_t _obuf[512];
|
||||
uint8_t *obuf;
|
||||
int get_obuf_length() const {return 512 - (obuf - _obuf);}
|
||||
int usb_xfer(unsigned wlen, unsigned rlen, unsigned *actual, bool defer);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include "rawParser.hpp"
|
||||
#include "spiFlash.hpp"
|
||||
|
||||
#include <byteswap.h>
|
||||
//#include <byteswap.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -140,7 +140,6 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
|
|||
}
|
||||
}
|
||||
}
|
||||
_jtag->setClkFreq(2500000);
|
||||
|
||||
/* erase and program flash differ for GW1N1 */
|
||||
if (idcode == 0x0900281B)
|
||||
|
|
@ -224,12 +223,16 @@ void Gowin::reset()
|
|||
|
||||
void Gowin::programFlash()
|
||||
{
|
||||
_jtag->setClkFreq(2500000);
|
||||
|
||||
const uint8_t *data = _fs->getData();
|
||||
int length = _fs->getLength();
|
||||
|
||||
send_command(0x3a);
|
||||
send_command(0);
|
||||
|
||||
send_command(CONFIG_DISABLE);
|
||||
send_command(NOOP);
|
||||
_jtag->go_test_logic_reset();
|
||||
_jtag->flush();
|
||||
usleep(500*1000);
|
||||
|
||||
eraseSRAM();
|
||||
|
|
@ -452,6 +455,13 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value)
|
|||
return true;
|
||||
}
|
||||
|
||||
inline uint32_t bswap_32(uint32_t x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
/* TN653 p. 17-21 */
|
||||
bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length)
|
||||
{
|
||||
|
|
@ -486,11 +496,12 @@ bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length)
|
|||
sendClkUs((is_gw1n1) ? 32 : 16);
|
||||
}
|
||||
sendClkUs((is_gw1n1) ? 2400 : 6);
|
||||
_jtag->flush();
|
||||
usleep(200);
|
||||
}
|
||||
send_command(CONFIG_DISABLE);
|
||||
send_command(NOOP);
|
||||
|
||||
_jtag->flush();
|
||||
usleep(600*1000);
|
||||
send_command(CONFIG_DISABLE);
|
||||
send_command(NOOP);
|
||||
|
|
@ -499,6 +510,7 @@ bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length)
|
|||
send_command(NOOP);
|
||||
if (_verbose)
|
||||
displayReadReg(readStatusReg());
|
||||
_jtag->flush();
|
||||
sleep(1);
|
||||
|
||||
return true;
|
||||
|
|
@ -519,7 +531,7 @@ bool Gowin::writeSRAM(const uint8_t *data, int length)
|
|||
_jtag->shiftDR(data, NULL, length);
|
||||
send_command(CONFIG_DISABLE); // config disable
|
||||
send_command(NOOP); // noop
|
||||
|
||||
_jtag->flush();
|
||||
sleep(1);
|
||||
|
||||
if (readStatusReg() & STATUS_DONE_FINAL)
|
||||
|
|
@ -553,6 +565,7 @@ bool Gowin::eraseFLASH()
|
|||
send_command(NOOP);
|
||||
if (_verbose)
|
||||
displayReadReg(readStatusReg());
|
||||
_jtag->flush();
|
||||
usleep(500*1000);
|
||||
if (_verbose)
|
||||
displayReadReg(readStatusReg());
|
||||
|
|
@ -562,9 +575,9 @@ bool Gowin::eraseFLASH()
|
|||
|
||||
void Gowin::sendClkUs(unsigned us)
|
||||
{
|
||||
//unsigned freq = _jtag->getClkFreq() / 1000000;
|
||||
//freq = (freq) ? freq : 1;
|
||||
unsigned clocks = us * 2; // at 2MHz 1us ~ 2 clocks
|
||||
uint64_t clocks = _jtag->getClkFreq();
|
||||
clocks *= us;
|
||||
clocks /= 1000000;
|
||||
_jtag->toggleClk(clocks);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue