root/src/dps8/dps8_absi.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. absi_show_nunits
  2. absi_set_nunits
  3. absi_show_device_name
  4. absi_set_device_name
  5. absi_reset
  6. absiAttach
  7. absiDetach
  8. absi_init
  9. absi_cmd
  10. absi_iom_cmd
  11. absi_process_event

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 336ce0b0-f62d-11ec-873c-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2007-2013 Michael Mondy
   9  * Copyright (c) 2015-2018 Charles Anthony
  10  * Copyright (c) 2021-2024 The DPS8M Development Team
  11  *
  12  * This software is made available under the terms of the ICU License.
  13  * See the LICENSE.md file at the top-level directory of this distribution.
  14  *
  15  * ---------------------------------------------------------------------------
  16  */
  17 
  18 #include <stdio.h>
  19 #include <ctype.h>
  20 #include <unistd.h>
  21 #include <stdint.h>
  22 
  23 #include "dps8.h"
  24 #include "dps8_iom.h"
  25 #include "dps8_absi.h"
  26 #include "dps8_sys.h"
  27 #include "dps8_cable.h"
  28 #include "dps8_cpu.h"
  29 #include "dps8_faults.h"
  30 #include "dps8_scu.h"
  31 #include "dps8_utils.h"
  32 
  33 #include "udplib.h"
  34 
  35 #if defined(FREE)
  36 # undef FREE
  37 #endif /* if defined(FREE) */
  38 #define FREE(p) do  \
  39   {                 \
  40     free((p));      \
  41     (p) = NULL;     \
  42   } while(0)
  43 
  44 #if defined(WITH_ABSI_DEV)
  45 # define DBG_CTR 1
  46 
  47 static struct absi_state
  48   {
  49     char device_name [MAX_DEV_NAME_LEN];
  50     int link;
  51   } absi_state [N_ABSI_UNITS_MAX];
  52 
  53 # define N_ABSI_UNITS 1 // default
  54 
  55 # define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
  56                      UNIT_IDLE )
  57 UNIT absi_unit[N_ABSI_UNITS_MAX] =
  58   {
  59     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
  60   };
  61 
  62 # define ABSI_UNIT_IDX(uptr) ((uptr) - absi_unit)
  63 
  64 static DEBTAB absi_dt[] =
  65   {
  66     { "NOTIFY", DBG_NOTIFY, NULL },
  67     { "INFO",   DBG_INFO,   NULL },
  68     { "ERR",    DBG_ERR,    NULL },
  69     { "WARN",   DBG_WARN,   NULL },
  70     { "DEBUG",  DBG_DEBUG,  NULL },
  71     { "ALL",    DBG_ALL,    NULL }, // Don't move as it messes up DBG message
  72     { NULL,     0,          NULL }
  73   };
  74 
  75 static t_stat absi_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
  76                                 UNUSED int val, UNUSED const void * desc)
  77   {
  78     sim_printf ("Number of ABSI units in system is %d\n", absi_dev.numunits);
  79     return SCPE_OK;
  80   }
  81 
  82 static t_stat absi_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
  83                                const char * cptr, UNUSED void * desc)
  84   {
  85     if (! cptr)
  86       return SCPE_ARG;
  87     int n = atoi (cptr);
  88     if (n < 1 || n > N_ABSI_UNITS_MAX)
  89       return SCPE_ARG;
  90     absi_dev.numunits = (uint32) n;
  91     return SCPE_OK;
  92   }
  93 
  94 static t_stat absi_show_device_name (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
  95                                     UNUSED int val, UNUSED const void * desc)
  96   {
  97     int n = (int) ABSI_UNIT_IDX (uptr);
  98     if (n < 0 || n >= N_ABSI_UNITS_MAX)
  99       return SCPE_ARG;
 100     if (absi_state[n].device_name[1] != 0)
 101       sim_printf("name     : %s", absi_state[n].device_name);
 102       else
 103         sim_printf("name     : ABSI%d", n);
 104     return SCPE_OK;
 105   }
 106 
 107 static t_stat absi_set_device_name (UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 108                                    const char * cptr, UNUSED void * desc)
 109   {
 110     int n = (int) ABSI_UNIT_IDX (uptr);
 111     if (n < 0 || n >= N_ABSI_UNITS_MAX)
 112       return SCPE_ARG;
 113     if (cptr)
 114       {
 115         strncpy (absi_state[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
 116         absi_state[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
 117       }
 118     else
 119       absi_state[n].device_name[0] = 0;
 120     return SCPE_OK;
 121   }
 122 
 123 # define UNIT_WATCH UNIT_V_UF
 124 
 125 static MTAB absi_mod[] =
 126   {
 127 # if !defined(SPEED)
 128     { UNIT_WATCH, 1, "WATCH",   "WATCH",   0, 0, NULL, NULL },
 129     { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
 130 # endif /* if !defined(SPEED) */
 131     {
 132       MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR,  /* Mask               */
 133       0,                                           /* Match              */
 134       "NUNITS",                                    /* Print string       */
 135       "NUNITS",                                    /* Match string       */
 136       absi_set_nunits,                             /* Validation routine */
 137       absi_show_nunits,                            /* Display routine    */
 138       "Number of ABSI units in the system",        /* Value descriptor   */
 139       NULL                                         /* Help               */
 140     },
 141     {
 142       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,   /* Mask               */
 143       0,                                           /* Match              */
 144       "NAME",                                      /* Print string       */
 145       "NAME",                                      /* Match string       */
 146       absi_set_device_name,                        /* Validation routine */
 147       absi_show_device_name,                       /* Display routine    */
 148       "Set the device name",                       /* Value descriptor   */
 149       NULL                                         /* Help               */
 150     },
 151     MTAB_eol
 152   };
 153 
 154 static t_stat absi_reset (UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 155   {
 156     //absiResetRX (0);
 157     //absiResetTX (0);
 158     return SCPE_OK;
 159   }
 160 
 161 static t_stat absiAttach (UNIT * uptr, const char * cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 162   {
 163     if (! cptr)
 164       return SCPE_ARG;
 165     int unitno = (int) (uptr - absi_unit);
 166 
 167     //    ATTACH HIn llll:w.x.y.z:rrrr - connect via UDP to a remote
 168 
 169     t_stat ret;
 170     char * pfn;
 171     //uint16 imp = 0; // we only support a single attachment to a single IMP
 172 
 173     // If we're already attached, then detach ...
 174     if ((uptr->flags & UNIT_ATT) != 0)
 175       detach_unit (uptr);
 176 
 177     // Make a copy of the "file name" argument.  udp_create() actually modifies
 178     // the string buffer we give it, so we make a copy now so we'll have
 179     // something to display in the "SHOW HIn ..." command.
 180     pfn = (char *) calloc ((CBUFSIZE + 1), sizeof (char));
 181     if (pfn == NULL)
 182       return SCPE_MEM;
 183     strncpy (pfn, cptr, CBUFSIZE);
 184 
 185     // Create the UDP connection.
 186     ret = udp_create (cptr, & absi_state[unitno].link);
 187     if (ret != SCPE_OK)
 188       {
 189         FREE (pfn);
 190         return ret;
 191       }
 192 
 193     uptr->flags |= UNIT_ATT;
 194     uptr->filename = pfn;
 195     return SCPE_OK;
 196   }
 197 
 198 // Detach (connect) ...
 199 static t_stat absiDetach (UNIT * uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 200   {
 201     int unitno = (int) (uptr - absi_unit);
 202     t_stat ret;
 203     if ((uptr->flags & UNIT_ATT) == 0)
 204       return SCPE_OK;
 205     if (absi_state[unitno].link == NOLINK)
 206       return SCPE_OK;
 207 
 208     ret = udp_release (absi_state[unitno].link);
 209     if (ret != SCPE_OK)
 210       return ret;
 211     absi_state[unitno].link = NOLINK;
 212     uptr->flags &= ~ (unsigned int) UNIT_ATT;
 213     FREE (uptr->filename);
 214     return SCPE_OK;
 215   }
 216 
 217 DEVICE absi_dev = {
 218     "ABSI",       /* Name                */
 219     absi_unit,    /* Units               */
 220     NULL,         /* Registers           */
 221     absi_mod,     /* Modifiers           */
 222     N_ABSI_UNITS, /* #units              */
 223     10,           /* Address radix       */
 224     24,           /* Address width       */
 225     1,            /* Address increment   */
 226     8,            /* Data radix          */
 227     36,           /* Data width          */
 228     NULL,         /* Examine             */
 229     NULL,         /* Deposit             */
 230     absi_reset,   /* Reset               */
 231     NULL,         /* Boot                */
 232     absiAttach,   /* Attach              */
 233     absiDetach,   /* Detach              */
 234     NULL,         /* Context             */
 235     DEV_DEBUG,    /* Flags               */
 236     0,            /* Debug control flags */
 237     absi_dt,      /* Debug flag names    */
 238     NULL,         /* Memory size change  */
 239     NULL,         /* Logical name        */
 240     NULL,         /* Help                */
 241     NULL,         /* Attach help         */
 242     NULL,         /* Attach context      */
 243     NULL,         /* Description         */
 244     NULL          /* End                 */
 245 };
 246 
 247 /*
 248  * absi_init()
 249  */
 250 
 251 // Once-only initialization
 252 
 253 void absi_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 254   {
 255     (void)memset (absi_state, 0, sizeof (absi_state));
 256     for (int i = 0; i < N_ABSI_UNITS_MAX; i ++)
 257       absi_state[i].link = NOLINK;
 258   }
 259 
 260 static iom_cmd_rc_t absi_cmd (uint iomUnitIdx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 261   {
 262 # if defined(TESTING)
 263     cpu_state_t * cpup = _cpup;
 264 # endif
 265     iom_chan_data_t * p = &iom_chan_data[iomUnitIdx][chan];
 266 // sim_printf ("absi_cmd CHAN_CMD %o DEV_CODE %o DEV_CMD %o COUNT %o\n",
 267 //p->IDCW_CHAN_CMD, p->IDCW_DEV_CODE, p->IDCW_DEV_CMD, p->IDCW_COUNT);
 268     sim_debug (DBG_TRACE, & absi_dev,
 269                "absi_cmd CHAN_CMD %o DEV_CODE %o DEV_CMD %o COUNT %o\n",
 270                p->IDCW_CHAN_CMD, p->IDCW_DEV_CODE, p->IDCW_DEV_CMD,
 271                p->IDCW_COUNT);
 272 
 273     // Not IDCW?
 274     if (IS_NOT_IDCW (p))
 275       {
 276         sim_warn ("%s: Unexpected IOTx\n", __func__);
 277         return IOM_CMD_ERROR;
 278       }
 279 
 280     switch (p->IDCW_DEV_CMD)
 281       {
 282         case 000: // CMD 00 Request status
 283           {
 284             p->stati = 04000;
 285 sim_printf ("absi request status\n");
 286           }
 287           break;
 288 
 289         case 001: // CMD 01 Read
 290           {
 291             p->stati = 04000;
 292 sim_printf ("absi read\n");
 293           }
 294           break;
 295 
 296         case 011: // CMD 11 Write
 297           {
 298             p->stati = 04000;
 299 sim_printf ("absi write\n");
 300           }
 301           break;
 302 
 303         case 020: // CMD 20 Host switch down
 304           {
 305             p->stati = 04000;
 306 sim_printf ("absi host switch down\n");
 307           }
 308           break;
 309 
 310         case 040: // CMD 40 Reset status
 311           {
 312             p->stati = 04000;
 313 sim_printf ("absi reset status\n");
 314           }
 315           break;
 316 
 317         case 060: // CMD 60 Host switch up
 318           {
 319             p->stati = 04000;
 320 sim_printf ("absi host switch up\n");
 321           }
 322           break;
 323 
 324         default:
 325           {
 326             if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
 327               sim_warn ("%s: ABSI unrecognized device command  %02o\n", __func__, p->IDCW_DEV_CMD);
 328             p->stati = 04501; // cmd reject, invalid opcode
 329             p->chanStatus = chanStatIncorrectDCW;
 330           }
 331           return IOM_CMD_ERROR;
 332       }
 333 
 334     if (p->IDCW_CHAN_CMD == 0)
 335       return IOM_CMD_DISCONNECT; // Don't do DCW list
 336     return IOM_CMD_PROCEED;
 337   }
 338 
 339 //  1 == ignored command
 340 //  0 == ok
 341 // -1 == problem
 342 iom_cmd_rc_t absi_iom_cmd (uint iomUnitIdx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 343   {
 344     iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
 345 
 346     // Is it an IDCW?
 347     if (IS_IDCW (p))
 348       {
 349         return absi_cmd (iomUnitIdx, chan);
 350       }
 351     sim_printf ("%s expected IDCW\n", __func__);
 352     return IOM_CMD_ERROR;
 353   }
 354 
 355 void absi_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 356   {
 357 # define psz 17000
 358     uint16_t pkt[psz];
 359     for (uint32 unit = 0; unit < absi_dev.numunits; unit ++)
 360       {
 361         if (absi_state[unit].link == NOLINK)
 362           continue;
 363         //int sz = udp_receive ((int) unit, pkt, psz);
 364         int sz = udp_receive (absi_state[unit].link, pkt, psz);
 365         if (sz < 0)
 366           {
 367             (void)fprintf (stderr, "udp_receive failed\n");
 368           }
 369         else if (sz == 0)
 370           {
 371             //(void)fprintf (stderr, "udp_receive 0\n");
 372           }
 373         else
 374           {
 375             for (int i = 0; i < sz; i ++)
 376               {
 377                 (void)fprintf (stderr, "  %06o  %04x  ", pkt[i], pkt[i]);
 378                 for (int b = 0; b < 16; b ++)
 379                   (void)fprintf (stderr, "%c", pkt[i] & (1 << (16 - b)) ? '1' : '0');
 380                 (void)fprintf (stderr, "\n");
 381               }
 382             // Send a NOP reply
 383             //int16_t reply[2] = 0x0040
 384             int rc = udp_send (absi_state[unit].link, pkt, (uint16_t) sz,
 385                                PFLG_FINAL);
 386             if (rc < 0)
 387               {
 388                 (void)fprintf (stderr, "udp_send failed\n");
 389               }
 390           }
 391       }
 392   }
 393 #endif /* if defined(WITH_ABSI_DEV) */

/* [previous][next][first][last][top][bottom][index][help] */