
#name Amnesia
#type &ffa
#base 0

#set Service_Amnesia=&80320

#set errorlim	= 100
#set def_tables = 32

#set coordshift = 12

#set remoteID=&006E0000 ;must be present before a remote routine

#set BF_static		= 1
#set BF_qwa		= 1<<1
#set BF_intoff		= 1<<2

#set A_type_tidy	= 0
#set A_type_messy	= 1
#set A_type_static	= 2

#set R_skip_advance	= 1
#set R_tst		= 1<<1
#set R_alive		= 1<<31

#set PF_advance		= 1<<23
#set PF_plot		= 1<<22
#set PF_process		= 1<<21

#set Amf_plot		= 1<<0
#set Amf_user_plot	= 1<<1
#set Amf_velocity	= 1<<2
#set Amf_gravity	= 1<<3
#set Amf_use_plot_ofs	= 1<<4
#set Amf_anim		= 1<<5
#set Amf_make_objsize	= 1<<6
#set Amf_colch		= 1<<7
#set Amf_attn_timer	= 1<<8
#set Amf_dest_timer	= 1<<9
#set Amf_attn		= 1<<10
#set Amf_timer2		= 1<<11
#set Amf_zero_vec	= 1<<12
#set Amf_game_horiz	= 1<<13
#set Amf_game_vert	= 1<<14
#set Amf_plot_window	= 1<<15
#set Amf_kill_window	= 1<<16
#set Amf_colch_window	= 1<<17
#set Amf_save		= 1<<18
#set Amf_remote		= 1<<19
#set Amf_noleft		= 1<<20
#set Amf_noright	= 1<<21
#set Amf_noup		= 1<<22
#set Amf_nodown		= 1<<23


#set Amf_attn_mask	= &FF<<24

#set Amf_imask  = Amf_plot + Amf_velocity + Amf_gravity + Amf_use_plot_ofs + Amf_anim + Amf_make_objsize + Amf_colch + Amf_dest_timer + Amf_zero_vec + Amf_plot_window + Amf_save + Amf_colch_window + Amf_timer2 + Amf_remote

;imask are the events which are never returned to the user

struct v {
  .areastart	DCD 0
  .areatype	DCD 0
  .areasize	DCD 0
  .gamewindow	DBD 4; 4 words
  .plotwindow	DBD 4; 4 words
  .killwindow	DBD 4; 4 words
  .plotxofs     DCD 0
  .plotyofs	DCD 0
  .gravx	DCD 0
  .gravy	DCD 0
  .colch0	DCD 0
  .colch1	DCD 0
  .colch3	DCD 0
  .colchsave	DBD 4; 4 words - save area for colch regs
  .colchboxes	DBD 8; 8 words - store area for bounding boxes
  .errorctr	DCD 0
  .errorblock   DCD 0
  .errortable   DCD 0
  .remote	DCD 0
  .remoteR12	DCD 0
  .buffer 	DBD 16 ; 16 words
  .temp0  	DCD 0
  .temp1  	DCD 0
  .temp2  	DCD 0
  .sizeof
}

struct b {
  .id		DCD 0
  .ptr  	DCD 0
  .name		DBB 8 ; 8 bytes
  .size		DCD 0
  .flags	DCD 0
  .sizeof
}

struct t {
  .id		DCD 0
  .ptr 		DCD 0
  .name		DBB 8 ; 8 bytes
  .size		DCD 0
  .flags	DCD 0
  .objsize	DCD 0
  .number	DCD 0
  .tabflags	DCD 0
  .next		DCD 0
  .sizeof
}

struct save {
  .id		DCD 0
  .name		DBB 8 ; 8 bytes
  .objsize	DCD 0
  .number	DCD 0
  .gap		DCD 0
  .sizeof
}

struct h {
  .id		DCD 0
  .ptr		DCD 0
  .name		DBB 8 ; 8 bytes
  .size		DCD 0
  .flags	DCD 0
  .type		DCD 0
  .areasize	DCD 0
  .tlist	DCD 0
  .sizeof
}

struct o {
  .type		DCD 0
  .flags	DCD 0
  .x		DCD 0
  .y		DCD 0
  .xvec		DCD 0
  .yvec		DCD 0
  .timer	DCD 0
  .size		DCD 0
  .timer2	DCD 0
  .sizeof
}

struct c {	
  .id		DCD 0
  .ptr		DCD 0
  .name		DBB 8 ; 8 bytes
  .size		DCD 0
  .flags	DCD 0
  .writeofs	DCD 0
  .sizeof
}
  
struct cent {
  .ofs		DCD 0
  .minx         DCD 0
  .miny         DCD 0
  .maxx         DCD 0
  .maxy         DCD 0
  .sizeof
} 
  
struct tlist {
  .number	DCD 0
  .sizeof
}
.start
DCD 0
DCD init
DCD final
DCD service
DCD title
DCD help
DCD commandtable
DCD &49600
DCD swicode
DCD switab
DCD 0

.title
DCB "Amnesia"
DCB 0
.help
DCB "Amnesia		1.50 (20 Apr 1995)"
DCB 0
ALIGN
.commandtable
DCB "Amnesia",0
ALIGN
DCD 0
DCD 0
DCD 0
DCD amnesiahelp

DCB "Amnesia"
DCB 0
ALIGN
DCD amscode
DCD &000cff01
DCD amssyntax
DCD amshelp

DCB "AmnesiaFlags",0
ALIGN
DCD 0
DCD 0
DCD 0
DCD flagshelp
DCB "AmnesiaObjects",0
ALIGN
DCD 0
DCD 0
DCD 0
DCD objectshelp
DCB "AmnesiaSWIs",0
ALIGN
DCD 0
DCD 0
DCD 0
DCD swishelp

DCD 0; *** END MARKER ***

.amnesiahelp
DCB 27,0," is a module which provides memory allocation functions and handling routines for on-screen objects in a versatile form.  See the help files in the ",27,0," application for details.",10,13
DCB "Copyright A.Southgate 1994 - may be used and distributed freely.",10,13
DCB "Amnesia was written and is maintained by Andy Southgate - permanent address 5 Longview, Sutton, Cambs.",10,13
DCB 0
.amshelp
DCB 27,0," issues an Amnesia SWI from the command line.  Its mainly used by me for testing.  The SWI tail means the letters after Amnesia_ .  If TO is appended register results are returned.  String parameters should be entered in SINGLE quotes ('These ones')",10,13
.amssyntax
DCB "Syntax : *Amnesia <SWI tail> [<R0> [<R1> [<R2> .... <R9>]]] [TO]",10,13
DCB "Example: *Amnesia ClaimBlock 0 &800 'Aliens' 2_1101",0
.flagshelp
DCB "Amnesia area types area",10,13
DCB "0 - Tidy mode",10,13
DCB "1 - Messy mode",10,13
DCB "2 - Static mode",10,13
DCB "Amnesia block flags are (bit - action)",10,13
DCB "0 - Block is static - must not be moved",10,13
DCB "1 - Quad word align block",10,13
DCB "2 - Disable interrupts while moving block",10,13
DCB "Amnesia table flags are (bit - action)",10,13
DCB "0 - Objects require collision checking facilities",10,13
 
DCB "Amnesia object flags are (bit - action)",10,13
DCB "0 - FastSpr plot",10,13
DCB "1 - User plot",10,13
DCB "2 - Use velocity",10,13
DCB "3 - Apply Gravity",10,13
DCB "4 - Use plot offsets",10,13
DCB "5 - Use timer for FastSpr animation",10,13
DCB "6 - Make up the object size (from FastSpr file)",10,13
DCB "7 - Collison check object",10,13
DCB "8 - Generate attention request if timer expires",10,13
DCB "9 - Destroy object if timer expires",10,13
DCB "10 - Request attention always",10,13
DCB "11 - Run timer 2",10,13
DCB "12 - Zero velocity (and this bit) after first addition",10,13
DCB "13 - Attention if outside game window (horizontal)",10,13
DCB "14 - Attention if outside game window (vertical)",10,13
DCB "15 - Use plot window",10,13
DCB "16 - Use kill window",10,13
DCB "17 - Add to the collision checking table only if object inside plot window",10,13
DCB "18 - Object needs saving by Amnesia_TableSave",10,13
DCB "19 - reserved",10,13
DCB "Bits 20-23 are transient flags for the user.  They are zeroed on each process pass",10,13
DCB "Bits 24-31 are the user attention trigger bits.  If a user attention request bit is set when calling Amnesia_SelectTable, then all of the objects with that bit set in their flags will return for attention.",10,13

DCB 0
.objectshelp
DCB "The structure of an amnesia object is as follows :",10,13
DCB "base+0",9,"The object type.  If this is zero the object is ignored.  This number is passed to FastSpr as a sprite number when requested.",10,13
DCB "base+4",9,"The flag word (see AmnesiaFlags)",10,13
DCB "base+8",9,"The x coordinate (pixels per process pass << 12)",10,13
DCB "base+12",9,"The y coordinate",10,13
DCB "base+16",9,"The x velocity (added to the x coord every process pass",10,13
DCB "base+20",9,"The y velocity",10,13
DCB "base+24",9,"The timer.  Amnesia performs a SUB R0,R0,R0,LSL #16 to this value on each process pass",10,13
DCB "base+28",9,"The object size [x size][y size] in pixels, 16 bit values",10,13
DCB "base+32",9,"The second timer",10,13
DCB "Only the first two entries are always required.  The rest may be required depending on the settings of the flag word",10,13
DCB 0

.swishelp
DCB "Amnesia supports the following SWIs.",10,13,10,13
DCB 34,"Amnesia_Init",34,",start_address,size,area_type",10,13
DCB 34,"Amnesia_ClaimBlock",34,",ptr_address,size,name,block_flags",10,13
DCB 34,"Amnesia_ReleaseBlock",34,",block_address",10,13
DCB 34,"Amnesia_ExtendBlock",34,",ptr_address,length",10,13
DCB 34,"Amnesia_DescribeBlock",34,",block_address or block_number TO block_address,size,data_start,data_size,name,ptr_address,block_flags",10,13
DCB 34,"Amnesia_ClaimTable",34,",table_number,table_flags,name,number_of_objects,object_size",10,13
DCB 34,"Amnesia_ReleaseTable",34,",table_number",10,13
DCB 34,"Amnesia_ExtendTable",34,",table_number,,number_of_objects",10,13
DCB 34,"Amnesia_WipeTable",34,",table_number",10,13
DCB 34,"Amnesia_CountObjects",34,",table_number TO number_of_objects",10,13

DCB 34,"Amnesia_Tidy",34,"",10,13
DCB 34,"Amnesia_MakeObject",34,",table_number,object parameters in R1-R8",10,13
DCB 34,"Amnesia_MakeObjectSpace",34,",table_number TO ,object_address",10,13
DCB 34,"Amnesia_SelectTable",34,",table_number,process_type,plot TO R0,R1,R2",10,13
DCB 34,"Amnesia_ProcessTable",34,",R0,R1,R2 (from above) TO R0,obj_address,reason code",10,13
DCB 34,"Amnesia_DeleteObject",34,",,obj_address",10,13
DCB 34,"Amnesia_SetWindow",34,",window_number,min_x,min_y,max_x,max_y",10,13
DCB 34,"Amnesia_ReadWindow",34,",window_number TO ,min_x,min_y,max_x,max_y",10,13
DCB 34,"Amnesia_SetPlotOffset",34,",x,y",10,13
DCB 34,"Amnesia_ReadPlotOffset",34," TO x,y",10,13
DCB 34,"Amnesia_CollisionCheck",34,",table_number,table_number TO object_address,object_address,R2,R3",10,13
DCB 34,"Amnesia_GetColchBoxes",34," TO minx1,miny1,maxx1,maxy1,minx2,miny2,maxx2,maxy2",10,13

