root/src/dps8/segldr.c

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

DEFINITIONS

This source file includes following definitions.
  1. initPageTables
  2. addSDW
  3. stack
  4. bload
  5. msave
  6. mrestore
  7. segment_loader
  8. main

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: cda5f9ab-f62f-11ec-a92b-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2021 Charles Anthony
   9  * Copyright (c) 2021-2025 The DPS8M Development Team
  10  *
  11  * This software is made available under the terms of the ICU License.
  12  * See the LICENSE.md file at the top-level directory of this distribution.
  13  *
  14  * ---------------------------------------------------------------------------
  15  */
  16 
  17 #include <unistd.h>
  18 #include <errno.h>
  19 #include <string.h>
  20 #include <sys/types.h>
  21 #include <sys/stat.h>
  22 #include <fcntl.h>
  23 #if !defined(NO_LOCALE)
  24 # if defined(__APPLE__)
  25 #  include <xlocale.h>
  26 # endif
  27 # include <locale.h>
  28 #endif
  29 
  30 #include "dps8.h"
  31 #include "dps8_sys.h"
  32 #include "dps8_cpu.h"
  33 #include "dps8_scu.h"
  34 #include "dps8_iom.h"
  35 #include "dps8_cable.h"
  36 #include "dps8_state.h"
  37 #include "dps8_utils.h"
  38 
  39 #include "segldr.h"
  40 
  41 #if defined(NO_LOCALE)
  42 # define xstrerror_l strerror
  43 #endif
  44 
  45 /*
  46  * Segment loader memory layout
  47  *
  48  * 0000   Interrupt and fault vectors
  49  *
  50  * 2000   Bootstrap code entry
  51  *
  52  * 4000   Page tables
  53  *
  54  * Paged segments
  55  *
  56  *     4000 descriptor segment page table
  57  *     4000 PTW for segments 0-511. 0-777
  58  *     6000 descriptor segment page for segments 0-777
  59  *     7000 segment page tables
  60  *    10000 Segment storage
  61  *
  62  */
  63 
  64 #define ADDR_BOOT   02000
  65 #define ADDR_DSPT   04000
  66 #define ADDR_DSP    06000
  67 #define ADDR_PGS    07000
  68 #define ADDR_SEGS 0100000
  69 
  70 #define MAX_SEG_NO 0377
  71 
  72 /*
  73  *  sl init       initialize segment loader
  74  *  sl bload <segment number> <filename>
  75  *                copy the binary file into the next available storage
  76  *                and create an SDW for the file
  77  *  sl bload boot <filename>
  78  *                copy the binary file into memory starting at address 0
  79  *  al stack <segno> <n_pages>
  80  */
  81 
  82 static word24 nextSegAddr = ADDR_SEGS;
  83 static word24 nextPageAddr = ADDR_PGS;
  84 
  85 static void initPageTables (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  86   {
  87         for (uint addr = ADDR_DSPT; addr < ADDR_SEGS; addr ++)
  88           M[addr] = 0;
  89         // Place the PTW for the first 512 segments in the DSPT
  90         uint x1 = 0;
  91         word36 * ptwp = (word36 *) M + x1 + ADDR_DSPT;
  92         putbits36_18 (ptwp,  0, ADDR_DSP >> 6);  // points to the Descriptor Segment Page
  93         putbits36_1  (ptwp, 26,        0);  // unused
  94         putbits36_1  (ptwp, 29,        0);  // unmodified
  95         putbits36_1  (ptwp, 29,        0);  // unmodified
  96         putbits36_1  (ptwp, 33,        1);  // page is in memory
  97         putbits36_2  (ptwp, 34,        0);  // fault code
  98   }
  99 
 100 static void addSDW (word24 addr, long segnum, long length)
     /* [previous][next][first][last][top][bottom][index][help] */
 101   {
 102     // Round length up to page boundary
 103     // long lengthp = (length + 01777) & 077776000;
 104 
 105     // Number of pages
 106     long npages = (long)(length / 1024);
 107 
 108     // Add SDW, allocate space
 109     word14 bound = (word14)(((length + 15) >> 4) + 1);
 110 
 111     // Add PTW to DSPT
 112     word24 y1 = (word24)((2u * segnum) % 1024u);
 113 
 114     // Allocate target segment page table
 115     word24 pgTblAddr = (word24)(nextPageAddr);
 116     nextPageAddr += 1024;
 117 
 118     // Build Descriptor Segment Page SDW
 119     // word36 * sdwp = (word36 *) M + ADDR_DSP + y1;
 120     word24 sdw0 = ADDR_DSP + y1 + 0;
 121     word24 sdw1 = ADDR_DSP + y1 + 1;
 122     //sim_printf ("segnum %lo length %lu bound %u sdw0 %o sdw1 %o ADDR %06o\r\n",
 123     //            (unsigned long) segnum, length, bound, sdw0, sdw1, pgTblAddr);
 124     putbits36_24 ((word36 *) & M[sdw0],  0, pgTblAddr); // ADDR
 125 // I can't get segldr_boot to cross to ring 4
 126 //  putbits36_3  (& M[sdw0], 24, 4);                // R1
 127 //  putbits36_3  (& M[sdw0], 27, 4);                // R2
 128 //  putbits36_3  (& M[sdw0], 30, 4);                // R3
 129     putbits36_3  ((word36 *) & M[sdw0], 24, 0);     // R1
 130     putbits36_3  ((word36 *) & M[sdw0], 27, 0);     // R2
 131     putbits36_3  ((word36 *) & M[sdw0], 30, 0);     // R3
 132     putbits36_1  ((word36 *) & M[sdw0], 33, 1);     // F
 133     putbits36_2  ((word36 *) & M[sdw0], 34, 0);     // FC
 134     putbits36_1  ((word36 *) & M[sdw1],  0, 0);     // 0
 135     putbits36_14 ((word36 *) & M[sdw1],  1, bound); // BOUND
 136     putbits36_1  ((word36 *) & M[sdw1], 15, 1);     // R
 137     putbits36_1  ((word36 *) & M[sdw1], 16, 1);     // E
 138     putbits36_1  ((word36 *) & M[sdw1], 17, 1);     // W
 139     putbits36_1  ((word36 *) & M[sdw1], 18, 0);     // P
 140     putbits36_1  ((word36 *) & M[sdw1], 19, 0);     // U
 141     putbits36_1  ((word36 *) & M[sdw1], 20, 1);     // G
 142     putbits36_1  ((word36 *) & M[sdw1], 21, 1);     // C
 143     putbits36_14 ((word36 *) & M[sdw1], 21, 0);     // EB
 144 
 145     // Fill out PTWs on Segment page table
 146 
 147     for (word24 pg = 0; pg <= npages; pg ++)
 148       {
 149         // word36 * ptwp = (word36 *) M + pgTblAddr + pg;
 150         word24 ptw = pgTblAddr + pg;
 151         word18 pgAddr = (addr + pg * 1024) >> 6;
 152         putbits36_18 ((word36 *) & M[ptw],  0,    pgAddr); // points to the Segment Page
 153         putbits36_1  ((word36 *) & M[ptw], 26,         0);  // unused
 154         putbits36_1  ((word36 *) & M[ptw], 29,         0);  // unmodified
 155         putbits36_1  ((word36 *) & M[ptw], 29,         0);  // unmodified
 156         putbits36_1  ((word36 *) & M[ptw], 33,         1);  // page is in memory
 157         putbits36_2  ((word36 *) & M[ptw], 34,         0);  // fault code
 158         //sim_printf ("   ptw pg %u at %o addr %o\r\n", pg, pgTblAddr + pg, pgAddr);
 159       }
 160   }
 161 
 162 
 163 
 164 
 165 
 166 
 167 
 168 
 169 
 170 
 171 
 172 
 173 
 174 
 175 
 176 
 177 
 178 
 179 
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 
 191 
 192 
 193 static t_stat stack (char * p2, char * p3)
     /* [previous][next][first][last][top][bottom][index][help] */
 194   {
 195     // Segment number
 196     char * endptr;
 197     long segnum = strtol (p2, & endptr, 8);
 198     if (* endptr)
 199       {
 200         if (running_perf_test == true)
 201           exit(1);
 202         return SCPE_ARG;
 203       }
 204     if (segnum < 0 || segnum > MAX_SEG_NO)
 205       {
 206         sim_printf ("Segment number is limited to 0 to 0377\r\n");
 207         if (running_perf_test == true)
 208           exit(1);
 209         return SCPE_ARG;
 210       }
 211 
 212     long len = strtol (p3, & endptr, 8);
 213     if (* endptr)
 214       {
 215         if (running_perf_test == true)
 216           exit(1);
 217         return SCPE_ARG;
 218       }
 219     if (len < 1 || len > 255)
 220       {
 221         sim_printf ("Segment length is limited to 1 to 0377\r\n");
 222         if (running_perf_test == true)
 223           exit(1);
 224         return SCPE_ARG;
 225       }
 226 
 227     long length = len * 1024;
 228 
 229     // Add SDW
 230     addSDW (nextSegAddr, segnum, length);
 231 
 232     sim_printf ("Placed stack (%lo) at %o length %lo allocated %lo\r\n",
 233                 (unsigned long) segnum, nextSegAddr, (unsigned long) len, length);
 234     // Mark the pages as used
 235     nextSegAddr += length;
 236 
 237     return SCPE_OK;
 238   }
 239 
 240 static t_stat bload (char * p2, char * p3)
     /* [previous][next][first][last][top][bottom][index][help] */
 241   {
 242     // Segment number
 243     long segnum;
 244     if (strcasecmp ("boot", p2) == 0)
 245       {
 246         segnum = -1; // Indicate boot load
 247       }
 248     else
 249       {
 250         char * endptr;
 251         segnum = strtol (p2, & endptr, 8);
 252         if (* endptr)
 253           {
 254             if (running_perf_test == true)
 255               exit(1);
 256             return SCPE_ARG;
 257           }
 258         if (segnum < 0 || segnum > MAX_SEG_NO)
 259           {
 260             sim_printf ("Segment number is limited to 0 to 0377\r\n");
 261             if (running_perf_test == true)
 262               exit(1);
 263             return SCPE_ARG;
 264           }
 265       }
 266 
 267     // Segment image file
 268     int deckfd = open (p3, O_RDONLY);
 269     if (deckfd < 0)
 270       {
 271         if (errno) sim_printf ("Error: %s\r\n", xstrerror_l(errno));
 272         sim_printf ("Unable to open '%s'\r\n", p3);
 273         if (running_perf_test == true)
 274           exit(1);
 275         /*NOTREACHED*/ /* unreachable */
 276         return SCPE_ARG;
 277       }
 278 
 279     // Copy segment into memory
 280     word24 addr;
 281     word24 startAddr;
 282     if (segnum < 0)
 283       addr = 0;
 284     else
 285       addr = nextSegAddr;
 286 
 287     startAddr = addr;
 288 
 289     for (;;)
 290       {
 291         ssize_t sz;
 292         // 72 bits at a time; 2 dps8m words == 9 bytes
 293         uint8_t bytes [9];
 294         (void)memset (bytes, 0, 9);
 295         sz = read (deckfd, bytes, 9);
 296         if (sz == 0)
 297           break;
 298         //if (sz != n) short read?
 299         word36 even = extr36 (bytes, 0);
 300         word36 odd = extr36 (bytes, 1);
 301         //sim_printf ("%08o  %012"PRIo64"   %012"PRIo64"\r\n", addr, even, odd);
 302         M[addr ++] = even;
 303         M[addr ++] = odd;
 304       }
 305     word24 length = addr - startAddr;
 306 
 307     word24 lengthp;
 308     if (segnum >= 0)
 309       {
 310         // Add SDW
 311         addSDW (startAddr, segnum, length);
 312 
 313         // Round length up to page (1024) boundary
 314         lengthp = (length + 01777) & 077776000;
 315 
 316         // Mark the pages as used
 317         nextSegAddr += lengthp;
 318       }
 319     else
 320       {
 321         lengthp = 04000;
 322         addSDW (0, 0, lengthp);
 323       }
 324 
 325     sim_printf ("Loaded %s (%lo) at %o length %o allocated %o\r\n",
 326                 p3, segnum < 0 ? 0 : (unsigned long) segnum, startAddr, length, lengthp);
 327     close (deckfd);
 328     return SCPE_OK;
 329   }
 330 
 331 #define msize (MEMSIZE * sizeof (word36))
 332 
 333 static t_stat msave (char * p2, word24 sz)
     /* [previous][next][first][last][top][bottom][index][help] */
 334   {
 335     uint wrsz = sz * sizeof (word36);
 336     int fd = open (p2, O_WRONLY | O_CREAT, 0664);
 337     if (fd < 0)
 338       {
 339         if (errno) sim_printf ("Error: %s\r\n", xstrerror_l(errno));
 340         sim_printf ("Unable to open '%s'\r\n", p2);
 341         if (running_perf_test == true)
 342           exit(1);
 343         return SCPE_ARG;
 344       }
 345     ssize_t n = write (fd, (void *) M, wrsz);
 346     if (n != wrsz)
 347       {
 348         if (errno) sim_printf ("Error: %s\r\n", xstrerror_l(errno));
 349         sim_printf ("Unable to write '%s'\r\n", p2);
 350         if (running_perf_test == true)
 351           exit(1);
 352         (void) close (fd);
 353         return SCPE_ARG;
 354       }
 355     (void) close (fd);
 356     return SCPE_OK;
 357   }
 358 
 359 t_stat mrestore (char * p2)
     /* [previous][next][first][last][top][bottom][index][help] */
 360   {
 361     int fd = open (p2, O_RDONLY);
 362     if (fd < 0)
 363       {
 364         if (errno) sim_printf ("Error: %s\r\n", xstrerror_l(errno));
 365         sim_printf ("Unable to open '%s'\r\n", p2);
 366         if (running_perf_test == true)
 367           exit(1);
 368         return SCPE_ARG;
 369       }
 370     ssize_t n = read (fd, (void *) M, msize);
 371     if (n < 1)
 372       {
 373         if (errno) sim_printf ("Error: %s\r\n", xstrerror_l(errno));
 374         sim_printf ("Unable to read '%s'\r\n", p2);
 375         (void) close (fd);
 376         if (running_perf_test == true)
 377           exit(1);
 378         return SCPE_ARG;
 379       }
 380 #if defined(WIN_STDIO)
 381     sim_printf ("Read %llu bytes (%llu pages, %llu segments)\r\n",
 382 #else
 383     sim_printf ("Read %'llu bytes (%'llu pages, %'llu segments)\r\n",
 384 #endif /* if defined(WIN_STDIO) */
 385                 (unsigned long long) n,
 386                 (unsigned long long) (n / sizeof (word36)),
 387                 (unsigned long long) (n / sizeof (36) / 1024));
 388     (void) close (fd);
 389     return SCPE_OK;
 390   }
 391 
 392 t_stat segment_loader (int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 393   {
 394     size_t bufl = strlen (buf) + 1;
 395     char p1 [bufl], p2 [bufl], p3 [bufl];
 396     int nParams = sscanf (buf, "%s %s %s", p1, p2, p3);
 397     if (nParams <= 0)
 398       goto err;
 399     if (strncasecmp ("init", p1, strlen(p1)) == 0)
 400       {
 401         if (nParams != 1)
 402           goto err;
 403         nextSegAddr = ADDR_SEGS;
 404         initPageTables ();
 405       }
 406     else if (strcasecmp ("bload", p1) == 0)
 407       {
 408         if (nParams != 3)
 409           goto err;
 410         return bload (p2, p3);
 411       }
 412     else if (strcasecmp ("stack", p1) == 0)
 413       {
 414         if (nParams != 3)
 415           goto err;
 416         return stack (p2, p3);
 417       }
 418     else if (strcasecmp ("msave", p1) == 0)
 419       {
 420         if (nParams != 2)
 421           goto err;
 422         return msave (p2, nextSegAddr);
 423       }
 424     else if (strcasecmp ("mrestore", p1) == 0)
 425       {
 426         if (nParams != 2)
 427           goto err;
 428         return mrestore (p2);
 429       }
 430     else
 431       goto err;
 432     return SCPE_OK;
 433   err:
 434     sim_msg ("Usage:\r\n"
 435              "   sl init    initialize\r\n"
 436              "   sl bload   <segno> <filename>\r\n");
 437     if (running_perf_test == true)
 438       exit(0);
 439     return SCPE_ARG;
 440   }
 441 
 442 #if defined(PERF_STRIP)
 443 extern DEVICE opc_dev;
 444 int main (int argc, char * argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 445   {
 446 # if !defined(NO_LOCALE)
 447     (void)setlocale(LC_ALL, "");
 448 # endif
 449     running_perf_test = true;
 450     void dps8_init_strip (void);
 451     dps8_init_strip ();
 452     cpus[0].tweaks.enable_emcall = 1;
 453     opc_dev.numunits = 1;
 454     cpu_reset_unit_idx (0, false);
 455     mrestore ("strip.mem");
 456     threadz_sim_instr ();
 457     return 0;
 458   }
 459 #endif /* if defined(PERF_STRIP) */

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