home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
2
/
2037
/
upm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-28
|
7KB
|
321 lines
/*
up/m - unix CP/M.
(C) MCMXC - Nick Sayer - All rights reserved.
See COPYRIGHT file for more details.
Configuration section.
CPM_FILE - default file with CP/M HEX images.
Addresses 0-2K are CCP, 2K-5.5K - BDOS. 5.5K-16K - BIOS. Address 65535
will have the length (in pages) of CP/M.
Addresses 16K-? - relocation bitmap. Each bit in the bitmap represents
a BYTE in 0-16K. If the bit is 1, the high byte of the first address of
the destination address for the CCP should be added to the byte in 0-16K
image. That image is then moved to the proper location. The PC is set to
32K and the Z-80 starts running. The high byte of the first byte of the
CCP destination address is gotten from address 65535. This value is
then adjusted if CP/M is to be relocated lower than the default
top of memory. The CP/M image to load should have a resident run address
before relocation of 0.
*/
#define CPM_FILE "CPM"
#include <strings.h>
#include <ctype.h>
#include <sgtty.h>
#include <signal.h>
#include "upm.h"
WORD topmem=256; /* These may be changed by arguments */
char *cpm_file=CPM_FILE;
struct sgttyb tty_sgtty_data;
static BYTE dph[32]={
/* Disk Paramater Header (diskbufs[]) */
0x00,0x00, /* TRANSTABLE unused */
0x00,0x00, /* unused */
0x00,0x00,
0x00,0x00,
0x80,0xff, /* DIRBUF - patch with topmem-1 later */
0x10,0xff, /* DPB - patch with OUR page no. */
0x00,0x00, /* CHKVEC - not used */
0x20,0xff, /* ALLOCVEC - patch with OUR page no. */
/* Disk Paramater Block */
0x40,0x00, /* Sectors per track */
0x04, /* Block Shift */
0x0f, /* Block Mask */
0x00, /* Extent Mask */
0x00,0x10, /* Blocks on device - patch if variable size implemented */
0xff,0x01, /* Directory entries -1 */
0xff,0x00, /* Allocation masks for directory */
0x00,0x00, /* Check vector size - patch if checkvecs implemented */
0x00,0x00, /* offset to first user-track */
0x00 /* spare */
};
/* These are externs in upm.h, but they have to be declared somewhere. */
FILE *disks[16],*devices[5];
WORD diskbufs[16];
BYTE ccp_image[SIZE_CCP_IMAGE];
WORD ccp_start;
/*
relocade(address);
BYTE address;
Relocate CP/M image at 0000-4000 using bitmap at 4000-4800.
Copy image to new location, and copy first 5.5K to ccp_image[];
Stop if we get to the top of RAM.
*/
relocate(add,len)
BYTE add;
{
WORD i;
for (i=0;i!=(256*len);i++)
{
if ( real_z80_mem[16384+(i>>3)]&(1<<(i&7)) )
real_z80_mem[i]=real_z80_mem[i]+add;
real_z80_mem[i+(add<<8)]=real_z80_mem[i];
if (i<SIZE_CCP_IMAGE)
ccp_image[i]=real_z80_mem[i];
}
}
int debugflag = 0;
int dlogflag = 0;
debugit();
main(argc,argv)
int argc;
char **argv;
{
FILE *cpm;
char line[80];
int i;
signal(SIGINT,debugit);
for(i=0;i<16;i++)
{
disks[i]=NULL;
devices[i%5]=NULL; /* hack: only do 0-4 */
}
/* OPEN ~/.upmrc, send each line to process_args(line); */
argc--; argv++;
for(;argc--;argv++)
process_args(*argv);
if (disks[0]==NULL)
{
printf("A: must be assigned.\n");
exit(0);
}
/*
For each non-null pointer in disks[], lower topmem, and save the pointer
to diskbufs[]. This assigns space for the allocation vector, and the
DPH/DPB. Then copy in a "standard" DPH/DPB into the bottom. We'll
patch it later.
We really should allow disks to be sized at runtime, but for now
they're fixed at 8MB, so we lower topmem 3 for each one. 2 pages
for the alloc table, another page (actually 32 bytes)
for the miscelany.
*/
for(i=0;i!=16;i++)
{
char j;
if (disks[i]==NULL)
continue;
topmem-=3;
diskbufs[i]=topmem<<8;
for(j=0;j!=32;j++)
real_z80_mem[diskbufs[i]+j]=dph[j];
real_z80_mem[diskbufs[i]+0x0b]=real_z80_mem[diskbufs[i]+0x0f]=topmem;
}
/*
Now for each non-null disk[] readjust the dirbuf pointer.
We couldn't do it before because we didn't have a final
location for dirbuf. topmem-1 is the high-byte of the
final location for dirbuf. the low byte is 0x80.
This page of memory is shared with the BIOS "jump" table.
*/
for(i=0;i!=16;i++)
{
if (disks[i]==NULL)
continue;
real_z80_mem[diskbufs[i]+9]=topmem-1;
}
cpm=fopen(cpm_file,"r");
if (cpm==NULL)
{
printf("Can't open CP/M binaries: %s\n",sys_errlist[errno]);
exit(1);
}
loadhex(cpm);
ccp_start=(topmem-real_z80_mem[65535])<<8;
relocate(topmem-real_z80_mem[65535],real_z80_mem[65535]);
PC=0x8000;
/*
Now set up the terminal. Just toggling RAW should be enough.
*/
gtty(fileno(stdin),&tty_sgtty_data);
tty_sgtty_data.sg_flags|=RAW;
tty_sgtty_data.sg_flags&=~ECHO;
stty(fileno(stdin),&tty_sgtty_data);
do
{ z80_run();
if(debugflag>1 && debugit()) PC++;
else if(bios()) break;
} while(1); /* } while(!bios()); */
gtty(fileno(stdin),&tty_sgtty_data);
tty_sgtty_data.sg_flags&=~RAW;
tty_sgtty_data.sg_flags|=ECHO;
stty(fileno(stdin),&tty_sgtty_data);
}
/*
The arguments can include A:file-O:file, {TY, LP, PT, U1, U2}:file,
mem:0-128.
Disk files are fopen()ed "r+", and are assigned to disks[].
Device files are fopen()ed "r+" and are assigned to devices[], except
for LP:, which is fopen()ed "w".
The value after mem: lowers the top of memory by that many pages (256
bytes) to save space for things like BYE, etc.
The arguments MUST be stripped of white-spaces.
*/
process_args(arg)
char *arg;
{
char i,left[80],*right;
if (index(arg,':')==NULL)
{
printf("Missing ':' in argument.\n");
return;
}
strcpy(left,arg);
right=index(left,':')+1;
*index(left,':')='\0';
for(i=0;i!=strlen(left);i++)
if (islower(left[i]))
left[i]=toupper(left[i]);
if (strlen(left)==1 && (*left<='O') && (*left>='A'))
{
disks[*left-'A']=fopen(right,"r+");
return;
}
if (!strcmp(left,"MEM"))
{
topmem-=atoi(right);
return;
}
if (!strcmp(left,"TY"))
{
devices[F_TY]=fopen(right,"r+");
return;
}
if (!strcmp(left,"PT"))
{
devices[F_PT]=fopen(right,"r+");
return;
}
if (!strcmp(left,"LP"))
{
devices[F_LP]=fopen(right,"w");
return;
}
if (!strcmp(left,"U1"))
{
devices[F_U1]=fopen(right,"r+");
return;
}
if (!strcmp(left,"U2"))
{
devices[F_U2]=fopen(right,"r+");
return;
}
if (!strcmp(left,"DEBUG"))
{
debugflag=atoi(right);
return;
}
if (!strcmp(left,"DLOG"))
{
dlogflag=atoi(right);
return;
}
if (!strcmp(left,"BIOS"))
{
biosflag=atoi(right);
return;
}
if (!strcmp(left,"TRAP"))
{
sscanf(right,"%4x",&TRAPval);
return;
}
if (!strcmp(left,"TWRT"))
{
sscanf(right,"%4x",&TWRTval);
return;
}
}
coredump()
{
FILE *qb;
int i;
qb=fopen("mem","w");
for(i=0;i!=65536;i++)
putc(real_z80_mem[i],qb);
fclose(qb);
}