ain@j.cc.purdue.edu (Patrick White) (01/10/88)
Program Name: pstransformer Submitted By: Phil Staub <phils@tekig.tek.com> Summary: This is a replacement for the file "transformer" on the transformer disk. It solves the problem with extended memory among other things. Poster Boy: Pat White (ain@j.cc.purdue.edu) Untested. NOTES: Untested. -- Pat White (co-moderator comp.sources/binaries.amiga) UUCP: j.cc.purdue.edu!ain BITNET: PATWHITE@PURCCVM PHONE: (317) 743-8421 U.S. Mail: 320 Brown St. apt. 406, West Lafayette, IN 47906 ======================================== # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # PSTransformer.doc # PSTransformer.c # privhndlr.asm # start.asm # makefile # This archive created: Thu Dec 17 23:01:12 1987 cat << \SHAR_EOF > PSTransformer.doc PSTransformer Version 1.0 Q: What is PSTransformer? A: PSTransformer is a replacement for the file called "Transformer" on the AmigaTransformer distribution disk. It is distributed in source and binary form in hopes of maximum distribution. Q: Why should I use PSTransformer? A: AmigaTransformer, as distributed, has 3 major problems. 1. It only works with version 1.1 of AmigaDos. 2. It does not support expanded memory. 3. It does not work if you have replaced your 68000 microprocessor with a 68010 or 68020. PSTransformer attempts to solve these problems (and I hope is successful in doing so. Early results seem to indicate it will work in far more cases than my original posting). A little history. (Not for the feint of heart) I made an earlier attempt to correct the first of these problems. At that time I didn't have either expanded memory or a 68010/020, so I was satisfied with just making it work on 1.2. I posted that fix as ATPatch nearly a year ago. Unfortunately, ATPatch made Transformer as specific to version 1.2 as it originally was to 1.1. Also, neither of the other problems went away. So, I set out to see what I could do to extend the function of the original patch to fix the other problems. Back in August, some of you may recall that I sent out a request for beta testers for a new version which hopefully would do just that. Having only the expansion memory which comes when you install the CMI KickStart Eliminator, (which is not auto-config) I felt it necessary to test it with some other configurations to see if it worked. Unfortunately, the answer was "no". Back to the drawing board. Why didn't it work? I tried several things, and eventually reached the following conclusion. Transformer causes a "reset" instruction to be executed, to free up all of the memory except that which is absolutely needed by the basic services of the OS. This is because at the time Transformer was written, expansion memory was either a) not widely available, and b) not auto-config. To make sure that as few processes as possible are started up, thus using memory which otherwise is available for DOS to use, a cool start vector is inserted which intercepts the boot-up sequence, apparently before auto-config memory has been enabled. Before the reset, Transformer makes a list of all free memory, so that it can re-build the free list when it gets control as a result of the cool reset. This works fine as long as memory is really at the addresses in the free list before the reset. However, reset causes auto-config memory boards to become un-configured. Thus, the memory which we expect to be there, isn't. What options are there? Well, the first one was to find a way to re- configure the auto-config memory. I was all for that one at first. Unfortunately, not having the 1.2 native developer update with auto-docs, and somehow not finding a way to spring free enough cash to get same, I couldn't determine if there was a way to do it with an exec or expansion library call. And there simply wasn't enough room to patch in a routine of my own to get the job done. Besides, remember I don't have any auto-config expansion memory to try it on. Any debugging of such a thing would have to be done by shipping a copy off to someone with some expansion ram to have him/her try it, making the "test" phase of the edit-compile-test-debug-edit cycle unacceptably long. So I started searching for some other options. Finally, I began to wonder if the reason for the reset was almost exclusively for the purpose of freeing up memory. If so, I felt that, with the availability of extra memory these days being what it is, perhaps all I needed to do was to allocate memory out of what is available, up to the 640K that MSDOS allows. Lo and behold, this was the key! Since a reset would never be executed, auto-config memory would still be available. The only possible negative aspect here is users with minimum memory will not get as much memory for DOS use as would be possible when the reset is used. I strongly suspect that this will become less and less of a problem as a greater and greater percentage of Amiga owners have expanded memory. Now, how to patch this into the Transformer emulator? I soon decided that it would probably require more effort that the method I finally settled on: a replacement startup module. Q: How does PSTransformer work? A: Basically, the original program "Transformer" was nothing more than a way to load the emulator, overlay the preferences from the ATPREFS file, then branch to the beginning of the segment containing the emulator. Memory allocation, the cool reset vector handler, and the reset stuff were all in the emulator program. (Not to mention some nasty stuff re-initializing some of the resources). The intent of PSTransformer is to bypass the early phases of the emulator startup, entering (with registers set appropriately) at some convenient point after all the mess previously pertaining to the reset is over. PSTransformer now handles memory allocation in the startup module, as well as overlaying the preferences. It also inserts a special priviledged instruction handler inspired by Scott Turner's DeciGel program (Thanks Scott!!) to allow the use of 68010 (and hopefully 68020) processors. Then it branches off to a routine which sets up the registers with emulator code, emulator data, and DOS workspace addresses and sizes, then enters the emulator. And away we go. One other thing: I do something similar to what "FixHunk" does to ensure that the emulator loads into CHIP ram. I found out the hard way that it must be there for MS-DOS to read 720K formatted disks in the outboard drives. I don't understand why this is, and I'm not *that* anxious to find out. Q: How do I use PSTransformer? A: PSTransformer can be used from either WorkBench or CLI. First, of course, is to use a *copy* (not your original) AmigaTransformer disk. To use it from CLI, just put it on that disk, in the same directory as "Transformer", "AT1" and "ATPREFS". Then type "PSTransformer". I haven't provided an Icon to use from WorkBench. (This may sound silly, but I've never made one! Kind of tells you how often I use WorkBench, doesn't it?) I would recommend that you either use the one that's already there, renaming either the Icon or PSTransformer (no, I don't mind if you rename my work), or build one yourself. Q: How can I re-build the source? A: PSTransformer was compiled, assembled and linked with the Manx 3.40b package. A makefile is provided. Q: Are there any problems with PSTransformer? A: The question is bound to come up: "Does PSTransformer work on the 500/2000?" The answer is: "I'm not sure." I've got a report that DOS boots on a 2000, but then the keyboard is locked out. I don't understand why. Perhaps that's one you 2000 hotshots can find for me. As for the 500, I have no data. Unfortunately, you don't get as much DOS ram available in a minimum configuration (read: no expansion ram) as you used to. My suggestion here is to set up an extremely stripped down bootable disk and put the Transformer stuff on it. I mean *really* stripped down. Q: What about future versions? A: I'm willing to support PSTransformer, if necessary, until (if?) the fixes are found for the suspected 2000 bug I mentioned above. Beyond that, I'd have to see what kinds of support folks feel is necessary. This project has taken up a major portion of my hacking time for a good many months now, and, quite frankly, I'm tired of it, and I want to do something else. Maybe I'll feel differently after a while. Q: How about distribution? A: I hereby grant authority for anyone to distribute this program in source and/or binary form. Period. I would appreciate getting credit for my efforts, but since I'm distributing the source, there's not a lot I can do to prevent you from removing my name. All I can say is to ask you to please not do so. In light of the questionable status of so called "copyrighted public domain" software, I'm not putting any restrictions whatsoever on this. At least not for this version. Consider it my Christmas gift to all those on Usenet who have provided me (sometimes without their knowledge) with a *lot* of information and wonderful programs. If you have other questions or comments, you can reach me at: phils@tekigm2.TEK.COM or my work or home address/phone: Phil Staub Home: 14805 NE 77th St. Vancouver, Washington 98682 (206) 254-9754 Office: Tektronix, Inc. Accessories Engineering P.O. Box 3500, M/S C1-904 Vancouver, Washington 98668 (206) 253-5499 SHAR_EOF cat << \SHAR_EOF > PSTransformer.c #include <stdio.h> #include <libraries/dos.h> #include <hardware/custom.h> #include <hardware/dmabits.h> #include <exec/types.h> #include <exec/memory.h> #include <exec/execbase.h> #include <functions.h> #include <exec/lists.h> #include <graphics/gfxmacros.h> #define PREFERENCES_OFFSET 0x2 /* offset to an index to PREFS */ #define EMULATOR_ENTRY_POINT 0x298 /* actual start of the emulator */ #define DOSSIZE_OFFSET 0x3b /* offset into ATPREFS for dossize */ #define PRIVHNDLRSIZE 0x38 #define DATASIZE 0xa3ce #define HUNK_CODE 0x3e9L char *em = 0; /* pointer to loaded emulator code */ struct Segment *em_seg = 0; /* pointer to loaded emulator segment */ char *text = 0; /* pointer to emulator text */ char *data = 0; /* pointer to emulator data */ char *dos = 0; /* pointer to area for dos */ char *total_chip = 0; /* pointer to a temp area for sizing */ long tsize; /* amount of memory for emulator text */ long dsize = DATASIZE; /* amount of memory for emulator data */ long dossize; /* amount of memory allocated to dos */ long totalsize; /* total text+data */ long fsize; /* amount of available fast memory */ long csize; /* amount of available chip memory */ long size; /* larger of free chip or fast mem */ long tattributes; /* AllocMem attributes for emulator text */ long dattributes; /* AllocMem attributes for user DOS space */ long preferences_offset; /* offset to data area for ATPREFS */ long dossize_offset; /* offset to ATPREFS requested dos size */ int preferences_loaded; /* flag to indicate that we read ATPREFS */ struct FileHandle *handle = 0; /* file handle, general use */ char pref_buf[200]; /* buffer to hold preferences data */ extern struct ExecBase *SysBase; main() { /* The declaration for PrivHndlr should really be a * function returning void, but we declare it this way because * we are copying the routine into a new place in RAM. */ extern char PrivHndlr[]; extern int startup_text(); char s[10]; /* input buffer for testing for abort */ /* The first thing we have to do is to ensure that the emulator * loads into chip ram. This *could* have been done by * running "FixHunk" on the AT1 file, but since some people * don't have that, we achieve the same result by writing 0x40 at * an offset of 0x14 bytes from the start of the file. This sets * bit 30 of the hunk size longword. * * See page 283 of the Bantam AmigaDOS reference manual for more * details. */ handle = Open("AT1",(long)MODE_OLDFILE); if (!handle) errexit("Can't find AT1"); if (Seek(handle,(long)0x14,(long)OFFSET_BEGINNING) == -1) errexit("File Seek error: AT1"); /* we use the preferences buffer to hold the value to insert */ pref_buf[0] = (char)0x40; if (Write(handle, &pref_buf[0], (long)1) == -1) errexit("File Write error: AT1"); /* Now seek to the size of the text segment. */ if (Seek(handle,(long)0x1c,(long)OFFSET_BEGINNING) == -1) errexit("File Seek error: AT1"); /* See how big the text segment is. Use tsize as a 4 byte buffer, * and read 4 bytes. This is the size of the segment in long * words. Adjust for a byte count, and add 8 bytes * fudge factor for the segment overhead. (Size and * pointer to next) */ if (Read(handle,&tsize,(long)sizeof(long)) == -1) errexit("File Read error: AT1"); Close(handle); handle = 0; tsize = (tsize << 2) + 8; /* 8 bytes for segment overhead */ /* Read the default Transformer preferences from ATPREFS */ handle = Open("ATPREFS",(long)MODE_OLDFILE); if (!handle) { printf("Can't find ATPREFS. Using Default values.\n"); dossize = 640 * 1024; preferences_loaded = 0; } else { Read(handle,pref_buf,200L); Close(handle); handle = 0; preferences_loaded = 1; /* see how much DOS space the user has requested */ dossize = 1024 * (((pref_buf[DOSSIZE_OFFSET] & 0xff) << 8) + (pref_buf[DOSSIZE_OFFSET+1] & 0xff)) + 62; } /* We don't allow interruptions from now on from other tasks */ Forbid(); /* make an unreasonably large memory allocation request to * flush any libraries out which are no longer in use. */ (void)AllocMem(0x1000000L, (long)MEMF_CHIP); (void)AllocMem(0x1000000L, (long)MEMF_FAST); /* We have to determine how much free memory we will * have available for DOS. We need dsize + tsize bytes in * CHIP ram. Once that's obtained, we attempt to allocate the * amount of memory requested in ATPREFS for DOS. This can be * in either CHIP or FAST ram, depending on which we have more of. */ tsize = (tsize + 7) & ~7; /* round up to 8 byte boundary */ dsize = (dsize + 7) & ~7; /* round up to 8 byte boundary */ totalsize = tsize+dsize; /* allocate all we would need for both chip and text areas */ total_chip = AllocMem(totalsize, (long)(MEMF_CHIP|MEMF_PUBLIC)); /* we now need to see how much we have available for DOS */ fsize = AvailMem((long)(MEMF_FAST|MEMF_LARGEST)) & ~07; csize = AvailMem((long)(MEMF_CHIP|MEMF_LARGEST)) & ~07; /* have to leave some chip ram for display use */ csize -= 2048; /* If we have more FAST memory than we asked for for DOS use, * or if we have more free FAST memory than CHIP, use FAST * for DOS. Otherwise use CHIP. */ if ((fsize >= dossize) || (fsize >= csize)) { dattributes = MEMF_FAST|MEMF_PUBLIC; size = fsize; } else { dattributes = MEMF_CHIP|MEMF_PUBLIC; size = csize; } /* Free up the chunk we allocated above. We only allocated * it to determine how much ram we would have left after * allocation of space for emulator text and data. */ FreeMem(total_chip, totalsize); total_chip = NULL; /* Load the emulator segment */ em_seg = LoadSeg("AT1"); if (!em_seg) errexit("Can't load Emulator"); /* Convert the BPTR to the loaded segment to a pointer, * then increment it past the pointer to the "next" segment. */ em = (char *)BADDR(em_seg) + 4; /* If we were able to read ATPREFS, copy the preferences into * the appropriate place in the text area. */ if (preferences_loaded) { preferences_offset = *((long *)(&em[PREFERENCES_OFFSET])); movmem(pref_buf,&em[preferences_offset],(long)200); } /* We install a modified version of Scott Turner's DeciGel * program, which allows us to use a 68010 or 68020 processor. */ movmem(&PrivHndlr[0], &em[EMULATOR_ENTRY_POINT-PRIVHNDLRSIZE], (long)PRIVHNDLRSIZE); /* 'text' needs to point to the start of the emulator. */ text = &em[EMULATOR_ENTRY_POINT]; /* now get some space for the emulator data */ data = AllocMem(dsize, (long)MEMF_CHIP|MEMF_PUBLIC); if (!data) errexit("Can't get RAM for Emulator data\n"); /* We'll only get the lesser of 'dossize' or 'size' ramspace * for DOS. */ dossize = (dossize < size) ? dossize : size; dos = AllocMem(dossize,dattributes); /* Show us where we've allocated memory and how much of it there * is. Also, a little ego boosting here. */ printf("\nPSTransformer, Version 1.0, 12/17/87 by Phil Staub\n\n"); printf("Startup module for AmigaTransformer to provide support "); printf("for extended memory,\n"); printf("68010/68020, and multiple operating system versions.\n\n"); printf("\nAmigaTransformer Memory allocations\n"); printf("Emulator code : %10ld bytes at %08lx\n", tsize, text); printf("Emulator data : %10ld bytes at %08lx\n", dsize, data); printf("DOS User Space: %10ld bytes at %08lx\n\n", dossize, dos); /* now offer the chance to bail out */ printf("Continue? [y/n] "); gets(&s[0]); if (s[0] == 'n' || s[0] == 'N') errexit("AmigaTransformer exiting\n"); OFF_SPRITE; /* don't need the mouse pointer */ OFF_DISPLAY; /* turn off the display dma */ /* now branch off to an assembly language routine which * installs the Privileged instruction handler, sets up the * registers the way the emulator wants them, then starts the * emulator. */ startup_text(); } errexit(s) char *s; { printf("%s\n",s); if (em_seg) (void)UnLoadSeg((struct Segment *)em_seg); if (total_chip) FreeMem(total_chip, totalsize); if (data) FreeMem(data, dsize); if (dos) FreeMem(dos, dossize); if (handle) Close(handle); Permit(); exit(1); } SHAR_EOF cat << \SHAR_EOF > privhndlr.asm far code far data public _PrivHndlr PrivVect equ $20 ; Address of Privlege error vector ; ; This installs a handler for privilege violations ; caused when a 68010 executes a "move sr,ea" instruction ; in user mode. ; ; It was inspired by Scott Turner's "DeciGEL" program. ; ; ; code to handle move sr,ea instructions. this actually modifies ; code in place to a MOVE CCR,ea instruction, thus it is NO GOOD ; at all for code in ROM. (So big deal, eh?) ; _PrivHndlr: movem.l D0/A0,-(SP) ; Save registers move.l 10(SP),A0 ; Pointer to opcode move.w (A0),D0 ; Pickup opcode andi.w #$ffc0,D0 ; Mask out EA field cmpi.w #$40C0,D0 ; Is it a MOVE SR,ea? bne ReallyIllegal bset #1,(A0) ; Convert it to MOVE CCR,ea movem.l (sp)+,d0/a0 ; restore regs rte ; Rerun new opcode ReallyIllegal: movem.l (sp)+,d0/a0 ; restore regs Prev: jmp $FC0000 ; To previous handler, patched on ; installation of new handler ; ; This is where we branch to start up Transformer Emu_Start: lea Prev+2(pc),a0 ;save pointer to old handler move.l PrivVect,(a0) lea _PrivHndlr(pc),a0 ;install new vector move.l a0,PrivVect ; ; We fall through to the beginning of the Transformer here ; end SHAR_EOF cat << \SHAR_EOF > start.asm ; ; start.asm - setup the starting condition of the registers ; for AmigaTransformer. ; ; ; We have the emulator copied into it's final resting position ; and now we have to set up some of the registers as the emulator ; expects to find them. ; ; a3 base of emulator text area (_text) ; a4 base of emulator data area (_data) ; a5 base of MS-DOS user area (_dos) ; ; d2 amount of data area used for emulator (_dsize) ; d3 amount of text area used for emulator (_tsize) ; d7 size of MS-DOS area (_dossize) ; xdef _startup_text xdef _movmem xref _text xref _data xref _dos xref _dsize xref _tsize xref _dossize PRIVHNDLRSIZE equ $38 INSTALLERSIZE equ $10 cseg _startup_text move.l _text,a3 move.l _data,a4 move.l _dos,a5 move.l _dsize,d2 move.l _tsize,d3 move.l _dossize,d7 ; We actually start by branching off to the code to install ; the privileged instruction handler. jmp -INSTALLERSIZE(a3) ; ; movmem - move memory ; ; correctly handles overlapped moves ; _movmem movem.l 4(sp),a0/a1 move.l 12(sp),d0 ;fetch parameters cmp.l a0,a1 ;see which direction to move beq.s movend ; or if no move is necessary bls forward add.l d0,a0 ;move tail to tail add.l d0,a1 reverse move.b -(a0),-(a1) subq.l #1,d0 bne reverse movend rts ; forward ;move head to head move.b (a0)+,(a1)+ subq.l #1,d0 bne forward rts end SHAR_EOF cat << \SHAR_EOF > makefile OBJS = PSTransformer.o privhndlr.o start.o AFLAGS = -cd CFLAGS = +p .asm.o: as $(AFLAGS) -o $@ $*.asm PSTransformer: $(OBJS) ln +c $(OBJS) -o PSTransformer -lcl32 SHAR_EOF # End of shell archive exit 0