|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 7111 (0x1bc7)
Types: TextFile
Notes: UNIX file
Names: »commodore.old«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦2d53db1df⟧ UNIX Filesystem
└─⟦this⟧ »sys/z8001/src/commodore.old«
/*
* Coherent.
* Machine dependent routines for the Commodore
* M-series Z8001 processor running in
* Segmented mode.
*/
#include <coherent.h>
#include <clist.h>
#include <errno.h>
#include <inode.h>
#include <proc.h>
#include <seg.h>
#include <signal.h>
#include <uproc.h>
#include <romconf.h>
#include <alloc.h>
struct romconf romconf;
char *_bvirt;
/*
* General initialisation.
* Setup pointers to most data structures.
*/
commodore()
{
register vaddr_t p, p1;
extern char end, etext;
register unsigned e, et;
register char *t;
/*
* Segment 1 is ROM DS.
* It contains the romconf structure
* at offset of 0.
*/
t = ADDR(1, 0);
t = *(int **)t;
kkcopy(t, &romconf, sizeof romconf);
#if !K1
/*
* All ROMs now assume 1K segment size.
*/
romconf.rom_bram <<= 1;
romconf.rom_eram <<= 1;
#endif
corebot = romconf.rom_bram;
coretop = romconf.rom_eram;
/*
* Compute base of system (after Kernel Alloc Space).
* This base is in physical memory.
*/
t = &end;
e = t;
t = &etext;
et = t;
p1 = ctob((long)corebot);
p1 += bruc(et);
p1 += e;
p = bruc(p1+ALLSIZE);
allkp = setarena((char *)&end, asize = p-p1);
inodep = (INODE *)(&end + asize);
p += NINODE*sizeof(INODE);
if (e + asize + NINODE*sizeof(INODE) < e)
panic("System is too large");
p = (p + (long)(BSIZE-1)) & ~((long)(BSIZE-1));/* DMA needs aligned */
blockp = p;
_bvirt = pfix(BFS, p);
p += NBUF*BSIZE;
clistp = pfix(CLS, p);
p += NCLIST*sizeof(CLIST);
corebot = btocru(p);
msize = ctokrd(coretop-corebot);
}
/*
* Calculate segmentation for a new process.
* Segmented system has a separate (and only one)
* stack segment.
* Right now only separated (possibly) I/D (i.e.
* 2 segments.
*/
mproto()
{
register PROC *pp;
#if !NLD
register SEG *pi, *pd;
#else
register int sn;
register int i;
#endif
u.u_sproto.mp_nseg = 0;
pp = SELF;
if ((pp->p_flags & PFKERN) != 0) {
if (pp->p_segp[SIPTEXT] != NULL
|| pp->p_segp[SISTEXT] != NULL
|| pp->p_segp[SISDATA] != NULL
|| (pp->p_segp[SIPDATA]!=NULL && pp->p_segp[SIPDATA]->s_size>MSSIZE)) {
u.u_error = ENOEXEC;
return (0);
}
return (1);
}
#if !NLD
if (pp->p_segp[SISTEXT]!=NULL || pp->p_segp[SISDATA]!=NULL)
panic("Shared exec");
pd = pp->p_segp[SIPDATA];
if ((pi = pp->p_segp[SIPTEXT]) == NULL)
pi = pd; /* Non sep i/d */
if (uproto(pp->p_segp[SISTACK], USS, SISTACK)==0
|| uproto(pi, UIS, SIPTEXT)==0
|| uproto(pd, UDS, SIPDATA)==0)
return (0);
#else
sn = USTACK;
for (i=SISTACK; i<=SIPDATA; i++) {
if ((sn = uproto(pp->p_segp[i], sn, i)) == 0)
return (0);
if (i == SISTACK)
sn = USEG;
}
/*
* Handle shared libraries here -- USLIBP, USLIBS
*/
#endif
return (1);
}
/*
* Load up the segmentation hardware.
* Recalculate the prototype if necessary (after fork
* and swaps)
*/
segload()
{
if ((SELF->p_flags & (PFSPROTO|PFKERN)) != 0) {
if ((SELF->p_flags & PFKERN) != 0)
return;
sproto();
}
loadmmu(u.u_sproto.mp_nseg, &u.u_sproto.mp_hsegs[0]);
}
/*
* Set up segmentation for one segment.
* Returns the next available segment (or zero on error).
* `sp' is the segment pointer, `sn' is the hardware
* segment number at which to start and `si' is
* the index into Coherent's software segment table.
* The structure of this routine leaves something
* to be desired in clarity.
*/
static
uproto(sp, sn, si)
register SEG *sp;
register int sn;
int si;
{
register struct hsegs *hp;
register int f, l, hl;
register saddr_t b;
unsigned base;
/*
* Check here for unused segments.
*/
if (sp == NULL)
return (sn);
hp = &u.u_sproto.mp_hsegs[sn];
f = sp->s_flags&SFSHRX ? 0x01 : 0; /* read only? */
base = 0;
b = sp->s_mbase;
l = sp->s_size;
if ((sp->s_flags & SFDOWN) != 0) {
if (l >= MSSIZE-1)
return (0);
f |= 0x20; /* Downward growing segment */
hl = MSSIZE-l;
b -= hl;
base = ctob(hl);
}
b <<= CSH;
u.u_segl[si].sr_base = ADDR(sn, base);
while (l > 0) {
if (sn >= NHUSEG)
return (0);
if (l >= MSSIZE) {
printf("Large sproto, size=%u, sn=%d\n", l, sn);
hl = 0xFF; /* Full segment */
} else if ((sp->s_flags & SFDOWN) != 0)
hl = (MSSIZE-l)<<CSH;
else
hl = (l<<CSH)-1;
hp->mp_base = b;
b += 256;
hp->mp_len = hl;
hp->mp_attr = f;
sn++;
hp++;
l -= MSSIZE;
}
if (sn > u.u_sproto.mp_nseg)
u.u_sproto.mp_nseg = sn;
return (sn);
}
/*
* Copy `n' clicks from the segment base `s1' to `s2' from right to left.
*/
srlcopy(s1, s2, n)
register saddr_t s1;
register saddr_t s2;
register unsigned n;
{
if (n == 0)
return;
s1 += n;
s2 += n;
do {
slrcopy(--s1, --s2, 1);
} while (--n);
}
/*
* Set up initial context for a process running in kernel mode.
*/
msetsys(mp, f, m)
register MCON *mp;
int (*f)();
saddr_t m;
{
mp->mc_omap = m<<CSH;
mp->mc_sp = (char *)&u + UPASIZE-sizeof(f);
mp->mc_pc = f;
mp->mc_fcw = MFSYS|MFVIE|MFSEG;
mp->mc_depth = 1;
}
/*
* Set up a new user process.
*/
msetusr(pc, sp)
vaddr_t pc;
vaddr_t sp;
{
*((long *)(regl+OPC)) = pc;
if ((SELF->p_flags & PFKERN) != 0) {
regl[OFCW] |= MFSYS;
regl[OOS] = SELF->p_segp[SIPDATA]->s_mbase << CSH;
} else
*((long *)(regl+OR14)) = sp;
}
/*
* Set the given address in the user area to the given value if it is
* okay to do so.
*/
msetuof(a, v)
register int a;
register unsigned v;
{
a = -(UPASIZE - a)/2;
switch (a) {
case OR0:
case OR1:
case OR2:
case OR3:
case OR4:
case OR5:
case OR6:
case OR7:
case OR8:
case OR9:
case OR10:
case OR11:
case OR12:
case OR13:
case OR14:
case OR15:
case OPCSEG:
case OPCOFF:
regl[a] = v;
break;
case OFCW:
if ((v&~MFCCB) != 0)
return (0);
regl[OFCW] &= ~MFCCB;
regl[OFCW] |= v;
break;
default:
u.u_error = EINVAL;
return (0);
}
return (1);
}
/*
* Cause a signal routine to be executed.
*/
msigint(n, f)
register int n;
register int (*f)();
{
register int *usp;
usp = *(int **)®l[OR14];
putupd(--(int **)usp, *(int **)®l[OPC]);
putuwd(--usp, regl[OFCW]);
putuwd(--usp, n);
regl[OFCW] &= ~MFNVE;
*(int **)®l[OPC] = f;
*(int **)®l[OR14] = usp;
if (n!=SIGEPA && n!=SIGTRAP)
u.u_sfunc[n-1] = SIG_DFL;
}
/*
* Cause the next instruction to single step.
* Non-vectored interrupt enable signals assembler
* code to arm the single-step logic on return
* from this trap.
*/
msigsin()
{
regl[OFCW] |= MFNVE;
}
/*
* Idle process.
*/
idle()
{
for (;;) {
disflag = 1;
_idle();
}
}
/*
* Set an interrupt vector.
* Make an entry in the "vecs" table, for
* use by the interrupt dispatcher. No interrupt
* controller needs to be armed on this machine.
* Levels must be even on the z8001.
*/
setivec(level, fun)
register int level;
int (*fun)();
{
register vaddr_t t1, t2;
extern int (*vecs[])();
extern saddr_t vmaps[];
extern int vret();
level >>= 1;
t1 = (vaddr_t)vecs[level];
t2 = (vaddr_t)vret;
if ((unsigned)t1 != (unsigned)t2) {
u.u_error = EDBUSY;
return;
}
vecs[level] = fun;
vmaps[level] = omapget();
}
/*
* Clear an interrupt vector.
*/
clrivec(level)
register int level;
{
extern int (*vecs[])();
extern int vret();
level >>= 1;
vecs[level] = vret;
}