From a6a4e5d439cb46becf8f22dad7347d0f5fe5a24e Mon Sep 17 00:00:00 2001 From: Philipp Hachtmann Date: Sun, 27 Sep 2015 15:49:42 +0200 Subject: [PATCH 1/1] Initial commit This initial commit adds speed8 and the hpgl plotting program. Signed-off-by: Philipp Hachtmann --- .gitignore | 4 + sw/plot_hpgl/pc/Makefile | 24 +++ sw/plot_hpgl/pc/hpgl.c | 273 ++++++++++++++++++++++++++ sw/plot_hpgl/pc/hpgl.h | 58 ++++++ sw/plot_hpgl/pc/optimize.c | 217 ++++++++++++++++++++ sw/plot_hpgl/pc/optimize.h | 11 ++ sw/plot_hpgl/pdp8/PLOT.FT | 45 +++++ sw/speed8/pc/.gitignore | 1 + sw/speed8/pc/Makefile | 21 ++ sw/speed8/pc/link.c | 125 ++++++++++++ sw/speed8/pc/link.h | 14 ++ sw/speed8/pc/log.c | 35 ++++ sw/speed8/pc/log.h | 30 +++ sw/speed8/pc/memory.c | 33 ++++ sw/speed8/pc/memory.h | 14 ++ sw/speed8/pc/rk05.c | 304 ++++++++++++++++++++++++++++ sw/speed8/pc/rk05.h | 28 +++ sw/speed8/pc/rktool.c | 247 +++++++++++++++++++++++ sw/speed8/pc/speed8.h | 30 +++ sw/speed8/pdp8/.gitignore | 3 + sw/speed8/pdp8/Makefile | 19 ++ sw/speed8/pdp8/README | 6 + sw/speed8/pdp8/SPEED8.PA | 256 ++++++++++++++++++++++++ sw/speed8/pdp8/speed8.pal | 392 +++++++++++++++++++++++++++++++++++++ 24 files changed, 2190 insertions(+) create mode 100644 .gitignore create mode 100644 sw/plot_hpgl/pc/Makefile create mode 100644 sw/plot_hpgl/pc/hpgl.c create mode 100644 sw/plot_hpgl/pc/hpgl.h create mode 100644 sw/plot_hpgl/pc/optimize.c create mode 100644 sw/plot_hpgl/pc/optimize.h create mode 100644 sw/plot_hpgl/pdp8/PLOT.FT create mode 100644 sw/speed8/pc/.gitignore create mode 100644 sw/speed8/pc/Makefile create mode 100644 sw/speed8/pc/link.c create mode 100644 sw/speed8/pc/link.h create mode 100644 sw/speed8/pc/log.c create mode 100644 sw/speed8/pc/log.h create mode 100644 sw/speed8/pc/memory.c create mode 100644 sw/speed8/pc/memory.h create mode 100644 sw/speed8/pc/rk05.c create mode 100644 sw/speed8/pc/rk05.h create mode 100644 sw/speed8/pc/rktool.c create mode 100644 sw/speed8/pc/speed8.h create mode 100644 sw/speed8/pdp8/.gitignore create mode 100644 sw/speed8/pdp8/Makefile create mode 100644 sw/speed8/pdp8/README create mode 100644 sw/speed8/pdp8/SPEED8.PA create mode 100644 sw/speed8/pdp8/speed8.pal diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7108a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*.o +*.d +tmp diff --git a/sw/plot_hpgl/pc/Makefile b/sw/plot_hpgl/pc/Makefile new file mode 100644 index 0000000..de6e487 --- /dev/null +++ b/sw/plot_hpgl/pc/Makefile @@ -0,0 +1,24 @@ + +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 + + diff --git a/sw/plot_hpgl/pc/hpgl.c b/sw/plot_hpgl/pc/hpgl.c new file mode 100644 index 0000000..70bb2f8 --- /dev/null +++ b/sw/plot_hpgl/pc/hpgl.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* #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; +} diff --git a/sw/plot_hpgl/pc/hpgl.h b/sw/plot_hpgl/pc/hpgl.h new file mode 100644 index 0000000..595f52c --- /dev/null +++ b/sw/plot_hpgl/pc/hpgl.h @@ -0,0 +1,58 @@ +#ifndef HPGL_H +#define HPGL_H +#include + +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 diff --git a/sw/plot_hpgl/pc/optimize.c b/sw/plot_hpgl/pc/optimize.c new file mode 100644 index 0000000..5a434d0 --- /dev/null +++ b/sw/plot_hpgl/pc/optimize.c @@ -0,0 +1,217 @@ +#include +#include +#include + + +//#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; + } + } +} diff --git a/sw/plot_hpgl/pc/optimize.h b/sw/plot_hpgl/pc/optimize.h new file mode 100644 index 0000000..5a8bc72 --- /dev/null +++ b/sw/plot_hpgl/pc/optimize.h @@ -0,0 +1,11 @@ + +#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 diff --git a/sw/plot_hpgl/pdp8/PLOT.FT b/sw/plot_hpgl/pdp8/PLOT.FT new file mode 100644 index 0000000..ffa75b4 --- /dev/null +++ b/sw/plot_hpgl/pdp8/PLOT.FT @@ -0,0 +1,45 @@ +C PHILIPP'S FILE PLOTTER 2010! + +0100 DIMENSION NAME(3) + +C 565 0.01 INCH, DATA IN CM + CALL PLOTS(0.0254,0) + +C CALL PLOTS(0.004,0) + +0150 XMAX=0 +0200 WRITE (4,300) +0300 FORMAT (' FILE TO PLOT:') +0400 READ (4,600) NAME +0500 CALL USR(5,NAME,2,ERR) +0501 IF (NAME(1) .EQ. ' ') GO TO 200 +0600 FORMAT (3A6) + + + +1200 CALL CHKEOF(EOF) +1300 READ (5,1000) PEN,X,Y +1000 FORMAT (A3,2F13.5) +1500 IF (EOF.NE.0) GO TO 7000 + +C ROTATE +C TMP=Y +C Y=-X +C X=-TMP + + TMP=Y + Y=-X + X=TMP + +2000 IF (PEN.EQ.'PU,') P=3 +2100 IF (PEN.EQ.'PD,') P=2 + IF (X.GE.XMAX) XMAX=X + CALL XYPLOT(X,Y,P) + +1700 GO TO 1200 + +7000 CALL XYPLOT(XMAX+1,0,-3); + CALL PLEXIT + +9999 GO TO 150 + diff --git a/sw/speed8/pc/.gitignore b/sw/speed8/pc/.gitignore new file mode 100644 index 0000000..c64fb19 --- /dev/null +++ b/sw/speed8/pc/.gitignore @@ -0,0 +1 @@ +rktool \ No newline at end of file diff --git a/sw/speed8/pc/Makefile b/sw/speed8/pc/Makefile new file mode 100644 index 0000000..688398a --- /dev/null +++ b/sw/speed8/pc/Makefile @@ -0,0 +1,21 @@ + + +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 diff --git a/sw/speed8/pc/link.c b/sw/speed8/pc/link.c new file mode 100644 index 0000000..c04eb78 --- /dev/null +++ b/sw/speed8/pc/link.c @@ -0,0 +1,125 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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>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 + +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 diff --git a/sw/speed8/pc/log.c b/sw/speed8/pc/log.c new file mode 100644 index 0000000..b1ec19c --- /dev/null +++ b/sw/speed8/pc/log.c @@ -0,0 +1,35 @@ + +#include +#include +#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; +} + diff --git a/sw/speed8/pc/log.h b/sw/speed8/pc/log.h new file mode 100644 index 0000000..7d642b1 --- /dev/null +++ b/sw/speed8/pc/log.h @@ -0,0 +1,30 @@ + +#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 diff --git a/sw/speed8/pc/memory.c b/sw/speed8/pc/memory.c new file mode 100644 index 0000000..ee4e65a --- /dev/null +++ b/sw/speed8/pc/memory.c @@ -0,0 +1,33 @@ + +#include + +#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; +} + diff --git a/sw/speed8/pc/memory.h b/sw/speed8/pc/memory.h new file mode 100644 index 0000000..8a14514 --- /dev/null +++ b/sw/speed8/pc/memory.h @@ -0,0 +1,14 @@ +#ifndef MEMORY_H +#define MEMORY_H + + +extern int get_buffer(uint16_t * buffer); +extern int get_buffer(uint16_t * buffer); + + + + + + + +#endif diff --git a/sw/speed8/pc/rk05.c b/sw/speed8/pc/rk05.c new file mode 100644 index 0000000..588254d --- /dev/null +++ b/sw/speed8/pc/rk05.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include + +#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=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 + +//#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 diff --git a/sw/speed8/pc/rktool.c b/sw/speed8/pc/rktool.c new file mode 100644 index 0000000..0835d37 --- /dev/null +++ b/sw/speed8/pc/rktool.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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] [-l] \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>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; +} diff --git a/sw/speed8/pc/speed8.h b/sw/speed8/pc/speed8.h new file mode 100644 index 0000000..5dc7ed5 --- /dev/null +++ b/sw/speed8/pc/speed8.h @@ -0,0 +1,30 @@ +#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 diff --git a/sw/speed8/pdp8/.gitignore b/sw/speed8/pdp8/.gitignore new file mode 100644 index 0000000..5ba71cc --- /dev/null +++ b/sw/speed8/pdp8/.gitignore @@ -0,0 +1,3 @@ +*.lst +*.rim +*.BN \ No newline at end of file diff --git a/sw/speed8/pdp8/Makefile b/sw/speed8/pdp8/Makefile new file mode 100644 index 0000000..bcd9ef4 --- /dev/null +++ b/sw/speed8/pdp8/Makefile @@ -0,0 +1,19 @@ +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 diff --git a/sw/speed8/pdp8/README b/sw/speed8/pdp8/README new file mode 100644 index 0000000..fda7480 --- /dev/null +++ b/sw/speed8/pdp8/README @@ -0,0 +1,6 @@ + +Speed 8 PDP8 part. + +speed8.pal: The source code +SPEED8.PA: Binary source code, created from speed8.pal + diff --git a/sw/speed8/pdp8/SPEED8.PA b/sw/speed8/pdp8/SPEED8.PA new file mode 100644 index 0000000..4ad1464 --- /dev/null +++ b/sw/speed8/pdp8/SPEED8.PA @@ -0,0 +1,256 @@ +*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 diff --git a/sw/speed8/pdp8/speed8.pal b/sw/speed8/pdp8/speed8.pal new file mode 100644 index 0000000..617c195 --- /dev/null +++ b/sw/speed8/pdp8/speed8.pal @@ -0,0 +1,392 @@ + +/ 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 +/ + +*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 + + +$ -- 2.32.0