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-2023 The DPS8M Development Team
  10  *
  11  * All rights reserved.
  12  *
  13  * This software is made available under the terms of the ICU
  14  * License, version 1.8.1 or later.  For more details, see the
  15  * LICENSE.md file at the top-level directory of this distribution.
  16  *
  17  * ---------------------------------------------------------------------------
  18  */
  19 
  20 #include <unistd.h>
  21 #include <errno.h>
  22 #include <string.h>
  23 #include <sys/types.h>
  24 #include <sys/stat.h>
  25 #include <fcntl.h>
  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", (unsigned long) segnum, length, bound, sdw0, sdw1, pgTblAddr);
 117     putbits36_24 ((word36 *) & M[sdw0],  0, pgTblAddr); // ADDR
 118 // I can't get segldr_boot to cross to ring 4
 119 //    putbits36_3  (& M[sdw0], 24, 4);                // R1
 120 //    putbits36_3  (& M[sdw0], 27, 4);                // R2
 121 //    putbits36_3  (& M[sdw0], 30, 4);                // R3
 122     putbits36_3  ((word36 *) & M[sdw0], 24, 0);     // R1
 123     putbits36_3  ((word36 *) & M[sdw0], 27, 0);     // R2
 124     putbits36_3  ((word36 *) & M[sdw0], 30, 0);     // R3
 125     putbits36_1  ((word36 *) & M[sdw0], 33, 1);     // F
 126     putbits36_2  ((word36 *) & M[sdw0], 34, 0);     // FC
 127     putbits36_1  ((word36 *) & M[sdw1],  0, 0);     // 0
 128     putbits36_14 ((word36 *) & M[sdw1],  1, bound); // BOUND
 129     putbits36_1  ((word36 *) & M[sdw1], 15, 1);     // R
 130     putbits36_1  ((word36 *) & M[sdw1], 16, 1);     // E
 131     putbits36_1  ((word36 *) & M[sdw1], 17, 1);     // W
 132     putbits36_1  ((word36 *) & M[sdw1], 18, 0);     // P
 133     putbits36_1  ((word36 *) & M[sdw1], 19, 0);     // U
 134     putbits36_1  ((word36 *) & M[sdw1], 20, 1);     // G
 135     putbits36_1  ((word36 *) & M[sdw1], 21, 1);     // C
 136     putbits36_14 ((word36 *) & M[sdw1], 21, 0);     // EB
 137 
 138     // Fill out PTWs on Segment page table
 139 
 140     for (word24 pg = 0; pg <= npages; pg ++)
 141       {
 142         // word36 * ptwp = (word36 *) M + pgTblAddr + pg;
 143         word24 ptw = pgTblAddr + pg;
 144         word18 pgAddr = (addr + pg * 1024) >> 6;
 145         putbits36_18 ((word36 *) & M[ptw],  0,    pgAddr); // points to the Segment Page
 146         putbits36_1  ((word36 *) & M[ptw], 26,         0);  // unused
 147         putbits36_1  ((word36 *) & M[ptw], 29,         0);  // unmodified
 148         putbits36_1  ((word36 *) & M[ptw], 29,         0);  // unmodified
 149         putbits36_1  ((word36 *) & M[ptw], 33,         1);  // page is in memory
 150         putbits36_2  ((word36 *) & M[ptw], 34,         0);  // fault code
 151         //sim_printf ("   ptw pg %u at %o addr %o\n", pg, pgTblAddr + pg, pgAddr);
 152       }
 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 static t_stat stack (char * p2, char * p3)
     /* [previous][next][first][last][top][bottom][index][help] */
 187   {
 188 
 189     // Segment number
 190     char * endptr;
 191     long segnum = strtol (p2, & endptr, 8);
 192     if (* endptr)
 193       {
 194 #ifdef PERF_STRIP
 195         exit(1);
 196         /*NOTREACHED*/ /* unreachable */
 197 #endif /* ifdef 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 #ifdef PERF_STRIP
 204         exit(1);
 205         /*NOTREACHED*/ /* unreachable */
 206 #endif /* ifdef PERF_STRIP */
 207         return SCPE_ARG;
 208       }
 209 
 210     long len = strtol (p3, & endptr, 8);
 211     if (* endptr)
 212       {
 213 #ifdef PERF_STRIP
 214         exit(1);
 215         /*NOTREACHED*/ /* unreachable */
 216 #endif /* ifdef 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 #ifdef PERF_STRIP
 223         exit(1);
 224         /*NOTREACHED*/ /* unreachable */
 225 #endif /* ifdef 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", (unsigned long) segnum, nextSegAddr, (unsigned long) len, length);
 235     // Mark the pages as used
 236     nextSegAddr += length;
 237 
 238     return SCPE_OK;
 239   }
 240 
 241 static t_stat bload (char * p2, char * p3)
     /* [previous][next][first][last][top][bottom][index][help] */
 242   {
 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 #ifdef PERF_STRIP
 257             exit(1);
 258             /*NOTREACHED*/ /* unreachable */
 259 #endif /* ifdef 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 #ifdef PERF_STRIP
 266             exit(1);
 267             /*NOTREACHED*/ /* unreachable */
 268 #endif /* ifdef 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", strerror(errno));
 278         sim_printf ("Unable to open '%s'\n", p3);
 279 #ifdef PERF_STRIP
 280         exit(1);
 281         /*NOTREACHED*/ /* unreachable */
 282 #endif /* ifdef 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         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", p3, segnum < 0 ? 0 : (unsigned long) segnum, startAddr, length, lengthp);
 333     close (deckfd);
 334     return SCPE_OK;
 335   }
 336 
 337 #define msize (MEMSIZE * sizeof (word36))
 338 
 339 static t_stat msave (char * p2, word24 sz)
     /* [previous][next][first][last][top][bottom][index][help] */
 340   {
 341     uint wrsz = sz * sizeof (word36);
 342     int fd = open (p2, O_WRONLY | O_CREAT, 0664);
 343     if (fd < 0)
 344       {
 345         if (errno) sim_printf ("Error: %s\n", strerror(errno));
 346         sim_printf ("Unable to open '%s'\n", p2);
 347 #ifdef PERF_STRIP
 348         exit(1);
 349         /*NOTREACHED*/ /* unreachable */
 350 #endif /* ifdef PERF_STRIP */
 351         return SCPE_ARG;
 352       }
 353     ssize_t n = write (fd, (void *) M, wrsz);
 354     if (n != wrsz)
 355       {
 356         if (errno) sim_printf ("Error: %s\n", strerror(errno));
 357         sim_printf ("Unable to write '%s'\n", p2);
 358 #ifdef PERF_STRIP
 359         exit(1);
 360         /*NOTREACHED*/ /* unreachable */
 361 #endif /* ifdef PERF_STRIP */
 362         return SCPE_ARG;
 363       }
 364     (void) close (fd);
 365     return SCPE_OK;
 366   }
 367 
 368 static t_stat mrestore (char * p2)
     /* [previous][next][first][last][top][bottom][index][help] */
 369   {
 370     int fd = open (p2, O_RDONLY);
 371     if (fd < 0)
 372       {
 373         if (errno) sim_printf ("Error: %s\n", strerror(errno));
 374         sim_printf ("Unable to open '%s'\n", p2);
 375 #ifdef PERF_STRIP
 376         exit(1);
 377         /*NOTREACHED*/ /* unreachable */
 378 #endif /* ifdef PERF_STRIP */
 379         return SCPE_ARG;
 380       }
 381     ssize_t n = read (fd, (void *) M, msize);
 382     if (n < 1)
 383       {
 384         if (errno) sim_printf ("Error: %s\n", strerror(errno));
 385         sim_printf ("Unable to read '%s'\n", p2);
 386         (void) close (fd);
 387 #ifdef PERF_STRIP
 388         exit(1);
 389         /*NOTREACHED*/ /* unreachable */
 390 #endif /* ifdef PERF_STRIP */
 391         return SCPE_ARG;
 392       }
 393 #ifdef WIN_STDIO
 394     sim_printf ("Read %llu bytes (%llu pages, %llu segments)\n",
 395 #else
 396     sim_printf ("Read %'llu bytes (%'llu pages, %'llu segments)\n",
 397 #endif /* ifdef WIN_STDIO */
 398                 (unsigned long long) n,
 399                 (unsigned long long) (n / sizeof (word36)),
 400                 (unsigned long long) (n / sizeof (36) / 1024));
 401     (void) close (fd);
 402     return SCPE_OK;
 403   }
 404 
 405 t_stat segment_loader (int32 arg, const char * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 406   {
 407     size_t bufl = strlen (buf) + 1;
 408     char p1 [bufl], p2 [bufl], p3 [bufl];
 409     int nParams = sscanf (buf, "%s %s %s", p1, p2, p3);
 410     if (nParams <= 0)
 411       goto err;
 412     if (strncasecmp ("init", p1, strlen(p1)) == 0)
 413       {
 414         if (nParams != 1)
 415           goto err;
 416         nextSegAddr = ADDR_SEGS;
 417         initPageTables ();
 418       }
 419     else if (strcasecmp ("bload", p1) == 0)
 420       {
 421         if (nParams != 3)
 422           goto err;
 423         return bload (p2, p3);
 424       }
 425     else if (strcasecmp ("stack", p1) == 0)
 426       {
 427         if (nParams != 3)
 428           goto err;
 429         return stack (p2, p3);
 430       }
 431     else if (strcasecmp ("msave", p1) == 0)
 432       {
 433         if (nParams != 2)
 434           goto err;
 435         return msave (p2, nextSegAddr);
 436       }
 437     else if (strcasecmp ("mrestore", p1) == 0)
 438       {
 439         if (nParams != 2)
 440           goto err;
 441         return mrestore (p2);
 442       }
 443     else
 444       goto err;
 445     return SCPE_OK;
 446   err:
 447     sim_msg ("Usage:\n"
 448              "   sl init    initialize\n"
 449              "   sl bload   <segno> <filename>\n");
 450 #ifdef PERF_STRIP
 451     exit(0);
 452     /*NOTREACHED*/ /* unreachable */
 453 #endif /* ifdef PERF_STRIP */
 454     return SCPE_ARG;
 455   }
 456 
 457 #ifdef PERF_STRIP
 458 extern DEVICE opc_dev;
 459 int main (int argc, char * argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 460   {
 461     setlocale(LC_NUMERIC, "");
 462     void dps8_init_strip (void);
 463     dps8_init_strip ();
 464     cpus[0].tweaks.enable_emcall = 1;
 465     opc_dev.numunits = 1;
 466     cpu_reset_unit_idx (0, false);
 467     mrestore ("strip.mem");
 468     threadz_sim_instr ();
 469     return 0;
 470   }
 471 #endif

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