Files
2023-03-13 08:36:51 +00:00

355 lines
8.2 KiB
C

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
//#include <asm/termios.h>
//#include <asm/ioctls.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
//#include <poll.h>
#include <stdint.h>
#include "parse_ihex.h"
#define BPS 460800
#ifndef BOTHER
#define BOTHER CBAUDEX
#endif
extern int ioctl(int d, unsigned long request, ...);
static int
serial_open(const char *device)
{
struct termios2 settings;
int fd;
fd = open(device, O_RDWR);
if (fd < 0) {
perror("open failed");
return -1;
}
if (ioctl(fd, TCGETS2, &settings) < 0) {
perror("ioctl TCGETS2 failed");
close(fd);
return -1;
}
settings.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | INPCK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON | PARMRK);
settings.c_iflag |= IGNBRK | IGNPAR;
settings.c_oflag &= ~OPOST;
settings.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
settings.c_cflag &= ~(CSIZE | PARODD | CBAUD | PARENB);
settings.c_cflag |= CS8 | BOTHER | CREAD;
settings.c_ispeed = BPS;
settings.c_ospeed = BPS;
if (ioctl(fd, TCSETS2, &settings) < 0) {
perror("ioctl TCSETS2 failed");
close(fd);
return -1;
}
return fd;
}
static void
usage(void)
{
fputs("Usage: [OPTION].. FILE\n"
"Upload image file to memSIM2 EPROM emulator\n\n"
"Options:\n"
"\t-d DEVICE Serial device\n"
"\t-m MEMTYPE Memory type (2764,27128,27256,27512,27010,27020,27040)\n"
"\t-r RESETTIME Time of reset pulse in milliseconds.\n"
"\t > 0 for positive pulse, < 0 for negative pulse\n"
"\t-e Enable emulation\n"
"\t-h This help\n",
stderr);
}
static int
read_binary(FILE *file, uint8_t *mem, size_t mem_size, long offset)
{
int res;
unsigned long addr = 0;
if (offset > 0) {
res = fseek(file, offset, SEEK_SET);
if (res < 0) {
perror("Failed to seek to offset in binary file\n");
return -1;
}
} else {
addr = -offset;
}
if (addr >= mem_size) {
fprintf(stderr,"Offset outside memory");
return -1;
}
mem_size -= addr;
res = fread(mem + addr, sizeof(uint8_t), mem_size, file);
if (res < 0) {
perror("Failed to read from binary file\n");
return -1;
}
return 0;
}
static int
read_image(const char *filename, uint8_t *mem, size_t mem_size, long offset)
{
char *suffix;
FILE *file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Failed to open file '%s': %s\n",
filename, strerror(errno));
return -1;
}
suffix = rindex(filename,'.');
if (!suffix) {
fprintf(stderr, "Filename has no suffix\n");
fclose(file);
return -1;
}
suffix++;
if (strcmp(suffix, "ihx") == 0 || strcmp(suffix, "IHX") == 0) {
unsigned int min;
unsigned int max;
if (parse_ihex(file, mem, mem_size, &min, &max) < 0) {
fclose(file);
return -1;
}
} else if (strcmp(suffix, "bin") == 0 || strcmp(suffix, "BIN") == 0) {
if (read_binary(file, mem, mem_size, offset) < 0) {
fclose(file);
return -1;
}
} else {
fprintf(stderr, "Unknown suffix (no .ihx or .bin)\n");
fclose(file);
return -1;
}
fclose(file);
return 0;
}
static int
write_all(int fd, const uint8_t *data, size_t count)
{
size_t full = count;
int w;
while(count > 0) {
w = write(fd, data, count);
/* fprintf(stderr, "Wrote %d\n", w); */
if (w < 0) {
return w;
}
data += w;
count -= w;
}
return full;
}
static int
read_all(int fd, uint8_t *data, size_t count, int timeout)
{
struct pollfd fds;
size_t full = count;
fds.fd = fd;
fds.events = POLLIN;
while(count > 0) {
int r;
r = poll(&fds, 1, timeout);
if (r <= 0) return 0;
r = read(fd, data, count);
if (r <= 0) return r;
count -= r;
data += r;
}
return full;
}
static uint8_t mem[512*1024];
#define MEM_TYPE_INDEX 2
#define RESET_ENABLE_INDEX 3
#define RESET_TIME_INDEX 4
#define EMU_ENA_INDEX 7
#define SELFTEST_INDEX 8
#define CHKSUM_INDEX 12
struct MemType
{
const char *name;
char cmd;
unsigned long size;
};
const struct MemType memory_types[] =
{
{"2764", '0', 8*1024},
{"27128", '1', 16*1024},
{"27256", '2', 32*1024},
{"27512", '3', 64*1024},
{"27010", '4', 128*1024},
{"27020", '5', 256*1024},
{"27040", '6', 512*1024}
};
int
main(int argc, char *argv[])
{
int res;
int fd;
int i;
long offset = 0;
char reset_enable = '0';
int reset_time = 100;
const struct MemType *mem_type = &memory_types[3];
char emu_enable = 'D';
char selftest = 'N';
char *device = "/dev/ttyUSB0";
int opt;
char emu_cmd[16+1];
char emu_reply[16+1];
while((opt = getopt(argc, argv, "hd:m:r:e")) != -1) {
switch(opt) {
case 'd':
device = optarg;
break;
case 'm':
mem_type = NULL;
for (i = 0; i < (sizeof(memory_types) / sizeof(memory_types[0])); i++) {
if (strcmp(optarg, memory_types[i].name) == 0) {
mem_type = &memory_types[i];
break;
}
}
if (!mem_type) {
fprintf(stderr, "Unknown memory type\n");
return EXIT_FAILURE;
}
break;
case 'r':
reset_time = atoi(optarg);
if (reset_time < -255 || reset_time > 255) {
fprintf(stderr, "Reset time out of range\n");
return EXIT_FAILURE;
}
if (reset_time == 0) {
reset_enable = '0';
} else if (reset_time > 0) {
reset_enable = 'P';
} else {
reset_enable = 'N';
reset_time = -reset_time;
}
break;
case 'e':
emu_enable = 'E';
break;
case 'h':
usage();
return EXIT_SUCCESS;
case '?':
return EXIT_FAILURE;
}
}
fd = serial_open(device);
if (fd < 0) return EXIT_FAILURE;
#if 0
/* Identify simulator */
memcpy(emu_cmd, "MI000000000000\r\n",sizeof(emu_cmd));
res = write_all(fd, (uint8_t*)emu_cmd, sizeof(emu_cmd) - 1);
if (res != sizeof(emu_cmd) - 1) {
perror("Failed to write initialization");
}
res = read_all(fd, (uint8_t*)emu_reply, 16, 5000);
if (res == 0) {
fprintf(stderr, "Timeout while waiting for initialization reply\n");
close(fd);
return EXIT_FAILURE;
}
emu_reply[16] = '\0';
printf("Reply: %s\n", emu_reply);
#endif
/* Configuration */
snprintf(emu_cmd, sizeof(emu_cmd), "MC%c%c%03d%c%c00023\r\n",mem_type->cmd,reset_enable, reset_time,emu_enable, selftest);
#if DEBUG
fprintf(stderr, "Config: %s\n", emu_cmd);
#endif
res = write_all(fd, (uint8_t*)emu_cmd, sizeof(emu_cmd) - 1);
if (res != sizeof(emu_cmd) - 1) {
perror("Failed to write configuration");
}
res = read_all(fd, (uint8_t*)emu_reply, 16, 5000);
if (res == 0) {
fprintf(stderr, "Timeout while waiting for configuration reply\n");
close(fd);
return EXIT_FAILURE;
}
if (res != 16) {
perror("Failed to read configuration reply");
close(fd);
return EXIT_FAILURE;
}
#if DEBUG
emu_reply[16] = '\0';
printf("Reply: %s\n", emu_reply);
#endif
if (memcmp(emu_cmd, emu_reply, 8) != 0) {
fprintf(stderr, "Response didn't match command\n");
close(fd);
return EXIT_FAILURE;
}
if (argc > optind) {
res = read_image(argv[optind], mem, mem_type->size, offset);
if (res < 0) {
close(fd);
return EXIT_FAILURE;
}
snprintf(emu_cmd, sizeof(emu_cmd), "MD%04ld00000058\r\n",mem_type->size / 1024);
#ifdef DEBUG
fprintf(stderr, "Data: %s\n", emu_cmd);
#endif
fprintf(stderr, "Writing %ld bytes to simulator...\n", mem_type->size);
res = write_all(fd, (uint8_t*)emu_cmd, sizeof(emu_cmd) - 1);
if (res != sizeof(emu_cmd) - 1) {
perror("Failed to write data header");
}
res = write_all(fd, mem, mem_type->size);
if (res < 0) {
perror("Failed to write data");
close(fd);
return EXIT_FAILURE;
}
res = read_all(fd, (uint8_t*)emu_reply, 16, 15000);
if (res == 0) {
fprintf(stderr, "Timeout while waiting for write operation\n");
close(fd);
return EXIT_FAILURE;
}
if (res != 16) {
perror("Failed to read data reply");
close(fd);
return EXIT_FAILURE;
}
#ifdef DEBUG
emu_reply[16] = '\0';
printf("Reply: %s\n", emu_reply);
#endif
if (memcmp(emu_cmd, emu_reply, 8) != 0) {
fprintf(stderr, "Response didn't match command\n");
close(fd);
return EXIT_FAILURE;
}
fprintf(stderr, "Done\n");
}
close(fd);
return EXIT_SUCCESS;
}