RISC-V/V203F6P6/programmer/software/programmer.cpp
2025-02-04 16:32:08 +01:00

216 lines
5.9 KiB
C++

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "programmer.h"
#define trace printf
Programmer::Programmer() : BaseLayer(), ring(), ihx(),
line_len(0u), line_index(0u), begin_addr(0u), file_len(0u) {
file_pool = new uint8_t [MaxPages * PageSize];
memory_pool = new uint8_t [MaxPages * PageSize];
}
Programmer::~Programmer() {
delete [] memory_pool;
delete [] file_pool;
}
void Programmer::Flush() {
char c;
while (ring.Read(c));
}
uint32_t Programmer::Up(const char * data, const uint32_t len) {
for (unsigned n=0u; n<len; n++) ring.Write (data [n]);
return len;
}
void Programmer::read_flash_binary(const char * name, const unsigned int blen) {
file_len = blen * PageSize;
if (file_len > (MaxPages * PageSize)) {
fprintf(stderr, "read request too long - %d\n", file_len);
}
printf("read %d bytes...\n", file_len);
read_flash(file_len);
FILE * out = fopen(name, "w");
int r = fwrite(memory_pool, 1, file_len, out);
printf("writen %d bytes to %s\n", r, name);
fclose(out);
}
void Programmer::verify_flash_binary(const char * name) {
if (!open_file_for_read(name)) return;
printf("verify %d bytes...\n", file_len);
read_flash(file_len);
unsigned err = 0u;
for (unsigned n=0u; n<file_len; n++) {
if (file_pool[n] != memory_pool[n]) {
fprintf(stderr, "err at 0x%06X: 0x%02X != 0x%02X\n", n, file_pool[n], memory_pool[n]);
err += 1u;
}
}
if (err) printf("verify errors: %d\n", err);
else printf("flash OK\n");
}
void Programmer::write_flash_binary(const char * name) {
if (!open_file_for_read(name)) return;
uint32_t blocks = file_len / PageSize;
if (file_len % PageSize) blocks += 1u;
erase_blocks (blocks);
begin_addr = 0u;
StartOperation(begin_addr);
unsigned ofs = 0u, rem = file_len, chunk;
while (true) {
chunk = rem > 0x20 ? 0x20 : rem;
unsigned rl = ihx.DataRecord(strbuf, file_pool + begin_addr + ofs, chunk);
SendString(strbuf, rl);
while (!GetLine());
RowTypes t = ihx.parseRecord(line, line_len);
if (t != ackRecord) fprintf(stderr, "BAD WriteOperation 0x%X\n", begin_addr + ofs);
ihx.AddOffset(chunk);
ofs += chunk;
rem -= chunk;
printf("write at 0x%04X \r", begin_addr + ofs);
fflush(stdout);
if (ofs >= ihxPage) {
begin_addr += ihxPage;
StartOperation(begin_addr);
ofs = 0u;
}
if (rem == 0u) break;
}
printf("\n");
}
void Programmer::SendString(const char * ptr, const uint32_t len) {
/*
fprintf(stdout, "TX");
int r = fwrite (ptr, 1, len, stdout); (void) r;
fflush (stdout);
*/
unsigned ofs = 0u, res = len;
while (res) {
const unsigned n = Down (ptr + ofs, res);
ofs += n;
res -= n;
}
}
bool Programmer::open_file_for_read(const char * name) {
struct stat prop;
const int r = stat (name, & prop);
if (r) {
fprintf(stderr, "file %s not exists.", name);
return false;
}
const unsigned flen = prop.st_size;
if (flen > (MaxPages * PageSize)) {
fprintf(stderr, "verify/write request too long - %d\n", flen);
return false;
}
FILE * in = fopen (name, "r");
if (!in) {
fprintf(stderr, "file %s not open for read.", name);
return false;
}
const int l = fread (file_pool, 1, flen, in);
printf("%s: readen = %d bytes\n", name, l);
fclose(in);
file_len = flen;
return true;
}
bool Programmer::GetLine() {
char c;
while (ring.Read(c)) {
line [line_index++] = c;
if (c == '\n') {
line_len = line_index;
/*
fprintf(stdout, "RX");
int r = fwrite (line, 1, line_len, stdout); (void) r;
fflush (stdout);
*/
line_index = 0u;
return true;
}
}
return false;
}
void Programmer::ParseLine() {
RowTypes t = ihx.parseRecord (line, line_len);
switch (t) {
case dataRecord: AcquireDataRecord (); break;
case reqRecord: AcquireReqRecord (); break;
default:
trace ("BAD record 0x%02X\r\n", t);
break;
}
}
void Programmer::StartOperation(const unsigned addr) {
uint32_t res = ihx.ElaRecord(strbuf, addr);
SendString (strbuf, res);
while (!GetLine());
RowTypes t = ihx.parseRecord(line, line_len);
if (t != ackRecord) fprintf(stderr, "BAD StartOperation\n");
}
void Programmer::AcquireDataRecord() {
uint32_t ofs, len;
uint8_t * ptr = ihx.getDataRow (ofs, len);
memcpy (memory_pool + begin_addr + ofs, ptr, len);
if (len) {
ihx.AddOffset (len); // posun offsetu az po ack
return;
}
}
void Programmer::AcquireReqRecord() {
static constexpr unsigned chunk_size = 0x10;
uint8_t data [chunk_size];
uint32_t res = 0x10, len, ofs;
len = chunk_size;
ihx.getOffset (ofs);
//trace ("AcquireReqRecord: %04X, len=%d\r\n", ofs, len);
memcpy (data, memory_pool + begin_addr + ofs, len);
res = ihx.DataRecord (strbuf, data, len);
SendString (strbuf, res);
}
void Programmer::read_flash(const unsigned len) {
StartOperation(begin_addr);
while (true) {
const uint32_t res = ihx.BTxRecord (strbuf, reqRecord);
SendString (strbuf, res);
while (!GetLine());
ParseLine();
uint32_t ofs;
ihx.getOffset(ofs);
printf("read flash at 0x%X \r", begin_addr + ofs);
fflush(stdout);
if (ofs >= ihxPage) {
begin_addr += ihxPage;
StartOperation(begin_addr);
ofs = 0u;
}
if ((begin_addr + ofs) >= len) break;
}
printf("\n");
}
void Programmer::Erase(const unsigned int n) {
uint32_t ofs, addr = n * 0x10u; // adresa zmenšena 256x
ihx.getOffset(ofs);
ihx.AddOffset(addr - ofs);
uint32_t res = ihx.BTxRecord (strbuf, ersRecord);
SendString (strbuf, res);
}
void Programmer::erase_blocks(const unsigned int blocks) {
StartOperation(0u);
for (unsigned n=0u; n<blocks; n++) {
Erase(n);
while (!GetLine());
RowTypes t = ihx.parseRecord(line, line_len);
if (t != ackRecord) fprintf(stderr, "BAD EraseOperation %d\n", n);
printf("erase block %d \r", n+1);
fflush(stdout);
}
printf("\n");
}