From 14dccaa4e7c1b34630c62a76e2e386a9817af5b5 Mon Sep 17 00:00:00 2001 From: Bob Supnik Date: Fri, 17 Jun 2022 09:03:47 -0700 Subject: [PATCH] simh v3.12-2 --- Interdata/id_fd.c | 5 +- PDP11/pdp11_rq.c | 274 +++++++++++- doc/pdp11_doc.doc | Bin 211456 -> 210944 bytes doc/simh_doc.doc | Bin 214016 -> 166912 bytes makefile | 1074 +++++++++++++++++++++++++++++++++++++-------- scp.c | 273 +++++++----- sim_defs.h | 235 +++++++--- sim_rev.h | 93 +++- 8 files changed, 1574 insertions(+), 380 deletions(-) diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index d4944394..3293eb14 100644 --- a/Interdata/id_fd.c +++ b/Interdata/id_fd.c @@ -1,6 +1,6 @@ /* id_fd.c: Interdata floppy disk simulator - Copyright (c) 2001-2013, Robert M Supnik + Copyright (c) 2001-2021, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ fd M46-630 floppy disk + 31-Jan-21 RMS Revised for new register macros 03-Sep-13 RMS Added explicit void * cast 19-Mar-12 RMS Fixed macro naming conflict (Mark Pizzolato) @@ -169,7 +170,7 @@ REG fd_reg[] = { { HRDATA (STA, fd_sta, 8) }, { HRDATA (BUF, fd_db, 8) }, { HRDATA (LRN, fd_lrn, 16) }, - { BRDATA (ESTA, fd_es, 16, 8, ES_SIZE * FD_NUMDR) }, + { CRDATA (ESTA, fd_es, 16, 8, ES_SIZE * FD_NUMDR) }, { BRDATA (DBUF, fdxb, 16, 8, FD_NUMBY) }, { HRDATA (DBPTR, fd_bptr, 8) }, { FLDATA (WDV, fd_wdv, 0) }, diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index ffbdb085..25af52ac 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1,6 +1,6 @@ /* pdp11_rq.c: MSCP disk controller simulator - Copyright (c) 2002-2018, Robert M Supnik + Copyright (c) 2002-2022, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,8 @@ rq RQDX3 disk controller + 06=Mar-22 RMS Added more disk types (Mark Pizzolato) + 31-Jan-21 RMS Revised for new register macros 28-May-18 RMS Changed to avoid nested comment warnings (Mark Pizzolato) 23-Oct-13 RMS Revised for new boot setup routine 17-Mar-13 RMS Fixed bug in ABORT link walk loop (Dave Bryan) @@ -249,6 +251,7 @@ x RA73 70(+1) 21 2667+ 21 1 ? 3920490 #define RQDF_RMV 01 /* removable */ #define RQDF_RO 02 /* read only */ #define RQDF_SDI 04 /* SDI drive */ +#define RQDF_DSSI 010 /* DSSI drive */ #define RX50_DTYPE 0 #define RX50_SECT 10 @@ -525,6 +528,160 @@ x RA73 70(+1) 21 2667+ 21 1 ? 3920490 #define RD32_MED 0x25644020 #define RD32_FLGS 0 +/* Below here, imported from V4 */ + +#define RC25_DTYPE 17 /* */ +#define RC25_SECT 50 /* */ +#define RC25_SURF 8 +#define RC25_CYL 1260 /* */ +#define RC25_TPG RC25_SURF +#define RC25_GPC 1 +#define RC25_XBN 0 /* */ +#define RC25_DBN 0 /* */ +#define RC25_LBN 50902 /* ? 50*8*1260 ? */ +#define RC25_RCTS 0 /* */ +#define RC25_RCTC 1 +#define RC25_RBN 0 /* */ +#define RC25_MOD 2 +#define RC25_MED 0x20643019 +#define RC25_FLGS RQDF_RMV + +#define RCF25_DTYPE 18 /* */ +#define RCF25_SECT 50 /* */ +#define RCF25_SURF 8 +#define RCF25_CYL 1260 /* */ +#define RCF25_TPG RCF25_SURF +#define RCF25_GPC 1 +#define RCF25_XBN 0 /* */ +#define RCF25_DBN 0 /* */ +#define RCF25_LBN 50902 /* ? 50*8*1260 ? */ +#define RCF25_RCTS 0 /* */ +#define RCF25_RCTC 1 +#define RCF25_RBN 0 /* */ +#define RCF25_MOD 3 +#define RCF25_MED 0x20643319 +#define RCF25_FLGS 0 + +#define RA80_DTYPE 19 /* SDI drive */ +#define RA80_SECT 31 /* +1 spare/track */ +#define RA80_SURF 14 +#define RA80_CYL 546 /* */ +#define RA80_TPG RA80_SURF +#define RA80_GPC 1 +#define RA80_XBN 0 /* */ +#define RA80_DBN 0 /* */ +#define RA80_LBN 237212 /* 31*14*546 */ +#define RA80_RCTS 0 /* */ +#define RA80_RCTC 1 +#define RA80_RBN 0 /* */ +#define RA80_MOD 1 +#define RA80_MED 0x25641050 +#define RA80_FLGS RQDF_SDI + +// [RLA] Most of these RA70 parameters came from doing a DUSTAT on a real +// [RLA] RA70 drive. The remainder are just educated guesses... + +#define RA70_DTYPE 20 /* SDI drive */ +#define RA70_SECT 33 /* +1 spare/track */ +#define RA70_SURF 11 /* tracks/cylinder */ +#define RA70_CYL 1507 /* 0-1506 user */ +#define RA70_TPG RA70_SURF +#define RA70_GPC 1 +#define RA70_XBN 0 /* ??? */ +#define RA70_DBN 0 /* ??? */ +#define RA70_LBN 547041 /* 33*11*1507 */ +#define RA70_RCTS 198 /* Size of the RCT */ +#define RA70_RCTC 7 /* Number of RCT copies */ +#define RA70_RBN 16577 /* 1*11*1507 */ +#define RA70_MOD 18 +#define RA70_MED 0x25641046 /* RA70 MEDIA ID */ +#define RA70_FLGS RQDF_SDI + +// [RLA] Likewise for the RA73 ... +#define RA73_DTYPE 21 /* SDI drive */ +#define RA73_SECT 70 /* +1 spare/track */ +#define RA73_SURF 21 /* tracks/cylinder */ +#define RA73_CYL 2667 /* 0-2666 user */ +#define RA73_TPG RA73_SURF +#define RA73_GPC 1 +#define RA73_XBN 0 /* ??? */ +#define RA73_DBN 0 /* ??? */ +#define RA73_LBN 3920490 /* 70*21*2667 */ +#define RA73_RCTS 198 /* Size of the RCT ??????*/ +#define RA73_RCTC 7 /* Number of RCT copies */ +#define RA73_RBN 56007 /* 1*21*2667 */ +#define RA73_MOD 47 +#define RA73_MED 0x25641049 /* RA73 MEDIA ID */ +#define RA73_FLGS RQDF_SDI + +/* The RF drives don't have any useful error parameters. */ +/* These entries are derived from basic geometry and size */ +/* info in Ultrix 4.5 disktab entries. */ + +#define RF30_DTYPE 22 /* DSSI drive */ +#define RF30_SECT 37 /* +1 spare/track */ +#define RF30_SURF 6 +#define RF30_CYL 1320 /* 0-1914 user */ +#define RF30_TPG RF30_SURF +#define RF30_GPC 1 +#define RF30_XBN 1456 /* cyl 1917-1918? */ +#define RF30_DBN 1456 /* cyl 1919-1920? */ +#define RF30_LBN 293040 /* 37*6*1320 */ +#define RF30_RCTS 1428 /* cyl 1915-1916? */ +#define RF30_RCTC 1 +#define RF30_RBN 26810 /* 1 *14*1915 */ +#define RF30_MOD 21 +#define RF30_MED 0x2264601E +#define RF30_FLGS RQDF_DSSI + +#define RF31_DTYPE 23 /* DSSI drive */ +#define RF31_SECT 50 /* +1 spare/track */ +#define RF31_SURF 8 +#define RF31_CYL 1861 /* 0-1860 user */ +#define RF31_TPG RF31_SURF +#define RF31_GPC 1 +#define RF31_XBN 1456 /* cyl 1917-1918? */ +#define RF31_DBN 1456 /* cyl 1919-1920? */ +#define RF31_LBN 744400 /* 50*8*1861 */ +#define RF31_RCTS 1428 /* cyl 1915-1916? */ +#define RF31_RCTC 1 +#define RF31_RBN 26810 /* 1 *14*1915 */ +#define RF31_MOD 27 +#define RF31_MED 0x2264601F +#define RF31_FLGS RQDF_DSSI + +#define RF71_DTYPE 24 /* DSSI drive */ +#define RF71_SECT 37 /* +1 spare/track */ +#define RF71_SURF 16 +#define RF71_CYL 1320 /* 0-1914 user */ +#define RF71_TPG RF71_SURF +#define RF71_GPC 1 +#define RF71_XBN 1456 /* cyl 1917-1918? */ +#define RF71_DBN 1456 /* cyl 1919-1920? */ +#define RF71_LBN 781440 /* 37*16*1320 */ +#define RF71_RCTS 1428 /* cyl 1915-1916? */ +#define RF71_RCTC 1 +#define RF71_RBN 26810 /* 1 *14*1915 */ +#define RF71_MOD 40 +#define RF71_MED 0x22646047 +#define RF71_FLGS RQDF_DSSI + +#define RF72_DTYPE 25 /* DSSI drive */ +#define RF72_SECT 50 /* +1 spare/track */ +#define RF72_SURF 21 +#define RF72_CYL 1861 /* 0-1860 user */ +#define RF72_TPG RF72_SURF +#define RF72_GPC 1 +#define RF72_XBN 1456 /* cyl 1917-1918? */ +#define RF72_DBN 1456 /* cyl 1919-1920? */ +#define RF72_LBN 1954050 /* 50*21*1861 */ +#define RF72_RCTS 1428 /* cyl 1915-1916? */ +#define RF72_RCTC 1 +#define RF72_RBN 26810 /* 1 *14*1915 */ +#define RF72_MOD 28 +#define RF72_MED 0x22646048 +#define RF72_FLGS RQDF_DSSI + struct drvtyp { int32 sect; /* sectors */ int32 surf; /* surfaces */ @@ -551,15 +708,87 @@ struct drvtyp { #define RQ_SIZE(d) (d##_LBN * RQ_NUMBY) static struct drvtyp drv_tab[] = { - { RQ_DRV (RX50), "RX50" }, { RQ_DRV (RX33), "RX33" }, - { RQ_DRV (RD51), "RD51" }, { RQ_DRV (RD31), "RD31" }, - { RQ_DRV (RD52), "RD52" }, { RQ_DRV (RD53), "RD53" }, - { RQ_DRV (RD54), "RD54" }, { RQ_DRV (RA82), "RA82" }, - { RQ_DRV (RRD40), "RRD40" }, { RQ_DRV (RA72), "RA72" }, - { RQ_DRV (RA90), "RA90" }, { RQ_DRV (RA92), "RA92" }, - { RQ_DRV (RA8U), "RAUSER" }, { RQ_DRV (RA60), "RA60" }, - { RQ_DRV (RA81), "RA81" }, { RQ_DRV (RA71), "RA71" }, + { RQ_DRV (RX50), "RX50" }, + { RQ_DRV (RX33), "RX33" }, + { RQ_DRV (RD51), "RD51" }, + { RQ_DRV (RD31), "RD31" }, + { RQ_DRV (RD52), "RD52" }, + { RQ_DRV (RD53), "RD53" }, + { RQ_DRV (RD54), "RD54" }, + { RQ_DRV (RA82), "RA82" }, + { RQ_DRV (RRD40), "RRD40" }, + { RQ_DRV (RA72), "RA72" }, + { RQ_DRV (RA90), "RA90" }, + { RQ_DRV (RA92), "RA82" }, + { RQ_DRV (RA8U), "RAUSER" }, + { RQ_DRV (RA60), "RA60" }, + { RQ_DRV (RA81), "RA81" }, + { RQ_DRV (RA71), "RA71" }, { RQ_DRV (RD32), "RD32" }, + { RQ_DRV (RC25), "RC25" }, + { RQ_DRV (RCF25), "RCF25" }, + { RQ_DRV (RA80), "RA80" }, + { RQ_DRV (RA70), "RA70" }, + { RQ_DRV (RA73), "RA73" }, + { RQ_DRV (RF30), "RF30" }, + { RQ_DRV (RF31), "RF31" }, + { RQ_DRV (RF71), "RF71" }, + { RQ_DRV (RF72), "RF72" }, + { 0 } + }; + +/* Controller parameters */ + +#define DEFAULT_CTYPE 0 + +// AFAIK the UNIBUS KLESI and QBUS KLESI used the same controller type... + +#define KLESI_CTYPE 1 // RC25 controller (UNIBUS and QBUS both) +#define KLESI_UQPM 1 +#define KLESI_MODEL 1 + +#define RUX50_CTYPE 2 // UNIBUS RX50-only controller +#define RUX50_UQPM 2 +#define RUX50_MODEL 2 + +#define UDA50_CTYPE 3 // UNIBUS SDI (RAxx) controller +#define UDA50_UQPM 6 +#define UDA50_MODEL 6 + +#define RQDX3_CTYPE 4 // QBUS RX50/RDxx controller +#define RQDX3_UQPM 19 +#define RQDX3_MODEL 19 + +#define KDA50_CTYPE 5 // QBUS SDI (RAxx) controller +#define KDA50_UQPM 13 +#define KDA50_MODEL 13 + +#define KRQ50_CTYPE 6 // QBUS RRD40/50 CDROM controller +#define KRQ50_UQPM 16 +#define KRQ50_MODEL 16 + +#define KRU50_CTYPE 7 // UNIBUS RRD40/50 CDROM controller +#define KRU50_UQPM 26 +#define KRU50_MODEL 26 + +struct ctlrtyp { + uint32 uqpm; /* port model */ + uint16 model; /* controller model */ + const char *name; /* name */ + }; + +#define RQ_CTLR(d) \ + d##_UQPM, d##_MODEL + +static struct ctlrtyp ctlr_tab[] = { + { 0, 0, "DEFAULT" }, + { RQ_CTLR (KLESI), "KLESI" }, + { RQ_CTLR (RUX50), "RUX50" }, + { RQ_CTLR (UDA50), "UDA50" }, + { RQ_CTLR (RQDX3), "RQDX3" }, + { RQ_CTLR (KDA50), "KDA50" }, + { RQ_CTLR (KRQ50), "KRQ50" }, + { RQ_CTLR (KRU50), "KRU50" }, { 0 } }; @@ -592,6 +821,7 @@ typedef struct { uint32 credits; /* credits */ uint32 hat; /* host timer */ uint32 htmo; /* host timeout */ +// uint32 ctype; /* controller type */ struct uq_ring cq; /* cmd ring */ struct uq_ring rq; /* rsp ring */ struct rqpkt pak[RQ_NPKTS]; /* packet queue */ @@ -708,7 +938,7 @@ REG rq_reg[] = { { DRDATA (I4TIME, rq_itime4, 24), PV_LEFT + REG_NZ }, { DRDATA (QTIME, rq_qtime, 24), PV_LEFT + REG_NZ }, { DRDATA (XTIME, rq_xtime, 24), PV_LEFT + REG_NZ }, - { BRDATA (PKTS, rq_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { XRDATA (PKTS, rq_ctx.pak, DEV_RDX, 16, 0, RQ_NPKTS * (RQ_PKT_SIZE_W + 1), sizeof (int16), sizeof (int16)) }, { URDATA (CPKT, rq_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rq_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rq_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, @@ -754,6 +984,8 @@ MTAB rq_mod[] = { &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA60_DTYPE, NULL, "RA60", &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RA80_DTYPE, NULL, "RA80", + &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA81_DTYPE, NULL, "RA81", &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA82_DTYPE, NULL, "RA82", @@ -762,16 +994,32 @@ MTAB rq_mod[] = { &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RRD40_DTYPE, NULL, "CDROM", &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RA70_DTYPE, NULL, "RA70", + &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA71_DTYPE, NULL, "RA71", &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA72_DTYPE, NULL, "RA72", &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RA73_DTYPE, NULL, "RA73", + &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA90_DTYPE, NULL, "RA90", &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA92_DTYPE, NULL, "RA92", &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RA8U_DTYPE, NULL, "RAUSER", &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RC25_DTYPE, NULL, "RC25", + &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RCF25_DTYPE, NULL, "RCF25", + &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RF30_DTYPE, NULL, "RF30", + &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RF31_DTYPE, NULL, "RF31", + &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RA8U_DTYPE, NULL, "RAUSER", + &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RA8U_DTYPE, NULL, "RA8U", + &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, 0, "TYPE", NULL, NULL, &rq_show_type, NULL }, #if defined (VM_PDP11) @@ -847,7 +1095,7 @@ REG rqb_reg[] = { { FLDATA (PRGI, rqb_ctx.prgi, 0), REG_HIDDEN }, { FLDATA (PIP, rqb_ctx.pip, 0), REG_HIDDEN }, { FLDATA (INT, rqb_ctx.irq, 0) }, - { BRDATA (PKTS, rqb_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { XRDATA (PKTS, rqb_ctx.pak, DEV_RDX, 16, 0, RQ_NPKTS * (RQ_PKT_SIZE_W + 1), sizeof (int16), sizeof (int16)) }, { URDATA (CPKT, rqb_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rqb_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rqb_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, @@ -916,7 +1164,7 @@ REG rqc_reg[] = { { FLDATA (PRGI, rqc_ctx.prgi, 0), REG_HIDDEN }, { FLDATA (PIP, rqc_ctx.pip, 0), REG_HIDDEN }, { FLDATA (INT, rqc_ctx.irq, 0) }, - { BRDATA (PKTS, rqc_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { XRDATA (PKTS, rqc_ctx.pak, DEV_RDX, 16, 0, RQ_NPKTS * (RQ_PKT_SIZE_W + 1), sizeof (int16), sizeof (int16)) }, { URDATA (CPKT, rqc_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rqc_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rqc_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, @@ -985,7 +1233,7 @@ REG rqd_reg[] = { { FLDATA (PRGI, rqd_ctx.prgi, 0), REG_HIDDEN }, { FLDATA (PIP, rqd_ctx.pip, 0), REG_HIDDEN }, { FLDATA (INT, rqd_ctx.irq, 0) }, - { BRDATA (PKTS, rqd_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { XRDATA (PKTS, rqd_ctx.pak, DEV_RDX, 16, 0, RQ_NPKTS * (RQ_PKT_SIZE_W + 1), sizeof (int16), sizeof (int16)) }, { URDATA (CPKT, rqd_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rqd_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rqd_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, diff --git a/doc/pdp11_doc.doc b/doc/pdp11_doc.doc index e37deaeb1617b68520090a02ba82dcb4db54d75d..e2fdbe0cf7f1d276df725a679031c39794ce2fee 100644 GIT binary patch delta 18393 zcmcKCcU%-#+wk!-vw(^c#e#|rMNDj{V2izD@4e7$sMs|oDlYbV$AUVjvA2jND$2&* zdkJa}(qHe4h7@7xLYm-5qvk&bh8@&Yam8nw%r_WsZ3j%Nd$V z|H-A)5|-uRr_Y~1%adU|ScpYf42yGB(>iT|Zr8lO%4VljO725{|1Aqym3r1jQ{Sk- zfq?^?$2E^je=+lIHai#P8KkT4c8v}c&wPw_4yJ-({Pk$N^mS(Ez@tG%Gc+sZ=H($Ab z?5UJzSQk6@+_D*&e|$QGy~#9CJknR8 zeXR`~+9GyU?L{}V^kC|{sb6}fNBz5ML=Pv2qh z{?>=euZ>bqOiIaPH>FIfdVp+5lka6ia;jy~EoM?>qV6?5J} zOzp%Ucz}mS>5f_jr=O2(So-sk8AnF<8{O)ABOp*KZ;bDuc^MBnY8_0YJFPJe`|J5k zspAr?3r3qx+A!}b?wR};XwK<{oMQbQk+?aV?D`f1tuDNF!J#ier!AAUJEx#!$ z|7y$2>sn4tE3+X+`^H#xUCZmahrig53%H0&h{Ho9;|)@frKVDjH4WEC+8T3}CQ98x z0v_WPKEcsPsgm%5UsI)qU?e7EE`pmWwFU>EHD?`q^ca#+qODRj&VQbnfm+5x1(h5fD!X_GX3ggg7+60MMe_xL%Z z4J_Q>K@Qr$3(_Wou@=%U2cc*iX`fes(oJ_Vp2uiUjSmr;ldBJ$#Oq#<8>`Vg%! z60@-bXK^1o#jg-*p(8pWyrWXv@Ea03u^yZ|Q@s#^y+}djF6<~q;JvjExiQWK>dr>4 zKeZ?$M=bqTD(5NDx<6E5$phI|`E1+g%IC@Zy7r(UV8#M; z>%~6c5U#?>mw?4wtivW8fXR<&KxKapFOk*o?PmG@K1VpOG};C>jODe^6>1 z<|Ew9%`aGo6F39=F-l$jQK{G1{1dT^j$@S?grQi4SdNSz5fGx(5yYa?1dfO7kS}D% z?x4~nrP^UP@=azVu>?tQoT8M!GdJ&EJ^cUlOV5XP(p-%@4fP!6TrNTJ0S#1@tP`c| z^vpW3yTpjDmSuDeoq5l3I%#Siq|n2i2&^-J%=>f9^(QG++6Pg|fRhGGFC zaT%}RLSNU(#!VkA4zOH$so9ELMs_TgXn+ORAkmSAk0=?)r=mLiFajg76j89i+*_$o z?0^K+8Jxv)^gFR6JogrC0 z3cDcLeH)VDI`R*d?a4#E_tb;FY#&}PfToaY;Ew=I!Frsx}yhvhE$Oa*od=ugwJprVX!?bWOHJ_*c`VJWCeyH9Eb1-CW?_aq$u@8HHwn0 zIE`fa(r7XVZqyY^c9pf3jCK8DUAoU!3Q{2ksQ|IbQ&z?r!`H;?d| z&wF78=3$eWo2?kSKq-%fq$;W|QmQ6uV;>Hq=VC_x*pCA^flD}MP%d#B8<%h_SW4OX zg(!h(Io*YvsDvumjq58Z57@qn?!UuLEaH&5ntHcJsnhUSOVcHO`THdC$rsNhBqm=^ zK5PB`@|7bAXA{mwD%+2%OOW^Q6{<~h-Fm9fj(gwchF@_#i!sSr?{4TfGAz>ebrbKu%41q-Z zG)%`D?89}K!iZ9I#%L_XQ9On{nIRcc3XLF{G6=y7ZQJwD^UPpg3&SQv;09vw8M(cN612Z92Bo=XaPXUo4Qi=l7 z9zS6fY(>SoDN25f*ck1KQN*3*v7V5}cGiN7KMLuU%u;+xQhcNU^}&2Bz#}|Hk##f= zs-P;`BM6hR0>9%1-l6b%nht$11yivW>#!I5@E4vT)w*4rffv^047{+65R2({MrLovFQ1HyIn1y1af$T19dVaWUfzt%zsu(?zs#l?mx}8y#-U2O zy>U1|FJ??Fu2(gtcGB`$&(}0ZW2Uq2?vQ>AFxs-N`J43PftBqKn4x%b0Ftiw4xLylb>T#=E(U!SRx6*^)R z!f_Z0P`gP+e2;b*j(OORN5~mPp@lDg#Ae)tM5{AS;WQpWqE{z!O>jeTd{h=@stW(> z$Stq6KuZk6M0^?fO^Ey;%)xd@Cd6RGUWy`);W+-pQ)v76e3U>#_~IwbLnP80$Qb*b zUi|ODrjzkUAf+x>Gj5o#vMxo-ISuhvn$DEZ%)@)<&-je<`)PD^I6!+M5|`2QAP3b$ zWI1l2+hGo5M=8|kd5reN6&b?neoB0`IaV6c;!Nn!0 zr2hm%E(c`KG#oW11nBvV3jw;9xrub*RXl?eo#2V)=!dD;0_mU&_zTiex#^rdsDUp# z?F!HJpyQ6w^ z@J3g3!!QiT9IVADJVA~llzB8kf6Tx-9L8NZ5I{vB!Bhv=a2?6W*tV}{ysRM6S4bib z4Iz=(3z?&F7*QwDxC|1J=h2GjYYjUBPXf>teYWX^cz za&(e2C;K6jWdFCht#A3G6=^GLyaNMbb0NRB}6 zw?UGGvHA~Q`Wva&u5x+7)!5=KM-%In1#fy!R=NpWHuWQGB%?OKmQ|@Nf51&L=oYe) zMUqKwC=PElK_Dh#4J^2V*T_w_l|(B@_Km{-*n6_V0!W%}LIiH%HeMqM#YtI7;d+=0 zNo5Oc>0E;pmXsa|TUtAi%~?|Wgn(1j4LjEEWumYQK9>LEjC}{tj;)02Z6wen#4X(VTm>>bgUJ;@w zgANG6fY;2RBvIIs=_wR{L$9MV=3*h%;DPxqgIn0YW5@t+TtW5}o=3U&RJl|p5D<-C zA2=^S)-=vfP?2P44g(R$`iY|!BC!Vvc%5kwY#R*Q?rYc<{-5vF;u~5iBfOGc*4#-t zxDtB7jIEIVx&z0!^nNSBy*nBs2y?L=(RhafcL`$j#1w46am3>z^2L*U=!j56;G>eC zuTOEv>sRmzviY!ELCG>_wawu{Uy%N!_ zAyNGwB*GTer3vV97>}I-D=C`m3zPISO@ zNN%jeD%?R9@}vp|Lvm&kYo`**q+XPQt!7+exhFNlRy(G!d=$r! zg&HEY#0%c&hj};(sV{f&8cC?Y2H5IN3zio{>JI{%$QM zK%}8;ACahOocL%eCkjB``XS`4s@Q8P3fFNbo2J@3YU)vTO*PJ;sYvWW0-T*RwGyka z8gEhf8#V#sb86~Oe8{D#9L}05gp$shS+!u{6&mH%)R8=z^3AKMkr;=~ID<==nNL$E z@EOHiG*u?Qrdp#nN)^;pJ2Wb!sSzkzSW~4j6cf<6h^FS^F>)1UXNqa6M{!LBmMEpE zg(Wmq++9<(Q0iMvjYa40G}RqHqEu;(Yt!$vymb<;CqySCrvCRgIyF%qA5UaKe$!t( z{`U&MClYRqI9-Bnc0Xc0D>2q~(DND59rPT=mWFyoBf7ZmZf+|5a~Nr;Xs4;ZFmMbn zk(-8>PN)i7N8FI-9C!|~S&0qYrgNl&^3y@mNgeQzj*`yGO$SMbHNibdhowiW5p+|V zDJA;p7h^SBpXR0?590{lz}Bxt=+_<@{X34nl|J5<(a%r0_oQ1ZpgE+Q$072`N5INTZ&8O>F+*bJDDEH@w)m0Q*@79w zi^R?zNc@~cX<|m=r)@_3^x@uv_>nlOpAk##xo=1;NlayAwKcQN9htYW9nUJu{HFDc zV3QHwiLH~h`#_>_B!*;)LNm*^aR-fvM2X4}NMz2#Y@%`wc0(fc0xseua=U4&GCJc& zEX4^VBR`Rxv4xf;iCR|lRrs;E6FAa_bt|7E&7$!RDaCJLA=0AbSbZ?uJEa#siyb|W6`Z5$&2=t z$N-oTioMu}TeuAl5w;)WW1N;VV;1L6E!wE}kWGy5!G_7kOvh^2Hb^!`Hp2Fyv-q$G z$cOoO@j>2nGHz66r{G+bl7+I>G*ulv;SY!Eyyy3tT93mxh0}PA88ztino=KYYN{og z*3#5qOu=L1sjaEJxLa3K@n}|`L_-)(HQ z4cOC?(waq36s<5A=}~A2Pt>~oD=XynB{+en$V01FLT8w<0=C|8rZ>Jv0HkMT!kJE? zhm;30cTzJtCm6QQn#%Gr?13#SeDxcD*N`t}53OTB>pUV;!G1)b{M|)l?)1!^`;ZQ9 zPv=S}kHTt5XP-ndI$Aot2K+Gz5&%o_0TKxAjX4sdG5TXBGRjGM!3)%L%Eo?cO<@aD zoeXN~-Ial9Z#GX>-+{CE3ocDKCczKWu?w-#h_|BX35h)eIfy?eRE5N%AN(;0^ROI8 z5sgPkL+)nOZ)9xZ*DIc^P#-PP6@xJek$8Yayuj4vnwo}{ScUU=4d)h=Ak;+we!*cJ zL6ermFm@smnc9l+pE2yF)+&8opAz@2u~oi?x+;PhqkrEx8MFFR1-WrD4))g@n57M5 z^PXqg#QtoKY@&R01Ru8}^$=j1pByU`?aYgu^@D0ZuIgBJ|ocba2jN>+skxR>ChVK z-=3B)hRAh4nVgsT78wXjv6nuOUH{csUCva)vMh4s_e*oG`ZHyrUhL8oF?P5Wsm&A0{4yxKJ0&{ZOUkTUYWer%q!z zkqk-ya*cdJLcWk7*Z$>tyIkj%OUrUCSFWAPWi+{RCD(`Ka*SL8kr{27J(kH@CP#-@ zXDnszPv+WWj!UK_BI46e$>l6p&K~8YO-_>JR78fKGS-u!l?-5HydVc;soGK{r2doFqrlJiau|NCdhvRHAuubD;9TV-8SfI1nWIXvT-qrVzt& zK@T$TXP4TrJA<&5T`I`#RK;#~DTZCz%`UZLmqxHl5$w`%c1Ot9_9AeHU6OB*HHCal zE0tYxW_M~~1G{vGU24fLwPBY+*_EZZ#O{d8`&4_?l-==19d_viyEKp8If%OK(jV;7 zHFjwPyAy#hcBv-2RFd6kj@(tquJm1^ZwWbEG*T|=Nlr^E@#O=o$3`PpwC-*+jMm+Z zk#e&vS`V^hzoZY-%yWtUCD`ADGiRK_IXuH_yu$|+^kHrZ@_z%ghlD_9^nm;y5=U_w z(YT67cm|(lO#34M{V}%%QyAET11-4Nb%}**c#qF0LMIeQ5P~tWEwkcy)Q*ioVtdv@ z-i~B4Dxe;A;1I6i5gK%&(J=vY(V#Q)J_z=uJy9ZvDS;q*Z2TaC6;Fbhhr+7COdO%q z5We(^w&;LKmU>+9Z2u>s6XIc|osE9pqWM1Ww}|{=_r5FXZnaU;lBS>~>j7H(&xL zVm*FEnPp6vVju=%C<*xkvaF>4bFQSmL%w_C1Nr{V7>tE{2WJ`fU_Vx_WAYnka31fG z23P8Q5!6H-^n@Qm5Q-I8jYBw!c-)6(-atR11U%3XP0$DZF%>hg0h@3NXOV=r_--S8 z3CB%LuEGz!k%A9M565sG=Ds^Qf}utfDT3J+rXAt&I}whP`?$7> zRA~FD0VstZ@Do;HE$SVh`{0itEW$6Sa*$GnuJFTuj_?}#a`X#6O8NJhvrf((0c5T&0JWat4ugyR>iSM#*S{iwdZODyW0{Xn@A>L34CMS9GtV1u0(^`ePslVF+en zE*8Q-IF?}}wqP3~u?rT&;vNRoVEWK{(6*bH5+xi{dSQ4kt zv-j{Ki44!XdZB!WSv-a~+{1emGkovr=gbFd6A#cEP-sxE3AF;ZeVFM*#b#s>26rSb zP^BvuBd{0ya0|C_qZ=ave1g`UPey5ck6P%BK8Wl=5TkleUh7GgRO`hG@I?S-U?wW~ zazMe)2*Y0NM=n3gH46B1kL6f_egUK>Qjms_K&mC0_2IfOF5(Yd=*#c~$#~b7EGgQL z#sL3sv1*M}n1ZPN1E?1`HIVWQyFm7Z8CK!JB#wTVJ(<>l1^aOy zPmnf+^G+0)#xVnR(EtN55FrSK436cC(!*xa|D$Gc*9M_NomF0qBEJOu-7+z6XDp z=zE{=!yV*Mvmn?XXd6X)*}M@aR|@x z5{|3+jtNSj6dIxl`ePs_VJenm6%OM#x~`!$Va6nELIf7Br8QA^16>32J8nLq+(yz3 zO*hjl*p9O(u!R#Bj7JFOZ)HS;12~Guc!s{)IMcu_+{KgM*a_He=Xih;@IW%&;IEx@ z%TD^g$}Ubz@Eos^cQ=C;)InXy_w~x5`|rdC=I$Z*kaI7!0DaIGZ}9;|IGnq|2Tf7x z5Py%`xQlIvIqG7}5w0#CG1D9@EW;^Wz}pjC`8`R~pQ7op3G($IkJDrZTBAJ{VhJ{5 z8}8sP>YStCpxSv-8@_)K1DK2{s1ePMp&dG!xfzNP7<8F?ti)R6xXvD86n@4XyhXhm z9H!AJhE~Bu$hSr|V>_-Q2A^Sflm5pHyh9r7Z?khK4s%Iv>Y@Q$d!VE@BKVvVBprs>M zMlc5Ba0tio33_&(!vq|_VI0FLm}fG7G!JESYRU`WI;USQYn+ESML0HM9>c6f=;p%c z2A2F>!$1tfE*W|)aAP2Ywb+QgIEWa;Aq5{%v^aAXm|lvB%TiocDEzIa%A+f~!&F97 zc9;MI%gbtN9q!>h7BXyGiu-to_c&6Xv0w#099g*jksUKCF;|55NW~B)Nk(8dv-GEG zFoD8cl1D8w(+(`uMF0k2GG-wS{HqPBBuZfi_TVfoK*or#;ll8&AgZDk{LmNEAw#_{ zhjJR%NbFFpp2iWD8{61!Im;^%jmvn1Cvd6Hm2i|sS#(8r48|}_!wf`Xw>)MZeh&V? z6}-WFtZYaN;bvpTmDtpT*4oOA%o|mFs`u9HEZq6oTVA}-A87VPy{HjJ^ef%H)E*Z1 z;{q;029ghvj1*+?reb&-+H1YNOWE4w03sR@Nqo#y>nB(OUh6e9!~9y$Ygv}0+kd0w zF;;7)JX&sJw`TGV;NN*r`~wK zrhKmTNkwn{y=;3<&z1ffe{QL-n@Z|s8vYVK{Z@m^4mA|#8R}I<4jM#r8MToW?UX53 z2i^9pWv-nmNONe+hc-_C*J2iA^)PBWn0DFa7`kYHCCS0$M7y=uT1I6xb>O~smdN0F`lNL)<0yB z(X>*VKg@2imnk@#?H`9(YK-{4X@A-lnl!5g%Qd*JoMY JR5oR||3CZSh~EGJ delta 18551 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 N?@zP5^fF~}{2z`{Z|nd7 diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc index 9ca95cf719dc3f73d6daed25338b730c1db9ec47..a62660c3c8da24bb1fa41f80ea150faf114a4fa0 100644 GIT binary patch delta 32968 zcmdtr349G#AMo)rbCXCy61%J<*4TmwMO%%XSZb@<2|{Q>L{RG$)Y4XILq_ddT3d@+ zg5t4v5o_)HT022$RWwmd*{xaIp=@=b7o15n&38Sy6cp3 zFI2BHaQiIJM-K=xU=VRX1 z>E}J?H!PU4S_*s9_Pvar|6=~DK0{ zyJdJ;&@9(1fAr_OtXcl(&+?1LAN}k4v%W?8Jo5EPUex4!1$nMj)B4HN&vN-eE~2u% zP4oply6Yl1y8l;!+*^krKcaI=!HC>29sutj+gqgR`w0@?qN^jo%?RQ=t z(e4=aZvD~UFA^fe7deC|#rK-&AM$*M*D_36Q?!aa%jT9p18wttHQ)Mr>+3>{q7~$8 zW-*EFGi5=V)z)XQ&XyLJvVi4yQ{OoKS+6|(HEnk{N6DgTFRcsGU+ZmFdX}6`wbWS2 z8v3VCKkKD``u()m3BEbz1nXr^dprF~pM76$Yt4XX-?x5G_Q%?}2>Vryos$)h;PSz4 z!BxuFiis^BTroH}p``04Do<-&gLztY-Swcm5|YrrP?1%qydsr^-+la7_3(M9Cam%E zUp2I_lk(+~((a}s@+VZQS8dhOdexPL zG7Xv~3_LUZu$yrH1x194GXT>nH@UqS!m-WtZ7bU-wb*nAYswnuCtD+{lEB=~8ZY5B2$SbGvEBOoG zKA(L1{Oxs%*UdOTW6ZkP#j)papYLRU$I={umdYMXdbL-!UX@SPLv|bP&uliFrFqP0 zk&tog)d?$Tsf4FK&2HmaH*bWoNa;4Oqdgq-iq}6j#8^>dOY5JfubsmGaTj6>wqgf% zBC()STyyZ0P2#QOHeWluW6h35iHqVB7bPBEb2xTUYzNyr^@X*Z?-43lHG{Qx+-A>Z zpHuHk8T1ZAA291BH*A@8wf&6?)8|UReIgrm@SGZy#W2(BGilANLo2)OZLOW(jNz=; zPQGWW$4ATUt>o7nd}R|Amc6E^5@>c~MC^`0&{_6u-n0Dt^67iVZyrzgiM7Ae!S)WZ zWnJq9#)#Qz6KkbM80R)tx;ZTqimWTfy6UUOz|lAO+3gjEaL`w2hz9GY=FD0tyKRtp zM$SeM6^l$#{FPKi%T-+NOiId@36w2UM#=Ac<9PCMnaz@|*(~{Zawq#cjHb$%tySBO zLA|{p^zD2qp0iuCryLE-%Bp7n?QE7+&2|)NJCqDs- ej9Zj(?f9-B^jG3Ltif6& zmXp~mNH$2tY-O{ij101B25b24XB=;zGpkCr?lCgYX0411%Xs@S2nWQ4wvk;i8ZJi80R)t`io?>)P08kUt+oxT!ztd?<$GOiup_wx!d z1Vb?bBas*?^H^=!Aa%2q$0~3zoK-Ve^VoMBGTZ0Os*;_XTr#18}kXV2}kkYZ025TOh%2>fZXI7P*RURv3Tv*22_iE*_8OCtdYbWD8 z)>h`R_OgjO%0APXJhq{L5Z~i4{+m2DfxMTUHnHZhoW{A0mHr}m>=R?)=o|cM=CQ+? zTUVLKy2&=_A={*9_VZXOz0TeQ#!7vGJT}_6tgPzvmB?d`#x2UYc6^(2)u{zq;vKX> zVx-JtePn|~Wh;-}=Sx{NgEfy0GR~P*C1;h#9?@a5T5UE?aQwe>mTb6jgY??TIFCii zJl0n>QH<;}vE;Eig@l-k_4se{SRYSAHR@~4AemV6*e#ZxVWq!F9*Z$9>^ZA`1&%A% zYi@Bej}4M-^1f`7q1n%4=e;ti)ECHOJ&eoBs!m^tJa)wxpqb>cx0ojswa@?!kvLrD zv5~StMrA9H9rnq(8LWA%t#Qt*Dmkk>c9Q!gGVD@@)_9vz_9vda|*l5{A zV`ZNiM;;qS01rnZ{+m43#LrNT`dTy1WBYs!a~p%|MeQ^9-C2DRHWFGri zw#g^5O{Qc&k8LlUNu?ShIlJfi>l>GqRh|Cd&SMR;bDsYvV}Ke%F0FQa6F*c!s*YyH zDfkqBQVox>y$F{v@hh&NQh*S_I9*hT6~(wXP)t+usHL^ZA1VX2Z~PTEE$Sm4EK{3r zDy1|Y+_WKko_^0ep_A&ODvI{~9;He_;q6V|^?@(^5rD+cWFnm^gCSAz%=oe?mr?5{ zF0x%VP4dq=4y=i^hH=iUS~;skx`}%E|03i8y(`8G|kS#S! z@h@GA-BfLK#O)KiPi$Piar%kz%Wp4_y}jJ_x`X94cOC?ott}EnK-nu%U+1%{w6*j~ zLeM^U#xb4UYo_KtA;yJ0XVsZsb<0kI&FpGwlk8qj&BngiPs=q&UM-y`TjC4(uz-$} z?rLeeYo+yVSFDQ`H&o|yYQQ=cUr4|IFDl=1g)Y&c5@sZRE8Aj)Y=-X?f4RF!T9`CtVba3G@rPrR{fqn^tI^7PGMdWz!)6Khk94}3XI@$Asm{PZo3)?V&vT%lf(8SFzdZ`$W) zS$nTC8}HoAUv=f19ZtYfzGFiEx z9oVmUY3Cj&If^Q(aP$zaB}LBqQ~;A6VrLA;OT1TGbeZVFD)NLu|u#OsgTpQryRH@O+(0hc_ys5{A7&PQ-3= zEg>#K)Zs)e-bFO#)DvPchBgr51AK??QL!N>L(rlT^C1?4FbR{f9vARlm=OIi4ioSl zPNGX=mI*V)$mbb6%)+=Pln68N1=eE|c4II8OiBB9A?3h@ofmlHLdt6EMA~OrOo;%? zy|AgJZQa)r?Q&0M=;5}Tf%Q(Ne`5QpgZ@?7PoDbb^YX?siH1DmS}@9zZsjT(+@byV zRTN@B^f;Joh=rw0|9~H{C4|m`5yZtvOu$4efF3g^nSKC0b^@zv2d*n)l{=OwwLVo= z&TCJO5wn4nR5#7#xZ?KA8yw8#(6r-95yf4LKdt!i^wVL*#~QevfdpeiG{RIYgAC9; z=wF@qKtqDC5#pc+=Q5`CARPN9F@^_ti0U)6@fIBbqeA(m3}fHcqU3RB7arWN z8Q;I6RrFDtYO|6RZ{>>C^&_PuPrMasK4+ZmAHT5lX-oGu@q1PDVMRXErWtf~Rk-cS zp-noictifLc)nGe?vGT+o>&yd-q@Gd$LNj6vC_~RH!>YWZ>(VJl?{1T z>3t@&XkgIEWh1-A5+ozZ~Z%te-6$pZ+x0G6%J{74gx~TZN=sC+l z&snNGA@ZRW zBG420n{kglf|X|40avxTwj!rmOFnpOw+|5u=UlBXYuR6hXgBhxu4dUPelmx6u@pb( zOYOsSKa9f!$feK1B7B3kZxeuM-<%$ae&~;xSdHo}`4u{xXeGos6l=|{3}cas((f=* zdB@D}Vlhz{4KNm)u?>6hD{{BtceU^~B5)DcQ1x97v=NS87=$6%hk|Vxr=SRGq9MZ2 z3v;j#tFYS4!%igQ1Ww`x?xSEk_77-_t{8(4a14K9MtdRVV?jqDe!=3dbn)(VMJ(wd zghvGP_M{eivFkubbj4qAi{ut-n9J}`0S{CD)qj}{>&$ur?-ER#w!#3&cAgErjYrbX zpVOu@Y;C)S=SMB51tih7>kvSj7KLo%W*7t6)(fx=M(4_Stn>+Fy*$wN+Zn#(r zy`@amZa+|*%p?rINIsU)@BxycN5d7So6-7uH1uS87k)q$T3(NePE7B$MZ+CiL=>V? z^(csBdNyP<$N+ef*5#AVTvzfbX}Lk$=cne(w43|LZ_AL8VX_8maRf&p!{jkS36omb z)q#@Y3&Q0~Ti6`pc~WN~K0#m?ItJPhO7CJ3WLWJ%&TzI6mQ1fj1}H_-kM8aW!_WWZ z1)VqjF!F!0*0hxdSvNSlYvrVyZ!Y#mPbX|2S*xv(fK51!g53ybbj4VFjmuE!+^?e> zCPH@jZ;%4n@m=ZoL3kH2_y{r?EQN`L-~e~XihUxwM6*nE?JGpzzWlE8XH3k+AN{Dm7{)#L60xzY6t{5~l?PB6 zm^+a4gXQ=WO9ruEti>k0KA6gUpYb>bViY!@)DYSb)zA{}qWut}J%))`EWtJ89LnGg zOOb@F_yK?5F`5k{QK2~^a2Oqivqk8Ep%{)ea2P=$E#vshhDXag$1QJ|vlzWwX3B7$ z%zlB-_DgwHo#Tx|^^C{j)?Z(edy6*4wwgyf%|~b2Nw(J%Y=vyMN9aIvb;K_?WN5nF zhUQzq^l_X(K!3U&x}iHB;34QL+L23KDBJg&;%0ti$aLa=|3VSdV%5^_=~rwSCHka) zFI_RU10T}S9~qz0Z-|^*KP+~%j+ZTCXWo|MXJ1(ldZ>S92=h=vJv5FT48{=VWAQEY zuz$>S4MJUpdsmFcW+?Cb2;oA!%RcZL%+UM5pW1QF2+*HqB&cKyR5#zQ<$y1wEg%8bWe} zo<^=S?Mk}P(@7Z9Uy>>o;1FcmcnD9@L=DIk(h;j6Q^!>}$^79sLXM}ZTE|oS_j7Dx z$>YmR90r^-sm|v8YM!zC)z0V&AqW35#C#q3atV~gyBLT;7(9}{4uN1Qy)t^^J$!|q z@fc-Bk>oHGD{%$B@gzUIjRSay-{XZzlp7wZ9C&FXeAQCc>!eJDXs7pc zYdxo|y(k`| zg(!{)L}LZk;79DmK^((bTpZ29t}^i#qQ`JJhGZPY>ajvxhtmg);?WtOU@3mUZ9Kxw zaqQy8GoFLP1olp7F_FC%X5$Eoe#H0>l~E0KF#`L|Jg6V@MR=e-8lx%B;Q|^>Azz|5 zqOkyr@C%;cgHKrzzQ7{n{)}B4swGeu)J0>&PZMH1Toc(i%+g2;Yk6>$8yU?TDJTb|1#`dhCKD?H&dh3oY?6 zCgCt-Or)a1hZGo-uo)?MA}l{zp~w8y0eN~=^LtF`WaqI?S>BW9T4jbRActe1PX>8(WNHkgP?2e=TGGCE743~HhQ z-p5#cj^&Wiy9P3XWdJ832SF?Yxh%?I0aoIPNMh9MVL9ew6n=@Sy!JrJX&LeA^Xv1j zW&RCNKc~kb*9?a1GiiFfhxu@t#rY59nN6Hx48~#t5};ug<{}xl(0>j)U(}h)pKd|; zJVv~6^GMKNQvYaxhA?9k;;|IV@X1#~%){GXvuD5?-*TLd>4;v<@EQFOgSqg#KwLro z<)RFSjF!QqpY@{)Df_lA-8X07Qv*zX-?)U?vp{6tVMlCtYYx^9ueKlJQMDY9tEN+UbpSgSmwmIy{wI(q)-h)=$fy<{KB>_>)Z@q#8X8I}wU^7E@WMzLXS+ z*kzn!!i;ZtO?c{|+J?CC+rpk&dHkz3RlgzVb^)aT{UY*LlV-QAQBBo(JR$v8^CyBtC`FsuMANt7wp`ZNB7eT0nX6OVxndpgR z9`D`9Z*W{gWuQ80pfREljggp*Ew~NGwH%M&jkR(-*vB4hA+qVbtvfQy4Rtcus+_a7 zt@SaxFDyG3H&$i4rdU*PamI^#Nc1 zg!?*b9K$gmC*ZZ71)(hJBN88BAvWP`E*{R|9-e4<@~Cn4Ue?UI;ip|0WYD8Z*^BCG z-wGG|l(Tj0?jx5IxPfeisn~#X$n!nt3lW2fSb-z>1Nk>H=D=`#jia~$?@f$9(F+qc z2_LbPiJx!}%4YV?sEl@-HFIvYs`g24M(^2saAO>8FMLj7tR2f4kCiwF`FHi|q8{2{ zAil;P{El*4Xc^4L4>*bY@ZZW{1bs0PA7Un!VK45&ZyTw-?lya&87pnHj+NHhr)rsn zo+>fXE|Z)s;3>cFIu^1IPZ0D2jgG;1A0OgN z+=9=KL^wLZjCn}HO}PI==@5WW^uVY1{wI>!0VYy@vX|0Uz`~oTT+3~+ZWq~$bSceV zM87rGHp|Bq)n>WuW#z1__I)u`UO+v~lQmh}wu7zmN?|pwKa*$?gSq$-cj394>;343 zNDM(D7ULxDp>i@Yi$0izUHBUX_mHd51~F+GekPn=Ca?PO=9KHDBtfn$MlC z=E)_#ZT2!u!z^sWP255%D(<7ZA_05xI|BA|Ru^Nj8s|{p09g{P5rsL}iaQ4=q3c0e z!sc39UF-K9+ipHiU-cbWZ`x0~7nT#^O3wQE7VwIJ#i~7ULKmAo#Er z9-x%Ao;djH7%`Ui;8sla?wD=^U-Ao0DW;YTBqGy(p7Vn9MESh*K3T{f@dYgrL%5e# zee4&PtTk!YD?OtI5ru*ebFUXhV-2q1I{t#k5k^Z0LqB|ppKt*e@c_O@$(I<6shEbZ zaRPacvDb3rp(j4VnPb){W4GMF+6DHza$c!RPQ}}NEp7WL#Xo()_w`!xwoiH4r##d3 zutKCP^BKx_7I)!toKrvOg7NqgJ8%t!P7sYKjq0d}KG5(3Zo%UupCb(KVLayH2V8*T zDGp@tByBUbz55jpjZtQ#eFwf)BR7!XET;oN&>kHSjn6RyOK=bu;Btlxk9Y9_*1|Zvu-p=&52@TVI*IL97A%G3We09% zadpXSOS*-%_)4meyDYYTbC$@ZC09^A`{>)`XWbG{xu$FIKFjDH126__k>ebL5X9pk zuE6^|V?zwXSNH{2a20>R_X7KCRJfp3D#5Q<*l%Xh78Yf+F|RBo&+Y?z88(v}VU(R( z*FB1txXW9311f(Um}zr{|TR~9P=X{ z^KlH`^u{P?*oNOx>pDe4e=Ni=$a{n4!8;g?-SE0e4?zSp97efY>|!ws&mJ;ZFImdZ zHscoDZqpml4xivW9;3`1QV+)AYaEAj3iF~P-p4ZRM+!pj@*ei$4vO4kn1X?rhdp?< zJeB2O-cNqE7uD|5>(LT1_!x7s4#~KRYxk|Er8#5fkyO!1DX%0wuCBV2RUT`~8)_Y` zVT4+sfQhC!_tW(uk2dVh^YLi0L^NKU^Fz(6sA-_KFGBTHlG5g_mC?NQ`F^B`<6n#z zAZmyT{EHU7MPJcN3>HD6AMf_yRS@s>(|(Rn{gl&bi|n1zBBKn8v@UP}Uyf!qL98ZL zg!3xOwu7h;_C2}WK-MAu z;_+2HwH$M{7xdH@U()x?nV0aRb3(Rg6Cza@cAb; z4x)3IqX_5kxt0|9LKUI%>_$ynf3&C=wTMgF%c(JHskE0#J7UxZO4@5Jf2>;3+5X)o zv1(v3N7muUI-FQXZvHm)-xcnqu2hiLU^|P+3CDAJ}G-yxfJ5f7P@**+l*+O!+qf z>*nEj0`KP~*XQHF8S-z_sC-%eK@<7+9UegbQGmDT9p@l_u~zvQus2gW&sDbs={AOxnn><972Y__(y^Puq%8|JoG+GBs za%3R)oN`wscMmcp%Z(dGndwJj3N(C<8JLM#TK`~EA-@GoF2q-$2x2joU@4YqD}zlP zk_LUC{$VnYqSk9wHzJM8iTD4^?MC{W@0%-l8Yf;^?9dcZ${HK)nIOx8`*5E}S0e zN^k1U(6txA7ReB}52qXGUDfDaHR2fV4PgXF4_ikMYczqu`9y+zvh@;e(@#ZN5j~B8 z2>K^-^@r{dPS^Wn4qb09gB{{OW*J8UCpbZOL)-JIy2L!00$--Uw}IEn%fp};*T@Nf#;lLEJ)z@;hhcnU1<4f_I9C~!>*+=2qPr@#*=@Gc6x zj{w<FkkZj0AZ8}A_oDR_j(aPl&f@4U#?D1@RYjv#dNW2;fLFbNIL z{%j?3qYwsT7&?|9t0R9&-bWPrp=cn>!f9N_$kGf~a13Wrr3@`%=3y81z_l!g%=i?E zn2tsGPkCYrZZu6^48ce|0>ds*6>nlIe#9@8I8;CZn$Z^vA)9m=Rw9ICRt>#ij^d#S zZQTk%)hHFF)F6Apk+yfo*id$6c&k1GFa$MWkd3BIi2?M*U>w3}wCX_Ip;adi1~42W z;nJCnfFE&F1kn++f4>M0Tre4PFc0#kubnuGlemfpSRBJX3hxZyQ}#B&5@ zV(SUn1a1Hg2?&A0FvN<{B*V7YF1--tf^oYg)4995P!UOyXbt8L8_~Bi2K^%tSx6N$8 zX4=2Rf9StBf>ZbvH_>JbT??0R1B13Pe!<_{X_6fz7_`NZowPIR?PeE^=4gxU*o~6O zEFVFrgq_%f&HLHK?>E!6nD`04zcA3jM@Q&_xQ{>a`Y~by4#yd^U?7H~{7F(X`eFcl zPjNd08l9#PFk=Fa;0&D4&;)oLwXq#Pn|V;r()TeO2);tE!WsMu_p9PvQQ#_7f?DW`o;ZY4cz`De zxkjo)E!0Om#^W%K;{hJw;~T6DH*O@IpRS%$wI|cnirUth9BA%kA9nzoyeKECd9yg2 z#wB#|qi17OF?uEz-LIr5-fwh7ugpb7LI4@Aopb@q3_Smu**7&l*tqXzvD0DnnLYj*i?47*nmyQ znMf%-6A8ZAY$-0yC3PTl9?gP+^XdJVv5<6u>0j}T%3o9EkoR76hlV*=g5}tP9XN`U zxQ+XeN0W~5f**q9ey%d=A`BhS1@isTn1-3yiQPzr(_-QTg%F5xcnfvV1|1NIXvE_K zBw{9(;X7={4=`Wh;X0ncw1nzJIdnn~#9$!C;X};Ee5}TL?80uG#YOyvM{r$Al_LNp zP!A2!0pS>g;Y(@%`AjUr3ar64?80Fj$5q_ILp(;#Wh4&xA^<@MK`qonCv?RI_U>Cz z-+ud@rPjWTB#|DrC5y~zbP+M5h~6E|*%q?CE;WYtVM6p|Ob;e!B_uwkh};!74@ zPOJiE%)vD{=U}&so>-2(aC4?^5rfIti(3eEVO|WxR2S;xC=(A+&6NQHreHZ9!#gK; zDq;jS;uMPHA_6c0i|{L)*tC|2#Ri;!hdTpf#9#`J;}Pn6P*BXlW)J$r-%J$F&F&PV zu>+S-G7mFj7-r%)9^tjT6cjV@J#N7*AB}==Xh_0M)={|hCyeHEX{*F z!61#UY&H3Fstng{uHKLhrtMjvF49gfP|GC^T&NCoaI~Dk(kfk5YdSh{e#}YRx?C-( zh5n#+uzeK2l-K^(R8QmQ%hww}*T350IJ5TKrFMVWOP#2#_*SiBD?pxK)p*+q&aX5U zTYtCzN&CB$=%0MovNgflia*p!FLRTUny*pInG^?Y#5#LP|6i>3lG@3Q_Qtft!MwZa zxG8gZ7zrL4BkBwNb(QO%Y1kN(RB|Cbs~ zqlB%rN;}l5E>5<;Jm93o>`-gJSXllG9c9^%>X4TirgDqhYMrlhMm%PB`qur2t@F|o z#LKKrH%lHA{Q`v|zD|)XURY~((B2QszmVjf?6ODa%Co#K@{2tm^0}T5EgyZeS}miM z|BXs)@}s>HEeq*;$i5J2`ekl{EhPW7rM{$|`i~ZqQ8T@HCVev{|Hod#mbP#|Yiy>H zn#Tj<=lcG`(m2s8>>p8$|70if(!0<AXkAb3(rvYW+TO=gt8hnk*GAp3&%}ysZ$7!MRne>pG>Dxw zD@R%3$9q+Zalrf|$E@Og7ULjHxtBfj?y{t%IZa&@r~VYF{|(E3oUAo-Gr78n#$)n` zl-!*5WYyf~=o#YNu(>RaOG>JTa4F98C8~%E>gLSI|Il@%o2fuTSJg>Nb~AYfa5QTB zktLG!pLwzgI9hXbH$7J54Jy~y<~Fre)R4+r`#h#nb#M3BUy9E|kToeHn6MHDt?f1P7X82MQt?a@mK#k+J0$n`tde zwH4;zG|Asoz?=Uf+)_Z>#;C0=Q%O;kO%95KjAJb>#PmjS`Ed}hDxe}NAsCer z0?XGAg_!*PU9u_BTwGh&l%)R`##P+8)J}OWXgZDI}?4P1Anm)0lEeTWXs^En&aq{{X|x BhUWkP literal 214016 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 | grep 'GNU Make' | awk '{ if ($$3 < "3.81") {print "old"} }')) + GMAKE_VERSION = $(shell gmake --version /dev/null 2>&1 | grep 'GNU Make' | awk '{ print $$3 }') + $(warning *** Warning *** GNU Make Version $(GMAKE_VERSION) is too old to) + $(warning *** Warning *** fully process this makefile) +endif +BUILD_SINGLE := ${MAKECMDGOALS} $(BLANK_SUFFIX) +BUILD_MULTIPLE_VERB = is +# building the pdp1, pdp11, tx-0, or any microvax simulator could use video support +ifneq (,$(or $(findstring XXpdp1XX,$(addsuffix XX,$(addprefix XX,${MAKECMDGOALS}))),$(findstring pdp11,${MAKECMDGOALS}),$(findstring tx-0,${MAKECMDGOALS}),$(findstring microvax1,${MAKECMDGOALS}),$(findstring microvax2,${MAKECMDGOALS}),$(findstring microvax3900,${MAKECMDGOALS}),$(findstring microvax2000,${MAKECMDGOALS}),$(findstring vaxstation3100,${MAKECMDGOALS}),$(findstring XXvaxXX,$(addsuffix XX,$(addprefix XX,${MAKECMDGOALS}))))) + VIDEO_USEFUL = true +endif +# building the besm6 needs both video support and fontfile support +ifneq (,$(findstring besm6,${MAKECMDGOALS})) + VIDEO_USEFUL = true + BESM6_BUILD = true +endif +# building the Imlac needs video support +ifneq (,$(findstring imlac,${MAKECMDGOALS})) + VIDEO_USEFUL = true +endif +# building the TT2500 needs video support +ifneq (,$(findstring tt2500,${MAKECMDGOALS})) + VIDEO_USEFUL = true +endif +# building the PDP6, KA10 or KI10 needs video support +ifneq (,$(or $(findstring pdp6,${MAKECMDGOALS}),$(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS}))) + VIDEO_USEFUL = true +endif +# building the KA10, KI10 or KL10 networking can be used. +ifneq (,$(or $(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS},$(findstring pdp10-kl,${MAKECMDGOALS})))) NETWORK_USEFUL = true - ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) +endif +# building the PDP-7 needs video support +ifneq (,$(findstring pdp7,${MAKECMDGOALS})) + VIDEO_USEFUL = true +endif +# building the pdp11, pdp10, or any vax simulator could use networking support +ifneq (,$(or $(findstring pdp11,${MAKECMDGOALS}),$(findstring pdp10,${MAKECMDGOALS}),$(findstring vax,${MAKECMDGOALS}),$(findstring infoserver,${MAKECMDGOALS}),$(findstring 3b2,${MAKECMDGOALS})$(findstring all,${MAKECMDGOALS}))) + NETWORK_USEFUL = true + ifneq (,$(findstring all,${MAKECMDGOALS})) BUILD_MULTIPLE = s + BUILD_MULTIPLE_VERB = are + VIDEO_USEFUL = true + BESM6_BUILD = true + endif + ifneq (,$(word 2,${MAKECMDGOALS})) + BUILD_MULTIPLE = s + BUILD_MULTIPLE_VERB = are endif else - ifeq ($(MAKECMDGOALS),) + ifeq (${MAKECMDGOALS},) # default target is all NETWORK_USEFUL = true + VIDEO_USEFUL = true BUILD_MULTIPLE = s - BUILD_SINGLE := all $(BLANK_PREFIX) + BUILD_MULTIPLE_VERB = are + BUILD_SINGLE := all $(BUILD_SINGLE) + BESM6_BUILD = true endif endif -ifeq ($(WIN32),) #*nix Environments (&& cygwin) - ifeq ($(GCC),) - GCC = gcc +# someone may want to explicitly build simulators without network support +ifneq ($(NONETWORK),) + NETWORK_USEFUL = +endif +# ... or without video support +ifneq ($(NOVIDEO),) + VIDEO_USEFUL = +endif +ifneq ($(findstring Windows,${OS}),) + ifeq ($(findstring .exe,${SHELL}),.exe) + # MinGW + WIN32 := 1 + # Tests don't run under MinGW + TESTS := 0 + else # Msys or cygwin + ifeq (MINGW,$(findstring MINGW,$(shell uname))) + $(info *** This makefile can not be used with the Msys bash shell) + $(error Use build_mingw.bat ${MAKECMDGOALS} from a Windows command prompt) + endif + endif +endif + +find_exe = $(abspath $(strip $(firstword $(foreach dir,$(strip $(subst :, ,${PATH})),$(wildcard $(dir)/$(1)))))) +find_lib = $(abspath $(strip $(firstword $(foreach dir,$(strip ${LIBPATH}),$(wildcard $(dir)/lib$(1).${LIBEXT}))))) +find_include = $(abspath $(strip $(firstword $(foreach dir,$(strip ${INCPATH}),$(wildcard $(dir)/$(1).h))))) +ifneq (0,$(TESTS)) + find_test = RegisterSanityCheck $(abspath $(wildcard $(1)/tests/$(2)_test.ini)) /dev/null)) + $(info *** Warning *** Using local cc since gcc isn't available locally.) + $(info *** Warning *** You may need to install gcc to build working simulators.) + GCC = cc + else + GCC = gcc + endif endif OSTYPE = $(shell uname) # OSNAME is used in messages to indicate the source of libpcap components @@ -62,69 +208,112 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OSTYPE = cygwin OSNAME = windows-build endif - ifeq (,$(shell $(GCC) -v /dev/null 2>&1 | grep 'clang')) - GCC_VERSION = $(shell $(GCC) -v /dev/null 2>&1 | grep 'gcc version' | awk '{ print $$3 }') + ifeq (Darwin,$(OSTYPE)) + ifeq (,$(shell which port)$(shell which brew)) + $(info *** Info *** simh dependent packages on macOS must be provided by either the) + $(info *** Info *** MacPorts package system or by the HomeBrew package system.) + $(info *** Info *** Neither of these seem to be installed on the local system.) + $(info *** Info ***) + ifeq (,$(INCLUDES)$(LIBRARIES)) + $(info *** Info *** Users wanting to build simulators with locally built dependent) + $(info *** Info *** packages or packages provided by an unsupported package) + $(info *** Info *** management system may be able to override where this procedure) + $(info *** Info *** looks for include files and/or libraries. Overrides can be) + $(info *** Info *** specified by defining exported environment variables or GNU make) + $(info *** Info *** command line arguments which specify INCLUDES and/or LIBRARIES.) + $(info *** Info *** If this works, that's great, if it doesn't you are on your own!) + else + $(info *** Warning *** Attempting to build on macOS with:) + $(info *** Warning *** INCLUDES defined as $(INCLUDES)) + $(info *** Warning *** and) + $(info *** Warning *** LIBRARIES defined as $(LIBRARIES)) + endif + endif + endif + ifeq (,$(shell ${GCC} -v /dev/null 2>&1 | grep 'clang')) + GCC_VERSION = $(shell ${GCC} -v /dev/null 2>&1 | grep 'gcc version' | awk '{ print $$3 }') COMPILER_NAME = GCC Version: $(GCC_VERSION) ifeq (,$(GCC_VERSION)) ifeq (SunOS,$(OSTYPE)) - ifneq (,$(shell $(GCC) -V 2>&1 | grep 'Sun C')) - SUNC_VERSION = $(shell $(GCC) -V 2>&1 | grep 'Sun C') + ifneq (,$(shell ${GCC} -V 2>&1 | grep 'Sun C')) + SUNC_VERSION = $(shell ${GCC} -V 2>&1 | grep 'Sun C') COMPILER_NAME = $(wordlist 2,10,$(SUNC_VERSION)) CC_STD = -std=c99 endif endif ifeq (HP-UX,$(OSTYPE)) - ifneq (,$(shell what `which $(firstword $(GCC)) 2>&1`| grep -i compiler)) - COMPILER_NAME = $(strip $(shell what `which $(firstword $(GCC)) 2>&1` | grep -i compiler)) + ifneq (,$(shell what `which $(firstword ${GCC}) 2>&1`| grep -i compiler)) + COMPILER_NAME = $(strip $(shell what `which $(firstword ${GCC}) 2>&1` | grep -i compiler)) CC_STD = -std=gnu99 endif endif else - ifeq (,$(findstring ++,$(GCC))) + ifeq (,$(findstring ++,${GCC})) CC_STD = -std=gnu99 else CPP_BUILD = 1 endif endif else - NO_LTO = 1 - OS_CCDEFS += -Wno-parentheses - ifeq (Apple,$(shell $(GCC) -v /dev/null 2>&1 | grep 'Apple' | awk '{ print $$1 }')) - COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'Apple' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') + ifeq (Apple,$(shell ${GCC} -v /dev/null 2>&1 | grep 'Apple' | awk '{ print $$1 }')) + COMPILER_NAME = $(shell ${GCC} -v /dev/null 2>&1 | grep 'Apple' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') CLANG_VERSION = $(word 4,$(COMPILER_NAME)) else - COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 }') + COMPILER_NAME = $(shell ${GCC} -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 }') CLANG_VERSION = $(word 3,$(COMPILER_NAME)) ifeq (,$(findstring .,$(CLANG_VERSION))) - COMPILER_NAME = $(shell $(GCC) -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') + COMPILER_NAME = $(shell ${GCC} -v /dev/null 2>&1 | grep 'clang version' | awk '{ print $$1 " " $$2 " " $$3 " " $$4 }') CLANG_VERSION = $(word 4,$(COMPILER_NAME)) endif endif - ifeq (,$(findstring ++,$(GCC))) + ifeq (,$(findstring ++,${GCC})) CC_STD = -std=c99 else CPP_BUILD = 1 + OS_CCDEFS += -Wno-deprecated + endif + endif + ifeq (git-repo,$(shell if ${TEST} -e ./.git; then echo git-repo; fi)) + GIT_PATH=$(strip $(shell which git)) + ifeq (,$(GIT_PATH)) + $(error building using a git repository, but git is not available) + endif + ifeq (commit-id-exists,$(shell if ${TEST} -e .git-commit-id; then echo commit-id-exists; fi)) + CURRENT_GIT_COMMIT_ID=$(strip $(shell grep 'SIM_GIT_COMMIT_ID' .git-commit-id | awk '{ print $$2 }')) + ACTUAL_GIT_COMMIT_ID=$(strip $(shell git log -1 --pretty="%H")) + ifneq ($(CURRENT_GIT_COMMIT_ID),$(ACTUAL_GIT_COMMIT_ID)) + NEED_COMMIT_ID = need-commit-id + # make sure that the invalidly formatted .git-commit-id file wasn't generated + # by legacy git hooks which need to be removed. + $(shell rm -f .git/hooks/post-checkout .git/hooks/post-commit .git/hooks/post-merge) + endif + else + NEED_COMMIT_ID = need-commit-id + endif + ifneq (,$(shell git update-index --refresh --)) + GIT_EXTRA_FILES=+uncommitted-changes + endif + ifneq (,$(or $(NEED_COMMIT_ID),$(GIT_EXTRA_FILES))) + isodate=$(shell git log -1 --pretty="%ai"|sed -e 's/ /T/'|sed -e 's/ //') + $(shell git log -1 --pretty="SIM_GIT_COMMIT_ID %H$(GIT_EXTRA_FILES)%nSIM_GIT_COMMIT_TIME $(isodate)" >.git-commit-id) endif endif LTO_EXCLUDE_VERSIONS = PCAPLIB = pcap - ifeq (agcc,$(findstring agcc,$(GCC))) # Android target build? - OS_CCDEFS = -D_GNU_SOURCE - ifeq (,$(NOASYNCH)) - OS_CCDEFS += -DSIM_ASYNCH_IO - endif + ifeq (agcc,$(findstring agcc,${GCC})) # Android target build? + OS_CCDEFS = -D_GNU_SOURCE -DSIM_ASYNCH_IO OS_LDFLAGS = -lm else # Non-Android (or Native Android) Builds ifeq (,$(INCLUDES)$(LIBRARIES)) - INCPATH:=$(shell LANG=C; $(GCC) -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | tr -d '\n') - ifeq (,$(INCPATH)) + INCPATH:=$(shell LANG=C; ${GCC} -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | tr -d '\n') + ifeq (,${INCPATH}) INCPATH:=/usr/include endif LIBPATH:=/usr/lib else $(info *** Warning ***) ifeq (,$(INCLUDES)) - INCPATH:=$(shell LANG=C; $(GCC) -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | tr -d '\n') + INCPATH:=$(shell LANG=C; ${GCC} -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | tr -d '\n') else $(info *** Warning *** Unsupported build with INCLUDES defined as: $(INCLUDES)) INCPATH:=$(strip $(subst :, ,$(INCLUDES))) @@ -144,30 +333,31 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) $(info *** Warning ***) endif OS_CCDEFS += -D_GNU_SOURCE - GCC_OPTIMIZERS_CMD = $(GCC) -v --help 2>&1 - GCC_WARNINGS_CMD = $(GCC) -v --help 2>&1 - LD_ELF = $(shell echo | $(GCC) -E -dM - | grep __ELF__) + GCC_OPTIMIZERS_CMD = ${GCC} -v --help 2>&1 + GCC_WARNINGS_CMD = ${GCC} -v --help 2>&1 + LD_ELF = $(shell echo | ${GCC} -E -dM - | grep __ELF__) ifeq (Darwin,$(OSTYPE)) OSNAME = OSX LIBEXT = dylib ifneq (include,$(findstring include,$(UNSUPPORTED_BUILD))) - INCPATH:=$(shell LANG=C; $(GCC) -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | grep -v 'framework directory' | tr -d '\n') + INCPATH:=$(shell LANG=C; ${GCC} -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | grep -v 'framework directory' | tr -d '\n') endif - ifeq (incopt,$(shell if $(TEST) -d /opt/local/include; then echo incopt; fi)) + ifeq (incopt,$(shell if ${TEST} -d /opt/local/include; then echo incopt; fi)) INCPATH += /opt/local/include OS_CCDEFS += -I/opt/local/include endif - ifeq (libopt,$(shell if $(TEST) -d /opt/local/lib; then echo libopt; fi)) + ifeq (libopt,$(shell if ${TEST} -d /opt/local/lib; then echo libopt; fi)) LIBPATH += /opt/local/lib OS_LDFLAGS += -L/opt/local/lib endif - ifeq (HomeBrew,$(shell if $(TEST) -d /usr/local/Cellar; then echo HomeBrew; fi)) - INCPATH += $(foreach dir,$(wildcard /usr/local/Cellar/*/*),$(dir)/include) - LIBPATH += $(foreach dir,$(wildcard /usr/local/Cellar/*/*),$(dir)/lib) - endif - ifeq (libXt,$(shell if $(TEST) -d /usr/X11/lib; then echo libXt; fi)) - LIBPATH += /usr/X11/lib - OS_LDFLAGS += -L/usr/X11/lib + ifeq (HomeBrew,$(or $(shell if ${TEST} -d /usr/local/Cellar; then echo HomeBrew; fi),$(shell if ${TEST} -d /opt/homebrew/Cellar; then echo HomeBrew; fi))) + ifeq (local,$(shell if $(TEST) -d /usr/local/Cellar; then echo local; fi)) + HBPATH = /usr/local + else + HBPATH = /opt/homebrew + endif + INCPATH += $(foreach dir,$(wildcard $(HBPATH)/Cellar/*/*),$(realpath $(dir)/include)) + LIBPATH += $(foreach dir,$(wildcard $(HBPATH)/Cellar/*/*),$(realpath $(dir)/lib)) endif else ifeq (Linux,$(OSTYPE)) @@ -176,12 +366,15 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif ifneq (lib,$(findstring lib,$(UNSUPPORTED_BUILD))) ifeq (Android,$(shell uname -o)) - ifneq (,$(shell if $(TEST) -d /system/lib; then echo systemlib; fi)) + ifneq (,$(shell if ${TEST} -d ${PREFIX}/lib; then echo prefixlib; fi)) + LIBPATH += ${PREFIX}/lib + endif + ifneq (,$(shell if ${TEST} -d /system/lib; then echo systemlib; fi)) LIBPATH += /system/lib endif LIBPATH += $(LD_LIBRARY_PATH) endif - ifeq (ldconfig,$(shell if $(TEST) -e /sbin/ldconfig; then echo ldconfig; fi)) + ifeq (ldconfig,$(shell if ${TEST} -e /sbin/ldconfig; then echo ldconfig; fi)) LIBPATH := $(sort $(foreach lib,$(shell /sbin/ldconfig -p | grep ' => /' | sed 's/^.* => //'),$(dir $(lib)))) endif endif @@ -194,11 +387,11 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif LIBEXT = so OS_LDFLAGS += -lsocket -lnsl - ifeq (incsfw,$(shell if $(TEST) -d /opt/sfw/include; then echo incsfw; fi)) + ifeq (incsfw,$(shell if ${TEST} -d /opt/sfw/include; then echo incsfw; fi)) INCPATH += /opt/sfw/include OS_CCDEFS += -I/opt/sfw/include endif - ifeq (libsfw,$(shell if $(TEST) -d /opt/sfw/lib; then echo libsfw; fi)) + ifeq (libsfw,$(shell if ${TEST} -d /opt/sfw/lib; then echo libsfw; fi)) LIBPATH += /opt/sfw/lib OS_LDFLAGS += -L/opt/sfw/lib -R/opt/sfw/lib endif @@ -206,18 +399,18 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) else ifeq (cygwin,$(OSTYPE)) # use 0readme_ethernet.txt documented Windows pcap build components - INCPATH += ../windows-build/winpcap/WpdPack/include - LIBPATH += ../windows-build/winpcap/WpdPack/lib + INCPATH += ../windows-build/winpcap/WpdPack/Include + LIBPATH += ../windows-build/winpcap/WpdPack/Lib PCAPLIB = wpcap LIBEXT = a else ifneq (,$(findstring AIX,$(OSTYPE))) OS_LDFLAGS += -lm -lrt - ifeq (incopt,$(shell if $(TEST) -d /opt/freeware/include; then echo incopt; fi)) + ifeq (incopt,$(shell if ${TEST} -d /opt/freeware/include; then echo incopt; fi)) INCPATH += /opt/freeware/include OS_CCDEFS += -I/opt/freeware/include endif - ifeq (libopt,$(shell if $(TEST) -d /opt/freeware/lib; then echo libopt; fi)) + ifeq (libopt,$(shell if ${TEST} -d /opt/freeware/lib; then echo libopt; fi)) LIBPATH += /opt/freeware/lib OS_LDFLAGS += -L/opt/freeware/lib endif @@ -255,23 +448,17 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) LIBPATH = $(subst :, ,$(LPATH)) endif endif - OS_LDFLAGS += $(patsubst %,-L%,$(LIBPATH)) + OS_LDFLAGS += $(patsubst %,-L%,${LIBPATH}) endif endif endif - ifeq (usrpkglib,$(shell if $(TEST) -d /usr/pkg/lib; then echo usrpkglib; fi)) + ifeq (usrpkglib,$(shell if ${TEST} -d /usr/pkg/lib; then echo usrpkglib; fi)) LIBPATH += /usr/pkg/lib INCPATH += /usr/pkg/include OS_LDFLAGS += -L/usr/pkg/lib -R/usr/pkg/lib OS_CCDEFS += -I/usr/pkg/include endif - ifeq (X11R7,$(shell if $(TEST) -d /usr/X11R7/lib; then echo X11R7; fi)) - LIBPATH += /usr/X11R7/lib - INCPATH += /usr/X11R7/include - OS_LDFLAGS += -L/usr/X11R7/lib -R/usr/X11R7/lib - OS_CCDEFS += -I/usr/X11R7/include - endif - ifeq (/usr/local/lib,$(findstring /usr/local/lib,$(LIBPATH))) + ifeq (/usr/local/lib,$(findstring /usr/local/lib,${LIBPATH})) INCPATH += /usr/local/include OS_CCDEFS += -I/usr/local/include endif @@ -295,19 +482,31 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif endif endif + ifeq (,$(filter /lib/,$(LIBPATH))) + ifeq (existlib,$(shell if $(TEST) -d /lib/; then echo existlib; fi)) + LIBPATH += /lib/ + endif + endif + ifeq (,$(filter /usr/lib/,$(LIBPATH))) + ifeq (existusrlib,$(shell if $(TEST) -d /usr/lib/; then echo existusrlib; fi)) + LIBPATH += /usr/lib/ + endif + endif + export CPATH = $(subst $() $(),:,$(INCPATH)) + export LIBRARY_PATH = $(subst $() $(),:,$(LIBPATH)) # Some gcc versions don't support LTO, so only use LTO when the compiler is known to support it ifeq (,$(NO_LTO)) ifneq (,$(GCC_VERSION)) - ifeq (,$(shell $(GCC) -v /dev/null 2>&1 | grep '\-\-enable-lto')) + ifeq (,$(shell ${GCC} -v /dev/null 2>&1 | grep '\-\-enable-lto')) LTO_EXCLUDE_VERSIONS += $(GCC_VERSION) endif endif endif endif - $(info lib paths are: $(LIBPATH)) - $(info include paths are: $(INCPATH)) - find_lib = $(strip $(firstword $(foreach dir,$(strip $(LIBPATH)),$(wildcard $(dir)/lib$(1).$(LIBEXT))))) - find_include = $(strip $(firstword $(foreach dir,$(strip $(INCPATH)),$(wildcard $(dir)/$(1).h)))) + $(info lib paths are: ${LIBPATH}) + $(info include paths are: ${INCPATH}) + need_search = $(strip $(shell ld -l$(1) /dev/null 2>&1 | grep $(1) | sed s/$(1)//)) + LD_SEARCH_NEEDED := $(call need_search,ZzzzzzzZ) ifneq (,$(call find_lib,m)) OS_LDFLAGS += -lm $(info using libm: $(call find_lib,m)) @@ -316,14 +515,48 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OS_LDFLAGS += -lrt $(info using librt: $(call find_lib,rt)) endif - ifneq (,$(call find_lib,pthread)) - ifneq (,$(call find_include,pthread)) - OS_CCDEFS += -DUSE_READER_THREAD - ifeq (,$(NOASYNCH)) - OS_CCDEFS += -DSIM_ASYNCH_IO - endif + ifneq (,$(call find_include,pthread)) + ifneq (,$(call find_lib,pthread)) + OS_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO OS_LDFLAGS += -lpthread $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) + else + LIBEXTSAVE := ${LIBEXT} + LIBEXT = a + ifneq (,$(call find_lib,pthread)) + OS_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO + OS_LDFLAGS += -lpthread + $(info using libpthread: $(call find_lib,pthread) $(call find_include,pthread)) + else + ifneq (,$(findstring Haiku,$(OSTYPE))) + OS_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO + $(info using libpthread: $(call find_include,pthread)) + else + ifeq (Darwin,$(OSTYPE)) + OS_CCDEFS += -DUSE_READER_THREAD -DSIM_ASYNCH_IO + OS_LDFLAGS += -lpthread + $(info using macOS libpthread: $(call find_include,pthread)) + endif + endif + endif + LIBEXT = $(LIBEXTSAVE) + endif + endif + # Find PCRE RegEx library. + ifneq (,$(call find_include,pcre)) + ifneq (,$(call find_lib,pcre)) + OS_CCDEFS += -DHAVE_PCRE_H + OS_LDFLAGS += -lpcre + $(info using libpcre: $(call find_lib,pcre) $(call find_include,pcre)) + ifeq ($(LD_SEARCH_NEEDED),$(call need_search,pcre)) + OS_LDFLAGS += -L$(dir $(call find_lib,pcre)) + endif + endif + endif + # Find available ncurses library. + ifneq (,$(call find_include,ncurses)) + ifneq (,$(call find_lib,ncurses)) + OS_CURSES_DEFS += -DHAVE_NCURSES -lncurses endif endif ifneq (,$(call find_include,semaphore)) @@ -332,24 +565,145 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) $(info using semaphore: $(call find_include,semaphore)) endif endif - ifneq (,$(call find_include,sys/mman)) - ifneq (,$(shell grep shm_open $(call find_include,sys/mman))) - OS_CCDEFS += -DHAVE_SHM_OPEN - $(info using mman: $(call find_include,sys/mman)) - endif + ifneq (,$(call find_include,sys/ioctl)) + OS_CCDEFS += -DHAVE_SYS_IOCTL + endif + ifneq (,$(call find_include,linux/cdrom)) + OS_CCDEFS += -DHAVE_LINUX_CDROM endif ifneq (,$(call find_include,dlfcn)) ifneq (,$(call find_lib,dl)) - OS_CCDEFS += -DHAVE_DLOPEN=$(LIBEXT) + OS_CCDEFS += -DSIM_HAVE_DLOPEN=${LIBEXT} OS_LDFLAGS += -ldl $(info using libdl: $(call find_lib,dl) $(call find_include,dlfcn)) else - ifeq (BSD,$(findstring BSD,$(OSTYPE))) - OS_CCDEFS += -DHAVE_DLOPEN=so + ifneq (,$(findstring BSD,$(OSTYPE))$(findstring AIX,$(OSTYPE))$(findstring Haiku,$(OSTYPE))) + OS_CCDEFS += -DSIM_HAVE_DLOPEN=so $(info using libdl: $(call find_include,dlfcn)) + else + ifneq (,$(call find_lib,dld)) + OS_CCDEFS += -DSIM_HAVE_DLOPEN=${LIBEXT} + OS_LDFLAGS += -ldld + $(info using libdld: $(call find_lib,dld) $(call find_include,dlfcn)) + else + ifeq (Darwin,$(OSTYPE)) + OS_CCDEFS += -DSIM_HAVE_DLOPEN=dylib + $(info using macOS dlopen with .dylib) + endif + endif endif endif endif + ifneq (,$(call find_include,utime)) + OS_CCDEFS += -DHAVE_UTIME + endif + ifneq (,$(call find_include,png)) + ifneq (,$(call find_lib,png)) + OS_CCDEFS += -DHAVE_LIBPNG + OS_LDFLAGS += -lpng + $(info using libpng: $(call find_lib,png) $(call find_include,png)) + ifneq (,$(call find_include,zlib)) + ifneq (,$(call find_lib,z)) + OS_CCDEFS += -DHAVE_ZLIB + OS_LDFLAGS += -lz + $(info using zlib: $(call find_lib,z) $(call find_include,zlib)) + endif + endif + endif + endif + ifneq (,$(call find_include,glob)) + OS_CCDEFS += -DHAVE_GLOB + else + ifneq (,$(call find_include,fnmatch)) + OS_CCDEFS += -DHAVE_FNMATCH + endif + endif + ifneq (,$(call find_include,sys/mman)) + ifneq (,$(shell grep shm_open $(call find_include,sys/mman))) + # some Linux installs have been known to have the include, but are + # missing librt (where the shm_ APIs are implemented on Linux) + # other OSes seem have these APIs implemented elsewhere + ifneq (,$(if $(findstring Linux,$(OSTYPE)),$(call find_lib,rt),OK)) + OS_CCDEFS += -DHAVE_SHM_OPEN + $(info using mman: $(call find_include,sys/mman)) + endif + endif + endif + ifneq (,$(VIDEO_USEFUL)) + ifeq (cygwin,$(OSTYPE)) + LIBEXTSAVE := ${LIBEXT} + LIBEXT = dll.a + endif + ifneq (,$(call find_include,SDL2/SDL)) + ifneq (,$(call find_lib,SDL2)) + ifneq (,$(findstring Haiku,$(OSTYPE))) + ifneq (,$(shell which sdl2-config)) + SDLX_CONFIG = sdl2-config + endif + else + SDLX_CONFIG = $(realpath $(dir $(call find_include,SDL2/SDL))../../bin/sdl2-config) + endif + ifneq (,$(SDLX_CONFIG)) + VIDEO_CCDEFS += -DHAVE_LIBSDL -DUSE_SIM_VIDEO `$(SDLX_CONFIG) --cflags` + VIDEO_LDFLAGS += `$(SDLX_CONFIG) --libs` + VIDEO_FEATURES = - video capabilities provided by libSDL2 (Simple Directmedia Layer) + DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/sim_ws.c + DISPLAYVT = ${DISPLAYD}/vt11.c + DISPLAY340 = ${DISPLAYD}/type340.c + DISPLAYNG = ${DISPLAYD}/ng.c + DISPLAYIII = ${DISPLAYD}/iii.c + DISPLAY_OPT += -DUSE_DISPLAY $(VIDEO_CCDEFS) $(VIDEO_LDFLAGS) + $(info using libSDL2: $(call find_include,SDL2/SDL)) + ifeq (Darwin,$(OSTYPE)) + VIDEO_CCDEFS += -DSDL_MAIN_AVAILABLE + endif + endif + endif + endif + ifeq (cygwin,$(OSTYPE)) + LIBEXT = $(LIBEXTSAVE) + endif + ifeq (,$(findstring HAVE_LIBSDL,$(VIDEO_CCDEFS))) + $(info *** Info ***) + $(info *** Info *** The simulator$(BUILD_MULTIPLE) you are building could provide more functionality) + $(info *** Info *** if video support was available on your system.) + $(info *** Info *** To gain this functionality:) + ifeq (Darwin,$(OSTYPE)) + ifeq (/opt/local/bin/port,$(shell which port)) + $(info *** Info *** Install the MacPorts libSDL2 package to provide this) + $(info *** Info *** functionality for your OS X system:) + $(info *** Info *** # port install libsdl2 libpng zlib) + endif + ifeq (/usr/local/bin/brew,$(shell which brew)) + ifeq (/opt/local/bin/port,$(shell which port)) + $(info *** Info ***) + $(info *** Info *** OR) + $(info *** Info ***) + endif + $(info *** Info *** Install the HomeBrew libSDL2 package to provide this) + $(info *** Info *** functionality for your OS X system:) + $(info *** Info *** $$ brew install sdl2 libpng zlib) + else + ifeq (,$(shell which port)) + $(info *** Info *** Install MacPorts or HomeBrew and rerun this make for) + $(info *** Info *** specific advice) + endif + endif + else + ifneq (,$(and $(findstring Linux,$(OSTYPE)),$(call find_exe,apt-get))) + $(info *** Info *** Install the development components of libSDL2 packaged for) + $(info *** Info *** your operating system distribution for your Linux) + $(info *** Info *** system:) + $(info *** Info *** $$ sudo apt-get install libsdl2-dev libpng-dev) + else + $(info *** Info *** Install the development components of libSDL2 packaged by your) + $(info *** Info *** operating system distribution and rebuild your simulator to) + $(info *** Info *** enable this extra functionality.) + endif + endif + $(info *** Info ***) + endif + endif ifneq (,$(NETWORK_USEFUL)) ifneq (,$(call find_include,pcap)) ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include)) @@ -360,9 +714,29 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const)) BPF_CONST_STRING = -DBPF_CONST_STRING endif + NETWORK_CCDEFS += -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_LAN_FEATURES += PCAP ifneq (,$(call find_lib,$(PCAPLIB))) ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line - NETWORK_CCDEFS = -DUSE_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_CCDEFS += -DUSE_NETWORK + ifeq (,$(findstring Linux,$(OSTYPE))$(findstring Darwin,$(OSTYPE))) + $(info *** Warning ***) + $(info *** Warning *** Statically linking against libpcap is provides no measurable) + $(info *** Warning *** benefits over dynamically linking libpcap.) + $(info *** Warning ***) + $(info *** Warning *** Support for linking this way is currently deprecated and may be removed) + $(info *** Warning *** in the future.) + $(info *** Warning ***) + else + $(info *** Error ***) + $(info *** Error *** Statically linking against libpcap is provides no measurable) + $(info *** Error *** benefits over dynamically linking libpcap.) + $(info *** Error ***) + $(info *** Error *** Support for linking statically has been removed on the $(OSTYPE)) + $(info *** Error *** platform.) + $(info *** Error ***) + $(error Retry your build without specifying USE_NETWORK=1) + endif ifeq (cygwin,$(OSTYPE)) # cygwin has no ldconfig so explicitly specify pcap object library NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) @@ -372,71 +746,196 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components else # default build uses dynamic libpcap - NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_CCDEFS += -DUSE_SHARED $(info using libpcap: $(call find_include,pcap)) NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components endif else - NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) - NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components - $(info using libpcap: $(call find_include,pcap)) + LIBEXTSAVE := ${LIBEXT} + LIBEXT = a + ifneq (,$(call find_lib,$(PCAPLIB))) + NETWORK_CCDEFS += -DUSE_NETWORK + NETWORK_LDFLAGS := -L$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + endif + LIBEXT = $(LIBEXTSAVE) + ifeq (Darwin,$(OSTYPE)$(findstring USE_,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_SHARED + NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components + $(info using macOS dynamic libpcap: $(call find_include,pcap)) + endif endif else - # Look for package built from tcpdump.org sources with default install target (or cygwin winpcap) - LIBPATH += /usr/local/lib - INCPATH += /usr/local/include - LIBEXTSAVE := $(LIBEXT) - LIBEXT = a - ifneq (,$(call find_lib,$(PCAPLIB))) - ifneq (,$(call find_include,pcap)) - $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) - ifeq (cygwin,$(OSTYPE)) - NETWORK_CCDEFS = -DUSE_NETWORK -I$(dir $(call find_include,pcap)) - NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) - NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories + # On non-Linux platforms, we'll still try to provide deprecated support for libpcap in /usr/local + INCPATHSAVE := ${INCPATH} + ifeq (,$(findstring Linux,$(OSTYPE))) + # Look for package built from tcpdump.org sources with default install target (or cygwin winpcap) + INCPATH += /usr/local/include + PCAP_H_FOUND = $(call find_include,pcap) + endif + ifneq (,$(strip $(PCAP_H_FOUND))) + ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include)) + PCAP_H_PATH = $(dir $(call find_include,pcap))pcap/pcap.h + else + PCAP_H_PATH = $(call find_include,pcap) + endif + ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const)) + BPF_CONST_STRING = -DBPF_CONST_STRING + endif + LIBEXTSAVE := ${LIBEXT} + # first check if binary - shared objects are available/installed in the linker known search paths + ifneq (,$(call find_lib,$(PCAPLIB))) + NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_FEATURES = - dynamic networking support using libpcap components from www.tcpdump.org and locally installed libpcap.${LIBEXT} + $(info using libpcap: $(call find_include,pcap)) + else + LIBPATH += /usr/local/lib + LIBEXT = a + ifneq (,$(call find_lib,$(PCAPLIB))) + $(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap)) + ifeq (cygwin,$(OSTYPE)) + NETWORK_CCDEFS = -DUSE_NETWORK -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) + NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB) + NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories + else + NETWORK_CCDEFS := -DUSE_NETWORK -DHAVE_PCAP_NETWORK -isystem -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) $(call find_lib,$(PCAPLIB)) + NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) + $(info *** Warning *** libpcap components from www.tcpdump.org.) + $(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap) + $(info *** Warning *** components for simh networking. For best results, with) + $(info *** Warning *** simh networking, it is recommended that you install the) + $(info *** Warning *** libpcap-dev (or libpcap-devel) package from your $(OSNAME) distribution) + $(info *** Warning ***) + $(info *** Warning *** Building with the components manually installed from www.tcpdump.org) + $(info *** Warning *** is officially deprecated. Attempting to do so is unsupported.) + $(info *** Warning ***) + endif else - NETWORK_CCDEFS := -DUSE_NETWORK -isystem $(dir $(call find_include,pcap)) $(call find_lib,$(PCAPLIB)) - NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org - $(info *** Warning ***) - $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using) - $(info *** Warning *** libpcap components from www.tcpdump.org.) - $(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap) - $(info *** Warning *** components for simh networking. For best results, with) - $(info *** Warning *** simh networking, it is recommended that you install the) - $(info *** Warning *** libpcap-dev package from your $(OSTYPE) distribution) - $(info *** Warning ***) + $(error using libpcap: $(call find_include,pcap) missing $(PCAPLIB).${LIBEXT}) + endif + NETWORK_LAN_FEATURES += PCAP + endif + LIBEXT = $(LIBEXTSAVE) + else + INCPATH = $(INCPATHSAVE) + $(info *** Warning ***) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) $(BUILD_MULTIPLE_VERB) being built WITHOUT) + $(info *** Warning *** libpcap networking support) + $(info *** Warning ***) + $(info *** Warning *** To build simulator(s) with libpcap networking support you) + ifneq (,$(and $(findstring Linux,$(OSTYPE)),$(call find_exe,apt-get))) + $(info *** Warning *** should install the libpcap development components for) + $(info *** Warning *** for your Linux system:) + $(info *** Warning *** $$ sudo apt-get install libpcap-dev) + else + $(info *** Warning *** should read 0readme_ethernet.txt and follow the instructions) + $(info *** Warning *** regarding the needed libpcap development components for your) + $(info *** Warning *** $(OSTYPE) platform) + endif + $(info *** Warning ***) + endif + endif + # Consider other network connections + ifneq (,$(call find_lib,vdeplug)) + # libvdeplug requires the use of the OS provided libpcap + ifeq (,$(findstring usr/local,$(NETWORK_CCDEFS))) + ifneq (,$(call find_include,libvdeplug)) + # Provide support for vde networking + NETWORK_CCDEFS += -DHAVE_VDE_NETWORK + NETWORK_LAN_FEATURES += VDE + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK + endif + ifeq (Darwin,$(OSTYPE)) + NETWORK_LDFLAGS += -lvdeplug -L$(dir $(call find_lib,vdeplug)) + else + NETWORK_LDFLAGS += -lvdeplug -Wl,-R,$(dir $(call find_lib,vdeplug)) -L$(dir $(call find_lib,vdeplug)) + endif + $(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug)) + endif + endif + endif + ifeq (,$(findstring HAVE_VDE_NETWORK,$(NETWORK_CCDEFS))) + # Support is available on Linux for libvdeplug. Advise on its usage + ifneq (,$(findstring Linux,$(OSTYPE))$(findstring Darwin,$(OSTYPE))) + ifneq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + $(info *** Info ***) + $(info *** Info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) $(BUILD_MULTIPLE_VERB) being built with) + $(info *** Info *** minimal libpcap networking support) + $(info *** Info ***) + endif + $(info *** Info ***) + $(info *** Info *** Simulators on your $(OSNAME) platform can also be built with) + $(info *** Info *** extended LAN Ethernet networking support by using VDE Ethernet.) + $(info *** Info ***) + $(info *** Info *** To build simulator(s) with extended networking support you) + ifeq (Darwin,$(OSTYPE)) + ifeq (/opt/local/bin/port,$(shell which port)) + $(info *** Info *** should install the MacPorts vde2 package to provide this) + $(info *** Info *** functionality for your OS X system:) + $(info *** Info *** # port install vde2) + endif + ifeq (/usr/local/bin/brew,$(shell which brew)) + ifeq (/opt/local/bin/port,$(shell which port)) + $(info *** Info ***) + $(info *** Info *** OR) + $(info *** Info ***) + endif + $(info *** Info *** should install the HomeBrew vde package to provide this) + $(info *** Info *** functionality for your OS X system:) + $(info *** Info *** $$ brew install vde) + else + ifeq (,$(shell which port)) + $(info *** Info *** should install MacPorts or HomeBrew and rerun this make for) + $(info *** Info *** specific advice) + endif endif else - $(error using libpcap: $(call find_lib,$(PCAPLIB)) missing pcap.h) - endif - endif - LIBEXT = $(LIBEXTSAVE) - endif - ifneq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) - # Given we have libpcap components, consider other network connections as well - ifneq (,$(call find_lib,vdeplug)) - # libvdeplug requires the use of the OS provided libpcap - ifeq (,$(findstring usr/local,$(NETWORK_CCDEFS))) - ifneq (,$(call find_include,libvdeplug)) - # Provide support for vde networking - NETWORK_CCDEFS += -DUSE_VDE_NETWORK - NETWORK_LDFLAGS += -lvdeplug - $(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug)) + ifneq (,$(and $(findstring Linux,$(OSTYPE)),$(call find_exe,apt-get))) + $(info *** Info *** should install the vde2 package to provide this) + $(info *** Info *** functionality for your $(OSNAME) system:) + ifneq (,$(shell apt list 2>/dev/null| grep libvdeplug-dev)) + $(info *** Info *** $$ sudo apt-get install libvdeplug-dev) + else + $(info *** Info *** $$ sudo apt-get install vde2) + endif + else + $(info *** Info *** should read 0readme_ethernet.txt and follow the instructions) + $(info *** Info *** regarding the needed libvdeplug components for your $(OSNAME)) + $(info *** Info *** platform) endif endif + $(info *** Info ***) endif - ifneq (,$(call find_include,linux/if_tun)) - # Provide support for Tap networking on Linux - NETWORK_CCDEFS += -DUSE_TAP_NETWORK + endif + ifneq (,$(call find_include,linux/if_tun)) + # Provide support for Tap networking on Linux + NETWORK_CCDEFS += -DHAVE_TAP_NETWORK + NETWORK_LAN_FEATURES += TAP + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK endif - ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi)) - # Provide support for Tap networking on BSD platforms (including OS X) - NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP + endif + ifeq (bsdtuntap,$(shell if ${TEST} -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext -o -e /Applications/Tunnelblick.app/Contents/Resources/tap-notarized.kext; then echo bsdtuntap; fi)) + # Provide support for Tap networking on BSD platforms (including OS X) + NETWORK_CCDEFS += -DHAVE_TAP_NETWORK -DHAVE_BSDTUNTAP + NETWORK_LAN_FEATURES += TAP + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK endif - else - NETWORK_FEATURES = - WITHOUT networking support + endif + ifeq (slirp,$(shell if ${TEST} -e slirp_glue/sim_slirp.c; then echo slirp; fi)) + NETWORK_CCDEFS += -Islirp -Islirp_glue -Islirp_glue/qemu -DHAVE_SLIRP_NETWORK -DUSE_SIMH_SLIRP_DEBUG slirp/*.c slirp_glue/*.c + NETWORK_LAN_FEATURES += NAT(SLiRP) + endif + ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS))$(findstring HAVE_VDE_NETWORK,$(NETWORK_CCDEFS))) + NETWORK_CCDEFS += -DUSE_NETWORK + NETWORK_FEATURES = - WITHOUT Local LAN networking support $(info *** Warning ***) - $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) are being built WITHOUT networking support) + $(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) $(BUILD_MULTIPLE_VERB) being built WITHOUT LAN networking support) $(info *** Warning ***) $(info *** Warning *** To build simulator(s) with networking support you should read) $(info *** Warning *** 0readme_ethernet.txt and follow the instructions regarding the) @@ -445,70 +944,276 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif NETWORK_OPT = $(NETWORK_CCDEFS) endif - ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi)) - MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi + ifneq (binexists,$(shell if ${TEST} -e BIN/buildtools; then echo binexists; fi)) + MKDIRBIN = @mkdir -p BIN/buildtools + endif + ifeq (commit-id-exists,$(shell if ${TEST} -e .git-commit-id; then echo commit-id-exists; fi)) + GIT_COMMIT_ID=$(shell grep 'SIM_GIT_COMMIT_ID' .git-commit-id | awk '{ print $$2 }') + GIT_COMMIT_TIME=$(shell grep 'SIM_GIT_COMMIT_TIME' .git-commit-id | awk '{ print $$2 }') + else + ifeq (,$(shell grep 'define SIM_GIT_COMMIT_ID' sim_rev.h | grep 'Format:')) + GIT_COMMIT_ID=$(shell grep 'define SIM_GIT_COMMIT_ID' sim_rev.h | awk '{ print $$3 }') + GIT_COMMIT_TIME=$(shell grep 'define SIM_GIT_COMMIT_TIME' sim_rev.h | awk '{ print $$3 }') + else + ifeq (git-submodule,$(if $(shell cd .. ; git rev-parse --git-dir 2>/dev/null),git-submodule)) + GIT_COMMIT_ID=$(shell cd .. ; git submodule status | grep " $(notdir $(realpath .)) " | awk '{ print $$1 }') + GIT_COMMIT_TIME=$(shell git --git-dir=$(realpath .)/.git log $(GIT_COMMIT_ID) -1 --pretty="%aI") + else + $(info *** Error ***) + $(info *** Error *** The simh git commit id can not be determined.) + $(info *** Error ***) + $(info *** Error *** There are ONLY two supported ways to acquire and build) + $(info *** Error *** the simh source code:) + $(info *** Error *** 1: directly with git via:) + $(info *** Error *** $$ git clone https://github.com/simh/simh) + $(info *** Error *** $$ cd simh) + $(info *** Error *** $$ make {simulator-name}) + $(info *** Error *** OR) + $(info *** Error *** 2: download the source code zip archive from:) + $(info *** Error *** $$ wget(or via browser) https://github.com/simh/simh/archive/master.zip) + $(info *** Error *** $$ unzip master.zip) + $(info *** Error *** $$ cd simh-master) + $(info *** Error *** $$ make {simulator-name}) + $(info *** Error ***) + $(error get simh source either with zip download or git clone) + endif + endif endif else #Win32 Environments (via MinGW32) - GCC = gcc - GCC_Path := $(dir $(shell where gcc.exe)) - GCC_VERSION = $(word 3,$(shell $(GCC) --version)) - LTO_EXCLUDE_VERSIONS = 4.5.2 - ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) - PTHREADS_CCDEFS = -DUSE_READER_THREAD -DPTW32_STATIC_LIB -D_POSIX_C_SOURCE -I../windows-build/pthreads/Pre-built.2/include - ifeq (,$(NOASYNCH)) - PTHREADS_CCDEFS += -DSIM_ASYNCH_IO - endif - PTHREADS_LDFLAGS = -lpthreadGC2 -L..\windows-build\pthreads\Pre-built.2\lib + GCC := gcc + GCC_Path := $(abspath $(dir $(word 1,$(wildcard $(addsuffix /${GCC}.exe,$(subst ;, ,${PATH})))))) + ifeq (rename-build-support,$(shell if exist ..\windows-build-windows-build echo rename-build-support)) + REMOVE_OLD_BUILD := $(shell if exist ..\windows-build rmdir/s/q ..\windows-build) + FIXED_BUILD := $(shell move ..\windows-build-windows-build ..\windows-build >NUL) + endif + GCC_VERSION = $(word 3,$(shell ${GCC} --version)) + COMPILER_NAME = GCC Version: $(GCC_VERSION) + ifeq (,$(findstring ++,${GCC})) + CC_STD = -std=gnu99 else - ifeq (pthreads,$(shell if exist $(dir $(GCC_Path))..\include\pthread.h echo pthreads)) - PTHREADS_CCDEFS = -DUSE_READER_THREAD - ifeq (,$(NOASYNCH)) - PTHREADS_CCDEFS += -DSIM_ASYNCH_IO - endif - PTHREADS_LDFLAGS = -lpthread + CPP_BUILD = 1 + endif + LTO_EXCLUDE_VERSIONS = 4.5.2 + ifeq (,$(PATH_SEPARATOR)) + PATH_SEPARATOR := ; + endif + INCPATH = $(abspath $(wildcard $(GCC_Path)\..\include $(subst $(PATH_SEPARATOR), ,$(CPATH)) $(subst $(PATH_SEPARATOR), ,$(C_INCLUDE_PATH)))) + LIBPATH = $(abspath $(wildcard $(GCC_Path)\..\lib $(subst :, ,$(LIBRARY_PATH)))) + $(info lib paths are: ${LIBPATH}) + $(info include paths are: ${INCPATH}) + # Give preference to any MinGW provided threading (if available) + ifneq (,$(call find_include,pthread)) + PTHREADS_CCDEFS = -DUSE_READER_THREAD -DSIM_ASYNCH_IO + PTHREADS_LDFLAGS = -lpthread + else + ifeq (pthreads,$(shell if exist ..\windows-build\pthreads\Pre-built.2\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DUSE_READER_THREAD -DPTW32_STATIC_LIB -D_POSIX_C_SOURCE -I../windows-build/pthreads/Pre-built.2/include -DSIM_ASYNCH_IO + PTHREADS_LDFLAGS = -lpthreadGC2 -L..\windows-build\pthreads\Pre-built.2\lib endif endif ifeq (pcap,$(shell if exist ..\windows-build\winpcap\Wpdpack\include\pcap.h echo pcap)) - PCAP_CCDEFS = -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk -DUSE_SHARED NETWORK_LDFLAGS = - NETWORK_OPT = -DUSE_SHARED + NETWORK_OPT = -DUSE_SHARED -I../windows-build/winpcap/Wpdpack/include NETWORK_FEATURES = - dynamic networking support using windows-build provided libpcap components + NETWORK_LAN_FEATURES += PCAP else - ifeq (pcap,$(shell if exist $(dir $(GCC_Path))..\include\pcap.h echo pcap)) - PCAP_CCDEFS = -DUSE_SHARED -I$(GCC_Path)..\include\ddk + ifneq (,$(call find_include,pcap)) NETWORK_LDFLAGS = NETWORK_OPT = -DUSE_SHARED NETWORK_FEATURES = - dynamic networking support using libpcap components found in the MinGW directories + NETWORK_LAN_FEATURES += PCAP endif endif - OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) - OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) + ifneq (,$(VIDEO_USEFUL)) + SDL_INCLUDE = $(word 1,$(shell dir /b /s ..\windows-build\libSDL\SDL.h)) + ifeq (SDL.h,$(findstring SDL.h,$(SDL_INCLUDE))) + VIDEO_CCDEFS += -DHAVE_LIBSDL -DUSE_SIM_VIDEO -I$(abspath $(dir $(SDL_INCLUDE))) + ifneq ($(DEBUG),) + VIDEO_LDFLAGS += $(abspath $(dir $(SDL_INCLUDE))\..\..\..\lib\lib-VC2008\Debug)/SDL2.lib + else + VIDEO_LDFLAGS += $(abspath $(dir $(SDL_INCLUDE))\..\..\..\lib\lib-VC2008\Release)/SDL2.lib + endif + VIDEO_FEATURES = - video capabilities provided by libSDL2 (Simple Directmedia Layer) + DISPLAYL = ${DISPLAYD}/display.c $(DISPLAYD)/sim_ws.c + DISPLAYVT = ${DISPLAYD}/vt11.c + DISPLAY340 = ${DISPLAYD}/type340.c + DISPLAYNG = ${DISPLAYD}/ng.c + DISPLAY_OPT += -DUSE_DISPLAY $(VIDEO_CCDEFS) $(VIDEO_LDFLAGS) + else + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info ** This build could produce simulators with video capabilities. **) + $(info ** However, the required files to achieve this can't be found on **) + $(info ** this system. Download the file: **) + $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) + $(info ** Extract the windows-build-windows-build folder it contains to **) + $(info ** $(abspath ..\) **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info .) + endif + endif + OS_CCDEFS += -fms-extensions $(PTHREADS_CCDEFS) + OS_LDFLAGS += -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe - ifneq (binexists,$(shell if exist BIN echo binexists)) - MKDIRBIN = if not exist BIN mkdir BIN + ifneq (clean,${MAKECMDGOALS}) + ifneq (buildtoolsexists,$(shell if exist BIN\buildtools (echo buildtoolsexists) else (mkdir BIN\buildtools))) + MKDIRBIN= + endif endif ifneq ($(USE_NETWORK),) - NETWORK_OPT = -DUSE_SHARED + NETWORK_OPT += -DUSE_SHARED endif + ifeq (git-repo,$(shell if exist .git echo git-repo)) + GIT_PATH := $(shell where git) + ifeq (,$(GIT_PATH)) + $(error building using a git repository, but git is not available) + endif + ifeq (commit-id-exists,$(shell if exist .git-commit-id echo commit-id-exists)) + CURRENT_GIT_COMMIT_ID=$(shell for /F "tokens=2" %%i in ("$(shell findstr /C:"SIM_GIT_COMMIT_ID" .git-commit-id)") do echo %%i) + ifneq (, $(shell git update-index --refresh --)) + ACTUAL_GIT_COMMIT_EXTRAS=+uncommitted-changes + endif + ACTUAL_GIT_COMMIT_ID=$(strip $(shell git log -1 --pretty=%H))$(ACTUAL_GIT_COMMIT_EXTRAS) + ifneq ($(CURRENT_GIT_COMMIT_ID),$(ACTUAL_GIT_COMMIT_ID)) + NEED_COMMIT_ID = need-commit-id + # make sure that the invalidly formatted .git-commit-id file wasn't generated + # by legacy git hooks which need to be removed. + $(shell if exist .git\hooks\post-checkout del .git\hooks\post-checkout) + $(shell if exist .git\hooks\post-commit del .git\hooks\post-commit) + $(shell if exist .git\hooks\post-merge del .git\hooks\post-merge) + endif + else + NEED_COMMIT_ID = need-commit-id + endif + ifeq (need-commit-id,$(NEED_COMMIT_ID)) + ifneq (, $(shell git update-index --refresh --)) + ACTUAL_GIT_COMMIT_EXTRAS=+uncommitted-changes + endif + ACTUAL_GIT_COMMIT_ID=$(strip $(shell git log -1 --pretty=%H))$(ACTUAL_GIT_COMMIT_EXTRAS) + isodate=$(shell git log -1 --pretty=%ai) + commit_time=$(word 1,$(isodate))T$(word 2,$(isodate))$(word 3,$(isodate)) + $(shell echo SIM_GIT_COMMIT_ID $(ACTUAL_GIT_COMMIT_ID)>.git-commit-id) + $(shell echo SIM_GIT_COMMIT_TIME $(commit_time)>>.git-commit-id) + endif + endif + ifneq (,$(shell if exist .git-commit-id echo git-commit-id)) + GIT_COMMIT_ID=$(shell for /F "tokens=2" %%i in ("$(shell findstr /C:"SIM_GIT_COMMIT_ID" .git-commit-id)") do echo %%i) + GIT_COMMIT_TIME=$(shell for /F "tokens=2" %%i in ("$(shell findstr /C:"SIM_GIT_COMMIT_TIME" .git-commit-id)") do echo %%i) + else + ifeq (,$(shell findstr /C:"define SIM_GIT_COMMIT_ID" sim_rev.h | findstr Format)) + GIT_COMMIT_ID=$(shell for /F "tokens=3" %%i in ("$(shell findstr /C:"define SIM_GIT_COMMIT_ID" sim_rev.h)") do echo %%i) + GIT_COMMIT_TIME=$(shell for /F "tokens=3" %%i in ("$(shell findstr /C:"define SIM_GIT_COMMIT_TIME" sim_rev.h)") do echo %%i) + endif + endif + ifneq (windows-build,$(shell if exist ..\windows-build\README.md echo windows-build)) + ifneq (,$(GIT_PATH)) + $(info Cloning the windows-build dependencies into $(abspath ..)/windows-build) + $(shell git clone https://github.com/simh/windows-build ../windows-build) + else + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info ** This build is operating without the required windows-build **) + $(info ** components and therefore will produce less than optimal **) + $(info ** simulator operation and features. **) + $(info ** Download the file: **) + $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) + $(info ** Extract the windows-build-windows-build folder it contains to **) + $(info ** $(abspath ..\) **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info .) + endif + else + # Version check on windows-build + WINDOWS_BUILD = $(word 2,$(shell findstr WINDOWS-BUILD ..\windows-build\Windows-Build_Versions.txt)) + ifeq (,$(WINDOWS_BUILD)) + WINDOWS_BUILD = 00000000 + endif + ifneq (,$(or $(shell if 20190124 GTR $(WINDOWS_BUILD) echo old-windows-build),$(and $(shell if 20171112 GTR $(WINDOWS_BUILD) echo old-windows-build),$(findstring pthreadGC2,$(PTHREADS_LDFLAGS))))) + $(info .) + $(info windows-build components at: $(abspath ..\windows-build)) + $(info .) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info ** This currently available windows-build components are out of **) + ifneq (,$(GIT_PATH)) + $(info ** date. You need to update to the latest windows-build **) + $(info ** dependencies by executing these commands: **) + $(info ** **) + $(info ** > cd ..\windows-build **) + $(info ** > git pull **) + $(info ** **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(error .) + else + $(info ** date. For the most functional and stable features you shoud **) + $(info ** Download the file: **) + $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) + $(info ** Extract the windows-build-windows-build folder it contains to **) + $(info ** $(abspath ..\) **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info .) + $(error Update windows-build) + endif + endif + ifeq (pcre,$(shell if exist ..\windows-build\PCRE\include\pcre.h echo pcre)) + OS_CCDEFS += -DHAVE_PCRE_H -DPCRE_STATIC -I$(abspath ../windows-build/PCRE/include) + OS_LDFLAGS += -lpcre -L../windows-build/PCRE/lib/ + $(info using libpcre: $(abspath ../windows-build/PCRE/lib/pcre.a) $(abspath ../windows-build/PCRE/include/pcre.h)) + endif + ifeq (slirp,slirp) + NETWORK_OPT += -Islirp -Islirp_glue -Islirp_glue/qemu -DHAVE_SLIRP_NETWORK -DUSE_SIMH_SLIRP_DEBUG slirp/*.c slirp_glue/*.c -lIphlpapi + NETWORK_LAN_FEATURES += NAT(SLiRP) + endif + endif + ifneq (,$(call find_include,ddk/ntdddisk)) + CFLAGS_I = -DHAVE_NTDDDISK_H + endif +endif # Win32 (via MinGW) +ifneq (,$(GIT_COMMIT_ID)) + CFLAGS_GIT = -DSIM_GIT_COMMIT_ID=$(GIT_COMMIT_ID) +endif +ifneq (,$(GIT_COMMIT_TIME)) + CFLAGS_GIT += -DSIM_GIT_COMMIT_TIME=$(GIT_COMMIT_TIME) +endif +ifneq (,$(UNSUPPORTED_BUILD)) + CFLAGS_GIT += -DSIM_BUILD=Unsupported=$(UNSUPPORTED_BUILD) endif ifneq ($(DEBUG),) CFLAGS_G = -g -ggdb -g3 CFLAGS_O = -O0 BUILD_FEATURES = - debugging support else - CFLAGS_O = -O2 - LDFLAGS_O = - ifeq (Darwin,$(OSTYPE)) + ifneq (,$(findstring clang,$(COMPILER_NAME))$(findstring LLVM,$(COMPILER_NAME))) + CFLAGS_O = -O2 -fno-strict-overflow + GCC_OPTIMIZERS_CMD = ${GCC} --help NO_LTO = 1 + else + NO_LTO = 1 + ifeq (Darwin,$(OSTYPE)) + CFLAGS_O += -O4 -flto -fwhole-program + else + CFLAGS_O := -O2 + endif endif + LDFLAGS_O = GCC_MAJOR_VERSION = $(firstword $(subst ., ,$(GCC_VERSION))) ifneq (3,$(GCC_MAJOR_VERSION)) ifeq (,$(GCC_OPTIMIZERS_CMD)) - GCC_OPTIMIZERS_CMD = $(GCC) --help=optimizers + GCC_OPTIMIZERS_CMD = ${GCC} --help=optimizers + GCC_COMMON_CMD = ${GCC} --help=common endif + endif + ifneq (,$(GCC_OPTIMIZERS_CMD)) GCC_OPTIMIZERS = $(shell $(GCC_OPTIMIZERS_CMD)) endif + ifneq (,$(GCC_COMMON_CMD)) + GCC_OPTIMIZERS += $(shell $(GCC_COMMON_CMD)) + endif ifneq (,$(findstring $(GCC_VERSION),$(LTO_EXCLUDE_VERSIONS))) NO_LTO = 1 endif @@ -540,13 +1245,10 @@ else endif ifneq (3,$(GCC_MAJOR_VERSION)) ifeq (,$(GCC_WARNINGS_CMD)) - GCC_WARNINGS_CMD = $(GCC) --help=warnings - endif - ifneq (,$(findstring -Wunused-result,$(shell $(GCC_WARNINGS_CMD)))) - CFLAGS_O += -Wno-unused-result + GCC_WARNINGS_CMD = ${GCC} --help=warnings endif endif -ifneq (clean,$(MAKECMDGOALS)) +ifneq (clean,${MAKECMDGOALS}) BUILD_FEATURES := $(BUILD_FEATURES). $(COMPILER_NAME) $(info ***) $(info *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with:) @@ -554,16 +1256,34 @@ ifneq (clean,$(MAKECMDGOALS)) ifneq (,$(NETWORK_FEATURES)) $(info *** $(NETWORK_FEATURES).) endif + ifneq (,$(NETWORK_LAN_FEATURES)) + $(info *** - Local LAN packet transports: $(NETWORK_LAN_FEATURES)) + endif + ifneq (,$(VIDEO_FEATURES)) + $(info *** $(VIDEO_FEATURES).) + endif + ifneq (,$(TESTING_FEATURES)) + $(info *** $(TESTING_FEATURES).) + endif + ifneq (,$(GIT_COMMIT_ID)) + $(info ***) + $(info *** git commit id is $(GIT_COMMIT_ID).) + $(info *** git commit time is $(GIT_COMMIT_TIME).) + endif $(info ***) endif +ifneq ($(DONT_USE_ROMS),) + ROMS_OPT = -DDONT_USE_INTERNAL_ROM +else + BUILD_ROMS = ${BIN}buildtools/BuildROMs${EXE} +endif ifneq ($(DONT_USE_READER_THREAD),) NETWORK_OPT += -DDONT_USE_READER_THREAD endif -CC_STD = -std=c99 CC_OUTSPEC = -o $@ -CC = $(GCC) $(CC_STD) -U__STRICT_ANSI__ $(CFLAGS_G) $(CFLAGS_O) -I . $(OS_CCDEFS) $(ROMS_OPT) -LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) +CC := ${GCC} ${CC_STD} -U__STRICT_ANSI__ ${CFLAGS_G} ${CFLAGS_O} ${CFLAGS_GIT} ${CFLAGS_I} -DSIM_COMPILER="${COMPILER_NAME}" -DSIM_BUILD_TOOL=simh-makefile -I . ${OS_CCDEFS} ${ROMS_OPT} +LDFLAGS := ${OS_LDFLAGS} ${NETWORK_LDFLAGS} ${LDFLAGS_O} # # Common Libraries diff --git a/scp.c b/scp.c index 0eb3d0f8..6bfbdc01 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2020, Robert M Supnik + Copyright (c) 1993-2022, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,7 +23,17 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 06-Mar-22 RMS Removed UNIT_RAW support 21-Oct-21 RMS Fixed bug in byte deposits if aincr > 1 + 20=Sep-21 RMS Fixed bug in nested DO recognition (per Mark Pizzolato) + 15-Apr-21 RMS Changed RUN to store new PC value both before RESET + (former behavior) and after (per Mark Pizzolato) + 18-Mar-21 JDB Revised "attach_unit" and "detach_unit" for pipe support + Modified tests to allow UNIT_RO without UNIT_ROABLE + 16-Feb-21 JDB Rewrote get_rval, put_rval to support arrays of structures + 01-Feb-21 JDB Added casts for down-conversions + 25-Jan-21 JDB REG "size" field now determines access size + REG "maxval" field now determines maximum allowed value 30-Nov-20 RMS Fixed RUN problem if CPU reset clears PC (Mark Pizzolato) 09-Nov-20 RMS Added hack for sim_card multiple attach (Mark Pizzolato) 23-Oct-20 JDB Added tmxr_post_logs calls to flush and close log files @@ -230,8 +240,9 @@ #include "sim_tmxr.h" #include #include +#include -#if defined(HAVE_DLOPEN) /* Dynamic Readline support */ +#if defined(SIM_HAVE_DLOPEN) /* Dynamic Readline support */ #include #endif @@ -258,8 +269,6 @@ x = sim_interval #define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT]) -#define SZ_R(rp) \ - (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT]) #if defined (USE_INT64) #define SZ_LOAD(sz,v,mb,j) \ if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + ((uint32) j)); \ @@ -374,7 +383,8 @@ t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, uint32 idx); t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx); t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr); -t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr, int32 dfltinc); +t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, + UNIT *uptr, int32 dfltinc); t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, UNIT *uptr, int32 dfltinc); t_stat step_svc (UNIT *ptr); @@ -1020,7 +1030,7 @@ do { sim_switches = 0; /* init switches */ isdo = FALSE; if (cmdp = find_cmd (gbuf)) { /* lookup command */ - isdo = (MATCH_CMD (gbuf, "DO") == 0); + isdo = (strcmp (cmdp->name, "DO") == 0); if (isdo) { /* DO command? */ if (flag >= DO_NEST_LVL) /* nest too deep? */ stat = SCPE_NEST; @@ -1374,8 +1384,9 @@ if (cptr) if (uptr == NULL) return SCPE_NOFNC; if (((uptr->flags & UNIT_SEQ) == 0) || /* must be sequential, */ - ((uptr->flags & UNIT_ROABLE) != 0) || /* not RO settable */ - ((uptr->flags & UNIT_MUSTBUF) != 0)) /* not buffered */ + ((uptr->flags & (UNIT_RO | UNIT_ROABLE)) != 0) || /* not RO settable */ + ((uptr->flags & UNIT_MUSTBUF) != 0) || /* not buffered */ + ((uptr->dynflags & UNIT_PIPE) != 0)) /* not a pipe */ return SCPE_NOFNC; if ((uptr->flags & UNIT_ATT) == 0) /* must be attached */ return SCPE_UNATT; @@ -2127,9 +2138,21 @@ return attach_unit (uptr, cptr); /* no, std routine */ /* Attach unit to file */ +#if !defined (S_ISFIFO) + #if !defined (S_IFMT) && defined (_S_IFMT) + #define S_IFMT _S_IFMT + #endif + #if defined (_S_IFIFO) + #define S_ISFIFO(m) (((m) & S_IFMT) == _S_IFIFO) + #else + #define S_ISFIFO(m) 0 + #endif +#endif + t_stat attach_unit (UNIT *uptr, char *cptr) { DEVICE *dptr; +struct stat info; if (!(uptr->flags & UNIT_ATTABLE)) /* not attachable? */ return SCPE_NOATT; @@ -2141,8 +2164,24 @@ uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */ if (uptr->filename == NULL) return SCPE_MEM; strncpy (uptr->filename, cptr, CBUFSIZE); /* save name */ -if (sim_switches & SWMASK ('R')) { /* read only? */ - if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ + +if ((!stat (cptr, &info)) && S_ISFIFO (info.st_mode)) /* if file exists and is a pipe */ + if (uptr->flags & UNIT_SEQ) { /* then if the unit is sequential */ + if (uptr->flags & (UNIT_RO | UNIT_ROABLE)) /* if the unit is readable */ + uptr->fileref = sim_fopen (cptr, "rb"); /* then open the pipe for reading */ + else /* otherwise */ + uptr->fileref = sim_fopen (cptr, "wb"); /* open the pipe for writing */ + + if (uptr->fileref == NULL) /* if the file failed to open */ + return attach_err (uptr, SCPE_OPENERR); /* then report the error */ + else /* otherwise */ + uptr->dynflags = uptr->dynflags | UNIT_PIPE; /* set the pipe flag */ + } + else /* otherwise the unit is not sequential */ + return SCPE_NOFNC; /* so it cannot be attached to a pipe */ + +else if (sim_switches & SWMASK ('R')) { /* read only? */ + if ((uptr->flags & (UNIT_RO | UNIT_ROABLE)) == 0) /* allowed? */ return attach_err (uptr, SCPE_NORO); /* no, error */ uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */ if (uptr->fileref == NULL) /* open fail? */ @@ -2152,18 +2191,18 @@ if (sim_switches & SWMASK ('R')) { /* read only? */ sim_printf ("%s: unit is read only\n", sim_dname (dptr)); } else if (sim_switches & SWMASK ('N')) { /* new file only? */ - uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ - if (uptr->fileref == NULL) /* open fail? */ - return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - if (!sim_quiet) - sim_printf ("%s: creating new file\n", sim_dname (dptr)); + uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ + if (uptr->fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + if (!sim_quiet) + sim_printf ("%s: creating new file\n", sim_dname (dptr)); } else { /* normal */ uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */ if (uptr->fileref == NULL) { /* open fail? */ if ((errno == EROFS) || (errno == EACCES)) { /* read only? */ - if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ - return attach_err (uptr, SCPE_NORO); /* no error */ + if ((uptr->flags & (UNIT_RO | UNIT_ROABLE)) == 0) /* allowed? */ + return attach_err (uptr, SCPE_NORO); /* no error */ uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ @@ -2316,6 +2355,7 @@ if ((uptr->flags & UNIT_BUF) && (uptr->filebuf)) { /* buffered? */ } uptr->flags = uptr->flags & ~(UNIT_ATT | /* clear ATT */ ((uptr->flags & UNIT_ROABLE) ? UNIT_RO : 0)); /* clear RO if dynamic */ +uptr->dynflags = uptr->dynflags & ~UNIT_PIPE; /* clear the pipe flag */ free (uptr->filename); uptr->filename = NULL; if (fclose (uptr->fileref) == EOF) @@ -2560,7 +2600,7 @@ void *mbuf; int32 j, blkcnt, limit, unitno, time, flg; uint32 us, depth; t_addr k, high, old_capac; -t_value val, mask; +t_value val, max; t_stat r; size_t sz; t_bool v35, v32; @@ -2732,10 +2772,13 @@ for ( ;; ) { /* device loop */ if (depth != rptr->depth) /* [V2.10+] mismatch? */ sim_printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n", sim_dname (dptr), buf, depth, rptr->depth); - mask = width_mask[rptr->width]; /* get mask */ + if (rptr->maxval > 0) /* if a maximum value is defined */ + max = rptr->maxval; /* then use it */ + else /* otherwise */ + max = width_mask[rptr->width]; /* the mask defines the maximum value */ for (us = 0; us < depth; us++) { /* loop thru values */ READ_I (val); /* read value */ - if (val > mask) /* value ok? */ + if (val > max) /* value ok? */ sim_printf ("Invalid register value: %s %s\n", sim_dname (dptr), buf); else if (us < rptr->depth) /* in range? */ put_rval (rptr, us, val); @@ -2777,14 +2820,17 @@ if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */ pcv = sim_vm_parse_addr (sim_dflt_dev, gbuf, &tptr); else pcv = strtotv (gbuf, &tptr, sim_PC->radix);/* parse PC */ if ((tptr == gbuf) || (*tptr != 0) || /* error? */ - (pcv > width_mask[sim_PC->width])) + (pcv > (sim_PC->maxval > 0 + ? sim_PC->maxval + : width_mask[sim_PC->width]))) return SCPE_ARG; + put_rval (sim_PC, 0, pcv); /* store new PC */ } if ((flag == RU_RUN) && /* run? */ ((r = run_boot_prep ()) != SCPE_OK)) /* reset sim */ return r; if (new_pcv) /* new PC value? */ - put_rval (sim_PC, 0, pcv); + put_rval (sim_PC, 0, pcv); /* store again */ } else if (flag == RU_STEP) { /* step */ @@ -2830,7 +2876,8 @@ else if (flag != RU_CONT) /* must be cont */ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* reposition all */ for (j = 0; j < dptr->numunits; j++) { /* seq devices */ uptr = dptr->units + j; - if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ)) + if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ) && + (uptr->dynflags & UNIT_PIPE) == 0) sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); } } @@ -2875,7 +2922,6 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files if ((uptr->flags & UNIT_ATT) && /* attached, */ !(uptr->flags & UNIT_BUF) && /* not buffered, */ (uptr->fileref) && /* real file, */ - !(uptr->flags & UNIT_RAW) && /* not raw, */ !(uptr->flags & UNIT_RO)) /* not read only? */ fflush (uptr->fileref); } @@ -3155,11 +3201,15 @@ t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, t_addr i, mask; t_stat reason, dfltinc; + if (uptr->flags & UNIT_DIS) /* disabled? */ return SCPE_UDIS; mask = (t_addr) width_mask[dptr->awidth]; if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG; +dfltinc = parse_sym ("0", 0, uptr, sim_eval, sim_switches); +if (dfltinc > 0) /* parse_sym doing nums? */ + dfltinc = 1 - dptr->aincr; /* no, use std dflt incr */ for (i = low; i <= high; ) { /* all paths must incr!! */ reason = get_aval (i, dptr, uptr); /* get data */ if (reason != SCPE_OK) /* return if error */ @@ -3229,43 +3279,50 @@ return SCPE_OK; idx = index Outputs: return = register value + + Implementation notes: + + 1. The stride is the size of the element spacing for arrays, which is + equivalent to the addressing increment for array subscripting. For + scalar registers, the stride will be zero (as will the idx value), so the + access pointer is same as the specified location pointer. + + 2. The size of the t_value type is determined by the USE_INT64 symbol and + will be either a 32-bit or a 64-bit type. It represents the largest + value that can be returned and so is the default if one of the smaller + sizes is not indicated. If USE_INT64 is not defined, t_value will be + identical to uint32. In this case, compilers are generally smart enough + to eliminate the 32-bit size test and combine the two assignments into a + single default assignment. */ t_value get_rval (REG *rptr, uint32 idx) { -size_t sz; t_value val; -UNIT *uptr; +void *ptr; -sz = SZ_R (rptr); -if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { - idx = idx + rptr->qptr; - if (idx >= rptr->depth) idx = idx - rptr->depth; +if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { /* if the register is a circular queue */ + idx = idx + rptr->qptr; /* then adjust the index relative to the queue */ + if (idx >= rptr->depth) /* if the index is beyond the end of the array */ + idx = idx - rptr->depth; /* then wrap it around */ } -if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { - uptr = ((UNIT *) rptr->loc) + idx; -#if defined (USE_INT64) - if (sz <= sizeof (uint32)) - val = *((uint32 *) uptr); - else val = *((t_uint64 *) uptr); -#else - val = *((uint32 *) uptr); -#endif - } -else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && - (sz == sizeof (uint8))) - val = *(((uint8 *) rptr->loc) + idx); -else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && - (sz == sizeof (uint16))) - val = *(((uint16 *) rptr->loc) + idx); -#if defined (USE_INT64) -else if (sz <= sizeof (uint32)) - val = *(((uint32 *) rptr->loc) + idx); -else val = *(((t_uint64 *) rptr->loc) + idx); -#else -else val = *(((uint32 *) rptr->loc) + idx); -#endif -val = (val >> rptr->offset) & width_mask[rptr->width]; + +ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting byte of the item */ + +if (rptr->size == sizeof (uint8)) /* get the value */ + val = *((uint8 *) ptr); /* using a size */ + /* appropriate to */ +else if (rptr->size == sizeof (uint16)) /* the size of */ + val = *((uint16 *) ptr); /* the underlying type */ + +else if (rptr->size == sizeof (uint32)) + val = *((uint32 *) ptr); + +else /* if the element size is non-standard */ + val = *((t_value *) ptr); /* then access using the largest size permitted */ + +val = (val >> rptr->offset) & width_mask[rptr->width]; /* shift and mask to obtain the final value */ + return val; } @@ -3283,7 +3340,7 @@ return val; t_stat dep_reg (int32 flag, char *cptr, REG *rptr, uint32 idx) { t_stat r; -t_value val, mask; +t_value val, max; int32 rdx; char *tptr, gbuf[CBUFSIZE]; @@ -3300,17 +3357,20 @@ if (flag & EX_I) { if (*cptr == 0) /* success */ return SCPE_OK; } -mask = width_mask[rptr->width]; +if (rptr->maxval > 0) /* if a maximum value is defined */ + max = rptr->maxval; /* then use it */ +else /* otherwise */ + max = width_mask[rptr->width]; /* the mask defines the maximum value */ GET_RADIX (rdx, rptr->radix); if ((rptr->flags & REG_VMAD) && sim_vm_parse_addr) { /* address form? */ val = sim_vm_parse_addr (sim_dflt_dev, cptr, &tptr); - if ((tptr == cptr) || (*tptr != 0) || (val > mask)) + if ((tptr == cptr) || (*tptr != 0) || (val > max)) return SCPE_ARG; } else if (!(rptr->flags & REG_VMFLAGS) || /* dont use sym? */ (parse_sym (cptr, (rptr->flags & REG_UFMASK) | rdx, NULL, &val, sim_switches | SIM_SW_REG) > SCPE_OK)) { - val = get_uint (cptr, rdx, mask, &r); + val = get_uint (cptr, rdx, max, &r); if (r != SCPE_OK) return SCPE_ARG; } @@ -3326,59 +3386,54 @@ return SCPE_OK; rptr = pointer to register descriptor idx = index val = new value - mask = mask Outputs: none + + + Implementation notes: + + 1. mask and val are of type t_value, so an explicit cast is not needed for + that type of assignment. + + 2. See the notes for the get_rval routine for additional information + regarding the stride calculation and the t_value default assignment, */ void put_rval (REG *rptr, uint32 idx, t_value val) { -size_t sz; t_value mask; -UNIT *uptr; +void *ptr; -#define PUT_RVAL(sz,rp,id,v,m) \ - *(((sz *) rp->loc) + id) = \ - (*(((sz *) rp->loc) + id) & \ - ~((m) << (rp)->offset)) | ((v) << (rp)->offset) +if (rptr == sim_PC) /* if the PC is changing */ + sim_brk_npc (0); /* then notify the breakpoint package */ -if (rptr == sim_PC) - sim_brk_npc (0); -sz = SZ_R (rptr); -mask = width_mask[rptr->width]; -if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { - idx = idx + rptr->qptr; - if (idx >= rptr->depth) - idx = idx - rptr->depth; +mask = ~(width_mask [rptr->width] << rptr->offset); /* set up a mask to produce a hole in the element */ +val = val << rptr->offset; /* and position the new value to fit the hole */ + +if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { /* if the register is a circular queue */ + idx = idx + rptr->qptr; /* then adjust the index relative to the queue */ + if (idx >= rptr->depth) /* if the index is beyond the end of the array */ + idx = idx - rptr->depth; /* then wrap it around */ } -if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { - uptr = ((UNIT *) rptr->loc) + idx; -#if defined (USE_INT64) - if (sz <= sizeof (uint32)) - *((uint32 *) uptr) = (*((uint32 *) uptr) & - ~(((uint32) mask) << rptr->offset)) | - (((uint32) val) << rptr->offset); - else *((t_uint64 *) uptr) = (*((t_uint64 *) uptr) - & ~(mask << rptr->offset)) | (val << rptr->offset); -#else - *((uint32 *) uptr) = (*((uint32 *) uptr) & - ~(((uint32) mask) << rptr->offset)) | - (((uint32) val) << rptr->offset); -#endif - } -else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && - (sz == sizeof (uint8))) - PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask); -else if (((rptr->depth > 1) || (rptr->flags & REG_FIT)) && - (sz == sizeof (uint16))) - PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask); -#if defined (USE_INT64) -else if (sz <= sizeof (uint32)) - PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); -else PUT_RVAL (t_uint64, rptr, idx, val, mask); -#else -else PUT_RVAL (uint32, rptr, idx, val, mask); -#endif + +ptr = ((char *) rptr->loc) + (idx * rptr->stride); /* point at the starting byte of the item */ + +if (rptr->size == sizeof (uint8)) /* store the value */ + *((uint8 *) ptr) = /* using a size */ + (uint8) (*((uint8 *) ptr) & mask | val); /* appropriate to */ + /* the size of */ +else if (rptr->size == sizeof (uint16)) /* the underlying type */ + *((uint16 *) ptr) = + (uint16) (*((uint16 *) ptr) & mask | val); + +else if (rptr->size == sizeof (uint32)) + *((uint32 *) ptr) = + (uint32) (*((uint32 *) ptr) & mask | val); + +else /* if the element size is non-standard */ + *((t_value *) ptr) = /* then access using the largest size permitted */ + *((t_value *) ptr) & mask | val; + return; } @@ -3411,7 +3466,7 @@ if (!(flag & EX_E)) GET_RADIX (rdx, dptr->dradix); if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) { fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO); - return dfltinc; + reason = dfltinc; } if (flag & EX_I) fprintf (ofile, "\t"); @@ -3452,8 +3507,8 @@ for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) { else { if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; - if (((uptr->flags & UNIT_RAW) != 0) || - (uptr->fileref == NULL)) + if ((uptr->fileref == NULL) || + ((uptr->dynflags & UNIT_PIPE) != 0)) return SCPE_NOFNC; if (((uptr->flags & UNIT_FIX) != 0) && (j >= uptr->capac)) { @@ -3545,7 +3600,7 @@ for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) { else { if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; - if (uptr->flags & UNIT_RAW) + if (uptr->dynflags & UNIT_PIPE) return SCPE_NOFNC; if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) return SCPE_NXM; @@ -3641,7 +3696,7 @@ return read_line_p (NULL, cptr, size, stream); char *read_line_p (char *prompt, char *cptr, int32 size, FILE *stream) { char *tptr; -#if defined(HAVE_DLOPEN) +#if defined(SIM_HAVE_DLOPEN) static int initialized = 0; static char *(*p_readline)(const char *) = NULL; static void (*p_add_history)(const char *) = NULL; @@ -3705,7 +3760,7 @@ while (isspace (*cptr)) /* trim leading spc */ if (*cptr == ';') /* ignore comment */ *cptr = 0; -#if defined (HAVE_DLOPEN) +#if defined (SIM_HAVE_DLOPEN) if (prompt && p_add_history && *cptr) /* Save non blank lines in history */ p_add_history (cptr); #endif @@ -3730,7 +3785,7 @@ char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc) { while ((isspace (*iptr) == 0) && (*iptr != 0) && (*iptr != mchar)) { if (islower (*iptr) && uc) - *optr = toupper (*iptr); + *optr = (char) toupper (*iptr); else *optr = *iptr; iptr++; optr++; } @@ -4528,7 +4583,7 @@ do { d = d - 1; digit = (int32) (val % radix); val = val / radix; - dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10); + dbuf[d] = (char) ((digit <= 9)? '0' + digit: 'A' + (digit - 10)); } while ((d > 0) && (val != 0)); if (format != PV_LEFT) { diff --git a/sim_defs.h b/sim_defs.h index 440520e6..2d5d278a 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -1,6 +1,6 @@ /* sim_defs.h: simulator definitions - Copyright (c) 1993-2020, Robert M Supnik + Copyright (c) 1993-2022, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,13 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 10-Mar-22 JDB Modified REG macros to fix "stringizing" problem + 12-Nov-21 JDB Added UNIT_EXTEND dynamic flag + 17-Mar-21 JDB Added UNIT_PIPE dynamic flag + 16-Feb-21 JDB Added "stride" to REG to support arrays of structures + Modified REG macros to initialize strides + 21-Jan-21 JDB Added "size" and "maxval" fields to the REG structure + Modified REG macros to initialize access sizes 09-Nov-20 RMS More V4.X compatibility hooks (Mark Pizzolato) 26-Oct-19 RMS Removed MTAB_VAL definition 23-Jun-17 RMS Added #include sim_rev.h (Mark Pizzolato) @@ -137,7 +144,7 @@ typedef signed short int16; typedef signed int int32; typedef unsigned char uint8; typedef unsigned short uint16; -typedef unsigned int uint32; +typedef unsigned int uint32; typedef int t_stat; /* status */ typedef int t_bool; /* boolean */ @@ -417,11 +424,13 @@ struct sim_unit { #define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1)) #define UNIT_RFLAGS (UNIT_UFMASK|UNIT_DIS) /* restored flags */ -/* Unit dynamic flags (dynflags) (from 4.0) +/* Unit dynamic flags (dynflags) (from 4.0) These flags are only set dynamically */ #define UNIT_ATTMULT 000001 /* allow multiple ATT cmd */ -#define UNIT_V_DF_TAPE 3 /* tape density reservation */ +#define UNIT_PIPE 000002 /* file is a pipe */ +#define UNIT_EXTEND 000004 /* extended SIMH tape format is enabled */ +#define UNIT_V_DF_TAPE 3 /* tape density reservation (bits 3-5) */ #define UNIT_W_DF_TAPE 3 /* Register data structure */ @@ -433,7 +442,10 @@ struct sim_reg { uint32 width; /* width */ uint32 offset; /* starting bit */ uint32 depth; /* save depth */ + size_t size; /* size of location in bytes */ + size_t stride; /* spacing of array elements in bytes */ uint32 flags; /* flags */ + t_value maxval; /* maximum value */ uint32 qptr; /* circ q ptr */ }; @@ -443,11 +455,10 @@ struct sim_reg { #define REG_RO 00004 /* read only */ #define REG_HIDDEN 00010 /* hidden */ #define REG_NZ 00020 /* must be non-zero */ -#define REG_UNIT 00040 /* in unit struct */ #define REG_CIRC 00100 /* circular array */ #define REG_VMIO 00200 /* use VM data print/parse */ #define REG_VMAD 00400 /* use VM addr print/parse */ -#define REG_FIT 01000 /* fit access to size */ +#define REG_FIT 00000 /* fit access to size (obsolete) */ #define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ #define REG_V_UF 16 /* device specific */ @@ -520,7 +531,7 @@ struct sim_schtab { struct sim_brktab { t_addr addr; /* address */ int32 typ; /* mask of types */ - int32 cnt; /* proceed count */ + int32 cnt; /* proceed count */ char *act; /* action string */ }; @@ -540,31 +551,117 @@ struct sim_debtab { #define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),0,(cap),0,0 -#if defined (__STDC__) || defined (_WIN32) -#define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1 -#define DRDATA(nm,loc,wd) #nm, &(loc), 10, (wd), 0, 1 -#define HRDATA(nm,loc,wd) #nm, &(loc), 16, (wd), 0, 1 -#define FLDATA(nm,loc,pos) #nm, &(loc), 2, 1, (pos), 1 -#define GRDATA(nm,loc,rdx,wd,pos) #nm, &(loc), (rdx), (wd), (pos), 1 -#define BRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep) -#define VBRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep) -#define SAVEDATA(nm,loc) \ - #nm, &(loc), 8, 8, 0, sizeof(loc), REG_HRO +/* Register initialization macros. + + The following macros should be used to initialize the elements of a + simulator's register array. The macros provide simplified initialization, + ensure that unspecified fields are set appropriately, and insulate the + simulator writer from changes in the underlying REG structure. + + The macros take varying numbers of parameters with the following meanings: + + Param Meaning + ----- ------------------------------------------ + nm Register symbolic name + loc Location of the associated variable + aloc Location of the associated array + floc Location of the associated structure field + rdx Display and entry radix + wd Field width in bits + off Field offset in bits from LSB + dep Number of array elements + siz Element size in bytes + str Array element spacing in bytes + + The macros have the following uses: + + Macro Use with + -------- --------------------------------------------------------------- + ORDATA Scalar with octal display/entry + DRDATA Scalar with decimal display/entry + HRDATA Scalar with hexadecimal display/entry + FLDATA Scalar with single bit display/entry + GRDATA Scalar with with specification of radix/width/offset parameters + + BRDATA Singly-subscripted array + CRDATA Doubly-subscripted array + + SRDATA Singly-subscripted array of general structure fields + URDATA Singly-subscripted array of UNIT structure fields + + XRDATA Generic type with specification of all parameters + SAVEDATA Generic type used only for persistence across SAVE/RESTORE + + Normally, scalar and array locations specify the variable name; the names are + converted internally to pointers as needed. However, the starting point of + a partial array may be specified by passing a pointer to the desired element. + For example: + + BRDATA (SYM, array, ...) + + ...specifies a register starting with array element zero, while: + + BRDATA (SYM, &array[3], ...) + + ...specifies a register starting with array element three. + + For arrays of general structures, the names of the array and selected field + are given: + + SRDATA (SYM, array, field, ...) + + This specifies a arrayed register whose elements are array[0].field, + array[1].field, etc. + + + Implementation notes: + + 1. The "RegCheck" macro is used to ensure that each of the user macros has + the correct number of parameters. This improves maintenance reliability, + as changes to the REG structure need to be reflected only in the + "RegCheck" macro. + + 2. "Stringization" must occur at the first macro call level to support + register names that are themselves macros. Otherwise, macro expansion + will occur before stringization, resulting in the wrong register name. + + 3. Additional REG initialization values may be supplied after a macro + invocation. If present, these begin with the "flags" field. + + 4. The URDATA macro is obsolescent and present for backward-compatibility. + It is a special case of the generic SRDATA macro, which provides the same + functionality. Note also that URDATA requires a "flags" parameter value, + which is optional for all other macros. + + 5. The SAVEDATA macro is useful to indicate global variables whose values + must persist across a SAVE and RESTORE. Such data is hidden from the + register user interface. +*/ + +#define RegCheck(nm,loc,rdx,wd,off,dep,siz,str) \ + nm, (loc), (rdx), (wd), (off), (dep), (siz), (str) + +#define ORDATA(nm,loc,wd) RegCheck (#nm, &(loc), 8, (wd), 0, 1, sizeof (loc), 0) +#define DRDATA(nm,loc,wd) RegCheck (#nm, &(loc), 10, (wd), 0, 1, sizeof (loc), 0) +#define HRDATA(nm,loc,wd) RegCheck (#nm, &(loc), 16, (wd), 0, 1, sizeof (loc), 0) +#define FLDATA(nm,loc,off) RegCheck (#nm, &(loc), 2, 1, (off), 1, sizeof (loc), 0) +#define GRDATA(nm,loc,rdx,wd,off) RegCheck (#nm, &(loc), (rdx), (wd), (off), 1, sizeof (loc), 0) + +#define BRDATA(nm,aloc,rdx,wd,dep) RegCheck (#nm, (aloc), (rdx), (wd), 0, (dep), sizeof *(aloc), sizeof *(aloc)) +#define CRDATA(nm,aloc,rdx,wd,dep) RegCheck (#nm, (aloc), (rdx), (wd), 0, (dep), sizeof **(aloc), sizeof **(aloc)) + +#define SRDATA(nm,aloc,floc,rdx,wd,off,dep) \ + RegCheck (#nm, &((aloc)->floc), (rdx), (wd), (off), (dep), \ + sizeof ((aloc)->floc), sizeof (*(aloc))) + +#define XRDATA(nm,loc,rdx,wd,off,dep,siz,str) \ + RegCheck (#nm, (loc), (rdx), (wd), (off), (dep), (siz), (str)) + #define URDATA(nm,loc,rdx,wd,off,dep,fl) \ - #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#else -#define ORDATA(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 -#define DRDATA(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 -#define HRDATA(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 -#define FLDATA(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 -#define GRDATA(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 -#define BRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) -#define VBRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) -#define SAVEDATA(nm,loc) \ - "nm", &(loc), 8, 8, 0, sizeof(loc), REG_HRO -#define URDATA(nm,loc,rdx,wd,off,dep,fl) \ - "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#endif + RegCheck (#nm, &(loc), (rdx), (wd), (off), (dep), \ + sizeof (loc), sizeof (UNIT)), (fl) + +#define SAVEDATA(nm,loc) RegCheck (#nm, &(loc), 8, 8, 0, sizeof (loc), 1, 1), REG_HRO /* Typedefs for principal structures */ @@ -587,7 +684,41 @@ typedef struct sim_debtab DEBTAB; #include "sim_fio.h" #include "sim_sock.h" -/* V4 compatibility definitions +/* V4 register definitions. + + + Implementation notes: + + 1. Unfortunately, the requirement that "stringization" must occur at the + first macro call level precludes defining these V4 macros in terms of + their V3 equivalents. Hence, the V3 definitions must be repeated here. +*/ + +#define ORDATAD(nm,loc,wd,desc) RegCheck (#nm, &(loc), 8, (wd), 0, 1, sizeof (loc), 0) +#define DRDATAD(nm,loc,wd,desc) RegCheck (#nm, &(loc), 10, (wd), 0, 1, sizeof (loc), 0) +#define HRDATAD(nm,loc,wd,desc) RegCheck (#nm, &(loc), 16, (wd), 0, 1, sizeof (loc), 0) +#define FLDATAD(nm,loc,off,desc) RegCheck (#nm, &(loc), 2, 1, (off), 1, sizeof (loc), 0) +#define GRDATAD(nm,loc,rdx,wd,off,desc) RegCheck (#nm, &(loc), (rdx), (wd), (off), 1, sizeof (loc), 0) +#define BRDATAD(nm,loc,rdx,wd,dep,desc) RegCheck (#nm, (loc), (rdx), (wd), 0, (dep), \ + sizeof *(loc), sizeof *(loc)) +#define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) RegCheck (#nm, &(loc), (rdx), (wd), (off), (dep), \ + sizeof (loc), sizeof (UNIT)), (fl) + +#define ORDATADF(nm,loc,wd,desc,flds) RegCheck (#nm, &(loc), 8, (wd), 0, 1, sizeof (loc), 0) +#define DRDATADF(nm,loc,wd,desc,flds) RegCheck (#nm, &(loc), 10, (wd), 0, 1, sizeof (loc), 0) +#define HRDATADF(nm,loc,wd,desc,flds) RegCheck (#nm, &(loc), 16, (wd), 0, 1, sizeof (loc), 0) +#define FLDATADF(nm,loc,off,desc,flds) RegCheck (#nm, &(loc), 2, 1, (off), 1, sizeof (loc), 0) +#define GRDATADF(nm,loc,rdx,wd,off,desc,flds) RegCheck (#nm, &(loc), (rdx), (wd), (off), 1, sizeof (loc), 0) +#define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) RegCheck (#nm, (loc), (rdx), (wd), 0, (dep), \ + sizeof *(loc), sizeof *(loc)) +#define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc,flds) RegCheck (#nm, &(loc), (rdx), (wd), (off), (dep), \ + sizeof (loc), sizeof (UNIT)), (fl) + +#ifndef INT64_C +#define INT64_C(x) (x##LL) +#endif + +/* V4 compatibility definitions. The SCP API for version 4.0 introduces a number of "pointer-to-const" parameter qualifiers that were not present in the 3.x versions. To maintain @@ -596,46 +727,6 @@ typedef struct sim_debtab DEBTAB; when compiling for SIMH 3.x. */ -#if defined (__STDC__) || defined (_WIN32) -#define ORDATAD(nm,loc,wd,desc) #nm, &(loc), 8, (wd), 0, 1 -#define DRDATAD(nm,loc,wd,desc) #nm, &(loc), 10, (wd), 0, 1 -#define HRDATAD(nm,loc,wd,desc) #nm, &(loc), 16, (wd), 0, 1 -#define FLDATAD(nm,loc,pos,desc) #nm, &(loc), 2, 1, (pos), 1 -#define GRDATAD(nm,loc,rdx,wd,pos,desc) #nm, &(loc), (rdx), (wd), (pos), 1 -#define BRDATAD(nm,loc,rdx,wd,dep,desc) #nm, (loc), (rdx), (wd), 0, (dep) -#define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \ - #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#define ORDATADF(nm,loc,wd,desc) #nm, &(loc), 8, (wd), 0, 1 -#define DRDATADF(nm,loc,wd,desc) #nm, &(loc), 10, (wd), 0, 1 -#define HRDATADF(nm,loc,wd,desc) #nm, &(loc), 16, (wd), 0, 1 -#define FLDATADF(nm,loc,pos,desc) #nm, &(loc), 2, 1, (pos), 1 -#define GRDATADF(nm,loc,rdx,wd,pos,desc) #nm, &(loc), (rdx), (wd), (pos), 1 -#define BRDATADF(nm,loc,rdx,wd,dep,desc) #nm, (loc), (rdx), (wd), 0, (dep) -#define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc) \ - #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#else -#define ORDATAD(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 -#define DRDATAD(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 -#define HRDATAD(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 -#define FLDATAD(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 -#define GRDATAD(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 -#define BRDATAD(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) -#define URDATAD(nm,loc,rdx,wd,off,dep,fl) \ - "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#define ORDATADF(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 -#define DRDATADF(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 -#define HRDATADF(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 -#define FLDATADF(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 -#define GRDATADF(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 -#define BRDATADF(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) -#define URDATADF(nm,loc,rdx,wd,off,dep,fl) \ - "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#endif - -#ifndef INT64_C -#define INT64_C(x) (x##LL) -#endif - #ifdef PF_USER #undef PF_USER #endif /* PF_USER */ diff --git a/sim_rev.h b/sim_rev.h index 2d065509..9f06f716 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -1,6 +1,6 @@ /* sim_rev.h: simulator revisions and current rev level - Copyright (c) 1993-2020, Robert M Supnik + Copyright (c) 1993-2021, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,19 +28,60 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 11 +#define SIM_MINOR 12 #define SIM_PATCH 2 #define SIM_DELTA 0 -/* V3.11 revision history +/* V3.12 revision history - V3.11 incorporates SCP additions and extensions by Dave Bryan to support his - HP simulators. + V3.12 incorporates a major rework of the register sizing macros and access + logic by Dave Bryan. patch date module(s) and fix(es) - 2 tbd scp.h + 2 26-Mar-2022 sim_defs.h, scp.c + - deprecated UNIT_RAW, UNIT_TEXT + - dropped non-C_STD string support + + sim_tape.h, sim_tape.c + - added extended tape format (Dave Bryan) + + all magtape simulators + - added extra case points for new MTSE definitions + + pdp11_kg.c + - fixed bug in repeated operations (Paul Koning) + + pdp11_rq.c + - added additional disk types + + pdp8_fpp.c + - fix fencepost error in FP multiply extended precision (Rick Murphy) + + 1 01-Nov-2021 scp.c + - fixed bugs in ID and search on PDP11, VAX, etc. + + sim_tape.c, sim_tape.h (Dave Bryan) + - added sim_tape_erase routine + - improved tape_erase_fwd corrupt image error checking + + pdp11_cpumod.c, pdp11_cpumod.h + - added MMU as settable option to 11/23, 11/40, 11/45 + + pdp8_cpu.c + - fixed bug in reporting device conflicts (Hans-Bernd Eggenstein) + + pdp8_fpp.c + - added DEVNO reporting + + pdp8_ttx.c + - added DEVNO reporting from V4 + + 0 15-Jun-2021 scp.h - changed sim_vm_init to build time option (Dave Bryan) + - changed register structure to separate access size from display size (Dave Bryan) + - added maximum value to register structure (Dave Bryan) + - added UNIT_PIPE dynamic flag (Dave Bryan) scp.c - changed sim_vm_init to build time option (Dave Bryan) @@ -48,16 +89,31 @@ patch date module(s) and fix(es) - flush terminal line logs at return from simulation (Dave Bryan) - close terminal line logs at exit from simulator (Dave Bryan) - fixed RUN problem if CPU reset clears PC (Mark Pizzolato) + - separated register access size from display size (Dave Bryan) + - added maximum value for register input (Dave Bryan) + - added support for pipes as sequential IO sources (Dave Bryan) sim_tmxr.h, sim_tmxr.c - added capability to flush/close log files (Dave Bryan) + i1401_defs.h, i1401_cpu.c + - added maximum value for address registers + + i1620_defs.h, i1620_cpu.c + - added maximum value for address registers + + i7094_mt.c + - replaced dynamic buffer allocation with static (Mark Pizzolato) + nova_cpu.c - fixed bug in history handling of C bit (Samuel Deutsch) pdp10_tu.c - fixed bad macro (Mark Pizzolato) + pdp11_cpumod.h + - added MMU as settable option to 11/23, 11/40, 11/45 + pdp11_cpumod.c - fixed KDJ11E programmable rate select (Paul Koning) @@ -67,6 +123,19 @@ patch date module(s) and fix(es) pdp18b_dr15.c - zero out shared section on initial allocate (Dave Bryan) + pdp18b_dt.c, pdp18b_rf.c + - fixed bug if read overwrites WC memory location + + pdp8_clk.c + - added diagnostic mode for timing dependency in TSS/8 + + pdp8_df.c, pdp8_dt.c, pdpd8_rf.c + - fixed bug if read overwrites WC memory location + + pdp8_sys.c + - fixed treatment of RUBOUT in binary loader (Mark Pizzolato) + - fixed decoding of RF/DF and LP intructions + s3_sys.c - fixed bldaddr length (Mark Pizzolatto) @@ -76,20 +145,30 @@ patch date module(s) and fix(es) sds_cr.c, sds_cp.c - New devices (Ken Rector) + sds_cpu.c, sds_mt.c, sds_rad.c + - Added C register support (Ken Rector) + sds_io.c - TOP disconnects the channel rather than setting CHF_EOR - Fixed overrun/underrun handling in single-word IO sds_stddev.c - TTO recognizes no leader flag (Ken Rector) + - Added C register support to PTR boot (Ken Rector) sds_sys.c - Fixed handling of SDS character value 060 (Ken Rector) - - Addec card reader and punch (Ken Rector) + - Added card reader and punch (Ken Rector) + - Added C register support to loader (Ken Rector) vax_cpu.c - added idle test for VMS 5.0/5.1 (Mark Pizzolato) +/* V3.11 revision history + + V3.11 incorporates SCP additions and extensions by Dave Bryan to support his + HP simulators. + 1 31-Mar-2020 scp.c and sim_tmxr_c - new extensions to support HP simulators - added SET APPEND command