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

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