From e0e58fce66fba074e64e78d123571e02646368e2 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 16 Mar 2016 12:49:03 -0700 Subject: [PATCH] PDP15: Update pdp18b_rp from Bob Supnik. 1. Added RP03 support and supporting "SET" commands. 2. Fixed implementation of DPCF (it's a full reset and not blocked by BUSY). 3. Fixed handling of JOB DONE flag (not touched by NOP, SEEK, or RECAL). --- PDP18B/pdp18b_rp.c | 109 ++++++++++++++++++++++++++++++--------------- doc/pdp18b_doc.doc | Bin 111104 -> 111104 bytes 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/PDP18B/pdp18b_rp.c b/PDP18B/pdp18b_rp.c index 18c3c676..912d3968 100644 --- a/PDP18B/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -23,8 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - rp RP15/RP02 disk pack + rp RP15/RP02/RP03 disk pack + 15-Mar-16 RMS Added RP03 support + Fixed handling of done flag 07-Mar-16 RMS Revised for dynamically allocated memory 13-Sep-15 RMS Added APIVEC register 14-Jan-04 RMS Revised IO device call interface @@ -46,15 +48,20 @@ #define RP_NUMWD 256 /* words/sector */ #define RP_NUMSC 10 /* sectors/surface */ #define RP_NUMSF 20 /* surfaces/cylinder */ -#define RP_NUMCY 203 /* cylinders/drive */ +#define RP02_NUMCY 203 /* cylinders/drive */ +#define RP03_NUMCY 406 #define RP_NUMDR 8 /* drives/controller */ -#define RP_SIZE (RP_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD) - /* words/drive */ +#define RP02_SIZE (RP02_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD) +#define RP03_SIZE (RP03_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD) +#define RP_QCYL(f) (((f) & UNIT_RP03)? RP03_NUMCY: RP02_NUMCY) +#define RP_QSIZE(f) (((f) & UNIT_RP03)? RP03_SIZE: RP02_SIZE) /* Unit specific flags */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_V_RP03 (UNIT_V_UF + 1) /* RP03 */ #define UNIT_WLK (1u << UNIT_V_WLK) +#define UNIT_RP03 (1u << UNIT_V_RP03) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Parameters in the unit descriptor */ @@ -120,16 +127,23 @@ #define DA_V_SECT 0 /* sector */ #define DA_M_SECT 017 +#define DA_V_C256 4 +#define DA_C256 (1 << DA_V_C256) #define DA_V_SURF 5 #define DA_M_SURF 037 #define DA_V_CYL 10 /* cylinder */ #define DA_M_CYL 0377 #define GET_SECT(x) (((x) >> DA_V_SECT) & DA_M_SECT) #define GET_SURF(x) (((x) >> DA_V_SURF) & DA_M_SURF) -#define GET_CYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) +#define GET_CYL(x) ((((x) >> DA_V_CYL) & DA_M_CYL) + \ + (((x) & DA_C256)? 256: 0)) #define GET_DA(x) ((((GET_CYL (x) * RP_NUMSF) + GET_SURF (x)) * \ RP_NUMSC) + GET_SECT (x)) +/* Current cylinder */ + +#define CCYL_RP03 0400000 /* RP03 flag */ + #define RP_MIN 2 #define MAX(x,y) (((x) > (y))? (x): (y)) @@ -154,6 +168,7 @@ int32 rp64 (int32 dev, int32 pulse, int32 dat); int32 rp_iors (void); t_stat rp_svc (UNIT *uptr); void rp_updsta (int32 newa, int32 newb); +t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rp_reset (DEVICE *dptr); t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_detach (UNIT *uptr); @@ -169,14 +184,14 @@ t_stat rp_detach (UNIT *uptr); DIB rp_dib = { DEV_RP, 2, &rp_iors, { &rp63, &rp64 } }; UNIT rp_unit[] = { - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) } + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) }, + { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP02_SIZE) } }; REG rp_reg[] = { @@ -196,6 +211,8 @@ REG rp_reg[] = { }; MTAB rp_mod[] = { + { UNIT_RP03, 0, "RP02", "RP02", &rp_set_size }, + { UNIT_RP03, UNIT_RP03, "RP03", "RP03", &rp_set_size }, { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, @@ -204,7 +221,7 @@ MTAB rp_mod[] = { DEVICE rp_dev = { "RP", rp_unit, rp_reg, rp_mod, - RP_NUMDR, 8, 24, 1, 8, 18, + RP_NUMDR, 8, 26, 1, 8, 18, NULL, NULL, &rp_reset, NULL, &rp_attach, &rp_detach, &rp_dib, DEV_DISABLE @@ -236,20 +253,21 @@ if (pulse & 02) { } if (pulse & 04) { if (rp_busy) { /* busy? */ - rp_updsta (0, STB_PGE); + rp_updsta (0, STB_PGE); /* prog error */ return dat; } else if (sb == 000) { /* DPLA */ + int32 u = GET_UNIT (rp_sta); rp_da = dat & DMASK; if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0); if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0); - if (GET_CYL (rp_da) >= RP_NUMCY) + if (GET_CYL (rp_da) >= RP_QCYL (rp_unit[u].flags)) rp_updsta (STA_NXC, 0); } else if (sb == 020) { /* DPCS */ - rp_sta = rp_sta & ~(STA_HNF | STA_DON); + rp_sta = rp_sta & ~(STA_HNF | STA_DON); /* clr err, done */ rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE | STB_TME | STB_PGE | STB_EOP); rp_updsta (0, 0); @@ -275,8 +293,11 @@ if (pulse & 01) { dat = IOT_SKP | dat; } if (pulse & 02) { - if (sb == 000) /* DPOU */ - dat = dat | rp_unit[GET_UNIT (rp_sta)].CYL; + if (sb == 000) { /* DPOU */ + u = GET_UNIT (rp_sta); + uptr = rp_dev.units + u; /* select unit */ + dat = dat | uptr->CYL | ((uptr->flags & UNIT_RP03)? CCYL_RP03: 0); + } else if (sb == 020) /* DPOA */ dat = dat | rp_da; else if (sb == 040) /* DPOC */ @@ -285,25 +306,26 @@ if (pulse & 02) { dat = dat | rp_wc; } if (pulse & 04) { - if (rp_busy) { /* busy? */ - rp_updsta (0, STB_PGE); + if (sb == 000) { /* DPCF */ + rp_reset (&rp_dev); /* reset dev */ return dat; } - if (sb == 000) /* DPCF */ - rp_sta = rp_sta & ~STA_RW; - else if (sb == 020) /* DPLZ */ + if (rp_busy != 0) { /* others: busy? */ + rp_updsta (0, STB_PGE); /* prog error */ + return dat; + } + if (sb == 020) /* DPLZ */ rp_sta = rp_sta & (dat | ~STA_RW); else if (sb == 040) /* DPLO */ rp_sta = rp_sta | (dat & STA_RW); else if (sb == 060) /* DPLF */ rp_sta = (rp_sta & ~STA_RW) | (dat & STA_RW); - rp_sta = rp_sta & ~STA_DON; /* clear done */ u = GET_UNIT (rp_sta); /* get unit num */ uptr = rp_dev.units + u; /* select unit */ if ((rp_sta & STA_GO) && !sim_is_active (uptr)) { f = uptr->FUNC = GET_FUNC (rp_sta); /* get function */ rp_busy = 1; /* set ctrl busy */ - rp_sta = rp_sta & ~(STA_HNF | STA_DON); /* clear flags */ + rp_sta = rp_sta & ~STA_HNF; /* clear flag */ rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE | STB_TME | STB_PGE | STB_EOP | (1 << (STB_V_ATT0 - u))); if (((uptr->flags & UNIT_ATT) == 0) || (f == FN_IDLE) || @@ -313,6 +335,7 @@ if (pulse & 04) { c = GET_CYL (rp_da); c = abs (c - uptr->CYL) * rp_swait; /* seek time */ sim_activate (uptr, MAX (RP_MIN, c + rp_rwait)); + rp_sta = rp_sta & ~STA_DON; /* clear done */ } } } @@ -323,7 +346,7 @@ return dat; /* Unit service If function = idle, clear busy - If seek or recal initial state, clear attention line, compute seek time, + If seek or recal initial state, clear busy, compute seek time, put on cylinder, set second state If unit not attached, give error If seek or recal second state, set attention line, compute errors @@ -375,13 +398,14 @@ if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0); if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0); -if (GET_CYL (rp_da) >= RP_NUMCY) +if (GET_CYL (rp_da) >= RP_QCYL (uptr->flags)) rp_updsta (STA_NXC, 0); if (rp_sta & (STA_NXS | STA_NXF | STA_NXC)) { /* or bad disk addr? */ rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */ return SCPE_OK; } +uptr->CYL = GET_CYL (rp_da); /* on cylinder */ pa = rp_ma & AMASK; /* get mem addr */ da = GET_DA (rp_da) * RP_NUMWD; /* get disk addr */ wc = 01000000 - rp_wc; /* get true wc */ @@ -389,12 +413,12 @@ if (((uint32) (pa + wc)) > MEMSIZE) { /* memory overrun? */ nexm = 1; /* set nexm flag */ wc = MEMSIZE - pa; /* limit xfer */ } -if ((da + wc) > RP_SIZE) { /* disk overrun? */ +if ((da + wc) > RP_QSIZE (uptr->flags)) { /* disk overrun? */ rp_updsta (0, STB_EOP); /* error */ - wc = RP_SIZE - da; /* limit xfer */ + wc = RP_QSIZE (uptr->flags) - da; /* limit xfer */ } -err = fseek (uptr->fileref, da * sizeof (int), SEEK_SET); +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); if ((f == FN_READ) && (err == 0)) { /* read? */ awc = fxread (&M[pa], sizeof (int32), wc, uptr->fileref); @@ -407,7 +431,7 @@ if ((f == FN_WRITE) && (err == 0)) { /* write? */ fxwrite (&M[pa], sizeof (int32), wc, uptr->fileref); err = ferror (uptr->fileref); if ((err == 0) && (i = (wc & (RP_NUMWD - 1)))) { - fxwrite (fill, sizeof (int), i, uptr->fileref); + fxwrite (fill, sizeof (int32), i, uptr->fileref); err = ferror (uptr->fileref); } } @@ -427,11 +451,13 @@ rp_wc = (rp_wc + wc) & DMASK; /* final word count */ rp_ma = (rp_ma + wc) & DMASK; /* final mem addr */ da = (da + wc + (RP_NUMWD - 1)) / RP_NUMWD; /* final sector num */ cyl = da / (RP_NUMSC * RP_NUMSF); /* get cyl */ -if (cyl >= RP_NUMCY) - cyl = RP_NUMCY - 1; +if (cyl >= RP_QCYL (uptr->flags)) /* cyl ovflo wraps */ + cyl = 0; surf = (da % (RP_NUMSC * RP_NUMSF)) / RP_NUMSC; /* get surface */ sect = (da % (RP_NUMSC * RP_NUMSF)) % RP_NUMSC; /* get sector */ -rp_da = (cyl << DA_V_CYL) | (surf << DA_V_SURF) | (sect << DA_V_SECT); +rp_da = ((cyl & DA_M_CYL) << DA_V_CYL) | (surf << DA_V_SURF) | (sect << DA_V_SECT); +if (cyl >= 256) /* cyl >= 8 bits? */ + rp_da = rp_da | DA_C256; rp_busy = 0; /* clear busy */ rp_updsta (STA_DON, 0); /* set done */ @@ -462,7 +488,7 @@ else if (sim_is_active (uptr)) { if ((f == FN_SEEK) || (f == FN_RECAL)) rp_stb = rp_stb | STB_SUSU | STB_SUNR; } -else if (uptr->CYL >= RP_NUMCY) +else if (uptr->CYL >= RP_QCYL (uptr->flags)) rp_sta = rp_sta | STA_SUSI; if ((rp_sta & STA_EFLGS) || (rp_stb & STB_EFLGS)) rp_sta = rp_sta | STA_ERR; @@ -503,6 +529,7 @@ t_stat rp_attach (UNIT *uptr, char *cptr) { t_stat reason; +uptr->capac = RP_QSIZE (uptr->flags); reason = attach_unit (uptr, cptr); rp_updsta (0, 0); return reason; @@ -518,3 +545,13 @@ reason = detach_unit (uptr); rp_updsta (0, 0); return reason; } + +/* Set size routine */ + +t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; +uptr->capac = RP_QSIZE (val); +return SCPE_OK; +} diff --git a/doc/pdp18b_doc.doc b/doc/pdp18b_doc.doc index 4c6a3850a95eaf85c5c45084faba040216ba0b7e..cddbc23e185e68c3fc762a8a7ed4e8b7ebd8a581 100644 GIT binary patch delta 10294 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 A3C1siiFC_5WGc=6e@>luG6o&Av*_;PXCy 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