home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / EXTRA-ST / CPM-80-E / CPM-0.2 / CPM-0 / cpm-0.2 / bios.c next >
Encoding:
C/C++ Source or Header  |  1994-06-17  |  18.1 KB  |  736 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    CP/M emulator version 0.1                         */
  5. /*                                         */
  6. /*    written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)             */
  7. /*    June-1994                                 */
  8. /*                                         */
  9. /*    This file is distributed under the GNU COPYRIGHT             */
  10. /*    see COPYRIGHT.GNU for Copyright details                     */
  11. /*                                         */
  12. /*                                         */
  13. /*****************************************************************************/
  14. #include "cpmemu.h"
  15. #include <ctype.h>
  16. #include <unistd.h>
  17.  
  18. #define CPMLIBDIR "/usr/local/lib/cpm"
  19.  
  20. struct z80regs z80regs,
  21.     z80regs0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  22. unsigned short dmaaddr = 0x80;
  23. unsigned short usercode = 0x00;
  24. unsigned char z80mem[65536L+6];
  25. static int SPT = 64;
  26.  
  27. union zeropage {
  28.     struct c {
  29.         uchar jpbyte0;
  30.         ushrt wbootvec;
  31.         uchar iobyte;
  32.         uchar usrdrv;
  33.         uchar jpbyte5;
  34.         ushrt bdosvec;
  35.         uchar fill1[0x54];
  36.         uchar fcb[36];
  37.         uchar dma[128];
  38.     };
  39.     uchar z[256];
  40. } zeropage;
  41.  
  42. static char zeropage0[8] = {
  43.     0xc3, (BIOS+3) & 0xff, (BIOS+3) >> 8, 0x80, 0x00, 0xc3, BDOS & 0xff, BDOS >> 8 };
  44. static char cpmsys[0x1600];
  45. unsigned bios_dma = 0x80, bios_track = 0, bios_sector = 0;
  46. static FILE *bios_fp = NULL;
  47. static const char *cpmimage;
  48.  
  49. /* BIOS data locations: */
  50. #define DPH0        (BIOS+0x36U)
  51. #define DPB0        (DPH0+16U)
  52. #define DATA_START    (DPB0+15U)
  53. #define DIRBUF        0xff80U        /* fixed! */
  54.  
  55.  
  56. static void make_jumpers(void) {
  57.     int i;
  58.     for (i = 0; i < 18; ++i) {
  59.     /* make jump table at BIOS start. This HAS to be a true jump table, */
  60.     /* since some programs rely on this */
  61.     z80mem[BIOS+3*i] = 0xc3; /* Z80-jump instruction */
  62.     z80mem[BIOS+3*i+1] = DIRBUF - 20 + i;
  63.     z80mem[BIOS+3*i+2] = DIRBUF >> 8;
  64.     }
  65.     z80mem[0x38] = 0xc9;    /* no interrupt */
  66. }
  67. /* just for information: */
  68. static struct dph {
  69.     ushrt xlat, scr1, scr2, scr3;
  70.     ushrt dirbuf;
  71.     ushrt dpb;
  72.     ushrt csv;
  73.     ushrt alv;
  74. } dph0 = { 0, 0, 0, 0, DIRBUF, DPB0, 0, 0 };
  75.  
  76. void cpm_init(const char *imagefile, const char *systemfile, struct dpb *dpb0) {
  77.     register unsigned i;
  78.     FILE *fp;
  79.  
  80.     cpmimage = imagefile;
  81.     memset(z80mem+0x100, 0x76, sizeof(z80mem)-0x100);    /* HALT insn */
  82.  
  83.     if (!(fp = fopen(systemfile, "rb"))) {
  84.     fprintf(stderr, "cpm: cannot open system file \"%s\"\n", systemfile);
  85.     exit(1);
  86.     }
  87.     fread(cpmsys, 0x1600, 1, fp);
  88.     if (!cpmsys[0] && !cpmsys[1] && !cpmsys[2]) {
  89.     memmove(cpmsys, cpmsys+5, 0x806);
  90.     memmove(cpmsys+0x806, cpmsys+0x806+7, 0xe00-13);
  91.     }
  92.     fclose(fp);
  93.  
  94.     for (i = 0; i <= NBREAKS; ++i)
  95.     breakpoint[i].action = 0;
  96.  
  97.     for (i = 0; i < 8; ++i)
  98.         zeropage.z[i] = zeropage0[i];
  99.     for (i = 8; i < 256; ++i)
  100.         zeropage.z[i] = 0x76;
  101.     memcpy(z80mem, zeropage.z, 0x100);
  102.     memcpy(z80mem+BIOS-0x1600, cpmsys, 0x1600);
  103.  
  104.     dpb0->blm = (1 << dpb0->bsh) - 1;
  105.     dpb0->exm = dpb0->blm >> 3;
  106.     if (dpb0->dsm >= 256)
  107.     dpb0->exm >>= 1;
  108.     /* build alloc0, alloc1 bitmasks */
  109.     {   int bits = ((int)dpb0->drm + 1) / ((int)dpb0->blm + 1) / 4;
  110.     if (bits <= 8) {
  111.          dpb0->alloc0 = 256 - (256 >> bits);
  112.         dpb0->alloc1 = 0;
  113.     } else {
  114.          dpb0->alloc0 = 255;
  115.         dpb0->alloc1 = 256 - (256 >> (bits-8));
  116.     }
  117.     }
  118.  
  119.     SPT = dpb0->spt;
  120.     /* Transfer dpb */
  121.     z80mem[DPB0+ 0] = dpb0->spt & 0xff;
  122.     z80mem[DPB0+ 1] = dpb0->spt >> 8;
  123.     z80mem[DPB0+ 2] = dpb0->bsh;
  124.     z80mem[DPB0+ 3] = dpb0->blm;
  125.     z80mem[DPB0+ 4] = dpb0->exm;
  126.     z80mem[DPB0+ 5] = dpb0->dsm & 0xff;
  127.     z80mem[DPB0+ 6] = dpb0->dsm >> 8;
  128.     z80mem[DPB0+ 7] = dpb0->drm & 0xff;
  129.     z80mem[DPB0+ 8] = dpb0->drm >> 8;
  130.     z80mem[DPB0+ 9] = dpb0->alloc0;
  131.     z80mem[DPB0+10] = dpb0->alloc1;
  132.     z80mem[DPB0+11] = dpb0->cks & 0xff;
  133.     z80mem[DPB0+12] = dpb0->cks >> 8;
  134.     z80mem[DPB0+13] = dpb0->off & 0xff;
  135.     z80mem[DPB0+14] = dpb0->off >> 8;
  136.  
  137.     i = DATA_START;    /* begin allocating csv & alv */
  138.     dph0.csv = i;
  139.     i += dpb0->cks;
  140.     dph0.alv = i;
  141.     i += (dpb0->dsm+1 + 7) >> 3;
  142.     if (i > DIRBUF-16) {
  143.     fprintf(stderr, "Error configuring BIOS tables: out of memory!\n");
  144.     exit(1);
  145.     }
  146.     /* Transfer dph */
  147.     memcpy(z80mem+DPH0, &dph0, 16);
  148.  
  149.     make_jumpers();
  150.     z80regs.sp = 0x80;
  151. }
  152.  
  153. void loadfile(const char *name) {
  154.     FILE *fp;
  155.     unsigned p;
  156.  
  157.     if (!(fp = fopen(name, "rb"))) {
  158.     fprintf(stderr, "cpm: cannot open file \"%s\"\n", name);
  159.     exit(1);
  160.     }
  161.     p = 256;
  162.     while (fread(z80mem+p, 1, 256, fp) == 256)
  163.     p += 256;
  164.     fclose(fp);
  165. }
  166.  
  167. void cpminit2(int argc, char *argv[]) {
  168.     z80mem[0x80] = 0;
  169.     z80mem[0x81] = 0x0d;
  170.     z80regs = z80regs0;
  171.     z80regs.pc = BIOS-0x1600;
  172.     z80regs.bc = 0;
  173.     if (argc) {
  174.     /* transfer command line into CCP */
  175.     int i, p;
  176.     p = BIOS - 0x1600 + 8;
  177.     for (i = 0; i < argc; ++i) {
  178.         char *s;    /* transfer one arg */
  179.         if (i)
  180.         z80mem[p++] = ' ';
  181.         for (s = argv[i]; *s; )
  182.         z80mem[p++] = *s++;
  183.         if (p > BIOS - 0x1600 + 128)
  184.         break;
  185.     }
  186.     z80mem[p] = 0;
  187.     z80mem[BIOS - 0x1600 + 7] = p - (BIOS - 0x1600 + 8);
  188.     {   unsigned char *s;
  189.         for (s = z80mem + BIOS - 0x1600 + 8; *s; ++s)
  190.         if (islower(*s))
  191.         *s = toupper(*s);
  192.     }
  193.     silent_exit = 1;
  194.     /* patch CCP return: */
  195.     for (p = BDOS; p > BIOS-0x1600; --p)
  196.         if (z80mem[p] == 0xcd && z80mem[p+1] == 0x00 && z80mem[p+2] == 0x01) {
  197.         z80mem[p+3] = 0xc3;
  198.         z80mem[p+4] = (unsigned char)(BIOS & 0xffU);
  199.         z80mem[p+5] = (unsigned char)(BIOS>>8);
  200.         break;
  201.         }
  202.     if (p == BIOS-0x1600) {
  203.         fprintf(stderr, "FATAL: cannot patch CCP return address\n");
  204.         exit(1);
  205.     }
  206.     }
  207. }
  208.  
  209.  
  210. /* return 0 = invalid (TRAP), 1 = BIOS hook */
  211. extern jmp_buf mainloop;
  212. static int storedfps = 0;
  213.  
  214. static void open_image(void) {
  215.     if (!(bios_fp = fopen(cpmimage, "r+b"))) {
  216.     fprintf(stderr, "cpm: cannot open disk image \"%s\"\n", cpmimage);
  217.     exit(1);
  218.     }
  219. }
  220.  
  221.  
  222. int check_BIOS_hook(void) {
  223.     int i;
  224.     static uchar buffbios[128];
  225.     static int currdsk = 0;
  226.  
  227.     if (z80regs.pc >= BIOS) {
  228.     switch (z80regs.pc) {
  229.     case BIOS:      /* System Reset (coldboot) */
  230.     case DIRBUF-20:
  231.         if (!silent_exit)
  232.         printf("\nCp/M BIOS COLDBOOT takes you back to Linux\n");
  233.         exit(0);
  234.     case BIOS+3:    /* System Reset (warmboot) */
  235.     case DIRBUF-19:
  236.         if (silent_exit)
  237.         exit(0);
  238.         storedfps = 0;    /* clean up! */
  239.         for (i = 0; i < 0x1600; ++i)
  240.         z80mem[i+BIOS-0x1600] = cpmsys[i];
  241.         for (i = 0; i < 8; ++i)
  242.         z80mem[i] = zeropage.z[i];
  243.         z80regs.bc = 0;
  244.         z80regs.pc = BIOS-0x1600+3;
  245.         z80regs.sp = 0x80;
  246.         make_jumpers();
  247.         if (bios_fp)
  248.         fflush(bios_fp);    /* prepare for disk change */
  249.         return 1;
  250.     case BIOS+6:    /* Console Status */
  251.     case DIRBUF-18:
  252.         z80regs.af = kbhit() ? 0xff : 0x00;
  253.     ret1:
  254.         z80mem[z80regs.pc=DIRBUF-1] = 0xc9;
  255.         return 1;
  256.     case BIOS+9:    /* Console In */
  257.     case DIRBUF-17:
  258.         z80regs.af = conin();
  259.         goto ret1;
  260.     case BIOS+12:   /* Console Out */
  261.     case DIRBUF-16:
  262.         vt52(z80regs.bc & 0xff);
  263.         goto ret1;
  264.     case BIOS+15:   /* List Out */
  265.     case DIRBUF-15:
  266.         goto ret1;
  267.     case BIOS+18:   /* Punch Out */
  268.     case DIRBUF-14:
  269.         goto ret1;
  270.     case BIOS+21:   /* Reader In */
  271.     case DIRBUF-13:
  272.         z80regs.af = 0;
  273.         goto ret1;
  274.     case BIOS+24:   /* Home */
  275.     case DIRBUF-12:
  276.         bios_track = 0;
  277.         bios_sector = 0;
  278.         goto ret1;
  279.     case BIOS+27:   /* Seldsk */
  280.     case DIRBUF-11:
  281.         currdsk = z80regs.bc & 0xff;
  282.         if (z80regs.bc & 0xff)
  283.         z80regs.hl = 0xffff;
  284.         else
  285.         z80regs.hl = DPH0;
  286.         goto ret1;
  287.     case BIOS+30:   /* Settrack */
  288.     case DIRBUF-10:
  289.         bios_track = z80regs.bc;
  290.         goto ret1;
  291.     case BIOS+33:   /* Set sector */
  292.     case DIRBUF- 9:
  293.         bios_sector = z80regs.bc & 0xff;
  294.         goto ret1;
  295.     case BIOS+36:   /* Set dma */
  296.     case DIRBUF- 8:
  297.         bios_dma = z80regs.bc;
  298.         goto ret1;
  299.     case BIOS+39:   /* Read */
  300.     case DIRBUF- 7:
  301.         if (currdsk) {
  302.         fprintf(stderr, "BDOS Err on %c: Select\n", currdsk+'A');
  303.         exit(1);
  304.         }
  305.         if (!bios_fp)
  306.         open_image();
  307.         fseek(bios_fp, ((long)bios_sector + (long)SPT * (long)bios_track) * 128L, 0);
  308.         fread(buffbios, 1, 128, bios_fp);
  309.         for (i = 0; i < 128; ++i)
  310.         z80mem[i + bios_dma] = buffbios[i];
  311.         z80regs.af = 0;
  312.         goto ret1;
  313.     case BIOS+42:   /* Write */
  314.     case DIRBUF- 6:
  315.         if (currdsk) {
  316.         fprintf(stderr, "BDOS Err on %c: Select\n", currdsk+'A');
  317.         exit(1);
  318.         }
  319.         if (!bios_fp)
  320.         open_image();
  321.         fseek(bios_fp, ((long)bios_sector + (long)SPT * (long)bios_track) * 128L, 0);
  322.         for (i = 0; i < 128; ++i)
  323.         buffbios[i] = z80mem[i + bios_dma];
  324.         fwrite(buffbios, 1, 128, bios_fp);
  325.         z80regs.af = 0;
  326.         goto ret1;
  327.     case BIOS+45:   /* List Status */
  328.     case DIRBUF- 5:
  329.         z80regs.af = 0;     /* not ready */
  330.         goto ret1;
  331.     case BIOS+48:   /* Sectran */       /* no sectran */
  332.     case DIRBUF- 4:
  333.         z80regs.hl = z80regs.bc & 0xff;
  334.         goto ret1;
  335.     default:
  336.         printf("Program traps in BIOS:\n");
  337.         debug = 1;
  338.         longjmp(mainloop, 1);
  339.     }
  340.     }
  341.     return 0;
  342. }
  343.  
  344. /* #include "cpmemu.h" */
  345.  
  346. #if 0
  347. static struct FCB {
  348.     char drive;
  349.     char name[11];
  350.     char data[24];
  351. } samplefcb;
  352. #endif
  353. static void FCB_to_filename(unsigned char *p, char *name) {
  354.     int i;
  355.     /* strcpy(name, "test/");
  356.        name += 5; */
  357.     for (i = 0; i < 8; ++i)
  358.     if (p[i+1] != ' ')
  359.         *name++ = tolower(p[i+1]);
  360.     if (p[9] != ' ') {
  361.     *name++ = '.';
  362.     for (i = 0; i < 3; ++i)
  363.         if (p[i+9] != ' ')
  364.         *name++ = tolower(p[i+9]);
  365.     }
  366.     *name = '\0';
  367. }
  368.  
  369. static struct stfps {
  370.     FILE *fp;
  371.     unsigned where;
  372.     char name[12];
  373. } stfps[100];
  374.  
  375. static void storefp(FILE *fp, unsigned where) {
  376.     int i;
  377.     int ind = -1;
  378.     for (i = 0; i < storedfps; ++i)
  379.     if (stfps[i].where == 0xffffU)
  380.         ind = i;
  381.     else if (stfps[i].where == where) {
  382.         ind = i;
  383.         goto putfp;
  384.     }
  385.     if (ind < 0) {
  386.     if (++storedfps > 100) {
  387.         fprintf(stderr, "out of fp stores!\n");
  388.         exit(1);
  389.     }
  390.     ind = storedfps - 1;
  391.     }
  392.     stfps[ind].where = where;
  393.  putfp:
  394.     stfps[ind].fp = fp;
  395.     memcpy(stfps[ind].name, z80mem+z80regs.de+1, 11);
  396.     stfps[ind].name[11] = '\0';
  397. }
  398. #if 1
  399. static FILE *getfp(unsigned where) {
  400.     int i;
  401.     for (i = 0; i < storedfps; ++i)
  402.     if (stfps[i].where == where) {
  403.         /* check name? */
  404.         return stfps[i].fp;
  405.     }
  406.     /* fcb not found. maybe it has been moved? */
  407.     for (i = 0; i < storedfps; ++i)
  408.     if (stfps[i].where != 0xffffU &&
  409.         !memcmp(z80mem+z80regs.de+1, stfps[i].name, 11)) {
  410.         stfps[i].where = where;    /* moved FCB */
  411.         return stfps[i].fp;
  412.     }
  413.  
  414.     fprintf(stderr, "error: cannot find fp entry for FCB at %04x"
  415.         " fctn %d, FCB named %s\n", where, z80regs.bc & 0xff,
  416.         z80mem+where+1);
  417.     for (i = 0; i < storedfps; ++i)
  418.     if (stfps[i].where != 0xffffU)
  419.         printf("%s %04x\n", stfps[i].name, stfps[i].where);
  420.     exit(1);
  421. }
  422. static void delfp(unsigned where) {
  423.     int i;
  424.     for (i = 0; i < storedfps; ++i)
  425.     if (stfps[i].where == where) {
  426.         stfps[i].where = 0xffffU;
  427.         return;
  428.     }
  429.     fprintf(stderr, "error: cannot del fp entry for FCB at %04x\n", where);
  430.     exit(1);
  431. }
  432. #endif
  433.  
  434.  
  435.  
  436. #include <dirent.h>
  437. #include <sys/stat.h>
  438.  
  439. #define ADDRESS  (((long)z80mem[z80regs.de+33] + \
  440.             (long)z80mem[z80regs.de+34] * 256) * 128L)
  441. /* (long)z80mem[z80regs.de+35] * 65536L; */
  442.  
  443. static DIR *dp = NULL;
  444. static unsigned sfn = 0;
  445.  
  446. /* emulation of BDOS calls */
  447.  
  448. void check_BDOS_hook(void) {
  449.     int i;
  450.     char name[32];
  451.     char name2[32];
  452.     struct stat stbuf;
  453.     FILE *fp;
  454.     char *s, *t;
  455.     const char *mode;
  456.     switch (z80regs.bc & 0xff) {
  457.     case  0:    /* System Reset */
  458.     if (silent_exit) {
  459.         /* printf("\nProgram terminates normally (BDOS function 0)\n"); */
  460.         exit(0);
  461.     }
  462.     for (i = 0; i < 0x1600; ++i)
  463.         z80mem[i+BIOS-0x1600] = cpmsys[i];
  464.     z80regs.bc = 0;
  465.     z80regs.pc = BIOS-0x1600+3;
  466.     z80regs.sp = 0x80;
  467.     break;
  468.     case 1:     /* Console Input */
  469.     z80regs.af = z80regs.hl = conin();
  470.     if ((z80regs.hl & 0xff) < ' ') {
  471.         switch(z80regs.hl) {
  472.         case '\r':
  473.         case '\n':
  474.         case '\t':
  475.         putch(z80regs.hl);
  476.         break;
  477.         default:
  478.         putch('^');
  479.         putch((z80regs.hl & 0xff)+'@');
  480.         if (z80regs.hl == 3) {    /* ctrl-C pressed */
  481.             z80regs.pc = BIOS+3;
  482.             check_BIOS_hook();
  483.             return;
  484.         }
  485.         }
  486.     } else {
  487.         vt52(z80regs.hl);
  488.     }
  489.     break;
  490.     case 2:     /* Console Output */
  491.     vt52(z80regs.de & 0xff);
  492.     break;
  493.     case 6:     /* direct I/O */
  494.     switch (z80regs.de & 0xff) {
  495.     case 0xff:  if (!kbhit()) {
  496.         z80regs.af = z80regs.hl = 0;
  497.         break;
  498.     }
  499.     case 0xfd:  z80regs.af = z80regs.hl = conin();
  500.         break;
  501.     case 0xfe:  z80regs.af = z80regs.hl = kbhit() ? 0xff : 0;
  502.         break;
  503.     default:    vt52(z80regs.de & 0xff);
  504.     }
  505.     break;
  506.     case 9:    /* Print String */
  507.     s = z80mem +z80regs.de;
  508.     while (*s != '$')
  509.         vt52(*s++);
  510.     break;
  511.     case 10:    /* Read Command Line */
  512.     s = rdcmdline(*(t = z80mem+z80regs.de), 1);
  513.     if (z80regs.pc == BIOS+3) {     /* ctrl-C pressed */
  514.         check_BIOS_hook();        /* execute WBOOT */
  515.         return;
  516.     }
  517.     ++t;
  518.     for (i = 0; i <= *s; ++i)
  519.         t[i] = s[i];
  520.     break;
  521.     case 12:    /* Return Version Number */
  522.     z80regs.af = z80regs.hl = 0x22;      /* emulate Cp/M 2.2 */
  523.     break;
  524.     case 26:    /* Set DMA Address */
  525.     dmaaddr = z80regs.de;
  526.     break;
  527.     case 32:    /* Get/Set User Code */
  528.     if (z80regs.de & 0xff == 0xff)  /* Get Code */
  529.         z80regs.af = z80regs.hl = usercode;
  530.     else
  531.         usercode = z80regs.de & 0x0f;
  532.     break;
  533.  
  534.     /* dunno if these are correct */
  535.  
  536.     case 11:    /* Console Status */
  537.     z80regs.af = z80regs.hl = kbhit() ? 0xff : 0x00;
  538.     break;
  539.  
  540.     case 13:    /* reset disk system */
  541.     /* storedfps = 0; */    /* WS crashes then */
  542.     if (dp)
  543.         closedir(dp);
  544.     dp = NULL;
  545.     dmaaddr = 0x80;
  546.     /* select only A:, all r/w */
  547.     break;
  548.     case 14:    /* select disk */
  549.     break;
  550.     case 15:    /* open file */
  551.     mode = "r+b";
  552.     fileio:
  553.     FCB_to_filename(z80mem+z80regs.de, name);
  554.     if (!(fp = fopen(name, mode))) {
  555.         if (*mode == 'r') {
  556.         char ss[50];
  557.         sprintf(ss, "%s/%s", CPMLIBDIR, name);
  558.         fp = fopen(ss, "rb");
  559.         }
  560.         if (!fp) {
  561.         /* still no success */
  562.         z80regs.af = z80regs.hl = 0xff;
  563.         break;
  564.         }
  565.     }
  566.     /* success */
  567.     memset(z80mem+z80regs.de+12, 0, 33-12);
  568.     z80mem[z80regs.de+15] = 0;    /* rc field of FCB */
  569.     if (fstat(fileno(fp), &stbuf) || !S_ISREG(stbuf.st_mode)) {
  570.         z80regs.af = z80regs.hl = 0xff;
  571.         fclose(fp);
  572.         break;
  573.     }
  574.     {   unsigned long pos;
  575.         pos = (stbuf.st_size + 127) >> 7;    /* number of records */
  576.         if (pos > 128)
  577.         z80mem[z80regs.de+15] = 0x80;
  578.         else
  579.         z80mem[z80regs.de+15] = pos;
  580.     }
  581.     z80regs.af = z80regs.hl = 0;
  582.     /* where to store fp? */
  583.     storefp(fp, z80regs.de);
  584.     /* printf("opening file %s\n", name); */
  585.     break;
  586.     case 16:    /* close file */
  587.     fp = getfp(z80regs.de);
  588.     delfp(z80regs.de);
  589.     fclose(fp);
  590.     break;
  591.     case 17:    /* search for first */
  592.     if (dp)
  593.         closedir(dp);
  594.     if (!(dp = opendir("."))) {
  595.         fprintf(stderr, "opendir fails\n");
  596.         exit(1);
  597.     }
  598.     sfn = z80regs.de;
  599.     /* fall through */
  600.     case 18:    /* search for next */
  601.     if (!dp)
  602.         goto retbad;
  603.     {   struct dirent *de;
  604.         unsigned char *p;
  605.         const char *sr;
  606.     nocpmname:
  607.         if (!(de = readdir(dp))) {
  608.         closedir(dp);
  609.         dp = NULL;
  610.         retbad:
  611.         z80regs.af = z80regs.hl = 0xff;
  612.         break;
  613.         }
  614.         /* compare data */
  615.         memset(p = z80mem+dmaaddr, 0, 128);    /* dmaaddr instead of DIRBUF!! */
  616.         if (*de->d_name == '.')
  617.         goto nocpmname;
  618.         if (strchr(sr = de->d_name, '.')) {
  619.         if (de->d_reclen > 12)    /* POSIX: namlen */
  620.             goto nocpmname;
  621.         } else if (de->d_reclen > 8)
  622.             goto nocpmname;
  623.         /* seems OK */
  624.         for (i = 0; i < 8; ++i)
  625.         if (*sr != '.' && *sr) {
  626.             *++p = toupper(*sr); sr++;
  627.         } else
  628.             *++p = ' ';
  629.         /* skip dot */
  630.         while (*sr && *sr != '.')
  631.         ++sr;
  632.         while (*sr == '.')
  633.         ++sr;
  634.         for (i = 0; i < 3; ++i)
  635.         if (*sr != '.' && *sr) {
  636.             *++p = toupper(*sr); sr++;
  637.         } else
  638.             *++p = ' ';
  639.         /* OK, fcb block is filled */
  640.         /* match name */
  641.         p -= 11;
  642.         sr = z80mem+sfn;
  643.         for (i = 1; i <= 12; ++i)
  644.         if (sr[i] != '?' && sr[i] != p[i])
  645.             goto nocpmname;
  646.         /* yup, it matches */
  647.         z80regs.af = z80regs.hl = 0x00;    /* always at pos 0 */
  648.         p[32] = p[64] = p[96] = 0xe5;
  649.     }
  650.     break;
  651.     case 19:    /* delete file (no wildcards yet) */
  652.     FCB_to_filename(z80mem+z80regs.de, name);
  653.     unlink(name);
  654.     break;
  655.     case 20:    /* read sequential */
  656.     fp = getfp(z80regs.de);
  657.     readseq:
  658.     if ((i = fread(z80mem+dmaaddr, 1, 128, fp)) > 0) {
  659.         if (i != 128)
  660.         memset(z80mem+dmaaddr+i, 0x1a, 128-i);
  661.         z80regs.af = z80regs.hl = 0x00;
  662.     } else
  663.         z80regs.af = z80regs.hl = 0x1;    /* ff => pip error */
  664.     break;
  665.     case 21:    /* write sequential */
  666.     fp = getfp(z80regs.de);
  667.     writeseq:
  668.     if (fwrite(z80mem+dmaaddr, 1, 128, fp) == 128)
  669.         z80regs.af = z80regs.hl = 0x00;
  670.     else
  671.         z80regs.af = z80regs.hl = 0xff;
  672.     break;
  673.     case 22:    /* make file */
  674.     mode = "w+b";
  675.     goto fileio;
  676.     case 23:    /* rename file */
  677.     FCB_to_filename(z80mem+z80regs.de, name);
  678.     FCB_to_filename(z80mem+z80regs.de+16, name2);
  679.     /* printf("rename %s %s called\n", name, name2); */
  680.     rename(name, name2);
  681.     break;
  682.     case 24:    /* return login vector */
  683.     z80regs.af = z80regs.hl = 1;    /* only A: online */
  684.     break;
  685.     case 25:    /* return current disk */
  686.     z80regs.af = z80regs.hl = 0;    /* only A: */
  687.     break;
  688.     case 29:    /* return r/o vector */
  689.     z80regs.af = z80regs.hl = 0;    /* none r/o */
  690.     break;
  691.     case 33:    /* read random record */
  692.     fp = getfp(z80regs.de);
  693.     /* printf("data is %02x %02x %02x\n", z80mem[z80regs.de+33],
  694.            z80mem[z80regs.de+34], z80mem[z80regs.de+35]); */
  695.     fseek(fp, ADDRESS, SEEK_SET);
  696.     goto readseq;
  697.     case 34:    /* write random record */
  698.     fp = getfp(z80regs.de);
  699.     /* printf("data is %02x %02x %02x\n", z80mem[z80regs.de+33],
  700.            z80mem[z80regs.de+34], z80mem[z80regs.de+35]); */
  701.     fseek(fp, ADDRESS, SEEK_SET);
  702.     goto writeseq;
  703.     case 35:    /* compute file size */
  704.     fp = getfp(z80regs.de);
  705.     fseek(fp, 0L, SEEK_END);
  706.     /* fall through */
  707.     case 36:    /* set random record */
  708.     fp = getfp(z80regs.de);
  709.     {   long pos;
  710.         pos = ftell(fp) >> 7;
  711.         z80regs.af = z80regs.hl = 0x00;    /* dunno, if necessary */
  712.         z80mem[z80regs.de+21] = pos & 0xff;
  713.         z80mem[z80regs.de+22] = pos >> 8;
  714.         z80mem[z80regs.de+23] = pos >> 16;
  715.     }
  716.     break;
  717.     case 41:
  718.     for (s = z80mem+z80regs.de; *s; ++s)
  719.         *s = tolower(*s);
  720.     z80regs.af = z80regs.hl = 
  721.         restricted_mode || chdir(z80mem+z80regs.de) ? 0xff : 0x00;
  722.     break;
  723.     default:
  724.     printf("\n\nUnrecognized BDOS-Function:\n");
  725.     printf("AF=%04x  BC=%04x  DE=%04x  HL=%04x  SP=%04x\nStack =",
  726.            z80regs.af, z80regs.bc, z80regs.de, z80regs.hl, z80regs.sp);
  727.     for (i = 0; i < 8; ++i)
  728.         printf(" %4x", z80mem[z80regs.sp+2*i]
  729.            + 256 * z80mem[z80regs.sp+2*i+1]);
  730.     printf("\n");
  731.     exit(1);
  732.     }
  733.     z80mem[z80regs.pc=DIRBUF-1] = 0xc9;
  734.     return;
  735. }
  736.