AMOS Professional extensions are written in Motorola 68000 Assembly Language.
+Music.s contains instructions for how to make an extension. I've added my own notes below and clarified some of the existing information.
Don't forget the terminating -1
! If you built it and forgot it, trying to start AMOS Pro will do nothing. Replace with you known good copy and reboot, then try again.
I
- none0
- long2
- string*0
- long2
- string*Strings are stored in AMOS with a word for string length (so strings can be up to 65535 characters in length), and then the string itself. I'm not sure if they're null terminated.
You can Rbsr
and other branch related jumps to your own stuff, but you can't Rjsr
to your routines! Only to built-in AMOS routines. Use Rbsr
and its equivalent! The Compiler will let you know of this mistake very quickly.
These call exec/AllocMem for you through AMOS.
L_RamChip
== PUBLIC|CLEAR|CHIP
L_RamChip2
== PUBLIC|CHIP
L_RamFast
== PUBLIC|CLEAR
L_RamFast2
== PUBLIC
MOVE.L #400,D0 Rjsr L_RamFast BNE RamAllocated ; couldn't get RAM, D0 is 0 RamAllocated: ; D0 contains address of RAM
Free it with L_RamFree
:
MOVE.L D0,A1 MOVE.L #length,D0 Rjsr L_RamFree
When you want to demand string space, you apply for it with L_Demande
.
The requested length goes into D3. It has to be even. You get the base address in both A0 and A1.
This is an AMOS string, so the first two bytes are the size of the string as a word. Then the string comes after.
Then, you have to eventually hand HiChaine(A5)
(be sure to preserve A5) the ending address of the string.
Make sure you don't try to allocate a zero width string with this! It will fail hard.
Writing out a routine in +CompExt.s with comments to understand this:
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; =COMP ERR$ ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lib_Par CompErr ; - - - - - - - - - - - - - Dload a2 ; get the data area moveq #0,d3 ; clean out d3 move.w LErreur-CD(a2),d3 ; this is the length of the error string as a word beq.s .Vide ; if it's zero there's nothing to do Rjsr L_Demande ; get string space, put the address in a0 and a1 move.w d3,d0 ; preserve existing length in d0 move.l a0,d3 ; move the address into d3 move.w d0,(a1)+ ; put the length into the start of the string subq.w #1,d0 ; reduce the length by 1 lea Erreur-CD(a2),a0 ; load the error string address into a0 .Loop1 move.b (a0)+,(a1)+ ; copy a bit from a0 to a1 dbra d0,.Loop1 ; decrement d0. if d0 is greater than 0, go to loop move.w a1,d1; put the current target address into a1 and.w #$0001,d1 ; keep the lowest bit add.w d1,a1 ; add the current address to a1 move.l a1,HiChaine(a5) ; update the high end of string memory moveq #2,d2 rts .Vide move.l ChVide(a5),d3 ; return empty string moveq #2,d2 rts
Here's a better version:
; D4 contains your string length MOVE.L D4,D3 AND.W #$FFFE,D3 ADDQ #2,D3 ; round up to the nearest 2 Rjsr L_Demande ; string is in A0/A1 LEA 2(A0,D3.W),A1 MOVE.L A1,HiChaine(A5) MOVE.L A0,A1 ; put A1 back MOVE.W D4,(A0)+ ; put length of string at start of memory .stringstuff MOVE.B (A2)+,(A0)+ BNE .stringstuff ; copy until null terminator
You know your string code is working if you can do this:
A$=My String Function$ ' returns "wow" Print "cat" + A$ + "dog" ' "catwowdog"
Send ChVide(A5)
to D3
. “vide” in French is “empty” so that makes sense.
AMOS Professional will let you be a little sloppy with the differences between Lib_Def
, Lib_Par
, Rbcc
, and Rjsr
. The compiler will not.
Ensure you have your compiler set up properly:
Save those settings and you can use apcmp file.amos inclib
in your build script to build something for testing.
If your code is crashing, check for the following:
Rbcc
for routines in your library.Rbcc
to Lib_Def
routines, not Lib_Par
routines.
If you do this, the compiler will be happy. I suggest having a test AMOS file you can compile and run that will exercise all the code that Rbcc
s within your own code and running it often, to keep you safe.
Peek
/Deek
/Leek
are one of the few ways you have of debugging things. Don't worry about allocating RAM and not freeing it at this point. You'll likely be rebooting very soon anyway…; functions dc.w L_Nul,L_ThisWillReturnAValue ; instructions dc.w L_ThisReturnsGarbage,L_Nul
Library_Digest
executable seems to load AMOS config and will OOM if the extension is broken? Or maybe this just needs a reboot. Or a rewrite in C.Dload A3
into code that takes function parameters? You need to preserve and restore A3, otherwise AMOS will crash.ASSIGN
to your code, Leaving your code file Out on the desktop, and whatever else you can do to get back into coding is necessary.INCLUDE
a file that contains Lib_Def
code.These use a bunch of macros I built for the BSD Socket extension:
C_Tk dc.w 1,0 ;... ; if something that accepts parameters and returns a value AddTokenFunction MyNewFunction dc.b "my new functio","n"+$80,"00,0",-1 ; if something that returns nothing and just has side effects AddTokenInstruction MyNewInstruction dc.b "my new instructio"."n"+$80,"I",-1
Lib_Par
section to the bottom of the fileLib_Par MyNewFunction PreserveStackFunction RestoreStackFunction Ret_Int
A3
in reverse order:; takes four parameters Lib_Par MyNewFunction PreserveStackFunction MOVE.L D3,D4 ; last parameter MOVE.L (A3)+,D3 ; second-to-last MOVE.L (A3)+,D2 ; second-to-first MOVE.L (A3)+,D1 ; first RestoreStackFunction Ret_Int
D3
:Lib_Par MyNewFunction PreserveStackFunction MOVE.L (A0),D3 ; return value RestoreStackFunction Ret_Int