You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/progs/psp/base/psp.cpp

347 lines
11 KiB

/***************************************************************************
* Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
* Copyright (C) 2002-2003 Stephen Landamore <stephen@landamore.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "psp.h"
#include "common/global/global.h"
#include "common/common/misc.h"
//-----------------------------------------------------------------------------
TQMemArray<uchar> Psp::createConfigInfo(const Pic::Data &data)
{
TQMemArray<uchar> array(33);
array.fill(0x00);
const Pic::Config &config = data.config();
for (uint i=0; i<uint(config._words.count()); i++) {
BitValue v = config._words[i].usedMask();
if ( data.nbBytesWord(Pic::MemoryRangeType::UserId)==1 ) array[i ^ 1] = v.byte(0);
else {
array[2*i] = v.byte(1);
array[2*i + 1] = v.byte(0);
}
}
for (uint i=0; i<16; i++) array[i + 16] = array[i];
// checksum
for (uint i=0; i<32; i++) array[32] += array[i];
return array;
}
TQMemArray<uchar> Psp::createDeviceInfo(const Pic::Data &data)
{
TQMemArray<uchar> config = createConfigInfo(data);
TQMemArray<uchar> array(45);
array.fill(0x00);
// memory code length
BitValue v = data.nbWords(Pic::MemoryRangeType::Code);
array[0] = v.byte(1);
array[1] = v.byte(0);
// address word width
v = data.mask(Pic::MemoryRangeType::Code);
array[2] = v.byte(1);
array[3] = v.byte(0);
// data word width
array[4] = v.byte(1);
array[5] = v.byte(0);
if ( data.isReadable(Pic::MemoryRangeType::UserId) ) {
// user id width
v = data.userIdRecommendedMask();
if ( data.nbBytesWord(Pic::MemoryRangeType::UserId)==1 ) v += v << 8;
array[6] = v.byte(1);
array[7] = v.byte(0);
// user id mask
array[8] = v.byte(1);
array[9] = v.byte(0);
}
// memory config mask
array[10] = config[0];
array[11] = config[1];
array[12] = config[16];
array[13] = config[17];
if ( data.isReadable(Pic::MemoryRangeType::Eeprom) ) {
// memory eeprom width
v = data.mask(Pic::MemoryRangeType::Eeprom);
array[14] = v.byte(1);
array[15] = v.byte(0);
// memory eeprom mask
array[16] = v.byte(1);
array[17] = v.byte(0);
}
if ( data.isReadable(Pic::MemoryRangeType::Cal) ) {
// memory calibration width
v = data.mask(Pic::MemoryRangeType::Cal);
array[18] = v.byte(1);
array[19] = v.byte(0);
// memory calibration mask
array[20] = v.byte(1);
array[21] = v.byte(0);
}
// memory code start
array[22] = 0x00;
array[23] = 0x00;
// memory code length
array[24] = 0x00; // array[0]; in lplab and for some devices in picp...
array[25] = 0x01; // array[1]; in lplab and for some devices in picp...
if ( data.isReadable(Pic::MemoryRangeType::UserId) ) {
// user id start
v = data.range(Pic::MemoryRangeType::UserId).start.toUInt();
array[26] = v.byte(1);
array[27] = v.byte(0);
// user id length
v = data.nbWords(Pic::MemoryRangeType::UserId);
if ( data.nbBytesWord(Pic::MemoryRangeType::UserId)==1 ) v >>= 1;
array[28] = v.byte(0);
}
if ( data.isReadable(Pic::MemoryRangeType::Config) ) {
// config start
v = data.range(Pic::MemoryRangeType::Config).start.toUInt();
array[29] = v.byte(1);
array[30] = v.byte(0);
// config length
v = data.nbWords(Pic::MemoryRangeType::Config);
if ( data.nbBytesWord(Pic::MemoryRangeType::Config)==1 ) v >>= 1;
array[31] = v.byte(0);
}
if ( data.isReadable(Pic::MemoryRangeType::Config) ) {
// eeprom start
array[32] = 0x00;
array[33] = 0x00;
// eeprom length
v = data.nbWords(Pic::MemoryRangeType::Eeprom);
array[34] = v.byte(1);
array[35] = v.byte(0);
}
if ( data.isReadable(Pic::MemoryRangeType::Cal) ) {
// calibration start
v = data.range(Pic::MemoryRangeType::Cal).start.toUInt();
array[36] = v.byte(1);
array[37] = v.byte(0);
// calibration length
v = data.nbWords(Pic::MemoryRangeType::Cal);
array[38] = v.byte(1);
array[39] = v.byte(0);
}
// programming
const Psp::Data &pdata = Psp::data(data.name());
array[40] = pdata.overprogram;
array[41] = pdata.tries;
array[42] = pdata.algorithm;
if ( data.memoryTechnology()==Device::MemoryTechnology::Flash ) array[43] |= 0x01;
if ( data.isReadable(Pic::MemoryRangeType::UserId) ) array[43] |= 0x02;
if ( data.isReadable(Pic::MemoryRangeType::Config) ) array[43] |= 0x04;
if ( data.isReadable(Pic::MemoryRangeType::Eeprom) ) array[43] |= 0x08;
if ( data.isReadable(Pic::MemoryRangeType::Cal) ) array[43] |= 0x10;
if ( data.config().findMask("PARITY") ) array[43] |= 0x20;
// checksum
for (uint i=0; i<44; i++) array[44] += array[i];
return array;
}
//-----------------------------------------------------------------------------
Psp::Hardware::Hardware(::Programmer::Base &base, const TQString &portDevice)
: Programmer::PicHardware(base, new SerialPort(portDevice, base), TQString())
{}
bool Psp::Hardware::internalConnectHardware()
{
if ( !port()->open() ) return false;
if ( !port()->reset() ) return false;
// #### TODO: detect Warp13 or JuPic
TQMemArray<uchar> a;
if ( !port()->command(0x88, 1, a) ) return false;
if ( a[0]!=0xAB ) {
log(Log::LineType::Error, i18n("Wrong programmer connected"));
return false;
}
return true;
}
bool Psp::Hardware::getFirmwareVersion(VersionData &version)
{
TQMemArray<uchar> a1;
if ( !port()->commandAck(0x8D, 2, &a1) ) return false;
if ( a1[1]==0xFF ) {
log(Log::LineType::Warning, i18n("Invalid firmware version"));
version = VersionData(0xFF, 0, 0);
} else {
TQMemArray<uchar> a2;
if ( !port()->receive(2, a2) ) return false;
version = VersionData(a1[1], a2[0], a2[1]);
}
return true;
}
bool Psp::Hardware::setTarget()
{
log(Log::DebugLevel::Max, "set target");
// load device info
if ( !port()->commandAck(0x81) ) return false;
TQMemArray<uchar> a = createDeviceInfo(device());
if ( !port()->send(a) ) return false;
if ( !port()->receiveEnd() ) return false;
// load config info
if ( !port()->commandAck(0x82) ) return false;
a = createConfigInfo(device());
if ( !port()->send(a) ) return false;
if ( !port()->receiveEnd() ) return false;
return true;
}
bool Psp::Hardware::setRange(uint start, uint size)
{
TQMemArray<uchar> a(6);
a[0] = 0x8E;
a[1] = start >> 16;
a[2] = (start >> 8) & 0xFF;
a[3] = start & 0xFF;
a[4] = size >> 8;
a[5] = size & 0xFF;
if ( !port()->send(a) ) return false;
TQMemArray<uchar> r;
if ( !port()->receive(6, r) ) return false;
for (uint i=0; i<6; i++) {
if ( r[i]!=a[i] ) {
log(Log::LineType::Error, i18n("Failed to set range"));
return false;
}
}
return true;
}
char Psp::Hardware::readCommand(Pic::MemoryRangeType type)
{
switch (type.type()) {
case Pic::MemoryRangeType::Code: return 'T';
case Pic::MemoryRangeType::Eeprom: return 'd';
case Pic::MemoryRangeType::Config: return 'f';
case Pic::MemoryRangeType::UserId: return 'e';
case Pic::MemoryRangeType::Cal: return 'c';
case Pic::MemoryRangeType::DeviceId:
case Pic::MemoryRangeType::CalBackup:
case Pic::MemoryRangeType::DebugVector:
case Pic::MemoryRangeType::ProgramExecutive:
case Pic::MemoryRangeType::HardwareStack:
case Pic::MemoryRangeType::Nb_Types: break;
}
return 0;
}
char Psp::Hardware::writeCommand(Pic::MemoryRangeType type)
{
switch (type.type()) {
case Pic::MemoryRangeType::Code: return 'Q';
case Pic::MemoryRangeType::Eeprom: return 'i';
case Pic::MemoryRangeType::Config: return 'g';
case Pic::MemoryRangeType::UserId: return 'h';
case Pic::MemoryRangeType::Cal: return 'q';
case Pic::MemoryRangeType::DeviceId:
case Pic::MemoryRangeType::CalBackup:
case Pic::MemoryRangeType::DebugVector:
case Pic::MemoryRangeType::ProgramExecutive:
case Pic::MemoryRangeType::HardwareStack:
case Pic::MemoryRangeType::Nb_Types: break;
}
return 0;
}
bool Psp::Hardware::readMemory(Pic::MemoryRangeType type, Device::Array &data, const ::Programmer::VerifyData *vdata)
{
TQMemArray<uchar> a;
uint nbWords = device().nbWords(type);
data.resize(nbWords);
uint nbBytes = nbWords * device().nbBytesWord(type);
char c = readCommand(type);
switch (type.type()) {
case Pic::MemoryRangeType::Code:
if ( !setRange(0, nbWords) ) return false;
if ( !port()->commandAck(c) ) return false;
for (uint i=0; i<data.count(); i++) {
if ( !port()->receive(2, a) ) return false;
data[i] = (a[0] << 8) + a[1];
// log(Log::DebugLevel::Max, TQString("code data %1: %2 (%3, %4)").tqarg(i).tqarg(toHexLabel(data[i], 4))
// .tqarg(toHexLabel(a[0], 2)).tqarg(toHexLabel(a[1], 2)));
}
if ( !port()->receiveEnd() ) return false;
break;
case Pic::MemoryRangeType::Eeprom:
if ( !port()->commandAck(c) ) return false;
for (uint i=0; i<data.count(); i++) {
if ( !port()->receive(1, a) ) return false;
data[i] = a[0];
}
if ( !port()->receiveEnd() ) return false;
break;
case Pic::MemoryRangeType::UserId:
if ( !port()->commandAckEnd(c, nbBytes+2, a) ) return false;
for (uint i=0; i<data.count(); i++) data[i] = (a[1+2*i] << 8) + a[1+2*i+1];
break;
case Pic::MemoryRangeType::Config:
if ( !port()->commandAckEnd(c, nbBytes+2, a) ) return false;
for (uint i=0; i<data.count(); i++) data[i] = (a[1+2*i] << 8) + a[1+2*i+1];
break;
case Pic::MemoryRangeType::Cal:
if ( !setRange(0, nbWords) ) return false;
if ( !port()->commandAckEnd(c, nbBytes+2, a) ) return false;
for (uint i=0; i<data.count(); i++) data[i] = (a[1+2*i] << 8) + a[1+2*i+1];
break;
case Pic::MemoryRangeType::DeviceId:
case Pic::MemoryRangeType::CalBackup:
data.resize(0);
return true;
case Pic::MemoryRangeType::DebugVector:
case Pic::MemoryRangeType::HardwareStack:
case Pic::MemoryRangeType::ProgramExecutive:
case Pic::MemoryRangeType::Nb_Types: Q_ASSERT(false); return false;
}
if (vdata) {
for (uint i=0; i<data.count(); i++)
if ( !verifyWord(i, data[i], type, *vdata) ) return false;
}
return true;
}
bool Psp::Hardware::writeMemory(Pic::MemoryRangeType type, const Device::Array &data, bool force)
{
Q_UNUSED(force); // #### TODO: optimize for program memory
if ( type==Pic::MemoryRangeType::Code && !setRange(0, data.count()) ) return false;
uint nbBytes = device().nbBytesWord(type);
if ( !port()->commandAck(writeCommand(type)) ) return false;
for (uint i=0; i<data.count(); i++)
if ( !port()->sendData(data[i].toUInt(), nbBytes) ) return false;
return port()->receiveEnd();
}
bool Psp::Hardware::eraseAll()
{
TQMemArray<uchar> a;
if ( !port()->commandAck(0x8F, 2, &a) ) return false;
if ( a[1]!=0x00 ) {
log(Log::LineType::Error, i18n("Erase failed"));
return false;
}
return true;
}