This initial commit adds speed8 and the hpgl plotting program.
Signed-off-by: Philipp Hachtmann <hachti@hachti.de>
--- /dev/null
+*~
+*.o
+*.d
+tmp
--- /dev/null
+
+all: default
+
+default: hpgl
+
+CFLAGS=-Wall -g
+LDFLAGS=-g -lm
+
+hpgl: hpgl.o optimize.o
+ gcc ${LDFLAGS} -o $@ $^
+
+hpgl.o: hpgl.c hpgl.h optimize.h
+ gcc ${CFLAGS} -c -o $@ $<
+
+optimize.o: optimize.c optimize.h
+ gcc ${CFLAGS} -c -o $@ $<
+
+clean:
+ @echo CLEAN
+ @rm -f *.o *~ hpgl
+
+.PHONY: default all clean
+
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/* #define DEBUG */
+
+#include "hpgl.h"
+#include "optimize.h"
+
+#define BUFFER_SIZE (32*1024*1024)
+
+static char data[BUFFER_SIZE];
+static int data_size;
+static int data_left;
+
+/*********************************++
+ *
+ * Read input data into a buffer
+ *
+ */
+static void read_file(int fd){
+ int res=0;
+ data_size=0;
+ while ((res=read(fd,data+data_size,BUFFER_SIZE-1-data_size))) data_size+=res;
+ data_left=data_size;
+ DBG("Read %i bytes.\n",data_left);
+}
+
+static int comp(char ** pptr, char * b){
+ char * ptr= *pptr;
+ if (strncmp(ptr,b,strlen(b))==0){
+ (*pptr)+=strlen(b);
+ data_left-=strlen(b);
+ return 1;
+ } else return 0;
+}
+
+static struct point * get_point(char ** pptr){
+ char * ptr2;
+ struct point *result = (struct point *)malloc(sizeof(struct point));
+ result->valid=1;
+ result->x=strtold(*pptr,&ptr2);
+ if (ptr2==*pptr) result->valid=0;
+ else {
+ *pptr=ptr2;
+ *pptr=index(*pptr,',')+1;
+ result->y=strtold(*pptr,&ptr2);
+ if (ptr2==*pptr) result->valid=0;
+ else *pptr=ptr2;
+ }
+ result->next=NULL;
+ result->previous_in_path=NULL;
+
+ if (result->valid)
+ (*pptr)++; /* Step over comma between point specs! */
+ return result;
+}
+
+static void output (struct path * first_path){
+ struct point * last_point=NULL;
+ struct path * current_path;
+
+ for (current_path=first_path; current_path != NULL;
+ current_path=current_path->next){
+
+ struct point * current_point;
+
+ /* Initial move to start of plot */
+ current_point=current_path->plot_start_point;
+ if (!equal(current_point,last_point)) {
+ printf("PU, %.2f,%.2f\n",current_point->x,current_point->y);
+ }
+
+ if (current_path->plot_start_point
+ == current_path->first_point){ /* Forward */
+
+ for (current_point=current_point->next; current_point != NULL;
+ current_point=current_point->next) {
+ if (!equal(current_point,last_point)) {
+ printf("PD, %.2f,%.2f\n",current_point->x,current_point->y);
+ }
+ last_point=current_point;
+ }
+ } else { /* Going backwards */
+ for (current_point=current_point->previous_in_path; current_point != NULL;
+ current_point=current_point->previous_in_path) {
+ if (!equal(current_point,last_point)) {
+ printf("PD, %.2f,%.2f\n",current_point->x,current_point->y);
+ }
+ last_point=current_point;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * *
+ * main() *
+ * *
+ *******************************************************************************
+ */
+int main(int argc, char ** args){
+
+ int fd=0; /* File descriptor for data input, defaults to standard input */
+
+ char * ptr=data; /* Input buffer */
+ enum plot_mode_t plot_mode=absolute; /* Coordinate modus */
+ enum pen_state_t pen_state=up;
+
+ struct point pen_pos={0,0,1};
+
+ double character_angle=0;
+ double character_size=40;
+
+ struct path * first_path=NULL;
+ struct path * current_path=NULL;
+
+ int in_path=0;
+
+ enum hpgl_cmd_t command; /* Current command being processed */
+
+ DBG("Start\n");
+
+ /* Open input file to read if specified. */
+ if (argc>1){
+ fd=open(args[1],O_RDONLY);
+ if (fd < 0){
+ ERR("Could not open file: \"%s\"\n",args[1]);
+ exit (-2);
+ }
+ }
+ /* fd=open("haus.hpl",O_RDONLY); */
+ read_file(fd);
+
+
+
+ /* Main-Loop */
+ while(data_left){
+ while(data_left-3 && isspace(ptr[0])) ptr++;
+
+ /* Determine command */
+ command=0;
+ if (comp(&ptr, "SC")) command=CMD_SC;
+ if (comp(&ptr, "PU")) command=CMD_PU;
+ if (comp(&ptr, "PD")) command=CMD_PD;
+ if (comp(&ptr, "LB")) command=CMD_LB;
+ if (comp(&ptr, "DI")) command=CMD_DI;
+ if (comp(&ptr, "SP")) command=CMD_SP;
+ if (comp(&ptr, "PA")) command=CMD_PA;
+ if (comp(&ptr, "PR")) command=CMD_PR;
+ if (comp(&ptr, "IN")) command=CMD_IN;
+ if (command==0) {data_left-- ; ptr++;}
+ else DBG("Command: %i %c%c\n",command,ptr[-2],ptr[-1]);
+
+ int process_points=0;
+ switch(command){
+
+ case CMD_NO_COMMAND:
+ break;
+ case CMD_PU: /* Pen up - not much to do here. */
+ pen_state=up;
+ in_path=0;
+ process_points=1;
+ break;
+
+ case CMD_PD:
+ pen_state=down;
+ if (!in_path){ /* Create and store a new path object with first point @pen_pos. */
+
+ struct point * new_point=(struct point *)malloc(sizeof(struct point));
+ new_point->x=pen_pos.x;
+ new_point->y=pen_pos.y;
+ new_point->next=NULL;
+ new_point->previous_in_path=NULL;
+ new_point->valid=1;
+
+ struct path * new_path=(struct path *)malloc(sizeof(struct path));
+ new_path->next=NULL; /* This is the last in the chain. */
+ new_path->first_point=new_point;
+ new_path->last_point=new_point;
+ new_path->plot_start_point=new_path->first_point;
+
+ if (first_path==NULL){ /* This is the first path */
+ first_path=new_path;
+ } else {
+ current_path->next=new_path; /* Append to linked list */
+ }
+ current_path=new_path; /* Update pointer to current path. */
+ in_path=1; /* We're in a path now, fine! */
+ }
+ process_points=1;
+ break;
+
+ case CMD_SC:
+ break;
+
+ case CMD_IN:
+ plot_mode=absolute;
+ pen_pos.x=0;
+ pen_pos.y=0;
+ pen_pos.valid=1;
+ character_angle=0;
+ character_size=40;
+ pen_state=up;
+ break;
+
+ case CMD_LB:
+ break;
+ case CMD_DI: /* Character direction */
+ break;
+ case CMD_SI: /* Character size */
+ break;
+ case CMD_SP: /* Select pen */
+ break;
+ case CMD_PA:
+ process_points=1;
+ plot_mode=absolute;
+ break;
+ case CMD_PR:
+ process_points=1;
+ plot_mode=relative;
+ break;
+ }
+
+ if (process_points) { /* Process point arguments */
+ struct point * new_point;
+ do{
+ new_point=get_point(&ptr);
+
+ if (new_point->valid) { /* The following only works if we got a good point! */
+
+ /* Scale: Plot in cm!! */
+ new_point->x = new_point->x / 500;
+ new_point->y = new_point->y / 500;
+
+ DBG("Found point: %6.2f,%6.2f\n",new_point->x,new_point->y);
+
+ /* Convert relative coordinates to absolute coordinates if needed */
+ if (plot_mode==relative){
+ DBG("Relative -> absolute coordinate calculation!\n");
+ new_point->x += pen_pos.x;
+ new_point->y += pen_pos.y;
+ }
+
+ if (pen_state==down) { /* We're in a path, so add the point to current path */
+ current_path->last_point->next=new_point; /* Add to the end of list */
+ new_point->previous_in_path=current_path->last_point; /* Backwards reference */
+ current_path->last_point=new_point; /* Fix the point */
+ }
+ pen_pos.x=new_point->x;
+ pen_pos.y=new_point->y;
+
+ }
+ } while (new_point->valid);
+ }
+
+ } /* while(data_left) */
+
+ struct path * output_paths;
+
+ round_path(first_path);
+
+ /* output_paths = optimize(first_path); */
+ output_paths=optimize(split_paths(first_path));
+ output(output_paths);
+ DBG("Programmende\n");
+ return 0;
+}
--- /dev/null
+#ifndef HPGL_H
+#define HPGL_H
+#include <stdio.h>
+
+struct point {
+ double x;
+ double y;
+ int valid;
+ struct point * next;
+ struct point * previous_in_path;
+};
+
+struct path {
+ struct point * first_point;
+ struct point * last_point;
+ struct point * plot_start_point;
+ struct point * plot_end_point;
+ struct path * next;
+
+ /* Internal special stuff */
+ double dist;
+ struct path *back;
+
+ //int done;
+};
+
+enum hpgl_cmd_t {
+ CMD_NO_COMMAND,
+ CMD_PU,
+ CMD_PD,
+ CMD_SC,
+ CMD_IN,
+ CMD_LB,
+ CMD_DI,
+ CMD_SI,
+ CMD_SP,
+ CMD_PA,
+ CMD_PR };
+
+ enum plot_mode_t {absolute, relative};
+ enum pen_state_t {up,down};
+
+
+#ifdef DEBUG
+
+#define POS {fprintf(stderr,"(%s, %i) %20s(): ",__FILE__, __LINE__,__FUNCTION__);}
+#define DBG(...) {POS; fprintf(stderr, "*** DEBUG: " __VA_ARGS__);}
+#define ERR(...) {POS; fprintf(stderr, "*** ERROR: " __VA_ARGS__); exit(-1); }
+
+#else
+#define POS {}
+#define DBG(...) {}
+#define ERR(...) {}
+#endif
+
+
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+//#define DEBUG
+#include "hpgl.h"
+
+/*
+ * Get plotting distance between points.
+ * Distances of X and Y are calculated. The longer one
+ * is returned. This applies to plotters that can do
+ * diagonal steps. In that case the shorter distance is "hidden"
+ * and doesn't consume time. If the plotter is unable to do diagonal
+ * steps the sum of both distances must be returned.
+ */
+double plot_distance(struct point *a, struct point *b){
+ // double dist_x = (a->x>b->x?a->x-b->x:b->x-a->x);
+ //double dist_y = (a->y>b->y?a->y-b->y:b->y-a->y);
+ //return (dist_x > dist_y?dist_x:dist_y);
+ double dist_x = fabs(a->x - b->x);
+ double dist_y = fabs(a->y - b->y);
+ return (dist_x > dist_y ? dist_x:dist_y);
+}
+
+static double path_distance(struct point *point, struct path *path){
+ double forward_dist=plot_distance(point, path->first_point);
+ double reverse_dist=plot_distance(point, path->last_point);
+
+ if (reverse_dist < forward_dist){
+ path->plot_start_point=path->last_point;
+ path->plot_end_point=path->first_point;
+ return reverse_dist;
+ } else {
+ path->plot_start_point=path->first_point;
+ path->plot_end_point=path->last_point;
+ return forward_dist;
+ }
+}
+
+double OLDpath_distance(struct point *origin, struct path *candidate){
+ double forward_dist=plot_distance(origin, candidate->first_point);
+ double reverse_dist=plot_distance(origin, candidate->last_point);
+ if (reverse_dist < forward_dist){
+ candidate->plot_start_point=candidate->last_point;
+ candidate->plot_end_point=candidate->first_point;
+ return reverse_dist;
+ } else {
+ candidate->plot_start_point=candidate->first_point;
+ candidate->plot_end_point=candidate->last_point;
+ return forward_dist;
+ }
+}
+
+int equal(struct point *a, struct point *b){
+ if ((a==NULL)||(b==NULL)) return 0;
+ if ((a->x == b->x) &&( a->y == b->y)) return 1;
+ else return 0;
+}
+
+static void link_reverse(struct path *path){
+ struct path *cur;
+ if (!path) return;
+ for (cur = path; cur->next; cur = cur->next)
+ cur->next->back = cur;
+}
+
+static void remove_path(struct path **target, struct path *path){
+
+ if (path == *target){ /* First element! */
+ *target = path->next;
+ return;
+ }
+ path->back->next = path->next;
+ if (path->next)
+ path->next->back = path->back;
+}
+
+struct path *optimize(struct path *input_list){
+ struct point __point;
+ __point.x=0;
+ __point.y=0;
+
+ struct point *point = &__point;
+ struct path *result = NULL;
+ struct path *result_last;
+ struct path *cur, *best;
+ int i;
+
+ link_reverse(input_list);
+ // DBG("link_reverse done\n");
+
+ i=0;
+ for (cur = input_list; cur; cur = cur->next)
+ DBG("%4i Input Path (%5.2f,%5.2f) -> (%5.2f,%5.2f)\n",
+ i++,
+ cur->plot_start_point->x,
+ cur->plot_start_point->y,
+ cur->plot_end_point->x,
+ cur->plot_end_point->y
+ );
+
+ while(input_list) {
+ best = NULL;
+ for (cur = input_list; cur; cur = cur->next) {
+ cur->dist = path_distance(point, cur);
+ if ((!best)||(cur->dist < best->dist)) {
+ best = cur;
+ /*
+ DBG("cur->dist = %5.2f, best->dist = %5.2f\n",
+ cur->dist, best->dist);
+ DBG("Cur Path (%5.2f,%5.2f) -> (%5.2f,%5.2f)\n",
+ cur->plot_start_point->x,
+ cur->plot_start_point->y,
+ cur->plot_end_point->x,
+ cur->plot_end_point->y
+ );
+ */
+
+ }
+ }
+ point = best->plot_end_point;
+
+ DBG("xbest Path (%5.2f,%5.2f) -> (%5.2f,%5.2f)\n",
+ best->plot_start_point->x,
+ best->plot_start_point->y,
+ best->plot_end_point->x,
+ best->plot_end_point->y
+ );
+
+ /* Take best result */
+ remove_path(&input_list, best);
+
+ if (!result) {
+ result = best;
+ } else {
+ result_last->next = best;
+ }
+ result_last = best;
+ result_last->next = NULL;
+ }
+
+#ifdef DEBUG
+ i = 0;
+ for (cur = result; cur; cur = cur->next)
+ DBG("%4i Path (%5.2f,%5.2f) -> (%5.2f,%5.2f)\n",
+ i++,
+ cur->plot_start_point->x,
+ cur->plot_start_point->y,
+ cur->plot_end_point->x,
+ cur->plot_end_point->y
+ );
+#endif
+
+ return result;
+}
+
+
+struct path *single_stroke_path(struct point *a, struct point *b){
+ struct path *result=(struct path *)malloc(sizeof(struct path));
+
+ struct point *aa=(struct point *)malloc(sizeof(struct point));
+ struct point *bb=(struct point *)malloc(sizeof(struct point));
+ memcpy(aa,a,sizeof(struct point));
+ memcpy(bb,b,sizeof(struct point));
+ aa->next=bb;
+ bb->next=NULL;
+ aa->previous_in_path=NULL;
+ bb->previous_in_path=aa;
+
+ result->next=NULL;
+ result->first_point=aa;
+ result->plot_start_point=aa;
+ result->last_point=bb;
+ result->plot_end_point=bb;
+ return result;
+}
+
+
+struct path *split_paths(struct path *source){
+ struct path *result=NULL;
+ struct path *last_result=NULL;
+
+ struct path *current_path;
+ for (current_path=source; current_path!=NULL; current_path=current_path->next){
+
+ struct point *current_point;
+
+ for (current_point=current_path->first_point; current_point->next!=NULL;
+ current_point=current_point->next){
+ struct path*tmp=single_stroke_path(current_point,current_point->next);
+ if (result==NULL){
+ result=tmp;
+ last_result=tmp;
+ } else {
+ last_result->next=tmp;
+ last_result=last_result->next;
+ }
+
+ }
+ }
+ return result;
+}
+
+
+void round_path(struct path *source){
+ struct path *current_path;
+ for (current_path=source; current_path!=NULL; current_path=current_path->next){
+ struct point *current_point;
+
+ for (current_point=current_path->first_point; current_point!=NULL;
+ current_point=current_point->next){
+ current_point->x=round(current_point->x*100.0)/100.0;
+ current_point->y=round(current_point->y*100.0)/100.0;
+ }
+ }
+}
--- /dev/null
+
+#ifndef OPTIMIZE_H
+#define OPTIMIZE_H
+
+extern struct path *optimize(struct path *first_path);
+struct path *split_paths(struct path *source);
+struct path *join_paths(struct path *source);
+extern void round_path(struct path *input);
+extern int equal(struct point *a, struct point *b);
+
+#endif
--- /dev/null
+C PHILIPP'S FILE PLOTTER 2010!\r
+\r
+0100 DIMENSION NAME(3)\r
+\r
+C 565 0.01 INCH, DATA IN CM\r
+ CALL PLOTS(0.0254,0)\r
+\r
+C CALL PLOTS(0.004,0)\r
+\r
+0150 XMAX=0\r
+0200 WRITE (4,300)\r
+0300 FORMAT (' FILE TO PLOT:')\r
+0400 READ (4,600) NAME\r
+0500 CALL USR(5,NAME,2,ERR)\r
+0501 IF (NAME(1) .EQ. ' ') GO TO 200 \r
+0600 FORMAT (3A6)\r
+\r
+\r
+\r
+1200 CALL CHKEOF(EOF)\r
+1300 READ (5,1000) PEN,X,Y\r
+1000 FORMAT (A3,2F13.5)\r
+1500 IF (EOF.NE.0) GO TO 7000\r
+\r
+C ROTATE\r
+C TMP=Y\r
+C Y=-X\r
+C X=-TMP\r
+\r
+ TMP=Y\r
+ Y=-X\r
+ X=TMP\r
+\r
+2000 IF (PEN.EQ.'PU,') P=3\r
+2100 IF (PEN.EQ.'PD,') P=2\r
+ IF (X.GE.XMAX) XMAX=X\r
+ CALL XYPLOT(X,Y,P)\r
+\r
+1700 GO TO 1200\r
+\r
+7000 CALL XYPLOT(XMAX+1,0,-3);\r
+ CALL PLEXIT\r
+\r
+9999 GO TO 150\r
+\r
--- /dev/null
+rktool
\ No newline at end of file
--- /dev/null
+
+
+RKTOOL_OBJS=rk05.o link.o memory.o log.o rktool.o
+
+CFLAGS=-Wall
+LDFLAGS=-lm
+
+rktool: $(RKTOOL_OBJS)
+ @echo LD $@
+ @$(CC) $(LDFLAGS) -o $@ $^
+
+%.o:%.c
+ @echo CC $@
+ @$(CC) $(CFLAGS) -c -o $@ $^
+
+
+clean:
+ @echo CLEAN
+ @rm -f *.o rktool *~
+
+.PHONY: clean
--- /dev/null
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <termios.h>
+
+#include "link.h"
+#include "log.h"
+
+static int fd=-1;
+static struct termios org_settings;
+static struct termios work_settings;
+
+int link_open(char * port){
+ int res;
+ fd=open(port,O_RDWR);
+ if (fd<0) return -1;
+
+ res=tcgetattr(fd,&org_settings);
+ if (res!=0) return -1;
+
+ res=tcgetattr(fd,&work_settings);
+ if (res!=0) return -1;
+
+ cfmakeraw(&work_settings);
+ res=tcsetattr(fd, TCSANOW, &work_settings);
+
+ if (res!=0) return -1;
+
+ return 0;
+}
+
+extern void link_close(void){
+ tcdrain(fd);
+ tcsetattr(fd, TCSANOW, &org_settings);
+ close(fd);
+}
+
+extern int link_flush(char * port){
+ int ifd=open(port, O_RDWR);
+ if (ifd<0) return -1;
+
+ fd_set fds;
+ struct timeval timeout={
+ .tv_sec=0,
+ .tv_usec=50000,
+ };
+ FD_ZERO(&fds);
+ FD_SET(ifd,&fds);
+
+ char tmpbuf[100];
+ while (timeout.tv_usec){
+ //debug("select\n");
+ select(ifd+1,&fds,NULL,NULL,&timeout);
+ //debug("select done\n");
+ if (timeout.tv_sec+timeout.tv_usec)
+ read(ifd,&tmpbuf, sizeof(tmpbuf));
+ }
+ close(ifd);
+ return 0;
+}
+
+int link_write(uint16_t * data, int len){
+ char * wbuf;
+ int i;
+ int remain;
+ if (fd<0) {
+ errno=EINVAL;
+ return -1;
+ }
+ wbuf=(char *)malloc(len*2);
+ if (!wbuf){
+ return -1;
+ }
+ for (i=0; i<len; i++){
+ wbuf[2*i]=(data[i]>>6)&077;
+ wbuf[2*i+1]=(data[i])&077;
+ }
+ remain=len*2;
+
+ while(remain){
+ int res=write(fd,wbuf+len*2-remain, remain);
+ if (res<0){
+ free(wbuf);
+ return -1;
+ }
+ remain-=res;
+ }
+ free(wbuf);
+ return len;
+}
+
+int link_read(uint16_t * buffer, int len){
+ int i;
+ char * rbuf;
+ int remain;
+ rbuf=(char *)malloc(len*2);
+ if (!rbuf) return -1;
+ if (!buffer){
+ errno=EINVAL;
+ return -1;
+ }
+ remain=len*2;
+ while(remain){
+ int res=read(fd,rbuf+len*2-remain, remain);
+ if (res<0){
+ free(rbuf);
+ return -1;
+ }
+ remain-=res;
+ }
+
+ for (i=0; i<len; i++){
+ buffer[i] = rbuf[2*i]&077;
+ buffer[i] |= rbuf[2*i+1]<<6;
+ buffer[i] &= 07777;
+ }
+ free(rbuf);
+ return len;
+}
--- /dev/null
+#ifndef LINK_H
+#define LINK_H
+
+#include <stdint.h>
+
+extern int link_open(char * port);
+extern void link_close(void);
+extern int link_flush(char * port);
+
+extern int link_read(uint16_t * buffer, int len);
+extern int link_write(uint16_t * buffer, int len);
+
+
+#endif
--- /dev/null
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "log.h"
+
+int loglevel=LL_DEFAULT;
+
+int debug(char * format,...){
+ va_list va;
+ va_start(va,format);
+ if (loglevel>=LL_DEBUG) return vfprintf(stderr, format, va);
+ else return 0;
+}
+
+int info(char * format,...){
+ va_list va;
+ va_start(va,format);
+ if (loglevel>=LL_INFO) return vfprintf(stderr, format, va);
+ else return 0;
+}
+
+int warn(char * format,...){
+ va_list va;
+ va_start(va,format);
+ if (loglevel>=LL_WARN) return vfprintf(stderr, format, va);
+ else return 0;
+}
+
+int err(char * format,...){
+ va_list va;
+ va_start(va,format);
+ if (loglevel>=LL_ERROR) return vfprintf(stderr, format, va);
+ else return 0;
+}
+
--- /dev/null
+
+#ifndef LOG_H
+#define LOG_H
+
+#define LL_QUIET 0
+#define LL_ERROR 1
+#define LL_WARN 2
+#define LL_INFO 3
+#define LL_DEBUG 4
+
+#define LL_DEFAULT LL_INFO
+
+extern int loglevel;
+
+extern int debug(char * format,...);
+extern int info(char * format,...);
+extern int warn(char * format,...);
+extern int err(char * format,...);
+
+#define warning(...) warn(__VA_ARGS__)
+#define error(...) err(__VA_ARGS__)
+#define dbg(...) debug(__VA_ARGS__)
+
+
+#define DEBUG if (loglevel>=LL_DEBUG)
+#define INFO if (loglevel>=LL_INFO)
+#define WARN if (loglevel>=LL_WARN)
+#define ERROR if (loglevel>=LL_ERROR)
+
+#endif
--- /dev/null
+
+#include <stdint.h>
+
+#include "speed8.h"
+#include "link.h"
+#include "memory.h"
+
+
+int get_buffer(uint16_t * buffer){
+ uint16_t cb[2];
+ int res;
+ cb[0]=ATTENTION;
+ cb[1]=CMD_GET_BUFFER;
+
+ res=link_write(cb,2);
+ if (res<0) return res;
+ res=link_read(buffer, 4096);
+ if (res<0) return res;
+ return 0;
+}
+
+int put_buffer(uint16_t * buffer){
+ uint16_t cb[2];
+ int res;
+ cb[0]=ATTENTION;
+ cb[1]=CMD_PUT_BUFFER;
+ res=link_write(cb,2);
+ if (res<0) return res;
+ res=link_write(buffer, 4096);
+ if (res<0) return res;
+ return 0;
+}
+
--- /dev/null
+#ifndef MEMORY_H
+#define MEMORY_H
+
+
+extern int get_buffer(uint16_t * buffer);
+extern int get_buffer(uint16_t * buffer);
+
+
+
+
+
+
+
+#endif
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include "rk05.h"
+#include "speed8.h"
+#include "link.h"
+#include "log.h"
+
+/* Commands for the RK8E controller */
+#define RK_CM_READ 00000
+#define RK_CM_SEEK_ONLY 03000
+#define RK_CM_WRITE 04000
+#define RK_CM_TRANS256 00000
+#define RK_CM_TRANS128 00100
+
+static char * bars(int width, int max, int current){
+ static char buffer[100];
+ if (width>80) width=80;
+ int i;
+ float width_f=width;
+ float max_f=max;
+ float current_f=current;
+ float step=width_f/max_f;
+ float dots=step*current_f;
+ int actual=round(dots);
+ buffer[0]='[';
+ buffer[width+1]=']';
+ for (i=0; i<width; i++){
+ if (i<actual) buffer[i+1]='*';
+ else buffer[i+1]=' ';
+ }
+ int perc=round((current_f/max_f)*100);
+ sprintf(buffer+width+2," %3i%%",perc);
+ return buffer;
+}
+
+int rk05_write_sector(uint8_t drive, uint16_t disk_address, uint16_t mem_address){
+ uint16_t cb[5];
+ debug("rk05_write_sector(): Drive %i, DA: %05o, CA: %04o\n",drive,disk_address, mem_address);
+ if ((disk_address>=203*2*16*256)||(mem_address>4095)||(drive>3)) {
+ debug("rk05_write_sector(): Invalid parameters!\n");
+ errno=EINVAL;
+ return -1;
+ }
+ cb[0]=ATTENTION;
+ cb[1]=CMD_RK_GO;
+ cb[2]=mem_address; // Current address
+ cb[3]=RK_CM_WRITE|(drive&3)<<1
+ | ((disk_address>>12)&1)
+ | RK_CM_TRANS256
+ | 010; // Field!!
+ cb[4]=disk_address&07777;
+ return link_write(cb,5);
+}
+
+int rk05_read_sector(uint8_t drive, uint16_t disk_address, uint16_t mem_address){
+ debug("rk05_read_sector(): Drive %i, DA: %05o, CA: %04o\n",drive,disk_address, mem_address);
+ uint16_t cb[5];
+ if ((disk_address>=RK05_TRACKS*16)||(mem_address>4095)||(drive>3)) {
+ debug("rk05_read_sector(): Invalid parameters!\n");
+ errno=EINVAL;
+ return -1;
+ }
+ cb[0]=ATTENTION;
+ cb[1]=CMD_RK_GO;
+ cb[2]=mem_address; // Current address
+ cb[3]=RK_CM_READ|(drive&3)<<1
+ | ((disk_address>>12)&1)
+ | 010; // Field!!
+ cb[4]=disk_address&07777;
+ link_write(cb,5);
+ return 0;
+}
+
+int rk05_write_track(uint8_t drive, uint16_t track){
+ uint16_t cb[4];
+ uint16_t sector=track*16+0;
+ debug("rk05_write_track(): Drive %i, Track: %i\n",drive,track);
+ if ((drive>3)||(track>=RK05_TRACKS)){
+ debug("rk05_write_track(): Invalid parameters!\n");
+ errno=EINVAL;
+ return -1;
+ }
+ cb[0]=ATTENTION;
+ cb[1]=CMD_RK_W_TRACK;
+ cb[2]=((drive&3)<<1)
+ |((sector>>12)&1);
+ cb[3]=(sector)&07777;
+ return link_write(cb,4);
+}
+
+int rk05_read_track(uint8_t drive, uint16_t track){
+ uint16_t cb[4];
+ uint16_t sector=track*16+0;
+ debug("rk05_read_track(): Drive %i, Track: %i\n",drive,track);
+ if ((drive>3)||(track>=RK05_TRACKS)){
+ debug("rk05_read_track(): Invalid parameters!\n");
+ errno=EINVAL;
+ return -1;
+ }
+ cb[0]=ATTENTION;
+ cb[1]=CMD_RK_R_TRACK;
+ cb[2]=((drive&3)<<1)
+ |((sector>>12)&1);
+ cb[3]=sector&07777;
+ return link_write(cb,4);
+}
+
+int rk05_status(uint16_t * status){
+ uint16_t cb[2];
+ int res;
+ debug("rk05_status()\n");
+ cb[0]=ATTENTION;
+ cb[1]=CMD_RK_STATUS;
+ res=link_write(cb,2);
+ if (res<0) return res;
+ res=link_read(cb,1);
+ if (res<0) return res;
+ if (status) *status=cb[0];
+ debug("rk05_status(): %04o\n",cb[0]);
+ return 0;
+}
+
+int rk05_recalibrate(uint8_t drive){
+ uint16_t cb[2];
+ debug("rk05_recalibrate(): Drive: %i\n",drive);
+ if (drive>3){
+ debug("rk05_recalibrate(): Invalid drive!\n");
+ errno=EINVAL;
+ return -1;
+ }
+ cb[0]=ATTENTION;
+ cb[1]=CMD_RK_RECAL0 + 0100*drive;
+ return link_write(cb,2);
+}
+
+
+int order1[16]={0, 2, 4, 6, 8, 10, 12, 14, 1,3,5,7,9,11,13,15};
+int order2[16]={0, 3, 6, 9, 12, 15, 1, 4, 7,10,13,2,5,8,11,14};
+int order3[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+int order4[16]={0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15};
+
+int rk05_read_disk(uint8_t disk, uint16_t * target){
+ int track,sector;
+ int res;
+ uint16_t status;
+ if (!target){
+ errno=EINVAL;
+ return -1;
+ }
+ res=rk05_recalibrate(disk);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ if (status != RK05_STATUS_OK){
+ err("Status error while recalibrating!\n");
+ ERROR rk05_perror(status);
+ errno=EIO;
+ return -1;
+ }
+
+ for (track=0; track<RK05_TRACKS; track++){
+ info("\rReading drive %i: CYL: %3i, SIDE: %i %s",
+ disk, track/2, track%2,bars(70,RK05_TRACKS-1,track));
+ res=rk05_read_track(disk, track);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+
+ if (status != RK05_STATUS_OK){
+ int retries;
+ info("\nAn error occured!\n");
+ INFO rk05_perror(status);
+ warning("Reading of track %i failed. Will try individual sectors now.\n", track);
+ res=rk05_recalibrate(disk);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ for (sector=0; sector<16; sector++){
+ retries=16;
+ while(retries){
+ debug("Reading sector %i with %i tries left\n",sector,retries);
+ res=rk05_read_sector(disk,track*16+order2[sector],order2[sector]*0400);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ if (status != RK05_STATUS_OK){
+ retries--;
+ warning("Error on sector %i, will retry %i times.\n",sector, retries);
+ INFO rk05_perror(status);
+ res=rk05_recalibrate(disk);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ } else {
+ retries++;
+ break;
+ }
+ }
+ }
+ if(retries==0){
+ err("Failed to read track %i. Giving up.\n",track);
+ errno=EIO;
+ return -1;
+ } else {
+ warning("Now it succeeded.\n");
+ }
+ }
+ res=get_buffer(target+(4096*track));
+ if(res<0) return res;
+ }
+ info("\n");
+ debug("rk05_read_disk():Success\n");
+ return 0;
+}
+
+int rk05_write_disk(uint8_t disk, uint16_t * target){
+ int track,sector;
+ int res;
+ uint16_t status;
+ if (!target){
+ errno=EINVAL;
+ return -1;
+ }
+ res=rk05_recalibrate(disk);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ if (status != RK05_STATUS_OK){
+ err("Status error while recalibrating!\n");
+ ERROR rk05_perror(status);
+ errno=EIO;
+ return -1;
+ }
+ for (track=0; track<RK05_TRACKS; track++){
+ info("\rWriting drive %i: CYL: %3i, SIDE: %i %s", disk, track/2, track%2, bars(70,RK05_TRACKS-1,track));
+ res=put_buffer(target+(4096*track));
+ if (res<0) return res;
+ res=rk05_write_track(disk,track);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+
+ if (status != RK05_STATUS_OK){
+ int retries;
+ info ("\nAn error occured!\n");
+ INFO rk05_perror(status);
+ warning("Writing of track %i failed. Will try individual sectors now.\n", track);
+ res=rk05_recalibrate(disk);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ for (sector=0; sector<16; sector++){
+ retries=16;
+ while(retries){
+ debug("Writing sector %i with %i tries left\n",order2[sector],retries);
+ res=rk05_write_sector(disk,track*16+order2[sector],order2[sector]*0400);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ if (status != RK05_STATUS_OK){
+ retries--;
+ warning("Error on sector %i, will retry %i times.\n",order2[sector], retries);
+ INFO rk05_perror(status);
+ res=rk05_recalibrate(disk);
+ if (res<0) return res;
+ res=rk05_status(&status);
+ if (res<0) return res;
+ } else {
+ retries++;
+ break;
+ }
+ }
+ }
+ if(retries==0){
+ err("Failed to write track %i. Giving up.\n",track);
+ errno=EIO;
+ return -1;
+ } else {
+ warning("Now it succeeded.\n");
+ }
+ }
+ }
+ info("\n");
+ debug("rk05_write_disk():Success\n");
+ return 0;
+}
+
+void rk05_perror(uint16_t status){
+ fprintf(stderr, "Status: %s\n",(status&04000?"Done":"Busy"));
+ if (status & 02000) fprintf(stderr,"Head in motion.\n");
+ if (status & 00400) fprintf(stderr,"Seek fail\n");
+ if (status & 00200) fprintf(stderr,"File not ready\n");
+ if (status & 00100) fprintf(stderr,"Control busy\n");
+ if (status & 00040) fprintf(stderr,"Timing error");
+ if (status & 00020) printf("Write lock error\n");
+ if (status & 00010) fprintf(stderr,"Parity error\n");
+ if (status & 00004) fprintf(stderr,"Data request late\n");
+ if (status & 00002) fprintf(stderr,"Drive status error\n");
+ if (status & 00001) fprintf(stderr,"Cylinder address error\n");
+}
--- /dev/null
+
+
+#ifndef RK05_H
+#define RK05_H
+#include <stdint.h>
+
+//#define RK05_CYLINDERS 203
+#define RK05_CYLINDERS 203
+#define RK05_DISKSIZE (RK05_CYLINDERS*2*16*256)
+#define RK05_TRACKS (RK05_CYLINDERS*2)
+
+#define RK05_STATUS_OK (04000)
+
+extern int rk05_write_sector(uint8_t drive, uint16_t disk_address, uint16_t mem_address);
+extern int rk05_read_sector(uint8_t drive, uint16_t disk_address, uint16_t mem_address);
+extern int rk05_status(uint16_t * status);
+extern int rk05_write_track(uint8_t drive, uint16_t track);
+extern int rk05_read_track(uint8_t drive, uint16_t track);
+extern int rk05_read_disk(uint8_t disk, uint16_t * target);
+extern int rk05_write_disk(uint8_t disk, uint16_t * target);
+
+
+extern void rk05_perror(uint16_t status);
+
+
+
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "speed8.h"
+#include "link.h"
+#include "rk05.h"
+#include "memory.h"
+#include "log.h"
+
+#define PORT "/dev/ttyUSB0"
+
+int fd;
+
+static const struct option longopts[]={
+ {"help",0,NULL,'h'},
+ {"read",0,NULL,'r'},
+ {"write",0,NULL,'w'},
+ {"verbose",0,NULL,'v'},
+ {"port",1,NULL,'p'},
+ {"drive",1,NULL,'d'},
+ {"quiet",0,NULL,'q'},
+ {"loglevel",1,NULL,'l'},
+ {"verify",0,NULL,'V'},
+ {NULL}
+};
+
+static const char optstring[]="hrwvp:d:l:qV";
+
+static void help(void){
+ fprintf(stderr, "\
+\n\
+ Usage: rktool {-r|-w} [-v] [-V] [-h] [-d<unit_number>] [-l<loglevel>] <imagefile>\n\
+\n\
+ This tool will help you to backup restore RK05 media on a PDP8 running speed8.\n\
+\n\
+ Options:\n\
+\n\
+ -r, --read Read disk (default if nothing specified)\n\
+ -w, --write Write disk\n\
+ -d, --drive= Select drive number 0-3 (defaults to 0)\n\
+ -p, --port= Serial port to use (defaults to /dev/ttyUSB0)\n\
+ -V, --verify Verify after read or write\n\
+ -v, --verbose Be verbose\n\
+ -q, --quiet Be quiet, opposite of -v\n\
+ -l, --loglevel= Set loglevel for debugging purposes\n\
+ -h, --help Display this help and exit\n\
+\n\
+");
+ exit(100);
+}
+
+static char defaultport[]=PORT;
+
+int main(int argc, char ** argv){
+ int res;
+ int e;
+
+ int drive=0;
+ #define READ 0
+ #define WRITE 1
+ int action=READ;
+ char * port=defaultport;
+ char * file=NULL;
+ int verify=0;
+ char opt;
+
+ opterr=1;
+ opt=getopt_long(argc,argv,optstring,longopts,NULL);
+
+ while(opt>0){
+ switch(opt){
+ case 'v':
+ loglevel++;
+ break;
+ case 'h':
+ help();
+ break;
+ case 'r':
+ action=READ;
+ break;
+ case 'w':
+ action=WRITE;
+ break;
+ case 'p':
+ if (!optarg) {
+ error("-p needs an argument!\n");
+ exit(1);
+ }
+ port=optarg;
+ break;
+ case 'd':
+ if (!optarg) {
+ error("-d needs an argument!\n");
+ exit(1);
+ }
+ drive=strtol(optarg, NULL, 0);
+ break;
+ case 'q':
+ loglevel=LL_QUIET;
+ break;
+ case 'l':
+ if (!optarg) {
+ error("-l needs an argument!\n");
+ exit(1);
+ }
+ loglevel=strtol(optarg,NULL,0);
+ break;
+ case 'V':
+ verify=1;
+ break;
+ case '?':
+ help();
+ break;
+ }
+ opt=getopt_long(argc,argv,optstring,longopts,NULL);
+ }
+
+ file=argv[optind];
+
+ if (!file) {
+ fprintf(stderr,"Error: No file specified!\n");
+ help();
+ }
+
+ debug("Opening port \"%s\".\n",port);
+ debug("Image file: %s\n", file);
+ debug("Flushing first\n");
+
+ res=link_flush(port);
+
+ if (res <0){
+ ERROR perror("While initializing link");
+ return -1;
+ }
+ debug("Opening for real now\n");
+ res=link_open(port);
+ if (res <0){
+ ERROR perror("While initializing link");
+ return -1;
+ }
+
+ if (action==WRITE){
+ uint16_t origin[RK05_DISKSIZE];
+ uint16_t readback[RK05_DISKSIZE];
+
+ int fd=open(file,O_RDONLY);
+ if (fd<0){
+ ERROR perror("While opening file");
+ exit(2);
+ }
+ res=read(fd,(char*)origin,sizeof(origin));
+ WARN if (res<RK05_DISKSIZE*2)
+ warn("Read only %i bytes! Hope, that's ok.\n",res);
+ close(fd);
+
+ res=rk05_write_disk(drive,origin);
+ if(res<0){
+ ERROR perror("While writing disk image");
+ exit(3);
+ }
+
+ if (verify){
+ info("Reading back image.\n");
+ res=rk05_read_disk(drive,readback);
+ if(res<0){
+ ERROR perror("While reading disk image");
+ exit(3);
+ }
+ int i;
+ e=0;
+ int cylinder,side,sector,word;
+ for (cylinder=0; cylinder<RK05_CYLINDERS;cylinder++)
+ for (side=0; side<1; side++)
+ for (sector=0; sector<16; sector++)
+ for (word=0; word<256; word++){
+ i=cylinder*2*16*256+side*16*256+sector*256+word;
+ if (readback[i]!=origin[i]){
+ error("Verify mismatch! Cylinder %i, Side %i, Sector %i, Word %i\n",
+ cylinder,side,sector,word);
+ e++;
+ }
+ }
+ if (e) {
+ error("Found %i verify errors!\n",e);
+ exit(3);
+ }
+ } // verify
+ } // WRITE
+
+ if (action==READ){
+
+ uint16_t target[RK05_DISKSIZE];
+ uint16_t target2[RK05_DISKSIZE];
+
+ info("Reading drive %i\n",drive);
+ res=0;
+ res=rk05_read_disk(drive,target);
+ if(res<0){
+ ERROR perror("While reading disk image");
+ exit(3);
+ }
+ if (verify){
+ e=0;
+ info("Reading again\n");
+ res=rk05_read_disk(drive,target2);
+ if(res<0){
+ ERROR perror("While reading disk image");
+ exit(3);
+ }
+ int i;
+ for (i=0; i<RK05_DISKSIZE ;i++){
+ debug("verify: %i\n",i);
+ if (target[i]!=target2[i]){
+ error("Verify mismatch! Cylinder %i, Side %i, Sector %i, Word %i\n",
+ i>>13,(i>>12)&1,(i>>8)&15,i&256);
+ e++;
+ }
+ }
+ }
+ int fd=open(file,O_WRONLY|O_CREAT|O_TRUNC,0640);
+ if (fd<0){
+ ERROR perror("While opening file");
+ exit(2);
+ }
+ debug("File \"%s\" opened.\n",file);
+ res=write(fd,target,sizeof(target));
+ if (res!=sizeof(target)){
+ ERROR perror ("While writing file to disk");
+ exit(1);
+ }
+
+ }
+
+ link_close();
+ link_flush(file);
+ if (e) {
+ error("Found %i verify errors!\n",e);
+ exit(5);
+ }
+ return 0;
+}
--- /dev/null
+#ifndef SPEED8_H
+#define SPEED8_H
+
+
+#define ATTENTION 036
+
+#define CMD_GET_BUFFER 00001
+#define CMD_PUT_BUFFER 00002
+
+#define CMD_RK_GO 00003
+#define CMD_RK_STATUS 00004
+#define CMD_RK_R_TRACK 00005
+#define CMD_RK_W_TRACK 00006
+#define CMD_RK_RECAL0 00007
+#define CMD_RK_RECAL1 00107
+#define CMD_RK_RECAL2 00207
+#define CMD_RK_RECAL3 00307
+
+
+
+
+extern int get_buffer(uint16_t * buffer);
+extern int put_buffer(uint16_t * buffer);
+
+
+
+
+
+
+#endif
--- /dev/null
+*.lst
+*.rim
+*.BN
\ No newline at end of file
--- /dev/null
+all: speed8.bin speed8.rim
+
+%.bin:%.pal
+ @echo PAL $@
+ @palbart $^
+
+%.rim:%.pal
+ @echo PAL $@
+ @palbart -r $^
+
+clean:
+ @echo CLEAN
+ @rm -f *.lst *.bin *.rim *.err *~
+
+boot: speed8.bin
+ @echo BOOT
+ @rb speed8.bin
+
+.PHONY: all clean boot
--- /dev/null
+
+Speed 8 PDP8 part.
+
+speed8.pal: The source code
+SPEED8.PA: Binary source code, created from speed8.pal
+
--- /dev/null
+*30
+ 6743
+ 5031
+
+*34
+ 0200
+ 1036
+ 1046
+ 1001
+ 1020
+ 0400
+ 0412
+ 0600
+ 0646
+ 0730
+ 7600
+*200
+ 4435
+ 1274
+ 7440
+ 5200
+ 4435
+ 3310
+ 1310
+ 1275
+ 7440
+ 5214
+ 4437
+ 5200
+ 7200
+ 1310
+ 1276
+ 7440
+ 5223
+ 4440
+ 5200
+ 7200
+ 1310
+ 1277
+ 7440
+ 5232
+ 4441
+ 5200
+ 7200
+ 1310
+ 1300
+ 7440
+ 5241
+ 4442
+ 5200
+ 7200
+ 1310
+ 1301
+ 7440
+ 5247
+ 4443
+ 7200
+ 1310
+ 1302
+ 7440
+ 5255
+ 4444
+ 7200
+ 1310
+ 0273
+ 1303
+ 7440
+ 5271
+ 1310
+ 7012
+ 7012
+ 7010
+ 0272
+ 4445
+ 5200
+ 0006
+ 7477
+ 7742
+ 7777
+ 7776
+ 7775
+ 7774
+ 7773
+ 7772
+ 7771
+ 7671
+ 7571
+ 7471
+ 7777
+*401
+ 7301
+ 6742
+ 4435
+ 6744
+ 4435
+ 6746
+ 4435
+ 6743
+ 5600
+ 0000
+ 6741
+ 5213
+ 6745
+ 4436
+ 5612
+*601
+ 7200
+ 1322
+ 3321
+ 7301
+ 6742
+ 7200
+ 3316
+ 6744
+ 4435
+ 3323
+ 1323
+ 1324
+ 6746
+ 4435
+ 3320
+ 1320
+ 6743
+ 7200
+ 2320
+ 1316
+ 1315
+ 3316
+ 1320
+ 6741
+ 5230
+ 7301
+ 6742
+ 1323
+ 1325
+ 6746
+ 1316
+ 6744
+ 1320
+ 6743
+ 2321
+ 5222
+ 5600
+ 0000
+ 7200
+ 1322
+ 3321
+ 7301
+ 6742
+ 7200
+ 3316
+ 6744
+ 4435
+ 3323
+ 1323
+ 1326
+ 6746
+ 4435
+ 3320
+ 1320
+ 6743
+ 7200
+ 2320
+ 1316
+ 1315
+ 3316
+ 1320
+ 6741
+ 5276
+ 7301
+ 6742
+ 1323
+ 1327
+ 6746
+ 7200
+ 1316
+ 6744
+ 1320
+ 6743
+ 2321
+ 5270
+ 5646
+ 0400
+ 0000
+ 0020
+ 0000
+ 0000
+ 7761
+ 0000
+ 0010
+ 1010
+ 4010
+ 5010
+ 0000
+ 3347
+ 7301
+ 6742
+ 1347
+ 6746
+ 7326
+ 6742
+ 6741
+ 5340
+ 1346
+ 1347
+ 6746
+ 5730
+ 0200
+ 0000
+*1000
+ 0000
+ 0000
+ 7200
+ 3200
+ 6211
+ 7200
+ 1600
+ 6417
+ 5207
+ 7002
+ 6417
+ 5212
+ 2200
+ 5205
+ 6201
+ 5601
+ 0000
+ 7200
+ 3200
+ 6211
+ 6407
+ 5224
+ 7002
+ 6407
+ 5227
+ 3600
+ 2200
+ 5224
+ 6201
+ 5620
+ 0000
+ 7200
+ 6407
+ 5240
+ 7002
+ 6407
+ 5243
+ 5636
+ 0000
+ 6417
+ 5247
+ 7002
+ 6417
+ 5252
+ 7002
+ 5646
--- /dev/null
+
+/ The RK fast access program
+/ Needs kturbo and tturbo instructions provided by omni-usb
+
+/ Communication is word-wise via the subroutines
+/ RWRD and SWRD and their aliases RWORD and SWORD
+
+/ All intelligence is located on the PC side :-)
+
+ IDEV=400
+ ODEV=410
+
+ KTURBO=6007 IDEV
+ TTURBO=6007 ODEV
+
+ / Commands sent from the PC
+ ATT=36
+ CMGET=1
+ CMPUT=2
+
+ /RK05 commands
+ CRKGO=3 / Execute command
+ CRKST=4 / Return drive status
+ CRKRT=5 / Read track
+ CRKWT=6 / Write track
+ CRKR0=007
+ CRKR1=107
+ CRKR2=207
+ CRKR3=307
+
+ /GO BACK TO RIMLOADER
+ CBOOT=04566
+
+/ RK05 commands are followed by the disk address and transfer length
+/ <ATT> <CRKGO> <CA_REG> <CM_REG> <DA_REG>
+
+*7700 JMP I XSTART
+
+*10
+AUTO0, 0
+AUTO1, 0
+AUTO2, 0
+AUTO3, 0
+AUTO4, 0
+AUTO5, 0
+AUTO6, 0
+AUTO7, 0
+
+*30
+RKBOOT, DLAG
+ JMP .
+
+*34
+XSTART, START
+XRWRD, RWRD
+XSWRD, SWRD
+XSBUF, SBUF
+XRBUF, RBUF
+XRKGO, RKGO
+XRKST, RKST
+XRKRT, RKRT
+XRKWT, RKWT
+XRECAL, RECAL
+XEXIT, EXIT
+
+ DSKP=6741
+ DCLR=6742
+ DLAG=6743
+ DLCA=6744
+ DRST=6745
+ DLDC=6746
+
+ RWORD=JMS I XRWRD
+ SWORD=JMS I XSWRD
+
+*200
+START,
+ RWORD
+ TAD KATT
+ SZA
+ JMP START
+ RWORD
+ DCA CMD
+ TAD CMD
+ TAD KCMGET
+ SZA
+ JMP NO1
+ JMS I XSBUF
+ JMP START
+
+NO1,
+ CLA
+ TAD CMD
+ TAD KCMPUT
+ SZA
+ JMP NO2
+ JMS I XRBUF
+ JMP START
+
+NO2,
+ CLA
+ TAD CMD
+ TAD KCRKGO
+ SZA
+ JMP NO3
+ JMS I XRKGO
+ JMP START
+NO3,
+ CLA
+ TAD CMD
+ TAD KCRKST
+ SZA
+ JMP NO4
+ JMS I XRKST
+ JMP START
+NO4,
+ CLA
+ TAD CMD
+ TAD KCRKRT
+ SZA
+ JMP NO5
+ JMS I XRKRT
+NO5,
+
+ CLA
+ TAD CMD
+ TAD KCRKWT
+ SZA
+ JMP NO6
+ JMS I XRKWT
+NO6,
+
+ CLA
+ TAD CMD
+ AND K7477 / MASK OUT DRIVE SELECT
+ TAD KCRKR0
+ SZA
+ JMP NO7
+ TAD CMD
+ RTR
+ RTR
+ RAR
+ AND K6
+ JMS I XRECAL
+
+NO7,
+
+ JMP START
+
+K6, 6
+K7477, 7477
+KATT, -ATT
+KCMGET, -CMGET
+KCMPUT, -CMPUT
+KCRKGO, -CRKGO
+KCRKST, -CRKST
+KCRKRT, -CRKRT
+KCRKWT, -CRKWT
+KCRKR0, -CRKR0
+KCRKR1, -CRKR1
+KCRKR2, -CRKR2
+KCRKR3, -CRKR3
+XBOOT, 7777
+CMD, 0
+
+/***********************************************
+PAGE
+/***********************************************
+
+RKGO, 0
+
+ CLA CLL IAC / Standard read from manual
+ DCLR
+
+ RWORD / MEMORY ADDRESS
+ DLCA
+
+ RWORD / COMMAND REGISTER
+ DLDC
+
+ RWORD / DISK ADDRESS
+ DLAG
+
+ JMP I RKGO
+
+RKST, 0
+ DSKP
+ JMP .-1
+ DRST
+ SWORD
+ JMP I RKST
+/***********************************************
+PAGE
+
+RKRT, 0
+ CLA
+ TAD K17N
+ DCA CNT
+ CLA CLL IAC / Standard read from manual
+ DCLR
+
+ CLA
+ DCA TPTR
+ DLCA
+
+ RWORD
+ DCA CMDP
+ TAD CMDP
+ TAD CMDR1
+ DLDC
+
+ RWORD
+ DCA ADR
+ TAD ADR
+ DLAG
+
+
+RTTL, CLA
+ ISZ ADR
+ TAD TPTR
+ TAD K400
+ DCA TPTR
+ TAD ADR
+
+ DSKP
+ JMP .-1
+
+ CLA CLL IAC / Standard read from manual
+ DCLR
+
+ TAD CMDP
+ TAD CMDR2
+ DLDC
+
+ TAD TPTR
+ DLCA
+ TAD ADR
+ DLAG
+ ISZ CNT
+ JMP RTTL
+ JMP I RKRT
+
+/**********************************************
+
+RKWT, 0
+ CLA
+ TAD K17N
+ DCA CNT
+ CLA CLL IAC / Clear control
+ DCLR
+
+ CLA
+ DCA TPTR
+ DLCA
+
+ RWORD
+ DCA CMDP
+ TAD CMDP
+ TAD CMDW1
+ DLDC
+
+ RWORD
+ DCA ADR
+ TAD ADR
+ DLAG
+
+WTTL, CLA
+ ISZ ADR
+ TAD TPTR
+ TAD K400
+ DCA TPTR
+ TAD ADR
+
+ DSKP
+ JMP .-1
+
+ CLA CLL IAC / Standard read from manual
+ DCLR
+
+ TAD CMDP
+ TAD CMDW2
+ DLDC
+ CLA
+
+ TAD TPTR
+ DLCA
+
+ TAD ADR
+ DLAG
+ ISZ CNT
+ JMP WTTL
+ JMP I RKWT
+
+K400, 400
+TPTR, 0
+K20N, 20
+ADR, 0
+CNT, 0
+K17N, -17
+CMDP, 0
+CMDR1, 0010
+CMDR2, 1010
+CMDW1, 4010
+CMDW2, 5010
+/**********************************************
+
+RECAL, 0
+ DCA DRIVE / SAVE DRIVE NUMBER*2 found in AC
+ CLA CLL IAC / Recal drive, clear errors and set to cyl 0
+ DCLR / From manual
+ TAD DRIVE
+ DLDC
+ CLA CLL CML RTL
+ DCLR
+ DSKP
+ JMP .-1
+ TAD K0200
+ TAD DRIVE
+ DLDC
+ JMP I RECAL
+
+K0200, 200
+DRIVE, 0
+
+/***********************************************
+/ Memory dump/restore routines
+
+PAGE
+
+PTR, 0
+
+SBUF, 0
+ CLA
+ DCA PTR
+ CDF 10
+SLOP, CLA
+ TAD I PTR
+ TTURBO
+ JMP .-1
+ BSW
+ TTURBO
+ JMP .-1
+ ISZ PTR
+ JMP SLOP
+ CDF 0
+ JMP I SBUF
+
+
+RBUF, 0
+ CLA
+ DCA PTR
+ CDF 10
+RLOP, KTURBO
+ JMP .-1
+ BSW
+ KTURBO
+ JMP .-1
+ DCA I PTR
+ ISZ PTR
+ JMP RLOP
+ CDF 0
+ JMP I RBUF
+
+RWRD, 0
+ CLA
+ KTURBO
+ JMP .-1
+ BSW
+ KTURBO
+ JMP .-1
+ JMP I RWRD
+
+SWRD, 0
+ TTURBO
+ JMP .-1
+ BSW
+ TTURBO
+ JMP .-1
+ BSW
+ JMP I SWRD
+
+
+/***********************************************
+/ What hapens on exit to 7600
+/ Relies on the fact that OS/8 won't allow overwriting here.
+
+*7600
+EXIT, HLT
+ JMP 30
+
+
+$