COURS202.TXT

From Atari Wiki
Revision as of 22:57, 16 December 2023 by Olivier.jan (talk | contribs) (Replacing content of with translated version)
Jump to navigation Jump to search
  ******************************************************************
  *                                                                *
  *               68000 ASSEMBLER COURSE ON ATARI ST               *
  *                                                                *
  *                 by The Ferocious Rabbit (from 44E)             *
  *                                                                *
  *                         Second series                          *
  *                                                                *
  *                         Lesson number 2                        *
  ******************************************************************
  So here we go again for new adventures! This second
  lesson will be about TRAPs and more precisely how to
  program them ourselves. We saw in the first series that
  TRAPs were an excellent way to access the operating system,
  and more generally to access protected spaces
  (only accessible in Supervisor mode). We had also
  studied the passing of parameters on the stack, which we
  used to make subroutines with parameters.
  The first example will consist of changing the background color
  of the screen, with a homemade routine that will be called
  by a TRAP.
  First, the routine:
  Given that a TRAP is always executed in Supervisor, we
  do not hesitate to use system addresses. The ST's color palette
  is located at the address $FF8240. Each color
  is coded on a word, so color 0 is at $FF8240, color 1
  at $FF8242, etc...
  We are going to make 2 routines. One that will set the background to red,
  the other will set the background to green. Here they are:
  RED     MOVE.W  #$700,$FF8240
          RTE
  GREEN   MOVE.W  #$070,$FF8240
          RTE
  A label identifies them (RED and GREEN). Colors are
  coded in RGB (red/green/blue) and the levels range from
  0 to 7. We notice that the routines do not end with
  RTS but by RTE. This means Return from exception. It is indeed
  a return from exception and not the return of a
  classic subroutine.
  Quick reminder: RTE reads "return from exception". I remind you
  that you must read EVERYTHING in English and not just the abbreviation
  whose meaning is often quite elusive.
  Here is the 'entire' program.
          MOVE.L  #MESSAGE,-(SP)  it's always nice to introduce yourself
          MOVE.W  #9,-(SP)
          TRAP    #1              call GEMDOS
          ADDQ.L  #6,SP   
  * Set the exception vector
          MOVE.L  #RED,-(SP)      'routine' address
          MOVE.W  #35,-(SP)       trap #3 vector number
          MOVE.W  #5,-(SP)        Setexec() function
          TRAP    #13             from the bios
          ADDQ.L  #8,SP
          MOVE.L  #GREEN,-(SP)    'routine' address
          MOVE.W  #36,-(SP)       trap #4 vector number
          MOVE.W  #5,-(SP)        Setexec() function
          TRAP    #13             from the bios
          ADDQ.L  #8,SP
  * The routines are now accessible by trap 3 and
  by trap 4.
          BSR     KEY
          TRAP    #3
          BSR     KEY
          TRAP    #4
          BSR     KEY
          TRAP    #3
          BSR     KEY
          
          MOVE.W  #0,-(SP)
          TRAP    #1
  *-------------------------------------*
  RED     MOVE.W  #$700,$FF8240
          RTE
          
  GREEN   MOVE.W  #$070,$FF8240
          RTE
  *-------------------------------------*
  KEY     MOVE.W  #7,-(SP)
          TRAP    #1
          ADDQ.L  #2,SP
          RTS
  *-------------------------------------*
          SECTION DATA
  MESSAGE DC.B    27,"E","TRAPS",0


  Easy, isn't it? And now that you know how to set
  your own routines in TRAP and that you also know how to pass
  parameters to a subroutine, all you have to do
  is to do the same thing. I think you're grown up enough to do
  it yourself and that's why we're not going to
  do it here. You only need to be careful with one thing: A subroutine only needs the return address and
  thus only stacks it. However, a TRAP, since it switches
  to Supervisor, also saves the Status Register. You must
  not forget to take this into account when calculating the jump
  that will allow you to retrieve your parameters passed on the
  stack. The return address is of course coded on 4 bytes and the
  Status Register on 2. There is therefore stacking of 6 bytes by the
  TRAP which automatically unstacks them on return in order to find
  where it comes from and also to restore the Status
  Register as it was before. Do not forget to correct the stack
  on return.
  As usual, take your time and do lots of little
  tests to perfectly understand the system.
  Also look carefully at the Bios function that we have
  used to implement our two routines. If instead of
  supplying the new address for the vector, we pass -1,
  this function will return to us, in D0.L, the current address
  corresponding to this vector. So there is nothing stopping us from requesting
  the address used by TRAP #1 (Gemdos), transfer this
  address to trap #0 (for example) and put our own
  routine in TRAP #1. This can also be useful for
  diverting the TRAP. For example, to automatically generate
  macros. It is possible to imagine a program residing in
  memory, which is placed instead of trap 13 (Bios). Each
  time there is a call to Bios, it is our routine that is
  triggered. Since calls are made with stacking
  of parameters, it is quite possible to know which
  Bios function is being called. It is then possible to react
  differently to certain functions. This allows for example to
  test presses on Alternate+function keys and in this
  case, to write phrases in the keyboard buffer, this in order
  to generate macros!
  Note: A trap cannot call traps placed 'below'
  itself. Thus, in a trap #1, it is quite possible
  to call a trap #13 but the reverse is not possible.
  Curious and interesting example:
          MOVE.W  #"A",-(SP)
          MOVE.W  #2,-(SP)
          TRAP    #1
          ADDQ.L  #4,SP
          MOVE.W  #0,-(SP)
          TRAP    #1
  This short program should not pose any problem. We display A
   and then we quit. Assemble it and then run under MONST.
  Press [Control] + P. You will then choose the preferences
  of MONST. Among them, there is "follow traps", which by default is on "NO". Type Y for YES.
  Once preferences are set, advance your program
  step by step with control+Z. Unlike other times,
  when you arrive on the TRAP you see what happens. Do not be
  surprised, it will be quite long because a lot happens to display a single character on the screen. The most
  amazing thing will be the call to trap #13. Yes indeed, to display a
  character the GEMDOS calls the Bios!!!!!
  Another equally interesting experience:
          MOVE.W  #"A",-(SP)
          MOVE.W  #2,-(SP)
          MOVE.W  #3,-(SP)
          TRAP    #13
          ADDQ.L  #6,SP   
          MOVE.W  #0,-(SP)
          TRAP    #1
  Display of A but this time with the Bconout() function of
  the Bios. Assemble and then run under MONST with trap tracking.
  When you get into the Bios (thus after the walk on
  the TRAP #13 instruction), advance the program step by step
  but from time to time type the letter V. This allows you to
  see the screen. To return to MONST type any
  key. Advance a few more instructions and then type V
  etc... After a while, you will see the letter A appear.
  Reflect on the concept of graphical screen and fonts and you will understand without difficulty what happens. Surprising, isn't it?
  A few more things: follow the traps of the Bios, Xbios,
  GemDos and look at what happens at the beginning. You will
  realize that there is registry saving on the stack. Only
  D3-D7/A3-A6 are saved and thus the content of D2 is potentially
  erasable by a call to the operating system. Caution is therefore
  advised. Also by following the TRAPs you will notice USP.
  This means User Stack Pointer and this is how the user stack is referred to.
  That's it, normally traps should no longer be a secret for you. You
  should know how to pass them parameters, reprogram them, etc...
  You should even realize that by following the operating system functions, you should be able to discover how certain
  things are done, and thus be able to rewrite portions of
  routines. 

Back to ASM_Tutorial