/*
|
/*
|
* load.c -- load S-records from serial line
|
* load.c -- load S-records from serial line
|
*/
|
*/
|
|
|
|
|
#include "common.h"
|
#include "common.h"
|
#include "stdarg.h"
|
#include "stdarg.h"
|
#include "romlib.h"
|
#include "romlib.h"
|
#include "load.h"
|
#include "load.h"
|
#include "serial.h"
|
#include "serial.h"
|
#include "cpu.h"
|
#include "cpu.h"
|
#include "mmu.h"
|
#include "mmu.h"
|
|
|
|
|
#define NUM_TRIES 10
|
#define NUM_TRIES 10
|
#define WAIT_DELAY 350000
|
#define WAIT_DELAY 350000
|
|
|
#define SYN ((unsigned char) 's')
|
#define SYN ((unsigned char) 's')
|
#define ACK ((unsigned char) 'a')
|
#define ACK ((unsigned char) 'a')
|
|
|
#define LINE_SIZE 520
|
#define LINE_SIZE 520
|
|
|
|
|
static Byte line[LINE_SIZE];
|
static Byte line[LINE_SIZE];
|
|
|
|
|
static Word getByte(int index) {
|
static Word getByte(int index) {
|
Word hi, lo;
|
Word hi, lo;
|
|
|
hi = line[index + 0];
|
hi = line[index + 0];
|
if (hi >= '0' && hi <= '9') {
|
if (hi >= '0' && hi <= '9') {
|
hi -= '0';
|
hi -= '0';
|
} else
|
} else
|
if (hi >= 'A' && hi <= 'F') {
|
if (hi >= 'A' && hi <= 'F') {
|
hi -= 'A' - 10;
|
hi -= 'A' - 10;
|
} else
|
} else
|
if (hi >= 'a' && hi <= 'f') {
|
if (hi >= 'a' && hi <= 'f') {
|
hi -= 'a' - 10;
|
hi -= 'a' - 10;
|
} else {
|
} else {
|
return -1;
|
return (Word) -1;
|
}
|
}
|
lo = line[index + 1];
|
lo = line[index + 1];
|
if (lo >= '0' && lo <= '9') {
|
if (lo >= '0' && lo <= '9') {
|
lo -= '0';
|
lo -= '0';
|
} else
|
} else
|
if (lo >= 'A' && lo <= 'F') {
|
if (lo >= 'A' && lo <= 'F') {
|
lo -= 'A' - 10;
|
lo -= 'A' - 10;
|
} else
|
} else
|
if (lo >= 'a' && lo <= 'f') {
|
if (lo >= 'a' && lo <= 'f') {
|
lo -= 'a' - 10;
|
lo -= 'a' - 10;
|
} else {
|
} else {
|
return -1;
|
return (Word) -1;
|
}
|
}
|
return (hi << 4) | lo;
|
return (hi << 4) | lo;
|
}
|
}
|
|
|
|
|
static void serialOut(int serno, Word c) {
|
static void serialOut(int serno, Word c) {
|
if (serno == 0) {
|
if (serno == 0) {
|
ser0out(c);
|
ser0out(c);
|
} else {
|
} else {
|
ser1out(c);
|
ser1out(c);
|
}
|
}
|
}
|
}
|
|
|
|
|
static int serialChk(int serno) {
|
static int serialChk(int serno) {
|
if (serno == 0) {
|
if (serno == 0) {
|
return ser0inchk();
|
return ser0inchk();
|
} else {
|
} else {
|
return ser1inchk();
|
return ser1inchk();
|
}
|
}
|
}
|
}
|
|
|
|
|
static Word serialIn(int serno) {
|
static Word serialIn(int serno) {
|
if (serno == 0) {
|
if (serno == 0) {
|
return ser0in();
|
return ser0in();
|
} else {
|
} else {
|
return ser1in();
|
return ser1in();
|
}
|
}
|
}
|
}
|
|
|
|
|
void load(int serno, Bool start) {
|
void load(int serno, Bool start) {
|
int i, j;
|
int i, j;
|
Bool run;
|
Bool run;
|
int type;
|
int type;
|
int count;
|
int count;
|
Word chksum;
|
Word chksum;
|
Word addr;
|
Word addr;
|
Byte b;
|
Byte b;
|
|
|
printf("Trying to connect to load server...\n");
|
printf("Trying to connect to load server...\n");
|
for (i = 0; i < NUM_TRIES; i++) {
|
for (i = 0; i < NUM_TRIES; i++) {
|
serialOut(serno, SYN);
|
serialOut(serno, SYN);
|
for (j = 0; j < WAIT_DELAY; j++) {
|
for (j = 0; j < WAIT_DELAY; j++) {
|
if (serialChk(serno) != 0) {
|
if (serialChk(serno) != 0) {
|
break;
|
break;
|
}
|
}
|
}
|
}
|
if (j < WAIT_DELAY) {
|
if (j < WAIT_DELAY) {
|
break;
|
break;
|
}
|
}
|
printf("Request timed out...\n");
|
printf("Request timed out...\n");
|
}
|
}
|
if (i == NUM_TRIES ||
|
if (i == NUM_TRIES ||
|
serialIn(serno) != ACK) {
|
serialIn(serno) != ACK) {
|
printf("Unable to establish connection to load server.\n");
|
printf("Unable to establish connection to load server.\n");
|
return;
|
return;
|
}
|
}
|
serialOut(serno, ACK);
|
serialOut(serno, ACK);
|
printf("Connected to load server.\n");
|
printf("Connected to load server.\n");
|
run = true;
|
run = true;
|
while (run) {
|
while (run) {
|
serialOut(serno, 'r');
|
serialOut(serno, 'r');
|
for (i = 0; i < LINE_SIZE; i++) {
|
for (i = 0; i < LINE_SIZE; i++) {
|
line[i] = serialIn(serno);
|
line[i] = serialIn(serno);
|
if (line[i] == '\n') {
|
if (line[i] == '\n') {
|
break;
|
break;
|
}
|
}
|
}
|
}
|
if (i == LINE_SIZE) {
|
if (i == LINE_SIZE) {
|
printf("Error: too many characters in S-record!\n");
|
printf("Error: too many characters in S-record!\n");
|
break;
|
break;
|
}
|
}
|
line[i] = '\0';
|
line[i] = '\0';
|
printf("%s\n", line);
|
printf("%s\n", line);
|
if (line[0] != 'S') {
|
if (line[0] != 'S') {
|
printf("Error: malformed S-record!\n");
|
printf("Error: malformed S-record!\n");
|
break;
|
break;
|
}
|
}
|
type = line[1];
|
type = line[1];
|
count = getByte(2);
|
count = getByte(2);
|
if (i != 2 * count + 4) {
|
if (i != 2 * count + 4) {
|
printf("Error: inconsistent byte count in S-record!\n");
|
printf("Error: inconsistent byte count in S-record!\n");
|
break;
|
break;
|
}
|
}
|
chksum = 0;
|
chksum = 0;
|
for (j = 2; j < i; j += 2) {
|
for (j = 2; j < i; j += 2) {
|
chksum += getByte(j);
|
chksum += getByte(j);
|
}
|
}
|
if ((chksum & 0xFF) != 0xFF) {
|
if ((chksum & 0xFF) != 0xFF) {
|
printf("Error: wrong checksum in S-record!\n");
|
printf("Error: wrong checksum in S-record!\n");
|
break;
|
break;
|
}
|
}
|
switch (type) {
|
switch (type) {
|
case '0':
|
case '0':
|
/* S0 record: header (skip) */
|
/* S0 record: header (skip) */
|
break;
|
break;
|
case '1':
|
case '1':
|
/* S1 record: 2 byte load address + data (load data) */
|
/* S1 record: 2 byte load address + data (load data) */
|
addr = (getByte( 4) << 8) |
|
addr = (getByte( 4) << 8) |
|
(getByte( 6) << 0);
|
(getByte( 6) << 0);
|
addr |= 0xC0000000;
|
addr |= 0xC0000000;
|
for (j = 0; j < count - 3; j++) {
|
for (j = 0; j < count - 3; j++) {
|
b = getByte(2 * j + 8);
|
b = getByte(2 * j + 8);
|
mmuWriteByte(addr + j, b);
|
mmuWriteByte(addr + j, b);
|
}
|
}
|
break;
|
break;
|
case '2':
|
case '2':
|
/* S2 record: 3 byte load address + data (load data) */
|
/* S2 record: 3 byte load address + data (load data) */
|
addr = (getByte( 4) << 16) |
|
addr = (getByte( 4) << 16) |
|
(getByte( 6) << 8) |
|
(getByte( 6) << 8) |
|
(getByte( 8) << 0);
|
(getByte( 8) << 0);
|
addr |= 0xC0000000;
|
addr |= 0xC0000000;
|
for (j = 0; j < count - 4; j++) {
|
for (j = 0; j < count - 4; j++) {
|
b = getByte(2 * j + 10);
|
b = getByte(2 * j + 10);
|
mmuWriteByte(addr + j, b);
|
mmuWriteByte(addr + j, b);
|
}
|
}
|
break;
|
break;
|
case '3':
|
case '3':
|
/* S3 record: 4 byte load address + data (load data) */
|
/* S3 record: 4 byte load address + data (load data) */
|
addr = (getByte( 4) << 24) |
|
addr = (getByte( 4) << 24) |
|
(getByte( 6) << 16) |
|
(getByte( 6) << 16) |
|
(getByte( 8) << 8) |
|
(getByte( 8) << 8) |
|
(getByte(10) << 0);
|
(getByte(10) << 0);
|
addr |= 0xC0000000;
|
addr |= 0xC0000000;
|
for (j = 0; j < count - 5; j++) {
|
for (j = 0; j < count - 5; j++) {
|
b = getByte(2 * j + 12);
|
b = getByte(2 * j + 12);
|
mmuWriteByte(addr + j, b);
|
mmuWriteByte(addr + j, b);
|
}
|
}
|
break;
|
break;
|
case '5':
|
case '5':
|
/* S5 record: record count (skip) */
|
/* S5 record: record count (skip) */
|
break;
|
break;
|
case '7':
|
case '7':
|
/* S7 record: 4 byte start address (set PC, stop loading) */
|
/* S7 record: 4 byte start address (set PC, stop loading) */
|
addr = (getByte( 4) << 24) |
|
addr = (getByte( 4) << 24) |
|
(getByte( 6) << 16) |
|
(getByte( 6) << 16) |
|
(getByte( 8) << 8) |
|
(getByte( 8) << 8) |
|
(getByte(10) << 0);
|
(getByte(10) << 0);
|
addr |= 0xC0000000;
|
addr |= 0xC0000000;
|
cpuSetPC(addr);
|
cpuSetPC(addr);
|
run = false;
|
run = false;
|
break;
|
break;
|
case '8':
|
case '8':
|
/* S8 record: 3 byte start address (set PC, stop loading) */
|
/* S8 record: 3 byte start address (set PC, stop loading) */
|
addr = (getByte( 4) << 16) |
|
addr = (getByte( 4) << 16) |
|
(getByte( 6) << 8) |
|
(getByte( 6) << 8) |
|
(getByte( 8) << 0);
|
(getByte( 8) << 0);
|
addr |= 0xC0000000;
|
addr |= 0xC0000000;
|
cpuSetPC(addr);
|
cpuSetPC(addr);
|
run = false;
|
run = false;
|
break;
|
break;
|
case '9':
|
case '9':
|
/* S9 record: 2 byte start address (set PC, stop loading) */
|
/* S9 record: 2 byte start address (set PC, stop loading) */
|
addr = (getByte( 4) << 8) |
|
addr = (getByte( 4) << 8) |
|
(getByte( 6) << 0);
|
(getByte( 6) << 0);
|
addr |= 0xC0000000;
|
addr |= 0xC0000000;
|
cpuSetPC(addr);
|
cpuSetPC(addr);
|
run = false;
|
run = false;
|
break;
|
break;
|
default:
|
default:
|
/* unknown type of S-record */
|
/* unknown type of S-record */
|
printf("Error: unknown type of S-record!\n");
|
printf("Error: unknown type of S-record!\n");
|
run = false;
|
run = false;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
serialOut(serno, 'q');
|
serialOut(serno, 'q');
|
printf("Connection to load server closed.\n");
|
printf("Connection to load server closed.\n");
|
if (start) {
|
if (start) {
|
cpuRun();
|
cpuRun();
|
}
|
}
|
}
|
}
|
|
|