diff --git a/README.md b/README.md index 1b59c4f..f5f4b3d 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,12 @@ The maintenance manual has flow charts, schematics and explanations: The code is more or less a transcription of the schematics into C. This means you will not understand it unless you're familiar with the maintenance manual. Pulses are represented as functions, when a pulse triggers another pulse -it does so by the `nextpulse` function which adds a pulse to the list of next pulses. -In the main cpu loop the list of current pulses is iterated and each pulse is called, -then (after checking some external signals) the current and next pulse lists are swapped -and the process begins anew. -The timing was not accurately modeled and there is room for improvement. -Due to the inexact timing the hardware connections (through the memory and IO bus) -were not implemented too accurately. This may change in the future. +it does so by the `pulse` function which queues a pulse in a list +of pulses that are to happen, sorted chronologically. +Between pulses that happen at different times +various things are done like checking external pulses and advancing the +simulation state. +The timing is not yet 100% accurate but it's pretty close. ### Building @@ -36,8 +35,8 @@ Otherwise you need SDL and pthread. ### Running -The cpu (apr), console tty and paper tape/punch are implemented. -There are no other external devices yet. +The cpu (apr), console tty, paper tape and punch, +the data control and DECtape are implemented. The only things missing from the cpu is the repeat key mechanism. ## Verilog Simulation @@ -59,17 +58,72 @@ The TTY is connected to UART over GPIO pins 4 (RX) and 5 (TX) ## File tree -* `emu` source for the emulator -* `verilog` source for the verilog simulation -* `art` everything graphical -* `code` some test code for the PDP-6 -* `panel6` virtual panel for the FPGA -* `tools` tools like an assembler and linker -* `misc` some misc. and old stuff +* emu the C emulator +* emu/main_panel.c main file for emulator with panel simulation +* emu/main_serial.c main file for emulator with panel over serial line +* emu/emu.c top level emulator code +* emu/cmd.c command line interface +* emu/apr.c Arithmetic Processor 166 emulation +* emu/mem.c core and fast memory emulation +* emu/tty.c Teleprinter 626 emulator +* emu/pt.c Paper tape reader 760 and punch 761 emulation +* emu/dc.c Data Control 136 emulation +* emu/dt.c DECtape 551 and 555 emulation +* emu/netmem.c network protocol for shared memory +* emu/util.c various utility functions +* emu/util.h +* emu/test_*.c test code, not too important anymore +* emu/pdp6.h main header +* emu/args.h argument parsing +* emu/elements.inc panel definition +* emu/cmds.txt command line interface documentation +* emu/init.ini emulator init file +* emu/mem_* core memory backing store + +* tools +* tools/dtr2dta.c convert between raw (dtr) and simh (dta) DECtape format +* tools/mkpty.c make a pty and connect to the controlling tty +* tools/mkpty33.c as above but try to pretend an ASR33 +* tools/as6.c an assembler, roughly modeled on MACRO +* tools/ld6.c a loader or relocatable files +* tools/pdp6bin.h +* tools/pdp6common.c useful functions for PDP-6 code +* tools/pdp6common.h +* tools/rel.c I have no recollection of this code +* tools/reltest.c old test code to create a REL file +* tools/test.s old test code for the assembler/linker +* tools/test2.s +* tools/ptdump.c print a paper tape file in octal +* tools/dtdump.c print dtr DECtape + +* verilog +* verilog/apr.v Arithmetic Processor 166 simulation +* verilog/core161c.v Core memory 161C simulation +* verilog/fast162.v Fast memory 162 simulation +* verilog/modules.v utility modules +* verilog/pdp6.v top level module +* verilog/quartus various files for my terasic board +* verilog/test_dec.v inst decoding test +* verilog/test.v misc tests +* verilog/test1.inc +* verilog/test2.inc +* verilog/test_fp.inc + +* code random code for the PDP-6, mostly testing +* code/bootstrap.txt a list of boot loaders +* code/dtboot.s loads the first block from a DECtape +* code/main.s random entry +* code/tty.s tty character IO + +* panel stand alone panel with lots of duplicate code + +* art image files for the panel + +* misc nothing important ## To do - repeat and maint. switches -- test thoroughly! -- devices (test UT, implement 340) -- timing +- improve timing +- implement 340 display +- do more tests diff --git a/emu/dc.c b/emu/dc.c index 84ddfdd..b19c1b2 100644 --- a/emu/dc.c +++ b/emu/dc.c @@ -199,6 +199,7 @@ wake_dc(void *dev) } if(IOB_DATAI){ bus->c12 |= dc->db; +//printf("Sending DB to APR: %012lo\n", dc->db); dc->db_rq = 0; set_dbda_move(dc); } @@ -218,6 +219,7 @@ wake_dc(void *dev) DB_CLR; if(IOB_DATAO_SET){ dc->db |= bus->c12; +//printf("Got DB from APR: %012lo\n", dc->db); set_dbda_move(dc); } diff --git a/emu/dt.c b/emu/dt.c index 3e75e59..04eedfc 100644 --- a/emu/dt.c +++ b/emu/dt.c @@ -116,6 +116,8 @@ makedx(int argc, char *argv[]) /* Control */ +int dtdbg; + enum { TapeEndF = 022, @@ -196,7 +198,18 @@ enum // TODO: not sure if BM SYNC || DATA SYNC is correct #define UTE_ACTIVE_ERROR (!UT_ALL && prev.rw_state == RW_ACTIVE && (BM_SYNC || DATA_SYNC)) -//#define debug(...) printf(__VA_ARGS__) +static void +dbg(char *fmt, ...) +{ + if(dtdbg){ + va_list ap; + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); + } +} + +//#define debug(...) dbg(__VA_ARGS__) #define debug(...) #define PRINT1 \ @@ -262,6 +275,13 @@ char state = 'n'; #define REV (dt->ut_rev && !UT_BM) +/* This is a function for debugging purposes */ +static void +setstat(Dt551 *dt, int state) +{ + dt->rw_state = state; +} + static void dt_tp0(Dt551 *dt) { @@ -327,7 +347,7 @@ dt_tp2(Dt551 *dt) dt->ut_go = 0; dt->ut_tape_end_flag = 1; /* TODO: is this right? */ - dt->rw_state = RW_NULL; + setstat(dt, RW_NULL); } /* Block mark timing. @@ -354,7 +374,7 @@ dt_tp2(Dt551 *dt) /* Send 6 bit byte to DC every two steps when reading */ - if(UT_READ && RW_EVEN) + if(UT_READ && RW_EVEN){ /* except checksums */ if((prev.tdata & 0102) == 0){ int rwb = dt->rwb; @@ -364,6 +384,7 @@ dt_tp2(Dt551 *dt) if(UTE_DC_DISCONNECT) dt->ut_incomp_block = 1; // 3-17 } + } /* Clear LB before reading the reverse checksum */ if(tdedge & 0100) @@ -392,12 +413,12 @@ dt_tp2(Dt551 *dt) if(UT_BM && tbedge & 1 || // 3-6 UT_DATA && tdedge & 0100 || // 3-9 UT_ALL && tbedge & 010) // 3-11 - dt->rw_state = RW_ACTIVE; + setstat(dt, RW_ACTIVE); /* What to do after block */ if(tdedge & 1){ if(RW_DATA_CONT) // 3-10 - dt->rw_state = RW_RQ; + setstat(dt, RW_RQ); if(RW_DATA_STOP) // 3-11 dt->ut_jb_done_flag = 1; /* test checksum. NB: manual says should be 0 @@ -415,7 +436,7 @@ debug("CHECKSUM ERR\n"); /* Catch wrongly set active state; 3-16 */ if(UTE_ACTIVE_ERROR){ dt->ut_info_error = 1; - dt->rw_state = RW_NULL; + setstat(dt, RW_NULL); } /* Catch invalid mark code */ if(UTE_ERROR){ @@ -425,7 +446,7 @@ debug("TRACK ERROR\n"); /* Stop activity once job gets done */ if(!prev.ut_jb_done_flag && dt->ut_jb_done_flag) // 3-8 - dt->rw_state = RW_NULL; + setstat(dt, RW_NULL); } static void @@ -519,9 +540,9 @@ debug("ILL op %d %d %d\n", nunits, dt->ut_btm_switch, UT_WRTM); } if(UT_WRTM) // 3-14 - dt->rw_state = RW_ACTIVE; + setstat(dt, RW_ACTIVE); else if(!UT_DN) // TODO: is this right? - dt->rw_state = RW_RQ; + setstat(dt, RW_RQ); }else /* Don't move during delay. * TODO: is this right? */ @@ -620,7 +641,7 @@ wake_dt(void *dev) } if(bus->devcode == UTC){ if(IOB_STATUS){ -printf("UTC STATUS\n"); +dbg("UTC STATUS\n"); if(dt->ut_units_select) bus->c12 |= F19; if(dt->ut_tape_end_enable) bus->c12 |= F20; if(dt->ut_jb_done_enable) bus->c12 |= F21; @@ -633,7 +654,7 @@ printf("UTC STATUS\n"); bus->c12 |= dt->ut_pia & 07; } if(IOB_CONO_CLEAR){ -//printf("UTC CONO CLEAR\n"); +dbg("UTC CONO CLEAR\n"); dt->ut_incomp_block = 0; dt->ut_wren = 0; dt->time_flag = 0; @@ -643,10 +664,9 @@ printf("UTC STATUS\n"); dt->ut_jb_done_flag = 0; // 3-5 - dt->rw_state = RW_NULL; + setstat(dt, RW_NULL); } if(IOB_CONO_SET){ -//printf("UTC CONO SET\n"); dt->ut_pia = bus->c12 & 07; dt->ut_units = bus->c12>>3 & 07; dt->ut_fcn = bus->c12>>6 & 07; @@ -661,11 +681,30 @@ printf("UTC STATUS\n"); // UT CONO SET LONG, 1ms after UT CONO SET // triggers UT START level until end of delay +dbg("UTC CONO SET %06lo\n", bus->c12 & 0777777); +dbg("SEL/%o GO/%o REV/%o TIME/%o FCN/%o\n", dt->ut_units_select, + dt->ut_go, dt->ut_rev, + dt->ut_time, dt->ut_fcn); + /* update selection, also done after delay */ selectdx(dt); dt->delay = 0; if(dt->ut_time){ + + /* TODO: unsure what to do here. + * The state cleared here usually + * becomes invalid in cases where + * a delay is needed. + * Ideally we simulate those circumstances + * better, but for now clear it here. */ + dt->tmk = 0; + dt->rwb = 0; + dt->tbm = 0; + dt->tdata = 0; + dt->utek = 0; + dt->uteck = 0; + switch(dt->ut_time){ case 1: // 20ms dt->delay = 600; @@ -683,10 +722,11 @@ printf("UTC STATUS\n"); dt->time_flag = 0; // now wait +dbg("starting delay %d\n", dt->delay); }else if(!UT_DN && // TODO: is this right? !UT_WRTM) // 3-14 - dt->rw_state = RW_RQ; + setstat(dt, RW_RQ); } } recalc_dt_req(dt); @@ -717,6 +757,7 @@ dtdep(Device *dev, const char *reg, word data) dt = (Dt551*)dev; if(strcmp(reg, "btm_wr") == 0) dt->ut_btm_switch = data&1; + else if(strcmp(reg, "dbg") == 0) dtdbg = data&1; else return 1; return 0; } diff --git a/emu/init.ini b/emu/init.ini index 212a746..1d4b3ab 100644 --- a/emu/init.ini +++ b/emu/init.ini @@ -34,7 +34,8 @@ attach ptr ../code/test.rim #attach ptr ../lars_sysgen/sysgen.pt attach ptp ../code/ptp.out #attach dx0 ../test/out.dt6 -attach dx0 ../test/test.dt6 +#attach dx0 ../test/test.dt6 +attach dx0 ../test/ddt.dtr #load -b ../maint/pdp6.part1 diff --git a/emu/mem_0 b/emu/mem_0 index b9c6544..cce9b0b 100644 --- a/emu/mem_0 +++ b/emu/mem_0 @@ -9,9 +9,10 @@ 720040000013 345540000006 602540777777 -000000000013 +700600014300 254000000006 -000020: +000017: +254000037726 710600000060 710740000010 254000000021 @@ -20,7 +21,67 @@ 254000000024 000027: 254000000021 -032760: +032664: +052260547440 +400000000000 +052260547463 +401000000000 +052260547467 +402000000000 +052260547454 +403000000000 +052320235340 +700300000000 +052320234450 +700340000000 +052717441670 +700040000000 +052717442250 +700140000000 +051453454300 +700000000000 +051453477100 +700100000000 +052320173300 +700240000000 +052320216100 +700200000000 +064145630000 +000400000000 +064327442000 +010000000000 +064330034000 +010400000000 +067364207000 +012000000000 +061226766000 +012400000000 +053035301000 +013000000000 +052733550000 +020000000000 +070165411000 +021000000000 +070171331000 +021400000000 +052733745000 +061000000000 +052734142000 +061400000000 +053137621000 +060400000000 +075334270000 +000000036636 +075265230000 +000000036633 +012754626000 +032752: +052754626000 +000000034000 +075010344000 +000000036637 +075022154000 +000000036642 075033764000 000000036645 075045574000 @@ -252,7 +313,7 @@ 260040033331 201240000040 254000033430 -340000033526 +740000033526 200240033333 135240037114 261040033333 @@ -449,11 +510,17 @@ 315104033625 000004033634 033640: -254000034135 -340000036170 -340000033435 -340000033435 -034000: +740000034043 +033642: +740000033435 +740000033435 +740000033435 +740000033435 +740000033435 +740000033435 +033776: +777666032664 +000000033776 402000036723 402000036600 356000036630 @@ -679,7 +746,8 @@ 201245000133 260040033430 254000034222 -000010036572 +000310036572 +440700034343 034346: 441100034352 331100034352 @@ -1804,26 +1872,24 @@ 660240000200 254000036471 777666032664 -000000000020 -036525: -000000000020 -000000000020 -000000000024 036534: 777777777777 -036545: -002235510000 +000000032664 +000000032664 036550: -000000000020 -000000000020 -000000000001 +000000037423 +000000037423 +000000000002 036554: 000000000112 -036573: -710600000060 -004400036014 -036577: -000000036545 +000000000105 +036572: +000000000326 +326100037430 +036411000000 +036576: +777666032664 +600000032732 036601: 254000033430 200261777777 @@ -1834,14 +1900,31 @@ 254000033430 205240604040 000000036627 -036631: +036630: +000000000001 000000037777 036633: -340000000000 +740000000200 000000001177 -000000000010 +000215000010 777777777777 -036713: +036673: +777777777777 +036675: +777666032664 +777777000010 +254000037066 +000000000010 +740000037604 +254000037066 +000000000001 +400000000031 +777777777777 +200500037260 +036710: +740000037463 +000000000002 +000000000400 000000036060 000000036134 000000000010 @@ -1849,9 +1932,9 @@ 000000036134 000000000010 777777777777 -000000000020 +000000000001 036726: -340000034010 +740000034010 336000036721 254000036733 350000036726 @@ -2011,3 +2094,266 @@ 300600036626 360610036603 000040000040 +037177: +400000000000 +444464000000 +444464000000 +302000000000 +037255: +757367573675 +020410204102 +020410204102 +020410204102 +020410204102 +041020410204 +041020410204 +041020410204 +041020573674 +661020410204 +041020410204 +041020410204 +041020410204 +041020410204 +041020000000 +037376: +777777777777 +000000000010 +402000037777 +700200635550 +265300037471 +201200037746 +403100037176 +250104000001 +253100037406 +201202777777 +326200037404 +403600000000 +211500000001 +205040400000 +250140000001 +205040400000 +205240020600 +306600000046 +254000037735 +721200000000 +134100037777 +326100037430 +712340000040 +254000037424 +712040000002 +265300037473 +465100000177 +342100037400 +340100000007 +345100037516 +271100000135 +321100037521 +322100037414 +603240770000 +136100000005 +254000037422 +303600000055 +267600037462 +721200000000 +321600037451 +542200037447 +322600037066 +254000037402 +563000033777 +254000034000 +201200037176 +402000000040 +200140037750 +306600000064 +200220033777 +606600000003 +251144777777 +265640037601 +265300037624 +316340000004 +254000037462 +322140037402 +322500037751 +334300037663 +334100037527 +334100037432 +336000037777 +712140000002 +712300000020 +254000037475 +325106000000 +201100000012 +254000037473 +616105000001 +344240037502 +265300037471 +306005740524 +254000037402 +201705740604 +242700777777 +135100037752 +200056037254 +137040037753 +265300037745 +267100037742 +607040004040 +135600000005 +326600037706 +342100037437 +200540037754 +205400777750 +340400037574 +336010037176 +332010037177 +604000000015 +542400037536 +316150037176 +312050037177 +253400037524 +321400037541 +323500037470 +201400000055 +332010037177 +254000037470 +336000000012 +403040000003 +202150037176 +202050037177 +201410000001 +242400777777 +323500037552 +412510037254 +436510037303 +403440000005 +602500000004 +254000037453 +200100037755 +201340037747 +336002000000 +253100037557 +202100000004 +336002000000 +332002000001 +253100037562 +274200000002 +271202000000 +202207000000 +200340000002 +321100037557 +200340037756 +201200037747 +265300037624 +255000000007 +200204000000 +325200037621 +334640037524 +316200037756 +661440400000 +265300037624 +200340000004 +325440037601 +325200037442 +325600037614 +564300000004 +270300000004 +273320033777 +540200000006 +241340000001 +265300037624 +270344000000 +253200037614 +254015000000 +321500037402 +265300037624 +624500037447 +367240037647 +354000000011 +137040000013 +134100000013 +306100000037 +254000037466 +661112777777 +302402000000 +326100037625 +137400000013 +322500037626 +200140037377 +721700000040 +254000037640 +721340200000 +660140002000 +477000000002 +721203220200 +720200004010 +721700000006 +254000037470 +720340001000 +254000037647 +325112037703 +560140037377 +720040000001 +275051000000 +325000037663 +322040037667 +321040037644 +664140002000 +340040037400 +341040037643 +660140010000 +344000037645 +331000000012 +660140000400 +721203220300 +331000000012 +720200003410 +201240000200 +344100037647 +720040000016 +312726000000 +254000037470 +254000037705 +720066000000 +254000037705 +720166000000 +254006000000 +201100000044 +265300037473 +302600000053 +306600000044 +343500037711 +306600000047 +254020037447 +306600000051 +211500000005 +303600000031 +254000037413 +242040000003 +246000000003 +326040037721 +303000000007 +267200037442 +242000000003 +202000037377 +201440000100 +265300037637 +340102037177 +367240037647 +254000037402 +541240037176 +205100770000 +616240037414 +254000037502 +607240770000 +265300037745 +201300037736 +134100000005 +201102000040 +254000037473 +037750: +000040000041 +344500037730 +000116037303 +010100000002 +000500037254 +740623000020 +254000000001 diff --git a/tools/Makefile b/tools/Makefile index 571c0e4..9cf72ba 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,4 +1,4 @@ -all: as6 ld6 ptdump +all: as6 ld6 ptdump dtr2dta dta2dtr as6: as6.c pdp6common.c cc -g as6.c pdp6common.c -o as6 @@ -6,3 +6,9 @@ ld6: ld6.c pdp6common.c cc -g ld6.c pdp6common.c -o ld6 ptdump: ptdump.c pdp6common.c cc -g ptdump.c pdp6common.c -o ptdump + +dtr2dta: dtr2dta.c + cc -o $@ $< + +dta2dtr: dtr2dta.c + cc -o $@ $< diff --git a/test/dtread.c b/tools/dtdump.c similarity index 100% rename from test/dtread.c rename to tools/dtdump.c diff --git a/tools/dtr2dta.c b/tools/dtr2dta.c new file mode 100644 index 0000000..7c12e95 --- /dev/null +++ b/tools/dtr2dta.c @@ -0,0 +1,427 @@ +#include +#include +#include +#include + +#define nil NULL +typedef unsigned char uchar; +typedef unsigned int uint; +typedef uint64_t word; + +enum +{ + TapeEndF = 022, + TapeEndR = 055, + + BlockSpace = 025, + + BlockEndF = 026, + BlockEndR = 045, + + DataSync = 032, /* rev guard */ + BlockSync = 051, /* guard */ + + DataEndF = 073, /* pre-final, final, ck, rev lock */ + DataEndR = 010, /* lock, rev ck, rev final, rev pre-final */ + + Data = 070, + + NUMBLOCKS = 01102, + +// DTSIZE = 922512 + // 01102 blocks, 2700 word for start/end each + safe zone + DTSIZE = 987288 + 1000 +}; + +FILE* +mustopen(const char *name, const char *mode) +{ + FILE *f; + if(f = fopen(name, mode), f == nil){ + fprintf(stderr, "couldn't open file: %s\n", name); + exit(1); + } + return f; +} + +/* Read raw tape data (forward) */ +void +readf(uchar **dtp, uchar *mark, word *wrd) +{ + int i; + uchar l; + uchar m; + word w; + + m = 0; + w = 0; + for(i = 0; i < 6; i++){ + l = *(*dtp)++; + m = (m << 1) | !!(l&010); + w = (w << 3) | l&7; + } + *mark = m; + *wrd = w; +} + +/* Write raw tape data (forwad */ +void +writef(uchar **p, int mark, int *ck, int data) +{ + int i; + uchar d; + if(ck){ + *ck ^= ~data & 077; + *ck ^= ~data>>6 & 077; + *ck ^= ~data>>12 & 077; + } + for(i = 0; i < 6; i++){ + if(mark) + d = !!(mark & 040) << 3; + else + d = !!(**p & 010) << 3; + if(data & 01000000) + d |= **p & 07; + else{ + d |= (data & 0700000) >> 15; + data = (data << 3) & 0777777; + } + mark <<= 1; + **p = d; + (*p)++; + } +} + +#define LDB(p, s, w) ((w)>>(p) & (1<<(s))-1) +#define XLDB(ppss, w) LDB((ppss)>>6 & 077, (ppss)&077, w) +#define MASK(p, s) ((1<<(s))-1 << (p)) +#define DPB(b, p, s, w) ((w)&~MASK(p,s) | (b)<<(p) & MASK(p,s)) +#define XDPB(b, ppss, w) DPB(b, (ppss)>>6 & 077, (ppss)&077, w) + +void +writesimh(FILE *f, word w) +{ + uchar c[8]; + uint l, r; + + r = LDB(0, 18, w); + l = LDB(18, 18, w); + c[0] = LDB(0, 8, l); + c[1] = LDB(8, 8, l); + c[2] = LDB(16, 8, l); + c[3] = LDB(24, 8, l); + c[4] = LDB(0, 8, r); + c[5] = LDB(8, 8, r); + c[6] = LDB(16, 8, r); + c[7] = LDB(24, 8, r); + fwrite(c, 1, 8, f); +} + +word +readsimh(FILE *f) +{ + uchar c[8]; + word w[2]; + if(fread(c, 1, 8, f) != 8) + return ~0; + w[0] = c[3]<<24 | c[2]<<16 | c[1]<<8 | c[0]; + w[1] = c[7]<<24 | c[6]<<16 | c[5]<<8 | c[4]; + return (w[0]<<18 | w[1]) & 0777777777777; +} + +char* +tostr(int m) +{ + return m == TapeEndF ? "End Zone Fwd" : + m == TapeEndR ? "End Zone Rev" : + m == BlockSpace ? "Block Space" : + m == BlockEndF ? "Block End Fwd" : + m == BlockEndR ? "Block End Rev" : + m == DataSync ? "Data Sync" : + m == BlockSync ? "Block Sync" : + m == DataEndF ? "Data End Fwd" : + m == DataEndR ? "Data End Rev" : + m == Data ? "Data" : + "Unknown"; +} + +void +rawdump(uchar *dtp) +{ + uchar mark; + word w; + uchar *end; + end = dtp + DTSIZE; + while(dtp < end){ + readf(&dtp, &mark, &w); + printf("%02o[%-13s] %06o\n", mark, tostr(mark), w); + } +} + +#define CHKWORD(exp) \ + readf(&dtp, &mark, &w); \ + if(mark != exp){ \ + fprintf(stderr, "expected %s(%02o) got %s(%02o)\n", \ + tostr(exp), exp, tostr(mark), mark); \ + return 0; \ + } \ + +int +validate(uchar *dtp) +{ + uchar mark; + word w; + int i, j; + + CHKWORD(TapeEndR); + CHKWORD(TapeEndR); + for(i = 0; i < NUMBLOCKS; i++){ + CHKWORD(BlockSpace); + CHKWORD(BlockEndF); + CHKWORD(DataSync); + CHKWORD(DataEndR); + CHKWORD(DataEndR); + CHKWORD(DataEndR); + CHKWORD(DataEndR); + for(j = 1; j < 127; j++){ + CHKWORD(Data); + CHKWORD(Data); + } + CHKWORD(DataEndF); + CHKWORD(DataEndF); + CHKWORD(DataEndF); + CHKWORD(DataEndF); + CHKWORD(BlockSync); + CHKWORD(BlockEndR); + CHKWORD(BlockSpace); + } + CHKWORD(TapeEndF); + CHKWORD(TapeEndF); + return 1; +} + +void +dumpdta(uchar *dtp, FILE *f) +{ + uchar mark; + word w, w2; + int i, j; + + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w); + for(i = 0; i < NUMBLOCKS; i++){ + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w2); + w = w << 18 | w2; + + // data unused + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w2); + w = w << 18 | w2; + + readf(&dtp, &mark, &w); + for(j = 0; j < 128; j++){ + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w2); + writesimh(f, w<<18 | w2); + } + readf(&dtp, &mark, &w); + + // data unused + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w2); + w = w << 18 | w2; + + // reverse block mark + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w2); + w = w << 18 | w2; + } + readf(&dtp, &mark, &w); + readf(&dtp, &mark, &w); +} + +void +wrf(FILE *f, int mark, int *ck, int data) +{ + uchar buf[6], *p; + p = buf; + writef(&p, mark, ck, data); + fwrite(buf, 1, 6, f); +}; + +void +dumpdtr(word *wp, word *bmp, word *ibp, FILE *f) +{ + word w; + int i, j; + int ck; + + wrf(f, TapeEndR, nil, 0); + wrf(f, TapeEndR, nil, 0); + + for(i = 0; i < NUMBLOCKS; i++){ + w = *bmp++; + wrf(f, BlockSpace, nil, LDB(18, 18, w)); // block mark + wrf(f, BlockEndF, nil, LDB(0, 18, w)); // block mark + + w = *ibp++; + wrf(f, DataSync, nil, LDB(18, 18, w)); + wrf(f, DataEndR, nil, LDB(0, 18, w)); + + ck = 0; + wrf(f, DataEndR, &ck, 0007777); // rev check + + /* the data */ + w = *wp++; + wrf(f, DataEndR, &ck, LDB(18, 18, w)); + wrf(f, DataEndR, &ck, LDB(0, 18, w)); + for(j = 1; j < 127; j++){ + w = *wp++; + wrf(f, Data, &ck, LDB(18, 18, w)); + wrf(f, Data, &ck, LDB(0, 18, w)); + } + w = *wp++; + wrf(f, DataEndF, &ck, LDB(18, 18, w)); + wrf(f, DataEndF, &ck, LDB(0, 18, w)); + + wrf(f, DataEndF, nil, (ck & 077) << 12 | 07777); // check + + w = *ibp++; + wrf(f, DataEndF, nil, LDB(18, 18, w)); + wrf(f, BlockSync, nil, LDB(0, 18, w)); + + w = *bmp++; + wrf(f, BlockEndR, nil, LDB(18, 18, w)); // rev block mark + wrf(f, BlockSpace, nil, LDB(0, 18, w)); // rev block mark + } + + wrf(f, TapeEndF, nil, 0); + wrf(f, TapeEndF, nil, 0); +} + +uchar* +findstart(uchar *buf) +{ + uchar *t; + int i; + word w; + uchar m; + + for(i = 0; i < 1000; i++){ + t = buf; + readf(&t, &m, &w); + if(m == TapeEndR) + goto found; + buf++; + } + return nil; +found: + while(readf(&buf, &m, &w), m == TapeEndR); + return buf-18; +} + +uchar dtbuf[DTSIZE], *dtp; +word blockbuf[NUMBLOCKS*0200]; +word bmbuf[NUMBLOCKS*2]; +word ibbuf[NUMBLOCKS*2]; + +/* Fill block mark and interblock word buffers */ +void +makefmt(void) +{ + int i, j; + word co; + + for(i = 0; i < NUMBLOCKS; i++){ + /* forward and reverse block number */ + bmbuf[i*2] = i; + // last one is 700707070707 really because it can't be written easily + co = 0; + for(j = 0; j < 12; j++) + co |= ((bmbuf[i*2]>>j*3) & 07) << (11-j)*3; + co ^= 0777777777777; + bmbuf[i*2+1] = co; + + /* interblock words - used to find block 75 which contains the loader */ + + /* forward word */ + if(i < 075) + ibbuf[i*2] = 0721200220107; // move forward + else if(i == 075) + ibbuf[i*2] = 0577777777777; // nop + else + ibbuf[i*2] = 0721200233107; // move backward + + /* reverse word */ + // last one is 777077707007 really because it can't be written easily + if(i < 073) + ibbuf[i*2+1] = 0721200223107; // move forward + else + ibbuf[i*2+1] = 0721200230107; // move backward + } + + /* Last block isn't written quite correctly. To simulate: */ + // ibbuf[01101*2 + 0] = 0077070007000; + // ibbuf[01101*2 + 1] = 0777077707007; + // bmbuf[01101*2 + 1] = 0700707070707; +} + +int +readdtr(FILE *f) +{ + fread(dtbuf, 1, DTSIZE, f); + fclose(f); + dtp = findstart(dtbuf); + if(dtp == nil){ + fprintf(stderr, "no start\n"); + return 1; + } + if(!validate(dtp)){ + fprintf(stderr, "invalid file format\n"); + return 1; + } + return 0; +} + +int +readdta(FILE *f) +{ + word w; + int n; + + n = 0; + while(w = readsimh(f), w != ~0 && n < NUMBLOCKS*0200) + blockbuf[n++] = w; + return n != NUMBLOCKS*0200; +} + +int +dtr2dta(void) +{ + if(readdtr(stdin)) + return 1; + dumpdta(dtp, stdout); + return 0; +} + +int +dta2dtr(void) +{ + if(readdta(stdin)) + return 1; + makefmt(); + dumpdtr(blockbuf, bmbuf, ibbuf, stdout); + return 0; +} + +int +main(int argc, char *argv[]) +{ + + if(strstr(argv[0], "dtr2dta")) return dtr2dta(); + else if(strstr(argv[0], "dta2dtr")) return dta2dtr(); + else fprintf(stderr, "Unknown %s\n", argv[0]); + + return 0; +} diff --git a/misc/mkpty.c b/tools/mkpty.c similarity index 100% rename from misc/mkpty.c rename to tools/mkpty.c diff --git a/misc/mkpty33.c b/tools/mkpty33.c similarity index 100% rename from misc/mkpty33.c rename to tools/mkpty33.c