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         return SCPE_ARG;
 364       }
 365     (void) close (fd);
 366     return SCPE_OK;
 367   }
 368 
 369 t_stat mrestore (char * p2)
     /* [previous][next][first][last][top][bottom][index][help] */
 370   {
 371     int fd = open (p2, O_RDONLY);
 372     if (fd < 0)
 373       {
 374         if (errno) sim_printf ("Error: %s\n", xstrerror_l(errno));
 375         sim_printf ("Unable to open '%s'\n", p2);
 376 #if defined(PERF_STRIP)
 377         exit(1);
 378         /*NOTREACHED*/ /* unreachable */
 379 #endif /* if defined(PERF_STRIP) */
 380         return SCPE_ARG;
 381       }
 382     ssize_t n = read (fd, (void *) M, msize);
 383     if (n < 1)
 384       {
 385         if (errno) sim_printf ("Error: %s\n", xstrerror_l(errno));
 386         sim_printf ("Unable to read '%s'\n", p2);
 387         (void) close (fd);
 388 #if defined(PERF_STRIP)
 389         exit(1);
 390         /*NOTREACHED*/ /* unreachable */
 391 #endif /* if defined(PERF_STRIP) */
 392         return SCPE_ARG;
 393       }
 394 #if defined(WIN_STDIO)
 395     sim_printf ("Read %llu bytes (%llu pages, %llu segments)\n",
 396 #else
 397     sim_printf ("Read %'llu bytes (%'llu pages, %'llu segments)\n",
 398 #endif /* if defined(WIN_STDIO) */
 399                 (unsigned long long) n,
 400                 (unsigned long long) (n / sizeof (word36)),
 401                 (unsigned long long) (n / sizeof (36) / 1024));
 402     (void) close (fd);
 403     return SCPE_OK;
 404   }
 405 
 406 t_stat segment_loader (int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 407   {
 408     size_t bufl = strlen (buf) + 1;
 409     char p1 [bufl], p2 [bufl], p3 [bufl];
 410     int nParams = sscanf (buf, "%s %s %s", p1, p2, p3);
 411     if (nParams <= 0)
 412       goto err;
 413     if (strncasecmp ("init", p1, strlen(p1)) == 0)
 414       {
 415         if (nParams != 1)
 416           goto err;
 417         nextSegAddr = ADDR_SEGS;
 418         initPageTables ();
 419       }
 420     else if (strcasecmp ("bload", p1) == 0)
 421       {
 422         if (nParams != 3)
 423           goto err;
 424         return bload (p2, p3);
 425       }
 426     else if (strcasecmp ("stack", p1) == 0)
 427       {
 428         if (nParams != 3)
 429           goto err;
 430         return stack (p2, p3);
 431       }
 432     else if (strcasecmp ("msave", p1) == 0)
 433       {
 434         if (nParams != 2)
 435           goto err;
 436         return msave (p2, nextSegAddr);
 437       }
 438     else if (strcasecmp ("mrestore", p1) == 0)
 439       {
 440         if (nParams != 2)
 441           goto err;
 442         return mrestore (p2);
 443       }
 444     else
 445       goto err;
 446     return SCPE_OK;
 447   err:
 448     sim_msg ("Usage:\n"
 449              "   sl init    initialize\n"
 450              "   sl bload   <segno> <filename>\n");
 451 #if defined(PERF_STRIP)
 452     exit(0);
 453     /*NOTREACHED*/ /* unreachable */
 454 #endif /* if defined(PERF_STRIP) */
 455     return SCPE_ARG;
 456   }
 457 
 458 #if defined(PERF_STRIP)
 459 extern DEVICE opc_dev;
 460 int main (int argc, char * argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 461   {
 462     (void)setlocale(LC_ALL, "");
 463     void dps8_init_strip (void);
 464     dps8_init_strip ();
 465     cpus[0].tweaks.enable_emcall = 1;
 466     opc_dev.numunits = 1;
 467     cpu_reset_unit_idx (0, false);
 468     mrestore ("strip.mem");
 469     threadz_sim_instr ();
 470     return 0;
 471   }
 472 #endif /* if defined(PERF_STRIP) */

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