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-2022 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 #ifdef TESTING
  39 # undef FREE
  40 # define FREE(p) free(p)
  41 #endif /* ifdef TESTING */
  42 
  43 #ifdef WITH_ABSI_DEV
  44 # define DBG_CTR 1
  45 
  46 static struct absi_state
  47   {
  48     char device_name [MAX_DEV_NAME_LEN];
  49     int link;
  50   } absi_state [N_ABSI_UNITS_MAX];
  51 
  52 # define N_ABSI_UNITS 1 // default
  53 
  54 # define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
  55                      UNIT_IDLE )
  56 UNIT absi_unit[N_ABSI_UNITS_MAX] =
  57   {
  58     {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
  59   };
  60 
  61 # define ABSI_UNIT_IDX(uptr) ((uptr) - absi_unit)
  62 
  63 static DEBTAB absi_dt[] =
  64   {
  65     { "NOTIFY", DBG_NOTIFY, NULL },
  66     { "INFO",   DBG_INFO,   NULL },
  67     { "ERR",    DBG_ERR,    NULL },
  68     { "WARN",   DBG_WARN,   NULL },
  69     { "DEBUG",  DBG_DEBUG,  NULL },
  70     { "ALL",    DBG_ALL,    NULL }, // don't move as it messes up DBG message
  71     { NULL,     0,          NULL }
  72   };
  73 
  74 static t_stat absi_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
  75                                 UNUSED int val, UNUSED const void * desc)
  76   {
  77     sim_printf ("Number of ABSI units in system is %d\n", absi_dev.numunits);
  78     return SCPE_OK;
  79   }
  80 
  81 static t_stat absi_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
  82                                const char * cptr, UNUSED void * desc)
  83   {
  84     if (! cptr)
  85       return SCPE_ARG;
  86     int n = atoi (cptr);
  87     if (n < 1 || n > N_ABSI_UNITS_MAX)
  88       return SCPE_ARG;
  89     absi_dev.numunits = (uint32) n;
  90     return SCPE_OK;
  91   }
  92 
  93 static t_stat absi_show_device_name (UNUSED FILE * st, UNIT * uptr,
     /* [previous][next][first][last][top][bottom][index][help] */
  94                                     UNUSED int val, UNUSED const void * desc)
  95   {
  96     int n = (int) ABSI_UNIT_IDX (uptr);
  97     if (n < 0 || n >= N_ABSI_UNITS_MAX)
  98       return SCPE_ARG;
  99     if (absi_state[n].device_name[1] != 0)
 100       sim_printf("name     : %s", absi_state[n].device_name);
 101       else
 102         sim_printf("name     : ABSI%d", n);
 103     return SCPE_OK;
 104   }
 105 
 106 static t_stat absi_set_device_name (UNIT * uptr, UNUSED int32 value,
     /* [previous][next][first][last][top][bottom][index][help] */
 107                                    const char * cptr, UNUSED void * desc)
 108   {
 109     int n = (int) ABSI_UNIT_IDX (uptr);
 110     if (n < 0 || n >= N_ABSI_UNITS_MAX)
 111       return SCPE_ARG;
 112     if (cptr)
 113       {
 114         strncpy (absi_state[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
 115         absi_state[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
 116       }
 117     else
 118       absi_state[n].device_name[0] = 0;
 119     return SCPE_OK;
 120   }
 121 
 122 # define UNIT_WATCH UNIT_V_UF
 123 
 124 static MTAB absi_mod[] =
 125   {
 126 # ifndef SPEED
 127     { UNIT_WATCH, 1, "WATCH",   "WATCH",   0, 0, NULL, NULL },
 128     { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
 129 # endif
 130     {
 131       MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR,  /* Mask               */
 132       0,                                           /* Match              */
 133       "NUNITS",                                    /* Print string       */
 134       "NUNITS",                                    /* Match string       */
 135       absi_set_nunits,                             /* Validation routine */
 136       absi_show_nunits,                            /* Display routine    */
 137       "Number of ABSI units in the system",        /* Value descriptor   */
 138       NULL                                         /* Help               */
 139     },
 140     {
 141       MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,   /* Mask               */
 142       0,                                           /* Match              */
 143       "NAME",                                      /* Print string       */
 144       "NAME",                                      /* Match string       */
 145       absi_set_device_name,                        /* Validation routine */
 146       absi_show_device_name,                       /* Display routine    */
 147       "Set the device name",                       /* Value descriptor   */
 148       NULL                                         /* Help               */
 149     },
 150     MTAB_eol
 151   };
 152 
 153 static t_stat absi_reset (UNUSED DEVICE * dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 154   {
 155     //absiResetRX (0);
 156     //absiResetTX (0);
 157     return SCPE_OK;
 158   }
 159 
 160 static t_stat absiAttach (UNIT * uptr, const char * cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 161   {
 162     if (! cptr)
 163       return SCPE_ARG;
 164     int unitno = (int) (uptr - absi_unit);
 165 
 166     //    ATTACH HIn llll:w.x.y.z:rrrr - connect via UDP to a remote
 167 
 168     t_stat ret;
 169     char * pfn;
 170     //uint16 imp = 0; // we only support a single attachment to a single IMP
 171 
 172     // If we're already attached, then detach ...
 173     if ((uptr->flags & UNIT_ATT) != 0)
 174       detach_unit (uptr);
 175 
 176     // Make a copy of the "file name" argument.  udp_create() actually modifies
 177     // the string buffer we give it, so we make a copy now so we'll have
 178     // something to display in the "SHOW HIn ..." command.
 179     pfn = (char *) calloc ((CBUFSIZE + 1), sizeof (char));
 180     if (pfn == NULL)
 181       return SCPE_MEM;
 182     strncpy (pfn, cptr, CBUFSIZE);
 183 
 184     // Create the UDP connection.
 185     ret = udp_create (cptr, & absi_state[unitno].link);
 186     if (ret != SCPE_OK)
 187       {
 188         FREE (pfn);
 189         return ret;
 190       }
 191 
 192     uptr->flags |= UNIT_ATT;
 193     uptr->filename = pfn;
 194     return SCPE_OK;
 195   }
 196 
 197 // Detach (connect) ...
 198 static t_stat absiDetach (UNIT * uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 199   {
 200     int unitno = (int) (uptr - absi_unit);
 201     t_stat ret;
 202     if ((uptr->flags & UNIT_ATT) == 0)
 203       return SCPE_OK;
 204     if (absi_state[unitno].link == NOLINK)
 205       return SCPE_OK;
 206 
 207     ret = udp_release (absi_state[unitno].link);
 208     if (ret != SCPE_OK)
 209       return ret;
 210     absi_state[unitno].link = NOLINK;
 211     uptr->flags &= ~ (unsigned int) UNIT_ATT;
 212     FREE (uptr->filename);
 213     uptr->filename = NULL;
 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     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     iom_chan_data_t * p = &iom_chan_data[iomUnitIdx][chan];
 263 // sim_printf ("absi_cmd CHAN_CMD %o DEV_CODE %o DEV_CMD %o COUNT %o\n",
 264 //p->IDCW_CHAN_CMD, p->IDCW_DEV_CODE, p->IDCW_DEV_CMD, p->IDCW_COUNT);
 265     sim_debug (DBG_TRACE, & absi_dev,
 266                "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,
 268                p->IDCW_COUNT);
 269 
 270     // Not IDCW?
 271     if (IS_NOT_IDCW (p))
 272       {
 273         sim_warn ("%s: Unexpected IOTx\n", __func__);
 274         return IOM_CMD_ERROR;
 275       }
 276 
 277     switch (p->IDCW_DEV_CMD)
 278       {
 279         case 000: // CMD 00 Request status
 280           {
 281             p->stati = 04000;
 282 sim_printf ("absi request status\n");
 283           }
 284           break;
 285 
 286         case 001: // CMD 01 Read
 287           {
 288             p->stati = 04000;
 289 sim_printf ("absi read\n");
 290           }
 291           break;
 292 
 293         case 011: // CMD 11 Write
 294           {
 295             p->stati = 04000;
 296 sim_printf ("absi write\n");
 297           }
 298           break;
 299 
 300         case 020: // CMD 20 Host switch down
 301           {
 302             p->stati = 04000;
 303 sim_printf ("absi host switch down\n");
 304           }
 305           break;
 306 
 307         case 040: // CMD 40 Reset status
 308           {
 309             p->stati = 04000;
 310 sim_printf ("absi reset status\n");
 311           }
 312           break;
 313 
 314         case 060: // CMD 60 Host switch up
 315           {
 316             p->stati = 04000;
 317 sim_printf ("absi host switch up\n");
 318           }
 319           break;
 320 
 321         default:
 322           {
 323             if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
 324               sim_warn ("%s: ABSI unrecognized device command  %02o\n", __func__, p->IDCW_DEV_CMD);
 325             p->stati = 04501; // cmd reject, invalid opcode
 326             p->chanStatus = chanStatIncorrectDCW;
 327           }
 328           return IOM_CMD_ERROR;
 329       }
 330 
 331     if (p->IDCW_CHAN_CMD == 0)
 332       return IOM_CMD_DISCONNECT; // don't do DCW list
 333     return IOM_CMD_PROCEED;
 334   }
 335 
 336 //  1 == ignored command
 337 //  0 == ok
 338 // -1 == problem
 339 iom_cmd_rc_t absi_iom_cmd (uint iomUnitIdx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 340   {
 341     iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
 342 
 343     // Is it an IDCW?
 344     if (IS_IDCW (p))
 345       {
 346         return absi_cmd (iomUnitIdx, chan);
 347       }
 348     sim_printf ("%s expected IDCW\n", __func__);
 349     return IOM_CMD_ERROR;
 350   }
 351 
 352 void absi_process_event (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 353   {
 354 # define psz 17000
 355     uint16_t pkt[psz];
 356     for (uint32 unit = 0; unit < absi_dev.numunits; unit ++)
 357       {
 358         if (absi_state[unit].link == NOLINK)
 359           continue;
 360         //int sz = udp_receive ((int) unit, pkt, psz);
 361         int sz = udp_receive (absi_state[unit].link, pkt, psz);
 362         if (sz < 0)
 363           {
 364             fprintf (stderr, "udp_receive failed\n");
 365           }
 366         else if (sz == 0)
 367           {
 368             //fprintf (stderr, "udp_receive 0\n");
 369           }
 370         else
 371           {
 372             for (int i = 0; i < sz; i ++)
 373               {
 374                 fprintf (stderr, "  %06o  %04x  ", pkt[i], pkt[i]);
 375                 for (int b = 0; b < 16; b ++)
 376                   fprintf (stderr, "%c", pkt[i] & (1 << (16 - b)) ? '1' : '0');
 377                 fprintf (stderr, "\n");
 378               }
 379             // Send a NOP reply
 380             //int16_t reply[2] = 0x0040
 381             int rc = udp_send (absi_state[unit].link, pkt, (uint16_t) sz,
 382                                PFLG_FINAL);
 383             if (rc < 0)
 384               {
 385                 fprintf (stderr, "udp_send failed\n");
 386               }
 387           }
 388       }
 389   }
 390 #endif /* ifdef WITH_ABSI_DEV */

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