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

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