Amiga Machine Language (Chapter 8)

A - Wiki wikiből

     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
       Here is a list of vectors that are used to jump to the exception  
       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) 
       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:
              move.l  #trap0,$80        ;set vector for TRAP #0
       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)
              subq.l  #1,d0             ;counter -1
              bne     loop              ;count dwn to zero
              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
              move.l  #$2ffff,d0        ;pass tone length in D0
              trap    #0                ;carry out exception:peep
       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!
Személyes eszközök