Syntax20b.Scn.Fnt ParcElems Alloc Syntax24b.Scn.Fnt Syntax10.Scn.Fnt Syntax10b.Scn.Fnt Syntax10i.Scn.Fnt FoldElems Syntax16.Scn.Fnt Syntax12.Scn.Fnt (* AMIGA *) MODULE Amiga; Data types, constants, variables, and procedures used to interface to the Amiga OS, and to link various high-level modules together. IMPORT SYSTEM, A:=AmigaAsl, D:=AmigaDos, E:=AmigaExec, G:=AmigaGraphics, I:=AmigaIntuition, U:=AmigaUtility, T:=AmigaTimer; CONST These default values are used, if no Oberon4Amiga environment variable was found. defaultHeight =800; defaultWidth = 1024; defaultDepth = 4; maxDepth = 8; The name of the environment variable used. envarcName is used for pre V39 AmigaOS, where the copy in the ENVARC: directory is not made automatically by SetEnv. envName = "Oberon4Amiga"; envarcName = "ENVARC:Oberon4Amiga"; The first value of the environment variable contains a version field. This is the current version. infoVersion = 6; pointerSize = 16*4; The title of the screen, and also the copyright notice appearing in the Log on system startup. screenTitle = "Oberon System V4 for Amiga V1.3"; TrapErr* = 0; ExceptionErr* = 1; SystemErr* = 2; (** values for ErrorFrame.type *) The sizes for the ChipMemPool PoolPuddleSize = 32768; PoolThreshSize = PoolPuddleSize DIV 2; Absolute=LONGINT; Module=LONGINT; NewProc*=PROCEDURE(tag:LONGINT):LONGINT; The content of the environment varibale. Currently it is stored binary, as is. All but the version field contain values needed for opening the initial screen. Info=RECORD version:LONGINT; displayID:LONGINT; height:INTEGER; width:INTEGER; depth:INTEGER; oscan:LONGINT; autoScroll:BOOLEAN; useWBWindow: BOOLEAN; modifyColors: BOOLEAN END; Real pointers declarations. The Amiga* modules only export these pointer types as LONGINT, to avoid problems with the garbage collection. ProcessPtr=POINTER TO D.Process; ScreenPtr=POINTER TO I.Screen; WindowPtr=POINTER TO I.Window; BitmapPtr=POINTER TO G.BitMap; RPPtr=POINTER TO G.RastPort; IOExtTimerPtr = POINTER TO T.TimeRequest; This is the Amiga specific way to store an Oberon pattern. PatternInfoPtr*= POINTER TO PatternInfo; PatternInfo*= RECORD modulo*: INTEGER; w*, h*: SHORTINT; data*: LONGINT; (* Pointer to individual pattern in chip mem. This pointer is used for patterns and Oberon fonts. *) offset*: INTEGER; (* Offset to individual pattern in chip mem. This offset is used for Amiga fonts. *) END; characters are patterns with additional informations needed by the Display.GetChar routine. They are not part of Patterns, because they are of now use as soon, as the character was "transformed" into a simple pattern by Display.GetChar. CharInfo*=RECORD (PatternInfo) (* Font related character info *) dx*, x*, y*: SHORTINT END; This is the Amiga specific representation of a font. Data and size point to a contiguos memory block which contains all character data (as they are build by the diskfont.library). Font*= POINTER TO FontInfo; FontInfo*= RECORD data*: LONGINT; (* Pointer to character data block in chip mem. *) size*: LONGINT; (* size of data block *) info*: ARRAY 256 OF CharInfo; amigaFont*: G.TextFontPtr; END; This contains the information needed as starting point to build a trap viewer. ErrorFrame*= RECORD PC-: LONGINT; (** PC value *) SP-: LONGINT; (** Stack Pointer *) FP-: LONGINT; (** Frame Pointer *) type-: LONGINT; (** type of error: TrapErr, ExceptionErr, SystemErr, 3 = Assertion, 4 = BreakPoint, 5 = Explicit *) val-: LONGINT (** type = TrapErr => trap number; type = ExceptionErr => exception mask (SET) *) END; Through this procedure variables, the routines from OLoad are called. For this to work, OLoad will patch in the address of a procedure into this variable. This can obviously work only, if the offset in memory of this variable is known. Therefore it is VERY IMPORTANT, that these variables remains the first declared variables in the module, and thus start at offset -4. The two guard variables are filled with some predefined values by OLoad so that on module initialisation it can be verifyed, if the variables have moved in respect to what OLoad expects . guard1:LONGINT; loaderCall:PROCEDURE(); guard2:LONGINT; These variables export the window and rast port which have to be used for the Oberon screen, as well as their dimensions. Depth-, OberonDepth-, ColorOffset-: INTEGER; Height-:INTEGER; Width-:INTEGER; window-: I.WindowPtr; WBWindow-: BOOLEAN; ModifyColors-: BOOLEAN; PensObtained: BOOLEAN; The next two variables allow the customization of two Amiga specific behaviours. dontConvert inhibits the conversion of ISO-Latin1-Input to the Oberon character set convention. This is needed, if an Latin1 document has to be edited. This variable is initialised to FALSE. useLAltAsMouse enables the usage of the left alt key as a replacement for a middle mouse button, when only a two button mouse is available. This variable is initialised to TRUE. dontConvert*:BOOLEAN; useLAltAsMouse*:BOOLEAN; This varible is initialised to the screen title. A read only variable is exported instead of the screenTitle constant, to avoid the generation of a new symbol file just because the string content has changed. version-:ARRAY 64 OF CHAR; idlePri*:SHORTINT; normalPri*:SHORTINT; This is the stack pointer to which the trap handler has to return. It is remembered in Amiga.Loop and used in ???. stackPtr-: LONGINT; thinks for the Timer Device TimerOpen*: BOOLEAN; TimerMP: E.MsgPortPtr; TimerIOPtr: E.MessagePtr; TicsToWait*: LONGINT; Name of the current printer. Will be send to the OberonPrint script PrinterName*: ARRAY 64 OF CHAR; Threshold for the Color of Pictures to be printed as white, 0<=n<=256 PictPrintThresh*: INTEGER; Define the Type of the Main Loop MainLoopType*: BOOLEAN; Pointer to Chip-Memory-Pool (used only if exeVersion>=39 ChipMemPool-: E.MemPoolPtr; Flag for the Requester of System.Quit UseQuitRequester*: BOOLEAN; Arrays for Character Conversion Amiga <-> Oberon AtoO, OtoA: ARRAY 256 OF CHAR; ??? oldProcessWindow:I.WindowPtr; screen:I.ScreenPtr; pointerData:LONGINT; Procedures of OLoad are called with register D3 containing the address of a variable of type CallData. The first long word of CallData contains a function code. The following long words contain parameters as requested by the specific function. Addresses are passed whenever a VAR parameter is requested. CallData=ARRAY 8 OF LONGINT; (* Close Timer Device *) PROCEDURE CloseTimerDevice; BEGIN IF TimerOpen THEN E.CloseDevice(TimerIOPtr) END; IF TimerIOPtr#0 THEN E.DeleteIORequest(TimerIOPtr) END; IF TimerMP#0 THEN E.DeleteMsgPort(TimerMP) END; TimerOpen:=FALSE; TimerMP:=0; TimerIOPtr:=0 END CloseTimerDevice; (* Open Timer Device *) PROCEDURE OpenTimerDevice; BEGIN IF ~TimerOpen THEN TimerMP:=E.CreateMsgPort(); IF TimerMP#0 THEN TimerIOPtr:=E.CreateIORequest(TimerMP, SIZE(T.TimeRequest)); IF TimerIOPtr#0 THEN IF E.OpenDevice(T.timerName, T.microHz, TimerIOPtr, {})=0 THEN TimerOpen:=TRUE END END END; IF ~TimerOpen THEN CloseTimerDevice() END END OpenTimerDevice; (* Wait sec and micro/1000000 seconds using Timer Device *) PROCEDURE WaitTime*(sec, micro: LONGINT); TimerIO: IOExtTimerPtr; r: SHORTINT; BEGIN TimerIO:=SYSTEM.VAL(IOExtTimerPtr, TimerIOPtr); TimerIO.command:=T.addRequest; TimerIO.time.secs:=sec; TimerIO.time.micro:=micro; r:=E.DoIO(TimerIOPtr) END WaitTime; PROCEDURE -SaveRegs 048H,0E7H,0FFH,0FEH,02AH,04EH; (* MOVEM D0-D7/A0-A6,-(A7) MOVEA.L A6,A5 *) PROCEDURE -LoadRegs 04CH,0DFH,07FH,0FFH; (* MOVEM.L (A7)+,D0-D7/A0-A6 *) PROCEDURE CallModula(VAR data:CallData); BEGIN SaveRegs; SYSTEM.PUTREG(3,SYSTEM.ADR(data)); loaderCall(); (* The code for this is in OLoad. *) LoadRegs END CallModula; PROCEDURE Allocate*(VAR adr:LONGINT; size:LONGINT); Allocates an Amiga OS memory block. Used by Kernel and Fonts. cd:CallData; BEGIN cd[0]:=7; cd[1]:=SYSTEM.ADR(adr); cd[2]:=size; CallModula(cd) END Allocate; PROCEDURE Assert*(cond:BOOLEAN; msg:ARRAY OF CHAR); Perform an Arts.Assert. cd:CallData; BEGIN cd[0]:=10; IF cond THEN cd[1]:=1 ELSE cd[1]:=0 END; cd[2]:=SYSTEM.ADR(msg); CallModula(cd) END Assert; PROCEDURE Deallocate*(adr:LONGINT; size:LONGINT); Deallocates an Amiga OS memory block. Used by Kernel and Fonts. cd:CallData; BEGIN cd[0]:=12; cd[1]:=adr; cd[2]:=size; CallModula(cd) END Deallocate; PROCEDURE GetSearchPath*(VAR searchPath: ARRAY OF CHAR); Returns the search path which the loader received as parameter. cd:CallData; BEGIN cd[0]:=17; cd[1]:=SYSTEM.ADR(searchPath); cd[2]:=LEN(searchPath); CallModula(cd) END GetSearchPath; PROCEDURE ThisMod*(name:ARRAY OF CHAR; VAR module:Module; VAR res:INTEGER; VAR modules:Module; VAR imported:ARRAY OF CHAR); With this routine, Modules.ThisMod accesses the loaders ThisMod instead of reimplementing it. cd:CallData; BEGIN cd[0]:=4; cd[1]:=SYSTEM.ADR(name); cd[2]:=SYSTEM.ADR(module); cd[3]:=SYSTEM.ADR(res); cd[4]:=SYSTEM.ADR(modules); cd[5]:=SYSTEM.ADR(imported); CallModula(cd) END ThisMod; PROCEDURE ThisCommand*(mod:Module; cmdname:ARRAY OF CHAR; VAR adr:Absolute; VAR res:INTEGER); With this routine, Modules.ThisCommand accesses the loaders ThisCommand instead of reimplementing it. cd:CallData; BEGIN cd[0]:=5; cd[1]:=mod; cd[2]:=SYSTEM.ADR(cmdname); cd[3]:=SYSTEM.ADR(adr); cd[4]:=SYSTEM.ADR(res); CallModula(cd) END ThisCommand; PROCEDURE Free*(name:ARRAY OF CHAR; all:BOOLEAN; VAR res:INTEGER; VAR modules:Module); With this routine, Modules.Free accesses the loaders Free instead of reimplementing it. cd:CallData; BEGIN cd[0]:=6; cd[1]:=SYSTEM.ADR(name); IF all THEN cd[2]:=1 ELSE cd[2]:=0 END; cd[3]:=SYSTEM.ADR(res); cd[4]:=SYSTEM.ADR(modules); CallModula(cd) END Free; PROCEDURE Terminate*(); Calls Arts.Terminate to bringdown Oberon. Show Requester bevor quitting, if Amiga.UseQuitRequester is TRUE. cd:CallData; BEGIN IF ~WBWindow THEN I.ClearPointer(window) END; IF (~UseQuitRequester) OR (I.CallEasyRequest(window, {}, "Oberon System V4 for Amiga", "Do you really want to quit ?","Yes|No")#0) THEN cd[0]:=3; CallModula(cd) END; IF ~WBWindow THEN I.SetPointer(window,pointerData,2,16,0,0) END; END Terminate; PROCEDURE InstallNew*(proc:NewProc); Passes the address of Kernel.SysNew to OLoad, so that it can use it to fixx all NEW references. cd:CallData; BEGIN cd[0]:=0; cd[1]:=SYSTEM.VAL(LONGINT,proc); CallModula(cd) END InstallNew; PROCEDURE InstallSysNew*(proc:NewProc); Passes the address of Kernel.SysNew to OLoad, so that it can use it to fixx all SYSTEM.NEW references. cd:CallData; BEGIN cd[0]:=1; cd[1]:=SYSTEM.VAL(LONGINT,proc); CallModula(cd) END InstallSysNew; PROCEDURE InstallModuleList*(modList:LONGINT); Passes the address of Kernel.module to OLoad, so that it can update it, whenever it is needed (ThisMod/Free). cd:CallData; BEGIN cd[0]:=13; cd[1]:=modList; CallModula(cd) END InstallModuleList; PROCEDURE TermProcedure*(proc:PROCEDURE); Passes the address of Kernel.FinalizeAll to OLoad, so that it can call it on termination. cd:CallData; BEGIN cd[0]:=8; cd[1]:=SYSTEM.VAL(LONGINT,proc); CallModula(cd) END TermProcedure; PROCEDURE InstallTrapHandler*(p: PROCEDURE); Installs trap handler in Arts.TrapStub cd:CallData; BEGIN cd[0]:=14; cd[1]:=SYSTEM.VAL(LONGINT,p); CallModula(cd) END InstallTrapHandler; PROCEDURE RestoreTrapHandler*; restores old trap handler in Arts.TrapStub cd:CallData; BEGIN cd[0]:=15; CallModula(cd) END RestoreTrapHandler; PROCEDURE GetErrorFrame*(VAR err: ErrorFrame); gets trap information from Arts.errorFrame cd:CallData; BEGIN cd[0]:=16; cd[1]:=SYSTEM.ADR(err); CallModula(cd) END GetErrorFrame; PROCEDURE SystemHere*; Tells loader, that system has come up to the point, that it can display itself any error messages. cd:CallData; BEGIN cd[0]:=18; CallModula(cd) END SystemHere; PROCEDURE Turbo*; Set task priority high. Used before starting a command. VAR task: E.TaskPtr; dummy: LONGINT; BEGIN task := E.FindTask(0); dummy := E.SetTaskPri(task, normalPri) END Turbo; PROCEDURE Idle*; Set task priority low. Used after a command finishes and Oberon.Loop resumes. VAR task: E.TaskPtr; dummy: LONGINT; BEGIN task := E.FindTask(0); dummy := E.SetTaskPri(task, idlePri) END Idle; PROCEDURE Close*; Free the custom (= blank) pointer sprite. Restore the original window in the process structure. Close Oberon window and screen. Free Chip-Mem-Pool. Close Timer Device proc:ProcessPtr; scr:ScreenPtr; win:WindowPtr; i: INTEGER; BEGIN IF pointerData#0 THEN I.ClearPointer(window); IF E.execVersion<39 THEN E.FreeMem(pointerData,pointerSize) END; pointerData:=0 END; IF oldProcessWindow#0 THEN proc:=SYSTEM.VAL(ProcessPtr,E.FindTask(0)); proc.windowPtr:=oldProcessWindow; oldProcessWindow:=0 END; win := SYSTEM.VAL(WindowPtr, window); scr := SYSTEM.VAL(ScreenPtr, screen); IF PensObtained THEN FOR i:=0 TO SHORT(ASH(1, OberonDepth))-1 DO G.ReleasePen(scr.viewPort.colorMap, i+ColorOffset) END; END; IF win#NIL THEN I.CloseWindow(window); win := NIL END; IF scr#NIL THEN I.CloseScreen(screen); scr := NIL END; window := SYSTEM.VAL(LONGINT, win); screen := SYSTEM.VAL(LONGINT, scr); IF ChipMemPool#0 THEN E.DeletePool(ChipMemPool) END; IF TimerOpen THEN CloseTimerDevice() END END Close; PROCEDURE GetDefaultMode(VAR info:Info; VAR fromEnv:BOOLEAN); Initialise info with the values from the environment. If this is not possible, use the default sizes, and the screen mode of the workbench screen (if available). fromEnv returns FALSE, if the environment wasn't found. key:LONGINT; len:LONGINT; scr:ScreenPtr; DosV36: BOOLEAN; BEGIN DosV36:=D.dosVersion<=37; (* docu said 36, but testing said 37 *) len:=D.GetVar(envName,SYSTEM.ADR(info),SIZE(Info),{D.globalOnly,D.binaryVar,D.dontNullTerm}); fromEnv:=((DosV36 & (len=SIZE(Info)-1)) OR ((~DosV36) & (len=SIZE(Info)))) & (info.version=infoVersion); IF ~fromEnv THEN scr:=SYSTEM.VAL(ScreenPtr,I.LockPubScreen(0)); IF scr#NIL THEN key:=G.GetVPModeID(SYSTEM.ADR(scr.viewPort)); I.UnlockPubScreen(0,SYSTEM.VAL(I.ScreenPtr,scr)) ELSE key:=G.hiresLaceKey END; info.version:=infoVersion; info.displayID:=key; info.width:=defaultWidth; info.height:=defaultHeight; info.depth:=defaultDepth; info.oscan:=I.oScanText; info.autoScroll:=TRUE; info.useWBWindow:=FALSE; info.modifyColors:=FALSE; END GetDefaultMode; PROCEDURE ReadScreenMode*(VAR displayID:LONGINT; VAR height, width, depth: INTEGER; VAR oscan:LONGINT; VAR autoScroll, WBWindow, PrivateColors: BOOLEAN); Read the environment variable, and extract from it all values needed for screen initialization. Use the default values, if the environment variable doesn't exist, or has a wrong version. dummy:BOOLEAN; info:Info; BEGIN GetDefaultMode(info,dummy); displayID:=info.displayID; width:=info.width; height:=info.height; depth:=info.depth; oscan:=info.oscan; autoScroll:=info.autoScroll; WBWindow:=info.useWBWindow; PrivateColors:=info.modifyColors; END ReadScreenMode; PROCEDURE WriteScreenMode*(displayID:LONGINT; height, width, depth: INTEGER; oscan:LONGINT; autoScroll, useWBWindow, modifyColors:BOOLEAN); Store the screen values into the environment variable. On pre 3.0 Amigas write them also to the envarc: files as SetVar won't do it for you. dummy:LONGINT; dummyB:BOOLEAN; f:D.FileHandlePtr; info:Info; BEGIN info.version:=infoVersion; info.displayID:=displayID; info.width:=width; info.height:=height; info.depth:=depth; info.oscan:=oscan; info.autoScroll:=autoScroll; info.useWBWindow:=useWBWindow; info.modifyColors:=modifyColors; dummyB:=D.SetVar( envName,SYSTEM.ADR(info),SIZE(Info),{D.globalOnly,D.saveVar,D.binaryVar,D.dontNullTerm} IF A.aslVersion<39 THEN f:=D.Open(envarcName,D.readWrite); IF f#0 THEN dummy:=D.Write(f,info,SIZE(Info)); dummyB:=D.Close(f) END END WriteScreenMode; PROCEDURE ChangeMode2(info:Info); Present a screen mode requester prefilled with the values from info. Store the returned values into the environment. ScreenModeRequesterPtr=POINTER TO A.ScreenModeRequester; ok, useWBWindow, modifyColors: BOOLEAN; screenRequest:ScreenModeRequesterPtr; tags:ARRAY 15 OF U.TagItem; BEGIN IF ~WBWindow THEN I.ClearPointer(window) END; tags[0].tag:=A.tsmDoAutoScroll; tags[0].data:=SYSTEM.VAL(LONGINT,TRUE); tags[1].tag:=A.tsmDoDepth; tags[1].data:=SYSTEM.VAL(LONGINT,TRUE); tags[2].tag:=A.tsmDoHeight; tags[2].data:=SYSTEM.VAL(LONGINT,TRUE); tags[3].tag:=A.tsmDoOverscanType; tags[3].data:=SYSTEM.VAL(LONGINT,TRUE); tags[4].tag:=A.tsmDoWidth; tags[4].data:=SYSTEM.VAL(LONGINT,TRUE); tags[5].tag:=A.tsmInitialAutoScroll; IF info.autoScroll THEN tags[5].data:=-1 ELSE tags[5].data:=0 END; tags[6].tag:=A.tsmInitialDisplayDepth; tags[6].data:=info.depth; tags[7].tag:=A.tsmInitialDisplayHeight; tags[7].data:=info.height; tags[8].tag:=A.tsmInitialDisplayID; tags[8].data:=info.displayID; tags[9].tag:=A.tsmInitialDisplayWidth; tags[9].data:=info.width; tags[10].tag:=A.tsmInitialOverscanType; tags[10].data:=info.oscan; tags[11].tag:=A.tsmScreen; tags[11].data:=screen; tags[12].tag:=A.tsmMaxDepth; tags[12].data:=maxDepth; tags[13].tag:=U.done; screenRequest:=SYSTEM.VAL(ScreenModeRequesterPtr,A.AllocAslRequest(A.aslScreenModeRequest,tags)); Assert(screenRequest#NIL,"No ScreenModeRequester"); tags[0].tag:=U.done; ok:=A.AslRequest(SYSTEM.VAL(LONGINT,screenRequest),tags); IF ok THEN useWBWindow:= I.CallEasyRequest(window, {}, "Oberon System V4 for Amiga", "Use Custom Screen ?","Yes|No")=0; modifyColors:=FALSE; IF useWBWindow THEN modifyColors:=I.CallEasyRequest(window, {}, "Oberon System V4 for Amiga", "Modify Default Colors If Necessary ?", "Yes|No")#0; END; WriteScreenMode( screenRequest.displayID,SHORT(screenRequest.displayHeight),SHORT(screenRequest.displayWidth) ,screenRequest.displayDepth,screenRequest.overscanType,screenRequest.autoScroll#0 ,useWBWindow, modifyColors END; A.FreeAslRequest(SYSTEM.VAL(LONGINT,screenRequest)); screenRequest:=NIL; IF ~WBWindow THEN I.SetPointer(window,pointerData,2,16,0,0) END END ChangeMode2; PROCEDURE ChangeMode*(VAR res:INTEGER); Present screen mode requester if the OS version supports it. Used by System.ChangeMode. dummy:BOOLEAN; info:Info; BEGIN IF A.aslVersion>=38 THEN GetDefaultMode(info,dummy); ChangeMode2(info); res:=0 ELSE res:=1 END ChangeMode; PROCEDURE DosCmd*(cmd, outName:ARRAY OF CHAR; VAR res:INTEGER); Run a program with STDIN set to NIL: and STDOUT set to output. in,out:D.FileHandlePtr; tags:ARRAY 4 OF U.TagItem; BEGIN in:=D.Open("NIL:",D.oldFile); ASSERT(in#0); out:=D.Open(outName,D.newFile); ASSERT(out#0); tags[0].tag:=D.sysInput; tags[0].data:=in; tags[1].tag:=D.sysOutput; tags[1].data:=out; tags[2].tag:=D.npCloseOutput; tags[2].data:=SYSTEM.VAL(LONGINT,FALSE); tags[3].tag:=U.done; res:=SHORT(D.System(cmd,tags)); IF D.Close(out) THEN END; IF D.Close(in) THEN END END DosCmd; PROCEDURE SwapBits*(b: SYSTEM.BYTE):SYSTEM.BYTE; Swaps the bits within a byte [76543210] -> [01234567] i:INTEGER; in,res:LONGINT; BEGIN res:=0; in:=ORD(SYSTEM.VAL(CHAR,b)); FOR i:=0 TO 7 DO res:=res*2+in MOD 2; in:=in DIV 2 END; RETURN CHR(res) END SwapBits; PROCEDURE ConvertAnsiToOberon*(VAR buf:ARRAY OF CHAR; len:LONGINT); Convert ANSI (ISO latin1) Codes to the Oberon font. This conversion can be switched off by setting dontConvert:=TRUE. i:LONGINT; BEGIN IF dontConvert THEN RETURN END; FOR i:=0 TO len-1 DO buf[i]:=AtoO[ORD(buf[i])] END ConvertAnsiToOberon; PROCEDURE Loop*; This is the loop, which the loader calls instead of Oberon.Loop. It remembers the current stack pointer before calling Oberon.Loop, so the trap handler can return us into the loop, and we can restart Oberon.Loop after each trap. imported:ARRAY 32 OF CHAR; mod,modules:Module; oberonLoop:PROCEDURE; res:INTEGER; BEGIN ThisMod("Oberon",mod,res,modules,imported); Assert(res=0,"Amiga.Loop: Oberon not found"); ThisCommand(mod,"Loop",SYSTEM.VAL(Absolute,oberonLoop),res); Assert(res=0,"Amiga.Loop: Oberon.Loop not found"); LOOP SaveRegs; SYSTEM.GETREG(15,stackPtr); DEC(stackPtr,4); (* stack pointer value after call of oberonLoop. *) oberonLoop; LoadRegs END Loop; PROCEDURE ConvAtoO*(ch: CHAR): CHAR; (*<Oberon BEGIN IF dontConvert THEN RETURN ch ELSE RETURN AtoO[ORD(ch)] END ConvAtoO; PROCEDURE ConvOtoA*(ch: CHAR): CHAR; (*<Amiga BEGIN IF dontConvert THEN RETURN ch ELSE RETURN OtoA[ORD(ch)] END ConvOtoA; PROCEDURE InitCharConv; (*<=39 THEN ChipMemPool:=E.CreatePool({E.memChip}, PoolPuddleSize, PoolThreshSize); Assert(ChipMemPool#0, "Can not create memory pool for fonts") ELSE ChipMemPool:=0 END; IF ChipMemPool#0 THEN pointerData:=E.AllocPooled(ChipMemPool, pointerSize); FOR i:=0 TO pointerSize-1 DO SYSTEM.PUT(pointerData+i, CHR(0)) END ELSE pointerData:=E.AllocMem(pointerSize,{E.memChip,E.memClear}) END; version:=screenTitle; IF A.aslVersion>=38 THEN GetDefaultMode(info,fromEnv); IF ~fromEnv THEN ChangeMode2(info); GetDefaultMode(info,fromEnv) END ELSE GetDefaultMode(info,fromEnv) END; WBWindow:=info.useWBWindow; ModifyColors:=info.modifyColors; IF WBWindow THEN OpenWBWindow() ELSE OpenScreen() END; proc:=SYSTEM.VAL(ProcessPtr,E.FindTask(0)); oldProcessWindow:=proc.windowPtr; proc.windowPtr:=window; I.SetPointer(window,pointerData,15,16,0,0); I.ActivateWindow(window); scrrp:=SYSTEM.VAL(RPPtr, SYSTEM.ADR(scr.rastPort)); bm:=SYSTEM.VAL(BitmapPtr, scrrp.bitMap); Depth:=bm.depth; IF info.depth<=Depth THEN OberonDepth:=info.depth ELSE OberonDepth:=Depth END; TermProcedure(Close); dontConvert:=FALSE; useLAltAsMouse:=TRUE; idlePri:=-128; normalPri:=0; OpenTimerDevice(); TicsToWait:=20000; MainLoopType:=TimerOpen; (* Use AmigaLoop if Timer Device is open *) PrinterName:="PrinterOut.ps"; PictPrintThresh:=128; UseQuitRequester:=FALSE; InitCharConv END Init; BEGIN TimerOpen:=FALSE; TimerMP:=0; TimerIOPtr:=0; stackPtr:=0; Ensure, that OLoad probably guessed right, when patching in loaderCall. Assert((guard1=002468ACEH) & (guard2=013579BDFH),"Amiga: wrong loader call guards."); Init END Amiga.