DCB 34,"Amnesia_LoadFile",34,",ptr_address,filename,pathname",10,13
DCB 34,"Amnesia_SaveFile",34,",block_address,filename,filetype",10,13
DCB 34,"Amnesia_LoadTable",34,",table_number,filename,pathname",10,13
DCB 34,"Amnesia_SaveTable",34,",table_number,filename",10,13
DCB 34,"Amnesia_GetTableAddress",34,",table_number TO table_address",10,13
DCB 34,"Amnesia_Blocks",34,10,13
DCB 0

ALIGN
.r12temp
DCD 0
.amscode
STMFD R13!,{R7-R11,R14}
STR R12,r12temp
LDR R12,[R12]
ADR R3,switails
STR R0,[R12,#v.temp0]  ;command tail
STR R1,[R12,#v.temp1]  ;number of parms
MOV R0,#0
STR R0,[R12,#v.temp2]
MOV R9,#0; swi name table entry counter
.loop9
LDR R2,[R12,#v.temp0]

._loop
LDRB R0,[R2]
CMP R0,#" "
ADDEQ R2,R2,#1
BEQ _loop
._loop
LDRB R0,[R2],#1

CMP R0,#"."
BEQ amsfounddot
CMP R0,#32
BLE amsspace
BIC R0,R0,#32
LDRB R1,[R3],#1
BIC R1,R1,#32
CMP R1,R0
BEQ _loop
._loop
LDRB R1,[R3],#1
CMP R1,#0
BNE _loop
LDRB R1,[R3]
CMP R1,#0
BEQ amsnomatch
ADD R9,R9,#1
.amsskip
B loop9
.amsspace
LDRB R1,[R3]
CMP R1,#0
BEQ amsfound
B amsskip
.amsnomatch
LDMFD R13!,{R7-R11,R14}

B amsnomatcherr
.amsfounddot
LDR R4,[R12,#v.temp1]; number of parms
LDRB R0,[R2]
CMP R0,#" "
CMPNE R0,#&0D; end marker
ADDNE R4,R4,#1
STR R4,[R12,#v.temp1]
B amsfound

.amsfound
STR R2,[R12,#v.temp0]
ADD R10,R12,#v.buffer
MOV R1,#10
MOV R0,#0;clear buffer

._loop
STR R0,[R10],#4
SUBS R1,R1,#1
BGT _loop

LDR R1,[R12,#v.temp0]; command string
LDR R4,[R12,#v.temp1]; number of parms
ADD R10,R12,#v.buffer;write address
.loop3
CMP R4,#1
BLE amsreaddone
.loop4
LDRB R3,[R1]
CMP R3,#"T"
CMPNE R3,#"t"
BEQ amsto
CMP R3,#" "
ADDEQ R1,R1,#1
BEQ loop4
CMP R3,#"'"; quotes character
BEQ amsstring
MOV R0,#&8000000A
SWI XOS_ReadUnsigned
BVS badnumber
STR R2,[R10],#4
.amsstringins
SUB R4,R4,#1
B loop3
.amsstring
STR R1,[R10],#4
ADD R1,R1,#1
._loop
LDRB R3,[R1]
CMP R3,#32
BLT amsstringins
ADD R1,R1,#1
CMP R3,#"'"; quotes
BNE _loop
B amsstringins

.amsreaddone
MOV R11,R9; set swi modulo
ADD R10,R12,#v.buffer
LDMIA R10,{R0-R9}
LDR R12,r12temp
BL swicode

MOV R10,PC
STMFD R13!,{PC}
LDR R12,r12temp
LDR R12,[R12]
LDR R11,[R12,#v.temp2]
CMP R11,#1
BLEQ showregs
LDMFD R13!,{R10}
TEQP PC,R10
LDMFD R13!,{R7-R11,PC}

.amsto
MOV R0,#1
STR R0,[R12,#v.temp2]
B amsreaddone


.showregs
STMFD R13!,{R0,R14}
STMFD R13!,{R10}
ADD R10,R12,#v.buffer
STMIA R10,{R0-R9}
MOV R11,#0
.loop5
SWI 256+"R"
ADD R0,R11,#"0"
SWI OS_WriteC
SWI OS_WriteS
DCB "  = &",0
ALIGN
LDR R0,[R10],#4
ADD R1,R12,#v.temp0
MOV R2,#12
SWI OS_ConvertHex8
SWI OS_Write0
SWI 256+" "
CMP R11,#3
CMPNE R11,#7
SWIEQ OS_NewLine
ADD R11,R11,#1
CMP R11,#10
BLT loop5
SWI OS_NewLine
LDMFD R13!,{R0}
SWI OS_WriteS
DCB "Mode ",0
ALIGN
AND R1,R0,#3
CMP R1,#3
SWIEQ 256+"S"
SWIEQ 256+"V"
SWIEQ 256+"C"
CMP R1,#0
SWIEQ 256+"U"
SWIEQ 256+"S"
SWIEQ 256+"R"
SWI OS_WriteS
DCB " flags set: ",0
ALIGN
TST R0,#1<<31
SWIEQ 256+"n"
SWINE 256+"N"
TST R0,#1<<30
SWIEQ 256+"z"
SWINE 256+"Z"
TST R0,#1<<29
SWIEQ 256+"c"
SWINE 256+"C"
TST R0,#1<<28
SWIEQ 256+"v"
SWINE 256+"V"
TST R0,#1<<27
SWIEQ 256+"i"
SWINE 256+"I"
TST R0,#1<<26
SWIEQ 256+"f"
SWINE 256+"F"
SWI OS_NewLine
LDMFD R13!,{R0,PC}

.tidystr
DCB "Tidy",0
.messystr
DCB "Messy",0
.staticstr
DCB "Static",0
.unknownstr
DCB "*Unknown*",0
ALIGN

.blocksswi
STMFD R13!,{R1-R9,R14}
LDR R11,[R12,#v.areastart]
MOV R0,#0
STR R0,[R12,#v.errorctr]

SWI OS_WriteS
DCB "Amnesia area - type : ",0
ALIGN
LDR R1,[R12,#v.areatype]
AND R1,R1,#&FF
ADR R0,unknownstr
CMP R1,#A_type_tidy
ADREQ R0,tidystr
CMP R1,#A_type_messy
ADREQ R0,messystr
CMP R1,#A_type_static
ADREQ R0,staticstr
SWI OS_Write0
SWI OS_WriteS
DCB ".",10,13,"Address ",0
ALIGN

MOV R0,R11
BL writehex
MOV R0,R11
MOV R1,R0
SWI OS_ValidateAddress
LDMCSFD R13!,{R1-R9,R14}
BCS badareaerr

SWI OS_WriteS
DCB ", size ",0
ALIGN
LDR R0,[R11,#h.areasize]
BL writehex
CMP R0,#24
LDMLTFD R13!,{R1-R9,R14}
BLT badareaerr

MOV R0,R11
LDR R1,[R11,#h.areasize]
ADD R1,R0,R1
SWI OS_ValidateAddress
LDMCSFD R13!,{R1-R9,R14}
BCS badareaerr
SWI OS_WriteS
DCB ", free ",0
ALIGN
BL getfreespace
BLVS blocksbadfree
BLVC writehex
SWI OS_WriteS
DCB ", available ",0
ALIGN
BL getavailablespace
BLVS blocksbadfree
BLVC writehex
SWI OS_WriteS
DCB ".",10,13,10,0
ALIGN
LDR R0,[R11,#h.areasize]
ADD R11,R11,R0;point to end of block

MOV R8,#0
.loop7
SUB R10,R11,#8
._loop
LDR R9,[R10],#-4
CMP R9,#0
BEQ _loop
LDR R10,[R11,#-4]!
CMP R10,#-1
BEQ amsblocksend
CMP R10,#0
BLEQ noblockinfo
BL blockinfo
LDMVSFD R13!,{R1-R9,R14}
BVS err
.noblockinfo
ADD R8,R8,#1
LDR R0,[R12,#v.errorctr]
CMP R0,#errorlim
LDMGTFD R13!,{R1-R9,R14}
BGT toomanyerr
SWI OS_ReadEscapeState
BCC loop7
.amsblocksend
LDR R0,[R12,#v.errortable]
CMP R0,#-1
BLNE printerrortable
LDR R0,[R12,#v.errorblock]
CMP R0,#-1
BLNE printerrorblock

LDMFD R13!,{R1-R9,PC}

.printerrorblock
STMFD R13!,{R14}
SWI OS_WriteS
DCB "Error occurred during attempt to access block at ",0
ALIGN
LDR R0,[R12,#v.errorblock]
BL writehex
SWI OS_WriteS
DCB ".",10,13,0
ALIGN
MOV R0,#-1
STR R0,[R12,#v.errorblock]
LDMFD R13!,{PC}



.printerrortable
STMFD R13!,{R14}
SWI OS_WriteS
DCB "Error occurred during access to table number ",0
ALIGN
LDR R0,[R12,#v.errortable]
BIC R0,R0,#&FFFF<<16
ADD R1,R12,#v.buffer
MOV R2,#16
SWI OS_ConvertCardinal4
SWI OS_Write0
SWI OS_WriteS
DCB ".",10,13,0
ALIGN
MOV R0,#-1
STR R0,[R12,#v.errortable]
LDMFD R13!,{PC}

.blockstr
DCB "Block  ",0
.tablestr
DCB "TBlock ",0
ALIGN


.blockinfo
STMFD R13!,{R8-R11,R14}
MOV R0,R8
BL describeblockswi
BVS blockinfoerr
.blockinfoerrins
STMFD R13!,{R0-R3}
ADR R0,blockstr
TST R6,#1<<31
ADRNE R0,tablestr
SWI OS_Write0
MOV R0,R8
ADD R1,R12,#v.temp0
MOV R2,#12
SWI OS_ConvertCardinal2
SWI OS_Write0
CMP R8,#10
SWILT 256+" "
CMP R8,#100
SWILT 256+" "
SWI OS_WriteS
DCB "-",0
ALIGN
MOV R3,#8
MOV R1,R4
.loop8
LDRB R0,[R1],#1
CMP R0,#0
MOVEQ R0,#32
CMP R0,#32
MOVLT R0,#"."
SWI OS_WriteC
SUBS R3,R3,#1
BGT loop8
LDMFD R13!,{R0-R3}
SWI OS_WriteS
DCB " ",0
ALIGN
MOV R0,R0
BL writehex
;SWI OS_WriteS
;DCB " size ",0
;ALIGN
;MOV R0,R1
;BL writehex

SWI OS_WriteS
DCB " data ",0
ALIGN
MOV R0,R2
BL writehex
SWI OS_WriteS
DCB " space ",0
ALIGN
MOV R0,R3
BL writehex
SWI OS_WriteS
DCB " ptr ",0
ALIGN
MOV R0,R5
BL writehex
;SWI OS_WriteS
;DCB " flg ",0
;ALIGN
;MOV R0,R6
;BL writehex
SWI OS_NewLine
BL integcheck
.blockinfoskip
LDMFD R13!,{R8-R11,PC}

.blockinfoerr
SWI OS_WriteS
DCB "*** Cannot find reference to next block - table list corrupt",13,10,0
ALIGN
BL errorinc
B blockinfoskip

.integcheck
STMFD R13!,{R14}
LDR R0,[R10,#b.id]
LDR R1,blockid
CMP R0,R1
BLNE noblockid
LDR R0,[R10,#b.size]
ADD R1,R10,R0
CMP R9,#-1
CMPNE R1,R9
BLNE badblocktable
LDMFD R13!,{PC}

.noblockid
STMFD R13!,{R14}
SWI OS_WriteS
DCB "*** Block corrupt : guard word is ",0
ALIGN
BL writehex
SWI OS_WriteS
DCB ", should be ",0
ALIGN
MOV R0,R1
BL writehex
SWI OS_WriteS
DCB 10,13,0
ALIGN
BL errorinc
LDMFD R13!,{PC}

.badblocktable
STMFD R13!,{R14}
SWI OS_WriteS
DCB "Gap    ",0
ALIGN
SUB R0,R9,R1
CMP R0,#12
BLE notgapintidy
LDR R0,[R12,#v.areatype]
AND R0,R0,#&FF
CMP R0,#A_type_tidy
BNE notgapintidy
SWI OS_WriteS
DCB " *** IN TIDY HEAP *** size ",0
ALIGN
.notgapintidy
SUB R0,R9,R1
BL writehex
SWI OS_WriteS
DCB " bytes. ",10,13,0
ALIGN
CMP R0,#0
LDMGEFD R13!,{PC}
SWI OS_WriteS
DCB "*** Negative Gap - area corrupt",10,13,0
ALIGN
BL errorinc

LDMFD R13!,{PC}

.errorinc
LDR R0,[R12,#v.errorctr]
ADD R0,R0,#1
STR R0,[R12,#v.errorctr]
MOV PC,R14

.blocksbadfree
STMFD R13!,{R14}
SWI OS_WriteS
DCB "*Unknown*",0
ALIGN
LDMFD R13!,{PC}^;keep flags




.writehex
STMFD R13!,{R0-R2,R14}
SWI 256+"&"
ADD R1,R12,#v.temp0
MOV R2,#12
SWI OS_ConvertHex8
SWI OS_Write0
LDMFD R13!,{R0-R2,PC}

.switab
DCB "Amnesia",0
.switails
DCB "Init",0
DCB "ClaimBlock",0
DCB "ReleaseBlock",0
DCB "ClaimTable",0
DCB "ReleaseTable",0
DCB "Tidy",0
DCB "SelectTable",0
DCB "ProcessTable",0
DCB "CollisionCheck",0
DCB "GetColchBoxes",0
DCB "SetPlotOffset",0
DCB "ReadPlotOffset",0

DCB "SetWindow",0
DCB "ReadWindow",0
DCB "MakeObject",0
DCB "MakeObjectSpace",0
DCB "DeleteObject",0

DCB "LoadFile",0
DCB "SaveFile",0
DCB "ExtendBlock",0
DCB "ExtendTable",0
DCB "WipeTable",0
DCB "CountObjects",0
DCB "SetGravity",0
DCB "ReadGravity",0
DCB "DescribeBlock",0
DCB "Blocks",0
DCB "SaveTable",0
DCB "LoadTable",0
DCB "GetTableAddress",0
DCB "LoadHammered",0
DCB "Remote",0
DCB 0; *** END MARKER ***
#set swis = 32
ALIGN

.swicode
CMP R11,#swis
BGE badswino
LDR R12,[R12]
LDR R10,[R12,#v.areastart]
CMP R10,#0
BEQ swinostart
.swinostartins
ADR R10,swiofstab
LDR R10,[R10,R11,LSL #2]
ADR R11,swiofstab
ADD PC,R10,R11
.swiofstab
DCD initswi 		- swiofstab
DCD claimblockswi 	- swiofstab
DCD releaseblockswi 	- swiofstab
DCD claimtableswi 	- swiofstab
DCD releasetableswi 	- swiofstab
DCD tidyswi 		- swiofstab
DCD selecttableswi 	- swiofstab
DCD processtableswi	- swiofstab
DCD colchswi		- swiofstab
DCD colchboxesswi	- swiofstab
DCD setplotofsswi	- swiofstab
DCD readplotofsswi	- swiofstab
DCD setwindowswi	- swiofstab
DCD readwindowswi	- swiofstab
DCD makeobjectswi 	- swiofstab
DCD makeobjectspaceswi	- swiofstab
DCD deleteobjectswi     - swiofstab
DCD loadfileswi		- swiofstab
DCD savefileswi		- swiofstab
DCD extendblockswi	- swiofstab
DCD notyeterr		- swiofstab
DCD wipetabswi		- swiofstab
DCD countobjectsswi     - swiofstab
DCD setgravityswi	- swiofstab
DCD readgravityswi	- swiofstab
DCD describeblockswi 	- swiofstab
DCD blocksswi 		- swiofstab
DCD savetableswi	- swiofstab
DCD loadtableswi	- swiofstab
DCD gettableaddrswi	- swiofstab
DCD loadhammeredswi	- swiofstab
DCD remoteswi		- swiofstab
.badswino
B unknownswi

.swinostart
CMP R11,#0
BEQ swinostartins
B notiniterr

.initswi
STMFD R13!,{R1-R9,R14}
BL discardarea
BIC R0,R0,#3
ADD R1,R1,#3
BIC R1,R1,#3
CMP R1,#0
LDMEQFD R13!,{R1-R9,PC}
CMP R1,#h.sizeof+8
LDMLTFD R13!,{R1-R9,R14}
BLT noroomerr
STR R0,[R12,#v.areastart]
STR R1,[R12,#v.areasize]
STR R2,[R12,#v.areatype]
CMP R0,#0
BLEQ getarearma
BVS noarearma
LDR R0,[R12,#v.areastart]
LDR R1,[R12,#v.areasize]
CMP R0,#0
CMP R1,#0
BEQ badinitswi
ADD R1,R0,R1
SWI OS_ValidateAddress
BCS badinitswi
BL initarea
MOV R0,#-1
STR R0,[R12,#v.errortable]
STR R0,[R12,#v.errorblock]
BL maketlist
LDMVSFD R13!,{R1-R9,R14}
BVS err
LDMFD R13!,{R1-R9,PC}
.badinitswi
MOV R0,#0
STR R0,[R12,#v.areastart]
LDMFD R13!,{R1-R9,R14}
MOV R1,#0
B badblockerr
.noarearma
MOV R0,#0
STR R0,[R12,#v.areastart]
LDMFD R13!,{R1-R9,R14}
MOV R1,#0
B noroomrmaerr

.blockid
DCB "AmBl"
ALIGN

.initarea
STMFD R13!,{R14}
LDR R10,[R12,#v.areastart]
ADR R0,blockid
LDR R0,[R0]
STR R0,[R10,#h.id]
MOV R0,#0
STR R0,[R10,#h.tlist]
STR R0,[R10,#h.ptr]
MOV R0,#&40000000
STR R0,[R10,#h.flags]
LDR R0,[R12,#v.areatype]
STR R0,[R10,#h.type]
LDR R0,[R12,#v.areasize]
STR R0,[R10,#h.areasize]
MOV R0,#h.sizeof
STR R0,[R10,#h.size]
ADD R0,R10,#h.name
ADR R1,areanamestr
MOV R2,#8
BL strncpy
LDR R0,[R12,#v.areasize]
LDR R1,[R12,#v.areastart]
ADD R1,R0,R1
MOV R0,R10
STR R0,[R1,#-4]
MVN R0,#0
STR R0,[R1,#-8]
MVN R0,#&7F000000
MOV R1,R0
MOV R2,#&7F000000
MOV R3,R0
ADD R4,R12,#v.gamewindow
STMIA R4!,{R0-R3}
STMIA R4!,{R0-R3}
STMIA R4!,{R0-R3}
LDMFD R13!,{PC}
.areanamestr
DCB "Header",0
ALIGN

.setwindowswi
STMFD R13!,{R0-R4,R14}
CMP R0,#2
LDMGTFD R13!,{R0-R4,R14}
BGT windownonerr
CMP R1,R3
CMPLE R2,R4
LDMGTFD R13!,{R0-R4,R14}
BGT windowdodgyerr
ADD R0,R12,R0,LSL #4
ADD R0,R0,#v.gamewindow
STMIA R0,{R1-R4}
LDMFD R13!,{R0-R4,PC}^

.readwindowswi
STMFD R13!,{R0,R14}
CMP R0,#2
LDMGTFD R13!,{R0,R14}
BGT windownonerr
ADD R0,R12,R0,LSL #4
ADD R0,R0,#v.gamewindow
LDMIA R0,{R1-R4}
LDMFD R13!,{R0,PC}^



.tidyswi
STMFD R13!,{R1-R9,R14}
MOV R5,#0    ;just do the pointers
BL tidyblocks
LDMVSFD R13!,{R1-R9,PC}
MOV R5,#1    ;now do the blocks
BL tidyblocks
LDMFD R13!,{R1-R9,PC}

.tidyblocks
STMFD R13!,{R14}
LDR R11,[R12,#v.areastart]
LDR R0,[R11,#h.areasize]
ADD R10,R11,R0 ;scan the blocks
MOV R6,R10; read from R10, write to R6
MOV R8,R11
.loop10
LDR R9,[R10,#-4]!
CMP R9,#0
BEQ loop10
SUB R6,R6,#4; writing to R6 removes zero entries from the
		;block table
CMP R9,#-1
BEQ tidydone
CMP R8,R9
BGT tidyoverlap
LDR R4,[R9,#b.ptr]
CMP R4,#0
MOVEQ R8,R9; do not move if no pointer

LDR R4,[R9,#b.flags]
TST R4,#BF_static
MOVNE R8,R9; do not move if static
TST R4,#BF_qwa
BICNE R8,R8,#15
ADDNE R8,R8,#12  ;quad word align copy destination
CMP R8,R9
LDMGTFD R13!,{R14}
BGT qwaerr 

MOV R0,R8
MOV R1,R9
MOV R2,R5; update pointer or move flag
LDR R7,[R9,#b.size]
TST R4,#BF_intoff
CMPNE R5,#0; the real move
SWINE OS_IntOff
BL moveblock
LDMVSFD R13!,{PC}
TST R4,#BF_intoff
CMPNE R5,#0
SWINE OS_IntOn

CMP R5,#0
STRNE R8,[R6]; update the block table
ADD R8,R8,R7
B loop10
.tidydone
CMP R5,#0
MVN R0,#0
STRNE R0,[R6]
LDMFD R13!,{PC}

.tidyoverlap
LDMFD R13!,{R14}
B areacorrupterr

.moveblock
; R0 = destination
; R1 = address of entry in block table
; R2 = update pointer(0) or move(1)

STMFD R13!,{R1-R9,R14}
LDR R4,blockid
LDR R5,[R1,#b.id]
CMP R5,R4
MOVNE R0,R1; for v.errorblock
LDMNEFD R13!,{R1-R9,R14}
BNE movenonblockerr
CMP R0,R1
LDMEQFD R13!,{R1-R9,PC}
LDR R4,[R1,#b.ptr]
LDR R5,[R4]
LDR R6,[R10]
ADD R6,R6,#b.sizeof;  The block table points to the start of the block
		; whereas the user pointer points to the start of free space
CMP R5,R6
CMPNE R2,#1; do this test only on the first (R2=0) pass
BNE inconblock
ADD R6,R0,#b.sizeof
CMP R2,#0
STREQ R6,[R4]; replace the user pointer
LDMEQFD R13!,{R1-R9,PC}
LDR R2,[R1,#b.size]
.loop11
LDR R5,[R1],#4
STR R5,[R0],#4
SUBS R2,R2,#4
BGT loop11
LDMFD R13!,{R1-R9,PC}

.inconblock
STR R1,[R12,#v.errorblock]
LDMFD R13!,{R1-R9,R14}
B inconblockerr


.tlisttext
DCB "TableLst"
ALIGN

.maketlist
STMFD R13!,{R0-R3,R14}
MOV R0,#0
BL getblockaddr
LDMVSFD R13!,{R1-R4,PC};discard stacked R0-R3
MOV R11,R0
ADD R0,R11,#h.tlist
MOV R1,#tlist.sizeof+8*def_tables
ADR R2,tlisttext
MOV R3,#0
BL claimblockswi
LDMVSFD R13!,{R1-R4,R14}
BVS tlisterr
LDR R10,[R11,#h.tlist]
MOV R0,#def_tables
STR R0,[R10,#tlist.number]
LDMFD R13!,{R0-R3,PC}

.wipeblock
STMFD R13!,{R1-R2,R14}
LDR R1,[R0,#b.size]
ADD R0,R0,#b.sizeof
SUB R1,R1,#b.sizeof
MOV R2,#0
._loop
STR R2,[R0],#4
SUBS R1,R1,#4
BGT _loop
LDMFD R13!,{R1-R2,PC}

.getblockaddr
STMFD R13!,{R1-R3,R14}
MOV R3,R0
LDR R1,[R12,#v.areastart]
LDR R2,[R12,#v.areasize]
ADD R1,R1,R2
._loop
LDR R2,[R1,#-4]!
CMP R2,#-1
MOVEQ R0,R3
LDMEQFD R13!,{R1-R3,R14}
BEQ getblockerr
SUBS R0,R0,#1
BPL _loop
MOV R0,R2
LDMFD R13!,{R1-R3,PC}^

.claimtableswi
STMFD R13!,{R1-R10,R14}
MOV R6,R0
MOV R8,R1
MOV R7,R3
BL gettlistaddr
LDMVSFD R13!,{R1-R10,R14}
BVS err
MOV R10,R0
LDR R0,[R10]
CMP R0,#0
BEQ noprevtable
MOV R0,R6; original R0
BL releasetableswi
LDMVSFD R13!,{R1-R10,R14}
BVS err
.noprevtable
MOV R0,#0
STR R0,[R10,#4]; indicate no colch table
MUL R1,R3,R4
ADD R1,R1,#t.sizeof-b.sizeof

;MOV R2,R2; name
MOV R3,#0
MOV R0,R10
BL claimblockswi
LDMVSFD R13!,{R1-R10,R14}
BVS err

SUB R9,R0,#b.sizeof
STR R8,[R9,#t.tabflags]; was R1
STR R7,[R9,#t.number]  ; was R3
STR R4,[R9,#t.objsize]
MOV R0,#0
STR R0,[R9,#t.next]
MOV R0,#&80000000
STR R0,[R9,#t.flags]
MOV R0,R7
TST R8,#1; is collision checking required?
BEQ noclaimcolch
BL claimcolchtab
LDMVSFD R13!,{R1-R10,PC}
.noclaimcolch
LDMFD R13!,{R1-R10,PC}^

.colchstr
DCB "ColChk",0,0
ALIGN

.claimcolchtab
STMFD R13!,{R8-R10,R14}
ADD R0,R12,#v.temp0
ADR R1,colchstr
LDMIA R1,{R2,R3}
STMIA R0,{R2,R3}
ADD R1,R0,#6
MOV R0,R6
MOV R2,#2
SWI XOS_ConvertCardinal1
CMP R0,R0; clear V
LDR R0,[R9,#t.number]
MOV R2,#cent.sizeof
MUL R1,R0,R2
ADD R1,R1,#c.sizeof - b.sizeof
ADD R0,R10,#4
ADD R2,R12,#v.temp0
MOV R3,#0
BL claimblockswi
LDMVSFD R13!,{R8-R10,PC}
LDR R8,[R10,#4]
SUB R8,R8,#b.sizeof
MOV R0,#c.sizeof
STR R0,[R8,#c.writeofs]
LDMFD R13!,{R8-R10,PC}^

.releasetableswi
STMFD R13!,{R10,R14}
BL gettlistaddr
LDMVSFD R13!,{R10,PC}
MOV R9,R0
LDR R0,[R0]
BL releaseblockswi
LDMVSFD R13!,{R10,PC}
LDR R0,[R9,#4]
CMP R0,#0
LDMEQFD R13!,{R10,PC}
BL releaseblockswi
LDMFD R13!,{R10,PC}; includes returning error

.wipetabswi
.wipetab
STMFD R13!,{R1-R5,R14}
BL gettableaddr
LDMVSFD R13!,{R1-R5,R14}
BVS err
SUB R0,R0,#b.sizeof
ADD R5,R0,#t.sizeof
LDR R3,[R0,#t.number]
LDR R4,[R0,#t.objsize]
MOV R1,#0
STR R1,[R0,#t.next]
MOV R0,#0

._loop
STR R0,[R5],R4
SUBS R3,R3,#1
BGT _loop
LDMFD R13!,{R1-R5,PC}

.gettableaddrswi
.gettableaddr
STMFD R13!,{R1-R2,R14}
MOV R2,R0
BL gettlistaddr
LDMVSFD R13!,{R1-R2,PC}
LDR R1,[R0]
CMP R1,#0
MOVEQ R0,R2
LDMEQFD R13!,{R1-R2,R14}
BEQ notableerr
MOV R0,R1
LDMFD R13!,{R1-R2,PC}

.gettlistaddr
STMFD R13!,{R1-R2,R14}
BIC R0,R0,#&FF<<24
LDR R1,[R12,#v.areastart]
LDR R2,[R1,#h.tlist]
CMP R2,#0
LDMEQFD R13!,{R1-R2,R14}
BEQ notlisterr
LDR R1,[R2,#tlist.number]
CMP R0,#0
MOVLT R0,#&7F000000
CMP R0,R1
LDMGEFD R13!,{R1-R2,R14}
BGE tabletoohigherr
ADD R2,R2,#tlist.sizeof
ADD R0,R2,R0,LSL #3
LDMFD R13!,{R1-R2,PC}

.loadtableswi
STMFD R13!,{R1-R9,R14}
BL gettlistaddr
LDMVSFD R13!,{R1-R9,PC}
MOV R11,R0
LDR R11,[R11]
CMP R11,#0
LDMEQFD R13!,{R1-R9,R14}
BEQ notableerr
SUB R11,R11,#b.sizeof
LDR R9,[R11,#t.objsize]; table objsize
LDR R8,[R11,#t.number]
BL openloadfile
LDMVSFD R13!,{R1-R9,PC}
CMP R0,#0
LDMEQFD R13!,{R1-R9,R14}
MOVEQ R2,#0
BEQ notafileerr
MOV R7,R0; our file handle
MOV R0,#3
MOV R1,R7
ADD R10,R12,#v.buffer
MOV R2,R10
MOV R3,#save.sizeof
MOV R4,#0
SWI XOS_GBPB
LDMVSFD R13!,{R1-R9,PC}

LDR R6,[R10,#save.objsize]
CMP R6,R9
BLNE objsizewarn
ADD R0,R11,#t.name
ADD R1,R10,#save.name
LDMIA R0,{R2-R3}
LDMIA R1,{R4-R5}
CMP R2,R4
CMPEQ R3,R5
BLNE namematchwarn
LDR R5,[R10,#save.number]
ADD R10,R11,#t.sizeof
.loopg1
CMP R5,#0
BLE endloadtable
LDR R0,[R10]
CMP R0,#0
BNE loadtableskip
BL foundloadtable
LDMVSFD R13!,{R1-R9,PC}
.loadtableskip
ADD R10,R10,R9
SUBS R8,R8,#1
BGT loopg1
.endloadtable
BL closefile
MOV R0,R5
CMP R5,#0
LDMFD R13!,{R1-R9,R14}
BIC R14,R14,#1<<29; carry flag
ORRNE R14,R14,#1<<29
MOVS PC,R14

.foundloadtable
STMFD R13!,{R1-R6,R14}
MOV R0,#4
MOV R1,R7
MOV R2,R10
MOV R3,R6
SWI XOS_GBPB
SUB R5,R5,#1
LDMFD R13!,{R1-R6,PC}

.savetableswi
STMFD R13!,{R1-R9,R14}
BL gettlistaddr
LDMVSFD R13!,{R1-R9,PC}
MOV R11,R0
LDR R11,[R11]
CMP R11,#0
LDMEQFD R13!,{R1-R9,R14}
BEQ notableerr
SUB R11,R11,#b.sizeof
ADD R10,R11,#t.sizeof
LDR R9,[R11,#t.objsize]
LDR R8,[R11,#t.number]
MOV R6,#0
BL openfile
LDMVSFD R13!,{R1-R9,PC}
CMP R0,#0
LDMEQFD R13!,{R1-R9,PC}
BEQ badsaveerr
MOV R7,R0; our file handle
MOV R0,#18
MOV R2,#&FFD
SWI XOS_File
BLVS closefile
LDMVSFD R13!,{R1-R9,PC}
BL makesavetablehdr
BLVS closefile
LDMVSFD R13!,{R1-R9,PC}
.loopg0
LDR R0,[R10]
CMP R0,#0
BEQ dontsave
LDR R0,[R10,#o.flags]
TST R0,#Amf_save
BEQ dontsave ;Don't save if this bit is clear
MOV R0,#2
MOV R1,R7
MOV R2,R10
LDR R3,[R11,#t.objsize]
SWI XOS_GBPB
BLVS closefile
LDMVSFD R13!,{R1-R9,PC}
ADD R6,R6,#1
.dontsave
LDR R0,[R11,#t.objsize]
ADD R10,R10,R0
SUBS R8,R8,#1
BGT loopg0
STR R6,[R12,#v.temp0]
MOV R0,#1
MOV R1,R7
ADD R2,R12,#v.temp0
MOV R3,#4
MOV R4,#save.number
SWI XOS_GBPB
BLVS closefile
LDMVSFD R13!,{PC}
BL closefile
LDMFD R13!,{R1-R9,PC}

.openloadfile
STMFD R13!,{R1-R3,R14}
MOV R0,#&46
CMP R2,#0
MOVEQ R0,#&44
SWI XOS_Find
LDMFD R13!,{R1-R3,PC}

.openfile
STMFD R13!,{R1-R3,R14}
MOV R0,#&80
SWI XOS_Find
LDMFD R13!,{R1-R3,PC}

.closefile
STMFD R13!,{R0-R3,R14}
MOV R0,#&0
MOV R1,R7
SWI XOS_Find
LDMFD R13!,{R0-R3,PC}^

.savetableid
DCB "AmTb"
ALIGN
.makesavetablehdr
STMFD R13!,{R14}
MOV R0,#1
MOV R1,R7
ADR R2,savetableid
MOV R3,#4
MOV R4,#save.id
SWI XOS_GBPB
LDMVSFD R13!,{PC}
MOV R0,#1
MOV R1,R7
ADD R2,R11,#t.name
MOV R3,#8
MOV R4,#save.name
SWI XOS_GBPB
LDMVSFD R13!,{PC}
MOV R0,#1
MOV R1,R7
ADD R2,R11,#t.objsize
MOV R3,#4
MOV R4,#save.objsize
SWI XOS_GBPB
LDMVSFD R13!,{PC}
MOV R0,#1
MOV R1,R7
ADR R2,savetableid
MOV R3,#4
MOV R4,#save.gap ;set up pointer
SWI XOS_GBPB
LDMFD R13!,{PC}

.selecttableswi
STMFD R13!,{R3-R9,R14}
MOV R4,R0
CMP R2,#0
ORREQ R4,R4,#PF_plot
CMP R1,#0
ORREQ R4,R4,#PF_process
CMP R1,#2
ORREQ R2,R2,#R_tst
BIC R0,R0,#&FF<<24
BL gettlistaddr
LDMVSFD R13!,{R3-R9,PC}
MOV R10,R0
LDR R1,[R10]
CMP R1,#0
LDMEQFD R13!,{R3-R9,R14}
MOVEQ R0,R4
BEQ notableerr
LDR R1,[R10,#4]; colchtab ptr
CMP R1,#0
TSTNE R4,#PF_process
MOVNE R2,#c.sizeof
STRNE R2,[R1,#c.writeofs-b.sizeof]; wipes colch table
LDR R0,[R10]
SUB R0,R0,#b.sizeof
ADD R1,R0,#t.sizeof    ; first object
TST R4,#PF_process
MOVNE R2,#0
ORR R2,R2,#R_skip_advance
ORR R0,R4,#PF_advance
LDMFD R13!,{R3-R9,PC}^

.scantable
TST R2,#R_skip_advance
ADDEQ R10,R10,R9
BIC R2,R2,#R_alive+R_skip_advance
BIC R5,R2,#3
TST R2,#R_tst
BNE scantst
.scancmp
._loop
#rept 8
CMP R10,R8
BGE scanfordone
LDR R0,[R10,R5]
BIC R0,R0,R4
CMP R0,R3
BEQ scanfound
ADD R10,R10,R9
#endr
B _loop
.scantst
CMP R10,R8
BGE scanfordone
CMP R3,#0
BEQ scanfound
._loop
LDR R0,[R10,R5]
BIC R0,R0,R4
TST R0,R3
BNE scanfound
ADD R10,R10,R9
#rept 7
CMP R10,R8
BGE scanfordone
LDR R0,[R10,R5]
BIC R0,R0,R4
TST R0,R3
BNE scanfound
ADD R10,R10,R9
#endr
B _loop

.scanfordone
MOV R2,#0
LDMFD R13!,{R3-R9,PC}^
.scanfound
MOV R0,R11
MOV R1,R10
ORR R2,R2,#R_alive
LDMFD R13!,{R3-R9,PC}^

.processtableswi
; receives and returns
; R0 = table handle+flags
; R1 = current object pointer
; R2 = reason code
STMFD R13!,{R3-R9,R14}
MOV R11,R0
MOV R10,R1
BIC R0,R0,#&FFFF<<16
BL gettlistaddr
LDMVSFD R13!,{R3-R9,PC}
STR R0,[R12,#v.temp0]
LDR R0,[R0]; get tableaddr
SUB R7,R0,#b.sizeof
LDR R0,[R7,#t.size]
ADD R8,R7,R0
CMP R7,R10
CMPLT R10,R8
MOVGT R0,R11; for error report
LDMGTFD R13!,{R3-R9,R14}
BGT objectoutsideerr
LDR R9,[R7,#t.objsize]
TST R11,#PF_process
BEQ scantable
CMP R2,#R_skip_advance
BEQ skipadvance
TST R11,#PF_advance
BEQ noadvance 
.lookforobj
ADD R10,R10,R9; advance
.skipadvance

;R8  = end of table in memory
;R9  = [t.objsize]
;R10 = address of next object to test

._loop
#rept 8
CMP R10,R8
BGE lookfordone
LDR R0,[R10],R9
CMP R0,#0
BNE objfound
#endr
B _loop
.lookfordone
MOV R2,#0
LDMFD R13!,{R3-R9,PC}^

.objfound
SUB R10,R10,R9; R10 now points to the found object
STMFD R13!,{R7-R9}
; we need for later
; R7 as pointer to t struct
; R8 as end address
; R9 as object length

LDMIA R10,{R1-R8}
TST R2,#Amf_remote
BNE doremote
.remoteins0
BIC R2,R2,#%1111<<20
STR R2,[R10,#4]
AND R9,R11,#&FF<<24; R9 = the trigger mask
ORR R9,R9,#Amf_colch+Amf_attn+Amf_anim
TST R11,#PF_plot
ORRNE R9,R9,#Amf_plot+Amf_user_plot; request user plot if plots requested
TST R2,#Amf_use_plot_ofs
ORRNE R9,R9,#Amf_use_plot_ofs
TST R2,#Amf_velocity + Amf_attn_timer + Amf_dest_timer + Amf_anim
TSTEQ R2,#Amf_zero_vec + Amf_timer2
BEQ skipvelocity
TST R2,#Amf_velocity
ADDNE R3,R3,R5
ADDNE R4,R4,R6
TST R2,#Amf_zero_vec
MOVNE R5,#0
MOVNE R6,#0
TST R2,#Amf_gravity
BLNE addgravity
TST R2,#Amf_attn_timer + Amf_dest_timer + Amf_anim
SUBNE R7,R7,R7,LSL #16
CMP R7,#0; test for timer expiry
ORRLT R9,R9,#Amf_attn_timer + Amf_dest_timer
STMIA R10,{R1-R7}
TST R2,#Amf_timer2
BLNE runtimer2
.skipvelocity

TST R2,#Amf_game_horiz + Amf_game_vert + Amf_plot_window + Amf_kill_window
BEQ nowindows
STMFD R13!,{R2,R7}
MOV R14,R2       ;NOTE
MOV R5,R8,LSR #16
MOV R6,R8,LSL #16; R1 is <<16 its real value
;		and don't forget the <<12 from pixels to coords
MOV R5,R5,LSL #16
SUB R1,R3,R5,LSR #17-coordshift
ADD R3,R3,R5,LSR #17-coordshift

SUB R2,R4,R6,LSR #17-coordshift
ADD R4,R4,R6,LSR #17-coordshift
TST R14,#Amf_game_horiz + Amf_game_vert
BEQ nogamewindow
ADD R0,R12,#v.gamewindow  ;the game window triggers when any part of the
;			 object	is outside of it

LDMIA R0,{R5-R8}
CMP R1,R5
CMPGE R7,R3
ORRLT R9,R9,#Amf_game_horiz
CMP R2,R6
CMPGE R8,R4
ORRLT R9,R9,#Amf_game_vert
.nogamewindow

TST R14,#Amf_kill_window
BEQ nokillwindow
ADD R0,R12,#v.killwindow
LDMIA R0,{R5-R8}       ;the kill window triggers if an object is entirely
;			outside of it.
CMP R1,R7
CMPLE R5,R3
CMPLE R2,R8
CMPLE R6,R4
ORRGT R9,R9,#Amf_kill_window
.nokillwindow
TST R14,#Amf_plot_window
BEQ noplotwindow
TST R9,#Amf_use_plot_ofs
LDRNE R5,[R12,#v.plotxofs]
LDRNE R6,[R12,#v.plotyofs]
ADDNE R1,R1,R5
ADDNE R3,R3,R5
ADDNE R2,R2,R6
ADDNE R4,R4,R6
ADD R0,R12,#v.plotwindow
LDMIA R0,{R5-R8}       ;the plot window triggers if an object is entirely
;			outside of it.
CMP R1,R7
CMPLT R5,R3
CMPLT R2,R8
CMPLT R6,R4
ORRGE R9,R9,#Amf_plot_window
TST R9,#Amf_plot_window
TSTNE R2,#Amf_colch_window
ORRNE R9,R9,#Amf_colch_window
.noplotwindow
LDMFD R13!,{R2,R7}
.nowindows

; reset regs to return
BIC R0,R11,#PF_advance; signal that we havn't finished
MOV R1,R10
AND R2,R9,R2
TST R2,#Amf_plot_window
BICNE R2,R2,#Amf_plot + Amf_user_plot
BICS R9,R2,#Amf_imask
LDMFD R13!,{R7-R9}
LDMNEFD R13!,{R3-R9,PC}^ ; return if attention required
.noadvance
MOV R0,#0
TST R2,#Amf_kill_window
STRNE R0,[R10,#o.type]

TST R2,#Amf_dest_timer
BEQ nodesttimer
LDR R1,[R10,#o.timer]
CMP R1,#0
STRLT R0,[R10,#o.type]
.nodesttimer

LDR R0,[R10,#o.type]
CMP R0,#0
BEQ objectdead
TST R2,#Amf_plot
BLNE plotobj     ;uses previous R0
				
TST R2,#Amf_colch
BEQ objectskip
TST R2,#Amf_colch_window
BNE objectskip
BL colchadd
LDMVSFD R13!,{R3-R9,PC}
.objectskip
.objectdead
;SWI OS_ReadEscapeState
;BCC lookforobj
B lookforobj
LDMFD R13!,{R3-R9,PC}

.runtimer2
STMFD R13!,{R0}
LDR R0,[R10,#o.timer2]
SUB R0,R0,R0,LSL #16
STR R0,[R10,#o.timer2]
CMP R0,#0
ORRGT R9,R9,#Amf_timer2
LDMFD R13!,{R0}
MOV PC,R14

.addgravity
LDR R0,[R12,#v.gravx]
ADD R5,R5,R0
LDR R0,[R12,#v.gravy]
ADD R6,R6,R0
MOV PC,R14

.plotobj
STMFD R13!,{R0-R3,R14}
TST R2,#Amf_anim
BLNE fastspranim
TST R2,#Amf_use_plot_ofs
LDRNE R3,[R12,#v.plotxofs]
LDR R1,[R10,#o.x]
ADDNE R1,R1,R3
LDRNE R3,[R12,#v.plotyofs]
LDR R2,[R10,#o.y]
ADDNE R2,R2,R3
MOV R1,R1,ASR #coordshift
MOV R2,R2,ASR #coordshift
SWI FastSpr_Plot
LDMFD R13!,{R0-R3,PC}

.fastspranim
TST R2,#Amf_timer2
LDREQ R1,[R10,#o.timer]
LDRNE R1,[R10,#o.timer2]
AND R1,R1,#&FF<<24
ORR R0,R0,R1,LSR #8
MOV PC,R14

.doremote
LDR R0,[R12,#v.remote]
CMP R0,#0
BEQ remoteins0
LDR R14,[R0,#-4]
SUBS R14,R14,#remoteID
BNE remoteins0
STMFD R13!,{R9-R12}
LDR R12,[R12,#v.remoteR12]
MOV R14,PC
MOV PC,R0
LDMFD R13!,{R9-R12}
LDMIA R10,{R1-R8}
B remoteins0

.colchadd
STMFD R13!,{R1-R9,R14}
LDR R0,[R12,#v.temp0]
LDR R9,[R0,#4]; get colchtab addr
CMP R9,#0
BEQ colchnotable
SUB R9,R9,#b.sizeof
LDR R1,[R9,#c.writeofs]
LDR R2,[R9,#c.size]
CMP R1,R2
BGE colchnoroom
SUB R0,R10,R7;offset within table
ADD R7,R9,R1; position to write to
LDR R3,[R10,#o.x]
LDR R4,[R10,#o.y]
LDR R8,[R10,#o.size]
MOV R5,R8,LSR #16
MOV R6,R8,LSL #16; R6 is <<16 its real value
MOV R5,R5,LSL #16; now so is R5
SUB R1,R3,R5,LSR #17-coordshift
ADD R3,R3,R5,LSR #17-coordshift
SUB R2,R4,R6,LSR #17-coordshift
ADD R4,R4,R6,LSR #17-coordshift
STMIA R7!,{R0-R4}
SUB R1,R7,R9; restore writeofs
STR R1,[R9,#c.writeofs]
LDMFD R13!,{R1-R9,PC}^
.colchnotable
LDMFD R13!,{R1-R9,R14}
B colchnotableerr

.colchnoroom
LDMFD R13!,{R1-R9,R14}
B colchnoroomerr

.colchswi
STMFD R13!,{R4-R9,R14}
CMP R0,#&8000
BLGE nofirstcolch
BL firstcolch
LDMVSFD R13!,{R4-R9,PC}
.nofirstcolch
ADD R4,R12,#v.colchsave
LDMIA R4,{R0-R3}

.loop13
CMP R2,R0
BGE colchend2
LDMIA R2,{R4-R7}
ADD R2,R2,#cent.sizeof

.loop12
#rept 4
CMP R3,R1
BGE colchend1
LDMIA R3,{R8-R11}
ADD R3,R3,#cent.sizeof
CMP R4,R10
CMPLE R8,R6
CMPLE R5,R11
CMPLE R9,R7
BLE contact
#endr
B loop12

.colchend1
CMP R0,R1 ;are we checking a table with itself?
ADDEQ R3,R2,#cent.sizeof
LDRNE R3,[R12,#v.colch3]; wind R3 back to start of table
B loop13

.colchend2
MOV R0,#0
LDMFD R13!,{R4-R9,PC}^

.contact
ADD R14,R12,#v.colchboxes
STMIA R14,{R4-R11}      ;R4 minx1, R5 miny1, R6  maxx1, R7  maxy1
			;R8 minx2, R9 miny2, R10 maxx2, R11 maxy2
ADD R4,R12,#v.colchsave
STMIA R4,{R0-R3}
LDR R2,[R2,#-cent.sizeof-4]
LDR R3,[R3,#-cent.sizeof-4]
LDR R0,[R12,#v.colch0]
ADD R0,R0,R2
LDR R1,[R12,#v.colch1]
ADD R1,R1,R3
LDMFD R13!,{R4-R9,PC}^
;returns object addresses in R0,R1

.firstcolch
STMFD R13!,{R14}
BL gettlistaddr
LDMVSFD R13!,{PC}
LDR R4,[R0,#4]
CMP R4,#0
SUB R4,R4,#b.sizeof
LDR R5,[R0]
SUB R5,R5,#b.sizeof
STR R5,[R12,#v.colch0]
LDMEQFD R13!,{R14}
BEQ colchnotableerr

MOV R0,R1
BL gettlistaddr
LDMVSFD R13!,{PC}
LDR R1,[R0,#4]
CMP R1,#0
SUB R1,R1,#b.sizeof
LDR R5,[R0]
SUB R5,R5,#b.sizeof
STR R5,[R12,#v.colch1]
LDMEQFD R13!,{R14}
BEQ colchnotableerr
MOV R0,R4
ADD R2,R0,#c.sizeof+4
ADD R3,R1,#c.sizeof+4
CMP R0,R1
ADDEQ R3,R3,#cent.sizeof; skip first object if R0=R1
LDR R4,[R0,#c.writeofs]
ADD R0,R0,R4
LDR R4,[R1,#c.writeofs]
ADD R1,R1,R4
STR R3,[R12,#v.colch3]
ADD R4,R12,#v.colchsave
STMIA R4,{R0-R3}
LDMFD R13!,{PC}^

.colchboxesswi
STMFD R13!,{R14}
ADD R14,R12,#v.colchboxes
LDMIA R14,{R0-R7}
LDMFD R13!,{PC}
;R0 minx1, R1 miny1, R2 maxx1, R3 maxy2
;R4 minx2, R5 miny2, R6 maxx2, R7 maxy2

.makeobjectswi
STMFD R13!,{R2-R8,R14}
BL makeobjectspaceswi
MOVCS R1,#0
MOVVS R1,#0
LDMVSFD R13!,{R2-R8,PC}
LDMCSFD R13!,{R2-R8,PC}
TST R2,#Amf_make_objsize
BLNE makeupsize
CMP R0,#&8000
LDMLTFD R13!,{R2-R8,R14}
BLT fatalerr
STMIA R0,{R1-R8}
MOV R1,R0
LDMFD R13!,{R2-R8,PC}

.makeupsize
STMFD R13!,{R0-R1,R14}
MOV R0,R1
SWI FastSpr_ReadSize
ORR R8,R1,R0,LSL #16
LDMFD R13!,{R0-R1,PC}

.makeobjectspaceswi
STMFD R13!,{R1-R9,R14}
BL gettableaddr
LDMVSFD R13!,{R1-R9,PC}
SUB R11,R0,#b.sizeof

LDR R0,[R11,#t.next]
LDR R1,[R11,#t.number]
BL scantablespace
BEQ objspacefound
MOV R0,#0
LDR R1,[R11,#t.next]
BL scantablespace
BEQ objspacefound
LDMFD R13!,{R1-R9,R14}
MOV R1,#0
MOV R0,#0
ORR R14,R14,#1<<29; set carry flag
MOVS PC,R14

.objspacefound
STR R0,[R11,#t.next]
LDMFD R13!,{R1-R9,R14}
MOV R0,R10
BIC R14,R14,#3<<28
MOVS PC,R14

.deleteobjectswi
STMFD R13!,{R0,R14}
MOV R0,#0
STR R0,[R1]
LDMFD R13!,{R0,PC}

.countobjectsswi
STMFD R13!,{R1-R9,R14}
BL gettableaddr
LDMVSFD R13!,{R1-R9,PC}
SUB R11,R0,#b.sizeof
ADD R10,R11,#t.sizeof
LDR R2,[R11,#t.objsize]
LDR R1,[R11,#t.number]
MOV R3,#0;counter
CMP R1,#8
BLT slowcount
.fastcountloop
#rept 8
LDR R4,[R10],R2
CMP R4,#0
ADDNE R3,R3,#1
#endr
SUB R1,R1,#8
CMP R1,#8
BGE fastcountloop
.slowcount
CMP R1,#0
BLE countskip
.slowcountloop
LDR R4,[R10],R2
CMP R4,#0
ADDNE R3,R3,#1
SUBS R1,R1,#1
BGT slowcountloop
.countskip
MOV R0,R3
LDMFD R13!,{R1-R9,PC}

.scantablespace
ADD R10,R11,#t.sizeof
LDR R2,[R11,#t.objsize]
MUL R3,R2,R0; R2 is considered smallest
ADD R10,R10,R3; R10 points to our object.
SUB R4,R1,R0
CMP R4,#8
BLT nofastscan
.fastscan
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
LDR R4,[R10],R2
CMP R4,#0
BEQ scanfoundspace
ADD R0,R0,#8
SUB R4,R1,R0
CMP R4,#8
BGE fastscan
.nofastscan
._loop
CMP R0,R1
BGE scannospace
LDR R4,[R10],R2
CMP R4,#0
ADD R0,R0,#1
BNE _loop
.scanfoundspace
SUB R10,R10,R2; correct for overshoot
MOV PC,R14; EQ is already set
.scannospace
BIC R14,R14,#1<<30; flag non-zero
MOVS PC,R14

.setgravityswi
STR R0,[R12,#v.gravx]
STR R1,[R12,#v.gravy]
MOV PC,R14
.readgravityswi
LDR R0,[R12,#v.gravx]
LDR R1,[R12,#v.gravy]
MOV PC,R14

.remoteswi
STMFD R13!,{R1-R2,R14}
MOV R2,R1
CMP R0,#0
BEQ remoteok
MOV R1,R0
SWI OS_ValidateAddress
LDMCSFD R13!,{R1-R2,R14}
BCS badptrerr
LDR R1,[R0,#-4]
SUBS R1,R1,#remoteID
LDMNEFD R13!,{R1-R2,R14}
BNE remoteerr
.remoteok
STR R0,[R12,#v.remote]
STR R2,[R12,#v.remoteR12]
LDMFD R13!,{R1-R2,PC}

.claimblockswi
STMFD R13!,{R1-R11,R14}
ADD R1,R1,#3
BIC R1,R1,#3
ADD R1,R1,#b.sizeof
ADD R4,R12,#v.buffer
STMIA R4,{R0-R3} ;avoiding stack
CMP R0,#0
BEQ nomemcheck
MOV R1,R0
SWI OS_ValidateAddress
LDMCSFD R13!,{R1-R11,R14}
BCS badptrerr

.nomemcheck
ADD R4,R12,#v.buffer
LDMIA R4,{R0-R3}; No writeback
BL getavailablespace
LDMVSFD R13!,{R1-R11,PC}

ADD R8,R1,#b.sizeof+16; for block table entry
CMP R0,R8
BGE claimisok
LDR R0,[R12,#v.areatype]
AND R0,R0,#&FF
CMP R0,#A_type_messy
LDMNEFD R13!,{R1-R11,R14}
BNE noroomerr
BL tidyswi
LDMVSFD R13!,{R1-R11,PC}
ADD R4,R12,#v.buffer
LDMIA R4,{R0-R3}; No writeback
BL getavailablespace
LDMVSFD R13!,{R1-R11,PC}
ADD R8,R1,#b.sizeof+16; for block table entry including possible qwa
CMP R0,R8
LDMLTFD R13!,{R1-R11,R14}
BLT noroomerr
                   ;drops through
.claimisok
LDMIA R4,{R0-R3}
BL scanblocktable
LDMVSFD R13!,{R1-R11,PC}
TST R3,#BF_qwa
ADDNE R1,R1,#16
BICNE R1,R1,#15
SUBNE R1,R1,#4
MOV R10,R0
STR R1,[R10]
MVN R8,#0
STR R8,[R10,#-4]
ADD R4,R12,#v.buffer
LDMIA R4,{R0-R3}
BL initblock
LDR R4,[R10]
ADD R5,R4,#b.sizeof
CMP R0,#0
STRNE R5,[R0]
MOV R0,R4
BL wipeblock
MOV R0,R5
LDMFD R13!,{R1-R11,PC}^

.extendblockswi
STMFD R13!,{R1-R9,R14}
MOV R8,R1
CMP R0,#&8000
ADDGE R0,R0,#b.sizeof
BL findblockentry
LDMVSFD R13!,{R1-R9,PC}
LDR R10,[R0]
LDR R9,[R10,#b.size]
CMP R1,R9
BGT blockextend
STR R1,[R10,#b.size]
LDR R0,[R12,#v.areatype]
CMP R0,#A_type_tidy
BLEQ tidyswi
LDMFD R13!,{R1-R9,PC}

.blockextend
LDR R0,[R10,#b.ptr]
MOV R1,R8
ADD R2,R10,#b.name
LDR R3,[R10,#b.flags]
BL claimblockswi
LDMVSFD R13!,{R1-R9,PC}
ADD R1,R10,#b.sizeof
MOV R2,R8
BL copyblock
MOV R0,R10
BL releaseblockinternal
LDMVSFD R13!,{R1-R9,PC}
LDR R0,[R12,#v.areatype]
CMP R0,#A_type_tidy
BLEQ tidyswi
LDMFD R13!,{R1-R9,PC}

.copyblock
STMFD R13!,{R0-R3,R14}
.loop14
LDR R3,[R1],#4
STR R3,[R0],#4
SUBS R2,R2,#4
BGT loop14
LDMFD R13!,{R0-R3,PC}




.releaseblockinternal
STMFD R13!,{R1-R4,R14}
B releaseblockins


.releaseblockswi
STMFD R13!,{R1-R4,R14}
CMP R0,#0
LDMEQFD R13!,{R1-R4,R14}
BEQ discardarea

CMP R0,#&8000
SUBGE R0,R0,#b.sizeof
.releaseblockins
MOV R4,R0
BL findblockentry
BVS releasenofind
MOV R3,R0
LDR R2,[R3]
CMP R2,#0
BEQ releasenonblock
LDR R0,blockid
LDR R1,[R2,#b.id]
CMP R0,R1
BNE releasecorruptblock
LDR R1,[R2,#b.ptr]
CMP R1,#0
MOV R0,#0
STRNE R0,[R1]; set pointer to null
STR R0,[R2,#b.id]  ; delete ID word
.releasecorruptins
MOV R0,#0
STR R0,[R3]  ; zero entry in block list
.releasenofindins
LDR R0,[R12,#v.areatype]
AND R0,R0,#&FF
CMP R0,#A_type_tidy
BNE donttidy
BL tidyswi
LDMVSFD R13!,{R1-R4,PC}
.donttidy

LDMFD R13!,{R1-R4,PC}^

.releasenofind
STR R4,[R12,#v.errorblock]
SWI OS_WriteS
DCB "Amnesia : Release of non-existent block (failed to find) - continuing...",10,13,0
ALIGN
B releasenofindins

.releasecorruptblock
STR R4,[R12,#v.errorblock]
SWI OS_WriteS
DCB "Amnesia : Release of corrupt block (incorrect guard word) - continuing...",10,13,0
ALIGN
B releasecorruptins

.releasenonblock
STR R4,[R12,#v.errorblock]
SWI OS_WriteS
DCB "Amnesia : Release of non-existent block (zero entry) - continuing...",10,13,0
ALIGN
B releasecorruptins

.initblock
STMFD R13!,{R0-R4,R14}
LDR R4,[R10]
STR R0,[R4,#b.ptr]
STR R1,[R4,#b.size]
STR R3,[R4,#b.flags]
ADD R0,R4,#b.name
MOV R1,R2
CMP R1,#0
ADREQ R1,defaultname
MOV R2,#8
BL strncpy
LDR R0,blockid
STR R0,[R4,#b.id]
LDMFD R13!,{R0-R4,PC}^


.defaultname
DCB "None",0
ALIGN

.describeblockswi
STMFD R13!,{R7-R11,R14}
CMP R0,#&8000
SUBGE R0,R0,#b.sizeof
BL xfindblockentry
LDMVSFD R13!,{R7-R11,R14}
BVS err
LDR R0,[R0]
;MOV R0,R0;block addr
LDR R1,[R0,#b.size];block size
ADD R2,R0,#b.sizeof;data addr
SUB R3,R1,#b.sizeof;data size
ADD R4,R0,#b.name;ptr to name
LDR R5,[R0,#b.ptr];ptr to ptr
LDR R6,[R0,#b.flags]
LDMFD R13!,{R7-R11,PC}

.scanblocktable
;returns R0 pointing to the end marker of the block table
;R1 pointing to the start of free space
;R2 the number of blocks
STMFD R13!,{R3-R11,R14}
LDR R11,[R12,#v.areastart]
LDR R0,[R11,#h.areasize]
ADD R10,R11,R0 ;scan the blocks
LDR R7,blockid
MOV R5,#0; space counter
MOV R6,R11; header - last valid entry
.loopB
LDR R9,[R10,#-4]!
CMP R9,#0
BEQ loopB
CMP R9,#-1
BEQ scanblocktableend
MOV R6,R10
LDR R0,[R9]
CMP R0,R7
LDMNEFD R13!,{R3-R11,R14}
BNE scanbadblockerr
ADD R5,R5,#1
B loopB
.scanblocktableend
MOV R0,R10
LDR R2,[R6]
LDR R1,[R2,#b.size]
ADD R1,R2,R1
MOV R2,R5
LDMFD R13!,{R3-R11,PC}^

.xfindblockentry
STMFD R13!,{R7-R11,R14}
MOV R8,R0
LDR R11,[R12,#v.areastart]
LDR R10,[R11,#h.areasize]
ADD R10,R11,R10
CMP R8,#&8000
BLT xfindblockno
.loopE
LDR R9,[R10,#-4]!
CMP R9,#0
BEQ loopE
CMP R9,R8
BEQ foundblock
CMP R9,#-1
BEQ notfoundblock

B loopE


.findblockentry
STMFD R13!,{R7-R11,R14}
MOV R8,R0
LDR R11,[R12,#v.areastart]
LDR R10,[R11,#h.areasize]
ADD R10,R11,R10
LDR R7,blockid
CMP R8,#&8000
BLT findblockno
.loopC
LDR R9,[R10,#-4]!
CMP R9,#0
BEQ loopC
CMP R9,R8
BEQ foundblock
CMP R9,#-1
BEQ notfoundblock

LDR R0,[R9]
CMP R0,R7
LDMNEFD R13!,{R7-R11,R14}
BNE scanbadblockerr
B loopC
.foundblock
MOV R0,R10
LDMFD R13!,{R7-R11,PC}
.notfoundblock
MOV R0,R8
LDMFD R13!,{R7-R11,R14}
B notfoundblockerr

.xfindblockno
.loopF
LDR R9,[R10,#-4]!
CMP R9,#-1
BEQ notfoundblock
MOV R0,R9             ;check for amnesia block
MOV R1,R0
SWI OS_ValidateAddress
LDMCSFD R13!,{R7-R11,R14}
BCS areacorrupterr
SUBS R8,R8,#1
BPL loopF
B foundblock

.findblockno
.loopD
LDR R9,[R10,#-4]!
CMP R9,#-1
BEQ notfoundblock
CMP R9,#0
BEQ findblocknoskip
LDR R0,[R9]
CMP R0,R7
LDMNEFD R13!,{R7-R11,R14}
BNE scanbadblockerr
.findblocknoskip
SUBS R8,R8,#1
BPL loopD
B foundblock


.getfreespace
STMFD R13!,{R1-R2,R14}
BL getusedspace
LDMVSFD R13!,{R1-R2,PC}
LDR R1,[R12,#v.areastart]
LDR R1,[R1,#h.areasize]
SUB R0,R1,R0
LDMFD R13!,{R1-R2,PC}

.getavailablespace
STMFD R13!,{R1-R2,R14}
BL getusedspace
LDMVSFD R13!,{R1-R2,PC}
MOV R0,R1
LDMFD R13!,{R1-R2,PC}


.getusedspace
STMFD R13!,{R2-R11,R14}
LDR R11,[R12,#v.areastart]
LDR R0,[R11,#h.areasize]
ADD R10,R11,R0 ;let's count up the blocks
LDR R7,blockid
MOV R5,#0; space counter
MOV R4,R11
MOV R3,R10
.loopA
LDR R9,[R10,#-4]!
CMP R9,#-1
BEQ usedspaceend
MOV R0,R9
MOV R1,R0
SWI OS_ValidateAddress
LDMCSFD R13!,{R2-R11,R14}
BCS areacorrupterr
SUB R3,R3,#4
ADD R5,R5,#4;for block table entries
CMP R9,#0
BEQ loopA
LDR R0,[R9]
CMP R0,R7
LDMNEFD R13!,{R2-R11,R14}
BNE usedbadblockerr
LDR R2,[R9,#b.size]
ADD R5,R5,R2
ADD R4,R9,R2
B loopA
.usedspaceend
MOV R0,R5
SUB R1,R3,R4
LDMFD R13!,{R2-R11,PC}

.discardarea
STMFD R13!,{R0-R11,R14}
LDR R0,[R12,#v.areastart]
CMP R0,#0
LDMEQFD R13!,{R0-R11,PC}
STMFD R13!,{R0-R3}
ADR R0,start
MOV R1,#Service_Amnesia
MOV R2,R12
MOV R3,#0
SWI OS_ServiceCall
LDMFD R13!,{R0-R3}
LDR R0,[R12,#v.areatype]
TST R0,#1<<31
MOV R2,#v.areastart
BLNE releaserma
MOV R0,#0
STR R0,[R12,#v.areastart]
LDMFD R13!,{R0-R11,PC}

.newapplication
STMFD R13!,{R0,R14}
LDR R0,[R12,#v.areatype]
TST R0,#1<<31
BLEQ discardarea
LDMFD R13!,{R0,PC}

.getarearma
STMFD R13!,{R14}
LDR R0,[R12,#v.areatype]
ORR R0,R0,#1<<31        ;flag as 'in RMA'
STR R0,[R12,#v.areatype]
MOV R2,#v.areastart
LDR R3,[R12,#v.areasize]
BL claimrma
LDMFD R13!,{PC}

.setplotofsswi
STR R0,[R12,#v.plotxofs]
STR R1,[R12,#v.plotyofs]
MOV PC,R14

.readplotofsswi
LDR R0,[R12,#v.plotxofs]
LDR R1,[R12,#v.plotyofs]
MOV PC,R14

.defaultpath
DCB "File$Path",0
ALIGN

.loadfileswi
STMFD R13!,{R1-R9,R14}
         ; R1 = filename
MOV R3,R0; R3 = pointer address as supplied
MOV R4,R2; R4 = pathname
CMP R4,#0
ADREQ R4,defaultpath
MOV R0,#15
STMFD R13!,{R1-R4}
SWI XOS_File
MOV R6,R4; R6 = file length
LDMFD R13!,{R1-R4}
LDMVSFD R13!,{R1-R9,PC}
CMP R0,#1
LDMNEFD R13!,{R2-R10,R14} 
MOVNE R2,R0;for error report
BNE notafileerr

STMFD R13!,{R1-R4}
MOV R5,R1
._loop
LDRB R0,[R5]
CMP R0,#32
ADDGT R5,R5,#1
BGT _loop
SUB R2,R5,#8
CMP R2,R1
MOVLT R2,R1
MOV R0,R3
MOV R1,R6
MOV R3,#2
BL claimblockswi
MOV R5,R0; R5 = block address
LDMFD R13!,{R1-R4}
LDMVSFD R13!,{R1-R9,PC}
STMFD R13!,{R1-R5}
MOV R0,#14
MOV R2,R5
MOV R3,#0 ; and R4 as preserved
SWI XOS_File
LDMFD R13!,{R1-R5}
LDMVSFD R13!,{R1-R9,PC}
MOV R0,R5
LDMFD R13!,{R1-R9,PC}^

.savefileswi
STMFD R13!,{R1-R9,R14}
STMFD R13!,{R1-R2}
BL describeblockswi
MOV R4,R2
ADD R5,R2,R3; end address
LDMFD R13!,{R1-R2}
LDMVSFD R13!,{R1-R9,PC}
MOV R0,#10
SWI XOS_File
LDMFD R13!,{R1-R9,PC} ;returns possible error from SWI

.loadhammeredswi
STMFD R13!,{R1-R9,R14}
        ; R1 = filename
MOV R7,R0; R7 = pointer address as supplied
CMP R2,#0
ADREQ R2,defaultpath
MOV R4,R2; R4 = pathname
MOV R0,#0
SWI XBlitz_HammerOp
LDMVSFD R13!,{R1-R9,PC}
MOV R6,R3
CMP R3,#0
MOVEQ R0,R7
LDMEQFD R13!,{R1-R9,R14}
BEQ loadfileswi

STMFD R13!,{R1-R4}
MOV R5,R1
._loop
LDRB R0,[R5]
CMP R0,#32
ADDGT R5,R5,#1
BGT _loop
SUB R2,R5,#8
CMP R2,R1
MOVLT R2,R1
MOV R0,R7
MOV R1,R6
MOV R3,#2
BL claimblockswi
MOV R8,R0; R8 = block address
LDMFD R13!,{R1-R4}
LDMVSFD R13!,{R1-R9,PC}
MOV R0,#1
MOV R2,R4
MOV R3,R8
SWI XBlitz_HammerOp
LDMVSFD R13!,{R1-R9,PC}
MOV R0,R8
LDMFD R13!,{R1-R9,PC}^


.claimrma

;on entry	r2=pointer to block is at r12+r2 block
;		r3=requested size
;sets V if error

STMFD R13!,{R0-R4,R14}
MOV R0,#6
MOV R4,R2
SWI XOS_Module
MOVVS R2,#0
STR R2,[R12,R4]
LDMFD R13!,{R0-R4,PC}

.releaserma
STMFD R13!,{R0-R4,R14}
MOV R0,#7
MOV R4,R2
LDR R2,[R12,R2]
SWI XOS_Module
BLVS releaseerr
MOV R2,#0
STR R2,[R12,R4]
LDMFD R13!,{R0-R4,PC}
.releaseerr
STMFD R13!,{R14}
ADD R0,R0,#4
SWI OS_Write0
SWI OS_NewLine
LDMFD R13!,{PC}

.strncpy
STMFD R13!,{R0-R4,R14}
MOV R4,#0
MOV R3,#1; ie not zero
.loop6
CMP R3,#0
LDRNEB R3,[R1],#1
CMP R3,#"'"
BLEQ strnquote
STRB R3,[R0],#1
SUBS R2,R2,#1
BGT loop6
LDMFD R13!,{R0-R4,PC}
.strnquote
CMP R4,#"'"
MOVEQ R3,#0
MOVEQ PC,R14
MOV R4,#"'"
LDRB R3,[R1],#1
CMP R3,#"'"
MOVEQ R3,#0
MOV PC,R14

.service
CMP R1,#&4E
MOVNES PC,R14
STMFD R13!,{R0-R12,R14}
LDR R12,[R12]
BL newapplication
LDMFD R13!,{R0-R12,PC}

.init
STMFD R13!,{R7-R12,R14}
MOV R0,#6
MOV R3,#v.sizeof
SWI XOS_Module
STR R2,[R12]
LDR R12,[R12]
BVS initabort
MOV R0,#0
STR R0,[R12,#v.areastart]
STR R0,[R12,#v.gravx]
STR R0,[R12,#v.gravy]
LDMFD R13!,{R7-R12,PC}

.final
STMFD R13!,{R7-R12,R14}
LDR R12,[R12]
BL discardarea
.initabort
MOV R0,#7
MOV R2,R12
SWI XOS_Module
LDMFD R13!,{R7-R12,PC}^

.badnumber
STMFD R13!,{R0}
._loop
LDRB R0,[R1],#1
CMP R0,#" "
SWIGE OS_WriteC
BLGE _loop
SWI OS_WriteS
DCB 10,13,"!",10,13,0
ALIGN
LDMFD R13!,{R0}
SWI OS_GenerateError


.err
ORR R14,R14,#1<<28
MOVS PC,R14
.unknownswi
ADR R0,unknownswitext
B err
.unknownswitext
DCD &80C901
DCB "Amnesia : Unrecognised SWI",0
ALIGN
.amsnomatcherr
ADR R0,nomatcherrblock
B err
.nomatcherrblock
DCD &80C902
DCB "Amnesia : Unrecognised SWI tail",0
ALIGN
.badblockerr
ADR R0,badblocktext
B err
.badblocktext
DCD &80C903
DCB "Amnesia : Invalid memory block",0
ALIGN
.noroomrmaerr
ADR R0,noroomrmatext
B err
.noroomrmatext
DCD &80C904
DCB "Amnesia : Not enough memory in module area",0
ALIGN
.noroomerr
ADR R0,noroomtext
B err
.noroomtext
DCD &80C905
DCB "Amnesia : Not enough memory in Amnesia area",0
ALIGN
.notiniterr
ADR R0,notinittext
B err
.notinittext
DCD &80C906
DCB "Amnesia : Cannot perform operation - no area initialised",0
ALIGN
.toomanyerr
ADR R0,toomanytext
B err
.toomanytext
DCD &80C907
DCB "Amnesia : *** Aborting - Too many errors",0
ALIGN
.usedbadblockerr
ADR R0,usedbadblocktext
B err
.usedbadblocktext
DCD &80C908
DCB "Amnesia : Bad block detected when calculating used space",0
ALIGN
.scanbadblockerr
MOV R1,R0
ADR R0,scanbadblocktext
B err
.scanbadblocktext
DCD &80C909
DCB "Amnesia : Bad block detected when scanning block table",0
ALIGN
.badptrerr
ADR R0,badptrtext
B err
.badptrtext
DCD &80C90A
DCB "Amnesia : Supplied pointer address is not in valid memory",0
ALIGN
.tlisterr
STMFD R13!,{R14}
ADD R0,R0,#4
MOV R1,#0
MOV R2,#0
SWI OS_PrettyPrint
SWI OS_NewLine
LDMFD R13!,{R14}
ADR R0,tlisterrtext
B err
.tlisterrtext
DCD &80C90B
DCB "Amnesia : Failed to make a table list",0
ALIGN
.errbuf
DCD 0
.getblockerr
STR R0,[R12,#v.errorblock]
ADR R0,getblockerrtext
B err
.getblockerrtext
DCD &80C90C
DCB "Amnesia : Block does not exist",0
ALIGN
.notlisterr
ADR R0,notlisterrtext
B err
.notlisterrtext
DCD &80C90D
DCB "Amnesia : Cannot produce table - no internal table list",0
ALIGN
.tabletoohigherr
STR R0,[R12,#v.errortable]
ADR R0,tabletoohigherrtext
B err
.tabletoohigherrtext
DCD &80C90E
DCB "Amnesia : Table number is too high",0
ALIGN
.notableerr
STR R0,[R12,#v.errortable]
ADR R0,notableerrtext
B err
.notableerrtext
DCD &80C90F
DCB "Amnesia : Reference to table which does not exist",0
ALIGN
.notfoundblockerr
STR R0,[R12,#v.errorblock]
ADR R0,notfoundblockerrtext
B err
.notfoundblockerrtext
DCD &80C910
DCB "Amnesia : Cannot find requested block",0
ALIGN
.areacorrupterr
ADR R0,areacorrupterrtext
B err
.areacorrupterrtext
DCD &80C911
DCB "Amnesia : Area is corrupted.  Use *Ams Blocks",0
ALIGN
.badareaerr
STMFD R13!,{R14}
SWI OS_NewLine
LDMFD R13!,{R14}
ADR R0,badareaerrtext
B err
.badareaerrtext
DCD &80C912
DCB "Amnesia : Amnesia area is not consistent with normal operation",0
ALIGN
.movenonblockerr
STR R0,[R12,#v.errorblock]
ADR R0,movenonblockerrtext
B err
.movenonblockerrtext
DCD &80C913
DCB "Amnesia : Attempt to move a bad block",0
ALIGN

.inconblockerr
ADR R0,inconblockerrtext
B err
.inconblockerrtext
DCD &80C914
DCB "Amnesia : Block position and pointer to position do not agree",0
ALIGN
.needspaceerr
ADR R0,needspaceerrtext
B err
.needspaceerrtext
DCD &80C915
DCB "Amnesia : Abbreviated SWI tails with parameters must be followed by a space",0
ALIGN
.objectoutsideerr
STR R0,[R12,#v.errortable]
ADR R0,objectoutsideerrtext
B err
.objectoutsideerrtext
DCD &80C916
DCB "Amnesia : ProcessTable has received an object address outside of the table",0
ALIGN
.windownonerr
ADR R0,windownonerrtext
B err
.windownonerrtext
DCD &80C917
DCB "Amnesia : Bad window number - must be 0-2",0
ALIGN
.windowdodgyerr
ADR R0,windowdodgyerrtext
B err
.windowdodgyerrtext
DCD &80C918
DCB "Amnesia : Bad window - minimum greater than maximum",0
ALIGN
.colchnotableerr
ADR R0,colchnotableerrtext
B err
.colchnotableerrtext
DCD &80C919
DCB "Amnesia : Collision checking not requested when claiming table",0
ALIGN
.colchnoroomerr
ADR R0,colchnoroomerrtext
B err
.colchnoroomerrtext
DCD &80C920
DCB "Amnesia : No room in collision checking block",0
ALIGN
.notafileerr
STMFD R13!,{R14}
MOV R0,#19
SWI XOS_File
LDMFD R13!,{R14}
B err
.fatalerr
ADR R0,fatalerrtext
B err
.fatalerrtext
DCD &80C921
DCB "Amnesia : ***** Internal error ***** - please report any appearance of this error to the author, together with the circumstances in which the error occured.",0
ALIGN
.qwaerr
STR R0,[R12,#v.errorblock]
ADR R0,qwaerrtext
B err
.qwaerrtext
DCD &80C922
DCB "Amnesia : Area tidy would require a forward block shift.  Area corrupt?",0
ALIGN
.notyeterr
ADR R0,notyeterrtext
B err
.notyeterrtext
DCD &80C924
DCB "Amnesia : SWI not supported by this version",0
ALIGN
.badsaveerr
ADR R0,badsaveerrtext
B err
.badsaveerrtext
DCD &80C925
DCB "Amnesia : Failed to save",0
ALIGN

.remoteerr
ADR R0,remoteerrtext
B err
.remoteerrtext
DCD &80C926
DCB "Amnesia : Remote routine guard ID not present.  The word before the routine must be &006E0000.",0
ALIGN

.namematchwarn
STMFD R13!,{R14}
SWI OS_WriteS
DCB "Amnesia : LoadTable warning - The table name does not match that in the file",10,13,0
ALIGN
LDMFD R13!,{PC}

.objsizewarn
STMFD R13!,{R14}
SWI OS_WriteS
DCB "Amnesia : LoadTable warning - Object length does not match that in the file",10,13,0
ALIGN
LDMFD R13!,{PC}
