Amiga Machine Language (Chapter 8)
Innen: amigaspirit.hu - pegasos.hu Wiki
Ugrás a navigációhozUgrás a kereséshez
Chapter 8. ---------- 8.Advanced Programming. ----------------------- You've learned a lot about machine language programming on the Amiga.What you need yet are a few routines that can be used as programming tools.We'll work on that right now.They'll be easy to use in your own program.The sky's the limit now!
8.1.Supervisor Mode. -------------------- As mentioned in the chapter on the MC68000 processor,there are two operating modes:the User and the Supervisor mode.It is often necessary to move between the two modes.However,this isn't a simple process. The reason you want to do this,is that in User mode,you can't access the Status register.If you write to one of them,an Exception is executed which crashes the program.
How can you get in Supervisor mode?
No problem.The operating system of the Amiga contains a function in the EXEC library that lets you get into supervisor mode.Its called SuperState and it doesn't need any parameters.You can easily call this program by using the following lines:
execbase = 4 ;exec base address superstate =-150 ;turn on function ... move.l execbase,a6 ;exec base address in A6 jsr superstate(a6) ;turn on supervisor mode move.l d0,savesp ;save return value ... savesp:blk.l 1 ;space for sp value
You get the value of the Stack Pointer(SP)back in the D0 register. You'll also find it in register A7,but this register is changed regularly.The reason is that in Supervisor mode,the Amiga works with all the Interrupts and with the SP,and there are lots of Interrupts for this computor.We'll talk about interrupts in a bit.
After this call,you'll use the user stack instead of the supervisor stack.In this way,you can access the old user stack.You need to make sure that the user stack is large enough since the interrupts must have enough room for their data on the stack. You need to save the value returned in D0,because you'll need this value later.You need to return to user mode sometime.Theres a function for this in the exec library as well.It is called the UserState function.It needs one parameter,the SP value that comes back from the SuperState function. Since you've saved this value in the long word starting at "savesp",you can write the following:
userstate =-156 ... move.l execbase,a6 ;exec base address in A6 move.l savesp,d0 ;put old sp in D0 jsr userstate(a6) ;return to user mode
Now you are back in the user mode.The user stack point(USP)is the same as before.You can write functions that need to be run from the supervisor mode as subroutines.First you call superstate,save the return value,execute the desired function,call userstate,and end with a RTS command.If the USP was changed,the RTS command would'nt work right,and the computor would jump who knows where and perhaps crash.Here it works though. Now comes the question:how does the operating system get the supervisor mode?Thats not too difficult;it goes like this:
The superstate function attempts to access a Status Register.This causes an Exception to occur and a routine is called whose address begins at the long word starting at $20.It is the Exception Vector for Privilege Violation.The routine that it branches to is called in supervisor mode.Then it tests where this exception came from.If the routine finds that the exception comes from the superstate routine whose address it knows,the matter is settled.It just branches to the routine without turning off the user mode.Thats all there is to it.
8.2.Exception Programming. -------------------------- The exceptions described in the processor chapter offer you a lot of oppertunities to control the Amiga's functions.You can use them to specify how errors should be handled and even list a crash program.
Here is a list of vectors that are used to jump to the exception routines:
Number Address Use with ------------------------------------------------------------------ 2 $008 Bus error 3 $00C Address eror 4 $010 Illegal command 5 $014 Division by zero 6 $018 CHK command 7 $01C TRAPV command 8 $020 Privilege Violation 9 $024 Trace 10 $028 Axxx command emulation 11 $02C Fxxx command emulation $030-$038 Reserved 15 $03C Uninitialized interrupt $040-$05F Reserved 24 $060 Unauthorised interrupt 25-31 $064-$083 Level 1-7 interrupt 32-47 $080-$0BF TRAP commands $0C0-$0FF Reserved 64-255 $100-$3FF User interrupt vector
Lets look at the TRAP commands as an example.They aren't used in the Amiga operating system.A TRAP command and a number between zero and fifteen are used to call one of the 16 posible TRAP routines.If the command TRAP #0 is executed,the processor (in supervisor mode)branches to the routine whose address lies at $80 in memory.This routine must end with a RTE(ReTurn from Exception) command. Some operating systems,for example,the ATARI ST's TOS operating systems,are completely callable via these TRAP's.Parameters are put on the stack,and then a TRAP command is executed.The advantage is that you don't have to know any of the operating systems addresses.In the Amiga you must know the addresses(Execbase=4).
Lets write your own TRAP routine to demonstrate the use of the TRAP command.You'll need three program sections:
1.The initialization of the TRAP vector. 2.The TRAP routine itself(It must end with RTE). 3.A test routine that calls the TRAP command.
Initialization is very short:
init: move.l #trap0,$80 ;set vector for TRAP #0 rts
Now you need to write the trap0 routine.Lets use the example from the hardware chapter that produced a beep. Lets write this routine using as little effort as possible.Change the RTS to a RTE at the end,erase the line in which the loop counter D0 was loaded for the tone production,and change the loop so that it works with long words.Now you can load the register with an arbitrary value and have the TRAP #0 followed by a peep of arbitrary duration.
;** beep tone production after a TRAP #0 **
ctlw =$dff096 ;DMA control c0thi =$dff0a0 ;HI table address c0tlo =c0thi+2 ;LO table address c0tl =c0thi+4 ;table length c0per =c0thi+6 ;read in rate c0vol =c0thi+8 ;volume
trap0: ;* produce a short peep move.l #table,c0thi ;table beginning move #4,c0tl ;table length move #300,c0per ;read in rate move #40,c0vol ;volume move #$8201,ctlw ;start DMA (sound)
loop: subq.l #1,d0 ;counter -1 bne loop ;count dwn to zero
still: move #1,ctlw ;turn on tone rte ;exception end
table: ;sound table dc.b -40,-70,-40,0,40,70,40,0
You need to make sure that "table"is in CHIP RAM($00000-$7FFFF), otherwise the sound chip can't access the data!
After entering this,you can test it out using the following routine:
test: move.l #$2ffff,d0 ;pass tone length in D0 trap #0 ;carry out exception:peep rts
Now assemble both routines and start the initialization routine, init.Nothing happens. Start the second routine,test.A beep that lasts about one second is output. One thing you must keep in mind is that if you change the program and reassemble it,the address of the trap0 routine can change. Before you execute the TRAP command,you must repeat the initializ- ation,so that the computor doesn't jump to the wrong location!