changeset 323:cefa700d1b8f

frbl: beginning of frbl2test
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 05 Mar 2020 22:05:01 +0000
parents 6e442ed0f64d
children 43c92df87ac6
files .hgignore frbl/test/Makefile frbl/test/frbl2.c frbl/test/hexdecode.c frbl/test/main.c frbl/test/srecreader.c frbl/test/srecreader.h frbl/test/ttypassthru.c
diffstat 8 files changed, 446 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu Mar 05 07:09:15 2020 +0000
+++ b/.hgignore	Thu Mar 05 22:05:01 2020 +0000
@@ -27,6 +27,7 @@
 
 ^frbl/reconst/[A-Za-z_0-9]*\.disasm$
 ^frbl/reconst/[A-Za-z_0-9]*\.obj$
+^frbl/test/frbl2test$
 
 ^leo-obj/.*\.ctypes$
 ^leo-obj/.*\.disasm$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/Makefile	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,12 @@
+CC=	gcc
+CFLAGS=	-O2
+PROGS=	frbl2test
+FRBL2_OBJS=	frbl2.o hexdecode.o main.o srecreader.o ttypassthru.o
+
+all:	${PROGS}
+
+frbl2test:	${FRBL2_OBJS}
+	${CC} ${CFLAGS} -o $@ ${FRBL2_OBJS}
+
+clean:
+	rm -f *.o *.out *errs ${PROGS}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/frbl2.c	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,118 @@
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "srecreader.h"
+
+extern char *target_ttydev;
+extern int target_fd;
+extern struct srecreader srimage;
+
+#define	MAX_IMAGE_LEN	32768
+
+static u_char codeimage[MAX_IMAGE_LEN];
+static unsigned codeimage_len;
+static uint32_t loadaddr;
+
+read_srec_image()
+{
+	u_char *writep;
+	uint32_t endaddr;
+	int i;
+
+	if (open_srec_file(&srimage) < 0)
+		exit(1);
+	for (;;) {
+		if (read_s_record(&srimage) < 0)
+			exit(1);
+		switch (srimage.record_type) {
+		case '0':
+			if (srimage.lineno == 1)
+				continue;
+			fprintf(stderr,
+		"%s: S0 record found in line %d (expected in line 1 only)\n",
+				srimage.filename, srimage.lineno);
+			exit(1);
+		case '3':
+		case '7':
+			if (s3s7_get_addr_data(&srimage) < 0)
+				exit(1);
+			break;
+		default:
+			fprintf(stderr,
+				"%s line %d: S%c record type not supported\n",
+				srimage.filename, srimage.lineno,
+				srimage.record_type);
+			exit(1);
+		}
+		if (srimage.record_type == '7')
+			break;
+		/* must be S3 */
+		if (srimage.datalen < 1) {
+			fprintf(stderr,
+				"%s line %d: S3 record has zero data length\n",
+				srimage.filename, srimage.lineno);
+			exit(1);
+		}
+		if (srimage.datalen & 1) {
+			fprintf(stderr,
+				"%s line %d: S3 record has odd data length\n",
+				srimage.filename, srimage.lineno);
+			exit(1);
+		}
+		if (srimage.addr & 1) {
+			fprintf(stderr,
+				"%s line %d: S3 record has odd address\n",
+				srimage.filename, srimage.lineno);
+			exit(1);
+		}
+		/* handle first record */
+		if (!codeimage_len) {
+			endaddr = loadaddr = srimage.addr;
+			writep = codeimage;
+		}
+		if (srimage.addr != endaddr) {
+			fprintf(stderr, "%s line %d: address discontinuity\n",
+				srimage.filename, srimage.lineno);
+			exit(1);
+		}
+		if (codeimage_len + srimage.datalen > MAX_IMAGE_LEN) {
+			fprintf(stderr,
+				"%s line %d: max image length exceeded\n",
+				srimage.filename, srimage.lineno);
+			exit(1);
+		}
+		/* reverse byte order */
+		for (i = 0; i < srimage.datalen; i += 2) {
+			*writep++ = srimage.record[i+6];
+			*writep++ = srimage.record[i+5];
+		}
+		endaddr += srimage.datalen;
+		codeimage_len += srimage.datalen;
+	}
+	/* got S7 */
+	fclose(srimage.openfile);
+	if (!codeimage_len) {
+		fprintf(stderr,
+		"%s line %d: S7 without any preceding S3 data records\n",
+			srimage.filename, srimage.lineno);
+		exit(1);
+	}
+	if (srimage.addr != loadaddr) {
+		fprintf(stderr,
+		"%s line %d: S7 address differs from image load address\n",
+			srimage.filename, srimage.lineno);
+		exit(1);
+	}
+	/* all good */
+	return(0);
+}
+
+frbl_test_main()
+{
+	read_srec_image();
+	/* remainder to be implemented */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/hexdecode.c	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,30 @@
+/*
+ * This module contains the decode_hex_byte() function,
+ * which is used by the SREC file reader and will likely be used
+ * by other code as well, such as the dump-to-file function
+ * of loadtool.
+ */
+
+#include <ctype.h>
+
+decode_hex_byte(s)
+	char *s;
+{
+	register int u, l;
+
+	if (!isxdigit(s[0]) || !isxdigit(s[1]))
+		return(-1);
+	if (isdigit(s[0]))
+		u = s[0] - '0';
+	else if (isupper(s[0]))
+		u = s[0] - 'A' + 10;
+	else
+		u = s[0] - 'a' + 10;
+	if (isdigit(s[1]))
+		l = s[1] - '0';
+	else if (isupper(s[1]))
+		l = s[1] - 'A' + 10;
+	else
+		l = s[1] - 'a' + 10;
+	return((u << 4) | l);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/main.c	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,59 @@
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <termios.h>
+#include <unistd.h>
+#include "srecreader.h"
+
+char *target_ttydev;
+int target_fd;
+int baudrate_code;
+struct termios target_termios;
+struct srecreader srimage;
+
+main(argc, argv)
+	char **argv;
+{
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s ttyport baud image.srec\n", argv[0]);
+		exit(1);
+	}
+	target_ttydev = argv[1];
+	if (!strcmp(argv[2], "115200"))
+		baudrate_code = B115200;
+	else if (!strcmp(argv[2], "230400"))
+		baudrate_code = B230400;
+	else {
+		fprintf(stderr,
+			"error: baud rate argument must be 115200 or 230400\n");
+		exit(1);
+	}
+	srimage.filename = argv[3];
+
+	target_fd = open(target_ttydev, O_RDWR|O_NONBLOCK);
+	if (target_fd < 0) {
+		perror(target_ttydev);
+		exit(1);
+	}
+	ioctl(target_fd, TIOCEXCL);
+	target_termios.c_iflag = IGNBRK;
+	target_termios.c_oflag = 0;
+	target_termios.c_cflag = CLOCAL|HUPCL|CREAD|CS8;
+	target_termios.c_lflag = 0;
+	target_termios.c_cc[VMIN] = 1;
+	target_termios.c_cc[VTIME] = 0;
+	cfsetispeed(&target_termios, baudrate_code);
+	cfsetospeed(&target_termios, baudrate_code);
+	if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) {
+		perror("tcsetattr");
+		exit(1);
+	}
+	frbl_test_main();
+	tty_passthru();
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/srecreader.c	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,106 @@
+/*
+ * This module contains the functions for reading S-record files.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <strings.h>
+#include "srecreader.h"
+
+open_srec_file(sr)
+	struct srecreader *sr;
+{
+	sr->openfile = fopen(sr->filename, "r");
+	if (!sr->openfile) {
+		perror(sr->filename);
+		return(-1);
+	}
+	sr->lineno = 0;
+	return(0);
+}
+
+static
+srec2bin(sr, asciiline)
+	struct srecreader *sr;
+	char *asciiline;
+{
+	register int i, l, b;
+
+	l = decode_hex_byte(asciiline + 2);
+	if (l < 1) {
+		fprintf(stderr, "%s line %d: S-record length octet is bad\n",
+			sr->filename, sr->lineno);
+		return(-1);
+	}
+	sr->record[0] = l;
+	for (i = 1; i <= l; i++) {
+		b = decode_hex_byte(asciiline + i*2 + 2);
+		if (b < 0) {
+			fprintf(stderr,
+				"%s line %d: S-record hex decode error\n",
+				sr->filename, sr->lineno);
+			return(-1);
+		}
+		sr->record[i] = b;
+	}
+	return(0);
+}
+
+static
+srec_cksum(sr)
+	struct srecreader *sr;
+{
+	u_char accum;
+	register int i, len;
+
+	len = sr->record[0] + 1;
+	accum = 0;
+	for (i = 0; i < len; i++)
+		accum += sr->record[i];
+	if (accum != 0xFF) {
+		fprintf(stderr, "%s line %d: bad S-record checksum\n",
+			sr->filename, sr->lineno);
+		return(-1);
+	}
+	return(0);
+}
+
+read_s_record(sr)
+	struct srecreader *sr;
+{
+	char asciiline[1024];
+
+	if (!fgets(asciiline, sizeof asciiline, sr->openfile)) {
+		fprintf(stderr, "%s: premature EOF after %d S-records\n",
+			sr->filename, sr->lineno);
+		return(-1);
+	}
+	sr->lineno++;
+	if (asciiline[0] != 'S' || !isdigit(asciiline[1])) {
+		fprintf(stderr, "%s line %d: S-record expected\n",
+			sr->filename, sr->lineno);
+		return(-1);
+	}
+	sr->record_type = asciiline[1];
+	if (srec2bin(sr, asciiline) < 0)
+		return(-1);
+	return srec_cksum(sr);
+}
+
+s3s7_get_addr_data(sr)
+	struct srecreader *sr;
+{
+	if (sr->record[0] < 5) {
+		fprintf(stderr, "%s line %d: S%c record is too short\n",
+			sr->filename, sr->lineno, sr->record_type);
+		return(-1);
+	}
+	sr->datalen = sr->record[0] - 5;
+	sr->addr = ((uint32_t)sr->record[1] << 24) |
+		   ((uint32_t)sr->record[2] << 16) |
+		   ((uint32_t)sr->record[3] << 8) |
+		    (uint32_t)sr->record[4];
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/srecreader.h	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,11 @@
+/* this header file defines the data structures for the SREC reader module */
+
+struct srecreader {
+	char		*filename;
+	FILE		*openfile;
+	int		lineno;
+	u_char		record[256];	/* binary */
+	char		record_type;	/* ASCII char */
+	u_char		datalen;
+	uint32_t	addr;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frbl/test/ttypassthru.c	Thu Mar 05 22:05:01 2020 +0000
@@ -0,0 +1,109 @@
+/*
+ * This module implements the pass-thru operation mode, in which
+ * the Unix host tty is cross-connected directly to the target
+ * running some code we have just loaded.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <termios.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+
+extern int errno;
+
+extern int target_fd;
+
+static struct termios saved_termios, my_termios;
+
+static void
+safe_output(buf, cc)
+	u_char *buf;
+{
+	int i, c;
+
+	for (i = 0; i < cc; i++) {
+		c = buf[i];
+		if (c == '\r' || c == '\n' || c == '\t' || c == '\b') {
+			putchar(c);
+			continue;
+		}
+		if (c & 0x80) {
+			putchar('M');
+			putchar('-');
+			c &= 0x7F;
+		}
+		if (c < 0x20) {
+			putchar('^');
+			putchar(c + '@');
+		} else if (c == 0x7F) {
+			putchar('^');
+			putchar('?');
+		} else
+			putchar(c);
+	}
+	fflush(stdout);
+}
+
+static void
+loop()
+{
+	char buf[BUFSIZ];
+	fd_set fds, fds1;
+	register int i, cc, max;
+
+	FD_ZERO(&fds);
+	FD_SET(0, &fds);
+	FD_SET(target_fd, &fds);
+	max = target_fd + 1;
+	for (;;) {
+		bcopy(&fds, &fds1, sizeof(fd_set));
+		i = select(max, &fds1, NULL, NULL, NULL);
+		if (i < 0) {
+			if (errno == EINTR)
+				continue;
+			tcsetattr(0, TCSAFLUSH, &saved_termios);
+			perror("select");
+			exit(1);
+		}
+		if (FD_ISSET(0, &fds1)) {
+			cc = read(0, buf, sizeof buf);
+			if (cc <= 0)
+				return;
+			if (cc == 1 && buf[0] == 0x1C)
+				return;
+			write(target_fd, buf, cc);
+		}
+		if (FD_ISSET(target_fd, &fds1)) {
+			cc = read(target_fd, buf, sizeof buf);
+			if (cc <= 0) {
+				tcsetattr(0, TCSAFLUSH, &saved_termios);
+				fprintf(stderr, "EOF/error on target tty\n");
+				exit(1);
+			}
+			safe_output(buf, cc);
+		}
+	}
+}
+
+tty_passthru()
+{
+	static int zero = 0;
+
+	ioctl(target_fd, FIONBIO, &zero);
+
+	tcgetattr(0, &saved_termios);
+	bcopy(&saved_termios, &my_termios, sizeof(struct termios));
+	cfmakeraw(&my_termios);
+	my_termios.c_cc[VMIN] = 1;
+	my_termios.c_cc[VTIME] = 0;
+	tcsetattr(0, TCSAFLUSH, &my_termios);
+
+	printf("Entering tty pass-thru; type ^\\ to exit\r\n\n");
+	loop();
+	tcsetattr(0, TCSAFLUSH, &saved_termios);
+	return 0;
+}