summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BootBlockbin0 -> 1024 bytes
-rw-r--r--CDTV.S145
-rw-r--r--CDisk.S1123
-rw-r--r--Documentation/GameExec.doc158
-rw-r--r--Documentation/README70
-rw-r--r--EndLabel.S14
-rw-r--r--Exec.S816
-rw-r--r--FFS.S254
-rw-r--r--FinalBooter.S312
-rw-r--r--Keyboard.S423
-rw-r--r--LoadSeg.S211
-rw-r--r--Makefile110
-rw-r--r--Memory.S416
-rw-r--r--MyExec.i431
-rw-r--r--PPDecrunch.S151
-rw-r--r--RawDoFmt.S351
-rw-r--r--Rnd.S55
-rw-r--r--SCOPTIONS24
-rw-r--r--Start.c487
-rw-r--r--SysCDisk.S303
-rw-r--r--SysStart.c220
-rw-r--r--protcustom.i125
-rw-r--r--relcustom.i168
-rw-r--r--zeropage.i39
24 files changed, 6406 insertions, 0 deletions
diff --git a/BootBlock b/BootBlock
new file mode 100644
index 0000000..576e1f1
--- /dev/null
+++ b/BootBlock
Binary files differ
diff --git a/CDTV.S b/CDTV.S
new file mode 100644
index 0000000..cef9344
--- /dev/null
+++ b/CDTV.S
@@ -0,0 +1,145 @@
+
+ IDNT CDTV
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+ INCLUDE "exec/macros.i"
+ INCLUDE "exec/io.i"
+
+ XREF @CreateIO,@DeleteIO,_RawPrintfFunc
+ XDEF InitCDFunc,ExitCDFunc,PlayCDTrackFunc
+ XDEF WaitCDTrackFunc
+
+CD_PLAYTRACK: EQU 43
+CD_MUTE: EQU 56
+
+*****************************************************************************
+* CDTV-IORequest erstellen und Device öffnen
+
+InitCDFunc: movem.l d1/a0-a2/a6,-(SP)
+
+ moveq.l #IOSTD_SIZE,d0
+ bsr @CreateIO
+ move.l d0,CDIOReq
+ beq.s 1$ ; No mem --->
+ movea.l d0,a2
+
+ moveq #0,d0 ; Unit
+ moveq #0,d1 ; Flags
+ lea CDTVName(PC),a0
+ movea.l a2,a1
+ movea.l 4,a6
+ JSRLIB OpenDevice
+ tst.l d0 ; Device OK ?
+ beq.s 1$ ; yep --->
+ bsr.s ExitCDFunc ; Sonst Request freigeben
+ bra.s 2$
+1$:
+ movea.l CDIOReq,a1
+ move.w #CD_MUTE,IO_COMMAND(a1)
+ move.l #$7fff,IO_OFFSET(a1)
+ move.l #1,IO_LENGTH(a1)
+ move.l #0,IO_DATA(a1)
+ JSRLIB DoIO
+
+ pea CDDevOKText(PC)
+ bsr _RawPrintfFunc
+ addq #4,SP
+2$:
+ movem.l (SP)+,d1/a0-a2/a6
+ rts
+
+*****************************************************************************
+* CDTV-Resourcen wieder freigeben
+
+ExitCDFunc: movem.l d1-d2/a0-a1/a6,-(SP)
+
+ move.l CDIOReq,d2
+ beq.s 2$
+ movea.l d2,a1
+ tst.l IO_DEVICE(a1)
+ ble.s 1$
+ movea.l 4,a6
+ JSRLIB CloseDevice
+1$:
+ movea.l d2,a1 ; IO-Request
+ bsr @DeleteIO ; freigeben
+ clr.l CDIOReq ; Wichtig!
+2$:
+ movem.l (SP)+,d1-d2/a0-a1/a6
+ rts
+
+*****************************************************************************
+* CDTV-Track abspielen
+
+PlayCDTrackFunc:
+ movem.l d1-d3/a0-a1/a6,-(SP)
+
+ move.l CDIOReq,-(SP)
+ move.l d0,-(SP)
+ pea PlayText(PC)
+ bsr _RawPrintfFunc
+ lea 12(SP),SP
+
+ movea.l 4,a6
+ move.l CDIOReq,d3
+ beq.s 2$
+
+ ;; movea.l d3,a1
+ ;; cmpi.w #CD_PLAYTRACK,IO_COMMAND(a1) ; Schon initialisiert ?
+ ;; bne.s 1$ ; nein ---> Nicht warten
+ ;; JSRLIB AbortIO
+ bsr.s WaitCDTrackFunc
+1$:
+ movea.l d3,a1
+ move.w #CD_PLAYTRACK,IO_COMMAND(a1)
+ move.l d0,IO_OFFSET(a1) ; Gewünschter Track
+ clr.l IO_LENGTH(a1)
+ clr.l IO_DATA(a1)
+ JSRLIB SendIO
+2$:
+ movem.l (SP)+,d1-d3/a0-a1/a6
+ rts
+
+*****************************************************************************
+* Auf CD warten
+
+WaitCDTrackFunc:
+ movem.l d0-d3/a0-a1/a6,-(SP)
+
+ movea.l 4,a6
+ move.l CDIOReq,d3
+ beq.s 2$
+
+ pea WaitText(PC)
+ bsr _RawPrintfFunc
+ addq #4,SP
+
+ movea.l d3,a1
+ cmpi.w #CD_PLAYTRACK,IO_COMMAND(a1) ; Schon initialisiert ?
+ bne.s 1$ ; nein ---> Nicht warten
+ JSRLIB WaitIO
+1$:
+ pea WaitFinText(PC)
+ bsr _RawPrintfFunc
+ addq #4,SP
+2$:
+ movem.l (SP)+,d0-d3/a0-a1/a6
+ rts
+
+*****************************************************************************
+
+CDTVName: dc.b "cdtv.device",0
+
+CDDevOKText: dc.b "CDTV device OK",13,10,0
+PlayText: dc.b "PlayCDTrack(%ld), req=$%08lx",13,10,0
+WaitText: dc.b "Waiting for audio to finish ... ",0
+WaitFinText: dc.b "Done.",13,10,0
+
+ EVEN
+
+ SECTION bss,BSS
+CDIOReq: ds.l 1
+
+ END
+
diff --git a/CDisk.S b/CDisk.S
new file mode 100644
index 0000000..fce2e0f
--- /dev/null
+++ b/CDisk.S
@@ -0,0 +1,1123 @@
+*****************************************************************************
+** **
+** C - D I S K - The ultimate Amiga Disk Control Software **
+** **
+** (Lese- und Schreibroutinen ohne Blitter) **
+** **
+** by Christian A. Weber, Zürich/Switzwerland **
+** **
+*****************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 13-Jan-88 V0.01 Project BDisk started **
+** 05-Feb-88 V0.04 BDisk Last updated **
+** 27-May-88 V0.10 CDisk created from BDisk **
+** 17-Aug-88 V1.01 First working version **
+** 25-Aug-88 V1.02 Roottrack-bug fixed **
+** 04-Sep-88 V1.03 Disk length set from 6500 to 6650 **
+** 06-Sep-88 V2.01 Write-Routinen implementiert **
+** 30-Oct-88 V2.02 Derselbe Track wird nicht mehr mehrmals gelesen **
+** 22-Nov-88 V2.03 Write-Bug korrigiert **
+** 29-Jan-89 V2.04 Timeouts vergrössert für 68020 **
+** 10-Apr-89 V2.05 Labels angepasst, cleanup etc. **
+** 26-Apr-89 V2.06 Kein 'MotorOff' wenn Unit nicht gefunden **
+** 29-Jun-89 V2.07 Angepasst an Genim2-Assembler **
+** 01-Aug-89 V3.01 Völlig umgekrempelt, läuft jetzt im Interrupt **
+** 27-Aug-89 V3.10 Läuft nun endlich (fast) fehlerfrei im Interrupt **
+** 30-Aug-89 V3.15 RAMDisk-Routinen auch hier eingebaut **
+** 01-Sep-89 V3.20 Unterstützt FFS-RAMDrive **
+** 02-Sep-89 V3.21 ReadyTimeOut implementiert **
+** 27-Nov-89 V3.22 LoadFastFile() implementiert **
+** 21-Mar-90 V3.23 Code aufgeräumt, alte RAM-Disk rausgeworfen **
+** 29-Dec-90 V3.24 Gecrunchte Files werden automatisch entcruncht **
+** 06-May-91 V4.00 Tada! Schreibroutine eingebaut **
+** 16-Apr-92 V4.01 PP_SAVEMARGIN added, PowerPacker jetzt 100% **
+** **
+*****************************************************************************
+
+ IDNT CDisk
+ SECTION text,CODE
+
+CRUNCH
+
+;;DEBUG
+;;LIGHTSHOW
+
+ IFD DEBUG
+DERR_DRIVENOTREADY: EQU $21
+DERR_DMATIMEOUT: EQU $22
+DERR_NOSYNC: EQU $23
+DERR_BADCHECKSUM: EQU $24
+DERR_BADTRACK: EQU $25
+DERR_WRONGDISK: EQU $26
+DERR_WRONGPRODUCT: EQU $27
+ ENDC
+
+CUSTOMOFFSET: EQU $19BE
+
+ INCLUDE "MyExec.i"
+
+ INCLUDE "relcustom.i"
+ ;; INCLUDE "protcustom.i"
+
+ INCLUDE "hardware/intbits.i"
+ INCLUDE "hardware/cia.i"
+
+ IFD RAMVERSION
+ XREF ProcessFFSPacket ; Für ramdrive.device
+ ENDC
+
+ IFD CRUNCH
+ XREF PPDecrunch
+ ENDC
+
+ XDEF InitDiskFunc ; Disk-System initialisieren
+ XDEF SetNoDiskHandlerFunc
+ XDEF ReadFileFunc ; 'Datei' lesen
+ XDEF LoadFileFunc ; Speicher reservieren & File lesen
+ XDEF LoadFastFileFunc ; FAST alloc & File lesen
+ XDEF WriteFileFunc ; 'Datei' schreiben
+ XDEF SendPacketFunc ; Asynchronen Lese-Request schicken
+
+***************************************************************************
+
+ciabase: EQU $bfd000-$16ff ; scramble disassemblies
+a_pra: EQU $bfe001-ciabase
+a_talo: EQU $bfe401-ciabase
+a_tahi: EQU $bfe501-ciabase
+a_icr: EQU $bfed01-ciabase
+a_cra: EQU $bfee01-ciabase
+b_prb: EQU $bfd100-ciabase
+b_icr: EQU $bfdd00-ciabase
+
+***************************************************************************
+
+TIMERRATE: EQU 2836 ; Taktrate der Diskroutine
+DMATIME: EQU 25000 ; Max. # Ticks zum Read/Write von 1 Spur
+READYTIME: EQU 2800 ; Max. # Ticks bis DriveReady kommt
+READBYTES: EQU 6800 ; Anzahl zu lesende MFM-Words
+WRITEBYTES: EQU 6300 ; Anzahl zu schreibende MFM-Words ohne Gap
+TRACKBUFSIZE: EQU 16300 ; Größe des gesamten Buffers
+GAPBYTES: EQU 1664 ; Größe der Track-Gap in Bytes
+TRIALS: EQU 5 ; Anzahl Versuche bei r/w error
+MAXUNITS: EQU 4 ; Maximale Anzahl Drives
+
+DISKMAGIC: EQU $43485700 ; Currently 'CHW',0
+FFSMAGIC: EQU $444f5301 ; 'DOS',1
+FN_HEADER: EQU $7f030000 ; Disk <??> Track <2> Offset <0>
+
+***************************************************************************
+
+ *** Die Disk-Header-Struktur, wird von Disk eingelesen
+
+ STRUCTURE DiskHeader,0
+
+ LONG dh_DiskMagic ; Disk-Magic, muss DISKMAGIC sein
+ WORD dh_ProductKey ; Identifikation des Produkts
+ WORD dh_DiskNumber ; Nummer der Disk oder 0 = no disk
+ STRUCT dh_Reserved,8 ; 8 Bytes Future Expansion
+
+ LABEL dh_SIZEOF
+
+***************************************************************************
+
+ *** Die Disk-Unit-Struktur, existiert für jedes Laufwerk
+
+ STRUCTURE DiskUnit,0
+
+ APTR du_MFMBuffer ; Zeiger auf 16K CHIP-RAM
+ WORD du_DiskNumber ; Disk-Nummer oder 0 wenn ungültig
+ WORD du_CurrentTrack ; Aktueller TRACK (0..159)
+ WORD du_DestTrack ; Ziel-Spur
+ WORD du_TrackSize ; Anzahl Bytes der gelesenen Spur
+ WORD du_Sync ; Sync-Wert für dieses Drive
+ LONG du_FileName ; DiskMaker-Filename
+ APTR du_DestAddr ; Aktuelle Ladeadresse
+ LONG du_FileSize ; Größe des aktuellen Files
+ APTR du_ActPacket ; Zeiger auf aktuelles Packet
+ WORD du_TimeOutCntr ; TimeOut-Zähler für Read
+ BYTE du_Status ; Siehe DS_ - Definitionen
+ BYTE du_OnMask ; Motor On, z.B. $01101111 für df1
+ BYTE du_OffMask ; Motor Off, z.B. $11101111 für df1
+ BYTE du_RetryCntr ; Zähler für Retry
+
+ LABEL du_SIZEOF ; Größe dieser Struktur
+
+
+ *** Werte für DiskUnit.du_Status (IN 2ERSCHRITTEN ALS INDEX!!)
+
+DS_IDLE: EQU 0 ; Unit hat nichts zu tun
+DS_RECALIBRATE: EQU 2 ; Unit ist am auf Track 0 zurücksteppen
+DS_STEP: EQU 4 ; Laufwerk ist am steppen
+DS_SETTLE: EQU 6 ; Laufwerk hat fertiggesteppt, DMA starten
+DS_WAITDMA: EQU 8 ; Wir warten auf's Read/Write-DMA-Ende
+
+DSF_WRITING: EQU $80 ; Schreib-Flag (MUSS $80 sein für tst.b!)
+
+
+***************************************************************************
+** **
+** I N I T D I S K - Disk-System init, Recalibrate, Timer alloc ... **
+** **
+** Parameter : nix **
+** **
+***************************************************************************
+
+InitDiskFunc: movem.l d0-d7/a0-a5,-(SP)
+
+ bsr GetD7A4A5 ; Get BitMask,CiaBase,Custom
+ clr.l InsertDiskRoutine ; InsertDisker retten
+
+ *** UnitPointer-Tabelle löschen
+
+ lea UnitTab(PC),a0
+ moveq #16,d0 ; 4 Pointers
+ jsr meb_ClearMem(a6) ; löschen
+
+ *** MFM-Buffer holen, Track-Gap und ½ Sync erzeugen für Write
+
+ move.l #TRACKBUFSIZE,d0 ; Amount
+ jsr meb_AllocMem(a6) ; CHIP-RAM reservieren
+ movea.l d0,a0 ; A0 : MFM-Buffer
+ lea GAPBYTES(a0),a1 ; Buffer-Start für Read
+ move.l a1,MFMBuffer
+
+ move.l d7,d0 ; $55555555
+ add.l d0,d0 ; $aaaaaaaa
+ move.w #TRACKBUFSIZE/4-1,d2
+2$: move.l d0,(a0)+
+ dbf d2,2$
+ move.w #$4489*2,-(a1) ; ½ SYNC
+ lsr.w (a1) ; gegen die Cracker
+
+ *** Unit-Strukturen für angeschlossene Laufwerke erstellen
+
+checkdrives: lea UnitTab(PC),a2 ; Zeiger auf Units
+ moveq #MAXUNITS-1,d3 ; Anzahl Laufwerke zu suchen
+ move.b #%11110111,d2 ; D2 := Select-Maske DF0
+ bra.s 2$ ; DF0 ist immer da
+
+1$: bsr CheckUnit ; Testen ob Unit angeschlossen
+ tst.b d0 ; 3.5"-Drive vorhanden ?
+ bne.s 3$ ; nein --->
+
+2$: moveq.l #du_SIZEOF,d0 ; Größe einer Unit
+ jsr meb_AllocFastClearMem(a6) ; Unit allozieren
+ movea.l d0,a3 ; Unit merken
+ move.l a3,(a2)+ ; und in Tabelle eintragen
+
+ move.l #$4489*6337,d0 ; Gegen Cracker
+ move.l MFMBuffer,du_MFMBuffer(a3)
+ ;; clr.w du_DiskNumber(a3) ; Keine Disk in diesem Drive
+ ;; clr.w du_CurrentTrack(a3)
+ ;; clr.w du_DestTrack(a3)
+ ;; clr.w du_TrackSize(a3) ; 0 = ungültig
+ divs.w #6337,d0 ; Gibt $4489
+ move.w d0,du_Sync(a3)
+ ;; move.b #DS_IDLE,du_Status(a3) ; Drive schläft
+ move.b d2,du_OffMask(a3)
+ move.b d2,du_OnMask(a3)
+ bclr.b #CIAB_DSKMOTOR,du_OnMask(a3)
+
+3$: rol.b #1,d2 ; SEL für nächstes Drive
+ dbf d3,1$ ; ---> Für alle Drives
+
+ *** Alle Motoren abschalten
+
+ st.b b_prb(a4) ; Deselect all
+ bsr ShortDelay
+ move.b #%10000111,b_prb(a4) ; Select all
+ bsr ShortDelay
+ st.b b_prb(a4) ; Deselect all
+
+ *** DiskRequest-Liste initialisieren
+
+ lea meb_DiskList(a6),a0
+ jsr meb_NewList(a6)
+
+ *** Timer initialisieren, TimerInterrupt-Handler installieren
+
+ lea MyTimerHandler(PC),a0
+ move.l a0,meb_CiaATimerAVector(a6)
+ andi.b #%11100110,a_cra(a4) ; Timer A Continuous
+ move.b #TIMERRATE&$ff,a_talo(a4)
+ move.b #TIMERRATE>>8,a_tahi(a4)
+ ori.b #%00010001,a_cra(a4) ; Timer A ForceLoad|Start
+
+ move.w #$8008,intena(a5) ; PORTS-Interrupt on
+ move.b #$81,$bfed01 ; Im CIA ICR auch
+ move.w #$8010,dmacon(a5) ; Disk DMA enable
+
+ movem.l (SP)+,d0-d7/a0-a5
+ rts
+
+***************************************************************************
+
+ *** Testen ob Laufwerk mit Select-Maske in D2 vorhanden ist
+
+CheckUnit: lea b_prb(a4),a0
+ moveq #$7f,d0 ; Alle Drives deselektieren
+ move.b d0,(a0)
+ bsr ShortDelay
+ and.b d2,d0 ; Select-Bit löschen
+ move.b d0,(a0) ; Select Drive, Motor on
+ bsr ShortDelay
+ st.b (a0) ; Laufwerk deselektieren
+ bsr ShortDelay
+ move.b d2,(a0) ; Select Drive, Motor off
+ bsr ShortDelay
+ st.b (a0) ; Laufwerk deselektieren
+
+ moveq #31,d1 ; 32 Bits
+ moveq.l #0,d0 ; Ergebnis löschen
+1$: add.l d0,d0 ; Ergebnis 1 nach links
+ move.b d2,(a0) ; Laufwerk selektieren
+ bsr ShortDelay
+ btst.b #5,a_pra(a4) ; Disk Ready ?
+ beq.s 2$ ; RDY==0 ---> Drive vorhanden
+ bset #0,d0 ; Sonst Bit 0 in D0 setzen
+2$: st.b (a0) ; Motor ausschalten
+ bsr ShortDelay
+ dbf d1,1$ ; loop --->
+ rts
+
+
+***************************************************************************
+** **
+** S E T N O D I S K H A N D L E R - NoDisk-Handler setzen **
+** **
+** Parameter : A0.L: InsertDisk-Handler oder 0 **
+** **
+***************************************************************************
+
+SetNoDiskHandlerFunc:
+ move.l a0,InsertDiskRoutine
+ rts
+
+
+***************************************************************************
+** **
+** R E A D F I L E - Datei von Disk an angegebene Adresse laden **
+** **
+** Parameter : D0.L : DiskAdresse (Disk/Track/Offset) der Datei **
+** A0.L : Ladeadresse **
+** **
+** Resultat : nix **
+** **
+***************************************************************************
+
+ReadFileFunc: movem.l d1/a0-a1,-(SP)
+ moveq #0|DPF_REPLYBYTE,d1 ; LESEN
+ bra.s APost ; Paket aufgeben
+
+
+***************************************************************************
+** **
+** W R I T E F I L E - Existierende 'Datei' auf Disk überschreiben **
+** **
+** Parameter : D0.L : DiskAdresse (Disk/Track/Offset) der Datei **
+** A0.L : Adresse der Daten für das File **
+** **
+** Resultat : nix **
+** **
+***************************************************************************
+
+WriteFileFunc: movem.l d1/a0-a1,-(SP)
+ move.b #DPF_WRITE|DPF_REPLYBYTE,d1 ; SCHREIBEN
+ bra.s APost ; Paket aufgeben
+
+
+***************************************************************************
+** **
+** L O A D F I L E - Speicher reservieren, Datei von Disk lesen **
+** **
+** Parameter : D0.L : DiskAdresse (Disk/Track/Offset) der Datei **
+** **
+** Resultat : D0.L : Adresse des Files, 0 if error **
+** Z-Bit: gelöscht wenn OK, gesetzt wenn Error **
+** **
+***************************************************************************
+
+LoadFileFunc: movem.l d1/a0-a1,-(SP)
+ moveq #DPF_REPLYBYTE|DPF_ALLOCMEM,d1 ; Packet Flags
+ bra.s APost ; Paket aufgeben
+
+LoadFastFileFunc:
+ movem.l d1/a0-a1,-(SP)
+ moveq #DPF_REPLYBYTE|DPF_ALLOCFASTMEM,d1 ; Packet Flags
+ ;; bra.s APost ; Paket aufgeben
+
+
+APost: lea -dp_SIZEOF-2(SP),SP ; DiskPacket erstellen
+ move.l a0,dp_Address(SP) ; Ladeadresse eintragen
+ movea.l SP,a0 ; A0 : Packet
+ move.l d0,dp_FileName(a0) ; Dateinamen eintragen
+ lea dp_SIZEOF(SP),a1 ; A1 : End-Flag
+ clr.b (a1) ; löschen
+ move.l a1,dp_Reply(a0)
+ move.b d1,dp_Flags(a0) ; DPF_REPLYBYTE [|DPF_WRITE] usw.
+ bsr.s SendPacketFunc
+1$: tst.b (a1) ; Warten bis File geladen/geschrieben
+ beq.s 1$
+ move.l dp_Address(SP),d0 ; Resultat: Adresse
+ lea dp_SIZEOF+2(SP),SP ; DiskPacket freigeben
+ movem.l (SP)+,d1/a0-a1
+ rts
+
+
+***************************************************************************
+** **
+** S E N D P A C K E T - Asynchronen Read-Request aufgeben **
+** **
+** Parameter : A0.L : Zeiger auf struct DiskPacket **
+** **
+** Resultat : nix **
+** **
+***************************************************************************
+
+SendPacketFunc: movem.l d7/a0-a1/a4-a5,-(SP)
+ bsr GetD7A4A5 ; Für ProcessNextRequest()
+ movea.l a0,a1 ; Packet
+ lea meb_DiskList(a6),a0
+ jsr meb_AddTail(a6) ; Packet anhängen
+ bsr.s ProcessNextRequest ; System ankicken
+ movem.l (SP)+,d7/a0-a1/a4-a5
+ rts
+
+
+***************************************************************************
+
+ *** Nächsten Request aus Diskliste verarbeiten
+
+ProcessNextRequest:
+ movem.l d0-d2/a0-a2/a3,-(SP)
+ move.l ActUnit(PC),d0 ; Working? (tst.l ActUnit(PC))
+ bne .EndProcReq ; ja --->
+ lea meb_DiskList(a6),a0
+ jsr meb_RemHead(a6) ; setzt CCR
+ beq .EndProcReq ; Kein Request pending --->
+ movea.l d0,a2 ; A2 : Aktuelles Packet
+
+ *** Falls RAM-Disk erlaubt: RAMDisk-Request bearbeiten
+
+ moveq.l #0,d2
+ move.b dp_FileName(a2),d2 ; D2 : DiskNumber
+
+ IFD RAMVERSION
+ movea.l a2,a0 ; A0: Packet
+ movea.l meb_RAMDiskBase(a6),a1 ; Filename=RAM-Basis
+ cmpi.l #FFSMAGIC,(a1) ; RAM-Disk in Ordnung ?
+ beq.s 1$ ; ja --->
+ MSG <"RAMDISK CORRUPT, A0=PACKET, A1=BASE">
+1$: bsr ProcessFFSPacket ; Packet (A0) bearbeiten (FFS)
+ bsr ReplyPacket ; Packet (A0) beantworten
+ bra .EndProcReq ; --->
+ ENDC
+
+ *** Drives nach gewünschter Disk absuchen
+
+.SearchDisk: moveq.l #MAXUNITS-1,d0 ; 4 Units maximal
+ lea UnitTab(PC),a1 ; Start des Pointer-Arrays
+4$: move.l (a1)+,d1 ; Get next unit
+ beq.s 5$ ; 0 ---> Unit überhüpfen
+ movea.l d1,a3
+ cmp.w du_DiskNumber(a3),d2 ; Disk in diesem Drive ?
+ beq.s .DiskFound ; ja --->
+5$: dbf d0,4$ ; sonst nächstes Drive testen
+
+ *** Disk nicht gefunden: Header aller Drives einlesen
+
+ moveq.l #MAXUNITS-1,d0 ; 4 Units maximal
+ lea UnitTab(PC),a1 ; Start des Pointer-Arrays
+6$: move.l (a1)+,d1 ; Get next unit
+ beq.s 7$ ; 0 ---> Unit überhüpfen
+ movea.l d1,a3
+ bsr GetHeader ; DiskHeader einlesen
+ cmp.w du_DiskNumber(a3),d2 ; Disk in diesem Drive ?
+ beq.s .DiskFound ; ja --->
+7$: dbf d0,6$ ; sonst nächstes Drive testen
+
+ *** Disk nicht gefunden: User-Routine aufrufen oder weiter probieren
+
+ move.l InsertDiskRoutine(PC),d1 ; von InitDisk()
+ beq.s 8$
+ movea.l d1,a1
+ move.l d2,d0 ; Disk-Nummer für User
+ move.l dp_FileName(a2),d1 ; Filename für User
+ jsr (a1) ; User-Routine aufrufen
+8$:
+ bra.s .SearchDisk ; ---> Loop
+
+ *** Disk gefunden: Packet an Unit (a3) schicken
+
+.DiskFound: move.l a2,du_ActPacket(a3) ; Dieses Packet war's!
+ move.l dp_FileName(a2),du_FileName(a3)
+ move.l dp_Address(a2),du_DestAddr(a3)
+ bsr.s StartUnit
+
+.EndProcReq: movem.l (SP)+,d0-d2/a0-a2/a3
+ rts
+
+***************************************************************************
+
+ *** Header einer Disk (a3) lesen und eintragen
+
+GetHeader: movem.l d0-d2/a0-a1,-(SP)
+ lea -dh_SIZEOF-16(SP),SP ; Platz für Header
+
+ clr.w du_DiskNumber(a3) ; Markierung für RawRead()
+ move.l #FN_HEADER,du_FileName(a3) ; Header-'Name'
+ bsr.s StartUnit
+
+ move sr,d0 ; ** DEBUG **
+ move #$2000,sr ; ** DEBUG **
+1$: stop #$2000 ; Auf Interrupt warten
+ cmpi.b #DS_IDLE,du_Status(a3) ; Fertig ?
+ bne.s 1$ ; nein --->
+ move d0,sr ; ** DEBUG **
+
+ movea.l du_MFMBuffer(a3),a0
+ lea 2+16(a0),a0 ; Start des DiskHeaders
+ movea.l SP,a1 ; Destination
+ moveq #dh_SIZEOF,d0 ; Anzahl Bytes
+ bsr MFMDecode
+
+ cmpi.l #DISKMAGIC,dh_DiskMagic(SP)
+ bne.s 99$ ; Keine CDisk-Disk --->
+ move.w meb_ProductCode(a6),d0
+ beq.s 2$ ; Produkt-Egal-Magic --->
+ cmp.w dh_ProductKey(SP),d0
+ bne.s 99$
+2$: move.w dh_DiskNumber(SP),du_DiskNumber(a3) ; Tada!
+
+99$: lea dh_SIZEOF+16(SP),SP ; Header freigeben
+ movem.l (SP)+,d0-d2/a0-a1
+ rts
+
+
+***************************************************************************
+
+ *** Unit (a3) starten
+
+StartUnit: move.l d0,-(SP)
+ clr.l du_FileSize(a3) ; Länge := 0
+ move.b #TRIALS,du_RetryCntr(a3) ; # Versuche setzen
+ move.w du_FileName(a3),d0 ; Disk# & Track (.W)
+ andi.w #$ff,d0
+ move.w d0,du_DestTrack(a3)
+ move.b #$7f,b_prb(a4) ; Motor on
+ bsr ShortDelay
+ move.b du_OnMask(a3),b_prb(a4) ; Motor on & Select
+ move.b #DS_STEP,du_Status(a3) ; Schreiten!
+ tst.w du_CurrentTrack(a3)
+ bgt.s 1$ ; Spur > 0 --->
+ move.b #DS_RECALIBRATE,du_Status(a3) ; 1. Mal: recalibrate
+1$: move.l a3,ActUnit ; Tada!
+ move.l (SP)+,d0
+ rts
+
+***************************************************************************
+
+ *** Packet (A0) beantworten
+
+ReplyPacket: movem.l a0-a2,-(SP)
+ movea.l a0,a2 ; A2 : Packet
+
+ IFD CRUNCH
+ bclr.b #DPB_CRUNCHED,dp_Flags(a2)
+ beq.s 1$
+ movea.l dp_Address(a2),a0 ; A0 : Start der gecrunchten Daten
+ move.l dp_FileSize(a2),d0 ; D0 : File-Länge gecruncht
+ move.l (a0),dp_FileSize(a2) ; Echte Länge für User
+ bsr PPDecrunch ; File decrunchen
+1$:
+ ENDC
+ movea.l dp_Reply(a2),a1 ; A1 : User's Reply-Adresse
+ btst.b #DPB_REPLYHANDLER,dp_Flags(a2)
+ beq.s 2$
+ movea.l a2,a0 ; A0 : Packet für User
+ jsr (a1) ; ReplyHandler aufrufen
+ bra.s 99$ ; --->
+2$:
+ btst.b #DPB_REPLYBYTE,dp_Flags(a2)
+ beq.s 3$
+ st.b (a1) ; ReplyByte setzen
+ ;; bra.s 99$ ; --->
+3$:
+99$: movem.l (SP)+,a0-a2
+ rts
+
+
+***************************************************************************
+** **
+** TimerInterrupt-Handler: Kommandos auswerten und ausführen **
+** **
+***************************************************************************
+
+MyTimerHandler: movem.l d0-d7/a0-a5,-(SP)
+ move.l ActUnit(PC),d0 ; Gibt's Arbeit ?
+ beq.s 99$ ; nein --->
+ bsr GetD7A4A5 ; Get BitMask,Custom,CiaBase
+ movea.l d0,a3 ; a3 : Unit
+ move.b du_Status(a3),d0 ; Action to take
+ andi.w #$000f,d0 ; Flag-Bits interessieren nicht
+ lea .ComTable(PC),a0 ; Command offset table
+ adda.w 0(a0,d0.w),a0 ; plus actual command offset
+ IFD LIGHTSHOW
+ move.w #$ff0,$dff180
+ ENDC
+ jsr (a0) ; Go do the code
+ IFD LIGHTSHOW
+ move.w #$000,$dff180
+ ENDC
+99$: movem.l (SP)+,d0-d7/a0-a5
+ rts
+
+.ComTable: dc.w DoIdle-.ComTable ; DS_IDLE
+ dc.w DoReCalibrate-.ComTable ; DS_RECALIBRATE
+ dc.w DoStep-.ComTable ; DS_STEP
+ dc.w DoSettle-.ComTable ; DS_SETTLE
+ dc.w DoWaitDMA-.ComTable ; DS_WAITDMA
+
+***************************************************************************
+
+ *** Kommando DS_IDLE: nix machen
+
+DoIdle:
+ IFD LIGHTSHOW
+ move.w #$f00,color(a5) ; rot
+ ENDC
+ rts
+
+***************************************************************************
+
+ *** Kommando DS_RECALIBRATE: Auf Track 0 zurückfahren
+
+DoReCalibrate:
+ IFD LIGHTSHOW
+ move.w #$0f0,color(a5) ; grün
+ ENDC
+ clr.w du_TrackSize(a3) ; Track ist ungültig
+ btst.b #CIAB_DSKTRACK0,a_pra(a4) ; Track 0 ?
+ beq.s .ReCalFin ; ja --->
+ bset.b #CIAB_DSKDIREC,b_prb(a4) ; Nach Aussen
+ bclr.b #CIAB_DSKSTEP,b_prb(a4) ; Steppen
+ bsr ShortDelay
+ bset.b #CIAB_DSKSTEP,b_prb(a4)
+ bra ShortDelay ; --->
+
+.ReCalFin: clr.w du_CurrentTrack(a3) ; Hier sind wir jetzt
+ move.b #DS_STEP,du_Status(a3) ; Und wieder steppen
+ rts
+
+***************************************************************************
+
+ *** Kommando DS_STEP: Ziel-Track ansteuern
+
+DoStep:
+ IFD LIGHTSHOW
+ move.w #$ff0,color(a5) ; gelb
+ ENDC
+ move.w du_DestTrack(a3),d1 ; Destination Track
+ cmpi.w #80,d1 ; == Root-Track ?
+ bne.s 1$ ; nein --->
+ addq.w #2,du_DestTrack(a3) ; sonst überhüpfen
+ bra.s DoStep ; und nochmal das ganze
+1$:
+ move.w du_CurrentTrack(a3),d0 ; Hier sind wir
+ ;; cmp.w d1,d0 ; Sind wir schon richtig ?
+ ;; bne.s 2$ ; nein --->
+ ;; tst.w du_TrackSize(a3) ; Spur schon gelesen ?
+ ;; beq.s 2$ ; nein --->
+ ;; move.b #DS_WAITDMA,du_Status(a3) ; Sonst sofort Statuswechsel
+ ;; move.w #INTF_SETCLR|INTF_DSKBLK,intreq(a5) ; Interrupt auslösen
+ ;; bra.s 99$ ; --->
+ ;; 2$:
+ lsr.w #1,d0 ; Nur Cylindernr interessiert
+ lsr.w #1,d1 ; Nur Cylindernr interessiert
+ cmp.w d1,d0
+ beq.s .TrackFound
+ blt.s .StepIn
+
+.StepOut: subq.w #2,du_CurrentTrack(a3)
+ btst.b #CIAB_DSKTRACK0,a_pra(a4) ; Track 0 ?
+ beq.s 99$ ; ja ---> fertig
+ bset.b #CIAB_DSKDIREC,b_prb(a4)
+ bra.s .Step
+
+.StepIn: addq.w #2,du_CurrentTrack(a3)
+ bclr.b #CIAB_DSKDIREC,b_prb(a4)
+ ;; bra.s .Step
+
+.Step: clr.w du_TrackSize(a3) ; Track ist nicht gelesen
+ bclr.b #CIAB_DSKSTEP,b_prb(a4)
+ bsr ShortDelay
+ bset.b #CIAB_DSKSTEP,b_prb(a4)
+ bsr ShortDelay
+ bra.s 99$ ; ---> fertig
+
+.TrackFound: move.w du_DestTrack(a3),d0 ; Wir sind am Ziel
+ move.w d0,du_CurrentTrack(a3)
+ btst #0,d0 ; Seite ermitteln
+ bne.s 3$
+ bset.b #CIAB_DSKSIDE,b_prb(a4) ; Seite 0
+ bra.s 4$
+3$: bclr.b #CIAB_DSKSIDE,b_prb(a4) ; Seite 1
+4$: move.b #DS_SETTLE,du_Status(a3)
+99$:
+ rts
+
+***************************************************************************
+
+ *** Kommando DS_SETTLE: DMA für nächste Spur starten
+
+DoSettle:
+ IFD LIGHTSHOW
+ move.w #$00f,color(a5) ; blau
+ ENDC
+ movea.l du_MFMBuffer(a3),a0 ; A0: The Buffer
+ clr.l (a0) ; Falls gar nix gelesen wird
+ move.w du_Sync(a3),dsksync(a5) ; SYNC-Wort
+ move.w #$0c00,d0
+ move.w #INTF_DSKBLK,intreq(a5) ; DSKBLK-Intreq löschen
+ move.w d0,adkcon(a5) ; Precomp 0
+ lea dsklen-14(a5),a1
+ tst.b du_Status(a3) ; Schreiben ?
+ bpl.s 1$ ; Noe --->
+
+ add.w #$9100-$0c00,d0 ; $9100 (MFMPRECOMP|FAST)
+ lea -GAPBYTES(a0),a0 ; Gap-Bytes auch schreiben
+ move.w #(WRITEBYTES+GAPBYTES/2)|$C000,d1 ; Words to write
+ move.b #DS_WAITDMA|DSF_WRITING,du_Status(a3) ; Statusübergang
+
+ ;; btst.b #CIAB_DSKPROT,a_pra(a4) ; Disk schreibgeschützt ?
+ ;; bne.s 2$ ; nein --->
+ ;; moveq #ER_WRITEPROT,d0
+ ;; bra.s
+
+ bra.s 2$
+1$:
+ add.w #$9500-$0c00,d0 ; $9500 (MFMPRECOMP|WORDSYNC|FAST)
+ move.w #READBYTES|$8000,d1 ; Words to read
+ move.b #DS_WAITDMA,du_Status(a3) ; Statusübergang
+2$:
+ move.l a0,dskpt(a5) ; Lese- bzw. Schreib-Adresse
+ move.w d0,adkcon(a5)
+ bsr ShortDelay ; Das brauchts glaub
+ move.w d1,dsklen(a5) ; Anzahl Words zu lesen/schreiben
+ move.w d1,14(a1) ; =DskLen, DMA starten
+
+ move.w #DMATIME,du_TimeOutCntr(a3) ; Lesezeit setzen
+
+99$: rts
+
+***************************************************************************
+
+ *** Kommando DS_WAITDMA: Warten bis Disk-DMA fertig, dann processing
+
+DoWaitDMA:
+ IFD LIGHTSHOW
+ move.w #$f0f,color(a5) ; pink
+ ENDC
+ BTSTW INTB_DSKBLK,intreqr(a5) ; Spur fertig gelesen?
+ bne.s .ProcTrack ; ja --->
+ cmpi.w #DMATIME-READYTIME,du_TimeOutCntr(a3)
+ bgt.s 0$ ; Noch kein Ready-TimeOut --->
+ IFD DEBUG
+ moveq #DERR_DRIVENOTREADY,d0
+ ENDC
+ btst.b #CIAB_DSKRDY,a_pra(a4) ; Drive ready ?
+ bne.s 1$ ; nein ---> Error
+0$:
+ IFD DEBUG
+ moveq #DERR_DMATIMEOUT,d0
+ ENDC
+ subq.w #1,du_TimeOutCntr(a3) ; Schon TimeOut ?
+ bpl .DoWaitDMAEnd ; Noch nicht ---> fertig
+1$:
+ move.w #0,dsklen(a5) ; DMA OFF (NICHT clr!)
+ bra .ReadRetry ; Retry oder Error
+
+ *** Gelesene Spur verarbeiten: Test ob 1. Sync OK
+
+.ProcTrack: move.w #INTF_DSKBLK,intreq(a5) ; DSKBLK-Intreq löschen
+ move.w #0,dsklen(a5) ; DMA OFF (NICHT clr!)
+
+ movea.l du_MFMBuffer(a3),a2 ; A2 : MFM-Buffer
+ IFD DEBUG
+ moveq #DERR_NOSYNC,d0
+ ENDC
+ move.w du_Sync(a3),d1
+ cmp.w (a2),d1 ; 2. Sync-Wort OK ?
+ bne .ReadRetry ; Retry oder Error
+
+ *** Anzahl codierte LONGS des Tracks berechnen und eintragen & D2
+
+.GetSize: lea 2(a2),a0 ; Start der Daten nach Sync
+ movem.l (a0),d1/d2 ; 1. Headerlangwort
+ and.l d7,d1
+ and.l d7,d2
+ add.l d2,d2
+ or.l d1,d2 ; D2: Anzahl Datenbytes
+ move.w d2,du_TrackSize(a3) ; in Unit-Struktur eintragen
+
+ *** Checksumme des Tracks errechnen & prüfen
+
+ bsr CalcCheckSum ; D0:=Checksumme, A0 := Adr
+ move.l d0,d1 ; D1: Ist-Checksumme
+
+ movem.l (a0),d0/d2 ; Soll-Checksumme
+ and.l d7,d0
+ and.l d7,d2
+ add.l d2,d2
+ or.l d0,d2 ; D2: Soll-Checksumme
+
+ IFD DEBUG
+ moveq #DERR_BADCHECKSUM,d0
+ ENDC
+ cmp.l d2,d1 ; Checksumme richtig ?
+ bne .ReadRetry ; nein ---> Retry oder Error
+2$:
+ *** Testen ob es der richtige Track ist
+
+.CheckTrackNo: movem.l 2+8(a2),d1/d2 ; 2. Headerlangwort
+ and.l d7,d1
+ and.l d7,d2
+ add.l d2,d2
+ or.l d2,d1 ; D1 : 2. HeaderLong
+
+ IFD DEBUG
+ moveq #DERR_BADTRACK,d0
+ ENDC
+ cmp.b du_CurrentTrack+1(a3),d1 ; Richtige Spur ?
+ bne .ReCalibrate ; nein --->
+
+ *** Testen ob's die richtige Disknummer ist
+
+ lsr.w #8,d1
+ move.w du_DiskNumber(a3),d0
+ beq .ReadFinished ; Bei GetHeader(): fertig!
+ cmp.b d0,d1 ; Richtige Disk ?
+ beq.s 3$ ; ja --->
+ IFD DEBUG
+ moveq #DERR_WRONGDISK,d0
+ ENDC
+ move.w d1,du_DiskNumber(a3) ; Neue Disknummer eintragen
+ bra .ReadError ; ---> Request zurückpushen
+3$:
+ swap d1 ; DiskKey
+ move.w meb_ProductCode(a6),d0
+ beq.s 4$ ; Product-Egal-Magic
+ cmp.w d0,d1 ; richtige Disk ?
+ beq.s 4$ ; ja --->
+ clr.w du_DiskNumber(a3)
+ IFD DEBUG
+ moveq #DERR_WRONGPRODUCT,d0
+ ENDC
+ bra .ReadError ; ---> Request zurückpushen
+4$:
+ *** Testen ob's die 1. Spur des Files ist, ggf. File-Länge nach D5
+
+ tst.l du_FileSize(a3) ; Länge schon eingetragen ?
+ bne.s .ProcDataTrack ; ja --->
+
+ move.w du_FileName+2(a3),d2 ; File-Byte-Offset
+ add.w d2,d2 ; D2 : MFM-Offset
+ movem.l 2+16(a2,d2.w),d0/d5 ; kodierte File-Länge
+ and.l d7,d0 ; MFM-decodieren
+ and.l d7,d5
+ add.l d5,d5
+ or.l d0,d5 ; D5 : Länge des Files
+
+ *** Testen ob File gecruncht ist, ggf. Flag setzen und rumwursteln
+
+ movea.l du_ActPacket(a3),a0 ; A0 : Packet
+ IFD CRUNCH
+ bclr.l #31,d5 ; File gecruncht ?
+ beq.s 41$ ; nein --->
+ bset.b #DPB_CRUNCHED,dp_Flags(a0) ; Crunch-Flag setzen
+
+ movem.l 2+16+8(a2,d2.w),d0/d6 ; 1. Langwort im File
+ and.l d7,d0 ; MFM-decodieren
+ and.l d7,d6
+ add.l d6,d6
+ or.l d0,d6 ; D6 : Ungecrunchte Länge
+ moveq.l #PP_SAVEMARGIN,d0 ; Für auf-sich-selber-decrunchen
+ add.l d0,d6 ; Alloc-Länge += Sicherheitsbereich
+ bra.s 42$
+41$: move.l d5,d6 ; Nicht gecruncht
+42$:
+ ELSEIF
+ move.l d5,d6 ; D6 : Amount für AllocMem()
+ ENDC
+ move.l d5,du_FileSize(a3) ; Lade-Länge eintragen
+ move.l d5,dp_FileSize(a0) ; Lade-Länge für Decruncher
+
+ *** Testen ob Speicher reserviert werden muss, ggf. reservieren
+
+ bclr.b #DPB_ALLOCMEM,dp_Flags(a0) ; CHIP-Alloc gewünscht ?
+ beq.s 5$ ; nein --->
+ move.l d6,d0 ; Amount
+ jsr meb_AllocMem(a6)
+ bra.s 6$ ; --->
+5$:
+ bclr.b #DPB_ALLOCFASTMEM,dp_Flags(a0) ; FAST-Alloc gewünscht?
+ beq.s 61$ ; nein --->
+ move.l d6,d0 ; Amount
+ jsr meb_AllocFastMem(a6)
+6$: move.l d0,dp_Address(a0) ; Adresse ins Packet
+ move.l d0,du_DestAddr(a3) ; Adresse in DiskUnit
+61$:
+ *** 1. Spur (ab File-Start+4) kodieren / dekodieren
+
+ lea 18+8(a2,d2.w),a0 ; File-Data-Start im Puffer
+ moveq.l #0,d0
+ move.w du_TrackSize(a3),d0 ; Länge dieses Tracks
+ sub.w du_FileName+2(a3),d0 ; minus Start-Offset
+ subq.l #4,d0 ; minus Längen-Langwort
+ bra.s 7$ ; --->
+
+ *** Daten-Spur ab Track-Start kodieren / dekodieren
+
+.ProcDataTrack:
+ lea 18(a2),a0 ; Track-Data-Start im Puffer
+ moveq.l #0,d0
+ move.w du_TrackSize(a3),d0 ; Länge dieses Tracks
+7$: cmp.l du_FileSize(a3),d0 ; weniger als 1 Track ?
+ blt.s 8$ ; nein --->
+ move.l du_FileSize(a3),d0 ; Sonst begrenzen
+8$:
+ tst.b du_Status(a3) ; Haben wir soeben geschrieben ?
+ bmi.s 10$ ; ja --->
+
+ movea.l du_ActPacket(a3),a1
+ tst.b dp_Flags(a1) ; Kodieren oder dekodieren?
+ movea.l du_DestAddr(a3),a1 ; Destination (doesn't change ccr)
+ bpl.s 9$
+ bsr MFMEncode ; D0 Bytes A1 nach A0 kodieren
+ move.b #DS_SETTLE|DSF_WRITING,du_Status(a3) ; Schreiben!!
+ bra .DoWaitDMAEnd ; --->
+
+9$: bsr MFMDecode ; D0 Bytes A0 nach A1 dekodieren
+
+ *** Nächsten Track zum Lesen vorbereiten
+
+10$: add.l d0,du_DestAddr(a3) ; INC address
+ sub.l d0,du_FileSize(a3) ; DEC verbleibende Länge
+ ble .ReadFinished ; Fertig ---> (Tada!)
+ addq.w #1,du_DestTrack(a3) ; Nächste Spur
+ move.b #DS_STEP,du_Status(a3) ; Schreiten
+ bra .DoWaitDMAEnd ; --->
+
+ *** ReadError: RetryCounter runterzählen und ggf. retry
+
+.ReadRetry: clr.w du_TrackSize(a3) ; Spur ungültig
+ move.b #DS_STEP,du_Status(a3) ; Retry without bumping
+ bra.s 11$ ; --->
+
+.ReCalibrate: move.b #DS_RECALIBRATE,du_Status(a3) ; Bump
+
+11$: subq.b #1,du_RetryCntr(a3) ; Namal probiere ?
+ bgt .DoWaitDMAEnd ; ja --->
+
+.ReadError:
+ IFD DEBUG
+ movea.l du_ActPacket(a3),a0 ; Für MSG
+ MSG <"Read Error D0=Error A0=Packet A2=MFM A3=Unit">
+ ELSEIF
+ move.w #$fff,$dff180 ; Weiss=Failure
+ ENDC
+ clr.w du_DiskNumber(a3) ; Ungültige Diskette
+ lea meb_DiskList(a6),a0
+ move.l du_ActPacket(a3),d0 ; Packet ?
+ beq.s 12$ ; nein --->
+ movea.l d0,a1
+ jsr meb_AddHead(a6) ; Request nochmals bearbeiten
+12$:
+ *** Lese-Abschluss bei Error/Success, quittieren falls Success
+
+.ReadFinished: move.b #DS_IDLE,du_Status(a3) ; Nix mehr tun
+ clr.l ActUnit ; Drive freigeben
+ st.b b_prb(a4) ; Motor off
+ bsr ShortDelay
+ move.b du_OffMask(a3),b_prb(a4); Motor off & Select
+ bsr ShortDelay
+ st.b b_prb(a4) ; Drive deselektieren
+ bsr ShortDelay
+
+ tst.w du_DiskNumber(a3) ; War alles OK ?
+ beq.s .Kick ; nein --->
+ move.l du_ActPacket(a3),d0
+ beq.s .Kick ; kein Packet --->
+ movea.l d0,a0
+ bsr ReplyPacket ; Packet (A0) beantworten
+
+.Kick: bsr ProcessNextRequest ; Nächsten Request ankicken
+
+.DoWaitDMAEnd: rts
+
+
+
+*****************************************************************************
+* Checksumme des Tracks berechnen
+* IN: A2=MFM-Buffer-Start (2. SYNC), A3=Unit
+* OUT: D0=Checksumme, A0=Adresse der Checksumme im MFM-Buffer
+
+CalcCheckSum: movem.l d1-d2,-(SP) ; A0 NICHT retten!
+ lea 2(a2),a0 ; Start der Daten nach Sync
+ move.w du_TrackSize(a3),d2 ; Tracklänge in Bytes
+ lsr.w #1,d2 ; /2 gibt # MFM-Longs
+ addq.w #3,d2 ; 2 Headerlongs - 1 für dbf
+ moveq #0,d0 ; D0: Checksumme
+.SumLoop: move.l (a0)+,d1
+ eor.l d1,d0
+ dbf d2,.SumLoop
+ and.l d7,d0 ; Taktbits ausblenden
+ movem.l (SP)+,d1-d2
+ rts
+
+*****************************************************************************
+* MFM-Dekodierung (CDisk-Format)
+* D0 = # Bytes, D7=$55555555, A0=Source (MFM), A1=Destination
+
+MFMDecode: movem.l d0-d5/a0-a1,-(SP)
+ move.w d0,d5 ; Anzahl Bytes
+ andi.w #7,d5 ; D5 := Anzahl Rest-Bytes
+ lsr.w #3,d0 ; D0 := Anzahl LONGS/2
+ bra.s 2$ ; für dbf
+
+1$: movem.l (a0)+,d1/d2/d3/d4 ; 4 MFM-Longs gibt 8 Bytes
+ and.l d7,d1
+ and.l d7,d2
+ and.l d7,d3
+ and.l d7,d4
+ add.l d2,d2
+ add.l d4,d4
+ or.l d2,d1
+ or.l d4,d3
+ move.l d1,(a1)+
+ move.l d3,(a1)+
+2$: dbf d0,1$
+
+ bclr #2,d5 ; mehr als 1 LONG noch ?
+ beq.s 3$ ; nein --->
+ movem.l (a0)+,d1/d2 ; 1 Langwort mehr für Rest
+ and.l d7,d1
+ and.l d7,d2
+ add.l d2,d2
+ or.l d2,d1
+ move.l d1,(a1)+
+3$:
+ movem.l (a0)+,d1/d2 ; 1 Langwort mehr für Rest
+ and.l d7,d1
+ and.l d7,d2
+ add.l d2,d2
+ or.l d2,d1
+
+4$: subq.w #1,d5
+ bmi.s 5$
+ rol.l #8,d1 ; Nächstes Byte
+ move.b d1,(a1)+
+ bra.s 4$
+5$:
+ movem.l (SP)+,d0-d5/a0-a1
+ rts
+
+*****************************************************************************
+* MFM-Kodierung (CDisk-Format)
+* D0 = # Bytes, D7=$55555555, A0=Destination, A1=Source (MFM), A2=MFM-BufferStart
+
+MFMEncode: movem.l d0-d1/a0-a1,-(SP)
+ move.l d0,d1 ; Anzahl Bytes
+ lsr.w #2,d1 ; Anzahl Longs
+ bra.s 2$ ; für dbf
+1$: move.l (a1)+,d0 ; 1 Source-Longwort
+ bsr.s PutD0 ; codieren und nach (A0)++
+2$: dbf d1,1$
+
+ bsr CalcCheckSum ; Prüfsumme der Spur berechnen
+ bsr PutD0 ; und eintragen
+ moveq #0,d0 ; Abschluß-AAAAAAAA
+ bsr PutD0 ; eintragen (wozu? hmmmm..)
+
+ movem.l (SP)+,d0-d1/a0-a1
+ ;; bra SetClockBits
+
+ *** Im ganzen Track Taktbits setzen/löschen, D7=BitMask
+
+SetClockBits: movem.l d0-d3/a0,-(SP)
+ lea 2(a2),a0 ; A0 : MFM-Buffer (OHNE SYNC!!)
+ move.w #WRITEBYTES/2,d3 ; 1 LONG mehr anpassen
+1$: move.l (a0),d0
+ and.l d7,d0 ; Alle Taktbits löschen
+ move.l d0,d2
+ eor.l d7,d2 ; Datenbits invertieren
+ move.l d2,d1
+ lsr.l #1,d1 ; D1: invert. Daten nach rechts
+ bset.l #31,d1
+ lsl.l #1,d2 ; D2: invert. Daten nach links
+ addq.w #1,d2 ; = bset #0,d2
+ and.l d2,d1
+ or.l d1,d0 ; nur 1 falls zwischen 2 Nullen
+ btst.b #0,-1(a0) ; Grenztest nach unten
+ beq.s 2$
+ bclr.l #31,d0
+2$: move.l d0,(a0)+
+ dbf d3,1$
+ movem.l (SP)+,d0-d3/a0
+ rts
+
+ *** D0.L MFM codieren und in (A0)++ eintragen
+
+PutD0: move.l d0,(a0)+
+ lsr.l #1,d0
+ move.l d0,(a0)+
+ rts
+
+**************************************************************************
+
+ *** Wichtige Register initialisieren
+
+GetD7A4A5: movem.l InitVals(PC),d7/a4/a5
+ rts
+
+InitVals: dc.l $55555555 ; D7
+ dc.l ciabase ; A4
+ dc.l custom ; A5
+
+**************************************************************************
+
+ *** Kurz verzögern, nach Schreiben in Hardware-Register
+
+ShortDelay: move.l d0,-(SP)
+ moveq #2,d0 ; 3 Rasterzeilen
+ bsr.s WaitLines
+ move.l (SP)+,d0
+ rts
+
+**************************************************************************
+
+ *** Genau D0.L * 64 Mikrosekunden warten (+- 64 µs)
+
+WaitLines: movem.l d0/d1,-(SP)
+1$: move.b vhposr(a5),d1
+2$: cmp.b vhposr(a5),d1
+ beq.s 2$
+ dbf d0,1$
+ movem.l (SP)+,d0/d1
+ rts
+
+
+***************************************************************************
+* D A T E N (auch im CODE-Segment wegen PC-relativ) *
+***************************************************************************
+
+MFMBuffer: ds.l 1 ; MFM-Buffer + GAPBYTES
+UnitTab: ds.l MAXUNITS ; Unit-Zeiger-Array
+ActUnit: ds.l 1 ; Zeiger auf aktive Unit
+InsertDiskRoutine: ds.l 1 ; User's InsertDisk handler
+
+
+ END
diff --git a/Documentation/GameExec.doc b/Documentation/GameExec.doc
new file mode 100644
index 0000000..e9818bf
--- /dev/null
+++ b/Documentation/GameExec.doc
@@ -0,0 +1,158 @@
+GAME EXEC - The ultimate Amiga operating system for game development
+---------
+
+Version 4.4, 16-Apr-92
+
+© 1987-92 Christian A. Weber, Christian B. Haller, René Straub, Roman Werner
+
+
+
+ *** Erlaubte Einträge in MyExecBase:
+
+ APTR meb_SuperStackUpper ; SuperStack am Anfang (READ ONLY!)
+ WORD meb_AttnFlags ; Kopie von ExecBase->AttnFlags
+ WORD meb_SystemBplcon0 ; Kopie von gfxbase->system_bplcon0
+ BYTE meb_VBlankFrequency ; Kopie von ExecBase->VBlankFrequency
+ BYTE meb_expad2
+
+ BYTE meb_ActualKey ; RawKeyCode
+ BYTE meb_ActualQualifiers ; Qualifier-Bits, (BitNr=KeyCode-$60)
+ BYTE meb_ActualASCIIKey ; ASCII-Code
+ BYTE meb_CheatFlag ; >0 falls Cheat mode on
+
+ STRUCT meb_BobList,lh_SIZEOF ; für die Bobroutine
+ APTR meb_TripleScreen ; für die Bobroutine
+ WORD meb_SignalSet ; für die Bobroutine
+
+ LONG meb_UserData1 ; Frei für den User, am Anfang 0
+ LONG meb_UserData2 ; Frei für den User, am Anfang 0
+
+ STRUCT meb_exreserved,6 ; + pad auf LONG, NICHT benutzen!
+
+ *** Level 3 Interrupt-Vektoren, zum Patchen oder 0 reinschreiben
+
+ UWORD meb_VBLIntPad
+ UWORD meb_VBLIntJump
+ APTR meb_VBLIntVector
+
+ UWORD meb_CopperIntPad
+ UWORD meb_CopperIntJump
+ APTR meb_CopperIntVector
+
+ *** Cia-Interrupt-Vektoren, zum Patchen oder 0 reinschreiben
+
+ APTR meb_CiaATimerAVector
+ APTR meb_CiaATimerBVector
+ APTR meb_CiaAAlarmVector
+ APTR meb_CiaASerialVector
+ APTR meb_CiaAFlagVector
+
+ APTR meb_CiaBTimerAVector
+ APTR meb_CiaBTimerBVector
+ APTR meb_CiaBAlarmVector
+ APTR meb_CiaBSerialVector
+ APTR meb_CiaBFlagVector
+
+
+ *** System-Funktionen (use at your own risk!)
+
+ ULONG meb_SecretMagic ; PRIVAT
+ FUNCTION InitExec ; (ExecEvent) (CRP)
+ FUNCTION ColdReboot ; () ()
+ FUNCTION InitChipMem ; (Address,Size) (A0/D0)
+ FUNCTION InitFastMem ; (Address,Size) (A0/D0)
+ FUNCTION InitDisk ; (Product) (D0)
+ FUNCTION InitKey ; () ()
+ FUNCTION SetCache ; (NewCacheBits) (D0)
+
+ *** Debug-Funktionen
+
+ FUNCTION Debug ; () ()
+
+ *** Speicherverwaltung
+
+ FUNCTION AllocMem ; (Amount) (D0)
+ FUNCTION AllocClearMem ; (Amount) (D0)
+ FUNCTION AllocFastMem ; (Amount) (D0)
+ FUNCTION AllocFastClearMem ;(Amount) (D0)
+ FUNCTION FreeMem ; (Address) (A1)
+ FUNCTION AvailMem ; () ()
+ FUNCTION AvailFastMem ; () ()
+ FUNCTION CheckMem ; () ()
+ FUNCTION CopyMem ; (Src,Dest,Len) (A0/A1/D0)
+ FUNCTION CopyMemQuick ; (Src,Dest,Len) (A0/A1/D0)
+ FUNCTION ClearMem ; (Address,Len) (A0/D0)
+
+ *** Semaphoren
+
+ FUNCTION Disable ; () ()
+ FUNCTION Enable ; () ()
+ FUNCTION OwnBlitter ; () ()
+ FUNCTION DisownBlitter ; () ()
+
+ *** Listenverwaltung
+
+ FUNCTION NewList ; (List) (A0)
+ FUNCTION Enqueue ; (List,Node) (A0/A1)
+ FUNCTION Remove ; (Node) (A1)
+ FUNCTION AddHead ; (List,Node) (A0/A1)
+ FUNCTION AddTail ; (List,Node) (A0/A1)
+ FUNCTION RemHead ; (List) (A0)
+
+ *** Tastatur
+
+ FUNCTION GetKey ; () ()
+ FUNCTION WaitKey ; () ()
+ FUNCTION FlushKeyBuf ; () ()
+ FUNCTION SetMap ; (KeyMap oder 0) (A0)
+ FUNCTION SetResetHandler ; (Handler) (A0)
+ FUNCTION SetCheatText ; (RawKeyCodes) (A0)
+
+ *** Ausgabe
+
+ FUNCTION RawDoFmt ; (wie normal :-)) (...)
+ FUNCTION RawPrintf ; (Stack) (...)
+ FUNCTION PlayCDTrack ; (TrackNumber) (D0)
+ FUNCTION WaitCDTrack ; (nüt) ()
+
+ *** Zufall
+
+ FUNCTION Randomize ; (Value1,Value2) (D0/D1)
+ FUNCTION Random ; (Limit) (D0)
+
+ *** Disk-Routinen
+
+ FUNCTION SetNoDiskHandler ;(Routine) (A0)
+ FUNCTION ReadFile ; (Name,Address) (D0/A0)
+ FUNCTION WriteFile ; (Name,Address) (D0/A0)
+ FUNCTION LoadFile ; (Name) (D0)
+ FUNCTION LoadFastFile ; (Name) (D0)
+ FUNCTION LoadSeg ; (Name) (D0)
+ FUNCTION UnLoadSeg ; (Segment) (A1)
+ FUNCTION BufReadFile ; (Name,Address (D0/A0)
+ FUNCTION BufLoadFile ; (Name) (D0)
+ FUNCTION DeleteFileNode ; (Name) (D0)
+ FUNCTION DeleteFileList ; () ()
+ FUNCTION SendPacket ; (Packet) (A0)
+
+ *** Bob-Routinen
+
+ FUNCTION WaitBlit ; (Custom) (A5)
+ FUNCTION InitDrawBob ; (BitMap) (A0)
+ FUNCTION AddBob ; (NewBob) (A1)
+ FUNCTION RemBob ; (Bob) (A0)
+ FUNCTION RemAllBobs ; () ()
+ FUNCTION RestoreBobList ; (BitMap) (A1)
+ FUNCTION DrawBobList ; (BitMap) (A1)
+ FUNCTION RestoreOneBob ; (Bob,BitMap) (A0/A1)
+ FUNCTION DrawOneBob ; (Bob,BitMap) (A0/A1)
+ FUNCTION AnimateOneBob ; (Bob) (A0)
+ FUNCTION MoveOneBob ; (Bob) (A0)
+ FUNCTION TestPoint ; (X,Y) (D0/D1)
+ FUNCTION SetMovePrg ; (Bob,MPrg,Speed,Step) (A0/A1/D0/D1)
+ FUNCTION SetAnimPrg ; (Bob,APrg,Speed) (A0/A1/D0)
+ FUNCTION SetGlobalClip ; (X,Y) (D0/D1)
+ FUNCTION HandleCollision ; () ()
+ FUNCTION CollOneBob ; (Bob) (A0)
+ FUNCTION FlashBob ; (Bob,Time,Color) (A0/D0/D1)
+ FUNCTION GetBobData ; (Bob) (A0)->A2
diff --git a/Documentation/README b/Documentation/README
new file mode 100644
index 0000000..264a52b
--- /dev/null
+++ b/Documentation/README
@@ -0,0 +1,70 @@
+GAME EXEC - The ultimate Amiga operating system for game development
+---------
+
+Version 4.4, 16-Apr-92
+
+© 1987-92 Christian A. Weber, Christian B. Haller, René Straub, Roman Werner
+
+
+Features
+--------
+
+- Powerful debugging function, such as debug output to serial port or calling
+ ROMCrack, the ultimate Kickstart-based monitor/disassembler by SCA
+
+- Memory managment (Allocate, clear, copy Chip + Fast mem)
+
+- Semaphores (Disable/Enable interrupts, Own/Disown blitter in System mode)
+
+- Linked List management
+
+- Keyboard handler including support for custom keymaps
+
+- Output formatting (printf-style)
+
+- Optional CDTV functions: play audio tracks
+
+- Random number generator
+
+- Powerful interrupt-driven floppy disk routines supporting up to 4 dives
+ supporting PowerPacker-compressed files and loading in the background
+
+- BOBOL® the ultimate Bob Animation System: Bob rendering, double/triple
+ buffering, Animation, collision testing, clipping etc. using a powerful
+ control languange
+
+
+Versions
+--------
+
+There are 3 versions of Game Exec:
+
+- Standard version: Runs completely without Amiga OS
+
+- System version (SysStart): runs within Amiga OS (used for development)
+ this version optionally supports the CDTV
+
+- Ram version (runs without Amiga OS, but uses a FFS ram disk instead of floppy)
+
+
+Modification History
+--------------------
+
+18-May-89 CHW Recreated this file!
+20-Jun-89 CHW Supports 1MB CHIP RAM
+29-Jun-89 CHW Auf Genim2 umgeschrieben
+22-Aug-89 CHW AddHead() added
+27-Aug-89 CHW AddHead() rettet nun die Register (!^%#$@)
+13-Sep-89 CHW CopyMem() rettet nun D0 (grmbl!)
+06-Nov-89 CHW SetCache() added
+27-Nov-89 CHW FastMem support routines added
+04-Feb-90 CHW Zero-Handler & other Guru handlers added
+11-Feb-90 CHW Supervisor-Stack ist jetzt im FAST-RAM
+28-Mar-90 CHW ColdReboot() implementiert, ABORT springt dahin
+18-Sep-90 CHW CheckMem() implementiert und so
+20-Oct-90 CHW Config-File entfernt, MainPrg muss am Anfang sein
+30-Dec-90 CHW Gecrunchte Files werden automatisch entcruncht
+06-Jan-91 CHH BufLoadFile testet ob genug RAM vorhanden ist
+11-Feb-91 CHH BufReadFile eingebaut
+18-Feb-91 CHW Multitasking-fähige Version
+06-May-91 CHW Diskroutine kann jetzt schreiben
diff --git a/EndLabel.S b/EndLabel.S
new file mode 100644
index 0000000..bebbaf8
--- /dev/null
+++ b/EndLabel.S
@@ -0,0 +1,14 @@
+ IDNT EndLabel
+
+ XREF __MyExecBase
+ XDEF __H2_end,_MyExecBase
+
+
+ SECTION data,DATA
+
+_MyExecBase: dc.l __MyExecBase
+ dc.b "EXECEND." ; Endmarkierung
+
+ SECTION last,BSS
+ ds.l 1 ; Sonst exportiert Genam __H2_end nicht ?!
+__H2_end:
diff --git a/Exec.S b/Exec.S
new file mode 100644
index 0000000..dcdcd18
--- /dev/null
+++ b/Exec.S
@@ -0,0 +1,816 @@
+**************************************************************************
+** **
+** MYEXEC - Verschiedene Routinen die so manches Programm braucht **
+** **
+** by Christian A. Weber, Zurich/Switzwerland **
+** **
+**************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 18-May-89 CHW Recreated this file! **
+** 20-Jun-89 CHW Supports 1MB CHIP RAM **
+** 29-Jun-89 CHW Auf Genim2 umgeschrieben **
+** 22-Aug-89 CHW AddHead() added **
+** 27-Aug-89 CHW AddHead() rettet nun die Register (!^%#$@) **
+** 13-Sep-89 CHW CopyMem() rettet nun D0 (grmbl!) **
+** 06-Nov-89 CHW SetCache() added **
+** 27-Nov-89 CHW FastMem support routines added **
+** 04-Feb-90 CHW Zero-Handler & other Guru handlers added **
+** 11-Feb-90 CHW Supervisor-Stack ist jetzt im FAST-RAM **
+** 28-Mar-90 CHW ColdReboot() implementiert, ABORT springt dahin **
+** 18-Sep-90 CHW CheckMem() implementiert und so **
+** 20-Oct-90 CHW Config-File entfernt, MainPrg muss am Anfang sein **
+** 30-Dec-90 CHW Gecrunchte Files werden automatisch entcruncht **
+** 06-Jan-91 CHH BufLoadFile testet ob genug RAM vorhanden ist **
+** 11-Feb-91 CHH BufReadFile eingebaut **
+** 18-Feb-91 CHW Multitasking-fähige Version **
+** 06-May-91 CHW Diskroutine kann jetzt schreiben **
+** **
+**************************************************************************
+
+ IDNT Exec
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+ INCLUDE "exec/macros.i"
+ INCLUDE "zeropage.i"
+ INCLUDE "hardware/custom.i"
+ INCLUDE "hardware/dmabits.i"
+ INCLUDE "hardware/intbits.i"
+
+
+STACKSIZE: EQU 5432 ; Grösse des Super-Stacks
+
+ROMCRACKEXCEPT: EQU $fc2ff4+(2*6) ; ROMCrack Exception-Einspr.
+ROMCRACKSPEC: EQU $fc2ff4+(4*6) ; ROMCrack Special-Einsprung
+
+INITMAGIC: EQU 'INIT' ; steht vor InitExecFunc()
+FFSMAGIC: EQU $444f5301
+
+FN_MAINPRG: EQU $01030010 ; Disk 1, Track 3, 1. File
+
+**************************************************************************
+
+ XREF _custom,__H2_end
+
+ XREF InitChipMemFunc,InitFastMemFunc
+ XREF AllocMemFunc,AllocClearMemFunc
+ XREF AllocFastMemFunc,AllocFastClearMemFunc
+ XREF AvailMemFunc,AvailFastMemFunc,CheckMemFunc
+ XREF FreeMemFunc,ClearMemFunc,CopyMemQuickFunc,CopyMemFunc
+ XREF InitKeyFunc,GetKeyFunc,WaitKeyFunc,FlushKeyBufFunc
+ XREF SetMapFunc,SetResetHandlerFunc,SetCheatTextFunc
+ XREF RawDoFmtFunc,_RawPrintfFunc
+ XREF RandomizeFunc,RandomFunc
+
+ XREF InitDiskFunc,SetNoDiskHandlerFunc,ReadFileFunc
+ XREF WriteFileFunc,LoadFileFunc,LoadFastFileFunc
+ XREF LoadSegFunc,UnLoadSegFunc,SendPacketFunc
+ XREF InitRAMLib,BufReadFileFunc,BufLoadFileFunc
+ XREF DeleteFileNodeFunc,DeleteFileListFunc
+
+ XREF WaitBlit,InitDrawBob,AddBob,RemBob,RemAllBobs
+ XREF RestoreBobList,DrawBobList
+ XREF RestoreOneBob,DrawOneBob
+ XREF AnimateOneBob,MoveOneBob,TestPoint
+ XREF SetMovePrg,SetAnimPrg,SetGlobalClip
+ XREF HandleCollision,CollOneBob,FlashBob,GetBobData
+ IFD SYSTEM
+ XREF ExitKeyFunc
+ XREF InitCDFunc,ExitCDFunc,PlayCDTrackFunc,WaitCDTrackFunc
+ ENDC
+
+ XDEF __MyExecBase,_InitExec,_idstring
+
+ XDEF InitExecFunc,ColdRebootFunc,SetCacheFunc,DebugFunc
+ XDEF NewListFunc,EnqueueFunc,RemoveFunc
+ XDEF AddHeadFunc,AddTailFunc,RemHeadFunc
+ XDEF DisableFunc,EnableFunc
+
+**************************************************************************
+
+ *** Die Zero-Page mit den vielen Vektoren
+
+__MyExecBase:
+Null: DC.L 0 ; $00 := 0 für Sprites usw.
+ BRA.W JumpZero ; $04 Falls jemand nach 0 springt ...
+ DC.L Guru2Handler ; $08
+ DC.L Guru3Handler ; $0C
+ DC.L Guru4Handler ; $10
+ DC.L Guru5Handler ; $14
+ DC.L Guru6Handler ; $18
+ DC.L Guru7Handler ; $1C
+ DC.L Guru8Handler ; $20
+ DC.L Guru9Handler ; $24
+ DC.L GuruAHandler ; $28
+ DC.L GuruBHandler ; $2C
+ DC.L GuruCHandler ; $30
+ DC.L GuruDHandler ; $34
+ DC.L GuruEHandler ; $38
+ DC.L GuruFHandler ; $3C
+ DCB.L 9,0 ; $40-$60 ; Reserved exceptions
+ DC.L DebugFunc ; $64 ; Interrupt Level 1
+ DC.L CiaAServer ; $68 ; Interrupt Level 2
+ DC.L VBLServer ; $6C ; Interrupt Level 3
+ DC.L DebugFunc ; $70 ; Interrupt Level 4
+ DC.L DebugFunc ; $74 ; Interrupt Level 5
+ DC.L CiaBServer ; $78 ; Interrupt Level 6
+ DC.L ColdRebootFunc ; $7C ; Interrupt Level 7
+ DCB.L 16,0 ; $80-$BC ; Trap-Vectors 0-15
+ DC.B "CHW!" ; $C0 ; Kennung für Booter!
+ DCB.L 15,0 ; $C4-$FC ; Reserviert
+
+ *** Tada! Die ExecBase-Struktur
+
+ DC.L 0 ; Nicht debuggen!
+ DC.L 'ICH!' ; ROMCrackMagic für Mem
+ DC.L $1d0000 ; ROMCrackBSS
+ DC.L $1e0000 ; ROMCrackChipMem
+ DC.L ROMCrackText ; ROMCrack's Debug-Text
+
+ *** Private Einträge
+
+ DCB.B mh_SIZEOF,0 ; MemoryRegionHeader
+ DCB.B mh_SIZEOF,0 ; FastMemoryRegionHeader
+ DC.L 0 ; RAMDiskBase
+ DC.L 0 ; RAMDiskSize
+ DC.L FN_MAINPRG ; MainPrgName
+ DC.L $affebad,356789 ; LastRnd1,LastRnd2
+ DCB.B lh_SIZEOF,0 ; DiskList
+ DCB.B lh_SIZEOF,0 ; FileList (für RAMLib)
+ DC.W 0 ; Product-Code
+ DC.B -1 ; IDNestCnt
+ DC.B 0 ; ExecFlags
+
+ *** Erlaubte Einträge
+
+ DC.L 0 ; SuperStackUpper
+ DC.W 0 ; AttnFlags
+ DC.W 0 ; SystemBplcon0
+ DC.B 0 ; VBlankFrequency
+ DC.B 0 ; expad2
+
+ DC.B 0 ; ActualKey
+ DC.B 0 ; ActualQualifiers
+ DC.B 0 ; ActualASCIIKey
+ DC.B 0 ; CheatFlag
+
+ DCB.B lh_SIZEOF,0 ; BobList
+ DC.L 0 ; TripleScreen: Zeiger auf 3. BitMap
+ DC.W 0 ; SignalSet (für Bobroutine)
+
+ DC.L 0 ; UserData1
+ DC.L 0 ; UserData2
+
+ DCB.B 6,0 ; exreserved, pad auf LONG
+
+ DC.W 0 ; LONG-Align
+ DC.W $4EF9 ; VBL-Jmp
+ DC.L 0 ; VBL-Vektor
+
+ DC.W 0 ; LONG-Align
+ DC.W $4EF9 ; Copper-Jmp
+ DC.L 0 ; Copper-Vektor
+
+ DCB.L 2*5,0 ; Cia-Interruptvektoren
+
+ DC.L INITMAGIC ; Steht vor InitExecFunc()
+_InitExec:
+ BRA.W InitExecFunc ; MUSS 1. Funktion sein: FinalBooter.S
+ BRA.W ColdRebootFunc ; MUSS 2. Funktion sein: FinalBooter.S
+ BRA.W InitChipMemFunc
+ BRA.W InitFastMemFunc
+ BRA.W InitDiskFunc
+ BRA.W InitKeyFunc
+ BRA.W SetCacheFunc
+
+ BRA.W DebugFunc
+
+ BRA.W AllocMemFunc
+ BRA.W AllocClearMemFunc
+ BRA.W AllocFastMemFunc
+ BRA.W AllocFastClearMemFunc
+ BRA.W FreeMemFunc
+ BRA.W AvailMemFunc
+ BRA.W AvailFastMemFunc
+ BRA.W CheckMemFunc
+ BRA.W CopyMemFunc
+ BRA.W CopyMemQuickFunc
+ BRA.W ClearMemFunc
+
+ BRA.W DisableFunc
+ BRA.W EnableFunc
+ BRA.W OwnBlitterFunc
+ BRA.W DisownBlitterFunc
+
+ BRA.W NewListFunc
+ BRA.W EnqueueFunc
+ BRA.W RemoveFunc
+ BRA.W AddHeadFunc
+ BRA.W AddTailFunc
+ BRA.W RemHeadFunc
+
+ BRA.W GetKeyFunc
+ BRA.W WaitKeyFunc
+ BRA.W FlushKeyBufFunc
+ BRA.W SetMapFunc
+ BRA.W SetResetHandlerFunc
+ BRA.W SetCheatTextFunc
+
+ BRA.W RawDoFmtFunc
+ BRA.W _RawPrintfFunc
+ BRA.W PlayCDTrackFunc
+ BRA.W WaitCDTrackFunc
+
+ BRA.W RandomizeFunc
+ BRA.W RandomFunc
+
+ BRA.W SetNoDiskHandlerFunc
+ BRA.W ReadFileFunc
+ BRA.W WriteFileFunc
+ BRA.W LoadFileFunc
+ BRA.W LoadFastFileFunc
+ BRA.W LoadSegFunc
+ BRA.W UnLoadSegFunc
+ BRA.W BufReadFileFunc
+ BRA.W BufLoadFileFunc
+ BRA.W DeleteFileNodeFunc
+ BRA.W DeleteFileListFunc
+ BRA.W SendPacketFunc
+
+ BRA.W WaitBlit
+ BRA.W InitDrawBob
+ BRA.W AddBob
+ BRA.W RemBob
+ BRA.W RemAllBobs
+ BRA.W RestoreBobList
+ BRA.W DrawBobList
+ BRA.W RestoreOneBob
+ BRA.W DrawOneBob
+ BRA.W AnimateOneBob
+ BRA.W MoveOneBob
+ BRA.W TestPoint
+ BRA.W SetMovePrg
+ BRA.W SetAnimPrg
+ BRA.W SetGlobalClip
+ BRA.W HandleCollision
+ BRA.W CollOneBob
+ BRA.W FlashBob
+ BRA.W GetBobData
+
+
+ IFNE (*-Null)-__EXECBASESIZE
+ Fail "ExecBase structure size mismatch!"
+ ENDC
+
+
+ BRA.W UndefdFunc
+ BRA.W UndefdFunc
+ BRA.W UndefdFunc
+ BRA.W UndefdFunc
+
+
+ DCB.B 7,0
+VersTag: DC.B 0,"$VER: "
+
+_idstring:
+ROMCrackText: DC.B "GAME EXEC Operating System V4.4 (16-Apr-92)",0
+ DC.B "Copyright (c) 1989 - 1992 by Christian A. Weber,"
+ DC.B "Bruggerweg 2, CH-8037 Zuerich, Switzerland.",10,0
+ DC.B "All Rights Reserved.",10,0
+ DC.B "Greetings to Chris Haller, René Straub, Roman Werner",10,0
+ DCB.B 27,0
+
+ExceptText: DC.B "Exception "
+exno: DC.B "xx",0
+
+JumpZeroText: DC.B "Caught jump to 0",0
+UndefdText: DC.B "Undef'd routine",0
+ EVEN
+
+
+**************************************************************************
+** E X E C - I N I T I A L I S I E R U N G
+**************************************************************************
+
+ *** SYSTEM:
+ *** D0=AttnFlags, D1=SystemBplcon0, D2=VBlankFrequency,
+ *** D3=Product Code, A0=CHIPRAM-Base, A1=CHIPRAM-Ende,
+ *** A2=FASTRAM-Base, A3=FASTRAM-Ende D4=MainPrg-Name
+
+ *** SONST:
+ *** D0=AttnFlags, D1=SystemBplcon0, D2=VBlankFrequency,
+ *** D3=Product Code, A0=RAMDiskBase, A1=RAMDiskSize,
+ *** A2=FASTRAM-Base, A3=FASTRAM-Ende A7=CHIPRAM-Ende-8
+
+InitExecFunc:
+ IFND SYSTEM
+ move #$2700,sr
+ ENDC
+ lea _custom,a5
+ lea __MyExecBase(PC),a6
+
+ *** System-Status initialisieren (NUR 1x , NICHT BEI RESTART!)
+
+ tst.b meb_VBlankFrequency(a6) ; ExecBase schon installiert?
+ bne.s .NotFirst ; ja --->
+
+ move.w d0,meb_AttnFlags(a6)
+ move.w d1,meb_SystemBplcon0(a6)
+ move.b d2,meb_VBlankFrequency(a6)
+ move.w d3,meb_ProductCode(a6)
+ IFND DISKVERSION
+ move.l d4,meb_MainPrgName(a6)
+ ENDC
+
+ IFD SYSTEM
+ move.l (SP)+,ColdRebootJmp+2 ; Return-Adresse
+ move.l a0,meb_ChipMRHeader+mh_Lower(a6)
+ move.l a1,meb_ChipMRHeader+mh_Upper(a6)
+ ELSEIF
+ move.l a0,meb_RAMDiskBase(a6) ; Muss 0 sein falls kein RAM!
+ move.l a1,meb_RAMDiskSize(a6) ; Muss 0 sein falls kein RAM!
+
+ move.l #__H2_end,d0 ; Ende von Exec's BSS
+ addq.l #7,d0
+ andi.b #$f8,d0 ; Modulo-8 aufrunden
+ move.l d0,meb_ChipMRHeader+mh_Lower(a6)
+ move.l SP,meb_ChipMRHeader+mh_Upper(a6)
+ ENDC
+ move.l a2,meb_FastMRHeader+mh_Lower(a6)
+ move.l a3,meb_FastMRHeader+mh_Upper(a6)
+
+ *** StackPointer initialisieren (ins FAST-RAM falls vorhanden)
+
+ lea meb_FastMRHeader+mh_Upper(a6),a0
+ tst.l (a0)
+ bne.s 1$ ; FAST-RAM vorhanden --->
+ lea meb_ChipMRHeader+mh_Upper(a6),a0
+1$:
+ move.l (a0),d0 ; Alte Obergrenze
+ move.l d0,meb_SuperStackUpper(a6) ; nach StackPointer
+ sub.l #STACKSIZE,d0 ; Stack-Grösse wegzählen
+ move.l d0,(a0) ; Neue Obergrenze setzen
+
+ *** VBL und Copper-Interrupt-Server installieren falls SYSTEM
+
+ IFD SYSTEM
+ move.l a6,-(SP)
+ movea.l 4,a6
+
+ moveq #INTB_VERTB,d0
+ lea MyVertInt(PC),a1
+ JSRLIB AddIntServer
+
+ moveq #INTB_COPER,d0
+ lea MyCopInt(PC),a1
+ JSRLIB AddIntServer
+
+ movea.l (SP)+,a6
+
+ bsr InitCDFunc
+ ENDC
+
+.NotFirst:
+
+ *** Speicherverwaltung initialisieren
+
+ movea.l meb_SuperStackUpper(a6),SP ; StackPointer holen
+
+ movea.l meb_ChipMRHeader+mh_Lower(a6),a0
+ move.l meb_ChipMRHeader+mh_Upper(a6),d0
+ sub.l a0,d0 ; D0 := Länge
+ jsr meb_ClearMem(a6) ; ** DEBUG ** Cracker-Schutz: Speicher mit Muster füllen
+ jsr meb_InitChipMem(a6)
+
+ movea.l meb_FastMRHeader+mh_Lower(a6),a0
+ move.l meb_FastMRHeader+mh_Upper(a6),d0
+ sub.l a0,d0 ; D0 := Länge
+ beq.s 2$ ; Kein FAST-RAM --->
+ jsr meb_ClearMem(a6) ; ** DEBUG ** Cracker-Schutz: Speicher mit Muster füllen
+ jsr meb_InitFastMem(a6)
+2$:
+ *** Jenes Zeugs initialisieren
+
+ IFND SYSTEM
+ move.w #$7fff,intena(a5) ; Alle Interrupts off
+ move.w #$7fff,intreq(a5) ; Interrupt-Requests löschen
+ move #$2000,sr ; Interrupt Level 0
+ move.w #INTF_SETCLR|INTF_INTEN|INTF_VERTB|INTF_COPER,intena(a5)
+ move.w #$7fff,dmacon(a5) ; Alle DMAs off
+ move.w #DMAF_SETCLR|DMAF_MASTER,dmacon(a5)
+ ENDC
+ jsr meb_InitKey(a6) ; Tastatur on
+ jsr meb_InitDisk(a6) ; Diskroutine on
+ bsr InitRAMLib ; RAMLib initialisieren
+
+ *** 1. File einladen & starten
+
+ move.l meb_MainPrgName(a6),d0 ; 1. Modul
+ jsr meb_LoadSeg(a6) ; meinprg laden
+ movea.l d0,a0 ; Muss A0 sein, User weiss es!
+ jmp (a0) ; A6 muss MyExecBase sein!
+
+**************************************************************************
+
+ *** System resetten (wir sind im Supervisor)
+
+ColdRebootFunc:
+ IFD SYSTEM
+ bsr ExitCDFunc
+ bsr ExitKeyFunc
+
+ move.l a6,-(SP)
+ movea.l 4,a6
+
+ moveq #INTB_VERTB,d0
+ lea MyVertInt(PC),a1
+ JSRLIB RemIntServer
+
+ moveq #INTB_COPER,d0
+ lea MyCopInt(PC),a1
+ JSRLIB RemIntServer
+
+ movea.l (SP)+,a6
+
+ColdRebootJmp: jmp (1$).L ; Zum Patchen
+1$:
+ ENDC
+
+ IFD DISKVERSION
+ btst #AFB_68020,meb_AttnFlags+1(a6) ; MMU ?
+ beq.s 2$ ; nein --->
+ clr.l -(SP) ; Code für MMU off
+ move.l SP,a0
+ dc.w $f010,$4000 ; pmove (a0),tc
+2$: nop
+ nop
+ lea 2,a0
+ RESET
+ jmp (a0)
+ ENDC
+
+ IFD RAMVERSION
+ jmp $1FFFFA ; ABORT
+ ENDC
+
+
+**************************************************************************
+* Level 3 Interrupt Server
+
+ IFD SYSTEM
+
+VBLServer: EQU 0
+
+MyVertInt: dc.l 0,0
+ dc.b 0,60
+ dc.l _idstring
+ dc.l __MyExecBase
+ dc.l 1$
+
+ * D1/A0-A1/A5-A6 = Scratch
+
+1$: lea _custom,a5
+ movea.l a1,a6 ; _MyExecBase
+ tst.l meb_VBLIntVector(a6)
+ beq.s 2$
+ jsr meb_VBLIntJump(a6)
+2$: movea.l a5,a0 ; Custom für Gfx-IntServer
+ moveq.l #0,d0 ; Set Z bit
+ rts
+
+MyCopInt: dc.l 0,0
+ dc.b 0,60
+ dc.l _idstring
+ dc.l __MyExecBase
+ dc.l 1$
+
+1$: lea _custom,a5
+ movea.l a1,a6 ; _MyExecBase
+ tst.l meb_CopperIntVector(a6)
+ beq.s 2$
+ jsr meb_CopperIntJump(a6)
+2$: moveq.l #0,d0 ; Set Z bit
+ rts
+
+ ELSEIF
+
+VBLServer: movem.l a5/a6,-(SP)
+ lea _custom,a5 ; User weiss das!
+ lea __MyExecBase(PC),a6 ; User weiss das!
+ btst.b #INTB_VERTB,intreqr+1(a5)
+ beq.s 2$
+ tst.l meb_VBLIntVector(a6)
+ beq.s 1$
+ jsr meb_VBLIntJump(a6)
+1$: move.w #INTF_VERTB,intreq(a5)
+2$:
+ btst.b #INTB_COPER,intreqr+1(a5)
+ beq.s 4$
+ tst.l meb_CopperIntVector(a6)
+ beq.s 3$
+ jsr meb_CopperIntJump(a6)
+3$: move.w #INTF_COPER,intreq(a5)
+4$:
+ movem.l (SP)+,a5/a6
+ rte
+ ENDC
+
+**************************************************************************
+* CIA Interrupt Server
+
+ IFD SYSTEM
+
+CiaAServer: EQU 0
+CiaBServer: EQU 0
+
+ ELSEIF
+
+CiaAServer: movem.l d0/d2/a0/a2/a5/a6,-(SP) ; ACHTUNG: unten gleich!
+ lea _custom,a5 ; User weiss das!
+ lea __MyExecBase(PC),a6 ; User weiss das!
+ move.w #$0008,intreq(a5) ; Interruptrequest löschen
+ move.b $bfed01,d2 ; ICAA ICR auslesen
+ lea meb_CiaATimerAVector(a6),a2 ; Vektor-Basis
+ bra.s CiaCommon
+
+CiaBServer: movem.l d0/d2/a0/a2/a5/a6,-(SP) ; ACHTUNG: oben gleich!
+ lea _custom,a5 ; User weiss das!
+ lea __MyExecBase(PC),a6 ; User weiss das!
+ move.w #$2000,intreq(a5) ; Interruptrequest löschen
+ move.b $bfdd00,d2 ; ICAB ICR auslesen
+ lea meb_CiaBTimerAVector(a6),a2 ; Vektor-Basis
+ ;; bra.s CiaCommon
+
+CiaCommon: lsr.b #1,d2 ; Timer A Interrupt ?
+ bcc.s 1$ ; Nein --->
+ move.l (a2),d0 ; Vektor gültig ?
+ beq.s 1$ ; nein --->
+ movea.l d0,a0
+ jsr (a0)
+1$:
+ lsr.b #1,d2 ; Timer B Interrupt ?
+ bcc.s 2$ ; Nein --->
+ move.l 4(a2),d0 ; Vektor gültig ?
+ beq.s 2$ ; nein --->
+ movea.l d0,a0
+ jsr (a0)
+2$:
+ lsr.b #1,d2 ; Alarm Interrupt ?
+ bcc.s 3$ ; Nein --->
+ move.l 8(a2),d0 ; Vektor gültig ?
+ beq.s 3$ ; nein --->
+ movea.l d0,a0
+ jsr (a0)
+3$:
+ lsr.b #1,d2 ; Serial Interrupt ?
+ bcc.s 4$ ; Nein --->
+ move.l 12(a2),d0 ; Vektor gültig ?
+ beq.s 4$ ; nein --->
+ movea.l d0,a0
+ jsr (a0)
+4$:
+ lsr.b #1,d2 ; Flag Interrupt ?
+ bcc.s 5$ ; Nein --->
+ move.l 16(a2),d0 ; Vektor gültig ?
+ beq.s 5$ ; nein --->
+ movea.l d0,a0
+ jsr (a0)
+5$:
+ movem.l (SP)+,d0/d2/a0/a2/a5/a6
+ rte
+
+ ENDC
+
+**************************************************************************
+** E X C E P T I O N - H A N D L E R
+**************************************************************************
+
+ *** Die Einsprünge von den ZeroPage-Vektoren:
+
+GuruHandler: bsr.s CalcGuru
+;;Guru1Handler: bsr.s CalcGuru
+Guru2Handler: bsr.s CalcGuru
+Guru3Handler: bsr.s CalcGuru
+Guru4Handler: bsr.s CalcGuru
+Guru5Handler: bsr.s CalcGuru
+Guru6Handler: bsr.s CalcGuru
+Guru7Handler: bsr.s CalcGuru
+Guru8Handler: bsr.s CalcGuru
+Guru9Handler: bsr.s CalcGuru
+GuruAHandler: bsr.s CalcGuru
+GuruBHandler: bsr.s CalcGuru
+GuruCHandler: bsr.s CalcGuru
+GuruDHandler: bsr.s CalcGuru
+GuruEHandler: bsr.s CalcGuru
+GuruFHandler: bsr.s CalcGuru
+ nop ; Damit letzter Offset != 0
+
+CalcGuru: subi.l #GuruHandler,(SP) ; Vektornummer erzeugen
+ lsr.w 2(SP)
+ cmpi.w #$4ef9,ROMCRACKSPEC ; Ist's unsere Kickstart?
+ bne.s 1$ ; Nein --->
+ jmp ROMCRACKEXCEPT
+1$: move.l #ExceptText,meb_ROMCrackDebugText+__MyExecBase
+ move.w 2(SP),d0
+ lsr.w #4,d0
+ add.b #'0',d0
+ move.b d0,exno
+ move.w 2(SP),d0
+ and.w #15,d0
+ add.b #'0',d0
+ move.b d0,exno+1
+ bra ColdRebootFunc
+
+
+**************************************************************************
+* Handler für JMP 0
+
+JumpZero: move.l #JumpZeroText,meb_ROMCrackDebugText+__MyExecBase
+ bra.s DebugFunc
+
+ *** ROMCrack aufrufen
+
+UndefdFunc: move.l #UndefdText,$110
+
+DebugFunc: cmpi.w #$4ef9,ROMCRACKSPEC ; Ist's unsere Kickstart?
+ bne.s 1$ ; Nein --->
+ jmp ROMCRACKSPEC
+1$: bra ColdRebootFunc
+
+
+**************************************************************************
+** E X E C - R O U T I N E N
+**************************************************************************
+
+**************************************************************************
+* Cache D0 setzen
+
+SetCacheFunc:
+ IFD SYSTEM
+ XREF @SetCACR
+ bra @SetCACR
+ ELSEIF
+ btst.b #AFB_68020,meb_AttnFlags+1(a6) ; Cache vorhanden ?
+ beq.s 1$ ; nein --->
+ dc.w $4E7B,$0002 ; movec d0,cacr
+1$: rts
+ ENDC
+
+**************************************************************************
+* Blitter reservieren
+
+OwnBlitterFunc:
+ IFD SYSTEM
+ XREF _GfxBase
+ move.l a6,-(SP)
+ movea.l _GfxBase,a6
+ JSRLIB OwnBlitter
+ JSRLIB WaitBlit
+ movea.l (SP)+,a6
+ ELSEIF
+PlayCDTrackFunc:
+WaitCDTrackFunc:
+ ENDC
+ rts
+
+**************************************************************************
+* Blitter freigeben
+
+DisownBlitterFunc:
+ IFD SYSTEM
+ move.l a6,-(SP)
+ movea.l _GfxBase,a6
+ JSRLIB WaitBlit
+ JSRLIB DisownBlitter
+ movea.l (SP)+,a6
+ ENDC
+ rts
+
+**************************************************************************
+* Neue Liste initialisieren, A0: Liste
+
+NewListFunc: move.l a0,lh_Head(a0)
+ addq.l #lh_Tail,(a0) ; Head zeigt auf Tail
+ clr.l lh_Tail(a0) ; Tail ist immer 0
+ move.l a0,lh_TailPred(a0) ; TailPred zeigt auf Head
+ rts
+
+**************************************************************************
+* Node in Liste einfügen (nach Priorität), A0: Liste, A1: Node
+
+EnqueueFunc: movem.l d0-d1/a0,-(SP)
+ bsr.s DisableFunc
+ move.b ln_Pri(a1),d1
+ move.l lh_Head(a0),d0
+1$: movea.l d0,a0
+ move.l ln_Succ(a0),d0
+ beq.s 2$ ; Ende der Liste --->
+ cmp.b ln_Pri(a0),d1 ; Priorität kleiner oder gleich ?
+ ble.s 1$ ; ja ---> weitersuchen
+2$: move.l ln_Pred(a0),d0
+ move.l a1,ln_Pred(a0)
+ move.l a0,ln_Succ(a1)
+ move.l d0,ln_Pred(a1)
+ movea.l d0,a0
+ move.l a1,ln_Succ(a0)
+ bsr.s EnableFunc
+ movem.l (SP)+,d0-d1/a0
+ rts
+
+**************************************************************************
+* Node aus Liste entfernen, A1: Node
+
+RemoveFunc: movem.l a0/a1,-(SP)
+ bsr.s DisableFunc
+ movea.l ln_Succ(a1),a0
+ movea.l ln_Pred(a1),a1
+ move.l a0,ln_Succ(a1)
+ move.l a1,ln_Pred(a0)
+ bsr.s EnableFunc
+ movem.l (SP)+,a0/a1
+ rts
+
+**************************************************************************
+* Node an den Anfang der Liste anhängen, A0: Liste, A1: Node
+
+AddHeadFunc: movem.l d0/a0/a1,-(SP)
+ bsr.s DisableFunc
+ move.l lh_Head(a0),d0
+ move.l a1,lh_Head(a0)
+ movem.l d0/a0,ln_Succ(a1)
+ movea.l d0,a0
+ move.l a1,ln_Pred(a0)
+ bsr.s EnableFunc
+ movem.l (SP)+,d0/a0/a1
+ rts
+
+**************************************************************************
+* Interrupts sperren mit IDNestCnt und so
+
+DisableFunc:
+ IFD SYSTEM
+ move.l a6,-(SP)
+ movea.l 4,a6
+ JSRLIB Disable
+ movea.l (SP)+,a6
+ ELSEIF
+ move.w #$4000,$dff09a ; Master interrupt off
+ addq.b #1,meb_IDNestCnt(a6) ; INC counter
+ ENDC
+ rts
+
+**************************************************************************
+* Interrupts zulassen mit IDNestCnt und so
+
+EnableFunc:
+ IFD SYSTEM
+ move.l a6,-(SP)
+ movea.l 4,a6
+ JSRLIB Enable
+ movea.l (SP)+,a6
+ ELSEIF
+ subq.b #1,meb_IDNestCnt(a6)
+ bge.s 1$
+ move.w #$c000,$dff09a
+1$:
+ ENDC
+ rts
+
+**************************************************************************
+* Node ans Ende der Liste anhängen, A0: Liste, A1: Node
+
+AddTailFunc: movem.l d0/a0/a1,-(SP)
+ bsr.s DisableFunc
+ lea lh_Tail(a0),a0
+ move.l ln_Pred(a0),d0
+ move.l a1,ln_Pred(a0)
+ move.l a0,ln_Succ(a1)
+ move.l d0,ln_Pred(a1)
+ move.l d0,a0
+ move.l a1,ln_Succ(a0)
+ bsr.s EnableFunc
+ movem.l (SP)+,d0/a0/a1
+ rts
+
+**************************************************************************
+* Ersten Node aus Liste entfernen, A0: Liste gibt D0: Node, CCR
+
+RemHeadFunc: movem.l a0/a1,-(SP)
+ bsr.s DisableFunc
+ move.l lh_Head(a0),a1
+ move.l ln_Succ(a1),d0
+ beq.s 1$
+ move.l d0,lh_Head(a0)
+ exg d0,a1
+ move.l a0,ln_Pred(a1)
+1$: bsr.s EnableFunc
+ movem.l (SP)+,a0/a1
+ tst.l d0
+ rts
+
+**************************************************************************
+
+ END
diff --git a/FFS.S b/FFS.S
new file mode 100644
index 0000000..8e00927
--- /dev/null
+++ b/FFS.S
@@ -0,0 +1,254 @@
+***************************************************************************
+** **
+** FFS.S - FastFileSystem-Laderoutine (2. Generation) **
+** **
+***************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** Steinzeit RS Created this file! **
+** 01-Sep-89 CHW Adaptiert für Exec (Packet-Interface) **
+** ??-Nov-89 CHW File-Size/512-Bytes-Guru-Bug fixed (GRRRR!) **
+** 18-Sep-90 CHW 74-Block-Bug gefunden, (2 Tage futsch! #@$*&!) **
+** **
+** 19-Sep-90 CHW Neu programmiert, ist 200 Bytes kürzer worden :-) **
+** 29-Dec-90 CHW Pure-Flag bedeutet File ist gecruncht **
+** **
+***************************************************************************
+
+ OPT OW6+
+
+ IDNT FastFileSystem
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+
+CRUNCH
+ IFD RAMVERSION
+
+
+ XDEF ProcessFFSPacket
+
+***************************************************************************
+
+BLOCKSIZE: EQU 512 ; Grösse eines Disk-Blocks in Bytes
+ST.FILE: EQU -3 ; SubTyp eines Files
+
+ STRUCTURE FileHeaderBlock,0
+
+ ULONG fh_Type ; 0 T.SHORT
+ ULONG fh_OwnKey ; 1 Zeiger auf sich selbst
+ ULONG fh_HighSeq ; 2 Anzahl hier vermerkter Datenblöcke
+ ULONG fh_DataSize ; 3 Anzahl der benutzten Datenblöcke
+ ULONG fh_FirstData ; 4 Erster Datenblock
+ ULONG fh_CheckSum ; 5 Checksumme
+ STRUCT fh_BlockPtrs,4*72 ; 6 Zeiger auf Datenblöcke (rückwärts!)
+ LABEL fh_BlockPtrEnd ; 78
+ ULONG fh_unused78 ; 78
+ ULONG fh_unused79 ; 79
+ ULONG fh_Protect ; 80 Protection-Bits
+ ULONG fh_FileSize ; 81 Grösse der Datei in Bytes
+ STRUCT fh_Comment,4*23 ; 82 Kommentar als BCPL-String
+ ULONG fh_Days ; 105 Datum und Zeit der Erstellung
+ ULONG fh_Mins ; 106
+ ULONG fh_Ticks ; 107
+ STRUCT fh_Name,4*16 ; 108 Dateiname als BCPL-String
+ ULONG fh_HashChain ; 124
+ ULONG fh_Parent ; 125 Zeiger auf Ursprungs-Directory
+ ULONG fh_Extension ; 126 Null oder Zeiger auf Extension
+ ULONG fh_SecondaryType ; 127 Sekundärtyp (ST.FILE)
+
+ LABEL fh_SIZEOF
+
+ IFNE fh_SIZEOF-BLOCKSIZE
+ FAIL "Bad FileHeaderBlock structure!"
+ ENDC
+
+***************************************************************************
+* CDisk-Packet (A0) abarbeiten (File aus der RAMDisk laden)
+
+ProcessFFSPacket:
+ movem.l d0-d2/d7/a0-a3/a5,-(SP)
+ movea.l a0,a2 ; A2 : Packet
+ move.l #BLOCKSIZE,d7 ; D7 : BlockSize (immer)
+
+ move.l d7,d0 ; 1 Block
+ jsr meb_AllocFastMem(a6) ; reservieren
+ movea.l d0,a5 ; a5 : Block-Buffer
+
+ movea.l dp_FileName(a2),a0
+ bsr FindFile ; Fileheader suchen
+ bne.s 1$ ; OK --->
+ MSG <"FFS: File not found, A0=name A2=packet">
+ jmp meb_ColdReboot(a6)
+1$:
+ bsr GetBlock ; Fileheader laden
+ moveq.l #ST.FILE,d0
+ cmp.l fh_SecondaryType(a5),d0 ; Ist's ein File ?
+ beq.s 2$ ; ja --->
+ MSG <"FFS: Not a file, A0=name A2=packet">
+ jmp meb_ColdReboot(a6)
+2$:
+ move.l fh_FileSize(a5),d2 ; D2 : Datei-Größe in Bytes
+ move.l d2,dp_FileSize(a2) ; ins Packet eintragen
+
+ IFD CRUNCH
+ btst.b #5,fh_Protect+3(a5) ; Pure-Bit gesetzt ?
+ beq.s .NotCrunched
+ bset.b #DPB_CRUNCHED,dp_Flags(a2)
+ move.l fh_FirstData(a5),d0 ; 1. Datenblock
+ bsr GetBlock
+ moveq.l #PP_SAVEMARGIN,d2 ; Sicherheitsabstand
+ add.l (a5),d2 ; Plus ungecrunchte Länge
+ movea.l dp_FileName(a2),a0
+ bsr FindFile ; Fileheader suchen
+ bsr GetBlock ; Fileheader laden
+.NotCrunched:
+ ENDC
+ btst.b #DPB_ALLOCMEM,dp_Flags(a2) ; CHIP-Alloc gewünscht ?
+ beq.s .NoChipAlloc ; nein --->
+ move.l d2,d0 ; File-Länge
+ jsr meb_AllocMem(a6)
+ bra.s .AllocCont ; --->
+.NoChipAlloc:
+ btst.b #DPB_ALLOCFASTMEM,dp_Flags(a2) ; FAST-Alloc gewünscht?
+ beq.s .NoFastAlloc ; nein --->
+ move.l d2,d0 ; File-Länge
+ jsr meb_AllocFastMem(a6)
+.AllocCont: move.l d0,dp_Address(a2) ; Adresse ins Packet
+.NoFastAlloc:
+ IFD CRUNCH
+ move.l fh_FileSize(a5),d2 ; D2 : Datei-Größe in Bytes
+ ENDC
+ movea.l dp_Address(a2),a1 ; A1 : Ziel-Adresse
+.ExtLoop: move.l fh_HighSeq(a5),d1 ; D1 : Datablock-Zähler
+ lea fh_BlockPtrEnd(a5),a3 ; A3 : Datenblockpointer-Zeiger
+ bra.s .BlockDBF ; Für DBF
+.BlockLoop: move.l -(a3),d0
+ cmp.l d7,d2 ; Weniger als ein Block übrig ?
+ blo.s .LastBlock ; ja ---> Spezialfall
+ movea.l a1,a0 ; Destination
+ bsr ReadBlock ; Datenblock nach (A0) lesen
+ adda.l d7,a1 ; destination += BLOCKSIZE
+ sub.l d7,d2 ; file size -= BLOCKSIZE
+.BlockDBF dbf d1,.BlockLoop
+
+ move.l fh_Extension(a5),d0 ; File-Extension vorhanden ?
+ beq.s .End ; nein ---> fertig
+ bsr GetBlock ; Extension-Block nach (a5)
+ bra.s .ExtLoop ; ---> Loop
+
+.LastBlock bsr GetBlock ; letzten Block nach (a5)
+ movea.l a5,a0 ; Source
+ move.l d2,d0 ; Size
+ jsr meb_CopyMem(a6) ; Daten kopieren
+.End:
+ movea.l a5,a1 ; Hilfs-Block
+ jsr meb_FreeMem(a6) ; freigeben
+
+ movem.l (SP)+,d0-d2/d7/a0-a3/a5
+ rts
+
+***************************************************************************
+* File mit Namen (A0) finden und Header-Blocknummer nach D0 / CCR
+
+FindFile: movem.l d1-d3/a0-a2,-(SP)
+
+ move.l meb_RAMDiskSize(a6),d0 ; Grösse der Disk
+ lsr.l #5,d0 ; /BLOCKSIZE/2 gibt Mitte
+ lsr.l #5,d0
+ bsr GetBlock ; Rootblock einlesen
+
+ bsr CalcHash ; Hashwert von (A0) berechnen
+ beq.s .FileNotFound ; ungültig --->
+ move.l 0(a5,d0.w),d0 ; D0 : FileHeader-Blocknummer
+
+.BlockLoop: beq.s .FileNotFound ; Nummer ungültig --->
+ bsr GetBlock ; Fileheaderblock einlesen
+
+ movea.l a0,a1 ; Filename
+ lea fh_Name(a5),a2 ; Name im Fileheader
+ moveq.l #0,d3
+ move.b (a2)+,d3 ; Stringlänge
+ bra.s .Dbf
+.CmpLoop: move.b (a1)+,d1
+ move.b (a2)+,d2
+ andi.b #$df,d1 ; ToUpper
+ andi.b #$df,d2 ; ToUpper
+ cmp.b d2,d1
+ bne.s .NextHash ; Nicht gleich ---> weitersuchen
+.Dbf: dbf d3,.CmpLoop
+
+.FileNotFound: tst.l d0 ; CCR richtig setzen
+ movem.l (SP)+,d1-d3/a0-a2
+ rts
+
+.NextHash: move.l fh_HashChain(a5),d0 ; Liste durchackern
+ bra.s .BlockLoop ; ---> Loop
+
+***************************************************************************
+* Hashwert des C-Strings (A0) berechnen
+
+CalcHash: movem.l d1/a0-a1,-(SP)
+ moveq.l #0,d0 ; Hashwert resetten
+ tst.b (a0)
+ beq .End
+
+ movea.l a0,a1 ; Hash := strlen(name)
+1$: tst.b (a1)+
+ beq.s 2$
+ addq.l #1,d0
+ bra.s 1$
+2$:
+.Loop: moveq.l #0,d1
+ move.b (a0)+,d1 ; Nächstes Zeichen
+ beq.s 4$ ; Null ---> fertig
+ cmpi.w #'a',d1
+ blo.s 3$
+ cmpi.w #'z',d1
+ bhi.s 3$
+ andi.b #$df,d1 ; char = ToUpper(char)
+3$:
+ mulu.w #13,d0 ; Hash *= 13
+ add.l d1,d0 ; Hash += char
+ andi.l #$7ff,d0 ; Hash &= $7FF
+ bra.s .Loop
+4$:
+ divu.w #72,d0 ; Hash %= 72
+ swap d0
+ ext.l d0
+ addq.l #6,d0 ; Hash += 6 (Tabellenanfang)
+
+.End: lsl.l #2,d0 ; Hash *= 4, affect Z bit
+ movem.l (SP)+,d1/a0-a1
+ rts
+
+***************************************************************************
+* Einen Block (D0=Blocknummer) in Buffer (A5) einlesen
+
+GetBlock: move.l a0,-(SP)
+ movea.l a5,a0
+ bsr.s ReadBlock
+ movea.l (SP)+,a0
+ rts
+
+***************************************************************************
+* Einen Block (D0=Blocknummer) an Adresse (A0) einlesen
+
+ReadBlock: movem.l d0/a0-a1,-(SP)
+ lsl.l #5,d0 ; Blocknr *BLOCKSIZE = Offset
+ lsl.l #4,d0
+ move.l a0,a1 ; Destination
+ movea.l d0,a0 ; Offset
+ add.l meb_RAMDiskBase(a6),a0 ; Plus Basis-Adresse
+ move.l d7,d0 ; Länge: 1 Block
+ jsr meb_CopyMem(a6)
+ movem.l (SP)+,d0/a0-a1
+ rts
+
+ ENDC
+
+***************************************************************************
+
+ END
diff --git a/FinalBooter.S b/FinalBooter.S
new file mode 100644
index 0000000..aa7f0c5
--- /dev/null
+++ b/FinalBooter.S
@@ -0,0 +1,312 @@
+**************************************************************************
+** **
+** FinalBooter - Lädt und startet Exec. **
+** **
+**************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 19-May-89 CHW Created this file from Auto/Start.S **
+** 04-Jun-89 CHW Testet jetzt ob RAMDisk vorhanden ist **
+** 20-Jun-89 CHW Unterstützt jetzt 1MB CHIP-RAM wenn man's hat **
+** 21-Jun-89 CHW ENV-Variable 'RAMDISKBASE' implementiert **
+** 27-Jun-89 CHW Converted to genim2 **
+** 24-Aug-89 CHW Disk-Version implemented **
+** 30-Aug-89 CHW Adapted from Start to FinalBooter **
+** 27-Nov-89 CHW Fast-RAM implemented **
+** 15-Dec-89 CHW Code cleaned up, setzt jetzt VBR auf 0 if 68010+ **
+** 28-Mar-90 CHW Abort springt nach ColdReset() statt $fc0002 **
+** 01-Mar-91 CHW Benutzt jetzt die System-Includefiles **
+** **
+**************************************************************************
+
+ OPT O+,OW-,O5-
+
+ IDNT FinalBooter
+ SECTION text,CODE
+
+ INCLUDE "exec/types.i"
+ INCLUDE "exec/macros.i"
+ INCLUDE "exec/memory.i"
+ INCLUDE "exec/nodes.i"
+ INCLUDE "exec/ports.i"
+ INCLUDE "exec/io.i"
+ INCLUDE "exec/execbase.i"
+ INCLUDE "devices/trackdisk.i"
+ INCLUDE "graphics/rastport.i"
+ INCLUDE "hardware/custom.i"
+
+SUPERSTACK: EQU $80000-8 ; LONGWORD-aligned
+INITMAGIC: EQU 'INIT'
+EXECTRACKS: EQU 3 ; Anzahl Tracks für Exec
+EXECSIZE: EQU (EXECTRACKS*11-2)*512
+ABORT: EQU $1FFFFA
+
+TRIALS: EQU 3 ; 3x versuchen pro Drive
+
+ XREF @Exit,_custom
+ XDEF @Main
+
+**************************************************************************
+
+ DCB.B 8,0
+ DC.B "Copyright (c) 1988-1993 by "
+ DC.B "Christian A. Weber, Zürich, Switzerland. "
+ DC.B "All rights reserved.",0
+ DCB.B 6+8,0
+ EVEN
+@Main:
+ *** Evtl. Warn-Requester ausgeben
+
+ subq.l #2,d0 ; CLI mit Args ?
+ bpl.b 1$ ; ja ---> no warning
+ bsr ShowWarning
+ beq.b .Exit ; Cancel --->
+1$:
+ *** Globale Register initialisieren
+
+ movem.l InitRegs(PC),d5/d6/d7/a4/a5
+ movea.l 4,a6
+
+ *** Exec einladen
+
+ moveq #4*TRIALS-1,d4 ; Anzahl Versuche * Units -1
+ moveq #0,d3 ; Aktuelle Unit
+.ReadIt: bsr ReadExec ; Exec laden
+ bne.b .Okay ; OK --->
+ addq.w #1,d3 ; INC unit
+ andi.w #3,d3 ; immer rund herum
+ dbf d4,.ReadIt ; ---> Loop
+.Exit: moveq #20,d0 ; Error-Code
+ bra @Exit ; ---> Raus
+.Okay:
+ *** System-Status für MyExec merken etc.
+
+ move.w AttnFlags(a6),d3 ; FÜR MYEXEC!
+ move.b VBlankFrequency(a6),d2 ; FÜR MYEXEC!
+
+ lea GfxName(PC),a1
+ JSRLIB OldOpenLibrary
+ movea.l d0,a0
+ move.w 164(a0),d4 ; FÜR MYEXEC!
+
+ *** Chip-RAM-Obergrenze ermitteln und nach A4
+
+MegaTest: lea $1000(a4),a1 ; SuperStack+$1000
+ JSRLIB TypeOfMem
+ andi.w #MEMF_CHIP,d0 ; auch Chip ?
+ beq.b 1$ ; Nein, nur 512K --->
+ adda.l #$10000,a4 ; 64K mehr
+ bra.b MegaTest ; Weiter probieren
+1$:
+ *** Grössten Fast-RAM-Block reservieren und nach A2, Ende nach A3
+
+ JSRLIB Disable ; INTERRUPTS FUER IMMER WEG!
+
+_getfast: suba.l a2,a2 ; Default: No FAST RAM
+ suba.l a3,a3 ; Grösse 0
+ move.l #MEMF_FAST|MEMF_LARGEST,d1
+ JSRLIB AvailMem ; FAST-RAM-Grösse bestimmen
+ cmpi.l #300000,d0 ; genug damit sich's lohnt ?
+ blo.b 1$ ; nein --->
+ movea.l d0,a3 ; Size
+ moveq.l #MEMF_FAST,d1
+ JSRLIB AllocMem
+ movea.l d0,a2 ; A2: FastRAM-Base
+ adda.l d0,a3 ; A3: FastRAM-End
+1$:
+ *** Supervisor-Mode, Interrupts sperren
+
+_supie: move.w d7,dmacon(a5)
+ move.w d7,intena(a5)
+ lea 1$(PC),a5
+ JSRLIB Supervisor
+1$: lea _custom,a5
+ move #$2700,sr
+ movea.l a4,SP ; SupieStack init
+ btst #AFF_68010,d3 ; 68010+ ?
+ beq.b 2$ ; nein --->
+ suba.l a0,a0
+ DC.L $4E7B8801 ; movec.l a0,vbr
+2$:
+ *** MyExec installieren und starten
+
+_installexec: movea.l d5,a0 ; Source: Exec-Ladeadresse
+ suba.l a1,a1 ; Destination: 0
+ move.l d6,d0 ; ExecSize
+ ;; bra.b 2$ ; Für dbf, macht aber nix aus
+1$: move.b (a0)+,(a1)+
+2$: dbf d0,1$
+
+ move.l d3,d0 ; AttnFlags
+ move.l d4,d1 ; Bplcon0
+ move.l MyProduct(PC),d3 ; Von DiskMaker eingetragen
+ suba.l a0,a0 ; WICHTIG FüR CDISK !!
+ suba.l a1,a1 ; WICHTIG FüR CDISK !!
+
+ suba.l a4,a4
+3$: cmpi.l #INITMAGIC,(a4)
+ beq.b 4$
+ addq.l #2,a4 ; WORD-weise schreiten
+ bra.b 3$
+4$:
+ move.l a4,d6 ; Adresse der Vektoren-4
+ add.l #$4ef80008,d6 ; JMP<<16+4+4 (=2. Einspr.)
+ move.l d6,ABORT ; JMP ColdReset().W
+ move.w #$000,color(a5)
+ jmp 4(a4) ; Tada! (=1. Einspr.)
+
+**************************************************************************
+
+ReadExec:
+
+ *** IO-Request und Port initialisieren
+
+_initio: lea MyPort,a0 ; A0 : The Port
+ move.l ThisTask(a6),MP_SIGTASK(a0)
+ move.b #NT_MSGPORT,LN_TYPE(a0)
+ ;; move.b #PA_SIGNAL,MP_FLAGS(a0)
+ move.b #17,MP_SIGBIT(a0)
+
+ lea MyIO,a2 ; A2 : The IO-Request
+ move.b #NT_MESSAGE,LN_TYPE(a2)
+ move.w #IOSTD_SIZE,MN_LENGTH(a2)
+ move.l a0,MN_REPLYPORT(a2)
+
+ lea MP_MSGLIST(a0),a0 ; Die Message-Liste
+ move.l a0,LH_HEAD(a0) ; Macro NewList
+ addq.l #LH_TAIL,(a0)
+ ;; clr.l LH_TAIL(a0)
+ move.l a0,LH_TAILPRED(a0)
+
+ *** Trackdisk.device öffnen
+
+ move.l d3,d0 ; Unit number
+ moveq #0,d1 ; Flags
+ lea TrackDiskName(PC),a0
+ movea.l a2,a1 ; IOStdRequest Struktur
+ JSRLIB OpenDevice
+ tst.l d0 ; OK ?
+ bne.b .ReadError ; nein --->
+
+ *** Exec von Track 0 einlesen
+
+ move.w #CMD_READ,IO_COMMAND(a2)
+ move.l d6,IO_LENGTH(a2) ; ExecSize
+ move.l d5,IO_DATA(a2) ; ExecAdr
+ moveq.l #64,d0
+ lsl.l #4,d0 ; Gibt 1024
+ move.l d0,IO_OFFSET(a2)
+ movea.l a2,a1 ; IO-Request
+ JSRLIB DoIO
+ tst.b d0 ; Error ?
+ bne.b .ReadError ; ja --->
+
+ *** Motor abschalten
+
+ move.w #TD_MOTOR,IO_COMMAND(a2)
+ clr.l IO_LENGTH(a2) ; Motor off
+ movea.l a2,a1 ; IO-Request
+ JSRLIB DoIO
+
+ *** Test ob's unser Exec ist
+
+ movea.l d5,a0
+ tst.l (a0) ; Ist's unser Exec ?
+ bne.b .ReadError ; nein --->
+ cmpi.l #'CHW!',$c0(a0) ; Sicher ?
+ beq.b .ExecOK ; ja ---> Success
+
+.ReadError: moveq #0,d2 ; Error-Code: FAIL
+ bra.b 1$ ; --->
+
+.ExecOK: moveq #1,d2 ; Error-Code: SUCCESS
+
+1$: movea.l a2,a1
+ tst.l IO_DEVICE(a1)
+ bmi.b 2$
+ JSRLIB CloseDevice
+2$: move.l d2,d0 ; Set/Reset Z bit
+ rts
+
+**************************************************************************
+
+ShowWarning: lea IntuiName(PC),a1
+ movea.l 4,a6
+ JSRLIB OldOpenLibrary
+ movea.l d0,a6
+
+ suba.l a0,a0 ; Window
+ lea body(PC),a1
+ lea ptext(PC),a2
+ lea ntext(PC),a3
+ moveq.l #0,d0 ; pflag
+ moveq.l #0,d1 ; nflag
+ move.w #530,d2 ; width
+ moveq.l #78,d3 ; height
+ JSRLIB AutoRequest
+ tst.l d0 ; Z == CANCEL ? 1:0
+ rts
+
+**************************************************************************
+
+GfxName: dc.b "graphics.library",0
+IntuiName: dc.b "intuition.library",0
+TrackDiskName: dc.b "trackdisk.device",0
+
+ EVEN
+
+InitRegs: dc.l ExecBSS ; D5 : Exec-Ladeadresse
+ dc.l EXECSIZE ; D6 : Exec-LadeGröße
+ dc.l $7fff ; D7 : Int/DMADisable-Maske
+ dc.l SUPERSTACK ; A4 : SuperStack
+ dc.l _custom ; A5 : Custom
+
+
+ProdMagic: dc.l 'PROD' ; Muss vor MyProduct stehen
+MyProduct: dc.l 0 ; Wird von DiskMaker eingesetzt
+
+ EVEN
+body: dc.b 2,1,RP_JAM1,0
+ dc.w 14,8
+ dc.l 0,bodytext,body2
+
+body2: dc.b 2,1,RP_JAM1,0
+ dc.w 14,18
+ dc.l 0,body2text,body3
+
+body3: dc.b 2,1,RP_JAM1,0
+ dc.w 14,28
+ dc.l 0,body3text,0
+
+ptext: dc.b 2,1,RP_JAM2,0
+ dc.w 6,3
+ dc.l 0,ptexttext,0
+
+ntext: dc.b 2,1,RP_JAM2,0
+ dc.w 6,3
+ dc.l 0,ntexttext,0
+
+bodytext: dc.b "WARNING: This program will shut down the Amiga's",0
+body2text: dc.b "------- multi-tasking system. Finish all running",0
+body3text: dc.b " programs before selecting 'START GAME' !",0
+ptexttext: dc.b "START GAME",0
+ntexttext: dc.b "CANCEL",0
+
+
+ SECTION bss,BSS
+
+MyIO: ds.b IOSTD_SIZE+32
+
+MyAttnFlags: ds.w 1
+MySysBplcon0: ds.w 1
+MyVBlankFreq: ds.w 1
+
+MyPort: ds.b MP_SIZE+32
+
+ EVEN
+ExecBSS: ds.b EXECSIZE+32 ; Hierhin wird's geladen
+
+
+ END
diff --git a/Keyboard.S b/Keyboard.S
new file mode 100644
index 0000000..50fdb2d
--- /dev/null
+++ b/Keyboard.S
@@ -0,0 +1,423 @@
+**************************************************************************
+** **
+** Keyboard.S - Routinen zum Keyboard-Handling ohne System **
+** **
+**************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 13-Jun-88 Created this file! **
+** 29-May-89 SetMap function added **
+** 06-Jun-89 SetResetHandler function added **
+** 10-Nov-89 Numeric pad keys ()/*+- implemented **
+** 30-Mar-90 HELP key no longer used to exit/reset **
+** 30-Sep-90 Shift-Sternchen (Numeric Pad) ist ROMCrack-Einsprung **
+** 27-Feb-91 System-taugliche Version falls SYSTEM definiert **
+** **
+**************************************************************************
+
+ IDNT Keyboard
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+ INCLUDE "hardware/custom.i"
+
+ IFD SYSTEM
+ INCLUDE "exec/macros.i"
+ INCLUDE "exec/io.i"
+ INCLUDE "devices/input.i"
+ INCLUDE "devices/inputevent.i"
+ ENDC
+
+ XREF _custom,__MyExecBase
+
+ IFD SYSTEM
+ XREF _idstring,@CreateIO,@DeleteIO
+ XDEF ExitKeyFunc
+ ENDC
+ XDEF InitKeyFunc
+ XDEF GetKeyFunc,WaitKeyFunc,FlushKeyBufFunc
+ XDEF SetMapFunc,SetResetHandlerFunc,SetCheatTextFunc
+
+KEYBUFSIZE: EQU 40 ; Grösse des Tastaturpuffers in Bytes
+
+**************************************************************************
+* Keyboard-Interrupt bzw. Input-Handler initialisieren
+
+InitKeyFunc:
+ IFD SYSTEM
+ movem.l d1/a0-a2/a6,-(SP)
+ moveq.l #IOSTD_SIZE,d0
+ bsr @CreateIO
+ move.l d0,InputIOReq
+ beq.s 1$
+ movea.l d0,a2
+
+ moveq #0,d0 ; Unit
+ moveq #0,d1 ; Flags
+ lea InputName(PC),a0
+ movea.l a2,a1
+ movea.l 4,a6
+ JSRLIB OpenDevice
+
+ movea.l a2,a1
+ move.w #IND_ADDHANDLER,IO_COMMAND(a1)
+ move.l #MyInterrupt,IO_DATA(a1)
+ JSRLIB DoIO
+1$:
+ movem.l (SP)+,d1/a0-a2/a6
+ ELSEIF
+ move.l a0,-(SP)
+ lea KeyboardServer(PC),a0
+ move.l a0,meb_CiaASerialVector(a6)
+ move.w #$8008,_custom+intena ; Interrupt zulassen
+ move.b #$88,$bfed01 ; Im CIA ICR auch
+ move.l (SP)+,a0
+ ENDC
+ rts
+
+**************************************************************************
+* Keyboard-Inputhandler wieder rausschmeissen
+
+ IFD SYSTEM
+ExitKeyFunc: movem.l d1-d2/a0-a1/a6,-(SP)
+ move.l InputIOReq,d2
+ beq.s 1$
+ movea.l d2,a1
+ move.w #IND_REMHANDLER,IO_COMMAND(a1)
+ move.l #MyInterrupt,IO_DATA(a1)
+ movea.l 4,a6
+ JSRLIB DoIO
+
+ movea.l d2,a1
+ JSRLIB CloseDevice
+
+ movea.l d2,a1 ; IO-Request
+ ;; MSG <"Trying to DeleteIO (a1)">
+ ;; bsr @DeleteIO ; freigeben
+ clr.l InputIOReq
+1$:
+ movem.l (SP)+,d1-d2/a0-a1/a6
+ rts
+ ENDC
+
+**************************************************************************
+
+ *** ASCII-Zeichen aus Tastaturpuffer lesen, Null falls nix gedrückt
+
+GetKeyFunc: movem.l d1/a0,-(SP)
+ IFD SYSTEM
+ btst.b #EXECB_RESETREQUEST,meb_ExecFlags(a6)
+ beq.s 1$
+ jmp meb_ColdReboot(a6)
+1$:
+ ENDC
+ moveq.l #0,d0 ; Default: Null
+ move.w KeyBufPtr,d1
+ beq.s .NoKey
+ subq.w #1,d1
+ jsr meb_Disable(a6)
+ move.w d1,KeyBufPtr
+ lea KeyBuf,a0
+ move.b (a0),d0 ; nächstes Zeichen
+2$: move.b 1(a0),(a0)+ ; Puffer verschieben
+ dbf d1,2$
+ jsr meb_Enable(a6)
+.NoKey: tst.b d0 ; key ok ? Z=0 : Z=1
+ movem.l (SP)+,d1/a0
+ rts
+
+**************************************************************************
+
+ *** ASCII-Zeichen aus Tastaturpuffer lesen, warten falls nix parat
+
+WaitKeyFunc: bsr GetKeyFunc
+ bne.s 1$
+ move.b $bfe001,d0
+ not.b d0
+ andi.b #3,d0 ; Knopf Port 0 oder 1 gedrückt ?
+ beq.s WaitKeyFunc ; Nein ---> loop
+ moveq #0,d0 ; Gedrücktes Zeichen: 0
+1$: rts
+
+**************************************************************************
+
+ *** Tastaturpuffer leeren
+
+FlushKeyBufFunc:
+ clr.w KeyBufPtr
+ clr.b meb_ActualQualifiers(a6) ; ** DEBUG ** billiges trick!
+ rts
+
+**************************************************************************
+
+ *** Keymap (A0) setzen, Default falls A0 == 0
+
+SetMapFunc: movem.l d0/a0,-(SP)
+ move.l a0,d0 ; A0 == 0 ?
+ bne.s 1$ ; nein --->
+ lea DefaultKeyMap(PC),a0
+1$: move.l a0,KeyMapPtr
+ movem.l (SP)+,d0/a0
+ rts
+
+**************************************************************************
+
+ *** ResetHandler (A0) setzen, Default falls A0 == 0
+
+SetResetHandlerFunc:
+ movem.l d0/a0,-(SP)
+ move.l a0,d0 ; A0 == 0 ?
+ bne.s 1$ ; nein --->
+ lea meb_ColdReboot(a6),a0
+1$: move.l a0,ResetHandler
+ movem.l (SP)+,d0/a0
+ rts
+
+**************************************************************************
+
+ *** Cheat-Text (A0) setzen, Default falls A0 == 0
+
+SetCheatTextFunc:
+ movem.l d0/a0,-(SP)
+ move.l a0,d0 ; A0 == 0 ?
+ bne.s 1$ ; nein --->
+ lea DefaultCheatText,a0
+1$: move.l a0,CheatTextPtr
+ move.l a0,CheatPtr
+ movem.l (SP)+,d0/a0
+ rts
+
+**************************************************************************
+
+ *** IRQ-Routine der Tastatur, wird bei IRQ 2 (PORTS) angesprungen
+
+KeyboardServer:
+ IFD SYSTEM
+ btst #8,$dff016 ; Mittlere Maustaste ?
+ bne.s 0$ ; nee
+ move.l a0,d0 ; Sonst Handler beenden
+ rts
+
+0$: movem.l d1/a0-a3/a5-a6,-(SP)
+ lea _custom,a5
+ movea.l a1,a6 ; A6: MyExecBase
+ movea.l a0,a1 ; A1: EventChain
+ suba.l a2,a2 ; A2: Vorheriges event
+ movea.l a0,a3 ; A3: Neue chain
+
+1$: cmpi.b #IECLASS_RAWKEY,ie_Class(a1)
+ bne.s 2$
+ move.w ie_Code(a1),d0
+ bsr RawKeyConvert
+ bsr CheatTest
+ bra.s .delink
+2$:
+ cmpi.b #IECLASS_RAWMOUSE,ie_Class(a1)
+ bne.s 4$
+
+.delink: move.l a2,d0 ; 1. Event ?
+ beq.s 3$ ; ja --->
+ move.l ie_NextEvent(a1),ie_NextEvent(a2)
+ bra.s 4$
+3$: movea.l ie_NextEvent(a1),a3
+4$:
+ movea.l ie_NextEvent(a1),a1 ; Nächstes Event
+ move.l a1,d0 ; Liste fertig ?
+ bne.s 1$ ; nein ---> Loop
+
+ bsr ResetTest ; Reset-Handler nötig ?
+
+ move.l a3,d0
+ movem.l (SP)+,d1/a0-a3/a5-a6
+ rts
+ ELSEIF
+ movem.l d0-d7/a0-a5,-(SP)
+ lea _custom,a5
+
+ moveq #0,d0
+ move.b $bfec01,d0 ; read SDR
+ bset.b #6,$bfee01 ; Quittierung starten
+ not.b d0
+ ror.b #1,d0 ; up/down code ins Bit 7
+ bsr RawKeyConvert
+ bsr CheatTest
+
+;; IFD RAMVERSION
+ cmpi.b #$5D,d0 ; Sternchen aufm Zahlenblock ?
+ bne.s .NoRC ; nein --->
+ move.b meb_ActualQualifiers(a6),d1
+ andi.b #3,d1 ; left or right shift ?
+ beq.s .NoRC ; nein --->
+ movem.l (SP)+,d0-d7/a0-a5
+ move.l ((6+1)*4)+2(SP),a0 ; Rücksprungadresse vom Interrupt
+ jsr meb_Debug(a6) ; ROMCrack aufrufen
+ movem.l d0-d7/a0-a5,-(SP)
+.NoRC:
+;; ENDC
+ moveq #15,d0 ; 16 * 64 Mikrosec. warten
+bratfett: move.b vhposr(a5),d1
+1$: cmp.b vhposr(a5),d1
+ beq.s 1$
+ dbf d0,bratfett
+
+ bclr.b #6,$bfee01 ; Quittierung beenden
+ bsr ResetTest ; Reset-Handler nötig ?
+
+ movem.l (SP)+,d0-d7/a0-a5
+ rts
+ ENDC
+
+**************************************************************************
+
+ *** Raw-Code (D0.B) nach ActualKey und auch nach ASCII wandeln
+
+RawKeyConvert: ext.w d0 ; auf WORD erweitern für Index
+ bmi keyup ; Key Up --->
+
+keydown: cmpi.b #$60,d0 ; shift, alt, ctrl amiga etc. ?
+ blt.s 1$ ; nein --->
+ cmpi.b #$68,d0 ; > $68 (Error, etc.) ?
+ bge keyerror ; ja --->
+ bset.b d0,meb_ActualQualifiers(a6) ; entspr. Bit setzen (0-7)
+ bra keyend
+1$:
+ move.b d0,meb_ActualKey(a6) ; Raw-Code eintragen
+ move.b meb_ActualQualifiers(a6),d1
+ andi.b #7,d1 ; left, right shift or caps lock?
+ beq.s 2$ ; nein --->
+ addi.w #$60,d0 ; shift: Daten aus Tabelle 2
+2$: movea.l KeyMapPtr,a0 ; Zeiger auf aktuelle Keymap
+ move.b 0(a0,d0.w),d0
+ move.b d0,meb_ActualASCIIKey(a6)
+ beq.s keyend ; wenn 0: ignorieren
+ move.w KeyBufPtr,d1 ; D0 in den Tastaturpuffer
+ cmpi.w #KEYBUFSIZE,d1 ; Tastaturpuffer voll?
+ bge.s 3$ ; ja --> Key ignorieren
+ lea KeyBuf,a0
+ move.b d0,0(a0,d1.w)
+ addq.w #1,KeyBufPtr ; Anzahl erhöhen
+3$: bra.s keyend ; --->
+
+keyup: bclr #7,d0 ; Up/Down-Bit löschen
+ cmpi.b #$60,d0 ; shift, alt, ctrl amiga etc. ?
+ blt.s dokeyup ; nein --->
+ cmpi.b #$68,d0 ; > $68 (Error, etc.) ?
+ bge.s keyerror ; ja --->
+ bclr.b d0,meb_ActualQualifiers(a6) ; entspr. Bit löschen (0-7)
+ bra.s keyend
+
+keyerror: clr.b meb_ActualQualifiers(a6)
+dokeyup: clr.b meb_ActualKey(a6)
+ clr.b meb_ActualASCIIKey(a6)
+keyend: rts
+
+**************************************************************************
+* Testet Tastatur, ob CHEAT Mode angeschaltet werden soll
+
+CheatTest: move.l CheatPtr,a0 ; nächstes Zeichen, das kommt
+ move.b meb_ActualKey(a6),d0 ; Tastaturcode holen
+ beq.s 3$ ; nichts gedrückt --->
+ cmp.b (a0)+,d0 ; richtiges Zeichen?
+ bne.s 2$ ; nein --->
+ move.l a0,CheatPtr ; dort gehts weiter
+ tst.b (a0) ; alle Zeichen eingegeben?
+ bne.s 3$ ; nein --->
+ not.b meb_CheatFlag(a6) ; Flag umdrehen
+ move.w #10000,d0
+1$: move.w #$eef,color(a5) ; kurzes Flackern
+ tst.w vhposr(a5) ; Processor independant
+ dbf d0,1$
+ move.w #$000,color(a5)
+2$: move.l CheatTextPtr,CheatPtr ; wieder vorne anfangen
+3$: rts
+
+**************************************************************************
+
+ *** Testet ob 2 der 3 Reset-Tasten gedrückt sind
+
+ResetTest: move.b meb_ActualQualifiers(a6),d0
+ andi.b #%11001000,d0 ; Nur Ctrl, LeftAmiga, RightAmiga
+ cmpi.b #%11000000,d0
+ beq.s 1$
+ cmpi.b #%10001000,d0
+ beq.s 1$
+ cmpi.b #%01001000,d0
+ bne.s 2$
+1$:
+ IFD SYSTEM
+ bset.b #EXECB_RESETREQUEST,meb_ExecFlags(a6)
+ ELSEIF
+ movea.l ResetHandler,a0
+ jsr (a0)
+ ENDC
+2$:
+ rts
+
+**************************************************************************
+
+ *** KeyMap Ohne Shift (auch im CODE-Segment!)
+
+DefaultKeyMap:
+ dc.b 96,049,050,051,052,053,054,055 ; 00-07 `1234567
+ dc.b 56,057,048,045,061,092,000,048 ; 08-0F 890-=\ 0
+ dc.b 113,119,101,114,116,121,117,105 ; 10-17 qwertyui
+ dc.b 111,112,091,093,000,049,050,051 ; 18-1F op[] 123
+ dc.b 97,115,100,102,103,104,106,107 ; 20-27 asdfghjk
+ dc.b 108,059,039,036,000,052,053,054 ; 28-2F l;'$ 456 ($ on VSM)
+ dc.b 60,122,120,099,118,098,110,109 ; 30-37 <zxcvbnm (< on VSM)
+ dc.b 44,046,047,000,046,055,056,057 ; 38-3F ,./ .789
+ dc.b 32,008,009,010,010,027,127,000 ; 40-47 SPCBSTABCR CRESCDELnix
+ dc.b 00,000,045,000,016,017,019,018 ; 48-4F nixnix-nix UPDWNFWBW
+ dc.b 241,242,243,244,245,246,247,248 ; 50-57 f1-f8
+ dc.b 249,250,040,041,047,042,043,021 ; 58-5F f9f10() /*+HELP (numpad)
+
+ *** Mit Shift
+
+ dc.b 126,033,064,035,036,037,094,038 ; 00-07 ~!@#$%^&
+ dc.b 42,040,041,000,043,124,000,048 ; 08-0F *()_+| 0
+ dc.b 81,087,069,082,084,089,085,073 ; 10-17 QWERTYUI
+ dc.b 79,080,123,125,000,049,050,051 ; 18-1F OP{} 123
+ dc.b 65,083,068,070,071,072,074,075 ; 20-27 ASDFGHJK
+ dc.b 76,058,034,092,000,052,053,054 ; 28-2F L:"Pfund 456 (Pfund on VSM)
+ dc.b 62,090,088,067,086,066,078,077 ; 30-37 >ZXCVBNM (> on VSM)
+ dc.b 60,062,063,000,000,055,056,057 ; 38-3F <>? 789
+ dc.b 32,008,009,000,000,000,127,000 ; 40-47 SPCBSTABCR CRESCDELnix
+ dc.b 00,000,000,000,016,017,019,018 ; 48-4F nixnixPADnix UPDWNFWBW
+ dc.b 00,000,000,000,000,000,000,000 ; 50-57 f1-f8
+ dc.b 00,000,000,000,000,000,000,021 ; 58-5F f9f10 5*nix HELP
+
+**************************************************************************
+
+ IFD SYSTEM
+InputName: dc.b "input.device",0
+ EVEN
+ ENDC
+
+ SECTION Keyboard,DATA
+
+CheatTextPtr: dc.l DefaultCheatText ; Zeiger auf Anfang
+CheatPtr: dc.l DefaultCheatText ; Zeiger auf akt. Zeichen
+
+DefaultCheatText:
+ dc.b $21,$33,$20,$37,$20,$24,$17,$33,0 ; scamagic
+ EVEN
+
+ResetHandler: dc.l __MyExecBase+meb_ColdReboot
+KeyMapPtr: dc.l DefaultKeyMap ; Zeiger auf aktuelle KeyMap
+KeyBufPtr: dc.w 0
+KeyBuf: dcb.b KEYBUFSIZE+2,0
+ EVEN
+
+ IFD SYSTEM
+MyInterrupt: dc.l 0,0
+ dc.b 0,120
+ dc.l _idstring ; LN_NAME
+ dc.l __MyExecBase ; IS_DATA
+ dc.l KeyboardServer ; IS_CODE
+
+InputIOReq: dc.l 0
+ ENDC
+
+ END
diff --git a/LoadSeg.S b/LoadSeg.S
new file mode 100644
index 0000000..97040d0
--- /dev/null
+++ b/LoadSeg.S
@@ -0,0 +1,211 @@
+**************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 15-May-89 CHW Created this file! **
+** 24-Oct-90 CHW Schrottet die Memoryliste nicht mehr **
+** **
+**************************************************************************
+
+ IDNT LoadSeg
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+
+ XREF AllocMemFunc,FreeMemFunc
+ XREF LoadFileFunc,LoadFastFileFunc
+
+ XDEF LoadSegFunc,UnLoadSegFunc
+
+SEGMAGIC: EQU 'SEG2' ; Neues Format
+RELOCMAGIC: EQU 'RLOC'
+
+***************************************************************************
+
+ IFD sakdksdhgksdjhg
+
+'struct' SpecialFile
+{
+ ULONG ID; /* Segment-Start-Magic SPECIAL_SEGID */
+ ULONG CodeSize; /* CODE-Size (FAST-RAM) in Bytes */
+ ULONG DataSize; /* DATA-Size (CHIP-RAM) in Bytes */
+ ULONG BSSSize; /* BSS-Size, mindestens 4 Bytes FAST RAM */
+
+ BYTE Code[0]; /* CodeSize Bytes, geht ins FAST RAM */
+
+ ULONG rloc1; /* muss SPECIAL_RELOC sein */
+ ULONG Numccrelocs; /* Anzahl folgende Relocs */
+ BYTE CCRelocs[0]; /* Im Code nach Code relocs */
+
+ ULONG rloc2; /* muss SPECIAL_RELOC sein */
+ ULONG Numcdrelocs; /* Anzahl folgende Relocs */
+ BYTE CDRelocs[0]; /* Im Code nach Data relocs */
+
+ ULONG rloc3; /* muss SPECIAL_RELOC sein */
+ ULONG Numcbrelocs; /* Anzahl folgende Relocs */
+ BYTE CBRelocs[0]; /* Im Code nach BSS relocs */
+
+
+ BYTE Data[0]; /* DataSize Bytes, geht ins CHIP RAM */
+
+ ULONG rloc4; /* muss SPECIAL_RELOC sein */
+ ULONG Numdcrelocs; /* Anzahl folgende Relocs */
+ BYTE DCRelocs[0]; /* Im Data nach Code relocs */
+
+ ULONG rloc5; /* muss SPECIAL_RELOC sein */
+ ULONG Numddrelocs; /* Anzahl folgende Relocs */
+ BYTE DDRelocs[0]; /* Im Data nach Data relocs */
+
+ ULONG rloc6; /* muss SPECIAL_RELOC sein */
+ ULONG Numdbrelocs; /* Anzahl folgende Relocs */
+ BYTE DBRelocs[0]; /* Im Data nach BSS relocs */
+};
+
+ ENDC
+
+***************************************************************************
+
+ *** D0 : Filename
+
+LoadSegFunc: movem.l d1-d6/a0-a5,-(SP)
+ move.l #-RELOCMAGIC,d5
+ bsr LoadFastFileFunc ; File ins FAST RAM einladen
+ movea.l d0,a2 ; A2 : File-Base
+ move.l a2,d6 ; D6 : File-Base für später
+ neg.l d5 ; Gegen Cracker
+
+ *** Parameter aus FileHeader holen
+
+ move.l #~SEGMAGIC,d0
+ not.l d0 ; Gegen Cracker
+ cmp.l (a2)+,d0 ; Kennung OK ?
+ beq.s 1$ ; ja --->
+ MSG <"Not an object module, D6=File">
+ jmp meb_ColdReboot(a6)
+1$:
+ movem.l (a2)+,d2-d4 ; D2 : CODESIZE, D3: DATASIZE
+ ; D4 : BSSSIZE
+
+ *** Speicher für Code, Data und BSS allozieren
+
+ move.l d2,d0 ; CODE-Size
+ addq.l #8,d0 ; Platz für DATA- und BSS-Zeiger
+ jsr meb_AllocFastMem(a6) ; FAST RAM reservieren
+ movea.l d0,a3 ; A3 : CODE-Segment
+
+ move.l d3,d0 ; DATA-Size
+ jsr meb_AllocMem(a6) ; CHIP RAM reservieren
+ movea.l d0,a4 ; A4 : DATA-Segment
+ move.l a4,(a3)+ ; in Code-Segment merken
+
+ move.l d4,d0 ; BSS-Size
+ jsr meb_AllocClearMem(a6) ; BSS wird gelöscht
+ movea.l d0,a5 ; A5 : BSS-Segment
+ move.l a5,(a3)+ ; in Code-Segment merken
+
+ *** Code ins Code-Segment rüberkopieren, FilePtr auf Relocs
+
+ movea.l a2,a0 ; Source: File
+ movea.l a3,a1 ; Destination: Code-Segment
+ move.l d2,d0 ; Code-Size
+ jsr meb_CopyMem(a6) ; Segment kopieren
+ adda.l d2,a2 ; File-Zeiger vorrücken
+
+ *** Code to Code/Data/BSS Relocs ausführen
+ *** Relocs sind 16bit signed deltas oder 0 und dann 32bit signed
+
+ cmp.l (a2)+,d5 ; Magic vorhanden ?
+ bne BadReloc ; nein ---> Error
+ move.l (a2)+,d0 ; Anzahl Code-Code-Relocs
+ move.l a3,d1 ; Zu addierender Wert
+ movea.l a3,a0 ; Zu relozierender Code
+ bsr DoReloc
+
+ cmp.l (a2)+,d5 ; Magic vorhanden ?
+ bne BadReloc ; nein ---> Error
+ move.l (a2)+,d0 ; Anzahl Code-Data-Relocs
+ move.l a4,d1 ; Zu addierender Wert
+ movea.l a3,a0 ; Zu relozierender Code
+ bsr DoReloc
+
+ cmp.l (a2)+,d5 ; Magic vorhanden ?
+ bne BadReloc ; nein ---> Error
+ move.l (a2)+,d0 ; Anzahl Code-BSS-Relocs
+ move.l a5,d1 ; Zu addierender Wert
+ movea.l a3,a0 ; Zu relozierender Code
+ bsr DoReloc
+
+ *** Data ins Data-Segment rüberkopieren, FilePtr auf Relocs
+
+ movea.l a2,a0 ; Source: File
+ movea.l a4,a1 ; Destination: Data-Segment
+ move.l d3,d0 ; Data-Size
+ jsr meb_CopyMem(a6) ; Segment kopieren
+ adda.l d3,a2 ; File-Zeiger vorrücken
+
+ *** Data to Code/Data/BSS Relocs ausführen
+
+ cmp.l (a2)+,d5 ; Magic vorhanden ?
+ bne BadReloc ; nein ---> Error
+ move.l (a2)+,d0 ; Anzahl Data-Code-Relocs
+ move.l a3,d1 ; Zu addierender Wert
+ movea.l a4,a0 ; Zu relozierender Code
+ bsr DoReloc
+
+ cmp.l (a2)+,d5 ; Magic vorhanden ?
+ bne BadReloc ; nein ---> Error
+ move.l (a2)+,d0 ; Anzahl Data-Data-Relocs
+ move.l a4,d1 ; Zu addierender Wert
+ movea.l a4,a0 ; Zu relozierender Code
+ bsr DoReloc
+
+ cmp.l (a2)+,d5 ; Magic vorhanden ?
+ bne BadReloc ; nein ---> Error
+ move.l (a2)+,d0 ; Anzahl Data-BSS-Relocs
+ move.l a5,d1 ; Zu addierender Wert
+ movea.l a4,a0 ; Zu relozierender Code
+ bsr DoReloc
+
+ *** Ur-File freigeben
+
+ movea.l d6,a1 ; File
+ jsr meb_FreeMem(a6)
+LoadSegEnd:
+ move.l a3,d0 ; The File
+ movem.l (SP)+,d1-d6/a0-a5
+ rts
+
+BadReloc: MSG <"Bad reloc, D6=File">
+ jmp meb_ColdReboot(a6)
+
+
+ *** D0=Anzahl, D1=Offset, A0=Segment, A2=File, wird vorgerückt
+
+DoReloc: movem.l d1-d3,-(SP)
+ moveq.l #0,d2 ; Reloc-Pointer resetten
+ bra.s 3$ ; Für dbf
+1$: move.w (a2)+,d3 ; Nächste Adresse
+ ext.l d3 ; auf Langwort erweitern
+ bne.s 2$ ; nicht 0 ---> 16bit-delta
+ move.l (a2)+,d3 ; sonst 32bit-delta
+2$: add.l d3,d2 ; Delta-Wert addieren
+ add.l d1,0(a0,d2.l) ; Tada!
+3$: dbf d0,1$
+ movem.l (SP)+,d1-d3
+ rts
+
+***************************************************************************
+
+ *** A1 : Segmentliste von LoadSeg()
+
+UnLoadSegFunc: movem.l a0-a1,-(SP)
+ movea.l a1,a0
+ movea.l -(a0),a1 ; A1 : BSS-Segment
+ jsr meb_FreeMem(a6) ; Segment freigeben
+ movea.l -(a0),a1 ; A1 : Data-Segment
+ jsr meb_FreeMem(a6) ; Segment freigeben
+ movea.l a0,a1 ; A1 : CodeSegment
+ jsr meb_FreeMem(a6) ; Segment freigeben
+ movem.l (SP)+,a0-a1
+ rts
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bc8b7c1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+##########################################################################
+# #
+# Makefile für das mega-geniale Game-Exec-Betriebssystem von CHW :-) #
+# #
+# Created: 18-May-89 CHW Last update: 23-Feb-91 CHW #
+# #
+##########################################################################
+
+
+CC = SC
+CFLAGS =
+
+ASM = Genam
+AFLAGS = -l -iINCLUDE:
+
+LD = Slink
+LFLAGS = ADDSYM NOICONS
+
+
+
+.c.o:
+ $(CC) $(CFLAGS) $*.c
+
+.S.or:
+ -@Delete $@
+ $(ASM) $(AFLAGS) $*.S -o$*.or -eRAMVERSION=1
+
+.S.os:
+ -@Delete $@
+ $(ASM) $(AFLAGS) $*.S -o$*.os -eSYSTEM=1
+
+.S.o:
+ -@Delete $@
+ $(ASM) $(AFLAGS) $*.S -o$*.o -eDISKVERSION=1
+
+
+
+RAMMODS = Exec.or Memory.or LoadSeg.or Keyboard.or CDisk.or RAMLib.or\
+ PPDecrunch.or RawDoFmt.or DrawBob.or Rnd.or FFS.or EndLabel.or
+
+SYSMODS = Exec.os Memory.os LoadSeg.os Keyboard.os SysCDisk.os RAMLib.os\
+ PPDecrunch.os RawDoFmt.os DrawBob.os Rnd.os CDTV.os EndLabel.os
+
+DISKMODS = Exec.o Memory.o LoadSeg.o Keyboard.o CDisk.o RAMLib.o\
+ PPDecrunch.o RawDoFmt.o DrawBob.o Rnd.o FFS.o EndLabel.o
+
+
+
+All: Track0 Start SysStart FinalBooter Disk-Validator
+
+$(RAMMODS): myexec.i
+$(DISKMODS): myexec.i
+$(SYSMODS): myexec.i
+DrawBob.o: DrawBob.i
+
+
+RAMExec.S: $(RAMMODS)
+ $(LD) $(LFLAGS) FROM $(RAMMODS) TO T:__exectmp LIB LIB:small.lib
+ AbsLoad >NIL: -a0 -o T:__exectmp2 T:__exectmp
+ HexDump -L -X _ExecModuleStart -Y _ExecModuleEnd -O$@ T:__exectmp2
+ @Delete T:__exectmp T:__exectmp2
+
+Track0: $(DISKMODS)
+ $(LD) $(LFLAGS) FROM $(DISKMODS) TO T:__exectmp LIB LIB:small.lib
+ AbsLoad >NIL: -a0 -o T:__exectmp2 T:__exectmp
+ Join BootBlock T:__exectmp2 as Track0
+ @Delete T:__exectmp T:__exectmp2 QUIET
+
+Start: start.o RAMExec.o
+ -@Delete $@
+ $(LD) $(LFLAGS) FROM CCLIB:argsstartup20.o start.o ramexec.o TO $* \
+ LIB CCLIB:ch.lib LIB:sc.lib LIB:small.lib
+
+SysStart: sysstart.o $(SYSMODS)
+ -@Delete $@
+ $(LD) $(LFLAGS) FROM CCLIB:argsstartup20.o Sysstart.o $(SYSMODS) TO $* \
+ LIB CCLIB:ch.lib LIB:sc.lib LIB:small.lib
+
+FinalBooter: FinalBooter.o
+ -@Delete $@
+ $(LD) $(LFLAGS) FROM cclib:TinyStartup.o $*.o TO T:__exectmp LIB cclib:ch.lib LIB:small.lib
+ AbsLoad -©cb -o$@ T:__exectmp
+ @Delete T:__exectmp
+
+Disk-Validator: FinalBooter.S
+ -@Delete $@
+ $(ASM) FinalBooter.S -o$@ -eBCPL=1
+
+
+clean:
+ Delete *.o *.os *.or Track0 Start SysStart FinalBooter Disk-Validator ramexec.s
+
+
+install:
+ Copy MyExec.i DrawBob.i INCUSR: CLONE
+ Copy Start C+:Proprietary/ CLONE
+ Copy SysStart C+:Proprietary/ CLONE
+
+
+dist: Start Track0
+ -@Delete Exec.LHA
+ @lha -x -a a Exec.LHA Start Track0 MyExec.i DrawBob.i
+ @lha -x -a v Exec.LHA
+
+srcdist: Start BootBlock CDisk.o CDisk.r
+ -@Delete ExecSource.LHA
+ @lha -x -a a ExecSource.LHA *.S *.c
+ @lha -x -a d ExecSource.LHA ramexec.s
+ @lha -x -a a ExecSource.LHA BootBlock CDisk.o CDisk.r *.i Makefile
+ @lha -x -a v ExecSource.LHA
diff --git a/Memory.S b/Memory.S
new file mode 100644
index 0000000..ae6b75c
--- /dev/null
+++ b/Memory.S
@@ -0,0 +1,416 @@
+**************************************************************************
+** **
+** MEMORY - Die schnellste, beste, kürzeste Speicherverwaltung :-) **
+** **
+** by Christian A. Weber, Zurich/Switzwerland **
+** **
+**************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 15-May-89 CHW Created this file! **
+** 27-Nov-89 CHW Fast-Memory added **
+** 30-Jul-90 CHW Chip allocation for AllocFastMem() works now **
+** 18-Sep-90 CHW Chip allocation for AllocFastMem() really works **
+** 20-Nov-90 CHH NoMemHandler eingebaut ** **
+** **
+**************************************************************************
+
+ OPT OW6+
+
+ IDNT Memory
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+
+ XREF MyNoMemHandler
+
+ XDEF InitChipMemFunc,InitFastMemFunc
+ XDEF AllocMemFunc,AllocClearMemFunc
+ XDEF AllocFastMemFunc,AllocFastClearMemFunc
+ XDEF FreeMemFunc,CopyMemQuickFunc,CopyMemFunc,ClearMemFunc
+ XDEF AvailMemFunc,AvailFastMemFunc,CheckMemFunc
+
+***************************************************************************
+
+ *** ChipMemHeader init, A0=Adresse, D0=Size des freien Blocks
+
+InitChipMemFunc:
+ movem.l d0/a0-a1,-(SP)
+ lea meb_ChipMRHeader(a6),a1
+ bra.s DoInitMem
+
+ *** FastMemHeader init, A0=Adresse, D0=Size des freien Blocks
+
+InitFastMemFunc:
+ movem.l d0/a0-a1,-(SP)
+ lea meb_FastMRHeader(a6),a1
+ ;; bra.s DoInitMem
+
+DoInitMem: move.l a0,mh_Lower(a1)
+ move.l a0,mh_First(a1)
+ move.l d0,mh_Free(a1)
+ move.l d0,mc_Bytes(a0)
+ clr.l mc_Next(a0)
+ adda.l d0,a0
+ move.l a0,mh_Upper(a1)
+
+ movem.l (SP)+,d0/a0-a1
+ rts
+
+***************************************************************************
+
+ *** D0: Amount, gibt D0: Adresse oder ruft AllocChipMem() auf
+
+AllocFastMemFunc:
+ movem.l d1-d2/a0-a3,-(SP)
+ move.l d0,d1 ; Amount retten
+
+ tst.l meb_FastMRHeader+mh_Free(a6) ; Fast RAM vorhanden ?
+ beq.s ChipEntry ; nein --->
+
+ lea meb_FastMRHeader(a6),a0 ; The MemoryRegionHeader
+ bsr DoAlloc ; Speicher holen
+ bne.s 1$ ; OK --->
+ move.l d1,d0 ; Amount
+ bra.s ChipEntry ; ---> CHIP RAM holen
+1$:
+ movem.l (SP)+,d1-d2/a0-a3
+ rts
+
+***************************************************************************
+
+ *** D0: Amount, gibt D0: Adresse oder Guru
+ *** Wenn nicht genuegen Speicher vorhanden ist, wird ein evt.
+ *** vorhandener Handler angesprungen
+
+AllocMemFunc: movem.l d1-d2/a0-a3,-(SP)
+ move.l d0,d1 ; Amount retten
+ChipEntry: move.l d0,ActAmount
+ lea meb_ChipMRHeader(a6),a0 ; The MemoryRegionHeader
+ bsr DoAlloc ; --->
+ movem.l (SP)+,d1-d2/a0-a3
+ ;; tst.l d0
+ beq.s .NotEnough ; nicht genug --->
+ rts
+
+.NotEnough: movem.l d1-d7/a0-a6,-(SP)
+ move.l ActAmount,d1
+ bsr MyNoMemHandler
+ tst.w d0
+ beq .MemAlert
+ movem.l (SP)+,d1-d7/a0-a6
+ move.l ActAmount,d0
+ bra AllocMemFunc
+
+
+.MemAlert: movem.l (SP)+,d1-d7/a0-a6
+ move.l d1,d0 ; Amount für MSG
+ lea meb_ChipMRHeader(a6),a0 ; MemoryRegionHeader für MSG
+ move.l meb_ChipMRHeader+mh_Free(a6),d7 ; Free für MSG
+ movea.l (SP)+,a5 ; PC für MSG
+ lea AvailMemFunc,a1
+ MSG <'AllocMem: No mem, D0=amount, D7=free, A0=MRH, A1=AvailFunc A5=PC'>
+ jmp meb_ColdReboot(a6)
+
+***************************************************************************
+
+ *** D0: Amount, A0: MRH gibt D0: Adresse oder 0, rettet keine Regs!
+
+DoAlloc: tst.l d0 ; 0 Bytes reservieren ?
+ beq .AllocError ; ja ---> Guru
+ addq.l #4,d0 ; Remember-Size
+ addq.l #7,d0
+ andi.b #$f8,d0 ; Bytezahl modulo 8 aufrunden
+ jsr meb_Disable(a6)
+ ;; cmp.l mh_Free(a0),d0 ; Amount > freier Speicher ?
+ ;; bhi .NotEnoughMemory ; ja ---> Guru
+ lea mh_First(a0),a2 ; Zeiger auf 1. freien Chunk
+
+.AllocLoop: move.l (a2),d2 ; Link zum nächsten Chunk
+ beq.s .NotEnoughMemory ; Liste zu Ende ---> Guru
+ movea.l d2,a1 ; Nächster Blockanfang
+ cmp.l mc_Bytes(a1),d0 ; Chunklänge > Amount ?
+ bls.s 1$ ; ja ---> Chunk gefunden!
+ movea.l a1,a2 ; Nächster Blockanfang
+ bra.s .AllocLoop ; ---> Loop
+1$:
+ beq.s 2$ ; Chunklänge == Amount --->
+ lea 0(a1,d0.l),a3 ; Anfang des Restchunks
+ move.l (a1),(a3) ; Link eintragen
+ move.l mc_Bytes(a1),d2 ; Länge des freien Blocks
+ sub.l d0,d2 ; minus amount
+ move.l d2,mc_Bytes(a3) ; gibt Länge des Restchunks
+ move.l a3,(a2) ; Vorherigen Link korrigieren
+ bra.s 3$ ; --->
+
+2$: move.l (a1),(a2) ; Link zurückkopieren
+3$:
+ sub.l d0,mh_Free(a0) ; Frei-Zähler anpassen
+ move.l d0,(a1)+ ; Grösse für FreeMem eintragen
+ move.l a1,d0 ; Allozierter Bereich
+.AllocEnd:
+ jsr meb_Enable(a6) ; versabbert CCR!
+ tst.l d0
+ rts
+
+.NotEnoughMemory:
+ moveq.l #0,d0
+ bra.s .AllocEnd
+
+.AllocError: movem.l (SP)+,d1-d2/a0-a3
+ movea.l (SP)+,a5
+ MSG <'AllocMem: Got request for 0 bytes, A0=MRH, A5=PC'>
+ jmp meb_ColdReboot(a6)
+
+**************************************************************************
+
+ *** FAST-Speicher reservieren und löschen
+
+AllocFastClearMemFunc:
+ movem.l d1/a0,-(SP)
+ move.l d0,d1 ; Amount retten
+ bsr AllocFastMemFunc
+ bra.s DoAllocClear ; --->
+
+**************************************************************************
+
+ *** CHIP-Speicher reservieren und löschen
+
+AllocClearMemFunc:
+ movem.l d1/a0,-(SP)
+ move.l d0,d1 ; Amount retten
+ bsr AllocMemFunc
+DoAllocClear: movea.l d0,a0 ; Adresse
+ move.l d1,d0 ; Länge
+ bsr ClearMemFunc
+ move.l a0,d0 ; Adresse
+ movem.l (SP)+,d1/a0
+ rts
+
+***************************************************************************
+
+ *** Speicherbereich (A1) freigeben
+
+FreeMemFunc: movem.l d0-d2/a0-a2,-(SP)
+ jsr meb_Disable(a6)
+ move.l a1,d0 ; Null ?
+ beq .FreeEnd ; ja --->
+
+ cmp.l meb_ChipMRHeader+mh_Upper(a6),d0 ; Ist's CHIP-RAM ?
+ bhs.s 1$ ; nein --->
+ lea meb_ChipMRHeader(a6),a0 ; The MemoryRegionHeader
+ bra.s 2$
+1$:
+ lea meb_FastMRHeader(a6),a0
+2$:
+ move.l -(a1),d0 ; Länge des Blocks
+ beq .FreeError ; ja ---> Guru
+ move.l a1,d1 ; Freizugebender Block
+
+ lea mh_First(a0),a2 ; Zeiger auf 1. freien Chunk
+ move.l (a2),d2 ; Link zum nächsten Chunk
+ beq.s 5$ ; Ende der Liste --->
+
+3$: cmpa.l d2,a1 ; Start des freizugebenden Chunks
+ bcs.s 4$ ; < Anfang des Blocks --->
+ beq .FreeError ; == Anfang ---> Guru
+ movea.l d2,a2 ; Link zum nächsten Chunk
+ move.l (a2),d2 ; Neuer Link
+ bne.s 3$ ; Liste geht weiter ---> Loop
+4$:
+ moveq #mh_First,d1 ; war 16 (?)
+ add.l a0,d1 ; + MemoryRegionHeader
+ cmp.l a2,d1 ; zeigt A2 auf mh_First ?
+ beq.s 5$ ; ja ---> Spezialfall
+
+ move.l mc_Bytes(a2),d2 ; Länge des freien Chunks
+ add.l a2,d2 ; + Anfang = Chunk-Ende
+ cmp.l a1,d2 ; Anfang des freizugebenden Chunks
+ beq.s 6$ ; == Ende des freien Chunks --->
+ bhi.s .FreeError ; im freien Bereich ---> Guru
+
+5$: move.l (a2),(a1) ; Neuen Blockheader erzeugen
+ move.l a1,(a2)
+ move.l d0,mc_Bytes(a1)
+ bra.s 7$ ; --->
+6$:
+ add.l d0,mc_Bytes(a2) ; Blocklänge += Freibytes
+ move.l a2,a1 ; Blockanfang
+7$:
+ tst.l (a1) ; Link eingetragen ?
+ beq.s 8$ ; nein --->
+ move.l mc_Bytes(a1),d2 ; Blocklänge
+ add.l a1,d2 ; + Anfang = Ende+1
+ cmp.l (a1),d2 ; mit Linkadresse vergleichen
+ bhi.s .FreeError ; Linkadr. kleiner ---> Guru
+ bne.s 8$ ; Linkadresse grösser --->
+ move.l (a1),a2 ; Nächsten Chunk einlinken
+ move.l (a2),(a1)
+ move.l mc_Bytes(a2),d2
+ add.l d2,mc_Bytes(a1)
+8$:
+ add.l d0,mh_Free(a0) ; Frei-Zähler anpassen
+
+.FreeEnd: jsr meb_Enable(a6)
+ movem.l (SP)+,d0-d2/a0-a2
+ rts
+
+.FreeError: movem.l (SP)+,d0-d2/a0-a2
+ movea.l (SP)+,a5
+ MSG <'FreeMem: MemList corrupt, A0=MRH, A5=PC'>
+ jmp meb_ColdReboot(a6)
+
+***************************************************************************
+
+CheckMemFunc: movem.l d0-d1/a0-a1,-(SP)
+ jsr meb_Disable(a6)
+
+ lea meb_ChipMRHeader(a6),a0 ; The MemoryRegionHeader
+ bsr.s CheckMemList
+
+ tst.l meb_FastMRHeader+mh_First(a6) ; FAST RAM vorhanden ?
+ beq.s 1$
+ lea meb_FastMRHeader(a6),a0
+ bsr.s CheckMemList
+1$:
+ jsr meb_Enable(a6)
+ movem.l (SP)+,d0-d1/a0-a1
+ rts
+
+ *** Speicherliste (A0) testen, Message falls korrupt
+
+CheckMemList: moveq.l #0,d1 ; Free-Count löschen
+ lea mh_First(a0),a1 ; Zeiger auf 1. freien Chunk
+
+.CheckLoop: move.l mc_Next(a1),d0 ; Link zum nächsten Chunk
+ beq.s 1$ ; Ende der Liste --->
+ cmp.l a1,d0 ; Next < actual ?
+ bls.s .CheckError ; ja ---> Error
+ movea.l d0,a1
+ add.l mc_Bytes(a1),d1 ; FreeCount += bytes
+ bra.s .CheckLoop
+1$:
+ cmp.l mh_Free(a0),d1 ; FreeCount richtig ?
+ bne.s .CheckError
+ rts
+
+.CheckError: move.l mh_Free(a0),d0 ; Soll-Wert
+ MSG <'CheckMem: List corrupt, D0=soll, D1=ist, A0=MRH, A1=Chunk'>
+ jmp meb_ColdReboot(a6)
+
+**************************************************************************
+
+ *** Speicher schnell kopieren, WORD-aligned, Länge % 4 = 0
+
+CopyMemQuickFunc:
+ movem.l d0-d1/a0-a1,-(SP)
+ moveq #0,d1 ; Kein Byte-Rest
+ bra.s l272 ; --->
+
+ *** Speicher normal kopieren
+
+CopyMemFunc: movem.l d0-d1/a0-a1,-(SP)
+ moveq #12,d1
+ cmp.l d1,d0 ; Länge < 12 ?
+ bcs.s l277 ; ja ---> byteweise kopieren
+ move.l a0,d1 ; Source
+ btst #0,d1 ; Gerade ?
+ beq.s l271 ; ja --->
+ move.b (a0)+,(a1)+ ; Sonst 1 Byte kopieren
+ subq.l #1,d0
+l271: move.l a1,d1 ; Destination
+ btst #0,d1 ; Gerade ?
+ bne.s l277 ; nein ---> byteweise kopieren
+ move.l d0,d1 ; Länge
+ andi.w #3,d1 ; Byte-Rest von LONGs
+
+l272: move.w d1,-(SP) ; Rest retten für später
+ moveq #96,d1 ; 2* Länge von 12 Registern
+ cmp.l d1,d0
+ bcs.s l274 ; movem lohnt sich nicht --->
+
+ movem.l d1-d7/a2-a6,-(SP) ; Alles retten
+l273: movem.l (a0)+,d1-d7/a2-a6
+ movem.l d1-d7/a2-a6,(a1)
+ moveq #48,d1 ; 12 LONG-Register
+ adda.l d1,a1 ; INC dest
+ sub.l d1,d0 ; DEC len
+ cmp.l d1,d0 ; nochmal ?
+ bcc.s l273 ; ja --->
+ movem.l (SP)+,d1-d7/a2-a6
+
+l274: lsr.l #2,d0 ; restliche Longwords
+ beq.s l276 ; keine --->
+ subq.l #1,d0 ; für dbf
+ move.l d0,d1
+ swap d0
+l275: move.l (a0)+,(a1)+
+ dbf d1,l275
+ dbf d0,l275
+
+l276: move.w (SP)+,d1 ; Geretteter Byte-Rest
+ beq.s l27a ; 0 --->
+ moveq #0,d0
+ bra.s l279 ; byteweise kopieren
+
+l277: move.w d0,d1
+ swap d0
+ bra.s l279
+l278: move.b (a0)+,(a1)+
+l279: dbf d1,l278
+ dbf d0,l278
+l27a:
+ movem.l (SP)+,d0-d1/a0-a1
+ rts
+
+**************************************************************************
+
+ *** Speicher löschen, A0 : Adresse, D0 : Länge in Bytes ( <=1MB! )
+
+ClearMemFunc: movem.l d0-d2/a0,-(SP)
+ moveq.l #0,d2 ; Lösch-Register
+ move.l a0,d1
+ btst #0,d1 ; Adresse gerade ?
+ beq.s 1$ ; ja --->
+ subq.l #1,d0 ; DEC len
+ bmi.s 99$ ; Länge war 0 --->
+ move.b d2,(a0)+ ; 1 Byte löschen
+1$:
+ move.l d0,d1 ; Länge
+ lsr.l #4,d1 ; /16 weil 4 LONGs aufs mal
+ bra.s 3$ ; Für dbf
+2$: move.l d2,(a0)+
+ move.l d2,(a0)+
+ move.l d2,(a0)+
+ move.l d2,(a0)+
+3$: dbf d1,2$
+
+ andi.w #15,d0 ; restliche Bytes
+ bra.s 5$ ; Für dbf
+4$: move.b d2,(a0)+
+5$: dbf d0,4$
+99$:
+ movem.l (SP)+,d0-d2/a0
+ rts
+
+***************************************************************************
+
+ *** Anzahl freie Bytes CHIP-RAM nach D0
+
+AvailMemFunc: move.l meb_ChipMRHeader+mh_Free(a6),d0
+ rts
+
+***************************************************************************
+
+ *** Anzahl freie Bytes FAST-RAM nach D0
+
+AvailFastMemFunc:
+ move.l meb_FastMRHeader+mh_Free(a6),d0
+ rts
+
+
+ActAmount: ds.l 1
+
+ END
diff --git a/MyExec.i b/MyExec.i
new file mode 100644
index 0000000..1802037
--- /dev/null
+++ b/MyExec.i
@@ -0,0 +1,431 @@
+**************************************************************************
+** **
+** MYEXEC - Verschiedene Routinen die so manches Programm braucht **
+** **
+** by Christian A. Weber, Zurich/Switzwerland **
+** **
+**************************************************************************
+** **
+** Version 4.4, 16-Apr-92 **
+** **
+**************************************************************************
+
+ OPT O+,OW-,O5-
+
+ INCLUDE "exec/types.i"
+
+STRUCTURES_I SET 1 ; Damit's kein Chaos gibt ;-)
+
+PP_SAVEMARGIN: EQU 32 ; Anzahl PowerPacker-Sicherheitsbytes
+
+
+**************************************************************************
+* Beispiel: SYSCALL AllocMem
+
+SYSCALL: MACRO
+ XREF _MyExecBase
+ MOVE.L A6,-(SP)
+ MOVEA.L _MyExecBase,A6
+ JSR meb_\1(A6)
+ MOVEA.L (SP)+,A6
+ ENDM
+
+**************************************************************************
+* Beispiel: SYSJSR AllocMem (A6 muss auf _MyExecBase zeigen!)
+
+SYSJSR: MACRO
+ JSR meb_\1(A6)
+ ENDM
+
+**************************************************************************
+* Beispiel: SYSGET.b CheatFlag,D0
+
+SYSGET: MACRO
+ XREF _MyExecBase
+ MOVE.L A6,-(SP)
+ MOVEA.L _MyExecBase,A6
+ MOVE.\0 meb_\1(A6),\2
+ MOVEA.L (SP)+,A6
+ ENDM
+
+**************************************************************************
+* Beispiel: SYSPUT.l D0,UserData1
+
+SYSPUT: MACRO
+ XREF _MyExecBase
+ MOVE.L A6,-(SP)
+ MOVEA.L _MyExecBase,A6
+ MOVE.\0 \1,meb_\2(A6)
+ MOVEA.L (SP)+,A6
+ ENDM
+
+**************************************************************************
+* Beispiel: SYSLEA UserData1,A0
+
+SYSLEA: MACRO
+ XREF _MyExecBase
+ MOVE.L A6,-(SP)
+ MOVEA.L _MyExecBase,A6
+ LEA.L meb_\1(A6),\2
+ MOVEA.L (SP)+,A6
+ ENDM
+
+**************************************************************************
+* Beispiel: SYSTST.l TripleScreen
+
+SYSTST: MACRO
+ XREF _MyExecBase
+ MOVE.L A6,-(SP)
+ MOVEA.L _MyExecBase,A6
+ TST.\0 meb_\1(A6)
+ MOVEA.L (SP)+,A6
+ ENDM
+
+**************************************************************************
+
+DISABLE MACRO
+ FAIL Use SYSCALL Disable
+ ENDM
+
+ENABLE MACRO
+ FAIL Use SYSCALL Enable
+ ENDM
+
+
+clra MACRO
+ suba.l \1,\1
+ ENDM
+
+**************************************************************************
+
+FUNCTION MACRO
+ IFNE SOFFSET&1
+ FAIL FUNCTION at odd address
+ ENDC
+meb_\1 EQU SOFFSET
+SOFFSET SET SOFFSET+4
+ ENDM
+
+**************************************************************************
+* MSG "Text" ruft ROMCrack mit "Text" auf
+
+MSG MACRO
+ XREF _MyExecBase
+ bra.s .msg1\@
+.msg2\@: dc.b \1,0
+ EVEN
+.msg1\@: move.l a6,-(SP)
+ movea.l _MyExecBase,a6
+ move.l #.msg2\@,meb_ROMCrackDebugText ; NICHT (a6)!
+ jsr meb_Debug(a6)
+ move.l (SP)+,a6
+ ENDM
+
+**************************************************************************
+* SMSG "Text" gibt "Text" auf serial port aus
+
+SMSG MACRO
+ XREF _MyExecBase
+ bra.s .smsg1\@
+.smsg2\@: dc.b \1,0
+ EVEN
+.smsg1\@: move.l a6,-(SP)
+ movea.l _MyExecBase,a6
+ pea .smsg2\@(PC)
+ jsr meb_RawPrintf(a6)
+ addq.w #4,SP
+ move.l (SP)+,a6
+ ENDM
+
+**************************************************************************
+* BTSTW: Testet ein Bit in einem WORD
+
+BTSTW MACRO
+
+ IFNE NARG-2
+ FAIL BTSW: Format= BTSTW bitno,<ea>
+ ENDC
+
+ IFGT \1-8
+ btst.b #\1,\2
+ ENDC
+
+ IFLE \1-8
+ btst.b #\1,1+\2
+ ENDC
+
+ ENDM
+
+**************************************************************************
+
+ STRUCTURE Node,0
+
+ APTR ln_Succ
+ APTR ln_Pred
+ UBYTE ln_Type
+ BYTE ln_Pri
+ APTR ln_Name
+ LABEL ln_SIZEOF
+
+**************************************************************************
+
+ STRUCTURE MinNode,0
+
+ APTR mln_Succ
+ APTR mln_Pred
+ LABEL mln_SIZEOF
+
+**************************************************************************
+
+ STRUCTURE List,0
+
+ APTR lh_Head
+ APTR lh_Tail
+ APTR lh_TailPred
+ UBYTE lh_Type
+ UBYTE lh_pad
+ LABEL lh_SIZEOF
+
+**************************************************************************
+
+ STRUCTURE BitMap,0
+
+ WORD bm_BytesPerRow
+ WORD bm_Rows
+ BYTE bm_Flags
+ BYTE bm_Depth
+ WORD bm_Pad
+ STRUCT bm_Planes,8*4
+ LABEL bm_SIZEOF
+
+**************************************************************************
+
+ STRUCTURE DiskPacket,mln_SIZEOF ; Struktur für SendPacket()
+
+ LONG dp_FileName ; Filename von DiskMaker
+ APTR dp_Address ; Ladeadresse wenn nicht DPF_ALLOCMEM
+ LONG dp_FileSize ; Wird ausgefüllt von der Diskroutine
+ APTR dp_Reply ; Routine oder Flag-Adresse oder nix
+ LONG dp_UserData ; Frei benutzbar für den User
+ BYTE dp_Flags ; see DP-definitions below
+ BYTE dp_pad1 ; Strukturlänge auf WORD aufrunden
+ WORD dp_pad2 ; Strukturlänge auf LONG aufrunden :-)
+ LABEL dp_SIZEOF
+
+ BITDEF DP,REPLYHANDLER,0 ; Reply ist Routine (jsr)
+ BITDEF DP,REPLYBYTE,1 ; Reply ist Byte-Flag, wird $ff
+ BITDEF DP,ALLOCMEM,4 ; CHIP wird automatisch reserviert
+ BITDEF DP,ALLOCFASTMEM,5 ; FAST wird automatisch reserviert
+ BITDEF DP,CRUNCHED,6 ; INTERNAL USE ONLY !!!
+ BITDEF DP,WRITE,7 ; Auf Disk schreiben statt lesen
+
+**************************************************************************
+
+ STRUCTURE MemoryRegionHeader,0 ; EXEC-PRIVATE STRUKTUR !
+
+ APTR mh_Lower ; Zeiger auf Anfang der Region
+ APTR mh_Upper ; Zeiger auf Ende der Region
+ APTR mh_First ; Zeiger auf 1. freien Chunk
+ LONG mh_Free ; Anzahl freie Bytes der Region
+ LABEL mh_SIZEOF
+
+**************************************************************************
+
+ STRUCTURE MemoryChunk,0 ; EXEC-PRIVATE STRUKTUR !
+
+ APTR mc_Next ; Zeiger auf nächsten freien Chunk
+ LONG mc_Bytes ; Anzahl Bytes dieses Chunks
+ LABEL mc_SIZEOF
+
+**************************************************************************
+
+ *** AttentionFlag - Bits
+
+ BITDEF AF,68010,0 ; also set for 68020+
+ BITDEF AF,68020,1 ; also set for 68030+
+ BITDEF AF,68030,2 ; also set for 68040+
+ BITDEF AF,68040,3
+ BITDEF AF,68881,4 ; also set for 68882
+ BITDEF AF,68882,5
+
+ *** Flag - Bits, only for internal use :-)
+
+ BITDEF EXEC,BUFENABLE,0
+ BITDEF EXEC,RESETREQUEST,4
+
+**************************************************************************
+
+ STRUCTURE MyExecBaseStruct,$100
+
+ LONG meb_ROMCRACKMagic ; 'NCLR' oder 'DBUG' oder 0
+ LONG meb_ROMCrackConfigMagic ; 'ICH!'
+ APTR meb_ROMCrackBSS
+ APTR meb_ROMCrackChipMem
+ APTR meb_ROMCrackDebugText ; ROMCrack's Debug-Text
+
+ *** Private Einträge, SUBJECT TO CHANGE, NICHT BENUTZEN!
+
+ STRUCT meb_ChipMRHeader,mh_SIZEOF
+ STRUCT meb_FastMRHeader,mh_SIZEOF
+ APTR meb_RAMDiskBase
+ LONG meb_RAMDiskSize
+ LONG meb_MainPrgName
+ LONG meb_LastRnd1 ; Beide müssen nacheinander stehen
+ LONG meb_LastRnd2
+ STRUCT meb_DiskList,lh_SIZEOF ; Die Packet-Liste
+ STRUCT meb_FileList,lh_SIZEOF ; Die File-Cache-Liste
+ WORD meb_ProductCode
+ BYTE meb_IDNestCnt
+ BYTE meb_ExecFlags ; siehe EXECF_...
+
+ *** Erlaubte Einträge
+
+ APTR meb_SuperStackUpper ; SuperStack am Anfang (READ ONLY!)
+ WORD meb_AttnFlags ; Kopie von ExecBase->AttnFlags
+ WORD meb_SystemBplcon0 ; Kopie von gfxbase->system_bplcon0
+ BYTE meb_VBlankFrequency ; Kopie von ExecBase->VBlankFrequency
+ BYTE meb_expad2
+
+ BYTE meb_ActualKey ; RawKeyCode
+ BYTE meb_ActualQualifiers ; Qualifier-Bits, (BitNr=KeyCode-$60)
+ BYTE meb_ActualASCIIKey ; ASCII-Code
+ BYTE meb_CheatFlag ; >0 falls Cheat mode on
+
+ STRUCT meb_BobList,lh_SIZEOF ; für die Bobroutine
+ APTR meb_TripleScreen ; für die Bobroutine
+ WORD meb_SignalSet ; für die Bobroutine
+
+ LONG meb_UserData1 ; Frei für den User, am Anfang 0
+ LONG meb_UserData2 ; Frei für den User, am Anfang 0
+
+ STRUCT meb_exreserved,6 ; + pad auf LONG, NICHT benutzen!
+
+ *** Level 3 Interrupt-Vektoren, zum Patchen oder 0 reinschreiben
+
+ UWORD meb_VBLIntPad
+ UWORD meb_VBLIntJump
+ APTR meb_VBLIntVector
+
+ UWORD meb_CopperIntPad
+ UWORD meb_CopperIntJump
+ APTR meb_CopperIntVector
+
+ *** Cia-Interrupt-Vektoren, zum Patchen oder 0 reinschreiben
+
+ APTR meb_CiaATimerAVector
+ APTR meb_CiaATimerBVector
+ APTR meb_CiaAAlarmVector
+ APTR meb_CiaASerialVector
+ APTR meb_CiaAFlagVector
+
+ APTR meb_CiaBTimerAVector
+ APTR meb_CiaBTimerBVector
+ APTR meb_CiaBAlarmVector
+ APTR meb_CiaBSerialVector
+ APTR meb_CiaBFlagVector
+
+
+ *** System-Funktionen (use at your own risk!)
+
+ ULONG meb_SecretMagic ; PRIVAT
+ FUNCTION InitExec ; (ExecEvent) (CRP)
+ FUNCTION ColdReboot ; () ()
+ FUNCTION InitChipMem ; (Address,Size) (A0/D0)
+ FUNCTION InitFastMem ; (Address,Size) (A0/D0)
+ FUNCTION InitDisk ; (Product) (D0)
+ FUNCTION InitKey ; () ()
+ FUNCTION SetCache ; (NewCacheBits) (D0)
+
+ *** Debug-Funktionen
+
+ FUNCTION Debug ; () ()
+
+ *** Speicherverwaltung
+
+ FUNCTION AllocMem ; (Amount) (D0)
+ FUNCTION AllocClearMem ; (Amount) (D0)
+ FUNCTION AllocFastMem ; (Amount) (D0)
+ FUNCTION AllocFastClearMem ;(Amount) (D0)
+ FUNCTION FreeMem ; (Address) (A1)
+ FUNCTION AvailMem ; () ()
+ FUNCTION AvailFastMem ; () ()
+ FUNCTION CheckMem ; () ()
+ FUNCTION CopyMem ; (Src,Dest,Len) (A0/A1/D0)
+ FUNCTION CopyMemQuick ; (Src,Dest,Len) (A0/A1/D0)
+ FUNCTION ClearMem ; (Address,Len) (A0/D0)
+
+ *** Semaphoren
+
+ FUNCTION Disable ; () ()
+ FUNCTION Enable ; () ()
+ FUNCTION OwnBlitter ; () ()
+ FUNCTION DisownBlitter ; () ()
+
+ *** Listenverwaltung
+
+ FUNCTION NewList ; (List) (A0)
+ FUNCTION Enqueue ; (List,Node) (A0/A1)
+ FUNCTION Remove ; (Node) (A1)
+ FUNCTION AddHead ; (List,Node) (A0/A1)
+ FUNCTION AddTail ; (List,Node) (A0/A1)
+ FUNCTION RemHead ; (List) (A0)
+
+ *** Tastatur
+
+ FUNCTION GetKey ; () ()
+ FUNCTION WaitKey ; () ()
+ FUNCTION FlushKeyBuf ; () ()
+ FUNCTION SetMap ; (KeyMap oder 0) (A0)
+ FUNCTION SetResetHandler ; (Handler) (A0)
+ FUNCTION SetCheatText ; (RawKeyCodes) (A0)
+
+ *** Ausgabe
+
+ FUNCTION RawDoFmt ; (wie normal :-)) (...)
+ FUNCTION RawPrintf ; (Stack) (...)
+ FUNCTION PlayCDTrack ; (TrackNumber) (D0)
+ FUNCTION WaitCDTrack ; (nüt) ()
+
+ *** Zufall
+
+ FUNCTION Randomize ; (Value1,Value2) (D0/D1)
+ FUNCTION Random ; (Limit) (D0)
+
+ *** Disk-Routinen
+
+ FUNCTION SetNoDiskHandler ;(Routine) (A0)
+ FUNCTION ReadFile ; (Name,Address) (D0/A0)
+ FUNCTION WriteFile ; (Name,Address) (D0/A0)
+ FUNCTION LoadFile ; (Name) (D0)
+ FUNCTION LoadFastFile ; (Name) (D0)
+ FUNCTION LoadSeg ; (Name) (D0)
+ FUNCTION UnLoadSeg ; (Segment) (A1)
+ FUNCTION BufReadFile ; (Name,Address (D0/A0)
+ FUNCTION BufLoadFile ; (Name) (D0)
+ FUNCTION DeleteFileNode ; (Name) (D0)
+ FUNCTION DeleteFileList ; () ()
+ FUNCTION SendPacket ; (Packet) (A0)
+
+ *** Bob-Routinen
+
+ FUNCTION WaitBlit ; (Custom) (A5)
+ FUNCTION InitDrawBob ; (BitMap) (A0)
+ FUNCTION AddBob ; (NewBob) (A1)
+ FUNCTION RemBob ; (Bob) (A0)
+ FUNCTION RemAllBobs ; () ()
+ FUNCTION RestoreBobList ; (BitMap) (A1)
+ FUNCTION DrawBobList ; (BitMap) (A1)
+ FUNCTION RestoreOneBob ; (Bob,BitMap) (A0/A1)
+ FUNCTION DrawOneBob ; (Bob,BitMap) (A0/A1)
+ FUNCTION AnimateOneBob ; (Bob) (A0)
+ FUNCTION MoveOneBob ; (Bob) (A0)
+ FUNCTION TestPoint ; (X,Y) (D0/D1)
+ FUNCTION SetMovePrg ; (Bob,MPrg,Speed,Step) (A0/A1/D0/D1)
+ FUNCTION SetAnimPrg ; (Bob,APrg,Speed) (A0/A1/D0)
+ FUNCTION SetGlobalClip ; (X,Y) (D0/D1)
+ FUNCTION HandleCollision ; () ()
+ FUNCTION CollOneBob ; (Bob) (A0)
+ FUNCTION FlashBob ; (Bob,Time,Color) (A0/D0/D1)
+ FUNCTION GetBobData ; (Bob) (A0)->A2
+
+ LABEL __EXECBASESIZE
diff --git a/PPDecrunch.S b/PPDecrunch.S
new file mode 100644
index 0000000..f606593
--- /dev/null
+++ b/PPDecrunch.S
@@ -0,0 +1,151 @@
+*****************************************************************************
+** **
+** PPDecrunch - Eine Datei PowerPacker-decrunchen auf sich selber **
+** **
+** Parameter : A0.L : Adresse **
+** D0.L : Länge der gecrunchten Daten **
+** **
+** Resultat : nix **
+** **
+*****************************************************************************
+
+ IDNT PPDecrunch
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+
+ XDEF PPDecrunch
+
+PPDecrunch: movem.l d0-d7/a0-a5,-(SP)
+ lea Efficiency(PC),a5 ; A5: Pointer to efficiency
+ move.l a0,-(SP) ; Buffer für später
+ lea PP_SAVEMARGIN(a0),a3 ; A3: Destination
+ move.l a3,-(SP) ; Quelle für später
+ move.l (a0)+,-(SP) ; Decrunchte Grösse für später
+
+ move.l (a0)+,(a5) ; Efficiency eintragen
+ lea -8(a0,d0.l),a0 ; A0: Source-Ende
+
+ move.l a6,-(SP)
+ bsr.b Decrunch
+ movea.l (SP)+,a6
+
+ move.l (SP)+,d0 ; Decrunchte Grösse
+ movea.l (SP)+,a0 ; Quelle
+ movea.l (SP)+,a1 ; Ziel
+ jsr meb_CopyMem(a6) ; runterschieben
+
+ movem.l (SP)+,d0-d7/a0-a5
+ rts
+
+Efficiency: dc.l 0
+
+
+****************************************************************************
+* *
+* PowerPacker Decrunch assembler subroutine V2.0 (reentrant !) *
+* DESTROYS ALL REGISTERS! *
+* *
+* call as: *
+* pp_DecrunchBuffer (endcrun, buffer, &efficiency, coloraddr); *
+* with: *
+* A0 endcrun : UBYTE * just after last byte of crunched file *
+* A3 buffer : UBYTE * to memory block to decrunch in *
+* A5 &efficiency: ptr to Longword defining efficiency of crunched file *
+* *
+* NOTE: *
+* Decrunch a few bytes higher (safety margin) than the crunched file *
+* to decrunch in the same memory space. (8 bytes suffice) *
+* *
+****************************************************************************
+
+Decrunch: moveq #3,d6
+ moveq #7,d7
+ moveq #1,d5
+ move.l a3,a2 ; remember start of file
+ move.l -(a0),d1 ; get file length and empty bits
+ tst.b d1
+ beq.b NoEmptyBits
+ bsr.b ReadBit ; this will always get the next long (D5 = 1)
+ subq.b #1,d1
+ lsr.l d1,d5 ; get rid of empty bits
+NoEmptyBits:
+ lsr.l #8,d1
+ add.l d1,a3 ; a3 = endfile
+LoopCheckCrunch:
+ bsr.b ReadBit ; check if crunch or normal
+ bcs.b CrunchedBytes
+NormalBytes:
+ moveq #0,d2
+Read2BitsRow:
+ moveq #1,d0
+ bsr.b ReadD1
+ add.w d1,d2
+ cmp.w d6,d1
+ beq.b Read2BitsRow
+ReadNormalByte:
+ moveq #7,d0
+ bsr.b ReadD1
+ move.b d1,-(a3)
+ dbf d2,ReadNormalByte
+ cmp.l a3,a2
+ bcs.b CrunchedBytes
+ rts
+ReadBit:
+ lsr.l #1,d5 ; this will set X if d5 becomes zero
+ beq.b GetNextLong
+ rts
+GetNextLong:
+ move.l -(a0),d5
+ roxr.l #1,d5 ; X-bit set by lsr above
+ rts
+ReadD1sub:
+ subq.w #1,d0
+ReadD1:
+ moveq #0,d1
+ReadBits:
+ lsr.l #1,d5 ; this will set X if d5 becomes zero
+ beq.b GetNext
+RotX:
+ roxl.l #1,d1
+ dbf d0,ReadBits
+ rts
+GetNext:
+ move.l -(a0),d5
+ roxr.l #1,d5 ; X-bit set by lsr above
+ bra.b RotX
+CrunchedBytes:
+ moveq #1,d0
+ bsr.b ReadD1 ; read code
+ moveq #0,d0
+ move.b 0(a5,d1.w),d0 ; get number of bits of offset
+ move.w d1,d2 ; d2 = code = length-2
+ cmp.w d6,d2 ; if d2 = 3 check offset bit and read length
+ bne.b ReadOffset
+ bsr.b ReadBit ; read offset bit (long/short)
+ bcs.b LongBlockOffset
+ moveq #7,d0
+LongBlockOffset:
+ bsr.b ReadD1sub
+ move.w d1,d3 ; d3 = offset
+Read3BitsRow:
+ moveq #2,d0
+ bsr.b ReadD1
+ add.w d1,d2 ; d2 = length-1
+ cmp.w d7,d1 ; cmp with #7
+ beq.b Read3BitsRow
+ bra.b DecrunchBlock
+ReadOffset:
+ bsr.b ReadD1sub ; read offset
+ move.w d1,d3 ; d3 = offset
+DecrunchBlock:
+ addq.w #1,d2
+DecrunchBlockLoop:
+ move.b 0(a3,d3.w),-(a3)
+ dbf d2,DecrunchBlockLoop
+EndOfLoop:
+ cmp.l a3,a2
+ bcs LoopCheckCrunch
+ rts
+
+ END
diff --git a/RawDoFmt.S b/RawDoFmt.S
new file mode 100644
index 0000000..3b2487c
--- /dev/null
+++ b/RawDoFmt.S
@@ -0,0 +1,351 @@
+***************************************************************************
+** **
+** RawDoFmt - Die geniale Ausgabe-Routine, beherrscht neuerdings **
+** auch Binär-Zahlen (%b, %lb, %04b etc.) **
+** **
+***************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 01-May-89 CHW Created this file from CHH's HdExec.S **
+** 01-May-89 CHW Binary String Conversion added, code cleaned up **
+** 25-Nov-89 CHW Linksize changed from 34 to 64 (Paranoia?) **
+** **
+***************************************************************************
+
+ OPT O+,OW-,O5-,OW6+
+
+ SECTION text,CODE
+
+ XDEF RawDoFmtFunc,_RawPrintfFunc
+
+RB_LEFTALIGNED: EQU 0 ; Flag-Definitionen
+RB_ZEROFILL: EQU 1
+RB_LONGARG: EQU 2
+
+LINKSIZE: EQU 64 ; Jaja, binär wird lang...
+
+
+***************************************************************************
+
+ *** A0=Formatstring A1=Args A2=Routine A3=Ptr für Routine
+
+RawDoFmtFunc: movem.l d0-d6/a0-a5,-(a7)
+ link a6,#-LINKSIZE ; Puffer für Umwandlungen
+ move.l a1,-(SP) ; Argumente
+ move.l a0,a4 ; Formatstring
+
+MainLoop: move.b (a4)+,d0 ; Nächstes Zeichen
+ beq.s Ende ; fertig --->
+ cmpi.b #'%',d0
+ beq.s DoFormat
+DirectOut: jsr (a2) ; Zeichen direkt ausgeben
+ bra.s MainLoop ; --->
+
+Ende: jsr (a2) ; Endzeichen ausgeben
+ unlk a6
+ movem.l (SP)+,d0-d6/a0-a5
+ rts
+
+ *** Format-Anweisung bearbeiten
+
+DoFormat: lea -LINKSIZE(a6),a5 ; Start des Puffers
+ clr.w d3 ; Flags löschen
+ cmpi.b #'-',(a4) ; Erstes Zeichen == '-' ?
+ bne.s 1$ ; nein --->
+ bset #RB_LEFTALIGNED,d3 ; Linksbündig-Flag setzen
+ addq.l #1,a4 ; Formatzeiger vorrücken
+1$:
+ cmpi.b #'0',(a4) ; Nächstes Zeichen == '0' ?
+ bne.s 2$ ; nein --->
+ bset #RB_ZEROFILL,d3 ; Flag für mit Nullen füllen
+2$:
+ bsr DecimalConvert
+ move.w d0,d6 ; D6 := minimale Feldbreite
+ clr.l d5
+ cmpi.b #'.',(a4) ; Nächstes Zeichen == '.' ?
+ bne.s 3$ ; nein --->
+ addq.w #1,a4 ; Formatzeiger vorrücken
+ bsr DecimalConvert
+ move.w d0,d5 ; D5 := maximale Feldbreite
+3$:
+ cmpi.b #'l',(a4) ; Nächstes Zeichen == 'l' ?
+ bne.s 4$ ; nein --->
+ bset #RB_LONGARG,d3 ; Flag für LONG-Argument
+ addq.w #1,a4 ; Formatzeiger vorrücken
+4$:
+ move.b (a4)+,d0 ; Nächstes Zeichen
+ cmpi.b #'d',d0 ; 'd': Dezimaldarstellung ?
+ bne.s 5$ ; nein --->
+ bsr.s GetData ; Daten nach D4
+ bsr D4ToDez ; und in String verwandeln
+ bra.s AusgAbschl
+5$:
+ cmpi.b #'x',d0 ; 'x': Hex-Darstellung ?
+ bne.s 6$ ; nein --->
+ bsr.s GetData ; Daten nach D4
+ bsr D4ToHex ; und in String verwandeln
+ bra.s AusgAbschl
+6$:
+ cmpi.b #'b',d0 ; 'b': Binär-Darstellung ?
+ bne.s 7$ ; nein --->
+ bsr.s GetData ; Daten nach D4
+ bsr D4ToBin ; und in String verwandeln
+ bra.s AusgAbschl
+7$:
+ cmpi.b #'s',d0 ; 's': String ?
+ bne.s 8$ ; nein --->
+ move.l (a7),a1 ; A1: Ausgabedaten
+ move.l (a1)+,a5 ; A5: Zeiger auf String
+ move.l a1,(a7) ; Neues A1 zurückschreiben
+ bra.s AusgAbschl2
+8$:
+ cmpi.b #'c',d0 ; 'c': Einzelnes Zeichen ?
+ bne DirectOut ; nein --->
+ bsr.s GetData ; Zeichencode nach D4
+ move.b d4,(a5)+ ; und in Puffer schreiben
+
+
+AusgAbschl: clr.b (a5) ; Puffer mit 0 abschliessen
+ lea -LINKSIZE(a6),a5 ; A5: Pufferanfang
+
+AusgAbschl2: move.l a5,a0
+ bsr.s StrLenD2
+ tst.w d5 ; Maximale Feldlänge ?
+ beq.s 1$ ; nein --->
+ cmp.w d5,d2 ; String länger als max. ?
+ bhi.s 2$ ; ja --->
+1$:
+ move.w d2,d5 ; Feldlänge := Stringlänge
+2$:
+ sub.w d5,d6 ; D6 := Feldlänge-Stringlänge
+ bpl.s 3$ ; Feldlänge grösser --->
+ clr.w d6
+3$:
+ btst #RB_LEFTALIGNED,d3 ; Linksbündige Ausgabe ?
+ bne.s 5$ ; ja --->
+ bsr Filler ; Mit 0 oder Space füllen
+
+ bra.s 5$ ; für dbf
+4$: move.b (a5)+,d0 ; Nächstes Zeichen
+ jsr (a2) ; ausgeben
+5$: dbf d5,4$
+
+ btst #RB_LEFTALIGNED,d3 ; Linksbündig ?
+ beq MainLoop ; nein --->
+ bsr Filler ; sonst auffüllen
+ bra MainLoop ; --->
+
+**************************************************************************
+
+ *** Ausgabedaten nach D4 holen
+
+GetData: move.l 4(a7),a1 ; Argument-Array
+ btst #RB_LONGARG,d3 ; LONG-Argument ?
+ bne.s 1$ ; ja --->
+ move.w (a1)+,d4 ; Datenwort holen
+ move.l a1,4(a7) ; Neues A1 zurückschreiben
+ ext.l d4 ; Wort auf LONG erweitern
+ rts
+1$:
+ move.l (a1)+,d4 ; Datenlangwort holen
+ move.l a1,4(a7) ; Neues A1 zurückschreiben
+ rts
+
+***************************************************************************
+
+ *** Stringlänge von (a0) nach D2
+
+StrLenD2: moveq #-1,d2
+1$: tst.b (a0)+
+ dbeq d2,1$
+ neg.l d2
+ subq.w #1,d2
+ rts
+
+***************************************************************************
+
+ *** Dezimal-String (A4) in Zahl D0 umwandeln
+
+DecimalConvert: clr.l d0
+ clr.l d2
+1$: move.b (a4)+,d2 ; Nächstes Zeichen
+ cmpi.b #'0',d2
+ bcs.s 2$
+ cmpi.b #'9',d2
+ bhi.s 2$
+ move.l d0,d1
+ lsl.l #2,d0 ; Zahl *= 4
+ add.l d1,d0 ; gibt * 5
+ add.l d0,d0 ; gibt * 10
+ subi.b #'0',d2
+ add.l d2,d0 ; Zahl += nächste Ziffer
+ bra.s 1$ ; ---> Loop
+2$: subq.l #1,a4
+ rts
+
+***************************************************************************
+
+ *** Zahl D4 in Dezimal-String (A5)+ umwandeln
+
+D4ToDez: tst.l d4 ; Zahl testen
+ beq.s D4To_End ; == 0 --->
+ bmi.s 1$ ; < 0 --->
+ neg.l d4 ; Zahl negieren
+ bra.s 2$ ; --->
+1$: move.b #'-',(a5)+ ; Minuszeichen
+2$:
+ lea ZehnerPotenzen(PC),a0
+ st d1 ; Anfangsnullenflag setzen
+3$:
+ move.l (a0)+,d2 ; D2 := nächster Tabellenwert
+ beq.s D4To_End ; Tabelle fertig --->
+
+ moveq #-1,d0 ; Zähler := 0
+4$: add.l d2,d4 ; So oft D2 zur Zahl addieren
+ dbgt d0,4$ ; bis sie positiv ist
+ sub.l d2,d4 ; dann einmal subtrahieren
+ addq.w #1,d0 ; Wurde nur 1* addiert ?
+ bne.s 5$ ; nein --->
+ tst.b d1 ; Ist es eine führende 0 ?
+ bne.s 3$ ; ja ---> nicht ausgeben
+5$:
+ sf d1 ; Anfangsnullenflag löschen
+ neg.b d0 ; Zahl der Additionen -1
+ addi.b #'0',d0 ; ergibt Zifferncode
+ move.b d0,(a5)+ ; Ziffer in Puffer
+ bra.s 3$ ; ---> Loop
+D4To_End:
+ neg.b d4 ; D4 := Letzte Ziffer
+ addi.b #'0',d4 ; ergibt Zifferncode
+ move.b d4,(a5)+ ; Ziffer in Puffer
+ rts
+
+ZehnerPotenzen: dc.l 1000000000
+ dc.l 100000000
+ dc.l 10000000
+ dc.l 1000000
+ dc.l 100000
+ dc.l 10000
+ dc.l 1000
+ dc.l 100
+ dc.l 10
+ dc.l 0 ; Endmarke
+ dc.l $43485721
+
+***************************************************************************
+
+ *** Zahl D4 in Hex-String (A5)+ umwandeln
+
+D4ToHex: tst.l d4 ; Zahl testen
+ beq D4To_End ; == 0 --->
+ st d1 ; Anfangsnullenflag setzen
+ btst #RB_LONGARG,d3 ; LONG-Argument ?
+ bne.s 1$ ; ja --->
+ moveq #3,d2 ; sonst 4 Stellen
+ swap d4 ; Zahlwert in oberes Wort
+ bra.s 2$
+1$: moveq #7,d2 ; 8 Stellen
+2$:
+ rol.l #4,d4 ; Bits 0-3 := nächste Stelle
+ move.b d4,d0
+ andi.b #15,d0
+ bne.s 3$ ; Nicht 0 --->
+ tst.b d1 ; Anfangsnull ?
+ bne.s 6$ ; ja ---> nicht ausgeben
+3$:
+ sf d1 ; Anfangsnullenflag löschen
+ cmpi.b #9,d0 ; Ziffer > 9 ?
+ bhi.s 4$ ; ja --->
+ addi.b #'0',d0
+ bra.s 5$
+4$: addi.b #'A'-10,d0
+5$: move.b d0,(a5)+ ; Ziffer in Puffer
+6$: dbf d2,2$ ; Loop --->
+ rts
+
+***************************************************************************
+
+ *** Zahl D4 in Binär-String (A5)+ umwandeln
+
+D4ToBin: tst.l d4 ; Zahl testen
+ beq D4To_End ; == 0 --->
+ st d1 ; Anfangsnullenflag setzen
+ btst #RB_LONGARG,d3 ; LONG-Argument ?
+ bne.s 1$ ; ja --->
+ moveq #15,d2 ; sonst 16 Stellen
+ swap d4 ; Zahlwert in oberes Wort
+ bra.s 2$
+1$: moveq #31,d2 ; 32 Stellen
+2$: roxl.l #1,d4 ; Nächste Stelle in Carry
+ bcs.s 3$ ; 1 --->
+ tst.b d1 ; Anfangsnull ?
+ bne.s 5$ ; ja ---> nicht ausgeben
+ moveq #'0',d0
+ bra.s 4$ ; --->
+3$: sf d1 ; Anfangsnullenflag löschen
+ moveq #'1',d0
+4$: move.b d0,(a5)+ ; Ziffer in Puffer
+5$: dbf d2,2$ ; Loop --->
+ rts
+
+***************************************************************************
+
+ *** Nullen oder Leerstellen ausgeben
+
+Filler: move.b #' ',d2 ; Füllcode: Space
+ btst #RB_ZEROFILL,d3 ; Füllen mit Nullen ?
+ beq.s 2$ ; nein --->
+ move.b #'0',d2 ; Sonst Füllcode '0'
+ bra.s 2$ ; Für dbf
+1$: move.b d2,d0 ; Füllcode
+ jsr (a2) ; ausgeben
+2$: dbf d6,1$
+ rts
+
+
+*************************************************************************
+*
+* _RawPrintf.asm - Self-contained printf clone. Formatted strings
+* are sent directly out the serial port. Xon/Xoff
+* handshake is supported.
+* This function may be called at any time, including
+* interrupts.
+*
+* Bryce Nesbitt, 02-24-89
+*
+*************************************************************************
+
+ XDEF _RawPrintfFunc
+
+_RawPrintfFunc: movem.l a0/a1,-(SP)
+ move.l 4*3(SP),A0 ;grab format string
+ lea.l 4*4(SP),A1 ;grab stack address of parameters
+ movem.l A2/A3/D0/D1,-(SP)
+ lea.l PSCODE(pc),a2
+ suba.l a3,a3
+ bsr RawDoFmtFunc
+ movem.l (SP)+,D0/D1/A2/A3
+ movem.l (SP)+,a0/a1
+ rts
+
+
+PSCODE: tst.b d0
+ beq.s ignore
+1$ move.w $DFF018,d1 ;_serdatr
+ btst #13,d1 ;TBE bit
+ beq.s 1$
+ and.b #$7f,d1
+ cmp.b #$18,d1 ;Check for CAN (^X)
+ beq.s ignore
+ cmp.b #$13,d1 ;Check for Xoff
+ beq.s 1$
+ and.w #$ff,d0
+ or.w #$100,d0
+ move.w d0,$DFF030 ;_serdat
+ignore: rts
+
+*****************************************************************************
+
+ END
diff --git a/Rnd.S b/Rnd.S
new file mode 100644
index 0000000..8aeea74
--- /dev/null
+++ b/Rnd.S
@@ -0,0 +1,55 @@
+
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+
+ XDEF RandomizeFunc,RandomFunc
+
+
+ *** Random initialisieren, D0/D1 : Zufallswerte
+
+RandomizeFunc: movem.l d0-d3,-(SP)
+ add.l d0,d1 ; user seed in d0 (d1 too)
+ move.l d0,meb_LastRnd1(a6) ; save for next time through
+ move.l d1,meb_LastRnd2(a6)
+ bsr.s LongRnd
+ movem.l (SP)+,d0-d3
+ rts
+
+
+ *** Zufallszahl [0..D0.W] berechnen
+
+RandomFunc: movem.l d1-d4,-(SP)
+ move.w d0,d4 ; save upper limit
+ beq.s 1$ ; range of 0 returns 0 always
+ bsr.s LongRnd ; get a longword random number
+ clr.w d0 ; use upper word (it's most random)
+ swap d0
+ divu.w d4,d0 ; divide by range...
+ clr.w d0 ; ...and use remainder for the value
+ swap d0 ; result in D0.W
+1$: movem.l (SP)+,d1-d4
+ rts
+
+
+LongRnd: movem.l meb_LastRnd1(a6),d0/d1 ; D0=LSB's, D1=MSB's of random number
+ andi.b #$0e,d0 ; ensure upper 59 bits are an...
+ ori.b #$20,d0 ; ...odd binary number
+ move.l d0,d2
+ move.l d1,d3
+ add.l d2,d2 ; accounts for 1 of 17 left shifts
+ addx.l d3,d3 ; [D2/D3] = RND*2
+ add.l d2,d0
+ addx.l d3,d1 ; [D0/D1] = RND*3
+ swap d3 ; shift [D2/D3] additional 16 times
+ swap d2
+ move.w d2,d3
+ clr.w d2
+ add.l d2,d0 ; add to [D0/D1]
+ addx.l d3,d1
+ movem.l d0/d1,meb_LastRnd1(a6) ; save for next time through
+ move.l d1,d0 ; most random part to D0
+ rts
+
+
+ END
diff --git a/SCOPTIONS b/SCOPTIONS
new file mode 100644
index 0000000..504d97c
--- /dev/null
+++ b/SCOPTIONS
@@ -0,0 +1,24 @@
+MATH=FFP
+PARAMETERS=REGISTERS
+NOSTACKCHECK
+STRINGMERGE
+UNSIGNEDCHARS
+STRUCTUREEQUIVALENCE
+OPTIMIZE
+MAP
+MAPHUNK
+MAPSYMBOLS
+MAPLIB
+MAPXREFERENCE
+MAPOVERLAY
+NOVERSION
+NOICONS
+MEMORYSIZE=HUGE
+INCLUDEDIR=SC:Include
+INCLUDEDIR=INCUSR:
+DEFINE __USE_SYSBASE
+CODENAME=text
+DATANAME=data
+BSSNAME=bss
+MAPFILE=RAM:slink.map
+MAXIMUMWARNINGS=50
diff --git a/Start.c b/Start.c
new file mode 100644
index 0000000..e0dc229
--- /dev/null
+++ b/Start.c
@@ -0,0 +1,487 @@
+/****************************************************************************
+** **
+** Start.c - Rettet CHIP-RAM, lädt und startet Exec, Exit. **
+** **
+*****************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 19-May-89 CHW Created this file from Auto/Start.S **
+** 04-Jun-89 CHW Testet jetzt ob RAMDisk vorhanden ist **
+** 20-Jun-89 CHW Unterstützt jetzt 1MB CHIP-RAM wenn man's hat **
+** 21-Jun-89 CHW ENV-Variable 'RAMDISKBASE' implementiert **
+** 27-Jun-89 CHW Converted to genim2 **
+** 24-Aug-89 CHW Disk-Version implemented **
+** 27-Nov-89 CHW FastRAM implemented **
+** 15-Dec-89 CHW VBR wird nach 0 gelegt **
+** 30-Jan-90 CHW 1MB ChipRAM wird bei $a0000 statt $90000 getestet **
+** 03-Apr-90 CHW CiaKick eingebaut **
+** 24-Jul-90 CHW NoSave option eingebaut **
+** 03-Sep-90 CHW C-Version, ARP Parser, variable MemSize eingebaut **
+** 01-Oct-90 CHW CHIPSIZE-Option funktioniert jetzt **
+** 17-Oct-90 CHW CHIPSIZE-Option funktioniert wirklich :-) **
+** 23-Feb-91 CHW Läuft jetzt mit dem 2.0 ramdrive.device **
+** 09-May-91 RHS RamDrive Grösse wird jetzt richtig gelesen **
+** 16-Jun-91 CHH TimerB Bug behoben. **
+** 16-Jun-91 CHW/CHH Läuft jetzt unter 2.0 ("chip memory" :-() **
+** **
+****************************************************************************/
+
+#define VERBOSE
+
+#include <proto/exec.h>
+#include <exec/io.h>
+#include <exec/memory.h>
+#include <exec/execbase.h>
+#include <proto/graphics.h>
+#include <proto/intuition.h>
+#include <graphics/gfxbase.h>
+#include <hardware/custom.h>
+#include <hardware/dmabits.h>
+#include <hardware/intbits.h>
+#include <resources/cia.h>
+#include <dos/dosextens.h>
+#include <dos/filehandler.h>
+#include <string.h> /* z.B. für __builtin_memcpy */
+#include <dos.h> /* Für getreg und so */
+
+#include <chlib.h>
+
+extern void exit(long);
+
+extern struct ExecBase *SysBase;
+extern struct DosLibrary *DOSBase;
+extern BPTR StdErr; /* Standard Error output stream */
+extern BYTE NewOS;
+extern struct Custom __far custom;
+
+extern char ExecModuleStart,ExecModuleEnd;
+
+struct GfxBase *GfxBase;
+struct IntuitionBase *IntuitionBase;
+
+char ident[] = "$VER: Exec V4.5 (" __DATE__ ") by Christian A. Weber";
+char CLI_Template[] = "NS=NOSAVE/S,NF=NOFAST/S,CS=CHIPSIZE/N";
+char CLI_Help[] = "Usage: Start [NOSAVE] [NOFAST] [CHIPSIZE size]";
+struct
+{
+ LONG NoSave;
+ LONG NoFast;
+ LONG *ChipSizePtr;
+} argv;
+
+
+/***************************************************************************/
+
+#define ABORT 0x1FFFFA /* Am Ende des CHIP RAMs */
+#define DISKMAGIC 0x43485700 /* Currently 'CHW',0 */
+#define INITMAGIC 0x494E4954 /* 'INIT' */
+#define FFSMAGIC 0x444f5301 /* 'DOS',1 */
+#define local
+
+struct RUN /* 2.0 RAD Unit-Struktur */
+{
+ struct MinNode Node;
+ void *MemPtr;
+ UWORD MatchWord;
+};
+
+struct Mem
+{
+ struct Mem *Next;
+ void *Address;
+ ULONG Size;
+} *chipmemlist; /* Liste der geretteten CHIP-Blöcke */
+
+UBYTE *radmem; /* Startadresse der RAD-Disk */
+ULONG radsize; /* Grösse der RAD-Disk */
+ULONG radunit; /* Unit-Nummer der RAD-Disk */
+
+UBYTE *fastbase; /* Startadresse des FAST-RAMs für Exec */
+LONG fastsize; /* Grösse des FAST-RAMs für Exec */
+
+UWORD dmaconsave,intenasave;
+ULONG attnflags,vblankfreq,sysbplcon0;
+ULONG oldcacr,oldvbr;
+
+ULONG oldssp,oldusp; /* Gerettete Supervisor- und User-Stackpointer */
+ULONG stacktop; /* Obergrenze des Chip-RAMs für Exec */
+
+ULONG GetVBR(void) { return 0; } /* Macht das Sinn?? */
+void SetVBR(ULONG vbr) { }
+
+
+#ifdef DEBUG
+/***************************************************************************/
+/* Auf Maustaste warten und dabei Farbe ausgeben */
+
+local void Maus(UWORD col)
+{
+ LONG i;
+ while((*(UBYTE *)0xbfe001)&0x40)
+ custom.color[0]=col;
+ while(!((*(UBYTE *)0xbfe001)&0x40))
+ ;
+ for(i=0; i<200000; ++i)
+ custom.color[0]=(UWORD)i;
+ custom.color[0]=0;
+}
+#endif
+
+/***************************************************************************/
+/* Gerettetes CHIP-RAM zurückkopieren */
+
+local void RestoreChipRAM(void)
+{
+ struct Mem *mc;
+
+ for(mc=chipmemlist; mc; mc=mc->Next)
+ memcpy(mc->Address,mc+1,mc->Size);
+}
+
+/***************************************************************************/
+/* Save-Buffers des CHIP-RAMs freigeben */
+
+local void FreeChipRAMSaveBuffers(void)
+{
+ struct Mem *mc,*next;
+ LONG size=0;
+
+ for(mc=chipmemlist; mc; mc=next)
+ {
+ size+=mc->Size;
+ next=mc->Next;
+ FreeMem(mc,mc->Size+sizeof(*mc));
+ }
+ chipmemlist = NULL;
+ printf("Saved Chip-RAM = %ld bytes.\n",size);
+}
+
+/***************************************************************************/
+/* Alles allozierte CHIP-RAM retten und in eine Liste eintragen */
+
+local BOOL SaveChipRAM(void)
+{
+ struct MemHeader *mrh;
+ struct MemChunk *mc;
+ struct Mem *dc, *olddc = (struct Mem *)&chipmemlist;
+ ULONG last=0;
+
+ if(!(mrh=(struct MemHeader *)FindName(&SysBase->MemList,"Chip Memory")))
+ {
+ if(!(mrh=(struct MemHeader *)FindName(&SysBase->MemList,"chip memory")))
+ {
+ Enable();
+ DisownBlitter();
+ Puts("Can't find the Chip Memory header");
+ return FALSE;
+ }
+ }
+
+ for (mc = mrh->mh_First;; mc=mc->mc_Next)
+ {
+ ULONG size;
+ if (mc == NULL)
+ mc = (struct MemChunk *)(SysBase->MaxLocMem - sizeof(*mc));
+
+ size = (ULONG)mc - (ULONG)last + sizeof(*mc);
+ if ((ULONG)last < (ULONG)mc) /* avoid crash on A4000 emu */
+ break;
+
+#ifdef VERBOSE
+ printf("$%06lx-$%06lx (%lu bytes)", last, last+size-1, size);
+#endif
+
+ if (dc = AllocMem(size + sizeof(struct Mem), MEMF_FAST))
+ {
+#ifdef VERBOSE
+ printf("\t -> $%08lx\n", dc+1);
+#endif
+ dc->Next=NULL;
+ dc->Address=(void *)last;
+ dc->Size=size;
+ CopyMem((void *)last,(void *)(dc+1),size);
+ last=(ULONG)mc+mc->mc_Bytes;
+ olddc->Next=dc; olddc=dc;
+
+ if(mc==(struct MemChunk *)(SysBase->MaxLocMem-sizeof(*mc)))
+ break;
+ }
+ else
+ {
+ Enable();
+ DisownBlitter();
+ printf("Can't allocate %lu bytes FAST RAM\n",size+sizeof(struct Mem));
+ FreeChipRAMSaveBuffers();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************/
+/* CIA-Resource ankicken */
+
+local void KickResource(char *name)
+{
+ UBYTE *ciabase=(UBYTE *)FindName(&SysBase->ResourceList,name);
+ ciabase[0x29] = 0x7F; /* Alle Interrupt-Request-Bits setzen */
+}
+
+/***************************************************************************/
+/* Alles freigeben, back to DOS */
+
+__saveds void ExitRoutine(ULONG D0, ULONG D1, void *A0, void *A1)
+{
+ int i;
+ static char text[100];
+ putreg(REG_A7,oldusp-256); /* Temporärer Stack auf unserem Userstack */
+ custom.intena = 0x7FFF; /* Alle Interrupts sperren */
+ custom.dmacon = 0x7FFF; /* DMA abschalten */
+ custom.color[0] = 0x173; /* Grünlich */
+
+ strcpy(text,*(void **)0x110); /* ROMCrack-Text retten */
+#if 0
+ memset(NULL,0xAA,stacktop); /* CHIP-RAM löschen mit $AA */
+#endif
+ custom.color[0] = 0x713; /* Rötlich */
+ RestoreChipRAM(); /* Und CHIP-RAM wieder restoren */
+
+ /* AB HIER IST DAS BETRIEBSSYSTEM WIEDER VORHANDEN */
+
+ UserState((void *)oldssp); /* Zurück in den Usermode */
+
+ custom.cop1lc = (ULONG)GfxBase->copinit; /* Bild wieder einschalten */
+ custom.dmacon = dmaconsave | DMAF_SETCLR; /* Original dmacon zurückholen */
+ custom.intena = intenasave | INTF_SETCLR; /* Dito mit intena */
+
+ for(i=0; i<8; ++i)
+ custom.spr[i].dataa = custom.spr[i].datab=0;
+
+ SetVBR(oldvbr);
+ SetCACR(oldcacr);
+
+ WaitBlit();
+ DisownBlitter();
+ Enable();
+ RemakeDisplay();
+
+ FreeChipRAMSaveBuffers(); /* Chip-SaveBuffer freigeben */
+
+ if (fastbase)
+ {
+ FreeMem(fastbase,fastsize);
+ fastbase=NULL;
+ }
+
+ KickResource(CIABNAME); /* CIA-Resources ankicken (alle Interrupts auslösen) */
+ KickResource(CIAANAME);
+
+ *(UBYTE *)0xbfed01=0x82;
+
+ printf("Last message: %s\nD0=%08lx D1=%08lx A0=%08lx A1=%08lx\n",text,D0,D1,A0,A1);
+
+ CloseLibrary((struct Library *)IntuitionBase);
+ CloseLibrary((struct Library *)GfxBase);
+
+ exit(RETURN_OK);
+}
+
+/***************************************************************************/
+
+int GetDriveVars(char *drive)
+{
+ struct DeviceNode *ldn;
+ int found=FALSE;
+
+ Forbid();
+
+ for(ldn=BADDR(((struct DosInfo *)BADDR(((struct RootNode *)DOSBase->dl_Root)->rn_Info))->di_DevInfo);
+ ldn; ldn=BADDR(ldn->dn_Next))
+ {
+ if((ldn->dn_Type==DLT_DEVICE) && (ldn->dn_Startup>0x40))
+ {
+ struct FileSysStartupMsg *fs = BADDR(ldn->dn_Startup);
+ struct DosEnvec *de = BADDR(fs->fssm_Environ);
+ char *name=(UBYTE *)BADDR(ldn->dn_Name);
+ int i;
+
+ for(i=0; i< *name; ++i)
+ if((name[i+1]&0xDF) != (drive[i]&0xDF)) goto next;
+ if((drive[i] != ':') && drive[i] != '\0') goto next;
+
+ radsize = ((de->de_HighCyl) - (de->de_LowCyl) +1 )*de->de_BlocksPerTrack*de->de_Surfaces;
+ radsize <<= 9; /* blocks -> bytes */
+ radunit = fs->fssm_Unit;
+ found=TRUE;
+ break;
+ }
+next: ;
+ }
+ while(ldn=BADDR(ldn->dn_Next));
+
+ Permit();
+ return found;
+}
+
+/***************************************************************************/
+/* Hauptprogramm */
+
+LONG Main(LONG arglen, char *argline)
+{
+ struct IOStdReq RADIO;
+ ULONG usestacktop;
+
+ Puts(ident+6);
+
+ GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
+ IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
+
+ if(GetDriveVars("EXEC:")==FALSE)
+ {
+ Puts("Würden Sie bitte gütigerweise das EXEC mounten?!");
+ return RETURN_ERROR;
+ }
+
+ if(!OpenDevice("ramdrive.device",radunit,(struct IORequest *)&RADIO,0))
+ {
+radok:
+ /* Startadresse rausfinden */
+ radmem = ((struct RUN *)(RADIO.io_Unit))->MemPtr;
+ if(((struct RUN *)(RADIO.io_Unit))->MatchWord != 0x4AFC)
+ Puts("WARNING: No resident tag!");
+
+ CloseDevice((struct IORequest *)&RADIO);
+
+ if(*(ULONG *)radmem == FFSMAGIC) /* 'DOS1' am Anfang ? */
+ {
+ ULONG execentry;
+ printf("RAMDrive: $%08lx (%ldK)\n",radmem,radsize>>10);
+
+ usestacktop = stacktop = (ULONG)SysBase->MaxLocMem;
+
+ if(argv.ChipSizePtr)
+ {
+ usestacktop = *argv.ChipSizePtr << 10;
+ if((usestacktop<100000) || (usestacktop>stacktop))
+ {
+ Puts("Bad CHIP size, please try again!");
+ return RETURN_ERROR;
+ }
+ }
+
+ printf("Chip RAM: $00000000 (%ldK)\n",usestacktop>>10);
+
+
+ if(!argv.NoFast) /* Grössten freien FAST-RAM-Block reservieren */
+ {
+ if(fastsize = AvailMem(MEMF_FAST|MEMF_LARGEST) & ~0xff)
+ {
+ fastsize -= (stacktop-AvailMem(MEMF_CHIP)+10000);
+ if(fastsize>=10000L)
+ {
+ fastbase = AllocMem(fastsize,MEMF_FAST);
+ printf("Fast RAM: $%08lx (%ldK)\n",fastbase,fastsize>>10);
+ }
+ else
+ {
+ fastsize=0;
+ Puts("Not enough FAST RAM available :-)");
+ }
+ }
+ else Puts("No FAST RAM available.");
+ }
+
+
+ /* AB HIER DARF IM CHIP-RAM NICHTS MEHR VERÄNDERT WERDEN */
+
+ OwnBlitter();
+ WaitBlit();
+ Disable();
+
+ /* System-Status für MyExec merken/retten etc. */
+
+ dmaconsave = custom.dmaconr&~DMAF_SPRITE;
+ intenasave = custom.intenar&~INTF_INTEN;
+ attnflags = SysBase->AttnFlags;
+ vblankfreq = SysBase->VBlankFrequency;
+ sysbplcon0 = GfxBase->system_bplcon0;
+ oldcacr = GetCACR(); /* Altes CACR retten */
+ oldvbr = GetVBR(); /* Altes VBR retten */
+ oldusp = getreg(REG_A7); /* Alten User-Stack retten */
+
+ if(!argv.NoSave) /* CHIP-RAM retten */
+ {
+ if(!SaveChipRAM()) return RETURN_ERROR;
+ }
+ else Puts("CHIP RAM will not be saved.");
+
+ SetCACR(0L); /* Alle Cache off */
+ SetVBR(NULL); /* VBR nach 0 legen */
+
+
+ /* AB HIER KEIN BETRIEBSSYSTEM MEHR!! */
+
+ oldssp = (ULONG)SuperState(); /* Supervisor-Mode auf Userstack */
+ putreg(REG_A7,usestacktop-80); /* Neuer Supervisor-Stackpointer */
+ custom.intena = 0x7FFF; /* Interrupts sperren */
+ custom.dmacon = 0x7FFF; /* Und DMA auch */
+
+ custom.color[0] = 0x400; /* Bildschirm dunkelrot */
+#if 0
+ memset(NULL,0,usestacktop); /* CHIP-RAM löschen */
+#endif
+ memcpy(NULL,&ExecModuleStart,&ExecModuleEnd-&ExecModuleStart);
+
+ for(execentry=0; *(ULONG *)execentry!=INITMAGIC; execentry+=2) ; /* Entry suchen */
+ execentry += 4;
+
+ if(argv.NoSave) /* Kein Save -> ABORT macht ColdReboot() */
+ {
+ *(ULONG *)ABORT = 0x4EF80008+execentry; /* JMP<<16+4+4=2.Vektor */
+ }
+ else
+ {
+ *(UWORD *)ABORT = 0x4EF9; /* Rücksprung-JMP */
+ *(void **)(ABORT+2) = (void *)ExitRoutine; /* Cleanup-Routine */
+ }
+
+ custom.color[0] = 0xF00; /* Bildschirm rot */
+
+ {
+ register void (* __asm init)(
+ register __d0 LONG, register __d1 LONG,
+ register __d2 LONG, register __d3 LONG,
+ register __d4 LONG,
+ register __a0 void *,register __a1 void *,
+ register __a2 void *,register __a3 void *);
+
+ init =(void *)execentry;
+
+ if (0) init( attnflags, /* D0 */
+ sysbplcon0, /* D1 */
+ vblankfreq, /* D2 */
+ 0, /* D3 : Product-Code */
+ (LONG)"MainPrg", /* D4 : MainPrg-Name */
+ radmem, /* A0 : RAD-Startadresse */
+ (void *)radsize, /* A1 : RAD-Grösse */
+ fastbase, /* A2 : FAST-Startadresse */
+ fastbase+fastsize /* A3 : FAST-Endadresse */
+ );
+ ExitRoutine();
+ /* not reached */
+ }
+ }
+ else Puts("Du musst eine FFS-RamDisk haben, du Depp!");
+ }
+ else if(!OpenDevice("ffsdrive.device",radunit,(struct IORequest *)&RADIO,0))
+ goto radok;
+ else
+ Puts("Can't open ramdrive.device or ffsdrive.device");
+
+ return RETURN_OK;
+}
+
diff --git a/SysCDisk.S b/SysCDisk.S
new file mode 100644
index 0000000..2d56e30
--- /dev/null
+++ b/SysCDisk.S
@@ -0,0 +1,303 @@
+
+ IDNT SysCDisk
+ SECTION text,CODE
+
+ INCLUDE "MyExec.i"
+ INCLUDE "exec/macros.i"
+ INCLUDE "dos/dos.i"
+
+ XREF _DOSBase,@CheckFile
+
+;CRUNCH
+
+ XREF _RawPrintfFunc
+ IFD CRUNCH
+ XREF PPDecrunch
+ ENDC
+
+ XDEF InitDiskFunc ; Disk-System initialisieren
+ XDEF SetNoDiskHandlerFunc
+ XDEF ReadFileFunc ; 'Datei' lesen
+ XDEF WriteFileFunc ; 'Datei' schreiben
+ XDEF LoadFileFunc ; Speicher reservieren & File lesen
+ XDEF LoadFastFileFunc ; FAST alloc & File lesen
+ XDEF SendPacketFunc ; Asynchronen Lese-Request schicken
+
+
+***************************************************************************
+** **
+** I N I T D I S K - Disk-System init, Recalibrate, Timer alloc ... **
+** **
+** Parameter : nix **
+** **
+***************************************************************************
+
+InitDiskFunc: movem.l d0/a0,-(SP)
+
+ clr.l InsertDiskRoutine
+
+ *** DiskRequest-Liste initialisieren
+
+ lea meb_DiskList(a6),a0
+ jsr meb_NewList(a6)
+
+ movem.l (SP)+,d0/a0
+ rts
+
+
+***************************************************************************
+** **
+** S E T N O D I S K H A N D L E R - NoDisk-Handler setzen **
+** **
+** Parameter : A0.L: InsertDisk-Handler oder 0 **
+** **
+***************************************************************************
+
+SetNoDiskHandlerFunc:
+ move.l a0,InsertDiskRoutine
+ rts
+
+
+**************************************************************************
+** **
+** R E A D F I L E - 'Datei' von Disk lesen & MFM-dekodieren **
+** **
+** Parameter : D0.L : DiskAdresse (Disk/Track/Offset) der Datei **
+** A0.L : Ladeadresse **
+** **
+** Resultat : D0.L : Fehlernummer, 0 if successful **
+** Z-Bit: gesetzt if OK, gelöscht wenn Fehler **
+** **
+**************************************************************************
+
+ReadFileFunc: movem.l a0-a1,-(SP)
+ lea -dp_SIZEOF-2(SP),SP ; DiskPacket erstellen
+ move.l d0,dp_FileName(SP)
+ move.l a0,dp_Address(SP)
+ movea.l SP,a0 ; A0 : Packet
+ lea dp_SIZEOF(SP),a1 ; A1 : End-Flag
+ clr.b (a1) ; löschen
+ move.l a1,dp_Reply(a0)
+ move.b #DPF_REPLYBYTE,dp_Flags(a0)
+ bsr.s SendPacketFunc
+1$: tst.b (a1) ; Warten bis File geladen!
+ beq.s 1$
+ lea dp_SIZEOF+2(SP),SP ; DiskPacket freigeben
+ moveq #0,d0 ; Success ** DEBUG **
+ movem.l (SP)+,a0-a1
+ rts
+
+
+**************************************************************************
+** **
+** L O A D F I L E - Speicher reservieren, Datei von Disk lesen **
+** **
+** Parameter : D0.L : DiskAdresse (Disk/Track/Offset) der Datei **
+** **
+** Resultat : D0.L : Adresse des Files, 0 if error **
+** Z-Bit: gelöscht wenn OK, gesetzt wenn Error **
+** **
+**************************************************************************
+
+LoadFileFunc: movem.l d1/a0-a1,-(SP)
+ moveq #DPF_REPLYBYTE|DPF_ALLOCMEM,d1 ; Packet Flags
+ bra.s DoLoadFile ; --->
+
+LoadFastFileFunc:
+ movem.l d1/a0-a1,-(SP)
+ moveq #DPF_REPLYBYTE|DPF_ALLOCFASTMEM,d1 ; Packet Flags
+ ;; bra.s DoLoadFile ; --->
+
+DoLoadFile: lea -dp_SIZEOF-2(SP),SP ; DiskPacket erstellen
+ movea.l SP,a0 ; A0 : Packet
+ lea dp_SIZEOF(SP),a1 ; A1 : End-Flag
+ move.l d0,dp_FileName(a0)
+ clr.b (a1) ; End-Flag löschen
+ move.l a1,dp_Reply(a0)
+ move.b d1,dp_Flags(a0) ; ReplyType & MemoryType
+ bsr.s SendPacketFunc
+1$: tst.b (a1) ; Warten bis File geladen!
+ beq.s 1$
+ move.l dp_Address(SP),d0 ; Resultat: Adresse
+ lea dp_SIZEOF+2(SP),SP ; Doesn't change CCR
+ movem.l (SP)+,d1/a0-a1
+ rts
+
+
+**************************************************************************
+** **
+** S E N D P A C K E T - Asynchronen Read-Request aufgeben **
+** **
+** Parameter : A0.L : Zeiger auf struct DiskPacket **
+** **
+** Resultat : nix **
+** **
+**************************************************************************
+
+SendPacketFunc: movem.l d7/a0-a1/a4-a5,-(SP)
+ movea.l a0,a1 ; Packet
+ lea meb_DiskList(a6),a0
+ jsr meb_AddTail(a6) ; Packet anhängen
+ bsr.s ProcessNextRequest ; System ankicken
+ movem.l (SP)+,d7/a0-a1/a4-a5
+ rts
+
+
+**************************************************************************
+
+ *** Nächsten Request aus Diskliste verarbeiten
+
+ProcessNextRequest:
+ movem.l d0-d7/a0-a5,-(SP)
+
+ lea meb_DiskList(a6),a0
+ jsr meb_RemHead(a6) ; setzt CCR
+ beq .EndProcReq ; Kein Request pending --->
+ movea.l d0,a2 ; A2 : Aktuelles Packet
+
+ *** "Loading 'filename' (flags)" auf Debug-Konsole ausgeben
+
+ moveq #0,d0
+ move.b dp_Flags(a2),d0
+ move.w d0,-(SP)
+ move.l dp_FileName(a2),-(SP)
+ pea LoadingFmt(PC)
+ bsr _RawPrintfFunc
+ lea 10(SP),SP
+
+ *** Packet bearbeiten
+
+ movea.l a6,a5 ; A5 : MyExecBase
+
+ movea.l dp_FileName(a2),a0
+ bsr @CheckFile
+ move.l d0,d2 ; D2 : File-Länge
+ move.l d2,-(SP)
+ bne 1$ ; OK -->
+ pea NotFoundText(PC)
+ bsr _RawPrintfFunc
+ addq.w #4,SP
+ bra .Error
+1$
+ btst.b #DPB_ALLOCMEM,dp_Flags(a2) ; CHIP-Alloc gewünscht ?
+ beq.s .NoChipAlloc ; nein --->
+ move.l d2,d0 ; File-Länge
+ movea.l a5,a6 ; MyExecBase
+ jsr meb_AllocMem(a6)
+ bra.s .AllocCont ; --->
+.NoChipAlloc:
+ btst.b #DPB_ALLOCFASTMEM,dp_Flags(a2) ; FAST-Alloc gewünscht?
+ beq.s .NoFastAlloc ; nein --->
+ move.l d2,d0 ; File-Länge
+ movea.l a5,a6 ; MyExecBase
+ jsr meb_AllocFastMem(a6)
+.AllocCont: move.l d0,dp_Address(a2) ; Adresse ins Packet
+.NoFastAlloc:
+
+ move.l dp_FileName(a2),d1
+ move.l #MODE_OLDFILE,d2
+ movea.l _DOSBase,a6
+ JSRLIB Open
+ move.l d0,d7
+ bne.s 2$
+
+ movea.l dp_FileName(a2),a0
+ lea df0buf,a1
+.copy: move.b (a0)+,(a1)+
+ bne.s .copy
+
+ move.l #buf,d1
+ JSRLIB Open
+ move.l d0,d7
+ beq.s .Error
+2$
+ move.l d7,d1
+ move.l dp_Address(a2),d2
+ move.l #10000000,d3
+ JSRLIB Read
+
+ move.l d0,-(SP)
+ pea BytesFmt(PC)
+ bsr _RawPrintfFunc
+ lea 8(SP),SP
+
+ move.l d7,d1
+ JSRLIB Close
+
+ movea.l a2,a0
+ movea.l a5,a6 ; MyExecBase
+ bsr.s ReplyPacket ; Packet (A0) beantworten
+
+.EndProcReq: movem.l (SP)+,d0-d7/a0-a5
+ rts
+
+.Error: movea.l a5,a6 ; MyExecBase
+ jmp meb_ColdReboot(a6) ; Raus hier!
+
+
+***************************************************************************
+
+ *** Packet (A0) beantworten
+
+ReplyPacket: movem.l a0-a2,-(SP)
+ movea.l a0,a2 ; A2 : Packet
+ movea.l dp_Reply(a2),a1 ; A1 : User's Reply-Adresse
+
+ *** Text ausgeben
+
+ move.l dp_Address(a2),-(SP)
+ pea LoadedFmt(PC)
+ bsr _RawPrintfFunc
+ lea 8(SP),SP
+
+ IFD CRUNCH
+ bclr.b #DPB_CRUNCHED,dp_Flags(a2)
+ beq.s 1$
+ movea.l dp_Address(a2),a0 ; A0 : Decrunch-Start
+ move.l dp_FileSize(a2),d0 ; D0 : File-Länge gecruncht
+ move.l (a0),dp_FileSize(a2) ; Echte Länge für User
+ bsr PPDecrunch
+1$:
+ ENDC
+ btst.b #DPB_REPLYHANDLER,dp_Flags(a2)
+ beq.s 2$
+ movea.l a2,a0 ; A0 : Packet für User
+ jsr (a1) ; ReplyHandler aufrufen
+ bra.s 99$ ; --->
+2$:
+ btst.b #DPB_REPLYBYTE,dp_Flags(a2)
+ beq.s 3$
+ st.b (a1) ; ReplyByte setzen
+ ;; bra.s 99$ ; --->
+3$:
+99$: movem.l (SP)+,a0-a2
+ rts
+
+**************************************************************************
+** **
+** W R I T E F I L E - Existierende 'Datei' auf Disk überschreiben **
+** **
+** Parameter : D0.L : FN_-Konstante (von DiskMaker erzeugt) **
+** A0.L : Adresse der Daten für das File **
+** **
+**************************************************************************
+
+WriteFileFunc: rts
+
+
+**************************************************************************
+* D A T E N (auch im CODE-Segment wegen PC-relativ) *
+**************************************************************************
+
+InsertDiskRoutine: ds.l 1 ; User's InsertDisk handler
+
+
+LoadingFmt: dc.b "Loading '%s' (flags=$%02x) ... ",0
+BytesFmt: dc.b "%ld bytes ",0
+LoadedFmt: dc.b "at $%08lx",10,13,0
+NotFoundText: dc.b "file not found",10,13,0
+
+buf: dc.b "DF0:"
+df0buf: ds.b 64
+
+ END
diff --git a/SysStart.c b/SysStart.c
new file mode 100644
index 0000000..808bc43
--- /dev/null
+++ b/SysStart.c
@@ -0,0 +1,220 @@
+/****************************************************************************
+** **
+** SysStart.c - Startet Exec MIT Betriebssystem **
+** **
+*****************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 24-Feb-91 CHW Created this file from Start.S **
+** **
+****************************************************************************/
+
+#include <proto/exec.h>
+#include <exec/io.h>
+#include <exec/memory.h>
+#include <exec/execbase.h>
+#include <proto/graphics.h>
+#include <proto/intuition.h>
+#include <graphics/gfxbase.h>
+#include <hardware/custom.h>
+#include <hardware/dmabits.h>
+#include <hardware/intbits.h>
+//#include <resources/cia.h>
+#include <string.h> /* z.B. für __builtin_memcpy */
+#include <dos.h>
+
+#include <chlib.h>
+
+
+char ident[] = "$VER: SysStart 5.0 by Christian A. Weber (" __DATE__ ")";
+char CLI_Template[] = "CS=CHIPSIZE/N,FS=FASTSIZE/N,MOD/K,PRI/N";
+char CLI_Help[] = "Usage: SysStart [CHIPSIZE kbytes] [FASTSIZE kbytes] [MOD name] [PRI pri]";
+
+extern __regargs void Exit(LONG);
+extern void RawPrintfFunc(char *, ...);
+
+extern struct ExecBase *SysBase;
+extern struct GfxBase *GfxBase;
+
+extern BPTR StdErr; /* Standard Error output stream */
+extern struct Custom far volatile custom;
+
+extern void __asm __far InitExec(
+ register __d0 LONG, register __d1 LONG,
+ register __d2 LONG, register __d3 LONG, register __d4 LONG,
+ register __a0 void *,register __a1 void *,
+ register __a2 void *,register __a3 void *);
+
+
+struct
+{
+ LONG *ChipSizePtr;
+ LONG *FastSizePtr;
+ char *ModName;
+ LONG *PriPtr;
+} argv;
+
+
+UBYTE *chipbase; /* Startadresse des CHIP-RAMs für Exec */
+LONG chipsize; /* Grösse des CHIP-RAMs für Exec */
+
+UBYTE *fastbase; /* Startadresse des FAST-RAMs für Exec */
+LONG fastsize; /* Grösse des FAST-RAMs für Exec */
+
+UWORD dmaconsave, intenasave;
+ULONG attnflags, vblankfreq, sysbplcon0;
+BYTE oldtaskpri;
+
+
+/***************************************************************************/
+/* Alles freigeben, back to DOS */
+
+__saveds void ExitRoutine(void)
+{
+ int i;
+ custom.color[0] = 0x173; /* Grünlich */
+
+ RawPrintfFunc("SysStart: ExitRoutine()\r\n");
+ printf("done.\n");
+
+ WaitBlit();
+ DisownBlitter();
+
+ custom.cop1lc = (ULONG)GfxBase->copinit; /* Bild wieder einschalten */
+
+ custom.dmacon = 0x7FFF;
+ custom.dmacon = dmaconsave | DMAF_SETCLR; /* Original dmacon zurückholen */
+
+ custom.intena = 0x7FFF;
+ custom.intena = intenasave | INTF_SETCLR; /* Dito mit intena */
+
+ for(i=0; i<8; ++i)
+ custom.spr[i].dataa = custom.spr[i].datab = 0;
+
+ RemakeDisplay();
+ SetTaskPri(SysBase->ThisTask, oldtaskpri);
+
+ if (fastbase)
+ {
+ FreeMem(fastbase, fastsize);
+ fastbase = NULL;
+ }
+
+ if (chipbase)
+ {
+ FreeMem(chipbase, chipsize);
+ chipbase = NULL;
+ }
+
+ CloseIntLib();
+ CloseGfxLib();
+
+ Exit(RETURN_OK);
+}
+
+
+/***************************************************************************/
+/* Hauptprogramm */
+
+LONG Main(LONG arglen, char *argline)
+{
+ char *module = "MainPrg";
+ LONG taskpri=4;
+
+ OpenGfxLib();
+ OpenIntLib();
+
+ Puts(ident+6);
+
+ AllocMem(0x40000000,0); /* Flushlibs */
+ AllocMem(0x40000000,0);
+
+ if (argv.ChipSizePtr)
+ {
+ chipsize = *argv.ChipSizePtr << 10; /* KBytes to Bytes */
+ if(chipsize < 100000)
+ {
+ Puts("CHIP size must be > 100K, please try again!");
+ return RETURN_ERROR;
+ }
+ }
+ else
+ {
+ chipsize = (AvailMem(MEMF_CHIP|MEMF_LARGEST) - 30000) & ~0xff;
+ if(chipsize > 1000000)
+ chipsize = (3*chipsize)/4;
+ }
+
+
+ if (argv.FastSizePtr)
+ {
+ fastsize = *argv.FastSizePtr << 10;
+ }
+ else
+ {
+ fastsize = (AvailMem(MEMF_FAST|MEMF_LARGEST) - 50000) & ~0xff;
+ if(fastsize > 1000000)
+ fastsize = (3*fastsize)/4;
+ }
+
+ if (argv.ModName)
+ module = argv.ModName;
+
+ if (argv.PriPtr)
+ taskpri = *argv.PriPtr;
+
+
+ if (chipbase = AllocMem(chipsize, MEMF_CHIP|MEMF_CLEAR))
+ {
+ printf("Chip RAM: $%08lx (%ldK)\n", chipbase, chipsize >> 10);
+
+ if (fastbase = AllocMem(fastsize, MEMF_FAST|MEMF_CLEAR))
+ {
+ printf("Fast RAM: $%08lx (%ldK)\n", fastbase, fastsize >> 10);
+ }
+ else
+ {
+ fastsize = 0;
+ Puts("Not enough FAST RAM available");
+ }
+
+ OwnBlitter();
+ WaitBlit();
+
+ oldtaskpri = SetTaskPri(SysBase->ThisTask,taskpri);
+
+ /* System-Status für MyExec merken/retten etc. */
+
+ dmaconsave = custom.dmaconr; // &~DMAF_SPRITE;
+ intenasave = custom.intenar; // &~INTF_INTEN;
+ attnflags = SysBase->AttnFlags;
+ vblankfreq = SysBase->VBlankFrequency;
+ sysbplcon0 = GfxBase->system_bplcon0;
+
+ custom.color[0] = 0xF00; /* Bildschirm rot */
+
+ printf("Running %s ... ", module);
+ RawPrintfFunc("%s: Running %s ...\r\n", ident+6, module);
+
+ InitExec( attnflags, /* D0 */
+ sysbplcon0, /* D1 */
+ vblankfreq, /* D2 */
+ 0, /* D3 : Product-Code */
+ (LONG)module, /* D4 : MainPrg-Name */
+ chipbase, /* A0 : CHIP-Startadresse */
+ chipbase+chipsize, /* A1 : CHIP-Grösse */
+ fastbase, /* A2 : FAST-Startadresse */
+ fastbase+fastsize /* A3 : FAST-Endadresse */
+ );
+
+ ExitRoutine();
+ /* not reached */
+
+ }
+ else printf("Can't get %ldK CHIP RAM!\n",chipsize/1024);
+
+ return RETURN_WARN;
+
+}
diff --git a/protcustom.i b/protcustom.i
new file mode 100644
index 0000000..b720fe8
--- /dev/null
+++ b/protcustom.i
@@ -0,0 +1,125 @@
+**************************************************************************
+** **
+** protcustom.i - Offsets der Amiga Custom-Chips, Base falsch! **
+** **
+**************************************************************************
+** **
+** Modification History **
+** -------------------- **
+** **
+** 20-Jan-88 Created this file from relcustom.i **
+** 26-Apr-89 sprdatb corrected (was 8, should be 6) **
+** 29-Jun-89 Ist jetzt auch Genim2-kompatibel **
+** 16-Sep-90 CUSTOMOFFSET muss jetzt extern definiert werden **
+** **
+**************************************************************************
+
+custom: EQU $dff000-CUSTOMOFFSET ; Start der Custom-Chips
+
+bltddat: EQU $000+CUSTOMOFFSET
+dmaconr: EQU $002+CUSTOMOFFSET
+vposr: EQU $004+CUSTOMOFFSET
+vhposr: EQU $006+CUSTOMOFFSET
+dskdatr: EQU $008+CUSTOMOFFSET
+joy0dat: EQU $00A+CUSTOMOFFSET
+joy1dat: EQU $00C+CUSTOMOFFSET
+clxdat: EQU $00E+CUSTOMOFFSET
+adkconr: EQU $010+CUSTOMOFFSET
+pot0dat: EQU $012+CUSTOMOFFSET
+pot1dat: EQU $014+CUSTOMOFFSET
+potinp: EQU $016+CUSTOMOFFSET
+serdatr: EQU $018+CUSTOMOFFSET
+dskbytr: EQU $01A+CUSTOMOFFSET
+intenar: EQU $01C+CUSTOMOFFSET
+intreqr: EQU $01E+CUSTOMOFFSET
+dskpt: EQU $020+CUSTOMOFFSET
+dsklen: EQU $024+CUSTOMOFFSET
+dskdat: EQU $026+CUSTOMOFFSET
+refptr: EQU $028+CUSTOMOFFSET
+vposw: EQU $02A+CUSTOMOFFSET
+vhposw: EQU $02C+CUSTOMOFFSET
+copcon: EQU $02E+CUSTOMOFFSET
+serdat: EQU $030+CUSTOMOFFSET
+serper: EQU $032+CUSTOMOFFSET
+potgo: EQU $034+CUSTOMOFFSET
+joytest: EQU $036+CUSTOMOFFSET
+strequ: EQU $038+CUSTOMOFFSET
+strvbl: EQU $03A+CUSTOMOFFSET
+strhor: EQU $03C+CUSTOMOFFSET
+strlong: EQU $03E+CUSTOMOFFSET
+
+bltcon0: EQU $040+CUSTOMOFFSET
+bltcon1: EQU $042+CUSTOMOFFSET
+bltafwm: EQU $044+CUSTOMOFFSET
+bltalwm: EQU $046+CUSTOMOFFSET
+bltcpt: EQU $048+CUSTOMOFFSET
+bltbpt: EQU $04C+CUSTOMOFFSET
+bltapt: EQU $050+CUSTOMOFFSET
+bltdpt: EQU $054+CUSTOMOFFSET
+bltsize: EQU $058+CUSTOMOFFSET
+
+bltcmod: EQU $060+CUSTOMOFFSET
+bltbmod: EQU $062+CUSTOMOFFSET
+bltamod: EQU $064+CUSTOMOFFSET
+bltdmod: EQU $066+CUSTOMOFFSET
+
+bltcdat: EQU $070+CUSTOMOFFSET
+bltbdat: EQU $072+CUSTOMOFFSET
+bltadat: EQU $074+CUSTOMOFFSET
+
+dsksync: EQU $07E+CUSTOMOFFSET
+
+cop1lc: EQU $080+CUSTOMOFFSET
+cop2lc: EQU $084+CUSTOMOFFSET
+copjmp1: EQU $088+CUSTOMOFFSET
+copjmp2: EQU $08A+CUSTOMOFFSET
+copins: EQU $08C+CUSTOMOFFSET
+diwstrt: EQU $08E+CUSTOMOFFSET
+diwstop: EQU $090+CUSTOMOFFSET
+ddfstrt: EQU $092+CUSTOMOFFSET
+ddfstop: EQU $094+CUSTOMOFFSET
+dmacon: EQU $096+CUSTOMOFFSET
+clxcon: EQU $098+CUSTOMOFFSET
+intena: EQU $09A+CUSTOMOFFSET
+intreq: EQU $09C+CUSTOMOFFSET
+adkcon: EQU $09E+CUSTOMOFFSET
+
+aud: EQU $0A0+CUSTOMOFFSET
+aud0: EQU $0A0+CUSTOMOFFSET ; Basis fuer Audio-Kanal 0
+aud1: EQU $0B0+CUSTOMOFFSET ; Basis fuer Audio-Kanal 1
+aud2: EQU $0C0+CUSTOMOFFSET ; Basis fuer Audio-Kanal 2
+aud3: EQU $0D0+CUSTOMOFFSET ; Basis fuer Audio-Kanal 3
+
+audlc: EQU $00
+audlen: EQU $04
+audper: EQU $06
+audvol: EQU $08
+auddat: EQU $0A
+
+bplpt: EQU $0E0+CUSTOMOFFSET ; Basis fuer BitPlane Pointer
+bpl1pt: EQU $0E0+CUSTOMOFFSET
+bpl2pt: EQU $0E4+CUSTOMOFFSET
+bpl3pt: EQU $0E8+CUSTOMOFFSET
+bpl4pt: EQU $0EC+CUSTOMOFFSET
+bpl5pt: EQU $0F0+CUSTOMOFFSET
+bpl6pt: EQU $0F4+CUSTOMOFFSET
+
+bplcon0: EQU $100+CUSTOMOFFSET
+bplcon1: EQU $102+CUSTOMOFFSET
+bplcon2: EQU $104+CUSTOMOFFSET
+bpl1mod: EQU $108+CUSTOMOFFSET
+bpl2mod: EQU $10A+CUSTOMOFFSET
+bpldat: EQU $110+CUSTOMOFFSET
+
+sprpt: EQU $120+CUSTOMOFFSET ; Basis fuer Sprite-Pointers
+spr: EQU $140+CUSTOMOFFSET ; Basis fuer Sprites
+
+sprpos: EQU $00+CUSTOMOFFSET
+sprctl: EQU $02+CUSTOMOFFSET
+sprdataa: EQU $04+CUSTOMOFFSET
+sprdatab: EQU $06+CUSTOMOFFSET
+
+color: EQU $180+CUSTOMOFFSET
+
+beamcon0: EQU $1DC+CUSTOMOFFSET ; Fatter Agnus only
+
diff --git a/relcustom.i b/relcustom.i
new file mode 100644
index 0000000..f4a90ed
--- /dev/null
+++ b/relcustom.i
@@ -0,0 +1,168 @@
+*********************************************************************
+** **
+** relcustom.i - Alle Offsets der Amiga Custom-Chips **
+** **
+** Created: 27-Oct-87 CHW Last update: 16-Jan-88 CHW **
+** **
+*********************************************************************
+
+custom: EQU $dff000 ; Startadresse der Custom-Chips
+
+bltddat: EQU $000
+dmaconr: EQU $002
+vposr: EQU $004
+vhposr: EQU $006
+dskdatr: EQU $008
+joy0dat: EQU $00A
+joy1dat: EQU $00C
+clxdat: EQU $00E
+adkconr: EQU $010
+pot0dat: EQU $012
+pot1dat: EQU $014
+potinp: EQU $016
+serdatr: EQU $018
+dskbytr: EQU $01A
+intenar: EQU $01C
+intreqr: EQU $01E
+dskpt: EQU $020
+dsklen: EQU $024
+dskdat: EQU $026
+refptr: EQU $028
+vposw: EQU $02A
+vhposw: EQU $02C
+copcon: EQU $02E
+serdat: EQU $030
+serper: EQU $032
+potgo: EQU $034
+joytest: EQU $036
+strequ: EQU $038
+strvbl: EQU $03A
+strhor: EQU $03C
+strlong: EQU $03E
+
+bltcon0: EQU $040
+bltcon1: EQU $042
+bltafwm: EQU $044
+bltalwm: EQU $046
+bltcpt: EQU $048
+bltbpt: EQU $04C
+bltapt: EQU $050
+bltdpt: EQU $054
+bltsize: EQU $058
+
+bltcmod: EQU $060
+bltbmod: EQU $062
+bltamod: EQU $064
+bltdmod: EQU $066
+
+bltcdat: EQU $070
+bltbdat: EQU $072
+bltadat: EQU $074
+
+dsksync: EQU $07E
+
+cop1lc: EQU $080
+cop2lc: EQU $084
+copjmp1: EQU $088
+copjmp2: EQU $08A
+copins: EQU $08C
+diwstrt: EQU $08E
+diwstop: EQU $090
+ddfstrt: EQU $092
+ddfstop: EQU $094
+dmacon: EQU $096
+clxcon: EQU $098
+intena: EQU $09A
+intreq: EQU $09C
+adkcon: EQU $09E
+
+aud: EQU $0A0
+aud0: EQU $0A0 ; Basis fuer Audio-Kanal 0
+aud1: EQU $0B0 ; Basis fuer Audio-Kanal 1
+aud2: EQU $0C0 ; Basis fuer Audio-Kanal 2
+aud3: EQU $0D0 ; Basis fuer Audio-Kanal 3
+
+audlc: EQU $00
+audlen: EQU $04
+audper: EQU $06
+audvol: EQU $08
+auddat: EQU $0A
+
+bplpt: EQU $0E0 ; Basis fuer BitPlane Pointer
+bpl1pt: EQU $0E0
+bpl2pt: EQU $0E4
+bpl3pt: EQU $0E8
+bpl4pt: EQU $0EC
+bpl5pt: EQU $0F0
+bpl6pt: EQU $0F4
+
+bplcon0: EQU $100
+bplcon1: EQU $102
+bplcon2: EQU $104
+bpl1mod: EQU $108
+bpl2mod: EQU $10A
+bpldat: EQU $110
+
+sprpt: EQU $120 ; Basis fuer Sprite-Pointers
+spr: EQU $140 ; Basis fuer Sprites
+
+sprpos: EQU $00
+sprctl: EQU $02
+sprdata: EQU $04
+sprdatb: EQU $08
+
+color: EQU $180
+
+htotal EQU $1c0
+hsstop EQU $1c2
+hbstrt EQU $1c4
+hbstop EQU $1c6
+vtotal EQU $1c8
+vsstop EQU $1ca
+vbstrt EQU $1cc
+vbstop EQU $1ce
+sprhstrt EQU $1d0
+sprhstop EQU $1d2
+bplhstrt EQU $1d4
+bplhstop EQU $1d6
+hhposw EQU $1d8
+hhposr EQU $1da
+beamcon0 EQU $1dc
+hsstrt EQU $1de
+vsstrt EQU $1e0
+hcenter EQU $1e2
+diwhigh EQU $1e4
+
+
+VARVBLANK EQU $1000 ; Variable vertical blank enable
+LOLDIS EQU $0800 ; long line disable
+CSCBLANKEN EQU $0400 ; redirect composite sync
+VARVSYNC EQU $0200 ; Variable vertical sync enable
+VARHSYNC EQU $0100 ; Variable horizontal sync enable
+VARBEAM EQU $0080 ; variable beam counter enable
+DISPLAYDUAL EQU $0040 ; use UHRES pointer and standard pointers
+DISPLAYPAL EQU $0020 ; set decodes to generate PAL display
+VARCSYNC EQU $0010 ; Variable composite sync enable
+CSBLANK EQU $0008 ; Composite blank out to CSY* pin
+CSYNCTRUE EQU $0004 ; composite sync true signal
+VSYNCTRUE EQU $0002 ; vertical sync true
+HSYNCTRUE EQU $0001 ; horizontal sync true
+
+ ** new defines for bplcon0
+USE_BPLCON3 EQU 1
+ ** new defines for bplcon2
+
+BPLCON2_ZDCTEN EQU (1<<10) ; colormapped genlock bit
+BPLCON2_ZDBPEN EQU (1<<11) ; use bitplane as genlock bits
+BPLCON2_ZDBPSEL0 EQU (1<<12) ; three bits to select one
+BPLCON2_ZDBPSEL1 EQU (1<<13) ; of 8 bitplanes in
+BPLCON2_ZDBPSEL2 EQU (1<<14) ; ZDBPEN genlock mode
+
+ ** defines for bplcon3 register
+
+BPLCON3_EXTBLNKEN EQU (1<<0) ; external blank enable
+BPLCON3_EXTBLKZD EQU (1<<1) ; external blank ored into trnsprncy
+BPLCON3_ZDCLKEN EQU (1<<2) ; zd pin outputs a 14mhz clock
+BPLCON3_BRDNTRAN EQU (1<<4) ; border is opaque
+BPLCON3_BRDNBLNK EQU (1<<5) ; border is opaque
+
diff --git a/zeropage.i b/zeropage.i
new file mode 100644
index 0000000..b1f2436
--- /dev/null
+++ b/zeropage.i
@@ -0,0 +1,39 @@
+***************************************************************************
+** **
+** zeropage.i - Alle Interrupt- und Exception-Vektoren **
+** **
+** Modification History **
+** -------------------- **
+** **
+** 06-May-89 CHW Created this file! **
+** **
+***************************************************************************
+
+ STRUCTURE ZeroPage,0
+
+ APTR ResetSSP ; 0
+ APTR ResetVector ; 1
+ APTR BusErrorVector ; 2
+ APTR AddrErrVector ; 3
+ APTR IllegalVector ; 4
+ APTR DivZeroVector ; 5
+ APTR ChkVector ; 6
+ APTR TrapVVector ; 7
+ APTR PrivVector ; 8
+ APTR TraceVector ; 9
+ APTR LineAVector ; A
+ APTR LineFVector ; B
+ APTR Reserved0C ; C
+ APTR ProtocolVector ; D
+ APTR FormatVector ; E
+ APTR NotIntVector ; F
+ STRUCT Reserved10,8*4 ; 10-17
+ APTR WrongIntVector ; 18
+ APTR Level1Vector ; 19
+ APTR Level2Vector ; 1A
+ APTR Level3Vector ; 1B
+ APTR Level4Vector ; 1C
+ APTR Level5Vector ; 1D
+ APTR Level6Vector ; 1E
+ APTR Level7Vector ; 1F
+ STRUCT TrapVectors,16*4 ; 20-2F